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