зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1315928 - Update cubeb from upstream to f8467510a8b. r=kinetik
MozReview-Commit-ID: 7M6LVOGxTVB
This commit is contained in:
Родитель
4095709c00
Коммит
eefc8725dd
|
@ -5,4 +5,4 @@ Makefile.in build files for the Mozilla build system.
|
|||
|
||||
The cubeb git repository is: git://github.com/kinetiknz/cubeb.git
|
||||
|
||||
The git commit ID used was 98b189d2aad06bef758a5ae76fb758fa4dfa9bba.
|
||||
The git commit ID used was f8467510a8b36793b1b8b7e85461e2e189eb7015.
|
||||
|
|
|
@ -169,6 +169,7 @@ struct cubeb_stream {
|
|||
cubeb_stream_params input_stream_params;
|
||||
cubeb_stream_params output_stream_params;
|
||||
cubeb_devid input_device;
|
||||
bool is_default_input;
|
||||
cubeb_devid output_device;
|
||||
/* User pointer of data_callback */
|
||||
void * user_ptr;
|
||||
|
@ -178,8 +179,12 @@ struct cubeb_stream {
|
|||
/* I/O AudioUnits */
|
||||
AudioUnit input_unit;
|
||||
AudioUnit output_unit;
|
||||
/* Sample rate of input device*/
|
||||
/* I/O device sample rate */
|
||||
Float64 input_hw_rate;
|
||||
Float64 output_hw_rate;
|
||||
/* Expected I/O thread interleave,
|
||||
* calculated from I/O hw rate. */
|
||||
int expected_output_callbacks_in_a_row;
|
||||
owned_critical_section mutex;
|
||||
/* Hold the input samples in every
|
||||
* input callback iteration */
|
||||
|
@ -193,7 +198,7 @@ struct cubeb_stream {
|
|||
std::atomic<bool> shutdown;
|
||||
std::atomic<bool> draining;
|
||||
/* Latency requested by the user. */
|
||||
uint64_t latency_frames;
|
||||
uint32_t latency_frames;
|
||||
std::atomic<uint64_t> current_latency_frames;
|
||||
uint64_t hw_latency_frames;
|
||||
std::atomic<float> panning;
|
||||
|
@ -258,6 +263,8 @@ audiotimestamp_to_latency(AudioTimeStamp const * tstamp, cubeb_stream * stream)
|
|||
static void
|
||||
audiounit_make_silent(AudioBuffer * ioData)
|
||||
{
|
||||
assert(ioData);
|
||||
assert(ioData->mData);
|
||||
memset(ioData->mData, 0, ioData->mDataByteSize);
|
||||
}
|
||||
|
||||
|
@ -286,7 +293,6 @@ audiounit_render_input(cubeb_stream * stm,
|
|||
|
||||
if (r != noErr) {
|
||||
PRINT_ERROR_CODE("AudioUnitRender", r);
|
||||
audiounit_make_silent(&input_buffer_list.mBuffers[0]);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -326,6 +332,16 @@ audiounit_input_callback(void * user_ptr,
|
|||
return noErr;
|
||||
}
|
||||
|
||||
// This happens when we're finally getting a new input callback after having
|
||||
// switched device, we can clear the input buffer now, only keeping the data
|
||||
// we just got.
|
||||
if (stm->output_callback_in_a_row > stm->expected_output_callbacks_in_a_row) {
|
||||
stm->input_linear_buffer->pop(
|
||||
nullptr,
|
||||
stm->input_linear_buffer->length() -
|
||||
input_frames * stm->input_stream_params.channels);
|
||||
}
|
||||
|
||||
OSStatus r = audiounit_render_input(stm, flags, tstamp, bus, input_frames);
|
||||
if (r != noErr) {
|
||||
return r;
|
||||
|
@ -333,18 +349,7 @@ audiounit_input_callback(void * user_ptr,
|
|||
|
||||
// Full Duplex. We'll call data_callback in the AudioUnit output callback.
|
||||
if (stm->output_unit != NULL) {
|
||||
// This happens when we're finally getting a new input callback after having
|
||||
// switched device, we can clear the input buffer now, only keeping the data
|
||||
// we just got.
|
||||
if (stm->output_callback_in_a_row > 2) {
|
||||
stm->input_linear_buffer->pop(
|
||||
nullptr,
|
||||
stm->input_linear_buffer->length() -
|
||||
input_frames * stm->input_stream_params.channels);
|
||||
}
|
||||
|
||||
stm->output_callback_in_a_row = 0;
|
||||
|
||||
return noErr;
|
||||
}
|
||||
|
||||
|
@ -368,6 +373,27 @@ audiounit_input_callback(void * user_ptr,
|
|||
return noErr;
|
||||
}
|
||||
|
||||
static bool
|
||||
is_extra_input_needed(cubeb_stream * stm)
|
||||
{
|
||||
/* If the output callback came first and this is a duplex stream, we need to
|
||||
* fill in some additional silence in the resampler.
|
||||
* Otherwise, if we had more than expected callbacks in a row, or we're currently
|
||||
* switching, we add some silence as well to compensate for the fact that
|
||||
* we're lacking some input data. */
|
||||
|
||||
/* If resampling is taking place after every output callback
|
||||
* the input buffer expected to be empty. Any frame left over
|
||||
* from resampling is stored inside the resampler available to
|
||||
* be used in next iteration as needed.
|
||||
* BUT when noop_resampler is operating we have left over
|
||||
* frames since it does not store anything internally. */
|
||||
return stm->frames_read == 0 ||
|
||||
(stm->input_linear_buffer->length() == 0 &&
|
||||
(stm->output_callback_in_a_row > stm->expected_output_callbacks_in_a_row ||
|
||||
stm->switching_device));
|
||||
}
|
||||
|
||||
static OSStatus
|
||||
audiounit_output_callback(void * user_ptr,
|
||||
AudioUnitRenderActionFlags * /* flags */,
|
||||
|
@ -413,17 +439,12 @@ audiounit_output_callback(void * user_ptr,
|
|||
output_buffer = outBufferList->mBuffers[0].mData;
|
||||
/* If Full duplex get also input buffer */
|
||||
if (stm->input_unit != NULL) {
|
||||
/* If the output callback came first and this is a duplex stream, we need to
|
||||
* fill in some additional silence in the resampler.
|
||||
* Otherwise, if we had more than two callback in a row, or we're currently
|
||||
* switching, we add some silence as well to compensate for the fact that
|
||||
* we're lacking some input data. */
|
||||
if (stm->frames_read == 0 ||
|
||||
(stm->input_linear_buffer->length() == 0 &&
|
||||
(stm->output_callback_in_a_row > 2 || stm->switching_device))) {
|
||||
LOG("(%p) Output callback came first send silent.", stm);
|
||||
stm->input_linear_buffer->push_silence(stm->input_buffer_frames *
|
||||
stm->input_desc.mChannelsPerFrame);
|
||||
if (is_extra_input_needed(stm)) {
|
||||
uint32_t min_input_frames_required = ceilf(stm->input_hw_rate / stm->output_hw_rate *
|
||||
stm->input_buffer_frames);
|
||||
stm->input_linear_buffer->push_silence(min_input_frames_required * stm->input_desc.mChannelsPerFrame);
|
||||
LOG("(%p) %s pushed %u frames of input silence.", stm, stm->frames_read == 0 ? "Input hasn't started," :
|
||||
stm->switching_device ? "Device switching," : "Drop out,", min_input_frames_required);
|
||||
}
|
||||
// The input buffer
|
||||
input_buffer = stm->input_linear_buffer->data();
|
||||
|
@ -575,19 +596,35 @@ audiounit_property_listener_callback(AudioObjectID /* id */, UInt32 address_coun
|
|||
was_running = !stm->shutdown;
|
||||
|
||||
LOG("(%p) Audio device changed, %d events.", stm, address_count);
|
||||
if (g_log_level) {
|
||||
for (UInt32 i = 0; i < address_count; i++) {
|
||||
switch(addresses[i].mSelector) {
|
||||
case kAudioHardwarePropertyDefaultOutputDevice:
|
||||
LOG("(%p) %d mSelector == kAudioHardwarePropertyDefaultOutputDevice", stm, i);
|
||||
break;
|
||||
case kAudioHardwarePropertyDefaultInputDevice:
|
||||
LOG("(%p) %d mSelector == kAudioHardwarePropertyDefaultInputDevice", stm, i);
|
||||
break;
|
||||
case kAudioDevicePropertyDataSource:
|
||||
LOG("(%p) %d mSelector == kAudioHardwarePropertyDataSource", stm, i);
|
||||
break;
|
||||
}
|
||||
for (UInt32 i = 0; i < address_count; i++) {
|
||||
switch(addresses[i].mSelector) {
|
||||
case kAudioHardwarePropertyDefaultOutputDevice: {
|
||||
LOG("Event[%d] - mSelector == kAudioHardwarePropertyDefaultOutputDevice", i);
|
||||
// Allow restart to choose the new default
|
||||
stm->output_device = nullptr;
|
||||
}
|
||||
break;
|
||||
case kAudioHardwarePropertyDefaultInputDevice: {
|
||||
LOG("Event[%d] - mSelector == kAudioHardwarePropertyDefaultInputDevice", i);
|
||||
// Allow restart to choose the new default
|
||||
stm->input_device = nullptr;
|
||||
}
|
||||
break;
|
||||
case kAudioDevicePropertyDeviceIsAlive: {
|
||||
LOG("Event[%d] - mSelector == kAudioDevicePropertyDeviceIsAlive", i);
|
||||
// If this is the default input device ignore the event,
|
||||
// kAudioHardwarePropertyDefaultInputDevice will take care of the switch
|
||||
if (stm->is_default_input) {
|
||||
LOG("It's the default input device, ignore the event");
|
||||
return noErr;
|
||||
}
|
||||
// Allow restart to choose the new default. Event register only for input.
|
||||
stm->input_device = nullptr;
|
||||
}
|
||||
break;
|
||||
case kAudioDevicePropertyDataSource:
|
||||
LOG("Event[%d] - mSelector == kAudioHardwarePropertyDataSource", i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -595,6 +632,7 @@ audiounit_property_listener_callback(AudioObjectID /* id */, UInt32 address_coun
|
|||
switch(addresses[i].mSelector) {
|
||||
case kAudioHardwarePropertyDefaultOutputDevice:
|
||||
case kAudioHardwarePropertyDefaultInputDevice:
|
||||
case kAudioDevicePropertyDeviceIsAlive:
|
||||
/* fall through */
|
||||
case kAudioDevicePropertyDataSource: {
|
||||
auto_lock lock(stm->mutex);
|
||||
|
@ -660,6 +698,8 @@ audiounit_remove_listener(cubeb_stream * stm, AudioDeviceID id,
|
|||
return AudioObjectRemovePropertyListener(id, &address, listener, stm);
|
||||
}
|
||||
|
||||
static AudioObjectID audiounit_get_default_device_id(cubeb_device_type type);
|
||||
|
||||
static int
|
||||
audiounit_install_device_changed_callback(cubeb_stream * stm)
|
||||
{
|
||||
|
@ -678,6 +718,7 @@ audiounit_install_device_changed_callback(cubeb_stream * stm)
|
|||
r = audiounit_add_listener(stm, output_dev_id, kAudioDevicePropertyDataSource,
|
||||
kAudioDevicePropertyScopeOutput, &audiounit_property_listener_callback);
|
||||
if (r != noErr) {
|
||||
PRINT_ERROR_CODE("AudioObjectAddPropertyListener/output/kAudioDevicePropertyDataSource", r);
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
|
@ -688,6 +729,7 @@ audiounit_install_device_changed_callback(cubeb_stream * stm)
|
|||
r = audiounit_add_listener(stm, kAudioObjectSystemObject, kAudioHardwarePropertyDefaultOutputDevice,
|
||||
kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback);
|
||||
if (r != noErr) {
|
||||
PRINT_ERROR_CODE("AudioObjectAddPropertyListener/output/kAudioHardwarePropertyDefaultOutputDevice", r);
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
}
|
||||
|
@ -703,6 +745,7 @@ audiounit_install_device_changed_callback(cubeb_stream * stm)
|
|||
r = audiounit_add_listener(stm, input_dev_id, kAudioDevicePropertyDataSource,
|
||||
kAudioDevicePropertyScopeInput, &audiounit_property_listener_callback);
|
||||
if (r != noErr) {
|
||||
PRINT_ERROR_CODE("AudioObjectAddPropertyListener/input/kAudioDevicePropertyDataSource", r);
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
|
@ -710,6 +753,17 @@ audiounit_install_device_changed_callback(cubeb_stream * stm)
|
|||
r = audiounit_add_listener(stm, kAudioObjectSystemObject, kAudioHardwarePropertyDefaultInputDevice,
|
||||
kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback);
|
||||
if (r != noErr) {
|
||||
PRINT_ERROR_CODE("AudioObjectAddPropertyListener/input/kAudioHardwarePropertyDefaultInputDevice", r);
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
/* Event to notify when the input is going away. */
|
||||
AudioDeviceID dev = stm->input_device ? reinterpret_cast<intptr_t>(stm->input_device) :
|
||||
audiounit_get_default_device_id(CUBEB_DEVICE_TYPE_INPUT);
|
||||
r = audiounit_add_listener(stm, dev, kAudioDevicePropertyDeviceIsAlive,
|
||||
kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback);
|
||||
if (r != noErr) {
|
||||
PRINT_ERROR_CODE("AudioObjectAddPropertyListener/input/kAudioDevicePropertyDeviceIsAlive", r);
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
}
|
||||
|
@ -1053,11 +1107,11 @@ audiounit_create_unit(AudioUnit * unit,
|
|||
} else {
|
||||
devid = reinterpret_cast<intptr_t>(device);
|
||||
}
|
||||
int err = AudioUnitSetProperty(*unit, kAudioOutputUnitProperty_CurrentDevice,
|
||||
kAudioUnitScope_Global,
|
||||
is_input ? AU_IN_BUS : AU_OUT_BUS,
|
||||
&devid, sizeof(AudioDeviceID));
|
||||
if (err != noErr) {
|
||||
rv = AudioUnitSetProperty(*unit, kAudioOutputUnitProperty_CurrentDevice,
|
||||
kAudioUnitScope_Global,
|
||||
is_input ? AU_IN_BUS : AU_OUT_BUS,
|
||||
&devid, sizeof(AudioDeviceID));
|
||||
if (rv != noErr) {
|
||||
PRINT_ERROR_CODE("AudioUnitSetProperty/kAudioOutputUnitProperty_CurrentDevice", rv);
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
@ -1181,7 +1235,6 @@ setup_audiounit_stream(cubeb_stream * stm)
|
|||
UInt32 size;
|
||||
|
||||
if (has_input(stm)) {
|
||||
LOG("(%p) Opening input side, rate: %u", stm, stm->input_stream_params.rate);
|
||||
r = audiounit_create_unit(&stm->input_unit, true,
|
||||
&stm->input_stream_params,
|
||||
stm->input_device);
|
||||
|
@ -1192,7 +1245,6 @@ setup_audiounit_stream(cubeb_stream * stm)
|
|||
}
|
||||
|
||||
if (has_output(stm)) {
|
||||
LOG("(%p) Opening output side, rate: %u", stm, stm->input_stream_params.rate);
|
||||
r = audiounit_create_unit(&stm->output_unit, false,
|
||||
&stm->output_stream_params,
|
||||
stm->output_device);
|
||||
|
@ -1204,6 +1256,9 @@ setup_audiounit_stream(cubeb_stream * stm)
|
|||
|
||||
/* Setup Input Stream! */
|
||||
if (has_input(stm)) {
|
||||
LOG("(%p) Opening input side: rate %u, channels %u, format %d, latency in frames %u.",
|
||||
stm, stm->input_stream_params.rate, stm->input_stream_params.channels,
|
||||
stm->input_stream_params.format, stm->latency_frames);
|
||||
/* Get input device sample rate. */
|
||||
AudioStreamBasicDescription input_hw_desc;
|
||||
size = sizeof(AudioStreamBasicDescription);
|
||||
|
@ -1218,6 +1273,7 @@ setup_audiounit_stream(cubeb_stream * stm)
|
|||
return CUBEB_ERROR;
|
||||
}
|
||||
stm->input_hw_rate = input_hw_desc.mSampleRate;
|
||||
LOG("(%p) Input device sampling rate: %.2f", stm, stm->input_hw_rate);
|
||||
|
||||
/* Set format description according to the input params. */
|
||||
r = audio_stream_desc_init(&stm->input_desc, &stm->input_stream_params);
|
||||
|
@ -1297,6 +1353,9 @@ setup_audiounit_stream(cubeb_stream * stm)
|
|||
|
||||
/* Setup Output Stream! */
|
||||
if (has_output(stm)) {
|
||||
LOG("(%p) Opening output side: rate %u, channels %u, format %d, latency in frames %u.",
|
||||
stm, stm->output_stream_params.rate, stm->output_stream_params.channels,
|
||||
stm->output_stream_params.format, stm->latency_frames);
|
||||
r = audio_stream_desc_init(&stm->output_desc, &stm->output_stream_params);
|
||||
if (r != CUBEB_OK) {
|
||||
LOG("(%p) Could not initialize the audio stream description.", stm);
|
||||
|
@ -1317,6 +1376,8 @@ setup_audiounit_stream(cubeb_stream * stm)
|
|||
PRINT_ERROR_CODE("AudioUnitGetProperty/output/tkAudioUnitProperty_StreamFormat", r);
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
stm->output_hw_rate = output_hw_desc.mSampleRate;
|
||||
LOG("(%p) Output device sampling rate: %.2f", stm, output_hw_desc.mSampleRate);
|
||||
|
||||
r = AudioUnitSetProperty(stm->output_unit,
|
||||
kAudioUnitProperty_StreamFormat,
|
||||
|
@ -1449,6 +1510,14 @@ setup_audiounit_stream(cubeb_stream * stm)
|
|||
return CUBEB_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (stm->input_unit && stm->output_unit) {
|
||||
// According to the I/O hardware rate it is expected a specific pattern of callbacks
|
||||
// for example is input is 44100 and output is 48000 we expected no more than 2
|
||||
// out callback in a row.
|
||||
stm->expected_output_callbacks_in_a_row = ceilf(stm->output_hw_rate / stm->input_hw_rate);
|
||||
}
|
||||
|
||||
return CUBEB_OK;
|
||||
}
|
||||
|
||||
|
@ -1492,6 +1561,9 @@ audiounit_stream_init(cubeb * context,
|
|||
if (input_stream_params) {
|
||||
stm->input_stream_params = *input_stream_params;
|
||||
stm->input_device = input_device;
|
||||
stm->is_default_input = input_device == nullptr ||
|
||||
(audiounit_get_default_device_id(CUBEB_DEVICE_TYPE_INPUT) ==
|
||||
reinterpret_cast<intptr_t>(input_device));
|
||||
}
|
||||
if (output_stream_params) {
|
||||
stm->output_stream_params = *output_stream_params;
|
||||
|
|
Загрузка…
Ссылка в новой задаче