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
This commit is contained in:
wu@webrtc.org 2014-02-13 23:18:49 +00:00
parent 0de29504ab
commit b9a088b920
54 changed files with 834 additions and 225 deletions

View File

@ -106,6 +106,8 @@ void LocalAudioTrackHandler::Stop() {
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 @@ RemoteAudioTrackHandler::RemoteAudioTrackHandler(
: 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 @@ void RemoteAudioTrackHandler::OnEnabledChanged() {
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,

View File

@ -118,7 +118,8 @@ class LocalAudioTrackHandler : public TrackHandler {
// 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 @@ class RemoteAudioTrackHandler : public TrackHandler {
virtual void OnEnabledChanged() OVERRIDE;
private:
// AudioSourceInterface::AudioObserver implementation.
virtual void OnSetVolume(double volume) OVERRIDE;
AudioTrackInterface* audio_track_;
AudioProviderInterface* provider_;
};

View File

@ -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 @@ class MockAudioProvider : public AudioProviderInterface {
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 @@ class MediaStreamHandlerTest : public testing::Test {
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 @@ class MediaStreamHandlerTest : public testing::Test {
}
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 @@ TEST_F(MediaStreamHandlerTest, RemoteVideoTrackDisable) {
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

View File

@ -142,9 +142,24 @@ class VideoTrackInterface : public MediaStreamTrackInterface {
// 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.

View File

@ -53,6 +53,10 @@ class AudioProviderInterface {
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() {}
};

View File

@ -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 @@ class RemoteMediaStreamFactory {
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,

View File

@ -459,13 +459,19 @@ talk_base::scoped_refptr<DtmfSenderInterface> PeerConnection::CreateDtmfSender(
}
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 @@ void PeerConnection::SetLocalDescription(
}
// 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 @@ void PeerConnection::SetRemoteDescription(
}
// 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 @@ const SessionDescriptionInterface* PeerConnection::remote_description() const {
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();
}

View File

@ -76,6 +76,9 @@ class PeerConnection : public PeerConnectionInterface,
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();

View File

@ -166,6 +166,15 @@ class PeerConnectionInterface : public talk_base::RefCountInterface {
};
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 @@ class PeerConnectionInterface : public talk_base::RefCountInterface {
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;

View File

@ -45,6 +45,9 @@ BEGIN_PROXY_MAP(PeerConnection)
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)

View File

@ -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

View File

@ -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_

View File

@ -78,6 +78,7 @@ const char StatsReport::kStatsValueNameEchoReturnLossEnhancement[] =
const char StatsReport::kStatsValueNameEncodeUsagePercent[] =
"googEncodeUsagePercent";
const char StatsReport::kStatsValueNameExpandRate[] = "googExpandRate";
const char StatsReport::kStatsValueNameFingerprint[] = "googFingerprint";
const char StatsReport::kStatsValueNameFingerprintAlgorithm[] =
"googFingerprintAlgorithm";
@ -121,12 +122,17 @@ const char StatsReport::kStatsValueNameLocalCertificateId[] =
"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 @@ void StatsReport::AddValue(const std::string& name, int64 value) {
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 @@ void ExtractStats(const cricket::VoiceReceiverInfo& info, StatsReport* report) {
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::VideoSenderInfo& info, StatsReport* report) {
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 @@ void ExtractStats(const cricket::BandwidthEstimationInfo& info,
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 @@ void ExtractStatsFromList(const std::vector<T>& data,
ExtractRemoteStats(*it, report);
}
}
};
}
} // namespace
@ -463,7 +497,8 @@ bool StatsCollector::GetStats(MediaStreamTrackInterface* track,
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 @@ void StatsCollector::UpdateStats() {
if (session_) {
ExtractSessionInfo();
ExtractVoiceInfo();
ExtractVideoInfo();
ExtractVideoInfo(level);
}
}
@ -569,6 +604,14 @@ std::string StatsCollector::AddOneCertificateReport(
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 @@ void StatsCollector::ExtractVoiceInfo() {
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 @@ void StatsCollector::ExtractVideoInfo() {
} 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);
}
}

View File

@ -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 @@ class StatsCollector {
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 @@ class StatsCollector {
void ExtractSessionInfo();
void ExtractVoiceInfo();
void ExtractVideoInfo();
void ExtractVideoInfo(PeerConnectionInterface::StatsOutputLevel level);
double GetTimeNow();
void BuildSsrcToTransportId();
WebRtcSession* session() { return session_; }

View File

@ -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 @@ class MockVideoMediaChannel : public cricket::FakeVideoMediaChannel {
: 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 @@ class StatsCollectorTest : public testing::Test {
EXPECT_CALL(session_, video_channel())
.WillRepeatedly(ReturnNull());
stats.UpdateStats();
stats.UpdateStats(PeerConnectionInterface::kStatsOutputLevelStandard);
stats.GetStats(NULL, &reports);
@ -302,16 +305,24 @@ class StatsCollectorTest : public testing::Test {
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 @@ TEST_F(StatsCollectorTest, BytesCounterHandles64Bits) {
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 @@ TEST_F(StatsCollectorTest, BandwidthEstimationInfoIsReported) {
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 @@ TEST_F(StatsCollectorTest, SessionObjectExists) {
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 @@ TEST_F(StatsCollectorTest, OnlyOneSessionObjectExists) {
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 @@ TEST_F(StatsCollectorTest, TrackAndSsrcObjectExistAfterUpdateSsrcStats) {
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 @@ TEST_F(StatsCollectorTest, TransportObjectLinkedFromSsrcObject) {
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 @@ TEST_F(StatsCollectorTest, TransportObjectLinkedFromSsrcObject) {
.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 @@ TEST_F(StatsCollectorTest, RemoteSsrcInfoIsAbsent) {
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 @@ TEST_F(StatsCollectorTest, RemoteSsrcInfoIsPresent) {
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 @@ TEST_F(StatsCollectorTest, NoTransport) {
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 @@ TEST_F(StatsCollectorTest, NoCertificates) {
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 @@ TEST_F(StatsCollectorTest, NoCertificates) {
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

View File

@ -53,6 +53,8 @@ class StatsReport {
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 @@ class StatsReport {
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 @@ class StatsReport {
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 @@ class StatsReport {
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;

View File

@ -31,6 +31,7 @@ if env.Bit('have_webrtc_voice') and env.Bit('have_webrtc_video'):
'peerconnectionfactory.cc',
'peerconnection.cc',
'portallocatorfactory.cc',
'remoteaudiosource.cc',
'roapmessages.cc',
'roapsession.cc',
'roapsignaling.cc',

View File

@ -866,6 +866,18 @@ void WebRtcSession::SetAudioSend(uint32 ssrc, bool enable,
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());

View File

@ -165,6 +165,7 @@ class WebRtcSession : public cricket::BaseSession,
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,

View File

@ -28,6 +28,7 @@
#ifndef TALK_BASE_ASYNCPACKETSOCKET_H_
#define TALK_BASE_ASYNCPACKETSOCKET_H_
#include "talk/base/buffer.h"
#include "talk/base/dscp.h"
#include "talk/base/sigslot.h"
#include "talk/base/socket.h"
@ -35,6 +36,29 @@
namespace talk_base {
// This structure holds the info needed to update the packet send time header
// extension, including the information needed to update the authentication tag
// after changing the value.
struct PacketTimeUpdateParams {
PacketTimeUpdateParams()
: rtp_sendtime_extension_id(-1), srtp_auth_tag_len(-1),
srtp_packet_index(-1) {
}
int rtp_sendtime_extension_id; // extension header id present in packet.
Buffer srtp_auth_key; // Authentication key.
int srtp_auth_tag_len; // Authentication tag length.
int64 srtp_packet_index; // Required for Rtp Packet authentication.
};
// This structure holds meta information for the packet which is about to send
// over network.
struct PacketOptions {
PacketOptions() : dscp(DSCP_NO_CHANGE) {}
DiffServCodePoint dscp;
PacketTimeUpdateParams packet_time_params;
};
// This structure will have the information about when packet is actually
// received by socket.
struct PacketTime {

View File

@ -109,10 +109,12 @@ class FakeNetworkManager : public NetworkManagerBase,
prefix_length = kFakeIPv6NetworkPrefixLength;
}
IPAddress prefix = TruncateIP(it->ipaddr(), prefix_length);
std::string key = MakeNetworkKey(it->hostname(), prefix, prefix_length);
scoped_ptr<Network> net(new Network(it->hostname(),
it->hostname(),
prefix,
prefix_length));
prefix_length,
key));
net->AddIP(it->ipaddr());
networks.push_back(net.release());
}

View File

@ -38,9 +38,12 @@ namespace talk_base {
class FakeSSLCertificate : public talk_base::SSLCertificate {
public:
explicit FakeSSLCertificate(const std::string& data) : data_(data) {}
// SHA-1 is the default digest algorithm because it is available in all build
// configurations used for unit testing.
explicit FakeSSLCertificate(const std::string& data)
: data_(data), digest_algorithm_(DIGEST_SHA_1) {}
explicit FakeSSLCertificate(const std::vector<std::string>& certs)
: data_(certs.front()) {
: data_(certs.front()), digest_algorithm_(DIGEST_SHA_1) {
std::vector<std::string>::const_iterator it;
// Skip certs[0].
for (it = certs.begin() + 1; it != certs.end(); ++it) {
@ -58,10 +61,11 @@ class FakeSSLCertificate : public talk_base::SSLCertificate {
VERIFY(SSLIdentity::PemToDer(kPemTypeCertificate, data_, &der_string));
der_buffer->SetData(der_string.c_str(), der_string.size());
}
void set_digest_algorithm(const std::string& algorithm) {
digest_algorithm_ = algorithm;
}
virtual bool GetSignatureDigestAlgorithm(std::string* algorithm) const {
// SHA-1 is chosen because it is available in all build configurations
// used for unit testing.
*algorithm = DIGEST_SHA_1;
*algorithm = digest_algorithm_;
return true;
}
virtual bool ComputeDigest(const std::string &algorithm,
@ -86,6 +90,7 @@ class FakeSSLCertificate : public talk_base::SSLCertificate {
}
std::string data_;
std::vector<FakeSSLCertificate> certs_;
std::string digest_algorithm_;
};
class FakeSSLIdentity : public talk_base::SSLIdentity {

View File

@ -54,6 +54,8 @@ class MacCocoaSocketServer : public MacBaseSocketServer {
private:
MacCocoaSocketServerHelper* helper_;
NSTimer* timer_; // Weak.
// The count of how many times we're inside the NSApplication main loop.
int run_count_;
DISALLOW_EVIL_CONSTRUCTORS(MacCocoaSocketServer);
};

View File

@ -53,6 +53,25 @@
- (void)timerFired:(NSTimer*)timer {
socketServer_->WakeUp();
}
- (void)breakMainloop {
[NSApp stop:self];
// NSApp stop only exits after finishing processing of the
// current event. Since we're potentially in a timer callback
// and not an NSEvent handler, we need to trigger a dummy one
// and turn the loop over. We may be able to skip this if we're
// on the ss' thread and not inside the app loop already.
NSEvent* event = [NSEvent otherEventWithType:NSApplicationDefined
location:NSMakePoint(0,0)
modifierFlags:0
timestamp:0
windowNumber:0
context:nil
subtype:0
data1:0
data2:0];
[NSApp postEvent:event atStart:NO];
}
@end
namespace talk_base {
@ -60,6 +79,7 @@ namespace talk_base {
MacCocoaSocketServer::MacCocoaSocketServer() {
helper_ = [[MacCocoaSocketServerHelper alloc] initWithSocketServer:this];
timer_ = nil;
run_count_ = 0;
// Initialize the shared NSApplication
[NSApplication sharedApplication];
@ -71,12 +91,19 @@ MacCocoaSocketServer::~MacCocoaSocketServer() {
[helper_ release];
}
// ::Wait is reentrant, for example when blocking on another thread while
// responding to I/O. Calls to [NSApp] MUST be made from the main thread
// only!
bool MacCocoaSocketServer::Wait(int cms, bool process_io) {
talk_base::ScopedAutoreleasePool pool;
if (!process_io && cms == 0) {
// No op.
return true;
}
if ([NSApp isRunning]) {
// Only allow reentrant waiting if we're in a blocking send.
ASSERT(!process_io && cms == kForever);
}
if (!process_io) {
// No way to listen to common modes and not get socket events, unless
@ -96,7 +123,9 @@ bool MacCocoaSocketServer::Wait(int cms, bool process_io) {
}
// Run until WakeUp is called, which will call stop and exit this loop.
run_count_++;
[NSApp run];
run_count_--;
if (!process_io) {
// Reenable them. Hopefully this won't cause spurious callbacks or
@ -107,28 +136,22 @@ bool MacCocoaSocketServer::Wait(int cms, bool process_io) {
return true;
}
// Can be called from any thread. Post a message back to the main thread to
// break out of the NSApp loop.
void MacCocoaSocketServer::WakeUp() {
// Timer has either fired or shortcutted.
[timer_ invalidate];
[timer_ release];
timer_ = nil;
[NSApp stop:nil];
if (timer_ != nil) {
[timer_ invalidate];
[timer_ release];
timer_ = nil;
}
// NSApp stop only exits after finishing processing of the
// current event. Since we're potentially in a timer callback
// and not an NSEvent handler, we need to trigger a dummy one
// and turn the loop over. We may be able to skip this if we're
// on the ss' thread and not inside the app loop already.
NSEvent *event = [NSEvent otherEventWithType:NSApplicationDefined
location:NSMakePoint(0,0)
modifierFlags:0
timestamp:0
windowNumber:0
context:nil
subtype:1
data1:1
data2:1];
[NSApp postEvent:event atStart:YES];
// [NSApp isRunning] returns unexpected results when called from another
// thread. Maintain our own count of how many times to break the main loop.
if (run_count_ > 0) {
[helper_ performSelectorOnMainThread:@selector(breakMainloop)
withObject:nil
waitUntilDone:false];
}
}
} // namespace talk_base

View File

@ -79,16 +79,7 @@ const uint32 kSignalNetworksMessage = 2;
// Fetch list of networks every two seconds.
const int kNetworksUpdateIntervalMs = 2000;
// Makes a string key for this network. Used in the network manager's maps.
// Network objects are keyed on interface name, network prefix and the
// length of that prefix.
std::string MakeNetworkKey(const std::string& name, const IPAddress& prefix,
int prefix_length) {
std::ostringstream ost;
ost << name << "%" << prefix.ToString() << "/" << prefix_length;
return ost.str();
}
const int kHighestNetworkPreference = 127;
bool CompareNetworks(const Network* a, const Network* b) {
if (a->prefix_length() == b->prefix_length()) {
@ -99,9 +90,36 @@ bool CompareNetworks(const Network* a, const Network* b) {
return a->name() < b->name();
}
bool SortNetworks(const Network* a, const Network* b) {
// Network types will be preferred above everything else while sorting
// Networks.
// Networks are sorted first by type.
if (a->type() != b->type()) {
return a->type() < b->type();
}
// After type, networks are sorted by IP address precedence values
// from RFC 3484-bis
if (IPAddressPrecedence(a->ip()) != IPAddressPrecedence(b->ip())) {
return IPAddressPrecedence(a->ip()) > IPAddressPrecedence(b->ip());
}
// TODO(mallinath) - Add VPN and Link speed conditions while sorting.
// Networks are sorted last by key.
return a->key() > b->key();
}
} // namespace
std::string MakeNetworkKey(const std::string& name, const IPAddress& prefix,
int prefix_length) {
std::ostringstream ost;
ost << name << "%" << prefix.ToString() << "/" << prefix_length;
return ost.str();
}
NetworkManager::NetworkManager() {
}
@ -180,6 +198,29 @@ void NetworkManagerBase::MergeNetworkList(const NetworkList& new_networks,
}
}
networks_ = merged_list;
// If the network lists changes, we resort it.
if (changed) {
std::sort(networks_.begin(), networks_.end(), SortNetworks);
// Now network interfaces are sorted, we should set the preference value
// for each of the interfaces we are planning to use.
// Preference order of network interfaces might have changed from previous
// sorting due to addition of higher preference network interface.
// Since we have already sorted the network interfaces based on our
// requirements, we will just assign a preference value starting with 127,
// in decreasing order.
int pref = kHighestNetworkPreference;
for (NetworkList::const_iterator iter = networks_.begin();
iter != networks_.end(); ++iter) {
(*iter)->set_preference(pref);
if (pref > 0) {
--pref;
} else {
LOG(LS_ERROR) << "Too many network interfaces to handle!";
break;
}
}
}
}
BasicNetworkManager::BasicNetworkManager()
@ -240,6 +281,7 @@ void BasicNetworkManager::ConvertIfAddrs(struct ifaddrs* interfaces,
continue;
}
}
int prefix_length = CountIPMaskBits(mask);
prefix = TruncateIP(ip, prefix_length);
std::string key = MakeNetworkKey(std::string(cursor->ifa_name),
@ -249,7 +291,8 @@ void BasicNetworkManager::ConvertIfAddrs(struct ifaddrs* interfaces,
scoped_ptr<Network> network(new Network(cursor->ifa_name,
cursor->ifa_name,
prefix,
prefix_length));
prefix_length,
key));
network->set_scope_id(scope_id);
network->AddIP(ip);
bool ignored = ((cursor->ifa_flags & IFF_LOOPBACK) ||
@ -386,6 +429,7 @@ bool BasicNetworkManager::CreateNetworks(bool include_ignored,
continue;
}
}
IPAddress prefix;
int prefix_length = GetPrefix(prefixlist, ip, &prefix);
std::string key = MakeNetworkKey(name, prefix, prefix_length);
@ -394,7 +438,8 @@ bool BasicNetworkManager::CreateNetworks(bool include_ignored,
scoped_ptr<Network> network(new Network(name,
description,
prefix,
prefix_length));
prefix_length,
key));
network->set_scope_id(scope_id);
network->AddIP(ip);
bool ignore = ((adapter_addrs->IfType == IF_TYPE_SOFTWARE_LOOPBACK) ||
@ -561,12 +606,21 @@ void BasicNetworkManager::DumpNetworks(bool include_ignored) {
}
}
Network::Network(const std::string& name, const std::string& desc,
const IPAddress& prefix, int prefix_length,
const std::string& key)
: name_(name), description_(desc), prefix_(prefix),
prefix_length_(prefix_length), key_(key), scope_id_(0), ignored_(false),
uniform_numerator_(0), uniform_denominator_(0), exponential_numerator_(0),
exponential_denominator_(0), type_(ADAPTER_TYPE_UNKNOWN), preference_(0) {
}
Network::Network(const std::string& name, const std::string& desc,
const IPAddress& prefix, int prefix_length)
: name_(name), description_(desc), prefix_(prefix),
prefix_length_(prefix_length), scope_id_(0), ignored_(false),
uniform_numerator_(0), uniform_denominator_(0), exponential_numerator_(0),
exponential_denominator_(0) {
exponential_denominator_(0), type_(ADAPTER_TYPE_UNKNOWN), preference_(0) {
}
std::string Network::ToString() const {
@ -600,4 +654,5 @@ bool Network::SetIPs(const std::vector<IPAddress>& ips, bool changed) {
ips_ = ips;
return changed;
}
} // namespace talk_base

View File

@ -45,9 +45,23 @@ struct ifaddrs;
namespace talk_base {
class Network;
class NetworkSession;
class Thread;
enum AdapterType {
// This enum resembles the one in Chromium net::ConnectionType.
ADAPTER_TYPE_UNKNOWN = 0,
ADAPTER_TYPE_ETHERNET = 1,
ADAPTER_TYPE_WIFI = 2,
ADAPTER_TYPE_CELLULAR = 3,
ADAPTER_TYPE_VPN = 4
};
// Makes a string key for this network. Used in the network manager's maps.
// Network objects are keyed on interface name, network prefix and the
// length of that prefix.
std::string MakeNetworkKey(const std::string& name, const IPAddress& prefix,
int prefix_length);
// Generic network manager interface. It provides list of local
// networks.
class NetworkManager {
@ -168,7 +182,12 @@ class BasicNetworkManager : public NetworkManagerBase,
// Represents a Unix-type network interface, with a name and single address.
class Network {
public:
Network() : prefix_(INADDR_ANY), scope_id_(0) {}
Network() : prefix_(INADDR_ANY), scope_id_(0),
type_(ADAPTER_TYPE_UNKNOWN) {}
Network(const std::string& name, const std::string& description,
const IPAddress& prefix, int prefix_length,
const std::string& key);
Network(const std::string& name, const std::string& description,
const IPAddress& prefix, int prefix_length);
@ -184,6 +203,10 @@ class Network {
// Returns the length, in bits, of this network's prefix.
int prefix_length() const { return prefix_length_; }
// |key_| has unique value per network interface. Used in sorting network
// interfaces. Key is derived from interface name and it's prefix.
std::string key() const { return key_; }
// Returns the Network's current idea of the 'best' IP it has.
// 'Best' currently means the first one added.
// TODO: We should be preferring temporary addresses.
@ -215,27 +238,32 @@ class Network {
bool ignored() const { return ignored_; }
void set_ignored(bool ignored) { ignored_ = ignored; }
AdapterType type() const { return type_; }
int preference() const { return preference_; }
void set_preference(int preference) { preference_ = preference; }
// Debugging description of this network
std::string ToString() const;
private:
typedef std::vector<NetworkSession*> SessionList;
std::string name_;
std::string description_;
IPAddress prefix_;
int prefix_length_;
std::string key_;
std::vector<IPAddress> ips_;
int scope_id_;
bool ignored_;
SessionList sessions_;
double uniform_numerator_;
double uniform_denominator_;
double exponential_numerator_;
double exponential_denominator_;
AdapterType type_;
int preference_;
friend class NetworkManager;
};
} // namespace talk_base
#endif // TALK_BASE_NETWORK_H_

View File

@ -527,6 +527,33 @@ TEST_F(NetworkTest, TestIPv6Toggle) {
}
}
TEST_F(NetworkTest, TestNetworkListSorting) {
BasicNetworkManager manager;
Network ipv4_network1("test_eth0", "Test Network Adapter 1",
IPAddress(0x12345600U), 24);
ipv4_network1.AddIP(IPAddress(0x12345600U));
IPAddress ip;
IPAddress prefix;
EXPECT_TRUE(IPFromString("2400:4030:1:2c00:be30:abcd:efab:cdef", &ip));
prefix = TruncateIP(ip, 64);
Network ipv6_eth1_publicnetwork1_ip1("test_eth1", "Test NetworkAdapter 2",
prefix, 64);
ipv6_eth1_publicnetwork1_ip1.AddIP(ip);
NetworkManager::NetworkList list;
list.push_back(new Network(ipv4_network1));
list.push_back(new Network(ipv6_eth1_publicnetwork1_ip1));
Network* net1 = list[0];
Network* net2 = list[1];
bool changed = false;
MergeNetworkList(manager, list, &changed);
ASSERT_TRUE(changed);
// After sorting IPv6 network should be higher order than IPv4 networks.
EXPECT_TRUE(net1->preference() < net2->preference());
}
#if defined(POSIX)
// Verify that we correctly handle interfaces with no address.
TEST_F(NetworkTest, TestConvertIfAddrsNoAddress) {

37
talk/base/openssl.h Normal file
View File

@ -0,0 +1,37 @@
/*
* libjingle
* Copyright 2013, 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_BASE_OPENSSL_H_
#define TALK_BASE_OPENSSL_H_
#include <openssl/ssl.h>
#if (OPENSSL_VERSION_NUMBER < 0x10001000L)
#error OpenSSL is older than 1.0.1, which is the minimum supported version.
#endif
#endif // TALK_BASE_OPENSSL_H_

View File

@ -41,7 +41,6 @@
#include <openssl/err.h>
#include <openssl/opensslv.h>
#include <openssl/rand.h>
#include <openssl/ssl.h>
#include <openssl/x509v3.h>
#if HAVE_CONFIG_H
@ -50,6 +49,7 @@
#include "talk/base/common.h"
#include "talk/base/logging.h"
#include "talk/base/openssl.h"
#include "talk/base/sslroots.h"
#include "talk/base/stringutils.h"
@ -688,11 +688,7 @@ bool OpenSSLAdapter::VerifyServerName(SSL* ssl, const char* host,
int extension_nid = OBJ_obj2nid(X509_EXTENSION_get_object(extension));
if (extension_nid == NID_subject_alt_name) {
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
const X509V3_EXT_METHOD* meth = X509V3_EXT_get(extension);
#else
X509V3_EXT_METHOD* meth = X509V3_EXT_get(extension);
#endif
if (!meth)
break;
@ -703,12 +699,8 @@ bool OpenSSLAdapter::VerifyServerName(SSL* ssl, const char* host,
// See http://readlist.com/lists/openssl.org/openssl-users/0/4761.html.
unsigned char* ext_value_data = extension->value->data;
#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
const unsigned char **ext_value_data_ptr =
(const_cast<const unsigned char **>(&ext_value_data));
#else
unsigned char **ext_value_data_ptr = &ext_value_data;
#endif
if (meth->it) {
ext_str = ASN1_item_d2i(NULL, ext_value_data_ptr,

View File

@ -30,6 +30,7 @@
#include "talk/base/openssldigest.h"
#include "talk/base/common.h"
#include "talk/base/openssl.h"
namespace talk_base {
@ -78,7 +79,6 @@ bool OpenSSLDigest::GetDigestEVP(const std::string& algorithm,
md = EVP_md5();
} else if (algorithm == DIGEST_SHA_1) {
md = EVP_sha1();
#if OPENSSL_VERSION_NUMBER >= 0x00908000L
} else if (algorithm == DIGEST_SHA_224) {
md = EVP_sha224();
} else if (algorithm == DIGEST_SHA_256) {
@ -87,7 +87,6 @@ bool OpenSSLDigest::GetDigestEVP(const std::string& algorithm,
md = EVP_sha384();
} else if (algorithm == DIGEST_SHA_512) {
md = EVP_sha512();
#endif
} else {
return false;
}
@ -108,7 +107,6 @@ bool OpenSSLDigest::GetDigestName(const EVP_MD* md,
*algorithm = DIGEST_MD5;
} else if (md_type == NID_sha1) {
*algorithm = DIGEST_SHA_1;
#if OPENSSL_VERSION_NUMBER >= 0x00908000L
} else if (md_type == NID_sha224) {
*algorithm = DIGEST_SHA_224;
} else if (md_type == NID_sha256) {
@ -117,7 +115,6 @@ bool OpenSSLDigest::GetDigestName(const EVP_MD* md,
*algorithm = DIGEST_SHA_384;
} else if (md_type == NID_sha512) {
*algorithm = DIGEST_SHA_512;
#endif
} else {
algorithm->clear();
return false;

View File

@ -32,7 +32,6 @@
// Must be included first before openssl headers.
#include "talk/base/win32.h" // NOLINT
#include <openssl/ssl.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/pem.h>
@ -43,6 +42,7 @@
#include "talk/base/checks.h"
#include "talk/base/helpers.h"
#include "talk/base/logging.h"
#include "talk/base/openssl.h"
#include "talk/base/openssldigest.h"
namespace talk_base {
@ -66,15 +66,6 @@ static const int CERTIFICATE_WINDOW = -60*60*24;
static EVP_PKEY* MakeKey() {
LOG(LS_INFO) << "Making key pair";
EVP_PKEY* pkey = EVP_PKEY_new();
#if OPENSSL_VERSION_NUMBER < 0x00908000l
// Only RSA_generate_key is available. Use that.
RSA* rsa = RSA_generate_key(KEY_LENGTH, 0x10001, NULL, NULL);
if (!EVP_PKEY_assign_RSA(pkey, rsa)) {
EVP_PKEY_free(pkey);
RSA_free(rsa);
return NULL;
}
#else
// RSA_generate_key is deprecated. Use _ex version.
BIGNUM* exponent = BN_new();
RSA* rsa = RSA_new();
@ -89,7 +80,6 @@ static EVP_PKEY* MakeKey() {
}
// ownership of rsa struct was assigned, don't free it.
BN_free(exponent);
#endif
LOG(LS_INFO) << "Returning key pair";
return pkey;
}

View File

@ -37,7 +37,6 @@
#include <openssl/crypto.h>
#include <openssl/err.h>
#include <openssl/rand.h>
#include <openssl/ssl.h>
#include <openssl/x509v3.h>
#include <vector>
@ -45,6 +44,7 @@
#include "talk/base/common.h"
#include "talk/base/logging.h"
#include "talk/base/stream.h"
#include "talk/base/openssl.h"
#include "talk/base/openssladapter.h"
#include "talk/base/openssldigest.h"
#include "talk/base/opensslidentity.h"
@ -53,15 +53,6 @@
namespace talk_base {
#if (OPENSSL_VERSION_NUMBER >= 0x10001000L)
#define HAVE_DTLS_SRTP
#endif
#if (OPENSSL_VERSION_NUMBER >= 0x10000000L)
#define HAVE_DTLS
#endif
#ifdef HAVE_DTLS_SRTP
// SRTP cipher suite table
struct SrtpCipherMapEntry {
const char* external_name;
@ -74,7 +65,6 @@ static SrtpCipherMapEntry SrtpCipherMap[] = {
{"AES_CM_128_HMAC_SHA1_32", "SRTP_AES128_CM_SHA1_32"},
{NULL, NULL}
};
#endif
//////////////////////////////////////////////////////////////////////
// StreamBIO
@ -248,7 +238,6 @@ bool OpenSSLStreamAdapter::ExportKeyingMaterial(const std::string& label,
bool use_context,
uint8* result,
size_t result_len) {
#ifdef HAVE_DTLS_SRTP
int i;
i = SSL_export_keying_material(ssl_, result, result_len,
@ -260,9 +249,6 @@ bool OpenSSLStreamAdapter::ExportKeyingMaterial(const std::string& label,
return false;
return true;
#else
return false;
#endif
}
bool OpenSSLStreamAdapter::SetDtlsSrtpCiphers(
@ -272,7 +258,6 @@ bool OpenSSLStreamAdapter::SetDtlsSrtpCiphers(
if (state_ != SSL_NONE)
return false;
#ifdef HAVE_DTLS_SRTP
for (std::vector<std::string>::const_iterator cipher = ciphers.begin();
cipher != ciphers.end(); ++cipher) {
bool found = false;
@ -298,13 +283,9 @@ bool OpenSSLStreamAdapter::SetDtlsSrtpCiphers(
srtp_ciphers_ = internal_ciphers;
return true;
#else
return false;
#endif
}
bool OpenSSLStreamAdapter::GetDtlsSrtpCipher(std::string* cipher) {
#ifdef HAVE_DTLS_SRTP
ASSERT(state_ == SSL_CONNECTED);
if (state_ != SSL_CONNECTED)
return false;
@ -326,9 +307,6 @@ bool OpenSSLStreamAdapter::GetDtlsSrtpCipher(std::string* cipher) {
ASSERT(false); // This should never happen
return false;
#else
return false;
#endif
}
int OpenSSLStreamAdapter::StartSSLWithServer(const char* server_name) {
@ -665,14 +643,12 @@ int OpenSSLStreamAdapter::ContinueSSL() {
case SSL_ERROR_WANT_READ: {
LOG(LS_VERBOSE) << " -- error want read";
#ifdef HAVE_DTLS
struct timeval timeout;
if (DTLSv1_get_timeout(ssl_, &timeout)) {
int delay = timeout.tv_sec * 1000 + timeout.tv_usec/1000;
Thread::Current()->PostDelayed(delay, this, MSG_TIMEOUT, 0);
}
#endif
}
break;
@ -727,9 +703,7 @@ void OpenSSLStreamAdapter::OnMessage(Message* msg) {
// Process our own messages and then pass others to the superclass
if (MSG_TIMEOUT == msg->message_id) {
LOG(LS_INFO) << "DTLS timeout expired";
#ifdef HAVE_DTLS
DTLSv1_handle_timeout(ssl_);
#endif
ContinueSSL();
} else {
StreamInterface::OnMessage(msg);
@ -740,19 +714,11 @@ SSL_CTX* OpenSSLStreamAdapter::SetupSSLContext() {
SSL_CTX *ctx = NULL;
if (role_ == SSL_CLIENT) {
#ifdef HAVE_DTLS
ctx = SSL_CTX_new(ssl_mode_ == SSL_MODE_DTLS ?
DTLSv1_client_method() : TLSv1_client_method());
#else
ctx = SSL_CTX_new(TLSv1_client_method());
#endif
} else {
#ifdef HAVE_DTLS
ctx = SSL_CTX_new(ssl_mode_ == SSL_MODE_DTLS ?
DTLSv1_server_method() : TLSv1_server_method());
#else
ctx = SSL_CTX_new(TLSv1_server_method());
#endif
}
if (ctx == NULL)
return NULL;
@ -771,14 +737,12 @@ SSL_CTX* OpenSSLStreamAdapter::SetupSSLContext() {
SSL_CTX_set_verify_depth(ctx, 4);
SSL_CTX_set_cipher_list(ctx, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
#ifdef HAVE_DTLS_SRTP
if (!srtp_ciphers_.empty()) {
if (SSL_CTX_set_tlsext_use_srtp(ctx, srtp_ciphers_.c_str())) {
SSL_CTX_free(ctx);
return NULL;
}
}
#endif
return ctx;
}
@ -852,27 +816,15 @@ bool OpenSSLStreamAdapter::SSLPostConnectionCheck(SSL* ssl,
}
bool OpenSSLStreamAdapter::HaveDtls() {
#ifdef HAVE_DTLS
return true;
#else
return false;
#endif
}
bool OpenSSLStreamAdapter::HaveDtlsSrtp() {
#ifdef HAVE_DTLS_SRTP
return true;
#else
return false;
#endif
}
bool OpenSSLStreamAdapter::HaveExporter() {
#ifdef HAVE_DTLS_SRTP
return true;
#else
return false;
#endif
}
} // namespace talk_base

View File

@ -541,6 +541,8 @@ class PhysicalSocket : public AsyncSocket, public sigslot::has_slots<> {
case OPT_DSCP:
LOG(LS_WARNING) << "Socket::OPT_DSCP not supported.";
return -1;
case OPT_RTP_SENDTIME_EXTN_ID:
return -1; // No logging is necessary as this not a OS socket option.
default:
ASSERT(false);
return -1;

View File

@ -185,7 +185,10 @@ class Socket {
OPT_SNDBUF, // send buffer size
OPT_NODELAY, // whether Nagle algorithm is enabled
OPT_IPV6_V6ONLY, // Whether the socket is IPv6 only.
OPT_DSCP // DSCP code
OPT_DSCP, // DSCP code
OPT_RTP_SENDTIME_EXTN_ID, // This is a non-traditional socket option param.
// This is specific to libjingle and will be used
// if SendTime option is needed at socket level.
};
virtual int GetOption(Option opt, int* value) = 0;
virtual int SetOption(Option opt, int value) = 0;

View File

@ -339,7 +339,7 @@ class AsyncInvokeTest : public testing::Test {
Thread* expected_thread_;
};
TEST_F(AsyncInvokeTest, FireAndForget) {
TEST_F(AsyncInvokeTest, DISABLED_FireAndForget) {
AsyncInvoker invoker;
// Create and start the thread.
Thread thread;
@ -350,7 +350,7 @@ TEST_F(AsyncInvokeTest, FireAndForget) {
EXPECT_TRUE_WAIT(called, kWaitTimeout);
}
TEST_F(AsyncInvokeTest, WithCallback) {
TEST_F(AsyncInvokeTest, DISABLED_WithCallback) {
AsyncInvoker invoker;
// Create and start the thread.
Thread thread;
@ -379,7 +379,7 @@ TEST_F(AsyncInvokeTest, DISABLED_CancelInvoker) {
EXPECT_EQ(0, int_value_);
}
TEST_F(AsyncInvokeTest, CancelCallingThread) {
TEST_F(AsyncInvokeTest, DISABLED_CancelCallingThread) {
AsyncInvoker invoker;
{ // Create and start the thread.
Thread thread;
@ -396,7 +396,7 @@ TEST_F(AsyncInvokeTest, CancelCallingThread) {
EXPECT_EQ(0, int_value_);
}
TEST_F(AsyncInvokeTest, KillInvokerBeforeExecute) {
TEST_F(AsyncInvokeTest, DISABLED_KillInvokerBeforeExecute) {
Thread thread;
thread.Start();
{
@ -413,7 +413,7 @@ TEST_F(AsyncInvokeTest, KillInvokerBeforeExecute) {
EXPECT_EQ(0, int_value_);
}
TEST_F(AsyncInvokeTest, Flush) {
TEST_F(AsyncInvokeTest, DISABLED_Flush) {
AsyncInvoker invoker;
bool flag1 = false;
bool flag2 = false;
@ -431,7 +431,7 @@ TEST_F(AsyncInvokeTest, Flush) {
EXPECT_TRUE(flag2);
}
TEST_F(AsyncInvokeTest, FlushWithIds) {
TEST_F(AsyncInvokeTest, DISABLED_FlushWithIds) {
AsyncInvoker invoker;
bool flag1 = false;
bool flag2 = false;

View File

@ -715,6 +715,7 @@
'conditions': [
['OS!="ios"', {
'sources': [
'base/openssl.h',
'base/openssladapter.cc',
'base/openssladapter.h',
'base/openssldigest.cc',
@ -1175,6 +1176,8 @@
'app/webrtc/portallocatorfactory.cc',
'app/webrtc/portallocatorfactory.h',
'app/webrtc/proxy.h',
'app/webrtc/remoteaudiosource.cc',
'app/webrtc/remoteaudiosource.h',
'app/webrtc/remotevideocapturer.cc',
'app/webrtc/remotevideocapturer.h',
'app/webrtc/sctputils.cc',

View File

@ -560,7 +560,8 @@ class FakeVideoMediaChannel : public RtpHelper<VideoMediaChannel> {
return true;
}
virtual bool GetStats(VideoMediaInfo* info) { return false; }
virtual bool GetStats(const StatsOptions& options,
VideoMediaInfo* info) { return false; }
virtual bool SendIntraFrame() {
sent_intra_frame_ = true;
return true;

View File

@ -297,7 +297,9 @@ class FileVideoChannel : public VideoMediaChannel {
virtual bool SetCapturer(uint32 ssrc, VideoCapturer* capturer) {
return false;
}
virtual bool GetStats(VideoMediaInfo* info) { return true; }
virtual bool GetStats(const StatsOptions& options, VideoMediaInfo* info) {
return true;
}
virtual bool SendIntraFrame() { return false; }
virtual bool RequestIntraFrame() { return false; }

View File

@ -273,10 +273,11 @@ bool HybridVideoMediaChannel::RequestIntraFrame() {
active_channel_->RequestIntraFrame();
}
bool HybridVideoMediaChannel::GetStats(VideoMediaInfo* info) {
bool HybridVideoMediaChannel::GetStats(
const StatsOptions& options, VideoMediaInfo* info) {
// TODO(juberti): Ensure that returning no stats until SetSendCodecs is OK.
return active_channel_ &&
active_channel_->GetStats(info);
active_channel_->GetStats(options, info);
}
void HybridVideoMediaChannel::OnPacketReceived(

View File

@ -86,7 +86,7 @@ class HybridVideoMediaChannel : public VideoMediaChannel {
virtual bool SendIntraFrame();
virtual bool RequestIntraFrame();
virtual bool GetStats(VideoMediaInfo* info);
virtual bool GetStats(const StatsOptions& options, VideoMediaInfo* info);
virtual void OnPacketReceived(talk_base::Buffer* packet,
const talk_base::PacketTime& packet_time);

View File

@ -881,7 +881,8 @@ struct BandwidthEstimationInfo {
actual_enc_bitrate(0),
retransmit_bitrate(0),
transmit_bitrate(0),
bucket_delay(0) {
bucket_delay(0),
total_received_propagation_delta_ms(0) {
}
int available_send_bandwidth;
@ -891,6 +892,11 @@ struct BandwidthEstimationInfo {
int retransmit_bitrate;
int transmit_bitrate;
int bucket_delay;
// The following stats are only valid when
// StatsOptions::include_received_propagation_stats is true.
int total_received_propagation_delta_ms;
std::vector<int> recent_received_propagation_delta_ms;
std::vector<int64> recent_received_packet_group_arrival_time_ms;
};
struct VoiceMediaInfo {
@ -922,6 +928,12 @@ struct DataMediaInfo {
std::vector<DataReceiverInfo> receivers;
};
struct StatsOptions {
StatsOptions() : include_received_propagation_stats(false) {}
bool include_received_propagation_stats;
};
class VoiceMediaChannel : public MediaChannel {
public:
enum Error {
@ -1040,7 +1052,12 @@ class VideoMediaChannel : public MediaChannel {
// |capturer|. If |ssrc| is non zero create a new stream with |ssrc| as SSRC.
virtual bool SetCapturer(uint32 ssrc, VideoCapturer* capturer) = 0;
// Gets quality stats for the channel.
virtual bool GetStats(VideoMediaInfo* info) = 0;
virtual bool GetStats(const StatsOptions& options, VideoMediaInfo* info) = 0;
// This is needed for MediaMonitor to use the same template for voice, video
// and data MediaChannels.
bool GetStats(VideoMediaInfo* info) {
return GetStats(StatsOptions(), info);
}
// Send an intra frame to the receivers.
virtual bool SendIntraFrame() = 0;

View File

@ -183,7 +183,8 @@ void VideoAdapter::SetInputFormat(const VideoFormat& format) {
output_format_.interval = talk_base::_max(
output_format_.interval, input_format_.interval);
if (old_input_interval != input_format_.interval) {
LOG(LS_INFO) << "VAdapt Input Interval: " << input_format_.interval;
LOG(LS_INFO) << "VAdapt input interval changed from "
<< old_input_interval << " to " << input_format_.interval;
}
}
@ -218,7 +219,8 @@ void VideoAdapter::SetOutputFormat(const VideoFormat& format) {
output_format_.interval = talk_base::_max(
output_format_.interval, input_format_.interval);
if (old_output_interval != output_format_.interval) {
LOG(LS_INFO) << "VAdapt Output Interval: " << output_format_.interval;
LOG(LS_INFO) << "VAdapt output interval changed from "
<< old_output_interval << " to " << output_format_.interval;
}
}
@ -283,16 +285,12 @@ bool VideoAdapter::AdaptFrame(const VideoFrame* in_frame,
}
if (should_drop) {
// Show VAdapt log every 90 frames dropped. (3 seconds)
// TODO(fbarchard): Consider GetLogSeverity() to change interval to less
// for LS_VERBOSE and more for LS_INFO.
bool show = (frames_in_ - frames_out_) % 90 == 0;
if (show) {
if ((frames_in_ - frames_out_) % 90 == 0) {
// TODO(fbarchard): Reduce to LS_VERBOSE when adapter info is not needed
// in default calls.
LOG(LS_INFO) << "VAdapt Drop Frame: " << frames_scaled_
<< " / " << frames_out_
<< " / " << frames_in_
LOG(LS_INFO) << "VAdapt Drop Frame: scaled " << frames_scaled_
<< " / out " << frames_out_
<< " / in " << frames_in_
<< " Changes: " << adaption_changes_
<< " Input: " << in_frame->GetWidth()
<< "x" << in_frame->GetHeight()
@ -344,9 +342,9 @@ bool VideoAdapter::AdaptFrame(const VideoFrame* in_frame,
if (show) {
// TODO(fbarchard): Reduce to LS_VERBOSE when adapter info is not needed
// in default calls.
LOG(LS_INFO) << "VAdapt Frame: " << frames_scaled_
<< " / " << frames_out_
<< " / " << frames_in_
LOG(LS_INFO) << "VAdapt Frame: scaled " << frames_scaled_
<< " / out " << frames_out_
<< " / in " << frames_in_
<< " Changes: " << adaption_changes_
<< " Input: " << in_frame->GetWidth()
<< "x" << in_frame->GetHeight()

View File

@ -781,7 +781,7 @@ class VideoMediaChannelTest : public testing::Test,
void GetStats() {
SendAndReceive(DefaultCodec());
cricket::VideoMediaInfo info;
EXPECT_TRUE(channel_->GetStats(&info));
EXPECT_TRUE(channel_->GetStats(cricket::StatsOptions(), &info));
ASSERT_EQ(1U, info.senders.size());
// TODO(whyuan): bytes_sent and bytes_rcvd are different. Are both payload?
@ -839,7 +839,7 @@ class VideoMediaChannelTest : public testing::Test,
EXPECT_FRAME_ON_RENDERER_WAIT(
renderer2, 1, DefaultCodec().width, DefaultCodec().height, kTimeout);
cricket::VideoMediaInfo info;
EXPECT_TRUE(channel_->GetStats(&info));
EXPECT_TRUE(channel_->GetStats(cricket::StatsOptions(), &info));
ASSERT_EQ(1U, info.senders.size());
// TODO(whyuan): bytes_sent and bytes_rcvd are different. Are both payload?
@ -912,7 +912,7 @@ class VideoMediaChannelTest : public testing::Test,
// Get stats, and make sure they are correct for two senders.
cricket::VideoMediaInfo info;
EXPECT_TRUE(channel_->GetStats(&info));
EXPECT_TRUE(channel_->GetStats(cricket::StatsOptions(), &info));
ASSERT_EQ(2U, info.senders.size());
EXPECT_EQ(NumRtpPackets(),
info.senders[0].packets_sent + info.senders[1].packets_sent);

View File

@ -447,6 +447,10 @@ class FakeWebRtcVideoEngine
WEBRTC_ASSERT_CHANNEL(channel);
return channels_.find(channel)->second->send;
}
bool GetReceive(int channel) const {
WEBRTC_ASSERT_CHANNEL(channel);
return channels_.find(channel)->second->receive_;
}
int GetCaptureChannelId(int capture_id) const {
WEBRTC_ASSERT_CAPTURER(capture_id);
return capturers_.find(capture_id)->second->channel_id();

View File

@ -60,6 +60,7 @@
#include "talk/media/webrtc/webrtcvie.h"
#include "talk/media/webrtc/webrtcvoe.h"
#include "talk/media/webrtc/webrtcvoiceengine.h"
#include "webrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h"
#if !defined(LIBPEERCONNECTION_LIB)
#ifndef HAVE_WEBRTC_VIDEO
@ -2253,7 +2254,8 @@ bool WebRtcVideoMediaChannel::SetRenderer(uint32 ssrc,
return true;
}
bool WebRtcVideoMediaChannel::GetStats(VideoMediaInfo* info) {
bool WebRtcVideoMediaChannel::GetStats(const StatsOptions& options,
VideoMediaInfo* info) {
// Get sender statistics and build VideoSenderInfo.
unsigned int total_bitrate_sent = 0;
unsigned int video_bitrate_sent = 0;
@ -2453,11 +2455,29 @@ bool WebRtcVideoMediaChannel::GetStats(VideoMediaInfo* info) {
LOG_RTCERR1(GetEstimatedReceiveBandwidth, channel->channel_id());
}
}
// Build BandwidthEstimationInfo.
// TODO(zhurunz): Add real unittest for this.
BandwidthEstimationInfo bwe;
// TODO(jiayl): remove the condition when the necessary changes are available
// outside the dev branch.
#ifdef USE_WEBRTC_DEV_BRANCH
if (options.include_received_propagation_stats) {
webrtc::ReceiveBandwidthEstimatorStats additional_stats;
// Only call for the default channel because the returned stats are
// collected for all the channels using the same estimator.
if (engine_->vie()->rtp()->GetReceiveBandwidthEstimatorStats(
recv_channels_[0]->channel_id(), &additional_stats)) {
bwe.total_received_propagation_delta_ms =
additional_stats.total_propagation_time_delta_ms;
bwe.recent_received_propagation_delta_ms.swap(
additional_stats.recent_propagation_time_delta_ms);
bwe.recent_received_packet_group_arrival_time_ms.swap(
additional_stats.recent_arrival_time_ms);
}
}
#endif
// Calculations done above per send/receive stream.
bwe.actual_enc_bitrate = video_bitrate_sent;
bwe.transmit_bitrate = total_bitrate_sent;
@ -2632,6 +2652,15 @@ bool WebRtcVideoMediaChannel::SetSendRtpHeaderExtensions(
return false;
}
}
if (send_time_extension) {
// For video RTP packets, we would like to update AbsoluteSendTimeHeader
// Extension closer to the network, @ socket level before sending.
// Pushing the extension id to socket layer.
MediaChannel::SetOption(NetworkInterface::ST_RTP,
talk_base::Socket::OPT_RTP_SENDTIME_EXTN_ID,
send_time_extension->id);
}
return true;
}
@ -3083,6 +3112,13 @@ bool WebRtcVideoMediaChannel::ConfigureChannel(int channel_id,
}
}
// Start receiving for both receive and send channels so that we get incoming
// RTP (if receiving) as well as RTCP feedback (if sending).
if (engine()->vie()->base()->StartReceive(channel_id) != 0) {
LOG_RTCERR1(StartReceive, channel_id);
return false;
}
return true;
}
@ -3532,14 +3568,6 @@ bool WebRtcVideoMediaChannel::SetReceiveCodecs(
}
}
}
// Start receiving packets if at least one receive codec has been set.
if (!receive_codecs_.empty()) {
if (engine()->vie()->base()->StartReceive(channel_id) != 0) {
LOG_RTCERR1(StartReceive, channel_id);
return false;
}
}
return true;
}

View File

@ -258,7 +258,7 @@ class WebRtcVideoMediaChannel : public talk_base::MessageHandler,
virtual bool AddRecvStream(const StreamParams& sp);
virtual bool RemoveRecvStream(uint32 ssrc);
virtual bool SetRenderer(uint32 ssrc, VideoRenderer* renderer);
virtual bool GetStats(VideoMediaInfo* info);
virtual bool GetStats(const StatsOptions& options, VideoMediaInfo* info);
virtual bool SetCapturer(uint32 ssrc, VideoCapturer* capturer);
virtual bool SendIntraFrame();
virtual bool RequestIntraFrame();

View File

@ -1077,6 +1077,8 @@ TEST_F(WebRtcVideoEngineTestFake, SetRender) {
TEST_F(WebRtcVideoEngineTestFake, SetSend) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
// Verify receiving is also started.
EXPECT_TRUE(vie_.GetReceive(channel_num));
// Set send codecs on the channel.
std::vector<cricket::VideoCodec> codecs;
@ -1298,12 +1300,20 @@ TEST_F(WebRtcVideoEngineTestFake, MultipleSendStreamsWithOneCapturer) {
ASSERT_NE(-1, channel1);
ASSERT_NE(channel0, channel1);
// Both channels should have started receiving after created.
EXPECT_TRUE(vie_.GetReceive(channel0));
EXPECT_TRUE(vie_.GetReceive(channel1));
// Set send codec.
std::vector<cricket::VideoCodec> codecs;
cricket::VideoCodec send_codec(100, "VP8", 640, 480, 30, 0);
codecs.push_back(send_codec);
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
EXPECT_TRUE(channel_->SetSend(true));
EXPECT_TRUE(vie_.GetSend(channel0));
EXPECT_TRUE(vie_.GetSend(channel1));
EXPECT_TRUE(capturer.CaptureFrame());
EXPECT_EQ(1, vie_.GetIncomingFrameNum(channel0));
EXPECT_EQ(1, vie_.GetIncomingFrameNum(channel1));
@ -1347,7 +1357,7 @@ TEST_F(WebRtcVideoEngineTestFake, DISABLED_SendReceiveBitratesStats) {
EXPECT_NE(first_receive_channel, second_receive_channel);
cricket::VideoMediaInfo info;
EXPECT_TRUE(channel_->GetStats(&info));
EXPECT_TRUE(channel_->GetStats(cricket::StatsOptions(), &info));
ASSERT_EQ(1U, info.bw_estimations.size());
ASSERT_EQ(0, info.bw_estimations[0].actual_enc_bitrate);
ASSERT_EQ(0, info.bw_estimations[0].transmit_bitrate);
@ -1374,7 +1384,7 @@ TEST_F(WebRtcVideoEngineTestFake, DISABLED_SendReceiveBitratesStats) {
first_channel_receive_bandwidth);
info.Clear();
EXPECT_TRUE(channel_->GetStats(&info));
EXPECT_TRUE(channel_->GetStats(cricket::StatsOptions(), &info));
ASSERT_EQ(1U, info.bw_estimations.size());
ASSERT_EQ(send_video_bitrate, info.bw_estimations[0].actual_enc_bitrate);
ASSERT_EQ(send_total_bitrate, info.bw_estimations[0].transmit_bitrate);
@ -1391,7 +1401,7 @@ TEST_F(WebRtcVideoEngineTestFake, DISABLED_SendReceiveBitratesStats) {
second_channel_receive_bandwidth);
info.Clear();
EXPECT_TRUE(channel_->GetStats(&info));
EXPECT_TRUE(channel_->GetStats(cricket::StatsOptions(), &info));
ASSERT_EQ(1U, info.bw_estimations.size());
ASSERT_EQ(send_video_bitrate, info.bw_estimations[0].actual_enc_bitrate);
ASSERT_EQ(send_total_bitrate, info.bw_estimations[0].transmit_bitrate);

View File

@ -33,6 +33,7 @@
#include <string>
#include <sstream>
#include <iomanip>
#include "talk/base/basictypes.h"
#include "talk/base/socketaddress.h"
#include "talk/p2p/base/constants.h"
@ -163,13 +164,30 @@ class Candidate {
return ToStringInternal(true);
}
uint32 GetPriority(uint32 type_preference) const {
uint32 GetPriority(uint32 type_preference,
int network_adapter_preference) const {
// RFC 5245 - 4.1.2.1.
// priority = (2^24)*(type preference) +
// (2^8)*(local preference) +
// (2^0)*(256 - component ID)
// |local_preference| length is 2 bytes, 0-65535 inclusive.
// In our implemenation we will partion local_preference into
// 0 1
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | NIC Pref | Addr Pref |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// NIC Type - Type of the network adapter e.g. 3G/Wifi/Wired.
// Addr Pref - Address preference value as per RFC 3484.
// local preference is calculated as - NIC Type << 8 | Addr_Pref.
int addr_pref = IPAddressPrecedence(address_.ipaddr());
return (type_preference << 24) | (addr_pref << 8) | (256 - component_);
int local_preference = (network_adapter_preference << 8) | addr_pref;
return (type_preference << 24) |
(local_preference << 8) |
(256 - component_);
}
private:
@ -177,9 +195,9 @@ class Candidate {
std::ostringstream ost;
std::string address = sensitive ? address_.ToSensitiveString() :
address_.ToString();
ost << "Cand[" << id_ << ":" << component_ << ":"
<< type_ << ":" << protocol_ << ":"
<< network_name_ << ":" << address << ":"
ost << "Cand[" << foundation_ << ":" << component_ << ":"
<< protocol_ << ":" << priority_ << ":"
<< address << ":" << type_ << ":" << related_address_ << ":"
<< username_ << ":" << password_ << "]";
return ost.str();
}

View File

@ -493,7 +493,8 @@ void P2PTransportChannel::OnUnknownAddress(
port->Network()->name(), 0U,
talk_base::ToString<uint32>(talk_base::ComputeCrc32(id)));
new_remote_candidate.set_priority(
new_remote_candidate.GetPriority(ICE_TYPE_PREFERENCE_SRFLX));
new_remote_candidate.GetPriority(ICE_TYPE_PREFERENCE_SRFLX,
port->Network()->preference()));
}
if (port->IceProtocol() == ICEPROTO_RFC5245) {

View File

@ -1559,8 +1559,11 @@ TEST_F(P2PTransportChannelMultihomedTest, DISABLED_TestBasic) {
// Test that we can quickly switch links if an interface goes down.
TEST_F(P2PTransportChannelMultihomedTest, TestFailover) {
AddAddress(0, kPublicAddrs[0]);
AddAddress(1, kPublicAddrs[1]);
// Adding alternate address will make sure |kPublicAddrs| has the higher
// priority than others. This is due to FakeNetwork::AddInterface method.
AddAddress(1, kAlternateAddrs[1]);
AddAddress(1, kPublicAddrs[1]);
// Use only local ports for simplicity.
SetAllocatorFlags(0, kOnlyLocalPorts);
SetAllocatorFlags(1, kOnlyLocalPorts);

View File

@ -258,7 +258,7 @@ void Port::AddAddress(const talk_base::SocketAddress& address,
c.set_type(type);
c.set_protocol(protocol);
c.set_address(address);
c.set_priority(c.GetPriority(type_preference));
c.set_priority(c.GetPriority(type_preference, network_->preference()));
c.set_username(username_fragment());
c.set_password(password_);
c.set_network_name(network_->name());

View File

@ -53,8 +53,8 @@ using talk_base::Thread;
static const SocketAddress kClientAddr("11.11.11.11", 0);
static const SocketAddress kClientIPv6Addr(
"2401:fa00:4:1000:be30:5bff:fee5:c3", 0);
static const SocketAddress kClientAddr2("22.22.22.22", 0);
static const SocketAddress kNatAddr("77.77.77.77", talk_base::NAT_SERVER_PORT);
static const SocketAddress kRemoteClientAddr("22.22.22.22", 0);
static const SocketAddress kStunAddr("99.99.99.1", cricket::STUN_SERVER_PORT);
static const SocketAddress kRelayUdpIntAddr("99.99.99.2", 5000);
static const SocketAddress kRelayUdpExtAddr("99.99.99.3", 5001);
@ -492,6 +492,23 @@ TEST_F(PortAllocatorTest, TestGetAllPortsNoUdpAllowed) {
EXPECT_TRUE_WAIT(candidate_allocation_done_, 9000);
}
TEST_F(PortAllocatorTest, TestCandidatePriorityOfMultipleInterfaces) {
AddInterface(kClientAddr);
AddInterface(kClientAddr2);
// Allocating only host UDP ports. This is done purely for testing
// convenience.
allocator().set_flags(cricket::PORTALLOCATOR_DISABLE_TCP |
cricket::PORTALLOCATOR_DISABLE_STUN |
cricket::PORTALLOCATOR_DISABLE_RELAY);
EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP));
session_->StartGettingPorts();
EXPECT_TRUE_WAIT(candidate_allocation_done_, kDefaultAllocationTimeout);
ASSERT_EQ(2U, candidates_.size());
EXPECT_EQ(2U, ports_.size());
// Candidates priorities should be different.
EXPECT_NE(candidates_[0].priority(), candidates_[1].priority());
}
// Test to verify ICE restart process.
TEST_F(PortAllocatorTest, TestGetAllPortsRestarts) {
AddInterface(kClientAddr);

View File

@ -1744,9 +1744,10 @@ void VideoChannel::ChangeState() {
LOG(LS_INFO) << "Changing video state, recv=" << recv << " send=" << send;
}
bool VideoChannel::GetStats(VideoMediaInfo* stats) {
bool VideoChannel::GetStats(
const StatsOptions& options, VideoMediaInfo* stats) {
return InvokeOnWorker(Bind(&VideoMediaChannel::GetStats,
media_channel(), stats));
media_channel(), options, stats));
}
void VideoChannel::StartMediaMonitor(int cms) {

View File

@ -524,7 +524,7 @@ class VideoChannel : public BaseChannel {
int GetScreencastFps(uint32 ssrc);
int GetScreencastMaxPixels(uint32 ssrc);
// Get statistics about the current media session.
bool GetStats(VideoMediaInfo* stats);
bool GetStats(const StatsOptions& options, VideoMediaInfo* stats);
sigslot::signal2<VideoChannel*, const std::vector<ConnectionInfo>&>
SignalConnectionMonitor;