Update libjingle to 55618622.
Update libyuv to r826.
TEST=try bots
R=niklas.enbom@webrtc.org
Review URL: https://webrtc-codereview.appspot.com/2889004
git-svn-id: http://webrtc.googlecode.com/svn/trunk@5038 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/DEPS b/DEPS
index 6bf74cb..205ba4e 100644
--- a/DEPS
+++ b/DEPS
@@ -72,7 +72,7 @@
Var("chromium_trunk") + "/deps/third_party/libvpx@225010",
"third_party/libyuv":
- (Var("googlecode_url") % "libyuv") + "/trunk@723",
+ (Var("googlecode_url") % "libyuv") + "/trunk@826",
"third_party/opus":
Var("chromium_trunk") + "/src/third_party/opus@185405",
diff --git a/talk/app/webrtc/localaudiosource.cc b/talk/app/webrtc/localaudiosource.cc
index 3663aac..2cd472a 100644
--- a/talk/app/webrtc/localaudiosource.cc
+++ b/talk/app/webrtc/localaudiosource.cc
@@ -53,7 +53,9 @@
"googHighpassFilter";
const char MediaConstraintsInterface::kTypingNoiseDetection[] =
"googTypingNoiseDetection";
-const char MediaConstraintsInterface::kInternalAecDump[] = "internalAecDump";
+const char MediaConstraintsInterface::kAudioMirroring[] = "googAudioMirroring";
+// TODO(perkj): Remove kInternalAecDump once its not used by Chrome.
+const char MediaConstraintsInterface::kInternalAecDump[] = "deprecatedAecDump";
namespace {
@@ -90,10 +92,10 @@
options->noise_suppression.Set(value);
else if (iter->key == MediaConstraintsInterface::kHighpassFilter)
options->highpass_filter.Set(value);
- else if (iter->key == MediaConstraintsInterface::kInternalAecDump)
- options->aec_dump.Set(value);
else if (iter->key == MediaConstraintsInterface::kTypingNoiseDetection)
options->typing_detection.Set(value);
+ else if (iter->key == MediaConstraintsInterface::kAudioMirroring)
+ options->stereo_swapping.Set(value);
else
success = false;
}
@@ -103,14 +105,16 @@
} // namespace
talk_base::scoped_refptr<LocalAudioSource> LocalAudioSource::Create(
+ const PeerConnectionFactoryInterface::Options& options,
const MediaConstraintsInterface* constraints) {
talk_base::scoped_refptr<LocalAudioSource> source(
new talk_base::RefCountedObject<LocalAudioSource>());
- source->Initialize(constraints);
+ source->Initialize(options, constraints);
return source;
}
void LocalAudioSource::Initialize(
+ const PeerConnectionFactoryInterface::Options& options,
const MediaConstraintsInterface* constraints) {
if (!constraints)
return;
@@ -119,12 +123,14 @@
// constraints.
FromConstraints(constraints->GetOptional(), &options_);
- cricket::AudioOptions options;
- if (!FromConstraints(constraints->GetMandatory(), &options)) {
+ cricket::AudioOptions audio_options;
+ if (!FromConstraints(constraints->GetMandatory(), &audio_options)) {
source_state_ = kEnded;
return;
}
- options_.SetAll(options);
+ options_.SetAll(audio_options);
+ if (options.enable_aec_dump)
+ options_.aec_dump.Set(true);
source_state_ = kLive;
}
diff --git a/talk/app/webrtc/localaudiosource.h b/talk/app/webrtc/localaudiosource.h
index e0fda03..fb769ed 100644
--- a/talk/app/webrtc/localaudiosource.h
+++ b/talk/app/webrtc/localaudiosource.h
@@ -30,6 +30,7 @@
#include "talk/app/webrtc/mediastreaminterface.h"
#include "talk/app/webrtc/notifier.h"
+#include "talk/app/webrtc/peerconnectioninterface.h"
#include "talk/base/scoped_ptr.h"
#include "talk/media/base/mediachannel.h"
@@ -44,6 +45,7 @@
public:
// Creates an instance of LocalAudioSource.
static talk_base::scoped_refptr<LocalAudioSource> Create(
+ const PeerConnectionFactoryInterface::Options& options,
const MediaConstraintsInterface* constraints);
virtual SourceState state() const { return source_state_; }
@@ -58,7 +60,8 @@
}
private:
- void Initialize(const MediaConstraintsInterface* constraints);
+ void Initialize(const PeerConnectionFactoryInterface::Options& options,
+ const MediaConstraintsInterface* constraints);
cricket::AudioOptions options_;
SourceState source_state_;
diff --git a/talk/app/webrtc/localaudiosource_unittest.cc b/talk/app/webrtc/localaudiosource_unittest.cc
index ae07787..f8880e0 100644
--- a/talk/app/webrtc/localaudiosource_unittest.cc
+++ b/talk/app/webrtc/localaudiosource_unittest.cc
@@ -39,6 +39,7 @@
using webrtc::LocalAudioSource;
using webrtc::MediaConstraintsInterface;
using webrtc::MediaSourceInterface;
+using webrtc::PeerConnectionFactoryInterface;
TEST(LocalAudioSourceTest, SetValidOptions) {
webrtc::FakeConstraints constraints;
@@ -52,7 +53,8 @@
constraints.AddOptional(MediaConstraintsInterface::kHighpassFilter, true);
talk_base::scoped_refptr<LocalAudioSource> source =
- LocalAudioSource::Create(&constraints);
+ LocalAudioSource::Create(PeerConnectionFactoryInterface::Options(),
+ &constraints);
bool value;
EXPECT_TRUE(source->options().echo_cancellation.Get(&value));
@@ -72,7 +74,8 @@
TEST(LocalAudioSourceTest, OptionNotSet) {
webrtc::FakeConstraints constraints;
talk_base::scoped_refptr<LocalAudioSource> source =
- LocalAudioSource::Create(&constraints);
+ LocalAudioSource::Create(PeerConnectionFactoryInterface::Options(),
+ &constraints);
bool value;
EXPECT_FALSE(source->options().highpass_filter.Get(&value));
}
@@ -83,7 +86,8 @@
constraints.AddOptional(MediaConstraintsInterface::kEchoCancellation, true);
talk_base::scoped_refptr<LocalAudioSource> source =
- LocalAudioSource::Create(&constraints);
+ LocalAudioSource::Create(PeerConnectionFactoryInterface::Options(),
+ &constraints);
bool value;
EXPECT_TRUE(source->options().echo_cancellation.Get(&value));
@@ -96,7 +100,8 @@
constraints.AddOptional("invalidKey", false);
talk_base::scoped_refptr<LocalAudioSource> source =
- LocalAudioSource::Create(&constraints);
+ LocalAudioSource::Create(PeerConnectionFactoryInterface::Options(),
+ &constraints);
EXPECT_EQ(MediaSourceInterface::kLive, source->state());
bool value;
@@ -110,7 +115,8 @@
constraints.AddMandatory("invalidKey", false);
talk_base::scoped_refptr<LocalAudioSource> source =
- LocalAudioSource::Create(&constraints);
+ LocalAudioSource::Create(PeerConnectionFactoryInterface::Options(),
+ &constraints);
EXPECT_EQ(MediaSourceInterface::kEnded, source->state());
bool value;
diff --git a/talk/app/webrtc/mediaconstraintsinterface.h b/talk/app/webrtc/mediaconstraintsinterface.h
index 48022dd..97d5cf6 100644
--- a/talk/app/webrtc/mediaconstraintsinterface.h
+++ b/talk/app/webrtc/mediaconstraintsinterface.h
@@ -81,6 +81,7 @@
static const char kNoiseSuppression[]; // googNoiseSuppression
static const char kHighpassFilter[]; // googHighpassFilter
static const char kTypingNoiseDetection[]; // googTypingNoiseDetection
+ static const char kAudioMirroring[]; // googAudioMirroring
// Google-specific constraint keys for a local video source
static const char kNoiseReduction[]; // googNoiseReduction
@@ -106,6 +107,8 @@
static const char kEnableDtlsSrtp[]; // Enable DTLS-SRTP
// Temporary pseudo-constraints used to enable DataChannels
static const char kEnableRtpDataChannels[]; // Enable RTP DataChannels
+ // TODO(perkj): Remove kEnableSctpDataChannels once Chrome use
+ // PeerConnectionFactory::SetOptions.
static const char kEnableSctpDataChannels[]; // Enable SCTP DataChannels
// The prefix of internal-only constraints whose JS set values should be
@@ -116,9 +119,8 @@
// line flags. So they are prefixed with "internal" so JS values will be
// removed.
// Used by a local audio source.
+ // TODO(perkj): Remove once Chrome use PeerConnectionFactory::SetOptions.
static const char kInternalAecDump[]; // internalAecDump
- // Used for disabling security and use plain RTP.
- static const char kInternalDisableEncryption[]; // internalDisableEncryption
protected:
// Dtor protected as objects shouldn't be deleted via this interface
diff --git a/talk/app/webrtc/mediastreamsignaling.cc b/talk/app/webrtc/mediastreamsignaling.cc
index 771a4e8..ef9f3e0 100644
--- a/talk/app/webrtc/mediastreamsignaling.cc
+++ b/talk/app/webrtc/mediastreamsignaling.cc
@@ -267,6 +267,10 @@
}
scoped_refptr<DataChannel> channel(
data_channel_factory_->CreateDataChannel(label, &config));
+ if (!channel.get()) {
+ LOG(LS_ERROR) << "Failed to create DataChannel from the OPEN message.";
+ return false;
+ }
data_channels_[label] = channel;
stream_observer_->OnAddDataChannel(channel);
// It's immediately ready to use.
diff --git a/talk/app/webrtc/peerconnection.cc b/talk/app/webrtc/peerconnection.cc
index 7fafad7..de88f88 100644
--- a/talk/app/webrtc/peerconnection.cc
+++ b/talk/app/webrtc/peerconnection.cc
@@ -317,7 +317,8 @@
stats_.set_session(session_.get());
// Initialize the WebRtcSession. It creates transport channels etc.
- if (!session_->Initialize(constraints, dtls_identity_service))
+ if (!session_->Initialize(factory_->options(), constraints,
+ dtls_identity_service))
return false;
// Register PeerConnection as receiver of local ice candidates.
diff --git a/talk/app/webrtc/peerconnection_unittest.cc b/talk/app/webrtc/peerconnection_unittest.cc
index 9de6ec9..76d9cd7 100644
--- a/talk/app/webrtc/peerconnection_unittest.cc
+++ b/talk/app/webrtc/peerconnection_unittest.cc
@@ -157,8 +157,8 @@
// Disable highpass filter so that we can get all the test audio frames.
constraints.AddMandatory(
MediaConstraintsInterface::kHighpassFilter, false);
- talk_base::scoped_refptr<webrtc::LocalAudioSource> source =
- webrtc::LocalAudioSource::Create(&constraints);
+ talk_base::scoped_refptr<webrtc::AudioSourceInterface> source =
+ peer_connection_factory_->CreateAudioSource(&constraints);
// TODO(perkj): Test audio source when it is implemented. Currently audio
// always use the default input.
talk_base::scoped_refptr<webrtc::AudioTrackInterface> audio_track(
diff --git a/talk/app/webrtc/peerconnectionfactory.cc b/talk/app/webrtc/peerconnectionfactory.cc
index 7d30fab..e8b8f63 100644
--- a/talk/app/webrtc/peerconnectionfactory.cc
+++ b/talk/app/webrtc/peerconnectionfactory.cc
@@ -261,7 +261,7 @@
PeerConnectionFactory::CreateAudioSource_s(
const MediaConstraintsInterface* constraints) {
talk_base::scoped_refptr<LocalAudioSource> source(
- LocalAudioSource::Create(constraints));
+ LocalAudioSource::Create(options_, constraints));
return source;
}
diff --git a/talk/app/webrtc/peerconnectionfactory.h b/talk/app/webrtc/peerconnectionfactory.h
index 7faf609..dff885d 100644
--- a/talk/app/webrtc/peerconnectionfactory.h
+++ b/talk/app/webrtc/peerconnectionfactory.h
@@ -40,6 +40,10 @@
class PeerConnectionFactory : public PeerConnectionFactoryInterface,
public talk_base::MessageHandler {
public:
+ virtual void SetOptions(const Options& options) {
+ options_ = options;
+ }
+
virtual talk_base::scoped_refptr<PeerConnectionInterface>
CreatePeerConnection(
const PeerConnectionInterface::IceServers& configuration,
@@ -77,6 +81,7 @@
virtual cricket::ChannelManager* channel_manager();
virtual talk_base::Thread* signaling_thread();
virtual talk_base::Thread* worker_thread();
+ const Options& options() const { return options_; }
protected:
PeerConnectionFactory();
@@ -109,6 +114,7 @@
bool owns_ptrs_;
talk_base::Thread* signaling_thread_;
talk_base::Thread* worker_thread_;
+ Options options_;
talk_base::scoped_refptr<PortAllocatorFactoryInterface> allocator_factory_;
// External Audio device used for audio playback.
talk_base::scoped_refptr<AudioDeviceModule> default_adm_;
diff --git a/talk/app/webrtc/peerconnectioninterface.h b/talk/app/webrtc/peerconnectioninterface.h
index bd86f3e..a127dad 100644
--- a/talk/app/webrtc/peerconnectioninterface.h
+++ b/talk/app/webrtc/peerconnectioninterface.h
@@ -390,6 +390,19 @@
// argument.
class PeerConnectionFactoryInterface : public talk_base::RefCountInterface {
public:
+ class Options {
+ public:
+ Options() :
+ enable_aec_dump(false),
+ disable_encryption(false),
+ disable_sctp_data_channels(false) {
+ }
+ bool enable_aec_dump;
+ bool disable_encryption;
+ bool disable_sctp_data_channels;
+ };
+
+ virtual void SetOptions(const Options& options) = 0;
virtual talk_base::scoped_refptr<PeerConnectionInterface>
CreatePeerConnection(
const PeerConnectionInterface::IceServers& configuration,
diff --git a/talk/app/webrtc/statscollector.cc b/talk/app/webrtc/statscollector.cc
index 42ae662..db7cac4 100644
--- a/talk/app/webrtc/statscollector.cc
+++ b/talk/app/webrtc/statscollector.cc
@@ -82,6 +82,15 @@
"googFrameRateDecoded";
const char StatsReport::kStatsValueNameFrameRateOutput[] =
"googFrameRateOutput";
+const char StatsReport::kStatsValueNameDecodeMs[] = "googDecodeMs";
+const char StatsReport::kStatsValueNameMaxDecodeMs[] = "googMaxDecodeMs";
+const char StatsReport::kStatsValueNameCurrentDelayMs[] = "googCurrentDelayMs";
+const char StatsReport::kStatsValueNameTargetDelayMs[] = "googTargetDelayMs";
+const char StatsReport::kStatsValueNameJitterBufferMs[] = "googJitterBufferMs";
+const char StatsReport::kStatsValueNameMinPlayoutDelayMs[] =
+ "googMinPlayoutDelayMs";
+const char StatsReport::kStatsValueNameRenderDelayMs[] = "googRenderDelayMs";
+
const char StatsReport::kStatsValueNameFrameRateInput[] = "googFrameRateInput";
const char StatsReport::kStatsValueNameFrameRateSent[] = "googFrameRateSent";
const char StatsReport::kStatsValueNameFrameWidthReceived[] =
@@ -119,6 +128,7 @@
const char StatsReport::kStatsReportTypeSession[] = "googLibjingleSession";
const char StatsReport::kStatsReportTypeBwe[] = "VideoBwe";
+const char StatsReport::kStatsReportTypeRemoteSsrc[] = "remoteSsrc";
const char StatsReport::kStatsReportTypeSsrc[] = "ssrc";
const char StatsReport::kStatsReportTypeTrack[] = "googTrack";
const char StatsReport::kStatsReportTypeIceCandidate[] = "iceCandidate";
@@ -241,6 +251,21 @@
info.framerate_decoded);
report->AddValue(StatsReport::kStatsValueNameFrameRateOutput,
info.framerate_output);
+
+ report->AddValue(StatsReport::kStatsValueNameDecodeMs,
+ info.decode_ms);
+ report->AddValue(StatsReport::kStatsValueNameMaxDecodeMs,
+ info.max_decode_ms);
+ report->AddValue(StatsReport::kStatsValueNameCurrentDelayMs,
+ info.current_delay_ms);
+ report->AddValue(StatsReport::kStatsValueNameTargetDelayMs,
+ info.target_delay_ms);
+ report->AddValue(StatsReport::kStatsValueNameJitterBufferMs,
+ info.jitter_buffer_ms);
+ report->AddValue(StatsReport::kStatsValueNameMinPlayoutDelayMs,
+ info.min_playout_delay_ms);
+ report->AddValue(StatsReport::kStatsValueNameRenderDelayMs,
+ info.render_delay_ms);
}
void ExtractStats(const cricket::VideoSenderInfo& info, StatsReport* report) {
@@ -293,6 +318,18 @@
info.bucket_delay);
}
+void ExtractRemoteStats(const cricket::MediaSenderInfo& info,
+ StatsReport* report) {
+ report->timestamp = info.remote_stats[0].timestamp;
+ // TODO(hta): Extract some stats here.
+}
+
+void ExtractRemoteStats(const cricket::MediaReceiverInfo& info,
+ StatsReport* report) {
+ report->timestamp = info.remote_stats[0].timestamp;
+ // TODO(hta): Extract some stats here.
+}
+
uint32 ExtractSsrc(const cricket::VoiceReceiverInfo& info) {
return info.ssrc;
}
@@ -319,11 +356,20 @@
for (; it != data.end(); ++it) {
std::string id;
uint32 ssrc = ExtractSsrc(*it);
- StatsReport* report = collector->PrepareReport(ssrc, transport_id);
+ // Each object can result in 2 objects, a local and a remote object.
+ // TODO(hta): Handle the case of multiple SSRCs per object.
+ StatsReport* report = collector->PrepareLocalReport(ssrc, transport_id);
if (!report) {
continue;
}
ExtractStats(*it, report);
+ if (it->remote_stats.size() > 0) {
+ report = collector->PrepareRemoteReport(ssrc, transport_id);
+ if (!report) {
+ continue;
+ }
+ ExtractRemoteStats(*it, report);
+ }
}
};
@@ -406,8 +452,9 @@
}
}
-StatsReport* StatsCollector::PrepareReport(uint32 ssrc,
- const std::string& transport_id) {
+StatsReport* StatsCollector::PrepareLocalReport(
+ uint32 ssrc,
+ const std::string& transport_id) {
std::string ssrc_id = talk_base::ToString<uint32>(ssrc);
StatsMap::iterator it = reports_.find(StatsId(
StatsReport::kStatsReportTypeSsrc, ssrc_id));
@@ -427,10 +474,8 @@
&track_id);
}
- StatsReport* report = &reports_[
- StatsId(StatsReport::kStatsReportTypeSsrc, ssrc_id)];
- report->id = StatsId(StatsReport::kStatsReportTypeSsrc, ssrc_id);
- report->type = StatsReport::kStatsReportTypeSsrc;
+ StatsReport* report = GetOrCreateReport(StatsReport::kStatsReportTypeSsrc,
+ ssrc_id);
// Clear out stats from previous GatherStats calls if any.
if (report->timestamp != stats_gathering_started_) {
@@ -446,6 +491,44 @@
return report;
}
+StatsReport* StatsCollector::PrepareRemoteReport(
+ uint32 ssrc,
+ const std::string& transport_id) {
+ std::string ssrc_id = talk_base::ToString<uint32>(ssrc);
+ StatsMap::iterator it = reports_.find(StatsId(
+ StatsReport::kStatsReportTypeRemoteSsrc, ssrc_id));
+
+ std::string track_id;
+ if (it == reports_.end()) {
+ if (!session()->GetTrackIdBySsrc(ssrc, &track_id)) {
+ LOG(LS_WARNING) << "The SSRC " << ssrc
+ << " is not associated with a track";
+ return NULL;
+ }
+ } else {
+ // Keeps the old track id since we want to report the stats for inactive
+ // tracks.
+ ExtractValueFromReport(it->second,
+ StatsReport::kStatsValueNameTrackId,
+ &track_id);
+ }
+
+ StatsReport* report = GetOrCreateReport(
+ StatsReport::kStatsReportTypeRemoteSsrc, ssrc_id);
+
+ // Clear out stats from previous GatherStats calls if any.
+ // The timestamp will be added later. Zero it for debugging.
+ report->values.clear();
+ report->timestamp = 0;
+
+ report->AddValue(StatsReport::kStatsValueNameSsrc, ssrc_id);
+ report->AddValue(StatsReport::kStatsValueNameTrackId, track_id);
+ // Add the mapping of SSRC to transport.
+ report->AddValue(StatsReport::kStatsValueNameTransportId,
+ transport_id);
+ return report;
+}
+
std::string StatsCollector::AddOneCertificateReport(
const talk_base::SSLCertificate* cert, const std::string& issuer_id) {
// TODO(bemasc): Move this computation to a helper class that caches these
@@ -592,6 +675,9 @@
info.local_candidate.address().ToString());
report.AddValue(StatsReport::kStatsValueNameRemoteAddress,
info.remote_candidate.address().ToString());
+ report.AddValue(StatsReport::kStatsValueNameRtt, info.rtt);
+ report.AddValue(StatsReport::kStatsValueNameTransportType,
+ info.local_candidate.protocol());
reports_[report.id] = report;
}
}
@@ -668,4 +754,19 @@
return true;
}
+StatsReport* StatsCollector::GetOrCreateReport(const std::string& type,
+ const std::string& id) {
+ std::string statsid = StatsId(type, id);
+ StatsReport* report = NULL;
+ std::map<std::string, StatsReport>::iterator it = reports_.find(statsid);
+ if (it == reports_.end()) {
+ report = &reports_[statsid]; // Create new element.
+ report->id = statsid;
+ report->type = type;
+ } else {
+ report = &reports_[statsid];
+ }
+ return report;
+}
+
} // namespace webrtc
diff --git a/talk/app/webrtc/statscollector.h b/talk/app/webrtc/statscollector.h
index c34b5a0..01da059 100644
--- a/talk/app/webrtc/statscollector.h
+++ b/talk/app/webrtc/statscollector.h
@@ -65,9 +65,11 @@
// |reports|.
bool GetStats(MediaStreamTrackInterface* track, StatsReports* reports);
- WebRtcSession* session() { return session_; }
- // Prepare an SSRC report for the given ssrc. Used internally.
- StatsReport* PrepareReport(uint32 ssrc, const std::string& transport);
+ // Prepare an SSRC report for the given ssrc. Used internally
+ // in the ExtractStatsFromList template.
+ StatsReport* PrepareLocalReport(uint32 ssrc, const std::string& transport);
+ // Prepare an SSRC report for the given remote ssrc. Used internally.
+ StatsReport* PrepareRemoteReport(uint32 ssrc, const std::string& transport);
// Extracts the ID of a Transport belonging to an SSRC. Used internally.
bool GetTransportIdFromProxy(const std::string& proxy,
std::string* transport_id);
@@ -88,9 +90,12 @@
void ExtractVideoInfo();
double GetTimeNow();
void BuildSsrcToTransportId();
+ WebRtcSession* session() { return session_; }
+ webrtc::StatsReport* GetOrCreateReport(const std::string& type,
+ const std::string& id);
// A map from the report id to the report.
- std::map<std::string, webrtc::StatsReport> reports_;
+ std::map<std::string, StatsReport> reports_;
// Raw pointer to the session the statistics are gathered from.
WebRtcSession* session_;
double stats_gathering_started_;
diff --git a/talk/app/webrtc/statscollector_unittest.cc b/talk/app/webrtc/statscollector_unittest.cc
index d9cde5d..66a5ee0 100644
--- a/talk/app/webrtc/statscollector_unittest.cc
+++ b/talk/app/webrtc/statscollector_unittest.cc
@@ -58,6 +58,10 @@
const char kNotFound[] = "NOT FOUND";
const char kNoReports[] = "NO REPORTS";
+// Constant names for track identification.
+const char kTrackId[] = "somename";
+const uint32 kSsrcOfTrack = 1234;
+
class MockWebRtcSession : public webrtc::WebRtcSession {
public:
explicit MockWebRtcSession(cricket::ChannelManager* channel_manager)
@@ -207,11 +211,37 @@
new cricket::ChannelManager(media_engine_,
new cricket::FakeDeviceManager(),
talk_base::Thread::Current())),
- session_(channel_manager_.get()) {
+ session_(channel_manager_.get()),
+ track_id_(kTrackId) {
// By default, we ignore session GetStats calls.
EXPECT_CALL(session_, GetStats(_)).WillRepeatedly(Return(false));
}
+ // This creates a standard setup with a transport called "trspname"
+ // having one transport channel
+ // and the specified virtual connection name.
+ void InitSessionStats(const std::string vc_name) {
+ const std::string kTransportName("trspname");
+ cricket::TransportStats transport_stats;
+ cricket::TransportChannelStats channel_stats;
+ channel_stats.component = 1;
+ transport_stats.content_name = kTransportName;
+ transport_stats.channel_stats.push_back(channel_stats);
+
+ session_stats_.transport_stats[kTransportName] = transport_stats;
+ session_stats_.proxy_to_transport[vc_name] = kTransportName;
+ }
+
+ // Adds a track with a given SSRC into the stats.
+ void AddVideoTrackStats() {
+ stream_ = webrtc::MediaStream::Create("streamlabel");
+ track_= webrtc::VideoTrack::Create(kTrackId, NULL);
+ stream_->AddTrack(track_);
+ EXPECT_CALL(session_, GetTrackIdBySsrc(kSsrcOfTrack, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(track_id_),
+ Return(true)));
+ }
+
void TestCertificateReports(const talk_base::FakeSSLCertificate& local_cert,
const std::vector<std::string>& local_ders,
const talk_base::FakeSSLCertificate& remote_cert,
@@ -283,9 +313,14 @@
EXPECT_NE(kNotFound, remote_certificate_id);
CheckCertChainReports(reports, remote_ders, remote_certificate_id);
}
+
cricket::FakeMediaEngine* media_engine_;
talk_base::scoped_ptr<cricket::ChannelManager> channel_manager_;
MockWebRtcSession session_;
+ cricket::SessionStats session_stats_;
+ talk_base::scoped_refptr<webrtc::MediaStream> stream_;
+ talk_base::scoped_refptr<webrtc::VideoTrack> track_;
+ std::string track_id_;
};
// This test verifies that 64-bit counters are passed successfully.
@@ -297,17 +332,13 @@
webrtc::StatsReports reports; // returned values.
cricket::VideoSenderInfo video_sender_info;
cricket::VideoMediaInfo stats_read;
- const uint32 kSsrcOfTrack = 1234;
- const std::string kNameOfTrack("somename");
// The number of bytes must be larger than 0xFFFFFFFF for this test.
const int64 kBytesSent = 12345678901234LL;
const std::string kBytesSentString("12345678901234");
stats.set_session(&session_);
- talk_base::scoped_refptr<webrtc::MediaStream> stream(
- webrtc::MediaStream::Create("streamlabel"));
- stream->AddTrack(webrtc::VideoTrack::Create(kNameOfTrack, NULL));
- stats.AddStream(stream);
+ AddVideoTrackStats();
+ stats.AddStream(stream_);
// Construct a stats value to read.
video_sender_info.ssrcs.push_back(1234);
@@ -319,9 +350,6 @@
EXPECT_CALL(*media_channel, GetStats(_))
.WillOnce(DoAll(SetArgPointee<0>(stats_read),
Return(true)));
- EXPECT_CALL(session_, GetTrackIdBySsrc(kSsrcOfTrack, _))
- .WillOnce(DoAll(SetArgPointee<1>(kNameOfTrack),
- Return(true)));
stats.UpdateStats();
stats.GetStats(NULL, &reports);
std::string result = ExtractSsrcStatsValue(reports, "bytesSent");
@@ -339,16 +367,12 @@
cricket::VideoMediaInfo stats_read;
// Set up an SSRC just to test that we get both kinds of stats back: SSRC and
// BWE.
- const uint32 kSsrcOfTrack = 1234;
- const std::string kNameOfTrack("somename");
const int64 kBytesSent = 12345678901234LL;
const std::string kBytesSentString("12345678901234");
stats.set_session(&session_);
- talk_base::scoped_refptr<webrtc::MediaStream> stream(
- webrtc::MediaStream::Create("streamlabel"));
- stream->AddTrack(webrtc::VideoTrack::Create(kNameOfTrack, NULL));
- stats.AddStream(stream);
+ AddVideoTrackStats();
+ stats.AddStream(stream_);
// Construct a stats value to read.
video_sender_info.ssrcs.push_back(1234);
@@ -365,9 +389,7 @@
EXPECT_CALL(*media_channel, GetStats(_))
.WillOnce(DoAll(SetArgPointee<0>(stats_read),
Return(true)));
- EXPECT_CALL(session_, GetTrackIdBySsrc(kSsrcOfTrack, _))
- .WillOnce(DoAll(SetArgPointee<1>(kNameOfTrack),
- Return(true)));
+
stats.UpdateStats();
stats.GetStats(NULL, &reports);
std::string result = ExtractSsrcStatsValue(reports, "bytesSent");
@@ -417,13 +439,8 @@
MockVideoMediaChannel* media_channel = new MockVideoMediaChannel;
cricket::VideoChannel video_channel(talk_base::Thread::Current(),
media_engine_, media_channel, &session_, "", false, NULL);
- const std::string kTrackId("somename");
- talk_base::scoped_refptr<webrtc::MediaStream> stream(
- webrtc::MediaStream::Create("streamlabel"));
- talk_base::scoped_refptr<webrtc::VideoTrack> track =
- webrtc::VideoTrack::Create(kTrackId, NULL);
- stream->AddTrack(track);
- stats.AddStream(stream);
+ AddVideoTrackStats();
+ stats.AddStream(stream_);
stats.set_session(&session_);
@@ -449,13 +466,8 @@
MockVideoMediaChannel* media_channel = new MockVideoMediaChannel;
cricket::VideoChannel video_channel(talk_base::Thread::Current(),
media_engine_, media_channel, &session_, "", false, NULL);
- const std::string kTrackId("somename");
- talk_base::scoped_refptr<webrtc::MediaStream> stream(
- webrtc::MediaStream::Create("streamlabel"));
- talk_base::scoped_refptr<webrtc::VideoTrack> track =
- webrtc::VideoTrack::Create(kTrackId, NULL);
- stream->AddTrack(track);
- stats.AddStream(stream);
+ AddVideoTrackStats();
+ stats.AddStream(stream_);
stats.set_session(&session_);
@@ -464,7 +476,6 @@
// Constructs an ssrc stats update.
cricket::VideoSenderInfo video_sender_info;
cricket::VideoMediaInfo stats_read;
- const uint32 kSsrcOfTrack = 1234;
const int64 kBytesSent = 12345678901234LL;
// Construct a stats value to read.
@@ -477,23 +488,20 @@
EXPECT_CALL(*media_channel, GetStats(_))
.WillOnce(DoAll(SetArgPointee<0>(stats_read),
Return(true)));
- EXPECT_CALL(session_, GetTrackIdBySsrc(kSsrcOfTrack, _))
- .WillOnce(DoAll(SetArgPointee<1>(kTrackId),
- Return(true)));
stats.UpdateStats();
stats.GetStats(NULL, &reports);
- // |reports| should contain one session report, one track report, and one ssrc
- // report.
- EXPECT_EQ((size_t)3, reports.size());
+ // |reports| should contain at least one session report, one track report,
+ // and one ssrc report.
+ EXPECT_LE((size_t)3, reports.size());
const webrtc::StatsReport* track_report = FindNthReportByType(
reports, webrtc::StatsReport::kStatsReportTypeTrack, 1);
EXPECT_FALSE(track_report == NULL);
- stats.GetStats(track, &reports);
- // |reports| should contain one session report, one track report, and one ssrc
- // report.
- EXPECT_EQ((size_t)3, reports.size());
+ stats.GetStats(track_, &reports);
+ // |reports| should contain at least one session report, one track report,
+ // and one ssrc report.
+ EXPECT_LE((size_t)3, reports.size());
track_report = FindNthReportByType(
reports, webrtc::StatsReport::kStatsReportTypeTrack, 1);
EXPECT_FALSE(track_report == NULL);
@@ -516,13 +524,8 @@
const std::string kVcName("vcname");
cricket::VideoChannel video_channel(talk_base::Thread::Current(),
media_engine_, media_channel, &session_, kVcName, false, NULL);
- const std::string kTrackId("somename");
- talk_base::scoped_refptr<webrtc::MediaStream> stream(
- webrtc::MediaStream::Create("streamlabel"));
- talk_base::scoped_refptr<webrtc::VideoTrack> track =
- webrtc::VideoTrack::Create(kTrackId, NULL);
- stream->AddTrack(track);
- stats.AddStream(stream);
+ AddVideoTrackStats();
+ stats.AddStream(stream_);
stats.set_session(&session_);
@@ -531,7 +534,6 @@
// Constructs an ssrc stats update.
cricket::VideoSenderInfo video_sender_info;
cricket::VideoMediaInfo stats_read;
- const uint32 kSsrcOfTrack = 1234;
const int64 kBytesSent = 12345678901234LL;
// Construct a stats value to read.
@@ -544,23 +546,10 @@
EXPECT_CALL(*media_channel, GetStats(_))
.WillRepeatedly(DoAll(SetArgPointee<0>(stats_read),
Return(true)));
- EXPECT_CALL(session_, GetTrackIdBySsrc(kSsrcOfTrack, _))
- .WillOnce(DoAll(SetArgPointee<1>(kTrackId),
- Return(true)));
- // Instruct the session to return stats containing the transport channel.
- const std::string kTransportName("trspname");
- cricket::SessionStats session_stats;
- cricket::TransportStats transport_stats;
- cricket::TransportChannelStats channel_stats;
- channel_stats.component = 1;
- transport_stats.content_name = kTransportName;
- transport_stats.channel_stats.push_back(channel_stats);
-
- session_stats.transport_stats[kTransportName] = transport_stats;
- session_stats.proxy_to_transport[kVcName] = kTransportName;
+ InitSessionStats(kVcName);
EXPECT_CALL(session_, GetStats(_))
- .WillRepeatedly(DoAll(SetArgPointee<0>(session_stats),
+ .WillRepeatedly(DoAll(SetArgPointee<0>(session_stats_),
Return(true)));
stats.UpdateStats();
@@ -575,6 +564,78 @@
ASSERT_FALSE(transport_report == NULL);
}
+// This test verifies that a remote stats object will not be created for
+// an outgoing SSRC where remote stats are not returned.
+TEST_F(StatsCollectorTest, RemoteSsrcInfoIsAbsent) {
+ webrtc::StatsCollector stats; // Implementation under test.
+ MockVideoMediaChannel* media_channel = new MockVideoMediaChannel;
+ // The content_name known by the video channel.
+ const std::string kVcName("vcname");
+ cricket::VideoChannel video_channel(talk_base::Thread::Current(),
+ media_engine_, media_channel, &session_, kVcName, false, NULL);
+ AddVideoTrackStats();
+ stats.AddStream(stream_);
+
+ stats.set_session(&session_);
+
+ EXPECT_CALL(session_, video_channel())
+ .WillRepeatedly(ReturnNull());
+
+ stats.UpdateStats();
+ webrtc::StatsReports reports;
+ stats.GetStats(NULL, &reports);
+ const webrtc::StatsReport* remote_report = FindNthReportByType(reports,
+ webrtc::StatsReport::kStatsReportTypeRemoteSsrc, 1);
+ EXPECT_TRUE(remote_report == NULL);
+}
+
+// This test verifies that a remote stats object will be created for
+// an outgoing SSRC where stats are returned.
+TEST_F(StatsCollectorTest, RemoteSsrcInfoIsPresent) {
+ webrtc::StatsCollector stats; // Implementation under test.
+ MockVideoMediaChannel* media_channel = new MockVideoMediaChannel;
+ // The content_name known by the video channel.
+ const std::string kVcName("vcname");
+ cricket::VideoChannel video_channel(talk_base::Thread::Current(),
+ media_engine_, media_channel, &session_, kVcName, false, NULL);
+ AddVideoTrackStats();
+ stats.AddStream(stream_);
+
+ stats.set_session(&session_);
+
+ webrtc::StatsReports reports;
+
+ // Instruct the session to return stats containing the transport channel.
+ InitSessionStats(kVcName);
+ EXPECT_CALL(session_, GetStats(_))
+ .WillRepeatedly(DoAll(SetArgPointee<0>(session_stats_),
+ Return(true)));
+
+ // Constructs an ssrc stats update.
+ cricket::VideoMediaInfo stats_read;
+
+ cricket::SsrcReceiverInfo remote_ssrc_stats;
+ remote_ssrc_stats.timestamp = 12345.678;
+ remote_ssrc_stats.ssrc = kSsrcOfTrack;
+ cricket::VideoSenderInfo video_sender_info;
+ video_sender_info.ssrcs.push_back(kSsrcOfTrack);
+ video_sender_info.remote_stats.push_back(remote_ssrc_stats);
+ stats_read.senders.push_back(video_sender_info);
+
+ EXPECT_CALL(session_, video_channel())
+ .WillRepeatedly(Return(&video_channel));
+ EXPECT_CALL(*media_channel, GetStats(_))
+ .WillRepeatedly(DoAll(SetArgPointee<0>(stats_read),
+ Return(true)));
+
+ stats.UpdateStats();
+ stats.GetStats(NULL, &reports);
+ const webrtc::StatsReport* remote_report = FindNthReportByType(reports,
+ webrtc::StatsReport::kStatsReportTypeRemoteSsrc, 1);
+ EXPECT_FALSE(remote_report == NULL);
+ EXPECT_NE(0, remote_report->timestamp);
+}
+
// This test verifies that all chained certificates are correctly
// reported
TEST_F(StatsCollectorTest, ChainedCertificateReportsCreated) {
@@ -638,6 +699,7 @@
EXPECT_CALL(session_, GetStats(_))
.WillOnce(DoAll(SetArgPointee<0>(session_stats),
Return(true)));
+
EXPECT_CALL(session_, video_channel())
.WillRepeatedly(ReturnNull());
@@ -712,5 +774,4 @@
ASSERT_EQ(kNotFound, remote_certificate_id);
}
-
} // namespace
diff --git a/talk/app/webrtc/statstypes.h b/talk/app/webrtc/statstypes.h
index fb8c15b..e76aa86 100644
--- a/talk/app/webrtc/statstypes.h
+++ b/talk/app/webrtc/statstypes.h
@@ -88,6 +88,10 @@
// The |id| field is the SSRC in decimal form of the rtp stream.
static const char kStatsReportTypeSsrc[];
+ // StatsReport of |type| = "remoteSsrc" is statistics for a specific
+ // rtp stream, generated by the remote end of the connection.
+ static const char kStatsReportTypeRemoteSsrc[];
+
// StatsReport of |type| = "googTrack" is statistics for a specific media
// track. The |id| field is the track id.
static const char kStatsReportTypeTrack[];
@@ -137,6 +141,13 @@
static const char kStatsValueNameFrameRateReceived[];
static const char kStatsValueNameFrameRateDecoded[];
static const char kStatsValueNameFrameRateOutput[];
+ static const char kStatsValueNameDecodeMs[];
+ static const char kStatsValueNameMaxDecodeMs[];
+ static const char kStatsValueNameCurrentDelayMs[];
+ static const char kStatsValueNameTargetDelayMs[];
+ static const char kStatsValueNameJitterBufferMs[];
+ static const char kStatsValueNameMinPlayoutDelayMs[];
+ static const char kStatsValueNameRenderDelayMs[];
static const char kStatsValueNameFrameRateInput[];
static const char kStatsValueNameFrameRateSent[];
static const char kStatsValueNameFrameWidthReceived[];
diff --git a/talk/app/webrtc/test/fakeconstraints.h b/talk/app/webrtc/test/fakeconstraints.h
index 927432d..b23007e 100644
--- a/talk/app/webrtc/test/fakeconstraints.h
+++ b/talk/app/webrtc/test/fakeconstraints.h
@@ -119,7 +119,6 @@
}
void SetAllowDtlsSctpDataChannels() {
- SetMandatory(MediaConstraintsInterface::kEnableSctpDataChannels, true);
SetMandatory(MediaConstraintsInterface::kEnableDtlsSrtp, true);
}
diff --git a/talk/app/webrtc/webrtcsdp_unittest.cc b/talk/app/webrtc/webrtcsdp_unittest.cc
index 6f2e388..777a707 100644
--- a/talk/app/webrtc/webrtcsdp_unittest.cc
+++ b/talk/app/webrtc/webrtcsdp_unittest.cc
@@ -282,7 +282,7 @@
"a=ice-ufrag:ufrag_data\r\n"
"a=ice-pwd:pwd_data\r\n"
"a=mid:data_content_name\r\n"
- "a=sctpmap:5000 webrtc-datachannel 65536\r\n";
+ "a=sctpmap:5000 webrtc-datachannel 1024\r\n";
static const char kSdpSctpDataChannelWithCandidatesString[] =
"m=application 2345 DTLS/SCTP 5000\r\n"
@@ -297,7 +297,7 @@
"a=ice-ufrag:ufrag_data\r\n"
"a=ice-pwd:pwd_data\r\n"
"a=mid:data_content_name\r\n"
- "a=sctpmap:5000 webrtc-datachannel 65536\r\n";
+ "a=sctpmap:5000 webrtc-datachannel 1024\r\n";
// One candidate reference string as per W3c spec.
diff --git a/talk/app/webrtc/webrtcsession.cc b/talk/app/webrtc/webrtcsession.cc
index 74d1488..69a47c4 100644
--- a/talk/app/webrtc/webrtcsession.cc
+++ b/talk/app/webrtc/webrtcsession.cc
@@ -68,10 +68,7 @@
// line flag. So it is prefixed with kInternalConstraintPrefix so JS values
// will be removed.
const char MediaConstraintsInterface::kEnableSctpDataChannels[] =
- "internalSctpDataChannels";
-
-const char MediaConstraintsInterface::kInternalDisableEncryption[] =
- "internalDisableEncryption";
+ "deprecatedSctpDataChannels";
// Error messages
const char kSetLocalSdpFailed[] = "SetLocalDescription failed: ";
@@ -458,6 +455,7 @@
}
bool WebRtcSession::Initialize(
+ const PeerConnectionFactoryInterface::Options& options,
const MediaConstraintsInterface* constraints,
DTLSIdentityServiceInterface* dtls_identity_service) {
// TODO(perkj): Take |constraints| into consideration. Return false if not all
@@ -476,19 +474,16 @@
}
// Enable creation of RTP data channels if the kEnableRtpDataChannels is set.
- // It takes precendence over the kEnableSctpDataChannels constraint.
+ // It takes precendence over the disable_sctp_data_channels
+ // PeerConnectionFactoryInterface::Options.
if (FindConstraint(
constraints, MediaConstraintsInterface::kEnableRtpDataChannels,
&value, NULL) && value) {
LOG(LS_INFO) << "Allowing RTP data engine.";
data_channel_type_ = cricket::DCT_RTP;
} else {
- bool sctp_enabled = FindConstraint(
- constraints,
- MediaConstraintsInterface::kEnableSctpDataChannels,
- &value, NULL) && value;
// DTLS has to be enabled to use SCTP.
- if (sctp_enabled && dtls_enabled_) {
+ if (!options.disable_sctp_data_channels && dtls_enabled_) {
LOG(LS_INFO) << "Allowing SCTP data engine.";
data_channel_type_ = cricket::DCT_SCTP;
}
@@ -520,11 +515,7 @@
webrtc_session_desc_factory_->SignalIdentityReady.connect(
this, &WebRtcSession::OnIdentityReady);
- // Disable encryption if kDisableEncryption is set.
- if (FindConstraint(
- constraints,
- MediaConstraintsInterface::kInternalDisableEncryption,
- &value, NULL) && value) {
+ if (options.disable_encryption) {
webrtc_session_desc_factory_->set_secure(cricket::SEC_DISABLED);
}
diff --git a/talk/app/webrtc/webrtcsession.h b/talk/app/webrtc/webrtcsession.h
index 12e2291..dde33ca 100644
--- a/talk/app/webrtc/webrtcsession.h
+++ b/talk/app/webrtc/webrtcsession.h
@@ -110,7 +110,8 @@
MediaStreamSignaling* mediastream_signaling);
virtual ~WebRtcSession();
- bool Initialize(const MediaConstraintsInterface* constraints,
+ bool Initialize(const PeerConnectionFactoryInterface::Options& options,
+ const MediaConstraintsInterface* constraints,
DTLSIdentityServiceInterface* dtls_identity_service);
// Deletes the voice, video and data channel and changes the session state
// to STATE_RECEIVEDTERMINATE.
diff --git a/talk/app/webrtc/webrtcsession_unittest.cc b/talk/app/webrtc/webrtcsession_unittest.cc
index 493294f..ecbba18 100644
--- a/talk/app/webrtc/webrtcsession_unittest.cc
+++ b/talk/app/webrtc/webrtcsession_unittest.cc
@@ -81,6 +81,7 @@
using webrtc::IceCandidateCollection;
using webrtc::JsepIceCandidate;
using webrtc::JsepSessionDescription;
+using webrtc::PeerConnectionFactoryInterface;
using webrtc::PeerConnectionInterface;
using webrtc::SessionDescriptionInterface;
using webrtc::StreamCollection;
@@ -317,7 +318,8 @@
EXPECT_EQ(PeerConnectionInterface::kIceGatheringNew,
observer_.ice_gathering_state_);
- EXPECT_TRUE(session_->Initialize(constraints_.get(), identity_service));
+ EXPECT_TRUE(session_->Initialize(options_, constraints_.get(),
+ identity_service));
}
void InitWithDtmfCodec() {
@@ -919,6 +921,7 @@
cricket::TestStunServer stun_server_;
talk_base::FakeNetworkManager network_manager_;
cricket::BasicPortAllocator allocator_;
+ PeerConnectionFactoryInterface::Options options_;
talk_base::scoped_ptr<FakeConstraints> constraints_;
FakeMediaStreamSignaling mediastream_signaling_;
talk_base::scoped_ptr<WebRtcSessionForTest> session_;
@@ -1932,9 +1935,7 @@
}
TEST_F(WebRtcSessionTest, VerifyNoCryptoParamsInSDP) {
- constraints_.reset(new FakeConstraints());
- constraints_->AddOptional(
- webrtc::MediaConstraintsInterface::kInternalDisableEncryption, true);
+ options_.disable_encryption = true;
Init(NULL);
mediastream_signaling_.SendAudioVideoStream1();
scoped_ptr<SessionDescriptionInterface> offer(
@@ -2424,9 +2425,7 @@
// This test verifies the crypto parameter when security is disabled.
TEST_F(WebRtcSessionTest, TestCryptoAfterSetLocalDescriptionWithDisabled) {
- constraints_.reset(new FakeConstraints());
- constraints_->AddOptional(
- webrtc::MediaConstraintsInterface::kInternalDisableEncryption, true);
+ options_.disable_encryption = true;
Init(NULL);
mediastream_signaling_.SendAudioVideoStream1();
talk_base::scoped_ptr<SessionDescriptionInterface> offer(
@@ -2567,8 +2566,8 @@
constraints_.reset(new FakeConstraints());
constraints_->AddOptional(
webrtc::MediaConstraintsInterface::kEnableRtpDataChannels, true);
- constraints_->AddOptional(
- webrtc::MediaConstraintsInterface::kEnableSctpDataChannels, true);
+ options_.disable_sctp_data_channels = false;
+
InitWithDtls(false);
SetLocalDescriptionWithDataChannel();
@@ -2578,9 +2577,6 @@
TEST_F(WebRtcSessionTest, TestCreateOfferWithSctpEnabledWithoutStreams) {
MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
- constraints_.reset(new FakeConstraints());
- constraints_->AddOptional(
- webrtc::MediaConstraintsInterface::kEnableSctpDataChannels, true);
InitWithDtls(false);
talk_base::scoped_ptr<SessionDescriptionInterface> offer(CreateOffer(NULL));
@@ -2591,9 +2587,6 @@
TEST_F(WebRtcSessionTest, TestCreateAnswerWithSctpInOfferAndNoStreams) {
MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
SetFactoryDtlsSrtp();
- constraints_.reset(new FakeConstraints());
- constraints_->AddOptional(
- webrtc::MediaConstraintsInterface::kEnableSctpDataChannels, true);
InitWithDtls(false);
// Create remote offer with SCTP.
@@ -2613,8 +2606,6 @@
TEST_F(WebRtcSessionTest, TestSctpDataChannelWithoutDtls) {
constraints_.reset(new FakeConstraints());
constraints_->AddOptional(
- webrtc::MediaConstraintsInterface::kEnableSctpDataChannels, true);
- constraints_->AddOptional(
webrtc::MediaConstraintsInterface::kEnableDtlsSrtp, false);
InitWithDtls(false);
@@ -2625,24 +2616,26 @@
TEST_F(WebRtcSessionTest, TestSctpDataChannelWithDtls) {
MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
- constraints_.reset(new FakeConstraints());
- constraints_->AddOptional(
- webrtc::MediaConstraintsInterface::kEnableSctpDataChannels, true);
InitWithDtls(false);
SetLocalDescriptionWithDataChannel();
EXPECT_EQ(cricket::DCT_SCTP, data_engine_->last_channel_type());
}
+TEST_F(WebRtcSessionTest, TestDisableSctpDataChannels) {
+ MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
+ options_.disable_sctp_data_channels = true;
+ InitWithDtls(false);
+
+ SetLocalDescriptionWithDataChannel();
+ EXPECT_EQ(cricket::DCT_NONE, data_engine_->last_channel_type());
+}
+
TEST_F(WebRtcSessionTest, TestSctpDataChannelSendPortParsing) {
MAYBE_SKIP_TEST(talk_base::SSLStreamAdapter::HaveDtlsSrtp);
const int new_send_port = 9998;
const int new_recv_port = 7775;
- constraints_.reset(new FakeConstraints());
- constraints_->AddOptional(
- webrtc::MediaConstraintsInterface::kEnableSctpDataChannels, true);
-
InitWithDtls(false);
SetFactoryDtlsSrtp();
diff --git a/talk/base/atomicops.h b/talk/base/atomicops.h
index 94ade69..068cd5f 100644
--- a/talk/base/atomicops.h
+++ b/talk/base/atomicops.h
@@ -79,7 +79,7 @@
FixedSizeLockFreeQueue() : pushed_count_(0),
popped_count_(0),
capacity_(0),
- data_(NULL) {}
+ data_() {}
// Constructs an empty queue with the given capacity.
FixedSizeLockFreeQueue(size_t capacity) : pushed_count_(0),
popped_count_(0),
@@ -157,7 +157,7 @@
volatile Atomic32 pushed_count_;
volatile Atomic32 popped_count_;
size_t capacity_;
- talk_base::scoped_array<T> data_;
+ talk_base::scoped_ptr<T[]> data_;
DISALLOW_COPY_AND_ASSIGN(FixedSizeLockFreeQueue);
};
diff --git a/talk/base/buffer.h b/talk/base/buffer.h
index 311cfad..4709633 100644
--- a/talk/base/buffer.h
+++ b/talk/base/buffer.h
@@ -88,7 +88,7 @@
}
void SetCapacity(size_t capacity) {
if (capacity > capacity_) {
- talk_base::scoped_array<char> data(new char[capacity]);
+ talk_base::scoped_ptr<char[]> data(new char[capacity]);
memcpy(data.get(), data_.get(), length_);
data_.swap(data);
capacity_ = capacity;
@@ -109,7 +109,7 @@
SetData(data, length);
}
- scoped_array<char> data_;
+ scoped_ptr<char[]> data_;
size_t length_;
size_t capacity_;
};
diff --git a/talk/base/common.h b/talk/base/common.h
index b9aeca4..6350baf 100644
--- a/talk/base/common.h
+++ b/talk/base/common.h
@@ -25,7 +25,7 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef TALK_BASE_COMMON_H_
+#ifndef TALK_BASE_COMMON_H_ // NOLINT
#define TALK_BASE_COMMON_H_
#include "talk/base/basictypes.h"
@@ -64,7 +64,7 @@
#define strnicmp(x, y, n) strncasecmp(x, y, n)
#define stricmp(x, y) strcasecmp(x, y)
-// TODO: Remove this. std::max should be used everywhere in the code.
+// TODO(fbarchard): Remove this. std::max should be used everywhere in the code.
// NOMINMAX must be defined where we include <windows.h>.
#define stdmax(x, y) std::max(x, y)
#else
@@ -181,9 +181,28 @@
#if defined(WIN32)
#define OVERRIDE override
#elif defined(__clang__)
+// Clang defaults to C++03 and warns about using override. Squelch that.
+// Intentionally no push/pop here so all users of OVERRIDE ignore the warning
+// too. This is like passing -Wno-c++11-extensions, except that GCC won't die
+// (because it won't see this pragma).
+#pragma clang diagnostic ignored "-Wc++11-extensions"
#define OVERRIDE override
#else
#define OVERRIDE
#endif
-#endif // TALK_BASE_COMMON_H_
+// Annotate a function indicating the caller must examine the return value.
+// Use like:
+// int foo() WARN_UNUSED_RESULT;
+// To explicitly ignore a result, see |ignore_result()| in <base/basictypes.h>.
+// TODO(ajm): Hack to avoid multiple definitions until the base/ of webrtc and
+// libjingle are merged.
+#if !defined(WARN_UNUSED_RESULT)
+#if defined(COMPILER_GCC)
+#define WARN_UNUSED_RESULT __attribute__((warn_unused_result))
+#else
+#define WARN_UNUSED_RESULT
+#endif
+#endif // WARN_UNUSED_RESULT
+
+#endif // TALK_BASE_COMMON_H_ // NOLINT
diff --git a/talk/base/compile_assert.h b/talk/base/compile_assert.h
new file mode 100644
index 0000000..7252d08
--- /dev/null
+++ b/talk/base/compile_assert.h
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+
+// COMPILE_ASSERT macro, borrowed from google3/base/macros.h.
+#ifndef TALK_BASE_COMPILE_ASSERT_H_
+#define TALK_BASE_COMPILE_ASSERT_H_
+
+// The COMPILE_ASSERT macro can be used to verify that a compile time
+// expression is true. For example, you could use it to verify the
+// size of a static array:
+//
+// COMPILE_ASSERT(ARRAYSIZE(content_type_names) == CONTENT_NUM_TYPES,
+// content_type_names_incorrect_size);
+//
+// or to make sure a struct is smaller than a certain size:
+//
+// COMPILE_ASSERT(sizeof(foo) < 128, foo_too_large);
+//
+// The second argument to the macro is the name of the variable. If
+// the expression is false, most compilers will issue a warning/error
+// containing the name of the variable.
+
+// TODO(ajm): Hack to avoid multiple definitions until the base/ of webrtc and
+// libjingle are merged.
+#if !defined(COMPILE_ASSERT)
+template <bool>
+struct CompileAssert {
+};
+
+#define COMPILE_ASSERT(expr, msg) \
+ typedef CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1] // NOLINT
+#endif // COMPILE_ASSERT
+
+// Implementation details of COMPILE_ASSERT:
+//
+// - COMPILE_ASSERT works by defining an array type that has -1
+// elements (and thus is invalid) when the expression is false.
+//
+// - The simpler definition
+//
+// #define COMPILE_ASSERT(expr, msg) typedef char msg[(expr) ? 1 : -1]
+//
+// does not work, as gcc supports variable-length arrays whose sizes
+// are determined at run-time (this is gcc's extension and not part
+// of the C++ standard). As a result, gcc fails to reject the
+// following code with the simple definition:
+//
+// int foo;
+// COMPILE_ASSERT(foo, msg); // not supposed to compile as foo is
+// // not a compile-time constant.
+//
+// - By using the type CompileAssert<(bool(expr))>, we ensures that
+// expr is a compile-time constant. (Template arguments must be
+// determined at compile-time.)
+//
+// - The outer parentheses in CompileAssert<(bool(expr))> are necessary
+// to work around a bug in gcc 3.4.4 and 4.0.1. If we had written
+//
+// CompileAssert<bool(expr)>
+//
+// instead, these compilers will refuse to compile
+//
+// COMPILE_ASSERT(5 > 0, some_message);
+//
+// (They seem to think the ">" in "5 > 0" marks the end of the
+// template argument list.)
+//
+// - The array size is (bool(expr) ? 1 : -1), instead of simply
+//
+// ((expr) ? 1 : -1).
+//
+// This is to avoid running into a bug in MS VC 7.1, which
+// causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1.
+
+#endif // TALK_BASE_COMPILE_ASSERT_H_
diff --git a/talk/base/constructormagic.h b/talk/base/constructormagic.h
index 8b1f7ff..3023044 100644
--- a/talk/base/constructormagic.h
+++ b/talk/base/constructormagic.h
@@ -2,26 +2,26 @@
* libjingle
* Copyright 2004--2005, Google Inc.
*
- * Redistribution and use in source and binary forms, with or without
+ * 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,
+ * 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
+ * 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
+ * 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,
+ * 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
+ * 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.
*/
@@ -32,7 +32,10 @@
void operator=(const TypeName&)
// A macro to disallow the evil copy constructor and operator= functions
-// This should be used in the private: declarations for a class
+// This should be used in the private: declarations for a class.
+// Undefine this, just in case. Some third-party includes have their own
+// version.
+#undef DISALLOW_COPY_AND_ASSIGN
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName&); \
DISALLOW_ASSIGN(TypeName)
diff --git a/talk/base/cpumonitor.cc b/talk/base/cpumonitor.cc
index 0a70887..e9b481f 100644
--- a/talk/base/cpumonitor.cc
+++ b/talk/base/cpumonitor.cc
@@ -210,7 +210,7 @@
} else {
if (nt_query_system_information) {
ULONG returned_length = 0;
- scoped_array<SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION> processor_info(
+ scoped_ptr<SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION[]> processor_info(
new SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION[cpus_]);
nt_query_system_information(
::SystemProcessorPerformanceInformation,
@@ -281,6 +281,13 @@
const uint64 cpu_times = nice + system + user;
const uint64 total_times = cpu_times + idle;
#endif // defined(LINUX) || defined(ANDROID)
+
+#if defined(__native_client__)
+ // TODO(ryanpetrie): Implement this via PPAPI when it's available.
+ const uint64 cpu_times = 0;
+ const uint64 total_times = 0;
+#endif // defined(__native_client__)
+
system_.prev_load_time_ = timenow;
system_.prev_load_ = UpdateCpuLoad(total_times,
cpu_times * cpus_,
@@ -359,6 +366,12 @@
(usage.ru_utime.tv_sec + usage.ru_stime.tv_sec) * kNumMicrosecsPerSec +
usage.ru_utime.tv_usec + usage.ru_stime.tv_usec;
#endif // defined(LINUX) || defined(ANDROID)
+
+#if defined(__native_client__)
+ // TODO(ryanpetrie): Implement this via PPAPI when it's available.
+ const uint64 cpu_times = 0;
+#endif // defined(__native_client__)
+
process_.prev_load_time_ = timenow;
process_.prev_load_ = UpdateCpuLoad(total_times,
cpu_times,
diff --git a/talk/base/helpers.cc b/talk/base/helpers.cc
index bda940b..b10a3f7 100644
--- a/talk/base/helpers.cc
+++ b/talk/base/helpers.cc
@@ -239,7 +239,7 @@
const char* table, int table_size,
std::string* str) {
str->clear();
- scoped_array<uint8> bytes(new uint8[len]);
+ scoped_ptr<uint8[]> bytes(new uint8[len]);
if (!Rng().Generate(bytes.get(), len)) {
LOG(LS_ERROR) << "Failed to generate random string!";
return false;
diff --git a/talk/base/macutils.cc b/talk/base/macutils.cc
index c73b0fa..28f96e2 100644
--- a/talk/base/macutils.cc
+++ b/talk/base/macutils.cc
@@ -43,7 +43,7 @@
size_t maxlen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(str16),
kCFStringEncodingUTF8)
+ 1;
- scoped_array<char> buffer(new char[maxlen]);
+ scoped_ptr<char[]> buffer(new char[maxlen]);
if (!buffer || !CFStringGetCString(str16, buffer.get(), maxlen,
kCFStringEncodingUTF8))
return false;
diff --git a/talk/base/messagedigest.cc b/talk/base/messagedigest.cc
index 6136ae2..d91d067 100644
--- a/talk/base/messagedigest.cc
+++ b/talk/base/messagedigest.cc
@@ -85,7 +85,7 @@
}
std::string ComputeDigest(MessageDigest* digest, const std::string& input) {
- scoped_array<char> output(new char[digest->Size()]);
+ scoped_ptr<char[]> output(new char[digest->Size()]);
ComputeDigest(digest, input.data(), input.size(),
output.get(), digest->Size());
return hex_encode(output.get(), digest->Size());
@@ -120,7 +120,7 @@
}
// Copy the key to a block-sized buffer to simplify padding.
// If the key is longer than a block, hash it and use the result instead.
- scoped_array<uint8> new_key(new uint8[block_len]);
+ scoped_ptr<uint8[]> new_key(new uint8[block_len]);
if (key_len > block_len) {
ComputeDigest(digest, key, key_len, new_key.get(), block_len);
memset(new_key.get() + digest->Size(), 0, block_len - digest->Size());
@@ -129,13 +129,13 @@
memset(new_key.get() + key_len, 0, block_len - key_len);
}
// Set up the padding from the key, salting appropriately for each padding.
- scoped_array<uint8> o_pad(new uint8[block_len]), i_pad(new uint8[block_len]);
+ scoped_ptr<uint8[]> o_pad(new uint8[block_len]), i_pad(new uint8[block_len]);
for (size_t i = 0; i < block_len; ++i) {
o_pad[i] = 0x5c ^ new_key[i];
i_pad[i] = 0x36 ^ new_key[i];
}
// Inner hash; hash the inner padding, and then the input buffer.
- scoped_array<uint8> inner(new uint8[digest->Size()]);
+ scoped_ptr<uint8[]> inner(new uint8[digest->Size()]);
digest->Update(i_pad.get(), block_len);
digest->Update(input, in_len);
digest->Finish(inner.get(), digest->Size());
@@ -158,7 +158,7 @@
std::string ComputeHmac(MessageDigest* digest, const std::string& key,
const std::string& input) {
- scoped_array<char> output(new char[digest->Size()]);
+ scoped_ptr<char[]> output(new char[digest->Size()]);
ComputeHmac(digest, key.data(), key.size(),
input.data(), input.size(), output.get(), digest->Size());
return hex_encode(output.get(), digest->Size());
diff --git a/talk/base/move.h b/talk/base/move.h
new file mode 100644
index 0000000..0cd1dcf
--- /dev/null
+++ b/talk/base/move.h
@@ -0,0 +1,207 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_WEBRTC_FILES_TALK_BASE_MOVE_H_
+#define THIRD_PARTY_WEBRTC_FILES_TALK_BASE_MOVE_H_
+
+// Macro with the boilerplate that makes a type move-only in C++03.
+//
+// USAGE
+//
+// This macro should be used instead of DISALLOW_COPY_AND_ASSIGN to create
+// a "move-only" type. Unlike DISALLOW_COPY_AND_ASSIGN, this macro should be
+// the first line in a class declaration.
+//
+// A class using this macro must call .Pass() (or somehow be an r-value already)
+// before it can be:
+//
+// * Passed as a function argument
+// * Used as the right-hand side of an assignment
+// * Returned from a function
+//
+// Each class will still need to define their own "move constructor" and "move
+// operator=" to make this useful. Here's an example of the macro, the move
+// constructor, and the move operator= from the scoped_ptr class:
+//
+// template <typename T>
+// class scoped_ptr {
+// MOVE_ONLY_TYPE_FOR_CPP_03(scoped_ptr, RValue)
+// public:
+// scoped_ptr(RValue& other) : ptr_(other.release()) { }
+// scoped_ptr& operator=(RValue& other) {
+// swap(other);
+// return *this;
+// }
+// };
+//
+// Note that the constructor must NOT be marked explicit.
+//
+// For consistency, the second parameter to the macro should always be RValue
+// unless you have a strong reason to do otherwise. It is only exposed as a
+// macro parameter so that the move constructor and move operator= don't look
+// like they're using a phantom type.
+//
+//
+// HOW THIS WORKS
+//
+// For a thorough explanation of this technique, see:
+//
+// http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Move_Constructor
+//
+// The summary is that we take advantage of 2 properties:
+//
+// 1) non-const references will not bind to r-values.
+// 2) C++ can apply one user-defined conversion when initializing a
+// variable.
+//
+// The first lets us disable the copy constructor and assignment operator
+// by declaring private version of them with a non-const reference parameter.
+//
+// For l-values, direct initialization still fails like in
+// DISALLOW_COPY_AND_ASSIGN because the copy constructor and assignment
+// operators are private.
+//
+// For r-values, the situation is different. The copy constructor and
+// assignment operator are not viable due to (1), so we are trying to call
+// a non-existent constructor and non-existing operator= rather than a private
+// one. Since we have not committed an error quite yet, we can provide an
+// alternate conversion sequence and a constructor. We add
+//
+// * a private struct named "RValue"
+// * a user-defined conversion "operator RValue()"
+// * a "move constructor" and "move operator=" that take the RValue& as
+// their sole parameter.
+//
+// Only r-values will trigger this sequence and execute our "move constructor"
+// or "move operator=." L-values will match the private copy constructor and
+// operator= first giving a "private in this context" error. This combination
+// gives us a move-only type.
+//
+// For signaling a destructive transfer of data from an l-value, we provide a
+// method named Pass() which creates an r-value for the current instance
+// triggering the move constructor or move operator=.
+//
+// Other ways to get r-values is to use the result of an expression like a
+// function call.
+//
+// Here's an example with comments explaining what gets triggered where:
+//
+// class Foo {
+// MOVE_ONLY_TYPE_FOR_CPP_03(Foo, RValue);
+//
+// public:
+// ... API ...
+// Foo(RValue other); // Move constructor.
+// Foo& operator=(RValue rhs); // Move operator=
+// };
+//
+// Foo MakeFoo(); // Function that returns a Foo.
+//
+// Foo f;
+// Foo f_copy(f); // ERROR: Foo(Foo&) is private in this context.
+// Foo f_assign;
+// f_assign = f; // ERROR: operator=(Foo&) is private in this context.
+//
+//
+// Foo f(MakeFoo()); // R-value so alternate conversion executed.
+// Foo f_copy(f.Pass()); // R-value so alternate conversion executed.
+// f = f_copy.Pass(); // R-value so alternate conversion executed.
+//
+//
+// IMPLEMENTATION SUBTLETIES WITH RValue
+//
+// The RValue struct is just a container for a pointer back to the original
+// object. It should only ever be created as a temporary, and no external
+// class should ever declare it or use it in a parameter.
+//
+// It is tempting to want to use the RValue type in function parameters, but
+// excluding the limited usage here for the move constructor and move
+// operator=, doing so would mean that the function could take both r-values
+// and l-values equially which is unexpected. See COMPARED To Boost.Move for
+// more details.
+//
+// An alternate, and incorrect, implementation of the RValue class used by
+// Boost.Move makes RValue a fieldless child of the move-only type. RValue&
+// is then used in place of RValue in the various operators. The RValue& is
+// "created" by doing *reinterpret_cast<RValue*>(this). This has the appeal
+// of never creating a temporary RValue struct even with optimizations
+// disabled. Also, by virtue of inheritance you can treat the RValue
+// reference as if it were the move-only type itself. Unfortunately,
+// using the result of this reinterpret_cast<> is actually undefined behavior
+// due to C++98 5.2.10.7. In certain compilers (e.g., NaCl) the optimizer
+// will generate non-working code.
+//
+// In optimized builds, both implementations generate the same assembly so we
+// choose the one that adheres to the standard.
+//
+//
+// COMPARED TO C++11
+//
+// In C++11, you would implement this functionality using an r-value reference
+// and our .Pass() method would be replaced with a call to std::move().
+//
+// This emulation also has a deficiency where it uses up the single
+// user-defined conversion allowed by C++ during initialization. This can
+// cause problems in some API edge cases. For instance, in scoped_ptr, it is
+// impossible to make a function "void Foo(scoped_ptr<Parent> p)" accept a
+// value of type scoped_ptr<Child> even if you add a constructor to
+// scoped_ptr<> that would make it look like it should work. C++11 does not
+// have this deficiency.
+//
+//
+// COMPARED TO Boost.Move
+//
+// Our implementation similar to Boost.Move, but we keep the RValue struct
+// private to the move-only type, and we don't use the reinterpret_cast<> hack.
+//
+// In Boost.Move, RValue is the boost::rv<> template. This type can be used
+// when writing APIs like:
+//
+// void MyFunc(boost::rv<Foo>& f)
+//
+// that can take advantage of rv<> to avoid extra copies of a type. However you
+// would still be able to call this version of MyFunc with an l-value:
+//
+// Foo f;
+// MyFunc(f); // Uh oh, we probably just destroyed |f| w/o calling Pass().
+//
+// unless someone is very careful to also declare a parallel override like:
+//
+// void MyFunc(const Foo& f)
+//
+// that would catch the l-values first. This was declared unsafe in C++11 and
+// a C++11 compiler will explicitly fail MyFunc(f). Unfortunately, we cannot
+// ensure this in C++03.
+//
+// Since we have no need for writing such APIs yet, our implementation keeps
+// RValue private and uses a .Pass() method to do the conversion instead of
+// trying to write a version of "std::move()." Writing an API like std::move()
+// would require the RValue struct to be public.
+//
+//
+// CAVEATS
+//
+// If you include a move-only type as a field inside a class that does not
+// explicitly declare a copy constructor, the containing class's implicit
+// copy constructor will change from Containing(const Containing&) to
+// Containing(Containing&). This can cause some unexpected errors.
+//
+// http://llvm.org/bugs/show_bug.cgi?id=11528
+//
+// The workaround is to explicitly declare your copy constructor.
+//
+#define MOVE_ONLY_TYPE_FOR_CPP_03(type, rvalue_type) \
+ private: \
+ struct rvalue_type { \
+ explicit rvalue_type(type* object) : object(object) {} \
+ type* object; \
+ }; \
+ type(type&); \
+ void operator=(type&); \
+ public: \
+ operator rvalue_type() { return rvalue_type(this); } \
+ type Pass() { return type(rvalue_type(this)); } \
+ private:
+
+#endif // THIRD_PARTY_WEBRTC_FILES_TALK_BASE_MOVE_H_
diff --git a/talk/base/natserver.cc b/talk/base/natserver.cc
index ef85f74..3ad378c 100644
--- a/talk/base/natserver.cc
+++ b/talk/base/natserver.cc
@@ -149,7 +149,7 @@
// Forward this packet to the internal address.
// First prepend the address in a quasi-STUN format.
- scoped_array<char> real_buf(new char[size + kNATEncodedIPv6AddressSize]);
+ scoped_ptr<char[]> real_buf(new char[size + kNATEncodedIPv6AddressSize]);
size_t addrlength = PackAddressForNAT(real_buf.get(),
size + kNATEncodedIPv6AddressSize,
remote_addr);
diff --git a/talk/base/natsocketfactory.cc b/talk/base/natsocketfactory.cc
index 1686f20..395069e 100644
--- a/talk/base/natsocketfactory.cc
+++ b/talk/base/natsocketfactory.cc
@@ -154,7 +154,7 @@
return socket_->SendTo(data, size, addr);
}
// This array will be too large for IPv4 packets, but only by 12 bytes.
- scoped_array<char> buf(new char[size + kNATEncodedIPv6AddressSize]);
+ scoped_ptr<char[]> buf(new char[size + kNATEncodedIPv6AddressSize]);
size_t addrlength = PackAddressForNAT(buf.get(),
size + kNATEncodedIPv6AddressSize,
addr);
diff --git a/talk/base/nethelpers.cc b/talk/base/nethelpers.cc
index eebc6cf..05e02c9 100644
--- a/talk/base/nethelpers.cc
+++ b/talk/base/nethelpers.cc
@@ -109,7 +109,7 @@
return false;
}
DWORD protbuff_size = 4096;
- scoped_array<char> protocols;
+ scoped_ptr<char[]> protocols;
LPWSAPROTOCOL_INFOW protocol_infos = NULL;
int requested_protocols[2] = {AF_INET6, 0};
diff --git a/talk/base/network.cc b/talk/base/network.cc
index cbfcb5f..d4dda13 100644
--- a/talk/base/network.cc
+++ b/talk/base/network.cc
@@ -316,7 +316,7 @@
NetworkMap current_networks;
// MSDN recommends a 15KB buffer for the first try at GetAdaptersAddresses.
size_t buffer_size = 16384;
- scoped_array<char> adapter_info(new char[buffer_size]);
+ scoped_ptr<char[]> adapter_info(new char[buffer_size]);
PIP_ADAPTER_ADDRESSES adapter_addrs =
reinterpret_cast<PIP_ADAPTER_ADDRESSES>(adapter_info.get());
int adapter_flags = (GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_ANYCAST |
diff --git a/talk/base/network_unittest.cc b/talk/base/network_unittest.cc
index ce19120..e11e78d 100644
--- a/talk/base/network_unittest.cc
+++ b/talk/base/network_unittest.cc
@@ -120,7 +120,8 @@
EXPECT_FALSE(IsIgnoredNetwork(network_manager, include_me));
}
-TEST_F(NetworkTest, TestCreateNetworks) {
+// Test is failing on Windows opt: b/11288214
+TEST_F(NetworkTest, DISABLED_TestCreateNetworks) {
BasicNetworkManager manager;
NetworkManager::NetworkList result = GetNetworks(manager, true);
// We should be able to bind to any addresses we find.
diff --git a/talk/base/physicalsocketserver.cc b/talk/base/physicalsocketserver.cc
index 21d6eab..891330a 100644
--- a/talk/base/physicalsocketserver.cc
+++ b/talk/base/physicalsocketserver.cc
@@ -534,6 +534,9 @@
*slevel = IPPROTO_TCP;
*sopt = TCP_NODELAY;
break;
+ case OPT_DSCP:
+ LOG(LS_WARNING) << "Socket::OPT_DSCP not supported.";
+ return -1;
default:
ASSERT(false);
return -1;
diff --git a/talk/base/scoped_ptr.h b/talk/base/scoped_ptr.h
index 5a8364e..c12948b 100644
--- a/talk/base/scoped_ptr.h
+++ b/talk/base/scoped_ptr.h
@@ -1,34 +1,102 @@
-// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999.
-// Copyright (c) 2001, 2002 Peter Dimov
-//
-// Permission to copy, use, modify, sell and distribute this software
-// is granted provided this copyright notice appears in all copies.
-// This software is provided "as is" without express or implied
-// warranty, and with no claim as to its suitability for any purpose.
-//
-// See http://www.boost.org/libs/smart_ptr/scoped_ptr.htm for documentation.
-//
+// Borrowed from chromium.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
-// scoped_ptr mimics a built-in pointer except that it guarantees deletion
-// of the object pointed to, either on destruction of the scoped_ptr or via
-// an explicit reset(). scoped_ptr is a simple solution for simple needs;
-// use shared_ptr or std::auto_ptr if your needs are more complex.
+// Scopers help you manage ownership of a pointer, helping you easily manage the
+// a pointer within a scope, and automatically destroying the pointer at the
+// end of a scope. There are two main classes you will use, which correspond
+// to the operators new/delete and new[]/delete[].
+//
+// Example usage (scoped_ptr<T>):
+// {
+// scoped_ptr<Foo> foo(new Foo("wee"));
+// } // foo goes out of scope, releasing the pointer with it.
+//
+// {
+// scoped_ptr<Foo> foo; // No pointer managed.
+// foo.reset(new Foo("wee")); // Now a pointer is managed.
+// foo.reset(new Foo("wee2")); // Foo("wee") was destroyed.
+// foo.reset(new Foo("wee3")); // Foo("wee2") was destroyed.
+// foo->Method(); // Foo::Method() called.
+// foo.get()->Method(); // Foo::Method() called.
+// SomeFunc(foo.release()); // SomeFunc takes ownership, foo no longer
+// // manages a pointer.
+// foo.reset(new Foo("wee4")); // foo manages a pointer again.
+// foo.reset(); // Foo("wee4") destroyed, foo no longer
+// // manages a pointer.
+// } // foo wasn't managing a pointer, so nothing was destroyed.
+//
+// Example usage (scoped_ptr<T[]>):
+// {
+// scoped_ptr<Foo[]> foo(new Foo[100]);
+// foo.get()->Method(); // Foo::Method on the 0th element.
+// foo[10].Method(); // Foo::Method on the 10th element.
+// }
+//
+// These scopers also implement part of the functionality of C++11 unique_ptr
+// in that they are "movable but not copyable." You can use the scopers in
+// the parameter and return types of functions to signify ownership transfer
+// in to and out of a function. When calling a function that has a scoper
+// as the argument type, it must be called with the result of an analogous
+// scoper's Pass() function or another function that generates a temporary;
+// passing by copy will NOT work. Here is an example using scoped_ptr:
+//
+// void TakesOwnership(scoped_ptr<Foo> arg) {
+// // Do something with arg
+// }
+// scoped_ptr<Foo> CreateFoo() {
+// // No need for calling Pass() because we are constructing a temporary
+// // for the return value.
+// return scoped_ptr<Foo>(new Foo("new"));
+// }
+// scoped_ptr<Foo> PassThru(scoped_ptr<Foo> arg) {
+// return arg.Pass();
+// }
+//
+// {
+// scoped_ptr<Foo> ptr(new Foo("yay")); // ptr manages Foo("yay").
+// TakesOwnership(ptr.Pass()); // ptr no longer owns Foo("yay").
+// scoped_ptr<Foo> ptr2 = CreateFoo(); // ptr2 owns the return Foo.
+// scoped_ptr<Foo> ptr3 = // ptr3 now owns what was in ptr2.
+// PassThru(ptr2.Pass()); // ptr2 is correspondingly NULL.
+// }
+//
+// Notice that if you do not call Pass() when returning from PassThru(), or
+// when invoking TakesOwnership(), the code will not compile because scopers
+// are not copyable; they only implement move semantics which require calling
+// the Pass() function to signify a destructive transfer of state. CreateFoo()
+// is different though because we are constructing a temporary on the return
+// line and thus can avoid needing to call Pass().
+//
+// Pass() properly handles upcast in initialization, i.e. you can use a
+// scoped_ptr<Child> to initialize a scoped_ptr<Parent>:
+//
+// scoped_ptr<Foo> foo(new Foo());
+// scoped_ptr<FooParent> parent(foo.Pass());
+//
+// PassAs<>() should be used to upcast return value in return statement:
+//
+// scoped_ptr<Foo> CreateFoo() {
+// scoped_ptr<FooChild> result(new FooChild());
+// return result.PassAs<Foo>();
+// }
+//
+// Note that PassAs<>() is implemented only for scoped_ptr<T>, but not for
+// scoped_ptr<T[]>. This is because casting array pointers may not be safe.
-// scoped_ptr_malloc added in by Google. When one of
-// these goes out of scope, instead of doing a delete or delete[], it
-// calls free(). scoped_ptr_malloc<char> is likely to see much more
-// use than any other specializations.
-
-// release() added in by Google. Use this to conditionally
-// transfer ownership of a heap-allocated object to the caller, usually on
-// method success.
#ifndef TALK_BASE_SCOPED_PTR_H__
#define TALK_BASE_SCOPED_PTR_H__
#include <cstddef> // for std::ptrdiff_t
#include <stdlib.h> // for free() decl
+#include <algorithm> // For std::swap().
+
#include "talk/base/common.h" // for ASSERT
+#include "talk/base/compile_assert.h" // for COMPILE_ASSERT
+#include "talk/base/move.h" // for MOVE_ONLY_TYPE_FOR_CPP_03
+#include "talk/base/template_util.h" // for is_convertible, is_array
#ifdef _WIN32
namespace std { using ::ptrdiff_t; };
@@ -36,242 +104,495 @@
namespace talk_base {
-template <typename T>
-class scoped_ptr {
- private:
-
- T* ptr;
-
- scoped_ptr(scoped_ptr const &);
- scoped_ptr & operator=(scoped_ptr const &);
-
- public:
-
- typedef T element_type;
-
- explicit scoped_ptr(T* p = NULL): ptr(p) {}
-
- ~scoped_ptr() {
- typedef char type_must_be_complete[sizeof(T)];
+// Function object which deletes its parameter, which must be a pointer.
+// If C is an array type, invokes 'delete[]' on the parameter; otherwise,
+// invokes 'delete'. The default deleter for scoped_ptr<T>.
+template <class T>
+struct DefaultDeleter {
+ DefaultDeleter() {}
+ template <typename U> DefaultDeleter(const DefaultDeleter<U>& other) {
+ // IMPLEMENTATION NOTE: C++11 20.7.1.1.2p2 only provides this constructor
+ // if U* is implicitly convertible to T* and U is not an array type.
+ //
+ // Correct implementation should use SFINAE to disable this
+ // constructor. However, since there are no other 1-argument constructors,
+ // using a COMPILE_ASSERT() based on is_convertible<> and requiring
+ // complete types is simpler and will cause compile failures for equivalent
+ // misuses.
+ //
+ // Note, the is_convertible<U*, T*> check also ensures that U is not an
+ // array. T is guaranteed to be a non-array, so any U* where U is an array
+ // cannot convert to T*.
+ enum { T_must_be_complete = sizeof(T) };
+ enum { U_must_be_complete = sizeof(U) };
+ COMPILE_ASSERT((talk_base::is_convertible<U*, T*>::value),
+ U_ptr_must_implicitly_convert_to_T_ptr);
+ }
+ inline void operator()(T* ptr) const {
+ enum { type_must_be_complete = sizeof(T) };
delete ptr;
}
-
- void reset(T* p = NULL) {
- typedef char type_must_be_complete[sizeof(T)];
-
- if (ptr != p) {
- T* obj = ptr;
- ptr = p;
- // Delete last, in case obj destructor indirectly results in ~scoped_ptr
- delete obj;
- }
- }
-
- T& operator*() const {
- ASSERT(ptr != NULL);
- return *ptr;
- }
-
- T* operator->() const {
- ASSERT(ptr != NULL);
- return ptr;
- }
-
- T* get() const {
- return ptr;
- }
-
- void swap(scoped_ptr & b) {
- T* tmp = b.ptr;
- b.ptr = ptr;
- ptr = tmp;
- }
-
- T* release() {
- T* tmp = ptr;
- ptr = NULL;
- return tmp;
- }
-
- T** accept() {
- if (ptr) {
- delete ptr;
- ptr = NULL;
- }
- return &ptr;
- }
-
- T** use() {
- return &ptr;
- }
-
- // Allow scoped_ptr<T> to be used in boolean expressions, but not
- // implicitly convertible to a real bool (which is dangerous).
- // Borrowed from chromium's scoped_ptr implementation.
- typedef T* scoped_ptr::*Testable;
- operator Testable() const { return ptr ? &scoped_ptr::ptr : NULL; }
-
};
-template<typename T> inline
-void swap(scoped_ptr<T>& a, scoped_ptr<T>& b) {
- a.swap(b);
-}
-
-
-
-
-// scoped_array extends scoped_ptr to arrays. Deletion of the array pointed to
-// is guaranteed, either on destruction of the scoped_array or via an explicit
-// reset(). Use shared_array or std::vector if your needs are more complex.
-
-template<typename T>
-class scoped_array {
- private:
-
- T* ptr;
-
- scoped_array(scoped_array const &);
- scoped_array & operator=(scoped_array const &);
-
- public:
-
- typedef T element_type;
-
- explicit scoped_array(T* p = NULL) : ptr(p) {}
-
- ~scoped_array() {
- typedef char type_must_be_complete[sizeof(T)];
+// Specialization of DefaultDeleter for array types.
+template <class T>
+struct DefaultDeleter<T[]> {
+ inline void operator()(T* ptr) const {
+ enum { type_must_be_complete = sizeof(T) };
delete[] ptr;
}
- void reset(T* p = NULL) {
- typedef char type_must_be_complete[sizeof(T)];
+ private:
+ // Disable this operator for any U != T because it is undefined to execute
+ // an array delete when the static type of the array mismatches the dynamic
+ // type.
+ //
+ // References:
+ // C++98 [expr.delete]p3
+ // http://cplusplus.github.com/LWG/lwg-defects.html#938
+ template <typename U> void operator()(U* array) const;
+};
- if (ptr != p) {
- T* arr = ptr;
- ptr = p;
- // Delete last, in case arr destructor indirectly results in ~scoped_array
- delete [] arr;
+template <class T, int n>
+struct DefaultDeleter<T[n]> {
+ // Never allow someone to declare something like scoped_ptr<int[10]>.
+ COMPILE_ASSERT(sizeof(T) == -1, do_not_use_array_with_size_as_type);
+};
+
+// Function object which invokes 'free' on its parameter, which must be
+// a pointer. Can be used to store malloc-allocated pointers in scoped_ptr:
+//
+// scoped_ptr<int, talk_base::FreeDeleter> foo_ptr(
+// static_cast<int*>(malloc(sizeof(int))));
+struct FreeDeleter {
+ inline void operator()(void* ptr) const {
+ free(ptr);
+ }
+};
+
+namespace internal {
+
+// Minimal implementation of the core logic of scoped_ptr, suitable for
+// reuse in both scoped_ptr and its specializations.
+template <class T, class D>
+class scoped_ptr_impl {
+ public:
+ explicit scoped_ptr_impl(T* p) : data_(p) { }
+
+ // Initializer for deleters that have data parameters.
+ scoped_ptr_impl(T* p, const D& d) : data_(p, d) {}
+
+ // Templated constructor that destructively takes the value from another
+ // scoped_ptr_impl.
+ template <typename U, typename V>
+ scoped_ptr_impl(scoped_ptr_impl<U, V>* other)
+ : data_(other->release(), other->get_deleter()) {
+ // We do not support move-only deleters. We could modify our move
+ // emulation to have talk_base::subtle::move() and
+ // talk_base::subtle::forward()
+ // functions that are imperfect emulations of their C++11 equivalents,
+ // but until there's a requirement, just assume deleters are copyable.
+ }
+
+ template <typename U, typename V>
+ void TakeState(scoped_ptr_impl<U, V>* other) {
+ // See comment in templated constructor above regarding lack of support
+ // for move-only deleters.
+ reset(other->release());
+ get_deleter() = other->get_deleter();
+ }
+
+ ~scoped_ptr_impl() {
+ if (data_.ptr != NULL) {
+ // Not using get_deleter() saves one function call in non-optimized
+ // builds.
+ static_cast<D&>(data_)(data_.ptr);
}
}
- T& operator[](std::ptrdiff_t i) const {
- ASSERT(ptr != NULL);
- ASSERT(i >= 0);
- return ptr[i];
+ void reset(T* p) {
+ // This is a self-reset, which is no longer allowed: http://crbug.com/162971
+ if (p != NULL && p == data_.ptr)
+ abort();
+
+ // Note that running data_.ptr = p can lead to undefined behavior if
+ // get_deleter()(get()) deletes this. In order to pevent this, reset()
+ // should update the stored pointer before deleting its old value.
+ //
+ // However, changing reset() to use that behavior may cause current code to
+ // break in unexpected ways. If the destruction of the owned object
+ // dereferences the scoped_ptr when it is destroyed by a call to reset(),
+ // then it will incorrectly dispatch calls to |p| rather than the original
+ // value of |data_.ptr|.
+ //
+ // During the transition period, set the stored pointer to NULL while
+ // deleting the object. Eventually, this safety check will be removed to
+ // prevent the scenario initially described from occuring and
+ // http://crbug.com/176091 can be closed.
+ T* old = data_.ptr;
+ data_.ptr = NULL;
+ if (old != NULL)
+ static_cast<D&>(data_)(old);
+ data_.ptr = p;
}
- T* get() const {
- return ptr;
- }
+ T* get() const { return data_.ptr; }
- void swap(scoped_array & b) {
- T* tmp = b.ptr;
- b.ptr = ptr;
- ptr = tmp;
+ D& get_deleter() { return data_; }
+ const D& get_deleter() const { return data_; }
+
+ void swap(scoped_ptr_impl& p2) {
+ // Standard swap idiom: 'using std::swap' ensures that std::swap is
+ // present in the overload set, but we call swap unqualified so that
+ // any more-specific overloads can be used, if available.
+ using std::swap;
+ swap(static_cast<D&>(data_), static_cast<D&>(p2.data_));
+ swap(data_.ptr, p2.data_.ptr);
}
T* release() {
- T* tmp = ptr;
- ptr = NULL;
- return tmp;
+ T* old_ptr = data_.ptr;
+ data_.ptr = NULL;
+ return old_ptr;
}
T** accept() {
- if (ptr) {
- delete [] ptr;
- ptr = NULL;
- }
- return &ptr;
+ reset(NULL);
+ return &(data_.ptr);
}
- // Allow scoped_array<T> to be used in boolean expressions, but not
- // implicitly convertible to a real bool (which is dangerous).
- // Borrowed from chromium's scoped_array implementation.
- typedef T* scoped_array::*Testable;
- operator Testable() const { return ptr ? &scoped_array::ptr : NULL; }
+ T** use() {
+ return &(data_.ptr);
+ }
+
+ private:
+ // Needed to allow type-converting constructor.
+ template <typename U, typename V> friend class scoped_ptr_impl;
+
+ // Use the empty base class optimization to allow us to have a D
+ // member, while avoiding any space overhead for it when D is an
+ // empty class. See e.g. http://www.cantrip.org/emptyopt.html for a good
+ // discussion of this technique.
+ struct Data : public D {
+ explicit Data(T* ptr_in) : ptr(ptr_in) {}
+ Data(T* ptr_in, const D& other) : D(other), ptr(ptr_in) {}
+ T* ptr;
+ };
+
+ Data data_;
+
+ DISALLOW_COPY_AND_ASSIGN(scoped_ptr_impl);
};
-template<class T> inline
-void swap(scoped_array<T>& a, scoped_array<T>& b) {
- a.swap(b);
-}
+} // namespace internal
-// scoped_ptr_malloc<> is similar to scoped_ptr<>, but it accepts a
-// second template argument, the function used to free the object.
-
-template<typename T, void (*FF)(T*) = free> class scoped_ptr_malloc {
- private:
-
- T* ptr;
-
- scoped_ptr_malloc(scoped_ptr_malloc const &);
- scoped_ptr_malloc & operator=(scoped_ptr_malloc const &);
+// A scoped_ptr<T> is like a T*, except that the destructor of scoped_ptr<T>
+// automatically deletes the pointer it holds (if any).
+// That is, scoped_ptr<T> owns the T object that it points to.
+// Like a T*, a scoped_ptr<T> may hold either NULL or a pointer to a T object.
+// Also like T*, scoped_ptr<T> is thread-compatible, and once you
+// dereference it, you get the thread safety guarantees of T.
+//
+// The size of scoped_ptr is small. On most compilers, when using the
+// DefaultDeleter, sizeof(scoped_ptr<T>) == sizeof(T*). Custom deleters will
+// increase the size proportional to whatever state they need to have. See
+// comments inside scoped_ptr_impl<> for details.
+//
+// Current implementation targets having a strict subset of C++11's
+// unique_ptr<> features. Known deficiencies include not supporting move-only
+// deleteres, function pointers as deleters, and deleters with reference
+// types.
+template <class T, class D = talk_base::DefaultDeleter<T> >
+class scoped_ptr {
+ MOVE_ONLY_TYPE_FOR_CPP_03(scoped_ptr, RValue)
public:
-
+ // The element and deleter types.
typedef T element_type;
+ typedef D deleter_type;
- explicit scoped_ptr_malloc(T* p = 0): ptr(p) {}
+ // Constructor. Defaults to initializing with NULL.
+ scoped_ptr() : impl_(NULL) { }
- ~scoped_ptr_malloc() {
- FF(ptr);
+ // Constructor. Takes ownership of p.
+ explicit scoped_ptr(element_type* p) : impl_(p) { }
+
+ // Constructor. Allows initialization of a stateful deleter.
+ scoped_ptr(element_type* p, const D& d) : impl_(p, d) { }
+
+ // Constructor. Allows construction from a scoped_ptr rvalue for a
+ // convertible type and deleter.
+ //
+ // IMPLEMENTATION NOTE: C++11 unique_ptr<> keeps this constructor distinct
+ // from the normal move constructor. By C++11 20.7.1.2.1.21, this constructor
+ // has different post-conditions if D is a reference type. Since this
+ // implementation does not support deleters with reference type,
+ // we do not need a separate move constructor allowing us to avoid one
+ // use of SFINAE. You only need to care about this if you modify the
+ // implementation of scoped_ptr.
+ template <typename U, typename V>
+ scoped_ptr(scoped_ptr<U, V> other) : impl_(&other.impl_) {
+ COMPILE_ASSERT(!talk_base::is_array<U>::value, U_cannot_be_an_array);
}
- void reset(T* p = 0) {
- if (ptr != p) {
- FF(ptr);
- ptr = p;
- }
+ // Constructor. Move constructor for C++03 move emulation of this type.
+ scoped_ptr(RValue rvalue) : impl_(&rvalue.object->impl_) { }
+
+ // operator=. Allows assignment from a scoped_ptr rvalue for a convertible
+ // type and deleter.
+ //
+ // IMPLEMENTATION NOTE: C++11 unique_ptr<> keeps this operator= distinct from
+ // the normal move assignment operator. By C++11 20.7.1.2.3.4, this templated
+ // form has different requirements on for move-only Deleters. Since this
+ // implementation does not support move-only Deleters, we do not need a
+ // separate move assignment operator allowing us to avoid one use of SFINAE.
+ // You only need to care about this if you modify the implementation of
+ // scoped_ptr.
+ template <typename U, typename V>
+ scoped_ptr& operator=(scoped_ptr<U, V> rhs) {
+ COMPILE_ASSERT(!talk_base::is_array<U>::value, U_cannot_be_an_array);
+ impl_.TakeState(&rhs.impl_);
+ return *this;
}
- T& operator*() const {
- ASSERT(ptr != 0);
- return *ptr;
- }
+ // Reset. Deletes the currently owned object, if any.
+ // Then takes ownership of a new object, if given.
+ void reset(element_type* p = NULL) { impl_.reset(p); }
- T* operator->() const {
- ASSERT(ptr != 0);
- return ptr;
+ // Accessors to get the owned object.
+ // operator* and operator-> will assert() if there is no current object.
+ element_type& operator*() const {
+ ASSERT(impl_.get() != NULL);
+ return *impl_.get();
}
-
- T* get() const {
- return ptr;
+ element_type* operator->() const {
+ ASSERT(impl_.get() != NULL);
+ return impl_.get();
}
+ element_type* get() const { return impl_.get(); }
- void swap(scoped_ptr_malloc & b) {
- T* tmp = b.ptr;
- b.ptr = ptr;
- ptr = tmp;
- }
+ // Access to the deleter.
+ deleter_type& get_deleter() { return impl_.get_deleter(); }
+ const deleter_type& get_deleter() const { return impl_.get_deleter(); }
- T* release() {
- T* tmp = ptr;
- ptr = 0;
- return tmp;
- }
-
- T** accept() {
- if (ptr) {
- FF(ptr);
- ptr = 0;
- }
- return &ptr;
- }
-
- // Allow scoped_ptr_malloc<T> to be used in boolean expressions, but not
+ // Allow scoped_ptr<element_type> to be used in boolean expressions, but not
// implicitly convertible to a real bool (which is dangerous).
- // Borrowed from chromium's scoped_ptr_malloc implementation.
- typedef T* scoped_ptr_malloc::*Testable;
- operator Testable() const { return ptr ? &scoped_ptr_malloc::ptr : NULL; }
+ //
+ // Note that this trick is only safe when the == and != operators
+ // are declared explicitly, as otherwise "scoped_ptr1 ==
+ // scoped_ptr2" will compile but do the wrong thing (i.e., convert
+ // to Testable and then do the comparison).
+ private:
+ typedef talk_base::internal::scoped_ptr_impl<element_type, deleter_type>
+ scoped_ptr::*Testable;
+
+ public:
+ operator Testable() const { return impl_.get() ? &scoped_ptr::impl_ : NULL; }
+
+ // Comparison operators.
+ // These return whether two scoped_ptr refer to the same object, not just to
+ // two different but equal objects.
+ bool operator==(const element_type* p) const { return impl_.get() == p; }
+ bool operator!=(const element_type* p) const { return impl_.get() != p; }
+
+ // Swap two scoped pointers.
+ void swap(scoped_ptr& p2) {
+ impl_.swap(p2.impl_);
+ }
+
+ // Release a pointer.
+ // The return value is the current pointer held by this object.
+ // If this object holds a NULL pointer, the return value is NULL.
+ // After this operation, this object will hold a NULL pointer,
+ // and will not own the object any more.
+ element_type* release() WARN_UNUSED_RESULT {
+ return impl_.release();
+ }
+
+ // Delete the currently held pointer and return a pointer
+ // to allow overwriting of the current pointer address.
+ element_type** accept() WARN_UNUSED_RESULT {
+ return impl_.accept();
+ }
+
+ // Return a pointer to the current pointer address.
+ element_type** use() WARN_UNUSED_RESULT {
+ return impl_.use();
+ }
+
+ // C++98 doesn't support functions templates with default parameters which
+ // makes it hard to write a PassAs() that understands converting the deleter
+ // while preserving simple calling semantics.
+ //
+ // Until there is a use case for PassAs() with custom deleters, just ignore
+ // the custom deleter.
+ template <typename PassAsType>
+ scoped_ptr<PassAsType> PassAs() {
+ return scoped_ptr<PassAsType>(Pass());
+ }
+
+ private:
+ // Needed to reach into |impl_| in the constructor.
+ template <typename U, typename V> friend class scoped_ptr;
+ talk_base::internal::scoped_ptr_impl<element_type, deleter_type> impl_;
+
+ // Forbidden for API compatibility with std::unique_ptr.
+ explicit scoped_ptr(int disallow_construction_from_null);
+
+ // Forbid comparison of scoped_ptr types. If U != T, it totally
+ // doesn't make sense, and if U == T, it still doesn't make sense
+ // because you should never have the same object owned by two different
+ // scoped_ptrs.
+ template <class U> bool operator==(scoped_ptr<U> const& p2) const;
+ template <class U> bool operator!=(scoped_ptr<U> const& p2) const;
};
-template<typename T, void (*FF)(T*)> inline
-void swap(scoped_ptr_malloc<T,FF>& a, scoped_ptr_malloc<T,FF>& b) {
- a.swap(b);
+template <class T, class D>
+class scoped_ptr<T[], D> {
+ MOVE_ONLY_TYPE_FOR_CPP_03(scoped_ptr, RValue)
+
+ public:
+ // The element and deleter types.
+ typedef T element_type;
+ typedef D deleter_type;
+
+ // Constructor. Defaults to initializing with NULL.
+ scoped_ptr() : impl_(NULL) { }
+
+ // Constructor. Stores the given array. Note that the argument's type
+ // must exactly match T*. In particular:
+ // - it cannot be a pointer to a type derived from T, because it is
+ // inherently unsafe in the general case to access an array through a
+ // pointer whose dynamic type does not match its static type (eg., if
+ // T and the derived types had different sizes access would be
+ // incorrectly calculated). Deletion is also always undefined
+ // (C++98 [expr.delete]p3). If you're doing this, fix your code.
+ // - it cannot be NULL, because NULL is an integral expression, not a
+ // pointer to T. Use the no-argument version instead of explicitly
+ // passing NULL.
+ // - it cannot be const-qualified differently from T per unique_ptr spec
+ // (http://cplusplus.github.com/LWG/lwg-active.html#2118). Users wanting
+ // to work around this may use implicit_cast<const T*>().
+ // However, because of the first bullet in this comment, users MUST
+ // NOT use implicit_cast<Base*>() to upcast the static type of the array.
+ explicit scoped_ptr(element_type* array) : impl_(array) { }
+
+ // Constructor. Move constructor for C++03 move emulation of this type.
+ scoped_ptr(RValue rvalue) : impl_(&rvalue.object->impl_) { }
+
+ // operator=. Move operator= for C++03 move emulation of this type.
+ scoped_ptr& operator=(RValue rhs) {
+ impl_.TakeState(&rhs.object->impl_);
+ return *this;
+ }
+
+ // Reset. Deletes the currently owned array, if any.
+ // Then takes ownership of a new object, if given.
+ void reset(element_type* array = NULL) { impl_.reset(array); }
+
+ // Accessors to get the owned array.
+ element_type& operator[](size_t i) const {
+ ASSERT(impl_.get() != NULL);
+ return impl_.get()[i];
+ }
+ element_type* get() const { return impl_.get(); }
+
+ // Access to the deleter.
+ deleter_type& get_deleter() { return impl_.get_deleter(); }
+ const deleter_type& get_deleter() const { return impl_.get_deleter(); }
+
+ // Allow scoped_ptr<element_type> to be used in boolean expressions, but not
+ // implicitly convertible to a real bool (which is dangerous).
+ private:
+ typedef talk_base::internal::scoped_ptr_impl<element_type, deleter_type>
+ scoped_ptr::*Testable;
+
+ public:
+ operator Testable() const { return impl_.get() ? &scoped_ptr::impl_ : NULL; }
+
+ // Comparison operators.
+ // These return whether two scoped_ptr refer to the same object, not just to
+ // two different but equal objects.
+ bool operator==(element_type* array) const { return impl_.get() == array; }
+ bool operator!=(element_type* array) const { return impl_.get() != array; }
+
+ // Swap two scoped pointers.
+ void swap(scoped_ptr& p2) {
+ impl_.swap(p2.impl_);
+ }
+
+ // Release a pointer.
+ // The return value is the current pointer held by this object.
+ // If this object holds a NULL pointer, the return value is NULL.
+ // After this operation, this object will hold a NULL pointer,
+ // and will not own the object any more.
+ element_type* release() WARN_UNUSED_RESULT {
+ return impl_.release();
+ }
+
+ // Delete the currently held pointer and return a pointer
+ // to allow overwriting of the current pointer address.
+ element_type** accept() WARN_UNUSED_RESULT {
+ return impl_.accept();
+ }
+
+ // Return a pointer to the current pointer address.
+ element_type** use() WARN_UNUSED_RESULT {
+ return impl_.use();
+ }
+
+ private:
+ // Force element_type to be a complete type.
+ enum { type_must_be_complete = sizeof(element_type) };
+
+ // Actually hold the data.
+ talk_base::internal::scoped_ptr_impl<element_type, deleter_type> impl_;
+
+ // Disable initialization from any type other than element_type*, by
+ // providing a constructor that matches such an initialization, but is
+ // private and has no definition. This is disabled because it is not safe to
+ // call delete[] on an array whose static type does not match its dynamic
+ // type.
+ template <typename U> explicit scoped_ptr(U* array);
+ explicit scoped_ptr(int disallow_construction_from_null);
+
+ // Disable reset() from any type other than element_type*, for the same
+ // reasons as the constructor above.
+ template <typename U> void reset(U* array);
+ void reset(int disallow_reset_from_null);
+
+ // Forbid comparison of scoped_ptr types. If U != T, it totally
+ // doesn't make sense, and if U == T, it still doesn't make sense
+ // because you should never have the same object owned by two different
+ // scoped_ptrs.
+ template <class U> bool operator==(scoped_ptr<U> const& p2) const;
+ template <class U> bool operator!=(scoped_ptr<U> const& p2) const;
+};
+
+} // namespace talk_base
+
+// Free functions
+template <class T, class D>
+void swap(talk_base::scoped_ptr<T, D>& p1, talk_base::scoped_ptr<T, D>& p2) {
+ p1.swap(p2);
}
-} // namespace talk_base
+template <class T, class D>
+bool operator==(T* p1, const talk_base::scoped_ptr<T, D>& p2) {
+ return p1 == p2.get();
+}
+
+template <class T, class D>
+bool operator!=(T* p1, const talk_base::scoped_ptr<T, D>& p2) {
+ return p1 != p2.get();
+}
+
+// A function to convert T* into talk_base::scoped_ptr<T>
+// Doing e.g. make_scoped_ptr(new FooBarBaz<type>(arg)) is a shorter notation
+// for talk_base::scoped_ptr<FooBarBaz<type> >(new FooBarBaz<type>(arg))
+template <typename T>
+talk_base::scoped_ptr<T> make_scoped_ptr(T* ptr) {
+ return talk_base::scoped_ptr<T>(ptr);
+}
#endif // #ifndef TALK_BASE_SCOPED_PTR_H__
diff --git a/talk/base/socket_unittest.cc b/talk/base/socket_unittest.cc
index eafab81..a9c4dbb 100644
--- a/talk/base/socket_unittest.cc
+++ b/talk/base/socket_unittest.cc
@@ -693,8 +693,8 @@
// Create test data.
const size_t kDataSize = 1024 * 1024;
- scoped_array<char> send_buffer(new char[kDataSize]);
- scoped_array<char> recv_buffer(new char[kDataSize]);
+ scoped_ptr<char[]> send_buffer(new char[kDataSize]);
+ scoped_ptr<char[]> recv_buffer(new char[kDataSize]);
size_t send_pos = 0, recv_pos = 0;
for (size_t i = 0; i < kDataSize; ++i) {
send_buffer[i] = static_cast<char>(i % 256);
@@ -934,7 +934,7 @@
scoped_ptr<TestClient> client(
new TestClient(AsyncUDPSocket::Create(ss_, empty)));
int test_packet_size = 1200;
- talk_base::scoped_array<char> test_packet(new char[test_packet_size]);
+ talk_base::scoped_ptr<char[]> test_packet(new char[test_packet_size]);
// Init the test packet just to avoid memcheck warning.
memset(test_packet.get(), 0, test_packet_size);
// Set the send buffer size to the same size as the test packet to have a
diff --git a/talk/base/sslidentity_unittest.cc b/talk/base/sslidentity_unittest.cc
index e425df2..b63b8b9 100644
--- a/talk/base/sslidentity_unittest.cc
+++ b/talk/base/sslidentity_unittest.cc
@@ -57,7 +57,7 @@
class SSLIdentityTest : public testing::Test {
public:
SSLIdentityTest() :
- identity1_(NULL), identity2_(NULL) {
+ identity1_(), identity2_() {
}
~SSLIdentityTest() {
diff --git a/talk/base/stream.cc b/talk/base/stream.cc
index 996908d..c1cf907 100644
--- a/talk/base/stream.cc
+++ b/talk/base/stream.cc
@@ -166,7 +166,7 @@
///////////////////////////////////////////////////////////////////////////////
StreamTap::StreamTap(StreamInterface* stream, StreamInterface* tap)
- : StreamAdapterInterface(stream), tap_(NULL), tap_result_(SR_SUCCESS),
+ : StreamAdapterInterface(stream), tap_(), tap_result_(SR_SUCCESS),
tap_error_(0) {
AttachTap(tap);
}
diff --git a/talk/base/stream.h b/talk/base/stream.h
index 457396c..4571def 100644
--- a/talk/base/stream.h
+++ b/talk/base/stream.h
@@ -691,7 +691,7 @@
size_t offset, size_t* bytes_written);
StreamState state_; // keeps the opened/closed state of the stream
- scoped_array<char> buffer_; // the allocated buffer
+ scoped_ptr<char[]> buffer_; // the allocated buffer
size_t buffer_length_; // size of the allocated buffer
size_t data_length_; // amount of readable data in the buffer
size_t read_position_; // offset to the readable data
diff --git a/talk/base/systeminfo.cc b/talk/base/systeminfo.cc
index ec18658..ff331ac 100644
--- a/talk/base/systeminfo.cc
+++ b/talk/base/systeminfo.cc
@@ -74,7 +74,7 @@
// Determine buffer size, allocate and get processor information.
// Size can change between calls (unlikely), so a loop is done.
DWORD return_length = 0;
- scoped_array<SYSTEM_LOGICAL_PROCESSOR_INFORMATION> infos;
+ scoped_ptr<SYSTEM_LOGICAL_PROCESSOR_INFORMATION[]> infos;
while (!glpi(infos.get(), &return_length)) {
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
infos.reset(new SYSTEM_LOGICAL_PROCESSOR_INFORMATION[
@@ -183,6 +183,8 @@
if (!sysctlbyname("machdep.cpu.stepping", &sysctl_value, &length, NULL, 0)) {
cpu_stepping_ = static_cast<int>(sysctl_value);
}
+#elif defined(__native_client__)
+ // TODO(ryanpetrie): Implement this via PPAPI when it's available.
#else // LINUX || ANDROID
ProcCpuInfo proc_info;
if (proc_info.LoadFromSystem()) {
diff --git a/talk/base/template_util.h b/talk/base/template_util.h
new file mode 100644
index 0000000..5cc4ba4
--- /dev/null
+++ b/talk/base/template_util.h
@@ -0,0 +1,106 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef TALK_BASE_TEMPLATE_UTIL_H_
+#define TALK_BASE_TEMPLATE_UTIL_H_
+
+#include <cstddef> // For size_t.
+
+namespace talk_base {
+
+// template definitions from tr1
+
+template<class T, T v>
+struct integral_constant {
+ static const T value = v;
+ typedef T value_type;
+ typedef integral_constant<T, v> type;
+};
+
+template <class T, T v> const T integral_constant<T, v>::value;
+
+typedef integral_constant<bool, true> true_type;
+typedef integral_constant<bool, false> false_type;
+
+template <class T> struct is_pointer : false_type {};
+template <class T> struct is_pointer<T*> : true_type {};
+
+template <class T, class U> struct is_same : public false_type {};
+template <class T> struct is_same<T,T> : true_type {};
+
+template<class> struct is_array : public false_type {};
+template<class T, size_t n> struct is_array<T[n]> : public true_type {};
+template<class T> struct is_array<T[]> : public true_type {};
+
+template <class T> struct is_non_const_reference : false_type {};
+template <class T> struct is_non_const_reference<T&> : true_type {};
+template <class T> struct is_non_const_reference<const T&> : false_type {};
+
+template <class T> struct is_void : false_type {};
+template <> struct is_void<void> : true_type {};
+
+namespace internal {
+
+// Types YesType and NoType are guaranteed such that sizeof(YesType) <
+// sizeof(NoType).
+typedef char YesType;
+
+struct NoType {
+ YesType dummy[2];
+};
+
+// This class is an implementation detail for is_convertible, and you
+// don't need to know how it works to use is_convertible. For those
+// who care: we declare two different functions, one whose argument is
+// of type To and one with a variadic argument list. We give them
+// return types of different size, so we can use sizeof to trick the
+// compiler into telling us which function it would have chosen if we
+// had called it with an argument of type From. See Alexandrescu's
+// _Modern C++ Design_ for more details on this sort of trick.
+
+struct ConvertHelper {
+ template <typename To>
+ static YesType Test(To);
+
+ template <typename To>
+ static NoType Test(...);
+
+ template <typename From>
+ static From& Create();
+};
+
+// Used to determine if a type is a struct/union/class. Inspired by Boost's
+// is_class type_trait implementation.
+struct IsClassHelper {
+ template <typename C>
+ static YesType Test(void(C::*)(void));
+
+ template <typename C>
+ static NoType Test(...);
+};
+
+} // namespace internal
+
+// Inherits from true_type if From is convertible to To, false_type otherwise.
+//
+// Note that if the type is convertible, this will be a true_type REGARDLESS
+// of whether or not the conversion would emit a warning.
+template <typename From, typename To>
+struct is_convertible
+ : integral_constant<bool,
+ sizeof(internal::ConvertHelper::Test<To>(
+ internal::ConvertHelper::Create<From>())) ==
+ sizeof(internal::YesType)> {
+};
+
+template <typename T>
+struct is_class
+ : integral_constant<bool,
+ sizeof(internal::IsClassHelper::Test<T>(0)) ==
+ sizeof(internal::YesType)> {
+};
+
+} // namespace talk_base
+
+#endif // TALK_BASE_TEMPLATE_UTIL_H_
diff --git a/talk/base/win32filesystem.cc b/talk/base/win32filesystem.cc
index 42c0388..5caeac2 100644
--- a/talk/base/win32filesystem.cc
+++ b/talk/base/win32filesystem.cc
@@ -111,7 +111,7 @@
&token_user_size);
// Get the TOKEN_USER structure.
- scoped_array<char> token_user_bytes(new char[token_user_size]);
+ scoped_ptr<char[]> token_user_bytes(new char[token_user_size]);
PTOKEN_USER token_user = reinterpret_cast<PTOKEN_USER>(
token_user_bytes.get());
memset(token_user, 0, token_user_size);
@@ -137,7 +137,7 @@
GetLengthSid(token_user->User.Sid);
// Allocate it.
- scoped_array<char> acl_bytes(new char[acl_size]);
+ scoped_ptr<char[]> acl_bytes(new char[acl_size]);
PACL acl = reinterpret_cast<PACL>(acl_bytes.get());
memset(acl, 0, acl_size);
if (!::InitializeAcl(acl, acl_size, ACL_REVISION)) {
@@ -440,7 +440,7 @@
Pathname Win32Filesystem::GetCurrentDirectory() {
Pathname cwd;
int path_len = 0;
- scoped_array<wchar_t> path;
+ scoped_ptr<wchar_t[]> path;
do {
int needed = ::GetCurrentDirectory(path_len, path.get());
if (needed == 0) {
diff --git a/talk/base/win32regkey.cc b/talk/base/win32regkey.cc
index cb98caf..403fdc0 100644
--- a/talk/base/win32regkey.cc
+++ b/talk/base/win32regkey.cc
@@ -160,7 +160,7 @@
ASSERT(full_key_name != NULL);
DWORD byte_count = 0;
- scoped_array<byte> buffer;
+ scoped_ptr<byte[]> buffer;
HRESULT hr = GetValueStaticHelper(full_key_name, value_name,
REG_BINARY, buffer.accept(), &byte_count);
if (SUCCEEDED(hr)) {
@@ -179,7 +179,7 @@
ASSERT(full_key_name != NULL);
DWORD byte_count = 0;
- scoped_array<byte> buffer;
+ scoped_ptr<byte[]> buffer;
HRESULT hr = GetValueStaticHelper(full_key_name, value_name,
REG_BINARY, buffer.accept(), &byte_count);
if (SUCCEEDED(hr)) {
@@ -206,7 +206,7 @@
ASSERT(full_key_name != NULL);
ASSERT(value != NULL);
- scoped_array<wchar_t> buffer;
+ scoped_ptr<wchar_t[]> buffer;
HRESULT hr = RegKey::GetValue(full_key_name, value_name, buffer.accept());
if (SUCCEEDED(hr)) {
value->assign(buffer.get());
diff --git a/talk/base/win32socketserver.cc b/talk/base/win32socketserver.cc
index 55128e7..9566669 100644
--- a/talk/base/win32socketserver.cc
+++ b/talk/base/win32socketserver.cc
@@ -620,6 +620,9 @@
*slevel = IPPROTO_TCP;
*sopt = TCP_NODELAY;
break;
+ case OPT_DSCP:
+ LOG(LS_WARNING) << "Socket::OPT_DSCP not supported.";
+ return -1;
default:
ASSERT(false);
return -1;
diff --git a/talk/examples/call/callclient.cc b/talk/examples/call/callclient.cc
index 66c4b6f..afbdd29 100644
--- a/talk/examples/call/callclient.cc
+++ b/talk/examples/call/callclient.cc
@@ -396,7 +396,7 @@
transport_protocol_(cricket::ICEPROTO_HYBRID),
sdes_policy_(cricket::SEC_DISABLED),
dtls_policy_(cricket::SEC_DISABLED),
- ssl_identity_(NULL),
+ ssl_identity_(),
show_roster_messages_(false) {
xmpp_client_->SignalStateChange.connect(this, &CallClient::OnStateChange);
my_status_.set_caps_node(caps_node);
diff --git a/talk/examples/chat/chatapp.cc b/talk/examples/chat/chatapp.cc
index 1b59910..59b1c69 100644
--- a/talk/examples/chat/chatapp.cc
+++ b/talk/examples/chat/chatapp.cc
@@ -38,10 +38,10 @@
ChatApp::ChatApp(buzz::XmppClient* xmpp_client, talk_base::Thread* main_thread)
: xmpp_client_(xmpp_client),
- presence_out_task_(NULL),
- presence_receive_task_(NULL),
- message_send_task_(NULL),
- message_received_task_(NULL),
+ presence_out_task_(),
+ presence_receive_task_(),
+ message_send_task_(),
+ message_received_task_(),
console_task_(new buzz::ConsoleTask(main_thread)),
ui_state_(STATE_BASE) {
xmpp_client_->SignalStateChange.connect(this, &ChatApp::OnStateChange);
diff --git a/talk/examples/peerconnection/client/linux/main_wnd.h b/talk/examples/peerconnection/client/linux/main_wnd.h
index c23c116..5a44640 100644
--- a/talk/examples/peerconnection/client/linux/main_wnd.h
+++ b/talk/examples/peerconnection/client/linux/main_wnd.h
@@ -110,7 +110,7 @@
}
protected:
- talk_base::scoped_array<uint8> image_;
+ talk_base::scoped_ptr<uint8[]> image_;
int width_;
int height_;
GtkMainWnd* main_wnd_;
diff --git a/talk/examples/peerconnection/client/main_wnd.h b/talk/examples/peerconnection/client/main_wnd.h
index 0ed0f14..6d2bf3e 100644
--- a/talk/examples/peerconnection/client/main_wnd.h
+++ b/talk/examples/peerconnection/client/main_wnd.h
@@ -147,7 +147,7 @@
HWND wnd_;
BITMAPINFO bmi_;
- talk_base::scoped_array<uint8> image_;
+ talk_base::scoped_ptr<uint8[]> image_;
CRITICAL_SECTION buffer_lock_;
talk_base::scoped_refptr<webrtc::VideoTrackInterface> rendered_track_;
};
diff --git a/talk/media/base/cpuid.cc b/talk/media/base/cpuid.cc
index 9fd7865..bd87d2e 100644
--- a/talk/media/base/cpuid.cc
+++ b/talk/media/base/cpuid.cc
@@ -51,8 +51,8 @@
bool IsCoreIOrBetter() {
#if !defined(DISABLE_YUV) && (defined(__i386__) || defined(__x86_64__) || \
defined(_M_IX86) || defined(_M_X64))
- int cpu_info[4];
- libyuv::CpuId(cpu_info, 0); // Function 0: Vendor ID
+ uint32 cpu_info[4];
+ libyuv::CpuId(0, 0, &cpu_info[0]); // Function 0: Vendor ID
if (cpu_info[1] == 0x756e6547 && cpu_info[3] == 0x49656e69 &&
cpu_info[2] == 0x6c65746e) { // GenuineIntel
// Detect CPU Family and Model
@@ -62,7 +62,7 @@
// 13:12 - Processor Type
// 19:16 - Extended Model
// 27:20 - Extended Family
- libyuv::CpuId(cpu_info, 1); // Function 1: Family and Model
+ libyuv::CpuId(1, 0, &cpu_info[0]); // Function 1: Family and Model
int family = ((cpu_info[0] >> 8) & 0x0f) | ((cpu_info[0] >> 16) & 0xff0);
int model = ((cpu_info[0] >> 4) & 0x0f) | ((cpu_info[0] >> 12) & 0xf0);
// CpuFamily | CpuModel | Name
diff --git a/talk/media/base/fakevideocapturer.h b/talk/media/base/fakevideocapturer.h
index 5a33265..8dc69c3 100644
--- a/talk/media/base/fakevideocapturer.h
+++ b/talk/media/base/fakevideocapturer.h
@@ -101,7 +101,7 @@
frame.time_stamp = initial_unix_timestamp_ + next_timestamp_;
next_timestamp_ += 33333333; // 30 fps
- talk_base::scoped_array<char> data(new char[size]);
+ talk_base::scoped_ptr<char[]> data(new char[size]);
frame.data = data.get();
// Copy something non-zero into the buffer so Validate wont complain that
// the frame is all duplicate.
diff --git a/talk/media/base/mediachannel.h b/talk/media/base/mediachannel.h
index f90265c..3dc9c56 100644
--- a/talk/media/base/mediachannel.h
+++ b/talk/media/base/mediachannel.h
@@ -162,29 +162,51 @@
void SetAll(const AudioOptions& change) {
echo_cancellation.SetFrom(change.echo_cancellation);
auto_gain_control.SetFrom(change.auto_gain_control);
+ rx_auto_gain_control.SetFrom(change.rx_auto_gain_control);
noise_suppression.SetFrom(change.noise_suppression);
highpass_filter.SetFrom(change.highpass_filter);
stereo_swapping.SetFrom(change.stereo_swapping);
typing_detection.SetFrom(change.typing_detection);
+ aecm_generate_comfort_noise.SetFrom(change.aecm_generate_comfort_noise);
conference_mode.SetFrom(change.conference_mode);
adjust_agc_delta.SetFrom(change.adjust_agc_delta);
experimental_agc.SetFrom(change.experimental_agc);
experimental_aec.SetFrom(change.experimental_aec);
aec_dump.SetFrom(change.aec_dump);
+ tx_agc_target_dbov.SetFrom(change.tx_agc_target_dbov);
+ tx_agc_digital_compression_gain.SetFrom(
+ change.tx_agc_digital_compression_gain);
+ tx_agc_limiter.SetFrom(change.tx_agc_limiter);
+ rx_agc_target_dbov.SetFrom(change.rx_agc_target_dbov);
+ rx_agc_digital_compression_gain.SetFrom(
+ change.rx_agc_digital_compression_gain);
+ rx_agc_limiter.SetFrom(change.rx_agc_limiter);
+ recording_sample_rate.SetFrom(change.recording_sample_rate);
+ playout_sample_rate.SetFrom(change.playout_sample_rate);
}
bool operator==(const AudioOptions& o) const {
return echo_cancellation == o.echo_cancellation &&
auto_gain_control == o.auto_gain_control &&
+ rx_auto_gain_control == o.rx_auto_gain_control &&
noise_suppression == o.noise_suppression &&
highpass_filter == o.highpass_filter &&
stereo_swapping == o.stereo_swapping &&
typing_detection == o.typing_detection &&
+ aecm_generate_comfort_noise == o.aecm_generate_comfort_noise &&
conference_mode == o.conference_mode &&
experimental_agc == o.experimental_agc &&
experimental_aec == o.experimental_aec &&
adjust_agc_delta == o.adjust_agc_delta &&
- aec_dump == o.aec_dump;
+ aec_dump == o.aec_dump &&
+ tx_agc_target_dbov == o.tx_agc_target_dbov &&
+ tx_agc_digital_compression_gain == o.tx_agc_digital_compression_gain &&
+ tx_agc_limiter == o.tx_agc_limiter &&
+ rx_agc_target_dbov == o.rx_agc_target_dbov &&
+ rx_agc_digital_compression_gain == o.rx_agc_digital_compression_gain &&
+ rx_agc_limiter == o.rx_agc_limiter &&
+ recording_sample_rate == o.recording_sample_rate &&
+ playout_sample_rate == o.playout_sample_rate;
}
std::string ToString() const {
@@ -192,15 +214,27 @@
ost << "AudioOptions {";
ost << ToStringIfSet("aec", echo_cancellation);
ost << ToStringIfSet("agc", auto_gain_control);
+ ost << ToStringIfSet("rx_agc", rx_auto_gain_control);
ost << ToStringIfSet("ns", noise_suppression);
ost << ToStringIfSet("hf", highpass_filter);
ost << ToStringIfSet("swap", stereo_swapping);
ost << ToStringIfSet("typing", typing_detection);
+ ost << ToStringIfSet("comfort_noise", aecm_generate_comfort_noise);
ost << ToStringIfSet("conference", conference_mode);
ost << ToStringIfSet("agc_delta", adjust_agc_delta);
ost << ToStringIfSet("experimental_agc", experimental_agc);
ost << ToStringIfSet("experimental_aec", experimental_aec);
ost << ToStringIfSet("aec_dump", aec_dump);
+ ost << ToStringIfSet("tx_agc_target_dbov", tx_agc_target_dbov);
+ ost << ToStringIfSet("tx_agc_digital_compression_gain",
+ tx_agc_digital_compression_gain);
+ ost << ToStringIfSet("tx_agc_limiter", tx_agc_limiter);
+ ost << ToStringIfSet("rx_agc_target_dbov", rx_agc_target_dbov);
+ ost << ToStringIfSet("rx_agc_digital_compression_gain",
+ rx_agc_digital_compression_gain);
+ ost << ToStringIfSet("rx_agc_limiter", rx_agc_limiter);
+ ost << ToStringIfSet("recording_sample_rate", recording_sample_rate);
+ ost << ToStringIfSet("playout_sample_rate", playout_sample_rate);
ost << "}";
return ost.str();
}
@@ -210,6 +244,8 @@
Settable<bool> echo_cancellation;
// Audio processing to adjust the sensitivity of the local mic dynamically.
Settable<bool> auto_gain_control;
+ // Audio processing to apply gain to the remote audio.
+ Settable<bool> rx_auto_gain_control;
// Audio processing to filter out background noise.
Settable<bool> noise_suppression;
// Audio processing to remove background noise of lower frequencies.
@@ -218,11 +254,21 @@
Settable<bool> stereo_swapping;
// Audio processing to detect typing.
Settable<bool> typing_detection;
+ Settable<bool> aecm_generate_comfort_noise;
Settable<bool> conference_mode;
Settable<int> adjust_agc_delta;
Settable<bool> experimental_agc;
Settable<bool> experimental_aec;
Settable<bool> aec_dump;
+ // Note that tx_agc_* only applies to non-experimental AGC.
+ Settable<uint16> tx_agc_target_dbov;
+ Settable<uint16> tx_agc_digital_compression_gain;
+ Settable<bool> tx_agc_limiter;
+ Settable<uint16> rx_agc_target_dbov;
+ Settable<uint16> rx_agc_digital_compression_gain;
+ Settable<bool> rx_agc_limiter;
+ Settable<uint32> recording_sample_rate;
+ Settable<uint32> playout_sample_rate;
};
// Options that can be applied to a VideoMediaChannel or a VideoMediaEngine.
@@ -244,12 +290,13 @@
video_adapt_third.SetFrom(change.video_adapt_third);
video_noise_reduction.SetFrom(change.video_noise_reduction);
video_three_layers.SetFrom(change.video_three_layers);
- video_enable_camera_list.SetFrom(change.video_enable_camera_list);
video_one_layer_screencast.SetFrom(change.video_one_layer_screencast);
video_high_bitrate.SetFrom(change.video_high_bitrate);
video_watermark.SetFrom(change.video_watermark);
video_temporal_layer_screencast.SetFrom(
change.video_temporal_layer_screencast);
+ video_temporal_layer_realtime.SetFrom(
+ change.video_temporal_layer_realtime);
video_leaky_bucket.SetFrom(change.video_leaky_bucket);
cpu_overuse_detection.SetFrom(change.cpu_overuse_detection);
conference_mode.SetFrom(change.conference_mode);
@@ -269,11 +316,11 @@
video_adapt_third == o.video_adapt_third &&
video_noise_reduction == o.video_noise_reduction &&
video_three_layers == o.video_three_layers &&
- video_enable_camera_list == o.video_enable_camera_list &&
video_one_layer_screencast == o.video_one_layer_screencast &&
video_high_bitrate == o.video_high_bitrate &&
video_watermark == o.video_watermark &&
video_temporal_layer_screencast == o.video_temporal_layer_screencast &&
+ video_temporal_layer_realtime == o.video_temporal_layer_realtime &&
video_leaky_bucket == o.video_leaky_bucket &&
cpu_overuse_detection == o.cpu_overuse_detection &&
conference_mode == o.conference_mode &&
@@ -295,12 +342,13 @@
ost << ToStringIfSet("video adapt third", video_adapt_third);
ost << ToStringIfSet("noise reduction", video_noise_reduction);
ost << ToStringIfSet("3 layers", video_three_layers);
- ost << ToStringIfSet("camera list", video_enable_camera_list);
ost << ToStringIfSet("1 layer screencast", video_one_layer_screencast);
ost << ToStringIfSet("high bitrate", video_high_bitrate);
ost << ToStringIfSet("watermark", video_watermark);
ost << ToStringIfSet("video temporal layer screencast",
video_temporal_layer_screencast);
+ ost << ToStringIfSet("video temporal layer realtime",
+ video_temporal_layer_realtime);
ost << ToStringIfSet("leaky bucket", video_leaky_bucket);
ost << ToStringIfSet("cpu overuse detection", cpu_overuse_detection);
ost << ToStringIfSet("conference mode", conference_mode);
@@ -326,8 +374,6 @@
Settable<bool> video_noise_reduction;
// Experimental: Enable multi layer?
Settable<bool> video_three_layers;
- // Experimental: Enable camera list?
- Settable<bool> video_enable_camera_list;
// Experimental: Enable one layer screencast?
Settable<bool> video_one_layer_screencast;
// Experimental: Enable WebRtc higher bitrate?
@@ -336,6 +382,8 @@
Settable<bool> video_watermark;
// Experimental: Enable WebRTC layered screencast.
Settable<bool> video_temporal_layer_screencast;
+ // Experimental: Enable WebRTC temporal layer strategy for realtime video.
+ Settable<bool> video_temporal_layer_realtime;
// Enable WebRTC leaky bucket when sending media packets.
Settable<bool> video_leaky_bucket;
// Enable WebRTC Cpu Overuse Detection, which is a new version of the CPU
@@ -513,15 +561,68 @@
SEND_MICROPHONE
};
-struct VoiceSenderInfo {
- VoiceSenderInfo()
+// The stats information is structured as follows:
+// Media are represented by either MediaSenderInfo or MediaReceiverInfo.
+// Media contains a vector of SSRC infos that are exclusively used by this
+// media. (SSRCs shared between media streams can't be represented.)
+
+// Information about an SSRC.
+// This data may be locally recorded, or received in an RTCP SR or RR.
+struct SsrcSenderInfo {
+ SsrcSenderInfo()
: ssrc(0),
- bytes_sent(0),
+ timestamp(0) {
+ }
+ uint32 ssrc;
+ double timestamp; // NTP timestamp, represented as seconds since epoch.
+};
+
+struct SsrcReceiverInfo {
+ SsrcReceiverInfo()
+ : ssrc(0),
+ timestamp(0) {
+ }
+ uint32 ssrc;
+ double timestamp;
+};
+
+struct MediaSenderInfo {
+ MediaSenderInfo()
+ : bytes_sent(0),
packets_sent(0),
packets_lost(0),
fraction_lost(0.0),
+ rtt_ms(0) {
+ }
+ int64 bytes_sent;
+ int packets_sent;
+ int packets_lost;
+ float fraction_lost;
+ int rtt_ms;
+ std::string codec_name;
+ std::vector<SsrcSenderInfo> local_stats;
+ std::vector<SsrcReceiverInfo> remote_stats;
+};
+
+struct MediaReceiverInfo {
+ MediaReceiverInfo()
+ : bytes_rcvd(0),
+ packets_rcvd(0),
+ packets_lost(0),
+ fraction_lost(0.0) {
+ }
+ int64 bytes_rcvd;
+ int packets_rcvd;
+ int packets_lost;
+ float fraction_lost;
+ std::vector<SsrcReceiverInfo> local_stats;
+ std::vector<SsrcSenderInfo> remote_stats;
+};
+
+struct VoiceSenderInfo : public MediaSenderInfo {
+ VoiceSenderInfo()
+ : ssrc(0),
ext_seqnum(0),
- rtt_ms(0),
jitter_ms(0),
audio_level(0),
aec_quality_min(0.0),
@@ -533,13 +634,7 @@
}
uint32 ssrc;
- std::string codec_name;
- int64 bytes_sent;
- int packets_sent;
- int packets_lost;
- float fraction_lost;
int ext_seqnum;
- int rtt_ms;
int jitter_ms;
int audio_level;
float aec_quality_min;
@@ -550,13 +645,9 @@
bool typing_noise_detected;
};
-struct VoiceReceiverInfo {
+struct VoiceReceiverInfo : public MediaReceiverInfo {
VoiceReceiverInfo()
: ssrc(0),
- bytes_rcvd(0),
- packets_rcvd(0),
- packets_lost(0),
- fraction_lost(0.0),
ext_seqnum(0),
jitter_ms(0),
jitter_buffer_ms(0),
@@ -567,10 +658,6 @@
}
uint32 ssrc;
- int64 bytes_rcvd;
- int packets_rcvd;
- int packets_lost;
- float fraction_lost;
int ext_seqnum;
int jitter_ms;
int jitter_buffer_ms;
@@ -581,16 +668,11 @@
float expand_rate;
};
-struct VideoSenderInfo {
+struct VideoSenderInfo : public MediaSenderInfo {
VideoSenderInfo()
- : bytes_sent(0),
- packets_sent(0),
- packets_cached(0),
- packets_lost(0),
- fraction_lost(0.0),
+ : packets_cached(0),
firs_rcvd(0),
nacks_rcvd(0),
- rtt_ms(0),
frame_width(0),
frame_height(0),
framerate_input(0),
@@ -602,15 +684,9 @@
std::vector<uint32> ssrcs;
std::vector<SsrcGroup> ssrc_groups;
- std::string codec_name;
- int64 bytes_sent;
- int packets_sent;
int packets_cached;
- int packets_lost;
- float fraction_lost;
int firs_rcvd;
int nacks_rcvd;
- int rtt_ms;
int frame_width;
int frame_height;
int framerate_input;
@@ -620,13 +696,9 @@
int adapt_reason;
};
-struct VideoReceiverInfo {
+struct VideoReceiverInfo : public MediaReceiverInfo {
VideoReceiverInfo()
- : bytes_rcvd(0),
- packets_rcvd(0),
- packets_lost(0),
- packets_concealed(0),
- fraction_lost(0.0),
+ : packets_concealed(0),
firs_sent(0),
nacks_sent(0),
frame_width(0),
@@ -635,17 +707,19 @@
framerate_decoded(0),
framerate_output(0),
framerate_render_input(0),
- framerate_render_output(0) {
+ framerate_render_output(0),
+ decode_ms(0),
+ max_decode_ms(0),
+ jitter_buffer_ms(0),
+ min_playout_delay_ms(0),
+ render_delay_ms(0),
+ target_delay_ms(0),
+ current_delay_ms(0) {
}
std::vector<uint32> ssrcs;
std::vector<SsrcGroup> ssrc_groups;
- int64 bytes_rcvd;
- // vector<int> layer_bytes_rcvd;
- int packets_rcvd;
- int packets_lost;
int packets_concealed;
- float fraction_lost;
int firs_sent;
int nacks_sent;
int frame_width;
@@ -657,31 +731,42 @@
int framerate_render_input;
// Framerate that the renderer reports.
int framerate_render_output;
+
+ // All stats below are gathered per-VideoReceiver, but some will be correlated
+ // across MediaStreamTracks. NOTE(hta): when sinking stats into per-SSRC
+ // structures, reflect this in the new layout.
+
+ // Current frame decode latency.
+ int decode_ms;
+ // Maximum observed frame decode latency.
+ int max_decode_ms;
+ // Jitter (network-related) latency.
+ int jitter_buffer_ms;
+ // Requested minimum playout latency.
+ int min_playout_delay_ms;
+ // Requested latency to account for rendering delay.
+ int render_delay_ms;
+ // Target overall delay: network+decode+render, accounting for
+ // min_playout_delay_ms.
+ int target_delay_ms;
+ // Current overall delay, possibly ramping towards target_delay_ms.
+ int current_delay_ms;
};
-struct DataSenderInfo {
+struct DataSenderInfo : public MediaSenderInfo {
DataSenderInfo()
- : ssrc(0),
- bytes_sent(0),
- packets_sent(0) {
+ : ssrc(0) {
}
uint32 ssrc;
- std::string codec_name;
- int64 bytes_sent;
- int packets_sent;
};
-struct DataReceiverInfo {
+struct DataReceiverInfo : public MediaReceiverInfo {
DataReceiverInfo()
- : ssrc(0),
- bytes_rcvd(0),
- packets_rcvd(0) {
+ : ssrc(0) {
}
uint32 ssrc;
- int64 bytes_rcvd;
- int packets_rcvd;
};
struct BandwidthEstimationInfo {
diff --git a/talk/media/base/videocapturer.cc b/talk/media/base/videocapturer.cc
index acab19d..900a6f1 100644
--- a/talk/media/base/videocapturer.cc
+++ b/talk/media/base/videocapturer.cc
@@ -373,7 +373,7 @@
// TODO(fbarchard): Avoid scale and convert if muted.
// Temporary buffer is scoped here so it will persist until i420_frame.Init()
// makes a copy of the frame, converting to I420.
- talk_base::scoped_array<uint8> temp_buffer;
+ talk_base::scoped_ptr<uint8[]> temp_buffer;
// YUY2 can be scaled vertically using an ARGB scaler. Aspect ratio is only
// a problem on OSX. OSX always converts webcams to YUY2 or UYVY.
bool can_scale =
diff --git a/talk/media/base/videocommon.cc b/talk/media/base/videocommon.cc
index 5dd45d7..b051d52 100644
--- a/talk/media/base/videocommon.cc
+++ b/talk/media/base/videocommon.cc
@@ -153,12 +153,15 @@
// Compute size to crop video frame to.
// If cropped_format_* is 0, return the frame_* size as is.
-void ComputeCrop(int cropped_format_width,
- int cropped_format_height,
+void ComputeCrop(int cropped_format_width, int cropped_format_height,
int frame_width, int frame_height,
int pixel_width, int pixel_height,
int rotation,
int* cropped_width, int* cropped_height) {
+ // Transform screen crop to camera space if rotated.
+ if (rotation == 90 || rotation == 270) {
+ std::swap(cropped_format_width, cropped_format_height);
+ }
ASSERT(cropped_format_width >= 0);
ASSERT(cropped_format_height >= 0);
ASSERT(frame_width > 0);
@@ -182,39 +185,26 @@
static_cast<float>(frame_height * pixel_height);
float crop_aspect = static_cast<float>(cropped_format_width) /
static_cast<float>(cropped_format_height);
- int new_frame_width = frame_width;
- int new_frame_height = frame_height;
- if (rotation == 90 || rotation == 270) {
- frame_aspect = 1.0f / frame_aspect;
- new_frame_width = frame_height;
- new_frame_height = frame_width;
- }
-
// kAspectThresh is the maximum aspect ratio difference that we'll accept
- // for cropping. The value 1.33 is based on 4:3 being cropped to 16:9.
+ // for cropping. The value 1.34 allows cropping from 4:3 to 16:9.
// Set to zero to disable cropping entirely.
// TODO(fbarchard): crop to multiple of 16 width for better performance.
- const float kAspectThresh = 16.f / 9.f / (4.f / 3.f) + 0.01f; // 1.33
+ const float kAspectThresh = 1.34f;
// Wide aspect - crop horizontally
if (frame_aspect > crop_aspect &&
frame_aspect < crop_aspect * kAspectThresh) {
// Round width down to multiple of 4 to avoid odd chroma width.
// Width a multiple of 4 allows a half size image to have chroma channel
- // that avoids rounding errors. lmi and webrtc have odd width limitations.
- new_frame_width = static_cast<int>((crop_aspect * frame_height *
+ // that avoids rounding errors.
+ frame_width = static_cast<int>((crop_aspect * frame_height *
pixel_height) / pixel_width + 0.5f) & ~3;
- } else if (crop_aspect > frame_aspect &&
- crop_aspect < frame_aspect * kAspectThresh) {
- new_frame_height = static_cast<int>((frame_width * pixel_width) /
+ } else if (frame_aspect < crop_aspect &&
+ frame_aspect > crop_aspect / kAspectThresh) {
+ frame_height = static_cast<int>((frame_width * pixel_width) /
(crop_aspect * pixel_height) + 0.5f) & ~1;
}
-
- *cropped_width = new_frame_width;
- *cropped_height = new_frame_height;
- if (rotation == 90 || rotation == 270) {
- *cropped_width = new_frame_height;
- *cropped_height = new_frame_width;
- }
+ *cropped_width = frame_width;
+ *cropped_height = frame_height;
}
// Compute the frame size that makes pixels square pixel aspect ratio.
diff --git a/talk/media/base/videocommon_unittest.cc b/talk/media/base/videocommon_unittest.cc
index 9122843..455a47b 100644
--- a/talk/media/base/videocommon_unittest.cc
+++ b/talk/media/base/videocommon_unittest.cc
@@ -276,6 +276,15 @@
EXPECT_EQ(640, cropped_width);
EXPECT_EQ(480, cropped_height);
+ // Request 9:16 from VGA rotated (portrait). Expect crop.
+ ComputeCrop(360, 640, // Crop size 9:16
+ 640, 480, // Frame is 3:4 portrait
+ 1, 1, // Normal 1:1 pixels
+ 90,
+ &cropped_width, &cropped_height);
+ EXPECT_EQ(640, cropped_width);
+ EXPECT_EQ(360, cropped_height);
+
// Cropped size 0x0. Expect no cropping.
// This is used when adding multiple capturers
ComputeCrop(0, 0, // Crop size 0x0
diff --git a/talk/media/base/videoframe_unittest.h b/talk/media/base/videoframe_unittest.h
index f70e567..361c195c 100644
--- a/talk/media/base/videoframe_unittest.h
+++ b/talk/media/base/videoframe_unittest.h
@@ -157,7 +157,7 @@
prefix.c_str(), frame.GetWidth(), frame.GetHeight());
size_t out_size = cricket::VideoFrame::SizeOf(frame.GetWidth(),
frame.GetHeight());
- talk_base::scoped_array<uint8> out(new uint8[out_size]);
+ talk_base::scoped_ptr<uint8[]> out(new uint8[out_size]);
frame.CopyToBuffer(out.get(), out_size);
return DumpSample(filename, out.get(), out_size);
}
@@ -514,7 +514,7 @@
T frame1, frame2;
ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
size_t buf_size = kWidth * kHeight * 2;
- talk_base::scoped_array<uint8> buf(new uint8[buf_size + kAlignment]);
+ talk_base::scoped_ptr<uint8[]> buf(new uint8[buf_size + kAlignment]);
uint8* y = ALIGNP(buf.get(), kAlignment);
uint8* u = y + kWidth * kHeight;
uint8* v = u + (kWidth / 2) * kHeight;
@@ -535,7 +535,7 @@
T frame1, frame2;
ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
size_t buf_size = kWidth * kHeight * 2;
- talk_base::scoped_array<uint8> buf(new uint8[buf_size + kAlignment]);
+ talk_base::scoped_ptr<uint8[]> buf(new uint8[buf_size + kAlignment]);
uint8* yuy2 = ALIGNP(buf.get(), kAlignment);
EXPECT_EQ(0, libyuv::I420ToYUY2(frame1.GetYPlane(), frame1.GetYPitch(),
frame1.GetUPlane(), frame1.GetUPitch(),
@@ -552,7 +552,7 @@
T frame1, frame2;
ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
size_t buf_size = kWidth * kHeight * 2;
- talk_base::scoped_array<uint8> buf(new uint8[buf_size + kAlignment + 1]);
+ talk_base::scoped_ptr<uint8[]> buf(new uint8[buf_size + kAlignment + 1]);
uint8* yuy2 = ALIGNP(buf.get(), kAlignment) + 1;
EXPECT_EQ(0, libyuv::I420ToYUY2(frame1.GetYPlane(), frame1.GetYPitch(),
frame1.GetUPlane(), frame1.GetUPitch(),
@@ -718,7 +718,7 @@
void ConstructRGB565() {
T frame1, frame2;
size_t out_size = kWidth * kHeight * 2;
- talk_base::scoped_array<uint8> outbuf(new uint8[out_size + kAlignment]);
+ talk_base::scoped_ptr<uint8[]> outbuf(new uint8[out_size + kAlignment]);
uint8 *out = ALIGNP(outbuf.get(), kAlignment);
T frame;
ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
@@ -734,7 +734,7 @@
void ConstructARGB1555() {
T frame1, frame2;
size_t out_size = kWidth * kHeight * 2;
- talk_base::scoped_array<uint8> outbuf(new uint8[out_size + kAlignment]);
+ talk_base::scoped_ptr<uint8[]> outbuf(new uint8[out_size + kAlignment]);
uint8 *out = ALIGNP(outbuf.get(), kAlignment);
T frame;
ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
@@ -750,7 +750,7 @@
void ConstructARGB4444() {
T frame1, frame2;
size_t out_size = kWidth * kHeight * 2;
- talk_base::scoped_array<uint8> outbuf(new uint8[out_size + kAlignment]);
+ talk_base::scoped_ptr<uint8[]> outbuf(new uint8[out_size + kAlignment]);
uint8 *out = ALIGNP(outbuf.get(), kAlignment);
T frame;
ASSERT_TRUE(LoadFrameNoRepeat(&frame1));
@@ -769,7 +769,7 @@
#define TEST_BYR(NAME, BAYER) \
void NAME() { \
size_t bayer_size = kWidth * kHeight; \
- talk_base::scoped_array<uint8> bayerbuf(new uint8[ \
+ talk_base::scoped_ptr<uint8[]> bayerbuf(new uint8[ \
bayer_size + kAlignment]); \
uint8 *bayer = ALIGNP(bayerbuf.get(), kAlignment); \
T frame1, frame2; \
@@ -994,7 +994,7 @@
}
// Convert back to ARGB.
size_t out_size = 4;
- talk_base::scoped_array<uint8> outbuf(new uint8[out_size + kAlignment]);
+ talk_base::scoped_ptr<uint8[]> outbuf(new uint8[out_size + kAlignment]);
uint8 *out = ALIGNP(outbuf.get(), kAlignment);
EXPECT_EQ(out_size, frame.ConvertToRgbBuffer(cricket::FOURCC_ARGB,
@@ -1031,7 +1031,7 @@
}
// Convert back to ARGB
size_t out_size = 10 * 4;
- talk_base::scoped_array<uint8> outbuf(new uint8[out_size + kAlignment]);
+ talk_base::scoped_ptr<uint8[]> outbuf(new uint8[out_size + kAlignment]);
uint8 *out = ALIGNP(outbuf.get(), kAlignment);
EXPECT_EQ(out_size, frame.ConvertToRgbBuffer(cricket::FOURCC_ARGB,
@@ -1162,7 +1162,7 @@
// Allocate a buffer with end page aligned.
const int kPadToHeapSized = 16 * 1024 * 1024;
- talk_base::scoped_array<uint8> page_buffer(
+ talk_base::scoped_ptr<uint8[]> page_buffer(
new uint8[((data_size + kPadToHeapSized + 4095) & ~4095)]);
uint8* data_ptr = page_buffer.get();
if (!data_ptr) {
@@ -1427,7 +1427,7 @@
int astride = kWidth * bpp + rowpad;
size_t out_size = astride * kHeight;
- talk_base::scoped_array<uint8> outbuf(new uint8[out_size + kAlignment + 1]);
+ talk_base::scoped_ptr<uint8[]> outbuf(new uint8[out_size + kAlignment + 1]);
memset(outbuf.get(), 0, out_size + kAlignment + 1);
uint8 *outtop = ALIGNP(outbuf.get(), kAlignment);
uint8 *out = outtop;
@@ -1841,7 +1841,7 @@
void ConvertToI422Buffer() {
T frame1, frame2;
size_t out_size = kWidth * kHeight * 2;
- talk_base::scoped_array<uint8> buf(new uint8[out_size + kAlignment]);
+ talk_base::scoped_ptr<uint8[]> buf(new uint8[out_size + kAlignment]);
uint8* y = ALIGNP(buf.get(), kAlignment);
uint8* u = y + kWidth * kHeight;
uint8* v = u + (kWidth / 2) * kHeight;
@@ -1865,7 +1865,7 @@
#define TEST_TOBYR(NAME, BAYER) \
void NAME() { \
size_t bayer_size = kWidth * kHeight; \
- talk_base::scoped_array<uint8> bayerbuf(new uint8[ \
+ talk_base::scoped_ptr<uint8[]> bayerbuf(new uint8[ \
bayer_size + kAlignment]); \
uint8 *bayer = ALIGNP(bayerbuf.get(), kAlignment); \
T frame; \
@@ -1894,7 +1894,7 @@
} \
void NAME##Unaligned() { \
size_t bayer_size = kWidth * kHeight; \
- talk_base::scoped_array<uint8> bayerbuf(new uint8[ \
+ talk_base::scoped_ptr<uint8[]> bayerbuf(new uint8[ \
bayer_size + 1 + kAlignment]); \
uint8 *bayer = ALIGNP(bayerbuf.get(), kAlignment) + 1; \
T frame; \
@@ -1931,7 +1931,7 @@
#define TEST_BYRTORGB(NAME, BAYER) \
void NAME() { \
size_t bayer_size = kWidth * kHeight; \
- talk_base::scoped_array<uint8> bayerbuf(new uint8[ \
+ talk_base::scoped_ptr<uint8[]> bayerbuf(new uint8[ \
bayer_size + kAlignment]); \
uint8 *bayer1 = ALIGNP(bayerbuf.get(), kAlignment); \
for (int i = 0; i < kWidth * kHeight; ++i) { \
@@ -1947,7 +1947,7 @@
kWidth * 4, \
kWidth, kHeight); \
} \
- talk_base::scoped_array<uint8> bayer2buf(new uint8[ \
+ talk_base::scoped_ptr<uint8[]> bayer2buf(new uint8[ \
bayer_size + kAlignment]); \
uint8 *bayer2 = ALIGNP(bayer2buf.get(), kAlignment); \
libyuv::ARGBToBayer##BAYER(reinterpret_cast<uint8*>(ms->GetBuffer()), \
@@ -2010,7 +2010,7 @@
ASSERT_TRUE(LoadFrame(ms.get(), cricket::FOURCC_I420, kWidth, kHeight,
&frame));
size_t out_size = kWidth * kHeight * 3 / 2;
- talk_base::scoped_array<uint8> out(new uint8[out_size]);
+ talk_base::scoped_ptr<uint8[]> out(new uint8[out_size]);
for (int i = 0; i < repeat_; ++i) {
EXPECT_EQ(out_size, frame.CopyToBuffer(out.get(), out_size));
}
@@ -2056,7 +2056,7 @@
void CopyToBuffer1Pixel() {
size_t out_size = 3;
- talk_base::scoped_array<uint8> out(new uint8[out_size + 1]);
+ talk_base::scoped_ptr<uint8[]> out(new uint8[out_size + 1]);
memset(out.get(), 0xfb, out_size + 1); // Fill buffer
uint8 pixel[3] = { 1, 2, 3 };
T frame;
diff --git a/talk/media/devices/carbonvideorenderer.h b/talk/media/devices/carbonvideorenderer.h
index e091186..6c52fcf 100644
--- a/talk/media/devices/carbonvideorenderer.h
+++ b/talk/media/devices/carbonvideorenderer.h
@@ -57,7 +57,7 @@
static OSStatus DrawEventHandler(EventHandlerCallRef handler,
EventRef event,
void* data);
- talk_base::scoped_array<uint8> image_;
+ talk_base::scoped_ptr<uint8[]> image_;
talk_base::CriticalSection image_crit_;
int image_width_;
int image_height_;
diff --git a/talk/media/devices/gdivideorenderer.cc b/talk/media/devices/gdivideorenderer.cc
index c8024b7..9633eb6 100755
--- a/talk/media/devices/gdivideorenderer.cc
+++ b/talk/media/devices/gdivideorenderer.cc
@@ -98,7 +98,7 @@
void OnRenderFrame(const VideoFrame* frame);
BITMAPINFO bmi_;
- talk_base::scoped_array<uint8> image_;
+ talk_base::scoped_ptr<uint8[]> image_;
talk_base::scoped_ptr<WindowThread> window_thread_;
// The initial position of the window.
int initial_x_;
diff --git a/talk/media/devices/gtkvideorenderer.h b/talk/media/devices/gtkvideorenderer.h
index 6276b51..744c19f 100755
--- a/talk/media/devices/gtkvideorenderer.h
+++ b/talk/media/devices/gtkvideorenderer.h
@@ -56,7 +56,7 @@
// Check if the window has been closed.
bool IsClosed() const;
- talk_base::scoped_array<uint8> image_;
+ talk_base::scoped_ptr<uint8[]> image_;
GtkWidget* window_;
GtkWidget* draw_area_;
// The initial position of the window.
diff --git a/talk/media/devices/macdevicemanager.cc b/talk/media/devices/macdevicemanager.cc
index 10d85a0..e92408e 100644
--- a/talk/media/devices/macdevicemanager.cc
+++ b/talk/media/devices/macdevicemanager.cc
@@ -120,7 +120,7 @@
}
size_t num_devices = propsize / sizeof(AudioDeviceID);
- talk_base::scoped_array<AudioDeviceID> device_ids(
+ talk_base::scoped_ptr<AudioDeviceID[]> device_ids(
new AudioDeviceID[num_devices]);
err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices,
diff --git a/talk/media/sctp/sctpdataengine.h b/talk/media/sctp/sctpdataengine.h
index cadf78c..d09b152 100644
--- a/talk/media/sctp/sctpdataengine.h
+++ b/talk/media/sctp/sctpdataengine.h
@@ -56,7 +56,7 @@
namespace cricket {
// The highest stream ID (Sid) that SCTP allows, and the number of streams we
// tell SCTP we're going to use.
-const uint32 kMaxSctpSid = USHRT_MAX;
+const uint32 kMaxSctpSid = 1023;
// A DataEngine that interacts with usrsctp.
//
diff --git a/talk/media/sctp/sctputils.cc b/talk/media/sctp/sctputils.cc
index c33c64e..4073905 100644
--- a/talk/media/sctp/sctputils.cc
+++ b/talk/media/sctp/sctputils.cc
@@ -35,7 +35,7 @@
namespace cricket {
// Format defined at
-// http://tools.ietf.org/html/draft-jesup-rtcweb-data-protocol-04
+// http://tools.ietf.org/html/draft-ietf-rtcweb-data-protocol-00#section-6.1
static const uint8 DATA_CHANNEL_OPEN_MESSAGE_TYPE = 0x03;
@@ -73,16 +73,17 @@
LOG(LS_WARNING) << "Could not read OPEN message channel type.";
return false;
}
- uint16 reliability_param;
- if (!buffer.ReadUInt16(&reliability_param)) {
- LOG(LS_WARNING) << "Could not read OPEN message reliabilility param.";
- return false;
- }
+
uint16 priority;
if (!buffer.ReadUInt16(&priority)) {
LOG(LS_WARNING) << "Could not read OPEN message reliabilility prioirty.";
return false;
}
+ uint32 reliability_param;
+ if (!buffer.ReadUInt32(&reliability_param)) {
+ LOG(LS_WARNING) << "Could not read OPEN message reliabilility param.";
+ return false;
+ }
uint16 label_length;
if (!buffer.ReadUInt16(&label_length)) {
LOG(LS_WARNING) << "Could not read OPEN message label length.";
@@ -116,10 +117,11 @@
case DCOMCT_ORDERED_PARTIAL_RTXS:
case DCOMCT_UNORDERED_PARTIAL_RTXS:
config->maxRetransmits = reliability_param;
-
+ break;
case DCOMCT_ORDERED_PARTIAL_TIME:
case DCOMCT_UNORDERED_PARTIAL_TIME:
config->maxRetransmitTime = reliability_param;
+ break;
}
return true;
@@ -130,11 +132,9 @@
const webrtc::DataChannelInit& config,
talk_base::Buffer* payload) {
// Format defined at
- // http://tools.ietf.org/html/draft-jesup-rtcweb-data-protocol-04
- // TODO(pthatcher)
-
+ // http://tools.ietf.org/html/draft-ietf-rtcweb-data-protocol-00#section-6.1
uint8 channel_type = 0;
- uint16 reliability_param = 0;
+ uint32 reliability_param = 0;
uint16 priority = 0;
if (config.ordered) {
if (config.maxRetransmits > -1) {
@@ -163,8 +163,8 @@
talk_base::ByteBuffer::ORDER_NETWORK);
buffer.WriteUInt8(DATA_CHANNEL_OPEN_MESSAGE_TYPE);
buffer.WriteUInt8(channel_type);
- buffer.WriteUInt16(reliability_param);
buffer.WriteUInt16(priority);
+ buffer.WriteUInt32(reliability_param);
buffer.WriteUInt16(static_cast<uint16>(label.length()));
buffer.WriteUInt16(static_cast<uint16>(config.protocol.length()));
buffer.WriteString(label);
diff --git a/talk/media/sctp/sctputils_unittest.cc b/talk/media/sctp/sctputils_unittest.cc
index 1cc9a70..70f67b8 100644
--- a/talk/media/sctp/sctputils_unittest.cc
+++ b/talk/media/sctp/sctputils_unittest.cc
@@ -37,7 +37,7 @@
const webrtc::DataChannelInit& config) {
uint8 message_type;
uint8 channel_type;
- uint16 reliability;
+ uint32 reliability;
uint16 priority;
uint16 label_length;
uint16 protocol_length;
@@ -57,15 +57,15 @@
channel_type);
}
- ASSERT_TRUE(buffer.ReadUInt16(&reliability));
+ ASSERT_TRUE(buffer.ReadUInt16(&priority));
+
+ ASSERT_TRUE(buffer.ReadUInt32(&reliability));
if (config.maxRetransmits > -1 || config.maxRetransmitTime > -1) {
EXPECT_EQ(config.maxRetransmits > -1 ?
config.maxRetransmits : config.maxRetransmitTime,
- reliability);
+ static_cast<int>(reliability));
}
- ASSERT_TRUE(buffer.ReadUInt16(&priority));
-
ASSERT_TRUE(buffer.ReadUInt16(&label_length));
ASSERT_TRUE(buffer.ReadUInt16(&protocol_length));
EXPECT_EQ(label.size(), label_length);
@@ -86,13 +86,14 @@
config.protocol = "y";
talk_base::Buffer packet;
- ASSERT(cricket::WriteDataChannelOpenMessage(input_label, config, &packet));
+ ASSERT_TRUE(
+ cricket::WriteDataChannelOpenMessage(input_label, config, &packet));
VerifyOpenMessageFormat(packet, input_label, config);
std::string output_label;
webrtc::DataChannelInit output_config;
- ASSERT(cricket::ParseDataChannelOpenMessage(
+ ASSERT_TRUE(cricket::ParseDataChannelOpenMessage(
packet, &output_label, &output_config));
EXPECT_EQ(input_label, output_label);
@@ -110,19 +111,21 @@
config.protocol = "y";
talk_base::Buffer packet;
- ASSERT(cricket::WriteDataChannelOpenMessage(input_label, config, &packet));
+ ASSERT_TRUE(
+ cricket::WriteDataChannelOpenMessage(input_label, config, &packet));
VerifyOpenMessageFormat(packet, input_label, config);
std::string output_label;
webrtc::DataChannelInit output_config;
- ASSERT(cricket::ParseDataChannelOpenMessage(
+ ASSERT_TRUE(cricket::ParseDataChannelOpenMessage(
packet, &output_label, &output_config));
EXPECT_EQ(input_label, output_label);
EXPECT_EQ(config.protocol, output_config.protocol);
EXPECT_EQ(config.ordered, output_config.ordered);
EXPECT_EQ(config.maxRetransmitTime, output_config.maxRetransmitTime);
+ EXPECT_EQ(-1, output_config.maxRetransmits);
}
TEST_F(SctpUtilsTest, WriteParseOpenMessageWithMaxRetransmits) {
@@ -132,17 +135,19 @@
config.protocol = "y";
talk_base::Buffer packet;
- ASSERT(cricket::WriteDataChannelOpenMessage(input_label, config, &packet));
+ ASSERT_TRUE(
+ cricket::WriteDataChannelOpenMessage(input_label, config, &packet));
VerifyOpenMessageFormat(packet, input_label, config);
std::string output_label;
webrtc::DataChannelInit output_config;
- ASSERT(cricket::ParseDataChannelOpenMessage(
+ ASSERT_TRUE(cricket::ParseDataChannelOpenMessage(
packet, &output_label, &output_config));
EXPECT_EQ(input_label, output_label);
EXPECT_EQ(config.protocol, output_config.protocol);
EXPECT_EQ(config.ordered, output_config.ordered);
EXPECT_EQ(config.maxRetransmits, output_config.maxRetransmits);
+ EXPECT_EQ(-1, output_config.maxRetransmitTime);
}
diff --git a/talk/media/webrtc/fakewebrtcvideoengine.h b/talk/media/webrtc/fakewebrtcvideoengine.h
index 31de172..0b68728 100644
--- a/talk/media/webrtc/fakewebrtcvideoengine.h
+++ b/talk/media/webrtc/fakewebrtcvideoengine.h
@@ -1046,7 +1046,14 @@
return 0;
}
WEBRTC_STUB(EnableColorEnhancement, (const int, const bool));
-
+#ifdef USE_WEBRTC_DEV_BRANCH
+ WEBRTC_VOID_STUB(RegisterPreEncodeCallback,
+ (int, webrtc::I420FrameCallback*));
+ WEBRTC_VOID_STUB(DeRegisterPreEncodeCallback, (int));
+ WEBRTC_VOID_STUB(RegisterPreRenderCallback,
+ (int, webrtc::I420FrameCallback*));
+ WEBRTC_VOID_STUB(DeRegisterPreRenderCallback, (int));
+#endif
// webrtc::ViEExternalCodec
WEBRTC_FUNC(RegisterExternalSendCodec,
(const int channel, const unsigned char pl_type, webrtc::VideoEncoder*,
diff --git a/talk/media/webrtc/fakewebrtcvoiceengine.h b/talk/media/webrtc/fakewebrtcvoiceengine.h
index c3cd786..9696518 100644
--- a/talk/media/webrtc/fakewebrtcvoiceengine.h
+++ b/talk/media/webrtc/fakewebrtcvoiceengine.h
@@ -87,6 +87,8 @@
fec(false),
nack(false),
media_processor_registered(false),
+ rx_agc_enabled(false),
+ rx_agc_mode(webrtc::kAgcDefault),
cn8_type(13),
cn16_type(105),
dtmf_type(106),
@@ -95,6 +97,7 @@
send_ssrc(0),
level_header_ext_(-1) {
memset(&send_codec, 0, sizeof(send_codec));
+ memset(&rx_agc_config, 0, sizeof(rx_agc_config));
}
bool external_transport;
bool send;
@@ -107,6 +110,9 @@
bool fec;
bool nack;
bool media_processor_registered;
+ bool rx_agc_enabled;
+ webrtc::AgcModes rx_agc_mode;
+ webrtc::AgcConfig rx_agc_config;
int cn8_type;
int cn16_type;
int dtmf_type;
@@ -144,6 +150,8 @@
send_fail_channel_(-1),
fail_start_recording_microphone_(false),
recording_microphone_(false),
+ recording_sample_rate_(-1),
+ playout_sample_rate_(-1),
media_processor_(NULL) {
memset(&agc_config_, 0, sizeof(agc_config_));
}
@@ -584,10 +592,22 @@
WEBRTC_STUB(AudioDeviceControl, (unsigned int, unsigned int, unsigned int));
WEBRTC_STUB(SetLoudspeakerStatus, (bool enable));
WEBRTC_STUB(GetLoudspeakerStatus, (bool& enabled));
- WEBRTC_STUB(SetRecordingSampleRate, (unsigned int samples_per_sec));
- WEBRTC_STUB_CONST(RecordingSampleRate, (unsigned int* samples_per_sec));
- WEBRTC_STUB(SetPlayoutSampleRate, (unsigned int samples_per_sec));
- WEBRTC_STUB_CONST(PlayoutSampleRate, (unsigned int* samples_per_sec));
+ WEBRTC_FUNC(SetRecordingSampleRate, (unsigned int samples_per_sec)) {
+ recording_sample_rate_ = samples_per_sec;
+ return 0;
+ }
+ WEBRTC_FUNC_CONST(RecordingSampleRate, (unsigned int* samples_per_sec)) {
+ *samples_per_sec = recording_sample_rate_;
+ return 0;
+ }
+ WEBRTC_FUNC(SetPlayoutSampleRate, (unsigned int samples_per_sec)) {
+ playout_sample_rate_ = samples_per_sec;
+ return 0;
+ }
+ WEBRTC_FUNC_CONST(PlayoutSampleRate, (unsigned int* samples_per_sec)) {
+ *samples_per_sec = playout_sample_rate_;
+ return 0;
+ }
WEBRTC_STUB(EnableBuiltInAEC, (bool enable));
virtual bool BuiltInAECIsEnabled() const { return true; }
@@ -841,12 +861,27 @@
WEBRTC_STUB(SetRxNsStatus, (int channel, bool enable, webrtc::NsModes mode));
WEBRTC_STUB(GetRxNsStatus, (int channel, bool& enabled,
webrtc::NsModes& mode));
- WEBRTC_STUB(SetRxAgcStatus, (int channel, bool enable,
- webrtc::AgcModes mode));
- WEBRTC_STUB(GetRxAgcStatus, (int channel, bool& enabled,
- webrtc::AgcModes& mode));
- WEBRTC_STUB(SetRxAgcConfig, (int channel, webrtc::AgcConfig config));
- WEBRTC_STUB(GetRxAgcConfig, (int channel, webrtc::AgcConfig& config));
+ WEBRTC_FUNC(SetRxAgcStatus, (int channel, bool enable,
+ webrtc::AgcModes mode)) {
+ channels_[channel]->rx_agc_enabled = enable;
+ channels_[channel]->rx_agc_mode = mode;
+ return 0;
+ }
+ WEBRTC_FUNC(GetRxAgcStatus, (int channel, bool& enabled,
+ webrtc::AgcModes& mode)) {
+ enabled = channels_[channel]->rx_agc_enabled;
+ mode = channels_[channel]->rx_agc_mode;
+ return 0;
+ }
+
+ WEBRTC_FUNC(SetRxAgcConfig, (int channel, webrtc::AgcConfig config)) {
+ channels_[channel]->rx_agc_config = config;
+ return 0;
+ }
+ WEBRTC_FUNC(GetRxAgcConfig, (int channel, webrtc::AgcConfig& config)) {
+ config = channels_[channel]->rx_agc_config;
+ return 0;
+ }
WEBRTC_STUB(RegisterRxVadObserver, (int, webrtc::VoERxVadCallback&));
WEBRTC_STUB(DeRegisterRxVadObserver, (int channel));
@@ -996,6 +1031,8 @@
int send_fail_channel_;
bool fail_start_recording_microphone_;
bool recording_microphone_;
+ int recording_sample_rate_;
+ int playout_sample_rate_;
DtmfInfo dtmf_info_;
webrtc::VoEMediaProcess* media_processor_;
};
diff --git a/talk/media/webrtc/webrtcvideoengine.cc b/talk/media/webrtc/webrtcvideoengine.cc
index 3f4667d..05f8b2b 100644
--- a/talk/media/webrtc/webrtcvideoengine.cc
+++ b/talk/media/webrtc/webrtcvideoengine.cc
@@ -309,6 +309,13 @@
: video_channel_(video_channel),
framerate_(0),
bitrate_(0),
+ decode_ms_(0),
+ max_decode_ms_(0),
+ current_delay_ms_(0),
+ target_delay_ms_(0),
+ jitter_buffer_ms_(0),
+ min_playout_delay_ms_(0),
+ render_delay_ms_(0),
firs_requested_(0) {
}
@@ -323,23 +330,42 @@
framerate_ = framerate;
bitrate_ = bitrate;
}
+
+ virtual void DecoderTiming(int decode_ms,
+ int max_decode_ms,
+ int current_delay_ms,
+ int target_delay_ms,
+ int jitter_buffer_ms,
+ int min_playout_delay_ms,
+ int render_delay_ms) {
+ talk_base::CritScope cs(&crit_);
+ decode_ms_ = decode_ms;
+ max_decode_ms_ = max_decode_ms;
+ current_delay_ms_ = current_delay_ms;
+ target_delay_ms_ = target_delay_ms;
+ jitter_buffer_ms_ = jitter_buffer_ms;
+ min_playout_delay_ms_ = min_playout_delay_ms;
+ render_delay_ms_ = render_delay_ms;
+ }
+
virtual void RequestNewKeyFrame(const int videoChannel) {
talk_base::CritScope cs(&crit_);
ASSERT(video_channel_ == videoChannel);
++firs_requested_;
}
- int framerate() const {
+ // Populate |rinfo| based on previously-set data in |*this|.
+ void ExportTo(VideoReceiverInfo* rinfo) {
talk_base::CritScope cs(&crit_);
- return framerate_;
- }
- int bitrate() const {
- talk_base::CritScope cs(&crit_);
- return bitrate_;
- }
- int firs_requested() const {
- talk_base::CritScope cs(&crit_);
- return firs_requested_;
+ rinfo->firs_sent = firs_requested_;
+ rinfo->framerate_rcvd = framerate_;
+ rinfo->decode_ms = decode_ms_;
+ rinfo->max_decode_ms = max_decode_ms_;
+ rinfo->current_delay_ms = current_delay_ms_;
+ rinfo->target_delay_ms = target_delay_ms_;
+ rinfo->jitter_buffer_ms = jitter_buffer_ms_;
+ rinfo->min_playout_delay_ms = min_playout_delay_ms_;
+ rinfo->render_delay_ms = render_delay_ms_;
}
private:
@@ -347,6 +373,13 @@
int video_channel_;
int framerate_;
int bitrate_;
+ int decode_ms_;
+ int max_decode_ms_;
+ int current_delay_ms_;
+ int target_delay_ms_;
+ int jitter_buffer_ms_;
+ int min_playout_delay_ms_;
+ int render_delay_ms_;
int firs_requested_;
};
@@ -2303,14 +2336,13 @@
rinfo.packets_lost = -1;
rinfo.packets_concealed = -1;
rinfo.fraction_lost = -1; // from SentRTCP
- rinfo.firs_sent = channel->decoder_observer()->firs_requested();
rinfo.nacks_sent = -1;
rinfo.frame_width = channel->render_adapter()->width();
rinfo.frame_height = channel->render_adapter()->height();
- rinfo.framerate_rcvd = channel->decoder_observer()->framerate();
int fps = channel->render_adapter()->framerate();
rinfo.framerate_decoded = fps;
rinfo.framerate_output = fps;
+ channel->decoder_observer()->ExportTo(&rinfo);
// Get sent RTCP statistics.
uint16 s_fraction_lost;
diff --git a/talk/media/webrtc/webrtcvideoengine_unittest.cc b/talk/media/webrtc/webrtcvideoengine_unittest.cc
index 9537673..9fbbbe4 100644
--- a/talk/media/webrtc/webrtcvideoengine_unittest.cc
+++ b/talk/media/webrtc/webrtcvideoengine_unittest.cc
@@ -118,7 +118,7 @@
}
cricket::WebRtcVideoFrame frame;
size_t size = width * height * 3 / 2; // I420
- talk_base::scoped_array<uint8> pixel(new uint8[size]);
+ talk_base::scoped_ptr<uint8[]> pixel(new uint8[size]);
if (!frame.Init(cricket::FOURCC_I420,
width, height, width, height,
pixel.get(), size, 1, 1, 0, 0, 0)) {
@@ -138,7 +138,7 @@
}
cricket::WebRtcVideoFrame frame;
size_t size = width * height * 3 / 2; // I420
- talk_base::scoped_array<uint8> pixel(new uint8[size]);
+ talk_base::scoped_ptr<uint8[]> pixel(new uint8[size]);
if (!frame.Init(cricket::FOURCC_I420,
width, height, width, height,
pixel.get(), size, 1, 1, 0, timestamp, 0)) {
@@ -1161,7 +1161,8 @@
}
-TEST_F(WebRtcVideoEngineTestFake, SendReceiveBitratesStats) {
+// Disabled since its flaky: b/11288120
+TEST_F(WebRtcVideoEngineTestFake, DISABLED_SendReceiveBitratesStats) {
EXPECT_TRUE(SetupEngine());
cricket::VideoOptions options;
options.conference_mode.Set(true);
diff --git a/talk/media/webrtc/webrtcvideoframe.h b/talk/media/webrtc/webrtcvideoframe.h
index 18475a6..e023234 100644
--- a/talk/media/webrtc/webrtcvideoframe.h
+++ b/talk/media/webrtc/webrtcvideoframe.h
@@ -55,7 +55,7 @@
const webrtc::VideoFrame* frame() const;
private:
- talk_base::scoped_array<char> data_;
+ talk_base::scoped_ptr<char[]> data_;
size_t length_;
webrtc::VideoFrame video_frame_;
};
diff --git a/talk/media/webrtc/webrtcvideoframe_unittest.cc b/talk/media/webrtc/webrtcvideoframe_unittest.cc
index 2f0decb..ebc345e 100644
--- a/talk/media/webrtc/webrtcvideoframe_unittest.cc
+++ b/talk/media/webrtc/webrtcvideoframe_unittest.cc
@@ -53,7 +53,7 @@
captured_frame.height = frame_height;
captured_frame.data_size = (frame_width * frame_height) +
((frame_width + 1) / 2) * ((frame_height + 1) / 2) * 2;
- talk_base::scoped_array<uint8> captured_frame_buffer(
+ talk_base::scoped_ptr<uint8[]> captured_frame_buffer(
new uint8[captured_frame.data_size]);
captured_frame.data = captured_frame_buffer.get();
diff --git a/talk/media/webrtc/webrtcvie.h b/talk/media/webrtc/webrtcvie.h
index 9550962..50cc5d7 100644
--- a/talk/media/webrtc/webrtcvie.h
+++ b/talk/media/webrtc/webrtcvie.h
@@ -45,6 +45,7 @@
#include "webrtc/video_engine/include/vie_network.h"
#include "webrtc/video_engine/include/vie_render.h"
#include "webrtc/video_engine/include/vie_rtp_rtcp.h"
+#include "webrtc/video_engine/new_include/frame_callback.h"
namespace cricket {
diff --git a/talk/media/webrtc/webrtcvoiceengine.cc b/talk/media/webrtc/webrtcvoiceengine.cc
index 83cbdaf..121dd46 100644
--- a/talk/media/webrtc/webrtcvoiceengine.cc
+++ b/talk/media/webrtc/webrtcvoiceengine.cc
@@ -528,7 +528,7 @@
// Save the default AGC configuration settings. This must happen before
// calling SetOptions or the default will be overwritten.
if (voe_wrapper_->processing()->GetAgcConfig(default_agc_config_) == -1) {
- LOG_RTCERR0(GetAGCConfig);
+ LOG_RTCERR0(GetAgcConfig);
return false;
}
@@ -686,6 +686,10 @@
webrtc::AgcModes agc_mode = webrtc::kAgcAdaptiveAnalog;
webrtc::NsModes ns_mode = webrtc::kNsHighSuppression;
bool aecm_comfort_noise = false;
+ if (options.aecm_generate_comfort_noise.Get(&aecm_comfort_noise)) {
+ LOG(LS_VERBOSE) << "Comfort noise explicitly set to "
+ << aecm_comfort_noise << " (default is false).";
+ }
#if defined(IOS)
// On iOS, VPIO provides built-in EC and AGC.
@@ -713,6 +717,9 @@
if (voep->SetEcStatus(echo_cancellation, ec_mode) == -1) {
LOG_RTCERR2(SetEcStatus, echo_cancellation, ec_mode);
return false;
+ } else {
+ LOG(LS_VERBOSE) << "Echo control set to " << echo_cancellation
+ << " with mode " << ec_mode;
}
#if !defined(ANDROID)
// TODO(ajm): Remove the error return on Android from webrtc.
@@ -734,6 +741,38 @@
if (voep->SetAgcStatus(auto_gain_control, agc_mode) == -1) {
LOG_RTCERR2(SetAgcStatus, auto_gain_control, agc_mode);
return false;
+ } else {
+ LOG(LS_VERBOSE) << "Auto gain set to " << auto_gain_control
+ << " with mode " << agc_mode;
+ }
+ }
+
+ if (options.tx_agc_target_dbov.IsSet() ||
+ options.tx_agc_digital_compression_gain.IsSet() ||
+ options.tx_agc_limiter.IsSet()) {
+ // Override default_agc_config_. Generally, an unset option means "leave
+ // the VoE bits alone" in this function, so we want whatever is set to be
+ // stored as the new "default". If we didn't, then setting e.g.
+ // tx_agc_target_dbov would reset digital compression gain and limiter
+ // settings.
+ // Also, if we don't update default_agc_config_, then adjust_agc_delta
+ // would be an offset from the original values, and not whatever was set
+ // explicitly.
+ default_agc_config_.targetLeveldBOv =
+ options.tx_agc_target_dbov.GetWithDefaultIfUnset(
+ default_agc_config_.targetLeveldBOv);
+ default_agc_config_.digitalCompressionGaindB =
+ options.tx_agc_digital_compression_gain.GetWithDefaultIfUnset(
+ default_agc_config_.digitalCompressionGaindB);
+ default_agc_config_.limiterEnable =
+ options.tx_agc_limiter.GetWithDefaultIfUnset(
+ default_agc_config_.limiterEnable);
+ if (voe_wrapper_->processing()->SetAgcConfig(default_agc_config_) == -1) {
+ LOG_RTCERR3(SetAgcConfig,
+ default_agc_config_.targetLeveldBOv,
+ default_agc_config_.digitalCompressionGaindB,
+ default_agc_config_.limiterEnable);
+ return false;
}
}
@@ -742,6 +781,9 @@
if (voep->SetNsStatus(noise_suppression, ns_mode) == -1) {
LOG_RTCERR2(SetNsStatus, noise_suppression, ns_mode);
return false;
+ } else {
+ LOG(LS_VERBOSE) << "Noise suppression set to " << noise_suppression
+ << " with mode " << ns_mode;
}
}
@@ -799,6 +841,20 @@
}
}
+ uint32 recording_sample_rate;
+ if (options.recording_sample_rate.Get(&recording_sample_rate)) {
+ if (voe_wrapper_->hw()->SetRecordingSampleRate(recording_sample_rate)) {
+ LOG_RTCERR1(SetRecordingSampleRate, recording_sample_rate);
+ }
+ }
+
+ uint32 playout_sample_rate;
+ if (options.playout_sample_rate.Get(&playout_sample_rate)) {
+ if (voe_wrapper_->hw()->SetPlayoutSampleRate(playout_sample_rate)) {
+ LOG_RTCERR1(SetPlayoutSampleRate, playout_sample_rate);
+ }
+ }
+
return true;
}
@@ -1136,6 +1192,18 @@
}
}
+ // Allow trace options to override the trace filter. We default
+ // it to log_filter_ (as a translation of libjingle log levels)
+ // elsewhere, but this allows clients to explicitly set webrtc
+ // log levels.
+ std::vector<std::string>::iterator tracefilter =
+ std::find(opts.begin(), opts.end(), "tracefilter");
+ if (tracefilter != opts.end() && ++tracefilter != opts.end()) {
+ if (!tracing_->SetTraceFilter(talk_base::FromString<int>(*tracefilter))) {
+ LOG_RTCERR1(SetTraceFilter, *tracefilter);
+ }
+ }
+
// Set AEC dump file
std::vector<std::string>::iterator recordEC =
std::find(opts.begin(), opts.end(), "recordEC");
@@ -1587,6 +1655,56 @@
// Will be interpreted when appropriate.
}
+ // Receiver-side auto gain control happens per channel, so set it here from
+ // options. Note that, like conference mode, setting it on the engine won't
+ // have the desired effect, since voice channels don't inherit options from
+ // the media engine when those options are applied per-channel.
+ bool rx_auto_gain_control;
+ if (options.rx_auto_gain_control.Get(&rx_auto_gain_control)) {
+ if (engine()->voe()->processing()->SetRxAgcStatus(
+ voe_channel(), rx_auto_gain_control,
+ webrtc::kAgcFixedDigital) == -1) {
+ LOG_RTCERR1(SetRxAgcStatus, rx_auto_gain_control);
+ return false;
+ } else {
+ LOG(LS_VERBOSE) << "Rx auto gain set to " << rx_auto_gain_control
+ << " with mode " << webrtc::kAgcFixedDigital;
+ }
+ }
+ if (options.rx_agc_target_dbov.IsSet() ||
+ options.rx_agc_digital_compression_gain.IsSet() ||
+ options.rx_agc_limiter.IsSet()) {
+ webrtc::AgcConfig config;
+ // If only some of the options are being overridden, get the current
+ // settings for the channel and bail if they aren't available.
+ if (!options.rx_agc_target_dbov.IsSet() ||
+ !options.rx_agc_digital_compression_gain.IsSet() ||
+ !options.rx_agc_limiter.IsSet()) {
+ if (engine()->voe()->processing()->GetRxAgcConfig(
+ voe_channel(), config) != 0) {
+ LOG(LS_ERROR) << "Failed to get default rx agc configuration for "
+ << "channel " << voe_channel() << ". Since not all rx "
+ << "agc options are specified, unable to safely set rx "
+ << "agc options.";
+ return false;
+ }
+ }
+ config.targetLeveldBOv =
+ options.rx_agc_target_dbov.GetWithDefaultIfUnset(
+ config.targetLeveldBOv);
+ config.digitalCompressionGaindB =
+ options.rx_agc_digital_compression_gain.GetWithDefaultIfUnset(
+ config.digitalCompressionGaindB);
+ config.limiterEnable = options.rx_agc_limiter.GetWithDefaultIfUnset(
+ config.limiterEnable);
+ if (engine()->voe()->processing()->SetRxAgcConfig(
+ voe_channel(), config) == -1) {
+ LOG_RTCERR4(SetRxAgcConfig, voe_channel(), config.targetLeveldBOv,
+ config.digitalCompressionGaindB, config.limiterEnable);
+ return false;
+ }
+ }
+
LOG(LS_INFO) << "Set voice channel options. Current options: "
<< options_.ToString();
return true;
diff --git a/talk/media/webrtc/webrtcvoiceengine_unittest.cc b/talk/media/webrtc/webrtcvoiceengine_unittest.cc
index acefc38..2e52c8f 100644
--- a/talk/media/webrtc/webrtcvoiceengine_unittest.cc
+++ b/talk/media/webrtc/webrtcvoiceengine_unittest.cc
@@ -55,9 +55,10 @@
}
};
-class NullVoETraceWrapper : public cricket::VoETraceWrapper {
+class FakeVoETraceWrapper : public cricket::VoETraceWrapper {
public:
virtual int SetTraceFilter(const unsigned int filter) {
+ filter_ = filter;
return 0;
}
virtual int SetTraceFile(const char* fileNameUTF8) {
@@ -66,6 +67,7 @@
virtual int SetTraceCallback(webrtc::TraceCallback* callback) {
return 0;
}
+ unsigned int filter_;
};
class WebRtcVoiceEngineTestFake : public testing::Test {
@@ -102,9 +104,10 @@
WebRtcVoiceEngineTestFake()
: voe_(kAudioCodecs, ARRAY_SIZE(kAudioCodecs)),
voe_sc_(kAudioCodecs, ARRAY_SIZE(kAudioCodecs)),
+ trace_wrapper_(new FakeVoETraceWrapper()),
engine_(new FakeVoEWrapper(&voe_),
new FakeVoEWrapper(&voe_sc_),
- new NullVoETraceWrapper()),
+ trace_wrapper_),
channel_(NULL), soundclip_(NULL) {
options_conference_.conference_mode.Set(true);
options_adjust_agc_.adjust_agc_delta.Set(-10);
@@ -277,6 +280,7 @@
protected:
cricket::FakeWebRtcVoiceEngine voe_;
cricket::FakeWebRtcVoiceEngine voe_sc_;
+ FakeVoETraceWrapper* trace_wrapper_;
cricket::WebRtcVoiceEngine engine_;
cricket::VoiceMediaChannel* channel_;
cricket::SoundclipMedia* soundclip_;
@@ -1873,6 +1877,84 @@
EXPECT_FALSE(voe_.GetPlayout(channel_num));
}
+TEST_F(WebRtcVoiceEngineTestFake, TxAgcConfigViaOptions) {
+ EXPECT_TRUE(SetupEngine());
+ webrtc::AgcConfig agc_config;
+ EXPECT_EQ(0, voe_.GetAgcConfig(agc_config));
+ EXPECT_EQ(0, agc_config.targetLeveldBOv);
+
+ cricket::AudioOptions options;
+ options.tx_agc_target_dbov.Set(3);
+ options.tx_agc_digital_compression_gain.Set(9);
+ options.tx_agc_limiter.Set(true);
+ options.auto_gain_control.Set(true);
+ EXPECT_TRUE(engine_.SetOptions(options));
+
+ EXPECT_EQ(0, voe_.GetAgcConfig(agc_config));
+ EXPECT_EQ(3, agc_config.targetLeveldBOv);
+ EXPECT_EQ(9, agc_config.digitalCompressionGaindB);
+ EXPECT_TRUE(agc_config.limiterEnable);
+
+ // Check interaction with adjust_agc_delta. Both should be respected, for
+ // backwards compatibility.
+ options.adjust_agc_delta.Set(-10);
+ EXPECT_TRUE(engine_.SetOptions(options));
+
+ EXPECT_EQ(0, voe_.GetAgcConfig(agc_config));
+ EXPECT_EQ(13, agc_config.targetLeveldBOv);
+}
+
+TEST_F(WebRtcVoiceEngineTestFake, RxAgcConfigViaOptions) {
+ EXPECT_TRUE(SetupEngine());
+ int channel_num = voe_.GetLastChannel();
+ cricket::AudioOptions options;
+ options.rx_agc_target_dbov.Set(6);
+ options.rx_agc_digital_compression_gain.Set(0);
+ options.rx_agc_limiter.Set(true);
+ options.rx_auto_gain_control.Set(true);
+ EXPECT_TRUE(channel_->SetOptions(options));
+
+ webrtc::AgcConfig agc_config;
+ EXPECT_EQ(0, engine_.voe()->processing()->GetRxAgcConfig(
+ channel_num, agc_config));
+ EXPECT_EQ(6, agc_config.targetLeveldBOv);
+ EXPECT_EQ(0, agc_config.digitalCompressionGaindB);
+ EXPECT_TRUE(agc_config.limiterEnable);
+}
+
+TEST_F(WebRtcVoiceEngineTestFake, SampleRatesViaOptions) {
+ EXPECT_TRUE(SetupEngine());
+ cricket::AudioOptions options;
+ options.recording_sample_rate.Set(48000u);
+ options.playout_sample_rate.Set(44100u);
+ EXPECT_TRUE(engine_.SetOptions(options));
+
+ unsigned int recording_sample_rate, playout_sample_rate;
+ EXPECT_EQ(0, voe_.RecordingSampleRate(&recording_sample_rate));
+ EXPECT_EQ(0, voe_.PlayoutSampleRate(&playout_sample_rate));
+ EXPECT_EQ(48000u, recording_sample_rate);
+ EXPECT_EQ(44100u, playout_sample_rate);
+}
+
+TEST_F(WebRtcVoiceEngineTestFake, TraceFilterViaTraceOptions) {
+ EXPECT_TRUE(SetupEngine());
+ engine_.SetLogging(talk_base::LS_INFO, "");
+ EXPECT_EQ(
+ // Info:
+ webrtc::kTraceStateInfo | webrtc::kTraceInfo |
+ // Warning:
+ webrtc::kTraceTerseInfo | webrtc::kTraceWarning |
+ // Error:
+ webrtc::kTraceError | webrtc::kTraceCritical,
+ static_cast<int>(trace_wrapper_->filter_));
+ // Now set it explicitly
+ std::string filter =
+ "tracefilter " + talk_base::ToString(webrtc::kTraceDefault);
+ engine_.SetLogging(talk_base::LS_VERBOSE, filter.c_str());
+ EXPECT_EQ(static_cast<unsigned int>(webrtc::kTraceDefault),
+ trace_wrapper_->filter_);
+}
+
// Test that we can set the outgoing SSRC properly.
// SSRC is set in SetupEngine by calling AddSendStream.
TEST_F(WebRtcVoiceEngineTestFake, SetSendSsrc) {
diff --git a/talk/p2p/base/dtlstransportchannel_unittest.cc b/talk/p2p/base/dtlstransportchannel_unittest.cc
index 6a4e5ad..c6e2804 100644
--- a/talk/p2p/base/dtlstransportchannel_unittest.cc
+++ b/talk/p2p/base/dtlstransportchannel_unittest.cc
@@ -233,7 +233,7 @@
void SendPackets(size_t channel, size_t size, size_t count, bool srtp) {
ASSERT(channel < channels_.size());
- talk_base::scoped_array<char> packet(new char[size]);
+ talk_base::scoped_ptr<char[]> packet(new char[size]);
size_t sent = 0;
do {
// Fill the packet with a known value and a sequence number to check
diff --git a/talk/p2p/base/p2ptransportchannel_unittest.cc b/talk/p2p/base/p2ptransportchannel_unittest.cc
index e3cddc0..07cfeaa 100644
--- a/talk/p2p/base/p2ptransportchannel_unittest.cc
+++ b/talk/p2p/base/p2ptransportchannel_unittest.cc
@@ -57,6 +57,11 @@
// Addresses on the public internet.
static const SocketAddress kPublicAddrs[2] =
{ SocketAddress("11.11.11.11", 0), SocketAddress("22.22.22.22", 0) };
+// IPv6 Addresses on the public internet.
+static const SocketAddress kIPv6PublicAddrs[2] = {
+ SocketAddress("2400:4030:1:2c00:be30:abcd:efab:cdef", 0),
+ SocketAddress("2620:0:1000:1b03:2e41:38ff:fea6:f2a4", 0)
+};
// For configuring multihomed clients.
static const SocketAddress kAlternateAddrs[2] =
{ SocketAddress("11.11.11.101", 0), SocketAddress("22.22.22.202", 0) };
@@ -1413,6 +1418,34 @@
GetEndpoint(1)->cd1_.ch_->DefaultDscpValue());
}
+// Verify IPv6 connection is preferred over IPv4.
+TEST_F(P2PTransportChannelTest, TestIPv6Connections) {
+ AddAddress(0, kIPv6PublicAddrs[0]);
+ AddAddress(0, kPublicAddrs[0]);
+ AddAddress(1, kIPv6PublicAddrs[1]);
+ AddAddress(1, kPublicAddrs[1]);
+
+ SetAllocationStepDelay(0, kMinimumStepDelay);
+ SetAllocationStepDelay(1, kMinimumStepDelay);
+
+ // Enable IPv6
+ SetAllocatorFlags(0, cricket::PORTALLOCATOR_ENABLE_IPV6);
+ SetAllocatorFlags(1, cricket::PORTALLOCATOR_ENABLE_IPV6);
+
+ CreateChannels(1);
+
+ EXPECT_TRUE_WAIT(ep1_ch1()->readable() && ep1_ch1()->writable() &&
+ ep2_ch1()->readable() && ep2_ch1()->writable(),
+ 1000);
+ EXPECT_TRUE(
+ ep1_ch1()->best_connection() && ep2_ch1()->best_connection() &&
+ LocalCandidate(ep1_ch1())->address().EqualIPs(kIPv6PublicAddrs[0]) &&
+ RemoteCandidate(ep1_ch1())->address().EqualIPs(kIPv6PublicAddrs[1]));
+
+ TestSendRecv(1);
+ DestroyChannels();
+}
+
// Test what happens when we have 2 users behind the same NAT. This can lead
// to interesting behavior because the STUN server will only give out the
// address of the outermost NAT.
diff --git a/talk/p2p/base/port_unittest.cc b/talk/p2p/base/port_unittest.cc
index d3e02ac..1cc3049 100644
--- a/talk/p2p/base/port_unittest.cc
+++ b/talk/p2p/base/port_unittest.cc
@@ -215,7 +215,7 @@
public:
TestChannel(Port* p1, Port* p2)
: ice_mode_(ICEMODE_FULL), src_(p1), dst_(p2), complete_count_(0),
- conn_(NULL), remote_request_(NULL), nominated_(false) {
+ conn_(NULL), remote_request_(), nominated_(false) {
src_->SignalPortComplete.connect(
this, &TestChannel::OnPortComplete);
src_->SignalUnknownAddress.connect(this, &TestChannel::OnUnknownAddress);
diff --git a/talk/p2p/base/pseudotcp.cc b/talk/p2p/base/pseudotcp.cc
index b647fbf..56aa5b0 100644
--- a/talk/p2p/base/pseudotcp.cc
+++ b/talk/p2p/base/pseudotcp.cc
@@ -539,7 +539,7 @@
uint32 now = Now();
- talk_base::scoped_array<uint8> buffer(new uint8[MAX_PACKET]);
+ talk_base::scoped_ptr<uint8[]> buffer(new uint8[MAX_PACKET]);
long_to_bytes(m_conv, buffer.get());
long_to_bytes(seq, buffer.get() + 4);
long_to_bytes(m_rcv_nxt, buffer.get() + 8);
diff --git a/talk/p2p/base/stun.cc b/talk/p2p/base/stun.cc
index 2a0f6d9..38fc96e 100644
--- a/talk/p2p/base/stun.cc
+++ b/talk/p2p/base/stun.cc
@@ -188,7 +188,7 @@
// Getting length of the message to calculate Message Integrity.
size_t mi_pos = current_pos;
- talk_base::scoped_array<char> temp_data(new char[current_pos]);
+ talk_base::scoped_ptr<char[]> temp_data(new char[current_pos]);
memcpy(temp_data.get(), data, current_pos);
if (size > mi_pos + kStunAttributeHeaderSize + kStunMessageIntegritySize) {
// Stun message has other attributes after message integrity.
diff --git a/talk/p2p/base/stunport.cc b/talk/p2p/base/stunport.cc
index 5e0e500..b440bf4 100644
--- a/talk/p2p/base/stunport.cc
+++ b/talk/p2p/base/stunport.cc
@@ -287,8 +287,13 @@
if (server_addr_.IsUnresolved()) {
ResolveStunAddress();
} else if (socket_->GetState() == talk_base::AsyncPacketSocket::STATE_BOUND) {
- if (server_addr_.family() == ip().family()) {
+ // Check if |server_addr_| is compatible with the port's ip.
+ if (IsCompatibleAddress(server_addr_)) {
requests_.Send(new StunBindingRequest(this, true, server_addr_));
+ } else {
+ // Since we can't send stun messages to the server, we should mark this
+ // port ready.
+ OnStunBindingOrResolveRequestFailed();
}
}
}
diff --git a/talk/p2p/base/testturnserver.h b/talk/p2p/base/testturnserver.h
index 32251c8..7a3c83f 100644
--- a/talk/p2p/base/testturnserver.h
+++ b/talk/p2p/base/testturnserver.h
@@ -47,8 +47,7 @@
const talk_base::SocketAddress& udp_int_addr,
const talk_base::SocketAddress& udp_ext_addr)
: server_(thread) {
- server_.AddInternalSocket(talk_base::AsyncUDPSocket::Create(
- thread->socketserver(), udp_int_addr), PROTO_UDP);
+ AddInternalSocket(udp_int_addr, cricket::PROTO_UDP);
server_.SetExternalSocketFactory(new talk_base::BasicPacketSocketFactory(),
udp_ext_addr);
server_.set_realm(kTestRealm);
@@ -62,6 +61,23 @@
TurnServer* server() { return &server_; }
+ void AddInternalSocket(const talk_base::SocketAddress& int_addr,
+ ProtocolType proto) {
+ talk_base::Thread* thread = talk_base::Thread::Current();
+ if (proto == cricket::PROTO_UDP) {
+ server_.AddInternalSocket(talk_base::AsyncUDPSocket::Create(
+ thread->socketserver(), int_addr), proto);
+ } else if (proto == cricket::PROTO_TCP) {
+ // For TCP we need to create a server socket which can listen for incoming
+ // new connections.
+ talk_base::AsyncSocket* socket =
+ thread->socketserver()->CreateAsyncSocket(SOCK_STREAM);
+ socket->Bind(int_addr);
+ socket->Listen(5);
+ server_.AddInternalServerSocket(socket, proto);
+ }
+ }
+
private:
// For this test server, succeed if the password is the same as the username.
// Obviously, do not use this in a production environment.
diff --git a/talk/p2p/base/turnport.cc b/talk/p2p/base/turnport.cc
index 35e51fc..880af839 100644
--- a/talk/p2p/base/turnport.cc
+++ b/talk/p2p/base/turnport.cc
@@ -206,6 +206,14 @@
return;
}
+ // If protocol family of server address doesn't match with local, return.
+ if (!IsCompatibleAddress(server_address_.address)) {
+ LOG(LS_ERROR) << "Server IP address family does not match with "
+ << "local host address family type";
+ OnAllocateError();
+ return;
+ }
+
if (!server_address_.address.port()) {
// We will set default TURN port, if no port is set in the address.
server_address_.address.SetPort(TURN_DEFAULT_PORT);
diff --git a/talk/p2p/base/turnport_unittest.cc b/talk/p2p/base/turnport_unittest.cc
index 726175c..11e2213 100644
--- a/talk/p2p/base/turnport_unittest.cc
+++ b/talk/p2p/base/turnport_unittest.cc
@@ -53,11 +53,17 @@
static const SocketAddress kLocalAddr1("11.11.11.11", 0);
static const SocketAddress kLocalAddr2("22.22.22.22", 0);
+static const SocketAddress kLocalIPv6Addr(
+ "2401:fa00:4:1000:be30:5bff:fee5:c3", 0);
static const SocketAddress kTurnUdpIntAddr("99.99.99.3",
cricket::TURN_SERVER_PORT);
static const SocketAddress kTurnTcpIntAddr("99.99.99.4",
cricket::TURN_SERVER_PORT);
static const SocketAddress kTurnUdpExtAddr("99.99.99.5", 0);
+static const SocketAddress kTurnUdpIPv6IntAddr(
+ "2400:4030:1:2c00:be30:abcd:efab:cdef", cricket::TURN_SERVER_PORT);
+static const SocketAddress kTurnUdpIPv6ExtAddr(
+ "2620:0:1000:1b03:2e41:38ff:fea6:f2a4", 0);
static const char kIceUfrag1[] = "TESTICEUFRAG0001";
static const char kIceUfrag2[] = "TESTICEUFRAG0002";
@@ -71,6 +77,8 @@
kTurnUdpIntAddr, cricket::PROTO_UDP);
static const cricket::ProtocolAddress kTurnTcpProtoAddr(
kTurnTcpIntAddr, cricket::PROTO_TCP);
+static const cricket::ProtocolAddress kTurnUdpIPv6ProtoAddr(
+ kTurnUdpIPv6IntAddr, cricket::PROTO_UDP);
class TurnPortTest : public testing::Test,
public sigslot::has_slots<> {
@@ -130,9 +138,15 @@
void CreateTurnPort(const std::string& username,
const std::string& password,
const cricket::ProtocolAddress& server_address) {
+ CreateTurnPort(kLocalAddr1, username, password, server_address);
+ }
+ void CreateTurnPort(const talk_base::SocketAddress& local_address,
+ const std::string& username,
+ const std::string& password,
+ const cricket::ProtocolAddress& server_address) {
cricket::RelayCredentials credentials(username, password);
turn_port_.reset(TurnPort::Create(main_, &socket_factory_, &network_,
- kLocalAddr1.ipaddr(), 0, 0,
+ local_address.ipaddr(), 0, 0,
kIceUfrag1, kIcePwd1,
server_address, credentials));
turn_port_->SignalPortComplete.connect(this,
@@ -265,10 +279,7 @@
}
TEST_F(TurnPortTest, TestTurnTcpAllocate) {
- talk_base::AsyncSocket* tcp_server_socket =
- CreateServerSocket(kTurnTcpIntAddr);
- turn_server_.server()->AddInternalServerSocket(
- tcp_server_socket, cricket::PROTO_TCP);
+ turn_server_.AddInternalSocket(kTurnTcpIntAddr, cricket::PROTO_TCP);
CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTcpProtoAddr);
EXPECT_EQ(0, turn_port_->SetOption(talk_base::Socket::OPT_SNDBUF, 10*1024));
turn_port_->PrepareAddress();
@@ -298,10 +309,7 @@
// Test that we can establish a TCP connection with TURN server.
TEST_F(TurnPortTest, TestTurnTcpConnection) {
- talk_base::AsyncSocket* tcp_server_socket =
- CreateServerSocket(kTurnTcpIntAddr);
- turn_server_.server()->AddInternalServerSocket(
- tcp_server_socket, cricket::PROTO_TCP);
+ turn_server_.AddInternalSocket(kTurnTcpIntAddr, cricket::PROTO_TCP);
CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTcpProtoAddr);
TestTurnConnection();
}
@@ -327,19 +335,44 @@
TestTurnConnection();
}
-// Do a TURN allocation, establish a connection, and send some data.
+// Do a TURN allocation, establish a UDP connection, and send some data.
TEST_F(TurnPortTest, TestTurnSendDataTurnUdpToUdp) {
// Create ports and prepare addresses.
CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr);
TestTurnSendData();
}
+// Do a TURN allocation, establish a TCP connection, and send some data.
TEST_F(TurnPortTest, TestTurnSendDataTurnTcpToUdp) {
- talk_base::AsyncSocket* tcp_server_socket =
- CreateServerSocket(kTurnTcpIntAddr);
- turn_server_.server()->AddInternalServerSocket(
- tcp_server_socket, cricket::PROTO_TCP);
+ turn_server_.AddInternalSocket(kTurnTcpIntAddr, cricket::PROTO_TCP);
// Create ports and prepare addresses.
CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTcpProtoAddr);
TestTurnSendData();
}
+
+// Test TURN fails to make a connection from IPv6 address to a server which has
+// IPv4 address.
+TEST_F(TurnPortTest, TestTurnLocalIPv6AddressServerIPv4) {
+ turn_server_.AddInternalSocket(kTurnUdpIPv6IntAddr, cricket::PROTO_UDP);
+ CreateTurnPort(kLocalIPv6Addr, kTurnUsername, kTurnPassword,
+ kTurnUdpProtoAddr);
+ turn_port_->PrepareAddress();
+ ASSERT_TRUE_WAIT(turn_error_, kTimeout);
+ EXPECT_TRUE(turn_port_->Candidates().empty());
+}
+
+// Test TURN make a connection from IPv6 address to a server which has
+// IPv6 intenal address. But in this test external address is a IPv4 address,
+// hence allocated address will be a IPv4 address.
+TEST_F(TurnPortTest, TestTurnLocalIPv6AddressServerIPv6ExtenalIPv4) {
+ turn_server_.AddInternalSocket(kTurnUdpIPv6IntAddr, cricket::PROTO_UDP);
+ CreateTurnPort(kLocalIPv6Addr, kTurnUsername, kTurnPassword,
+ kTurnUdpIPv6ProtoAddr);
+ turn_port_->PrepareAddress();
+ EXPECT_TRUE_WAIT(turn_ready_, kTimeout);
+ ASSERT_EQ(1U, turn_port_->Candidates().size());
+ EXPECT_EQ(kTurnUdpExtAddr.ipaddr(),
+ turn_port_->Candidates()[0].address().ipaddr());
+ EXPECT_NE(0, turn_port_->Candidates()[0].address().port());
+}
+
diff --git a/talk/p2p/client/basicportallocator.cc b/talk/p2p/client/basicportallocator.cc
index a728d98..9f10d33 100644
--- a/talk/p2p/client/basicportallocator.cc
+++ b/talk/p2p/client/basicportallocator.cc
@@ -708,7 +708,7 @@
config_(config),
state_(kInit),
flags_(flags),
- udp_socket_(NULL),
+ udp_socket_(),
phase_(0) {
}
diff --git a/talk/p2p/client/fakeportallocator.h b/talk/p2p/client/fakeportallocator.h
index 2368948..5375e50 100644
--- a/talk/p2p/client/fakeportallocator.h
+++ b/talk/p2p/client/fakeportallocator.h
@@ -32,7 +32,7 @@
factory_(factory),
network_("network", "unittest",
talk_base::IPAddress(INADDR_LOOPBACK), 8),
- port_(NULL), running_(false),
+ port_(), running_(false),
port_config_count_(0) {
network_.AddIP(talk_base::IPAddress(INADDR_LOOPBACK));
}
diff --git a/talk/p2p/client/portallocator_unittest.cc b/talk/p2p/client/portallocator_unittest.cc
index 1ee97f1..6966e44 100644
--- a/talk/p2p/client/portallocator_unittest.cc
+++ b/talk/p2p/client/portallocator_unittest.cc
@@ -50,6 +50,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 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);
@@ -740,6 +742,36 @@
EXPECT_EQ(1U, candidates_.size());
}
+// This test verifies allocator can use IPv6 addresses along with IPv4.
+TEST_F(PortAllocatorTest, TestEnableIPv6Addresses) {
+ allocator().set_flags(allocator().flags() |
+ cricket::PORTALLOCATOR_DISABLE_RELAY |
+ cricket::PORTALLOCATOR_ENABLE_IPV6 |
+ cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG |
+ cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET);
+ AddInterface(kClientIPv6Addr);
+ AddInterface(kClientAddr);
+ allocator_->set_step_delay(cricket::kMinimumStepDelay);
+ EXPECT_TRUE(CreateSession(cricket::ICE_CANDIDATE_COMPONENT_RTP));
+ session_->StartGettingPorts();
+ ASSERT_EQ_WAIT(4U, ports_.size(), kDefaultAllocationTimeout);
+ EXPECT_EQ(4U, candidates_.size());
+ EXPECT_TRUE_WAIT(candidate_allocation_done_, kDefaultAllocationTimeout);
+ EXPECT_PRED5(CheckCandidate, candidates_[0],
+ cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "udp",
+ kClientIPv6Addr);
+ EXPECT_PRED5(CheckCandidate, candidates_[1],
+ cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "udp",
+ kClientAddr);
+ EXPECT_PRED5(CheckCandidate, candidates_[2],
+ cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "tcp",
+ kClientIPv6Addr);
+ EXPECT_PRED5(CheckCandidate, candidates_[3],
+ cricket::ICE_CANDIDATE_COMPONENT_RTP, "local", "tcp",
+ kClientAddr);
+ EXPECT_EQ(4U, candidates_.size());
+}
+
// Test that the httpportallocator correctly maintains its lists of stun and
// relay servers, by never allowing an empty list.
TEST(HttpPortAllocatorTest, TestHttpPortAllocatorHostLists) {
diff --git a/talk/session/media/channel.cc b/talk/session/media/channel.cc
index db169be..9c9847f 100644
--- a/talk/session/media/channel.cc
+++ b/talk/session/media/channel.cc
@@ -399,7 +399,6 @@
writable_(false),
rtp_ready_to_send_(false),
rtcp_ready_to_send_(false),
- optimistic_data_send_(false),
was_ever_writable_(false),
local_content_direction_(MD_INACTIVE),
remote_content_direction_(MD_INACTIVE),
@@ -670,7 +669,7 @@
// transport.
TransportChannel* channel = (!rtcp || rtcp_mux_filter_.IsActive()) ?
transport_channel_ : rtcp_transport_channel_;
- if (!channel || (!optimistic_data_send_ && !channel->writable())) {
+ if (!channel || !channel->writable()) {
return false;
}
diff --git a/talk/session/media/channel.h b/talk/session/media/channel.h
index 3a627ed..51fb575 100644
--- a/talk/session/media/channel.h
+++ b/talk/session/media/channel.h
@@ -97,10 +97,6 @@
return rtcp_transport_channel_;
}
bool enabled() const { return enabled_; }
- // Set to true to have the channel optimistically allow data to be sent even
- // when the channel isn't fully writable.
- void set_optimistic_data_send(bool value) { optimistic_data_send_ = value; }
- bool optimistic_data_send() const { return optimistic_data_send_; }
// This function returns true if we are using SRTP.
bool secure() const { return srtp_filter_.IsActive(); }
@@ -362,7 +358,6 @@
bool writable_;
bool rtp_ready_to_send_;
bool rtcp_ready_to_send_;
- bool optimistic_data_send_;
bool was_ever_writable_;
MediaContentDirection local_content_direction_;
MediaContentDirection remote_content_direction_;
diff --git a/talk/session/media/channel_unittest.cc b/talk/session/media/channel_unittest.cc
index 24ece06..0273907 100644
--- a/talk/session/media/channel_unittest.cc
+++ b/talk/session/media/channel_unittest.cc
@@ -496,11 +496,6 @@
// overridden in specialized classes
}
- void SetOptimisticDataSend(bool optimistic_data_send) {
- channel1_->set_optimistic_data_send(optimistic_data_send);
- channel2_->set_optimistic_data_send(optimistic_data_send);
- }
-
// Creates a cricket::SessionDescription with one MediaContent and one stream.
// kPcmuCodec is used as audio codec and kH264Codec is used as video codec.
cricket::SessionDescription* CreateSessionDescriptionWithStream(uint32 ssrc) {
@@ -1394,19 +1389,8 @@
EXPECT_TRUE(CheckNoRtp1());
EXPECT_TRUE(CheckNoRtp2());
- // Lose writability, with optimistic send
- SetOptimisticDataSend(true);
+ // Lose writability, which should fail.
GetTransport1()->SetWritable(false);
- EXPECT_TRUE(media_channel1_->sending());
- EXPECT_TRUE(SendRtp1());
- EXPECT_TRUE(SendRtp2());
- EXPECT_TRUE(CheckRtp1());
- EXPECT_TRUE(CheckRtp2());
- EXPECT_TRUE(CheckNoRtp1());
- EXPECT_TRUE(CheckNoRtp2());
-
- // Check again with optimistic send off, which should fail.
- SetOptimisticDataSend(false);
EXPECT_FALSE(SendRtp1());
EXPECT_TRUE(SendRtp2());
EXPECT_TRUE(CheckRtp1());
@@ -1426,13 +1410,7 @@
GetTransport1()->SetDestination(NULL);
EXPECT_TRUE(media_channel1_->sending());
- // Should fail regardless of optimistic send at this point.
- SetOptimisticDataSend(true);
- EXPECT_FALSE(SendRtp1());
- EXPECT_TRUE(SendRtp2());
- EXPECT_TRUE(CheckRtp1());
- EXPECT_TRUE(CheckNoRtp2());
- SetOptimisticDataSend(false);
+ // Should fail also.
EXPECT_FALSE(SendRtp1());
EXPECT_TRUE(SendRtp2());
EXPECT_TRUE(CheckRtp1());
diff --git a/talk/session/media/mediasession.cc b/talk/session/media/mediasession.cc
index ea23591..ae3fb57 100644
--- a/talk/session/media/mediasession.cc
+++ b/talk/session/media/mediasession.cc
@@ -46,7 +46,7 @@
#ifdef HAVE_SCTP
#include "talk/media/sctp/sctpdataengine.h"
#else
-static const uint32 kMaxSctpSid = USHRT_MAX;
+static const uint32 kMaxSctpSid = 1023;
#endif
namespace {
diff --git a/talk/session/media/mediasession_unittest.cc b/talk/session/media/mediasession_unittest.cc
index 850d67f..ceb2bcd 100644
--- a/talk/session/media/mediasession_unittest.cc
+++ b/talk/session/media/mediasession_unittest.cc
@@ -882,8 +882,8 @@
answer_opts.data_channel_type = cricket::DCT_RTP;
offer_opts.data_channel_type = cricket::DCT_RTP;
- talk_base::scoped_ptr<SessionDescription> offer(NULL);
- talk_base::scoped_ptr<SessionDescription> answer(NULL);
+ talk_base::scoped_ptr<SessionDescription> offer;
+ talk_base::scoped_ptr<SessionDescription> answer;
offer_opts.rtcp_mux_enabled = true;
answer_opts.rtcp_mux_enabled = true;
diff --git a/talk/sound/alsasoundsystem.cc b/talk/sound/alsasoundsystem.cc
index de9e2d6..7a8857c 100644
--- a/talk/sound/alsasoundsystem.cc
+++ b/talk/sound/alsasoundsystem.cc
@@ -342,7 +342,7 @@
}
AlsaStream stream_;
- talk_base::scoped_array<char> buffer_;
+ talk_base::scoped_ptr<char[]> buffer_;
size_t buffer_size_;
DISALLOW_COPY_AND_ASSIGN(AlsaInputStream);
diff --git a/talk/xmllite/xmlbuilder.cc b/talk/xmllite/xmlbuilder.cc
index 486b6d5..f71e542 100644
--- a/talk/xmllite/xmlbuilder.cc
+++ b/talk/xmllite/xmlbuilder.cc
@@ -37,7 +37,7 @@
XmlBuilder::XmlBuilder() :
pelCurrent_(NULL),
- pelRoot_(NULL),
+ pelRoot_(),
pvParents_(new std::vector<XmlElement *>()) {
}
diff --git a/talk/xmpp/xmppclient.cc b/talk/xmpp/xmppclient.cc
index 9c49a9c..8927dad 100644
--- a/talk/xmpp/xmppclient.cc
+++ b/talk/xmpp/xmppclient.cc
@@ -46,8 +46,8 @@
explicit Private(XmppClient* client) :
client_(client),
- socket_(NULL),
- engine_(NULL),
+ socket_(),
+ engine_(),
proxy_port_(0),
pre_engine_error_(XmppEngine::ERROR_NONE),
pre_engine_subcode_(0),
diff --git a/talk/xmpp/xmppengineimpl.cc b/talk/xmpp/xmppengineimpl.cc
index 8bcea02..d4c9c7d 100644
--- a/talk/xmpp/xmppengineimpl.cc
+++ b/talk/xmpp/xmppengineimpl.cc
@@ -58,12 +58,12 @@
encrypted_(false),
error_code_(ERROR_NONE),
subcode_(0),
- stream_error_(NULL),
+ stream_error_(),
raised_reset_(false),
output_handler_(NULL),
session_handler_(NULL),
iq_entries_(new IqEntryVector()),
- sasl_handler_(NULL),
+ sasl_handler_(),
output_(new std::stringstream()) {
for (int i = 0; i < HL_COUNT; i+= 1) {
stanza_handlers_[i].reset(new StanzaHandlerVector());
diff --git a/talk/xmpp/xmpplogintask.cc b/talk/xmpp/xmpplogintask.cc
index eec943b..b3a2047 100644
--- a/talk/xmpp/xmpplogintask.cc
+++ b/talk/xmpp/xmpplogintask.cc
@@ -66,11 +66,11 @@
pelStanza_(NULL),
isStart_(false),
iqId_(STR_EMPTY),
- pelFeatures_(NULL),
+ pelFeatures_(),
fullJid_(STR_EMPTY),
streamId_(STR_EMPTY),
pvecQueuedStanzas_(new std::vector<XmlElement *>()),
- sasl_mech_(NULL) {
+ sasl_mech_() {
}
XmppLoginTask::~XmppLoginTask() {