RTC[In/Out]boundRTPStreamStats.mediaTrackId collected.

Based on the mapping between [Audio/Video]TrackInterface and
[Voice/Video][Sender/Receiver]Info.

The IDs of RTCMediaStreamTrackStats are updated to distinguish between
local and remote cases. Previously, if local and remote cases had the
same label only one of them would be included in the report (bug).

BUG=webrtc:6758, chromium:657854, chromium:657855, chromium:657856, chromium:627816

Review-Url: https://codereview.webrtc.org/2610843003
Cr-Commit-Position: refs/heads/master@{#16095}
diff --git a/webrtc/api/rtcstats_integrationtest.cc b/webrtc/api/rtcstats_integrationtest.cc
index 545f801..69dc834 100644
--- a/webrtc/api/rtcstats_integrationtest.cc
+++ b/webrtc/api/rtcstats_integrationtest.cc
@@ -490,7 +490,8 @@
     verifier->TestMemberIsUndefined(stream.associate_stats_id);
     verifier->TestMemberIsDefined(stream.is_remote);
     verifier->TestMemberIsDefined(stream.media_type);
-    verifier->TestMemberIsUndefined(stream.media_track_id);
+    verifier->TestMemberIsIDReference(
+        stream.media_track_id, RTCMediaStreamTrackStats::kType);
     verifier->TestMemberIsIDReference(
         stream.transport_id, RTCTransportStats::kType);
     verifier->TestMemberIsIDReference(stream.codec_id, RTCCodecStats::kType);
diff --git a/webrtc/api/rtcstatscollector.cc b/webrtc/api/rtcstatscollector.cc
index dc14970..eade3d3 100644
--- a/webrtc/api/rtcstatscollector.cc
+++ b/webrtc/api/rtcstatscollector.cc
@@ -53,9 +53,10 @@
       info.remote_candidate.id();
 }
 
-std::string RTCMediaStreamTrackStatsIDFromMediaStreamTrackInterface(
-    const MediaStreamTrackInterface& track) {
-  return "RTCMediaStreamTrack_" + track.id();
+std::string RTCMediaStreamTrackStatsIDFromTrackID(
+    const std::string& id, bool is_local) {
+  return (is_local ? "RTCMediaStreamTrack_local_" + id
+                   : "RTCMediaStreamTrack_remote_" + id);
 }
 
 std::string RTCTransportStatsIDFromTransportChannel(
@@ -327,8 +328,8 @@
     // Audio Tracks
     for (const rtc::scoped_refptr<AudioTrackInterface>& audio_track :
          stream->GetAudioTracks()) {
-      std::string id = RTCMediaStreamTrackStatsIDFromMediaStreamTrackInterface(
-        *audio_track.get());
+      std::string id = RTCMediaStreamTrackStatsIDFromTrackID(
+          audio_track->id(), is_local);
       if (report->Get(id)) {
         // Skip track, stats already exist for it.
         continue;
@@ -365,8 +366,8 @@
     // Video Tracks
     for (const rtc::scoped_refptr<VideoTrackInterface>& video_track :
          stream->GetVideoTracks()) {
-      std::string id = RTCMediaStreamTrackStatsIDFromMediaStreamTrackInterface(
-          *video_track.get());
+      std::string id = RTCMediaStreamTrackStatsIDFromTrackID(
+          video_track->id(), is_local);
       if (report->Get(id)) {
         // Skip track, stats already exist for it.
         continue;
@@ -450,7 +451,7 @@
     num_pending_partial_reports_ = 2;
     partial_report_timestamp_us_ = cache_now_us;
 
-    // Prepare |channel_names_| and |media_info_| for use in
+    // Prepare |channel_name_pairs_| for use in
     // |ProducePartialResultsOnNetworkThread|.
     channel_name_pairs_.reset(new ChannelNamePairs());
     if (pc_->session()->voice_channel()) {
@@ -474,7 +475,14 @@
           ChannelNamePair(*pc_->session()->sctp_content_name(),
                           *pc_->session()->sctp_transport_name()));
     }
-    media_info_.reset(PrepareMediaInfo_s().release());
+    // Prepare |track_media_info_map_| for use in
+    // |ProducePartialResultsOnNetworkThread| and
+    // |ProducePartialResultsOnSignalingThread|.
+    track_media_info_map_.reset(PrepareTrackMediaInfoMap_s().release());
+    // Prepare |track_to_id_| for use in |ProducePartialResultsOnNetworkThread|.
+    // This avoids a possible deadlock if |MediaStreamTrackInterface::id| is
+    // implemented to invoke on the signaling thread.
+    track_to_id_ = PrepareTrackToID_s();
 
     invoker_.AsyncInvoke<void>(RTC_FROM_HERE, network_thread_,
         rtc::Bind(&RTCStatsCollector::ProducePartialResultsOnNetworkThread,
@@ -527,11 +535,11 @@
     ProduceCertificateStats_n(
         timestamp_us, transport_cert_stats, report.get());
     ProduceCodecStats_n(
-        timestamp_us, *media_info_, report.get());
+        timestamp_us, *track_media_info_map_, report.get());
     ProduceIceCandidateAndPairStats_n(
         timestamp_us, *session_stats, report.get());
     ProduceRTPStreamStats_n(
-        timestamp_us, *session_stats, *media_info_, report.get());
+        timestamp_us, *session_stats, *track_media_info_map_, report.get());
     ProduceTransportStats_n(
         timestamp_us, *session_stats, transport_cert_stats, report.get());
   }
@@ -564,6 +572,9 @@
     cache_timestamp_us_ = partial_report_timestamp_us_;
     cached_report_ = partial_report_;
     partial_report_ = nullptr;
+    channel_name_pairs_.reset();
+    track_media_info_map_.reset();
+    track_to_id_.clear();
     DeliverCachedReport();
   }
 }
@@ -597,31 +608,35 @@
 }
 
 void RTCStatsCollector::ProduceCodecStats_n(
-    int64_t timestamp_us, const MediaInfo& media_info,
+    int64_t timestamp_us, const TrackMediaInfoMap& track_media_info_map,
     RTCStatsReport* report) const {
   RTC_DCHECK(network_thread_->IsCurrent());
   // Audio
-  if (media_info.voice) {
+  if (track_media_info_map.voice_media_info()) {
     // Inbound
-    for (const auto& pair : media_info.voice->receive_codecs) {
+    for (const auto& pair :
+         track_media_info_map.voice_media_info()->receive_codecs) {
       report->AddStats(CodecStatsFromRtpCodecParameters(
           timestamp_us, true, true, pair.second));
     }
     // Outbound
-    for (const auto& pair : media_info.voice->send_codecs) {
+    for (const auto& pair :
+         track_media_info_map.voice_media_info()->send_codecs) {
       report->AddStats(CodecStatsFromRtpCodecParameters(
           timestamp_us, false, true, pair.second));
     }
   }
   // Video
-  if (media_info.video) {
+  if (track_media_info_map.video_media_info()) {
     // Inbound
-    for (const auto& pair : media_info.video->receive_codecs) {
+    for (const auto& pair :
+         track_media_info_map.video_media_info()->receive_codecs) {
       report->AddStats(CodecStatsFromRtpCodecParameters(
           timestamp_us, true, false, pair.second));
     }
     // Outbound
-    for (const auto& pair : media_info.video->send_codecs) {
+    for (const auto& pair :
+         track_media_info_map.video_media_info()->send_codecs) {
       report->AddStats(CodecStatsFromRtpCodecParameters(
           timestamp_us, false, false, pair.second));
     }
@@ -731,17 +746,18 @@
 
 void RTCStatsCollector::ProduceRTPStreamStats_n(
     int64_t timestamp_us, const SessionStats& session_stats,
-    const MediaInfo& media_info, RTCStatsReport* report) const {
+    const TrackMediaInfoMap& track_media_info_map,
+    RTCStatsReport* report) const {
   RTC_DCHECK(network_thread_->IsCurrent());
 
   // Audio
-  if (media_info.voice) {
+  if (track_media_info_map.voice_media_info()) {
     std::string transport_id = RTCTransportStatsIDFromBaseChannel(
         session_stats.proxy_to_transport, *pc_->session()->voice_channel());
     RTC_DCHECK(!transport_id.empty());
     // Inbound
     for (const cricket::VoiceReceiverInfo& voice_receiver_info :
-         media_info.voice->receivers) {
+         track_media_info_map.voice_media_info()->receivers) {
       // TODO(nisse): SSRC == 0 currently means none. Delete check when that
       // is fixed.
       if (voice_receiver_info.ssrc() == 0)
@@ -753,6 +769,14 @@
               timestamp_us));
       SetInboundRTPStreamStatsFromVoiceReceiverInfo(
           voice_receiver_info, inbound_audio.get());
+      rtc::scoped_refptr<AudioTrackInterface> audio_track =
+          track_media_info_map_->GetAudioTrack(voice_receiver_info);
+      if (audio_track) {
+        RTC_DCHECK(track_to_id_.find(audio_track.get()) != track_to_id_.end());
+        inbound_audio->media_track_id =
+            RTCMediaStreamTrackStatsIDFromTrackID(
+                track_to_id_.find(audio_track.get())->second, false);
+      }
       inbound_audio->transport_id = transport_id;
       if (voice_receiver_info.codec_payload_type) {
         inbound_audio->codec_id =
@@ -763,7 +787,7 @@
     }
     // Outbound
     for (const cricket::VoiceSenderInfo& voice_sender_info :
-         media_info.voice->senders) {
+         track_media_info_map.voice_media_info()->senders) {
       // TODO(nisse): SSRC == 0 currently means none. Delete check when that
       // is fixed.
       if (voice_sender_info.ssrc() == 0)
@@ -775,6 +799,14 @@
               timestamp_us));
       SetOutboundRTPStreamStatsFromVoiceSenderInfo(
           voice_sender_info, outbound_audio.get());
+      rtc::scoped_refptr<AudioTrackInterface> audio_track =
+          track_media_info_map_->GetAudioTrack(voice_sender_info);
+      if (audio_track) {
+        RTC_DCHECK(track_to_id_.find(audio_track.get()) != track_to_id_.end());
+        outbound_audio->media_track_id =
+            RTCMediaStreamTrackStatsIDFromTrackID(
+                track_to_id_.find(audio_track.get())->second, true);
+      }
       outbound_audio->transport_id = transport_id;
       if (voice_sender_info.codec_payload_type) {
         outbound_audio->codec_id =
@@ -785,13 +817,13 @@
     }
   }
   // Video
-  if (media_info.video) {
+  if (track_media_info_map.video_media_info()) {
     std::string transport_id = RTCTransportStatsIDFromBaseChannel(
         session_stats.proxy_to_transport, *pc_->session()->video_channel());
     RTC_DCHECK(!transport_id.empty());
     // Inbound
     for (const cricket::VideoReceiverInfo& video_receiver_info :
-         media_info.video->receivers) {
+         track_media_info_map.video_media_info()->receivers) {
       // TODO(nisse): SSRC == 0 currently means none. Delete check when that
       // is fixed.
       if (video_receiver_info.ssrc() == 0)
@@ -803,6 +835,14 @@
               timestamp_us));
       SetInboundRTPStreamStatsFromVideoReceiverInfo(
           video_receiver_info, inbound_video.get());
+      rtc::scoped_refptr<VideoTrackInterface> video_track =
+          track_media_info_map_->GetVideoTrack(video_receiver_info);
+      if (video_track) {
+        RTC_DCHECK(track_to_id_.find(video_track.get()) != track_to_id_.end());
+        inbound_video->media_track_id =
+            RTCMediaStreamTrackStatsIDFromTrackID(
+                track_to_id_.find(video_track.get())->second, false);
+      }
       inbound_video->transport_id = transport_id;
       if (video_receiver_info.codec_payload_type) {
         inbound_video->codec_id =
@@ -813,7 +853,7 @@
     }
     // Outbound
     for (const cricket::VideoSenderInfo& video_sender_info :
-         media_info.video->senders) {
+         track_media_info_map.video_media_info()->senders) {
       // TODO(nisse): SSRC == 0 currently means none. Delete check when that
       // is fixed.
       if (video_sender_info.ssrc() == 0)
@@ -825,6 +865,14 @@
               timestamp_us));
       SetOutboundRTPStreamStatsFromVideoSenderInfo(
           video_sender_info, outbound_video.get());
+      rtc::scoped_refptr<VideoTrackInterface> video_track =
+          track_media_info_map_->GetVideoTrack(video_sender_info);
+      if (video_track) {
+        RTC_DCHECK(track_to_id_.find(video_track.get()) != track_to_id_.end());
+        outbound_video->media_track_id =
+            RTCMediaStreamTrackStatsIDFromTrackID(
+                track_to_id_.find(video_track.get())->second, true);
+      }
       outbound_video->transport_id = transport_id;
       if (video_sender_info.codec_payload_type) {
         outbound_video->codec_id =
@@ -928,25 +976,53 @@
   return transport_cert_stats;
 }
 
-std::unique_ptr<RTCStatsCollector::MediaInfo>
-RTCStatsCollector::PrepareMediaInfo_s() const {
+std::unique_ptr<TrackMediaInfoMap>
+RTCStatsCollector::PrepareTrackMediaInfoMap_s() const {
   RTC_DCHECK(signaling_thread_->IsCurrent());
-  std::unique_ptr<MediaInfo> media_info(new MediaInfo());
+  std::unique_ptr<cricket::VoiceMediaInfo> voice_media_info;
   if (pc_->session()->voice_channel()) {
-    cricket::VoiceMediaInfo voice_media_info;
-    if (pc_->session()->voice_channel()->GetStats(&voice_media_info)) {
-      media_info->voice = rtc::Optional<cricket::VoiceMediaInfo>(
-          std::move(voice_media_info));
+    voice_media_info.reset(new cricket::VoiceMediaInfo());
+    if (!pc_->session()->voice_channel()->GetStats(voice_media_info.get())) {
+      voice_media_info.reset();
     }
   }
+  std::unique_ptr<cricket::VideoMediaInfo> video_media_info;
   if (pc_->session()->video_channel()) {
-    cricket::VideoMediaInfo video_media_info;
-    if (pc_->session()->video_channel()->GetStats(&video_media_info)) {
-      media_info->video = rtc::Optional<cricket::VideoMediaInfo>(
-          std::move(video_media_info));
+    video_media_info.reset(new cricket::VideoMediaInfo());
+    if (!pc_->session()->video_channel()->GetStats(video_media_info.get())) {
+      video_media_info.reset();
     }
   }
-  return media_info;
+  std::unique_ptr<TrackMediaInfoMap> track_media_info_map(
+      new TrackMediaInfoMap(std::move(voice_media_info),
+                            std::move(video_media_info),
+                            pc_->GetSenders(),
+                            pc_->GetReceivers()));
+  return track_media_info_map;
+}
+
+std::map<MediaStreamTrackInterface*, std::string>
+RTCStatsCollector::PrepareTrackToID_s() const {
+  RTC_DCHECK(signaling_thread_->IsCurrent());
+  std::map<MediaStreamTrackInterface*, std::string> track_to_id;
+  StreamCollectionInterface* local_and_remote_streams[] =
+      { pc_->local_streams().get(), pc_->remote_streams().get() };
+  for (auto& streams : local_and_remote_streams) {
+    if (streams) {
+      for (size_t i = 0; i < streams->count(); ++i) {
+        MediaStreamInterface* stream = streams->at(i);
+        for (const rtc::scoped_refptr<AudioTrackInterface>& audio_track :
+             stream->GetAudioTracks()) {
+          track_to_id[audio_track.get()] = audio_track->id();
+        }
+        for (const rtc::scoped_refptr<VideoTrackInterface>& video_track :
+             stream->GetVideoTracks()) {
+          track_to_id[video_track.get()] = video_track->id();
+        }
+      }
+    }
+  }
+  return track_to_id;
 }
 
 void RTCStatsCollector::OnDataChannelCreated(DataChannel* channel) {
diff --git a/webrtc/api/rtcstatscollector.h b/webrtc/api/rtcstatscollector.h
index 0a99ae9..cd3c55e 100644
--- a/webrtc/api/rtcstatscollector.h
+++ b/webrtc/api/rtcstatscollector.h
@@ -20,6 +20,7 @@
 #include "webrtc/api/datachannelinterface.h"
 #include "webrtc/api/stats/rtcstats_objects.h"
 #include "webrtc/api/stats/rtcstatsreport.h"
+#include "webrtc/api/trackmediainfomap.h"
 #include "webrtc/base/asyncinvoker.h"
 #include "webrtc/base/optional.h"
 #include "webrtc/base/refcount.h"
@@ -93,10 +94,6 @@
     std::unique_ptr<rtc::SSLCertificateStats> local;
     std::unique_ptr<rtc::SSLCertificateStats> remote;
   };
-  struct MediaInfo {
-    rtc::Optional<cricket::VoiceMediaInfo> voice;
-    rtc::Optional<cricket::VideoMediaInfo> video;
-  };
 
   void AddPartialResults_s(rtc::scoped_refptr<RTCStatsReport> partial_report);
   void DeliverCachedReport();
@@ -108,7 +105,7 @@
       RTCStatsReport* report) const;
   // Produces |RTCCodecStats|.
   void ProduceCodecStats_n(
-      int64_t timestamp_us, const MediaInfo& media_info,
+      int64_t timestamp_us, const TrackMediaInfoMap& track_media_info_map,
       RTCStatsReport* report) const;
   // Produces |RTCDataChannelStats|.
   void ProduceDataChannelStats_s(
@@ -126,7 +123,8 @@
   // Produces |RTCInboundRTPStreamStats| and |RTCOutboundRTPStreamStats|.
   void ProduceRTPStreamStats_n(
       int64_t timestamp_us, const SessionStats& session_stats,
-      const MediaInfo& media_info, RTCStatsReport* report) const;
+      const TrackMediaInfoMap& track_media_info_map,
+      RTCStatsReport* report) const;
   // Produces |RTCTransportStats|.
   void ProduceTransportStats_n(
       int64_t timestamp_us, const SessionStats& session_stats,
@@ -136,7 +134,8 @@
   // Helper function to stats-producing functions.
   std::map<std::string, CertificateStatsPair>
   PrepareTransportCertificateStats_n(const SessionStats& session_stats) const;
-  std::unique_ptr<MediaInfo> PrepareMediaInfo_s() const;
+  std::unique_ptr<TrackMediaInfoMap> PrepareTrackMediaInfoMap_s() const;
+  std::map<MediaStreamTrackInterface*, std::string> PrepareTrackToID_s() const;
 
   // Slots for signals (sigslot) that are wired up to |pc_|.
   void OnDataChannelCreated(DataChannel* channel);
@@ -155,12 +154,13 @@
   rtc::scoped_refptr<RTCStatsReport> partial_report_;
   std::vector<rtc::scoped_refptr<RTCStatsCollectorCallback>> callbacks_;
 
-  // Set in |GetStatsReport|, used in |ProducePartialResultsOnNetworkThread|
-  // (not passed as arguments to avoid copies). This is thread safe - it is set
-  // at the start of |GetStatsReport| after making sure there are no pending
-  // stats requests in progress.
+  // Set in |GetStatsReport|, read in |ProducePartialResultsOnNetworkThread| and
+  // |ProducePartialResultsOnSignalingThread|, reset after work is complete. Not
+  // passed as arguments to avoid copies. This is thread safe - when we
+  // set/reset we know there are no pending stats requests in progress.
   std::unique_ptr<ChannelNamePairs> channel_name_pairs_;
-  std::unique_ptr<MediaInfo> media_info_;
+  std::unique_ptr<TrackMediaInfoMap> track_media_info_map_;
+  std::map<MediaStreamTrackInterface*, std::string> track_to_id_;
 
   // A timestamp, in microseconds, that is based on a timer that is
   // monotonically increasing. That is, even if the system clock is modified the
diff --git a/webrtc/api/rtcstatscollector_unittest.cc b/webrtc/api/rtcstatscollector_unittest.cc
index a942662..5392586 100644
--- a/webrtc/api/rtcstatscollector_unittest.cc
+++ b/webrtc/api/rtcstatscollector_unittest.cc
@@ -23,6 +23,8 @@
 #include "webrtc/api/stats/rtcstatsreport.h"
 #include "webrtc/api/test/mock_datachannel.h"
 #include "webrtc/api/test/mock_peerconnection.h"
+#include "webrtc/api/test/mock_rtpreceiver.h"
+#include "webrtc/api/test/mock_rtpsender.h"
 #include "webrtc/api/test/mock_webrtcsession.h"
 #include "webrtc/api/test/rtcstatsobtainer.h"
 #include "webrtc/base/checks.h"
@@ -288,6 +290,26 @@
   rtc::scoped_refptr<VideoTrackSourceInterface> source_;
 };
 
+rtc::scoped_refptr<MediaStreamTrackInterface> CreateFakeTrack(
+    cricket::MediaType media_type,
+    const std::string& track_id) {
+  if (media_type == cricket::MEDIA_TYPE_AUDIO) {
+    return FakeAudioTrackForStats::Create(
+        track_id,
+        MediaStreamTrackInterface::TrackState::kLive,
+        32767,
+        new FakeAudioProcessorForStats(
+            AudioProcessorInterface::AudioProcessorStats()));
+  } else {
+    RTC_DCHECK_EQ(media_type, cricket::MEDIA_TYPE_VIDEO);
+    return FakeVideoTrackForStats::Create(
+        track_id,
+        MediaStreamTrackInterface::TrackState::kLive,
+        new FakeVideoTrackSourceForStats(
+            VideoTrackSourceInterface::Stats()));
+  }
+}
+
 class RTCStatsCollectorTestHelper : public SetSessionDescriptionObserver {
  public:
   RTCStatsCollectorTestHelper()
@@ -309,6 +331,10 @@
     EXPECT_CALL(pc_, local_streams()).WillRepeatedly(Return(nullptr));
     EXPECT_CALL(pc_, remote_streams()).WillRepeatedly(Return(nullptr));
     EXPECT_CALL(pc_, session()).WillRepeatedly(Return(&session_));
+    EXPECT_CALL(pc_, GetSenders()).WillRepeatedly(Return(
+        std::vector<rtc::scoped_refptr<RtpSenderInterface>>()));
+    EXPECT_CALL(pc_, GetReceivers()).WillRepeatedly(Return(
+        std::vector<rtc::scoped_refptr<RtpReceiverInterface>>()));
     EXPECT_CALL(pc_, sctp_data_channels()).WillRepeatedly(
         ReturnRef(data_channels_));
     EXPECT_CALL(session_, video_channel()).WillRepeatedly(ReturnNull());
@@ -336,6 +362,81 @@
     RTC_NOTREACHED() << error;
   }
 
+  void SetupLocalTrackAndSender(cricket::MediaType media_type,
+                                const std::string& track_id,
+                                uint32_t ssrc) {
+    rtc::scoped_refptr<StreamCollection> local_streams =
+        StreamCollection::Create();
+    EXPECT_CALL(pc_, local_streams())
+        .WillRepeatedly(Return(local_streams));
+
+    rtc::scoped_refptr<MediaStream> local_stream =
+        MediaStream::Create("LocalStreamLabel");
+    local_streams->AddStream(local_stream);
+
+    rtc::scoped_refptr<MediaStreamTrackInterface> track;
+    if (media_type == cricket::MEDIA_TYPE_AUDIO) {
+      track = CreateFakeTrack(media_type, track_id);
+      local_stream->AddTrack(static_cast<AudioTrackInterface*>(track.get()));
+    } else {
+      track = CreateFakeTrack(media_type, track_id);
+      local_stream->AddTrack(static_cast<VideoTrackInterface*>(track.get()));
+    }
+
+    rtc::scoped_refptr<MockRtpSender> sender(
+        new rtc::RefCountedObject<MockRtpSender>());
+    EXPECT_CALL(*sender, track()).WillRepeatedly(Return(track));
+    EXPECT_CALL(*sender, ssrc()).WillRepeatedly(Return(ssrc));
+    EXPECT_CALL(*sender, media_type()).WillRepeatedly(Return(media_type));
+    EXPECT_CALL(*sender, GetParameters()).WillRepeatedly(Invoke(
+      [ssrc]() {
+        RtpParameters params;
+        params.encodings.push_back(RtpEncodingParameters());
+        params.encodings[0].ssrc = rtc::Optional<uint32_t>(ssrc);
+        return params;
+      }));
+    EXPECT_CALL(pc_, GetSenders()).WillRepeatedly(Return(
+        std::vector<rtc::scoped_refptr<RtpSenderInterface>>({
+            rtc::scoped_refptr<RtpSenderInterface>(sender.get()) })));
+  }
+
+  void SetupRemoteTrackAndReceiver(cricket::MediaType media_type,
+                                   const std::string& track_id,
+                                   uint32_t ssrc) {
+    rtc::scoped_refptr<StreamCollection> remote_streams =
+        StreamCollection::Create();
+    EXPECT_CALL(pc_, remote_streams())
+        .WillRepeatedly(Return(remote_streams));
+
+    rtc::scoped_refptr<MediaStream> remote_stream =
+        MediaStream::Create("RemoteStreamLabel");
+    remote_streams->AddStream(remote_stream);
+
+    rtc::scoped_refptr<MediaStreamTrackInterface> track;
+    if (media_type == cricket::MEDIA_TYPE_AUDIO) {
+      track = CreateFakeTrack(media_type, track_id);
+      remote_stream->AddTrack(static_cast<AudioTrackInterface*>(track.get()));
+    } else {
+      track = CreateFakeTrack(media_type, track_id);
+      remote_stream->AddTrack(static_cast<VideoTrackInterface*>(track.get()));
+    }
+
+    rtc::scoped_refptr<MockRtpReceiver> receiver(
+        new rtc::RefCountedObject<MockRtpReceiver>());
+    EXPECT_CALL(*receiver, track()).WillRepeatedly(Return(track));
+    EXPECT_CALL(*receiver, media_type()).WillRepeatedly(Return(media_type));
+    EXPECT_CALL(*receiver, GetParameters()).WillRepeatedly(Invoke(
+      [ssrc]() {
+        RtpParameters params;
+        params.encodings.push_back(RtpEncodingParameters());
+        params.encodings[0].ssrc = rtc::Optional<uint32_t>(ssrc);
+        return params;
+      }));
+    EXPECT_CALL(pc_, GetReceivers()).WillRepeatedly(Return(
+        std::vector<rtc::scoped_refptr<RtpReceiverInterface>>({
+            rtc::scoped_refptr<RtpReceiverInterface>(receiver.get()) })));
+  }
+
  private:
   rtc::ScopedFakeClock fake_clock_;
   RtcEventLogNullImpl event_log_;
@@ -1260,7 +1361,7 @@
   expected_local_stream.stream_identifier = local_stream->label();
   expected_local_stream.track_ids = std::vector<std::string>();
   expected_local_stream.track_ids->push_back(
-      "RTCMediaStreamTrack_LocalAudioTrackID");
+      "RTCMediaStreamTrack_local_LocalAudioTrackID");
   ASSERT_TRUE(report->Get(expected_local_stream.id()));
   EXPECT_EQ(expected_local_stream,
             report->Get(expected_local_stream.id())->cast_to<
@@ -1271,14 +1372,14 @@
   expected_remote_stream.stream_identifier = remote_stream->label();
   expected_remote_stream.track_ids = std::vector<std::string>();
   expected_remote_stream.track_ids->push_back(
-      "RTCMediaStreamTrack_RemoteAudioTrackID");
+      "RTCMediaStreamTrack_remote_RemoteAudioTrackID");
   ASSERT_TRUE(report->Get(expected_remote_stream.id()));
   EXPECT_EQ(expected_remote_stream,
             report->Get(expected_remote_stream.id())->cast_to<
                 RTCMediaStreamStats>());
 
   RTCMediaStreamTrackStats expected_local_audio_track(
-      "RTCMediaStreamTrack_LocalAudioTrackID", report->timestamp_us());
+      "RTCMediaStreamTrack_local_LocalAudioTrackID", report->timestamp_us());
   expected_local_audio_track.track_identifier = local_audio_track->id();
   expected_local_audio_track.remote_source = false;
   expected_local_audio_track.ended = true;
@@ -1292,7 +1393,7 @@
                 RTCMediaStreamTrackStats>());
 
   RTCMediaStreamTrackStats expected_remote_audio_track(
-      "RTCMediaStreamTrack_RemoteAudioTrackID", report->timestamp_us());
+      "RTCMediaStreamTrack_remote_RemoteAudioTrackID", report->timestamp_us());
   expected_remote_audio_track.track_identifier = remote_audio_track->id();
   expected_remote_audio_track.remote_source = true;
   expected_remote_audio_track.ended = false;
@@ -1332,7 +1433,7 @@
   rtc::scoped_refptr<const RTCStatsReport> report = GetStatsReport();
 
   RTCMediaStreamTrackStats expected_local_audio_track(
-      "RTCMediaStreamTrack_LocalAudioTrackID", report->timestamp_us());
+      "RTCMediaStreamTrack_local_LocalAudioTrackID", report->timestamp_us());
   expected_local_audio_track.track_identifier = local_audio_track->id();
   expected_local_audio_track.remote_source = false;
   expected_local_audio_track.ended = true;
@@ -1397,7 +1498,7 @@
   expected_local_stream.stream_identifier = local_stream->label();
   expected_local_stream.track_ids = std::vector<std::string>();
   expected_local_stream.track_ids->push_back(
-      "RTCMediaStreamTrack_LocalVideoTrackID");
+      "RTCMediaStreamTrack_local_LocalVideoTrackID");
   ASSERT_TRUE(report->Get(expected_local_stream.id()));
   EXPECT_EQ(expected_local_stream,
             report->Get(expected_local_stream.id())->cast_to<
@@ -1408,14 +1509,14 @@
   expected_remote_stream.stream_identifier = remote_stream->label();
   expected_remote_stream.track_ids = std::vector<std::string>();
   expected_remote_stream.track_ids->push_back(
-      "RTCMediaStreamTrack_RemoteVideoTrackID");
+      "RTCMediaStreamTrack_remote_RemoteVideoTrackID");
   ASSERT_TRUE(report->Get(expected_remote_stream.id()));
   EXPECT_EQ(expected_remote_stream,
             report->Get(expected_remote_stream.id())->cast_to<
                 RTCMediaStreamStats>());
 
   RTCMediaStreamTrackStats expected_local_video_track(
-      "RTCMediaStreamTrack_LocalVideoTrackID", report->timestamp_us());
+      "RTCMediaStreamTrack_local_LocalVideoTrackID", report->timestamp_us());
   expected_local_video_track.track_identifier = local_video_track->id();
   expected_local_video_track.remote_source = false;
   expected_local_video_track.ended = false;
@@ -1428,7 +1529,7 @@
                 RTCMediaStreamTrackStats>());
 
   RTCMediaStreamTrackStats expected_remote_video_track(
-      "RTCMediaStreamTrack_RemoteVideoTrackID", report->timestamp_us());
+      "RTCMediaStreamTrack_remote_RemoteVideoTrackID", report->timestamp_us());
   expected_remote_video_track.track_identifier = remote_video_track->id();
   expected_remote_video_track.remote_source = true;
   expected_remote_video_track.ended = true;
@@ -1448,6 +1549,9 @@
       test_->media_engine(), voice_media_channel, "VoiceContentName",
       kDefaultRtcpMuxRequired, kDefaultSrtpRequired);
 
+  test_->SetupRemoteTrackAndReceiver(
+      cricket::MEDIA_TYPE_AUDIO, "RemoteAudioTrackID", 1);
+
   cricket::VoiceMediaInfo voice_media_info;
 
   voice_media_info.receivers.push_back(cricket::VoiceReceiverInfo());
@@ -1496,6 +1600,8 @@
   expected_audio.ssrc = "1";
   expected_audio.is_remote = false;
   expected_audio.media_type = "audio";
+  expected_audio.media_track_id =
+      "RTCMediaStreamTrack_remote_RemoteAudioTrackID";
   expected_audio.transport_id = "RTCTransport_TransportName_" +
       rtc::ToString<>(cricket::ICE_CANDIDATE_COMPONENT_RTP);
   expected_audio.codec_id = "RTCCodec_InboundAudio_42";
@@ -1510,8 +1616,9 @@
       expected_audio.id())->cast_to<RTCInboundRTPStreamStats>();
   EXPECT_EQ(audio, expected_audio);
 
-  ASSERT_TRUE(report->Get(*expected_audio.transport_id));
-  ASSERT_TRUE(report->Get(*expected_audio.codec_id));
+  EXPECT_TRUE(report->Get(*expected_audio.media_track_id));
+  EXPECT_TRUE(report->Get(*expected_audio.transport_id));
+  EXPECT_TRUE(report->Get(*expected_audio.codec_id));
 }
 
 TEST_F(RTCStatsCollectorTest, CollectRTCInboundRTPStreamStats_Video) {
@@ -1521,6 +1628,9 @@
       video_media_channel, "VideoContentName", kDefaultRtcpMuxRequired,
       kDefaultSrtpRequired);
 
+  test_->SetupRemoteTrackAndReceiver(
+      cricket::MEDIA_TYPE_VIDEO, "RemoteVideoTrackID", 1);
+
   cricket::VideoMediaInfo video_media_info;
 
   video_media_info.receivers.push_back(cricket::VideoReceiverInfo());
@@ -1572,6 +1682,8 @@
   expected_video.ssrc = "1";
   expected_video.is_remote = false;
   expected_video.media_type = "video";
+  expected_video.media_track_id =
+      "RTCMediaStreamTrack_remote_RemoteVideoTrackID";
   expected_video.transport_id = "RTCTransport_TransportName_" +
       rtc::ToString<>(cricket::ICE_CANDIDATE_COMPONENT_RTP);
   expected_video.codec_id = "RTCCodec_InboundVideo_42";
@@ -1589,8 +1701,9 @@
       expected_video.id())->cast_to<RTCInboundRTPStreamStats>();
   EXPECT_EQ(video, expected_video);
 
-  ASSERT_TRUE(report->Get(*expected_video.transport_id));
-  ASSERT_TRUE(report->Get(*video.codec_id));
+  EXPECT_TRUE(report->Get(*expected_video.media_track_id));
+  EXPECT_TRUE(report->Get(*expected_video.transport_id));
+  EXPECT_TRUE(report->Get(*video.codec_id));
 }
 
 TEST_F(RTCStatsCollectorTest, CollectRTCOutboundRTPStreamStats_Audio) {
@@ -1600,6 +1713,9 @@
       test_->media_engine(), voice_media_channel, "VoiceContentName",
       kDefaultRtcpMuxRequired, kDefaultSrtpRequired);
 
+  test_->SetupLocalTrackAndSender(
+      cricket::MEDIA_TYPE_AUDIO, "LocalAudioTrackID", 1);
+
   cricket::VoiceMediaInfo voice_media_info;
 
   voice_media_info.senders.push_back(cricket::VoiceSenderInfo());
@@ -1645,6 +1761,7 @@
   expected_audio.ssrc = "1";
   expected_audio.is_remote = false;
   expected_audio.media_type = "audio";
+  expected_audio.media_track_id = "RTCMediaStreamTrack_local_LocalAudioTrackID";
   expected_audio.transport_id = "RTCTransport_TransportName_" +
       rtc::ToString<>(cricket::ICE_CANDIDATE_COMPONENT_RTP);
   expected_audio.codec_id = "RTCCodec_OutboundAudio_42";
@@ -1657,8 +1774,9 @@
       expected_audio.id())->cast_to<RTCOutboundRTPStreamStats>();
   EXPECT_EQ(audio, expected_audio);
 
-  ASSERT_TRUE(report->Get(*expected_audio.transport_id));
-  ASSERT_TRUE(report->Get(*expected_audio.codec_id));
+  EXPECT_TRUE(report->Get(*expected_audio.media_track_id));
+  EXPECT_TRUE(report->Get(*expected_audio.transport_id));
+  EXPECT_TRUE(report->Get(*expected_audio.codec_id));
 }
 
 TEST_F(RTCStatsCollectorTest, CollectRTCOutboundRTPStreamStats_Video) {
@@ -1668,6 +1786,9 @@
       video_media_channel, "VideoContentName", kDefaultRtcpMuxRequired,
       kDefaultSrtpRequired);
 
+  test_->SetupLocalTrackAndSender(
+      cricket::MEDIA_TYPE_VIDEO, "LocalVideoTrackID", 1);
+
   cricket::VideoMediaInfo video_media_info;
 
   video_media_info.senders.push_back(cricket::VideoSenderInfo());
@@ -1718,6 +1839,7 @@
   expected_video.ssrc = "1";
   expected_video.is_remote = false;
   expected_video.media_type = "video";
+  expected_video.media_track_id = "RTCMediaStreamTrack_local_LocalVideoTrackID";
   expected_video.transport_id = "RTCTransport_TransportName_" +
       rtc::ToString<>(cricket::ICE_CANDIDATE_COMPONENT_RTP);
   expected_video.codec_id = "RTCCodec_OutboundVideo_42";
@@ -1735,8 +1857,9 @@
       expected_video.id())->cast_to<RTCOutboundRTPStreamStats>();
   EXPECT_EQ(video, expected_video);
 
-  ASSERT_TRUE(report->Get(*expected_video.transport_id));
-  ASSERT_TRUE(report->Get(*expected_video.codec_id));
+  EXPECT_TRUE(report->Get(*expected_video.media_track_id));
+  EXPECT_TRUE(report->Get(*expected_video.transport_id));
+  EXPECT_TRUE(report->Get(*expected_video.codec_id));
 }
 
 TEST_F(RTCStatsCollectorTest, CollectRTCOutboundRTPStreamStats_Default) {
diff --git a/webrtc/api/stats/rtcstats_objects.h b/webrtc/api/stats/rtcstats_objects.h
index 22c06e4..80830c3 100644
--- a/webrtc/api/stats/rtcstats_objects.h
+++ b/webrtc/api/stats/rtcstats_objects.h
@@ -295,7 +295,6 @@
   // crbug.com/657855, 657856
   RTCStatsMember<bool> is_remote;  // = false
   RTCStatsMember<std::string> media_type;
-  // TODO(hbos): Not collected by |RTCStatsCollector|. crbug.com/657854, 659137
   RTCStatsMember<std::string> media_track_id;
   RTCStatsMember<std::string> transport_id;
   RTCStatsMember<std::string> codec_id;
diff --git a/webrtc/api/statscollector_unittest.cc b/webrtc/api/statscollector_unittest.cc
index 0f0c0fc..30bb2b8 100644
--- a/webrtc/api/statscollector_unittest.cc
+++ b/webrtc/api/statscollector_unittest.cc
@@ -522,6 +522,10 @@
     EXPECT_CALL(pc_, session()).WillRepeatedly(Return(&session_));
     EXPECT_CALL(pc_, sctp_data_channels())
         .WillRepeatedly(ReturnRef(data_channels_));
+    EXPECT_CALL(pc_, GetSenders()).WillRepeatedly(Return(
+        std::vector<rtc::scoped_refptr<RtpSenderInterface>>()));
+    EXPECT_CALL(pc_, GetReceivers()).WillRepeatedly(Return(
+        std::vector<rtc::scoped_refptr<RtpReceiverInterface>>()));
   }
 
   ~StatsCollectorTest() {}
diff --git a/webrtc/api/test/mock_peerconnection.h b/webrtc/api/test/mock_peerconnection.h
index 7cc2b0d..ca39d2a 100644
--- a/webrtc/api/test/mock_peerconnection.h
+++ b/webrtc/api/test/mock_peerconnection.h
@@ -33,6 +33,10 @@
   MOCK_METHOD0(remote_streams,
                rtc::scoped_refptr<StreamCollectionInterface>());
   MOCK_METHOD0(session, WebRtcSession*());
+  MOCK_CONST_METHOD0(GetSenders,
+                     std::vector<rtc::scoped_refptr<RtpSenderInterface>>());
+  MOCK_CONST_METHOD0(GetReceivers,
+                     std::vector<rtc::scoped_refptr<RtpReceiverInterface>>());
   MOCK_CONST_METHOD0(sctp_data_channels,
                      const std::vector<rtc::scoped_refptr<DataChannel>>&());
 };