Note: We no longer publish the latest version of our code here. We primarily use a kumc-bmi github organization. The heron ETL repository, in particular, is not public. Peers in the informatics community should see MultiSiteDev for details on requesting access.

source: webrtc/webrtc/modules/media_file/source/media_file_impl.cc @ 0:4bda6873e34c

pub_scrub_3792 tip
Last change on this file since 0:4bda6873e34c was 0:4bda6873e34c, checked in by Michael Prittie <mprittie@…>, 6 years ago

Scrubbed password for publication.

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