LCOV - code coverage report
Current view: top level - media/webrtc/trunk/webrtc/voice_engine - file_recorder.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 105 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 14 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
       3             :  *
       4             :  *  Use of this source code is governed by a BSD-style license
       5             :  *  that can be found in the LICENSE file in the root of the source
       6             :  *  tree. An additional intellectual property rights grant can be found
       7             :  *  in the file PATENTS.  All contributing project authors may
       8             :  *  be found in the AUTHORS file in the root of the source tree.
       9             :  */
      10             : 
      11             : #include "webrtc/voice_engine/file_recorder.h"
      12             : 
      13             : #include <list>
      14             : 
      15             : #include "webrtc/base/platform_thread.h"
      16             : #include "webrtc/common_audio/resampler/include/resampler.h"
      17             : #include "webrtc/common_types.h"
      18             : #include "webrtc/modules/include/module_common_types.h"
      19             : #include "webrtc/modules/media_file/media_file.h"
      20             : #include "webrtc/modules/media_file/media_file_defines.h"
      21             : #include "webrtc/system_wrappers/include/event_wrapper.h"
      22             : #include "webrtc/system_wrappers/include/logging.h"
      23             : #include "webrtc/typedefs.h"
      24             : #include "webrtc/voice_engine/coder.h"
      25             : 
      26             : namespace webrtc {
      27             : 
      28             : namespace {
      29             : 
      30             : // The largest decoded frame size in samples (60ms with 32kHz sample rate).
      31             : enum { MAX_AUDIO_BUFFER_IN_SAMPLES = 60 * 32 };
      32             : enum { MAX_AUDIO_BUFFER_IN_BYTES = MAX_AUDIO_BUFFER_IN_SAMPLES * 2 };
      33             : enum { kMaxAudioBufferQueueLength = 100 };
      34             : 
      35             : class CriticalSectionWrapper;
      36             : 
      37             : class FileRecorderImpl : public FileRecorder {
      38             :  public:
      39             :   FileRecorderImpl(uint32_t instanceID, FileFormats fileFormat);
      40             :   ~FileRecorderImpl() override;
      41             : 
      42             :   // FileRecorder functions.
      43             :   int32_t RegisterModuleFileCallback(FileCallback* callback) override;
      44             :   FileFormats RecordingFileFormat() const override;
      45             :   int32_t StartRecordingAudioFile(const char* fileName,
      46             :                                   const CodecInst& codecInst,
      47             :                                   uint32_t notificationTimeMs) override;
      48             :   int32_t StartRecordingAudioFile(OutStream* destStream,
      49             :                                   const CodecInst& codecInst,
      50             :                                   uint32_t notificationTimeMs) override;
      51             :   int32_t StopRecording() override;
      52             :   bool IsRecording() const override;
      53             :   int32_t codec_info(CodecInst* codecInst) const override;
      54             :   int32_t RecordAudioToFile(const AudioFrame& frame) override;
      55             : 
      56             :  private:
      57             :   int32_t WriteEncodedAudioData(const int8_t* audioBuffer, size_t bufferLength);
      58             : 
      59             :   int32_t SetUpAudioEncoder();
      60             : 
      61             :   uint32_t _instanceID;
      62             :   FileFormats _fileFormat;
      63             :   MediaFile* _moduleFile;
      64             : 
      65             :   CodecInst codec_info_;
      66             :   int8_t _audioBuffer[MAX_AUDIO_BUFFER_IN_BYTES];
      67             :   AudioCoder _audioEncoder;
      68             :   Resampler _audioResampler;
      69             : };
      70             : 
      71           0 : FileRecorderImpl::FileRecorderImpl(uint32_t instanceID, FileFormats fileFormat)
      72             :     : _instanceID(instanceID),
      73             :       _fileFormat(fileFormat),
      74           0 :       _moduleFile(MediaFile::CreateMediaFile(_instanceID)),
      75             :       codec_info_(),
      76             :       _audioBuffer(),
      77             :       _audioEncoder(instanceID),
      78           0 :       _audioResampler() {}
      79             : 
      80           0 : FileRecorderImpl::~FileRecorderImpl() {
      81           0 :   MediaFile::DestroyMediaFile(_moduleFile);
      82           0 : }
      83             : 
      84           0 : FileFormats FileRecorderImpl::RecordingFileFormat() const {
      85           0 :   return _fileFormat;
      86             : }
      87             : 
      88           0 : int32_t FileRecorderImpl::RegisterModuleFileCallback(FileCallback* callback) {
      89           0 :   if (_moduleFile == NULL) {
      90           0 :     return -1;
      91             :   }
      92           0 :   return _moduleFile->SetModuleFileCallback(callback);
      93             : }
      94             : 
      95           0 : int32_t FileRecorderImpl::StartRecordingAudioFile(const char* fileName,
      96             :                                                   const CodecInst& codecInst,
      97             :                                                   uint32_t notificationTimeMs) {
      98           0 :   if (_moduleFile == NULL) {
      99           0 :     return -1;
     100             :   }
     101           0 :   codec_info_ = codecInst;
     102           0 :   int32_t retVal = 0;
     103           0 :   retVal = _moduleFile->StartRecordingAudioFile(fileName, _fileFormat,
     104           0 :                                                 codecInst, notificationTimeMs);
     105             : 
     106           0 :   if (retVal == 0) {
     107           0 :     retVal = SetUpAudioEncoder();
     108             :   }
     109           0 :   if (retVal != 0) {
     110           0 :     LOG(LS_WARNING) << "Failed to initialize file " << fileName
     111           0 :                     << " for recording.";
     112             : 
     113           0 :     if (IsRecording()) {
     114           0 :       StopRecording();
     115             :     }
     116             :   }
     117           0 :   return retVal;
     118             : }
     119             : 
     120           0 : int32_t FileRecorderImpl::StartRecordingAudioFile(OutStream* destStream,
     121             :                                                   const CodecInst& codecInst,
     122             :                                                   uint32_t notificationTimeMs) {
     123           0 :   codec_info_ = codecInst;
     124           0 :   int32_t retVal = _moduleFile->StartRecordingAudioStream(
     125           0 :       *destStream, _fileFormat, codecInst, notificationTimeMs);
     126             : 
     127           0 :   if (retVal == 0) {
     128           0 :     retVal = SetUpAudioEncoder();
     129             :   }
     130           0 :   if (retVal != 0) {
     131           0 :     LOG(LS_WARNING) << "Failed to initialize outStream for recording.";
     132             : 
     133           0 :     if (IsRecording()) {
     134           0 :       StopRecording();
     135             :     }
     136             :   }
     137           0 :   return retVal;
     138             : }
     139             : 
     140           0 : int32_t FileRecorderImpl::StopRecording() {
     141           0 :   memset(&codec_info_, 0, sizeof(CodecInst));
     142           0 :   return _moduleFile->StopRecording();
     143             : }
     144             : 
     145           0 : bool FileRecorderImpl::IsRecording() const {
     146           0 :   return _moduleFile->IsRecording();
     147             : }
     148             : 
     149           0 : int32_t FileRecorderImpl::RecordAudioToFile(
     150             :     const AudioFrame& incomingAudioFrame) {
     151           0 :   if (codec_info_.plfreq == 0) {
     152           0 :     LOG(LS_WARNING) << "RecordAudioToFile() recording audio is not "
     153           0 :                     << "turned on.";
     154           0 :     return -1;
     155             :   }
     156           0 :   AudioFrame tempAudioFrame;
     157           0 :   tempAudioFrame.samples_per_channel_ = 0;
     158           0 :   if (incomingAudioFrame.num_channels_ == 2 && !_moduleFile->IsStereo()) {
     159             :     // Recording mono but incoming audio is (interleaved) stereo.
     160           0 :     tempAudioFrame.num_channels_ = 1;
     161           0 :     tempAudioFrame.sample_rate_hz_ = incomingAudioFrame.sample_rate_hz_;
     162           0 :     tempAudioFrame.samples_per_channel_ =
     163           0 :         incomingAudioFrame.samples_per_channel_;
     164           0 :     for (size_t i = 0; i < (incomingAudioFrame.samples_per_channel_); i++) {
     165             :       // Sample value is the average of left and right buffer rounded to
     166             :       // closest integer value. Note samples can be either 1 or 2 byte.
     167           0 :       tempAudioFrame.data_[i] = ((incomingAudioFrame.data_[2 * i] +
     168           0 :                                   incomingAudioFrame.data_[(2 * i) + 1] + 1) >>
     169           0 :                                  1);
     170             :     }
     171           0 :   } else if (incomingAudioFrame.num_channels_ == 1 && _moduleFile->IsStereo()) {
     172             :     // Recording stereo but incoming audio is mono.
     173           0 :     tempAudioFrame.num_channels_ = 2;
     174           0 :     tempAudioFrame.sample_rate_hz_ = incomingAudioFrame.sample_rate_hz_;
     175           0 :     tempAudioFrame.samples_per_channel_ =
     176           0 :         incomingAudioFrame.samples_per_channel_;
     177           0 :     for (size_t i = 0; i < (incomingAudioFrame.samples_per_channel_); i++) {
     178             :       // Duplicate sample to both channels
     179           0 :       tempAudioFrame.data_[2 * i] = incomingAudioFrame.data_[i];
     180           0 :       tempAudioFrame.data_[2 * i + 1] = incomingAudioFrame.data_[i];
     181             :     }
     182             :   }
     183             : 
     184           0 :   const AudioFrame* ptrAudioFrame = &incomingAudioFrame;
     185           0 :   if (tempAudioFrame.samples_per_channel_ != 0) {
     186             :     // If ptrAudioFrame is not empty it contains the audio to be recorded.
     187           0 :     ptrAudioFrame = &tempAudioFrame;
     188             :   }
     189             : 
     190             :   // Encode the audio data before writing to file. Don't encode if the codec
     191             :   // is PCM.
     192             :   // NOTE: stereo recording is only supported for WAV files.
     193             :   // TODO(hellner): WAV expect PCM in little endian byte order. Not
     194             :   // "encoding" with PCM coder should be a problem for big endian systems.
     195           0 :   size_t encodedLenInBytes = 0;
     196           0 :   if (_fileFormat == kFileFormatPreencodedFile ||
     197           0 :       STR_CASE_CMP(codec_info_.plname, "L16") != 0) {
     198           0 :     if (_audioEncoder.Encode(*ptrAudioFrame, _audioBuffer,
     199             :                              &encodedLenInBytes) == -1) {
     200           0 :       LOG(LS_WARNING) << "RecordAudioToFile() codec " << codec_info_.plname
     201           0 :                       << " not supported or failed to encode stream.";
     202           0 :       return -1;
     203             :     }
     204             :   } else {
     205           0 :     size_t outLen = 0;
     206           0 :     _audioResampler.ResetIfNeeded(ptrAudioFrame->sample_rate_hz_,
     207             :                                   codec_info_.plfreq,
     208           0 :                                   ptrAudioFrame->num_channels_);
     209           0 :     _audioResampler.Push(
     210             :         ptrAudioFrame->data_,
     211           0 :         ptrAudioFrame->samples_per_channel_ * ptrAudioFrame->num_channels_,
     212             :         reinterpret_cast<int16_t*>(_audioBuffer), MAX_AUDIO_BUFFER_IN_BYTES,
     213           0 :         outLen);
     214           0 :     encodedLenInBytes = outLen * sizeof(int16_t);
     215             :   }
     216             : 
     217             :   // Codec may not be operating at a frame rate of 10 ms. Whenever enough
     218             :   // 10 ms chunks of data has been pushed to the encoder an encoded frame
     219             :   // will be available. Wait until then.
     220           0 :   if (encodedLenInBytes) {
     221           0 :     if (WriteEncodedAudioData(_audioBuffer, encodedLenInBytes) == -1) {
     222           0 :       return -1;
     223             :     }
     224             :   }
     225           0 :   return 0;
     226             : }
     227             : 
     228           0 : int32_t FileRecorderImpl::SetUpAudioEncoder() {
     229           0 :   if (_fileFormat == kFileFormatPreencodedFile ||
     230           0 :       STR_CASE_CMP(codec_info_.plname, "L16") != 0) {
     231           0 :     if (_audioEncoder.SetEncodeCodec(codec_info_) == -1) {
     232           0 :       LOG(LS_ERROR) << "SetUpAudioEncoder() codec " << codec_info_.plname
     233           0 :                     << " not supported.";
     234           0 :       return -1;
     235             :     }
     236             :   }
     237           0 :   return 0;
     238             : }
     239             : 
     240           0 : int32_t FileRecorderImpl::codec_info(CodecInst* codecInst) const {
     241           0 :   if (codec_info_.plfreq == 0) {
     242           0 :     return -1;
     243             :   }
     244           0 :   *codecInst = codec_info_;
     245           0 :   return 0;
     246             : }
     247             : 
     248           0 : int32_t FileRecorderImpl::WriteEncodedAudioData(const int8_t* audioBuffer,
     249             :                                                 size_t bufferLength) {
     250           0 :   return _moduleFile->IncomingAudioData(audioBuffer, bufferLength);
     251             : }
     252             : 
     253             : }  // namespace
     254             : 
     255           0 : std::unique_ptr<FileRecorder> FileRecorder::CreateFileRecorder(
     256             :     uint32_t instanceID,
     257             :     FileFormats fileFormat) {
     258             :   return std::unique_ptr<FileRecorder>(
     259           0 :       new FileRecorderImpl(instanceID, fileFormat));
     260             : }
     261             : 
     262             : }  // namespace webrtc

Generated by: LCOV version 1.13