/* * 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(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