blob: 0fd9d9ee6abc85d5e002e25a857ebd92e2a83f9f [file] [log] [blame]
/*
* 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 "modules/media_file/media_file_impl.h"
#include "rtc_base/format_macros.h"
#include "rtc_base/logging.h"
#include "system_wrappers/include/file_wrapper.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),
_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) {
RTC_LOG(LS_INFO) << "MediaFileImpl()";
codec_info_.plname[0] = '\0';
_fileName[0] = '\0';
}
MediaFileImpl::~MediaFileImpl() {
RTC_LOG(LS_INFO) << "~MediaFileImpl()";
{
rtc::CritScope lock(&_crit);
if (_playingActive) {
StopPlaying();
}
if (_recordingActive) {
StopRecording();
}
delete _ptrFileUtilityObj;
if (_openFile) {
delete _ptrInStream;
_ptrInStream = NULL;
delete _ptrOutStream;
_ptrOutStream = NULL;
}
}
}
int64_t MediaFileImpl::TimeUntilNextProcess() {
RTC_LOG(LS_WARNING)
<< "TimeUntilNextProcess: This method is not used by MediaFile class.";
return -1;
}
void MediaFileImpl::Process() {
RTC_LOG(LS_WARNING) << "Process: This method is not used by MediaFile class.";
}
int32_t MediaFileImpl::PlayoutAudioData(int8_t* buffer,
size_t& dataLengthInBytes) {
RTC_LOG(LS_INFO) << "MediaFileImpl::PlayoutData(buffer= "
<< static_cast<void*>(buffer)
<< ", bufLen= " << dataLengthInBytes << ")";
const size_t bufferLengthInBytes = dataLengthInBytes;
dataLengthInBytes = 0;
if (buffer == NULL || bufferLengthInBytes == 0) {
RTC_LOG(LS_ERROR) << "Buffer pointer or length is NULL!";
return -1;
}
int32_t bytesRead = 0;
{
rtc::CritScope lock(&_crit);
if (!_playingActive) {
RTC_LOG(LS_WARNING) << "Not currently playing!";
return -1;
}
if (!_ptrFileUtilityObj) {
RTC_LOG(LS_ERROR) << "Playing, but no FileUtility object!";
StopPlaying();
return -1;
}
switch (_fileFormat) {
case kFileFormatPcm48kHzFile:
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: {
RTC_LOG(LS_ERROR) << "Invalid file format: " << _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.
rtc::CritScope 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) {
RTC_LOG(LS_INFO) << "MediaFileImpl::PlayoutStereoData(Left = "
<< static_cast<void*>(bufferLeft)
<< ", Right = " << static_cast<void*>(bufferRight)
<< ", Len= " << dataLengthInBytes << ")";
const size_t bufferLengthInBytes = dataLengthInBytes;
dataLengthInBytes = 0;
if (bufferLeft == NULL || bufferRight == NULL || bufferLengthInBytes == 0) {
RTC_LOG(LS_ERROR) << "A buffer pointer or the length is NULL!";
return -1;
}
bool playEnded = false;
uint32_t callbackNotifyMs = 0;
{
rtc::CritScope lock(&_crit);
if (!_playingActive || !_isStereo) {
RTC_LOG(LS_WARNING) << "Not currently playing stereo!";
return -1;
}
if (!_ptrFileUtilityObj) {
RTC_LOG(LS_ERROR)
<< "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:
RTC_LOG(LS_ERROR)
<< "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;
}
}
rtc::CritScope 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))) {
RTC_LOG(LS_ERROR) << "specified notification time is longer than amount of"
<< " ms that will be played";
return -1;
}
FileWrapper* inputStream = FileWrapper::Create();
if (inputStream == NULL) {
RTC_LOG(LS_INFO) << "Failed to allocate input stream for file " << fileName;
return -1;
}
if (!inputStream->OpenFile(fileName, true)) {
delete inputStream;
RTC_LOG(LS_ERROR) << "Could not open input file " << fileName;
return -1;
}
if (StartPlayingStream(*inputStream, loop, notificationTimeMs, format,
codecInst, startPointMs, stopPointMs) == -1) {
inputStream->CloseFile();
delete inputStream;
return -1;
}
rtc::CritScope 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;
}
rtc::CritScope lock(&_crit);
if (_playingActive || _recordingActive) {
RTC_LOG(LS_ERROR)
<< "StartPlaying called, but already playing or recording file "
<< ((_fileName[0] == '\0') ? "(name not set)" : _fileName);
return -1;
}
if (_ptrFileUtilityObj != NULL) {
RTC_LOG(LS_ERROR)
<< "StartPlaying called, but FileUtilityObj already exists!";
StopPlaying();
return -1;
}
_ptrFileUtilityObj = new ModuleFileUtility();
if (_ptrFileUtilityObj == NULL) {
RTC_LOG(LS_INFO) << "Failed to create FileUtilityObj!";
return -1;
}
switch (format) {
case kFileFormatWavFile: {
if (_ptrFileUtilityObj->InitWavReading(stream, startPointMs,
stopPointMs) == -1) {
RTC_LOG(LS_ERROR) << "Not a valid WAV file!";
StopPlaying();
return -1;
}
_fileFormat = kFileFormatWavFile;
break;
}
case kFileFormatCompressedFile: {
if (_ptrFileUtilityObj->InitCompressedReading(stream, startPointMs,
stopPointMs) == -1) {
RTC_LOG(LS_ERROR) << "Not a valid Compressed file!";
StopPlaying();
return -1;
}
_fileFormat = kFileFormatCompressedFile;
break;
}
case kFileFormatPcm8kHzFile:
case kFileFormatPcm16kHzFile:
case kFileFormatPcm32kHzFile:
case kFileFormatPcm48kHzFile: {
// 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) {
RTC_LOG(LS_ERROR) << "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) {
RTC_LOG(LS_ERROR) << "Not a valid PreEncoded file!";
StopPlaying();
return -1;
}
_fileFormat = kFileFormatPreencodedFile;
break;
}
default: {
RTC_LOG(LS_ERROR) << "Invalid file format: " << format;
assert(false);
break;
}
}
if (_ptrFileUtilityObj->codec_info(codec_info_) == -1) {
RTC_LOG(LS_ERROR) << "Failed to retrieve codec info!";
StopPlaying();
return -1;
}
_isStereo = (codec_info_.channels == 2);
if (_isStereo && (_fileFormat != kFileFormatWavFile)) {
RTC_LOG(LS_WARNING) << "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() {
rtc::CritScope 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) {
RTC_LOG(LS_WARNING) << "playing is not active!";
return -1;
}
_playingActive = false;
return 0;
}
bool MediaFileImpl::IsPlaying() {
RTC_LOG(LS_VERBOSE) << "MediaFileImpl::IsPlaying()";
rtc::CritScope lock(&_crit);
return _playingActive;
}
int32_t MediaFileImpl::IncomingAudioData(const int8_t* buffer,
const size_t bufferLengthInBytes) {
RTC_LOG(LS_INFO) << "MediaFile::IncomingData(buffer= "
<< static_cast<const void*>(buffer)
<< ", bufLen= " << bufferLengthInBytes << ")";
if (buffer == NULL || bufferLengthInBytes == 0) {
RTC_LOG(LS_ERROR) << "Buffer pointer or length is NULL!";
return -1;
}
bool recordingEnded = false;
uint32_t callbackNotifyMs = 0;
{
rtc::CritScope lock(&_crit);
if (!_recordingActive) {
RTC_LOG(LS_WARNING) << "Not currently recording!";
return -1;
}
if (_ptrOutStream == NULL) {
RTC_LOG(LS_ERROR) << "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:
case kFileFormatPcm48kHzFile:
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:
RTC_LOG(LS_ERROR) << "Invalid file format: " << _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) {
RTC_LOG(LS_WARNING) << "Failed to write all requested bytes!";
StopRecording();
recordingEnded = true;
}
}
// Only _callbackCrit may and should be taken when making callbacks.
rtc::CritScope 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) {
RTC_LOG(LS_INFO) << "Failed to allocate memory for output stream";
return -1;
}
if (!outputStream->OpenFile(fileName, false)) {
delete outputStream;
RTC_LOG(LS_ERROR) << "Could not open output file '" << fileName
<< "' for writing!";
return -1;
}
if (maxSizeBytes) {
outputStream->SetMaxFileSize(maxSizeBytes);
}
if (StartRecordingAudioStream(*outputStream, format, codecInst,
notificationTimeMs) == -1) {
outputStream->CloseFile();
delete outputStream;
return -1;
}
rtc::CritScope 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;
}
rtc::CritScope lock(&_crit);
if (_recordingActive || _playingActive) {
RTC_LOG(LS_ERROR)
<< "StartRecording called, but already recording or playing file "
<< _fileName << "!";
return -1;
}
if (_ptrFileUtilityObj != NULL) {
RTC_LOG(LS_ERROR)
<< "StartRecording called, but fileUtilityObj already exists!";
StopRecording();
return -1;
}
_ptrFileUtilityObj = new ModuleFileUtility();
if (_ptrFileUtilityObj == NULL) {
RTC_LOG(LS_INFO) << "Cannot allocate fileUtilityObj!";
return -1;
}
CodecInst tmpAudioCodec;
memcpy(&tmpAudioCodec, &codecInst, sizeof(CodecInst));
switch (format) {
case kFileFormatWavFile: {
if (_ptrFileUtilityObj->InitWavWriting(stream, codecInst) == -1) {
RTC_LOG(LS_ERROR) << "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) {
RTC_LOG(LS_ERROR) << "Failed to initialize Compressed file!";
delete _ptrFileUtilityObj;
_ptrFileUtilityObj = NULL;
return -1;
}
_fileFormat = kFileFormatCompressedFile;
break;
}
case kFileFormatPcm8kHzFile:
case kFileFormatPcm16kHzFile:
case kFileFormatPcm32kHzFile:
case kFileFormatPcm48kHzFile: {
if (!ValidFrequency(codecInst.plfreq) ||
_ptrFileUtilityObj->InitPCMWriting(stream, codecInst.plfreq) == -1) {
RTC_LOG(LS_ERROR) << "Failed to initialize PCM file!";
delete _ptrFileUtilityObj;
_ptrFileUtilityObj = NULL;
return -1;
}
_fileFormat = format;
break;
}
case kFileFormatPreencodedFile: {
if (_ptrFileUtilityObj->InitPreEncodedWriting(stream, codecInst) == -1) {
RTC_LOG(LS_ERROR) << "Failed to initialize Pre-Encoded file!";
delete _ptrFileUtilityObj;
_ptrFileUtilityObj = NULL;
return -1;
}
_fileFormat = kFileFormatPreencodedFile;
break;
}
default: {
RTC_LOG(LS_ERROR) << "Invalid file format " << format << " specified!";
delete _ptrFileUtilityObj;
_ptrFileUtilityObj = NULL;
return -1;
}
}
_isStereo = (tmpAudioCodec.channels == 2);
if (_isStereo) {
if (_fileFormat != kFileFormatWavFile) {
RTC_LOG(LS_WARNING) << "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)) {
RTC_LOG(LS_WARNING)
<< "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() {
rtc::CritScope lock(&_crit);
if (!_recordingActive) {
RTC_LOG(LS_WARNING) << "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() {
RTC_LOG(LS_VERBOSE) << "MediaFileImpl::IsRecording()";
rtc::CritScope lock(&_crit);
return _recordingActive;
}
int32_t MediaFileImpl::RecordDurationMs(uint32_t& durationMs) {
rtc::CritScope lock(&_crit);
if (!_recordingActive) {
durationMs = 0;
return -1;
}
durationMs = _recordDurationMs;
return 0;
}
bool MediaFileImpl::IsStereo() {
RTC_LOG(LS_VERBOSE) << "MediaFileImpl::IsStereo()";
rtc::CritScope lock(&_crit);
return _isStereo;
}
int32_t MediaFileImpl::SetModuleFileCallback(FileCallback* callback) {
rtc::CritScope 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();
if (utilityObj == NULL) {
RTC_LOG(LS_ERROR) << "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 {
rtc::CritScope lock(&_crit);
if (!_playingActive) {
positionMs = 0;
return -1;
}
positionMs = _playoutPositionMs;
return 0;
}
int32_t MediaFileImpl::codec_info(CodecInst& codecInst) const {
rtc::CritScope lock(&_crit);
if (!_playingActive && !_recordingActive) {
RTC_LOG(LS_ERROR) << "Neither playout nor recording has been initialized!";
return -1;
}
if (codec_info_.pltype == 0 && codec_info_.plname[0] == '\0') {
RTC_LOG(LS_ERROR) << "The CodecInst for "
<< (_playingActive ? "Playback" : "Recording")
<< " is unknown!";
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 ||
format == kFileFormatPcm48kHzFile) {
RTC_LOG(LS_ERROR) << "Codec info required for file format specified!";
return false;
}
}
return true;
}
bool MediaFileImpl::ValidFileName(const char* fileName) {
if ((fileName == NULL) || (fileName[0] == '\0')) {
RTC_LOG(LS_ERROR) << "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)) {
RTC_LOG(LS_ERROR) << "startPointMs must be less than stopPointMs!";
return false;
}
if (stopPointMs && ((stopPointMs - startPointMs) < 20)) {
RTC_LOG(LS_ERROR) << "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) ||
(frequency == 48000)) {
return true;
}
RTC_LOG(LS_ERROR) << "Frequency should be 8000, 16000, 32000, or 48000 (Hz)";
return false;
}
} // namespace webrtc