-
-
Save sukinull/9328109 to your computer and use it in GitHub Desktop.
webrtc_cmd.cc - using libjingle/webrtc in console
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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_START_PROCESS, | |
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 { | |
talk_base::CritScope cs(&crit_); | |
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) { | |
talk_base::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; | |
} | |
{ | |
talk_base::CritScope cs(&crit_); | |
playing_ = true; | |
} | |
bool start = true; | |
UpdateProcessing(start); | |
return 0; | |
} | |
int32_t FakeAudioCaptureModule::StopPlayout() { | |
bool start = false; | |
{ | |
talk_base::CritScope cs(&crit_); | |
playing_ = false; | |
start = ShouldStartProcessing(); | |
} | |
UpdateProcessing(start); | |
return 0; | |
} | |
bool FakeAudioCaptureModule::Playing() const { | |
talk_base::CritScope cs(&crit_); | |
return playing_; | |
} | |
int32_t FakeAudioCaptureModule::StartRecording() { | |
if (!rec_is_initialized_) { | |
return -1; | |
} | |
{ | |
talk_base::CritScope cs(&crit_); | |
recording_ = true; | |
} | |
bool start = true; | |
UpdateProcessing(start); | |
return 0; | |
} | |
int32_t FakeAudioCaptureModule::StopRecording() { | |
bool start = false; | |
{ | |
talk_base::CritScope cs(&crit_); | |
recording_ = false; | |
start = ShouldStartProcessing(); | |
} | |
UpdateProcessing(start); | |
return 0; | |
} | |
bool FakeAudioCaptureModule::Recording() const { | |
talk_base::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::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) { | |
talk_base::CritScope cs(&crit_); | |
current_mic_level_ = volume; | |
return 0; | |
} | |
int32_t FakeAudioCaptureModule::MicrophoneVolume(uint32_t* volume) const { | |
talk_base::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(talk_base::Message* msg) { | |
switch (msg->message_id) { | |
case MSG_START_PROCESS: | |
StartProcessP(); | |
break; | |
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; | |
} | |
bool FakeAudioCaptureModule::ShouldStartProcessing() { | |
return recording_ || playing_; | |
} | |
void FakeAudioCaptureModule::UpdateProcessing(bool start) { | |
if (start) { | |
process_thread_->Post(this, MSG_START_PROCESS); | |
} else { | |
process_thread_->Send(this, MSG_STOP_PROCESS); | |
} | |
} | |
void FakeAudioCaptureModule::StartProcessP() { | |
ASSERT(talk_base::Thread::Current() == process_thread_); | |
if (started_) { | |
// Already started. | |
return; | |
} | |
ProcessFrameP(); | |
} | |
void FakeAudioCaptureModule::ProcessFrameP() { | |
ASSERT(talk_base::Thread::Current() == process_thread_); | |
if (!started_) { | |
next_frame_time_ = talk_base::Time(); | |
started_ = true; | |
} | |
bool playing; | |
bool recording; | |
{ | |
talk_base::CritScope cs(&crit_); | |
playing = playing_; | |
recording = recording_; | |
} | |
// Receive and send frames every kTimePerFrameMs. | |
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_); | |
{ | |
talk_base::CritScope cs(&crit_callback_); | |
if (!audio_callback_) { | |
return; | |
} | |
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)) { | |
talk_base::CritScope cs(&crit_); | |
++frames_received_; | |
} | |
} | |
void FakeAudioCaptureModule::SendFrameP() { | |
ASSERT(talk_base::Thread::Current() == process_thread_); | |
talk_base::CritScope cs(&crit_callback_); | |
if (!audio_callback_) { | |
return; | |
} | |
bool key_pressed = false; | |
uint32_t current_mic_level = 0; | |
MicrophoneVolume(¤t_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); | |
} | |
void FakeAudioCaptureModule::StopProcessP() { | |
ASSERT(talk_base::Thread::Current() == process_thread_); | |
started_ = false; | |
process_thread_->Clear(this); | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <string> | |
#include "talk/app/webrtc/peerconnectioninterface.h" | |
#include "talk/app/webrtc/jsep.h" | |
#include "talk/app/webrtc/datachannelinterface.h" | |
#include "talk/app/webrtc/test/fakeconstraints.h" | |
#include "talk/base/json.h" | |
#include "talk/base/logging.h" | |
class WebRtcConnectionManager | |
: public webrtc::PeerConnectionObserver, | |
public webrtc::CreateSessionDescriptionObserver { | |
public: | |
WebRtcConnectionManager(); | |
bool InitConnection(); | |
void CreateOffer(); | |
void OnOfferRequest(webrtc::SessionDescriptionInterface* desc); | |
void OnOfferReply(webrtc::SessionDescriptionInterface* desc); | |
static webrtc::SessionDescriptionInterface* StringToDescription( | |
const std::string string_desc); | |
static std::string DescriptionToString( | |
const webrtc::SessionDescriptionInterface* desc); | |
virtual const webrtc::SessionDescriptionInterface* | |
local_description() const { | |
return peer_connection_->local_description(); | |
} | |
protected: | |
//~WebRtcConnectionManager(); | |
// inherited from PeerConnectionObserver | |
virtual void OnError(); | |
virtual void OnStateChange( | |
webrtc::PeerConnectionObserver::StateType state_changed); | |
virtual void OnAddStream(webrtc::MediaStreamInterface* stream); | |
virtual void OnRemoveStream(webrtc::MediaStreamInterface* stream); | |
virtual void OnIceCandidate(const webrtc::IceCandidateInterface* candidate); | |
// inherited from CreateSessionDescriptionObserver | |
virtual void OnSuccess(webrtc::SessionDescriptionInterface* desc); | |
virtual void OnFailure(const std::string &error); | |
virtual int AddRef() { return 1; } | |
virtual int Release() { return 0; } | |
private: | |
talk_base::scoped_refptr<webrtc::PeerConnectionFactoryInterface> | |
peer_connection_factory_; | |
webrtc::PeerConnectionInterface::IceServers servers_; | |
webrtc::PeerConnectionInterface::IceServer server_; | |
webrtc::FakeConstraints constraints_; | |
talk_base::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection_; | |
talk_base::scoped_refptr<webrtc::AudioTrackInterface> audio_track_; | |
talk_base::scoped_refptr<webrtc::MediaStreamInterface> stream_; | |
}; | |
const char kStunServerUri[] = "stun:stun.l.google.com:19302"; | |
const char kAudioLabel[] = "audio_label"; | |
const char kStreamLabel[] = "stream_label"; | |
class DummySetSessionDescriptionObserver | |
: public webrtc::SetSessionDescriptionObserver { | |
public: | |
static DummySetSessionDescriptionObserver* Create() { | |
return | |
new talk_base::RefCountedObject<DummySetSessionDescriptionObserver>(); | |
} | |
virtual void OnSuccess() { | |
LOG(INFO) << __FUNCTION__; | |
} | |
virtual void OnFailure(const std::string& error) { | |
LOG(INFO) << __FUNCTION__ << " " << error; | |
} | |
protected: | |
DummySetSessionDescriptionObserver() {} | |
~DummySetSessionDescriptionObserver() {} | |
}; | |
WebRtcConnectionManager::WebRtcConnectionManager() { | |
peer_connection_factory_ = webrtc::CreatePeerConnectionFactory(); | |
server_.uri = kStunServerUri; | |
servers_.push_back(server_); | |
constraints_.SetMandatoryReceiveAudio(false); | |
constraints_.SetMandatoryReceiveVideo(false); | |
constraints_.SetAllowRtpDataChannels(); | |
} | |
bool WebRtcConnectionManager::InitConnection() { | |
peer_connection_ = peer_connection_factory_->CreatePeerConnection(servers_, &constraints_, NULL, this); | |
audio_track_ = peer_connection_factory_->CreateAudioTrack(kAudioLabel, NULL); | |
stream_ = peer_connection_factory_->CreateLocalMediaStream(kStreamLabel); | |
stream_->AddTrack(audio_track_); | |
peer_connection_->AddStream(stream_, &constraints_); | |
return true; | |
} | |
void WebRtcConnectionManager::CreateOffer() { | |
peer_connection_->CreateOffer(this, &constraints_); | |
} | |
void WebRtcConnectionManager::OnOfferRequest( | |
webrtc::SessionDescriptionInterface* desc) { | |
peer_connection_->SetRemoteDescription( | |
DummySetSessionDescriptionObserver::Create(), desc); | |
peer_connection_->CreateAnswer(this, &constraints_); | |
} | |
void WebRtcConnectionManager::OnOfferReply( | |
webrtc::SessionDescriptionInterface* desc) { | |
peer_connection_->SetRemoteDescription( | |
DummySetSessionDescriptionObserver::Create(), desc); | |
} | |
void WebRtcConnectionManager::OnError() { | |
std::cout << "PEERCONNECTION ERROR" << std::endl; | |
} | |
void WebRtcConnectionManager::OnStateChange( | |
webrtc::PeerConnectionObserver::StateType state_changed) { | |
} | |
void WebRtcConnectionManager::OnAddStream( | |
webrtc::MediaStreamInterface* stream) { | |
} | |
void WebRtcConnectionManager::OnRemoveStream( | |
webrtc::MediaStreamInterface* stream) { | |
} | |
void WebRtcConnectionManager::OnIceCandidate( | |
const webrtc::IceCandidateInterface* candidate) { | |
std::cout << "ICE ICE baby" << std::endl; | |
} | |
void WebRtcConnectionManager::OnSuccess( | |
webrtc::SessionDescriptionInterface* desc) { | |
std::cout << "SETTING LOCAL" << std::endl; | |
peer_connection_->SetLocalDescription( | |
DummySetSessionDescriptionObserver::Create(), desc); | |
} | |
void WebRtcConnectionManager::OnFailure(const std::string &error) { | |
std::cout << error << std::endl; | |
} | |
webrtc::SessionDescriptionInterface* | |
WebRtcConnectionManager::StringToDescription(const std::string string_desc) { | |
Json::Reader reader; | |
Json::Value jdesc; | |
if (!reader.parse(string_desc, jdesc)) { | |
LOG(WARNING) << "Unknown string desc " << string_desc; | |
return NULL; | |
} | |
// replace with global constants | |
std::string type = jdesc["type"].asString(); | |
std::string sdp = jdesc["sdp"].asString(); | |
return webrtc::CreateSessionDescription(type, sdp); | |
} | |
std::string WebRtcConnectionManager::DescriptionToString( | |
const webrtc::SessionDescriptionInterface* desc) { | |
Json::FastWriter writer; | |
Json::Value jdesc; | |
jdesc["type"] = desc->type(); | |
std::string sdp; | |
desc->ToString(&sdp); | |
jdesc["sdp"] = sdp; | |
return writer.write(jdesc); | |
} | |
int main(int argc, char **argv) { | |
WebRtcConnectionManager manager; | |
while (1) { | |
std::string input; | |
std::cout << "Enter command:" << std::endl; | |
std::cin >> input; | |
if (input.compare("init") == 0) { | |
manager.InitConnection(); | |
} | |
else if (input.compare("offer") == 0) { | |
manager.CreateOffer(); | |
} | |
else if (input.compare("print") == 0) { | |
std::string string_desc = manager.DescriptionToString( | |
manager.local_description()); | |
std::cout << string_desc << std::endl; | |
} | |
else if (input.compare("request") == 0) { | |
std::string string_desc; | |
std::cout << "Enter request:" << std::endl; | |
std::getline(std::cin, string_desc); | |
std::getline(std::cin, string_desc); | |
webrtc::SessionDescriptionInterface* desc = | |
manager.StringToDescription(string_desc); | |
manager.OnOfferRequest(desc); | |
} | |
else if (input.compare("reply") == 0) { | |
std::string string_desc; | |
std::cout << "Enter reply:" << std::endl; | |
std::getline(std::cin, string_desc); | |
std::getline(std::cin, string_desc); | |
webrtc::SessionDescriptionInterface* desc = | |
manager.StringToDescription(string_desc); | |
manager.OnOfferReply(desc); | |
} | |
} | |
return 0; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment