Home | History | Annotate | Download | only in logging
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "media/cast/logging/encoding_event_subscriber.h"
      6 
      7 #include <cstring>
      8 #include <utility>
      9 
     10 #include "base/logging.h"
     11 #include "media/cast/logging/proto/proto_utils.h"
     12 
     13 using google::protobuf::RepeatedPtrField;
     14 using media::cast::proto::AggregatedFrameEvent;
     15 using media::cast::proto::AggregatedPacketEvent;
     16 using media::cast::proto::BasePacketEvent;
     17 using media::cast::proto::LogMetadata;
     18 
     19 namespace {
     20 
     21 // A size limit on maps to keep lookups fast.
     22 const size_t kMaxMapSize = 200;
     23 
     24 // The smallest (oredered by RTP timestamp) |kNumMapEntriesToTransfer| entries
     25 // will be moved when the map size reaches |kMaxMapSize|.
     26 // Must be smaller than |kMaxMapSize|.
     27 const size_t kNumMapEntriesToTransfer = 100;
     28 
     29 template <typename ProtoPtr>
     30 bool IsRtpTimestampLessThan(const ProtoPtr& lhs, const ProtoPtr& rhs) {
     31   return lhs->relative_rtp_timestamp() < rhs->relative_rtp_timestamp();
     32 }
     33 
     34 BasePacketEvent* GetNewBasePacketEvent(AggregatedPacketEvent* event_proto,
     35     int packet_id, int size) {
     36   BasePacketEvent* base = event_proto->add_base_packet_event();
     37   base->set_packet_id(packet_id);
     38   base->set_size(size);
     39   return base;
     40 }
     41 
     42 }
     43 
     44 namespace media {
     45 namespace cast {
     46 
     47 EncodingEventSubscriber::EncodingEventSubscriber(
     48     EventMediaType event_media_type,
     49     size_t max_frames)
     50     : event_media_type_(event_media_type),
     51       max_frames_(max_frames),
     52       frame_event_storage_index_(0),
     53       packet_event_storage_index_(0),
     54       seen_first_rtp_timestamp_(false),
     55       first_rtp_timestamp_(0u) {}
     56 
     57 EncodingEventSubscriber::~EncodingEventSubscriber() {
     58   DCHECK(thread_checker_.CalledOnValidThread());
     59 }
     60 
     61 void EncodingEventSubscriber::OnReceiveFrameEvent(
     62     const FrameEvent& frame_event) {
     63   DCHECK(thread_checker_.CalledOnValidThread());
     64 
     65   if (event_media_type_ != frame_event.media_type)
     66     return;
     67 
     68   RtpTimestamp relative_rtp_timestamp =
     69       GetRelativeRtpTimestamp(frame_event.rtp_timestamp);
     70   FrameEventMap::iterator it = frame_event_map_.find(relative_rtp_timestamp);
     71   linked_ptr<AggregatedFrameEvent> event_proto;
     72 
     73   // Look up existing entry. If not found, create a new entry and add to map.
     74   if (it == frame_event_map_.end()) {
     75     event_proto.reset(new AggregatedFrameEvent);
     76     event_proto->set_relative_rtp_timestamp(relative_rtp_timestamp);
     77     frame_event_map_.insert(
     78         std::make_pair(relative_rtp_timestamp, event_proto));
     79   } else {
     80     event_proto = it->second;
     81     if (event_proto->event_type_size() >= kMaxEventsPerProto) {
     82       DVLOG(2) << "Too many events in frame " << frame_event.rtp_timestamp
     83                << ". Using new frame event proto.";
     84       AddFrameEventToStorage(event_proto);
     85       event_proto.reset(new AggregatedFrameEvent);
     86       event_proto->set_relative_rtp_timestamp(relative_rtp_timestamp);
     87       it->second = event_proto;
     88     }
     89   }
     90 
     91   event_proto->add_event_type(ToProtoEventType(frame_event.type));
     92   event_proto->add_event_timestamp_ms(
     93       (frame_event.timestamp - base::TimeTicks()).InMilliseconds());
     94 
     95   if (frame_event.type == FRAME_ENCODED) {
     96     event_proto->set_encoded_frame_size(frame_event.size);
     97     if (frame_event.media_type == VIDEO_EVENT) {
     98       event_proto->set_encoded_frame_size(frame_event.size);
     99       event_proto->set_key_frame(frame_event.key_frame);
    100       event_proto->set_target_bitrate(frame_event.target_bitrate);
    101     }
    102   } else if (frame_event.type == FRAME_PLAYOUT) {
    103     event_proto->set_delay_millis(frame_event.delay_delta.InMilliseconds());
    104   }
    105 
    106   if (frame_event_map_.size() > kMaxMapSize)
    107     TransferFrameEvents(kNumMapEntriesToTransfer);
    108 
    109   DCHECK(frame_event_map_.size() <= kMaxMapSize);
    110   DCHECK(frame_event_storage_.size() <= max_frames_);
    111 }
    112 
    113 void EncodingEventSubscriber::OnReceivePacketEvent(
    114     const PacketEvent& packet_event) {
    115   DCHECK(thread_checker_.CalledOnValidThread());
    116 
    117   if (event_media_type_ != packet_event.media_type)
    118     return;
    119 
    120   RtpTimestamp relative_rtp_timestamp =
    121       GetRelativeRtpTimestamp(packet_event.rtp_timestamp);
    122   PacketEventMap::iterator it =
    123       packet_event_map_.find(relative_rtp_timestamp);
    124   linked_ptr<AggregatedPacketEvent> event_proto;
    125   BasePacketEvent* base_packet_event_proto = NULL;
    126 
    127   // Look up existing entry. If not found, create a new entry and add to map.
    128   if (it == packet_event_map_.end()) {
    129     event_proto.reset(new AggregatedPacketEvent);
    130     event_proto->set_relative_rtp_timestamp(relative_rtp_timestamp);
    131     packet_event_map_.insert(
    132         std::make_pair(relative_rtp_timestamp, event_proto));
    133     base_packet_event_proto = GetNewBasePacketEvent(
    134         event_proto.get(), packet_event.packet_id, packet_event.size);
    135   } else {
    136     // Found existing entry, now look up existing BasePacketEvent using packet
    137     // ID. If not found, create a new entry and add to proto.
    138     event_proto = it->second;
    139     RepeatedPtrField<BasePacketEvent>* field =
    140         event_proto->mutable_base_packet_event();
    141     for (RepeatedPtrField<BasePacketEvent>::pointer_iterator base_it =
    142              field->pointer_begin();
    143          base_it != field->pointer_end();
    144          ++base_it) {
    145       if ((*base_it)->packet_id() == packet_event.packet_id) {
    146         base_packet_event_proto = *base_it;
    147         break;
    148       }
    149     }
    150     if (!base_packet_event_proto) {
    151       if (event_proto->base_packet_event_size() >= kMaxPacketsPerFrame) {
    152         DVLOG(3) << "Too many packets in AggregatedPacketEvent "
    153                  << packet_event.rtp_timestamp << ". "
    154                  << "Using new packet event proto.";
    155         AddPacketEventToStorage(event_proto);
    156         event_proto.reset(new AggregatedPacketEvent);
    157         event_proto->set_relative_rtp_timestamp(relative_rtp_timestamp);
    158         it->second = event_proto;
    159       }
    160 
    161       base_packet_event_proto = GetNewBasePacketEvent(
    162           event_proto.get(), packet_event.packet_id, packet_event.size);
    163     } else if (base_packet_event_proto->event_type_size() >=
    164                kMaxEventsPerProto) {
    165       DVLOG(3) << "Too many events in packet "
    166                << packet_event.rtp_timestamp << ", "
    167                << packet_event.packet_id << ". Using new packet event proto.";
    168       AddPacketEventToStorage(event_proto);
    169       event_proto.reset(new AggregatedPacketEvent);
    170       event_proto->set_relative_rtp_timestamp(relative_rtp_timestamp);
    171       it->second = event_proto;
    172       base_packet_event_proto = GetNewBasePacketEvent(
    173           event_proto.get(), packet_event.packet_id, packet_event.size);
    174     }
    175   }
    176 
    177   base_packet_event_proto->add_event_type(
    178       ToProtoEventType(packet_event.type));
    179   base_packet_event_proto->add_event_timestamp_ms(
    180       (packet_event.timestamp - base::TimeTicks()).InMilliseconds());
    181 
    182   // |base_packet_event_proto| could have been created with a receiver event
    183   // which does not have the packet size and we would need to overwrite it when
    184   // we see a sender event, which does have the packet size.
    185   if (packet_event.size > 0) {
    186     base_packet_event_proto->set_size(packet_event.size);
    187   }
    188 
    189   if (packet_event_map_.size() > kMaxMapSize)
    190     TransferPacketEvents(kNumMapEntriesToTransfer);
    191 
    192   DCHECK(packet_event_map_.size() <= kMaxMapSize);
    193   DCHECK(packet_event_storage_.size() <= max_frames_);
    194 }
    195 
    196 void EncodingEventSubscriber::GetEventsAndReset(LogMetadata* metadata,
    197     FrameEventList* frame_events, PacketEventList* packet_events) {
    198   DCHECK(thread_checker_.CalledOnValidThread());
    199 
    200   // Flush all events.
    201   TransferFrameEvents(frame_event_map_.size());
    202   TransferPacketEvents(packet_event_map_.size());
    203   std::sort(frame_event_storage_.begin(), frame_event_storage_.end(),
    204             &IsRtpTimestampLessThan<linked_ptr<AggregatedFrameEvent> >);
    205   std::sort(packet_event_storage_.begin(), packet_event_storage_.end(),
    206             &IsRtpTimestampLessThan<linked_ptr<AggregatedPacketEvent> >);
    207 
    208   metadata->set_is_audio(event_media_type_ == AUDIO_EVENT);
    209   metadata->set_first_rtp_timestamp(first_rtp_timestamp_);
    210   metadata->set_num_frame_events(frame_event_storage_.size());
    211   metadata->set_num_packet_events(packet_event_storage_.size());
    212   metadata->set_reference_timestamp_ms_at_unix_epoch(
    213       (base::TimeTicks::UnixEpoch() - base::TimeTicks()).InMilliseconds());
    214   frame_events->swap(frame_event_storage_);
    215   packet_events->swap(packet_event_storage_);
    216   Reset();
    217 }
    218 
    219 void EncodingEventSubscriber::TransferFrameEvents(size_t max_num_entries) {
    220   DCHECK(frame_event_map_.size() >= max_num_entries);
    221 
    222   FrameEventMap::iterator it = frame_event_map_.begin();
    223   for (size_t i = 0;
    224        i < max_num_entries && it != frame_event_map_.end();
    225        i++, ++it) {
    226     AddFrameEventToStorage(it->second);
    227   }
    228 
    229   frame_event_map_.erase(frame_event_map_.begin(), it);
    230 }
    231 
    232 void EncodingEventSubscriber::TransferPacketEvents(size_t max_num_entries) {
    233   PacketEventMap::iterator it = packet_event_map_.begin();
    234   for (size_t i = 0;
    235        i < max_num_entries && it != packet_event_map_.end();
    236        i++, ++it) {
    237     AddPacketEventToStorage(it->second);
    238   }
    239 
    240   packet_event_map_.erase(packet_event_map_.begin(), it);
    241 }
    242 
    243 void EncodingEventSubscriber::AddFrameEventToStorage(
    244     const linked_ptr<AggregatedFrameEvent>& frame_event_proto) {
    245   if (frame_event_storage_.size() >= max_frames_) {
    246     frame_event_storage_[frame_event_storage_index_] = frame_event_proto;
    247   } else {
    248     frame_event_storage_.push_back(frame_event_proto);
    249   }
    250 
    251   frame_event_storage_index_ = (frame_event_storage_index_ + 1) % max_frames_;
    252 }
    253 
    254 void EncodingEventSubscriber::AddPacketEventToStorage(
    255     const linked_ptr<AggregatedPacketEvent>& packet_event_proto) {
    256   if (packet_event_storage_.size() >= max_frames_)
    257     packet_event_storage_[packet_event_storage_index_] = packet_event_proto;
    258   else
    259     packet_event_storage_.push_back(packet_event_proto);
    260 
    261   packet_event_storage_index_ = (packet_event_storage_index_ + 1) % max_frames_;
    262 }
    263 
    264 RtpTimestamp EncodingEventSubscriber::GetRelativeRtpTimestamp(
    265     RtpTimestamp rtp_timestamp) {
    266   if (!seen_first_rtp_timestamp_) {
    267     seen_first_rtp_timestamp_ = true;
    268     first_rtp_timestamp_ = rtp_timestamp;
    269   }
    270 
    271   return rtp_timestamp - first_rtp_timestamp_;
    272 }
    273 
    274 void EncodingEventSubscriber::Reset() {
    275   frame_event_map_.clear();
    276   frame_event_storage_.clear();
    277   frame_event_storage_index_ = 0;
    278   packet_event_map_.clear();
    279   packet_event_storage_.clear();
    280   packet_event_storage_index_ = 0;
    281   seen_first_rtp_timestamp_ = false;
    282   first_rtp_timestamp_ = 0u;
    283 }
    284 
    285 }  // namespace cast
    286 }  // namespace media
    287