This source file includes following definitions.
- stream
- stream_type
- GetTrackIds
- owner_
- SendLifetimeMessages
- OnChanged
- ReportAddedAndRemovedTracks
- ReportTracks
- AddStream
- RemoveStream
- IceConnectionChange
- SendLifetimeMessage
- MakeUniqueIdImpl
- MakeUniqueId
#include "content/renderer/media/webrtc/media_stream_track_metrics.h"
#include <inttypes.h>
#include <algorithm>
#include <set>
#include <string>
#include "base/md5.h"
#include "content/common/media/media_stream_track_metrics_host_messages.h"
#include "content/renderer/render_thread_impl.h"
#include "third_party/libjingle/source/talk/app/webrtc/mediastreaminterface.h"
using webrtc::AudioTrackVector;
using webrtc::MediaStreamInterface;
using webrtc::MediaStreamTrackInterface;
using webrtc::PeerConnectionInterface;
using webrtc::VideoTrackVector;
namespace content {
class MediaStreamTrackMetricsObserver : public webrtc::ObserverInterface {
public:
MediaStreamTrackMetricsObserver(
MediaStreamTrackMetrics::StreamType stream_type,
MediaStreamInterface* stream,
MediaStreamTrackMetrics* owner);
virtual ~MediaStreamTrackMetricsObserver();
void SendLifetimeMessages(MediaStreamTrackMetrics::LifetimeEvent event);
MediaStreamInterface* stream() { return stream_; }
MediaStreamTrackMetrics::StreamType stream_type() { return stream_type_; }
private:
typedef std::set<std::string> IdSet;
virtual void OnChanged() OVERRIDE;
template <class T>
IdSet GetTrackIds(const std::vector<talk_base::scoped_refptr<T> >& tracks) {
IdSet track_ids;
typename std::vector<talk_base::scoped_refptr<T> >::const_iterator it =
tracks.begin();
for (; it != tracks.end(); ++it) {
track_ids.insert((*it)->id());
}
return track_ids;
}
void ReportAddedAndRemovedTracks(
const IdSet& new_ids,
const IdSet& old_ids,
MediaStreamTrackMetrics::TrackType track_type);
void ReportTracks(const IdSet& ids,
MediaStreamTrackMetrics::TrackType track_type,
MediaStreamTrackMetrics::LifetimeEvent event);
bool has_reported_start_;
bool has_reported_end_;
IdSet audio_track_ids_;
IdSet video_track_ids_;
MediaStreamTrackMetrics::StreamType stream_type_;
talk_base::scoped_refptr<MediaStreamInterface> stream_;
MediaStreamTrackMetrics* owner_;
};
namespace {
struct ObserverFinder {
ObserverFinder(MediaStreamTrackMetrics::StreamType stream_type,
MediaStreamInterface* stream)
: stream_type(stream_type), stream_(stream) {}
bool operator()(MediaStreamTrackMetricsObserver* observer) {
return stream_ == observer->stream() &&
stream_type == observer->stream_type();
}
MediaStreamTrackMetrics::StreamType stream_type;
MediaStreamInterface* stream_;
};
}
MediaStreamTrackMetricsObserver::MediaStreamTrackMetricsObserver(
MediaStreamTrackMetrics::StreamType stream_type,
MediaStreamInterface* stream,
MediaStreamTrackMetrics* owner)
: has_reported_start_(false),
has_reported_end_(false),
stream_type_(stream_type),
stream_(stream),
owner_(owner) {
OnChanged();
stream_->RegisterObserver(this);
}
MediaStreamTrackMetricsObserver::~MediaStreamTrackMetricsObserver() {
stream_->UnregisterObserver(this);
SendLifetimeMessages(MediaStreamTrackMetrics::DISCONNECTED);
}
void MediaStreamTrackMetricsObserver::SendLifetimeMessages(
MediaStreamTrackMetrics::LifetimeEvent event) {
if (event == MediaStreamTrackMetrics::CONNECTED) {
if (has_reported_start_)
return;
DCHECK(!has_reported_start_ && !has_reported_end_);
has_reported_start_ = true;
} else {
DCHECK(event == MediaStreamTrackMetrics::DISCONNECTED);
if (has_reported_end_ || !has_reported_start_)
return;
has_reported_end_ = true;
}
ReportTracks(audio_track_ids_, MediaStreamTrackMetrics::AUDIO_TRACK, event);
ReportTracks(video_track_ids_, MediaStreamTrackMetrics::VIDEO_TRACK, event);
if (event == MediaStreamTrackMetrics::DISCONNECTED) {
DCHECK(has_reported_start_ && has_reported_end_);
has_reported_start_ = false;
has_reported_end_ = false;
}
}
void MediaStreamTrackMetricsObserver::OnChanged() {
AudioTrackVector all_audio_tracks = stream_->GetAudioTracks();
IdSet all_audio_track_ids = GetTrackIds(all_audio_tracks);
VideoTrackVector all_video_tracks = stream_->GetVideoTracks();
IdSet all_video_track_ids = GetTrackIds(all_video_tracks);
if (has_reported_start_ && !has_reported_end_) {
ReportAddedAndRemovedTracks(all_audio_track_ids,
audio_track_ids_,
MediaStreamTrackMetrics::AUDIO_TRACK);
ReportAddedAndRemovedTracks(all_video_track_ids,
video_track_ids_,
MediaStreamTrackMetrics::VIDEO_TRACK);
}
audio_track_ids_ = all_audio_track_ids;
video_track_ids_ = all_video_track_ids;
}
void MediaStreamTrackMetricsObserver::ReportAddedAndRemovedTracks(
const IdSet& new_ids,
const IdSet& old_ids,
MediaStreamTrackMetrics::TrackType track_type) {
DCHECK(has_reported_start_ && !has_reported_end_);
IdSet added_tracks;
std::set_difference(new_ids.begin(),
new_ids.end(),
old_ids.begin(),
old_ids.end(),
std::inserter(added_tracks, added_tracks.end()));
IdSet removed_tracks;
std::set_difference(old_ids.begin(),
old_ids.end(),
new_ids.begin(),
new_ids.end(),
std::inserter(removed_tracks, removed_tracks.end()));
ReportTracks(added_tracks, track_type, MediaStreamTrackMetrics::CONNECTED);
ReportTracks(
removed_tracks, track_type, MediaStreamTrackMetrics::DISCONNECTED);
}
void MediaStreamTrackMetricsObserver::ReportTracks(
const IdSet& ids,
MediaStreamTrackMetrics::TrackType track_type,
MediaStreamTrackMetrics::LifetimeEvent event) {
for (IdSet::const_iterator it = ids.begin(); it != ids.end(); ++it) {
owner_->SendLifetimeMessage(*it, track_type, event, stream_type_);
}
}
MediaStreamTrackMetrics::MediaStreamTrackMetrics() {}
MediaStreamTrackMetrics::~MediaStreamTrackMetrics() {
for (ObserverVector::iterator it = observers_.begin(); it != observers_.end();
++it) {
(*it)->SendLifetimeMessages(DISCONNECTED);
}
}
void MediaStreamTrackMetrics::AddStream(StreamType type,
MediaStreamInterface* stream) {
DCHECK(CalledOnValidThread());
observers_.insert(observers_.end(),
new MediaStreamTrackMetricsObserver(type, stream, this));
}
void MediaStreamTrackMetrics::RemoveStream(StreamType type,
MediaStreamInterface* stream) {
DCHECK(CalledOnValidThread());
ObserverVector::iterator it = std::find_if(
observers_.begin(), observers_.end(), ObserverFinder(type, stream));
if (it == observers_.end()) {
return;
}
observers_.erase(it);
}
void MediaStreamTrackMetrics::IceConnectionChange(
PeerConnectionInterface::IceConnectionState new_state) {
DCHECK(CalledOnValidThread());
for (ObserverVector::iterator it = observers_.begin(); it != observers_.end();
++it) {
switch (new_state) {
case PeerConnectionInterface::kIceConnectionConnected:
case PeerConnectionInterface::kIceConnectionCompleted:
(*it)->SendLifetimeMessages(CONNECTED);
break;
case PeerConnectionInterface::kIceConnectionFailed:
case PeerConnectionInterface::kIceConnectionNew:
case PeerConnectionInterface::kIceConnectionDisconnected:
case PeerConnectionInterface::kIceConnectionClosed:
(*it)->SendLifetimeMessages(DISCONNECTED);
break;
default:
break;
}
}
}
void MediaStreamTrackMetrics::SendLifetimeMessage(const std::string& track_id,
TrackType track_type,
LifetimeEvent event,
StreamType stream_type) {
RenderThreadImpl* render_thread = RenderThreadImpl::current();
if (render_thread) {
if (event == CONNECTED) {
RenderThreadImpl::current()->Send(
new MediaStreamTrackMetricsHost_AddTrack(
MakeUniqueId(track_id, stream_type),
track_type == AUDIO_TRACK,
stream_type == RECEIVED_STREAM));
} else {
DCHECK_EQ(DISCONNECTED, event);
RenderThreadImpl::current()->Send(
new MediaStreamTrackMetricsHost_RemoveTrack(
MakeUniqueId(track_id, stream_type)));
}
}
}
uint64 MediaStreamTrackMetrics::MakeUniqueIdImpl(uint64 pc_id,
const std::string& track_id,
StreamType stream_type) {
std::string unique_id_string =
base::StringPrintf("%" PRIu64 " %s %d",
pc_id,
track_id.c_str(),
stream_type == RECEIVED_STREAM ? 1 : 0);
base::MD5Context ctx;
base::MD5Init(&ctx);
base::MD5Update(&ctx, unique_id_string);
base::MD5Digest digest;
base::MD5Final(&digest, &ctx);
COMPILE_ASSERT(sizeof(digest.a) > sizeof(uint64), NeedBiggerDigest);
return *reinterpret_cast<uint64*>(digest.a);
}
uint64 MediaStreamTrackMetrics::MakeUniqueId(const std::string& track_id,
StreamType stream_type) {
return MakeUniqueIdImpl(
reinterpret_cast<uint64>(reinterpret_cast<void*>(this)),
track_id,
stream_type);
}
}