aboutsummaryrefslogtreecommitdiff
path: root/talk/app/webrtc/test
diff options
context:
space:
mode:
authorChih-hung Hsieh <chh@google.com>2015-12-01 17:07:48 +0000
committerandroid-build-merger <android-build-merger@google.com>2015-12-01 17:07:48 +0000
commita4acd9d6bc9b3b033d7d274316e75ee067df8d20 (patch)
tree672a185b294789cf991f385c3e395dd63bea9063 /talk/app/webrtc/test
parent3681b90ba4fe7a27232dd3e27897d5d7ed9d651c (diff)
parentfe8b4a657979b49e1701bd92f6d5814a99e0b2be (diff)
downloadwebrtc-a4acd9d6bc9b3b033d7d274316e75ee067df8d20.tar.gz
Merge changes I7bbf776e,I1b827825
am: fe8b4a6579 * commit 'fe8b4a657979b49e1701bd92f6d5814a99e0b2be': (7237 commits) WIP: Changes after merge commit 'cb3f9bd' Make the nonlinear beamformer steerable Utilize bitrate above codec max to protect video. Enable VP9 internal resize by default. Filter overlapping RTP header extensions. Make VCMEncodedFrameCallback const. MediaCodecVideoEncoder: Add number of quality resolution downscales to Encoded callback. Remove redudant encoder rate calls. Create isolate files for nonparallel tests. Register header extensions in RtpRtcpObserver to avoid log spam. Make an enum class out of NetEqDecoder, and hide the neteq_decoders_ table ACM: Move NACK functionality inside NetEq Fix chromium-style warnings in webrtc/sound/. Create a 'webrtc_nonparallel_tests' target. Update scalability structure data according to updates in the RTP payload profile. audio_coding: rename interface -> include Rewrote perform_action_on_all_files to be parallell. Update reference indices according to updates in the RTP payload profile. Disable P2PTransport...TestFailoverControlledSide on Memcheck pass clangcl compile options to ignore warnings in gflags.cc ...
Diffstat (limited to 'talk/app/webrtc/test')
-rw-r--r--talk/app/webrtc/test/fakeaudiocapturemodule.cc744
-rw-r--r--talk/app/webrtc/test/fakeaudiocapturemodule.h287
-rw-r--r--talk/app/webrtc/test/fakeaudiocapturemodule_unittest.cc216
-rw-r--r--talk/app/webrtc/test/fakeconstraints.h133
-rw-r--r--talk/app/webrtc/test/fakedatachannelprovider.h161
-rw-r--r--talk/app/webrtc/test/fakedtlsidentitystore.h143
-rw-r--r--talk/app/webrtc/test/fakemediastreamsignaling.h140
-rw-r--r--talk/app/webrtc/test/fakeperiodicvideocapturer.h89
-rw-r--r--talk/app/webrtc/test/fakevideotrackrenderer.h75
-rw-r--r--talk/app/webrtc/test/mockpeerconnectionobservers.h243
-rw-r--r--talk/app/webrtc/test/peerconnectiontestwrapper.cc297
-rw-r--r--talk/app/webrtc/test/peerconnectiontestwrapper.h122
-rw-r--r--talk/app/webrtc/test/testsdpstrings.h147
13 files changed, 2797 insertions, 0 deletions
diff --git a/talk/app/webrtc/test/fakeaudiocapturemodule.cc b/talk/app/webrtc/test/fakeaudiocapturemodule.cc
new file mode 100644
index 0000000000..3564d28d25
--- /dev/null
+++ b/talk/app/webrtc/test/fakeaudiocapturemodule.cc
@@ -0,0 +1,744 @@
+/*
+ * libjingle
+ * Copyright 2012 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "talk/app/webrtc/test/fakeaudiocapturemodule.h"
+
+#include "webrtc/base/common.h"
+#include "webrtc/base/refcount.h"
+#include "webrtc/base/thread.h"
+#include "webrtc/base/timeutils.h"
+
+// Audio sample value that is high enough that it doesn't occur naturally when
+// frames are being faked. E.g. NetEq will not generate this large sample value
+// unless it has received an audio frame containing a sample of this value.
+// Even simpler buffers would likely just contain audio sample values of 0.
+static const int kHighSampleValue = 10000;
+
+// Same value as src/modules/audio_device/main/source/audio_device_config.h in
+// https://code.google.com/p/webrtc/
+static const uint32_t kAdmMaxIdleTimeProcess = 1000;
+
+// Constants here are derived by running VoE using a real ADM.
+// The constants correspond to 10ms of mono audio at 44kHz.
+static const int kTimePerFrameMs = 10;
+static const uint8_t kNumberOfChannels = 1;
+static const int kSamplesPerSecond = 44000;
+static const int kTotalDelayMs = 0;
+static const int kClockDriftMs = 0;
+static const uint32_t kMaxVolume = 14392;
+
+enum {
+ MSG_START_PROCESS,
+ MSG_RUN_PROCESS,
+};
+
+FakeAudioCaptureModule::FakeAudioCaptureModule()
+ : last_process_time_ms_(0),
+ audio_callback_(nullptr),
+ recording_(false),
+ playing_(false),
+ play_is_initialized_(false),
+ rec_is_initialized_(false),
+ current_mic_level_(kMaxVolume),
+ started_(false),
+ next_frame_time_(0),
+ frames_received_(0) {
+}
+
+FakeAudioCaptureModule::~FakeAudioCaptureModule() {
+ if (process_thread_) {
+ process_thread_->Stop();
+ }
+}
+
+rtc::scoped_refptr<FakeAudioCaptureModule> FakeAudioCaptureModule::Create() {
+ rtc::scoped_refptr<FakeAudioCaptureModule> capture_module(
+ new rtc::RefCountedObject<FakeAudioCaptureModule>());
+ if (!capture_module->Initialize()) {
+ return nullptr;
+ }
+ return capture_module;
+}
+
+int FakeAudioCaptureModule::frames_received() const {
+ rtc::CritScope cs(&crit_);
+ return frames_received_;
+}
+
+int64_t FakeAudioCaptureModule::TimeUntilNextProcess() {
+ const uint32_t current_time = rtc::Time();
+ if (current_time < last_process_time_ms_) {
+ // TODO: wraparound could be handled more gracefully.
+ return 0;
+ }
+ const uint32_t elapsed_time = current_time - last_process_time_ms_;
+ if (kAdmMaxIdleTimeProcess < elapsed_time) {
+ return 0;
+ }
+ return kAdmMaxIdleTimeProcess - elapsed_time;
+}
+
+int32_t FakeAudioCaptureModule::Process() {
+ last_process_time_ms_ = rtc::Time();
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::ActiveAudioLayer(
+ AudioLayer* /*audio_layer*/) const {
+ ASSERT(false);
+ return 0;
+}
+
+webrtc::AudioDeviceModule::ErrorCode FakeAudioCaptureModule::LastError() const {
+ ASSERT(false);
+ return webrtc::AudioDeviceModule::kAdmErrNone;
+}
+
+int32_t FakeAudioCaptureModule::RegisterEventObserver(
+ webrtc::AudioDeviceObserver* /*event_callback*/) {
+ // Only used to report warnings and errors. This fake implementation won't
+ // generate any so discard this callback.
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::RegisterAudioCallback(
+ webrtc::AudioTransport* audio_callback) {
+ rtc::CritScope cs(&crit_callback_);
+ audio_callback_ = audio_callback;
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::Init() {
+ // Initialize is called by the factory method. Safe to ignore this Init call.
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::Terminate() {
+ // Clean up in the destructor. No action here, just success.
+ return 0;
+}
+
+bool FakeAudioCaptureModule::Initialized() const {
+ ASSERT(false);
+ return 0;
+}
+
+int16_t FakeAudioCaptureModule::PlayoutDevices() {
+ ASSERT(false);
+ return 0;
+}
+
+int16_t FakeAudioCaptureModule::RecordingDevices() {
+ ASSERT(false);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::PlayoutDeviceName(
+ uint16_t /*index*/,
+ char /*name*/[webrtc::kAdmMaxDeviceNameSize],
+ char /*guid*/[webrtc::kAdmMaxGuidSize]) {
+ ASSERT(false);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::RecordingDeviceName(
+ uint16_t /*index*/,
+ char /*name*/[webrtc::kAdmMaxDeviceNameSize],
+ char /*guid*/[webrtc::kAdmMaxGuidSize]) {
+ ASSERT(false);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::SetPlayoutDevice(uint16_t /*index*/) {
+ // No playout device, just playing from file. Return success.
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::SetPlayoutDevice(WindowsDeviceType /*device*/) {
+ if (play_is_initialized_) {
+ return -1;
+ }
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::SetRecordingDevice(uint16_t /*index*/) {
+ // No recording device, just dropping audio. Return success.
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::SetRecordingDevice(
+ WindowsDeviceType /*device*/) {
+ if (rec_is_initialized_) {
+ return -1;
+ }
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::PlayoutIsAvailable(bool* /*available*/) {
+ ASSERT(false);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::InitPlayout() {
+ play_is_initialized_ = true;
+ return 0;
+}
+
+bool FakeAudioCaptureModule::PlayoutIsInitialized() const {
+ return play_is_initialized_;
+}
+
+int32_t FakeAudioCaptureModule::RecordingIsAvailable(bool* /*available*/) {
+ ASSERT(false);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::InitRecording() {
+ rec_is_initialized_ = true;
+ return 0;
+}
+
+bool FakeAudioCaptureModule::RecordingIsInitialized() const {
+ ASSERT(false);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::StartPlayout() {
+ if (!play_is_initialized_) {
+ return -1;
+ }
+ {
+ rtc::CritScope cs(&crit_);
+ playing_ = true;
+ }
+ bool start = true;
+ UpdateProcessing(start);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::StopPlayout() {
+ bool start = false;
+ {
+ rtc::CritScope cs(&crit_);
+ playing_ = false;
+ start = ShouldStartProcessing();
+ }
+ UpdateProcessing(start);
+ return 0;
+}
+
+bool FakeAudioCaptureModule::Playing() const {
+ rtc::CritScope cs(&crit_);
+ return playing_;
+}
+
+int32_t FakeAudioCaptureModule::StartRecording() {
+ if (!rec_is_initialized_) {
+ return -1;
+ }
+ {
+ rtc::CritScope cs(&crit_);
+ recording_ = true;
+ }
+ bool start = true;
+ UpdateProcessing(start);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::StopRecording() {
+ bool start = false;
+ {
+ rtc::CritScope cs(&crit_);
+ recording_ = false;
+ start = ShouldStartProcessing();
+ }
+ UpdateProcessing(start);
+ return 0;
+}
+
+bool FakeAudioCaptureModule::Recording() const {
+ rtc::CritScope cs(&crit_);
+ return recording_;
+}
+
+int32_t FakeAudioCaptureModule::SetAGC(bool /*enable*/) {
+ // No AGC but not needed since audio is pregenerated. Return success.
+ return 0;
+}
+
+bool FakeAudioCaptureModule::AGC() const {
+ ASSERT(false);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::SetWaveOutVolume(uint16_t /*volume_left*/,
+ uint16_t /*volume_right*/) {
+ ASSERT(false);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::WaveOutVolume(
+ uint16_t* /*volume_left*/,
+ uint16_t* /*volume_right*/) const {
+ ASSERT(false);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::InitSpeaker() {
+ // No speaker, just playing from file. Return success.
+ return 0;
+}
+
+bool FakeAudioCaptureModule::SpeakerIsInitialized() const {
+ ASSERT(false);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::InitMicrophone() {
+ // No microphone, just playing from file. Return success.
+ return 0;
+}
+
+bool FakeAudioCaptureModule::MicrophoneIsInitialized() const {
+ ASSERT(false);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::SpeakerVolumeIsAvailable(bool* /*available*/) {
+ ASSERT(false);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::SetSpeakerVolume(uint32_t /*volume*/) {
+ ASSERT(false);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::SpeakerVolume(uint32_t* /*volume*/) const {
+ ASSERT(false);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::MaxSpeakerVolume(
+ uint32_t* /*max_volume*/) const {
+ ASSERT(false);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::MinSpeakerVolume(
+ uint32_t* /*min_volume*/) const {
+ ASSERT(false);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::SpeakerVolumeStepSize(
+ uint16_t* /*step_size*/) const {
+ ASSERT(false);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::MicrophoneVolumeIsAvailable(
+ bool* /*available*/) {
+ ASSERT(false);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::SetMicrophoneVolume(uint32_t volume) {
+ rtc::CritScope cs(&crit_);
+ current_mic_level_ = volume;
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::MicrophoneVolume(uint32_t* volume) const {
+ rtc::CritScope cs(&crit_);
+ *volume = current_mic_level_;
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::MaxMicrophoneVolume(
+ uint32_t* max_volume) const {
+ *max_volume = kMaxVolume;
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::MinMicrophoneVolume(
+ uint32_t* /*min_volume*/) const {
+ ASSERT(false);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::MicrophoneVolumeStepSize(
+ uint16_t* /*step_size*/) const {
+ ASSERT(false);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::SpeakerMuteIsAvailable(bool* /*available*/) {
+ ASSERT(false);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::SetSpeakerMute(bool /*enable*/) {
+ ASSERT(false);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::SpeakerMute(bool* /*enabled*/) const {
+ ASSERT(false);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::MicrophoneMuteIsAvailable(bool* /*available*/) {
+ ASSERT(false);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::SetMicrophoneMute(bool /*enable*/) {
+ ASSERT(false);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::MicrophoneMute(bool* /*enabled*/) const {
+ ASSERT(false);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::MicrophoneBoostIsAvailable(
+ bool* /*available*/) {
+ ASSERT(false);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::SetMicrophoneBoost(bool /*enable*/) {
+ ASSERT(false);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::MicrophoneBoost(bool* /*enabled*/) const {
+ ASSERT(false);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::StereoPlayoutIsAvailable(
+ bool* available) const {
+ // No recording device, just dropping audio. Stereo can be dropped just
+ // as easily as mono.
+ *available = true;
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::SetStereoPlayout(bool /*enable*/) {
+ // No recording device, just dropping audio. Stereo can be dropped just
+ // as easily as mono.
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::StereoPlayout(bool* /*enabled*/) const {
+ ASSERT(false);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::StereoRecordingIsAvailable(
+ bool* available) const {
+ // Keep thing simple. No stereo recording.
+ *available = false;
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::SetStereoRecording(bool enable) {
+ if (!enable) {
+ return 0;
+ }
+ return -1;
+}
+
+int32_t FakeAudioCaptureModule::StereoRecording(bool* /*enabled*/) const {
+ ASSERT(false);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::SetRecordingChannel(
+ const ChannelType channel) {
+ if (channel != AudioDeviceModule::kChannelBoth) {
+ // There is no right or left in mono. I.e. kChannelBoth should be used for
+ // mono.
+ ASSERT(false);
+ return -1;
+ }
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::RecordingChannel(ChannelType* channel) const {
+ // Stereo recording not supported. However, WebRTC ADM returns kChannelBoth
+ // in that case. Do the same here.
+ *channel = AudioDeviceModule::kChannelBoth;
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::SetPlayoutBuffer(const BufferType /*type*/,
+ uint16_t /*size_ms*/) {
+ ASSERT(false);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::PlayoutBuffer(BufferType* /*type*/,
+ uint16_t* /*size_ms*/) const {
+ ASSERT(false);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::PlayoutDelay(uint16_t* delay_ms) const {
+ // No delay since audio frames are dropped.
+ *delay_ms = 0;
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::RecordingDelay(uint16_t* /*delay_ms*/) const {
+ ASSERT(false);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::CPULoad(uint16_t* /*load*/) const {
+ ASSERT(false);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::StartRawOutputFileRecording(
+ const char /*pcm_file_name_utf8*/[webrtc::kAdmMaxFileNameSize]) {
+ ASSERT(false);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::StopRawOutputFileRecording() {
+ ASSERT(false);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::StartRawInputFileRecording(
+ const char /*pcm_file_name_utf8*/[webrtc::kAdmMaxFileNameSize]) {
+ ASSERT(false);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::StopRawInputFileRecording() {
+ ASSERT(false);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::SetRecordingSampleRate(
+ const uint32_t /*samples_per_sec*/) {
+ ASSERT(false);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::RecordingSampleRate(
+ uint32_t* /*samples_per_sec*/) const {
+ ASSERT(false);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::SetPlayoutSampleRate(
+ const uint32_t /*samples_per_sec*/) {
+ ASSERT(false);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::PlayoutSampleRate(
+ uint32_t* /*samples_per_sec*/) const {
+ ASSERT(false);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::ResetAudioDevice() {
+ ASSERT(false);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::SetLoudspeakerStatus(bool /*enable*/) {
+ ASSERT(false);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::GetLoudspeakerStatus(bool* /*enabled*/) const {
+ ASSERT(false);
+ return 0;
+}
+
+void FakeAudioCaptureModule::OnMessage(rtc::Message* msg) {
+ switch (msg->message_id) {
+ case MSG_START_PROCESS:
+ StartProcessP();
+ break;
+ case MSG_RUN_PROCESS:
+ ProcessFrameP();
+ break;
+ default:
+ // All existing messages should be caught. Getting here should never
+ // happen.
+ ASSERT(false);
+ }
+}
+
+bool FakeAudioCaptureModule::Initialize() {
+ // Set the send buffer samples high enough that it would not occur on the
+ // remote side unless a packet containing a sample of that magnitude has been
+ // sent to it. Note that the audio processing pipeline will likely distort the
+ // original signal.
+ SetSendBuffer(kHighSampleValue);
+ last_process_time_ms_ = rtc::Time();
+ return true;
+}
+
+void FakeAudioCaptureModule::SetSendBuffer(int value) {
+ Sample* buffer_ptr = reinterpret_cast<Sample*>(send_buffer_);
+ const size_t buffer_size_in_samples =
+ sizeof(send_buffer_) / kNumberBytesPerSample;
+ for (size_t i = 0; i < buffer_size_in_samples; ++i) {
+ buffer_ptr[i] = value;
+ }
+}
+
+void FakeAudioCaptureModule::ResetRecBuffer() {
+ memset(rec_buffer_, 0, sizeof(rec_buffer_));
+}
+
+bool FakeAudioCaptureModule::CheckRecBuffer(int value) {
+ const Sample* buffer_ptr = reinterpret_cast<const Sample*>(rec_buffer_);
+ const size_t buffer_size_in_samples =
+ sizeof(rec_buffer_) / kNumberBytesPerSample;
+ for (size_t i = 0; i < buffer_size_in_samples; ++i) {
+ if (buffer_ptr[i] >= value) return true;
+ }
+ return false;
+}
+
+bool FakeAudioCaptureModule::ShouldStartProcessing() {
+ return recording_ || playing_;
+}
+
+void FakeAudioCaptureModule::UpdateProcessing(bool start) {
+ if (start) {
+ if (!process_thread_) {
+ process_thread_.reset(new rtc::Thread());
+ process_thread_->Start();
+ }
+ process_thread_->Post(this, MSG_START_PROCESS);
+ } else {
+ if (process_thread_) {
+ process_thread_->Stop();
+ process_thread_.reset(nullptr);
+ }
+ started_ = false;
+ }
+}
+
+void FakeAudioCaptureModule::StartProcessP() {
+ ASSERT(process_thread_->IsCurrent());
+ if (started_) {
+ // Already started.
+ return;
+ }
+ ProcessFrameP();
+}
+
+void FakeAudioCaptureModule::ProcessFrameP() {
+ ASSERT(process_thread_->IsCurrent());
+ if (!started_) {
+ next_frame_time_ = rtc::Time();
+ started_ = true;
+ }
+
+ {
+ rtc::CritScope cs(&crit_);
+ // Receive and send frames every kTimePerFrameMs.
+ if (playing_) {
+ ReceiveFrameP();
+ }
+ if (recording_) {
+ SendFrameP();
+ }
+ }
+
+ next_frame_time_ += kTimePerFrameMs;
+ const uint32_t current_time = rtc::Time();
+ const uint32_t wait_time =
+ (next_frame_time_ > current_time) ? next_frame_time_ - current_time : 0;
+ process_thread_->PostDelayed(wait_time, this, MSG_RUN_PROCESS);
+}
+
+void FakeAudioCaptureModule::ReceiveFrameP() {
+ ASSERT(process_thread_->IsCurrent());
+ {
+ rtc::CritScope cs(&crit_callback_);
+ if (!audio_callback_) {
+ return;
+ }
+ ResetRecBuffer();
+ size_t nSamplesOut = 0;
+ int64_t elapsed_time_ms = 0;
+ int64_t ntp_time_ms = 0;
+ if (audio_callback_->NeedMorePlayData(kNumberSamples, kNumberBytesPerSample,
+ kNumberOfChannels, kSamplesPerSecond,
+ rec_buffer_, nSamplesOut,
+ &elapsed_time_ms, &ntp_time_ms) != 0) {
+ ASSERT(false);
+ }
+ ASSERT(nSamplesOut == kNumberSamples);
+ }
+ // The SetBuffer() function ensures that after decoding, the audio buffer
+ // should contain samples of similar magnitude (there is likely to be some
+ // distortion due to the audio pipeline). If one sample is detected to
+ // have the same or greater magnitude somewhere in the frame, an actual frame
+ // has been received from the remote side (i.e. faked frames are not being
+ // pulled).
+ if (CheckRecBuffer(kHighSampleValue)) {
+ rtc::CritScope cs(&crit_);
+ ++frames_received_;
+ }
+}
+
+void FakeAudioCaptureModule::SendFrameP() {
+ ASSERT(process_thread_->IsCurrent());
+ rtc::CritScope cs(&crit_callback_);
+ if (!audio_callback_) {
+ return;
+ }
+ bool key_pressed = false;
+ uint32_t current_mic_level = 0;
+ MicrophoneVolume(&current_mic_level);
+ if (audio_callback_->RecordedDataIsAvailable(send_buffer_, kNumberSamples,
+ kNumberBytesPerSample,
+ kNumberOfChannels,
+ kSamplesPerSecond, kTotalDelayMs,
+ kClockDriftMs, current_mic_level,
+ key_pressed,
+ current_mic_level) != 0) {
+ ASSERT(false);
+ }
+ SetMicrophoneVolume(current_mic_level);
+}
+
diff --git a/talk/app/webrtc/test/fakeaudiocapturemodule.h b/talk/app/webrtc/test/fakeaudiocapturemodule.h
new file mode 100644
index 0000000000..4284b9ed51
--- /dev/null
+++ b/talk/app/webrtc/test/fakeaudiocapturemodule.h
@@ -0,0 +1,287 @@
+/*
+ * libjingle
+ * Copyright 2012 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.
+ */
+
+// This class implements an AudioCaptureModule that can be used to detect if
+// audio is being received properly if it is fed by another AudioCaptureModule
+// in some arbitrary audio pipeline where they are connected. It does not play
+// out or record any audio so it does not need access to any hardware and can
+// therefore be used in the gtest testing framework.
+
+// Note P postfix of a function indicates that it should only be called by the
+// processing thread.
+
+#ifndef TALK_APP_WEBRTC_TEST_FAKEAUDIOCAPTUREMODULE_H_
+#define TALK_APP_WEBRTC_TEST_FAKEAUDIOCAPTUREMODULE_H_
+
+#include "webrtc/base/basictypes.h"
+#include "webrtc/base/criticalsection.h"
+#include "webrtc/base/messagehandler.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/base/scoped_ref_ptr.h"
+#include "webrtc/common_types.h"
+#include "webrtc/modules/audio_device/include/audio_device.h"
+
+namespace rtc {
+class Thread;
+} // namespace rtc
+
+class FakeAudioCaptureModule
+ : public webrtc::AudioDeviceModule,
+ public rtc::MessageHandler {
+ public:
+ typedef uint16_t Sample;
+
+ // The value for the following constants have been derived by running VoE
+ // using a real ADM. The constants correspond to 10ms of mono audio at 44kHz.
+ static const size_t kNumberSamples = 440;
+ static const size_t kNumberBytesPerSample = sizeof(Sample);
+
+ // Creates a FakeAudioCaptureModule or returns NULL on failure.
+ static rtc::scoped_refptr<FakeAudioCaptureModule> Create();
+
+ // Returns the number of frames that have been successfully pulled by the
+ // instance. Note that correctly detecting success can only be done if the
+ // pulled frame was generated/pushed from a FakeAudioCaptureModule.
+ int frames_received() const;
+
+ // Following functions are inherited from webrtc::AudioDeviceModule.
+ // Only functions called by PeerConnection are implemented, the rest do
+ // nothing and return success. If a function is not expected to be called by
+ // PeerConnection an assertion is triggered if it is in fact called.
+ int64_t TimeUntilNextProcess() override;
+ int32_t Process() override;
+
+ int32_t ActiveAudioLayer(AudioLayer* audio_layer) const override;
+
+ ErrorCode LastError() const override;
+ int32_t RegisterEventObserver(
+ webrtc::AudioDeviceObserver* event_callback) override;
+
+ // Note: Calling this method from a callback may result in deadlock.
+ int32_t RegisterAudioCallback(
+ webrtc::AudioTransport* audio_callback) override;
+
+ int32_t Init() override;
+ int32_t Terminate() override;
+ bool Initialized() const override;
+
+ int16_t PlayoutDevices() override;
+ int16_t RecordingDevices() override;
+ int32_t PlayoutDeviceName(uint16_t index,
+ char name[webrtc::kAdmMaxDeviceNameSize],
+ char guid[webrtc::kAdmMaxGuidSize]) override;
+ int32_t RecordingDeviceName(uint16_t index,
+ char name[webrtc::kAdmMaxDeviceNameSize],
+ char guid[webrtc::kAdmMaxGuidSize]) override;
+
+ int32_t SetPlayoutDevice(uint16_t index) override;
+ int32_t SetPlayoutDevice(WindowsDeviceType device) override;
+ int32_t SetRecordingDevice(uint16_t index) override;
+ int32_t SetRecordingDevice(WindowsDeviceType device) override;
+
+ int32_t PlayoutIsAvailable(bool* available) override;
+ int32_t InitPlayout() override;
+ bool PlayoutIsInitialized() const override;
+ int32_t RecordingIsAvailable(bool* available) override;
+ int32_t InitRecording() override;
+ bool RecordingIsInitialized() const override;
+
+ int32_t StartPlayout() override;
+ int32_t StopPlayout() override;
+ bool Playing() const override;
+ int32_t StartRecording() override;
+ int32_t StopRecording() override;
+ bool Recording() const override;
+
+ int32_t SetAGC(bool enable) override;
+ bool AGC() const override;
+
+ int32_t SetWaveOutVolume(uint16_t volume_left,
+ uint16_t volume_right) override;
+ int32_t WaveOutVolume(uint16_t* volume_left,
+ uint16_t* volume_right) const override;
+
+ int32_t InitSpeaker() override;
+ bool SpeakerIsInitialized() const override;
+ int32_t InitMicrophone() override;
+ bool MicrophoneIsInitialized() const override;
+
+ int32_t SpeakerVolumeIsAvailable(bool* available) override;
+ int32_t SetSpeakerVolume(uint32_t volume) override;
+ int32_t SpeakerVolume(uint32_t* volume) const override;
+ int32_t MaxSpeakerVolume(uint32_t* max_volume) const override;
+ int32_t MinSpeakerVolume(uint32_t* min_volume) const override;
+ int32_t SpeakerVolumeStepSize(uint16_t* step_size) const override;
+
+ int32_t MicrophoneVolumeIsAvailable(bool* available) override;
+ int32_t SetMicrophoneVolume(uint32_t volume) override;
+ int32_t MicrophoneVolume(uint32_t* volume) const override;
+ int32_t MaxMicrophoneVolume(uint32_t* max_volume) const override;
+
+ int32_t MinMicrophoneVolume(uint32_t* min_volume) const override;
+ int32_t MicrophoneVolumeStepSize(uint16_t* step_size) const override;
+
+ int32_t SpeakerMuteIsAvailable(bool* available) override;
+ int32_t SetSpeakerMute(bool enable) override;
+ int32_t SpeakerMute(bool* enabled) const override;
+
+ int32_t MicrophoneMuteIsAvailable(bool* available) override;
+ int32_t SetMicrophoneMute(bool enable) override;
+ int32_t MicrophoneMute(bool* enabled) const override;
+
+ int32_t MicrophoneBoostIsAvailable(bool* available) override;
+ int32_t SetMicrophoneBoost(bool enable) override;
+ int32_t MicrophoneBoost(bool* enabled) const override;
+
+ int32_t StereoPlayoutIsAvailable(bool* available) const override;
+ int32_t SetStereoPlayout(bool enable) override;
+ int32_t StereoPlayout(bool* enabled) const override;
+ int32_t StereoRecordingIsAvailable(bool* available) const override;
+ int32_t SetStereoRecording(bool enable) override;
+ int32_t StereoRecording(bool* enabled) const override;
+ int32_t SetRecordingChannel(const ChannelType channel) override;
+ int32_t RecordingChannel(ChannelType* channel) const override;
+
+ int32_t SetPlayoutBuffer(const BufferType type,
+ uint16_t size_ms = 0) override;
+ int32_t PlayoutBuffer(BufferType* type, uint16_t* size_ms) const override;
+ int32_t PlayoutDelay(uint16_t* delay_ms) const override;
+ int32_t RecordingDelay(uint16_t* delay_ms) const override;
+
+ int32_t CPULoad(uint16_t* load) const override;
+
+ int32_t StartRawOutputFileRecording(
+ const char pcm_file_name_utf8[webrtc::kAdmMaxFileNameSize]) override;
+ int32_t StopRawOutputFileRecording() override;
+ int32_t StartRawInputFileRecording(
+ const char pcm_file_name_utf8[webrtc::kAdmMaxFileNameSize]) override;
+ int32_t StopRawInputFileRecording() override;
+
+ int32_t SetRecordingSampleRate(const uint32_t samples_per_sec) override;
+ int32_t RecordingSampleRate(uint32_t* samples_per_sec) const override;
+ int32_t SetPlayoutSampleRate(const uint32_t samples_per_sec) override;
+ int32_t PlayoutSampleRate(uint32_t* samples_per_sec) const override;
+
+ int32_t ResetAudioDevice() override;
+ int32_t SetLoudspeakerStatus(bool enable) override;
+ int32_t GetLoudspeakerStatus(bool* enabled) const override;
+ virtual bool BuiltInAECIsAvailable() const { return false; }
+ virtual int32_t EnableBuiltInAEC(bool enable) { return -1; }
+ virtual bool BuiltInAGCIsAvailable() const { return false; }
+ virtual int32_t EnableBuiltInAGC(bool enable) { return -1; }
+ virtual bool BuiltInNSIsAvailable() const { return false; }
+ virtual int32_t EnableBuiltInNS(bool enable) { return -1; }
+ // End of functions inherited from webrtc::AudioDeviceModule.
+
+ // The following function is inherited from rtc::MessageHandler.
+ void OnMessage(rtc::Message* msg) override;
+
+ protected:
+ // The constructor is protected because the class needs to be created as a
+ // reference counted object (for memory managment reasons). It could be
+ // exposed in which case the burden of proper instantiation would be put on
+ // the creator of a FakeAudioCaptureModule instance. To create an instance of
+ // this class use the Create(..) API.
+ explicit FakeAudioCaptureModule();
+ // The destructor is protected because it is reference counted and should not
+ // be deleted directly.
+ virtual ~FakeAudioCaptureModule();
+
+ private:
+ // Initializes the state of the FakeAudioCaptureModule. This API is called on
+ // creation by the Create() API.
+ bool Initialize();
+ // SetBuffer() sets all samples in send_buffer_ to |value|.
+ void SetSendBuffer(int value);
+ // Resets rec_buffer_. I.e., sets all rec_buffer_ samples to 0.
+ void ResetRecBuffer();
+ // Returns true if rec_buffer_ contains one or more sample greater than or
+ // equal to |value|.
+ bool CheckRecBuffer(int value);
+
+ // Returns true/false depending on if recording or playback has been
+ // enabled/started.
+ bool ShouldStartProcessing();
+
+ // Starts or stops the pushing and pulling of audio frames.
+ void UpdateProcessing(bool start);
+
+ // Starts the periodic calling of ProcessFrame() in a thread safe way.
+ void StartProcessP();
+ // Periodcally called function that ensures that frames are pulled and pushed
+ // periodically if enabled/started.
+ void ProcessFrameP();
+ // Pulls frames from the registered webrtc::AudioTransport.
+ void ReceiveFrameP();
+ // Pushes frames to the registered webrtc::AudioTransport.
+ void SendFrameP();
+
+ // The time in milliseconds when Process() was last called or 0 if no call
+ // has been made.
+ uint32_t last_process_time_ms_;
+
+ // Callback for playout and recording.
+ webrtc::AudioTransport* audio_callback_;
+
+ bool recording_; // True when audio is being pushed from the instance.
+ bool playing_; // True when audio is being pulled by the instance.
+
+ bool play_is_initialized_; // True when the instance is ready to pull audio.
+ bool rec_is_initialized_; // True when the instance is ready to push audio.
+
+ // Input to and output from RecordedDataIsAvailable(..) makes it possible to
+ // modify the current mic level. The implementation does not care about the
+ // mic level so it just feeds back what it receives.
+ uint32_t current_mic_level_;
+
+ // next_frame_time_ is updated in a non-drifting manner to indicate the next
+ // wall clock time the next frame should be generated and received. started_
+ // ensures that next_frame_time_ can be initialized properly on first call.
+ bool started_;
+ uint32_t next_frame_time_;
+
+ rtc::scoped_ptr<rtc::Thread> process_thread_;
+
+ // Buffer for storing samples received from the webrtc::AudioTransport.
+ char rec_buffer_[kNumberSamples * kNumberBytesPerSample];
+ // Buffer for samples to send to the webrtc::AudioTransport.
+ char send_buffer_[kNumberSamples * kNumberBytesPerSample];
+
+ // Counter of frames received that have samples of high enough amplitude to
+ // indicate that the frames are not faked somewhere in the audio pipeline
+ // (e.g. by a jitter buffer).
+ int frames_received_;
+
+ // Protects variables that are accessed from process_thread_ and
+ // the main thread.
+ mutable rtc::CriticalSection crit_;
+ // Protects |audio_callback_| that is accessed from process_thread_ and
+ // the main thread.
+ rtc::CriticalSection crit_callback_;
+};
+
+#endif // TALK_APP_WEBRTC_TEST_FAKEAUDIOCAPTUREMODULE_H_
diff --git a/talk/app/webrtc/test/fakeaudiocapturemodule_unittest.cc b/talk/app/webrtc/test/fakeaudiocapturemodule_unittest.cc
new file mode 100644
index 0000000000..e2dc12375b
--- /dev/null
+++ b/talk/app/webrtc/test/fakeaudiocapturemodule_unittest.cc
@@ -0,0 +1,216 @@
+/*
+ * libjingle
+ * Copyright 2012 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "talk/app/webrtc/test/fakeaudiocapturemodule.h"
+
+#include <algorithm>
+
+#include "webrtc/base/criticalsection.h"
+#include "webrtc/base/gunit.h"
+#include "webrtc/base/scoped_ref_ptr.h"
+#include "webrtc/base/thread.h"
+
+using std::min;
+
+class FakeAdmTest : public testing::Test,
+ public webrtc::AudioTransport {
+ protected:
+ static const int kMsInSecond = 1000;
+
+ FakeAdmTest()
+ : push_iterations_(0),
+ pull_iterations_(0),
+ rec_buffer_bytes_(0) {
+ memset(rec_buffer_, 0, sizeof(rec_buffer_));
+ }
+
+ virtual void SetUp() {
+ fake_audio_capture_module_ = FakeAudioCaptureModule::Create();
+ EXPECT_TRUE(fake_audio_capture_module_.get() != NULL);
+ }
+
+ // Callbacks inherited from webrtc::AudioTransport.
+ // ADM is pushing data.
+ int32_t RecordedDataIsAvailable(const void* audioSamples,
+ const size_t nSamples,
+ const size_t nBytesPerSample,
+ const uint8_t nChannels,
+ const uint32_t samplesPerSec,
+ const uint32_t totalDelayMS,
+ const int32_t clockDrift,
+ const uint32_t currentMicLevel,
+ const bool keyPressed,
+ uint32_t& newMicLevel) override {
+ rtc::CritScope cs(&crit_);
+ rec_buffer_bytes_ = nSamples * nBytesPerSample;
+ if ((rec_buffer_bytes_ == 0) ||
+ (rec_buffer_bytes_ > FakeAudioCaptureModule::kNumberSamples *
+ FakeAudioCaptureModule::kNumberBytesPerSample)) {
+ ADD_FAILURE();
+ return -1;
+ }
+ memcpy(rec_buffer_, audioSamples, rec_buffer_bytes_);
+ ++push_iterations_;
+ newMicLevel = currentMicLevel;
+ return 0;
+ }
+
+ // ADM is pulling data.
+ int32_t NeedMorePlayData(const size_t nSamples,
+ const size_t nBytesPerSample,
+ const uint8_t nChannels,
+ const uint32_t samplesPerSec,
+ void* audioSamples,
+ size_t& nSamplesOut,
+ int64_t* elapsed_time_ms,
+ int64_t* ntp_time_ms) override {
+ rtc::CritScope cs(&crit_);
+ ++pull_iterations_;
+ const size_t audio_buffer_size = nSamples * nBytesPerSample;
+ const size_t bytes_out = RecordedDataReceived() ?
+ CopyFromRecBuffer(audioSamples, audio_buffer_size):
+ GenerateZeroBuffer(audioSamples, audio_buffer_size);
+ nSamplesOut = bytes_out / nBytesPerSample;
+ *elapsed_time_ms = 0;
+ *ntp_time_ms = 0;
+ return 0;
+ }
+
+ int push_iterations() const {
+ rtc::CritScope cs(&crit_);
+ return push_iterations_;
+ }
+ int pull_iterations() const {
+ rtc::CritScope cs(&crit_);
+ return pull_iterations_;
+ }
+
+ rtc::scoped_refptr<FakeAudioCaptureModule> fake_audio_capture_module_;
+
+ private:
+ bool RecordedDataReceived() const {
+ return rec_buffer_bytes_ != 0;
+ }
+ size_t GenerateZeroBuffer(void* audio_buffer, size_t audio_buffer_size) {
+ memset(audio_buffer, 0, audio_buffer_size);
+ return audio_buffer_size;
+ }
+ size_t CopyFromRecBuffer(void* audio_buffer, size_t audio_buffer_size) {
+ EXPECT_EQ(audio_buffer_size, rec_buffer_bytes_);
+ const size_t min_buffer_size = min(audio_buffer_size, rec_buffer_bytes_);
+ memcpy(audio_buffer, rec_buffer_, min_buffer_size);
+ return min_buffer_size;
+ }
+
+ mutable rtc::CriticalSection crit_;
+
+ int push_iterations_;
+ int pull_iterations_;
+
+ char rec_buffer_[FakeAudioCaptureModule::kNumberSamples *
+ FakeAudioCaptureModule::kNumberBytesPerSample];
+ size_t rec_buffer_bytes_;
+};
+
+TEST_F(FakeAdmTest, TestProccess) {
+ // Next process call must be some time in the future (or now).
+ EXPECT_LE(0, fake_audio_capture_module_->TimeUntilNextProcess());
+ // Process call updates TimeUntilNextProcess() but there are no guarantees on
+ // timing so just check that Process can ba called successfully.
+ EXPECT_LE(0, fake_audio_capture_module_->Process());
+}
+
+TEST_F(FakeAdmTest, PlayoutTest) {
+ EXPECT_EQ(0, fake_audio_capture_module_->RegisterAudioCallback(this));
+
+ bool stereo_available = false;
+ EXPECT_EQ(0,
+ fake_audio_capture_module_->StereoPlayoutIsAvailable(
+ &stereo_available));
+ EXPECT_TRUE(stereo_available);
+
+ EXPECT_NE(0, fake_audio_capture_module_->StartPlayout());
+ EXPECT_FALSE(fake_audio_capture_module_->PlayoutIsInitialized());
+ EXPECT_FALSE(fake_audio_capture_module_->Playing());
+ EXPECT_EQ(0, fake_audio_capture_module_->StopPlayout());
+
+ EXPECT_EQ(0, fake_audio_capture_module_->InitPlayout());
+ EXPECT_TRUE(fake_audio_capture_module_->PlayoutIsInitialized());
+ EXPECT_FALSE(fake_audio_capture_module_->Playing());
+
+ EXPECT_EQ(0, fake_audio_capture_module_->StartPlayout());
+ EXPECT_TRUE(fake_audio_capture_module_->Playing());
+
+ uint16_t delay_ms = 10;
+ EXPECT_EQ(0, fake_audio_capture_module_->PlayoutDelay(&delay_ms));
+ EXPECT_EQ(0, delay_ms);
+
+ EXPECT_TRUE_WAIT(pull_iterations() > 0, kMsInSecond);
+ EXPECT_GE(0, push_iterations());
+
+ EXPECT_EQ(0, fake_audio_capture_module_->StopPlayout());
+ EXPECT_FALSE(fake_audio_capture_module_->Playing());
+}
+
+TEST_F(FakeAdmTest, RecordTest) {
+ EXPECT_EQ(0, fake_audio_capture_module_->RegisterAudioCallback(this));
+
+ bool stereo_available = false;
+ EXPECT_EQ(0, fake_audio_capture_module_->StereoRecordingIsAvailable(
+ &stereo_available));
+ EXPECT_FALSE(stereo_available);
+
+ EXPECT_NE(0, fake_audio_capture_module_->StartRecording());
+ EXPECT_FALSE(fake_audio_capture_module_->Recording());
+ EXPECT_EQ(0, fake_audio_capture_module_->StopRecording());
+
+ EXPECT_EQ(0, fake_audio_capture_module_->InitRecording());
+ EXPECT_EQ(0, fake_audio_capture_module_->StartRecording());
+ EXPECT_TRUE(fake_audio_capture_module_->Recording());
+
+ EXPECT_TRUE_WAIT(push_iterations() > 0, kMsInSecond);
+ EXPECT_GE(0, pull_iterations());
+
+ EXPECT_EQ(0, fake_audio_capture_module_->StopRecording());
+ EXPECT_FALSE(fake_audio_capture_module_->Recording());
+}
+
+TEST_F(FakeAdmTest, DuplexTest) {
+ EXPECT_EQ(0, fake_audio_capture_module_->RegisterAudioCallback(this));
+
+ EXPECT_EQ(0, fake_audio_capture_module_->InitPlayout());
+ EXPECT_EQ(0, fake_audio_capture_module_->StartPlayout());
+
+ EXPECT_EQ(0, fake_audio_capture_module_->InitRecording());
+ EXPECT_EQ(0, fake_audio_capture_module_->StartRecording());
+
+ EXPECT_TRUE_WAIT(push_iterations() > 0, kMsInSecond);
+ EXPECT_TRUE_WAIT(pull_iterations() > 0, kMsInSecond);
+
+ EXPECT_EQ(0, fake_audio_capture_module_->StopPlayout());
+ EXPECT_EQ(0, fake_audio_capture_module_->StopRecording());
+}
diff --git a/talk/app/webrtc/test/fakeconstraints.h b/talk/app/webrtc/test/fakeconstraints.h
new file mode 100644
index 0000000000..8673d85097
--- /dev/null
+++ b/talk/app/webrtc/test/fakeconstraints.h
@@ -0,0 +1,133 @@
+/*
+ * libjingle
+ * Copyright 2012 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TALK_APP_WEBRTC_TEST_FAKECONSTRAINTS_H_
+#define TALK_APP_WEBRTC_TEST_FAKECONSTRAINTS_H_
+
+#include <string>
+#include <vector>
+
+#include "talk/app/webrtc/mediaconstraintsinterface.h"
+#include "webrtc/base/stringencode.h"
+
+namespace webrtc {
+
+class FakeConstraints : public webrtc::MediaConstraintsInterface {
+ public:
+ FakeConstraints() { }
+ virtual ~FakeConstraints() { }
+
+ virtual const Constraints& GetMandatory() const {
+ return mandatory_;
+ }
+
+ virtual const Constraints& GetOptional() const {
+ return optional_;
+ }
+
+ template <class T>
+ void AddMandatory(const std::string& key, const T& value) {
+ mandatory_.push_back(Constraint(key, rtc::ToString<T>(value)));
+ }
+
+ template <class T>
+ void SetMandatory(const std::string& key, const T& value) {
+ std::string value_str;
+ if (mandatory_.FindFirst(key, &value_str)) {
+ for (Constraints::iterator iter = mandatory_.begin();
+ iter != mandatory_.end(); ++iter) {
+ if (iter->key == key) {
+ mandatory_.erase(iter);
+ break;
+ }
+ }
+ }
+ mandatory_.push_back(Constraint(key, rtc::ToString<T>(value)));
+ }
+
+ template <class T>
+ void AddOptional(const std::string& key, const T& value) {
+ optional_.push_back(Constraint(key, rtc::ToString<T>(value)));
+ }
+
+ void SetMandatoryMinAspectRatio(double ratio) {
+ SetMandatory(MediaConstraintsInterface::kMinAspectRatio, ratio);
+ }
+
+ void SetMandatoryMinWidth(int width) {
+ SetMandatory(MediaConstraintsInterface::kMinWidth, width);
+ }
+
+ void SetMandatoryMinHeight(int height) {
+ SetMandatory(MediaConstraintsInterface::kMinHeight, height);
+ }
+
+ void SetOptionalMaxWidth(int width) {
+ AddOptional(MediaConstraintsInterface::kMaxWidth, width);
+ }
+
+ void SetMandatoryMaxFrameRate(int frame_rate) {
+ SetMandatory(MediaConstraintsInterface::kMaxFrameRate, frame_rate);
+ }
+
+ void SetMandatoryReceiveAudio(bool enable) {
+ SetMandatory(MediaConstraintsInterface::kOfferToReceiveAudio, enable);
+ }
+
+ void SetMandatoryReceiveVideo(bool enable) {
+ SetMandatory(MediaConstraintsInterface::kOfferToReceiveVideo, enable);
+ }
+
+ void SetMandatoryUseRtpMux(bool enable) {
+ SetMandatory(MediaConstraintsInterface::kUseRtpMux, enable);
+ }
+
+ void SetMandatoryIceRestart(bool enable) {
+ SetMandatory(MediaConstraintsInterface::kIceRestart, enable);
+ }
+
+ void SetAllowRtpDataChannels() {
+ SetMandatory(MediaConstraintsInterface::kEnableRtpDataChannels, true);
+ SetMandatory(MediaConstraintsInterface::kEnableDtlsSrtp, false);
+ }
+
+ void SetOptionalVAD(bool enable) {
+ AddOptional(MediaConstraintsInterface::kVoiceActivityDetection, enable);
+ }
+
+ void SetAllowDtlsSctpDataChannels() {
+ SetMandatory(MediaConstraintsInterface::kEnableDtlsSrtp, true);
+ }
+
+ private:
+ Constraints mandatory_;
+ Constraints optional_;
+};
+
+} // namespace webrtc
+
+#endif // TALK_APP_WEBRTC_TEST_FAKECONSTRAINTS_H_
diff --git a/talk/app/webrtc/test/fakedatachannelprovider.h b/talk/app/webrtc/test/fakedatachannelprovider.h
new file mode 100644
index 0000000000..ff44e585fe
--- /dev/null
+++ b/talk/app/webrtc/test/fakedatachannelprovider.h
@@ -0,0 +1,161 @@
+/*
+ * libjingle
+ * Copyright 2013 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TALK_APP_WEBRTC_TEST_FAKEDATACHANNELPROVIDER_H_
+#define TALK_APP_WEBRTC_TEST_FAKEDATACHANNELPROVIDER_H_
+
+#include "talk/app/webrtc/datachannel.h"
+
+class FakeDataChannelProvider : public webrtc::DataChannelProviderInterface {
+ public:
+ FakeDataChannelProvider()
+ : send_blocked_(false),
+ transport_available_(false),
+ ready_to_send_(false),
+ transport_error_(false) {}
+ virtual ~FakeDataChannelProvider() {}
+
+ bool SendData(const cricket::SendDataParams& params,
+ const rtc::Buffer& payload,
+ cricket::SendDataResult* result) override {
+ ASSERT(ready_to_send_ && transport_available_);
+ if (send_blocked_) {
+ *result = cricket::SDR_BLOCK;
+ return false;
+ }
+
+ if (transport_error_ || payload.size() == 0) {
+ *result = cricket::SDR_ERROR;
+ return false;
+ }
+
+ last_send_data_params_ = params;
+ return true;
+ }
+
+ bool ConnectDataChannel(webrtc::DataChannel* data_channel) override {
+ ASSERT(connected_channels_.find(data_channel) == connected_channels_.end());
+ if (!transport_available_) {
+ return false;
+ }
+ LOG(LS_INFO) << "DataChannel connected " << data_channel;
+ connected_channels_.insert(data_channel);
+ return true;
+ }
+
+ void DisconnectDataChannel(webrtc::DataChannel* data_channel) override {
+ ASSERT(connected_channels_.find(data_channel) != connected_channels_.end());
+ LOG(LS_INFO) << "DataChannel disconnected " << data_channel;
+ connected_channels_.erase(data_channel);
+ }
+
+ void AddSctpDataStream(int sid) override {
+ ASSERT(sid >= 0);
+ if (!transport_available_) {
+ return;
+ }
+ send_ssrcs_.insert(sid);
+ recv_ssrcs_.insert(sid);
+ }
+
+ void RemoveSctpDataStream(int sid) override {
+ ASSERT(sid >= 0);
+ send_ssrcs_.erase(sid);
+ recv_ssrcs_.erase(sid);
+ }
+
+ bool ReadyToSendData() const override { return ready_to_send_; }
+
+ // Set true to emulate the SCTP stream being blocked by congestion control.
+ void set_send_blocked(bool blocked) {
+ send_blocked_ = blocked;
+ if (!blocked) {
+ // Take a snapshot of the connected channels and check to see whether
+ // each value is still in connected_channels_ before calling
+ // OnChannelReady(). This avoids problems where the set gets modified
+ // in response to OnChannelReady().
+ for (webrtc::DataChannel *ch : std::set<webrtc::DataChannel*>(
+ connected_channels_.begin(), connected_channels_.end())) {
+ if (connected_channels_.count(ch)) {
+ ch->OnChannelReady(true);
+ }
+ }
+ }
+ }
+
+ // Set true to emulate the transport channel creation, e.g. after
+ // setLocalDescription/setRemoteDescription called with data content.
+ void set_transport_available(bool available) {
+ transport_available_ = available;
+ }
+
+ // Set true to emulate the transport ReadyToSendData signal when the transport
+ // becomes writable for the first time.
+ void set_ready_to_send(bool ready) {
+ ASSERT(transport_available_);
+ ready_to_send_ = ready;
+ if (ready) {
+ std::set<webrtc::DataChannel*>::iterator it;
+ for (it = connected_channels_.begin();
+ it != connected_channels_.end();
+ ++it) {
+ (*it)->OnChannelReady(true);
+ }
+ }
+ }
+
+ void set_transport_error() {
+ transport_error_ = true;
+ }
+
+ cricket::SendDataParams last_send_data_params() const {
+ return last_send_data_params_;
+ }
+
+ bool IsConnected(webrtc::DataChannel* data_channel) const {
+ return connected_channels_.find(data_channel) != connected_channels_.end();
+ }
+
+ bool IsSendStreamAdded(uint32_t stream) const {
+ return send_ssrcs_.find(stream) != send_ssrcs_.end();
+ }
+
+ bool IsRecvStreamAdded(uint32_t stream) const {
+ return recv_ssrcs_.find(stream) != recv_ssrcs_.end();
+ }
+
+ private:
+ cricket::SendDataParams last_send_data_params_;
+ bool send_blocked_;
+ bool transport_available_;
+ bool ready_to_send_;
+ bool transport_error_;
+ std::set<webrtc::DataChannel*> connected_channels_;
+ std::set<uint32_t> send_ssrcs_;
+ std::set<uint32_t> recv_ssrcs_;
+};
+#endif // TALK_APP_WEBRTC_TEST_FAKEDATACHANNELPROVIDER_H_
diff --git a/talk/app/webrtc/test/fakedtlsidentitystore.h b/talk/app/webrtc/test/fakedtlsidentitystore.h
new file mode 100644
index 0000000000..0f9bdb9e6c
--- /dev/null
+++ b/talk/app/webrtc/test/fakedtlsidentitystore.h
@@ -0,0 +1,143 @@
+/*
+ * libjingle
+ * Copyright 2013 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TALK_APP_WEBRTC_TEST_FAKEDTLSIDENTITYSERVICE_H_
+#define TALK_APP_WEBRTC_TEST_FAKEDTLSIDENTITYSERVICE_H_
+
+#include <string>
+
+#include "talk/app/webrtc/dtlsidentitystore.h"
+#include "talk/app/webrtc/peerconnectioninterface.h"
+#include "webrtc/base/rtccertificate.h"
+
+static const char kRSA_PRIVATE_KEY_PEM[] =
+ "-----BEGIN RSA PRIVATE KEY-----\n"
+ "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMYRkbhmI7kVA/rM\n"
+ "czsZ+6JDhDvnkF+vn6yCAGuRPV03zuRqZtDy4N4to7PZu9PjqrRl7nDMXrG3YG9y\n"
+ "rlIAZ72KjcKKFAJxQyAKLCIdawKRyp8RdK3LEySWEZb0AV58IadqPZDTNHHRX8dz\n"
+ "5aTSMsbbkZ+C/OzTnbiMqLL/vg6jAgMBAAECgYAvgOs4FJcgvp+TuREx7YtiYVsH\n"
+ "mwQPTum2z/8VzWGwR8BBHBvIpVe1MbD/Y4seyI2aco/7UaisatSgJhsU46/9Y4fq\n"
+ "2TwXH9QANf4at4d9n/R6rzwpAJOpgwZgKvdQjkfrKTtgLV+/dawvpxUYkRH4JZM1\n"
+ "CVGukMfKNrSVH4Ap4QJBAOJmGV1ASPnB4r4nc99at7JuIJmd7fmuVUwUgYi4XgaR\n"
+ "WhScBsgYwZ/JoywdyZJgnbcrTDuVcWG56B3vXbhdpMsCQQDf9zeJrjnPZ3Cqm79y\n"
+ "kdqANep0uwZciiNiWxsQrCHztywOvbFhdp8iYVFG9EK8DMY41Y5TxUwsHD+67zao\n"
+ "ZNqJAkEA1suLUP/GvL8IwuRneQd2tWDqqRQ/Td3qq03hP7e77XtF/buya3Ghclo5\n"
+ "54czUR89QyVfJEC6278nzA7n2h1uVQJAcG6mztNL6ja/dKZjYZye2CY44QjSlLo0\n"
+ "MTgTSjdfg/28fFn2Jjtqf9Pi/X+50LWI/RcYMC2no606wRk9kyOuIQJBAK6VSAim\n"
+ "1pOEjsYQn0X5KEIrz1G3bfCbB848Ime3U2/FWlCHMr6ch8kCZ5d1WUeJD3LbwMNG\n"
+ "UCXiYxSsu20QNVw=\n"
+ "-----END RSA PRIVATE KEY-----\n";
+
+static const char kCERT_PEM[] =
+ "-----BEGIN CERTIFICATE-----\n"
+ "MIIBmTCCAQKgAwIBAgIEbzBSAjANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDEwZX\n"
+ "ZWJSVEMwHhcNMTQwMTAyMTgyNDQ3WhcNMTQwMjAxMTgyNDQ3WjARMQ8wDQYDVQQD\n"
+ "EwZXZWJSVEMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMYRkbhmI7kVA/rM\n"
+ "czsZ+6JDhDvnkF+vn6yCAGuRPV03zuRqZtDy4N4to7PZu9PjqrRl7nDMXrG3YG9y\n"
+ "rlIAZ72KjcKKFAJxQyAKLCIdawKRyp8RdK3LEySWEZb0AV58IadqPZDTNHHRX8dz\n"
+ "5aTSMsbbkZ+C/OzTnbiMqLL/vg6jAgMBAAEwDQYJKoZIhvcNAQELBQADgYEAUflI\n"
+ "VUe5Krqf5RVa5C3u/UTAOAUJBiDS3VANTCLBxjuMsvqOG0WvaYWP3HYPgrz0jXK2\n"
+ "LJE/mGw3MyFHEqi81jh95J+ypl6xKW6Rm8jKLR87gUvCaVYn/Z4/P3AqcQTB7wOv\n"
+ "UD0A8qfhfDM+LK6rPAnCsVN0NRDY3jvd6rzix9M=\n"
+ "-----END CERTIFICATE-----\n";
+
+class FakeDtlsIdentityStore : public webrtc::DtlsIdentityStoreInterface,
+ public rtc::MessageHandler {
+ public:
+ typedef rtc::TypedMessageData<rtc::scoped_refptr<
+ webrtc::DtlsIdentityRequestObserver> > MessageData;
+
+ FakeDtlsIdentityStore() : should_fail_(false) {}
+
+ void set_should_fail(bool should_fail) {
+ should_fail_ = should_fail;
+ }
+
+ void RequestIdentity(
+ rtc::KeyType key_type,
+ const rtc::scoped_refptr<webrtc::DtlsIdentityRequestObserver>&
+ observer) override {
+ // TODO(hbos): Should be able to generate KT_ECDSA too.
+ RTC_DCHECK(key_type == rtc::KT_RSA || should_fail_);
+ MessageData* msg = new MessageData(
+ rtc::scoped_refptr<webrtc::DtlsIdentityRequestObserver>(observer));
+ rtc::Thread::Current()->Post(
+ this, should_fail_ ? MSG_FAILURE : MSG_SUCCESS, msg);
+ }
+
+ static rtc::scoped_refptr<rtc::RTCCertificate> GenerateCertificate() {
+ std::string cert;
+ std::string key;
+ rtc::SSLIdentity::PemToDer("CERTIFICATE", kCERT_PEM, &cert);
+ rtc::SSLIdentity::PemToDer("RSA PRIVATE KEY", kRSA_PRIVATE_KEY_PEM, &key);
+
+ std::string pem_cert = rtc::SSLIdentity::DerToPem(
+ rtc::kPemTypeCertificate,
+ reinterpret_cast<const unsigned char*>(cert.data()),
+ cert.length());
+ std::string pem_key = rtc::SSLIdentity::DerToPem(
+ rtc::kPemTypeRsaPrivateKey,
+ reinterpret_cast<const unsigned char*>(key.data()),
+ key.length());
+ rtc::scoped_ptr<rtc::SSLIdentity> identity(
+ rtc::SSLIdentity::FromPEMStrings(pem_key, pem_cert));
+
+ return rtc::RTCCertificate::Create(identity.Pass());
+ }
+
+ private:
+ enum {
+ MSG_SUCCESS,
+ MSG_FAILURE,
+ };
+
+ // rtc::MessageHandler implementation.
+ void OnMessage(rtc::Message* msg) {
+ MessageData* message_data = static_cast<MessageData*>(msg->pdata);
+ rtc::scoped_refptr<webrtc::DtlsIdentityRequestObserver> observer =
+ message_data->data();
+ switch (msg->message_id) {
+ case MSG_SUCCESS: {
+ std::string cert;
+ std::string key;
+ rtc::SSLIdentity::PemToDer("CERTIFICATE", kCERT_PEM, &cert);
+ rtc::SSLIdentity::PemToDer("RSA PRIVATE KEY", kRSA_PRIVATE_KEY_PEM,
+ &key);
+ observer->OnSuccess(cert, key);
+ break;
+ }
+ case MSG_FAILURE:
+ observer->OnFailure(0);
+ break;
+ }
+ delete message_data;
+ }
+
+ bool should_fail_;
+};
+
+#endif // TALK_APP_WEBRTC_TEST_FAKEDTLSIDENTITYSERVICE_H_
diff --git a/talk/app/webrtc/test/fakemediastreamsignaling.h b/talk/app/webrtc/test/fakemediastreamsignaling.h
new file mode 100644
index 0000000000..562c4ad306
--- /dev/null
+++ b/talk/app/webrtc/test/fakemediastreamsignaling.h
@@ -0,0 +1,140 @@
+/*
+ * libjingle
+ * Copyright 2013 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TALK_APP_WEBRTC_TEST_FAKEMEDIASTREAMSIGNALING_H_
+#define TALK_APP_WEBRTC_TEST_FAKEMEDIASTREAMSIGNALING_H_
+
+#include "talk/app/webrtc/audiotrack.h"
+#include "talk/app/webrtc/mediastreamsignaling.h"
+#include "talk/app/webrtc/videotrack.h"
+
+static const char kStream1[] = "stream1";
+static const char kVideoTrack1[] = "video1";
+static const char kAudioTrack1[] = "audio1";
+
+static const char kStream2[] = "stream2";
+static const char kVideoTrack2[] = "video2";
+static const char kAudioTrack2[] = "audio2";
+
+class FakeMediaStreamSignaling : public webrtc::MediaStreamSignaling,
+ public webrtc::MediaStreamSignalingObserver {
+ public:
+ explicit FakeMediaStreamSignaling(cricket::ChannelManager* channel_manager) :
+ webrtc::MediaStreamSignaling(rtc::Thread::Current(), this,
+ channel_manager) {
+ }
+
+ void SendAudioVideoStream1() {
+ ClearLocalStreams();
+ AddLocalStream(CreateStream(kStream1, kAudioTrack1, kVideoTrack1));
+ }
+
+ void SendAudioVideoStream2() {
+ ClearLocalStreams();
+ AddLocalStream(CreateStream(kStream2, kAudioTrack2, kVideoTrack2));
+ }
+
+ void SendAudioVideoStream1And2() {
+ ClearLocalStreams();
+ AddLocalStream(CreateStream(kStream1, kAudioTrack1, kVideoTrack1));
+ AddLocalStream(CreateStream(kStream2, kAudioTrack2, kVideoTrack2));
+ }
+
+ void SendNothing() {
+ ClearLocalStreams();
+ }
+
+ void UseOptionsAudioOnly() {
+ ClearLocalStreams();
+ AddLocalStream(CreateStream(kStream2, kAudioTrack2, ""));
+ }
+
+ void UseOptionsVideoOnly() {
+ ClearLocalStreams();
+ AddLocalStream(CreateStream(kStream2, "", kVideoTrack2));
+ }
+
+ void ClearLocalStreams() {
+ while (local_streams()->count() != 0) {
+ RemoveLocalStream(local_streams()->at(0));
+ }
+ }
+
+ // Implements MediaStreamSignalingObserver.
+ virtual void OnAddRemoteStream(webrtc::MediaStreamInterface* stream) {}
+ virtual void OnRemoveRemoteStream(webrtc::MediaStreamInterface* stream) {}
+ virtual void OnAddDataChannel(webrtc::DataChannelInterface* data_channel) {}
+ virtual void OnAddLocalAudioTrack(webrtc::MediaStreamInterface* stream,
+ webrtc::AudioTrackInterface* audio_track,
+ uint32_t ssrc) {}
+ virtual void OnAddLocalVideoTrack(webrtc::MediaStreamInterface* stream,
+ webrtc::VideoTrackInterface* video_track,
+ uint32_t ssrc) {}
+ virtual void OnAddRemoteAudioTrack(webrtc::MediaStreamInterface* stream,
+ webrtc::AudioTrackInterface* audio_track,
+ uint32_t ssrc) {}
+ virtual void OnAddRemoteVideoTrack(webrtc::MediaStreamInterface* stream,
+ webrtc::VideoTrackInterface* video_track,
+ uint32_t ssrc) {}
+ virtual void OnRemoveRemoteAudioTrack(
+ webrtc::MediaStreamInterface* stream,
+ webrtc::AudioTrackInterface* audio_track) {}
+ virtual void OnRemoveRemoteVideoTrack(
+ webrtc::MediaStreamInterface* stream,
+ webrtc::VideoTrackInterface* video_track) {}
+ virtual void OnRemoveLocalAudioTrack(webrtc::MediaStreamInterface* stream,
+ webrtc::AudioTrackInterface* audio_track,
+ uint32_t ssrc) {}
+ virtual void OnRemoveLocalVideoTrack(
+ webrtc::MediaStreamInterface* stream,
+ webrtc::VideoTrackInterface* video_track) {}
+ virtual void OnRemoveLocalStream(webrtc::MediaStreamInterface* stream) {}
+
+ private:
+ rtc::scoped_refptr<webrtc::MediaStreamInterface> CreateStream(
+ const std::string& stream_label,
+ const std::string& audio_track_id,
+ const std::string& video_track_id) {
+ rtc::scoped_refptr<webrtc::MediaStreamInterface> stream(
+ webrtc::MediaStream::Create(stream_label));
+
+ if (!audio_track_id.empty()) {
+ rtc::scoped_refptr<webrtc::AudioTrackInterface> audio_track(
+ webrtc::AudioTrack::Create(audio_track_id, NULL));
+ stream->AddTrack(audio_track);
+ }
+
+ if (!video_track_id.empty()) {
+ rtc::scoped_refptr<webrtc::VideoTrackInterface> video_track(
+ webrtc::VideoTrack::Create(video_track_id, NULL));
+ stream->AddTrack(video_track);
+ }
+ return stream;
+ }
+};
+
+#endif // TALK_APP_WEBRTC_TEST_FAKEMEDIASTREAMSIGNALING_H_
diff --git a/talk/app/webrtc/test/fakeperiodicvideocapturer.h b/talk/app/webrtc/test/fakeperiodicvideocapturer.h
new file mode 100644
index 0000000000..34e4278ba7
--- /dev/null
+++ b/talk/app/webrtc/test/fakeperiodicvideocapturer.h
@@ -0,0 +1,89 @@
+/*
+ * libjingle
+ * Copyright 2012 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.
+ */
+
+// FakePeriodicVideoCapturer implements a fake cricket::VideoCapturer that
+// creates video frames periodically after it has been started.
+
+#ifndef TALK_APP_WEBRTC_TEST_FAKEPERIODICVIDEOCAPTURER_H_
+#define TALK_APP_WEBRTC_TEST_FAKEPERIODICVIDEOCAPTURER_H_
+
+#include "talk/media/base/fakevideocapturer.h"
+#include "webrtc/base/thread.h"
+
+namespace webrtc {
+
+class FakePeriodicVideoCapturer : public cricket::FakeVideoCapturer {
+ public:
+ FakePeriodicVideoCapturer() {
+ std::vector<cricket::VideoFormat> formats;
+ formats.push_back(cricket::VideoFormat(1280, 720,
+ cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
+ formats.push_back(cricket::VideoFormat(640, 480,
+ cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
+ formats.push_back(cricket::VideoFormat(640, 360,
+ cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
+ formats.push_back(cricket::VideoFormat(320, 240,
+ cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
+ formats.push_back(cricket::VideoFormat(160, 120,
+ cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420));
+ ResetSupportedFormats(formats);
+ };
+
+ virtual cricket::CaptureState Start(const cricket::VideoFormat& format) {
+ cricket::CaptureState state = FakeVideoCapturer::Start(format);
+ if (state != cricket::CS_FAILED) {
+ rtc::Thread::Current()->Post(this, MSG_CREATEFRAME);
+ }
+ return state;
+ }
+ virtual void Stop() {
+ rtc::Thread::Current()->Clear(this);
+ }
+ // Inherited from MesageHandler.
+ virtual void OnMessage(rtc::Message* msg) {
+ if (msg->message_id == MSG_CREATEFRAME) {
+ if (IsRunning()) {
+ CaptureFrame();
+ rtc::Thread::Current()->PostDelayed(static_cast<int>(
+ GetCaptureFormat()->interval / rtc::kNumNanosecsPerMillisec),
+ this, MSG_CREATEFRAME);
+ }
+ } else {
+ FakeVideoCapturer::OnMessage(msg);
+ }
+ }
+
+ private:
+ enum {
+ // Offset 0xFF to make sure this don't collide with base class messages.
+ MSG_CREATEFRAME = 0xFF
+ };
+};
+
+} // namespace webrtc
+
+#endif // TALK_APP_WEBRTC_TEST_FAKEPERIODICVIDEOCAPTURER_H_
diff --git a/talk/app/webrtc/test/fakevideotrackrenderer.h b/talk/app/webrtc/test/fakevideotrackrenderer.h
new file mode 100644
index 0000000000..38b84a6aff
--- /dev/null
+++ b/talk/app/webrtc/test/fakevideotrackrenderer.h
@@ -0,0 +1,75 @@
+/*
+ * libjingle
+ * Copyright 2012 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TALK_APP_WEBRTC_TEST_FAKEVIDEOTRACKRENDERER_H_
+#define TALK_APP_WEBRTC_TEST_FAKEVIDEOTRACKRENDERER_H_
+
+#include "talk/app/webrtc/mediastreaminterface.h"
+#include "talk/media/base/fakevideorenderer.h"
+
+namespace webrtc {
+
+class FakeVideoTrackRenderer : public VideoRendererInterface {
+ public:
+ FakeVideoTrackRenderer(VideoTrackInterface* video_track)
+ : video_track_(video_track), last_frame_(NULL) {
+ video_track_->AddRenderer(this);
+ }
+ ~FakeVideoTrackRenderer() {
+ video_track_->RemoveRenderer(this);
+ }
+
+ virtual void RenderFrame(const cricket::VideoFrame* video_frame) override {
+ last_frame_ = const_cast<cricket::VideoFrame*>(video_frame);
+ if (!fake_renderer_.SetSize(static_cast<int>(video_frame->GetWidth()),
+ static_cast<int>(video_frame->GetHeight()),
+ 0)) {
+ return;
+ }
+
+ fake_renderer_.RenderFrame(video_frame);
+ }
+
+ int errors() const { return fake_renderer_.errors(); }
+ int width() const { return fake_renderer_.width(); }
+ int height() const { return fake_renderer_.height(); }
+ int num_rendered_frames() const {
+ return fake_renderer_.num_rendered_frames();
+ }
+ const cricket::VideoFrame* last_frame() const { return last_frame_; }
+
+ private:
+ cricket::FakeVideoRenderer fake_renderer_;
+ rtc::scoped_refptr<VideoTrackInterface> video_track_;
+
+ // Weak reference for frame pointer comparison only.
+ cricket::VideoFrame* last_frame_;
+};
+
+} // namespace webrtc
+
+#endif // TALK_APP_WEBRTC_TEST_FAKEVIDEOTRACKRENDERER_H_
diff --git a/talk/app/webrtc/test/mockpeerconnectionobservers.h b/talk/app/webrtc/test/mockpeerconnectionobservers.h
new file mode 100644
index 0000000000..f1bdbee9f5
--- /dev/null
+++ b/talk/app/webrtc/test/mockpeerconnectionobservers.h
@@ -0,0 +1,243 @@
+/*
+ * libjingle
+ * Copyright 2012 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.
+ */
+
+// This file contains mock implementations of observers used in PeerConnection.
+
+#ifndef TALK_APP_WEBRTC_TEST_MOCKPEERCONNECTIONOBSERVERS_H_
+#define TALK_APP_WEBRTC_TEST_MOCKPEERCONNECTIONOBSERVERS_H_
+
+#include <string>
+
+#include "talk/app/webrtc/datachannelinterface.h"
+
+namespace webrtc {
+
+class MockCreateSessionDescriptionObserver
+ : public webrtc::CreateSessionDescriptionObserver {
+ public:
+ MockCreateSessionDescriptionObserver()
+ : called_(false),
+ result_(false) {}
+ virtual ~MockCreateSessionDescriptionObserver() {}
+ virtual void OnSuccess(SessionDescriptionInterface* desc) {
+ called_ = true;
+ result_ = true;
+ desc_.reset(desc);
+ }
+ virtual void OnFailure(const std::string& error) {
+ called_ = true;
+ result_ = false;
+ }
+ bool called() const { return called_; }
+ bool result() const { return result_; }
+ SessionDescriptionInterface* release_desc() {
+ return desc_.release();
+ }
+
+ private:
+ bool called_;
+ bool result_;
+ rtc::scoped_ptr<SessionDescriptionInterface> desc_;
+};
+
+class MockSetSessionDescriptionObserver
+ : public webrtc::SetSessionDescriptionObserver {
+ public:
+ MockSetSessionDescriptionObserver()
+ : called_(false),
+ result_(false) {}
+ virtual ~MockSetSessionDescriptionObserver() {}
+ virtual void OnSuccess() {
+ called_ = true;
+ result_ = true;
+ }
+ virtual void OnFailure(const std::string& error) {
+ called_ = true;
+ result_ = false;
+ }
+ bool called() const { return called_; }
+ bool result() const { return result_; }
+
+ private:
+ bool called_;
+ bool result_;
+};
+
+class MockDataChannelObserver : public webrtc::DataChannelObserver {
+ public:
+ explicit MockDataChannelObserver(webrtc::DataChannelInterface* channel)
+ : channel_(channel), received_message_count_(0) {
+ channel_->RegisterObserver(this);
+ state_ = channel_->state();
+ }
+ virtual ~MockDataChannelObserver() {
+ channel_->UnregisterObserver();
+ }
+
+ void OnBufferedAmountChange(uint64_t previous_amount) override {}
+
+ void OnStateChange() override { state_ = channel_->state(); }
+ void OnMessage(const DataBuffer& buffer) override {
+ last_message_.assign(buffer.data.data<char>(), buffer.data.size());
+ ++received_message_count_;
+ }
+
+ bool IsOpen() const { return state_ == DataChannelInterface::kOpen; }
+ const std::string& last_message() const { return last_message_; }
+ size_t received_message_count() const { return received_message_count_; }
+
+ private:
+ rtc::scoped_refptr<webrtc::DataChannelInterface> channel_;
+ DataChannelInterface::DataState state_;
+ std::string last_message_;
+ size_t received_message_count_;
+};
+
+class MockStatsObserver : public webrtc::StatsObserver {
+ public:
+ MockStatsObserver() : called_(false), stats_() {}
+ virtual ~MockStatsObserver() {}
+
+ virtual void OnComplete(const StatsReports& reports) {
+ ASSERT(!called_);
+ called_ = true;
+ stats_.Clear();
+ stats_.number_of_reports = reports.size();
+ for (const auto* r : reports) {
+ if (r->type() == StatsReport::kStatsReportTypeSsrc) {
+ stats_.timestamp = r->timestamp();
+ GetIntValue(r, StatsReport::kStatsValueNameAudioOutputLevel,
+ &stats_.audio_output_level);
+ GetIntValue(r, StatsReport::kStatsValueNameAudioInputLevel,
+ &stats_.audio_input_level);
+ GetIntValue(r, StatsReport::kStatsValueNameBytesReceived,
+ &stats_.bytes_received);
+ GetIntValue(r, StatsReport::kStatsValueNameBytesSent,
+ &stats_.bytes_sent);
+ } else if (r->type() == StatsReport::kStatsReportTypeBwe) {
+ stats_.timestamp = r->timestamp();
+ GetIntValue(r, StatsReport::kStatsValueNameAvailableReceiveBandwidth,
+ &stats_.available_receive_bandwidth);
+ } else if (r->type() == StatsReport::kStatsReportTypeComponent) {
+ stats_.timestamp = r->timestamp();
+ GetStringValue(r, StatsReport::kStatsValueNameDtlsCipher,
+ &stats_.dtls_cipher);
+ GetStringValue(r, StatsReport::kStatsValueNameSrtpCipher,
+ &stats_.srtp_cipher);
+ }
+ }
+ }
+
+ bool called() const { return called_; }
+ size_t number_of_reports() const { return stats_.number_of_reports; }
+ double timestamp() const { return stats_.timestamp; }
+
+ int AudioOutputLevel() const {
+ ASSERT(called_);
+ return stats_.audio_output_level;
+ }
+
+ int AudioInputLevel() const {
+ ASSERT(called_);
+ return stats_.audio_input_level;
+ }
+
+ int BytesReceived() const {
+ ASSERT(called_);
+ return stats_.bytes_received;
+ }
+
+ int BytesSent() const {
+ ASSERT(called_);
+ return stats_.bytes_sent;
+ }
+
+ int AvailableReceiveBandwidth() const {
+ ASSERT(called_);
+ return stats_.available_receive_bandwidth;
+ }
+
+ std::string DtlsCipher() const {
+ ASSERT(called_);
+ return stats_.dtls_cipher;
+ }
+
+ std::string SrtpCipher() const {
+ ASSERT(called_);
+ return stats_.srtp_cipher;
+ }
+
+ private:
+ bool GetIntValue(const StatsReport* report,
+ StatsReport::StatsValueName name,
+ int* value) {
+ const StatsReport::Value* v = report->FindValue(name);
+ if (v) {
+ // TODO(tommi): We should really just be using an int here :-/
+ *value = rtc::FromString<int>(v->ToString());
+ }
+ return v != nullptr;
+ }
+
+ bool GetStringValue(const StatsReport* report,
+ StatsReport::StatsValueName name,
+ std::string* value) {
+ const StatsReport::Value* v = report->FindValue(name);
+ if (v)
+ *value = v->ToString();
+ return v != nullptr;
+ }
+
+ bool called_;
+ struct {
+ void Clear() {
+ number_of_reports = 0;
+ timestamp = 0;
+ audio_output_level = 0;
+ audio_input_level = 0;
+ bytes_received = 0;
+ bytes_sent = 0;
+ available_receive_bandwidth = 0;
+ dtls_cipher.clear();
+ srtp_cipher.clear();
+ }
+
+ size_t number_of_reports;
+ double timestamp;
+ int audio_output_level;
+ int audio_input_level;
+ int bytes_received;
+ int bytes_sent;
+ int available_receive_bandwidth;
+ std::string dtls_cipher;
+ std::string srtp_cipher;
+ } stats_;
+};
+
+} // namespace webrtc
+
+#endif // TALK_APP_WEBRTC_TEST_MOCKPEERCONNECTIONOBSERVERS_H_
diff --git a/talk/app/webrtc/test/peerconnectiontestwrapper.cc b/talk/app/webrtc/test/peerconnectiontestwrapper.cc
new file mode 100644
index 0000000000..2eb24d9700
--- /dev/null
+++ b/talk/app/webrtc/test/peerconnectiontestwrapper.cc
@@ -0,0 +1,297 @@
+/*
+ * 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.
+ */
+
+#include "talk/app/webrtc/fakeportallocatorfactory.h"
+#include "talk/app/webrtc/test/fakedtlsidentitystore.h"
+#include "talk/app/webrtc/test/fakeperiodicvideocapturer.h"
+#include "talk/app/webrtc/test/mockpeerconnectionobservers.h"
+#include "talk/app/webrtc/test/peerconnectiontestwrapper.h"
+#include "talk/app/webrtc/videosourceinterface.h"
+#include "webrtc/base/gunit.h"
+
+static const char kStreamLabelBase[] = "stream_label";
+static const char kVideoTrackLabelBase[] = "video_track";
+static const char kAudioTrackLabelBase[] = "audio_track";
+static const int kMaxWait = 10000;
+static const int kTestAudioFrameCount = 3;
+static const int kTestVideoFrameCount = 3;
+
+using webrtc::FakeConstraints;
+using webrtc::FakeVideoTrackRenderer;
+using webrtc::IceCandidateInterface;
+using webrtc::MediaConstraintsInterface;
+using webrtc::MediaStreamInterface;
+using webrtc::MockSetSessionDescriptionObserver;
+using webrtc::PeerConnectionInterface;
+using webrtc::SessionDescriptionInterface;
+using webrtc::VideoTrackInterface;
+
+void PeerConnectionTestWrapper::Connect(PeerConnectionTestWrapper* caller,
+ PeerConnectionTestWrapper* callee) {
+ caller->SignalOnIceCandidateReady.connect(
+ callee, &PeerConnectionTestWrapper::AddIceCandidate);
+ callee->SignalOnIceCandidateReady.connect(
+ caller, &PeerConnectionTestWrapper::AddIceCandidate);
+
+ caller->SignalOnSdpReady.connect(
+ callee, &PeerConnectionTestWrapper::ReceiveOfferSdp);
+ callee->SignalOnSdpReady.connect(
+ caller, &PeerConnectionTestWrapper::ReceiveAnswerSdp);
+}
+
+PeerConnectionTestWrapper::PeerConnectionTestWrapper(const std::string& name)
+ : name_(name) {}
+
+PeerConnectionTestWrapper::~PeerConnectionTestWrapper() {}
+
+bool PeerConnectionTestWrapper::CreatePc(
+ const MediaConstraintsInterface* constraints) {
+ allocator_factory_ = webrtc::FakePortAllocatorFactory::Create();
+ if (!allocator_factory_) {
+ return false;
+ }
+
+ fake_audio_capture_module_ = FakeAudioCaptureModule::Create();
+ if (fake_audio_capture_module_ == NULL) {
+ return false;
+ }
+
+ peer_connection_factory_ = webrtc::CreatePeerConnectionFactory(
+ rtc::Thread::Current(), rtc::Thread::Current(),
+ fake_audio_capture_module_, NULL, NULL);
+ if (!peer_connection_factory_) {
+ return false;
+ }
+
+ // CreatePeerConnection with IceServers.
+ webrtc::PeerConnectionInterface::IceServers ice_servers;
+ webrtc::PeerConnectionInterface::IceServer ice_server;
+ ice_server.uri = "stun:stun.l.google.com:19302";
+ ice_servers.push_back(ice_server);
+ rtc::scoped_ptr<webrtc::DtlsIdentityStoreInterface> dtls_identity_store(
+ rtc::SSLStreamAdapter::HaveDtlsSrtp() ?
+ new FakeDtlsIdentityStore() : nullptr);
+ peer_connection_ = peer_connection_factory_->CreatePeerConnection(
+ ice_servers, constraints, allocator_factory_.get(),
+ dtls_identity_store.Pass(), this);
+
+ return peer_connection_.get() != NULL;
+}
+
+rtc::scoped_refptr<webrtc::DataChannelInterface>
+PeerConnectionTestWrapper::CreateDataChannel(
+ const std::string& label,
+ const webrtc::DataChannelInit& init) {
+ return peer_connection_->CreateDataChannel(label, &init);
+}
+
+void PeerConnectionTestWrapper::OnAddStream(MediaStreamInterface* stream) {
+ LOG(LS_INFO) << "PeerConnectionTestWrapper " << name_
+ << ": OnAddStream";
+ // TODO(ronghuawu): support multiple streams.
+ if (stream->GetVideoTracks().size() > 0) {
+ renderer_.reset(new FakeVideoTrackRenderer(stream->GetVideoTracks()[0]));
+ }
+}
+
+void PeerConnectionTestWrapper::OnIceCandidate(
+ const IceCandidateInterface* candidate) {
+ std::string sdp;
+ EXPECT_TRUE(candidate->ToString(&sdp));
+ // Give the user a chance to modify sdp for testing.
+ SignalOnIceCandidateCreated(&sdp);
+ SignalOnIceCandidateReady(candidate->sdp_mid(), candidate->sdp_mline_index(),
+ sdp);
+}
+
+void PeerConnectionTestWrapper::OnDataChannel(
+ webrtc::DataChannelInterface* data_channel) {
+ SignalOnDataChannel(data_channel);
+}
+
+void PeerConnectionTestWrapper::OnSuccess(SessionDescriptionInterface* desc) {
+ // This callback should take the ownership of |desc|.
+ rtc::scoped_ptr<SessionDescriptionInterface> owned_desc(desc);
+ std::string sdp;
+ EXPECT_TRUE(desc->ToString(&sdp));
+
+ LOG(LS_INFO) << "PeerConnectionTestWrapper " << name_
+ << ": " << desc->type() << " sdp created: " << sdp;
+
+ // Give the user a chance to modify sdp for testing.
+ SignalOnSdpCreated(&sdp);
+
+ SetLocalDescription(desc->type(), sdp);
+
+ SignalOnSdpReady(sdp);
+}
+
+void PeerConnectionTestWrapper::CreateOffer(
+ const MediaConstraintsInterface* constraints) {
+ LOG(LS_INFO) << "PeerConnectionTestWrapper " << name_
+ << ": CreateOffer.";
+ peer_connection_->CreateOffer(this, constraints);
+}
+
+void PeerConnectionTestWrapper::CreateAnswer(
+ const MediaConstraintsInterface* constraints) {
+ LOG(LS_INFO) << "PeerConnectionTestWrapper " << name_
+ << ": CreateAnswer.";
+ peer_connection_->CreateAnswer(this, constraints);
+}
+
+void PeerConnectionTestWrapper::ReceiveOfferSdp(const std::string& sdp) {
+ SetRemoteDescription(SessionDescriptionInterface::kOffer, sdp);
+ CreateAnswer(NULL);
+}
+
+void PeerConnectionTestWrapper::ReceiveAnswerSdp(const std::string& sdp) {
+ SetRemoteDescription(SessionDescriptionInterface::kAnswer, sdp);
+}
+
+void PeerConnectionTestWrapper::SetLocalDescription(const std::string& type,
+ const std::string& sdp) {
+ LOG(LS_INFO) << "PeerConnectionTestWrapper " << name_
+ << ": SetLocalDescription " << type << " " << sdp;
+
+ rtc::scoped_refptr<MockSetSessionDescriptionObserver>
+ observer(new rtc::RefCountedObject<
+ MockSetSessionDescriptionObserver>());
+ peer_connection_->SetLocalDescription(
+ observer, webrtc::CreateSessionDescription(type, sdp, NULL));
+}
+
+void PeerConnectionTestWrapper::SetRemoteDescription(const std::string& type,
+ const std::string& sdp) {
+ LOG(LS_INFO) << "PeerConnectionTestWrapper " << name_
+ << ": SetRemoteDescription " << type << " " << sdp;
+
+ rtc::scoped_refptr<MockSetSessionDescriptionObserver>
+ observer(new rtc::RefCountedObject<
+ MockSetSessionDescriptionObserver>());
+ peer_connection_->SetRemoteDescription(
+ observer, webrtc::CreateSessionDescription(type, sdp, NULL));
+}
+
+void PeerConnectionTestWrapper::AddIceCandidate(const std::string& sdp_mid,
+ int sdp_mline_index,
+ const std::string& candidate) {
+ rtc::scoped_ptr<webrtc::IceCandidateInterface> owned_candidate(
+ webrtc::CreateIceCandidate(sdp_mid, sdp_mline_index, candidate, NULL));
+ EXPECT_TRUE(peer_connection_->AddIceCandidate(owned_candidate.get()));
+}
+
+void PeerConnectionTestWrapper::WaitForCallEstablished() {
+ WaitForConnection();
+ WaitForAudio();
+ WaitForVideo();
+}
+
+void PeerConnectionTestWrapper::WaitForConnection() {
+ EXPECT_TRUE_WAIT(CheckForConnection(), kMaxWait);
+ LOG(LS_INFO) << "PeerConnectionTestWrapper " << name_
+ << ": Connected.";
+}
+
+bool PeerConnectionTestWrapper::CheckForConnection() {
+ return (peer_connection_->ice_connection_state() ==
+ PeerConnectionInterface::kIceConnectionConnected) ||
+ (peer_connection_->ice_connection_state() ==
+ PeerConnectionInterface::kIceConnectionCompleted);
+}
+
+void PeerConnectionTestWrapper::WaitForAudio() {
+ EXPECT_TRUE_WAIT(CheckForAudio(), kMaxWait);
+ LOG(LS_INFO) << "PeerConnectionTestWrapper " << name_
+ << ": Got enough audio frames.";
+}
+
+bool PeerConnectionTestWrapper::CheckForAudio() {
+ return (fake_audio_capture_module_->frames_received() >=
+ kTestAudioFrameCount);
+}
+
+void PeerConnectionTestWrapper::WaitForVideo() {
+ EXPECT_TRUE_WAIT(CheckForVideo(), kMaxWait);
+ LOG(LS_INFO) << "PeerConnectionTestWrapper " << name_
+ << ": Got enough video frames.";
+}
+
+bool PeerConnectionTestWrapper::CheckForVideo() {
+ if (!renderer_) {
+ return false;
+ }
+ return (renderer_->num_rendered_frames() >= kTestVideoFrameCount);
+}
+
+void PeerConnectionTestWrapper::GetAndAddUserMedia(
+ bool audio, const webrtc::FakeConstraints& audio_constraints,
+ bool video, const webrtc::FakeConstraints& video_constraints) {
+ rtc::scoped_refptr<webrtc::MediaStreamInterface> stream =
+ GetUserMedia(audio, audio_constraints, video, video_constraints);
+ EXPECT_TRUE(peer_connection_->AddStream(stream));
+}
+
+rtc::scoped_refptr<webrtc::MediaStreamInterface>
+ PeerConnectionTestWrapper::GetUserMedia(
+ bool audio, const webrtc::FakeConstraints& audio_constraints,
+ bool video, const webrtc::FakeConstraints& video_constraints) {
+ std::string label = kStreamLabelBase +
+ rtc::ToString<int>(
+ static_cast<int>(peer_connection_->local_streams()->count()));
+ rtc::scoped_refptr<webrtc::MediaStreamInterface> stream =
+ peer_connection_factory_->CreateLocalMediaStream(label);
+
+ if (audio) {
+ FakeConstraints constraints = audio_constraints;
+ // Disable highpass filter so that we can get all the test audio frames.
+ constraints.AddMandatory(
+ MediaConstraintsInterface::kHighpassFilter, false);
+ rtc::scoped_refptr<webrtc::AudioSourceInterface> source =
+ peer_connection_factory_->CreateAudioSource(&constraints);
+ rtc::scoped_refptr<webrtc::AudioTrackInterface> audio_track(
+ peer_connection_factory_->CreateAudioTrack(kAudioTrackLabelBase,
+ source));
+ stream->AddTrack(audio_track);
+ }
+
+ if (video) {
+ // Set max frame rate to 10fps to reduce the risk of the tests to be flaky.
+ FakeConstraints constraints = video_constraints;
+ constraints.SetMandatoryMaxFrameRate(10);
+
+ rtc::scoped_refptr<webrtc::VideoSourceInterface> source =
+ peer_connection_factory_->CreateVideoSource(
+ new webrtc::FakePeriodicVideoCapturer(), &constraints);
+ std::string videotrack_label = label + kVideoTrackLabelBase;
+ rtc::scoped_refptr<webrtc::VideoTrackInterface> video_track(
+ peer_connection_factory_->CreateVideoTrack(videotrack_label, source));
+
+ stream->AddTrack(video_track);
+ }
+ return stream;
+}
diff --git a/talk/app/webrtc/test/peerconnectiontestwrapper.h b/talk/app/webrtc/test/peerconnectiontestwrapper.h
new file mode 100644
index 0000000000..b65426326f
--- /dev/null
+++ b/talk/app/webrtc/test/peerconnectiontestwrapper.h
@@ -0,0 +1,122 @@
+/*
+ * libjingle
+ * Copyright 2013 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TALK_APP_WEBRTC_TEST_PEERCONNECTIONTESTWRAPPER_H_
+#define TALK_APP_WEBRTC_TEST_PEERCONNECTIONTESTWRAPPER_H_
+
+#include "talk/app/webrtc/peerconnectioninterface.h"
+#include "talk/app/webrtc/test/fakeaudiocapturemodule.h"
+#include "talk/app/webrtc/test/fakeconstraints.h"
+#include "talk/app/webrtc/test/fakevideotrackrenderer.h"
+#include "webrtc/base/sigslot.h"
+
+namespace webrtc {
+class DtlsIdentityStoreInterface;
+class PortAllocatorFactoryInterface;
+}
+
+class PeerConnectionTestWrapper
+ : public webrtc::PeerConnectionObserver,
+ public webrtc::CreateSessionDescriptionObserver,
+ public sigslot::has_slots<> {
+ public:
+ static void Connect(PeerConnectionTestWrapper* caller,
+ PeerConnectionTestWrapper* callee);
+
+ explicit PeerConnectionTestWrapper(const std::string& name);
+ virtual ~PeerConnectionTestWrapper();
+
+ bool CreatePc(const webrtc::MediaConstraintsInterface* constraints);
+
+ rtc::scoped_refptr<webrtc::DataChannelInterface> CreateDataChannel(
+ const std::string& label,
+ const webrtc::DataChannelInit& init);
+
+ // Implements PeerConnectionObserver.
+ virtual void OnSignalingChange(
+ webrtc::PeerConnectionInterface::SignalingState new_state) {}
+ virtual void OnStateChange(
+ webrtc::PeerConnectionObserver::StateType state_changed) {}
+ virtual void OnAddStream(webrtc::MediaStreamInterface* stream);
+ virtual void OnRemoveStream(webrtc::MediaStreamInterface* stream) {}
+ virtual void OnDataChannel(webrtc::DataChannelInterface* data_channel);
+ virtual void OnRenegotiationNeeded() {}
+ virtual void OnIceConnectionChange(
+ webrtc::PeerConnectionInterface::IceConnectionState new_state) {}
+ virtual void OnIceGatheringChange(
+ webrtc::PeerConnectionInterface::IceGatheringState new_state) {}
+ virtual void OnIceCandidate(const webrtc::IceCandidateInterface* candidate);
+ virtual void OnIceComplete() {}
+
+ // Implements CreateSessionDescriptionObserver.
+ virtual void OnSuccess(webrtc::SessionDescriptionInterface* desc);
+ virtual void OnFailure(const std::string& error) {}
+
+ void CreateOffer(const webrtc::MediaConstraintsInterface* constraints);
+ void CreateAnswer(const webrtc::MediaConstraintsInterface* constraints);
+ void ReceiveOfferSdp(const std::string& sdp);
+ void ReceiveAnswerSdp(const std::string& sdp);
+ void AddIceCandidate(const std::string& sdp_mid, int sdp_mline_index,
+ const std::string& candidate);
+ void WaitForCallEstablished();
+ void WaitForConnection();
+ void WaitForAudio();
+ void WaitForVideo();
+ void GetAndAddUserMedia(
+ bool audio, const webrtc::FakeConstraints& audio_constraints,
+ bool video, const webrtc::FakeConstraints& video_constraints);
+
+ // sigslots
+ sigslot::signal1<std::string*> SignalOnIceCandidateCreated;
+ sigslot::signal3<const std::string&,
+ int,
+ const std::string&> SignalOnIceCandidateReady;
+ sigslot::signal1<std::string*> SignalOnSdpCreated;
+ sigslot::signal1<const std::string&> SignalOnSdpReady;
+ sigslot::signal1<webrtc::DataChannelInterface*> SignalOnDataChannel;
+
+ private:
+ void SetLocalDescription(const std::string& type, const std::string& sdp);
+ void SetRemoteDescription(const std::string& type, const std::string& sdp);
+ bool CheckForConnection();
+ bool CheckForAudio();
+ bool CheckForVideo();
+ rtc::scoped_refptr<webrtc::MediaStreamInterface> GetUserMedia(
+ bool audio, const webrtc::FakeConstraints& audio_constraints,
+ bool video, const webrtc::FakeConstraints& video_constraints);
+
+ std::string name_;
+ rtc::scoped_refptr<webrtc::PortAllocatorFactoryInterface>
+ allocator_factory_;
+ rtc::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection_;
+ rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface>
+ peer_connection_factory_;
+ rtc::scoped_refptr<FakeAudioCaptureModule> fake_audio_capture_module_;
+ rtc::scoped_ptr<webrtc::FakeVideoTrackRenderer> renderer_;
+};
+
+#endif // TALK_APP_WEBRTC_TEST_PEERCONNECTIONTESTWRAPPER_H_
diff --git a/talk/app/webrtc/test/testsdpstrings.h b/talk/app/webrtc/test/testsdpstrings.h
new file mode 100644
index 0000000000..e27c9a2f88
--- /dev/null
+++ b/talk/app/webrtc/test/testsdpstrings.h
@@ -0,0 +1,147 @@
+/*
+ * libjingle
+ * Copyright 2012 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.
+ */
+
+// This file contain SDP strings used for testing.
+
+#ifndef TALK_APP_WEBRTC_TEST_TESTSDPSTRINGS_H_
+#define TALK_APP_WEBRTC_TEST_TESTSDPSTRINGS_H_
+
+namespace webrtc {
+
+// SDP offer string from a Nightly FireFox build.
+static const char kFireFoxSdpOffer[] =
+ "v=0\r\n"
+ "o=Mozilla-SIPUA 23551 0 IN IP4 0.0.0.0\r\n"
+ "s=SIP Call\r\n"
+ "t=0 0\r\n"
+ "a=ice-ufrag:e5785931\r\n"
+ "a=ice-pwd:36fb7878390db89481c1d46daa4278d8\r\n"
+ "a=fingerprint:sha-256 A7:24:72:CA:6E:02:55:39:BA:66:DF:6E:CC:4C:D8:B0:1A:"
+ "BF:1A:56:65:7D:F4:03:AD:7E:77:43:2A:29:EC:93\r\n"
+ "m=audio 36993 RTP/SAVPF 109 0 8 101\r\n"
+ "c=IN IP4 74.95.2.170\r\n"
+ "a=rtpmap:109 opus/48000/2\r\n"
+ "a=ptime:20\r\n"
+ "a=rtpmap:0 PCMU/8000\r\n"
+ "a=rtpmap:8 PCMA/8000\r\n"
+ "a=rtpmap:101 telephone-event/8000\r\n"
+ "a=fmtp:101 0-15\r\n"
+ "a=sendrecv\r\n"
+ "a=candidate:0 1 UDP 2112946431 172.16.191.1 61725 typ host\r\n"
+ "a=candidate:2 1 UDP 2112487679 172.16.131.1 58798 typ host\r\n"
+ "a=candidate:4 1 UDP 2113667327 10.0.254.2 58122 typ host\r\n"
+ "a=candidate:5 1 UDP 1694302207 74.95.2.170 36993 typ srflx raddr "
+ "10.0.254.2 rport 58122\r\n"
+ "a=candidate:0 2 UDP 2112946430 172.16.191.1 55025 typ host\r\n"
+ "a=candidate:2 2 UDP 2112487678 172.16.131.1 63576 typ host\r\n"
+ "a=candidate:4 2 UDP 2113667326 10.0.254.2 50962 typ host\r\n"
+ "a=candidate:5 2 UDP 1694302206 74.95.2.170 41028 typ srflx raddr"
+ " 10.0.254.2 rport 50962\r\n"
+ "m=video 38826 RTP/SAVPF 120\r\n"
+ "c=IN IP4 74.95.2.170\r\n"
+ "a=rtpmap:120 VP8/90000\r\n"
+ "a=sendrecv\r\n"
+ "a=candidate:0 1 UDP 2112946431 172.16.191.1 62017 typ host\r\n"
+ "a=candidate:2 1 UDP 2112487679 172.16.131.1 59741 typ host\r\n"
+ "a=candidate:4 1 UDP 2113667327 10.0.254.2 62652 typ host\r\n"
+ "a=candidate:5 1 UDP 1694302207 74.95.2.170 38826 typ srflx raddr"
+ " 10.0.254.2 rport 62652\r\n"
+ "a=candidate:0 2 UDP 2112946430 172.16.191.1 63440 typ host\r\n"
+ "a=candidate:2 2 UDP 2112487678 172.16.131.1 51847 typ host\r\n"
+ "a=candidate:4 2 UDP 2113667326 10.0.254.2 58890 typ host\r\n"
+ "a=candidate:5 2 UDP 1694302206 74.95.2.170 33611 typ srflx raddr"
+ " 10.0.254.2 rport 58890\r\n"
+#ifdef HAVE_SCTP
+ "m=application 45536 SCTP/DTLS 5000\r\n"
+ "c=IN IP4 74.95.2.170\r\n"
+ "a=fmtp:5000 protocol=webrtc-datachannel;streams=16\r\n"
+ "a=sendrecv\r\n"
+ "a=candidate:0 1 UDP 2112946431 172.16.191.1 60248 typ host\r\n"
+ "a=candidate:2 1 UDP 2112487679 172.16.131.1 55925 typ host\r\n"
+ "a=candidate:4 1 UDP 2113667327 10.0.254.2 65268 typ host\r\n"
+ "a=candidate:5 1 UDP 1694302207 74.95.2.170 45536 typ srflx raddr"
+ " 10.0.254.2 rport 65268\r\n"
+ "a=candidate:0 2 UDP 2112946430 172.16.191.1 49162 typ host\r\n"
+ "a=candidate:2 2 UDP 2112487678 172.16.131.1 59635 typ host\r\n"
+ "a=candidate:4 2 UDP 2113667326 10.0.254.2 61232 typ host\r\n"
+ "a=candidate:5 2 UDP 1694302206 74.95.2.170 45468 typ srflx raddr"
+ " 10.0.254.2 rport 61232\r\n"
+#endif
+ ;
+
+// Audio SDP with a limited set of audio codecs.
+static const char kAudioSdp[] =
+ "v=0\r\n"
+ "o=- 7859371131 2 IN IP4 192.168.30.208\r\n"
+ "s=-\r\n"
+ "c=IN IP4 192.168.30.208\r\n"
+ "t=0 0\r\n"
+ "m=audio 16000 RTP/SAVPF 0 8 126\r\n"
+ "a=rtpmap:0 PCMU/8000\r\n"
+ "a=rtpmap:8 PCMA/8000\r\n"
+ "a=rtpmap:126 telephone-event/8000\r\n"
+ "a=sendrecv\r\n"
+ "a=rtcp:16000 IN IP4 192.168.30.208\r\n"
+ "a=rtcp-mux\r\n"
+ "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
+ "inline:tvKIFjbMQ7W0/C2RzhwN0oQglj/7GJg+frdsNRxt\r\n"
+ "a=ice-ufrag:AI2sRT3r\r\n"
+ "a=ice-pwd:lByS9z2RSQlSE9XurlvjYmEm\r\n"
+ "a=ssrc:4227871655 cname:GeAAgb6XCPNLVMX5\r\n"
+ "a=ssrc:4227871655 msid:1NFAV3iD08ioO2339rQS9pfOI9mDf6GeG9F4 a0\r\n"
+ "a=ssrc:4227871655 mslabel:1NFAV3iD08ioO2339rQS9pfOI9mDf6GeG9F4\r\n"
+ "a=ssrc:4227871655 label:1NFAV3iD08ioO2339rQS9pfOI9mDf6GeG9F4a0\r\n"
+ "a=mid:audio\r\n";
+
+static const char kAudioSdpWithUnsupportedCodecs[] =
+ "v=0\r\n"
+ "o=- 6858750541 2 IN IP4 192.168.30.208\r\n"
+ "s=-\r\n"
+ "c=IN IP4 192.168.30.208\r\n"
+ "t=0 0\r\n"
+ "m=audio 16000 RTP/SAVPF 0 8 18 110 126\r\n"
+ "a=rtpmap:0 PCMU/8000\r\n"
+ "a=rtpmap:8 PCMA/8000\r\n"
+ "a=rtpmap:18 WeirdCodec1/8000\r\n"
+ "a=rtpmap:110 WeirdCodec2/8000\r\n"
+ "a=rtpmap:126 telephone-event/8000\r\n"
+ "a=sendonly\r\n"
+ "a=rtcp:16000 IN IP4 192.168.30.208\r\n"
+ "a=rtcp-mux\r\n"
+ "a=crypto:1 AES_CM_128_HMAC_SHA1_80 "
+ "inline:tvKIFjbMQ7W0/C2RzhwN0oQglj/7GJg+frdsNRxt\r\n"
+ "a=ice-ufrag:AI2sRT3r\r\n"
+ "a=ice-pwd:lByS9z2RSQlSE9XurlvjYmEm\r\n"
+ "a=ssrc:4227871655 cname:TsmD02HRfhkJBm4m\r\n"
+ "a=ssrc:4227871655 msid:7nU0TApbB-n4dfPlCplWT9QTEsbBDS1IlpW3 a0\r\n"
+ "a=ssrc:4227871655 mslabel:7nU0TApbB-n4dfPlCplWT9QTEsbBDS1IlpW3\r\n"
+ "a=ssrc:4227871655 label:7nU0TApbB-n4dfPlCplWT9QTEsbBDS1IlpW3a0\r\n"
+ "a=mid:audio\r\n";
+
+} // namespace webrtc
+
+#endif // TALK_APP_WEBRTC_TEST_TESTSDPSTRINGS_H_