2011-07-07 08:21:25 +00:00
|
|
|
/*
|
2012-01-31 12:22:14 +00:00
|
|
|
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
2011-07-07 08:21:25 +00:00
|
|
|
*
|
|
|
|
|
* Use of this source code is governed by a BSD-style license
|
|
|
|
|
* that can be found in the LICENSE file in the root of the source
|
|
|
|
|
* tree. An additional intellectual property rights grant can be found
|
|
|
|
|
* in the file PATENTS. All contributing project authors may
|
|
|
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "voe_base_impl.h"
|
|
|
|
|
|
2011-09-07 15:11:18 +00:00
|
|
|
#include "audio_coding_module.h"
|
2011-07-07 08:21:25 +00:00
|
|
|
#include "audio_processing.h"
|
|
|
|
|
#include "channel.h"
|
2011-09-07 15:11:18 +00:00
|
|
|
#include "critical_section_wrapper.h"
|
|
|
|
|
#include "file_wrapper.h"
|
2012-09-21 20:46:40 +00:00
|
|
|
#include "modules/audio_device/audio_device_impl.h"
|
2011-07-07 08:21:25 +00:00
|
|
|
#include "output_mixer.h"
|
|
|
|
|
#include "signal_processing_library.h"
|
2011-09-07 15:11:18 +00:00
|
|
|
#include "trace.h"
|
|
|
|
|
#include "transmit_mixer.h"
|
2011-07-07 08:21:25 +00:00
|
|
|
#include "utility.h"
|
2011-09-07 15:11:18 +00:00
|
|
|
#include "voe_errors.h"
|
|
|
|
|
#include "voice_engine_impl.h"
|
2011-07-07 08:21:25 +00:00
|
|
|
|
|
|
|
|
#if (defined(_WIN32) && defined(_DLL) && (_MSC_VER == 1400))
|
|
|
|
|
// Fix for VS 2005 MD/MDd link problem
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
extern "C"
|
|
|
|
|
{ FILE _iob[3] = { __iob_func()[0], __iob_func()[1], __iob_func()[2]}; }
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
namespace webrtc
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
VoEBase* VoEBase::GetInterface(VoiceEngine* voiceEngine)
|
|
|
|
|
{
|
|
|
|
|
if (NULL == voiceEngine)
|
|
|
|
|
{
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2013-02-15 15:07:32 +00:00
|
|
|
VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine);
|
2012-04-26 15:28:22 +00:00
|
|
|
s->AddRef();
|
|
|
|
|
return s;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2012-04-04 14:57:19 +00:00
|
|
|
VoEBaseImpl::VoEBaseImpl(voe::SharedData* shared) :
|
2011-07-07 08:21:25 +00:00
|
|
|
_voiceEngineObserverPtr(NULL),
|
|
|
|
|
_callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
|
2012-04-04 14:57:19 +00:00
|
|
|
_voiceEngineObserver(false), _oldVoEMicLevel(0), _oldMicLevel(0),
|
|
|
|
|
_shared(shared)
|
2011-07-07 08:21:25 +00:00
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
2011-07-07 08:21:25 +00:00
|
|
|
"VoEBaseImpl() - ctor");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VoEBaseImpl::~VoEBaseImpl()
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
2011-07-07 08:21:25 +00:00
|
|
|
"~VoEBaseImpl() - dtor");
|
|
|
|
|
|
|
|
|
|
TerminateInternal();
|
|
|
|
|
|
|
|
|
|
delete &_callbackCritSect;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VoEBaseImpl::OnErrorIsReported(const ErrorCode error)
|
|
|
|
|
{
|
2012-03-07 08:12:21 +00:00
|
|
|
CriticalSectionScoped cs(&_callbackCritSect);
|
2011-07-07 08:21:25 +00:00
|
|
|
if (_voiceEngineObserver)
|
|
|
|
|
{
|
|
|
|
|
if (_voiceEngineObserverPtr)
|
|
|
|
|
{
|
|
|
|
|
int errCode(0);
|
|
|
|
|
if (error == AudioDeviceObserver::kRecordingError)
|
|
|
|
|
{
|
|
|
|
|
errCode = VE_RUNTIME_REC_ERROR;
|
2012-04-04 14:57:19 +00:00
|
|
|
WEBRTC_TRACE(kTraceInfo, kTraceVoice,
|
|
|
|
|
VoEId(_shared->instance_id(), -1),
|
|
|
|
|
"VoEBaseImpl::OnErrorIsReported() => VE_RUNTIME_REC_ERROR");
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
else if (error == AudioDeviceObserver::kPlayoutError)
|
|
|
|
|
{
|
|
|
|
|
errCode = VE_RUNTIME_PLAY_ERROR;
|
2012-04-04 14:57:19 +00:00
|
|
|
WEBRTC_TRACE(kTraceInfo, kTraceVoice,
|
|
|
|
|
VoEId(_shared->instance_id(), -1),
|
|
|
|
|
"VoEBaseImpl::OnErrorIsReported() => "
|
|
|
|
|
"VE_RUNTIME_PLAY_ERROR");
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
// Deliver callback (-1 <=> no channel dependency)
|
|
|
|
|
_voiceEngineObserverPtr->CallbackOnError(-1, errCode);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VoEBaseImpl::OnWarningIsReported(const WarningCode warning)
|
|
|
|
|
{
|
2012-03-07 08:12:21 +00:00
|
|
|
CriticalSectionScoped cs(&_callbackCritSect);
|
2011-07-07 08:21:25 +00:00
|
|
|
if (_voiceEngineObserver)
|
|
|
|
|
{
|
|
|
|
|
if (_voiceEngineObserverPtr)
|
|
|
|
|
{
|
|
|
|
|
int warningCode(0);
|
|
|
|
|
if (warning == AudioDeviceObserver::kRecordingWarning)
|
|
|
|
|
{
|
|
|
|
|
warningCode = VE_RUNTIME_REC_WARNING;
|
2012-04-04 14:57:19 +00:00
|
|
|
WEBRTC_TRACE(kTraceInfo, kTraceVoice,
|
|
|
|
|
VoEId(_shared->instance_id(), -1),
|
|
|
|
|
"VoEBaseImpl::OnErrorIsReported() => "
|
|
|
|
|
"VE_RUNTIME_REC_WARNING");
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
else if (warning == AudioDeviceObserver::kPlayoutWarning)
|
|
|
|
|
{
|
|
|
|
|
warningCode = VE_RUNTIME_PLAY_WARNING;
|
2012-04-04 14:57:19 +00:00
|
|
|
WEBRTC_TRACE(kTraceInfo, kTraceVoice,
|
|
|
|
|
VoEId(_shared->instance_id(), -1),
|
|
|
|
|
"VoEBaseImpl::OnErrorIsReported() => "
|
|
|
|
|
"VE_RUNTIME_PLAY_WARNING");
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
// Deliver callback (-1 <=> no channel dependency)
|
|
|
|
|
_voiceEngineObserverPtr->CallbackOnError(-1, warningCode);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WebRtc_Word32 VoEBaseImpl::RecordedDataIsAvailable(
|
2012-03-09 08:59:19 +00:00
|
|
|
const void* audioSamples,
|
2011-07-07 08:21:25 +00:00
|
|
|
const WebRtc_UWord32 nSamples,
|
|
|
|
|
const WebRtc_UWord8 nBytesPerSample,
|
|
|
|
|
const WebRtc_UWord8 nChannels,
|
|
|
|
|
const WebRtc_UWord32 samplesPerSec,
|
|
|
|
|
const WebRtc_UWord32 totalDelayMS,
|
|
|
|
|
const WebRtc_Word32 clockDrift,
|
|
|
|
|
const WebRtc_UWord32 currentMicLevel,
|
|
|
|
|
WebRtc_UWord32& newMicLevel)
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
2011-07-07 08:21:25 +00:00
|
|
|
"VoEBaseImpl::RecordedDataIsAvailable(nSamples=%u, "
|
|
|
|
|
"nBytesPerSample=%u, nChannels=%u, samplesPerSec=%u, "
|
|
|
|
|
"totalDelayMS=%u, clockDrift=%d, currentMicLevel=%u)",
|
|
|
|
|
nSamples, nBytesPerSample, nChannels, samplesPerSec,
|
|
|
|
|
totalDelayMS, clockDrift, currentMicLevel);
|
|
|
|
|
|
2012-04-04 14:57:19 +00:00
|
|
|
assert(_shared->transmit_mixer() != NULL);
|
|
|
|
|
assert(_shared->audio_device() != NULL);
|
2011-07-07 08:21:25 +00:00
|
|
|
|
|
|
|
|
bool isAnalogAGC(false);
|
|
|
|
|
WebRtc_UWord32 maxVolume(0);
|
|
|
|
|
WebRtc_UWord16 currentVoEMicLevel(0);
|
|
|
|
|
WebRtc_UWord32 newVoEMicLevel(0);
|
|
|
|
|
|
2012-04-04 14:57:19 +00:00
|
|
|
if (_shared->audio_processing() &&
|
|
|
|
|
(_shared->audio_processing()->gain_control()->mode()
|
2011-07-07 08:21:25 +00:00
|
|
|
== GainControl::kAdaptiveAnalog))
|
|
|
|
|
{
|
|
|
|
|
isAnalogAGC = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Will only deal with the volume in adaptive analog mode
|
|
|
|
|
if (isAnalogAGC)
|
|
|
|
|
{
|
|
|
|
|
// Scale from ADM to VoE level range
|
2012-04-04 14:57:19 +00:00
|
|
|
if (_shared->audio_device()->MaxMicrophoneVolume(&maxVolume) == 0)
|
2011-07-07 08:21:25 +00:00
|
|
|
{
|
|
|
|
|
if (0 != maxVolume)
|
|
|
|
|
{
|
|
|
|
|
currentVoEMicLevel = (WebRtc_UWord16) ((currentMicLevel
|
|
|
|
|
* kMaxVolumeLevel + (int) (maxVolume / 2))
|
|
|
|
|
/ (maxVolume));
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-09-28 17:45:03 +00:00
|
|
|
// We learned that on certain systems (e.g Linux) the currentVoEMicLevel
|
|
|
|
|
// can be greater than the maxVolumeLevel therefore
|
|
|
|
|
// we are going to cap the currentVoEMicLevel to the maxVolumeLevel
|
2012-02-16 18:15:54 +00:00
|
|
|
// and change the maxVolume to currentMicLevel if it turns out that
|
|
|
|
|
// the currentVoEMicLevel is indeed greater than the maxVolumeLevel.
|
2011-09-28 17:45:03 +00:00
|
|
|
if (currentVoEMicLevel > kMaxVolumeLevel)
|
|
|
|
|
{
|
|
|
|
|
currentVoEMicLevel = kMaxVolumeLevel;
|
2012-02-16 18:15:54 +00:00
|
|
|
maxVolume = currentMicLevel;
|
2011-09-28 17:45:03 +00:00
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Keep track if the MicLevel has been changed by the AGC, if not,
|
|
|
|
|
// use the old value AGC returns to let AGC continue its trend,
|
|
|
|
|
// so eventually the AGC is able to change the mic level. This handles
|
|
|
|
|
// issues with truncation introduced by the scaling.
|
|
|
|
|
if (_oldMicLevel == currentMicLevel)
|
|
|
|
|
{
|
|
|
|
|
currentVoEMicLevel = (WebRtc_UWord16) _oldVoEMicLevel;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Perform channel-independent operations
|
|
|
|
|
// (APM, mix with file, record to file, mute, etc.)
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->transmit_mixer()->PrepareDemux(audioSamples, nSamples, nChannels,
|
2012-06-27 03:25:31 +00:00
|
|
|
samplesPerSec, static_cast<WebRtc_UWord16>(totalDelayMS), clockDrift,
|
|
|
|
|
currentVoEMicLevel);
|
2011-07-07 08:21:25 +00:00
|
|
|
|
|
|
|
|
// Copy the audio frame to each sending channel and perform
|
|
|
|
|
// channel-dependent operations (file mixing, mute, etc.) to prepare
|
|
|
|
|
// for encoding.
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->transmit_mixer()->DemuxAndMix();
|
2011-07-07 08:21:25 +00:00
|
|
|
// Do the encoding and packetize+transmit the RTP packet when encoding
|
|
|
|
|
// is done.
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->transmit_mixer()->EncodeAndSend();
|
2011-07-07 08:21:25 +00:00
|
|
|
|
|
|
|
|
// Will only deal with the volume in adaptive analog mode
|
|
|
|
|
if (isAnalogAGC)
|
|
|
|
|
{
|
|
|
|
|
// Scale from VoE to ADM level range
|
2012-04-04 14:57:19 +00:00
|
|
|
newVoEMicLevel = _shared->transmit_mixer()->CaptureLevel();
|
2011-07-07 08:21:25 +00:00
|
|
|
if (newVoEMicLevel != currentVoEMicLevel)
|
|
|
|
|
{
|
|
|
|
|
// Add (kMaxVolumeLevel/2) to round the value
|
|
|
|
|
newMicLevel = (WebRtc_UWord32) ((newVoEMicLevel * maxVolume
|
|
|
|
|
+ (int) (kMaxVolumeLevel / 2)) / (kMaxVolumeLevel));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Pass zero if the level is unchanged
|
|
|
|
|
newMicLevel = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Keep track of the value AGC returns
|
|
|
|
|
_oldVoEMicLevel = newVoEMicLevel;
|
|
|
|
|
_oldMicLevel = currentMicLevel;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WebRtc_Word32 VoEBaseImpl::NeedMorePlayData(
|
|
|
|
|
const WebRtc_UWord32 nSamples,
|
|
|
|
|
const WebRtc_UWord8 nBytesPerSample,
|
|
|
|
|
const WebRtc_UWord8 nChannels,
|
|
|
|
|
const WebRtc_UWord32 samplesPerSec,
|
2012-03-09 08:59:19 +00:00
|
|
|
void* audioSamples,
|
2011-07-07 08:21:25 +00:00
|
|
|
WebRtc_UWord32& nSamplesOut)
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
2011-07-07 08:21:25 +00:00
|
|
|
"VoEBaseImpl::NeedMorePlayData(nSamples=%u, "
|
|
|
|
|
"nBytesPerSample=%d, nChannels=%d, samplesPerSec=%u)",
|
|
|
|
|
nSamples, nBytesPerSample, nChannels, samplesPerSec);
|
|
|
|
|
|
2012-04-04 14:57:19 +00:00
|
|
|
assert(_shared->output_mixer() != NULL);
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2012-06-27 03:25:31 +00:00
|
|
|
// TODO(andrew): if the device is running in mono, we should tell the mixer
|
|
|
|
|
// here so that it will only request mono from AudioCodingModule.
|
2011-07-07 08:21:25 +00:00
|
|
|
// Perform mixing of all active participants (channel-based mixing)
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->output_mixer()->MixActiveChannels();
|
2011-07-07 08:21:25 +00:00
|
|
|
|
|
|
|
|
// Additional operations on the combined signal
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->output_mixer()->DoOperationsOnCombinedSignal();
|
2011-07-07 08:21:25 +00:00
|
|
|
|
|
|
|
|
// Retrieve the final output mix (resampled to match the ADM)
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->output_mixer()->GetMixedAudio(samplesPerSec, nChannels,
|
2012-06-27 03:25:31 +00:00
|
|
|
&_audioFrame);
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2012-05-08 17:12:40 +00:00
|
|
|
assert(static_cast<int>(nSamples) == _audioFrame.samples_per_channel_);
|
2011-08-08 08:18:44 +00:00
|
|
|
assert(samplesPerSec ==
|
2012-05-02 23:56:37 +00:00
|
|
|
static_cast<WebRtc_UWord32>(_audioFrame.sample_rate_hz_));
|
2011-07-07 08:21:25 +00:00
|
|
|
|
|
|
|
|
// Deliver audio (PCM) samples to the ADM
|
|
|
|
|
memcpy(
|
|
|
|
|
(WebRtc_Word16*) audioSamples,
|
2012-05-02 23:56:37 +00:00
|
|
|
(const WebRtc_Word16*) _audioFrame.data_,
|
|
|
|
|
sizeof(WebRtc_Word16) * (_audioFrame.samples_per_channel_
|
|
|
|
|
* _audioFrame.num_channels_));
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2012-05-02 23:56:37 +00:00
|
|
|
nSamplesOut = _audioFrame.samples_per_channel_;
|
2011-07-07 08:21:25 +00:00
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int VoEBaseImpl::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
2011-07-07 08:21:25 +00:00
|
|
|
"RegisterVoiceEngineObserver(observer=0x%d)", &observer);
|
2012-03-07 08:12:21 +00:00
|
|
|
CriticalSectionScoped cs(&_callbackCritSect);
|
2011-07-07 08:21:25 +00:00
|
|
|
if (_voiceEngineObserverPtr)
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_INVALID_OPERATION, kTraceError,
|
|
|
|
|
"RegisterVoiceEngineObserver() observer already enabled");
|
2011-07-07 08:21:25 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Register the observer in all active channels
|
2012-04-04 14:57:19 +00:00
|
|
|
voe::ScopedChannel sc(_shared->channel_manager());
|
2011-07-07 08:21:25 +00:00
|
|
|
void* iterator(NULL);
|
|
|
|
|
voe::Channel* channelPtr = sc.GetFirstChannel(iterator);
|
|
|
|
|
while (channelPtr != NULL)
|
|
|
|
|
{
|
|
|
|
|
channelPtr->RegisterVoiceEngineObserver(observer);
|
|
|
|
|
channelPtr = sc.GetNextChannel(iterator);
|
|
|
|
|
}
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->transmit_mixer()->RegisterVoiceEngineObserver(observer);
|
2011-07-07 08:21:25 +00:00
|
|
|
|
|
|
|
|
_voiceEngineObserverPtr = &observer;
|
|
|
|
|
_voiceEngineObserver = true;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int VoEBaseImpl::DeRegisterVoiceEngineObserver()
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
2011-07-07 08:21:25 +00:00
|
|
|
"DeRegisterVoiceEngineObserver()");
|
2012-03-07 08:12:21 +00:00
|
|
|
CriticalSectionScoped cs(&_callbackCritSect);
|
2011-07-07 08:21:25 +00:00
|
|
|
if (!_voiceEngineObserverPtr)
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_INVALID_OPERATION, kTraceError,
|
2011-10-03 15:22:28 +00:00
|
|
|
"DeRegisterVoiceEngineObserver() observer already disabled");
|
2011-07-07 08:21:25 +00:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_voiceEngineObserver = false;
|
|
|
|
|
_voiceEngineObserverPtr = NULL;
|
|
|
|
|
|
|
|
|
|
// Deregister the observer in all active channels
|
2012-04-04 14:57:19 +00:00
|
|
|
voe::ScopedChannel sc(_shared->channel_manager());
|
2011-07-07 08:21:25 +00:00
|
|
|
void* iterator(NULL);
|
|
|
|
|
voe::Channel* channelPtr = sc.GetFirstChannel(iterator);
|
|
|
|
|
while (channelPtr != NULL)
|
|
|
|
|
{
|
|
|
|
|
channelPtr->DeRegisterVoiceEngineObserver();
|
|
|
|
|
channelPtr = sc.GetNextChannel(iterator);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-05 01:12:49 +00:00
|
|
|
int VoEBaseImpl::Init(AudioDeviceModule* external_adm,
|
|
|
|
|
AudioProcessing* audioproc)
|
2011-07-07 08:21:25 +00:00
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
2011-09-07 15:11:18 +00:00
|
|
|
"Init(external_adm=0x%p)", external_adm);
|
2012-04-04 14:57:19 +00:00
|
|
|
CriticalSectionScoped cs(_shared->crit_sec());
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2012-09-08 00:09:26 +00:00
|
|
|
WebRtcSpl_Init();
|
|
|
|
|
|
2012-04-04 14:57:19 +00:00
|
|
|
if (_shared->statistics().Initialized())
|
2011-07-07 08:21:25 +00:00
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2012-04-04 14:57:19 +00:00
|
|
|
if (_shared->process_thread())
|
2011-07-07 08:21:25 +00:00
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
if (_shared->process_thread()->Start() != 0)
|
2011-07-07 08:21:25 +00:00
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_THREAD_ERROR, kTraceError,
|
2011-10-03 15:22:28 +00:00
|
|
|
"Init() failed to start module process thread");
|
2011-07-07 08:21:25 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-12-21 18:00:59 +00:00
|
|
|
// Create an internal ADM if the user has not added an external
|
2011-11-16 10:33:53 +00:00
|
|
|
// ADM implementation as input to Init().
|
|
|
|
|
if (external_adm == NULL)
|
|
|
|
|
{
|
|
|
|
|
// Create the internal ADM implementation.
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->set_audio_device(AudioDeviceModuleImpl::Create(
|
|
|
|
|
VoEId(_shared->instance_id(), -1), _shared->audio_device_layer()));
|
2011-11-16 10:33:53 +00:00
|
|
|
|
2012-04-04 14:57:19 +00:00
|
|
|
if (_shared->audio_device() == NULL)
|
2011-11-16 10:33:53 +00:00
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_NO_MEMORY, kTraceCritical,
|
|
|
|
|
"Init() failed to create the ADM");
|
2011-11-16 10:33:53 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Use the already existing external ADM implementation.
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->set_audio_device(external_adm);
|
|
|
|
|
WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
2011-11-16 10:33:53 +00:00
|
|
|
"An external ADM implementation will be used in VoiceEngine");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Register the ADM to the process thread, which will drive the error
|
|
|
|
|
// callback mechanism
|
2012-04-04 14:57:19 +00:00
|
|
|
if (_shared->process_thread() &&
|
|
|
|
|
_shared->process_thread()->RegisterModule(_shared->audio_device()) != 0)
|
2011-11-16 10:33:53 +00:00
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
|
|
|
|
|
"Init() failed to register the ADM");
|
2011-11-16 10:33:53 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool available(false);
|
|
|
|
|
|
|
|
|
|
// --------------------
|
|
|
|
|
// Reinitialize the ADM
|
|
|
|
|
|
|
|
|
|
// Register the AudioObserver implementation
|
2012-04-04 14:57:19 +00:00
|
|
|
if (_shared->audio_device()->RegisterEventObserver(this) != 0) {
|
|
|
|
|
_shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
|
|
|
|
|
"Init() failed to register event observer for the ADM");
|
2012-01-31 12:22:14 +00:00
|
|
|
}
|
2011-11-16 10:33:53 +00:00
|
|
|
|
|
|
|
|
// Register the AudioTransport implementation
|
2012-04-04 14:57:19 +00:00
|
|
|
if (_shared->audio_device()->RegisterAudioCallback(this) != 0) {
|
|
|
|
|
_shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
|
|
|
|
|
"Init() failed to register audio callback for the ADM");
|
2012-01-31 12:22:14 +00:00
|
|
|
}
|
2011-11-16 10:33:53 +00:00
|
|
|
|
|
|
|
|
// ADM initialization
|
2012-04-04 14:57:19 +00:00
|
|
|
if (_shared->audio_device()->Init() != 0)
|
2011-11-16 10:33:53 +00:00
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
|
|
|
|
|
"Init() failed to initialize the ADM");
|
2011-11-16 10:33:53 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Initialize the default speaker
|
2012-04-04 14:57:19 +00:00
|
|
|
if (_shared->audio_device()->SetPlayoutDevice(
|
|
|
|
|
WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0)
|
2011-11-16 10:33:53 +00:00
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceInfo,
|
2011-11-16 10:33:53 +00:00
|
|
|
"Init() failed to set the default output device");
|
|
|
|
|
}
|
2012-04-04 14:57:19 +00:00
|
|
|
if (_shared->audio_device()->SpeakerIsAvailable(&available) != 0)
|
2011-11-16 10:33:53 +00:00
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
|
2011-11-16 10:33:53 +00:00
|
|
|
"Init() failed to check speaker availability, trying to "
|
|
|
|
|
"initialize speaker anyway");
|
|
|
|
|
}
|
|
|
|
|
else if (!available)
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
|
2011-11-16 10:33:53 +00:00
|
|
|
"Init() speaker not available, trying to initialize speaker "
|
|
|
|
|
"anyway");
|
|
|
|
|
}
|
2012-04-04 14:57:19 +00:00
|
|
|
if (_shared->audio_device()->InitSpeaker() != 0)
|
2011-11-16 10:33:53 +00:00
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
|
2011-11-16 10:33:53 +00:00
|
|
|
"Init() failed to initialize the speaker");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Initialize the default microphone
|
2012-04-04 14:57:19 +00:00
|
|
|
if (_shared->audio_device()->SetRecordingDevice(
|
|
|
|
|
WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0)
|
2011-11-16 10:33:53 +00:00
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceInfo,
|
2011-11-16 10:33:53 +00:00
|
|
|
"Init() failed to set the default input device");
|
|
|
|
|
}
|
2012-04-04 14:57:19 +00:00
|
|
|
if (_shared->audio_device()->MicrophoneIsAvailable(&available) != 0)
|
2011-11-16 10:33:53 +00:00
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
|
2011-11-16 10:33:53 +00:00
|
|
|
"Init() failed to check microphone availability, trying to "
|
|
|
|
|
"initialize microphone anyway");
|
|
|
|
|
}
|
|
|
|
|
else if (!available)
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
|
2011-11-16 10:33:53 +00:00
|
|
|
"Init() microphone not available, trying to initialize "
|
|
|
|
|
"microphone anyway");
|
|
|
|
|
}
|
2012-04-04 14:57:19 +00:00
|
|
|
if (_shared->audio_device()->InitMicrophone() != 0)
|
2011-11-16 10:33:53 +00:00
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
|
2011-11-16 10:33:53 +00:00
|
|
|
"Init() failed to initialize the microphone");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Set number of channels
|
2012-04-04 14:57:19 +00:00
|
|
|
if (_shared->audio_device()->StereoPlayoutIsAvailable(&available) != 0) {
|
|
|
|
|
_shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
|
|
|
|
|
"Init() failed to query stereo playout mode");
|
2012-01-31 12:22:14 +00:00
|
|
|
}
|
2012-04-04 14:57:19 +00:00
|
|
|
if (_shared->audio_device()->SetStereoPlayout(available) != 0)
|
2011-11-16 10:33:53 +00:00
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
|
2011-11-16 10:33:53 +00:00
|
|
|
"Init() failed to set mono/stereo playout mode");
|
|
|
|
|
}
|
2011-12-21 18:00:59 +00:00
|
|
|
|
|
|
|
|
// TODO(andrew): These functions don't tell us whether stereo recording
|
|
|
|
|
// is truly available. We simply set the AudioProcessing input to stereo
|
|
|
|
|
// here, because we have to wait until receiving the first frame to
|
|
|
|
|
// determine the actual number of channels anyway.
|
|
|
|
|
//
|
|
|
|
|
// These functions may be changed; tracked here:
|
|
|
|
|
// http://code.google.com/p/webrtc/issues/detail?id=204
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->audio_device()->StereoRecordingIsAvailable(&available);
|
|
|
|
|
if (_shared->audio_device()->SetStereoRecording(available) != 0)
|
2011-11-16 10:33:53 +00:00
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
|
2011-11-16 10:33:53 +00:00
|
|
|
"Init() failed to set mono/stereo recording mode");
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-05 01:12:49 +00:00
|
|
|
if (!audioproc) {
|
|
|
|
|
audioproc = AudioProcessing::Create(VoEId(_shared->instance_id(), -1));
|
|
|
|
|
if (!audioproc) {
|
|
|
|
|
LOG(LS_ERROR) << "Failed to create AudioProcessing.";
|
|
|
|
|
_shared->SetLastError(VE_NO_MEMORY);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_shared->set_audio_processing(audioproc);
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2013-03-05 01:12:49 +00:00
|
|
|
// Set the error state for any failures in this block.
|
|
|
|
|
_shared->SetLastError(VE_APM_ERROR);
|
|
|
|
|
if (audioproc->echo_cancellation()->set_device_sample_rate_hz(48000)) {
|
|
|
|
|
LOG_FERR1(LS_ERROR, set_device_sample_rate_hz, 48000);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
// Assume 16 kHz mono until the audio frames are received from the capture
|
|
|
|
|
// device, at which point this can be updated.
|
|
|
|
|
if (audioproc->set_sample_rate_hz(16000)) {
|
|
|
|
|
LOG_FERR1(LS_ERROR, set_sample_rate_hz, 16000);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
if (audioproc->set_num_channels(1, 1) != 0) {
|
|
|
|
|
LOG_FERR2(LS_ERROR, set_num_channels, 1, 1);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
if (audioproc->set_num_reverse_channels(1) != 0) {
|
|
|
|
|
LOG_FERR1(LS_ERROR, set_num_reverse_channels, 1);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2013-03-05 01:12:49 +00:00
|
|
|
// Configure AudioProcessing components. All are disabled by default.
|
|
|
|
|
if (audioproc->high_pass_filter()->Enable(true) != 0) {
|
|
|
|
|
LOG_FERR1(LS_ERROR, high_pass_filter()->Enable, true);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
if (audioproc->echo_cancellation()->enable_drift_compensation(false) != 0) {
|
|
|
|
|
LOG_FERR1(LS_ERROR, enable_drift_compensation, false);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
if (audioproc->noise_suppression()->set_level(kDefaultNsMode) != 0) {
|
|
|
|
|
LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
GainControl* agc = audioproc->gain_control();
|
|
|
|
|
if (agc->set_analog_level_limits(kMinVolumeLevel, kMaxVolumeLevel) != 0) {
|
|
|
|
|
LOG_FERR2(LS_ERROR, agc->set_analog_level_limits, kMinVolumeLevel,
|
|
|
|
|
kMaxVolumeLevel);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
if (agc->set_mode(kDefaultAgcMode) != 0) {
|
|
|
|
|
LOG_FERR1(LS_ERROR, agc->set_mode, kDefaultAgcMode);
|
|
|
|
|
return -1;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
2013-03-05 01:12:49 +00:00
|
|
|
if (agc->Enable(kDefaultAgcState) != 0) {
|
|
|
|
|
LOG_FERR1(LS_ERROR, agc->Enable, kDefaultAgcState);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
_shared->SetLastError(0); // Clear error state.
|
2011-07-07 08:21:25 +00:00
|
|
|
|
|
|
|
|
#ifdef WEBRTC_VOICE_ENGINE_AGC
|
2013-03-05 01:12:49 +00:00
|
|
|
bool agc_enabled = agc->mode() == GainControl::kAdaptiveAnalog &&
|
|
|
|
|
agc->is_enabled();
|
|
|
|
|
if (_shared->audio_device()->SetAGC(agc_enabled) != 0) {
|
|
|
|
|
LOG_FERR1(LS_ERROR, audio_device()->SetAGC, agc_enabled);
|
|
|
|
|
_shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR);
|
2013-03-05 23:36:10 +00:00
|
|
|
// TODO(ajm): No error return here due to
|
|
|
|
|
// https://code.google.com/p/webrtc/issues/detail?id=1464
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2012-04-04 14:57:19 +00:00
|
|
|
return _shared->statistics().SetInitialized();
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int VoEBaseImpl::Terminate()
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
2011-07-07 08:21:25 +00:00
|
|
|
"Terminate()");
|
2012-04-04 14:57:19 +00:00
|
|
|
CriticalSectionScoped cs(_shared->crit_sec());
|
2011-07-07 08:21:25 +00:00
|
|
|
return TerminateInternal();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int VoEBaseImpl::MaxNumOfChannels()
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
2011-07-07 08:21:25 +00:00
|
|
|
"MaxNumOfChannels()");
|
2012-04-04 14:57:19 +00:00
|
|
|
WebRtc_Word32 maxNumOfChannels =
|
|
|
|
|
_shared->channel_manager().MaxNumOfChannels();
|
|
|
|
|
WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
|
|
|
|
|
VoEId(_shared->instance_id(), -1),
|
|
|
|
|
"MaxNumOfChannels() => %d", maxNumOfChannels);
|
2011-07-07 08:21:25 +00:00
|
|
|
return (maxNumOfChannels);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int VoEBaseImpl::CreateChannel()
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
2011-07-07 08:21:25 +00:00
|
|
|
"CreateChannel()");
|
2012-04-04 14:57:19 +00:00
|
|
|
CriticalSectionScoped cs(_shared->crit_sec());
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2012-04-04 14:57:19 +00:00
|
|
|
if (!_shared->statistics().Initialized())
|
2011-07-07 08:21:25 +00:00
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
2011-07-07 08:21:25 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WebRtc_Word32 channelId = -1;
|
|
|
|
|
|
2012-04-04 14:57:19 +00:00
|
|
|
if (!_shared->channel_manager().CreateChannel(channelId))
|
2011-07-07 08:21:25 +00:00
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_CHANNEL_NOT_CREATED, kTraceError,
|
|
|
|
|
"CreateChannel() failed to allocate memory for channel");
|
2011-07-07 08:21:25 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool destroyChannel(false);
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
voe::ScopedChannel sc(_shared->channel_manager(), channelId);
|
2011-07-07 08:21:25 +00:00
|
|
|
voe::Channel* channelPtr = sc.ChannelPtr();
|
|
|
|
|
if (channelPtr == NULL)
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_CHANNEL_NOT_CREATED, kTraceError,
|
|
|
|
|
"CreateChannel() failed to allocate memory for channel");
|
2011-07-07 08:21:25 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
2012-04-04 14:57:19 +00:00
|
|
|
else if (channelPtr->SetEngineInformation(_shared->statistics(),
|
|
|
|
|
*_shared->output_mixer(),
|
|
|
|
|
*_shared->transmit_mixer(),
|
|
|
|
|
*_shared->process_thread(),
|
|
|
|
|
*_shared->audio_device(),
|
2011-07-07 08:21:25 +00:00
|
|
|
_voiceEngineObserverPtr,
|
|
|
|
|
&_callbackCritSect) != 0)
|
|
|
|
|
{
|
|
|
|
|
destroyChannel = true;
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_CHANNEL_NOT_CREATED, kTraceError,
|
|
|
|
|
"CreateChannel() failed to associate engine and channel."
|
|
|
|
|
" Destroying channel.");
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
else if (channelPtr->Init() != 0)
|
|
|
|
|
{
|
|
|
|
|
destroyChannel = true;
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_CHANNEL_NOT_CREATED, kTraceError,
|
|
|
|
|
"CreateChannel() failed to initialize channel. Destroying"
|
|
|
|
|
" channel.");
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (destroyChannel)
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->channel_manager().DestroyChannel(channelId);
|
2011-07-07 08:21:25 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
2012-04-04 14:57:19 +00:00
|
|
|
WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
|
|
|
|
|
VoEId(_shared->instance_id(), -1),
|
|
|
|
|
"CreateChannel() => %d", channelId);
|
2011-07-07 08:21:25 +00:00
|
|
|
return channelId;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int VoEBaseImpl::DeleteChannel(int channel)
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
2011-07-07 08:21:25 +00:00
|
|
|
"DeleteChannel(channel=%d)", channel);
|
2012-04-04 14:57:19 +00:00
|
|
|
CriticalSectionScoped cs(_shared->crit_sec());
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2012-04-04 14:57:19 +00:00
|
|
|
if (!_shared->statistics().Initialized())
|
2011-07-07 08:21:25 +00:00
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
2011-07-07 08:21:25 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
voe::ScopedChannel sc(_shared->channel_manager(), channel);
|
2011-07-07 08:21:25 +00:00
|
|
|
voe::Channel* channelPtr = sc.ChannelPtr();
|
|
|
|
|
if (channelPtr == NULL)
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
|
|
|
|
|
"DeleteChannel() failed to locate channel");
|
2011-07-07 08:21:25 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-04-04 14:57:19 +00:00
|
|
|
if (_shared->channel_manager().DestroyChannel(channel) != 0)
|
2011-07-07 08:21:25 +00:00
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
|
|
|
|
|
"DeleteChannel() failed to destroy channel");
|
2011-07-07 08:21:25 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (StopSend() != 0)
|
|
|
|
|
{
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (StopPlayout() != 0)
|
|
|
|
|
{
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2013-03-13 23:20:57 +00:00
|
|
|
|
2011-07-07 08:21:25 +00:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int VoEBaseImpl::StartReceive(int channel)
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
2011-07-07 08:21:25 +00:00
|
|
|
"StartReceive(channel=%d)", channel);
|
2012-04-04 14:57:19 +00:00
|
|
|
CriticalSectionScoped cs(_shared->crit_sec());
|
|
|
|
|
if (!_shared->statistics().Initialized())
|
2011-07-07 08:21:25 +00:00
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
2011-07-07 08:21:25 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
2012-04-04 14:57:19 +00:00
|
|
|
voe::ScopedChannel sc(_shared->channel_manager(), channel);
|
2011-07-07 08:21:25 +00:00
|
|
|
voe::Channel* channelPtr = sc.ChannelPtr();
|
|
|
|
|
if (channelPtr == NULL)
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
|
|
|
|
|
"StartReceive() failed to locate channel");
|
2011-07-07 08:21:25 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
return channelPtr->StartReceiving();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int VoEBaseImpl::StopReceive(int channel)
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
2011-07-07 08:21:25 +00:00
|
|
|
"StopListen(channel=%d)", channel);
|
2012-04-04 14:57:19 +00:00
|
|
|
CriticalSectionScoped cs(_shared->crit_sec());
|
|
|
|
|
if (!_shared->statistics().Initialized())
|
2011-07-07 08:21:25 +00:00
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
2011-07-07 08:21:25 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
2012-04-04 14:57:19 +00:00
|
|
|
voe::ScopedChannel sc(_shared->channel_manager(), channel);
|
2011-07-07 08:21:25 +00:00
|
|
|
voe::Channel* channelPtr = sc.ChannelPtr();
|
|
|
|
|
if (channelPtr == NULL)
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
|
|
|
|
|
"SetLocalReceiver() failed to locate channel");
|
2011-07-07 08:21:25 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
return channelPtr->StopReceiving();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int VoEBaseImpl::StartPlayout(int channel)
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
2011-07-07 08:21:25 +00:00
|
|
|
"StartPlayout(channel=%d)", channel);
|
2012-04-04 14:57:19 +00:00
|
|
|
CriticalSectionScoped cs(_shared->crit_sec());
|
|
|
|
|
if (!_shared->statistics().Initialized())
|
2011-07-07 08:21:25 +00:00
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
2011-07-07 08:21:25 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
2012-04-04 14:57:19 +00:00
|
|
|
voe::ScopedChannel sc(_shared->channel_manager(), channel);
|
2011-07-07 08:21:25 +00:00
|
|
|
voe::Channel* channelPtr = sc.ChannelPtr();
|
|
|
|
|
if (channelPtr == NULL)
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
|
|
|
|
|
"StartPlayout() failed to locate channel");
|
2011-07-07 08:21:25 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
if (channelPtr->Playing())
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (StartPlayout() != 0)
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
|
|
|
|
|
"StartPlayout() failed to start playout");
|
2011-07-07 08:21:25 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
return channelPtr->StartPlayout();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int VoEBaseImpl::StopPlayout(int channel)
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
2011-07-07 08:21:25 +00:00
|
|
|
"StopPlayout(channel=%d)", channel);
|
2012-04-04 14:57:19 +00:00
|
|
|
CriticalSectionScoped cs(_shared->crit_sec());
|
|
|
|
|
if (!_shared->statistics().Initialized())
|
2011-07-07 08:21:25 +00:00
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
2011-07-07 08:21:25 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
2012-04-04 14:57:19 +00:00
|
|
|
voe::ScopedChannel sc(_shared->channel_manager(), channel);
|
2011-07-07 08:21:25 +00:00
|
|
|
voe::Channel* channelPtr = sc.ChannelPtr();
|
|
|
|
|
if (channelPtr == NULL)
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
|
|
|
|
|
"StopPlayout() failed to locate channel");
|
2011-07-07 08:21:25 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
if (channelPtr->StopPlayout() != 0)
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
WEBRTC_TRACE(kTraceWarning, kTraceVoice,
|
|
|
|
|
VoEId(_shared->instance_id(), -1),
|
|
|
|
|
"StopPlayout() failed to stop playout for channel %d", channel);
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
return StopPlayout();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int VoEBaseImpl::StartSend(int channel)
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
2011-07-07 08:21:25 +00:00
|
|
|
"StartSend(channel=%d)", channel);
|
2012-04-04 14:57:19 +00:00
|
|
|
CriticalSectionScoped cs(_shared->crit_sec());
|
|
|
|
|
if (!_shared->statistics().Initialized())
|
2011-07-07 08:21:25 +00:00
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
2011-07-07 08:21:25 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
2012-04-04 14:57:19 +00:00
|
|
|
voe::ScopedChannel sc(_shared->channel_manager(), channel);
|
2011-07-07 08:21:25 +00:00
|
|
|
voe::Channel* channelPtr = sc.ChannelPtr();
|
|
|
|
|
if (channelPtr == NULL)
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
|
|
|
|
|
"StartSend() failed to locate channel");
|
2011-07-07 08:21:25 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
if (channelPtr->Sending())
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (StartSend() != 0)
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
|
|
|
|
|
"StartSend() failed to start recording");
|
2011-07-07 08:21:25 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
return channelPtr->StartSend();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int VoEBaseImpl::StopSend(int channel)
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
2011-07-07 08:21:25 +00:00
|
|
|
"StopSend(channel=%d)", channel);
|
2012-04-04 14:57:19 +00:00
|
|
|
CriticalSectionScoped cs(_shared->crit_sec());
|
|
|
|
|
if (!_shared->statistics().Initialized())
|
2011-07-07 08:21:25 +00:00
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
2011-07-07 08:21:25 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
2012-04-04 14:57:19 +00:00
|
|
|
voe::ScopedChannel sc(_shared->channel_manager(), channel);
|
2011-07-07 08:21:25 +00:00
|
|
|
voe::Channel* channelPtr = sc.ChannelPtr();
|
|
|
|
|
if (channelPtr == NULL)
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
|
|
|
|
|
"StopSend() failed to locate channel");
|
2011-07-07 08:21:25 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
if (channelPtr->StopSend() != 0)
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
WEBRTC_TRACE(kTraceWarning, kTraceVoice,
|
|
|
|
|
VoEId(_shared->instance_id(), -1),
|
|
|
|
|
"StopSend() failed to stop sending for channel %d", channel);
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
return StopSend();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int VoEBaseImpl::GetVersion(char version[1024])
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
2011-07-07 08:21:25 +00:00
|
|
|
"GetVersion(version=?)");
|
|
|
|
|
assert(kVoiceEngineVersionMaxMessageSize == 1024);
|
|
|
|
|
|
|
|
|
|
if (version == NULL)
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError);
|
2011-07-07 08:21:25 +00:00
|
|
|
return (-1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char versionBuf[kVoiceEngineVersionMaxMessageSize];
|
|
|
|
|
char* versionPtr = versionBuf;
|
|
|
|
|
|
|
|
|
|
WebRtc_Word32 len = 0;
|
|
|
|
|
WebRtc_Word32 accLen = 0;
|
|
|
|
|
|
|
|
|
|
len = AddVoEVersion(versionPtr);
|
|
|
|
|
if (len == -1)
|
|
|
|
|
{
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
versionPtr += len;
|
|
|
|
|
accLen += len;
|
|
|
|
|
assert(accLen < kVoiceEngineVersionMaxMessageSize);
|
|
|
|
|
|
|
|
|
|
len = AddBuildInfo(versionPtr);
|
|
|
|
|
if (len == -1)
|
|
|
|
|
{
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
versionPtr += len;
|
|
|
|
|
accLen += len;
|
|
|
|
|
assert(accLen < kVoiceEngineVersionMaxMessageSize);
|
|
|
|
|
|
2013-03-13 23:20:57 +00:00
|
|
|
#ifdef WEBRTC_EXTERNAL_TRANSPORT
|
|
|
|
|
len = AddExternalTransportBuild(versionPtr);
|
|
|
|
|
if (len == -1)
|
|
|
|
|
{
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
versionPtr += len;
|
|
|
|
|
accLen += len;
|
|
|
|
|
assert(accLen < kVoiceEngineVersionMaxMessageSize);
|
|
|
|
|
#endif
|
2011-07-07 08:21:25 +00:00
|
|
|
#ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT
|
|
|
|
|
len = AddExternalRecAndPlayoutBuild(versionPtr);
|
|
|
|
|
if (len == -1)
|
|
|
|
|
{
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
versionPtr += len;
|
|
|
|
|
accLen += len;
|
|
|
|
|
assert(accLen < kVoiceEngineVersionMaxMessageSize);
|
2012-01-04 15:00:12 +00:00
|
|
|
#endif
|
2011-07-07 08:21:25 +00:00
|
|
|
|
|
|
|
|
memcpy(version, versionBuf, accLen);
|
|
|
|
|
version[accLen] = '\0';
|
|
|
|
|
|
|
|
|
|
// to avoid the truncation in the trace, split the string into parts
|
|
|
|
|
char partOfVersion[256];
|
2012-04-04 14:57:19 +00:00
|
|
|
WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
|
|
|
|
|
VoEId(_shared->instance_id(), -1), "GetVersion() =>");
|
2011-07-07 08:21:25 +00:00
|
|
|
for (int partStart = 0; partStart < accLen;)
|
|
|
|
|
{
|
|
|
|
|
memset(partOfVersion, 0, sizeof(partOfVersion));
|
|
|
|
|
int partEnd = partStart + 180;
|
|
|
|
|
while (version[partEnd] != '\n' && version[partEnd] != '\0')
|
|
|
|
|
{
|
|
|
|
|
partEnd--;
|
|
|
|
|
}
|
|
|
|
|
if (partEnd < accLen)
|
|
|
|
|
{
|
|
|
|
|
memcpy(partOfVersion, &version[partStart], partEnd - partStart);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
memcpy(partOfVersion, &version[partStart], accLen - partStart);
|
|
|
|
|
}
|
|
|
|
|
partStart = partEnd;
|
2012-04-04 14:57:19 +00:00
|
|
|
WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
|
|
|
|
|
VoEId(_shared->instance_id(), -1), "%s", partOfVersion);
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WebRtc_Word32 VoEBaseImpl::AddBuildInfo(char* str) const
|
|
|
|
|
{
|
2012-04-24 14:50:50 +00:00
|
|
|
return sprintf(str, "Build: svn:%s %s\n", WEBRTC_SVNREVISION, BUILDINFO);
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WebRtc_Word32 VoEBaseImpl::AddVoEVersion(char* str) const
|
|
|
|
|
{
|
|
|
|
|
return sprintf(str, "VoiceEngine 4.1.0\n");
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-13 23:20:57 +00:00
|
|
|
#ifdef WEBRTC_EXTERNAL_TRANSPORT
|
|
|
|
|
WebRtc_Word32 VoEBaseImpl::AddExternalTransportBuild(char* str) const
|
|
|
|
|
{
|
|
|
|
|
return sprintf(str, "External transport build\n");
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2011-07-07 08:21:25 +00:00
|
|
|
#ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT
|
|
|
|
|
WebRtc_Word32 VoEBaseImpl::AddExternalRecAndPlayoutBuild(char* str) const
|
|
|
|
|
{
|
|
|
|
|
return sprintf(str, "External recording and playout build\n");
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
int VoEBaseImpl::LastError()
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
2011-07-07 08:21:25 +00:00
|
|
|
"LastError()");
|
2012-04-04 14:57:19 +00:00
|
|
|
return (_shared->statistics().LastError());
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int VoEBaseImpl::SetNetEQPlayoutMode(int channel, NetEqModes mode)
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
2011-07-07 08:21:25 +00:00
|
|
|
"SetNetEQPlayoutMode(channel=%i, mode=%i)", channel, mode);
|
2012-04-04 14:57:19 +00:00
|
|
|
if (!_shared->statistics().Initialized())
|
2011-07-07 08:21:25 +00:00
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
2011-07-07 08:21:25 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
2012-04-04 14:57:19 +00:00
|
|
|
voe::ScopedChannel sc(_shared->channel_manager(), channel);
|
2011-07-07 08:21:25 +00:00
|
|
|
voe::Channel* channelPtr = sc.ChannelPtr();
|
|
|
|
|
if (channelPtr == NULL)
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
|
|
|
|
|
"SetNetEQPlayoutMode() failed to locate channel");
|
2011-07-07 08:21:25 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
return channelPtr->SetNetEQPlayoutMode(mode);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int VoEBaseImpl::GetNetEQPlayoutMode(int channel, NetEqModes& mode)
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
2011-07-07 08:21:25 +00:00
|
|
|
"GetNetEQPlayoutMode(channel=%i, mode=?)", channel);
|
2012-04-04 14:57:19 +00:00
|
|
|
if (!_shared->statistics().Initialized())
|
2011-07-07 08:21:25 +00:00
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
2011-07-07 08:21:25 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
2012-04-04 14:57:19 +00:00
|
|
|
voe::ScopedChannel sc(_shared->channel_manager(), channel);
|
2011-07-07 08:21:25 +00:00
|
|
|
voe::Channel* channelPtr = sc.ChannelPtr();
|
|
|
|
|
if (channelPtr == NULL)
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
|
|
|
|
|
"GetNetEQPlayoutMode() failed to locate channel");
|
2011-07-07 08:21:25 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
return channelPtr->GetNetEQPlayoutMode(mode);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int VoEBaseImpl::SetOnHoldStatus(int channel, bool enable, OnHoldModes mode)
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
2011-07-07 08:21:25 +00:00
|
|
|
"SetOnHoldStatus(channel=%d, enable=%d, mode=%d)", channel,
|
|
|
|
|
enable, mode);
|
2012-04-04 14:57:19 +00:00
|
|
|
if (!_shared->statistics().Initialized())
|
2011-07-07 08:21:25 +00:00
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
2011-07-07 08:21:25 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
2012-04-04 14:57:19 +00:00
|
|
|
voe::ScopedChannel sc(_shared->channel_manager(), channel);
|
2011-07-07 08:21:25 +00:00
|
|
|
voe::Channel* channelPtr = sc.ChannelPtr();
|
|
|
|
|
if (channelPtr == NULL)
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
|
|
|
|
|
"SetOnHoldStatus() failed to locate channel");
|
2011-07-07 08:21:25 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
return channelPtr->SetOnHoldStatus(enable, mode);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int VoEBaseImpl::GetOnHoldStatus(int channel, bool& enabled, OnHoldModes& mode)
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
2011-07-07 08:21:25 +00:00
|
|
|
"GetOnHoldStatus(channel=%d, enabled=?, mode=?)", channel);
|
2012-04-04 14:57:19 +00:00
|
|
|
if (!_shared->statistics().Initialized())
|
2011-07-07 08:21:25 +00:00
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
2011-07-07 08:21:25 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
2012-04-04 14:57:19 +00:00
|
|
|
voe::ScopedChannel sc(_shared->channel_manager(), channel);
|
2011-07-07 08:21:25 +00:00
|
|
|
voe::Channel* channelPtr = sc.ChannelPtr();
|
|
|
|
|
if (channelPtr == NULL)
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
|
|
|
|
|
"GetOnHoldStatus() failed to locate channel");
|
2011-07-07 08:21:25 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
return channelPtr->GetOnHoldStatus(enabled, mode);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WebRtc_Word32 VoEBaseImpl::StartPlayout()
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
2011-07-07 08:21:25 +00:00
|
|
|
"VoEBaseImpl::StartPlayout()");
|
2012-04-04 14:57:19 +00:00
|
|
|
if (_shared->audio_device()->Playing())
|
2011-07-07 08:21:25 +00:00
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2012-04-04 14:57:19 +00:00
|
|
|
if (!_shared->ext_playout())
|
2011-07-07 08:21:25 +00:00
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
if (_shared->audio_device()->InitPlayout() != 0)
|
2011-07-07 08:21:25 +00:00
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
WEBRTC_TRACE(kTraceError, kTraceVoice,
|
|
|
|
|
VoEId(_shared->instance_id(), -1),
|
|
|
|
|
"StartPlayout() failed to initialize playout");
|
2011-07-07 08:21:25 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
2012-04-04 14:57:19 +00:00
|
|
|
if (_shared->audio_device()->StartPlayout() != 0)
|
2011-07-07 08:21:25 +00:00
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
WEBRTC_TRACE(kTraceError, kTraceVoice,
|
|
|
|
|
VoEId(_shared->instance_id(), -1),
|
|
|
|
|
"StartPlayout() failed to start playout");
|
2011-07-07 08:21:25 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WebRtc_Word32 VoEBaseImpl::StopPlayout()
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
2011-07-07 08:21:25 +00:00
|
|
|
"VoEBaseImpl::StopPlayout()");
|
|
|
|
|
|
2012-04-04 14:57:19 +00:00
|
|
|
WebRtc_Word32 numOfChannels = _shared->channel_manager().NumOfChannels();
|
2011-07-07 08:21:25 +00:00
|
|
|
if (numOfChannels <= 0)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WebRtc_UWord16 nChannelsPlaying(0);
|
|
|
|
|
WebRtc_Word32* channelsArray = new WebRtc_Word32[numOfChannels];
|
|
|
|
|
|
|
|
|
|
// Get number of playing channels
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->channel_manager().GetChannelIds(channelsArray, numOfChannels);
|
2011-07-07 08:21:25 +00:00
|
|
|
for (int i = 0; i < numOfChannels; i++)
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
voe::ScopedChannel sc(_shared->channel_manager(), channelsArray[i]);
|
2011-07-07 08:21:25 +00:00
|
|
|
voe::Channel* chPtr = sc.ChannelPtr();
|
|
|
|
|
if (chPtr)
|
|
|
|
|
{
|
|
|
|
|
if (chPtr->Playing())
|
|
|
|
|
{
|
|
|
|
|
nChannelsPlaying++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
delete[] channelsArray;
|
|
|
|
|
|
|
|
|
|
// Stop audio-device playing if no channel is playing out
|
|
|
|
|
if (nChannelsPlaying == 0)
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
if (_shared->audio_device()->StopPlayout() != 0)
|
2011-07-07 08:21:25 +00:00
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_CANNOT_STOP_PLAYOUT, kTraceError,
|
|
|
|
|
"StopPlayout() failed to stop playout");
|
2011-07-07 08:21:25 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WebRtc_Word32 VoEBaseImpl::StartSend()
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
2011-07-07 08:21:25 +00:00
|
|
|
"VoEBaseImpl::StartSend()");
|
2012-04-04 14:57:19 +00:00
|
|
|
if (_shared->audio_device()->Recording())
|
2011-07-07 08:21:25 +00:00
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2012-04-04 14:57:19 +00:00
|
|
|
if (!_shared->ext_recording())
|
2011-07-07 08:21:25 +00:00
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
if (_shared->audio_device()->InitRecording() != 0)
|
2011-07-07 08:21:25 +00:00
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
WEBRTC_TRACE(kTraceError, kTraceVoice,
|
|
|
|
|
VoEId(_shared->instance_id(), -1),
|
|
|
|
|
"StartSend() failed to initialize recording");
|
2011-07-07 08:21:25 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
2012-04-04 14:57:19 +00:00
|
|
|
if (_shared->audio_device()->StartRecording() != 0)
|
2011-07-07 08:21:25 +00:00
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
WEBRTC_TRACE(kTraceError, kTraceVoice,
|
|
|
|
|
VoEId(_shared->instance_id(), -1),
|
|
|
|
|
"StartSend() failed to start recording");
|
2011-07-07 08:21:25 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WebRtc_Word32 VoEBaseImpl::StopSend()
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
2011-07-07 08:21:25 +00:00
|
|
|
"VoEBaseImpl::StopSend()");
|
|
|
|
|
|
2012-04-04 14:57:19 +00:00
|
|
|
if (_shared->NumOfSendingChannels() == 0 &&
|
|
|
|
|
!_shared->transmit_mixer()->IsRecordingMic())
|
2011-07-07 08:21:25 +00:00
|
|
|
{
|
|
|
|
|
// Stop audio-device recording if no channel is recording
|
2012-04-04 14:57:19 +00:00
|
|
|
if (_shared->audio_device()->StopRecording() != 0)
|
2011-07-07 08:21:25 +00:00
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_CANNOT_STOP_RECORDING, kTraceError,
|
|
|
|
|
"StopSend() failed to stop recording");
|
2011-07-07 08:21:25 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->transmit_mixer()->StopSend();
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WebRtc_Word32 VoEBaseImpl::TerminateInternal()
|
|
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
2011-07-07 08:21:25 +00:00
|
|
|
"VoEBaseImpl::TerminateInternal()");
|
|
|
|
|
|
|
|
|
|
// Delete any remaining channel objects
|
2012-04-04 14:57:19 +00:00
|
|
|
WebRtc_Word32 numOfChannels = _shared->channel_manager().NumOfChannels();
|
2011-07-07 08:21:25 +00:00
|
|
|
if (numOfChannels > 0)
|
|
|
|
|
{
|
|
|
|
|
WebRtc_Word32* channelsArray = new WebRtc_Word32[numOfChannels];
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->channel_manager().GetChannelIds(channelsArray, numOfChannels);
|
2011-07-07 08:21:25 +00:00
|
|
|
for (int i = 0; i < numOfChannels; i++)
|
|
|
|
|
{
|
|
|
|
|
DeleteChannel(channelsArray[i]);
|
|
|
|
|
}
|
|
|
|
|
delete[] channelsArray;
|
|
|
|
|
}
|
|
|
|
|
|
2012-04-04 14:57:19 +00:00
|
|
|
if (_shared->process_thread())
|
2011-07-07 08:21:25 +00:00
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
if (_shared->audio_device())
|
2011-07-07 08:21:25 +00:00
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
if (_shared->process_thread()->
|
|
|
|
|
DeRegisterModule(_shared->audio_device()) != 0)
|
2011-07-07 08:21:25 +00:00
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_THREAD_ERROR, kTraceError,
|
|
|
|
|
"TerminateInternal() failed to deregister ADM");
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
}
|
2012-04-04 14:57:19 +00:00
|
|
|
if (_shared->process_thread()->Stop() != 0)
|
2011-07-07 08:21:25 +00:00
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_THREAD_ERROR, kTraceError,
|
|
|
|
|
"TerminateInternal() failed to stop module process thread");
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-05 01:12:49 +00:00
|
|
|
if (_shared->audio_device())
|
2011-07-07 08:21:25 +00:00
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
if (_shared->audio_device()->StopPlayout() != 0)
|
2011-07-07 08:21:25 +00:00
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
|
|
|
|
|
"TerminateInternal() failed to stop playout");
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
2012-04-04 14:57:19 +00:00
|
|
|
if (_shared->audio_device()->StopRecording() != 0)
|
2011-07-07 08:21:25 +00:00
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
|
|
|
|
|
"TerminateInternal() failed to stop recording");
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
2012-04-04 14:57:19 +00:00
|
|
|
if (_shared->audio_device()->RegisterEventObserver(NULL) != 0) {
|
|
|
|
|
_shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
|
|
|
|
|
"TerminateInternal() failed to de-register event observer "
|
|
|
|
|
"for the ADM");
|
2012-01-31 12:22:14 +00:00
|
|
|
}
|
2012-04-04 14:57:19 +00:00
|
|
|
if (_shared->audio_device()->RegisterAudioCallback(NULL) != 0) {
|
|
|
|
|
_shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
|
|
|
|
|
"TerminateInternal() failed to de-register audio callback "
|
|
|
|
|
"for the ADM");
|
2012-01-31 12:22:14 +00:00
|
|
|
}
|
2012-04-04 14:57:19 +00:00
|
|
|
if (_shared->audio_device()->Terminate() != 0)
|
2011-07-07 08:21:25 +00:00
|
|
|
{
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
|
|
|
|
|
"TerminateInternal() failed to terminate the ADM");
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->set_audio_device(NULL);
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2013-03-05 01:12:49 +00:00
|
|
|
if (_shared->audio_processing()) {
|
2012-04-04 14:57:19 +00:00
|
|
|
_shared->set_audio_processing(NULL);
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2012-04-04 14:57:19 +00:00
|
|
|
return _shared->statistics().SetUnInitialized();
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace webrtc
|