Revert changes to modules/audio_device files
This commit is contained in:
parent
37c5088468
commit
f6d7f2beaa
2
.github/workflows/webrtc.yml
vendored
2
.github/workflows/webrtc.yml
vendored
@ -14,7 +14,7 @@ jobs:
|
||||
- check: 'ringrtc'
|
||||
exclude: '(oboe|opus)'
|
||||
- check: 'sdk'
|
||||
exclude: '(objc)'
|
||||
exclude: '(objc|jni_helpers\.h)'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Run clang-format
|
||||
|
||||
@ -256,8 +256,6 @@ rtc_library("audio_device_impl") {
|
||||
":audio_device_default",
|
||||
":audio_device_dummy",
|
||||
":audio_device_generic",
|
||||
# RingRTC change to include Windows ADM2.
|
||||
":audio_device_module_from_input_and_output",
|
||||
"../../api:array_view",
|
||||
"../../api:make_ref_counted",
|
||||
"../../api:ref_count",
|
||||
|
||||
@ -1598,8 +1598,7 @@ int32_t AudioDeviceLinuxPulse::InitPulseAudio() {
|
||||
PaUnLock();
|
||||
return -1;
|
||||
}
|
||||
// RingRTC change to the name of the context.
|
||||
_paContext = LATE(pa_context_new)(_paMainloopApi, "Signal Calling");
|
||||
_paContext = LATE(pa_context_new)(_paMainloopApi, "WEBRTC VoiceEngine");
|
||||
|
||||
if (!_paContext) {
|
||||
RTC_LOG(LS_ERROR) << "could not create context";
|
||||
|
||||
@ -72,11 +72,7 @@ const uint32_t WEBRTC_PA_PLAYBACK_LATENCY_INCREMENT_MSECS = 20;
|
||||
// CPU from the overhead of transfering small amounts of data at once. Too large
|
||||
// and the amount of data remaining in the buffer right before refilling it
|
||||
// would be a buffer underflow risk. We set it to half of the buffer size.
|
||||
// RingRTC change to avoid scratchy audio.
|
||||
// Update: with 2, we often get scratchy audio.
|
||||
// The Pulse code indicates 2 is a bad idea and 4 is a good idea.
|
||||
// See https://github.com/pulseaudio/pulseaudio/blob/master/src/pulsecore/protocol-native.c#L814
|
||||
const uint32_t WEBRTC_PA_PLAYBACK_REQUEST_FACTOR = 4;
|
||||
const uint32_t WEBRTC_PA_PLAYBACK_REQUEST_FACTOR = 2;
|
||||
|
||||
// Capture.
|
||||
|
||||
|
||||
@ -118,6 +118,8 @@ AudioDeviceMac::AudioDeviceMac()
|
||||
_twoDevices(true),
|
||||
_doStop(false),
|
||||
_doStopRec(false),
|
||||
_macBookPro(false),
|
||||
_macBookProPanRight(false),
|
||||
_captureLatencyUs(0),
|
||||
_renderLatencyUs(0),
|
||||
_captureDelayUs(0),
|
||||
@ -291,7 +293,22 @@ AudioDeviceGeneric::InitStatus AudioDeviceMac::Init() {
|
||||
WEBRTC_CA_LOG_ERR(AudioObjectAddPropertyListener(
|
||||
kAudioObjectSystemObject, &propertyAddress, &objectListenerProc, this));
|
||||
|
||||
// RingRTC changes (code removed) to avoid speaker panning
|
||||
// Determine if this is a MacBook Pro
|
||||
_macBookPro = false;
|
||||
_macBookProPanRight = false;
|
||||
char buf[128];
|
||||
size_t length = sizeof(buf);
|
||||
memset(buf, 0, length);
|
||||
|
||||
int intErr = sysctlbyname("hw.model", buf, &length, NULL, 0);
|
||||
if (intErr != 0) {
|
||||
RTC_LOG(LS_ERROR) << "Error in sysctlbyname(): " << err;
|
||||
} else {
|
||||
RTC_LOG(LS_VERBOSE) << "Hardware model: " << buf;
|
||||
if (strncmp(buf, "MacBookPro", 10) == 0) {
|
||||
_macBookPro = true;
|
||||
}
|
||||
}
|
||||
|
||||
_initialized = true;
|
||||
|
||||
@ -960,9 +977,34 @@ int32_t AudioDeviceMac::InitPlayout() {
|
||||
_renderDeviceIsAlive = 1;
|
||||
_doStop = false;
|
||||
|
||||
// RingRTC changes (code removed) to avoid speaker panning
|
||||
// The internal microphone of a MacBook Pro is located under the left speaker
|
||||
// grille. When the internal speakers are in use, we want to fully stereo
|
||||
// pan to the right.
|
||||
AudioObjectPropertyAddress propertyAddress = {
|
||||
kAudioDevicePropertyDataSource, kAudioDevicePropertyScopeOutput, 0};
|
||||
if (_macBookPro) {
|
||||
_macBookProPanRight = false;
|
||||
Boolean hasProperty =
|
||||
AudioObjectHasProperty(_outputDeviceID, &propertyAddress);
|
||||
if (hasProperty) {
|
||||
UInt32 dataSource = 0;
|
||||
size = sizeof(dataSource);
|
||||
WEBRTC_CA_LOG_WARN(AudioObjectGetPropertyData(
|
||||
_outputDeviceID, &propertyAddress, 0, NULL, &size, &dataSource));
|
||||
|
||||
if (dataSource == 'ispk') {
|
||||
_macBookProPanRight = true;
|
||||
RTC_LOG(LS_VERBOSE)
|
||||
<< "MacBook Pro using internal speakers; stereo panning right";
|
||||
} else {
|
||||
RTC_LOG(LS_VERBOSE) << "MacBook Pro not using internal speakers";
|
||||
}
|
||||
|
||||
// Add a listener to determine if the status changes.
|
||||
WEBRTC_CA_LOG_WARN(AudioObjectAddPropertyListener(
|
||||
_outputDeviceID, &propertyAddress, &objectListenerProc, this));
|
||||
}
|
||||
}
|
||||
|
||||
// Get current stream description
|
||||
propertyAddress.mSelector = kAudioDevicePropertyStreamFormat;
|
||||
@ -1033,8 +1075,7 @@ int32_t AudioDeviceMac::InitPlayout() {
|
||||
}
|
||||
|
||||
int32_t AudioDeviceMac::InitRecording() {
|
||||
// RingRTC change to log more information around audio capture
|
||||
RTC_LOG(LS_WARNING) << "InitRecording";
|
||||
RTC_LOG(LS_INFO) << "InitRecording";
|
||||
MutexLock lock(&mutex_);
|
||||
|
||||
if (_recording) {
|
||||
@ -1264,8 +1305,6 @@ int32_t AudioDeviceMac::StartRecording() {
|
||||
}
|
||||
|
||||
_recording = true;
|
||||
// RingRTC change to log more information around audio capture
|
||||
RTC_LOG(LS_WARNING) << "Started recording";
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1284,8 +1323,6 @@ int32_t AudioDeviceMac::StopRecording() {
|
||||
// Recording side uses its own dedicated device and IOProc.
|
||||
if (_recording) {
|
||||
_recording = false;
|
||||
// RingRTC change to log more information around audio capture
|
||||
RTC_LOG(LS_WARNING) << "Stopped recording";
|
||||
_doStopRec = true; // Signal to io proc to stop audio device
|
||||
mutex_.Unlock(); // Cannot be under lock, risk of deadlock
|
||||
if (!_stopEventRec.Wait(TimeDelta::Seconds(2))) {
|
||||
@ -1314,10 +1351,8 @@ int32_t AudioDeviceMac::StopRecording() {
|
||||
// rendering has ended before stopping itself.
|
||||
if (_recording && captureDeviceIsAlive == 1) {
|
||||
_recording = false;
|
||||
// RingRTC change to log more information around audio capture
|
||||
RTC_LOG(LS_WARNING) << "Stopped recording";
|
||||
_doStop = true; // Signal to io proc to stop audio device
|
||||
mutex_.Unlock(); // Cannot be under lock, risk of deadlock
|
||||
_doStop = true; // Signal to io proc to stop audio device
|
||||
mutex_.Unlock(); // Cannot be under lock, risk of deadlock
|
||||
if (!_stopEvent.Wait(TimeDelta::Seconds(2))) {
|
||||
MutexLock lockScoped(&mutex_);
|
||||
RTC_LOG(LS_WARNING) << "Timed out stopping the shared IOProc."
|
||||
@ -1361,8 +1396,6 @@ int32_t AudioDeviceMac::StopRecording() {
|
||||
|
||||
_recIsInitialized = false;
|
||||
_recording = false;
|
||||
// RingRTC change to log more information around audio capture
|
||||
RTC_LOG(LS_WARNING) << "Stopped recording";
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1474,6 +1507,16 @@ int32_t AudioDeviceMac::StopPlayout() {
|
||||
WEBRTC_CA_LOG_WARN(AudioObjectRemovePropertyListener(
|
||||
_outputDeviceID, &propertyAddress, &objectListenerProc, this));
|
||||
|
||||
if (_macBookPro) {
|
||||
Boolean hasProperty =
|
||||
AudioObjectHasProperty(_outputDeviceID, &propertyAddress);
|
||||
if (hasProperty) {
|
||||
propertyAddress.mSelector = kAudioDevicePropertyDataSource;
|
||||
WEBRTC_CA_LOG_WARN(AudioObjectRemovePropertyListener(
|
||||
_outputDeviceID, &propertyAddress, &objectListenerProc, this));
|
||||
}
|
||||
}
|
||||
|
||||
_playIsInitialized = false;
|
||||
_playing = false;
|
||||
|
||||
@ -1865,6 +1908,8 @@ OSStatus AudioDeviceMac::implObjectListenerProc(
|
||||
HandleDeviceChange();
|
||||
} else if (addresses[i].mSelector == kAudioDevicePropertyStreamFormat) {
|
||||
HandleStreamFormatChange(objectId, addresses[i]);
|
||||
} else if (addresses[i].mSelector == kAudioDevicePropertyDataSource) {
|
||||
HandleDataSourceChange(objectId, addresses[i]);
|
||||
} else if (addresses[i].mSelector == kAudioDeviceProcessorOverload) {
|
||||
HandleProcessorOverload(addresses[i]);
|
||||
}
|
||||
@ -1950,13 +1995,10 @@ int32_t AudioDeviceMac::HandleStreamFormatChange(
|
||||
return -1;
|
||||
}
|
||||
|
||||
// RingRTC change to check for a channel change for the input device only
|
||||
if (propertyAddress.mScope == kAudioDevicePropertyScopeInput) {
|
||||
if (_ptrAudioBuffer && streamFormat.mChannelsPerFrame != _recChannels) {
|
||||
RTC_LOG(LS_ERROR) << "Changing channels not supported (mChannelsPerFrame = "
|
||||
<< streamFormat.mChannelsPerFrame << ")";
|
||||
return -1;
|
||||
}
|
||||
if (_ptrAudioBuffer && streamFormat.mChannelsPerFrame != _recChannels) {
|
||||
RTC_LOG(LS_ERROR) << "Changing channels not supported (mChannelsPerFrame = "
|
||||
<< streamFormat.mChannelsPerFrame << ")";
|
||||
return -1;
|
||||
}
|
||||
|
||||
RTC_LOG(LS_VERBOSE) << "Stream format:";
|
||||
@ -2012,8 +2054,31 @@ int32_t AudioDeviceMac::HandleStreamFormatChange(
|
||||
return 0;
|
||||
}
|
||||
|
||||
// RingRTC changes (code removed) to avoid speaker panning
|
||||
int32_t AudioDeviceMac::HandleDataSourceChange(
|
||||
const AudioObjectID objectId,
|
||||
const AudioObjectPropertyAddress propertyAddress) {
|
||||
OSStatus err = noErr;
|
||||
|
||||
if (_macBookPro &&
|
||||
propertyAddress.mScope == kAudioDevicePropertyScopeOutput) {
|
||||
RTC_LOG(LS_VERBOSE) << "Data source changed";
|
||||
|
||||
_macBookProPanRight = false;
|
||||
UInt32 dataSource = 0;
|
||||
UInt32 size = sizeof(UInt32);
|
||||
WEBRTC_CA_RETURN_ON_ERR(AudioObjectGetPropertyData(
|
||||
objectId, &propertyAddress, 0, NULL, &size, &dataSource));
|
||||
if (dataSource == 'ispk') {
|
||||
_macBookProPanRight = true;
|
||||
RTC_LOG(LS_VERBOSE)
|
||||
<< "MacBook Pro using internal speakers; stereo panning right";
|
||||
} else {
|
||||
RTC_LOG(LS_VERBOSE) << "MacBook Pro not using internal speakers";
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
int32_t AudioDeviceMac::HandleProcessorOverload(
|
||||
const AudioObjectPropertyAddress propertyAddress) {
|
||||
// TODO(xians): we probably want to notify the user in some way of the
|
||||
@ -2331,7 +2396,24 @@ bool AudioDeviceMac::RenderWorkerThread() {
|
||||
uint32_t nOutSamples = nSamples * _outDesiredFormat.mChannelsPerFrame;
|
||||
|
||||
SInt16* pPlayBuffer = (SInt16*)&playBuffer;
|
||||
// RingRTC changes (code removed) to avoid speaker panning
|
||||
if (_macBookProPanRight && (_playChannels == 2)) {
|
||||
// Mix entirely into the right channel and zero the left channel.
|
||||
SInt32 sampleInt32 = 0;
|
||||
for (uint32_t sampleIdx = 0; sampleIdx < nOutSamples; sampleIdx += 2) {
|
||||
sampleInt32 = pPlayBuffer[sampleIdx];
|
||||
sampleInt32 += pPlayBuffer[sampleIdx + 1];
|
||||
sampleInt32 /= 2;
|
||||
|
||||
if (sampleInt32 > 32767) {
|
||||
sampleInt32 = 32767;
|
||||
} else if (sampleInt32 < -32768) {
|
||||
sampleInt32 = -32768;
|
||||
}
|
||||
|
||||
pPlayBuffer[sampleIdx] = 0;
|
||||
pPlayBuffer[sampleIdx + 1] = static_cast<SInt16>(sampleInt32);
|
||||
}
|
||||
}
|
||||
|
||||
PaUtil_WriteRingBuffer(_paRenderBuffer, pPlayBuffer, nOutSamples);
|
||||
|
||||
@ -2348,11 +2430,8 @@ bool AudioDeviceMac::CaptureWorkerThread() {
|
||||
AudioBufferList engineBuffer;
|
||||
engineBuffer.mNumberBuffers = 1; // Interleaved channels.
|
||||
engineBuffer.mBuffers->mNumberChannels = _inDesiredFormat.mChannelsPerFrame;
|
||||
// RingRTC change to ensure AudioConverterFillComplexBuffer doesn't write
|
||||
// past the end of recordBuffer.
|
||||
// (Upstream, both `noRecSamples` and `mBytesPerPacket` take
|
||||
// mChannelsPerFrame into account, so if that's 2, this size is too large.)
|
||||
engineBuffer.mBuffers->mDataByteSize = sizeof(SInt16) * noRecSamples;
|
||||
engineBuffer.mBuffers->mDataByteSize =
|
||||
_inDesiredFormat.mBytesPerPacket * noRecSamples;
|
||||
engineBuffer.mBuffers->mData = recordBuffer.data();
|
||||
|
||||
err = AudioConverterFillComplexBuffer(_captureConverter, inConverterProc,
|
||||
@ -2396,9 +2475,6 @@ bool AudioDeviceMac::CaptureWorkerThread() {
|
||||
// deliver recorded samples at specified sample rate, mic level etc.
|
||||
// to the observer using callback
|
||||
_ptrAudioBuffer->DeliverRecordedData();
|
||||
} else {
|
||||
// RingRTC change to log more information around audio capture
|
||||
RTC_LOG(LS_ERROR) << "Ignoring captured audio samples for invalid size of " << size;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@ -307,6 +307,8 @@ class AudioDeviceMac : public AudioDeviceGeneric {
|
||||
bool _twoDevices;
|
||||
bool _doStop; // For play if not shared device or play+rec if shared device
|
||||
bool _doStopRec; // For rec if not shared device
|
||||
bool _macBookPro;
|
||||
bool _macBookProPanRight;
|
||||
|
||||
AudioConverterRef _captureConverter;
|
||||
AudioConverterRef _renderConverter;
|
||||
|
||||
@ -539,8 +539,7 @@ int32_t AudioMixerManagerMac::StereoPlayoutIsAvailable(bool& available) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// RingRTC change to allow output to stereo if more than 2 channels
|
||||
available = (_noOutputChannels >= 2);
|
||||
available = (_noOutputChannels == 2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -529,8 +529,7 @@ AudioDeviceWindowsCore::~AudioDeviceWindowsCore() {
|
||||
<< "AudioDeviceWindowsCore::~AudioDeviceWindowsCore()"
|
||||
" failed to free the loaded Avrt DLL module correctly";
|
||||
} else {
|
||||
// RingRTC change to reduce log noise.
|
||||
RTC_LOG(LS_INFO) << "AudioDeviceWindowsCore::~AudioDeviceWindowsCore()"
|
||||
RTC_LOG(LS_WARNING) << "AudioDeviceWindowsCore::~AudioDeviceWindowsCore()"
|
||||
" the Avrt DLL module is now unloaded";
|
||||
}
|
||||
}
|
||||
|
||||
@ -389,27 +389,15 @@ bool CoreAudioBase::Init() {
|
||||
}
|
||||
}
|
||||
|
||||
// RingRTC change to get the mix_format keep it in scope for multi-channel.
|
||||
WAVEFORMATPCMEX mix_format;
|
||||
HRESULT res = core_audio_utility::GetSharedModeMixFormat(
|
||||
audio_client.Get(), &mix_format);
|
||||
if (FAILED(res)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RTC_LOG(LS_WARNING) << (IsInput() ? "input " : "output ")
|
||||
<< "mix_format: "
|
||||
<< core_audio_utility::WaveFormatToString(&mix_format);
|
||||
|
||||
// Retrieve preferred audio input or output parameters for the given client
|
||||
// and the specified client properties. Override the preferred rate if sample
|
||||
// rate has been defined by the user. Rate conversion will be performed by
|
||||
// the audio engine to match the client if needed.
|
||||
AudioParameters params;
|
||||
res = sample_rate_ ? core_audio_utility::GetPreferredAudioParameters(
|
||||
audio_client.Get(), ¶ms, &mix_format, *sample_rate_)
|
||||
: core_audio_utility::GetPreferredAudioParameters(
|
||||
audio_client.Get(), ¶ms, &mix_format);
|
||||
HRESULT res = sample_rate_ ? core_audio_utility::GetPreferredAudioParameters(
|
||||
audio_client.Get(), ¶ms, *sample_rate_)
|
||||
: core_audio_utility::GetPreferredAudioParameters(
|
||||
audio_client.Get(), ¶ms);
|
||||
if (FAILED(res)) {
|
||||
return false;
|
||||
}
|
||||
@ -427,7 +415,9 @@ bool CoreAudioBase::Init() {
|
||||
// TODO(henrika): ensure that this approach works on different multi-channel
|
||||
// devices. Verified on:
|
||||
// - Corsair VOID PRO Surround USB Adapter (supports 7.1)
|
||||
// Try the first multi-channel format clamped to 2 (stereo).
|
||||
RTC_LOG(LS_WARNING)
|
||||
<< "Using channel upmixing in WASAPI audio engine (2 => "
|
||||
<< params.channels() << ")";
|
||||
format->nChannels = 2;
|
||||
}
|
||||
format->nSamplesPerSec = params.sample_rate();
|
||||
@ -451,27 +441,7 @@ bool CoreAudioBase::Init() {
|
||||
if (!sample_rate_) {
|
||||
if (!core_audio_utility::IsFormatSupported(
|
||||
audio_client.Get(), AUDCLNT_SHAREMODE_SHARED, &format_)) {
|
||||
// RingRTC change to try again to match a format for multi-channel.
|
||||
if (params.channels() > 2) {
|
||||
format->nChannels = params.channels();
|
||||
format->nBlockAlign = (format->wBitsPerSample / 8) * format->nChannels;
|
||||
format->nAvgBytesPerSec = format->nSamplesPerSec * format->nBlockAlign;
|
||||
|
||||
// Maintain the channel mask for multi-channel from the mix_format.
|
||||
format_.dwChannelMask = mix_format.dwChannelMask;
|
||||
|
||||
RTC_LOG(LS_WARNING) << "Trying again with: "
|
||||
<< core_audio_utility::WaveFormatToString(&format_);
|
||||
|
||||
if (!core_audio_utility::IsFormatSupported(
|
||||
audio_client.Get(), AUDCLNT_SHAREMODE_SHARED, &format_)) {
|
||||
RTC_LOG(LS_ERROR) << "No multi-channel format matched";
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
RTC_LOG(LS_ERROR) << "No format matched";
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -791,8 +761,8 @@ AudioSessionState CoreAudioBase::GetAudioSessionState() const {
|
||||
RTC_DCHECK(audio_session_control_.Get());
|
||||
_com_error error = audio_session_control_->GetState(&state);
|
||||
if (FAILED(error.Error())) {
|
||||
RTC_LOG(LS_ERROR) << "IAudioSessionControl::GetState failed: "
|
||||
<< core_audio_utility::ErrorToString(error);
|
||||
RTC_DLOG(LS_ERROR) << "IAudioSessionControl::GetState failed: "
|
||||
<< core_audio_utility::ErrorToString(error);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
@ -121,10 +121,7 @@ int CoreAudioInput::InitRecording() {
|
||||
WAVEFORMATEX* format = &format_.Format;
|
||||
RTC_DCHECK_EQ(format->wFormatTag, WAVE_FORMAT_EXTENSIBLE);
|
||||
audio_device_buffer_->SetRecordingSampleRate(format->nSamplesPerSec);
|
||||
|
||||
// RingRTC change to ensure that the audio_device_buffer is
|
||||
// configured for a limit of either 1 or 2 channels.
|
||||
audio_device_buffer_->SetRecordingChannels(std::min((UINT16)2, format->nChannels));
|
||||
audio_device_buffer_->SetRecordingChannels(format->nChannels);
|
||||
|
||||
// Create a modified audio buffer class which allows us to supply any number
|
||||
// of samples (and not only multiple of 10ms) to match the optimal buffer
|
||||
@ -273,9 +270,7 @@ bool CoreAudioInput::OnDataCallback(uint64_t device_frequency) {
|
||||
// This is concurrent examination of state across multiple threads so will
|
||||
// be somewhat error prone, but we should still be defensive and not use
|
||||
// audio_capture_client_ if we know it's not there.
|
||||
// RingRTC change to support Windows ADM2.
|
||||
RTC_LOG(LS_WARNING) << "CoreAudioInput::OnDataCallback not yet ready";
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
if (num_data_callbacks_ == 0) {
|
||||
RTC_LOG(LS_INFO) << "--- Input audio stream is alive ---";
|
||||
@ -358,26 +353,11 @@ bool CoreAudioInput::OnDataCallback(uint64_t device_frequency) {
|
||||
audio_data, format_.Format.nBlockAlign * num_frames_to_read);
|
||||
RTC_DLOG(LS_WARNING) << "Captured audio is replaced by silence";
|
||||
} else {
|
||||
// RingRTC change to shift multiple channels to stereo channels.
|
||||
UINT16 nChannels = format_.Format.nChannels;
|
||||
|
||||
if (nChannels > 2) {
|
||||
// Copy the first two channels of sample data from each frame and
|
||||
// shift to the beginning of the audio data buffer.
|
||||
int16_t* audio_data_ptr = (int16_t*)audio_data;
|
||||
for (UINT32 i = 1; i < num_frames_to_read; ++i) {
|
||||
memcpy(&audio_data_ptr[i * 2], &audio_data_ptr[i * nChannels], 2 * sizeof(int16_t));
|
||||
}
|
||||
|
||||
// Reset nChannels to stereo now that the data is shifted.
|
||||
nChannels = 2;
|
||||
}
|
||||
|
||||
// Copy recorded audio in `audio_data` to the WebRTC sink using the
|
||||
// FineAudioBuffer object.
|
||||
fine_audio_buffer_->DeliverRecordedData(
|
||||
webrtc::MakeArrayView(reinterpret_cast<const int16_t*>(audio_data),
|
||||
nChannels * num_frames_to_read),
|
||||
format_.Format.nChannels * num_frames_to_read),
|
||||
|
||||
latency_ms_);
|
||||
}
|
||||
|
||||
@ -118,11 +118,7 @@ int CoreAudioOutput::InitPlayout() {
|
||||
WAVEFORMATEX* format = &format_.Format;
|
||||
RTC_DCHECK_EQ(format->wFormatTag, WAVE_FORMAT_EXTENSIBLE);
|
||||
audio_device_buffer_->SetPlayoutSampleRate(format->nSamplesPerSec);
|
||||
|
||||
// RingRTC change to ensure that the audio_device_buffer is configured
|
||||
// for a limit of either 1 or 2 channels.
|
||||
audio_device_buffer_->SetPlayoutChannels(
|
||||
std::min((UINT16)2, format->nChannels));
|
||||
audio_device_buffer_->SetPlayoutChannels(format->nChannels);
|
||||
|
||||
// Create a modified audio buffer class which allows us to ask for any number
|
||||
// of samples (and not only multiple of 10ms) to match the optimal
|
||||
@ -159,7 +155,7 @@ int CoreAudioOutput::StartPlayout() {
|
||||
RTC_DCHECK(fine_audio_buffer_);
|
||||
RTC_DCHECK(audio_device_buffer_);
|
||||
if (!initialized_) {
|
||||
RTC_LOG(LS_WARNING)
|
||||
RTC_DLOG(LS_WARNING)
|
||||
<< "Playout can not start since InitPlayout must succeed first";
|
||||
}
|
||||
|
||||
@ -192,7 +188,7 @@ int CoreAudioOutput::StopPlayout() {
|
||||
// Release resources allocated in InitPlayout() and then return if this
|
||||
// method is called without any active output audio.
|
||||
if (!Playing()) {
|
||||
RTC_LOG(LS_WARNING) << "No output stream is active";
|
||||
RTC_DLOG(LS_WARNING) << "No output stream is active";
|
||||
ReleaseCOMObjects();
|
||||
initialized_ = false;
|
||||
return 0;
|
||||
@ -341,29 +337,9 @@ bool CoreAudioOutput::OnDataCallback(uint64_t device_frequency) {
|
||||
// `audio_data`. The playout latency is not updated for each callback.
|
||||
fine_audio_buffer_->GetPlayoutData(
|
||||
webrtc::MakeArrayView(reinterpret_cast<int16_t*>(audio_data),
|
||||
num_requested_frames *
|
||||
// RingRTC change to ensure that only 1 or 2
|
||||
// channels are read from the buffer.
|
||||
std::min((UINT16)2, format_.Format.nChannels)),
|
||||
num_requested_frames * format_.Format.nChannels),
|
||||
latency_ms_);
|
||||
|
||||
// RingRTC change to expand 2 channels to multiple channels.
|
||||
if (format_.Format.nChannels > 2) {
|
||||
UINT32 bytes_per_frame = format_.Format.nChannels * sizeof(int16_t);
|
||||
UINT32 bytes_per_stereo_frame = 2 * sizeof(int16_t);
|
||||
|
||||
// Shift each stereo frame to start on the render frame's stride and
|
||||
// set the remaining channels to zero (silence).
|
||||
int16_t* audio_data_ptr = (int16_t*)audio_data;
|
||||
for (UINT32 i = num_requested_frames - 1; i > 0; --i) {
|
||||
memmove(&audio_data_ptr[i * format_.Format.nChannels],
|
||||
&audio_data_ptr[i * 2], bytes_per_stereo_frame);
|
||||
memset(&audio_data_ptr[i * format_.Format.nChannels + 2],
|
||||
0, bytes_per_frame - bytes_per_stereo_frame);
|
||||
}
|
||||
memset(&audio_data_ptr[2], 0, bytes_per_frame - bytes_per_stereo_frame);
|
||||
}
|
||||
|
||||
// Release the buffer space acquired in IAudioRenderClient::GetBuffer.
|
||||
error = audio_render_client_->ReleaseBuffer(num_requested_frames, 0);
|
||||
if (FAILED(error.Error())) {
|
||||
|
||||
@ -496,7 +496,7 @@ bool GetDeviceNamesInternal(EDataFlow data_flow,
|
||||
}
|
||||
|
||||
if (number_of_active_devices == 0) {
|
||||
RTC_LOG(LS_WARNING) << "Found no active devices";
|
||||
RTC_DLOG(LS_WARNING) << "Found no active devices";
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -596,19 +596,21 @@ bool GetDeviceNamesInternal(EDataFlow data_flow,
|
||||
return true;
|
||||
}
|
||||
|
||||
// RingRTC change to pass the mix_format for multi-channel.
|
||||
HRESULT GetPreferredAudioParametersInternal(IAudioClient* client,
|
||||
AudioParameters* params,
|
||||
const WAVEFORMATPCMEX* mix_format,
|
||||
int fixed_sample_rate) {
|
||||
REFERENCE_TIME default_period = 0;
|
||||
HRESULT hr = core_audio_utility::GetDevicePeriod(client,
|
||||
AUDCLNT_SHAREMODE_SHARED,
|
||||
&default_period);
|
||||
WAVEFORMATPCMEX mix_format;
|
||||
HRESULT hr = core_audio_utility::GetSharedModeMixFormat(client, &mix_format);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
int sample_rate = mix_format->Format.nSamplesPerSec;
|
||||
REFERENCE_TIME default_period = 0;
|
||||
hr = core_audio_utility::GetDevicePeriod(client, AUDCLNT_SHAREMODE_SHARED,
|
||||
&default_period);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
int sample_rate = mix_format.Format.nSamplesPerSec;
|
||||
// Override default sample rate if `fixed_sample_rate` is set and different
|
||||
// from the default rate.
|
||||
if (fixed_sample_rate > 0 && fixed_sample_rate != sample_rate) {
|
||||
@ -616,10 +618,10 @@ HRESULT GetPreferredAudioParametersInternal(IAudioClient* client,
|
||||
<< sample_rate << " is replaced by " << fixed_sample_rate;
|
||||
sample_rate = fixed_sample_rate;
|
||||
}
|
||||
// TODO(henrika): utilize full mix_format->Format.wBitsPerSample.
|
||||
// TODO(henrika): utilize full mix_format.Format.wBitsPerSample.
|
||||
// const size_t bits_per_sample = AudioParameters::kBitsPerSample;
|
||||
// TODO(henrika): improve channel layout support.
|
||||
const size_t channels = mix_format->Format.nChannels;
|
||||
const size_t channels = mix_format.Format.nChannels;
|
||||
|
||||
// Use the native device period to derive the smallest possible buffer size
|
||||
// in shared mode.
|
||||
@ -1010,8 +1012,7 @@ HRESULT GetSharedModeMixFormat(IAudioClient* client,
|
||||
// Verify that the reported format can be mixed by the audio engine in
|
||||
// shared mode.
|
||||
if (!wrapped_format.IsPcm() && !wrapped_format.IsFloat()) {
|
||||
// RingRTC change to pass the mix_format for multi-channel.
|
||||
RTC_LOG(LS_ERROR)
|
||||
RTC_DLOG(LS_ERROR)
|
||||
<< "Only pure PCM or float audio streams can be mixed in shared mode";
|
||||
return AUDCLNT_E_UNSUPPORTED_FORMAT;
|
||||
}
|
||||
@ -1019,8 +1020,7 @@ HRESULT GetSharedModeMixFormat(IAudioClient* client,
|
||||
// Log a warning for the rare case where `mix_format` only contains a
|
||||
// stand-alone WAVEFORMATEX structure but don't return.
|
||||
if (!wrapped_format.IsExtensible()) {
|
||||
// RingRTC change to pass the mix_format for multi-channel.
|
||||
RTC_LOG(LS_WARNING)
|
||||
RTC_DLOG(LS_WARNING)
|
||||
<< "The returned format contains no extended information. "
|
||||
"The size is "
|
||||
<< wrapped_format.size() << " bytes.";
|
||||
@ -1057,9 +1057,9 @@ bool IsFormatSupported(IAudioClient* client,
|
||||
} else if ((error.Error() == S_FALSE) && (closest_match != nullptr)) {
|
||||
// Call succeeded with a closest match to the specified format. This log can
|
||||
// only be triggered for shared mode.
|
||||
// RingRTC change to pass the mix_format for multi-channel.
|
||||
RTC_LOG(LS_WARNING) << "No exact match, closest: "
|
||||
<< WaveFormatToString(closest_match.Get());
|
||||
RTC_LOG(LS_WARNING)
|
||||
<< "Exact format is not supported, but a closest match exists";
|
||||
RTC_LOG(LS_INFO) << WaveFormatToString(closest_match.Get());
|
||||
} else if ((error.Error() == AUDCLNT_E_UNSUPPORTED_FORMAT) &&
|
||||
(closest_match == nullptr)) {
|
||||
// The audio engine does not support the caller-specified format or any
|
||||
@ -1143,23 +1143,19 @@ HRESULT GetSharedModeEnginePeriod(IAudioClient3* client3,
|
||||
return error.Error();
|
||||
}
|
||||
|
||||
// RingRTC change to pass the mix_format for multi-channel.
|
||||
HRESULT GetPreferredAudioParameters(IAudioClient* client,
|
||||
AudioParameters* params,
|
||||
const WAVEFORMATPCMEX* mix_format) {
|
||||
AudioParameters* params) {
|
||||
RTC_DLOG(LS_INFO) << "GetPreferredAudioParameters";
|
||||
RTC_DCHECK(client);
|
||||
return GetPreferredAudioParametersInternal(client, params, mix_format, -1);
|
||||
return GetPreferredAudioParametersInternal(client, params, -1);
|
||||
}
|
||||
|
||||
// RingRTC change to pass the mix_format for multi-channel.
|
||||
HRESULT GetPreferredAudioParameters(IAudioClient* client,
|
||||
webrtc::AudioParameters* params,
|
||||
const WAVEFORMATPCMEX* mix_format,
|
||||
uint32_t sample_rate) {
|
||||
RTC_DLOG(LS_INFO) << "GetPreferredAudioParameters: " << sample_rate;
|
||||
RTC_DCHECK(client);
|
||||
return GetPreferredAudioParametersInternal(client, params, mix_format, sample_rate);
|
||||
return GetPreferredAudioParametersInternal(client, params, sample_rate);
|
||||
}
|
||||
|
||||
HRESULT SharedModeInitialize(IAudioClient* client,
|
||||
|
||||
@ -452,17 +452,13 @@ HRESULT GetSharedModeEnginePeriod(IAudioClient3* client3,
|
||||
// shared-mode streams. The acquired values should only be utilized for shared
|
||||
// mode streamed since there are no preferred settings for an exclusive mode
|
||||
// stream.
|
||||
// RingRTC change to pass the mix_format for multi-channel.
|
||||
HRESULT GetPreferredAudioParameters(IAudioClient* client,
|
||||
webrtc::AudioParameters* params,
|
||||
const WAVEFORMATPCMEX* mix_format);
|
||||
webrtc::AudioParameters* params);
|
||||
// As above but override the preferred sample rate and use `sample_rate`
|
||||
// instead. Intended mainly for testing purposes and in combination with rate
|
||||
// conversion.
|
||||
// RingRTC change to pass the mix_format for multi-channel.
|
||||
HRESULT GetPreferredAudioParameters(IAudioClient* client,
|
||||
webrtc::AudioParameters* params,
|
||||
const WAVEFORMATPCMEX* mix_format,
|
||||
uint32_t sample_rate);
|
||||
|
||||
// After activating an IAudioClient interface on an audio endpoint device,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user