
The complexity of the last ChannelManager and potentially usage of it as well caused race conditions and deadlocks in loopback voe_auto_test. This ref-counted solution takes no long-term locks, uses less locks overall and is significantly easier to understand. ScopedChannel has been split up into a ChannelOwner with a reference to a channel and an Iterator over ChannelManager. Previous code was really used for both things. ChannelOwner is used as a shared pointer to a channel object, while an Iterator should work as expected. BUG=2081 R=tommi@webrtc.org, xians@webrtc.org Review URL: https://webrtc-codereview.appspot.com/1802004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@4502 4adac7df-926f-26a2-2b94-8c16560cd09d
1359 lines
45 KiB
C++
1359 lines
45 KiB
C++
/*
|
|
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
|
*
|
|
* 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 "webrtc/voice_engine/voe_file_impl.h"
|
|
|
|
#include "webrtc/modules/media_file/interface/media_file.h"
|
|
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
|
|
#include "webrtc/system_wrappers/interface/file_wrapper.h"
|
|
#include "webrtc/system_wrappers/interface/trace.h"
|
|
#include "webrtc/voice_engine/channel.h"
|
|
#include "webrtc/voice_engine/include/voe_errors.h"
|
|
#include "webrtc/voice_engine/output_mixer.h"
|
|
#include "webrtc/voice_engine/transmit_mixer.h"
|
|
#include "webrtc/voice_engine/voice_engine_impl.h"
|
|
|
|
namespace webrtc {
|
|
|
|
VoEFile* VoEFile::GetInterface(VoiceEngine* voiceEngine)
|
|
{
|
|
#ifndef WEBRTC_VOICE_ENGINE_FILE_API
|
|
return NULL;
|
|
#else
|
|
if (NULL == voiceEngine)
|
|
{
|
|
return NULL;
|
|
}
|
|
VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine);
|
|
s->AddRef();
|
|
return s;
|
|
#endif
|
|
}
|
|
|
|
#ifdef WEBRTC_VOICE_ENGINE_FILE_API
|
|
|
|
VoEFileImpl::VoEFileImpl(voe::SharedData* shared) : _shared(shared)
|
|
{
|
|
WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
|
"VoEFileImpl::VoEFileImpl() - ctor");
|
|
}
|
|
|
|
VoEFileImpl::~VoEFileImpl()
|
|
{
|
|
WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
|
"VoEFileImpl::~VoEFileImpl() - dtor");
|
|
}
|
|
|
|
int VoEFileImpl::StartPlayingFileLocally(
|
|
int channel,
|
|
const char fileNameUTF8[1024],
|
|
bool loop, FileFormats format,
|
|
float volumeScaling,
|
|
int startPointMs,
|
|
int stopPointMs)
|
|
{
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
|
"StartPlayingFileLocally(channel=%d, fileNameUTF8[]=%s, "
|
|
"loop=%d, format=%d, volumeScaling=%5.3f, startPointMs=%d,"
|
|
" stopPointMs=%d)",
|
|
channel, fileNameUTF8, loop, format, volumeScaling,
|
|
startPointMs, stopPointMs);
|
|
assert(1024 == FileWrapper::kMaxFileNameSize);
|
|
if (!_shared->statistics().Initialized())
|
|
{
|
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
|
return -1;
|
|
}
|
|
voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
|
|
voe::Channel* channelPtr = ch.channel();
|
|
if (channelPtr == NULL)
|
|
{
|
|
_shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
|
|
"StartPlayingFileLocally() failed to locate channel");
|
|
return -1;
|
|
}
|
|
|
|
return channelPtr->StartPlayingFileLocally(fileNameUTF8,
|
|
loop,
|
|
format,
|
|
startPointMs,
|
|
volumeScaling,
|
|
stopPointMs,
|
|
NULL);
|
|
}
|
|
|
|
int VoEFileImpl::StartPlayingFileLocally(int channel,
|
|
InStream* stream,
|
|
FileFormats format,
|
|
float volumeScaling,
|
|
int startPointMs,
|
|
int stopPointMs)
|
|
{
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
|
"StartPlayingFileLocally(channel=%d, stream, format=%d, "
|
|
"volumeScaling=%5.3f, startPointMs=%d, stopPointMs=%d)",
|
|
channel, format, volumeScaling, startPointMs, stopPointMs);
|
|
|
|
if (!_shared->statistics().Initialized())
|
|
{
|
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
|
return -1;
|
|
}
|
|
|
|
voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
|
|
voe::Channel* channelPtr = ch.channel();
|
|
if (channelPtr == NULL)
|
|
{
|
|
_shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
|
|
"StartPlayingFileLocally() failed to locate channel");
|
|
return -1;
|
|
}
|
|
|
|
return channelPtr->StartPlayingFileLocally(stream,
|
|
format,
|
|
startPointMs,
|
|
volumeScaling,
|
|
stopPointMs,
|
|
NULL);
|
|
}
|
|
|
|
int VoEFileImpl::StopPlayingFileLocally(int channel)
|
|
{
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
|
"StopPlayingFileLocally()");
|
|
if (!_shared->statistics().Initialized())
|
|
{
|
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
|
return -1;
|
|
}
|
|
voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
|
|
voe::Channel* channelPtr = ch.channel();
|
|
if (channelPtr == NULL)
|
|
{
|
|
_shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
|
|
"StopPlayingFileLocally() failed to locate channel");
|
|
return -1;
|
|
}
|
|
return channelPtr->StopPlayingFileLocally();
|
|
}
|
|
|
|
int VoEFileImpl::IsPlayingFileLocally(int channel)
|
|
{
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
|
"IsPlayingFileLocally(channel=%d)", channel);
|
|
if (!_shared->statistics().Initialized())
|
|
{
|
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
|
return -1;
|
|
}
|
|
voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
|
|
voe::Channel* channelPtr = ch.channel();
|
|
if (channelPtr == NULL)
|
|
{
|
|
_shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
|
|
"StopPlayingFileLocally() failed to locate channel");
|
|
return -1;
|
|
}
|
|
return channelPtr->IsPlayingFileLocally();
|
|
}
|
|
|
|
int VoEFileImpl::ScaleLocalFilePlayout(int channel, float scale)
|
|
{
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
|
"ScaleLocalFilePlayout(channel=%d, scale=%5.3f)",
|
|
channel, scale);
|
|
if (!_shared->statistics().Initialized())
|
|
{
|
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
|
return -1;
|
|
}
|
|
voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
|
|
voe::Channel* channelPtr = ch.channel();
|
|
if (channelPtr == NULL)
|
|
{
|
|
_shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
|
|
"StopPlayingFileLocally() failed to locate channel");
|
|
return -1;
|
|
}
|
|
return channelPtr->ScaleLocalFilePlayout(scale);
|
|
}
|
|
|
|
int VoEFileImpl::StartPlayingFileAsMicrophone(int channel,
|
|
const char fileNameUTF8[1024],
|
|
bool loop,
|
|
bool mixWithMicrophone,
|
|
FileFormats format,
|
|
float volumeScaling)
|
|
{
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
|
"StartPlayingFileAsMicrophone(channel=%d, fileNameUTF8=%s, "
|
|
"loop=%d, mixWithMicrophone=%d, format=%d, "
|
|
"volumeScaling=%5.3f)",
|
|
channel, fileNameUTF8, loop, mixWithMicrophone, format,
|
|
volumeScaling);
|
|
assert(1024 == FileWrapper::kMaxFileNameSize);
|
|
if (!_shared->statistics().Initialized())
|
|
{
|
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
|
return -1;
|
|
}
|
|
|
|
const uint32_t startPointMs(0);
|
|
const uint32_t stopPointMs(0);
|
|
|
|
if (channel == -1)
|
|
{
|
|
int res = _shared->transmit_mixer()->StartPlayingFileAsMicrophone(
|
|
fileNameUTF8,
|
|
loop,
|
|
format,
|
|
startPointMs,
|
|
volumeScaling,
|
|
stopPointMs,
|
|
NULL);
|
|
if (res)
|
|
{
|
|
WEBRTC_TRACE(kTraceError, kTraceVoice,
|
|
VoEId(_shared->instance_id(), -1),
|
|
"StartPlayingFileAsMicrophone() failed to start playing file");
|
|
return(-1);
|
|
}
|
|
else
|
|
{
|
|
_shared->transmit_mixer()->SetMixWithMicStatus(mixWithMicrophone);
|
|
return(0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Add file after demultiplexing <=> affects one channel only
|
|
voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
|
|
voe::Channel* channelPtr = ch.channel();
|
|
if (channelPtr == NULL)
|
|
{
|
|
_shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
|
|
"StartPlayingFileAsMicrophone() failed to locate channel");
|
|
return -1;
|
|
}
|
|
|
|
int res = channelPtr->StartPlayingFileAsMicrophone(fileNameUTF8,
|
|
loop,
|
|
format,
|
|
startPointMs,
|
|
volumeScaling,
|
|
stopPointMs,
|
|
NULL);
|
|
if (res)
|
|
{
|
|
WEBRTC_TRACE(kTraceError, kTraceVoice,
|
|
VoEId(_shared->instance_id(), -1),
|
|
"StartPlayingFileAsMicrophone() failed to start playing file");
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
channelPtr->SetMixWithMicStatus(mixWithMicrophone);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
int VoEFileImpl::StartPlayingFileAsMicrophone(int channel,
|
|
InStream* stream,
|
|
bool mixWithMicrophone,
|
|
FileFormats format,
|
|
float volumeScaling)
|
|
{
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
|
"StartPlayingFileAsMicrophone(channel=%d, stream,"
|
|
" mixWithMicrophone=%d, format=%d, volumeScaling=%5.3f)",
|
|
channel, mixWithMicrophone, format, volumeScaling);
|
|
|
|
if (!_shared->statistics().Initialized())
|
|
{
|
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
|
return -1;
|
|
}
|
|
|
|
const uint32_t startPointMs(0);
|
|
const uint32_t stopPointMs(0);
|
|
|
|
if (channel == -1)
|
|
{
|
|
int res = _shared->transmit_mixer()->StartPlayingFileAsMicrophone(
|
|
stream,
|
|
format,
|
|
startPointMs,
|
|
volumeScaling,
|
|
stopPointMs,
|
|
NULL);
|
|
if (res)
|
|
{
|
|
WEBRTC_TRACE(kTraceError, kTraceVoice,
|
|
VoEId(_shared->instance_id(), -1),
|
|
"StartPlayingFileAsMicrophone() failed to start "
|
|
"playing stream");
|
|
return(-1);
|
|
}
|
|
else
|
|
{
|
|
_shared->transmit_mixer()->SetMixWithMicStatus(mixWithMicrophone);
|
|
return(0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Add file after demultiplexing <=> affects one channel only
|
|
voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
|
|
voe::Channel* channelPtr = ch.channel();
|
|
if (channelPtr == NULL)
|
|
{
|
|
_shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
|
|
"StartPlayingFileAsMicrophone() failed to locate channel");
|
|
return -1;
|
|
}
|
|
|
|
int res = channelPtr->StartPlayingFileAsMicrophone(
|
|
stream, format, startPointMs, volumeScaling, stopPointMs, NULL);
|
|
if (res)
|
|
{
|
|
WEBRTC_TRACE(kTraceError, kTraceVoice,
|
|
VoEId(_shared->instance_id(), -1),
|
|
"StartPlayingFileAsMicrophone() failed to start "
|
|
"playing stream");
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
channelPtr->SetMixWithMicStatus(mixWithMicrophone);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
int VoEFileImpl::StopPlayingFileAsMicrophone(int channel)
|
|
{
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
|
"StopPlayingFileAsMicrophone(channel=%d)", channel);
|
|
if (!_shared->statistics().Initialized())
|
|
{
|
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
|
return -1;
|
|
}
|
|
if (channel == -1)
|
|
{
|
|
// Stop adding file before demultiplexing <=> affects all channels
|
|
return _shared->transmit_mixer()->StopPlayingFileAsMicrophone();
|
|
}
|
|
else
|
|
{
|
|
// Stop adding file after demultiplexing <=> affects one channel only
|
|
voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
|
|
voe::Channel* channelPtr = ch.channel();
|
|
if (channelPtr == NULL)
|
|
{
|
|
_shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
|
|
"StopPlayingFileAsMicrophone() failed to locate channel");
|
|
return -1;
|
|
}
|
|
return channelPtr->StopPlayingFileAsMicrophone();
|
|
}
|
|
}
|
|
|
|
int VoEFileImpl::IsPlayingFileAsMicrophone(int channel)
|
|
{
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
|
"IsPlayingFileAsMicrophone(channel=%d)", channel);
|
|
if (!_shared->statistics().Initialized())
|
|
{
|
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
|
return -1;
|
|
}
|
|
if (channel == -1)
|
|
{
|
|
return _shared->transmit_mixer()->IsPlayingFileAsMicrophone();
|
|
}
|
|
else
|
|
{
|
|
// Stop adding file after demultiplexing <=> affects one channel only
|
|
voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
|
|
voe::Channel* channelPtr = ch.channel();
|
|
if (channelPtr == NULL)
|
|
{
|
|
_shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
|
|
"IsPlayingFileAsMicrophone() failed to locate channel");
|
|
return -1;
|
|
}
|
|
return channelPtr->IsPlayingFileAsMicrophone();
|
|
}
|
|
}
|
|
|
|
int VoEFileImpl::ScaleFileAsMicrophonePlayout(int channel, float scale)
|
|
{
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
|
"ScaleFileAsMicrophonePlayout(channel=%d, scale=%5.3f)",
|
|
channel, scale);
|
|
|
|
if (!_shared->statistics().Initialized())
|
|
{
|
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
|
return -1;
|
|
}
|
|
if (channel == -1)
|
|
{
|
|
return _shared->transmit_mixer()->ScaleFileAsMicrophonePlayout(scale);
|
|
}
|
|
else
|
|
{
|
|
// Stop adding file after demultiplexing <=> affects one channel only
|
|
voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
|
|
voe::Channel* channelPtr = ch.channel();
|
|
if (channelPtr == NULL)
|
|
{
|
|
_shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
|
|
"IsPlayingFileAsMicrophone() failed to locate channel");
|
|
return -1;
|
|
}
|
|
return channelPtr->ScaleFileAsMicrophonePlayout(scale);
|
|
}
|
|
}
|
|
|
|
int VoEFileImpl::StartRecordingPlayout(
|
|
int channel, const char* fileNameUTF8, CodecInst* compression,
|
|
int maxSizeBytes)
|
|
{
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
|
"StartRecordingPlayout(channel=%d, fileNameUTF8=%s, "
|
|
"compression, maxSizeBytes=%d)",
|
|
channel, fileNameUTF8, maxSizeBytes);
|
|
assert(1024 == FileWrapper::kMaxFileNameSize);
|
|
|
|
if (!_shared->statistics().Initialized())
|
|
{
|
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
|
return -1;
|
|
}
|
|
if (channel == -1)
|
|
{
|
|
return _shared->output_mixer()->StartRecordingPlayout
|
|
(fileNameUTF8, compression);
|
|
}
|
|
else
|
|
{
|
|
// Add file after demultiplexing <=> affects one channel only
|
|
voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
|
|
voe::Channel* channelPtr = ch.channel();
|
|
if (channelPtr == NULL)
|
|
{
|
|
_shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
|
|
"StartRecordingPlayout() failed to locate channel");
|
|
return -1;
|
|
}
|
|
return channelPtr->StartRecordingPlayout(fileNameUTF8, compression);
|
|
}
|
|
}
|
|
|
|
int VoEFileImpl::StartRecordingPlayout(
|
|
int channel, OutStream* stream, CodecInst* compression)
|
|
{
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
|
"StartRecordingPlayout(channel=%d, stream, compression)",
|
|
channel);
|
|
if (!_shared->statistics().Initialized())
|
|
{
|
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
|
return -1;
|
|
}
|
|
if (channel == -1)
|
|
{
|
|
return _shared->output_mixer()->
|
|
StartRecordingPlayout(stream, compression);
|
|
}
|
|
else
|
|
{
|
|
voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
|
|
voe::Channel* channelPtr = ch.channel();
|
|
if (channelPtr == NULL)
|
|
{
|
|
_shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
|
|
"StartRecordingPlayout() failed to locate channel");
|
|
return -1;
|
|
}
|
|
return channelPtr->StartRecordingPlayout(stream, compression);
|
|
}
|
|
}
|
|
|
|
int VoEFileImpl::StopRecordingPlayout(int channel)
|
|
{
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
|
"StopRecordingPlayout(channel=%d)", channel);
|
|
if (!_shared->statistics().Initialized())
|
|
{
|
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
|
return -1;
|
|
}
|
|
if (channel == -1)
|
|
{
|
|
return _shared->output_mixer()->StopRecordingPlayout();
|
|
}
|
|
else
|
|
{
|
|
voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
|
|
voe::Channel* channelPtr = ch.channel();
|
|
if (channelPtr == NULL)
|
|
{
|
|
_shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
|
|
"StopRecordingPlayout() failed to locate channel");
|
|
return -1;
|
|
}
|
|
return channelPtr->StopRecordingPlayout();
|
|
}
|
|
}
|
|
|
|
int VoEFileImpl::StartRecordingMicrophone(
|
|
const char* fileNameUTF8, CodecInst* compression, int maxSizeBytes)
|
|
{
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
|
"StartRecordingMicrophone(fileNameUTF8=%s, compression, "
|
|
"maxSizeBytes=%d)", fileNameUTF8, maxSizeBytes);
|
|
assert(1024 == FileWrapper::kMaxFileNameSize);
|
|
|
|
if (!_shared->statistics().Initialized())
|
|
{
|
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
|
return -1;
|
|
}
|
|
if (_shared->transmit_mixer()->StartRecordingMicrophone(fileNameUTF8,
|
|
compression))
|
|
{
|
|
WEBRTC_TRACE(kTraceError, kTraceVoice,
|
|
VoEId(_shared->instance_id(), -1),
|
|
"StartRecordingMicrophone() failed to start recording");
|
|
return -1;
|
|
}
|
|
if (_shared->audio_device()->Recording())
|
|
{
|
|
return 0;
|
|
}
|
|
if (!_shared->ext_recording())
|
|
{
|
|
if (_shared->audio_device()->InitRecording() != 0)
|
|
{
|
|
WEBRTC_TRACE(kTraceError, kTraceVoice,
|
|
VoEId(_shared->instance_id(), -1),
|
|
"StartRecordingMicrophone() failed to initialize recording");
|
|
return -1;
|
|
}
|
|
if (_shared->audio_device()->StartRecording() != 0)
|
|
{
|
|
WEBRTC_TRACE(kTraceError, kTraceVoice,
|
|
VoEId(_shared->instance_id(), -1),
|
|
"StartRecordingMicrophone() failed to start recording");
|
|
return -1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int VoEFileImpl::StartRecordingMicrophone(
|
|
OutStream* stream, CodecInst* compression)
|
|
{
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
|
"StartRecordingMicrophone(stream, compression)");
|
|
|
|
if (!_shared->statistics().Initialized())
|
|
{
|
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
|
return -1;
|
|
}
|
|
if (_shared->transmit_mixer()->StartRecordingMicrophone(stream,
|
|
compression) == -1)
|
|
{
|
|
WEBRTC_TRACE(kTraceError, kTraceVoice,
|
|
VoEId(_shared->instance_id(), -1),
|
|
"StartRecordingMicrophone() failed to start recording");
|
|
return -1;
|
|
}
|
|
if (_shared->audio_device()->Recording())
|
|
{
|
|
return 0;
|
|
}
|
|
if (!_shared->ext_recording())
|
|
{
|
|
if (_shared->audio_device()->InitRecording() != 0)
|
|
{
|
|
WEBRTC_TRACE(kTraceError, kTraceVoice,
|
|
VoEId(_shared->instance_id(), -1),
|
|
"StartRecordingMicrophone() failed to initialize recording");
|
|
return -1;
|
|
}
|
|
if (_shared->audio_device()->StartRecording() != 0)
|
|
{
|
|
WEBRTC_TRACE(kTraceError, kTraceVoice,
|
|
VoEId(_shared->instance_id(), -1),
|
|
"StartRecordingMicrophone() failed to start recording");
|
|
return -1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int VoEFileImpl::StopRecordingMicrophone()
|
|
{
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
|
"StopRecordingMicrophone()");
|
|
if (!_shared->statistics().Initialized())
|
|
{
|
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
|
return -1;
|
|
}
|
|
|
|
int err = 0;
|
|
|
|
// TODO(xians): consider removing Start/StopRecording() in
|
|
// Start/StopRecordingMicrophone() if no channel is recording.
|
|
if (_shared->NumOfSendingChannels() == 0 &&
|
|
_shared->audio_device()->Recording())
|
|
{
|
|
// Stop audio-device recording if no channel is recording
|
|
if (_shared->audio_device()->StopRecording() != 0)
|
|
{
|
|
_shared->SetLastError(VE_CANNOT_STOP_RECORDING, kTraceError,
|
|
"StopRecordingMicrophone() failed to stop recording");
|
|
err = -1;
|
|
}
|
|
}
|
|
|
|
if (_shared->transmit_mixer()->StopRecordingMicrophone() != 0)
|
|
{
|
|
WEBRTC_TRACE(kTraceError, kTraceVoice,
|
|
VoEId(_shared->instance_id(), -1),
|
|
"StopRecordingMicrophone() failed to stop recording to mixer");
|
|
err = -1;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
// TODO(andrew): a cursory inspection suggests there's a large amount of
|
|
// overlap in these convert functions which could be refactored to a helper.
|
|
int VoEFileImpl::ConvertPCMToWAV(const char* fileNameInUTF8,
|
|
const char* fileNameOutUTF8)
|
|
{
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
|
"ConvertPCMToWAV(fileNameInUTF8=%s, fileNameOutUTF8=%s)",
|
|
fileNameInUTF8, fileNameOutUTF8);
|
|
|
|
// Create file player object
|
|
FilePlayer& playerObj(*FilePlayer::CreateFilePlayer(
|
|
-1,
|
|
kFileFormatPcm16kHzFile));
|
|
|
|
int res=playerObj.StartPlayingFile(fileNameInUTF8,false,0,1.0,0,0, NULL);
|
|
if (res)
|
|
{
|
|
_shared->SetLastError(VE_BAD_FILE, kTraceError,
|
|
"ConvertPCMToWAV failed to create player object");
|
|
playerObj.StopPlayingFile();
|
|
FilePlayer::DestroyFilePlayer(&playerObj);
|
|
return -1;
|
|
}
|
|
|
|
// Create file recorder object
|
|
FileRecorder& recObj(*FileRecorder::CreateFileRecorder(
|
|
-1, kFileFormatWavFile));
|
|
|
|
CodecInst codecInst;
|
|
strncpy(codecInst.plname,"L16",32);
|
|
codecInst.channels = 1;
|
|
codecInst.rate = 256000;
|
|
codecInst.plfreq = 16000;
|
|
codecInst.pltype = 94;
|
|
codecInst.pacsize = 160;
|
|
|
|
res = recObj.StartRecordingAudioFile(fileNameOutUTF8,codecInst,0);
|
|
if (res)
|
|
{
|
|
_shared->SetLastError(VE_BAD_FILE, kTraceError,
|
|
"ConvertPCMToWAV failed to create recorder object");
|
|
playerObj.StopPlayingFile();
|
|
FilePlayer::DestroyFilePlayer(&playerObj);
|
|
recObj.StopRecording();
|
|
FileRecorder::DestroyFileRecorder(&recObj);
|
|
return -1;
|
|
}
|
|
|
|
// Run throught the file
|
|
AudioFrame audioFrame;
|
|
int16_t decodedData[160];
|
|
int decLength=0;
|
|
const uint32_t frequency = 16000;
|
|
|
|
while(!playerObj.Get10msAudioFromFile(decodedData,decLength,frequency))
|
|
{
|
|
if(decLength!=frequency/100)
|
|
{
|
|
// This is an OK way to end
|
|
break;
|
|
}
|
|
|
|
audioFrame.UpdateFrame(-1, 0, decodedData,
|
|
(uint16_t)decLength,
|
|
frequency, AudioFrame::kNormalSpeech,
|
|
AudioFrame::kVadActive);
|
|
|
|
res=recObj.RecordAudioToFile(audioFrame);
|
|
if(res)
|
|
{
|
|
WEBRTC_TRACE(kTraceError, kTraceVoice,
|
|
VoEId(_shared->instance_id(), -1),
|
|
"ConvertPCMToWAV failed during conversion (write frame)");
|
|
}
|
|
}
|
|
|
|
playerObj.StopPlayingFile();
|
|
recObj.StopRecording();
|
|
FilePlayer::DestroyFilePlayer(&playerObj);
|
|
FileRecorder::DestroyFileRecorder(&recObj);
|
|
|
|
return res;
|
|
}
|
|
|
|
int VoEFileImpl::ConvertPCMToWAV(InStream* streamIn, OutStream* streamOut)
|
|
{
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
|
"ConvertPCMToWAV(streamIn, streamOut)");
|
|
|
|
if ((streamIn == NULL) || (streamOut == NULL))
|
|
{
|
|
WEBRTC_TRACE(kTraceError, kTraceVoice,
|
|
VoEId(_shared->instance_id(), -1), "invalid stream handles");
|
|
return (-1);
|
|
}
|
|
|
|
// Create file player object
|
|
FilePlayer& playerObj(*FilePlayer::CreateFilePlayer(-1,
|
|
kFileFormatPcm16kHzFile));
|
|
int res = playerObj.StartPlayingFile(*streamIn,0,1.0,0,0,NULL);
|
|
if (res)
|
|
{
|
|
_shared->SetLastError(VE_BAD_FILE, kTraceError,
|
|
"ConvertPCMToWAV failed to create player object");
|
|
playerObj.StopPlayingFile();
|
|
FilePlayer::DestroyFilePlayer(&playerObj);
|
|
return -1;
|
|
}
|
|
|
|
// Create file recorder object
|
|
FileRecorder& recObj(*FileRecorder::CreateFileRecorder(-1,
|
|
kFileFormatWavFile));
|
|
CodecInst codecInst;
|
|
strncpy(codecInst.plname, "L16", 32);
|
|
codecInst.channels = 1;
|
|
codecInst.rate = 256000;
|
|
codecInst.plfreq = 16000;
|
|
codecInst.pltype = 94;
|
|
codecInst.pacsize = 160;
|
|
res = recObj.StartRecordingAudioFile(*streamOut,codecInst,0);
|
|
if (res)
|
|
{
|
|
_shared->SetLastError(VE_BAD_FILE, kTraceError,
|
|
"ConvertPCMToWAV failed to create recorder object");
|
|
playerObj.StopPlayingFile();
|
|
FilePlayer::DestroyFilePlayer(&playerObj);
|
|
recObj.StopRecording();
|
|
FileRecorder::DestroyFileRecorder(&recObj);
|
|
return -1;
|
|
}
|
|
|
|
// Run throught the file
|
|
AudioFrame audioFrame;
|
|
int16_t decodedData[160];
|
|
int decLength=0;
|
|
const uint32_t frequency = 16000;
|
|
|
|
while(!playerObj.Get10msAudioFromFile(decodedData,decLength,frequency))
|
|
{
|
|
if(decLength!=frequency/100)
|
|
{
|
|
// This is an OK way to end
|
|
break;
|
|
}
|
|
|
|
audioFrame.UpdateFrame(-1, 0, decodedData,
|
|
(uint16_t)decLength, frequency,
|
|
AudioFrame::kNormalSpeech,
|
|
AudioFrame::kVadActive);
|
|
|
|
res=recObj.RecordAudioToFile(audioFrame);
|
|
if(res)
|
|
{
|
|
WEBRTC_TRACE(kTraceError, kTraceVoice,
|
|
VoEId(_shared->instance_id(), -1),
|
|
"ConvertPCMToWAV failed during conversion (write frame)");
|
|
}
|
|
}
|
|
|
|
playerObj.StopPlayingFile();
|
|
recObj.StopRecording();
|
|
FilePlayer::DestroyFilePlayer(&playerObj);
|
|
FileRecorder::DestroyFileRecorder(&recObj);
|
|
|
|
return res;
|
|
}
|
|
|
|
int VoEFileImpl::ConvertWAVToPCM(const char* fileNameInUTF8,
|
|
const char* fileNameOutUTF8)
|
|
{
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
|
"ConvertWAVToPCM(fileNameInUTF8=%s, fileNameOutUTF8=%s)",
|
|
fileNameInUTF8, fileNameOutUTF8);
|
|
|
|
// Create file player object
|
|
FilePlayer& playerObj(*FilePlayer::CreateFilePlayer(-1,
|
|
kFileFormatWavFile));
|
|
int res = playerObj.StartPlayingFile(fileNameInUTF8,false,0,1.0,0,0,NULL);
|
|
if (res)
|
|
{
|
|
_shared->SetLastError(VE_BAD_FILE, kTraceError,
|
|
"ConvertWAVToPCM failed to create player object");
|
|
playerObj.StopPlayingFile();
|
|
FilePlayer::DestroyFilePlayer(&playerObj);
|
|
return -1;
|
|
}
|
|
|
|
// Create file recorder object
|
|
FileRecorder& recObj(*FileRecorder::CreateFileRecorder(
|
|
-1, kFileFormatPcm16kHzFile));
|
|
|
|
CodecInst codecInst;
|
|
strncpy(codecInst.plname,"L16",32);
|
|
codecInst.channels = 1;
|
|
codecInst.rate = 256000;
|
|
codecInst.plfreq = 16000;
|
|
codecInst.pltype = 94;
|
|
codecInst.pacsize = 160;
|
|
|
|
res = recObj.StartRecordingAudioFile(fileNameOutUTF8,codecInst,0);
|
|
if (res)
|
|
{
|
|
_shared->SetLastError(VE_BAD_FILE, kTraceError,
|
|
"ConvertWAVToPCM failed to create recorder object");
|
|
playerObj.StopPlayingFile();
|
|
FilePlayer::DestroyFilePlayer(&playerObj);
|
|
recObj.StopRecording();
|
|
FileRecorder::DestroyFileRecorder(&recObj);
|
|
return -1;
|
|
}
|
|
|
|
// Run throught the file
|
|
AudioFrame audioFrame;
|
|
int16_t decodedData[160];
|
|
int decLength=0;
|
|
const uint32_t frequency = 16000;
|
|
|
|
while(!playerObj.Get10msAudioFromFile(decodedData,decLength,frequency))
|
|
{
|
|
if(decLength!=frequency/100)
|
|
{
|
|
// This is an OK way to end
|
|
break;
|
|
}
|
|
|
|
audioFrame.UpdateFrame(-1, 0, decodedData,
|
|
(uint16_t)decLength,
|
|
frequency, AudioFrame::kNormalSpeech,
|
|
AudioFrame::kVadActive);
|
|
|
|
res=recObj.RecordAudioToFile(audioFrame);
|
|
if(res)
|
|
{
|
|
WEBRTC_TRACE(kTraceError, kTraceVoice,
|
|
VoEId(_shared->instance_id(), -1),
|
|
"ConvertWAVToPCM failed during conversion (write frame)");
|
|
}
|
|
}
|
|
|
|
playerObj.StopPlayingFile();
|
|
recObj.StopRecording();
|
|
FilePlayer::DestroyFilePlayer(&playerObj);
|
|
FileRecorder::DestroyFileRecorder(&recObj);
|
|
|
|
return res;
|
|
}
|
|
|
|
int VoEFileImpl::ConvertWAVToPCM(InStream* streamIn, OutStream* streamOut)
|
|
{
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
|
"ConvertWAVToPCM(streamIn, streamOut)");
|
|
|
|
if ((streamIn == NULL) || (streamOut == NULL))
|
|
{
|
|
WEBRTC_TRACE(kTraceError, kTraceVoice,
|
|
VoEId(_shared->instance_id(), -1), "invalid stream handles");
|
|
return (-1);
|
|
}
|
|
|
|
// Create file player object
|
|
FilePlayer& playerObj(*FilePlayer::CreateFilePlayer(-1,
|
|
kFileFormatWavFile));
|
|
int res = playerObj.StartPlayingFile(*streamIn,0,1.0,0,0,NULL);
|
|
if (res)
|
|
{
|
|
_shared->SetLastError(VE_BAD_FILE, kTraceError,
|
|
"ConvertWAVToPCM failed to create player object");
|
|
playerObj.StopPlayingFile();
|
|
FilePlayer::DestroyFilePlayer(&playerObj);
|
|
return -1;
|
|
}
|
|
|
|
// Create file recorder object
|
|
FileRecorder& recObj(*FileRecorder::CreateFileRecorder(
|
|
-1, kFileFormatPcm16kHzFile));
|
|
|
|
CodecInst codecInst;
|
|
strncpy(codecInst.plname,"L16",32);
|
|
codecInst.channels = 1;
|
|
codecInst.rate = 256000;
|
|
codecInst.plfreq = 16000;
|
|
codecInst.pltype = 94;
|
|
codecInst.pacsize = 160;
|
|
|
|
res = recObj.StartRecordingAudioFile(*streamOut,codecInst,0);
|
|
if (res)
|
|
{
|
|
_shared->SetLastError(VE_BAD_FILE, kTraceError,
|
|
"ConvertWAVToPCM failed to create recorder object");
|
|
playerObj.StopPlayingFile();
|
|
FilePlayer::DestroyFilePlayer(&playerObj);
|
|
recObj.StopRecording();
|
|
FileRecorder::DestroyFileRecorder(&recObj);
|
|
return -1;
|
|
}
|
|
|
|
// Run throught the file
|
|
AudioFrame audioFrame;
|
|
int16_t decodedData[160];
|
|
int decLength=0;
|
|
const uint32_t frequency = 16000;
|
|
|
|
while(!playerObj.Get10msAudioFromFile(decodedData,decLength,frequency))
|
|
{
|
|
if(decLength!=frequency/100)
|
|
{
|
|
// This is an OK way to end
|
|
break;
|
|
}
|
|
|
|
audioFrame.UpdateFrame(-1, 0, decodedData,
|
|
(uint16_t)decLength, frequency,
|
|
AudioFrame::kNormalSpeech,
|
|
AudioFrame::kVadActive);
|
|
|
|
res=recObj.RecordAudioToFile(audioFrame);
|
|
if(res)
|
|
{
|
|
WEBRTC_TRACE(kTraceError, kTraceVoice,
|
|
VoEId(_shared->instance_id(), -1),
|
|
"ConvertWAVToPCM failed during conversion (write frame)");
|
|
}
|
|
}
|
|
|
|
playerObj.StopPlayingFile();
|
|
recObj.StopRecording();
|
|
FilePlayer::DestroyFilePlayer(&playerObj);
|
|
FileRecorder::DestroyFileRecorder(&recObj);
|
|
|
|
return res;
|
|
}
|
|
|
|
int VoEFileImpl::ConvertPCMToCompressed(const char* fileNameInUTF8,
|
|
const char* fileNameOutUTF8,
|
|
CodecInst* compression)
|
|
{
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
|
"ConvertPCMToCompressed(fileNameInUTF8=%s, fileNameOutUTF8=%s"
|
|
", compression)", fileNameInUTF8, fileNameOutUTF8);
|
|
WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
|
" compression: plname=%s, plfreq=%d, pacsize=%d",
|
|
compression->plname, compression->plfreq,
|
|
compression->pacsize);
|
|
|
|
// Create file player object
|
|
FilePlayer& playerObj(*FilePlayer::CreateFilePlayer(
|
|
-1,
|
|
kFileFormatPcm16kHzFile));
|
|
int res = playerObj.StartPlayingFile(fileNameInUTF8,false,0,1.0,0,0, NULL);
|
|
if (res)
|
|
{
|
|
_shared->SetLastError(VE_BAD_FILE, kTraceError,
|
|
"ConvertPCMToCompressed failed to create player object");
|
|
// Clean up and shutdown the file player
|
|
playerObj.StopPlayingFile();
|
|
FilePlayer::DestroyFilePlayer(&playerObj);
|
|
return -1;
|
|
}
|
|
|
|
// Create file recorder object
|
|
FileRecorder& recObj(*FileRecorder::CreateFileRecorder(
|
|
-1,
|
|
kFileFormatCompressedFile));
|
|
res = recObj.StartRecordingAudioFile(fileNameOutUTF8, *compression,0);
|
|
if (res)
|
|
{
|
|
_shared->SetLastError(VE_BAD_FILE, kTraceError,
|
|
"ConvertPCMToCompressed failed to create recorder object");
|
|
playerObj.StopPlayingFile();
|
|
FilePlayer::DestroyFilePlayer(&playerObj);
|
|
recObj.StopRecording();
|
|
FileRecorder::DestroyFileRecorder(&recObj);
|
|
return -1;
|
|
}
|
|
|
|
// Run throught the file
|
|
AudioFrame audioFrame;
|
|
int16_t decodedData[160];
|
|
int decLength=0;
|
|
const uint32_t frequency = 16000;
|
|
|
|
while(!playerObj.Get10msAudioFromFile(decodedData,decLength,frequency))
|
|
{
|
|
if(decLength!=frequency/100)
|
|
{
|
|
// This is an OK way to end
|
|
break;
|
|
}
|
|
audioFrame.UpdateFrame(-1, 0, decodedData,
|
|
(uint16_t)decLength,
|
|
frequency, AudioFrame::kNormalSpeech,
|
|
AudioFrame::kVadActive);
|
|
|
|
res=recObj.RecordAudioToFile(audioFrame);
|
|
if(res)
|
|
{
|
|
WEBRTC_TRACE(kTraceError, kTraceVoice,
|
|
VoEId(_shared->instance_id(), -1),
|
|
"ConvertPCMToCompressed failed during conversion "
|
|
"(write frame)");
|
|
}
|
|
}
|
|
|
|
playerObj.StopPlayingFile();
|
|
recObj.StopRecording();
|
|
FilePlayer::DestroyFilePlayer(&playerObj);
|
|
FileRecorder::DestroyFileRecorder(&recObj);
|
|
|
|
return res;
|
|
}
|
|
|
|
int VoEFileImpl::ConvertPCMToCompressed(InStream* streamIn,
|
|
OutStream* streamOut,
|
|
CodecInst* compression)
|
|
{
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
|
"ConvertPCMToCompressed(streamIn, streamOut, compression)");
|
|
|
|
if ((streamIn == NULL) || (streamOut == NULL))
|
|
{
|
|
WEBRTC_TRACE(kTraceError, kTraceVoice,
|
|
VoEId(_shared->instance_id(), -1), "invalid stream handles");
|
|
return (-1);
|
|
}
|
|
|
|
WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
|
" compression: plname=%s, plfreq=%d, pacsize=%d",
|
|
compression->plname, compression->plfreq,
|
|
compression->pacsize);
|
|
|
|
// Create file player object
|
|
FilePlayer& playerObj(*FilePlayer::CreateFilePlayer(
|
|
-1, kFileFormatPcm16kHzFile));
|
|
|
|
int res = playerObj.StartPlayingFile(*streamIn,0,1.0,0,0,NULL);
|
|
if (res)
|
|
{
|
|
_shared->SetLastError(VE_BAD_FILE, kTraceError,
|
|
"ConvertPCMToCompressed failed to create player object");
|
|
playerObj.StopPlayingFile();
|
|
FilePlayer::DestroyFilePlayer(&playerObj);
|
|
return -1;
|
|
}
|
|
|
|
// Create file recorder object
|
|
FileRecorder& recObj(*FileRecorder::CreateFileRecorder(
|
|
-1, kFileFormatCompressedFile));
|
|
res = recObj.StartRecordingAudioFile(*streamOut,*compression,0);
|
|
if (res)
|
|
{
|
|
_shared->SetLastError(VE_BAD_FILE, kTraceError,
|
|
"ConvertPCMToCompressed failed to create recorder object");
|
|
playerObj.StopPlayingFile();
|
|
FilePlayer::DestroyFilePlayer(&playerObj);
|
|
recObj.StopRecording();
|
|
FileRecorder::DestroyFileRecorder(&recObj);
|
|
return -1;
|
|
}
|
|
|
|
// Run throught the file
|
|
AudioFrame audioFrame;
|
|
int16_t decodedData[160];
|
|
int decLength=0;
|
|
const uint32_t frequency = 16000;
|
|
|
|
while(!playerObj.Get10msAudioFromFile(decodedData,decLength,frequency))
|
|
{
|
|
if(decLength!=frequency/100)
|
|
{
|
|
// This is an OK way to end
|
|
break;
|
|
}
|
|
audioFrame.UpdateFrame(-1, 0, decodedData,
|
|
(uint16_t)decLength,
|
|
frequency, AudioFrame::kNormalSpeech,
|
|
AudioFrame::kVadActive);
|
|
|
|
res=recObj.RecordAudioToFile(audioFrame);
|
|
if(res)
|
|
{
|
|
WEBRTC_TRACE(kTraceError, kTraceVoice,
|
|
VoEId(_shared->instance_id(), -1),
|
|
"ConvertPCMToCompressed failed during conversion "
|
|
"(write frame)");
|
|
}
|
|
}
|
|
|
|
playerObj.StopPlayingFile();
|
|
recObj.StopRecording();
|
|
FilePlayer::DestroyFilePlayer(&playerObj);
|
|
FileRecorder::DestroyFileRecorder(&recObj);
|
|
|
|
return res;
|
|
}
|
|
|
|
int VoEFileImpl::ConvertCompressedToPCM(const char* fileNameInUTF8,
|
|
const char* fileNameOutUTF8)
|
|
{
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
|
"ConvertCompressedToPCM(fileNameInUTF8=%s,"
|
|
" fileNameOutUTF8=%s)",
|
|
fileNameInUTF8, fileNameOutUTF8);
|
|
|
|
// Create file player object
|
|
FilePlayer& playerObj(*FilePlayer::CreateFilePlayer(
|
|
-1, kFileFormatCompressedFile));
|
|
|
|
int res = playerObj.StartPlayingFile(fileNameInUTF8,false,0,1.0,0,0,NULL);
|
|
if (res)
|
|
{
|
|
_shared->SetLastError(VE_BAD_FILE, kTraceError,
|
|
"ConvertCompressedToPCM failed to create player object");
|
|
playerObj.StopPlayingFile();
|
|
FilePlayer::DestroyFilePlayer(&playerObj);
|
|
return -1;
|
|
}
|
|
|
|
// Create file recorder object
|
|
FileRecorder& recObj(*FileRecorder::CreateFileRecorder(
|
|
-1, kFileFormatPcm16kHzFile));
|
|
|
|
CodecInst codecInst;
|
|
strncpy(codecInst.plname,"L16",32);
|
|
codecInst.channels = 1;
|
|
codecInst.rate = 256000;
|
|
codecInst.plfreq = 16000;
|
|
codecInst.pltype = 94;
|
|
codecInst.pacsize = 160;
|
|
|
|
res = recObj.StartRecordingAudioFile(fileNameOutUTF8,codecInst,0);
|
|
if (res)
|
|
{
|
|
_shared->SetLastError(VE_BAD_FILE, kTraceError,
|
|
"ConvertCompressedToPCM failed to create recorder object");
|
|
playerObj.StopPlayingFile();
|
|
FilePlayer::DestroyFilePlayer(&playerObj);
|
|
recObj.StopRecording();
|
|
FileRecorder::DestroyFileRecorder(&recObj);
|
|
return -1;
|
|
}
|
|
|
|
// Run throught the file
|
|
AudioFrame audioFrame;
|
|
int16_t decodedData[160];
|
|
int decLength=0;
|
|
const uint32_t frequency = 16000;
|
|
|
|
while(!playerObj.Get10msAudioFromFile(decodedData,decLength,frequency))
|
|
{
|
|
if(decLength!=frequency/100)
|
|
{
|
|
// This is an OK way to end
|
|
break;
|
|
}
|
|
audioFrame.UpdateFrame(-1, 0, decodedData,
|
|
(uint16_t)decLength,
|
|
frequency,
|
|
AudioFrame::kNormalSpeech,
|
|
AudioFrame::kVadActive);
|
|
|
|
res=recObj.RecordAudioToFile(audioFrame);
|
|
if(res)
|
|
{
|
|
WEBRTC_TRACE(kTraceError, kTraceVoice,
|
|
VoEId(_shared->instance_id(), -1),
|
|
"ConvertCompressedToPCM failed during conversion "
|
|
"(write frame)");
|
|
}
|
|
}
|
|
|
|
playerObj.StopPlayingFile();
|
|
recObj.StopRecording();
|
|
FilePlayer::DestroyFilePlayer(&playerObj);
|
|
FileRecorder::DestroyFileRecorder(&recObj);
|
|
|
|
return res;
|
|
}
|
|
|
|
int VoEFileImpl::ConvertCompressedToPCM(InStream* streamIn,
|
|
OutStream* streamOut)
|
|
{
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
|
"ConvertCompressedToPCM(file, file);");
|
|
|
|
if ((streamIn == NULL) || (streamOut == NULL))
|
|
{
|
|
WEBRTC_TRACE(kTraceError, kTraceVoice,
|
|
VoEId(_shared->instance_id(), -1), "invalid stream handles");
|
|
return (-1);
|
|
}
|
|
|
|
// Create file player object
|
|
FilePlayer& playerObj(*FilePlayer::CreateFilePlayer(
|
|
-1, kFileFormatCompressedFile));
|
|
int res;
|
|
|
|
res = playerObj.StartPlayingFile(*streamIn,0,1.0,0,0,NULL);
|
|
if (res)
|
|
{
|
|
_shared->SetLastError(VE_BAD_FILE, kTraceError,
|
|
"ConvertCompressedToPCM failed to create player object");
|
|
playerObj.StopPlayingFile();
|
|
FilePlayer::DestroyFilePlayer(&playerObj);
|
|
return -1;
|
|
}
|
|
|
|
// Create file recorder object
|
|
FileRecorder& recObj(*FileRecorder::CreateFileRecorder(
|
|
-1, kFileFormatPcm16kHzFile));
|
|
|
|
CodecInst codecInst;
|
|
strncpy(codecInst.plname,"L16",32);
|
|
codecInst.channels = 1;
|
|
codecInst.rate = 256000;
|
|
codecInst.plfreq = 16000;
|
|
codecInst.pltype = 94;
|
|
codecInst.pacsize = 160;
|
|
|
|
res = recObj.StartRecordingAudioFile(*streamOut,codecInst,0);
|
|
if (res)
|
|
{
|
|
_shared->SetLastError(VE_BAD_FILE, kTraceError,
|
|
"ConvertCompressedToPCM failed to create recorder object");
|
|
playerObj.StopPlayingFile();
|
|
FilePlayer::DestroyFilePlayer(&playerObj);
|
|
recObj.StopRecording();
|
|
FileRecorder::DestroyFileRecorder(&recObj);
|
|
return -1;
|
|
}
|
|
|
|
// Run throught the file
|
|
AudioFrame audioFrame;
|
|
int16_t decodedData[160];
|
|
int decLength=0;
|
|
const uint32_t frequency = 16000;
|
|
|
|
while(!playerObj.Get10msAudioFromFile(decodedData,decLength,frequency))
|
|
{
|
|
if(decLength!=frequency/100)
|
|
{
|
|
// This is an OK way to end
|
|
break;
|
|
}
|
|
audioFrame.UpdateFrame(-1, 0, decodedData,
|
|
(uint16_t)decLength,
|
|
frequency,
|
|
AudioFrame::kNormalSpeech,
|
|
AudioFrame::kVadActive);
|
|
|
|
res=recObj.RecordAudioToFile(audioFrame);
|
|
if(res)
|
|
{
|
|
WEBRTC_TRACE(kTraceError, kTraceVoice,
|
|
VoEId(_shared->instance_id(), -1),
|
|
"ConvertCompressedToPCM failed during conversion "
|
|
"(write frame)");
|
|
}
|
|
}
|
|
|
|
playerObj.StopPlayingFile();
|
|
recObj.StopRecording();
|
|
FilePlayer::DestroyFilePlayer(&playerObj);
|
|
FileRecorder::DestroyFileRecorder(&recObj);
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
int VoEFileImpl::GetFileDuration(const char* fileNameUTF8,
|
|
int& durationMs,
|
|
FileFormats format)
|
|
{
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
|
"GetFileDuration(fileNameUTF8=%s, format=%d)",
|
|
fileNameUTF8, format);
|
|
|
|
// Create a dummy file module for this
|
|
MediaFile * fileModule=MediaFile::CreateMediaFile(-1);
|
|
|
|
// Temp container of the right format
|
|
uint32_t duration;
|
|
int res=fileModule->FileDurationMs(fileNameUTF8,duration,format);
|
|
if (res)
|
|
{
|
|
_shared->SetLastError(VE_BAD_FILE, kTraceError,
|
|
"GetFileDuration() failed measure file duration");
|
|
return -1;
|
|
}
|
|
durationMs = duration;
|
|
MediaFile::DestroyMediaFile(fileModule);
|
|
fileModule = NULL;
|
|
|
|
return(res);
|
|
}
|
|
|
|
int VoEFileImpl::GetPlaybackPosition(int channel, int& positionMs)
|
|
{
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
|
"GetPlaybackPosition(channel=%d)", channel);
|
|
|
|
voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
|
|
voe::Channel* channelPtr = ch.channel();
|
|
if (channelPtr == NULL)
|
|
{
|
|
_shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
|
|
"GetPlaybackPosition() failed to locate channel");
|
|
return -1;
|
|
}
|
|
return channelPtr->GetLocalPlayoutPosition(positionMs);
|
|
}
|
|
|
|
#endif // #ifdef WEBRTC_VOICE_ENGINE_FILE_API
|
|
|
|
} // namespace webrtc
|