diff --git a/modules/media_file/media_file.h b/modules/media_file/media_file.h index 6a7a02efcc..23becccb06 100644 --- a/modules/media_file/media_file.h +++ b/modules/media_file/media_file.h @@ -104,70 +104,10 @@ public: virtual int32_t PlayoutPositionMs( uint32_t& durationMs) const = 0; - // Write one audio frame, i.e. the bufferLength first bytes of audioBuffer, - // to file. The audio frame size is determined by the codecInst.pacsize - // parameter of the last sucessfull StartRecordingAudioFile(..) call. - // Note: bufferLength must be exactly one frame. - virtual int32_t IncomingAudioData( - const int8_t* audioBuffer, - const size_t bufferLength) = 0; - - // Open/creates file specified by fileName for writing (relative path is - // allowed). FileCallback::RecordNotification(..) will be called after - // notificationTimeMs of audio data has been recorded if - // notificationTimeMs is greater than zero. - // format specifies the type of file that should be created/opened. - // codecInst specifies the encoding of the audio data. maxSizeBytes - // specifies the number of bytes allowed to be written to file if it is - // greater than zero. - // Note: codecInst.channels should be set to 2 for stereo (and 1 for - // mono). Stereo is only supported for WAV files. - virtual int32_t StartRecordingAudioFile( - const char* fileName, - const FileFormats format, - const CodecInst& codecInst, - const uint32_t notificationTimeMs = 0, - const uint32_t maxSizeBytes = 0) = 0; - - // Prepare for recording audio to stream. - // FileCallback::RecordNotification(..) will be called after - // notificationTimeMs of audio data has been recorded if - // notificationTimeMs is greater than zero. - // format specifies the type of file that stream should correspond to. - // codecInst specifies the encoding of the audio data. - // Note: codecInst.channels should be set to 2 for stereo (and 1 for - // mono). Stereo is only supported for WAV files. - virtual int32_t StartRecordingAudioStream( - OutStream& stream, - const FileFormats format, - const CodecInst& codecInst, - const uint32_t notificationTimeMs = 0) = 0; - - // Stop recording to file or stream. - virtual int32_t StopRecording() = 0; - - // Return true if recording. - virtual bool IsRecording() = 0; - - // Set durationMs to the number of ms that has been recorded to file. - virtual int32_t RecordDurationMs(uint32_t& durationMs) = 0; - - // Return true if recording or playing is stereo. - virtual bool IsStereo() = 0; - // Register callback to receive media file related notifications. Disables // callbacks if callback is NULL. virtual int32_t SetModuleFileCallback(FileCallback* callback) = 0; - // Set durationMs to the size of the file (in ms) specified by fileName. - // format specifies the type of file fileName refers to. freqInHz specifies - // the sampling frequency of the file. - virtual int32_t FileDurationMs( - const char* fileName, - uint32_t& durationMs, - const FileFormats format, - const uint32_t freqInHz = 16000) = 0; - // Update codecInst according to the current audio codec being used for // reading or writing. virtual int32_t codec_info(CodecInst& codecInst) const = 0; diff --git a/modules/media_file/media_file_impl.cc b/modules/media_file/media_file_impl.cc index 0fd9d9ee6a..5c1a080bde 100644 --- a/modules/media_file/media_file_impl.cc +++ b/modules/media_file/media_file_impl.cc @@ -31,11 +31,9 @@ MediaFileImpl::MediaFileImpl(const int32_t id) _ptrInStream(NULL), _ptrOutStream(NULL), _fileFormat((FileFormats)-1), - _recordDurationMs(0), _playoutPositionMs(0), _notificationMs(0), _playingActive(false), - _recordingActive(false), _isStereo(false), _openFile(false), _fileName(), @@ -55,10 +53,6 @@ MediaFileImpl::~MediaFileImpl() { StopPlaying(); } - if (_recordingActive) { - StopRecording(); - } - delete _ptrFileUtilityObj; if (_openFile) { @@ -333,9 +327,9 @@ int32_t MediaFileImpl::StartPlayingStream(InStream& stream, } rtc::CritScope lock(&_crit); - if (_playingActive || _recordingActive) { + if (_playingActive) { RTC_LOG(LS_ERROR) - << "StartPlaying called, but already playing or recording file " + << "StartPlaying called, but already playing file " << ((_fileName[0] == '\0') ? "(name not set)" : _fileName); return -1; } @@ -465,322 +459,6 @@ bool MediaFileImpl::IsPlaying() { return _playingActive; } -int32_t MediaFileImpl::IncomingAudioData(const int8_t* buffer, - const size_t bufferLengthInBytes) { - RTC_LOG(LS_INFO) << "MediaFile::IncomingData(buffer= " - << static_cast(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(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); @@ -788,35 +466,6 @@ int32_t MediaFileImpl::SetModuleFileCallback(FileCallback* 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) { @@ -829,14 +478,12 @@ int32_t MediaFileImpl::PlayoutPositionMs(uint32_t& positionMs) const { 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!"; + if (!_playingActive) { + RTC_LOG(LS_ERROR) << "Playout has not 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!"; + RTC_LOG(LS_ERROR) << "The CodecInst for Playback is unknown!"; return -1; } memcpy(&codecInst, &codec_info_, sizeof(CodecInst)); diff --git a/modules/media_file/media_file_impl.h b/modules/media_file/media_file_impl.h index 7716d81078..f3ef595cd7 100644 --- a/modules/media_file/media_file_impl.h +++ b/modules/media_file/media_file_impl.h @@ -60,36 +60,8 @@ public: int32_t PlayoutPositionMs(uint32_t& positionMs) const override; - int32_t IncomingAudioData(const int8_t* audioBuffer, - const size_t bufferLength) override; - - int32_t StartRecordingAudioFile(const char* fileName, - const FileFormats format, - const CodecInst& codecInst, - const uint32_t notificationTimeMs = 0, - const uint32_t maxSizeBytes = 0) override; - - int32_t StartRecordingAudioStream( - OutStream& stream, - const FileFormats format, - const CodecInst& codecInst, - const uint32_t notificationTimeMs = 0) override; - - int32_t StopRecording() override; - - bool IsRecording() override; - - int32_t RecordDurationMs(uint32_t& durationMs) override; - - bool IsStereo() override; - int32_t SetModuleFileCallback(FileCallback* callback) override; - int32_t FileDurationMs(const char* fileName, - uint32_t& durationMs, - const FileFormats format, - const uint32_t freqInHz = 16000) override; - int32_t codec_info(CodecInst& codecInst) const override; private: @@ -130,12 +102,10 @@ private: OutStream* _ptrOutStream; FileFormats _fileFormat; - uint32_t _recordDurationMs; uint32_t _playoutPositionMs; uint32_t _notificationMs; bool _playingActive; - bool _recordingActive; bool _isStereo; bool _openFile; diff --git a/modules/media_file/media_file_unittest.cc b/modules/media_file/media_file_unittest.cc index 7df1a68cde..d06e77692a 100644 --- a/modules/media_file/media_file_unittest.cc +++ b/modules/media_file/media_file_unittest.cc @@ -51,56 +51,3 @@ TEST_F(MediaFileTest, MAYBE_StartPlayingAudioFileWithoutError) { ASSERT_EQ(0, media_file_->StopPlaying()); } - -#if defined(WEBRTC_IOS) -#define MAYBE_WriteWavFile DISABLED_WriteWavFile -#else -#define MAYBE_WriteWavFile WriteWavFile -#endif -TEST_F(MediaFileTest, MAYBE_WriteWavFile) { - // Write file. - static const size_t kHeaderSize = 44; - static const size_t kPayloadSize = 320; - webrtc::CodecInst codec = { - 0, "L16", 16000, static_cast(kPayloadSize), 1 - }; - std::string outfile = webrtc::test::OutputPath() + "wavtest.wav"; - ASSERT_EQ(0, - media_file_->StartRecordingAudioFile( - outfile.c_str(), webrtc::kFileFormatWavFile, codec)); - static const int8_t kFakeData[kPayloadSize] = {0}; - ASSERT_EQ(0, media_file_->IncomingAudioData(kFakeData, kPayloadSize)); - ASSERT_EQ(0, media_file_->StopRecording()); - - // Check the file we just wrote. - static const uint8_t kExpectedHeader[] = { - 'R', 'I', 'F', 'F', - 0x64, 0x1, 0, 0, // size of whole file - 8: 320 + 44 - 8 - 'W', 'A', 'V', 'E', - 'f', 'm', 't', ' ', - 0x10, 0, 0, 0, // size of fmt block - 8: 24 - 8 - 0x1, 0, // format: PCM (1) - 0x1, 0, // channels: 1 - 0x80, 0x3e, 0, 0, // sample rate: 16000 - 0, 0x7d, 0, 0, // byte rate: 2 * 16000 - 0x2, 0, // block align: NumChannels * BytesPerSample - 0x10, 0, // bits per sample: 2 * 8 - 'd', 'a', 't', 'a', - 0x40, 0x1, 0, 0, // size of payload: 320 - }; - static_assert(sizeof(kExpectedHeader) == kHeaderSize, "header size"); - - EXPECT_EQ(kHeaderSize + kPayloadSize, webrtc::test::GetFileSize(outfile)); - FILE* f = fopen(outfile.c_str(), "rb"); - ASSERT_TRUE(f); - - uint8_t header[kHeaderSize]; - ASSERT_EQ(1u, fread(header, kHeaderSize, 1, f)); - EXPECT_EQ(0, memcmp(kExpectedHeader, header, kHeaderSize)); - - uint8_t payload[kPayloadSize]; - ASSERT_EQ(1u, fread(payload, kPayloadSize, 1, f)); - EXPECT_EQ(0, memcmp(kFakeData, payload, kPayloadSize)); - - EXPECT_EQ(0, fclose(f)); -}