Bug 1315928 - Update cubeb from upstream to f8467510a8b. r=kinetik

MozReview-Commit-ID: 7M6LVOGxTVB
This commit is contained in:
Alex Chronopoulos 2016-11-08 14:02:49 +02:00
Родитель 4095709c00
Коммит eefc8725dd
2 изменённых файлов: 118 добавлений и 46 удалений

Просмотреть файл

@ -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;