|  | /* | 
|  | *  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/system_wrappers/include/file_wrapper.h" | 
|  | #include "webrtc/system_wrappers/include/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) { | 
|  | if (NULL == voiceEngine) { | 
|  | return NULL; | 
|  | } | 
|  | VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine); | 
|  | s->AddRef(); | 
|  | return s; | 
|  | } | 
|  |  | 
|  | 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); | 
|  | static_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) { | 
|  | 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::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); | 
|  | static_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::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); | 
|  | static_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); | 
|  | static_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()) { | 
|  | 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()) { | 
|  | 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; | 
|  | } | 
|  |  | 
|  | }  // namespace webrtc |