LCOV - code coverage report
Current view: top level - media/webrtc/trunk/webrtc/modules/media_file - media_file_impl.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 444 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 30 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 <assert.h>
      12             : 
      13             : #include "webrtc/base/format_macros.h"
      14             : #include "webrtc/modules/media_file/media_file_impl.h"
      15             : #include "webrtc/system_wrappers/include/critical_section_wrapper.h"
      16             : #include "webrtc/system_wrappers/include/file_wrapper.h"
      17             : #include "webrtc/system_wrappers/include/trace.h"
      18             : 
      19             : namespace webrtc {
      20           0 : MediaFile* MediaFile::CreateMediaFile(const int32_t id)
      21             : {
      22           0 :     return new MediaFileImpl(id);
      23             : }
      24             : 
      25           0 : void MediaFile::DestroyMediaFile(MediaFile* module)
      26             : {
      27           0 :     delete static_cast<MediaFileImpl*>(module);
      28           0 : }
      29             : 
      30           0 : MediaFileImpl::MediaFileImpl(const int32_t id)
      31             :     : _id(id),
      32           0 :       _crit(CriticalSectionWrapper::CreateCriticalSection()),
      33           0 :       _callbackCrit(CriticalSectionWrapper::CreateCriticalSection()),
      34             :       _ptrFileUtilityObj(NULL),
      35             :       codec_info_(),
      36             :       _ptrInStream(NULL),
      37             :       _ptrOutStream(NULL),
      38             :       _fileFormat((FileFormats)-1),
      39             :       _recordDurationMs(0),
      40             :       _playoutPositionMs(0),
      41             :       _notificationMs(0),
      42             :       _playingActive(false),
      43             :       _recordingActive(false),
      44             :       _isStereo(false),
      45             :       _openFile(false),
      46             :       _fileName(),
      47           0 :       _ptrCallback(NULL)
      48             : {
      49             :     WEBRTC_TRACE(kTraceMemory, kTraceFile, id, "Created");
      50             : 
      51           0 :     codec_info_.plname[0] = '\0';
      52           0 :     _fileName[0] = '\0';
      53           0 : }
      54             : 
      55             : 
      56           0 : MediaFileImpl::~MediaFileImpl()
      57             : {
      58             :     WEBRTC_TRACE(kTraceMemory, kTraceFile, _id, "~MediaFileImpl()");
      59             :     {
      60           0 :         CriticalSectionScoped lock(_crit);
      61             : 
      62           0 :         if(_playingActive)
      63             :         {
      64           0 :             StopPlaying();
      65             :         }
      66             : 
      67           0 :         if(_recordingActive)
      68             :         {
      69           0 :             StopRecording();
      70             :         }
      71             : 
      72           0 :         delete _ptrFileUtilityObj;
      73             : 
      74           0 :         if(_openFile)
      75             :         {
      76           0 :             delete _ptrInStream;
      77           0 :             _ptrInStream = NULL;
      78           0 :             delete _ptrOutStream;
      79           0 :             _ptrOutStream = NULL;
      80             :         }
      81             :     }
      82             : 
      83           0 :     delete _crit;
      84           0 :     delete _callbackCrit;
      85           0 : }
      86             : 
      87           0 : int64_t MediaFileImpl::TimeUntilNextProcess()
      88             : {
      89             :     WEBRTC_TRACE(
      90             :         kTraceWarning,
      91             :         kTraceFile,
      92             :         _id,
      93             :         "TimeUntilNextProcess: This method is not used by MediaFile class.");
      94           0 :     return -1;
      95             : }
      96             : 
      97           0 : void MediaFileImpl::Process()
      98             : {
      99             :     WEBRTC_TRACE(kTraceWarning, kTraceFile, _id,
     100             :                  "Process: This method is not used by MediaFile class.");
     101           0 : }
     102             : 
     103           0 : int32_t MediaFileImpl::PlayoutAudioData(int8_t* buffer,
     104             :                                         size_t& dataLengthInBytes)
     105             : {
     106             :     WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
     107             :                "MediaFileImpl::PlayoutData(buffer= 0x%x, bufLen= %" PRIuS ")",
     108             :                  buffer, dataLengthInBytes);
     109             : 
     110           0 :     const size_t bufferLengthInBytes = dataLengthInBytes;
     111           0 :     dataLengthInBytes = 0;
     112             : 
     113           0 :     if(buffer == NULL || bufferLengthInBytes == 0)
     114             :     {
     115             :         WEBRTC_TRACE(kTraceError, kTraceFile, _id,
     116             :                      "Buffer pointer or length is NULL!");
     117           0 :         return -1;
     118             :     }
     119             : 
     120           0 :     int32_t bytesRead = 0;
     121             :     {
     122           0 :         CriticalSectionScoped lock(_crit);
     123             : 
     124           0 :         if(!_playingActive)
     125             :         {
     126             :             WEBRTC_TRACE(kTraceWarning, kTraceFile, _id,
     127             :                          "Not currently playing!");
     128           0 :             return -1;
     129             :         }
     130             : 
     131           0 :         if(!_ptrFileUtilityObj)
     132             :         {
     133             :             WEBRTC_TRACE(kTraceError, kTraceFile, _id,
     134             :                          "Playing, but no FileUtility object!");
     135           0 :             StopPlaying();
     136           0 :             return -1;
     137             :         }
     138             : 
     139           0 :         switch(_fileFormat)
     140             :         {
     141             :             case kFileFormatPcm32kHzFile:
     142             :             case kFileFormatPcm16kHzFile:
     143             :             case kFileFormatPcm8kHzFile:
     144           0 :                 bytesRead = _ptrFileUtilityObj->ReadPCMData(
     145           0 :                     *_ptrInStream,
     146             :                     buffer,
     147           0 :                     bufferLengthInBytes);
     148           0 :                 break;
     149             :             case kFileFormatCompressedFile:
     150           0 :                 bytesRead = _ptrFileUtilityObj->ReadCompressedData(
     151           0 :                     *_ptrInStream,
     152             :                     buffer,
     153           0 :                     bufferLengthInBytes);
     154           0 :                 break;
     155             :             case kFileFormatWavFile:
     156           0 :                 bytesRead = _ptrFileUtilityObj->ReadWavDataAsMono(
     157           0 :                     *_ptrInStream,
     158             :                     buffer,
     159           0 :                     bufferLengthInBytes);
     160           0 :                 break;
     161             :             case kFileFormatPreencodedFile:
     162           0 :                 bytesRead = _ptrFileUtilityObj->ReadPreEncodedData(
     163           0 :                     *_ptrInStream,
     164             :                     buffer,
     165           0 :                     bufferLengthInBytes);
     166           0 :                 if(bytesRead > 0)
     167             :                 {
     168           0 :                     dataLengthInBytes = static_cast<size_t>(bytesRead);
     169           0 :                     return 0;
     170             :                 }
     171           0 :                 break;
     172             :             default:
     173             :             {
     174             :                 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
     175             :                              "Invalid file format: %d", _fileFormat);
     176           0 :                 assert(false);
     177             :                 break;
     178             :             }
     179             :         }
     180             : 
     181           0 :         if( bytesRead > 0)
     182             :         {
     183           0 :             dataLengthInBytes = static_cast<size_t>(bytesRead);
     184             :         }
     185             :     }
     186           0 :     HandlePlayCallbacks(bytesRead);
     187           0 :     return 0;
     188             : }
     189             : 
     190           0 : void MediaFileImpl::HandlePlayCallbacks(int32_t bytesRead)
     191             : {
     192           0 :     bool playEnded = false;
     193           0 :     uint32_t callbackNotifyMs = 0;
     194             : 
     195           0 :     if(bytesRead > 0)
     196             :     {
     197             :         // Check if it's time for PlayNotification(..).
     198           0 :         _playoutPositionMs = _ptrFileUtilityObj->PlayoutPositionMs();
     199           0 :         if(_notificationMs)
     200             :         {
     201           0 :             if(_playoutPositionMs >= _notificationMs)
     202             :             {
     203           0 :                 _notificationMs = 0;
     204           0 :                 callbackNotifyMs = _playoutPositionMs;
     205             :             }
     206             :         }
     207             :     }
     208             :     else
     209             :     {
     210             :         // If no bytes were read assume end of file.
     211           0 :         StopPlaying();
     212           0 :         playEnded = true;
     213             :     }
     214             : 
     215             :     // Only _callbackCrit may and should be taken when making callbacks.
     216           0 :     CriticalSectionScoped lock(_callbackCrit);
     217           0 :     if(_ptrCallback)
     218             :     {
     219           0 :         if(callbackNotifyMs)
     220             :         {
     221           0 :             _ptrCallback->PlayNotification(_id, callbackNotifyMs);
     222             :         }
     223           0 :         if(playEnded)
     224             :         {
     225           0 :             _ptrCallback->PlayFileEnded(_id);
     226             :         }
     227             :     }
     228           0 : }
     229             : 
     230           0 : int32_t MediaFileImpl::PlayoutStereoData(
     231             :     int8_t* bufferLeft,
     232             :     int8_t* bufferRight,
     233             :     size_t& dataLengthInBytes)
     234             : {
     235             :     WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
     236             :                  "MediaFileImpl::PlayoutStereoData(Left = 0x%x, Right = 0x%x,"
     237             :                  " Len= %" PRIuS ")",
     238             :                  bufferLeft,
     239             :                  bufferRight,
     240             :                  dataLengthInBytes);
     241             : 
     242           0 :     const size_t bufferLengthInBytes = dataLengthInBytes;
     243           0 :     dataLengthInBytes = 0;
     244             : 
     245           0 :     if(bufferLeft == NULL || bufferRight == NULL || bufferLengthInBytes == 0)
     246             :     {
     247             :         WEBRTC_TRACE(kTraceError, kTraceFile, _id,
     248             :                      "A buffer pointer or the length is NULL!");
     249           0 :         return -1;
     250             :     }
     251             : 
     252           0 :     bool playEnded = false;
     253           0 :     uint32_t callbackNotifyMs = 0;
     254             :     {
     255           0 :         CriticalSectionScoped lock(_crit);
     256             : 
     257           0 :         if(!_playingActive || !_isStereo)
     258             :         {
     259             :             WEBRTC_TRACE(kTraceWarning, kTraceFile, _id,
     260             :                          "Not currently playing stereo!");
     261           0 :             return -1;
     262             :         }
     263             : 
     264           0 :         if(!_ptrFileUtilityObj)
     265             :         {
     266             :             WEBRTC_TRACE(
     267             :                 kTraceError,
     268             :                 kTraceFile,
     269             :                 _id,
     270             :                 "Playing stereo, but the FileUtility objects is NULL!");
     271           0 :             StopPlaying();
     272           0 :             return -1;
     273             :         }
     274             : 
     275             :         // Stereo playout only supported for WAV files.
     276           0 :         int32_t bytesRead = 0;
     277           0 :         switch(_fileFormat)
     278             :         {
     279             :             case kFileFormatWavFile:
     280           0 :                     bytesRead = _ptrFileUtilityObj->ReadWavDataAsStereo(
     281           0 :                         *_ptrInStream,
     282             :                         bufferLeft,
     283             :                         bufferRight,
     284           0 :                         bufferLengthInBytes);
     285           0 :                     break;
     286             :             default:
     287             :                 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
     288             :                              "Trying to read non-WAV as stereo audio\
     289             :  (not supported)");
     290           0 :                 break;
     291             :         }
     292             : 
     293           0 :         if(bytesRead > 0)
     294             :         {
     295           0 :             dataLengthInBytes = static_cast<size_t>(bytesRead);
     296             : 
     297             :             // Check if it's time for PlayNotification(..).
     298           0 :             _playoutPositionMs = _ptrFileUtilityObj->PlayoutPositionMs();
     299           0 :             if(_notificationMs)
     300             :             {
     301           0 :                 if(_playoutPositionMs >= _notificationMs)
     302             :                 {
     303           0 :                     _notificationMs = 0;
     304           0 :                     callbackNotifyMs = _playoutPositionMs;
     305             :                 }
     306             :             }
     307             :         }
     308             :         else
     309             :         {
     310             :             // If no bytes were read assume end of file.
     311           0 :             StopPlaying();
     312           0 :             playEnded = true;
     313             :         }
     314             :     }
     315             : 
     316           0 :     CriticalSectionScoped lock(_callbackCrit);
     317           0 :     if(_ptrCallback)
     318             :     {
     319           0 :         if(callbackNotifyMs)
     320             :         {
     321           0 :             _ptrCallback->PlayNotification(_id, callbackNotifyMs);
     322             :         }
     323           0 :         if(playEnded)
     324             :         {
     325           0 :             _ptrCallback->PlayFileEnded(_id);
     326             :         }
     327             :     }
     328           0 :     return 0;
     329             : }
     330             : 
     331           0 : int32_t MediaFileImpl::StartPlayingAudioFile(
     332             :     const char* fileName,
     333             :     const uint32_t notificationTimeMs,
     334             :     const bool loop,
     335             :     const FileFormats format,
     336             :     const CodecInst* codecInst,
     337             :     const uint32_t startPointMs,
     338             :     const uint32_t stopPointMs)
     339             : {
     340           0 :     if(!ValidFileName(fileName))
     341             :     {
     342           0 :         return -1;
     343             :     }
     344           0 :     if(!ValidFileFormat(format,codecInst))
     345             :     {
     346           0 :         return -1;
     347             :     }
     348           0 :     if(!ValidFilePositions(startPointMs,stopPointMs))
     349             :     {
     350           0 :         return -1;
     351             :     }
     352             : 
     353             :     // Check that the file will play longer than notificationTimeMs ms.
     354           0 :     if((startPointMs && stopPointMs && !loop) &&
     355           0 :        (notificationTimeMs > (stopPointMs - startPointMs)))
     356             :     {
     357             :         WEBRTC_TRACE(
     358             :             kTraceError,
     359             :             kTraceFile,
     360             :             _id,
     361             :             "specified notification time is longer than amount of ms that will\
     362             :  be played");
     363           0 :         return -1;
     364             :     }
     365             : 
     366           0 :     FileWrapper* inputStream = FileWrapper::Create();
     367           0 :     if(inputStream == NULL)
     368             :     {
     369             :        WEBRTC_TRACE(kTraceMemory, kTraceFile, _id,
     370             :                     "Failed to allocate input stream for file %s", fileName);
     371           0 :         return -1;
     372             :     }
     373             : 
     374           0 :     if (!inputStream->OpenFile(fileName, true)) {
     375           0 :       delete inputStream;
     376             :       WEBRTC_TRACE(kTraceError, kTraceFile, _id, "Could not open input file %s",
     377             :                    fileName);
     378           0 :       return -1;
     379             :     }
     380             : 
     381           0 :     if(StartPlayingStream(*inputStream, loop, notificationTimeMs,
     382             :                           format, codecInst, startPointMs, stopPointMs) == -1)
     383             :     {
     384           0 :         inputStream->CloseFile();
     385           0 :         delete inputStream;
     386           0 :         return -1;
     387             :     }
     388             : 
     389           0 :     CriticalSectionScoped lock(_crit);
     390           0 :     _openFile = true;
     391           0 :     strncpy(_fileName, fileName, sizeof(_fileName));
     392           0 :     _fileName[sizeof(_fileName) - 1] = '\0';
     393           0 :     return 0;
     394             : }
     395             : 
     396           0 : int32_t MediaFileImpl::StartPlayingAudioStream(
     397             :     InStream& stream,
     398             :     const uint32_t notificationTimeMs,
     399             :     const FileFormats format,
     400             :     const CodecInst* codecInst,
     401             :     const uint32_t startPointMs,
     402             :     const uint32_t stopPointMs)
     403             : {
     404             :     return StartPlayingStream(stream, false, notificationTimeMs, format,
     405           0 :                               codecInst, startPointMs, stopPointMs);
     406             : }
     407             : 
     408           0 : int32_t MediaFileImpl::StartPlayingStream(
     409             :     InStream& stream,
     410             :     bool loop,
     411             :     const uint32_t notificationTimeMs,
     412             :     const FileFormats format,
     413             :     const CodecInst*  codecInst,
     414             :     const uint32_t startPointMs,
     415             :     const uint32_t stopPointMs)
     416             : {
     417           0 :     if(!ValidFileFormat(format,codecInst))
     418             :     {
     419           0 :         return -1;
     420             :     }
     421             : 
     422           0 :     if(!ValidFilePositions(startPointMs,stopPointMs))
     423             :     {
     424           0 :         return -1;
     425             :     }
     426             : 
     427           0 :     CriticalSectionScoped lock(_crit);
     428           0 :     if(_playingActive || _recordingActive)
     429             :     {
     430             :         WEBRTC_TRACE(
     431             :             kTraceError,
     432             :             kTraceFile,
     433             :             _id,
     434             :             "StartPlaying called, but already playing or recording file %s",
     435             :             (_fileName[0] == '\0') ? "(name not set)" : _fileName);
     436           0 :         return -1;
     437             :     }
     438             : 
     439           0 :     if(_ptrFileUtilityObj != NULL)
     440             :     {
     441             :         WEBRTC_TRACE(kTraceError,
     442             :                      kTraceFile,
     443             :                      _id,
     444             :                      "StartPlaying called, but FileUtilityObj already exists!");
     445           0 :         StopPlaying();
     446           0 :         return -1;
     447             :     }
     448             : 
     449           0 :     _ptrFileUtilityObj = new ModuleFileUtility(_id);
     450           0 :     if(_ptrFileUtilityObj == NULL)
     451             :     {
     452             :         WEBRTC_TRACE(kTraceMemory, kTraceFile, _id,
     453             :                      "Failed to create FileUtilityObj!");
     454           0 :         return -1;
     455             :     }
     456             : 
     457           0 :     switch(format)
     458             :     {
     459             :         case kFileFormatWavFile:
     460             :         {
     461           0 :             if(_ptrFileUtilityObj->InitWavReading(stream, startPointMs,
     462             :                                                   stopPointMs) == -1)
     463             :             {
     464             :                 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
     465             :                              "Not a valid WAV file!");
     466           0 :                 StopPlaying();
     467           0 :                 return -1;
     468             :             }
     469           0 :             _fileFormat = kFileFormatWavFile;
     470           0 :             break;
     471             :         }
     472             :         case kFileFormatCompressedFile:
     473             :         {
     474           0 :             if(_ptrFileUtilityObj->InitCompressedReading(stream, startPointMs,
     475             :                                                          stopPointMs) == -1)
     476             :             {
     477             :                 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
     478             :                              "Not a valid Compressed file!");
     479           0 :                 StopPlaying();
     480           0 :                 return -1;
     481             :             }
     482           0 :             _fileFormat = kFileFormatCompressedFile;
     483           0 :             break;
     484             :         }
     485             :         case kFileFormatPcm8kHzFile:
     486             :         case kFileFormatPcm16kHzFile:
     487             :         case kFileFormatPcm32kHzFile:
     488             :         {
     489             :             // ValidFileFormat() called in the beginneing of this function
     490             :             // prevents codecInst from being NULL here.
     491           0 :             assert(codecInst != NULL);
     492           0 :             if(!ValidFrequency(codecInst->plfreq) ||
     493           0 :                _ptrFileUtilityObj->InitPCMReading(stream, startPointMs,
     494             :                                                   stopPointMs,
     495           0 :                                                   codecInst->plfreq) == -1)
     496             :             {
     497             :                 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
     498             :                              "Not a valid raw 8 or 16 KHz PCM file!");
     499           0 :                 StopPlaying();
     500           0 :                 return -1;
     501             :             }
     502             : 
     503           0 :             _fileFormat = format;
     504           0 :             break;
     505             :         }
     506             :         case kFileFormatPreencodedFile:
     507             :         {
     508             :             // ValidFileFormat() called in the beginneing of this function
     509             :             // prevents codecInst from being NULL here.
     510           0 :             assert(codecInst != NULL);
     511           0 :             if(_ptrFileUtilityObj->InitPreEncodedReading(stream, *codecInst) ==
     512             :                -1)
     513             :             {
     514             :                 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
     515             :                              "Not a valid PreEncoded file!");
     516           0 :                 StopPlaying();
     517           0 :                 return -1;
     518             :             }
     519             : 
     520           0 :             _fileFormat = kFileFormatPreencodedFile;
     521           0 :             break;
     522             :         }
     523             :         default:
     524             :         {
     525             :             WEBRTC_TRACE(kTraceError, kTraceFile, _id,
     526             :                          "Invalid file format: %d", format);
     527           0 :             assert(false);
     528             :             break;
     529             :         }
     530             :     }
     531           0 :     if(_ptrFileUtilityObj->codec_info(codec_info_) == -1)
     532             :     {
     533             :         WEBRTC_TRACE(kTraceError, kTraceFile, _id,
     534             :                      "Failed to retrieve codec info!");
     535           0 :         StopPlaying();
     536           0 :         return -1;
     537             :     }
     538             : 
     539           0 :     _isStereo = (codec_info_.channels == 2);
     540           0 :     if(_isStereo && (_fileFormat != kFileFormatWavFile))
     541             :     {
     542             :         WEBRTC_TRACE(kTraceWarning, kTraceFile, _id,
     543             :                      "Stereo is only allowed for WAV files");
     544           0 :         StopPlaying();
     545           0 :         return -1;
     546             :     }
     547           0 :     _playingActive = true;
     548           0 :     _playoutPositionMs = _ptrFileUtilityObj->PlayoutPositionMs();
     549           0 :     _ptrInStream = &stream;
     550           0 :     _notificationMs = notificationTimeMs;
     551             : 
     552           0 :     return 0;
     553             : }
     554             : 
     555           0 : int32_t MediaFileImpl::StopPlaying()
     556             : {
     557             : 
     558           0 :     CriticalSectionScoped lock(_crit);
     559           0 :     _isStereo = false;
     560           0 :     if(_ptrFileUtilityObj)
     561             :     {
     562           0 :         delete _ptrFileUtilityObj;
     563           0 :         _ptrFileUtilityObj = NULL;
     564             :     }
     565           0 :     if(_ptrInStream)
     566             :     {
     567             :         // If MediaFileImpl opened the InStream it must be reclaimed here.
     568           0 :         if(_openFile)
     569             :         {
     570           0 :             delete _ptrInStream;
     571           0 :             _openFile = false;
     572             :         }
     573           0 :         _ptrInStream = NULL;
     574             :     }
     575             : 
     576           0 :     codec_info_.pltype = 0;
     577           0 :     codec_info_.plname[0] = '\0';
     578             : 
     579           0 :     if(!_playingActive)
     580             :     {
     581             :         WEBRTC_TRACE(kTraceWarning, kTraceFile, _id,
     582             :                      "playing is not active!");
     583           0 :         return -1;
     584             :     }
     585             : 
     586           0 :     _playingActive = false;
     587           0 :     return 0;
     588             : }
     589             : 
     590           0 : bool MediaFileImpl::IsPlaying()
     591             : {
     592             :     WEBRTC_TRACE(kTraceStream, kTraceFile, _id, "MediaFileImpl::IsPlaying()");
     593           0 :     CriticalSectionScoped lock(_crit);
     594           0 :     return _playingActive;
     595             : }
     596             : 
     597           0 : int32_t MediaFileImpl::IncomingAudioData(
     598             :     const int8_t*  buffer,
     599             :     const size_t bufferLengthInBytes)
     600             : {
     601             :     WEBRTC_TRACE(kTraceStream, kTraceFile, _id,
     602             :                  "MediaFile::IncomingData(buffer= 0x%x, bufLen= %" PRIuS,
     603             :                  buffer, bufferLengthInBytes);
     604             : 
     605           0 :     if(buffer == NULL || bufferLengthInBytes == 0)
     606             :     {
     607             :         WEBRTC_TRACE(kTraceError, kTraceFile, _id,
     608             :                      "Buffer pointer or length is NULL!");
     609           0 :         return -1;
     610             :     }
     611             : 
     612           0 :     bool recordingEnded = false;
     613           0 :     uint32_t callbackNotifyMs = 0;
     614             :     {
     615           0 :         CriticalSectionScoped lock(_crit);
     616             : 
     617           0 :         if(!_recordingActive)
     618             :         {
     619             :             WEBRTC_TRACE(kTraceWarning, kTraceFile, _id,
     620             :                          "Not currently recording!");
     621           0 :             return -1;
     622             :         }
     623           0 :         if(_ptrOutStream == NULL)
     624             :         {
     625             :             WEBRTC_TRACE(kTraceError, kTraceFile, _id,
     626             :                          "Recording is active, but output stream is NULL!");
     627           0 :             assert(false);
     628             :             return -1;
     629             :         }
     630             : 
     631           0 :         int32_t bytesWritten = 0;
     632           0 :         uint32_t samplesWritten = codec_info_.pacsize;
     633           0 :         if(_ptrFileUtilityObj)
     634             :         {
     635           0 :             switch(_fileFormat)
     636             :             {
     637             :                 case kFileFormatPcm8kHzFile:
     638             :                 case kFileFormatPcm16kHzFile:
     639             :                 case kFileFormatPcm32kHzFile:
     640           0 :                     bytesWritten = _ptrFileUtilityObj->WritePCMData(
     641           0 :                         *_ptrOutStream,
     642             :                         buffer,
     643           0 :                         bufferLengthInBytes);
     644             : 
     645             :                     // Sample size is 2 bytes.
     646           0 :                     if(bytesWritten > 0)
     647             :                     {
     648           0 :                         samplesWritten = bytesWritten/sizeof(int16_t);
     649             :                     }
     650           0 :                     break;
     651             :                 case kFileFormatCompressedFile:
     652           0 :                     bytesWritten = _ptrFileUtilityObj->WriteCompressedData(
     653           0 :                         *_ptrOutStream, buffer, bufferLengthInBytes);
     654           0 :                     break;
     655             :                 case kFileFormatWavFile:
     656           0 :                     bytesWritten = _ptrFileUtilityObj->WriteWavData(
     657           0 :                         *_ptrOutStream,
     658             :                         buffer,
     659           0 :                         bufferLengthInBytes);
     660           0 :                     if(bytesWritten > 0 && STR_NCASE_CMP(codec_info_.plname,
     661             :                                                          "L16", 4) == 0)
     662             :                     {
     663             :                         // Sample size is 2 bytes.
     664           0 :                         samplesWritten = bytesWritten/sizeof(int16_t);
     665             :                     }
     666           0 :                     break;
     667             :                 case kFileFormatPreencodedFile:
     668           0 :                     bytesWritten = _ptrFileUtilityObj->WritePreEncodedData(
     669           0 :                         *_ptrOutStream, buffer, bufferLengthInBytes);
     670           0 :                     break;
     671             :                 default:
     672             :                     WEBRTC_TRACE(kTraceError, kTraceFile, _id,
     673             :                                  "Invalid file format: %d", _fileFormat);
     674           0 :                     assert(false);
     675             :                     break;
     676             :             }
     677             :         } else {
     678             :             // TODO (hellner): quick look at the code makes me think that this
     679             :             //                 code is never executed. Remove?
     680           0 :             if(_ptrOutStream)
     681             :             {
     682           0 :                 if(_ptrOutStream->Write(buffer, bufferLengthInBytes))
     683             :                 {
     684           0 :                     bytesWritten = static_cast<int32_t>(bufferLengthInBytes);
     685             :                 }
     686             :             }
     687             :         }
     688             : 
     689           0 :         _recordDurationMs += samplesWritten / (codec_info_.plfreq / 1000);
     690             : 
     691             :         // Check if it's time for RecordNotification(..).
     692           0 :         if(_notificationMs)
     693             :         {
     694           0 :             if(_recordDurationMs  >= _notificationMs)
     695             :             {
     696           0 :                 _notificationMs = 0;
     697           0 :                 callbackNotifyMs = _recordDurationMs;
     698             :             }
     699             :         }
     700           0 :         if(bytesWritten < (int32_t)bufferLengthInBytes)
     701             :         {
     702             :             WEBRTC_TRACE(kTraceWarning, kTraceFile, _id,
     703             :                          "Failed to write all requested bytes!");
     704           0 :             StopRecording();
     705           0 :             recordingEnded = true;
     706             :         }
     707             :     }
     708             : 
     709             :     // Only _callbackCrit may and should be taken when making callbacks.
     710           0 :     CriticalSectionScoped lock(_callbackCrit);
     711           0 :     if(_ptrCallback)
     712             :     {
     713           0 :         if(callbackNotifyMs)
     714             :         {
     715           0 :             _ptrCallback->RecordNotification(_id, callbackNotifyMs);
     716             :         }
     717           0 :         if(recordingEnded)
     718             :         {
     719           0 :             _ptrCallback->RecordFileEnded(_id);
     720           0 :             return -1;
     721             :         }
     722             :     }
     723           0 :     return 0;
     724             : }
     725             : 
     726           0 : int32_t MediaFileImpl::StartRecordingAudioFile(
     727             :     const char* fileName,
     728             :     const FileFormats format,
     729             :     const CodecInst& codecInst,
     730             :     const uint32_t notificationTimeMs,
     731             :     const uint32_t maxSizeBytes)
     732             : {
     733           0 :     if(!ValidFileName(fileName))
     734             :     {
     735           0 :         return -1;
     736             :     }
     737           0 :     if(!ValidFileFormat(format,&codecInst))
     738             :     {
     739           0 :         return -1;
     740             :     }
     741             : 
     742           0 :     FileWrapper* outputStream = FileWrapper::Create();
     743           0 :     if(outputStream == NULL)
     744             :     {
     745             :         WEBRTC_TRACE(kTraceMemory, kTraceFile, _id,
     746             :                      "Failed to allocate memory for output stream");
     747           0 :         return -1;
     748             :     }
     749             : 
     750           0 :     if (!outputStream->OpenFile(fileName, false)) {
     751           0 :       delete outputStream;
     752             :       WEBRTC_TRACE(kTraceError, kTraceFile, _id,
     753             :                    "Could not open output file '%s' for writing!", fileName);
     754           0 :       return -1;
     755             :     }
     756             : 
     757           0 :     if(maxSizeBytes)
     758             :     {
     759           0 :         outputStream->SetMaxFileSize(maxSizeBytes);
     760             :     }
     761             : 
     762           0 :     if(StartRecordingAudioStream(*outputStream, format, codecInst,
     763           0 :                                  notificationTimeMs) == -1)
     764             :     {
     765           0 :         outputStream->CloseFile();
     766           0 :         delete outputStream;
     767           0 :         return -1;
     768             :     }
     769             : 
     770           0 :     CriticalSectionScoped lock(_crit);
     771           0 :     _openFile = true;
     772           0 :     strncpy(_fileName, fileName, sizeof(_fileName));
     773           0 :     _fileName[sizeof(_fileName) - 1] = '\0';
     774           0 :     return 0;
     775             : }
     776             : 
     777           0 : int32_t MediaFileImpl::StartRecordingAudioStream(
     778             :     OutStream& stream,
     779             :     const FileFormats format,
     780             :     const CodecInst& codecInst,
     781             :     const uint32_t notificationTimeMs)
     782             : {
     783             :     // Check codec info
     784           0 :     if(!ValidFileFormat(format,&codecInst))
     785             :     {
     786           0 :         return -1;
     787             :     }
     788             : 
     789           0 :     CriticalSectionScoped lock(_crit);
     790           0 :     if(_recordingActive || _playingActive)
     791             :     {
     792             :         WEBRTC_TRACE(
     793             :             kTraceError,
     794             :             kTraceFile,
     795             :             _id,
     796             :             "StartRecording called, but already recording or playing file %s!",
     797             :                    _fileName);
     798           0 :         return -1;
     799             :     }
     800             : 
     801           0 :     if(_ptrFileUtilityObj != NULL)
     802             :     {
     803             :         WEBRTC_TRACE(
     804             :             kTraceError,
     805             :             kTraceFile,
     806             :             _id,
     807             :             "StartRecording called, but fileUtilityObj already exists!");
     808           0 :         StopRecording();
     809           0 :         return -1;
     810             :     }
     811             : 
     812           0 :     _ptrFileUtilityObj = new ModuleFileUtility(_id);
     813           0 :     if(_ptrFileUtilityObj == NULL)
     814             :     {
     815             :         WEBRTC_TRACE(kTraceMemory, kTraceFile, _id,
     816             :                      "Cannot allocate fileUtilityObj!");
     817           0 :         return -1;
     818             :     }
     819             : 
     820             :     CodecInst tmpAudioCodec;
     821           0 :     memcpy(&tmpAudioCodec, &codecInst, sizeof(CodecInst));
     822           0 :     switch(format)
     823             :     {
     824             :         case kFileFormatWavFile:
     825             :         {
     826           0 :             if(_ptrFileUtilityObj->InitWavWriting(stream, codecInst) == -1)
     827             :             {
     828             :                 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
     829             :                              "Failed to initialize WAV file!");
     830           0 :                 delete _ptrFileUtilityObj;
     831           0 :                 _ptrFileUtilityObj = NULL;
     832           0 :                 return -1;
     833             :             }
     834           0 :             _fileFormat = kFileFormatWavFile;
     835           0 :             break;
     836             :         }
     837             :         case kFileFormatCompressedFile:
     838             :         {
     839             :             // Write compression codec name at beginning of file
     840           0 :             if(_ptrFileUtilityObj->InitCompressedWriting(stream, codecInst) ==
     841             :                -1)
     842             :             {
     843             :                 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
     844             :                              "Failed to initialize Compressed file!");
     845           0 :                 delete _ptrFileUtilityObj;
     846           0 :                 _ptrFileUtilityObj = NULL;
     847           0 :                 return -1;
     848             :             }
     849           0 :             _fileFormat = kFileFormatCompressedFile;
     850           0 :             break;
     851             :         }
     852             :         case kFileFormatPcm8kHzFile:
     853             :         case kFileFormatPcm16kHzFile:
     854             :         {
     855           0 :             if(!ValidFrequency(codecInst.plfreq) ||
     856           0 :                _ptrFileUtilityObj->InitPCMWriting(stream, codecInst.plfreq) ==
     857             :                -1)
     858             :             {
     859             :                 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
     860             :                              "Failed to initialize 8 or 16KHz PCM file!");
     861           0 :                 delete _ptrFileUtilityObj;
     862           0 :                 _ptrFileUtilityObj = NULL;
     863           0 :                 return -1;
     864             :             }
     865           0 :             _fileFormat = format;
     866           0 :             break;
     867             :         }
     868             :         case kFileFormatPreencodedFile:
     869             :         {
     870           0 :             if(_ptrFileUtilityObj->InitPreEncodedWriting(stream, codecInst) ==
     871             :                -1)
     872             :             {
     873             :                 WEBRTC_TRACE(kTraceError, kTraceFile, _id,
     874             :                              "Failed to initialize Pre-Encoded file!");
     875           0 :                 delete _ptrFileUtilityObj;
     876           0 :                 _ptrFileUtilityObj = NULL;
     877           0 :                 return -1;
     878             :             }
     879             : 
     880           0 :             _fileFormat = kFileFormatPreencodedFile;
     881           0 :             break;
     882             :         }
     883             :         default:
     884             :         {
     885             :             WEBRTC_TRACE(kTraceError, kTraceFile, _id,
     886             :                          "Invalid file format %d specified!", format);
     887           0 :             delete _ptrFileUtilityObj;
     888           0 :             _ptrFileUtilityObj = NULL;
     889           0 :             return -1;
     890             :         }
     891             :     }
     892           0 :     _isStereo = (tmpAudioCodec.channels == 2);
     893           0 :     if(_isStereo)
     894             :     {
     895           0 :         if(_fileFormat != kFileFormatWavFile)
     896             :         {
     897             :             WEBRTC_TRACE(kTraceWarning, kTraceFile, _id,
     898             :                          "Stereo is only allowed for WAV files");
     899           0 :             StopRecording();
     900           0 :             return -1;
     901             :         }
     902           0 :         if((STR_NCASE_CMP(tmpAudioCodec.plname, "L16", 4) != 0) &&
     903           0 :            (STR_NCASE_CMP(tmpAudioCodec.plname, "PCMU", 5) != 0) &&
     904           0 :            (STR_NCASE_CMP(tmpAudioCodec.plname, "PCMA", 5) != 0))
     905             :         {
     906             :             WEBRTC_TRACE(
     907             :                 kTraceWarning,
     908             :                 kTraceFile,
     909             :                 _id,
     910             :                 "Stereo is only allowed for codec PCMU, PCMA and L16 ");
     911           0 :             StopRecording();
     912           0 :             return -1;
     913             :         }
     914             :     }
     915           0 :     memcpy(&codec_info_, &tmpAudioCodec, sizeof(CodecInst));
     916           0 :     _recordingActive = true;
     917           0 :     _ptrOutStream = &stream;
     918           0 :     _notificationMs = notificationTimeMs;
     919           0 :     _recordDurationMs = 0;
     920           0 :     return 0;
     921             : }
     922             : 
     923           0 : int32_t MediaFileImpl::StopRecording()
     924             : {
     925             : 
     926           0 :     CriticalSectionScoped lock(_crit);
     927           0 :     if(!_recordingActive)
     928             :     {
     929             :         WEBRTC_TRACE(kTraceWarning, kTraceFile, _id,
     930             :                      "recording is not active!");
     931           0 :         return -1;
     932             :     }
     933             : 
     934           0 :     _isStereo = false;
     935             : 
     936           0 :     if(_ptrFileUtilityObj != NULL)
     937             :     {
     938             :         // Both AVI and WAV header has to be updated before closing the stream
     939             :         // because they contain size information.
     940           0 :         if((_fileFormat == kFileFormatWavFile) &&
     941           0 :             (_ptrOutStream != NULL))
     942             :         {
     943           0 :             _ptrFileUtilityObj->UpdateWavHeader(*_ptrOutStream);
     944             :         }
     945           0 :         delete _ptrFileUtilityObj;
     946           0 :         _ptrFileUtilityObj = NULL;
     947             :     }
     948             : 
     949           0 :     if(_ptrOutStream != NULL)
     950             :     {
     951             :         // If MediaFileImpl opened the OutStream it must be reclaimed here.
     952           0 :         if(_openFile)
     953             :         {
     954           0 :             delete _ptrOutStream;
     955           0 :             _openFile = false;
     956             :         }
     957           0 :         _ptrOutStream = NULL;
     958             :     }
     959             : 
     960           0 :     _recordingActive = false;
     961           0 :     codec_info_.pltype = 0;
     962           0 :     codec_info_.plname[0] = '\0';
     963             : 
     964           0 :     return 0;
     965             : }
     966             : 
     967           0 : bool MediaFileImpl::IsRecording()
     968             : {
     969             :     WEBRTC_TRACE(kTraceStream, kTraceFile, _id, "MediaFileImpl::IsRecording()");
     970           0 :     CriticalSectionScoped lock(_crit);
     971           0 :     return _recordingActive;
     972             : }
     973             : 
     974           0 : int32_t MediaFileImpl::RecordDurationMs(uint32_t& durationMs)
     975             : {
     976             : 
     977           0 :     CriticalSectionScoped lock(_crit);
     978           0 :     if(!_recordingActive)
     979             :     {
     980           0 :         durationMs = 0;
     981           0 :         return -1;
     982             :     }
     983           0 :     durationMs = _recordDurationMs;
     984           0 :     return 0;
     985             : }
     986             : 
     987           0 : bool MediaFileImpl::IsStereo()
     988             : {
     989             :     WEBRTC_TRACE(kTraceStream, kTraceFile, _id, "MediaFileImpl::IsStereo()");
     990           0 :     CriticalSectionScoped lock(_crit);
     991           0 :     return _isStereo;
     992             : }
     993             : 
     994           0 : int32_t MediaFileImpl::SetModuleFileCallback(FileCallback* callback)
     995             : {
     996             : 
     997           0 :     CriticalSectionScoped lock(_callbackCrit);
     998             : 
     999           0 :     _ptrCallback = callback;
    1000           0 :     return 0;
    1001             : }
    1002             : 
    1003           0 : int32_t MediaFileImpl::FileDurationMs(const char* fileName,
    1004             :                                       uint32_t& durationMs,
    1005             :                                       const FileFormats format,
    1006             :                                       const uint32_t freqInHz)
    1007             : {
    1008             : 
    1009           0 :     if(!ValidFileName(fileName))
    1010             :     {
    1011           0 :         return -1;
    1012             :     }
    1013           0 :     if(!ValidFrequency(freqInHz))
    1014             :     {
    1015           0 :         return -1;
    1016             :     }
    1017             : 
    1018           0 :     ModuleFileUtility* utilityObj = new ModuleFileUtility(_id);
    1019           0 :     if(utilityObj == NULL)
    1020             :     {
    1021             :         WEBRTC_TRACE(kTraceError, kTraceFile, _id,
    1022             :                      "failed to allocate utility object!");
    1023           0 :         return -1;
    1024             :     }
    1025             : 
    1026             :     const int32_t duration = utilityObj->FileDurationMs(fileName, format,
    1027           0 :                                                         freqInHz);
    1028           0 :     delete utilityObj;
    1029           0 :     if(duration == -1)
    1030             :     {
    1031           0 :         durationMs = 0;
    1032           0 :         return -1;
    1033             :     }
    1034             : 
    1035           0 :     durationMs = duration;
    1036           0 :     return 0;
    1037             : }
    1038             : 
    1039           0 : int32_t MediaFileImpl::PlayoutPositionMs(uint32_t& positionMs) const
    1040             : {
    1041           0 :     CriticalSectionScoped lock(_crit);
    1042           0 :     if(!_playingActive)
    1043             :     {
    1044           0 :         positionMs = 0;
    1045           0 :         return -1;
    1046             :     }
    1047           0 :     positionMs = _playoutPositionMs;
    1048           0 :     return 0;
    1049             : }
    1050             : 
    1051           0 : int32_t MediaFileImpl::codec_info(CodecInst& codecInst) const
    1052             : {
    1053           0 :     CriticalSectionScoped lock(_crit);
    1054           0 :     if(!_playingActive && !_recordingActive)
    1055             :     {
    1056             :         WEBRTC_TRACE(kTraceError, kTraceFile, _id,
    1057             :                      "Neither playout nor recording has been initialized!");
    1058           0 :         return -1;
    1059             :     }
    1060           0 :     if (codec_info_.pltype == 0 && codec_info_.plname[0] == '\0')
    1061             :     {
    1062             :         WEBRTC_TRACE(kTraceError, kTraceFile, _id,
    1063             :                      "The CodecInst for %s is unknown!",
    1064             :             _playingActive ? "Playback" : "Recording");
    1065           0 :         return -1;
    1066             :     }
    1067           0 :     memcpy(&codecInst,&codec_info_,sizeof(CodecInst));
    1068           0 :     return 0;
    1069             : }
    1070             : 
    1071           0 : bool MediaFileImpl::ValidFileFormat(const FileFormats format,
    1072             :                                     const CodecInst*  codecInst)
    1073             : {
    1074           0 :     if(codecInst == NULL)
    1075             :     {
    1076           0 :         if(format == kFileFormatPreencodedFile ||
    1077           0 :            format == kFileFormatPcm8kHzFile    ||
    1078           0 :            format == kFileFormatPcm16kHzFile   ||
    1079             :            format == kFileFormatPcm32kHzFile)
    1080             :         {
    1081             :             WEBRTC_TRACE(kTraceError, kTraceFile, -1,
    1082             :                          "Codec info required for file format specified!");
    1083           0 :             return false;
    1084             :         }
    1085             :     }
    1086           0 :     return true;
    1087             : }
    1088             : 
    1089           0 : bool MediaFileImpl::ValidFileName(const char* fileName)
    1090             : {
    1091           0 :     if((fileName == NULL) ||(fileName[0] == '\0'))
    1092             :     {
    1093             :         WEBRTC_TRACE(kTraceError, kTraceFile, -1, "FileName not specified!");
    1094           0 :         return false;
    1095             :     }
    1096           0 :     return true;
    1097             : }
    1098             : 
    1099             : 
    1100           0 : bool MediaFileImpl::ValidFilePositions(const uint32_t startPointMs,
    1101             :                                        const uint32_t stopPointMs)
    1102             : {
    1103           0 :     if(startPointMs == 0 && stopPointMs == 0) // Default values
    1104             :     {
    1105           0 :         return true;
    1106             :     }
    1107           0 :     if(stopPointMs &&(startPointMs >= stopPointMs))
    1108             :     {
    1109             :         WEBRTC_TRACE(kTraceError, kTraceFile, -1,
    1110             :                      "startPointMs must be less than stopPointMs!");
    1111           0 :         return false;
    1112             :     }
    1113           0 :     if(stopPointMs &&((stopPointMs - startPointMs) < 20))
    1114             :     {
    1115             :         WEBRTC_TRACE(kTraceError, kTraceFile, -1,
    1116             :                      "minimum play duration for files is 20 ms!");
    1117           0 :         return false;
    1118             :     }
    1119           0 :     return true;
    1120             : }
    1121             : 
    1122           0 : bool MediaFileImpl::ValidFrequency(const uint32_t frequency)
    1123             : {
    1124           0 :     if((frequency == 8000) || (frequency == 16000)|| (frequency == 32000))
    1125             :     {
    1126           0 :         return true;
    1127             :     }
    1128             :     WEBRTC_TRACE(kTraceError, kTraceFile, -1,
    1129             :                  "Frequency should be 8000, 16000 or 32000 (Hz)");
    1130           0 :     return false;
    1131             : }
    1132             : }  // namespace webrtc

Generated by: LCOV version 1.13