Bug 1342363 - Update cubeb from upstream to 25b593f. r=padenot

MozReview-Commit-ID: BAwQSDLJoMx

--HG--
extra : rebase_source : 01c1c72c3b287f6e6608b84fc00cd80177ae65cc
This commit is contained in:
Alex Chronopoulos 2017-02-24 13:24:32 +02:00
Родитель e7546e008c
Коммит 6b65c12c74
4 изменённых файлов: 254 добавлений и 206 удалений

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

@ -13,3 +13,4 @@ Landry Breuil <landry@openbsd.org>
Jacek Caban <jacek@codeweavers.com>
Paul Hancock <Paul.Hancock.17041993@live.com>
Ted Mielczarek <ted@mielczarek.org>
Chun-Min Chang <chun.m.chang@gmail.com>

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

@ -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 8977c13bf0dab9a7716501ae92ca5945fe4e1dae.
The git commit ID used was 25b593fa59d0c284ff2de54b10db927d48579f5e.

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

@ -35,18 +35,12 @@
#include <vector>
#if MAC_OS_X_VERSION_MIN_REQUIRED < 101000
typedef UInt32 AudioFormatFlags;
typedef UInt32 AudioFormatFlags;
#endif
#define AU_OUT_BUS 0
#define AU_IN_BUS 1
#define fieldOffset(type, field) ((size_t) &((type *) 0)->field)
#define PRINT_ERROR_CODE(str, r) do { \
LOG("System call failed: %s (rv: %d)", str, (int) r); \
} while(0)
const char * DISPATCH_QUEUE_LABEL = "org.mozilla.cubeb";
#ifdef ALOGV
@ -72,7 +66,6 @@ static int audiounit_setup_stream(cubeb_stream *stm);
static int audiounit_create_unit(AudioUnit * unit, bool is_input,
const cubeb_stream_params * /* stream_params */,
AudioDeviceID device);
static cubeb_channel_layout audiounit_get_channel_layout(bool preferred);
extern cubeb_ops const audiounit_ops;
@ -88,6 +81,8 @@ struct cubeb {
std::vector<AudioObjectID> devtype_device_array;
// The queue is asynchronously deallocated once all references to it are released
dispatch_queue_t serial_queue = dispatch_queue_create(DISPATCH_QUEUE_LABEL, DISPATCH_QUEUE_SERIAL);
// Current used channel layout
cubeb_channel_layout layout;
};
struct auto_array_wrapper {
@ -100,6 +95,53 @@ struct auto_array_wrapper {
virtual ~auto_array_wrapper() {}
};
template <typename T>
struct auto_array_wrapper_impl : public auto_array_wrapper {
explicit auto_array_wrapper_impl(uint32_t size)
: ar(size)
{}
void push(void * elements, size_t length) override {
auto_lock l(lock);
ar.push(static_cast<T *>(elements), length);
}
size_t length() override {
auto_lock l(lock);
return ar.length();
}
void push_silence(size_t length) override {
auto_lock l(lock);
ar.push_silence(length);
}
bool pop(size_t length) override {
auto_lock l(lock);
return ar.pop(nullptr, length);
}
// XXX: Taking the lock here is pointless.
void * data() override {
auto_lock l(lock);
return ar.data();
}
void clear() override {
auto_lock l(lock);
ar.clear();
}
~auto_array_wrapper_impl() {
auto_lock l(lock);
ar.clear();
}
private:
owned_critical_section lock;
auto_array<T> ar;
};
class auto_channel_layout
{
public:
@ -148,58 +190,22 @@ private:
AudioChannelLayout * layout;
};
template <typename T>
struct auto_array_wrapper_impl : public auto_array_wrapper {
explicit auto_array_wrapper_impl(uint32_t size)
: ar(size)
{}
void push(void * elements, size_t length) override {
auto_lock l(lock);
ar.push(static_cast<T *>(elements), length);
}
size_t length() override {
auto_lock l(lock);
return ar.length();
}
void push_silence(size_t length) override {
auto_lock l(lock);
ar.push_silence(length);
}
bool pop(size_t length) override {
auto_lock l(lock);
return ar.pop(nullptr, length);
}
// XXX: Taking the lock here is pointless.
void * data() override {
auto_lock l(lock);
return ar.data();
}
void clear() override {
auto_lock l(lock);
ar.clear();
}
~auto_array_wrapper_impl() {
auto_lock l(lock);
ar.clear();
}
private:
owned_critical_section lock;
auto_array<T> ar;
};
enum io_side {
INPUT,
OUTPUT,
};
static char const *
to_string(io_side side)
{
switch (side) {
case INPUT:
return "input";
case OUTPUT:
return "output";
}
}
struct cubeb_stream {
explicit cubeb_stream(cubeb * context);
@ -378,7 +384,7 @@ audiounit_render_input(cubeb_stream * stm,
&input_buffer_list);
if (r != noErr) {
PRINT_ERROR_CODE("AudioUnitRender", r);
LOG("AudioUnitRender rv=%d", r);
return r;
}
@ -616,7 +622,7 @@ audiounit_get_output_device_id(AudioDeviceID * device_id)
&size,
device_id);
if (r != noErr) {
PRINT_ERROR_CODE("output_device_id", r);
LOG("output_device_id rv=%d", r);
return CUBEB_ERROR;
}
@ -801,7 +807,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);
LOG("AudioObjectAddPropertyListener/output/kAudioDevicePropertyDataSource rv=%d", r);
return CUBEB_ERROR;
}
@ -812,7 +818,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);
LOG("AudioObjectAddPropertyListener/output/kAudioHardwarePropertyDefaultOutputDevice rv=%d", r);
return CUBEB_ERROR;
}
}
@ -828,7 +834,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);
LOG("AudioObjectAddPropertyListener/input/kAudioDevicePropertyDataSource rv=%d", r);
return CUBEB_ERROR;
}
@ -836,7 +842,7 @@ 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);
LOG("AudioObjectAddPropertyListener/input/kAudioHardwarePropertyDefaultInputDevice rv=%d", r);
return CUBEB_ERROR;
}
@ -846,7 +852,7 @@ audiounit_install_device_changed_callback(cubeb_stream * stm)
r = audiounit_add_listener(stm, dev, kAudioDevicePropertyDeviceIsAlive,
kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback);
if (r != noErr) {
PRINT_ERROR_CODE("AudioObjectAddPropertyListener/input/kAudioDevicePropertyDeviceIsAlive", r);
LOG("AudioObjectAddPropertyListener/input/kAudioDevicePropertyDeviceIsAlive rv=%d", r);
return CUBEB_ERROR;
}
}
@ -904,7 +910,7 @@ audiounit_uninstall_device_changed_callback(cubeb_stream * stm)
r = audiounit_remove_listener(stm, dev, kAudioDevicePropertyDeviceIsAlive,
kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback);
if (r != noErr) {
PRINT_ERROR_CODE("AudioObjectRemovePropertyListener/input/kAudioDevicePropertyDeviceIsAlive", r);
LOG("AudioObjectRemovePropertyListener/input/kAudioDevicePropertyDeviceIsAlive rv=%d", r);
return CUBEB_ERROR;
}
}
@ -939,7 +945,7 @@ audiounit_get_acceptable_latency_range(AudioValueRange * latency_range)
&size,
latency_range);
if (r != noErr) {
PRINT_ERROR_CODE("AudioObjectGetPropertyData/buffer size range", r);
LOG("AudioObjectGetPropertyData/buffer size range rv=%d", r);
return CUBEB_ERROR;
}
@ -1002,7 +1008,7 @@ audiounit_get_max_channel_count(cubeb * ctx, uint32_t * max_channels)
&size,
&stream_format);
if (r != noErr) {
PRINT_ERROR_CODE("AudioObjectPropertyAddress/StreamFormat", r);
LOG("AudioObjectPropertyAddress/StreamFormat rv=%d", r);
return CUBEB_ERROR;
}
@ -1071,17 +1077,111 @@ audiounit_get_preferred_sample_rate(cubeb * /* ctx */, uint32_t * rate)
return CUBEB_OK;
}
static cubeb_channel_layout
audiounit_convert_channel_layout(AudioChannelLayout * layout)
{
if (layout->mChannelLayoutTag != kAudioChannelLayoutTag_UseChannelDescriptions) {
// kAudioChannelLayoutTag_UseChannelBitmap
// kAudioChannelLayoutTag_Mono
// kAudioChannelLayoutTag_Stereo
// ....
LOG("Only handle UseChannelDescriptions for now.\n");
return CUBEB_LAYOUT_UNDEFINED;
}
cubeb_channel_map cm;
cm.channels = layout->mNumberChannelDescriptions;
for (UInt32 i = 0; i < layout->mNumberChannelDescriptions; ++i) {
cm.map[i] = channel_label_to_cubeb_channel(layout->mChannelDescriptions[i].mChannelLabel);
}
return cubeb_channel_map_to_layout(&cm);
}
static cubeb_channel_layout
audiounit_get_current_channel_layout(AudioUnit output_unit)
{
OSStatus rv = noErr;
UInt32 size = 0;
rv = AudioUnitGetPropertyInfo(output_unit,
kAudioUnitProperty_AudioChannelLayout,
kAudioUnitScope_Output,
AU_OUT_BUS,
&size,
nullptr);
if (rv != noErr) {
LOG("AudioUnitGetPropertyInfo/kAudioUnitProperty_AudioChannelLayout rv=%d", rv);
return CUBEB_LAYOUT_UNDEFINED;
}
assert(size > 0);
auto_channel_layout layout(size);
rv = AudioUnitGetProperty(output_unit,
kAudioUnitProperty_AudioChannelLayout,
kAudioUnitScope_Output,
AU_OUT_BUS,
layout.get(),
&size);
if (rv != noErr) {
LOG("AudioUnitGetProperty/kAudioUnitProperty_AudioChannelLayout rv=%d", rv);
return CUBEB_LAYOUT_UNDEFINED;
}
return audiounit_convert_channel_layout(layout.get());
}
static cubeb_channel_layout
audiounit_get_preferred_channel_layout()
{
OSStatus rv = noErr;
UInt32 size = 0;
AudioDeviceID id;
if (audiounit_get_output_device_id(&id) != CUBEB_OK) {
return CUBEB_LAYOUT_UNDEFINED;
}
AudioObjectPropertyAddress adr = { kAudioDevicePropertyPreferredChannelLayout,
kAudioDevicePropertyScopeOutput,
kAudioObjectPropertyElementMaster };
rv = AudioObjectGetPropertyDataSize(id, &adr, 0, NULL, &size);
if (rv != noErr) {
return CUBEB_LAYOUT_UNDEFINED;
}
assert(size > 0);
auto_channel_layout layout(size);
rv = AudioObjectGetPropertyData(id, &adr, 0, NULL, &size, layout.get());
if (rv != noErr) {
return CUBEB_LAYOUT_UNDEFINED;
}
return audiounit_convert_channel_layout(layout.get());
}
static int
audiounit_get_preferred_channel_layout(cubeb * /* ctx */, cubeb_channel_layout * layout)
audiounit_get_preferred_channel_layout(cubeb * ctx, cubeb_channel_layout * layout)
{
// The preferred layout is only returned when the connected sound device
// (e.g. ASUS Xonar U7), has preferred layout setting.
// For default output on Mac, there is no preferred channel layout,
// so it might return UNDEFINED.
// In that case, we should get the channel configuration directly.
*layout = audiounit_get_channel_layout(true);
*layout = audiounit_get_preferred_channel_layout();
// If the preferred channel layout is UNDEFINED, then we try to access the
// current applied channel layout.
if (*layout == CUBEB_LAYOUT_UNDEFINED) {
*layout = audiounit_get_channel_layout(false);
// If we already have at least one cubeb stream, then the current channel
// layout must be updated. We can return it directly.
if (ctx->active_streams) {
return ctx->layout;
}
// If there is no existed stream, then we create a default ouput unit and
// use it to get the current used channel layout.
AudioUnit output_unit;
audiounit_create_unit(&output_unit, false, nullptr, 0);
*layout = audiounit_get_current_channel_layout(output_unit);
}
if (*layout == CUBEB_LAYOUT_UNDEFINED) {
@ -1155,10 +1255,14 @@ audio_stream_desc_init(AudioStreamBasicDescription * ss,
}
static int
audiounit_layout_init(AudioUnit * unit,
io_side side,
const cubeb_stream_params * stream_params)
audiounit_set_channel_layout(AudioUnit unit,
io_side side,
const cubeb_stream_params * stream_params)
{
if (side != OUTPUT) {
return CUBEB_ERROR;
}
assert(stream_params->layout != CUBEB_LAYOUT_UNDEFINED);
assert(stream_params->channels == CUBEB_CHANNEL_LAYOUT_MAPS[stream_params->layout].channels);
@ -1199,7 +1303,7 @@ audiounit_layout_init(AudioUnit * unit,
// For those layouts that can't be matched to coreaudio's predefined layout,
// we use customized layout.
if (layout.get()->mChannelLayoutTag == kAudioChannelLayoutTag_Unknown) {
size_t size = fieldOffset(AudioChannelLayout, mChannelDescriptions[stream_params->channels]);
size_t size = offsetof(AudioChannelLayout, mChannelDescriptions[stream_params->channels]);
layout.reset(size);
layout.get()->mChannelLayoutTag = kAudioChannelLayoutTag_UseChannelDescriptions;
layout.get()->mNumberChannelDescriptions = stream_params->channels;
@ -1210,24 +1314,38 @@ audiounit_layout_init(AudioUnit * unit,
}
}
r = AudioUnitSetProperty(*unit,
r = AudioUnitSetProperty(unit,
kAudioUnitProperty_AudioChannelLayout,
side == INPUT ? kAudioUnitScope_Output : kAudioUnitScope_Input,
side == INPUT ? AU_IN_BUS : AU_OUT_BUS,
kAudioUnitScope_Input,
AU_OUT_BUS,
layout.get(),
layout.size());
if (r != noErr) {
if (side == INPUT) {
PRINT_ERROR_CODE("AudioUnitSetProperty/input/kAudioUnitProperty_AudioChannelLayout", r);
} else {
PRINT_ERROR_CODE("AudioUnitSetProperty/output/kAudioUnitProperty_AudioChannelLayout", r);
}
LOG("AudioUnitSetProperty/%s/kAudioUnitProperty_AudioChannelLayout rv=%d", to_string(side), r);
return CUBEB_ERROR;
}
return CUBEB_OK;
}
void
audiounit_layout_init(cubeb_stream * stm, io_side side)
{
// We currently don't support the input layout setting.
if (side == INPUT) {
return;
}
audiounit_set_channel_layout(stm->output_unit, OUTPUT, &stm->output_stream_params);
// Update the current used channel layout for the cubeb context.
// Notice that this channel layout may be different from the layout we set above,
// because OSX doesn't return error when the output device can NOT provide
// our desired layout. Thus, we update the layout evertime when the cubeb_stream
// is created and use it when we need to mix audio data.
stm->context->layout = audiounit_get_current_channel_layout(stm->output_unit);
}
static int
audiounit_create_unit(AudioUnit * unit,
bool is_input,
@ -1267,7 +1385,7 @@ audiounit_create_unit(AudioUnit * unit,
rv = AudioComponentInstanceNew(comp, unit);
if (rv != noErr) {
PRINT_ERROR_CODE("AudioComponentInstanceNew", rv);
LOG("AudioComponentInstanceNew rv=%d", rv);
return CUBEB_ERROR;
}
@ -1277,7 +1395,7 @@ audiounit_create_unit(AudioUnit * unit,
is_input ? kAudioUnitScope_Input : kAudioUnitScope_Output,
is_input ? AU_IN_BUS : AU_OUT_BUS, &enable, sizeof(UInt32));
if (rv != noErr) {
PRINT_ERROR_CODE("AudioUnitSetProperty/kAudioOutputUnitProperty_EnableIO", rv);
LOG("AudioUnitSetProperty/kAudioOutputUnitProperty_EnableIO rv=%d", rv);
return CUBEB_ERROR;
}
@ -1286,7 +1404,7 @@ audiounit_create_unit(AudioUnit * unit,
is_input ? kAudioUnitScope_Output : kAudioUnitScope_Input,
is_input ? AU_OUT_BUS : AU_IN_BUS, &enable, sizeof(UInt32));
if (rv != noErr) {
PRINT_ERROR_CODE("AudioUnitSetProperty/kAudioOutputUnitProperty_EnableIO", rv);
LOG("AudioUnitSetProperty/kAudioOutputUnitProperty_EnableIO rv=%d", rv);
return CUBEB_ERROR;
}
@ -1301,7 +1419,7 @@ audiounit_create_unit(AudioUnit * unit,
is_input ? AU_IN_BUS : AU_OUT_BUS,
&devid, sizeof(AudioDeviceID));
if (rv != noErr) {
PRINT_ERROR_CODE("AudioUnitSetProperty/kAudioOutputUnitProperty_CurrentDevice", rv);
LOG("AudioUnitSetProperty/kAudioOutputUnitProperty_CurrentDevice rv=%d", rv);
return CUBEB_ERROR;
}
}
@ -1346,7 +1464,7 @@ audiounit_clamp_latency(cubeb_stream * stm, uint32_t latency_frames)
&output_buffer_size,
&size);
if (r != noErr) {
PRINT_ERROR_CODE("AudioUnitGetProperty/output/kAudioDevicePropertyBufferFrameSize", r);
LOG("AudioUnitGetProperty/output/kAudioDevicePropertyBufferFrameSize rv=%d", r);
return 0;
}
@ -1363,7 +1481,7 @@ audiounit_clamp_latency(cubeb_stream * stm, uint32_t latency_frames)
&input_buffer_size,
&size);
if (r != noErr) {
PRINT_ERROR_CODE("AudioUnitGetProperty/input/kAudioDevicePropertyBufferFrameSize", r);
LOG("AudioUnitGetProperty/input/kAudioDevicePropertyBufferFrameSize rv=%d", r);
return 0;
}
@ -1398,16 +1516,16 @@ audiounit_clamp_latency(cubeb_stream * stm, uint32_t latency_frames)
static void
buffer_size_changed_callback(void * inClientData,
AudioUnit inUnit,
AudioUnitPropertyID inPropertyID,
AudioUnitScope inScope,
AudioUnitElement inElement)
AudioUnitPropertyID inPropertyID,
AudioUnitScope inScope,
AudioUnitElement inElement)
{
cubeb_stream * stm = (cubeb_stream *)inClientData;
AudioUnit au = inUnit;
AudioUnitScope au_scope = kAudioUnitScope_Input;
AudioUnitElement au_element = inElement;
const char * au_type = "output";
char const * au_type = "output";
if (au == stm->input_unit) {
au_scope = kAudioUnitScope_Output;
@ -1446,13 +1564,11 @@ audiounit_set_buffer_size(cubeb_stream * stm, uint32_t new_size_frames, io_side
AudioUnit au = stm->output_unit;
AudioUnitScope au_scope = kAudioUnitScope_Input;
AudioUnitElement au_element = AU_OUT_BUS;
const char * au_type = "output";
if (side == INPUT) {
au = stm->input_unit;
au_scope = kAudioUnitScope_Output;
au_element = AU_IN_BUS;
au_type = "input";
}
uint32_t buffer_frames = 0;
@ -1464,16 +1580,12 @@ audiounit_set_buffer_size(cubeb_stream * stm, uint32_t new_size_frames, io_side
&buffer_frames,
&size);
if (r != noErr) {
if (side == INPUT) {
PRINT_ERROR_CODE("AudioUnitGetProperty/input/kAudioDevicePropertyBufferFrameSize", r);
} else {
PRINT_ERROR_CODE("AudioUnitGetProperty/output/kAudioDevicePropertyBufferFrameSize", r);
}
LOG("AudioUnitGetProperty/%s/kAudioDevicePropertyBufferFrameSize rv=%d", to_string(side), r);
return CUBEB_ERROR;
}
if (new_size_frames == buffer_frames) {
LOG("(%p) No need to update %s buffer size already %u frames", stm, au_type, buffer_frames);
LOG("(%p) No need to update %s buffer size already %u frames", stm, to_string(side), buffer_frames);
return CUBEB_OK;
}
@ -1482,11 +1594,7 @@ audiounit_set_buffer_size(cubeb_stream * stm, uint32_t new_size_frames, io_side
buffer_size_changed_callback,
stm);
if (r != noErr) {
if (side == INPUT) {
PRINT_ERROR_CODE("AudioUnitAddPropertyListener/input/kAudioDevicePropertyBufferFrameSize", r);
} else {
PRINT_ERROR_CODE("AudioUnitAddPropertyListener/output/kAudioDevicePropertyBufferFrameSize", r);
}
LOG("AudioUnitAddPropertyListener/%s/kAudioDevicePropertyBufferFrameSize rv=%d", to_string(side), r);
return CUBEB_ERROR;
}
@ -1499,22 +1607,14 @@ audiounit_set_buffer_size(cubeb_stream * stm, uint32_t new_size_frames, io_side
&new_size_frames,
sizeof(new_size_frames));
if (r != noErr) {
if (side == INPUT) {
PRINT_ERROR_CODE("AudioUnitSetProperty/input/kAudioDevicePropertyBufferFrameSize", r);
} else {
PRINT_ERROR_CODE("AudioUnitSetProperty/output/kAudioDevicePropertyBufferFrameSize", r);
}
LOG("AudioUnitSetProperty/%s/kAudioDevicePropertyBufferFrameSize rv=%d", to_string(side), r);
r = AudioUnitRemovePropertyListenerWithUserData(au,
kAudioDevicePropertyBufferFrameSize,
buffer_size_changed_callback,
stm);
if (r != noErr) {
if (side == INPUT) {
PRINT_ERROR_CODE("AudioUnitAddPropertyListener/input/kAudioDevicePropertyBufferFrameSize", r);
} else {
PRINT_ERROR_CODE("AudioUnitAddPropertyListener/output/kAudioDevicePropertyBufferFrameSize", r);
}
LOG("AudioUnitAddPropertyListener/%s/kAudioDevicePropertyBufferFrameSize rv=%d", to_string(side), r);
}
return CUBEB_ERROR;
@ -1536,11 +1636,7 @@ audiounit_set_buffer_size(cubeb_stream * stm, uint32_t new_size_frames, io_side
buffer_size_changed_callback,
stm);
if (r != noErr) {
if (side == INPUT) {
PRINT_ERROR_CODE("AudioUnitAddPropertyListener/input/kAudioDevicePropertyBufferFrameSize", r);
} else {
PRINT_ERROR_CODE("AudioUnitAddPropertyListener/output/kAudioDevicePropertyBufferFrameSize", r);
}
LOG("AudioUnitAddPropertyListener/%s/kAudioDevicePropertyBufferFrameSize rv=%d", to_string(side), r);
return CUBEB_ERROR;
}
@ -1549,7 +1645,7 @@ audiounit_set_buffer_size(cubeb_stream * stm, uint32_t new_size_frames, io_side
return CUBEB_ERROR;
}
LOG("(%p) %s buffer size changed to %u frames.", stm, au_type, new_size_frames);
LOG("(%p) %s buffer size changed to %u frames.", stm, to_string(side), new_size_frames);
return CUBEB_OK;
}
@ -1574,7 +1670,7 @@ audiounit_configure_input(cubeb_stream * stm)
&input_hw_desc,
&size);
if (r != noErr) {
PRINT_ERROR_CODE("AudioUnitGetProperty/input/kAudioUnitProperty_StreamFormat", r);
LOG("AudioUnitGetProperty/input/kAudioUnitProperty_StreamFormat rv=%d", r);
return CUBEB_ERROR;
}
stm->input_hw_rate = input_hw_desc.mSampleRate;
@ -1607,7 +1703,7 @@ audiounit_configure_input(cubeb_stream * stm)
&src_desc,
sizeof(AudioStreamBasicDescription));
if (r != noErr) {
PRINT_ERROR_CODE("AudioUnitSetProperty/input/kAudioUnitProperty_StreamFormat", r);
LOG("AudioUnitSetProperty/input/kAudioUnitProperty_StreamFormat rv=%d", r);
return CUBEB_ERROR;
}
@ -1619,7 +1715,7 @@ audiounit_configure_input(cubeb_stream * stm)
&stm->input_buffer_frames,
sizeof(UInt32));
if (r != noErr) {
PRINT_ERROR_CODE("AudioUnitSetProperty/input/kAudioUnitProperty_MaximumFramesPerSlice", r);
LOG("AudioUnitSetProperty/input/kAudioUnitProperty_MaximumFramesPerSlice rv=%d", r);
return CUBEB_ERROR;
}
@ -1644,7 +1740,7 @@ audiounit_configure_input(cubeb_stream * stm)
&aurcbs_in,
sizeof(aurcbs_in));
if (r != noErr) {
PRINT_ERROR_CODE("AudioUnitSetProperty/input/kAudioOutputUnitProperty_SetInputCallback", r);
LOG("AudioUnitSetProperty/input/kAudioOutputUnitProperty_SetInputCallback rv=%d", r);
return CUBEB_ERROR;
}
LOG("(%p) Input audiounit init successfully.", stm);
@ -1681,7 +1777,7 @@ audiounit_configure_output(cubeb_stream * stm)
&output_hw_desc,
&size);
if (r != noErr) {
PRINT_ERROR_CODE("AudioUnitGetProperty/output/kAudioUnitProperty_StreamFormat", r);
LOG("AudioUnitGetProperty/output/kAudioUnitProperty_StreamFormat rv=%d", r);
return CUBEB_ERROR;
}
stm->output_hw_rate = output_hw_desc.mSampleRate;
@ -1694,7 +1790,7 @@ audiounit_configure_output(cubeb_stream * stm)
&stm->output_desc,
sizeof(AudioStreamBasicDescription));
if (r != noErr) {
PRINT_ERROR_CODE("AudioUnitSetProperty/output/kAudioUnitProperty_StreamFormat", r);
LOG("AudioUnitSetProperty/output/kAudioUnitProperty_StreamFormat rv=%d", r);
return CUBEB_ERROR;
}
@ -1712,7 +1808,7 @@ audiounit_configure_output(cubeb_stream * stm)
&stm->latency_frames,
sizeof(UInt32));
if (r != noErr) {
PRINT_ERROR_CODE("AudioUnitSetProperty/output/kAudioUnitProperty_MaximumFramesPerSlice", r);
LOG("AudioUnitSetProperty/output/kAudioUnitProperty_MaximumFramesPerSlice rv=%d", r);
return CUBEB_ERROR;
}
@ -1726,11 +1822,11 @@ audiounit_configure_output(cubeb_stream * stm)
&aurcbs_out,
sizeof(aurcbs_out));
if (r != noErr) {
PRINT_ERROR_CODE("AudioUnitSetProperty/output/kAudioUnitProperty_SetRenderCallback", r);
LOG("AudioUnitSetProperty/output/kAudioUnitProperty_SetRenderCallback rv=%d", r);
return CUBEB_ERROR;
}
audiounit_layout_init(&stm->output_unit, OUTPUT, &stm->output_stream_params);
audiounit_layout_init(stm, OUTPUT);
LOG("(%p) Output audiounit init successfully.", stm);
return CUBEB_OK;
@ -1872,7 +1968,7 @@ audiounit_setup_stream(cubeb_stream * stm)
if (stm->input_unit != NULL) {
r = AudioUnitInitialize(stm->input_unit);
if (r != noErr) {
PRINT_ERROR_CODE("AudioUnitInitialize/input", r);
LOG("AudioUnitInitialize/input rv=%d", r);
return CUBEB_ERROR;
}
}
@ -1880,7 +1976,7 @@ audiounit_setup_stream(cubeb_stream * stm)
if (stm->output_unit != NULL) {
r = AudioUnitInitialize(stm->output_unit);
if (r != noErr) {
PRINT_ERROR_CODE("AudioUnitInitialize/output", r);
LOG("AudioUnitInitialize/output rv=%d", r);
return CUBEB_ERROR;
}
}
@ -2122,7 +2218,7 @@ audiounit_stream_get_latency(cubeb_stream * stm, uint32_t * latency)
&unit_latency_sec,
&size);
if (r != noErr) {
PRINT_ERROR_CODE("AudioUnitGetProperty/kAudioUnitProperty_Latency", r);
LOG("AudioUnitGetProperty/kAudioUnitProperty_Latency rv=%d", r);
return CUBEB_ERROR;
}
@ -2134,7 +2230,7 @@ audiounit_stream_get_latency(cubeb_stream * stm, uint32_t * latency)
&size,
&device_latency_frames);
if (r != noErr) {
PRINT_ERROR_CODE("AudioUnitGetPropertyData/latency_frames", r);
LOG("AudioUnitGetPropertyData/latency_frames rv=%d", r);
return CUBEB_ERROR;
}
@ -2146,7 +2242,7 @@ audiounit_stream_get_latency(cubeb_stream * stm, uint32_t * latency)
&size,
&device_safety_offset);
if (r != noErr) {
PRINT_ERROR_CODE("AudioUnitGetPropertyData/safety_offset", r);
LOG("AudioUnitGetPropertyData/safety_offset rv=%d", r);
return CUBEB_ERROR;
}
@ -2173,7 +2269,7 @@ int audiounit_stream_set_volume(cubeb_stream * stm, float volume)
0, volume, 0);
if (r != noErr) {
PRINT_ERROR_CODE("AudioUnitSetParameter/kHALOutputParam_Volume", r);
LOG("AudioUnitSetParameter/kHALOutputParam_Volume rv=%d", r);
return CUBEB_ERROR;
}
return CUBEB_OK;
@ -2529,7 +2625,7 @@ audiounit_create_device_from_hwdev(AudioObjectID devid, cubeb_device_type type)
ret->latency_lo = latency + range.mMinimum;
ret->latency_hi = latency + range.mMaximum;
} else {
ret->latency_lo = 10 * ret->default_rate / 1000; /* Default to 10ms */
ret->latency_lo = 10 * ret->default_rate / 1000; /* Default to 10ms */
ret->latency_hi = 100 * ret->default_rate / 1000; /* Default to 100ms */
}
@ -2722,69 +2818,6 @@ int audiounit_register_device_collection_changed(cubeb * context,
return (ret == noErr) ? CUBEB_OK : CUBEB_ERROR;
}
static cubeb_channel_layout
audiounit_get_channel_layout(bool preferred)
{
OSStatus rv = noErr;
// Get the default ouput unit
AudioUnit output_unit;
audiounit_create_unit(&output_unit, false, nullptr, 0);
// Get the channel layout
UInt32 size = 0;
rv = AudioUnitGetPropertyInfo(output_unit,
preferred ? kAudioDevicePropertyPreferredChannelLayout :
kAudioUnitProperty_AudioChannelLayout,
kAudioUnitScope_Output,
AU_OUT_BUS,
&size,
nullptr);
if (rv != noErr) {
if (preferred) {
PRINT_ERROR_CODE("AudioUnitGetPropertyInfo/kAudioDevicePropertyPreferredChannelLayout", rv);
} else {
PRINT_ERROR_CODE("AudioUnitGetPropertyInfo/kAudioUnitProperty_AudioChannelLayout", rv);
}
return CUBEB_LAYOUT_UNDEFINED;
}
assert(size > 0);
auto_channel_layout layout(size);
rv = AudioUnitGetProperty(output_unit,
preferred ? kAudioDevicePropertyPreferredChannelLayout :
kAudioUnitProperty_AudioChannelLayout,
kAudioUnitScope_Output,
AU_OUT_BUS,
layout.get(),
&size);
if (rv != noErr) {
if (preferred) {
PRINT_ERROR_CODE("AudioUnitGetProperty/kAudioDevicePropertyPreferredChannelLayout", rv);
} else {
PRINT_ERROR_CODE("AudioUnitGetProperty/kAudioUnitProperty_AudioChannelLayout", rv);
}
return CUBEB_LAYOUT_UNDEFINED;
}
if (layout.get()->mChannelLayoutTag != kAudioChannelLayoutTag_UseChannelDescriptions) {
// kAudioChannelLayoutTag_UseChannelBitmap
// kAudioChannelLayoutTag_Mono
// kAudioChannelLayoutTag_Stereo
// ....
LOG("Only handle UseChannelDescriptions for now.\n");
return CUBEB_LAYOUT_UNDEFINED;
}
cubeb_channel_map cm;
cm.channels = layout.get()->mNumberChannelDescriptions;
for (UInt32 i = 0; i < layout.get()->mNumberChannelDescriptions; ++i) {
cm.map[i] = channel_label_to_cubeb_channel(layout.get()->mChannelDescriptions[i].mChannelLabel);
}
return cubeb_channel_map_to_layout(&cm);
}
cubeb_ops const audiounit_ops = {
/*.init =*/ audiounit_init,
/*.get_backend_id =*/ audiounit_get_backend_id,

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

@ -857,6 +857,11 @@ wasapi_stream_render_loop(LPVOID stream)
LOG("Unable to use mmcss to bump the render thread priority: %lx", GetLastError());
}
// This has already been nulled out, simply exit.
if (!emergency_bailout) {
is_playing = false;
}
/* WaitForMultipleObjects timeout can trigger in cases where we don't want to
treat it as a timeout, such as across a system sleep/wake cycle. Trigger
the timeout error handling only when the timeout_limit is reached, which is
@ -1166,12 +1171,16 @@ bool stop_and_join_render_thread(cubeb_stream * stm)
/* Something weird happened, leak the thread and continue the shutdown
* process. */
*(stm->emergency_bailout) = true;
// We give the ownership to the rendering thread.
stm->emergency_bailout = nullptr;
LOG("Destroy WaitForSingleObject on thread timed out,"
" leaking the thread: %lx", GetLastError());
rv = false;
}
if (r == WAIT_FAILED) {
*(stm->emergency_bailout) = true;
// We give the ownership to the rendering thread.
stm->emergency_bailout = nullptr;
LOG("Destroy WaitForSingleObject on thread failed: %lx", GetLastError());
rv = false;
}
@ -1599,8 +1608,15 @@ int setup_wasapi_stream(cubeb_stream * stm)
// This delays the input side slightly, but allow to not glitch when no input
// is available when calling into the resampler to call the callback: the input
// refill event will be set shortly after to compensate for this lack of data.
// In debug, four buffers are used, to avoid tripping up assertions down the line.
#if !defined(NDEBUG)
const int silent_buffer_count = 2;
#else
const int silent_buffer_count = 4;
#endif
stm->linear_input_buffer.push_silence(stm->input_buffer_frame_count *
stm->input_stream_params.channels * 2);
stm->input_stream_params.channels *
silent_buffer_count);
if (rv != CUBEB_OK) {
LOG("Failure to open the input side.");
@ -1821,9 +1837,6 @@ void wasapi_stream_destroy(cubeb_stream * stm)
if (stop_and_join_render_thread(stm)) {
delete stm->emergency_bailout.load();
stm->emergency_bailout = nullptr;
} else {
// If we're leaking, it must be that this is true.
XASSERT(*(stm->emergency_bailout));
}
unregister_notification_client(stm);
@ -1885,11 +1898,11 @@ int stream_start_one_side(cubeb_stream * stm, StreamDirection dir)
int wasapi_stream_start(cubeb_stream * stm)
{
auto_lock lock(stm->stream_reset_lock);
XASSERT(stm && !stm->thread && !stm->shutdown_event);
XASSERT(stm->output_client || stm->input_client);
auto_lock lock(stm->stream_reset_lock);
stm->emergency_bailout = new std::atomic<bool>(false);
if (stm->output_client) {
@ -1951,6 +1964,7 @@ int wasapi_stream_stop(cubeb_stream * stm)
}
if (stop_and_join_render_thread(stm)) {
// This is null if we've given the pointer to the other thread
if (stm->emergency_bailout.load()) {
delete stm->emergency_bailout.load();
stm->emergency_bailout = nullptr;