Update talk to 61538839.
TBR=mallinath
Review URL: https://webrtc-codereview.appspot.com/8669005
git-svn-id: http://webrtc.googlecode.com/svn/trunk@5548 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/talk/app/webrtc/mediastreamhandler.cc b/talk/app/webrtc/mediastreamhandler.cc
index a94eef3..ca8e105 100644
--- a/talk/app/webrtc/mediastreamhandler.cc
+++ b/talk/app/webrtc/mediastreamhandler.cc
@@ -106,6 +106,8 @@
void LocalAudioTrackHandler::OnEnabledChanged() {
cricket::AudioOptions options;
if (audio_track_->enabled() && audio_track_->GetSource()) {
+ // TODO(xians): Remove this static_cast since we should be able to connect
+ // a remote audio track to peer connection.
options = static_cast<LocalAudioSource*>(
audio_track_->GetSource())->options();
}
@@ -125,10 +127,12 @@
: TrackHandler(track, ssrc),
audio_track_(track),
provider_(provider) {
+ track->GetSource()->RegisterAudioObserver(this);
OnEnabledChanged();
}
RemoteAudioTrackHandler::~RemoteAudioTrackHandler() {
+ audio_track_->GetSource()->UnregisterAudioObserver(this);
}
void RemoteAudioTrackHandler::Stop() {
@@ -143,6 +147,14 @@
audio_track_->GetRenderer());
}
+void RemoteAudioTrackHandler::OnSetVolume(double volume) {
+ // When the track is disabled, the volume of the source, which is the
+ // corresponding WebRtc Voice Engine channel will be 0. So we do not allow
+ // setting the volume to the source when the track is disabled.
+ if (audio_track_->enabled())
+ provider_->SetAudioPlayoutVolume(ssrc(), volume);
+}
+
LocalVideoTrackHandler::LocalVideoTrackHandler(
VideoTrackInterface* track,
uint32 ssrc,
diff --git a/talk/app/webrtc/mediastreamhandler.h b/talk/app/webrtc/mediastreamhandler.h
index 625de85..53afd55 100644
--- a/talk/app/webrtc/mediastreamhandler.h
+++ b/talk/app/webrtc/mediastreamhandler.h
@@ -118,7 +118,8 @@
// RemoteAudioTrackHandler listen to events on a remote AudioTrack instance
// connected to a PeerConnection and orders the |provider| to executes the
// requested change.
-class RemoteAudioTrackHandler : public TrackHandler {
+class RemoteAudioTrackHandler : public AudioSourceInterface::AudioObserver,
+ public TrackHandler {
public:
RemoteAudioTrackHandler(AudioTrackInterface* track,
uint32 ssrc,
@@ -131,6 +132,9 @@
virtual void OnEnabledChanged() OVERRIDE;
private:
+ // AudioSourceInterface::AudioObserver implementation.
+ virtual void OnSetVolume(double volume) OVERRIDE;
+
AudioTrackInterface* audio_track_;
AudioProviderInterface* provider_;
};
diff --git a/talk/app/webrtc/mediastreamhandler_unittest.cc b/talk/app/webrtc/mediastreamhandler_unittest.cc
index 475258e..6eedb7e 100644
--- a/talk/app/webrtc/mediastreamhandler_unittest.cc
+++ b/talk/app/webrtc/mediastreamhandler_unittest.cc
@@ -31,6 +31,7 @@
#include "talk/app/webrtc/audiotrack.h"
#include "talk/app/webrtc/mediastream.h"
+#include "talk/app/webrtc/remoteaudiosource.h"
#include "talk/app/webrtc/streamcollection.h"
#include "talk/app/webrtc/videosource.h"
#include "talk/app/webrtc/videotrack.h"
@@ -59,6 +60,7 @@
MOCK_METHOD4(SetAudioSend, void(uint32 ssrc, bool enable,
const cricket::AudioOptions& options,
cricket::AudioRenderer* renderer));
+ MOCK_METHOD2(SetAudioPlayoutVolume, void(uint32 ssrc, double volume));
};
// Helper class to test MediaStreamHandler.
@@ -110,12 +112,11 @@
FakeVideoSource::Create());
video_track_ = VideoTrack::Create(kVideoTrackId, source);
EXPECT_TRUE(stream_->AddTrack(video_track_));
- audio_track_ = AudioTrack::Create(kAudioTrackId,
- NULL);
- EXPECT_TRUE(stream_->AddTrack(audio_track_));
}
void AddLocalAudioTrack() {
+ audio_track_ = AudioTrack::Create(kAudioTrackId, NULL);
+ EXPECT_TRUE(stream_->AddTrack(audio_track_));
EXPECT_CALL(audio_provider_, SetAudioSend(kAudioSsrc, true, _, _));
handlers_.AddLocalAudioTrack(stream_, stream_->GetAudioTracks()[0],
kAudioSsrc);
@@ -144,6 +145,9 @@
}
void AddRemoteAudioTrack() {
+ audio_track_ = AudioTrack::Create(kAudioTrackId,
+ RemoteAudioSource::Create().get());
+ EXPECT_TRUE(stream_->AddTrack(audio_track_));
EXPECT_CALL(audio_provider_, SetAudioPlayout(kAudioSsrc, true, _));
handlers_.AddRemoteAudioTrack(stream_, stream_->GetAudioTracks()[0],
kAudioSsrc);
@@ -292,4 +296,27 @@
handlers_.TearDown();
}
+TEST_F(MediaStreamHandlerTest, RemoteAudioTrackSetVolume) {
+ AddRemoteAudioTrack();
+
+ double volume = 0.5;
+ EXPECT_CALL(audio_provider_, SetAudioPlayoutVolume(kAudioSsrc, volume));
+ audio_track_->GetSource()->SetVolume(volume);
+
+ // Disable the audio track, this should prevent setting the volume.
+ EXPECT_CALL(audio_provider_, SetAudioPlayout(kAudioSsrc, false, _));
+ audio_track_->set_enabled(false);
+ audio_track_->GetSource()->SetVolume(1.0);
+
+ EXPECT_CALL(audio_provider_, SetAudioPlayout(kAudioSsrc, true, _));
+ audio_track_->set_enabled(true);
+
+ double new_volume = 0.8;
+ EXPECT_CALL(audio_provider_, SetAudioPlayoutVolume(kAudioSsrc, new_volume));
+ audio_track_->GetSource()->SetVolume(new_volume);
+
+ RemoveRemoteAudioTrack();
+ handlers_.TearDown();
+}
+
} // namespace webrtc
diff --git a/talk/app/webrtc/mediastreaminterface.h b/talk/app/webrtc/mediastreaminterface.h
index 96d0942..fa0572e 100644
--- a/talk/app/webrtc/mediastreaminterface.h
+++ b/talk/app/webrtc/mediastreaminterface.h
@@ -142,9 +142,24 @@
// AudioSourceInterface is a reference counted source used for AudioTracks.
// The same source can be used in multiple AudioTracks.
-// TODO(perkj): Extend this class with necessary methods to allow separate
-// sources for each audio track.
class AudioSourceInterface : public MediaSourceInterface {
+ public:
+ class AudioObserver {
+ public:
+ virtual void OnSetVolume(double volume) = 0;
+
+ protected:
+ virtual ~AudioObserver() {}
+ };
+
+ // TODO(xians): Makes all the interface pure virtual after Chrome has their
+ // implementations.
+ // Sets the volume to the source. |volume| is in the range of [0, 10].
+ virtual void SetVolume(double volume) {}
+
+ // Registers/unregisters observer to the audio source.
+ virtual void RegisterAudioObserver(AudioObserver* observer) {}
+ virtual void UnregisterAudioObserver(AudioObserver* observer) {}
};
// Interface for receiving audio data from a AudioTrack.
diff --git a/talk/app/webrtc/mediastreamprovider.h b/talk/app/webrtc/mediastreamprovider.h
index ae00b1d..5cf0e27 100644
--- a/talk/app/webrtc/mediastreamprovider.h
+++ b/talk/app/webrtc/mediastreamprovider.h
@@ -53,6 +53,10 @@
const cricket::AudioOptions& options,
cricket::AudioRenderer* renderer) = 0;
+ // Sets the audio playout volume of a remote audio track with |ssrc|.
+ // |volume| is in the range of [0, 10].
+ virtual void SetAudioPlayoutVolume(uint32 ssrc, double volume) = 0;
+
protected:
virtual ~AudioProviderInterface() {}
};
diff --git a/talk/app/webrtc/mediastreamsignaling.cc b/talk/app/webrtc/mediastreamsignaling.cc
index 610b3f8..14648ee 100644
--- a/talk/app/webrtc/mediastreamsignaling.cc
+++ b/talk/app/webrtc/mediastreamsignaling.cc
@@ -33,6 +33,7 @@
#include "talk/app/webrtc/mediastreamproxy.h"
#include "talk/app/webrtc/mediaconstraintsinterface.h"
#include "talk/app/webrtc/mediastreamtrackproxy.h"
+#include "talk/app/webrtc/remoteaudiosource.h"
#include "talk/app/webrtc/remotevideocapturer.h"
#include "talk/app/webrtc/sctputils.h"
#include "talk/app/webrtc/videosource.h"
@@ -140,7 +141,7 @@
AudioTrackInterface* AddAudioTrack(webrtc::MediaStreamInterface* stream,
const std::string& track_id) {
return AddTrack<AudioTrackInterface, AudioTrack, AudioTrackProxy>(
- stream, track_id, static_cast<AudioSourceInterface*>(NULL));
+ stream, track_id, RemoteAudioSource::Create().get());
}
VideoTrackInterface* AddVideoTrack(webrtc::MediaStreamInterface* stream,
diff --git a/talk/app/webrtc/peerconnection.cc b/talk/app/webrtc/peerconnection.cc
index 40640cf..b404ec4 100644
--- a/talk/app/webrtc/peerconnection.cc
+++ b/talk/app/webrtc/peerconnection.cc
@@ -459,13 +459,19 @@
}
bool PeerConnection::GetStats(StatsObserver* observer,
- MediaStreamTrackInterface* track) {
+ webrtc::MediaStreamTrackInterface* track) {
+ return GetStats(observer, track, kStatsOutputLevelStandard);
+}
+
+bool PeerConnection::GetStats(StatsObserver* observer,
+ MediaStreamTrackInterface* track,
+ StatsOutputLevel level) {
if (!VERIFY(observer != NULL)) {
LOG(LS_ERROR) << "GetStats - observer is NULL.";
return false;
}
- stats_.UpdateStats();
+ stats_.UpdateStats(level);
talk_base::scoped_ptr<GetStatsMsg> msg(new GetStatsMsg(observer));
if (!stats_.GetStats(track, &(msg->reports))) {
return false;
@@ -542,7 +548,7 @@
}
// Update stats here so that we have the most recent stats for tracks and
// streams that might be removed by updating the session description.
- stats_.UpdateStats();
+ stats_.UpdateStats(kStatsOutputLevelStandard);
std::string error;
if (!session_->SetLocalDescription(desc, &error)) {
PostSetSessionDescriptionFailure(observer, error);
@@ -565,7 +571,7 @@
}
// Update stats here so that we have the most recent stats for tracks and
// streams that might be removed by updating the session description.
- stats_.UpdateStats();
+ stats_.UpdateStats(kStatsOutputLevelStandard);
std::string error;
if (!session_->SetRemoteDescription(desc, &error)) {
PostSetSessionDescriptionFailure(observer, error);
@@ -606,7 +612,7 @@
void PeerConnection::Close() {
// Update stats here so that we have the most recent stats for tracks and
// streams before the channels are closed.
- stats_.UpdateStats();
+ stats_.UpdateStats(kStatsOutputLevelStandard);
session_->Terminate();
}
diff --git a/talk/app/webrtc/peerconnection.h b/talk/app/webrtc/peerconnection.h
index 9cc9f38..70155d9 100644
--- a/talk/app/webrtc/peerconnection.h
+++ b/talk/app/webrtc/peerconnection.h
@@ -76,6 +76,9 @@
const DataChannelInit* config);
virtual bool GetStats(StatsObserver* observer,
webrtc::MediaStreamTrackInterface* track);
+ virtual bool GetStats(StatsObserver* observer,
+ webrtc::MediaStreamTrackInterface* track,
+ StatsOutputLevel level);
virtual SignalingState signaling_state();
diff --git a/talk/app/webrtc/peerconnectioninterface.h b/talk/app/webrtc/peerconnectioninterface.h
index 667774e2..2f44885 100644
--- a/talk/app/webrtc/peerconnectioninterface.h
+++ b/talk/app/webrtc/peerconnectioninterface.h
@@ -166,6 +166,15 @@
};
typedef std::vector<IceServer> IceServers;
+ // Used by GetStats to decide which stats to include in the stats reports.
+ // |kStatsOutputLevelStandard| includes the standard stats for Javascript API;
+ // |kStatsOutputLevelDebug| includes both the standard stats and additional
+ // stats for debugging purposes.
+ enum StatsOutputLevel {
+ kStatsOutputLevelStandard,
+ kStatsOutputLevelDebug,
+ };
+
// Accessor methods to active local streams.
virtual talk_base::scoped_refptr<StreamCollectionInterface>
local_streams() = 0;
@@ -190,9 +199,14 @@
virtual talk_base::scoped_refptr<DtmfSenderInterface> CreateDtmfSender(
AudioTrackInterface* track) = 0;
+ // TODO(jiayl): remove the old API once all Chrome overrides are updated.
virtual bool GetStats(StatsObserver* observer,
MediaStreamTrackInterface* track) = 0;
+ virtual bool GetStats(StatsObserver* observer,
+ MediaStreamTrackInterface* track,
+ StatsOutputLevel level) = 0;
+
virtual talk_base::scoped_refptr<DataChannelInterface> CreateDataChannel(
const std::string& label,
const DataChannelInit* config) = 0;
diff --git a/talk/app/webrtc/peerconnectionproxy.h b/talk/app/webrtc/peerconnectionproxy.h
index f07416d..57bee51 100644
--- a/talk/app/webrtc/peerconnectionproxy.h
+++ b/talk/app/webrtc/peerconnectionproxy.h
@@ -45,6 +45,9 @@
PROXY_METHOD1(talk_base::scoped_refptr<DtmfSenderInterface>,
CreateDtmfSender, AudioTrackInterface*)
PROXY_METHOD2(bool, GetStats, StatsObserver*, MediaStreamTrackInterface*)
+ PROXY_METHOD3(bool, GetStats, StatsObserver*,
+ MediaStreamTrackInterface*,
+ StatsOutputLevel)
PROXY_METHOD2(talk_base::scoped_refptr<DataChannelInterface>,
CreateDataChannel, const std::string&, const DataChannelInit*)
PROXY_CONSTMETHOD0(const SessionDescriptionInterface*, local_description)
diff --git a/talk/app/webrtc/remoteaudiosource.cc b/talk/app/webrtc/remoteaudiosource.cc
new file mode 100644
index 0000000..1c275c7
--- /dev/null
+++ b/talk/app/webrtc/remoteaudiosource.cc
@@ -0,0 +1,72 @@
+/*
+ * libjingle
+ * Copyright 2014, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "talk/app/webrtc/remoteaudiosource.h"
+
+#include <algorithm>
+#include <functional>
+
+#include "talk/base/logging.h"
+
+namespace webrtc {
+
+talk_base::scoped_refptr<RemoteAudioSource> RemoteAudioSource::Create() {
+ return new talk_base::RefCountedObject<RemoteAudioSource>();
+}
+
+RemoteAudioSource::RemoteAudioSource() {
+}
+
+RemoteAudioSource::~RemoteAudioSource() {
+ ASSERT(audio_observers_.empty());
+}
+
+MediaSourceInterface::SourceState RemoteAudioSource::state() const {
+ return MediaSourceInterface::kLive;
+}
+
+void RemoteAudioSource::SetVolume(double volume) {
+ ASSERT(volume >= 0 && volume <= 10);
+ for (AudioObserverList::iterator it = audio_observers_.begin();
+ it != audio_observers_.end(); ++it) {
+ (*it)->OnSetVolume(volume);
+ }
+}
+
+void RemoteAudioSource::RegisterAudioObserver(AudioObserver* observer) {
+ ASSERT(observer != NULL);
+ ASSERT(std::find(audio_observers_.begin(), audio_observers_.end(),
+ observer) == audio_observers_.end());
+ audio_observers_.push_back(observer);
+}
+
+void RemoteAudioSource::UnregisterAudioObserver(AudioObserver* observer) {
+ ASSERT(observer != NULL);
+ audio_observers_.remove(observer);
+}
+
+} // namespace webrtc
diff --git a/talk/app/webrtc/remoteaudiosource.h b/talk/app/webrtc/remoteaudiosource.h
new file mode 100644
index 0000000..ed24214
--- /dev/null
+++ b/talk/app/webrtc/remoteaudiosource.h
@@ -0,0 +1,66 @@
+/*
+ * libjingle
+ * Copyright 2014, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TALK_APP_WEBRTC_REMOTEAUDIOSOURCE_H_
+#define TALK_APP_WEBRTC_REMOTEAUDIOSOURCE_H_
+
+#include <list>
+
+#include "talk/app/webrtc/mediastreaminterface.h"
+#include "talk/app/webrtc/notifier.h"
+
+namespace webrtc {
+
+using webrtc::AudioSourceInterface;
+
+// This class implements the audio source used by the remote audio track.
+class RemoteAudioSource : public Notifier<AudioSourceInterface> {
+ public:
+ // Creates an instance of RemoteAudioSource.
+ static talk_base::scoped_refptr<RemoteAudioSource> Create();
+
+ protected:
+ RemoteAudioSource();
+ virtual ~RemoteAudioSource();
+
+ private:
+ typedef std::list<AudioObserver*> AudioObserverList;
+
+ // MediaSourceInterface implementation.
+ virtual MediaSourceInterface::SourceState state() const OVERRIDE;
+
+ // AudioSourceInterface implementation.
+ virtual void SetVolume(double volume) OVERRIDE;
+ virtual void RegisterAudioObserver(AudioObserver* observer) OVERRIDE;
+ virtual void UnregisterAudioObserver(AudioObserver* observer) OVERRIDE;
+
+ AudioObserverList audio_observers_;
+};
+
+} // namespace webrtc
+
+#endif // TALK_APP_WEBRTC_REMOTEAUDIOSOURCE_H_
diff --git a/talk/app/webrtc/statscollector.cc b/talk/app/webrtc/statscollector.cc
index 2efc11b..a900bba 100644
--- a/talk/app/webrtc/statscollector.cc
+++ b/talk/app/webrtc/statscollector.cc
@@ -78,6 +78,7 @@
const char StatsReport::kStatsValueNameEncodeUsagePercent[] =
"googEncodeUsagePercent";
+const char StatsReport::kStatsValueNameExpandRate[] = "googExpandRate";
const char StatsReport::kStatsValueNameFingerprint[] = "googFingerprint";
const char StatsReport::kStatsValueNameFingerprintAlgorithm[] =
"googFingerprintAlgorithm";
@@ -121,12 +122,17 @@
"googLocalCertificateId";
const char StatsReport::kStatsValueNameNacksReceived[] = "googNacksReceived";
const char StatsReport::kStatsValueNameNacksSent[] = "googNacksSent";
-const char StatsReport::kStatsValueNameNetEqExpandRate[] =
- "googNetEqExpandRate";
const char StatsReport::kStatsValueNamePacketsReceived[] = "packetsReceived";
const char StatsReport::kStatsValueNamePacketsSent[] = "packetsSent";
const char StatsReport::kStatsValueNamePacketsLost[] = "packetsLost";
const char StatsReport::kStatsValueNameReadable[] = "googReadable";
+const char StatsReport::kStatsValueNameRecvPacketGroupArrivalTimeDebug[] =
+ "googReceivedPacketGroupArrivalTimeDebug";
+const char StatsReport::kStatsValueNameRecvPacketGroupPropagationDeltaDebug[] =
+ "googReceivedPacketGroupPropagationDeltaDebug";
+const char
+StatsReport::kStatsValueNameRecvPacketGroupPropagationDeltaSumDebug[] =
+ "googReceivedPacketGroupPropagationDeltaSumDebug";
const char StatsReport::kStatsValueNameRemoteAddress[] = "googRemoteAddress";
const char StatsReport::kStatsValueNameRemoteCandidateType[] =
"googRemoteCandidateType";
@@ -175,6 +181,20 @@
AddValue(name, talk_base::ToString<int64>(value));
}
+template <typename T>
+void StatsReport::AddValue(const std::string& name,
+ const std::vector<T>& value) {
+ std::ostringstream oss;
+ oss << "[";
+ for (size_t i = 0; i < value.size(); ++i) {
+ oss << talk_base::ToString<T>(value[i]);
+ if (i != value.size() - 1)
+ oss << ", ";
+ }
+ oss << "]";
+ AddValue(name, oss.str());
+}
+
void StatsReport::AddBoolean(const std::string& name, bool value) {
AddValue(name, value ? "true" : "false");
}
@@ -221,7 +241,7 @@
info.bytes_rcvd);
report->AddValue(StatsReport::kStatsValueNameJitterReceived,
info.jitter_ms);
- report->AddValue(StatsReport::kStatsValueNameNetEqExpandRate,
+ report->AddValue(StatsReport::kStatsValueNameExpandRate,
talk_base::ToString<float>(info.expand_rate));
report->AddValue(StatsReport::kStatsValueNamePacketsReceived,
info.packets_rcvd);
@@ -334,6 +354,7 @@
void ExtractStats(const cricket::BandwidthEstimationInfo& info,
double stats_gathering_started,
+ PeerConnectionInterface::StatsOutputLevel level,
StatsReport* report) {
report->id = StatsReport::kStatsReportVideoBweId;
report->type = StatsReport::kStatsReportTypeBwe;
@@ -358,6 +379,19 @@
info.transmit_bitrate);
report->AddValue(StatsReport::kStatsValueNameBucketDelay,
info.bucket_delay);
+ if (level >= PeerConnectionInterface::kStatsOutputLevelDebug) {
+ report->AddValue(
+ StatsReport::kStatsValueNameRecvPacketGroupPropagationDeltaSumDebug,
+ info.total_received_propagation_delta_ms);
+ if (info.recent_received_propagation_delta_ms.size() > 0) {
+ report->AddValue(
+ StatsReport::kStatsValueNameRecvPacketGroupPropagationDeltaDebug,
+ info.recent_received_propagation_delta_ms);
+ report->AddValue(
+ StatsReport::kStatsValueNameRecvPacketGroupArrivalTimeDebug,
+ info.recent_received_packet_group_arrival_time_ms);
+ }
+ }
}
void ExtractRemoteStats(const cricket::MediaSenderInfo& info,
@@ -399,7 +433,7 @@
ExtractRemoteStats(*it, report);
}
}
-};
+}
} // namespace
@@ -463,7 +497,8 @@
return true;
}
-void StatsCollector::UpdateStats() {
+void
+StatsCollector::UpdateStats(PeerConnectionInterface::StatsOutputLevel level) {
double time_now = GetTimeNow();
// Calls to UpdateStats() that occur less than kMinGatherStatsPeriod number of
// ms apart will be ignored.
@@ -476,7 +511,7 @@
if (session_) {
ExtractSessionInfo();
ExtractVoiceInfo();
- ExtractVideoInfo();
+ ExtractVideoInfo(level);
}
}
@@ -569,6 +604,14 @@
talk_base::scoped_ptr<talk_base::SSLFingerprint> ssl_fingerprint(
talk_base::SSLFingerprint::Create(digest_algorithm, cert));
+
+ // SSLFingerprint::Create can fail if the algorithm returned by
+ // SSLCertificate::GetSignatureDigestAlgorithm is not supported by the
+ // implementation of SSLCertificate::ComputeDigest. This currently happens
+ // with MD5- and SHA-224-signed certificates when linked to libNSS.
+ if (!ssl_fingerprint)
+ return std::string();
+
std::string fingerprint = ssl_fingerprint->GetRfc4572Fingerprint();
talk_base::Buffer der_buffer;
@@ -737,12 +780,17 @@
ExtractStatsFromList(voice_info.senders, transport_id, this);
}
-void StatsCollector::ExtractVideoInfo() {
+void StatsCollector::ExtractVideoInfo(
+ PeerConnectionInterface::StatsOutputLevel level) {
if (!session_->video_channel()) {
return;
}
+ cricket::StatsOptions options;
+ options.include_received_propagation_stats =
+ (level >= PeerConnectionInterface::kStatsOutputLevelDebug) ?
+ true : false;
cricket::VideoMediaInfo video_info;
- if (!session_->video_channel()->GetStats(&video_info)) {
+ if (!session_->video_channel()->GetStats(options, &video_info)) {
LOG(LS_ERROR) << "Failed to get video channel stats.";
return;
}
@@ -760,7 +808,7 @@
} else {
StatsReport* report = &reports_[StatsReport::kStatsReportVideoBweId];
ExtractStats(
- video_info.bw_estimations[0], stats_gathering_started_, report);
+ video_info.bw_estimations[0], stats_gathering_started_, level, report);
}
}
diff --git a/talk/app/webrtc/statscollector.h b/talk/app/webrtc/statscollector.h
index 01da059..6256d77 100644
--- a/talk/app/webrtc/statscollector.h
+++ b/talk/app/webrtc/statscollector.h
@@ -35,6 +35,7 @@
#include <map>
#include "talk/app/webrtc/mediastreaminterface.h"
+#include "talk/app/webrtc/peerconnectioninterface.h"
#include "talk/app/webrtc/statstypes.h"
#include "talk/app/webrtc/webrtcsession.h"
@@ -57,13 +58,14 @@
void AddStream(MediaStreamInterface* stream);
// Gather statistics from the session and store them for future use.
- void UpdateStats();
+ void UpdateStats(PeerConnectionInterface::StatsOutputLevel level);
// Gets a StatsReports of the last collected stats. Note that UpdateStats must
// be called before this function to get the most recent stats. |selector| is
// a track label or empty string. The most recent reports are stored in
// |reports|.
- bool GetStats(MediaStreamTrackInterface* track, StatsReports* reports);
+ bool GetStats(MediaStreamTrackInterface* track,
+ StatsReports* reports);
// Prepare an SSRC report for the given ssrc. Used internally
// in the ExtractStatsFromList template.
@@ -87,7 +89,7 @@
void ExtractSessionInfo();
void ExtractVoiceInfo();
- void ExtractVideoInfo();
+ void ExtractVideoInfo(PeerConnectionInterface::StatsOutputLevel level);
double GetTimeNow();
void BuildSsrcToTransportId();
WebRtcSession* session() { return session_; }
diff --git a/talk/app/webrtc/statscollector_unittest.cc b/talk/app/webrtc/statscollector_unittest.cc
index 1adcb0e..a7cda16 100644
--- a/talk/app/webrtc/statscollector_unittest.cc
+++ b/talk/app/webrtc/statscollector_unittest.cc
@@ -39,11 +39,14 @@
#include "talk/session/media/channelmanager.h"
#include "testing/base/public/gmock.h"
+using cricket::StatsOptions;
using testing::_;
using testing::DoAll;
+using testing::Field;
using testing::Return;
using testing::ReturnNull;
using testing::SetArgPointee;
+using webrtc::PeerConnectionInterface;
namespace cricket {
@@ -80,7 +83,7 @@
: cricket::FakeVideoMediaChannel(NULL) {
}
// MOCK_METHOD0(transport_channel, cricket::TransportChannel*());
- MOCK_METHOD1(GetStats, bool(cricket::VideoMediaInfo*));
+ MOCK_METHOD2(GetStats, bool(const StatsOptions&, cricket::VideoMediaInfo*));
};
bool GetValue(const webrtc::StatsReport* report,
@@ -289,7 +292,7 @@
EXPECT_CALL(session_, video_channel())
.WillRepeatedly(ReturnNull());
- stats.UpdateStats();
+ stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
stats.GetStats(NULL, &reports);
@@ -302,16 +305,24 @@
webrtc::StatsReport::kStatsReportTypeComponent,
reports,
webrtc::StatsReport::kStatsValueNameLocalCertificateId);
- EXPECT_NE(kNotFound, local_certificate_id);
- CheckCertChainReports(reports, local_ders, local_certificate_id);
+ if (local_ders.size() > 0) {
+ EXPECT_NE(kNotFound, local_certificate_id);
+ CheckCertChainReports(reports, local_ders, local_certificate_id);
+ } else {
+ EXPECT_EQ(kNotFound, local_certificate_id);
+ }
// Check remote certificate chain.
std::string remote_certificate_id = ExtractStatsValue(
webrtc::StatsReport::kStatsReportTypeComponent,
reports,
webrtc::StatsReport::kStatsValueNameRemoteCertificateId);
- EXPECT_NE(kNotFound, remote_certificate_id);
- CheckCertChainReports(reports, remote_ders, remote_certificate_id);
+ if (remote_ders.size() > 0) {
+ EXPECT_NE(kNotFound, remote_certificate_id);
+ CheckCertChainReports(reports, remote_ders, remote_certificate_id);
+ } else {
+ EXPECT_EQ(kNotFound, remote_certificate_id);
+ }
}
cricket::FakeMediaEngine* media_engine_;
@@ -347,10 +358,10 @@
EXPECT_CALL(session_, video_channel())
.WillRepeatedly(Return(&video_channel));
- EXPECT_CALL(*media_channel, GetStats(_))
- .WillOnce(DoAll(SetArgPointee<0>(stats_read),
+ EXPECT_CALL(*media_channel, GetStats(_, _))
+ .WillOnce(DoAll(SetArgPointee<1>(stats_read),
Return(true)));
- stats.UpdateStats();
+ stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
stats.GetStats(NULL, &reports);
std::string result = ExtractSsrcStatsValue(reports, "bytesSent");
EXPECT_EQ(kBytesSentString, result);
@@ -386,11 +397,11 @@
EXPECT_CALL(session_, video_channel())
.WillRepeatedly(Return(&video_channel));
- EXPECT_CALL(*media_channel, GetStats(_))
- .WillOnce(DoAll(SetArgPointee<0>(stats_read),
+ EXPECT_CALL(*media_channel, GetStats(_, _))
+ .WillOnce(DoAll(SetArgPointee<1>(stats_read),
Return(true)));
- stats.UpdateStats();
+ stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
stats.GetStats(NULL, &reports);
std::string result = ExtractSsrcStatsValue(reports, "bytesSent");
EXPECT_EQ(kBytesSentString, result);
@@ -406,7 +417,7 @@
stats.set_session(&session_);
EXPECT_CALL(session_, video_channel())
.WillRepeatedly(ReturnNull());
- stats.UpdateStats();
+ stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
stats.GetStats(NULL, &reports);
const webrtc::StatsReport* session_report = FindNthReportByType(
reports, webrtc::StatsReport::kStatsReportTypeSession, 1);
@@ -421,8 +432,8 @@
stats.set_session(&session_);
EXPECT_CALL(session_, video_channel())
.WillRepeatedly(ReturnNull());
- stats.UpdateStats();
- stats.UpdateStats();
+ stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
+ stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
stats.GetStats(NULL, &reports);
const webrtc::StatsReport* session_report = FindNthReportByType(
reports, webrtc::StatsReport::kStatsReportTypeSession, 1);
@@ -485,11 +496,11 @@
EXPECT_CALL(session_, video_channel())
.WillRepeatedly(Return(&video_channel));
- EXPECT_CALL(*media_channel, GetStats(_))
- .WillOnce(DoAll(SetArgPointee<0>(stats_read),
+ EXPECT_CALL(*media_channel, GetStats(_, _))
+ .WillOnce(DoAll(SetArgPointee<1>(stats_read),
Return(true)));
- stats.UpdateStats();
+ stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
stats.GetStats(NULL, &reports);
// |reports| should contain at least one session report, one track report,
// and one ssrc report.
@@ -543,8 +554,8 @@
EXPECT_CALL(session_, video_channel())
.WillRepeatedly(Return(&video_channel));
- EXPECT_CALL(*media_channel, GetStats(_))
- .WillRepeatedly(DoAll(SetArgPointee<0>(stats_read),
+ EXPECT_CALL(*media_channel, GetStats(_, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(stats_read),
Return(true)));
InitSessionStats(kVcName);
@@ -552,7 +563,7 @@
.WillRepeatedly(DoAll(SetArgPointee<0>(session_stats_),
Return(true)));
- stats.UpdateStats();
+ stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
stats.GetStats(NULL, &reports);
std::string transport_id = ExtractStatsValue(
webrtc::StatsReport::kStatsReportTypeSsrc,
@@ -581,7 +592,7 @@
EXPECT_CALL(session_, video_channel())
.WillRepeatedly(ReturnNull());
- stats.UpdateStats();
+ stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
webrtc::StatsReports reports;
stats.GetStats(NULL, &reports);
const webrtc::StatsReport* remote_report = FindNthReportByType(reports,
@@ -624,11 +635,11 @@
EXPECT_CALL(session_, video_channel())
.WillRepeatedly(Return(&video_channel));
- EXPECT_CALL(*media_channel, GetStats(_))
- .WillRepeatedly(DoAll(SetArgPointee<0>(stats_read),
+ EXPECT_CALL(*media_channel, GetStats(_, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(stats_read),
Return(true)));
- stats.UpdateStats();
+ stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
stats.GetStats(NULL, &reports);
const webrtc::StatsReport* remote_report = FindNthReportByType(reports,
webrtc::StatsReport::kStatsReportTypeRemoteSsrc, 1);
@@ -703,7 +714,7 @@
EXPECT_CALL(session_, video_channel())
.WillRepeatedly(ReturnNull());
- stats.UpdateStats();
+ stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
stats.GetStats(NULL, &reports);
// Check that the local certificate is absent.
@@ -756,7 +767,7 @@
EXPECT_CALL(session_, video_channel())
.WillRepeatedly(ReturnNull());
- stats.UpdateStats();
+ stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
stats.GetStats(NULL, &reports);
// Check that the local certificate is absent.
@@ -774,4 +785,63 @@
ASSERT_EQ(kNotFound, remote_certificate_id);
}
+// This test verifies that a remote certificate with an unsupported digest
+// algorithm is correctly ignored.
+TEST_F(StatsCollectorTest, UnsupportedDigestIgnored) {
+ // Build a local certificate.
+ std::string local_der = "This is the local der.";
+ talk_base::FakeSSLCertificate local_cert(DerToPem(local_der));
+
+ // Build a remote certificate with an unsupported digest algorithm.
+ std::string remote_der = "This is somebody else's der.";
+ talk_base::FakeSSLCertificate remote_cert(DerToPem(remote_der));
+ remote_cert.set_digest_algorithm("foobar");
+
+ TestCertificateReports(local_cert, std::vector<std::string>(1, local_der),
+ remote_cert, std::vector<std::string>());
+}
+
+// Verifies the correct optons are passed to the VideoMediaChannel when using
+// verbose output level.
+TEST_F(StatsCollectorTest, StatsOutputLevelVerbose) {
+ webrtc::StatsCollector stats; // Implementation under test.
+ MockVideoMediaChannel* media_channel = new MockVideoMediaChannel;
+ cricket::VideoChannel video_channel(talk_base::Thread::Current(),
+ media_engine_, media_channel, &session_, "", false, NULL);
+ stats.set_session(&session_);
+
+ webrtc::StatsReports reports; // returned values.
+ cricket::VideoMediaInfo stats_read;
+ cricket::BandwidthEstimationInfo bwe;
+ bwe.total_received_propagation_delta_ms = 10;
+ bwe.recent_received_propagation_delta_ms.push_back(100);
+ bwe.recent_received_propagation_delta_ms.push_back(200);
+ bwe.recent_received_packet_group_arrival_time_ms.push_back(1000);
+ bwe.recent_received_packet_group_arrival_time_ms.push_back(2000);
+ stats_read.bw_estimations.push_back(bwe);
+
+ EXPECT_CALL(session_, video_channel())
+ .WillRepeatedly(Return(&video_channel));
+
+ StatsOptions options;
+ options.include_received_propagation_stats = true;
+ EXPECT_CALL(*media_channel, GetStats(
+ Field(&StatsOptions::include_received_propagation_stats, true),
+ _))
+ .WillOnce(DoAll(SetArgPointee<1>(stats_read),
+ Return(true)));
+
+ stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelDebug);
+ stats.GetStats(NULL, &reports);
+ std::string result = ExtractBweStatsValue(
+ reports, "googReceivedPacketGroupPropagationDeltaSumDebug");
+ EXPECT_EQ("10", result);
+ result = ExtractBweStatsValue(
+ reports, "googReceivedPacketGroupPropagationDeltaDebug");
+ EXPECT_EQ("[100, 200]", result);
+ result = ExtractBweStatsValue(
+ reports, "googReceivedPacketGroupArrivalTimeDebug");
+ EXPECT_EQ("[1000, 2000]", result);
+}
+
} // namespace
diff --git a/talk/app/webrtc/statstypes.h b/talk/app/webrtc/statstypes.h
index 9110da3..39441e2 100644
--- a/talk/app/webrtc/statstypes.h
+++ b/talk/app/webrtc/statstypes.h
@@ -53,6 +53,8 @@
void AddValue(const std::string& name, const std::string& value);
void AddValue(const std::string& name, int64 value);
+ template <typename T>
+ void AddValue(const std::string& name, const std::vector<T>& value);
void AddBoolean(const std::string& name, bool value);
double timestamp; // Time since 1970-01-01T00:00:00Z in milliseconds.
@@ -141,6 +143,7 @@
static const char kStatsValueNameEchoDelayStdDev[];
static const char kStatsValueNameEchoReturnLoss[];
static const char kStatsValueNameEchoReturnLossEnhancement[];
+ static const char kStatsValueNameExpandRate[];
static const char kStatsValueNameFirsReceived[];
static const char kStatsValueNameFirsSent[];
static const char kStatsValueNameFrameHeightInput[];
@@ -164,7 +167,6 @@
static const char kStatsValueNameJitterReceived[];
static const char kStatsValueNameNacksReceived[];
static const char kStatsValueNameNacksSent[];
- static const char kStatsValueNameNetEqExpandRate[];
static const char kStatsValueNameRtt[];
static const char kStatsValueNameAvailableSendBandwidth[];
static const char kStatsValueNameAvailableReceiveBandwidth[];
@@ -189,6 +191,9 @@
static const char kStatsValueNameRemoteCertificateId[];
static const char kStatsValueNameLocalCandidateType[];
static const char kStatsValueNameRemoteCandidateType[];
+ static const char kStatsValueNameRecvPacketGroupArrivalTimeDebug[];
+ static const char kStatsValueNameRecvPacketGroupPropagationDeltaDebug[];
+ static const char kStatsValueNameRecvPacketGroupPropagationDeltaSumDebug[];
};
typedef std::vector<StatsReport> StatsReports;
diff --git a/talk/app/webrtc/webrtc.scons b/talk/app/webrtc/webrtc.scons
index 9b1af3c..dd4bea0 100644
--- a/talk/app/webrtc/webrtc.scons
+++ b/talk/app/webrtc/webrtc.scons
@@ -31,6 +31,7 @@
'peerconnectionfactory.cc',
'peerconnection.cc',
'portallocatorfactory.cc',
+ 'remoteaudiosource.cc',
'roapmessages.cc',
'roapsession.cc',
'roapsignaling.cc',
diff --git a/talk/app/webrtc/webrtcsession.cc b/talk/app/webrtc/webrtcsession.cc
index 59d7270..ef6af49 100644
--- a/talk/app/webrtc/webrtcsession.cc
+++ b/talk/app/webrtc/webrtcsession.cc
@@ -866,6 +866,18 @@
voice_channel_->SetChannelOptions(options);
}
+void WebRtcSession::SetAudioPlayoutVolume(uint32 ssrc, double volume) {
+ ASSERT(signaling_thread()->IsCurrent());
+ ASSERT(volume >= 0 && volume <= 10);
+ if (!voice_channel_) {
+ LOG(LS_ERROR) << "SetAudioPlayoutVolume: No audio channel exists.";
+ return;
+ }
+
+ if (!voice_channel_->SetOutputScaling(ssrc, volume, volume))
+ ASSERT(false);
+}
+
bool WebRtcSession::SetCaptureDevice(uint32 ssrc,
cricket::VideoCapturer* camera) {
ASSERT(signaling_thread()->IsCurrent());
diff --git a/talk/app/webrtc/webrtcsession.h b/talk/app/webrtc/webrtcsession.h
index 384ac47..628aa1e 100644
--- a/talk/app/webrtc/webrtcsession.h
+++ b/talk/app/webrtc/webrtcsession.h
@@ -165,6 +165,7 @@
virtual void SetAudioSend(uint32 ssrc, bool enable,
const cricket::AudioOptions& options,
cricket::AudioRenderer* renderer) OVERRIDE;
+ virtual void SetAudioPlayoutVolume(uint32 ssrc, double volume) OVERRIDE;
// Implements VideoMediaProviderInterface.
virtual bool SetCaptureDevice(uint32 ssrc,