Commit af5c23c7 authored by Henrik Boström's avatar Henrik Boström Committed by Commit Bot

MediaStreamTrackMetrics simplified to observe tracks, not streams.

Prior to this CL, MediaStreamTrackMetrics hooked up to streams, tracking
not only all of the streams' tracks (CONNECTED/DISCONNECTED) but also
any tracks that might be added or removed from the stream.

This has not been necessary to do for a long time, since the RTP Media
APIs are track-based, not stream-based, and the legacy
addStream()-streams are shimmed on top of addTrack(). Adding a track to
such a stream causes addTrack(), and there is no need for the
MediaStreamTrackMetrics class to observe the streams.

With this CL, MediaStreamTrackMetrics only care about tracks (direction,
kind and id). This also covers the Unified Plan use case of tracks not
necessarily belonging to any stream.

There is room for improvements in this area, such as counting tracks
added through replaceTrack(), but that should be handled separately.
This CL removes the dependency on streams which unblocks
RTCRtpTransceiver/Unified Plan work.

Bug: 810708, 777617
Change-Id: I347e729560717be83b7b1a3571f25a8497d65e46
Reviewed-on: https://chromium-review.googlesource.com/1117691Reviewed-by: default avatarHarald Alvestrand <hta@chromium.org>
Commit-Queue: Henrik Boström <hbos@chromium.org>
Cr-Commit-Position: refs/heads/master@{#572521}
parent d769acbd
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
#include "content/renderer/media/webrtc/media_stream_track_metrics.h" #include "content/renderer/media/webrtc/media_stream_track_metrics.h"
#include <inttypes.h> #include <inttypes.h>
#include <set>
#include <string> #include <string>
#include "base/md5.h" #include "base/md5.h"
...@@ -14,133 +13,44 @@ ...@@ -14,133 +13,44 @@
#include "content/public/common/service_names.mojom.h" #include "content/public/common/service_names.mojom.h"
#include "content/renderer/render_thread_impl.h" #include "content/renderer/render_thread_impl.h"
#include "services/service_manager/public/cpp/connector.h" #include "services/service_manager/public/cpp/connector.h"
#include "third_party/webrtc/api/mediastreaminterface.h"
using webrtc::AudioTrackVector;
using webrtc::MediaStreamInterface;
using webrtc::MediaStreamTrackInterface;
using webrtc::PeerConnectionInterface;
using webrtc::VideoTrackVector;
namespace content { namespace content {
namespace {
typedef std::set<std::string> IdSet;
template <class T>
IdSet GetTrackIds(const std::vector<rtc::scoped_refptr<T>>& tracks) {
IdSet track_ids;
for (const auto& track : tracks)
track_ids.insert(track->id());
return track_ids;
}
// TODO(tommi): Consolidate this and TrackObserver since these implementations
// are fundamentally achieving the same thing (aside from specific logic inside
// the OnChanged callbacks).
class MediaStreamObserver
: public base::RefCountedThreadSafe<MediaStreamObserver>,
public webrtc::ObserverInterface {
public:
typedef base::Callback<
void(const IdSet& audio_track_ids, const IdSet& video_track_ids)>
OnChangedCallback;
MediaStreamObserver(
const OnChangedCallback& callback,
const scoped_refptr<base::SingleThreadTaskRunner>& main_thread,
webrtc::MediaStreamInterface* stream)
: main_thread_(main_thread), stream_(stream), callback_(callback) {
signaling_thread_.DetachFromThread();
stream_->RegisterObserver(this);
}
const scoped_refptr<webrtc::MediaStreamInterface>& stream() const {
DCHECK(main_thread_->BelongsToCurrentThread());
return stream_;
}
void Unregister() {
DCHECK(main_thread_->BelongsToCurrentThread());
callback_.Reset();
stream_->UnregisterObserver(this);
stream_ = nullptr;
}
private:
friend class base::RefCountedThreadSafe<MediaStreamObserver>;
~MediaStreamObserver() override {
DCHECK(!stream_.get()) << "must have been unregistered before deleting";
}
// webrtc::ObserverInterface implementation.
void OnChanged() override {
DCHECK(signaling_thread_.CalledOnValidThread());
main_thread_->PostTask(
FROM_HERE, base::BindOnce(&MediaStreamObserver::OnChangedOnMainThread,
this, GetTrackIds(stream_->GetAudioTracks()),
GetTrackIds(stream_->GetVideoTracks())));
}
void OnChangedOnMainThread(const IdSet& audio_track_ids,
const IdSet& video_track_ids) {
DCHECK(main_thread_->BelongsToCurrentThread());
if (!callback_.is_null())
callback_.Run(audio_track_ids, video_track_ids);
}
const scoped_refptr<base::SingleThreadTaskRunner> main_thread_;
scoped_refptr<webrtc::MediaStreamInterface> stream_;
OnChangedCallback callback_; // Only touched on the main thread.
base::ThreadChecker signaling_thread_;
};
} // namespace
class MediaStreamTrackMetricsObserver { class MediaStreamTrackMetricsObserver {
public: public:
MediaStreamTrackMetricsObserver( MediaStreamTrackMetricsObserver(MediaStreamTrackMetrics::Direction direction,
MediaStreamTrackMetrics::StreamType stream_type, MediaStreamTrackMetrics::Kind kind,
MediaStreamInterface* stream, std::string track_id,
MediaStreamTrackMetrics* owner); MediaStreamTrackMetrics* owner);
~MediaStreamTrackMetricsObserver(); ~MediaStreamTrackMetricsObserver();
// Sends begin/end messages for all tracks currently tracked. // Sends begin/end messages for the track if not already reported.
void SendLifetimeMessages(MediaStreamTrackMetrics::LifetimeEvent event); void SendLifetimeMessageForTrack(
MediaStreamTrackMetrics::LifetimeEvent event);
MediaStreamInterface* stream() { MediaStreamTrackMetrics::Direction direction() {
DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(thread_checker_.CalledOnValidThread());
return observer_->stream().get(); return direction_;
} }
MediaStreamTrackMetrics::StreamType stream_type() { MediaStreamTrackMetrics::Kind kind() {
DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(thread_checker_.CalledOnValidThread());
return stream_type_; return kind_;
} }
private: std::string track_id() const {
void OnChanged(const IdSet& audio_track_ids, const IdSet& video_track_ids); DCHECK(thread_checker_.CalledOnValidThread());
return track_id_;
void ReportAddedAndRemovedTracks( }
const IdSet& new_ids,
const IdSet& old_ids,
MediaStreamTrackMetrics::TrackType track_type);
// Sends a lifetime message for the given tracks. OK to call with an
// empty |ids|, in which case the method has no side effects.
void ReportTracks(const IdSet& ids,
MediaStreamTrackMetrics::TrackType track_type,
MediaStreamTrackMetrics::LifetimeEvent event);
private:
// False until start/end of lifetime messages have been sent. // False until start/end of lifetime messages have been sent.
bool has_reported_start_; bool has_reported_start_;
bool has_reported_end_; bool has_reported_end_;
// IDs of audio and video tracks in the stream being observed. MediaStreamTrackMetrics::Direction direction_;
IdSet audio_track_ids_; MediaStreamTrackMetrics::Kind kind_;
IdSet video_track_ids_; std::string track_id_;
MediaStreamTrackMetrics::StreamType stream_type_;
scoped_refptr<MediaStreamObserver> observer_;
// Non-owning. // Non-owning.
MediaStreamTrackMetrics* owner_; MediaStreamTrackMetrics* owner_;
...@@ -151,47 +61,46 @@ namespace { ...@@ -151,47 +61,46 @@ namespace {
// Used with std::find_if. // Used with std::find_if.
struct ObserverFinder { struct ObserverFinder {
ObserverFinder(MediaStreamTrackMetrics::StreamType stream_type, ObserverFinder(MediaStreamTrackMetrics::Direction direction,
MediaStreamInterface* stream) MediaStreamTrackMetrics::Kind kind,
: stream_type(stream_type), stream_(stream) {} const std::string& track_id)
: direction_(direction), kind_(kind), track_id_(track_id) {}
bool operator()( bool operator()(
const std::unique_ptr<MediaStreamTrackMetricsObserver>& observer) { const std::unique_ptr<MediaStreamTrackMetricsObserver>& observer) {
return stream_ == observer->stream() && return direction_ == observer->direction() && kind_ == observer->kind() &&
stream_type == observer->stream_type(); track_id_ == observer->track_id();
} }
MediaStreamTrackMetrics::StreamType stream_type; MediaStreamTrackMetrics::Direction direction_;
MediaStreamInterface* stream_; MediaStreamTrackMetrics::Kind kind_;
std::string track_id_;
}; };
} // namespace } // namespace
MediaStreamTrackMetricsObserver::MediaStreamTrackMetricsObserver( MediaStreamTrackMetricsObserver::MediaStreamTrackMetricsObserver(
MediaStreamTrackMetrics::StreamType stream_type, MediaStreamTrackMetrics::Direction direction,
MediaStreamInterface* stream, MediaStreamTrackMetrics::Kind kind,
std::string track_id,
MediaStreamTrackMetrics* owner) MediaStreamTrackMetrics* owner)
: has_reported_start_(false), : has_reported_start_(false),
has_reported_end_(false), has_reported_end_(false),
audio_track_ids_(GetTrackIds(stream->GetAudioTracks())), direction_(direction),
video_track_ids_(GetTrackIds(stream->GetVideoTracks())), kind_(kind),
stream_type_(stream_type), track_id_(std::move(track_id)),
observer_(new MediaStreamObserver(
base::Bind(&MediaStreamTrackMetricsObserver::OnChanged,
base::Unretained(this)),
base::ThreadTaskRunnerHandle::Get(),
stream)),
owner_(owner) { owner_(owner) {
DCHECK(owner);
} }
MediaStreamTrackMetricsObserver::~MediaStreamTrackMetricsObserver() { MediaStreamTrackMetricsObserver::~MediaStreamTrackMetricsObserver() {
DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(thread_checker_.CalledOnValidThread());
observer_->Unregister(); SendLifetimeMessageForTrack(
SendLifetimeMessages(MediaStreamTrackMetrics::DISCONNECTED); MediaStreamTrackMetrics::LifetimeEvent::kDisconnected);
} }
void MediaStreamTrackMetricsObserver::SendLifetimeMessages( void MediaStreamTrackMetricsObserver::SendLifetimeMessageForTrack(
MediaStreamTrackMetrics::LifetimeEvent event) { MediaStreamTrackMetrics::LifetimeEvent event) {
DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(thread_checker_.CalledOnValidThread());
if (event == MediaStreamTrackMetrics::CONNECTED) { if (event == MediaStreamTrackMetrics::LifetimeEvent::kConnected) {
// Both ICE CONNECTED and COMPLETED can trigger the first // Both ICE CONNECTED and COMPLETED can trigger the first
// start-of-life event, so we only report the first. // start-of-life event, so we only report the first.
if (has_reported_start_) if (has_reported_start_)
...@@ -199,7 +108,7 @@ void MediaStreamTrackMetricsObserver::SendLifetimeMessages( ...@@ -199,7 +108,7 @@ void MediaStreamTrackMetricsObserver::SendLifetimeMessages(
DCHECK(!has_reported_start_ && !has_reported_end_); DCHECK(!has_reported_start_ && !has_reported_end_);
has_reported_start_ = true; has_reported_start_ = true;
} else { } else {
DCHECK(event == MediaStreamTrackMetrics::DISCONNECTED); DCHECK(event == MediaStreamTrackMetrics::LifetimeEvent::kDisconnected);
// We only report the first end-of-life event, since there are // We only report the first end-of-life event, since there are
// several cases where end-of-life can be reached. We also don't // several cases where end-of-life can be reached. We also don't
...@@ -209,10 +118,9 @@ void MediaStreamTrackMetricsObserver::SendLifetimeMessages( ...@@ -209,10 +118,9 @@ void MediaStreamTrackMetricsObserver::SendLifetimeMessages(
has_reported_end_ = true; has_reported_end_ = true;
} }
ReportTracks(audio_track_ids_, MediaStreamTrackMetrics::AUDIO_TRACK, event); owner_->SendLifetimeMessage(track_id_, kind_, event, direction_);
ReportTracks(video_track_ids_, MediaStreamTrackMetrics::VIDEO_TRACK, event);
if (event == MediaStreamTrackMetrics::DISCONNECTED) { if (event == MediaStreamTrackMetrics::LifetimeEvent::kDisconnected) {
// After disconnection, we can get reconnected, so we need to // After disconnection, we can get reconnected, so we need to
// forget that we've sent lifetime events, while retaining all // forget that we've sent lifetime events, while retaining all
// other state. // other state.
...@@ -222,76 +130,33 @@ void MediaStreamTrackMetricsObserver::SendLifetimeMessages( ...@@ -222,76 +130,33 @@ void MediaStreamTrackMetricsObserver::SendLifetimeMessages(
} }
} }
void MediaStreamTrackMetricsObserver::OnChanged(
const IdSet& audio_track_ids, const IdSet& video_track_ids) {
DCHECK(thread_checker_.CalledOnValidThread());
// We only report changes after our initial report, and never after
// our last report.
if (has_reported_start_ && !has_reported_end_) {
ReportAddedAndRemovedTracks(audio_track_ids,
audio_track_ids_,
MediaStreamTrackMetrics::AUDIO_TRACK);
ReportAddedAndRemovedTracks(video_track_ids,
video_track_ids_,
MediaStreamTrackMetrics::VIDEO_TRACK);
}
// We always update our sets of tracks.
audio_track_ids_ = audio_track_ids;
video_track_ids_ = video_track_ids;
}
void MediaStreamTrackMetricsObserver::ReportAddedAndRemovedTracks(
const IdSet& new_ids,
const IdSet& old_ids,
MediaStreamTrackMetrics::TrackType track_type) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(has_reported_start_ && !has_reported_end_);
IdSet added_tracks = base::STLSetDifference<IdSet>(new_ids, old_ids);
IdSet removed_tracks = base::STLSetDifference<IdSet>(old_ids, new_ids);
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) {
DCHECK(thread_checker_.CalledOnValidThread());
for (IdSet::const_iterator it = ids.begin(); it != ids.end(); ++it) {
owner_->SendLifetimeMessage(*it, track_type, event, stream_type_);
}
}
MediaStreamTrackMetrics::MediaStreamTrackMetrics() MediaStreamTrackMetrics::MediaStreamTrackMetrics()
: ice_state_(webrtc::PeerConnectionInterface::kIceConnectionNew) {} : ice_state_(webrtc::PeerConnectionInterface::kIceConnectionNew) {}
MediaStreamTrackMetrics::~MediaStreamTrackMetrics() { MediaStreamTrackMetrics::~MediaStreamTrackMetrics() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
for (const auto& observer : observers_) { for (const auto& observer : observers_) {
observer->SendLifetimeMessages(DISCONNECTED); observer->SendLifetimeMessageForTrack(LifetimeEvent::kDisconnected);
} }
} }
void MediaStreamTrackMetrics::AddStream(StreamType type, void MediaStreamTrackMetrics::AddTrack(Direction direction,
MediaStreamInterface* stream) { Kind kind,
const std::string& track_id) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
observers_.push_back( observers_.push_back(std::make_unique<MediaStreamTrackMetricsObserver>(
std::make_unique<MediaStreamTrackMetricsObserver>(type, stream, this)); direction, kind, std::move(track_id), this));
SendLifeTimeMessageDependingOnIceState(observers_.back().get()); SendLifeTimeMessageDependingOnIceState(observers_.back().get());
} }
void MediaStreamTrackMetrics::RemoveStream(StreamType type, void MediaStreamTrackMetrics::RemoveTrack(Direction direction,
MediaStreamInterface* stream) { Kind kind,
const std::string& track_id) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
auto it = std::find_if(observers_.begin(), observers_.end(), auto it = std::find_if(observers_.begin(), observers_.end(),
ObserverFinder(type, stream)); ObserverFinder(direction, kind, track_id));
if (it == observers_.end()) { if (it == observers_.end()) {
// Since external apps could call removeStream with a stream they // Since external apps could call removeTrack() with a stream they
// never added, this can happen without it being an error. // never added, this can happen without it being an error.
return; return;
} }
...@@ -300,40 +165,41 @@ void MediaStreamTrackMetrics::RemoveStream(StreamType type, ...@@ -300,40 +165,41 @@ void MediaStreamTrackMetrics::RemoveStream(StreamType type,
} }
void MediaStreamTrackMetrics::IceConnectionChange( void MediaStreamTrackMetrics::IceConnectionChange(
PeerConnectionInterface::IceConnectionState new_state) { webrtc::PeerConnectionInterface::IceConnectionState new_state) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
ice_state_ = new_state; ice_state_ = new_state;
for (const auto& observer : observers_) { for (const auto& observer : observers_) {
SendLifeTimeMessageDependingOnIceState(observer.get()); SendLifeTimeMessageDependingOnIceState(observer.get());
} }
} }
void MediaStreamTrackMetrics::SendLifeTimeMessageDependingOnIceState( void MediaStreamTrackMetrics::SendLifeTimeMessageDependingOnIceState(
MediaStreamTrackMetricsObserver* observer) { MediaStreamTrackMetricsObserver* observer) {
// There is a state transition diagram for these states at // There is a state transition diagram for these states at
// http://dev.w3.org/2011/webrtc/editor/webrtc.html#idl-def-RTCIceConnectionState // http://dev.w3.org/2011/webrtc/editor/webrtc.html#idl-def-RTCIceConnectionState
switch (ice_state_) { switch (ice_state_) {
case PeerConnectionInterface::kIceConnectionConnected: case webrtc::PeerConnectionInterface::kIceConnectionConnected:
case PeerConnectionInterface::kIceConnectionCompleted: case webrtc::PeerConnectionInterface::kIceConnectionCompleted:
observer->SendLifetimeMessages(CONNECTED); observer->SendLifetimeMessageForTrack(LifetimeEvent::kConnected);
break; break;
case PeerConnectionInterface::kIceConnectionFailed: case webrtc::PeerConnectionInterface::kIceConnectionFailed:
// We don't really need to handle FAILED (it is only supposed // We don't really need to handle FAILED (it is only supposed
// to be preceded by CHECKING so we wouldn't yet have sent a // to be preceded by CHECKING so we wouldn't yet have sent a
// lifetime message) but we might as well use belt and // lifetime message) but we might as well use belt and
// suspenders and handle it the same as the other "end call" // suspenders and handle it the same as the other "end call"
// states. It will be ignored anyway if the call is not // states. It will be ignored anyway if the call is not
// already connected. // already connected.
case PeerConnectionInterface::kIceConnectionNew: case webrtc::PeerConnectionInterface::kIceConnectionNew:
// It's a bit weird to count NEW as an end-lifetime event, but // It's a bit weird to count NEW as an end-lifetime event, but
// it's possible to transition directly from a connected state // it's possible to transition directly from a connected state
// (CONNECTED or COMPLETED) to NEW, which can then be followed // (CONNECTED or COMPLETED) to NEW, which can then be followed
// by a new connection. The observer will ignore the end // by a new connection. The observer will ignore the end
// lifetime event if it was not preceded by a begin-lifetime // lifetime event if it was not preceded by a begin-lifetime
// event. // event.
case PeerConnectionInterface::kIceConnectionDisconnected: case webrtc::PeerConnectionInterface::kIceConnectionDisconnected:
case PeerConnectionInterface::kIceConnectionClosed: case webrtc::PeerConnectionInterface::kIceConnectionClosed:
observer->SendLifetimeMessages(DISCONNECTED); observer->SendLifetimeMessageForTrack(LifetimeEvent::kDisconnected);
break; break;
default: default:
...@@ -345,28 +211,28 @@ void MediaStreamTrackMetrics::SendLifeTimeMessageDependingOnIceState( ...@@ -345,28 +211,28 @@ void MediaStreamTrackMetrics::SendLifeTimeMessageDependingOnIceState(
} }
void MediaStreamTrackMetrics::SendLifetimeMessage(const std::string& track_id, void MediaStreamTrackMetrics::SendLifetimeMessage(const std::string& track_id,
TrackType track_type, Kind kind,
LifetimeEvent event, LifetimeEvent event,
StreamType stream_type) { Direction direction) {
RenderThreadImpl* render_thread = RenderThreadImpl::current(); RenderThreadImpl* render_thread = RenderThreadImpl::current();
// |render_thread| can be NULL in certain cases when running as part // |render_thread| can be NULL in certain cases when running as part
// |of a unit test. // |of a unit test.
if (render_thread) { if (render_thread) {
if (event == CONNECTED) { if (event == LifetimeEvent::kConnected) {
GetMediaStreamTrackMetricsHost()->AddTrack( GetMediaStreamTrackMetricsHost()->AddTrack(
MakeUniqueId(track_id, stream_type), track_type == AUDIO_TRACK, MakeUniqueId(track_id, direction), kind == Kind::kAudio,
stream_type == RECEIVED_STREAM); direction == Direction::kReceive);
} else { } else {
DCHECK_EQ(DISCONNECTED, event); DCHECK_EQ(LifetimeEvent::kDisconnected, event);
GetMediaStreamTrackMetricsHost()->RemoveTrack( GetMediaStreamTrackMetricsHost()->RemoveTrack(
MakeUniqueId(track_id, stream_type)); MakeUniqueId(track_id, direction));
} }
} }
} }
uint64_t MediaStreamTrackMetrics::MakeUniqueIdImpl(uint64_t pc_id, uint64_t MediaStreamTrackMetrics::MakeUniqueIdImpl(uint64_t pc_id,
const std::string& track_id, const std::string& track_id,
StreamType stream_type) { Direction direction) {
// We use a hash over the |track| pointer and the PeerConnection ID, // We use a hash over the |track| pointer and the PeerConnection ID,
// plus a boolean flag indicating whether the track is remote (since // plus a boolean flag indicating whether the track is remote (since
// you might conceivably have a remote track added back as a sent // you might conceivably have a remote track added back as a sent
...@@ -376,10 +242,8 @@ uint64_t MediaStreamTrackMetrics::MakeUniqueIdImpl(uint64_t pc_id, ...@@ -376,10 +242,8 @@ uint64_t MediaStreamTrackMetrics::MakeUniqueIdImpl(uint64_t pc_id,
// no longer be considered), just one with virtually zero chance of // no longer be considered), just one with virtually zero chance of
// collisions when faced with non-malicious data. // collisions when faced with non-malicious data.
std::string unique_id_string = std::string unique_id_string =
base::StringPrintf("%" PRIu64 " %s %d", base::StringPrintf("%" PRIu64 " %s %d", pc_id, track_id.c_str(),
pc_id, direction == Direction::kReceive ? 1 : 0);
track_id.c_str(),
stream_type == RECEIVED_STREAM ? 1 : 0);
base::MD5Context ctx; base::MD5Context ctx;
base::MD5Init(&ctx); base::MD5Init(&ctx);
...@@ -392,10 +256,10 @@ uint64_t MediaStreamTrackMetrics::MakeUniqueIdImpl(uint64_t pc_id, ...@@ -392,10 +256,10 @@ uint64_t MediaStreamTrackMetrics::MakeUniqueIdImpl(uint64_t pc_id,
} }
uint64_t MediaStreamTrackMetrics::MakeUniqueId(const std::string& track_id, uint64_t MediaStreamTrackMetrics::MakeUniqueId(const std::string& track_id,
StreamType stream_type) { Direction direction) {
return MakeUniqueIdImpl( return MakeUniqueIdImpl(
reinterpret_cast<uint64_t>(reinterpret_cast<void*>(this)), track_id, reinterpret_cast<uint64_t>(reinterpret_cast<void*>(this)), track_id,
stream_type); direction);
} }
mojom::MediaStreamTrackMetricsHostPtr& mojom::MediaStreamTrackMetricsHostPtr&
......
...@@ -15,10 +15,6 @@ ...@@ -15,10 +15,6 @@
#include "content/common/media/media_stream.mojom.h" #include "content/common/media/media_stream.mojom.h"
#include "third_party/webrtc/api/peerconnectioninterface.h" #include "third_party/webrtc/api/peerconnectioninterface.h"
namespace webrtc {
class MediaStreamInterface;
}
namespace content { namespace content {
class MediaStreamTrackMetricsObserver; class MediaStreamTrackMetricsObserver;
...@@ -36,19 +32,16 @@ class CONTENT_EXPORT MediaStreamTrackMetrics { ...@@ -36,19 +32,16 @@ class CONTENT_EXPORT MediaStreamTrackMetrics {
explicit MediaStreamTrackMetrics(); explicit MediaStreamTrackMetrics();
~MediaStreamTrackMetrics(); ~MediaStreamTrackMetrics();
enum StreamType { SENT_STREAM, RECEIVED_STREAM }; enum class Direction { kSend, kReceive };
enum class Kind { kAudio, kVideo };
enum TrackType { AUDIO_TRACK, VIDEO_TRACK }; enum class LifetimeEvent { kConnected, kDisconnected };
enum LifetimeEvent { CONNECTED, DISCONNECTED };
// Starts tracking lifetimes of all the tracks in |stream| and any // Starts tracking the lifetime of the track until |RemoveTrack| is called
// tracks added or removed to/from the stream until |RemoveStream| // or this object's lifetime ends.
// is called or this object's lifetime ends. void AddTrack(Direction direction, Kind kind, const std::string& track_id);
void AddStream(StreamType type, webrtc::MediaStreamInterface* stream);
// Stops tracking lifetimes of tracks in |stream|. // Stops tracking the lifetime of the track.
void RemoveStream(StreamType type, webrtc::MediaStreamInterface* stream); void RemoveTrack(Direction direction, Kind kind, const std::string& track_id);
// Called to indicate changes in the ICE connection state for the // Called to indicate changes in the ICE connection state for the
// PeerConnection this object is associated with. Used to generate // PeerConnection this object is associated with. Used to generate
...@@ -71,9 +64,9 @@ class CONTENT_EXPORT MediaStreamTrackMetrics { ...@@ -71,9 +64,9 @@ class CONTENT_EXPORT MediaStreamTrackMetrics {
// PeerConnection), false for local streams (sent over a // PeerConnection), false for local streams (sent over a
// PeerConnection). // PeerConnection).
virtual void SendLifetimeMessage(const std::string& track_id, virtual void SendLifetimeMessage(const std::string& track_id,
TrackType track_type, Kind kind,
LifetimeEvent lifetime_event, LifetimeEvent lifetime_event,
StreamType stream_type); Direction direction);
protected: protected:
// Calls SendLifetimeMessage for |observer| depending on |ice_state_|. // Calls SendLifetimeMessage for |observer| depending on |ice_state_|.
...@@ -86,12 +79,12 @@ class CONTENT_EXPORT MediaStreamTrackMetrics { ...@@ -86,12 +79,12 @@ class CONTENT_EXPORT MediaStreamTrackMetrics {
// is a one-to-one relationship). // is a one-to-one relationship).
uint64_t MakeUniqueIdImpl(uint64_t pc_id, uint64_t MakeUniqueIdImpl(uint64_t pc_id,
const std::string& track, const std::string& track,
StreamType stream_type); Direction direction);
private: private:
// Make a unique ID for the given track, that is valid while the // Make a unique ID for the given track, that is valid while the
// track object and the PeerConnection it is attached to both exist. // track object and the PeerConnection it is attached to both exist.
uint64_t MakeUniqueId(const std::string& track, StreamType stream_type); uint64_t MakeUniqueId(const std::string& track_id, Direction direction);
mojom::MediaStreamTrackMetricsHostPtr& GetMediaStreamTrackMetricsHost(); mojom::MediaStreamTrackMetricsHostPtr& GetMediaStreamTrackMetricsHost();
......
...@@ -78,8 +78,7 @@ class MockMediaStreamTrackMetrics : public MediaStreamTrackMetrics { ...@@ -78,8 +78,7 @@ class MockMediaStreamTrackMetrics : public MediaStreamTrackMetrics {
virtual ~MockMediaStreamTrackMetrics() {} virtual ~MockMediaStreamTrackMetrics() {}
MOCK_METHOD4(SendLifetimeMessage, MOCK_METHOD4(SendLifetimeMessage,
void(const std::string&, TrackType, LifetimeEvent, StreamType)); void(const std::string&, Kind, LifetimeEvent, Direction));
using MediaStreamTrackMetrics::MakeUniqueIdImpl; using MediaStreamTrackMetrics::MakeUniqueIdImpl;
}; };
...@@ -170,88 +169,82 @@ TEST_F(MediaStreamTrackMetricsTest, MakeUniqueId) { ...@@ -170,88 +169,82 @@ TEST_F(MediaStreamTrackMetricsTest, MakeUniqueId) {
// Lower 32 bits the same, upper 32 differ. // Lower 32 bits the same, upper 32 differ.
EXPECT_NE( EXPECT_NE(
metrics_->MakeUniqueIdImpl( metrics_->MakeUniqueIdImpl(0x1000000000000001, "x",
0x1000000000000001, "x", MediaStreamTrackMetrics::RECEIVED_STREAM), MediaStreamTrackMetrics::Direction::kReceive),
metrics_->MakeUniqueIdImpl( metrics_->MakeUniqueIdImpl(0x2000000000000001, "x",
0x2000000000000001, "x", MediaStreamTrackMetrics::RECEIVED_STREAM)); MediaStreamTrackMetrics::Direction::kReceive));
// Track ID differs. // Track ID differs.
EXPECT_NE(metrics_->MakeUniqueIdImpl( EXPECT_NE(metrics_->MakeUniqueIdImpl(
42, "x", MediaStreamTrackMetrics::RECEIVED_STREAM), 42, "x", MediaStreamTrackMetrics::Direction::kReceive),
metrics_->MakeUniqueIdImpl( metrics_->MakeUniqueIdImpl(
42, "y", MediaStreamTrackMetrics::RECEIVED_STREAM)); 42, "y", MediaStreamTrackMetrics::Direction::kReceive));
// Remove vs. local track differs. // Remove vs. local track differs.
EXPECT_NE(metrics_->MakeUniqueIdImpl( EXPECT_NE(metrics_->MakeUniqueIdImpl(
42, "x", MediaStreamTrackMetrics::RECEIVED_STREAM), 42, "x", MediaStreamTrackMetrics::Direction::kReceive),
metrics_->MakeUniqueIdImpl( metrics_->MakeUniqueIdImpl(
42, "x", MediaStreamTrackMetrics::SENT_STREAM)); 42, "x", MediaStreamTrackMetrics::Direction::kSend));
} }
TEST_F(MediaStreamTrackMetricsTest, BasicRemoteStreams) { TEST_F(MediaStreamTrackMetricsTest, BasicRemoteStreams) {
scoped_refptr<MockAudioTrackInterface> audio(MakeAudioTrack("audio")); metrics_->AddTrack(MediaStreamTrackMetrics::Direction::kReceive,
scoped_refptr<MockVideoTrackInterface> video(MakeVideoTrack("video")); MediaStreamTrackMetrics::Kind::kAudio, "audio");
stream_->AddTrack(audio.get()); metrics_->AddTrack(MediaStreamTrackMetrics::Direction::kReceive,
stream_->AddTrack(video.get()); MediaStreamTrackMetrics::Kind::kVideo, "video");
metrics_->AddStream(MediaStreamTrackMetrics::RECEIVED_STREAM, stream_.get());
EXPECT_CALL(*metrics_, SendLifetimeMessage(
EXPECT_CALL(*metrics_, "audio", MediaStreamTrackMetrics::Kind::kAudio,
SendLifetimeMessage("audio", MediaStreamTrackMetrics::LifetimeEvent::kConnected,
MediaStreamTrackMetrics::AUDIO_TRACK, MediaStreamTrackMetrics::Direction::kReceive));
MediaStreamTrackMetrics::CONNECTED, EXPECT_CALL(*metrics_, SendLifetimeMessage(
MediaStreamTrackMetrics::RECEIVED_STREAM)); "video", MediaStreamTrackMetrics::Kind::kVideo,
EXPECT_CALL(*metrics_, MediaStreamTrackMetrics::LifetimeEvent::kConnected,
SendLifetimeMessage("video", MediaStreamTrackMetrics::Direction::kReceive));
MediaStreamTrackMetrics::VIDEO_TRACK,
MediaStreamTrackMetrics::CONNECTED,
MediaStreamTrackMetrics::RECEIVED_STREAM));
metrics_->IceConnectionChange( metrics_->IceConnectionChange(
PeerConnectionInterface::kIceConnectionConnected); PeerConnectionInterface::kIceConnectionConnected);
EXPECT_CALL(*metrics_, EXPECT_CALL(
SendLifetimeMessage("audio", *metrics_,
MediaStreamTrackMetrics::AUDIO_TRACK, SendLifetimeMessage("audio", MediaStreamTrackMetrics::Kind::kAudio,
MediaStreamTrackMetrics::DISCONNECTED, MediaStreamTrackMetrics::LifetimeEvent::kDisconnected,
MediaStreamTrackMetrics::RECEIVED_STREAM)); MediaStreamTrackMetrics::Direction::kReceive));
EXPECT_CALL(*metrics_, EXPECT_CALL(
SendLifetimeMessage("video", *metrics_,
MediaStreamTrackMetrics::VIDEO_TRACK, SendLifetimeMessage("video", MediaStreamTrackMetrics::Kind::kVideo,
MediaStreamTrackMetrics::DISCONNECTED, MediaStreamTrackMetrics::LifetimeEvent::kDisconnected,
MediaStreamTrackMetrics::RECEIVED_STREAM)); MediaStreamTrackMetrics::Direction::kReceive));
metrics_->IceConnectionChange( metrics_->IceConnectionChange(
PeerConnectionInterface::kIceConnectionDisconnected); PeerConnectionInterface::kIceConnectionDisconnected);
} }
TEST_F(MediaStreamTrackMetricsTest, BasicLocalStreams) { TEST_F(MediaStreamTrackMetricsTest, BasicLocalStreams) {
scoped_refptr<MockAudioTrackInterface> audio(MakeAudioTrack("audio")); metrics_->AddTrack(MediaStreamTrackMetrics::Direction::kSend,
scoped_refptr<MockVideoTrackInterface> video(MakeVideoTrack("video")); MediaStreamTrackMetrics::Kind::kAudio, "audio");
stream_->AddTrack(audio.get()); metrics_->AddTrack(MediaStreamTrackMetrics::Direction::kSend,
stream_->AddTrack(video.get()); MediaStreamTrackMetrics::Kind::kVideo, "video");
metrics_->AddStream(MediaStreamTrackMetrics::SENT_STREAM, stream_.get());
EXPECT_CALL(*metrics_, SendLifetimeMessage(
EXPECT_CALL(*metrics_, "audio", MediaStreamTrackMetrics::Kind::kAudio,
SendLifetimeMessage("audio", MediaStreamTrackMetrics::LifetimeEvent::kConnected,
MediaStreamTrackMetrics::AUDIO_TRACK, MediaStreamTrackMetrics::Direction::kSend));
MediaStreamTrackMetrics::CONNECTED, EXPECT_CALL(*metrics_, SendLifetimeMessage(
MediaStreamTrackMetrics::SENT_STREAM)); "video", MediaStreamTrackMetrics::Kind::kVideo,
EXPECT_CALL(*metrics_, MediaStreamTrackMetrics::LifetimeEvent::kConnected,
SendLifetimeMessage("video", MediaStreamTrackMetrics::Direction::kSend));
MediaStreamTrackMetrics::VIDEO_TRACK,
MediaStreamTrackMetrics::CONNECTED,
MediaStreamTrackMetrics::SENT_STREAM));
metrics_->IceConnectionChange( metrics_->IceConnectionChange(
PeerConnectionInterface::kIceConnectionConnected); PeerConnectionInterface::kIceConnectionConnected);
EXPECT_CALL(*metrics_, EXPECT_CALL(
SendLifetimeMessage("audio", *metrics_,
MediaStreamTrackMetrics::AUDIO_TRACK, SendLifetimeMessage("audio", MediaStreamTrackMetrics::Kind::kAudio,
MediaStreamTrackMetrics::DISCONNECTED, MediaStreamTrackMetrics::LifetimeEvent::kDisconnected,
MediaStreamTrackMetrics::SENT_STREAM)); MediaStreamTrackMetrics::Direction::kSend));
EXPECT_CALL(*metrics_, EXPECT_CALL(
SendLifetimeMessage("video", *metrics_,
MediaStreamTrackMetrics::VIDEO_TRACK, SendLifetimeMessage("video", MediaStreamTrackMetrics::Kind::kVideo,
MediaStreamTrackMetrics::DISCONNECTED, MediaStreamTrackMetrics::LifetimeEvent::kDisconnected,
MediaStreamTrackMetrics::SENT_STREAM)); MediaStreamTrackMetrics::Direction::kSend));
metrics_->IceConnectionChange(PeerConnectionInterface::kIceConnectionFailed); metrics_->IceConnectionChange(PeerConnectionInterface::kIceConnectionFailed);
} }
...@@ -259,341 +252,226 @@ TEST_F(MediaStreamTrackMetricsTest, LocalStreamAddedAferIceConnect) { ...@@ -259,341 +252,226 @@ TEST_F(MediaStreamTrackMetricsTest, LocalStreamAddedAferIceConnect) {
metrics_->IceConnectionChange( metrics_->IceConnectionChange(
PeerConnectionInterface::kIceConnectionConnected); PeerConnectionInterface::kIceConnectionConnected);
EXPECT_CALL(*metrics_, EXPECT_CALL(*metrics_, SendLifetimeMessage(
SendLifetimeMessage("audio", "audio", MediaStreamTrackMetrics::Kind::kAudio,
MediaStreamTrackMetrics::AUDIO_TRACK, MediaStreamTrackMetrics::LifetimeEvent::kConnected,
MediaStreamTrackMetrics::CONNECTED, MediaStreamTrackMetrics::Direction::kSend));
MediaStreamTrackMetrics::SENT_STREAM)); EXPECT_CALL(*metrics_, SendLifetimeMessage(
EXPECT_CALL(*metrics_, "video", MediaStreamTrackMetrics::Kind::kVideo,
SendLifetimeMessage("video", MediaStreamTrackMetrics::LifetimeEvent::kConnected,
MediaStreamTrackMetrics::VIDEO_TRACK, MediaStreamTrackMetrics::Direction::kSend));
MediaStreamTrackMetrics::CONNECTED,
MediaStreamTrackMetrics::SENT_STREAM)); metrics_->AddTrack(MediaStreamTrackMetrics::Direction::kSend,
MediaStreamTrackMetrics::Kind::kAudio, "audio");
scoped_refptr<MockAudioTrackInterface> audio(MakeAudioTrack("audio")); metrics_->AddTrack(MediaStreamTrackMetrics::Direction::kSend,
scoped_refptr<MockVideoTrackInterface> video(MakeVideoTrack("video")); MediaStreamTrackMetrics::Kind::kVideo, "video");
stream_->AddTrack(audio.get());
stream_->AddTrack(video.get());
metrics_->AddStream(MediaStreamTrackMetrics::SENT_STREAM, stream_.get());
} }
TEST_F(MediaStreamTrackMetricsTest, RemoteStreamAddedAferIceConnect) { TEST_F(MediaStreamTrackMetricsTest, RemoteStreamAddedAferIceConnect) {
metrics_->IceConnectionChange( metrics_->IceConnectionChange(
PeerConnectionInterface::kIceConnectionConnected); PeerConnectionInterface::kIceConnectionConnected);
EXPECT_CALL(*metrics_, EXPECT_CALL(*metrics_, SendLifetimeMessage(
SendLifetimeMessage("audio", "audio", MediaStreamTrackMetrics::Kind::kAudio,
MediaStreamTrackMetrics::AUDIO_TRACK, MediaStreamTrackMetrics::LifetimeEvent::kConnected,
MediaStreamTrackMetrics::CONNECTED, MediaStreamTrackMetrics::Direction::kReceive));
MediaStreamTrackMetrics::RECEIVED_STREAM)); EXPECT_CALL(*metrics_, SendLifetimeMessage(
EXPECT_CALL(*metrics_, "video", MediaStreamTrackMetrics::Kind::kVideo,
SendLifetimeMessage("video", MediaStreamTrackMetrics::LifetimeEvent::kConnected,
MediaStreamTrackMetrics::VIDEO_TRACK, MediaStreamTrackMetrics::Direction::kReceive));
MediaStreamTrackMetrics::CONNECTED,
MediaStreamTrackMetrics::RECEIVED_STREAM)); metrics_->AddTrack(MediaStreamTrackMetrics::Direction::kReceive,
MediaStreamTrackMetrics::Kind::kAudio, "audio");
scoped_refptr<MockAudioTrackInterface> audio(MakeAudioTrack("audio")); metrics_->AddTrack(MediaStreamTrackMetrics::Direction::kReceive,
scoped_refptr<MockVideoTrackInterface> video(MakeVideoTrack("video")); MediaStreamTrackMetrics::Kind::kVideo, "video");
stream_->AddTrack(audio.get());
stream_->AddTrack(video.get());
metrics_->AddStream(MediaStreamTrackMetrics::RECEIVED_STREAM, stream_.get());
}
TEST_F(MediaStreamTrackMetricsTest, RemoteStreamTrackAdded) {
scoped_refptr<MockAudioTrackInterface> initial(MakeAudioTrack("initial"));
scoped_refptr<MockAudioTrackInterface> added(MakeAudioTrack("added"));
stream_->AddTrack(initial.get());
metrics_->AddStream(MediaStreamTrackMetrics::RECEIVED_STREAM, stream_.get());
EXPECT_CALL(*metrics_,
SendLifetimeMessage("initial",
MediaStreamTrackMetrics::AUDIO_TRACK,
MediaStreamTrackMetrics::CONNECTED,
MediaStreamTrackMetrics::RECEIVED_STREAM));
metrics_->IceConnectionChange(
PeerConnectionInterface::kIceConnectionConnected);
EXPECT_CALL(*metrics_,
SendLifetimeMessage("added",
MediaStreamTrackMetrics::AUDIO_TRACK,
MediaStreamTrackMetrics::CONNECTED,
MediaStreamTrackMetrics::RECEIVED_STREAM));
AddAudioTrack(added.get());
EXPECT_CALL(*metrics_,
SendLifetimeMessage("initial",
MediaStreamTrackMetrics::AUDIO_TRACK,
MediaStreamTrackMetrics::DISCONNECTED,
MediaStreamTrackMetrics::RECEIVED_STREAM));
EXPECT_CALL(*metrics_,
SendLifetimeMessage("added",
MediaStreamTrackMetrics::AUDIO_TRACK,
MediaStreamTrackMetrics::DISCONNECTED,
MediaStreamTrackMetrics::RECEIVED_STREAM));
metrics_->IceConnectionChange(PeerConnectionInterface::kIceConnectionFailed);
} }
TEST_F(MediaStreamTrackMetricsTest, LocalStreamTrackRemoved) { TEST_F(MediaStreamTrackMetricsTest, LocalStreamTrackRemoved) {
scoped_refptr<MockAudioTrackInterface> first(MakeAudioTrack("first")); metrics_->AddTrack(MediaStreamTrackMetrics::Direction::kSend,
scoped_refptr<MockAudioTrackInterface> second(MakeAudioTrack("second")); MediaStreamTrackMetrics::Kind::kAudio, "first");
stream_->AddTrack(first.get()); metrics_->AddTrack(MediaStreamTrackMetrics::Direction::kSend,
stream_->AddTrack(second.get()); MediaStreamTrackMetrics::Kind::kAudio, "second");
metrics_->AddStream(MediaStreamTrackMetrics::SENT_STREAM, stream_.get());
EXPECT_CALL(*metrics_, SendLifetimeMessage(
EXPECT_CALL(*metrics_, "first", MediaStreamTrackMetrics::Kind::kAudio,
SendLifetimeMessage("first", MediaStreamTrackMetrics::LifetimeEvent::kConnected,
MediaStreamTrackMetrics::AUDIO_TRACK, MediaStreamTrackMetrics::Direction::kSend));
MediaStreamTrackMetrics::CONNECTED, EXPECT_CALL(*metrics_, SendLifetimeMessage(
MediaStreamTrackMetrics::SENT_STREAM)); "second", MediaStreamTrackMetrics::Kind::kAudio,
EXPECT_CALL(*metrics_, MediaStreamTrackMetrics::LifetimeEvent::kConnected,
SendLifetimeMessage("second", MediaStreamTrackMetrics::Direction::kSend));
MediaStreamTrackMetrics::AUDIO_TRACK,
MediaStreamTrackMetrics::CONNECTED,
MediaStreamTrackMetrics::SENT_STREAM));
metrics_->IceConnectionChange( metrics_->IceConnectionChange(
PeerConnectionInterface::kIceConnectionConnected); PeerConnectionInterface::kIceConnectionConnected);
EXPECT_CALL(*metrics_, EXPECT_CALL(
SendLifetimeMessage("first", *metrics_,
MediaStreamTrackMetrics::AUDIO_TRACK, SendLifetimeMessage("first", MediaStreamTrackMetrics::Kind::kAudio,
MediaStreamTrackMetrics::DISCONNECTED, MediaStreamTrackMetrics::LifetimeEvent::kDisconnected,
MediaStreamTrackMetrics::SENT_STREAM)); MediaStreamTrackMetrics::Direction::kSend));
stream_->RemoveTrack(first.get()); metrics_->RemoveTrack(MediaStreamTrackMetrics::Direction::kSend,
MediaStreamTrackMetrics::Kind::kAudio, "first");
EXPECT_CALL(*metrics_,
SendLifetimeMessage("second", EXPECT_CALL(
MediaStreamTrackMetrics::AUDIO_TRACK, *metrics_,
MediaStreamTrackMetrics::DISCONNECTED, SendLifetimeMessage("second", MediaStreamTrackMetrics::Kind::kAudio,
MediaStreamTrackMetrics::SENT_STREAM)); MediaStreamTrackMetrics::LifetimeEvent::kDisconnected,
MediaStreamTrackMetrics::Direction::kSend));
metrics_->IceConnectionChange(PeerConnectionInterface::kIceConnectionFailed); metrics_->IceConnectionChange(PeerConnectionInterface::kIceConnectionFailed);
} }
TEST_F(MediaStreamTrackMetricsTest, LocalStreamModificationsBeforeAndAfter) { TEST_F(MediaStreamTrackMetricsTest, RemoveAfterDisconnect) {
scoped_refptr<MockAudioTrackInterface> first(MakeAudioTrack("first")); metrics_->AddTrack(MediaStreamTrackMetrics::Direction::kSend,
scoped_refptr<MockAudioTrackInterface> second(MakeAudioTrack("second")); MediaStreamTrackMetrics::Kind::kAudio, "audio");
stream_->AddTrack(first.get());
metrics_->AddStream(MediaStreamTrackMetrics::SENT_STREAM, stream_.get()); EXPECT_CALL(*metrics_, SendLifetimeMessage(
"audio", MediaStreamTrackMetrics::Kind::kAudio,
// This gets added after we start observing, but no lifetime message MediaStreamTrackMetrics::LifetimeEvent::kConnected,
// should be sent at this point since the call is not connected. It MediaStreamTrackMetrics::Direction::kSend));
// should get sent only once it gets connected.
AddAudioTrack(second.get());
EXPECT_CALL(*metrics_,
SendLifetimeMessage("first",
MediaStreamTrackMetrics::AUDIO_TRACK,
MediaStreamTrackMetrics::CONNECTED,
MediaStreamTrackMetrics::SENT_STREAM));
EXPECT_CALL(*metrics_,
SendLifetimeMessage("second",
MediaStreamTrackMetrics::AUDIO_TRACK,
MediaStreamTrackMetrics::CONNECTED,
MediaStreamTrackMetrics::SENT_STREAM));
metrics_->IceConnectionChange( metrics_->IceConnectionChange(
PeerConnectionInterface::kIceConnectionConnected); PeerConnectionInterface::kIceConnectionConnected);
EXPECT_CALL(*metrics_, EXPECT_CALL(
SendLifetimeMessage("first", *metrics_,
MediaStreamTrackMetrics::AUDIO_TRACK, SendLifetimeMessage("audio", MediaStreamTrackMetrics::Kind::kAudio,
MediaStreamTrackMetrics::DISCONNECTED, MediaStreamTrackMetrics::LifetimeEvent::kDisconnected,
MediaStreamTrackMetrics::SENT_STREAM)); MediaStreamTrackMetrics::Direction::kSend));
EXPECT_CALL(*metrics_,
SendLifetimeMessage("second",
MediaStreamTrackMetrics::AUDIO_TRACK,
MediaStreamTrackMetrics::DISCONNECTED,
MediaStreamTrackMetrics::SENT_STREAM));
metrics_->IceConnectionChange(PeerConnectionInterface::kIceConnectionFailed); metrics_->IceConnectionChange(PeerConnectionInterface::kIceConnectionFailed);
// This happens after the call is disconnected so no lifetime // This happens after the call is disconnected so no lifetime
// message should be sent. // message should be sent.
RemoveAudioTrack(first.get()); metrics_->RemoveTrack(MediaStreamTrackMetrics::Direction::kSend,
MediaStreamTrackMetrics::Kind::kAudio, "audio");
} }
TEST_F(MediaStreamTrackMetricsTest, RemoteStreamMultipleDisconnects) { TEST_F(MediaStreamTrackMetricsTest, RemoteStreamMultipleDisconnects) {
scoped_refptr<MockAudioTrackInterface> audio(MakeAudioTrack("audio")); metrics_->AddTrack(MediaStreamTrackMetrics::Direction::kReceive,
stream_->AddTrack(audio.get()); MediaStreamTrackMetrics::Kind::kAudio, "audio");
metrics_->AddStream(MediaStreamTrackMetrics::RECEIVED_STREAM, stream_.get());
EXPECT_CALL(*metrics_, SendLifetimeMessage(
EXPECT_CALL(*metrics_, "audio", MediaStreamTrackMetrics::Kind::kAudio,
SendLifetimeMessage("audio", MediaStreamTrackMetrics::LifetimeEvent::kConnected,
MediaStreamTrackMetrics::AUDIO_TRACK, MediaStreamTrackMetrics::Direction::kReceive));
MediaStreamTrackMetrics::CONNECTED,
MediaStreamTrackMetrics::RECEIVED_STREAM));
metrics_->IceConnectionChange( metrics_->IceConnectionChange(
PeerConnectionInterface::kIceConnectionConnected); PeerConnectionInterface::kIceConnectionConnected);
EXPECT_CALL(*metrics_, EXPECT_CALL(
SendLifetimeMessage("audio", *metrics_,
MediaStreamTrackMetrics::AUDIO_TRACK, SendLifetimeMessage("audio", MediaStreamTrackMetrics::Kind::kAudio,
MediaStreamTrackMetrics::DISCONNECTED, MediaStreamTrackMetrics::LifetimeEvent::kDisconnected,
MediaStreamTrackMetrics::RECEIVED_STREAM)); MediaStreamTrackMetrics::Direction::kReceive));
metrics_->IceConnectionChange( metrics_->IceConnectionChange(
PeerConnectionInterface::kIceConnectionDisconnected); PeerConnectionInterface::kIceConnectionDisconnected);
metrics_->IceConnectionChange(PeerConnectionInterface::kIceConnectionFailed); metrics_->IceConnectionChange(PeerConnectionInterface::kIceConnectionFailed);
RemoveAudioTrack(audio.get()); metrics_->RemoveTrack(MediaStreamTrackMetrics::Direction::kReceive,
MediaStreamTrackMetrics::Kind::kAudio, "audio");
} }
TEST_F(MediaStreamTrackMetricsTest, RemoteStreamConnectDisconnectTwice) { TEST_F(MediaStreamTrackMetricsTest, RemoteStreamConnectDisconnectTwice) {
scoped_refptr<MockAudioTrackInterface> audio(MakeAudioTrack("audio")); metrics_->AddTrack(MediaStreamTrackMetrics::Direction::kReceive,
stream_->AddTrack(audio.get()); MediaStreamTrackMetrics::Kind::kAudio, "audio");
metrics_->AddStream(MediaStreamTrackMetrics::RECEIVED_STREAM, stream_.get());
for (size_t i = 0; i < 2; ++i) { for (size_t i = 0; i < 2; ++i) {
EXPECT_CALL(*metrics_, EXPECT_CALL(
SendLifetimeMessage("audio", *metrics_,
MediaStreamTrackMetrics::AUDIO_TRACK, SendLifetimeMessage("audio", MediaStreamTrackMetrics::Kind::kAudio,
MediaStreamTrackMetrics::CONNECTED, MediaStreamTrackMetrics::LifetimeEvent::kConnected,
MediaStreamTrackMetrics::RECEIVED_STREAM)); MediaStreamTrackMetrics::Direction::kReceive));
metrics_->IceConnectionChange( metrics_->IceConnectionChange(
PeerConnectionInterface::kIceConnectionConnected); PeerConnectionInterface::kIceConnectionConnected);
EXPECT_CALL(*metrics_, EXPECT_CALL(*metrics_,
SendLifetimeMessage("audio", SendLifetimeMessage(
MediaStreamTrackMetrics::AUDIO_TRACK, "audio", MediaStreamTrackMetrics::Kind::kAudio,
MediaStreamTrackMetrics::DISCONNECTED, MediaStreamTrackMetrics::LifetimeEvent::kDisconnected,
MediaStreamTrackMetrics::RECEIVED_STREAM)); MediaStreamTrackMetrics::Direction::kReceive));
metrics_->IceConnectionChange( metrics_->IceConnectionChange(
PeerConnectionInterface::kIceConnectionDisconnected); PeerConnectionInterface::kIceConnectionDisconnected);
} }
RemoveAudioTrack(audio.get()); metrics_->RemoveTrack(MediaStreamTrackMetrics::Direction::kReceive,
MediaStreamTrackMetrics::Kind::kAudio, "audio");
} }
TEST_F(MediaStreamTrackMetricsTest, LocalStreamRemovedNoDisconnect) { TEST_F(MediaStreamTrackMetricsTest, LocalStreamRemovedNoDisconnect) {
scoped_refptr<MockAudioTrackInterface> audio(MakeAudioTrack("audio")); metrics_->AddTrack(MediaStreamTrackMetrics::Direction::kSend,
scoped_refptr<MockVideoTrackInterface> video(MakeVideoTrack("video")); MediaStreamTrackMetrics::Kind::kAudio, "audio");
stream_->AddTrack(audio.get()); metrics_->AddTrack(MediaStreamTrackMetrics::Direction::kSend,
stream_->AddTrack(video.get()); MediaStreamTrackMetrics::Kind::kVideo, "video");
metrics_->AddStream(MediaStreamTrackMetrics::SENT_STREAM, stream_.get());
EXPECT_CALL(*metrics_, SendLifetimeMessage(
EXPECT_CALL(*metrics_, "audio", MediaStreamTrackMetrics::Kind::kAudio,
SendLifetimeMessage("audio", MediaStreamTrackMetrics::LifetimeEvent::kConnected,
MediaStreamTrackMetrics::AUDIO_TRACK, MediaStreamTrackMetrics::Direction::kSend));
MediaStreamTrackMetrics::CONNECTED, EXPECT_CALL(*metrics_, SendLifetimeMessage(
MediaStreamTrackMetrics::SENT_STREAM)); "video", MediaStreamTrackMetrics::Kind::kVideo,
EXPECT_CALL(*metrics_, MediaStreamTrackMetrics::LifetimeEvent::kConnected,
SendLifetimeMessage("video", MediaStreamTrackMetrics::Direction::kSend));
MediaStreamTrackMetrics::VIDEO_TRACK,
MediaStreamTrackMetrics::CONNECTED,
MediaStreamTrackMetrics::SENT_STREAM));
metrics_->IceConnectionChange( metrics_->IceConnectionChange(
PeerConnectionInterface::kIceConnectionConnected); PeerConnectionInterface::kIceConnectionConnected);
EXPECT_CALL(*metrics_, EXPECT_CALL(
SendLifetimeMessage("audio", *metrics_,
MediaStreamTrackMetrics::AUDIO_TRACK, SendLifetimeMessage("audio", MediaStreamTrackMetrics::Kind::kAudio,
MediaStreamTrackMetrics::DISCONNECTED, MediaStreamTrackMetrics::LifetimeEvent::kDisconnected,
MediaStreamTrackMetrics::SENT_STREAM)); MediaStreamTrackMetrics::Direction::kSend));
EXPECT_CALL(*metrics_, EXPECT_CALL(
SendLifetimeMessage("video", *metrics_,
MediaStreamTrackMetrics::VIDEO_TRACK, SendLifetimeMessage("video", MediaStreamTrackMetrics::Kind::kVideo,
MediaStreamTrackMetrics::DISCONNECTED, MediaStreamTrackMetrics::LifetimeEvent::kDisconnected,
MediaStreamTrackMetrics::SENT_STREAM)); MediaStreamTrackMetrics::Direction::kSend));
metrics_->RemoveStream(MediaStreamTrackMetrics::SENT_STREAM, stream_.get()); metrics_->RemoveTrack(MediaStreamTrackMetrics::Direction::kSend,
MediaStreamTrackMetrics::Kind::kAudio, "audio");
metrics_->RemoveTrack(MediaStreamTrackMetrics::Direction::kSend,
MediaStreamTrackMetrics::Kind::kVideo, "video");
} }
TEST_F(MediaStreamTrackMetricsTest, LocalStreamLargerTest) { TEST_F(MediaStreamTrackMetricsTest, LocalStreamLargerTest) {
scoped_refptr<MockAudioTrackInterface> audio1(MakeAudioTrack("audio1")); metrics_->AddTrack(MediaStreamTrackMetrics::Direction::kSend,
scoped_refptr<MockAudioTrackInterface> audio2(MakeAudioTrack("audio2")); MediaStreamTrackMetrics::Kind::kAudio, "audio");
scoped_refptr<MockAudioTrackInterface> audio3(MakeAudioTrack("audio3")); metrics_->AddTrack(MediaStreamTrackMetrics::Direction::kSend,
scoped_refptr<MockVideoTrackInterface> video1(MakeVideoTrack("video1")); MediaStreamTrackMetrics::Kind::kVideo, "video");
scoped_refptr<MockVideoTrackInterface> video2(MakeVideoTrack("video2"));
scoped_refptr<MockVideoTrackInterface> video3(MakeVideoTrack("video3")); EXPECT_CALL(*metrics_, SendLifetimeMessage(
stream_->AddTrack(audio1.get()); "audio", MediaStreamTrackMetrics::Kind::kAudio,
stream_->AddTrack(video1.get()); MediaStreamTrackMetrics::LifetimeEvent::kConnected,
metrics_->AddStream(MediaStreamTrackMetrics::SENT_STREAM, stream_.get()); MediaStreamTrackMetrics::Direction::kSend));
EXPECT_CALL(*metrics_, SendLifetimeMessage(
EXPECT_CALL(*metrics_, "video", MediaStreamTrackMetrics::Kind::kVideo,
SendLifetimeMessage("audio1", MediaStreamTrackMetrics::LifetimeEvent::kConnected,
MediaStreamTrackMetrics::AUDIO_TRACK, MediaStreamTrackMetrics::Direction::kSend));
MediaStreamTrackMetrics::CONNECTED,
MediaStreamTrackMetrics::SENT_STREAM));
EXPECT_CALL(*metrics_,
SendLifetimeMessage("video1",
MediaStreamTrackMetrics::VIDEO_TRACK,
MediaStreamTrackMetrics::CONNECTED,
MediaStreamTrackMetrics::SENT_STREAM));
metrics_->IceConnectionChange( metrics_->IceConnectionChange(
PeerConnectionInterface::kIceConnectionConnected); PeerConnectionInterface::kIceConnectionConnected);
EXPECT_CALL(*metrics_, EXPECT_CALL(
SendLifetimeMessage("audio2", *metrics_,
MediaStreamTrackMetrics::AUDIO_TRACK, SendLifetimeMessage("audio", MediaStreamTrackMetrics::Kind::kAudio,
MediaStreamTrackMetrics::CONNECTED, MediaStreamTrackMetrics::LifetimeEvent::kDisconnected,
MediaStreamTrackMetrics::SENT_STREAM)); MediaStreamTrackMetrics::Direction::kSend));
AddAudioTrack(audio2.get()); metrics_->RemoveTrack(MediaStreamTrackMetrics::Direction::kSend,
EXPECT_CALL(*metrics_, MediaStreamTrackMetrics::Kind::kAudio, "audio");
SendLifetimeMessage("video2",
MediaStreamTrackMetrics::VIDEO_TRACK, // Add back audio
MediaStreamTrackMetrics::CONNECTED, EXPECT_CALL(*metrics_, SendLifetimeMessage(
MediaStreamTrackMetrics::SENT_STREAM)); "audio", MediaStreamTrackMetrics::Kind::kAudio,
AddVideoTrack(video2.get()); MediaStreamTrackMetrics::LifetimeEvent::kConnected,
MediaStreamTrackMetrics::Direction::kSend));
EXPECT_CALL(*metrics_, metrics_->AddTrack(MediaStreamTrackMetrics::Direction::kSend,
SendLifetimeMessage("audio1", MediaStreamTrackMetrics::Kind::kAudio, "audio");
MediaStreamTrackMetrics::AUDIO_TRACK,
MediaStreamTrackMetrics::DISCONNECTED, EXPECT_CALL(
MediaStreamTrackMetrics::SENT_STREAM)); *metrics_,
RemoveAudioTrack(audio1.get()); SendLifetimeMessage("audio", MediaStreamTrackMetrics::Kind::kAudio,
MediaStreamTrackMetrics::LifetimeEvent::kDisconnected,
EXPECT_CALL(*metrics_, MediaStreamTrackMetrics::Direction::kSend));
SendLifetimeMessage("audio3", metrics_->RemoveTrack(MediaStreamTrackMetrics::Direction::kSend,
MediaStreamTrackMetrics::AUDIO_TRACK, MediaStreamTrackMetrics::Kind::kAudio, "audio");
MediaStreamTrackMetrics::CONNECTED, EXPECT_CALL(
MediaStreamTrackMetrics::SENT_STREAM)); *metrics_,
AddAudioTrack(audio3.get()); SendLifetimeMessage("video", MediaStreamTrackMetrics::Kind::kVideo,
EXPECT_CALL(*metrics_, MediaStreamTrackMetrics::LifetimeEvent::kDisconnected,
SendLifetimeMessage("video3", MediaStreamTrackMetrics::Direction::kSend));
MediaStreamTrackMetrics::VIDEO_TRACK, metrics_->RemoveTrack(MediaStreamTrackMetrics::Direction::kSend,
MediaStreamTrackMetrics::CONNECTED, MediaStreamTrackMetrics::Kind::kVideo, "video");
MediaStreamTrackMetrics::SENT_STREAM));
AddVideoTrack(video3.get());
// Add back audio1
EXPECT_CALL(*metrics_,
SendLifetimeMessage("audio1",
MediaStreamTrackMetrics::AUDIO_TRACK,
MediaStreamTrackMetrics::CONNECTED,
MediaStreamTrackMetrics::SENT_STREAM));
AddAudioTrack(audio1.get());
EXPECT_CALL(*metrics_,
SendLifetimeMessage("audio2",
MediaStreamTrackMetrics::AUDIO_TRACK,
MediaStreamTrackMetrics::DISCONNECTED,
MediaStreamTrackMetrics::SENT_STREAM));
RemoveAudioTrack(audio2.get());
EXPECT_CALL(*metrics_,
SendLifetimeMessage("video2",
MediaStreamTrackMetrics::VIDEO_TRACK,
MediaStreamTrackMetrics::DISCONNECTED,
MediaStreamTrackMetrics::SENT_STREAM));
RemoveVideoTrack(video2.get());
EXPECT_CALL(*metrics_,
SendLifetimeMessage("audio1",
MediaStreamTrackMetrics::AUDIO_TRACK,
MediaStreamTrackMetrics::DISCONNECTED,
MediaStreamTrackMetrics::SENT_STREAM));
RemoveAudioTrack(audio1.get());
EXPECT_CALL(*metrics_,
SendLifetimeMessage("video1",
MediaStreamTrackMetrics::VIDEO_TRACK,
MediaStreamTrackMetrics::DISCONNECTED,
MediaStreamTrackMetrics::SENT_STREAM));
RemoveVideoTrack(video1.get());
EXPECT_CALL(*metrics_,
SendLifetimeMessage("audio3",
MediaStreamTrackMetrics::AUDIO_TRACK,
MediaStreamTrackMetrics::DISCONNECTED,
MediaStreamTrackMetrics::SENT_STREAM));
EXPECT_CALL(*metrics_,
SendLifetimeMessage("video3",
MediaStreamTrackMetrics::VIDEO_TRACK,
MediaStreamTrackMetrics::DISCONNECTED,
MediaStreamTrackMetrics::SENT_STREAM));
metrics_->RemoveStream(MediaStreamTrackMetrics::SENT_STREAM, stream_.get());
} }
} // namespace content } // namespace content
...@@ -893,6 +893,13 @@ SdpSemanticRequested GetSdpSemanticRequested( ...@@ -893,6 +893,13 @@ SdpSemanticRequested GetSdpSemanticRequested(
return kSdpSemanticRequestedDefault; return kSdpSemanticRequestedDefault;
} }
MediaStreamTrackMetrics::Kind MediaStreamTrackMetricsKind(
const blink::WebMediaStreamTrack& track) {
return track.Source().GetType() == blink::WebMediaStreamSource::kTypeAudio
? MediaStreamTrackMetrics::Kind::kAudio
: MediaStreamTrackMetrics::Kind::kVideo;
}
} // namespace } // namespace
// Implementation of LocalRTCStatsRequest. // Implementation of LocalRTCStatsRequest.
...@@ -1826,6 +1833,9 @@ std::unique_ptr<blink::WebRTCRtpSender> RTCPeerConnectionHandler::AddTrack( ...@@ -1826,6 +1833,9 @@ std::unique_ptr<blink::WebRTCRtpSender> RTCPeerConnectionHandler::AddTrack(
webrtc_streams); webrtc_streams);
if (!webrtc_sender) if (!webrtc_sender)
return nullptr; return nullptr;
track_metrics_.AddTrack(MediaStreamTrackMetrics::Direction::kSend,
MediaStreamTrackMetricsKind(track),
track.Id().Utf8());
DCHECK(FindSender(RTCRtpSender::getId(webrtc_sender)) == rtp_senders_.end()); DCHECK(FindSender(RTCRtpSender::getId(webrtc_sender)) == rtp_senders_.end());
rtp_senders_.push_back(std::make_unique<RTCRtpSender>( rtp_senders_.push_back(std::make_unique<RTCRtpSender>(
native_peer_connection_, task_runner_, signaling_thread(), native_peer_connection_, task_runner_, signaling_thread(),
...@@ -1840,8 +1850,6 @@ std::unique_ptr<blink::WebRTCRtpSender> RTCPeerConnectionHandler::AddTrack( ...@@ -1840,8 +1850,6 @@ std::unique_ptr<blink::WebRTCRtpSender> RTCPeerConnectionHandler::AddTrack(
if (GetLocalStreamUsageCount(rtp_senders_, if (GetLocalStreamUsageCount(rtp_senders_,
stream_ref->adapter().web_stream()) == 1u) { stream_ref->adapter().web_stream()) == 1u) {
PerSessionWebRTCAPIMetrics::GetInstance()->IncrementStreamCounter(); PerSessionWebRTCAPIMetrics::GetInstance()->IncrementStreamCounter();
track_metrics_.AddStream(MediaStreamTrackMetrics::SENT_STREAM,
stream_ref->adapter().webrtc_stream().get());
} }
} }
return rtp_senders_.back()->ShallowCopy(); return rtp_senders_.back()->ShallowCopy();
...@@ -1850,11 +1858,15 @@ std::unique_ptr<blink::WebRTCRtpSender> RTCPeerConnectionHandler::AddTrack( ...@@ -1850,11 +1858,15 @@ std::unique_ptr<blink::WebRTCRtpSender> RTCPeerConnectionHandler::AddTrack(
bool RTCPeerConnectionHandler::RemoveTrack(blink::WebRTCRtpSender* web_sender) { bool RTCPeerConnectionHandler::RemoveTrack(blink::WebRTCRtpSender* web_sender) {
DCHECK(task_runner_->RunsTasksInCurrentSequence()); DCHECK(task_runner_->RunsTasksInCurrentSequence());
TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::RemoveTrack"); TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::RemoveTrack");
auto web_track = web_sender->Track();
auto it = FindSender(web_sender->Id()); auto it = FindSender(web_sender->Id());
if (it == rtp_senders_.end()) if (it == rtp_senders_.end())
return false; return false;
if (!(*it)->RemoveFromPeerConnection(native_peer_connection_.get())) if (!(*it)->RemoveFromPeerConnection(native_peer_connection_.get()))
return false; return false;
track_metrics_.RemoveTrack(MediaStreamTrackMetrics::Direction::kSend,
MediaStreamTrackMetricsKind(web_track),
web_track.Id().Utf8());
auto stream_refs = (*it)->stream_refs(); auto stream_refs = (*it)->stream_refs();
if (peer_connection_tracker_) { if (peer_connection_tracker_) {
peer_connection_tracker_->TrackRemoveTransceiver( peer_connection_tracker_->TrackRemoveTransceiver(
...@@ -1869,8 +1881,6 @@ bool RTCPeerConnectionHandler::RemoveTrack(blink::WebRTCRtpSender* web_sender) { ...@@ -1869,8 +1881,6 @@ bool RTCPeerConnectionHandler::RemoveTrack(blink::WebRTCRtpSender* web_sender) {
if (GetLocalStreamUsageCount(rtp_senders_, if (GetLocalStreamUsageCount(rtp_senders_,
stream_ref->adapter().web_stream()) == 0u) { stream_ref->adapter().web_stream()) == 0u) {
PerSessionWebRTCAPIMetrics::GetInstance()->DecrementStreamCounter(); PerSessionWebRTCAPIMetrics::GetInstance()->DecrementStreamCounter();
track_metrics_.RemoveStream(MediaStreamTrackMetrics::SENT_STREAM,
stream_ref->adapter().webrtc_stream().get());
} }
} }
return true; return true;
...@@ -2062,7 +2072,10 @@ void RTCPeerConnectionHandler::OnAddRemoteTrack( ...@@ -2062,7 +2072,10 @@ void RTCPeerConnectionHandler::OnAddRemoteTrack(
remote_stream_adapter_refs) { remote_stream_adapter_refs) {
DCHECK(task_runner_->RunsTasksInCurrentSequence()); DCHECK(task_runner_->RunsTasksInCurrentSequence());
TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::OnAddRemoteTrack"); TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::OnAddRemoteTrack");
auto web_track = remote_track_adapter_ref->web_track();
track_metrics_.AddTrack(MediaStreamTrackMetrics::Direction::kReceive,
MediaStreamTrackMetricsKind(web_track),
web_track.Id().Utf8());
for (const auto& remote_stream_adapter_ref : remote_stream_adapter_refs) { for (const auto& remote_stream_adapter_ref : remote_stream_adapter_refs) {
// New remote stream? // New remote stream?
if (GetRemoteStreamUsageCount( if (GetRemoteStreamUsageCount(
...@@ -2070,9 +2083,6 @@ void RTCPeerConnectionHandler::OnAddRemoteTrack( ...@@ -2070,9 +2083,6 @@ void RTCPeerConnectionHandler::OnAddRemoteTrack(
remote_stream_adapter_ref->adapter().webrtc_stream().get()) == 0) { remote_stream_adapter_ref->adapter().webrtc_stream().get()) == 0) {
// Update metrics. // Update metrics.
PerSessionWebRTCAPIMetrics::GetInstance()->IncrementStreamCounter(); PerSessionWebRTCAPIMetrics::GetInstance()->IncrementStreamCounter();
track_metrics_.AddStream(
MediaStreamTrackMetrics::RECEIVED_STREAM,
remote_stream_adapter_ref->adapter().webrtc_stream().get());
} }
} }
...@@ -2116,8 +2126,12 @@ void RTCPeerConnectionHandler::OnRemoveRemoteTrack( ...@@ -2116,8 +2126,12 @@ void RTCPeerConnectionHandler::OnRemoveRemoteTrack(
nullptr /* sender */, it->second->ShallowCopy() /* receiver */); nullptr /* sender */, it->second->ShallowCopy() /* receiver */);
} }
remote_stream_adapter_refs = it->second->StreamAdapterRefs(); remote_stream_adapter_refs = it->second->StreamAdapterRefs();
auto receiver = it->second->ShallowCopy();
track_metrics_.RemoveTrack(MediaStreamTrackMetrics::Direction::kReceive,
MediaStreamTrackMetricsKind(receiver->Track()),
receiver->Track().Id().Utf8());
if (!is_closed_) if (!is_closed_)
client_->DidRemoveRemoteTrack(it->second->ShallowCopy()); client_->DidRemoveRemoteTrack(std::move(receiver));
rtp_receivers_.erase(it); rtp_receivers_.erase(it);
} }
...@@ -2127,9 +2141,6 @@ void RTCPeerConnectionHandler::OnRemoveRemoteTrack( ...@@ -2127,9 +2141,6 @@ void RTCPeerConnectionHandler::OnRemoveRemoteTrack(
rtp_receivers_, rtp_receivers_,
remote_stream_adapter_ref->adapter().webrtc_stream().get()) == 0) { remote_stream_adapter_ref->adapter().webrtc_stream().get()) == 0) {
// Update metrics. // Update metrics.
track_metrics_.RemoveStream(
MediaStreamTrackMetrics::RECEIVED_STREAM,
remote_stream_adapter_ref->adapter().webrtc_stream().get());
PerSessionWebRTCAPIMetrics::GetInstance()->DecrementStreamCounter(); PerSessionWebRTCAPIMetrics::GetInstance()->DecrementStreamCounter();
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment