1/*
2 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
4 *  Use of this source code is governed by a BSD-style license
5 *  that can be found in the LICENSE file in the root of the source
6 *  tree. An additional intellectual property rights grant can be found
7 *  in the file PATENTS.  All contributing project authors may
8 *  be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "webrtc/modules/audio_device/audio_device_buffer.h"
12
13#include <assert.h>
14#include <string.h>
15
16#include "webrtc/modules/audio_device/audio_device_config.h"
17#include "webrtc/modules/audio_device/audio_device_utility.h"
18#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
19#include "webrtc/system_wrappers/interface/logging.h"
20#include "webrtc/system_wrappers/interface/trace.h"
21
22namespace webrtc {
23
24static const int kHighDelayThresholdMs = 300;
25static const int kLogHighDelayIntervalFrames = 500;  // 5 seconds.
26
27// ----------------------------------------------------------------------------
28//  ctor
29// ----------------------------------------------------------------------------
30
31AudioDeviceBuffer::AudioDeviceBuffer() :
32    _id(-1),
33    _critSect(*CriticalSectionWrapper::CreateCriticalSection()),
34    _critSectCb(*CriticalSectionWrapper::CreateCriticalSection()),
35    _ptrCbAudioTransport(NULL),
36    _recSampleRate(0),
37    _playSampleRate(0),
38    _recChannels(0),
39    _playChannels(0),
40    _recChannel(AudioDeviceModule::kChannelBoth),
41    _recBytesPerSample(0),
42    _playBytesPerSample(0),
43    _recSamples(0),
44    _recSize(0),
45    _playSamples(0),
46    _playSize(0),
47    _recFile(*FileWrapper::Create()),
48    _playFile(*FileWrapper::Create()),
49    _currentMicLevel(0),
50    _newMicLevel(0),
51    _typingStatus(false),
52    _playDelayMS(0),
53    _recDelayMS(0),
54    _clockDrift(0),
55    // Set to the interval in order to log on the first occurrence.
56    high_delay_counter_(kLogHighDelayIntervalFrames) {
57    // valid ID will be set later by SetId, use -1 for now
58    WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s created", __FUNCTION__);
59    memset(_recBuffer, 0, kMaxBufferSizeBytes);
60    memset(_playBuffer, 0, kMaxBufferSizeBytes);
61}
62
63// ----------------------------------------------------------------------------
64//  dtor
65// ----------------------------------------------------------------------------
66
67AudioDeviceBuffer::~AudioDeviceBuffer()
68{
69    WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s destroyed", __FUNCTION__);
70    {
71        CriticalSectionScoped lock(&_critSect);
72
73        _recFile.Flush();
74        _recFile.CloseFile();
75        delete &_recFile;
76
77        _playFile.Flush();
78        _playFile.CloseFile();
79        delete &_playFile;
80    }
81
82    delete &_critSect;
83    delete &_critSectCb;
84}
85
86// ----------------------------------------------------------------------------
87//  SetId
88// ----------------------------------------------------------------------------
89
90void AudioDeviceBuffer::SetId(uint32_t id)
91{
92    WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, id, "AudioDeviceBuffer::SetId(id=%d)", id);
93    _id = id;
94}
95
96// ----------------------------------------------------------------------------
97//  RegisterAudioCallback
98// ----------------------------------------------------------------------------
99
100int32_t AudioDeviceBuffer::RegisterAudioCallback(AudioTransport* audioCallback)
101{
102    CriticalSectionScoped lock(&_critSectCb);
103    _ptrCbAudioTransport = audioCallback;
104
105    return 0;
106}
107
108// ----------------------------------------------------------------------------
109//  InitPlayout
110// ----------------------------------------------------------------------------
111
112int32_t AudioDeviceBuffer::InitPlayout()
113{
114    WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s", __FUNCTION__);
115    return 0;
116}
117
118// ----------------------------------------------------------------------------
119//  InitRecording
120// ----------------------------------------------------------------------------
121
122int32_t AudioDeviceBuffer::InitRecording()
123{
124    WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s", __FUNCTION__);
125    return 0;
126}
127
128// ----------------------------------------------------------------------------
129//  SetRecordingSampleRate
130// ----------------------------------------------------------------------------
131
132int32_t AudioDeviceBuffer::SetRecordingSampleRate(uint32_t fsHz)
133{
134    WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "AudioDeviceBuffer::SetRecordingSampleRate(fsHz=%u)", fsHz);
135
136    CriticalSectionScoped lock(&_critSect);
137    _recSampleRate = fsHz;
138    return 0;
139}
140
141// ----------------------------------------------------------------------------
142//  SetPlayoutSampleRate
143// ----------------------------------------------------------------------------
144
145int32_t AudioDeviceBuffer::SetPlayoutSampleRate(uint32_t fsHz)
146{
147    WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "AudioDeviceBuffer::SetPlayoutSampleRate(fsHz=%u)", fsHz);
148
149    CriticalSectionScoped lock(&_critSect);
150    _playSampleRate = fsHz;
151    return 0;
152}
153
154// ----------------------------------------------------------------------------
155//  RecordingSampleRate
156// ----------------------------------------------------------------------------
157
158int32_t AudioDeviceBuffer::RecordingSampleRate() const
159{
160    return _recSampleRate;
161}
162
163// ----------------------------------------------------------------------------
164//  PlayoutSampleRate
165// ----------------------------------------------------------------------------
166
167int32_t AudioDeviceBuffer::PlayoutSampleRate() const
168{
169    return _playSampleRate;
170}
171
172// ----------------------------------------------------------------------------
173//  SetRecordingChannels
174// ----------------------------------------------------------------------------
175
176int32_t AudioDeviceBuffer::SetRecordingChannels(uint8_t channels)
177{
178    WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "AudioDeviceBuffer::SetRecordingChannels(channels=%u)", channels);
179
180    CriticalSectionScoped lock(&_critSect);
181    _recChannels = channels;
182    _recBytesPerSample = 2*channels;  // 16 bits per sample in mono, 32 bits in stereo
183    return 0;
184}
185
186// ----------------------------------------------------------------------------
187//  SetPlayoutChannels
188// ----------------------------------------------------------------------------
189
190int32_t AudioDeviceBuffer::SetPlayoutChannels(uint8_t channels)
191{
192    WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "AudioDeviceBuffer::SetPlayoutChannels(channels=%u)", channels);
193
194    CriticalSectionScoped lock(&_critSect);
195    _playChannels = channels;
196    // 16 bits per sample in mono, 32 bits in stereo
197    _playBytesPerSample = 2*channels;
198    return 0;
199}
200
201// ----------------------------------------------------------------------------
202//  SetRecordingChannel
203//
204//  Select which channel to use while recording.
205//  This API requires that stereo is enabled.
206//
207//  Note that, the nChannel parameter in RecordedDataIsAvailable will be
208//  set to 2 even for kChannelLeft and kChannelRight. However, nBytesPerSample
209//  will be 2 instead of 4 four these cases.
210// ----------------------------------------------------------------------------
211
212int32_t AudioDeviceBuffer::SetRecordingChannel(const AudioDeviceModule::ChannelType channel)
213{
214    CriticalSectionScoped lock(&_critSect);
215
216    if (_recChannels == 1)
217    {
218        return -1;
219    }
220
221    if (channel == AudioDeviceModule::kChannelBoth)
222    {
223        // two bytes per channel
224        _recBytesPerSample = 4;
225    }
226    else
227    {
228        // only utilize one out of two possible channels (left or right)
229        _recBytesPerSample = 2;
230    }
231    _recChannel = channel;
232
233    return 0;
234}
235
236// ----------------------------------------------------------------------------
237//  RecordingChannel
238// ----------------------------------------------------------------------------
239
240int32_t AudioDeviceBuffer::RecordingChannel(AudioDeviceModule::ChannelType& channel) const
241{
242    channel = _recChannel;
243    return 0;
244}
245
246// ----------------------------------------------------------------------------
247//  RecordingChannels
248// ----------------------------------------------------------------------------
249
250uint8_t AudioDeviceBuffer::RecordingChannels() const
251{
252    return _recChannels;
253}
254
255// ----------------------------------------------------------------------------
256//  PlayoutChannels
257// ----------------------------------------------------------------------------
258
259uint8_t AudioDeviceBuffer::PlayoutChannels() const
260{
261    return _playChannels;
262}
263
264// ----------------------------------------------------------------------------
265//  SetCurrentMicLevel
266// ----------------------------------------------------------------------------
267
268int32_t AudioDeviceBuffer::SetCurrentMicLevel(uint32_t level)
269{
270    _currentMicLevel = level;
271    return 0;
272}
273
274int32_t AudioDeviceBuffer::SetTypingStatus(bool typingStatus)
275{
276    _typingStatus = typingStatus;
277    return 0;
278}
279
280// ----------------------------------------------------------------------------
281//  NewMicLevel
282// ----------------------------------------------------------------------------
283
284uint32_t AudioDeviceBuffer::NewMicLevel() const
285{
286    return _newMicLevel;
287}
288
289// ----------------------------------------------------------------------------
290//  SetVQEData
291// ----------------------------------------------------------------------------
292
293void AudioDeviceBuffer::SetVQEData(int playDelayMs, int recDelayMs,
294                                   int clockDrift) {
295  if (high_delay_counter_ < kLogHighDelayIntervalFrames) {
296    ++high_delay_counter_;
297  } else {
298    if (playDelayMs + recDelayMs > kHighDelayThresholdMs) {
299      high_delay_counter_ = 0;
300      LOG(LS_WARNING) << "High audio device delay reported (render="
301                      << playDelayMs << " ms, capture=" << recDelayMs << " ms)";
302    }
303  }
304
305  _playDelayMS = playDelayMs;
306  _recDelayMS = recDelayMs;
307  _clockDrift = clockDrift;
308}
309
310// ----------------------------------------------------------------------------
311//  StartInputFileRecording
312// ----------------------------------------------------------------------------
313
314int32_t AudioDeviceBuffer::StartInputFileRecording(
315    const char fileName[kAdmMaxFileNameSize])
316{
317    WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s", __FUNCTION__);
318
319    CriticalSectionScoped lock(&_critSect);
320
321    _recFile.Flush();
322    _recFile.CloseFile();
323
324    return (_recFile.OpenFile(fileName, false, false, false));
325}
326
327// ----------------------------------------------------------------------------
328//  StopInputFileRecording
329// ----------------------------------------------------------------------------
330
331int32_t AudioDeviceBuffer::StopInputFileRecording()
332{
333    WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s", __FUNCTION__);
334
335    CriticalSectionScoped lock(&_critSect);
336
337    _recFile.Flush();
338    _recFile.CloseFile();
339
340    return 0;
341}
342
343// ----------------------------------------------------------------------------
344//  StartOutputFileRecording
345// ----------------------------------------------------------------------------
346
347int32_t AudioDeviceBuffer::StartOutputFileRecording(
348    const char fileName[kAdmMaxFileNameSize])
349{
350    WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s", __FUNCTION__);
351
352    CriticalSectionScoped lock(&_critSect);
353
354    _playFile.Flush();
355    _playFile.CloseFile();
356
357    return (_playFile.OpenFile(fileName, false, false, false));
358}
359
360// ----------------------------------------------------------------------------
361//  StopOutputFileRecording
362// ----------------------------------------------------------------------------
363
364int32_t AudioDeviceBuffer::StopOutputFileRecording()
365{
366    WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s", __FUNCTION__);
367
368    CriticalSectionScoped lock(&_critSect);
369
370    _playFile.Flush();
371    _playFile.CloseFile();
372
373    return 0;
374}
375
376// ----------------------------------------------------------------------------
377//  SetRecordedBuffer
378//
379//  Store recorded audio buffer in local memory ready for the actual
380//  "delivery" using a callback.
381//
382//  This method can also parse out left or right channel from a stereo
383//  input signal, i.e., emulate mono.
384//
385//  Examples:
386//
387//  16-bit,48kHz mono,  10ms => nSamples=480 => _recSize=2*480=960 bytes
388//  16-bit,48kHz stereo,10ms => nSamples=480 => _recSize=4*480=1920 bytes
389// ----------------------------------------------------------------------------
390
391int32_t AudioDeviceBuffer::SetRecordedBuffer(const void* audioBuffer,
392                                             uint32_t nSamples)
393{
394    CriticalSectionScoped lock(&_critSect);
395
396    if (_recBytesPerSample == 0)
397    {
398        assert(false);
399        return -1;
400    }
401
402    _recSamples = nSamples;
403    _recSize = _recBytesPerSample*nSamples; // {2,4}*nSamples
404    if (_recSize > kMaxBufferSizeBytes)
405    {
406        assert(false);
407        return -1;
408    }
409
410    if (nSamples != _recSamples)
411    {
412        WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "invalid number of recorded samples (%d)", nSamples);
413        return -1;
414    }
415
416    if (_recChannel == AudioDeviceModule::kChannelBoth)
417    {
418        // (default) copy the complete input buffer to the local buffer
419        memcpy(&_recBuffer[0], audioBuffer, _recSize);
420    }
421    else
422    {
423        int16_t* ptr16In = (int16_t*)audioBuffer;
424        int16_t* ptr16Out = (int16_t*)&_recBuffer[0];
425
426        if (AudioDeviceModule::kChannelRight == _recChannel)
427        {
428            ptr16In++;
429        }
430
431        // exctract left or right channel from input buffer to the local buffer
432        for (uint32_t i = 0; i < _recSamples; i++)
433        {
434            *ptr16Out = *ptr16In;
435            ptr16Out++;
436            ptr16In++;
437            ptr16In++;
438        }
439    }
440
441    if (_recFile.Open())
442    {
443        // write to binary file in mono or stereo (interleaved)
444        _recFile.Write(&_recBuffer[0], _recSize);
445    }
446
447    return 0;
448}
449
450// ----------------------------------------------------------------------------
451//  DeliverRecordedData
452// ----------------------------------------------------------------------------
453
454int32_t AudioDeviceBuffer::DeliverRecordedData()
455{
456    CriticalSectionScoped lock(&_critSectCb);
457
458    // Ensure that user has initialized all essential members
459    if ((_recSampleRate == 0)     ||
460        (_recSamples == 0)        ||
461        (_recBytesPerSample == 0) ||
462        (_recChannels == 0))
463    {
464        assert(false);
465        return -1;
466    }
467
468    if (_ptrCbAudioTransport == NULL)
469    {
470        WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "failed to deliver recorded data (AudioTransport does not exist)");
471        return 0;
472    }
473
474    int32_t res(0);
475    uint32_t newMicLevel(0);
476    uint32_t totalDelayMS = _playDelayMS +_recDelayMS;
477
478    res = _ptrCbAudioTransport->RecordedDataIsAvailable(&_recBuffer[0],
479                                                        _recSamples,
480                                                        _recBytesPerSample,
481                                                        _recChannels,
482                                                        _recSampleRate,
483                                                        totalDelayMS,
484                                                        _clockDrift,
485                                                        _currentMicLevel,
486                                                        _typingStatus,
487                                                        newMicLevel);
488    if (res != -1)
489    {
490        _newMicLevel = newMicLevel;
491    }
492
493    return 0;
494}
495
496// ----------------------------------------------------------------------------
497//  RequestPlayoutData
498// ----------------------------------------------------------------------------
499
500int32_t AudioDeviceBuffer::RequestPlayoutData(uint32_t nSamples)
501{
502    uint32_t playSampleRate = 0;
503    uint8_t playBytesPerSample = 0;
504    uint8_t playChannels = 0;
505    {
506        CriticalSectionScoped lock(&_critSect);
507
508        // Store copies under lock and use copies hereafter to avoid race with
509        // setter methods.
510        playSampleRate = _playSampleRate;
511        playBytesPerSample = _playBytesPerSample;
512        playChannels = _playChannels;
513
514        // Ensure that user has initialized all essential members
515        if ((playBytesPerSample == 0) ||
516            (playChannels == 0)       ||
517            (playSampleRate == 0))
518        {
519            assert(false);
520            return -1;
521        }
522
523        _playSamples = nSamples;
524        _playSize = playBytesPerSample * nSamples;  // {2,4}*nSamples
525        if (_playSize > kMaxBufferSizeBytes)
526        {
527            assert(false);
528            return -1;
529        }
530
531        if (nSamples != _playSamples)
532        {
533            WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "invalid number of samples to be played out (%d)", nSamples);
534            return -1;
535        }
536    }
537
538    uint32_t nSamplesOut(0);
539
540    CriticalSectionScoped lock(&_critSectCb);
541
542    if (_ptrCbAudioTransport == NULL)
543    {
544        WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "failed to feed data to playout (AudioTransport does not exist)");
545        return 0;
546    }
547
548    if (_ptrCbAudioTransport)
549    {
550        uint32_t res(0);
551        int64_t elapsed_time_ms = -1;
552        int64_t ntp_time_ms = -1;
553        res = _ptrCbAudioTransport->NeedMorePlayData(_playSamples,
554                                                     playBytesPerSample,
555                                                     playChannels,
556                                                     playSampleRate,
557                                                     &_playBuffer[0],
558                                                     nSamplesOut,
559                                                     &elapsed_time_ms,
560                                                     &ntp_time_ms);
561        if (res != 0)
562        {
563            WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "NeedMorePlayData() failed");
564        }
565    }
566
567    return nSamplesOut;
568}
569
570// ----------------------------------------------------------------------------
571//  GetPlayoutData
572// ----------------------------------------------------------------------------
573
574int32_t AudioDeviceBuffer::GetPlayoutData(void* audioBuffer)
575{
576    CriticalSectionScoped lock(&_critSect);
577
578    if (_playSize > kMaxBufferSizeBytes)
579    {
580       WEBRTC_TRACE(kTraceError, kTraceUtility, _id, "_playSize %i exceeds "
581       "kMaxBufferSizeBytes in AudioDeviceBuffer::GetPlayoutData", _playSize);
582       assert(false);
583       return -1;
584    }
585
586    memcpy(audioBuffer, &_playBuffer[0], _playSize);
587
588    if (_playFile.Open())
589    {
590        // write to binary file in mono or stereo (interleaved)
591        _playFile.Write(&_playBuffer[0], _playSize);
592    }
593
594    return _playSamples;
595}
596
597}  // namespace webrtc
598