зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1342363 - Update cubeb from upstream to 25b593f. r=padenot
MozReview-Commit-ID: BAwQSDLJoMx --HG-- extra : rebase_source : 01c1c72c3b287f6e6608b84fc00cd80177ae65cc
This commit is contained in:
Родитель
e7546e008c
Коммит
6b65c12c74
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче