2011-07-07 08:21:25 +00:00
|
|
|
/*
|
2012-02-20 09:17:41 +00:00
|
|
|
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
2011-07-07 08:21:25 +00:00
|
|
|
*
|
|
|
|
|
* Use of this source code is governed by a BSD-style license
|
|
|
|
|
* that can be found in the LICENSE file in the root of the source
|
|
|
|
|
* tree. An additional intellectual property rights grant can be found
|
|
|
|
|
* in the file PATENTS. All contributing project authors may
|
|
|
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
|
|
|
*/
|
|
|
|
|
|
2013-07-11 13:24:38 +00:00
|
|
|
#include "webrtc/modules/audio_device/audio_device_buffer.h"
|
2013-09-13 00:02:13 +00:00
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
Update a ton of audio code to use size_t more correctly and in general reduce
use of int16_t/uint16_t.
This is the upshot of a recommendation by henrik.lundin and kwiberg on an original small change ( https://webrtc-codereview.appspot.com/42569004/#ps1 ) to stop using int16_t just because values could fit in it, and is similar in nature to a previous "mass change to use size_t more" ( https://webrtc-codereview.appspot.com/23129004/ ) which also needed to be split up for review but to land all at once, since, like adding "const", such changes tend to cause a lot of transitive effects.
This was be reviewed and approved in pieces:
https://codereview.webrtc.org/1224093003
https://codereview.webrtc.org/1224123002
https://codereview.webrtc.org/1224163002
https://codereview.webrtc.org/1225133003
https://codereview.webrtc.org/1225173002
https://codereview.webrtc.org/1227163003
https://codereview.webrtc.org/1227203003
https://codereview.webrtc.org/1227213002
https://codereview.webrtc.org/1227893002
https://codereview.webrtc.org/1228793004
https://codereview.webrtc.org/1228803003
https://codereview.webrtc.org/1228823002
https://codereview.webrtc.org/1228823003
https://codereview.webrtc.org/1228843002
https://codereview.webrtc.org/1230693002
https://codereview.webrtc.org/1231713002
The change is being landed as TBR to all the folks who reviewed the above.
BUG=chromium:81439
TEST=none
R=andrew@webrtc.org, pbos@webrtc.org
TBR=aluebs, andrew, asapersson, henrika, hlundin, jan.skoglund, kwiberg, minyue, pbos, pthatcher
Review URL: https://codereview.webrtc.org/1230503003 .
Cr-Commit-Position: refs/heads/master@{#9768}
2015-08-24 14:52:23 -07:00
|
|
|
#include "webrtc/base/format_macros.h"
|
2013-07-11 13:24:38 +00:00
|
|
|
#include "webrtc/modules/audio_device/audio_device_config.h"
|
2015-10-28 18:17:40 +01:00
|
|
|
#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
|
|
|
|
|
#include "webrtc/system_wrappers/include/logging.h"
|
|
|
|
|
#include "webrtc/system_wrappers/include/trace.h"
|
2011-07-07 08:21:25 +00:00
|
|
|
|
|
|
|
|
namespace webrtc {
|
|
|
|
|
|
2013-09-11 22:35:00 +00:00
|
|
|
static const int kHighDelayThresholdMs = 300;
|
|
|
|
|
static const int kLogHighDelayIntervalFrames = 500; // 5 seconds.
|
|
|
|
|
|
2011-07-07 08:21:25 +00:00
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
// ctor
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
AudioDeviceBuffer::AudioDeviceBuffer()
|
|
|
|
|
: _id(-1),
|
|
|
|
|
_critSect(*CriticalSectionWrapper::CreateCriticalSection()),
|
|
|
|
|
_critSectCb(*CriticalSectionWrapper::CreateCriticalSection()),
|
|
|
|
|
_ptrCbAudioTransport(NULL),
|
|
|
|
|
_recSampleRate(0),
|
|
|
|
|
_playSampleRate(0),
|
|
|
|
|
_recChannels(0),
|
|
|
|
|
_playChannels(0),
|
|
|
|
|
_recChannel(AudioDeviceModule::kChannelBoth),
|
|
|
|
|
_recBytesPerSample(0),
|
|
|
|
|
_playBytesPerSample(0),
|
|
|
|
|
_recSamples(0),
|
|
|
|
|
_recSize(0),
|
|
|
|
|
_playSamples(0),
|
|
|
|
|
_playSize(0),
|
|
|
|
|
_recFile(*FileWrapper::Create()),
|
|
|
|
|
_playFile(*FileWrapper::Create()),
|
|
|
|
|
_currentMicLevel(0),
|
|
|
|
|
_newMicLevel(0),
|
|
|
|
|
_typingStatus(false),
|
|
|
|
|
_playDelayMS(0),
|
|
|
|
|
_recDelayMS(0),
|
|
|
|
|
_clockDrift(0),
|
|
|
|
|
// Set to the interval in order to log on the first occurrence.
|
|
|
|
|
high_delay_counter_(kLogHighDelayIntervalFrames) {
|
|
|
|
|
// valid ID will be set later by SetId, use -1 for now
|
|
|
|
|
WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s created",
|
|
|
|
|
__FUNCTION__);
|
|
|
|
|
memset(_recBuffer, 0, kMaxBufferSizeBytes);
|
|
|
|
|
memset(_playBuffer, 0, kMaxBufferSizeBytes);
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
// dtor
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
AudioDeviceBuffer::~AudioDeviceBuffer() {
|
|
|
|
|
WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s destroyed",
|
|
|
|
|
__FUNCTION__);
|
|
|
|
|
{
|
|
|
|
|
CriticalSectionScoped lock(&_critSect);
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
_recFile.Flush();
|
|
|
|
|
_recFile.CloseFile();
|
|
|
|
|
delete &_recFile;
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
_playFile.Flush();
|
|
|
|
|
_playFile.CloseFile();
|
|
|
|
|
delete &_playFile;
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
delete &_critSect;
|
|
|
|
|
delete &_critSectCb;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
// SetId
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
void AudioDeviceBuffer::SetId(uint32_t id) {
|
|
|
|
|
WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, id,
|
|
|
|
|
"AudioDeviceBuffer::SetId(id=%d)", id);
|
|
|
|
|
_id = id;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
// RegisterAudioCallback
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
int32_t AudioDeviceBuffer::RegisterAudioCallback(
|
|
|
|
|
AudioTransport* audioCallback) {
|
|
|
|
|
CriticalSectionScoped lock(&_critSectCb);
|
|
|
|
|
_ptrCbAudioTransport = audioCallback;
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
return 0;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
// InitPlayout
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
int32_t AudioDeviceBuffer::InitPlayout() {
|
|
|
|
|
WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s", __FUNCTION__);
|
|
|
|
|
return 0;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
// InitRecording
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
int32_t AudioDeviceBuffer::InitRecording() {
|
|
|
|
|
WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s", __FUNCTION__);
|
|
|
|
|
return 0;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
// SetRecordingSampleRate
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
int32_t AudioDeviceBuffer::SetRecordingSampleRate(uint32_t fsHz) {
|
|
|
|
|
CriticalSectionScoped lock(&_critSect);
|
|
|
|
|
_recSampleRate = fsHz;
|
|
|
|
|
return 0;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
// SetPlayoutSampleRate
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
int32_t AudioDeviceBuffer::SetPlayoutSampleRate(uint32_t fsHz) {
|
|
|
|
|
CriticalSectionScoped lock(&_critSect);
|
|
|
|
|
_playSampleRate = fsHz;
|
|
|
|
|
return 0;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
// RecordingSampleRate
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
int32_t AudioDeviceBuffer::RecordingSampleRate() const {
|
|
|
|
|
return _recSampleRate;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
// PlayoutSampleRate
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
int32_t AudioDeviceBuffer::PlayoutSampleRate() const {
|
|
|
|
|
return _playSampleRate;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
// SetRecordingChannels
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
int32_t AudioDeviceBuffer::SetRecordingChannels(size_t channels) {
|
|
|
|
|
CriticalSectionScoped lock(&_critSect);
|
|
|
|
|
_recChannels = channels;
|
|
|
|
|
_recBytesPerSample =
|
|
|
|
|
2 * channels; // 16 bits per sample in mono, 32 bits in stereo
|
|
|
|
|
return 0;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
// SetPlayoutChannels
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
int32_t AudioDeviceBuffer::SetPlayoutChannels(size_t channels) {
|
|
|
|
|
CriticalSectionScoped lock(&_critSect);
|
|
|
|
|
_playChannels = channels;
|
|
|
|
|
// 16 bits per sample in mono, 32 bits in stereo
|
|
|
|
|
_playBytesPerSample = 2 * channels;
|
|
|
|
|
return 0;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
// SetRecordingChannel
|
|
|
|
|
//
|
|
|
|
|
// Select which channel to use while recording.
|
|
|
|
|
// This API requires that stereo is enabled.
|
|
|
|
|
//
|
|
|
|
|
// Note that, the nChannel parameter in RecordedDataIsAvailable will be
|
|
|
|
|
// set to 2 even for kChannelLeft and kChannelRight. However, nBytesPerSample
|
|
|
|
|
// will be 2 instead of 4 four these cases.
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
int32_t AudioDeviceBuffer::SetRecordingChannel(
|
|
|
|
|
const AudioDeviceModule::ChannelType channel) {
|
|
|
|
|
CriticalSectionScoped lock(&_critSect);
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
if (_recChannels == 1) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
if (channel == AudioDeviceModule::kChannelBoth) {
|
|
|
|
|
// two bytes per channel
|
|
|
|
|
_recBytesPerSample = 4;
|
|
|
|
|
} else {
|
|
|
|
|
// only utilize one out of two possible channels (left or right)
|
|
|
|
|
_recBytesPerSample = 2;
|
|
|
|
|
}
|
|
|
|
|
_recChannel = channel;
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
return 0;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
// RecordingChannel
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
int32_t AudioDeviceBuffer::RecordingChannel(
|
|
|
|
|
AudioDeviceModule::ChannelType& channel) const {
|
|
|
|
|
channel = _recChannel;
|
|
|
|
|
return 0;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
// RecordingChannels
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
size_t AudioDeviceBuffer::RecordingChannels() const {
|
|
|
|
|
return _recChannels;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
// PlayoutChannels
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
size_t AudioDeviceBuffer::PlayoutChannels() const {
|
|
|
|
|
return _playChannels;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
// SetCurrentMicLevel
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
int32_t AudioDeviceBuffer::SetCurrentMicLevel(uint32_t level) {
|
|
|
|
|
_currentMicLevel = level;
|
|
|
|
|
return 0;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
int32_t AudioDeviceBuffer::SetTypingStatus(bool typingStatus) {
|
|
|
|
|
_typingStatus = typingStatus;
|
|
|
|
|
return 0;
|
2013-05-07 21:04:24 +00:00
|
|
|
}
|
|
|
|
|
|
2011-07-07 08:21:25 +00:00
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
// NewMicLevel
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
uint32_t AudioDeviceBuffer::NewMicLevel() const {
|
|
|
|
|
return _newMicLevel;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
// SetVQEData
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
void AudioDeviceBuffer::SetVQEData(int playDelayMs,
|
|
|
|
|
int recDelayMs,
|
2013-09-12 01:01:42 +00:00
|
|
|
int clockDrift) {
|
2013-09-11 22:35:00 +00:00
|
|
|
if (high_delay_counter_ < kLogHighDelayIntervalFrames) {
|
|
|
|
|
++high_delay_counter_;
|
|
|
|
|
} else {
|
|
|
|
|
if (playDelayMs + recDelayMs > kHighDelayThresholdMs) {
|
|
|
|
|
high_delay_counter_ = 0;
|
|
|
|
|
LOG(LS_WARNING) << "High audio device delay reported (render="
|
|
|
|
|
<< playDelayMs << " ms, capture=" << recDelayMs << " ms)";
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
2013-09-11 22:35:00 +00:00
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2013-09-11 22:35:00 +00:00
|
|
|
_playDelayMS = playDelayMs;
|
|
|
|
|
_recDelayMS = recDelayMs;
|
|
|
|
|
_clockDrift = clockDrift;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
// StartInputFileRecording
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
2013-04-09 10:30:35 +00:00
|
|
|
int32_t AudioDeviceBuffer::StartInputFileRecording(
|
2016-07-04 13:01:19 +02:00
|
|
|
const char fileName[kAdmMaxFileNameSize]) {
|
|
|
|
|
WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s", __FUNCTION__);
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
CriticalSectionScoped lock(&_critSect);
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
_recFile.Flush();
|
|
|
|
|
_recFile.CloseFile();
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
return _recFile.OpenFile(fileName, false) ? 0 : -1;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
// StopInputFileRecording
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
int32_t AudioDeviceBuffer::StopInputFileRecording() {
|
|
|
|
|
WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s", __FUNCTION__);
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
CriticalSectionScoped lock(&_critSect);
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
_recFile.Flush();
|
|
|
|
|
_recFile.CloseFile();
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
return 0;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
// StartOutputFileRecording
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
2013-04-09 10:30:35 +00:00
|
|
|
int32_t AudioDeviceBuffer::StartOutputFileRecording(
|
2016-07-04 13:01:19 +02:00
|
|
|
const char fileName[kAdmMaxFileNameSize]) {
|
|
|
|
|
WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s", __FUNCTION__);
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
CriticalSectionScoped lock(&_critSect);
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
_playFile.Flush();
|
|
|
|
|
_playFile.CloseFile();
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
return _playFile.OpenFile(fileName, false) ? 0 : -1;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
// StopOutputFileRecording
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
int32_t AudioDeviceBuffer::StopOutputFileRecording() {
|
|
|
|
|
WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s", __FUNCTION__);
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
CriticalSectionScoped lock(&_critSect);
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
_playFile.Flush();
|
|
|
|
|
_playFile.CloseFile();
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
return 0;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
// SetRecordedBuffer
|
|
|
|
|
//
|
|
|
|
|
// Store recorded audio buffer in local memory ready for the actual
|
|
|
|
|
// "delivery" using a callback.
|
|
|
|
|
//
|
|
|
|
|
// This method can also parse out left or right channel from a stereo
|
|
|
|
|
// input signal, i.e., emulate mono.
|
|
|
|
|
//
|
|
|
|
|
// Examples:
|
|
|
|
|
//
|
|
|
|
|
// 16-bit,48kHz mono, 10ms => nSamples=480 => _recSize=2*480=960 bytes
|
2011-11-25 02:45:39 +00:00
|
|
|
// 16-bit,48kHz stereo,10ms => nSamples=480 => _recSize=4*480=1920 bytes
|
2011-07-07 08:21:25 +00:00
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
2013-04-09 10:30:35 +00:00
|
|
|
int32_t AudioDeviceBuffer::SetRecordedBuffer(const void* audioBuffer,
|
2016-07-04 13:01:19 +02:00
|
|
|
size_t nSamples) {
|
|
|
|
|
CriticalSectionScoped lock(&_critSect);
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
if (_recBytesPerSample == 0) {
|
|
|
|
|
assert(false);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
_recSamples = nSamples;
|
|
|
|
|
_recSize = _recBytesPerSample * nSamples; // {2,4}*nSamples
|
|
|
|
|
if (_recSize > kMaxBufferSizeBytes) {
|
|
|
|
|
assert(false);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
if (_recChannel == AudioDeviceModule::kChannelBoth) {
|
|
|
|
|
// (default) copy the complete input buffer to the local buffer
|
|
|
|
|
memcpy(&_recBuffer[0], audioBuffer, _recSize);
|
|
|
|
|
} else {
|
|
|
|
|
int16_t* ptr16In = (int16_t*)audioBuffer;
|
|
|
|
|
int16_t* ptr16Out = (int16_t*)&_recBuffer[0];
|
|
|
|
|
|
|
|
|
|
if (AudioDeviceModule::kChannelRight == _recChannel) {
|
|
|
|
|
ptr16In++;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
// exctract left or right channel from input buffer to the local buffer
|
|
|
|
|
for (size_t i = 0; i < _recSamples; i++) {
|
|
|
|
|
*ptr16Out = *ptr16In;
|
|
|
|
|
ptr16Out++;
|
|
|
|
|
ptr16In++;
|
|
|
|
|
ptr16In++;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
2016-07-04 13:01:19 +02:00
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
if (_recFile.is_open()) {
|
|
|
|
|
// write to binary file in mono or stereo (interleaved)
|
|
|
|
|
_recFile.Write(&_recBuffer[0], _recSize);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
// DeliverRecordedData
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
int32_t AudioDeviceBuffer::DeliverRecordedData() {
|
|
|
|
|
CriticalSectionScoped lock(&_critSectCb);
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
// Ensure that user has initialized all essential members
|
|
|
|
|
if ((_recSampleRate == 0) || (_recSamples == 0) ||
|
|
|
|
|
(_recBytesPerSample == 0) || (_recChannels == 0)) {
|
|
|
|
|
assert(false);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
if (_ptrCbAudioTransport == NULL) {
|
|
|
|
|
WEBRTC_TRACE(
|
|
|
|
|
kTraceWarning, kTraceAudioDevice, _id,
|
|
|
|
|
"failed to deliver recorded data (AudioTransport does not exist)");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
int32_t res(0);
|
|
|
|
|
uint32_t newMicLevel(0);
|
|
|
|
|
uint32_t totalDelayMS = _playDelayMS + _recDelayMS;
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
res = _ptrCbAudioTransport->RecordedDataIsAvailable(
|
|
|
|
|
&_recBuffer[0], _recSamples, _recBytesPerSample, _recChannels,
|
|
|
|
|
_recSampleRate, totalDelayMS, _clockDrift, _currentMicLevel,
|
|
|
|
|
_typingStatus, newMicLevel);
|
|
|
|
|
if (res != -1) {
|
|
|
|
|
_newMicLevel = newMicLevel;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
// RequestPlayoutData
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
int32_t AudioDeviceBuffer::RequestPlayoutData(size_t nSamples) {
|
|
|
|
|
uint32_t playSampleRate = 0;
|
|
|
|
|
size_t playBytesPerSample = 0;
|
|
|
|
|
size_t playChannels = 0;
|
|
|
|
|
{
|
|
|
|
|
CriticalSectionScoped lock(&_critSect);
|
|
|
|
|
|
|
|
|
|
// Store copies under lock and use copies hereafter to avoid race with
|
|
|
|
|
// setter methods.
|
|
|
|
|
playSampleRate = _playSampleRate;
|
|
|
|
|
playBytesPerSample = _playBytesPerSample;
|
|
|
|
|
playChannels = _playChannels;
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
// Ensure that user has initialized all essential members
|
|
|
|
|
if ((playBytesPerSample == 0) || (playChannels == 0) ||
|
|
|
|
|
(playSampleRate == 0)) {
|
|
|
|
|
assert(false);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
_playSamples = nSamples;
|
|
|
|
|
_playSize = playBytesPerSample * nSamples; // {2,4}*nSamples
|
|
|
|
|
if (_playSize > kMaxBufferSizeBytes) {
|
|
|
|
|
assert(false);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
if (nSamples != _playSamples) {
|
|
|
|
|
WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
|
|
|
|
|
"invalid number of samples to be played out (%d)", nSamples);
|
|
|
|
|
return -1;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
2016-07-04 13:01:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t nSamplesOut(0);
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
CriticalSectionScoped lock(&_critSectCb);
|
|
|
|
|
|
|
|
|
|
if (_ptrCbAudioTransport == NULL) {
|
|
|
|
|
WEBRTC_TRACE(
|
|
|
|
|
kTraceWarning, kTraceAudioDevice, _id,
|
|
|
|
|
"failed to feed data to playout (AudioTransport does not exist)");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_ptrCbAudioTransport) {
|
|
|
|
|
uint32_t res(0);
|
|
|
|
|
int64_t elapsed_time_ms = -1;
|
|
|
|
|
int64_t ntp_time_ms = -1;
|
|
|
|
|
res = _ptrCbAudioTransport->NeedMorePlayData(
|
|
|
|
|
_playSamples, playBytesPerSample, playChannels, playSampleRate,
|
|
|
|
|
&_playBuffer[0], nSamplesOut, &elapsed_time_ms, &ntp_time_ms);
|
|
|
|
|
if (res != 0) {
|
|
|
|
|
WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
|
|
|
|
|
"NeedMorePlayData() failed");
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
2016-07-04 13:01:19 +02:00
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
return static_cast<int32_t>(nSamplesOut);
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
// GetPlayoutData
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
int32_t AudioDeviceBuffer::GetPlayoutData(void* audioBuffer) {
|
|
|
|
|
CriticalSectionScoped lock(&_critSect);
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
if (_playSize > kMaxBufferSizeBytes) {
|
|
|
|
|
WEBRTC_TRACE(kTraceError, kTraceUtility, _id,
|
|
|
|
|
"_playSize %" PRIuS
|
|
|
|
|
" exceeds kMaxBufferSizeBytes in "
|
|
|
|
|
"AudioDeviceBuffer::GetPlayoutData",
|
|
|
|
|
_playSize);
|
|
|
|
|
assert(false);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2011-11-29 18:49:54 +00:00
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
memcpy(audioBuffer, &_playBuffer[0], _playSize);
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
if (_playFile.is_open()) {
|
|
|
|
|
// write to binary file in mono or stereo (interleaved)
|
|
|
|
|
_playFile.Write(&_playBuffer[0], _playSize);
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2016-07-04 13:01:19 +02:00
|
|
|
return static_cast<int32_t>(_playSamples);
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace webrtc
|