diff options
Diffstat (limited to 'webrtc/modules/media_file/media_file_impl.cc')
-rw-r--r-- | webrtc/modules/media_file/media_file_impl.cc | 1137 |
1 files changed, 1137 insertions, 0 deletions
diff --git a/webrtc/modules/media_file/media_file_impl.cc b/webrtc/modules/media_file/media_file_impl.cc new file mode 100644 index 0000000000..abc7b9d9e0 --- /dev/null +++ b/webrtc/modules/media_file/media_file_impl.cc @@ -0,0 +1,1137 @@ +/* + * 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 <assert.h> + +#include "webrtc/base/format_macros.h" +#include "webrtc/modules/media_file/media_file_impl.h" +#include "webrtc/system_wrappers/include/critical_section_wrapper.h" +#include "webrtc/system_wrappers/include/file_wrapper.h" +#include "webrtc/system_wrappers/include/tick_util.h" +#include "webrtc/system_wrappers/include/trace.h" + +namespace webrtc { +MediaFile* MediaFile::CreateMediaFile(const int32_t id) +{ + return new MediaFileImpl(id); +} + +void MediaFile::DestroyMediaFile(MediaFile* module) +{ + delete static_cast<MediaFileImpl*>(module); +} + +MediaFileImpl::MediaFileImpl(const int32_t id) + : _id(id), + _crit(CriticalSectionWrapper::CreateCriticalSection()), + _callbackCrit(CriticalSectionWrapper::CreateCriticalSection()), + _ptrFileUtilityObj(NULL), + codec_info_(), + _ptrInStream(NULL), + _ptrOutStream(NULL), + _fileFormat((FileFormats)-1), + _recordDurationMs(0), + _playoutPositionMs(0), + _notificationMs(0), + _playingActive(false), + _recordingActive(false), + _isStereo(false), + _openFile(false), + _fileName(), + _ptrCallback(NULL) +{ + WEBRTC_TRACE(kTraceMemory, kTraceFile, id, "Created"); + + codec_info_.plname[0] = '\0'; + _fileName[0] = '\0'; +} + + +MediaFileImpl::~MediaFileImpl() +{ + WEBRTC_TRACE(kTraceMemory, kTraceFile, _id, "~MediaFileImpl()"); + { + CriticalSectionScoped lock(_crit); + + if(_playingActive) + { + StopPlaying(); + } + + if(_recordingActive) + { + StopRecording(); + } + + delete _ptrFileUtilityObj; + + if(_openFile) + { + delete _ptrInStream; + _ptrInStream = NULL; + delete _ptrOutStream; + _ptrOutStream = NULL; + } + } + + delete _crit; + delete _callbackCrit; +} + +int64_t MediaFileImpl::TimeUntilNextProcess() +{ + WEBRTC_TRACE( + kTraceWarning, + kTraceFile, + _id, + "TimeUntilNextProcess: This method is not used by MediaFile class."); + return -1; +} + +int32_t MediaFileImpl::Process() +{ + WEBRTC_TRACE(kTraceWarning, kTraceFile, _id, + "Process: This method is not used by MediaFile class."); + return -1; +} + +int32_t MediaFileImpl::PlayoutAudioData(int8_t* buffer, + size_t& dataLengthInBytes) +{ + WEBRTC_TRACE(kTraceStream, kTraceFile, _id, + "MediaFileImpl::PlayoutData(buffer= 0x%x, bufLen= %" PRIuS ")", + buffer, dataLengthInBytes); + + const size_t bufferLengthInBytes = dataLengthInBytes; + dataLengthInBytes = 0; + + if(buffer == NULL || bufferLengthInBytes == 0) + { + WEBRTC_TRACE(kTraceError, kTraceFile, _id, + "Buffer pointer or length is NULL!"); + return -1; + } + + int32_t bytesRead = 0; + { + CriticalSectionScoped lock(_crit); + + if(!_playingActive) + { + WEBRTC_TRACE(kTraceWarning, kTraceFile, _id, + "Not currently playing!"); + return -1; + } + + if(!_ptrFileUtilityObj) + { + WEBRTC_TRACE(kTraceError, kTraceFile, _id, + "Playing, but no FileUtility object!"); + StopPlaying(); + return -1; + } + + switch(_fileFormat) + { + case kFileFormatPcm32kHzFile: + case kFileFormatPcm16kHzFile: + case kFileFormatPcm8kHzFile: + bytesRead = _ptrFileUtilityObj->ReadPCMData( + *_ptrInStream, + buffer, + bufferLengthInBytes); + break; + case kFileFormatCompressedFile: + bytesRead = _ptrFileUtilityObj->ReadCompressedData( + *_ptrInStream, + buffer, + bufferLengthInBytes); + break; + case kFileFormatWavFile: + bytesRead = _ptrFileUtilityObj->ReadWavDataAsMono( + *_ptrInStream, + buffer, + bufferLengthInBytes); + break; + case kFileFormatPreencodedFile: + bytesRead = _ptrFileUtilityObj->ReadPreEncodedData( + *_ptrInStream, + buffer, + bufferLengthInBytes); + if(bytesRead > 0) + { + dataLengthInBytes = static_cast<size_t>(bytesRead); + return 0; + } + break; + default: + { + WEBRTC_TRACE(kTraceError, kTraceFile, _id, + "Invalid file format: %d", _fileFormat); + assert(false); + break; + } + } + + if( bytesRead > 0) + { + dataLengthInBytes = static_cast<size_t>(bytesRead); + } + } + HandlePlayCallbacks(bytesRead); + return 0; +} + +void MediaFileImpl::HandlePlayCallbacks(int32_t bytesRead) +{ + bool playEnded = false; + uint32_t callbackNotifyMs = 0; + + if(bytesRead > 0) + { + // Check if it's time for PlayNotification(..). + _playoutPositionMs = _ptrFileUtilityObj->PlayoutPositionMs(); + if(_notificationMs) + { + if(_playoutPositionMs >= _notificationMs) + { + _notificationMs = 0; + callbackNotifyMs = _playoutPositionMs; + } + } + } + else + { + // If no bytes were read assume end of file. + StopPlaying(); + playEnded = true; + } + + // Only _callbackCrit may and should be taken when making callbacks. + CriticalSectionScoped lock(_callbackCrit); + if(_ptrCallback) + { + if(callbackNotifyMs) + { + _ptrCallback->PlayNotification(_id, callbackNotifyMs); + } + if(playEnded) + { + _ptrCallback->PlayFileEnded(_id); + } + } +} + +int32_t MediaFileImpl::PlayoutStereoData( + int8_t* bufferLeft, + int8_t* bufferRight, + size_t& dataLengthInBytes) +{ + WEBRTC_TRACE(kTraceStream, kTraceFile, _id, + "MediaFileImpl::PlayoutStereoData(Left = 0x%x, Right = 0x%x," + " Len= %" PRIuS ")", + bufferLeft, + bufferRight, + dataLengthInBytes); + + const size_t bufferLengthInBytes = dataLengthInBytes; + dataLengthInBytes = 0; + + if(bufferLeft == NULL || bufferRight == NULL || bufferLengthInBytes == 0) + { + WEBRTC_TRACE(kTraceError, kTraceFile, _id, + "A buffer pointer or the length is NULL!"); + return -1; + } + + bool playEnded = false; + uint32_t callbackNotifyMs = 0; + { + CriticalSectionScoped lock(_crit); + + if(!_playingActive || !_isStereo) + { + WEBRTC_TRACE(kTraceWarning, kTraceFile, _id, + "Not currently playing stereo!"); + return -1; + } + + if(!_ptrFileUtilityObj) + { + WEBRTC_TRACE( + kTraceError, + kTraceFile, + _id, + "Playing stereo, but the FileUtility objects is NULL!"); + StopPlaying(); + return -1; + } + + // Stereo playout only supported for WAV files. + int32_t bytesRead = 0; + switch(_fileFormat) + { + case kFileFormatWavFile: + bytesRead = _ptrFileUtilityObj->ReadWavDataAsStereo( + *_ptrInStream, + bufferLeft, + bufferRight, + bufferLengthInBytes); + break; + default: + WEBRTC_TRACE(kTraceError, kTraceFile, _id, + "Trying to read non-WAV as stereo audio\ + (not supported)"); + break; + } + + if(bytesRead > 0) + { + dataLengthInBytes = static_cast<size_t>(bytesRead); + + // Check if it's time for PlayNotification(..). + _playoutPositionMs = _ptrFileUtilityObj->PlayoutPositionMs(); + if(_notificationMs) + { + if(_playoutPositionMs >= _notificationMs) + { + _notificationMs = 0; + callbackNotifyMs = _playoutPositionMs; + } + } + } + else + { + // If no bytes were read assume end of file. + StopPlaying(); + playEnded = true; + } + } + + CriticalSectionScoped lock(_callbackCrit); + if(_ptrCallback) + { + if(callbackNotifyMs) + { + _ptrCallback->PlayNotification(_id, callbackNotifyMs); + } + if(playEnded) + { + _ptrCallback->PlayFileEnded(_id); + } + } + return 0; +} + +int32_t MediaFileImpl::StartPlayingAudioFile( + const char* fileName, + const uint32_t notificationTimeMs, + const bool loop, + const FileFormats format, + const CodecInst* codecInst, + const uint32_t startPointMs, + const uint32_t stopPointMs) +{ + if(!ValidFileName(fileName)) + { + return -1; + } + if(!ValidFileFormat(format,codecInst)) + { + return -1; + } + if(!ValidFilePositions(startPointMs,stopPointMs)) + { + return -1; + } + + // Check that the file will play longer than notificationTimeMs ms. + if((startPointMs && stopPointMs && !loop) && + (notificationTimeMs > (stopPointMs - startPointMs))) + { + WEBRTC_TRACE( + kTraceError, + kTraceFile, + _id, + "specified notification time is longer than amount of ms that will\ + be played"); + return -1; + } + + FileWrapper* inputStream = FileWrapper::Create(); + if(inputStream == NULL) + { + WEBRTC_TRACE(kTraceMemory, kTraceFile, _id, + "Failed to allocate input stream for file %s", fileName); + return -1; + } + + if(inputStream->OpenFile(fileName, true, loop) != 0) + { + delete inputStream; + WEBRTC_TRACE(kTraceError, kTraceFile, _id, + "Could not open input file %s", fileName); + return -1; + } + + if(StartPlayingStream(*inputStream, loop, notificationTimeMs, + format, codecInst, startPointMs, stopPointMs) == -1) + { + inputStream->CloseFile(); + delete inputStream; + return -1; + } + + CriticalSectionScoped lock(_crit); + _openFile = true; + strncpy(_fileName, fileName, sizeof(_fileName)); + _fileName[sizeof(_fileName) - 1] = '\0'; + return 0; +} + +int32_t MediaFileImpl::StartPlayingAudioStream( + InStream& stream, + const uint32_t notificationTimeMs, + const FileFormats format, + const CodecInst* codecInst, + const uint32_t startPointMs, + const uint32_t stopPointMs) +{ + return StartPlayingStream(stream, false, notificationTimeMs, format, + codecInst, startPointMs, stopPointMs); +} + +int32_t MediaFileImpl::StartPlayingStream( + InStream& stream, + bool loop, + const uint32_t notificationTimeMs, + const FileFormats format, + const CodecInst* codecInst, + const uint32_t startPointMs, + const uint32_t stopPointMs) +{ + if(!ValidFileFormat(format,codecInst)) + { + return -1; + } + + if(!ValidFilePositions(startPointMs,stopPointMs)) + { + return -1; + } + + CriticalSectionScoped lock(_crit); + if(_playingActive || _recordingActive) + { + WEBRTC_TRACE( + kTraceError, + kTraceFile, + _id, + "StartPlaying called, but already playing or recording file %s", + (_fileName[0] == '\0') ? "(name not set)" : _fileName); + return -1; + } + + if(_ptrFileUtilityObj != NULL) + { + WEBRTC_TRACE(kTraceError, + kTraceFile, + _id, + "StartPlaying called, but FileUtilityObj already exists!"); + StopPlaying(); + return -1; + } + + _ptrFileUtilityObj = new ModuleFileUtility(_id); + if(_ptrFileUtilityObj == NULL) + { + WEBRTC_TRACE(kTraceMemory, kTraceFile, _id, + "Failed to create FileUtilityObj!"); + return -1; + } + + switch(format) + { + case kFileFormatWavFile: + { + if(_ptrFileUtilityObj->InitWavReading(stream, startPointMs, + stopPointMs) == -1) + { + WEBRTC_TRACE(kTraceError, kTraceFile, _id, + "Not a valid WAV file!"); + StopPlaying(); + return -1; + } + _fileFormat = kFileFormatWavFile; + break; + } + case kFileFormatCompressedFile: + { + if(_ptrFileUtilityObj->InitCompressedReading(stream, startPointMs, + stopPointMs) == -1) + { + WEBRTC_TRACE(kTraceError, kTraceFile, _id, + "Not a valid Compressed file!"); + StopPlaying(); + return -1; + } + _fileFormat = kFileFormatCompressedFile; + break; + } + case kFileFormatPcm8kHzFile: + case kFileFormatPcm16kHzFile: + case kFileFormatPcm32kHzFile: + { + // ValidFileFormat() called in the beginneing of this function + // prevents codecInst from being NULL here. + assert(codecInst != NULL); + if(!ValidFrequency(codecInst->plfreq) || + _ptrFileUtilityObj->InitPCMReading(stream, startPointMs, + stopPointMs, + codecInst->plfreq) == -1) + { + WEBRTC_TRACE(kTraceError, kTraceFile, _id, + "Not a valid raw 8 or 16 KHz PCM file!"); + StopPlaying(); + return -1; + } + + _fileFormat = format; + break; + } + case kFileFormatPreencodedFile: + { + // ValidFileFormat() called in the beginneing of this function + // prevents codecInst from being NULL here. + assert(codecInst != NULL); + if(_ptrFileUtilityObj->InitPreEncodedReading(stream, *codecInst) == + -1) + { + WEBRTC_TRACE(kTraceError, kTraceFile, _id, + "Not a valid PreEncoded file!"); + StopPlaying(); + return -1; + } + + _fileFormat = kFileFormatPreencodedFile; + break; + } + default: + { + WEBRTC_TRACE(kTraceError, kTraceFile, _id, + "Invalid file format: %d", format); + assert(false); + break; + } + } + if(_ptrFileUtilityObj->codec_info(codec_info_) == -1) + { + WEBRTC_TRACE(kTraceError, kTraceFile, _id, + "Failed to retrieve codec info!"); + StopPlaying(); + return -1; + } + + _isStereo = (codec_info_.channels == 2); + if(_isStereo && (_fileFormat != kFileFormatWavFile)) + { + WEBRTC_TRACE(kTraceWarning, kTraceFile, _id, + "Stereo is only allowed for WAV files"); + StopPlaying(); + return -1; + } + _playingActive = true; + _playoutPositionMs = _ptrFileUtilityObj->PlayoutPositionMs(); + _ptrInStream = &stream; + _notificationMs = notificationTimeMs; + + return 0; +} + +int32_t MediaFileImpl::StopPlaying() +{ + + CriticalSectionScoped lock(_crit); + _isStereo = false; + if(_ptrFileUtilityObj) + { + delete _ptrFileUtilityObj; + _ptrFileUtilityObj = NULL; + } + if(_ptrInStream) + { + // If MediaFileImpl opened the InStream it must be reclaimed here. + if(_openFile) + { + delete _ptrInStream; + _openFile = false; + } + _ptrInStream = NULL; + } + + codec_info_.pltype = 0; + codec_info_.plname[0] = '\0'; + + if(!_playingActive) + { + WEBRTC_TRACE(kTraceWarning, kTraceFile, _id, + "playing is not active!"); + return -1; + } + + _playingActive = false; + return 0; +} + +bool MediaFileImpl::IsPlaying() +{ + WEBRTC_TRACE(kTraceStream, kTraceFile, _id, "MediaFileImpl::IsPlaying()"); + CriticalSectionScoped lock(_crit); + return _playingActive; +} + +int32_t MediaFileImpl::IncomingAudioData( + const int8_t* buffer, + const size_t bufferLengthInBytes) +{ + WEBRTC_TRACE(kTraceStream, kTraceFile, _id, + "MediaFile::IncomingData(buffer= 0x%x, bufLen= %" PRIuS, + buffer, bufferLengthInBytes); + + if(buffer == NULL || bufferLengthInBytes == 0) + { + WEBRTC_TRACE(kTraceError, kTraceFile, _id, + "Buffer pointer or length is NULL!"); + return -1; + } + + bool recordingEnded = false; + uint32_t callbackNotifyMs = 0; + { + CriticalSectionScoped lock(_crit); + + if(!_recordingActive) + { + WEBRTC_TRACE(kTraceWarning, kTraceFile, _id, + "Not currently recording!"); + return -1; + } + if(_ptrOutStream == NULL) + { + WEBRTC_TRACE(kTraceError, kTraceFile, _id, + "Recording is active, but output stream is NULL!"); + assert(false); + return -1; + } + + int32_t bytesWritten = 0; + uint32_t samplesWritten = codec_info_.pacsize; + if(_ptrFileUtilityObj) + { + switch(_fileFormat) + { + case kFileFormatPcm8kHzFile: + case kFileFormatPcm16kHzFile: + case kFileFormatPcm32kHzFile: + bytesWritten = _ptrFileUtilityObj->WritePCMData( + *_ptrOutStream, + buffer, + bufferLengthInBytes); + + // Sample size is 2 bytes. + if(bytesWritten > 0) + { + samplesWritten = bytesWritten/sizeof(int16_t); + } + break; + case kFileFormatCompressedFile: + bytesWritten = _ptrFileUtilityObj->WriteCompressedData( + *_ptrOutStream, buffer, bufferLengthInBytes); + break; + case kFileFormatWavFile: + bytesWritten = _ptrFileUtilityObj->WriteWavData( + *_ptrOutStream, + buffer, + bufferLengthInBytes); + if(bytesWritten > 0 && STR_NCASE_CMP(codec_info_.plname, + "L16", 4) == 0) + { + // Sample size is 2 bytes. + samplesWritten = bytesWritten/sizeof(int16_t); + } + break; + case kFileFormatPreencodedFile: + bytesWritten = _ptrFileUtilityObj->WritePreEncodedData( + *_ptrOutStream, buffer, bufferLengthInBytes); + break; + default: + WEBRTC_TRACE(kTraceError, kTraceFile, _id, + "Invalid file format: %d", _fileFormat); + assert(false); + break; + } + } else { + // TODO (hellner): quick look at the code makes me think that this + // code is never executed. Remove? + if(_ptrOutStream) + { + if(_ptrOutStream->Write(buffer, bufferLengthInBytes)) + { + bytesWritten = static_cast<int32_t>(bufferLengthInBytes); + } + } + } + + _recordDurationMs += samplesWritten / (codec_info_.plfreq / 1000); + + // Check if it's time for RecordNotification(..). + if(_notificationMs) + { + if(_recordDurationMs >= _notificationMs) + { + _notificationMs = 0; + callbackNotifyMs = _recordDurationMs; + } + } + if(bytesWritten < (int32_t)bufferLengthInBytes) + { + WEBRTC_TRACE(kTraceWarning, kTraceFile, _id, + "Failed to write all requested bytes!"); + StopRecording(); + recordingEnded = true; + } + } + + // Only _callbackCrit may and should be taken when making callbacks. + CriticalSectionScoped lock(_callbackCrit); + if(_ptrCallback) + { + if(callbackNotifyMs) + { + _ptrCallback->RecordNotification(_id, callbackNotifyMs); + } + if(recordingEnded) + { + _ptrCallback->RecordFileEnded(_id); + return -1; + } + } + return 0; +} + +int32_t MediaFileImpl::StartRecordingAudioFile( + const char* fileName, + const FileFormats format, + const CodecInst& codecInst, + const uint32_t notificationTimeMs, + const uint32_t maxSizeBytes) +{ + if(!ValidFileName(fileName)) + { + return -1; + } + if(!ValidFileFormat(format,&codecInst)) + { + return -1; + } + + FileWrapper* outputStream = FileWrapper::Create(); + if(outputStream == NULL) + { + WEBRTC_TRACE(kTraceMemory, kTraceFile, _id, + "Failed to allocate memory for output stream"); + return -1; + } + + if(outputStream->OpenFile(fileName, false) != 0) + { + delete outputStream; + WEBRTC_TRACE(kTraceError, kTraceFile, _id, + "Could not open output file '%s' for writing!", + fileName); + return -1; + } + + if(maxSizeBytes) + { + outputStream->SetMaxFileSize(maxSizeBytes); + } + + if(StartRecordingAudioStream(*outputStream, format, codecInst, + notificationTimeMs) == -1) + { + outputStream->CloseFile(); + delete outputStream; + return -1; + } + + CriticalSectionScoped lock(_crit); + _openFile = true; + strncpy(_fileName, fileName, sizeof(_fileName)); + _fileName[sizeof(_fileName) - 1] = '\0'; + return 0; +} + +int32_t MediaFileImpl::StartRecordingAudioStream( + OutStream& stream, + const FileFormats format, + const CodecInst& codecInst, + const uint32_t notificationTimeMs) +{ + // Check codec info + if(!ValidFileFormat(format,&codecInst)) + { + return -1; + } + + CriticalSectionScoped lock(_crit); + if(_recordingActive || _playingActive) + { + WEBRTC_TRACE( + kTraceError, + kTraceFile, + _id, + "StartRecording called, but already recording or playing file %s!", + _fileName); + return -1; + } + + if(_ptrFileUtilityObj != NULL) + { + WEBRTC_TRACE( + kTraceError, + kTraceFile, + _id, + "StartRecording called, but fileUtilityObj already exists!"); + StopRecording(); + return -1; + } + + _ptrFileUtilityObj = new ModuleFileUtility(_id); + if(_ptrFileUtilityObj == NULL) + { + WEBRTC_TRACE(kTraceMemory, kTraceFile, _id, + "Cannot allocate fileUtilityObj!"); + return -1; + } + + CodecInst tmpAudioCodec; + memcpy(&tmpAudioCodec, &codecInst, sizeof(CodecInst)); + switch(format) + { + case kFileFormatWavFile: + { + if(_ptrFileUtilityObj->InitWavWriting(stream, codecInst) == -1) + { + WEBRTC_TRACE(kTraceError, kTraceFile, _id, + "Failed to initialize WAV file!"); + delete _ptrFileUtilityObj; + _ptrFileUtilityObj = NULL; + return -1; + } + _fileFormat = kFileFormatWavFile; + break; + } + case kFileFormatCompressedFile: + { + // Write compression codec name at beginning of file + if(_ptrFileUtilityObj->InitCompressedWriting(stream, codecInst) == + -1) + { + WEBRTC_TRACE(kTraceError, kTraceFile, _id, + "Failed to initialize Compressed file!"); + delete _ptrFileUtilityObj; + _ptrFileUtilityObj = NULL; + return -1; + } + _fileFormat = kFileFormatCompressedFile; + break; + } + case kFileFormatPcm8kHzFile: + case kFileFormatPcm16kHzFile: + { + if(!ValidFrequency(codecInst.plfreq) || + _ptrFileUtilityObj->InitPCMWriting(stream, codecInst.plfreq) == + -1) + { + WEBRTC_TRACE(kTraceError, kTraceFile, _id, + "Failed to initialize 8 or 16KHz PCM file!"); + delete _ptrFileUtilityObj; + _ptrFileUtilityObj = NULL; + return -1; + } + _fileFormat = format; + break; + } + case kFileFormatPreencodedFile: + { + if(_ptrFileUtilityObj->InitPreEncodedWriting(stream, codecInst) == + -1) + { + WEBRTC_TRACE(kTraceError, kTraceFile, _id, + "Failed to initialize Pre-Encoded file!"); + delete _ptrFileUtilityObj; + _ptrFileUtilityObj = NULL; + return -1; + } + + _fileFormat = kFileFormatPreencodedFile; + break; + } + default: + { + WEBRTC_TRACE(kTraceError, kTraceFile, _id, + "Invalid file format %d specified!", format); + delete _ptrFileUtilityObj; + _ptrFileUtilityObj = NULL; + return -1; + } + } + _isStereo = (tmpAudioCodec.channels == 2); + if(_isStereo) + { + if(_fileFormat != kFileFormatWavFile) + { + WEBRTC_TRACE(kTraceWarning, kTraceFile, _id, + "Stereo is only allowed for WAV files"); + StopRecording(); + return -1; + } + if((STR_NCASE_CMP(tmpAudioCodec.plname, "L16", 4) != 0) && + (STR_NCASE_CMP(tmpAudioCodec.plname, "PCMU", 5) != 0) && + (STR_NCASE_CMP(tmpAudioCodec.plname, "PCMA", 5) != 0)) + { + WEBRTC_TRACE( + kTraceWarning, + kTraceFile, + _id, + "Stereo is only allowed for codec PCMU, PCMA and L16 "); + StopRecording(); + return -1; + } + } + memcpy(&codec_info_, &tmpAudioCodec, sizeof(CodecInst)); + _recordingActive = true; + _ptrOutStream = &stream; + _notificationMs = notificationTimeMs; + _recordDurationMs = 0; + return 0; +} + +int32_t MediaFileImpl::StopRecording() +{ + + CriticalSectionScoped lock(_crit); + if(!_recordingActive) + { + WEBRTC_TRACE(kTraceWarning, kTraceFile, _id, + "recording is not active!"); + return -1; + } + + _isStereo = false; + + if(_ptrFileUtilityObj != NULL) + { + // Both AVI and WAV header has to be updated before closing the stream + // because they contain size information. + if((_fileFormat == kFileFormatWavFile) && + (_ptrOutStream != NULL)) + { + _ptrFileUtilityObj->UpdateWavHeader(*_ptrOutStream); + } + delete _ptrFileUtilityObj; + _ptrFileUtilityObj = NULL; + } + + if(_ptrOutStream != NULL) + { + // If MediaFileImpl opened the OutStream it must be reclaimed here. + if(_openFile) + { + delete _ptrOutStream; + _openFile = false; + } + _ptrOutStream = NULL; + } + + _recordingActive = false; + codec_info_.pltype = 0; + codec_info_.plname[0] = '\0'; + + return 0; +} + +bool MediaFileImpl::IsRecording() +{ + WEBRTC_TRACE(kTraceStream, kTraceFile, _id, "MediaFileImpl::IsRecording()"); + CriticalSectionScoped lock(_crit); + return _recordingActive; +} + +int32_t MediaFileImpl::RecordDurationMs(uint32_t& durationMs) +{ + + CriticalSectionScoped lock(_crit); + if(!_recordingActive) + { + durationMs = 0; + return -1; + } + durationMs = _recordDurationMs; + return 0; +} + +bool MediaFileImpl::IsStereo() +{ + WEBRTC_TRACE(kTraceStream, kTraceFile, _id, "MediaFileImpl::IsStereo()"); + CriticalSectionScoped lock(_crit); + return _isStereo; +} + +int32_t MediaFileImpl::SetModuleFileCallback(FileCallback* callback) +{ + + CriticalSectionScoped lock(_callbackCrit); + + _ptrCallback = callback; + return 0; +} + +int32_t MediaFileImpl::FileDurationMs(const char* fileName, + uint32_t& durationMs, + const FileFormats format, + const uint32_t freqInHz) +{ + + if(!ValidFileName(fileName)) + { + return -1; + } + if(!ValidFrequency(freqInHz)) + { + return -1; + } + + ModuleFileUtility* utilityObj = new ModuleFileUtility(_id); + if(utilityObj == NULL) + { + WEBRTC_TRACE(kTraceError, kTraceFile, _id, + "failed to allocate utility object!"); + return -1; + } + + const int32_t duration = utilityObj->FileDurationMs(fileName, format, + freqInHz); + delete utilityObj; + if(duration == -1) + { + durationMs = 0; + return -1; + } + + durationMs = duration; + return 0; +} + +int32_t MediaFileImpl::PlayoutPositionMs(uint32_t& positionMs) const +{ + CriticalSectionScoped lock(_crit); + if(!_playingActive) + { + positionMs = 0; + return -1; + } + positionMs = _playoutPositionMs; + return 0; +} + +int32_t MediaFileImpl::codec_info(CodecInst& codecInst) const +{ + CriticalSectionScoped lock(_crit); + if(!_playingActive && !_recordingActive) + { + WEBRTC_TRACE(kTraceError, kTraceFile, _id, + "Neither playout nor recording has been initialized!"); + return -1; + } + if (codec_info_.pltype == 0 && codec_info_.plname[0] == '\0') + { + WEBRTC_TRACE(kTraceError, kTraceFile, _id, + "The CodecInst for %s is unknown!", + _playingActive ? "Playback" : "Recording"); + return -1; + } + memcpy(&codecInst,&codec_info_,sizeof(CodecInst)); + return 0; +} + +bool MediaFileImpl::ValidFileFormat(const FileFormats format, + const CodecInst* codecInst) +{ + if(codecInst == NULL) + { + if(format == kFileFormatPreencodedFile || + format == kFileFormatPcm8kHzFile || + format == kFileFormatPcm16kHzFile || + format == kFileFormatPcm32kHzFile) + { + WEBRTC_TRACE(kTraceError, kTraceFile, -1, + "Codec info required for file format specified!"); + return false; + } + } + return true; +} + +bool MediaFileImpl::ValidFileName(const char* fileName) +{ + if((fileName == NULL) ||(fileName[0] == '\0')) + { + WEBRTC_TRACE(kTraceError, kTraceFile, -1, "FileName not specified!"); + return false; + } + return true; +} + + +bool MediaFileImpl::ValidFilePositions(const uint32_t startPointMs, + const uint32_t stopPointMs) +{ + if(startPointMs == 0 && stopPointMs == 0) // Default values + { + return true; + } + if(stopPointMs &&(startPointMs >= stopPointMs)) + { + WEBRTC_TRACE(kTraceError, kTraceFile, -1, + "startPointMs must be less than stopPointMs!"); + return false; + } + if(stopPointMs &&((stopPointMs - startPointMs) < 20)) + { + WEBRTC_TRACE(kTraceError, kTraceFile, -1, + "minimum play duration for files is 20 ms!"); + return false; + } + return true; +} + +bool MediaFileImpl::ValidFrequency(const uint32_t frequency) +{ + if((frequency == 8000) || (frequency == 16000)|| (frequency == 32000)) + { + return true; + } + WEBRTC_TRACE(kTraceError, kTraceFile, -1, + "Frequency should be 8000, 16000 or 32000 (Hz)"); + return false; +} +} // namespace webrtc |