Adds trunk/talk folder of revision 359 from libjingles google code to
trunk/talk
git-svn-id: http://webrtc.googlecode.com/svn/trunk@4318 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/talk/app/webrtc/test/fakeaudiocapturemodule.cc b/talk/app/webrtc/test/fakeaudiocapturemodule.cc
new file mode 100644
index 0000000..4bdaf89
--- /dev/null
+++ b/talk/app/webrtc/test/fakeaudiocapturemodule.cc
@@ -0,0 +1,716 @@
+/*
+ * 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 "talk/base/common.h"
+#include "talk/base/refcount.h"
+#include "talk/base/thread.h"
+#include "talk/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 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 int 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_RUN_PROCESS,
+ MSG_STOP_PROCESS,
+};
+
+FakeAudioCaptureModule::FakeAudioCaptureModule(
+ talk_base::Thread* process_thread)
+ : last_process_time_ms_(0),
+ audio_callback_(NULL),
+ recording_(false),
+ playing_(false),
+ play_is_initialized_(false),
+ rec_is_initialized_(false),
+ current_mic_level_(kMaxVolume),
+ started_(false),
+ next_frame_time_(0),
+ process_thread_(process_thread),
+ frames_received_(0) {
+}
+
+FakeAudioCaptureModule::~FakeAudioCaptureModule() {
+ // Ensure that thread stops calling ProcessFrame().
+ process_thread_->Send(this, MSG_STOP_PROCESS);
+}
+
+talk_base::scoped_refptr<FakeAudioCaptureModule> FakeAudioCaptureModule::Create(
+ talk_base::Thread* process_thread) {
+ if (process_thread == NULL) return NULL;
+
+ talk_base::scoped_refptr<FakeAudioCaptureModule> capture_module(
+ new talk_base::RefCountedObject<FakeAudioCaptureModule>(process_thread));
+ if (!capture_module->Initialize()) {
+ return NULL;
+ }
+ return capture_module;
+}
+
+int FakeAudioCaptureModule::frames_received() const {
+ return frames_received_;
+}
+
+int32_t FakeAudioCaptureModule::Version(char* /*version*/,
+ uint32_t& /*remaining_buffer_in_bytes*/,
+ uint32_t& /*position*/) const {
+ ASSERT(false);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::TimeUntilNextProcess() {
+ const uint32 current_time = talk_base::Time();
+ if (current_time < last_process_time_ms_) {
+ // TODO: wraparound could be handled more gracefully.
+ return 0;
+ }
+ const uint32 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_ = talk_base::Time();
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::ChangeUniqueId(const int32_t /*id*/) {
+ ASSERT(false);
+ 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) {
+ 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;
+ }
+ playing_ = true;
+ UpdateProcessing();
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::StopPlayout() {
+ playing_ = false;
+ UpdateProcessing();
+ return 0;
+}
+
+bool FakeAudioCaptureModule::Playing() const {
+ return playing_;
+}
+
+int32_t FakeAudioCaptureModule::StartRecording() {
+ if (!rec_is_initialized_) {
+ return -1;
+ }
+ recording_ = true;
+ UpdateProcessing();
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::StopRecording() {
+ recording_ = false;
+ UpdateProcessing();
+ return 0;
+}
+
+bool FakeAudioCaptureModule::Recording() const {
+ 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::SpeakerIsAvailable(bool* available) {
+ // No speaker, just dropping audio. Return success.
+ *available = true;
+ 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::MicrophoneIsAvailable(bool* available) {
+ // No microphone, just playing from file. Return success.
+ *available = true;
+ 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*/) {
+ ASSERT(false);
+ return 0;
+}
+
+int32_t FakeAudioCaptureModule::MicrophoneVolume(uint32_t* volume) const {
+ *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(talk_base::Message* msg) {
+ switch (msg->message_id) {
+ case MSG_RUN_PROCESS:
+ ProcessFrameP();
+ break;
+ case MSG_STOP_PROCESS:
+ StopProcessP();
+ 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_ = talk_base::Time();
+ return true;
+}
+
+void FakeAudioCaptureModule::SetSendBuffer(int value) {
+ Sample* buffer_ptr = reinterpret_cast<Sample*>(send_buffer_);
+ const int buffer_size_in_samples = sizeof(send_buffer_) /
+ kNumberBytesPerSample;
+ for (int 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 int buffer_size_in_samples = sizeof(rec_buffer_) /
+ kNumberBytesPerSample;
+ for (int i = 0; i < buffer_size_in_samples; ++i) {
+ if (buffer_ptr[i] >= value) return true;
+ }
+ return false;
+}
+
+void FakeAudioCaptureModule::UpdateProcessing() {
+ const bool process = recording_ || playing_;
+ if (process) {
+ if (started_) {
+ // Already started.
+ return;
+ }
+ process_thread_->Post(this, MSG_RUN_PROCESS);
+ } else {
+ process_thread_->Send(this, MSG_STOP_PROCESS);
+ }
+}
+
+void FakeAudioCaptureModule::ProcessFrameP() {
+ ASSERT(talk_base::Thread::Current() == process_thread_);
+ if (!started_) {
+ next_frame_time_ = talk_base::Time();
+ started_ = true;
+ }
+ // Receive and send frames every kTimePerFrameMs.
+ if (audio_callback_ != NULL) {
+ if (playing_) {
+ ReceiveFrameP();
+ }
+ if (recording_) {
+ SendFrameP();
+ }
+ }
+
+ next_frame_time_ += kTimePerFrameMs;
+ const uint32 current_time = talk_base::Time();
+ const uint32 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(talk_base::Thread::Current() == process_thread_);
+ ResetRecBuffer();
+ uint32_t nSamplesOut = 0;
+ if (audio_callback_->NeedMorePlayData(kNumberSamples, kNumberBytesPerSample,
+ kNumberOfChannels, kSamplesPerSecond,
+ rec_buffer_, nSamplesOut) != 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)) ++frames_received_;
+}
+
+void FakeAudioCaptureModule::SendFrameP() {
+ ASSERT(talk_base::Thread::Current() == process_thread_);
+ bool key_pressed = false;
+ if (audio_callback_->RecordedDataIsAvailable(send_buffer_, kNumberSamples,
+ kNumberBytesPerSample,
+ kNumberOfChannels,
+ kSamplesPerSecond, kTotalDelayMs,
+ kClockDriftMs, current_mic_level_,
+ key_pressed,
+ current_mic_level_) != 0) {
+ ASSERT(false);
+ }
+}
+
+void FakeAudioCaptureModule::StopProcessP() {
+ ASSERT(talk_base::Thread::Current() == process_thread_);
+ started_ = false;
+ process_thread_->Clear(this);
+}
diff --git a/talk/app/webrtc/test/fakeaudiocapturemodule.h b/talk/app/webrtc/test/fakeaudiocapturemodule.h
new file mode 100644
index 0000000..c32fa1f
--- /dev/null
+++ b/talk/app/webrtc/test/fakeaudiocapturemodule.h
@@ -0,0 +1,280 @@
+/*
+ * 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 "talk/base/basictypes.h"
+#include "talk/base/messagehandler.h"
+#include "talk/base/scoped_ref_ptr.h"
+#include "webrtc/common_types.h"
+#include "webrtc/modules/audio_device/include/audio_device.h"
+
+namespace talk_base {
+
+class Thread;
+
+} // namespace talk_base
+
+class FakeAudioCaptureModule
+ : public webrtc::AudioDeviceModule,
+ public talk_base::MessageHandler {
+ public:
+ typedef uint16 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.
+ enum{kNumberSamples = 440};
+ enum{kNumberBytesPerSample = sizeof(Sample)};
+
+ // Creates a FakeAudioCaptureModule or returns NULL on failure.
+ // |process_thread| is used to push and pull audio frames to and from the
+ // returned instance. Note: ownership of |process_thread| is not handed over.
+ static talk_base::scoped_refptr<FakeAudioCaptureModule> Create(
+ talk_base::Thread* process_thread);
+
+ // 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.
+ virtual int32_t Version(char* version,
+ uint32_t& remaining_buffer_in_bytes,
+ uint32_t& position) const;
+ virtual int32_t TimeUntilNextProcess();
+ virtual int32_t Process();
+ virtual int32_t ChangeUniqueId(const int32_t id);
+
+ virtual int32_t ActiveAudioLayer(AudioLayer* audio_layer) const;
+
+ virtual ErrorCode LastError() const;
+ virtual int32_t RegisterEventObserver(
+ webrtc::AudioDeviceObserver* event_callback);
+
+ virtual int32_t RegisterAudioCallback(webrtc::AudioTransport* audio_callback);
+
+ virtual int32_t Init();
+ virtual int32_t Terminate();
+ virtual bool Initialized() const;
+
+ virtual int16_t PlayoutDevices();
+ virtual int16_t RecordingDevices();
+ virtual int32_t PlayoutDeviceName(uint16_t index,
+ char name[webrtc::kAdmMaxDeviceNameSize],
+ char guid[webrtc::kAdmMaxGuidSize]);
+ virtual int32_t RecordingDeviceName(uint16_t index,
+ char name[webrtc::kAdmMaxDeviceNameSize],
+ char guid[webrtc::kAdmMaxGuidSize]);
+
+ virtual int32_t SetPlayoutDevice(uint16_t index);
+ virtual int32_t SetPlayoutDevice(WindowsDeviceType device);
+ virtual int32_t SetRecordingDevice(uint16_t index);
+ virtual int32_t SetRecordingDevice(WindowsDeviceType device);
+
+ virtual int32_t PlayoutIsAvailable(bool* available);
+ virtual int32_t InitPlayout();
+ virtual bool PlayoutIsInitialized() const;
+ virtual int32_t RecordingIsAvailable(bool* available);
+ virtual int32_t InitRecording();
+ virtual bool RecordingIsInitialized() const;
+
+ virtual int32_t StartPlayout();
+ virtual int32_t StopPlayout();
+ virtual bool Playing() const;
+ virtual int32_t StartRecording();
+ virtual int32_t StopRecording();
+ virtual bool Recording() const;
+
+ virtual int32_t SetAGC(bool enable);
+ virtual bool AGC() const;
+
+ virtual int32_t SetWaveOutVolume(uint16_t volume_left,
+ uint16_t volume_right);
+ virtual int32_t WaveOutVolume(uint16_t* volume_left,
+ uint16_t* volume_right) const;
+
+ virtual int32_t SpeakerIsAvailable(bool* available);
+ virtual int32_t InitSpeaker();
+ virtual bool SpeakerIsInitialized() const;
+ virtual int32_t MicrophoneIsAvailable(bool* available);
+ virtual int32_t InitMicrophone();
+ virtual bool MicrophoneIsInitialized() const;
+
+ virtual int32_t SpeakerVolumeIsAvailable(bool* available);
+ virtual int32_t SetSpeakerVolume(uint32_t volume);
+ virtual int32_t SpeakerVolume(uint32_t* volume) const;
+ virtual int32_t MaxSpeakerVolume(uint32_t* max_volume) const;
+ virtual int32_t MinSpeakerVolume(uint32_t* min_volume) const;
+ virtual int32_t SpeakerVolumeStepSize(uint16_t* step_size) const;
+
+ virtual int32_t MicrophoneVolumeIsAvailable(bool* available);
+ virtual int32_t SetMicrophoneVolume(uint32_t volume);
+ virtual int32_t MicrophoneVolume(uint32_t* volume) const;
+ virtual int32_t MaxMicrophoneVolume(uint32_t* max_volume) const;
+
+ virtual int32_t MinMicrophoneVolume(uint32_t* min_volume) const;
+ virtual int32_t MicrophoneVolumeStepSize(uint16_t* step_size) const;
+
+ virtual int32_t SpeakerMuteIsAvailable(bool* available);
+ virtual int32_t SetSpeakerMute(bool enable);
+ virtual int32_t SpeakerMute(bool* enabled) const;
+
+ virtual int32_t MicrophoneMuteIsAvailable(bool* available);
+ virtual int32_t SetMicrophoneMute(bool enable);
+ virtual int32_t MicrophoneMute(bool* enabled) const;
+
+ virtual int32_t MicrophoneBoostIsAvailable(bool* available);
+ virtual int32_t SetMicrophoneBoost(bool enable);
+ virtual int32_t MicrophoneBoost(bool* enabled) const;
+
+ virtual int32_t StereoPlayoutIsAvailable(bool* available) const;
+ virtual int32_t SetStereoPlayout(bool enable);
+ virtual int32_t StereoPlayout(bool* enabled) const;
+ virtual int32_t StereoRecordingIsAvailable(bool* available) const;
+ virtual int32_t SetStereoRecording(bool enable);
+ virtual int32_t StereoRecording(bool* enabled) const;
+ virtual int32_t SetRecordingChannel(const ChannelType channel);
+ virtual int32_t RecordingChannel(ChannelType* channel) const;
+
+ virtual int32_t SetPlayoutBuffer(const BufferType type,
+ uint16_t size_ms = 0);
+ virtual int32_t PlayoutBuffer(BufferType* type,
+ uint16_t* size_ms) const;
+ virtual int32_t PlayoutDelay(uint16_t* delay_ms) const;
+ virtual int32_t RecordingDelay(uint16_t* delay_ms) const;
+
+ virtual int32_t CPULoad(uint16_t* load) const;
+
+ virtual int32_t StartRawOutputFileRecording(
+ const char pcm_file_name_utf8[webrtc::kAdmMaxFileNameSize]);
+ virtual int32_t StopRawOutputFileRecording();
+ virtual int32_t StartRawInputFileRecording(
+ const char pcm_file_name_utf8[webrtc::kAdmMaxFileNameSize]);
+ virtual int32_t StopRawInputFileRecording();
+
+ virtual int32_t SetRecordingSampleRate(const uint32_t samples_per_sec);
+ virtual int32_t RecordingSampleRate(uint32_t* samples_per_sec) const;
+ virtual int32_t SetPlayoutSampleRate(const uint32_t samples_per_sec);
+ virtual int32_t PlayoutSampleRate(uint32_t* samples_per_sec) const;
+
+ virtual int32_t ResetAudioDevice();
+ virtual int32_t SetLoudspeakerStatus(bool enable);
+ virtual int32_t GetLoudspeakerStatus(bool* enabled) const;
+ // End of functions inherited from webrtc::AudioDeviceModule.
+
+ // The following function is inherited from talk_base::MessageHandler.
+ virtual void OnMessage(talk_base::Message* msg);
+
+ 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(talk_base::Thread* process_thread);
+ // 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);
+
+ // Starts or stops the pushing and pulling of audio frames depending on if
+ // recording or playback has been enabled/started.
+ void UpdateProcessing();
+
+ // 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();
+ // Stops the periodic calling of ProcessFrame() in a thread safe way.
+ void StopProcessP();
+
+ // The time in milliseconds when Process() was last called or 0 if no call
+ // has been made.
+ uint32 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 next_frame_time_;
+
+ // User provided thread context.
+ talk_base::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_;
+};
+
+#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 0000000..5738955
--- /dev/null
+++ b/talk/app/webrtc/test/fakeaudiocapturemodule_unittest.cc
@@ -0,0 +1,212 @@
+/*
+ * 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 "talk/base/gunit.h"
+#include "talk/base/scoped_ref_ptr.h"
+#include "talk/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(
+ talk_base::Thread::Current());
+ EXPECT_TRUE(fake_audio_capture_module_.get() != NULL);
+ }
+
+ // Callbacks inherited from webrtc::AudioTransport.
+ // ADM is pushing data.
+ virtual int32_t RecordedDataIsAvailable(const void* audioSamples,
+ const uint32_t nSamples,
+ const uint8_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) {
+ 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.
+ virtual int32_t NeedMorePlayData(const uint32_t nSamples,
+ const uint8_t nBytesPerSample,
+ const uint8_t nChannels,
+ const uint32_t samplesPerSec,
+ void* audioSamples,
+ uint32_t& nSamplesOut) {
+ ++pull_iterations_;
+ const uint32_t audio_buffer_size = nSamples * nBytesPerSample;
+ const uint32_t bytes_out = RecordedDataReceived() ?
+ CopyFromRecBuffer(audioSamples, audio_buffer_size):
+ GenerateZeroBuffer(audioSamples, audio_buffer_size);
+ nSamplesOut = bytes_out / nBytesPerSample;
+ return 0;
+ }
+
+ int push_iterations() const { return push_iterations_; }
+ int pull_iterations() const { return pull_iterations_; }
+
+ talk_base::scoped_refptr<FakeAudioCaptureModule> fake_audio_capture_module_;
+
+ private:
+ bool RecordedDataReceived() const {
+ return rec_buffer_bytes_ != 0;
+ }
+ int32_t GenerateZeroBuffer(void* audio_buffer, uint32_t audio_buffer_size) {
+ memset(audio_buffer, 0, audio_buffer_size);
+ return audio_buffer_size;
+ }
+ int32_t CopyFromRecBuffer(void* audio_buffer, uint32_t audio_buffer_size) {
+ EXPECT_EQ(audio_buffer_size, rec_buffer_bytes_);
+ const uint32_t min_buffer_size = min(audio_buffer_size, rec_buffer_bytes_);
+ memcpy(audio_buffer, rec_buffer_, min_buffer_size);
+ return min_buffer_size;
+ }
+
+ int push_iterations_;
+ int pull_iterations_;
+
+ char rec_buffer_[FakeAudioCaptureModule::kNumberSamples *
+ FakeAudioCaptureModule::kNumberBytesPerSample];
+ uint32_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 speaker_available = false;
+ EXPECT_EQ(0, fake_audio_capture_module_->SpeakerIsAvailable(
+ &speaker_available));
+ EXPECT_TRUE(speaker_available);
+
+ 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 microphone_available = false;
+ EXPECT_EQ(0, fake_audio_capture_module_->MicrophoneIsAvailable(
+ µphone_available));
+ EXPECT_TRUE(microphone_available);
+
+ 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 0000000..0299afa
--- /dev/null
+++ b/talk/app/webrtc/test/fakeconstraints.h
@@ -0,0 +1,118 @@
+/*
+ * 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 "talk/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, talk_base::ToString<T>(value)));
+ }
+
+ template <class T>
+ void AddOptional(const std::string& key, const T& value) {
+ optional_.push_back(Constraint(key, talk_base::ToString<T>(value)));
+ }
+
+ void SetMandatoryMinAspectRatio(double ratio) {
+ AddMandatory(MediaConstraintsInterface::kMinAspectRatio, ratio);
+ }
+
+ void SetMandatoryMinWidth(int width) {
+ AddMandatory(MediaConstraintsInterface::kMinWidth, width);
+ }
+
+ void SetMandatoryMinHeight(int height) {
+ AddMandatory(MediaConstraintsInterface::kMinHeight, height);
+ }
+
+ void SetOptionalMaxWidth(int width) {
+ AddOptional(MediaConstraintsInterface::kMaxWidth, width);
+ }
+
+ void SetMandatoryMaxFrameRate(int frame_rate) {
+ AddMandatory(MediaConstraintsInterface::kMaxFrameRate, frame_rate);
+ }
+
+ void SetMandatoryReceiveAudio(bool enable) {
+ AddMandatory(MediaConstraintsInterface::kOfferToReceiveAudio, enable);
+ }
+
+ void SetMandatoryReceiveVideo(bool enable) {
+ AddMandatory(MediaConstraintsInterface::kOfferToReceiveVideo, enable);
+ }
+
+ void SetMandatoryUseRtpMux(bool enable) {
+ AddMandatory(MediaConstraintsInterface::kUseRtpMux, enable);
+ }
+
+ void SetMandatoryIceRestart(bool enable) {
+ AddMandatory(MediaConstraintsInterface::kIceRestart, enable);
+ }
+
+ void SetAllowRtpDataChannels() {
+ AddMandatory(MediaConstraintsInterface::kEnableRtpDataChannels, true);
+ }
+
+ void SetOptionalVAD(bool enable) {
+ AddOptional(MediaConstraintsInterface::kVoiceActivityDetection, enable);
+ }
+
+ void SetAllowDtlsSctpDataChannels() {
+ AddMandatory(MediaConstraintsInterface::kEnableSctpDataChannels, true);
+ AddMandatory(MediaConstraintsInterface::kEnableDtlsSrtp, true);
+ }
+
+ private:
+ Constraints mandatory_;
+ Constraints optional_;
+};
+
+} // namespace webrtc
+
+#endif // TALK_APP_WEBRTC_TEST_FAKECONSTRAINTS_H_
diff --git a/talk/app/webrtc/test/fakeperiodicvideocapturer.h b/talk/app/webrtc/test/fakeperiodicvideocapturer.h
new file mode 100644
index 0000000..7f70ae2
--- /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/base/thread.h"
+#include "talk/media/base/fakevideocapturer.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) {
+ talk_base::Thread::Current()->Post(this, MSG_CREATEFRAME);
+ }
+ return state;
+ }
+ virtual void Stop() {
+ talk_base::Thread::Current()->Clear(this);
+ }
+ // Inherited from MesageHandler.
+ virtual void OnMessage(talk_base::Message* msg) {
+ if (msg->message_id == MSG_CREATEFRAME) {
+ if (IsRunning()) {
+ CaptureFrame();
+ talk_base::Thread::Current()->PostDelayed(static_cast<int>(
+ GetCaptureFormat()->interval / talk_base::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 0000000..0030a0c
--- /dev/null
+++ b/talk/app/webrtc/test/fakevideotrackrenderer.h
@@ -0,0 +1,70 @@
+/*
+ * 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:
+ explicit FakeVideoTrackRenderer(VideoTrackInterface* video_track)
+ : video_track_(video_track) {
+ video_track_->AddRenderer(this);
+ }
+ ~FakeVideoTrackRenderer() {
+ video_track_->RemoveRenderer(this);
+ }
+
+ // Implements VideoRendererInterface
+ virtual void SetSize(int width, int height) {
+ fake_renderer_.SetSize(width, height, 0);
+ }
+
+ virtual void RenderFrame(const cricket::VideoFrame* frame) {
+ fake_renderer_.RenderFrame(frame);
+ }
+
+ int errors() const { return fake_renderer_.errors(); }
+ int width() const { return fake_renderer_.width(); }
+ int height() const { return fake_renderer_.height(); }
+ int num_set_sizes() const { return fake_renderer_.num_set_sizes(); }
+ int num_rendered_frames() const {
+ return fake_renderer_.num_rendered_frames();
+ }
+
+ private:
+ cricket::FakeVideoRenderer fake_renderer_;
+ talk_base::scoped_refptr<VideoTrackInterface> video_track_;
+};
+
+} // 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 0000000..e2de379
--- /dev/null
+++ b/talk/app/webrtc/test/mockpeerconnectionobservers.h
@@ -0,0 +1,172 @@
+/*
+ * 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_;
+ talk_base::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) {
+ channel_->RegisterObserver(this);
+ state_ = channel_->state();
+ }
+ virtual ~MockDataChannelObserver() {
+ channel_->UnregisterObserver();
+ }
+
+ virtual void OnStateChange() { state_ = channel_->state(); }
+ virtual void OnMessage(const DataBuffer& buffer) {
+ last_message_.assign(buffer.data.data(), buffer.data.length());
+ }
+
+ bool IsOpen() const { return state_ == DataChannelInterface::kOpen; }
+ const std::string& last_message() const { return last_message_; }
+
+ private:
+ talk_base::scoped_refptr<webrtc::DataChannelInterface> channel_;
+ DataChannelInterface::DataState state_;
+ std::string last_message_;
+};
+
+class MockStatsObserver : public webrtc::StatsObserver {
+ public:
+ MockStatsObserver()
+ : called_(false) {}
+ virtual ~MockStatsObserver() {}
+ virtual void OnComplete(const std::vector<webrtc::StatsReport>& reports) {
+ called_ = true;
+ reports_ = reports;
+ }
+
+ bool called() const { return called_; }
+ size_t number_of_reports() const { return reports_.size(); }
+
+ int AudioOutputLevel() {
+ return GetSsrcStatsValue(
+ webrtc::StatsReport::kStatsValueNameAudioOutputLevel);
+ }
+
+ int AudioInputLevel() {
+ return GetSsrcStatsValue(
+ webrtc::StatsReport::kStatsValueNameAudioInputLevel);
+ }
+
+ int BytesReceived() {
+ return GetSsrcStatsValue(
+ webrtc::StatsReport::kStatsValueNameBytesReceived);
+ }
+
+ int BytesSent() {
+ return GetSsrcStatsValue(webrtc::StatsReport::kStatsValueNameBytesSent);
+ }
+
+ private:
+ int GetSsrcStatsValue(const std::string name) {
+ if (reports_.empty()) {
+ return 0;
+ }
+ for (size_t i = 0; i < reports_.size(); ++i) {
+ if (reports_[i].type != StatsReport::kStatsReportTypeSsrc)
+ continue;
+ webrtc::StatsReport::Values::const_iterator it =
+ reports_[i].values.begin();
+ for (; it != reports_[i].values.end(); ++it) {
+ if (it->name == name) {
+ return talk_base::FromString<int>(it->value);
+ }
+ }
+ }
+ return 0;
+ }
+
+ bool called_;
+ std::vector<webrtc::StatsReport> reports_;
+};
+
+} // namespace webrtc
+
+#endif // TALK_APP_WEBRTC_TEST_MOCKPEERCONNECTIONOBSERVERS_H_
diff --git a/talk/app/webrtc/test/testsdpstrings.h b/talk/app/webrtc/test/testsdpstrings.h
new file mode 100644
index 0000000..9f95d36
--- /dev/null
+++ b/talk/app/webrtc/test/testsdpstrings.h
@@ -0,0 +1,144 @@
+/*
+ * 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"
+ "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";
+
+// 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_