Index: webrtc/modules/utility/source/file_recorder_impl.cc |
diff --git a/webrtc/modules/utility/source/file_recorder_impl.cc b/webrtc/modules/utility/source/file_recorder_impl.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..82b37f0118e1ecda2f2577c4742387bfca86ae63 |
--- /dev/null |
+++ b/webrtc/modules/utility/source/file_recorder_impl.cc |
@@ -0,0 +1,259 @@ |
+/* |
+ * 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/engine_configurations.h" |
+#include "webrtc/modules/media_file/media_file.h" |
+#include "webrtc/modules/utility/source/file_recorder_impl.h" |
+#include "webrtc/system_wrappers/include/logging.h" |
+ |
+namespace webrtc { |
+FileRecorder* FileRecorder::CreateFileRecorder(uint32_t instanceID, |
+ FileFormats fileFormat) |
+{ |
+ return new FileRecorderImpl(instanceID, fileFormat); |
+} |
+ |
+void FileRecorder::DestroyFileRecorder(FileRecorder* recorder) |
+{ |
+ delete recorder; |
+} |
+ |
+FileRecorderImpl::FileRecorderImpl(uint32_t instanceID, |
+ FileFormats fileFormat) |
+ : _instanceID(instanceID), |
+ _fileFormat(fileFormat), |
+ _moduleFile(MediaFile::CreateMediaFile(_instanceID)), |
+ codec_info_(), |
+ _audioBuffer(), |
+ _audioEncoder(instanceID), |
+ _audioResampler() |
+{ |
+} |
+ |
+FileRecorderImpl::~FileRecorderImpl() |
+{ |
+ MediaFile::DestroyMediaFile(_moduleFile); |
+} |
+ |
+FileFormats FileRecorderImpl::RecordingFileFormat() const |
+{ |
+ return _fileFormat; |
+} |
+ |
+int32_t FileRecorderImpl::RegisterModuleFileCallback( |
+ FileCallback* callback) |
+{ |
+ if(_moduleFile == NULL) |
+ { |
+ return -1; |
+ } |
+ return _moduleFile->SetModuleFileCallback(callback); |
+} |
+ |
+int32_t FileRecorderImpl::StartRecordingAudioFile( |
+ const char* fileName, |
+ const CodecInst& codecInst, |
+ uint32_t notificationTimeMs) |
+{ |
+ if(_moduleFile == NULL) |
+ { |
+ return -1; |
+ } |
+ codec_info_ = codecInst; |
+ int32_t retVal = 0; |
+ retVal =_moduleFile->StartRecordingAudioFile(fileName, _fileFormat, |
+ codecInst, |
+ notificationTimeMs); |
+ |
+ if( retVal == 0) |
+ { |
+ retVal = SetUpAudioEncoder(); |
+ } |
+ if( retVal != 0) |
+ { |
+ LOG(LS_WARNING) << "Failed to initialize file " << fileName |
+ << " for recording."; |
+ |
+ if(IsRecording()) |
+ { |
+ StopRecording(); |
+ } |
+ } |
+ return retVal; |
+} |
+ |
+int32_t FileRecorderImpl::StartRecordingAudioFile( |
+ OutStream& destStream, |
+ const CodecInst& codecInst, |
+ uint32_t notificationTimeMs) |
+{ |
+ codec_info_ = codecInst; |
+ int32_t retVal = _moduleFile->StartRecordingAudioStream( |
+ destStream, |
+ _fileFormat, |
+ codecInst, |
+ notificationTimeMs); |
+ |
+ if( retVal == 0) |
+ { |
+ retVal = SetUpAudioEncoder(); |
+ } |
+ if( retVal != 0) |
+ { |
+ LOG(LS_WARNING) << "Failed to initialize outStream for recording."; |
+ |
+ if(IsRecording()) |
+ { |
+ StopRecording(); |
+ } |
+ } |
+ return retVal; |
+} |
+ |
+int32_t FileRecorderImpl::StopRecording() |
+{ |
+ memset(&codec_info_, 0, sizeof(CodecInst)); |
+ return _moduleFile->StopRecording(); |
+} |
+ |
+bool FileRecorderImpl::IsRecording() const |
+{ |
+ return _moduleFile->IsRecording(); |
+} |
+ |
+int32_t FileRecorderImpl::RecordAudioToFile( |
+ const AudioFrame& incomingAudioFrame) |
+{ |
+ if (codec_info_.plfreq == 0) |
+ { |
+ LOG(LS_WARNING) << "RecordAudioToFile() recording audio is not " |
+ << "turned on."; |
+ return -1; |
+ } |
+ AudioFrame tempAudioFrame; |
+ tempAudioFrame.samples_per_channel_ = 0; |
+ if( incomingAudioFrame.num_channels_ == 2 && |
+ !_moduleFile->IsStereo()) |
+ { |
+ // Recording mono but incoming audio is (interleaved) stereo. |
+ tempAudioFrame.num_channels_ = 1; |
+ tempAudioFrame.sample_rate_hz_ = incomingAudioFrame.sample_rate_hz_; |
+ tempAudioFrame.samples_per_channel_ = |
+ incomingAudioFrame.samples_per_channel_; |
+ for (size_t i = 0; |
+ i < (incomingAudioFrame.samples_per_channel_); i++) |
+ { |
+ // Sample value is the average of left and right buffer rounded to |
+ // closest integer value. Note samples can be either 1 or 2 byte. |
+ tempAudioFrame.data_[i] = |
+ ((incomingAudioFrame.data_[2 * i] + |
+ incomingAudioFrame.data_[(2 * i) + 1] + 1) >> 1); |
+ } |
+ } |
+ else if( incomingAudioFrame.num_channels_ == 1 && |
+ _moduleFile->IsStereo()) |
+ { |
+ // Recording stereo but incoming audio is mono. |
+ tempAudioFrame.num_channels_ = 2; |
+ tempAudioFrame.sample_rate_hz_ = incomingAudioFrame.sample_rate_hz_; |
+ tempAudioFrame.samples_per_channel_ = |
+ incomingAudioFrame.samples_per_channel_; |
+ for (size_t i = 0; |
+ i < (incomingAudioFrame.samples_per_channel_); i++) |
+ { |
+ // Duplicate sample to both channels |
+ tempAudioFrame.data_[2*i] = |
+ incomingAudioFrame.data_[i]; |
+ tempAudioFrame.data_[2*i+1] = |
+ incomingAudioFrame.data_[i]; |
+ } |
+ } |
+ |
+ const AudioFrame* ptrAudioFrame = &incomingAudioFrame; |
+ if(tempAudioFrame.samples_per_channel_ != 0) |
+ { |
+ // If ptrAudioFrame is not empty it contains the audio to be recorded. |
+ ptrAudioFrame = &tempAudioFrame; |
+ } |
+ |
+ // Encode the audio data before writing to file. Don't encode if the codec |
+ // is PCM. |
+ // NOTE: stereo recording is only supported for WAV files. |
+ // TODO (hellner): WAV expect PCM in little endian byte order. Not |
+ // "encoding" with PCM coder should be a problem for big endian systems. |
+ size_t encodedLenInBytes = 0; |
+ if (_fileFormat == kFileFormatPreencodedFile || |
+ STR_CASE_CMP(codec_info_.plname, "L16") != 0) |
+ { |
+ if (_audioEncoder.Encode(*ptrAudioFrame, _audioBuffer, |
+ encodedLenInBytes) == -1) |
+ { |
+ LOG(LS_WARNING) << "RecordAudioToFile() codec " |
+ << codec_info_.plname |
+ << " not supported or failed to encode stream."; |
+ return -1; |
+ } |
+ } else { |
+ size_t outLen = 0; |
+ _audioResampler.ResetIfNeeded(ptrAudioFrame->sample_rate_hz_, |
+ codec_info_.plfreq, |
+ ptrAudioFrame->num_channels_); |
+ _audioResampler.Push(ptrAudioFrame->data_, |
+ ptrAudioFrame->samples_per_channel_ * |
+ ptrAudioFrame->num_channels_, |
+ (int16_t*)_audioBuffer, |
+ MAX_AUDIO_BUFFER_IN_BYTES, outLen); |
+ encodedLenInBytes = outLen * sizeof(int16_t); |
+ } |
+ |
+ // Codec may not be operating at a frame rate of 10 ms. Whenever enough |
+ // 10 ms chunks of data has been pushed to the encoder an encoded frame |
+ // will be available. Wait until then. |
+ if (encodedLenInBytes) |
+ { |
+ if (WriteEncodedAudioData(_audioBuffer, encodedLenInBytes) == -1) |
+ { |
+ return -1; |
+ } |
+ } |
+ return 0; |
+} |
+ |
+int32_t FileRecorderImpl::SetUpAudioEncoder() |
+{ |
+ if (_fileFormat == kFileFormatPreencodedFile || |
+ STR_CASE_CMP(codec_info_.plname, "L16") != 0) |
+ { |
+ if(_audioEncoder.SetEncodeCodec(codec_info_) == -1) |
+ { |
+ LOG(LS_ERROR) << "SetUpAudioEncoder() codec " |
+ << codec_info_.plname << " not supported."; |
+ return -1; |
+ } |
+ } |
+ return 0; |
+} |
+ |
+int32_t FileRecorderImpl::codec_info(CodecInst& codecInst) const |
+{ |
+ if(codec_info_.plfreq == 0) |
+ { |
+ return -1; |
+ } |
+ codecInst = codec_info_; |
+ return 0; |
+} |
+ |
+int32_t FileRecorderImpl::WriteEncodedAudioData(const int8_t* audioBuffer, |
+ size_t bufferLength) |
+{ |
+ return _moduleFile->IncomingAudioData(audioBuffer, bufferLength); |
+} |
+} // namespace webrtc |