Bug 1318619 - Update cubeb upstream to 7f74039f92. r=kinetik

MozReview-Commit-ID: HDOkLLKKsm7
This commit is contained in:
Alex Chronopoulos 2016-11-18 12:30:23 +02:00
Родитель dd933addc1
Коммит 8ca2f49e54
9 изменённых файлов: 523 добавлений и 706 удалений

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

@ -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 8bab182cd70ff66dec5bbecb69a69422f5d57647.
The git commit ID used was 7f74039f92f4e7183188f9f00a207df8f16330a5.

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

@ -66,6 +66,7 @@ static long
test_data_callback(cubeb_stream * stm, void * user_ptr, const void * /*inputbuffer*/, void * outputbuffer, long nframes)
{
EXPECT_TRUE(stm && user_ptr == &dummy && outputbuffer && nframes > 0);
assert(outputbuffer);
#if (defined(_WIN32) || defined(__WIN32__))
memset(outputbuffer, 0, nframes * sizeof(float));
#else
@ -537,6 +538,7 @@ static long
test_drain_data_callback(cubeb_stream * stm, void * user_ptr, const void * /*inputbuffer*/, void * outputbuffer, long nframes)
{
EXPECT_TRUE(stm && user_ptr == &dummy && outputbuffer && nframes > 0);
assert(outputbuffer);
if (do_drain == 1) {
do_drain = 2;
return 0;

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

@ -114,7 +114,7 @@ TEST(cubeb, tone)
user_data = (struct cb_user_data *) malloc(sizeof(*user_data));
if (user_data == NULL) {
fprintf(stderr, "Error allocating user data\n");
ASSERT_EQ(r, CUBEB_OK);
FAIL();
}
user_data->position = 0;

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

@ -31,26 +31,12 @@
#include "cubeb_utils.h"
#include <algorithm>
#include <atomic>
#if !defined(kCFCoreFoundationVersionNumber10_7)
/* From CoreFoundation CFBase.h */
#define kCFCoreFoundationVersionNumber10_7 635.00
#endif
#if !TARGET_OS_IPHONE && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
#define AudioComponent Component
#define AudioComponentDescription ComponentDescription
#define AudioComponentFindNext FindNextComponent
#define AudioComponentInstanceNew OpenAComponent
#define AudioComponentInstanceDispose CloseComponent
#endif
#include <vector>
#if MAC_OS_X_VERSION_MIN_REQUIRED < 101000
typedef UInt32 AudioFormatFlags;
#endif
#define CUBEB_STREAM_MAX 8
#define AU_OUT_BUS 0
#define AU_IN_BUS 1
@ -72,144 +58,125 @@ static int setup_audiounit_stream(cubeb_stream * stm);
extern cubeb_ops const audiounit_ops;
struct cubeb {
cubeb_ops const * ops;
cubeb_ops const * ops = &audiounit_ops;
owned_critical_section mutex;
std::atomic<int> active_streams;
int limit_streams;
cubeb_device_collection_changed_callback collection_changed_callback;
void * collection_changed_user_ptr;
std::atomic<int> active_streams{ 0 };
cubeb_device_collection_changed_callback collection_changed_callback = nullptr;
void * collection_changed_user_ptr = nullptr;
/* Differentiate input from output devices. */
cubeb_device_type collection_changed_devtype;
uint32_t devtype_device_count;
AudioObjectID * devtype_device_array;
cubeb_device_type collection_changed_devtype = CUBEB_DEVICE_TYPE_UNKNOWN;
std::vector<AudioObjectID> devtype_device_array;
};
class auto_array_wrapper
{
public:
explicit auto_array_wrapper(auto_array<float> * ar)
: float_ar(ar)
, short_ar(nullptr)
{assert((float_ar && !short_ar) || (!float_ar && short_ar));}
struct auto_array_wrapper {
virtual void push(void * elements, size_t length) = 0;
virtual size_t length() = 0;
virtual void push_silence(size_t length) = 0;
virtual bool pop(size_t length) = 0;
virtual void * data() = 0;
virtual void clear() = 0;
virtual ~auto_array_wrapper() {}
};
explicit auto_array_wrapper(auto_array<short> * ar)
: float_ar(nullptr)
, short_ar(ar)
{assert((float_ar && !short_ar) || (!float_ar && short_ar));}
template <typename T>
struct auto_array_wrapper_impl : public auto_array_wrapper {
explicit auto_array_wrapper_impl(uint32_t size)
: ar(size)
{}
~auto_array_wrapper() {
void push(void * elements, size_t length) override {
auto_lock l(lock);
assert((float_ar && !short_ar) || (!float_ar && short_ar));
delete float_ar;
delete short_ar;
ar.push(static_cast<T *>(elements), length);
}
void push(void * elements, size_t length){
assert((float_ar && !short_ar) || (!float_ar && short_ar));
size_t length() override {
auto_lock l(lock);
if (float_ar)
return float_ar->push(static_cast<float*>(elements), length);
return short_ar->push(static_cast<short*>(elements), length);
return ar.length();
}
size_t length() {
assert((float_ar && !short_ar) || (!float_ar && short_ar));
void push_silence(size_t length) override {
auto_lock l(lock);
if (float_ar)
return float_ar->length();
return short_ar->length();
ar.push_silence(length);
}
void push_silence(size_t length) {
assert((float_ar && !short_ar) || (!float_ar && short_ar));
bool pop(size_t length) override {
auto_lock l(lock);
if (float_ar)
return float_ar->push_silence(length);
return short_ar->push_silence(length);
return ar.pop(nullptr, length);
}
bool pop(void * elements, size_t length) {
assert((float_ar && !short_ar) || (!float_ar && short_ar));
// XXX: Taking the lock here is pointless.
void * data() override {
auto_lock l(lock);
if (float_ar)
return float_ar->pop(static_cast<float*>(elements), length);
return short_ar->pop(static_cast<short*>(elements), length);
return ar.data();
}
void * data() {
assert((float_ar && !short_ar) || (!float_ar && short_ar));
void clear() override {
auto_lock l(lock);
if (float_ar)
return float_ar->data();
return short_ar->data();
ar.clear();
}
void clear() {
assert((float_ar && !short_ar) || (!float_ar && short_ar));
~auto_array_wrapper_impl() {
auto_lock l(lock);
if (float_ar) {
float_ar->clear();
} else {
short_ar->clear();
}
ar.clear();
}
private:
auto_array<float> * float_ar;
auto_array<short> * short_ar;
owned_critical_section lock;
auto_array<T> ar;
};
struct cubeb_stream {
explicit cubeb_stream(cubeb * context);
cubeb * context;
cubeb_data_callback data_callback;
cubeb_state_callback state_callback;
cubeb_device_changed_callback device_changed_callback;
cubeb_data_callback data_callback = nullptr;
cubeb_state_callback state_callback = nullptr;
cubeb_device_changed_callback device_changed_callback = nullptr;
/* Stream creation parameters */
cubeb_stream_params input_stream_params;
cubeb_stream_params output_stream_params;
cubeb_stream_params input_stream_params = { CUBEB_SAMPLE_FLOAT32NE, 0, 0 };
cubeb_stream_params output_stream_params = { CUBEB_SAMPLE_FLOAT32NE, 0, 0 };
bool is_default_input;
AudioDeviceID input_device;
AudioDeviceID output_device;
AudioDeviceID input_device = 0;
AudioDeviceID output_device = 0;
/* User pointer of data_callback */
void * user_ptr;
void * user_ptr = nullptr;
/* Format descriptions */
AudioStreamBasicDescription input_desc;
AudioStreamBasicDescription output_desc;
/* I/O AudioUnits */
AudioUnit input_unit;
AudioUnit output_unit;
AudioUnit input_unit = nullptr;
AudioUnit output_unit = nullptr;
/* I/O device sample rate */
Float64 input_hw_rate;
Float64 output_hw_rate;
Float64 input_hw_rate = 0;
Float64 output_hw_rate = 0;
/* Expected I/O thread interleave,
* calculated from I/O hw rate. */
int expected_output_callbacks_in_a_row;
int expected_output_callbacks_in_a_row = 0;
owned_critical_section mutex;
/* Hold the input samples in every
* input callback iteration */
auto_array_wrapper * input_linear_buffer;
std::unique_ptr<auto_array_wrapper> input_linear_buffer;
/* Frames on input buffer */
std::atomic<uint32_t> input_buffer_frames;
std::atomic<uint32_t> input_buffer_frames{ 0 };
/* Frame counters */
std::atomic<uint64_t> frames_played;
uint64_t frames_queued;
std::atomic<int64_t> frames_read;
std::atomic<bool> shutdown;
std::atomic<bool> draining;
std::atomic<uint64_t> frames_played{ 0 };
uint64_t frames_queued = 0;
std::atomic<int64_t> frames_read{ 0 };
std::atomic<bool> shutdown{ false };
std::atomic<bool> draining{ false };
/* Latency requested by the user. */
uint32_t latency_frames;
std::atomic<uint64_t> current_latency_frames;
uint64_t hw_latency_frames;
std::atomic<float> panning;
cubeb_resampler * resampler;
uint32_t latency_frames = 0;
std::atomic<uint64_t> current_latency_frames{ 0 };
uint64_t hw_latency_frames = UINT64_MAX;
std::atomic<float> panning{ 0 };
std::unique_ptr<cubeb_resampler, decltype(&cubeb_resampler_destroy)> resampler;
/* This is the number of output callback we got in a row. This is usually one,
* but can be two when the input and output rate are different, and more when
* a device has been plugged or unplugged, as there can be some time before
* the device is ready. */
std::atomic<int> output_callback_in_a_row;
std::atomic<int> output_callback_in_a_row{ 0 };
/* This is true if a device change callback is currently running. */
std::atomic<bool> switching_device;
std::atomic<bool> switching_device{ false };
};
bool has_input(cubeb_stream * stm)
@ -337,7 +304,6 @@ audiounit_input_callback(void * user_ptr,
// 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);
}
@ -357,7 +323,7 @@ audiounit_input_callback(void * user_ptr,
Resampler will deliver input buffer in the correct rate. */
assert(input_frames <= stm->input_linear_buffer->length() / stm->input_desc.mChannelsPerFrame);
long total_input_frames = stm->input_linear_buffer->length() / stm->input_desc.mChannelsPerFrame;
outframes = cubeb_resampler_fill(stm->resampler,
outframes = cubeb_resampler_fill(stm->resampler.get(),
stm->input_linear_buffer->data(),
&total_input_frames,
NULL,
@ -453,14 +419,14 @@ audiounit_output_callback(void * user_ptr,
}
/* Call user callback through resampler. */
outframes = cubeb_resampler_fill(stm->resampler,
outframes = cubeb_resampler_fill(stm->resampler.get(),
input_buffer,
input_buffer ? &input_frames : NULL,
output_buffer,
output_frames);
if (input_buffer) {
stm->input_linear_buffer->pop(nullptr, input_frames * stm->input_desc.mChannelsPerFrame);
stm->input_linear_buffer->pop(input_frames * stm->input_desc.mChannelsPerFrame);
}
if (outframes < 0) {
@ -497,25 +463,11 @@ extern "C" {
int
audiounit_init(cubeb ** context, char const * /* context_name */)
{
cubeb * ctx;
*context = NULL;
ctx = (cubeb *)calloc(1, sizeof(cubeb));
assert(ctx);
// Placement new to call the ctors of cubeb members.
new (ctx) cubeb();
ctx->ops = &audiounit_ops;
ctx->active_streams = 0;
ctx->limit_streams = kCFCoreFoundationVersionNumber < kCFCoreFoundationVersionNumber10_7;
#if !TARGET_OS_IPHONE
cubeb_set_coreaudio_notification_runloop();
#endif
*context = ctx;
*context = new cubeb;
return CUBEB_OK;
}
@ -985,6 +937,9 @@ audiounit_destroy(cubeb * ctx)
{
// Disabling this assert for bug 1083664 -- we seem to leak a stream
// assert(ctx->active_streams == 0);
if (ctx->active_streams > 0) {
LOG("(%p) API misuse, %d streams active when context destroyed!", ctx, ctx->active_streams.load());
}
/* Unregister the callback if necessary. */
if(ctx->collection_changed_callback) {
@ -992,8 +947,7 @@ audiounit_destroy(cubeb * ctx)
audiounit_remove_device_listener(ctx);
}
ctx->~cubeb();
free(ctx);
delete ctx;
}
static void audiounit_stream_destroy(cubeb_stream * stm);
@ -1123,20 +1077,11 @@ audiounit_create_unit(AudioUnit * unit,
static int
audiounit_init_input_linear_buffer(cubeb_stream * stream, uint32_t capacity)
{
uint32_t size = capacity * stream->input_buffer_frames * stream->input_desc.mChannelsPerFrame;
if (stream->input_desc.mFormatFlags & kAudioFormatFlagIsSignedInteger) {
stream->input_linear_buffer = new auto_array_wrapper(
new auto_array<short>(capacity *
stream->input_buffer_frames *
stream->input_desc.mChannelsPerFrame) );
stream->input_linear_buffer.reset(new auto_array_wrapper_impl<short>(size));
} else {
stream->input_linear_buffer = new auto_array_wrapper(
new auto_array<float>(capacity *
stream->input_buffer_frames *
stream->input_desc.mChannelsPerFrame) );
}
if (!stream->input_linear_buffer) {
return CUBEB_ERROR;
stream->input_linear_buffer.reset(new auto_array_wrapper_impl<float>(size));
}
assert(stream->input_linear_buffer->length() == 0);
@ -1153,12 +1098,6 @@ audiounit_init_input_linear_buffer(cubeb_stream * stream, uint32_t capacity)
return CUBEB_OK;
}
static void
audiounit_destroy_input_linear_buffer(cubeb_stream * stream)
{
delete stream->input_linear_buffer;
}
static uint32_t
audiounit_clamp_latency(cubeb_stream * stm,
uint32_t latency_frames)
@ -1483,13 +1422,13 @@ setup_audiounit_stream(cubeb_stream * stm)
/* Create resampler. Output params are unchanged
* because we do not need conversion on the output. */
stm->resampler = cubeb_resampler_create(stm,
has_input(stm) ? &input_unconverted_params : NULL,
has_output(stm) ? &stm->output_stream_params : NULL,
target_sample_rate,
stm->data_callback,
stm->user_ptr,
CUBEB_RESAMPLER_QUALITY_DESKTOP);
stm->resampler.reset(cubeb_resampler_create(stm,
has_input(stm) ? &input_unconverted_params : NULL,
has_output(stm) ? &stm->output_stream_params : NULL,
target_sample_rate,
stm->data_callback,
stm->user_ptr,
CUBEB_RESAMPLER_QUALITY_DESKTOP));
if (!stm->resampler) {
LOG("(%p) Could not create resampler.", stm);
return CUBEB_ERROR;
@ -1521,6 +1460,14 @@ setup_audiounit_stream(cubeb_stream * stm)
return CUBEB_OK;
}
cubeb_stream::cubeb_stream(cubeb * context)
: context(context)
, resampler(nullptr, cubeb_resampler_destroy)
{
PodZero(&input_desc, 1);
PodZero(&output_desc, 1);
}
static int
audiounit_stream_init(cubeb * context,
cubeb_stream ** stream,
@ -1534,30 +1481,26 @@ audiounit_stream_init(cubeb * context,
cubeb_state_callback state_callback,
void * user_ptr)
{
cubeb_stream * stm;
std::unique_ptr<cubeb_stream, decltype(&audiounit_stream_destroy)> stm(nullptr, audiounit_stream_destroy);
int r;
assert(context);
*stream = NULL;
if (context->limit_streams && context->active_streams >= CUBEB_STREAM_MAX) {
LOG("Reached the stream limit of %d", CUBEB_STREAM_MAX);
return CUBEB_ERROR;
if ((input_device && !input_stream_params) ||
(output_device && !output_stream_params)) {
return CUBEB_ERROR_INVALID_PARAMETER;
}
context->active_streams += 1;
stm = (cubeb_stream *) calloc(1, sizeof(cubeb_stream));
assert(stm);
// Placement new to call the ctors of cubeb_stream members.
new (stm) cubeb_stream();
stm.reset(new cubeb_stream(context));
/* These could be different in the future if we have both
* full-duplex stream and different devices for input vs output. */
stm->context = context;
stm->data_callback = data_callback;
stm->state_callback = state_callback;
stm->user_ptr = user_ptr;
stm->device_changed_callback = NULL;
if (input_stream_params) {
stm->input_stream_params = *input_stream_params;
stm->input_device = reinterpret_cast<uintptr_t>(input_device);
@ -1569,39 +1512,33 @@ audiounit_stream_init(cubeb * context,
stm->output_device = reinterpret_cast<uintptr_t>(output_device);
}
/* Init data members where necessary */
stm->hw_latency_frames = UINT64_MAX;
/* Silently clamp the latency down to the platform default, because we
* synthetize the clock from the callbacks, and we want the clock to update
* often. */
stm->latency_frames = audiounit_clamp_latency(stm, latency_frames);
stm->latency_frames = audiounit_clamp_latency(stm.get(), latency_frames);
assert(latency_frames > 0);
stm->switching_device = false;
{
// It's not critical to lock here, because no other thread has been started
// yet, but it allows to assert that the lock has been taken in
// `setup_audiounit_stream`.
auto_lock lock(stm->mutex);
r = setup_audiounit_stream(stm);
r = setup_audiounit_stream(stm.get());
}
if (r != CUBEB_OK) {
LOG("(%p) Could not setup the audiounit stream.", stm);
audiounit_stream_destroy(stm);
LOG("(%p) Could not setup the audiounit stream.", stm.get());
return r;
}
r = audiounit_install_device_changed_callback(stm);
r = audiounit_install_device_changed_callback(stm.get());
if (r != CUBEB_OK) {
LOG("(%p) Could not install the device change callback.", stm);
LOG("(%p) Could not install the device change callback.", stm.get());
return r;
}
*stream = stm;
LOG("Cubeb stream (%p) init successful.", stm);
*stream = stm.release();
LOG("Cubeb stream (%p) init successful.", *stream);
return CUBEB_OK;
}
@ -1614,14 +1551,14 @@ close_audiounit_stream(cubeb_stream * stm)
AudioComponentInstanceDispose(stm->input_unit);
}
audiounit_destroy_input_linear_buffer(stm);
stm->input_linear_buffer.reset();
if (stm->output_unit) {
AudioUnitUninitialize(stm->output_unit);
AudioComponentInstanceDispose(stm->output_unit);
}
cubeb_resampler_destroy(stm->resampler);
stm->resampler.reset();
}
static void
@ -1646,8 +1583,7 @@ audiounit_stream_destroy(cubeb_stream * stm)
assert(stm->context->active_streams >= 1);
stm->context->active_streams -= 1;
stm->~cubeb_stream();
free(stm);
delete stm;
}
void
@ -1935,7 +1871,7 @@ int audiounit_stream_register_device_changed_callback(cubeb_stream * stream,
}
static OSStatus
audiounit_get_devices(AudioObjectID ** devices, uint32_t * count)
audiounit_get_devices(std::vector<AudioObjectID> & devices)
{
OSStatus ret;
UInt32 size = 0;
@ -1948,22 +1884,16 @@ audiounit_get_devices(AudioObjectID ** devices, uint32_t * count)
return ret;
}
*count = static_cast<uint32_t>(size / sizeof(AudioObjectID));
if (size >= sizeof(AudioObjectID)) {
if (*devices != NULL) {
delete [] (*devices);
}
*devices = new AudioObjectID[*count];
PodZero(*devices, *count);
uint32_t count = static_cast<uint32_t>(size / sizeof(AudioObjectID));
if (count == 0) {
return -1;
}
assert(devices.empty());
devices.resize(count);
ret = AudioObjectGetPropertyData(kAudioObjectSystemObject, &adr, 0, NULL, &size, (void *)*devices);
if (ret != noErr) {
delete [] (*devices);
*devices = NULL;
}
} else {
*devices = NULL;
ret = -1;
ret = AudioObjectGetPropertyData(kAudioObjectSystemObject, &adr, 0, NULL, &size, devices.data());
if (ret != noErr) {
devices.clear();
}
return ret;
@ -2030,19 +1960,18 @@ audiounit_get_available_samplerate(AudioObjectID devid, AudioObjectPropertyScope
AudioValueRange range;
if (AudioObjectHasProperty(devid, &adr) &&
AudioObjectGetPropertyDataSize(devid, &adr, 0, NULL, &size) == noErr) {
uint32_t i, count = size / sizeof(AudioValueRange);
AudioValueRange * ranges = new AudioValueRange[count];
uint32_t count = size / sizeof(AudioValueRange);
std::vector<AudioValueRange> ranges(count);
range.mMinimum = 9999999999.0;
range.mMaximum = 0.0;
if (AudioObjectGetPropertyData(devid, &adr, 0, NULL, &size, ranges) == noErr) {
for (i = 0; i < count; i++) {
if (AudioObjectGetPropertyData(devid, &adr, 0, NULL, &size, ranges.data()) == noErr) {
for (uint32_t i = 0; i < count; i++) {
if (ranges[i].mMaximum > range.mMaximum)
range.mMaximum = ranges[i].mMaximum;
if (ranges[i].mMinimum < range.mMinimum)
range.mMinimum = ranges[i].mMinimum;
}
}
delete [] ranges;
*max = static_cast<uint32_t>(range.mMaximum);
*min = static_cast<uint32_t>(range.mMinimum);
} else {
@ -2177,112 +2106,79 @@ static int
audiounit_enumerate_devices(cubeb * /* context */, cubeb_device_type type,
cubeb_device_collection ** collection)
{
AudioObjectID * hwdevs = NULL;
uint32_t i, hwdevcount = 0;
std::vector<AudioObjectID> hwdevs;
uint32_t i;
OSStatus err;
if ((err = audiounit_get_devices(&hwdevs, &hwdevcount)) != noErr) {
err = audiounit_get_devices(hwdevs);
if (err != noErr) {
return CUBEB_ERROR;
}
*collection = static_cast<cubeb_device_collection *>(malloc(sizeof(cubeb_device_collection) +
sizeof(cubeb_device_info*) * (hwdevcount > 0 ? hwdevcount - 1 : 0)));
sizeof(cubeb_device_info*) * (hwdevs.size() > 0 ? hwdevs.size() - 1 : 0)));
(*collection)->count = 0;
if (hwdevcount > 0) {
cubeb_device_info * cur;
if (type & CUBEB_DEVICE_TYPE_OUTPUT) {
for (i = 0; i < hwdevcount; i++) {
if ((cur = audiounit_create_device_from_hwdev(hwdevs[i], CUBEB_DEVICE_TYPE_OUTPUT)) != NULL)
(*collection)->device[(*collection)->count++] = cur;
}
}
if (type & CUBEB_DEVICE_TYPE_INPUT) {
for (i = 0; i < hwdevcount; i++) {
if ((cur = audiounit_create_device_from_hwdev(hwdevs[i], CUBEB_DEVICE_TYPE_INPUT)) != NULL)
(*collection)->device[(*collection)->count++] = cur;
}
if (type & CUBEB_DEVICE_TYPE_OUTPUT) {
for (i = 0; i < hwdevs.size(); i++) {
cubeb_device_info * cur = audiounit_create_device_from_hwdev(hwdevs[i], CUBEB_DEVICE_TYPE_OUTPUT);
if (cur != nullptr)
(*collection)->device[(*collection)->count++] = cur;
}
}
delete [] hwdevs;
if (type & CUBEB_DEVICE_TYPE_INPUT) {
for (i = 0; i < hwdevs.size(); i++) {
cubeb_device_info * cur = audiounit_create_device_from_hwdev(hwdevs[i], CUBEB_DEVICE_TYPE_INPUT);
if (cur != nullptr)
(*collection)->device[(*collection)->count++] = cur;
}
}
return CUBEB_OK;
}
/* qsort compare method. */
int compare_devid(const void * a, const void * b)
static std::vector<AudioObjectID>
audiounit_get_devices_of_type(cubeb_device_type devtype)
{
return (*(AudioObjectID*)a - *(AudioObjectID*)b);
}
static uint32_t
audiounit_get_devices_of_type(cubeb_device_type devtype, AudioObjectID ** devid_array)
{
assert(devid_array == NULL || *devid_array == NULL);
AudioObjectPropertyAddress adr = { kAudioHardwarePropertyDevices,
kAudioObjectPropertyScopeGlobal,
kAudioObjectPropertyElementMaster };
UInt32 size = 0;
OSStatus ret = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &adr, 0, NULL, &size);
if (ret != noErr) {
return 0;
return std::vector<AudioObjectID>();
}
/* Total number of input and output devices. */
uint32_t count = (uint32_t)(size / sizeof(AudioObjectID));
AudioObjectID devices[count];
ret = AudioObjectGetPropertyData(kAudioObjectSystemObject, &adr, 0, NULL, &size, &devices);
std::vector<AudioObjectID> devices(count);
ret = AudioObjectGetPropertyData(kAudioObjectSystemObject, &adr, 0, NULL, &size, devices.data());
if (ret != noErr) {
return 0;
return std::vector<AudioObjectID>();
}
/* Expected sorted but did not find anything in the docs. */
qsort(devices, count, sizeof(AudioObjectID), compare_devid);
std::sort(devices.begin(), devices.end(), [](AudioObjectID a, AudioObjectID b) {
return a < b;
});
if (devtype == (CUBEB_DEVICE_TYPE_INPUT | CUBEB_DEVICE_TYPE_OUTPUT)) {
if (devid_array) {
*devid_array = new AudioObjectID[count];
assert(*devid_array);
memcpy(*devid_array, &devices, count * sizeof(AudioObjectID));
}
return count;
return devices;
}
AudioObjectPropertyScope scope = (devtype == CUBEB_DEVICE_TYPE_INPUT) ?
kAudioDevicePropertyScopeInput :
kAudioDevicePropertyScopeOutput;
uint32_t dev_count = 0;
AudioObjectID devices_in_scope[count];
for(uint32_t i = 0; i < count; ++i) {
std::vector<AudioObjectID> devices_in_scope;
for (uint32_t i = 0; i < count; ++i) {
/* For device in the given scope channel must be > 0. */
if (audiounit_get_channel_count(devices[i], scope) > 0) {
devices_in_scope[dev_count] = devices[i];
++dev_count;
devices_in_scope.push_back(devices[i]);
}
}
if (devid_array && dev_count > 0) {
*devid_array = new AudioObjectID[dev_count];
assert(*devid_array);
memcpy(*devid_array, &devices_in_scope, dev_count * sizeof(AudioObjectID));
}
return dev_count;
}
static uint32_t
audiounit_equal_arrays(AudioObjectID * left, AudioObjectID * right, uint32_t size)
{
/* Expected sorted arrays. */
for (uint32_t i = 0; i < size; ++i) {
if (left[i] != right[i]) {
return 0;
}
}
return 1;
return devices_in_scope;
}
static OSStatus
@ -2302,19 +2198,13 @@ audiounit_collection_changed_callback(AudioObjectID /* inObjectID */,
/* Differentiate input from output changes. */
if (context->collection_changed_devtype == CUBEB_DEVICE_TYPE_INPUT ||
context->collection_changed_devtype == CUBEB_DEVICE_TYPE_OUTPUT) {
AudioObjectID * devices = NULL;
uint32_t new_number_of_devices = audiounit_get_devices_of_type(context->collection_changed_devtype, &devices);
std::vector<AudioObjectID> devices = audiounit_get_devices_of_type(context->collection_changed_devtype);
/* When count is the same examine the devid for the case of coalescing. */
if (context->devtype_device_count == new_number_of_devices &&
audiounit_equal_arrays(devices, context->devtype_device_array, new_number_of_devices)) {
if (context->devtype_device_array == devices) {
/* Device changed for the other scope, ignore. */
delete [] devices;
return noErr;
}
/* Device on desired scope changed, reset counter and array. */
context->devtype_device_count = new_number_of_devices;
/* Free the old array before replace. */
delete [] context->devtype_device_array;
/* Device on desired scope changed. */
context->devtype_device_array = devices;
}
@ -2342,15 +2232,14 @@ audiounit_add_device_listener(cubeb * context,
audiounit_collection_changed_callback,
context);
if (ret == noErr) {
/* Expected zero after unregister. */
assert(context->devtype_device_count == 0);
assert(context->devtype_device_array == NULL);
/* Expected empty after unregister. */
assert(context->devtype_device_array.empty());
/* Listener works for input and output.
* When requested one of them we need to differentiate. */
if (devtype == CUBEB_DEVICE_TYPE_INPUT ||
devtype == CUBEB_DEVICE_TYPE_OUTPUT) {
/* Used to differentiate input from output device changes. */
context->devtype_device_count = audiounit_get_devices_of_type(devtype, &context->devtype_device_array);
context->devtype_device_array = audiounit_get_devices_of_type(devtype);
}
context->collection_changed_devtype = devtype;
context->collection_changed_callback = collection_changed_callback;
@ -2377,11 +2266,7 @@ audiounit_remove_device_listener(cubeb * context)
context->collection_changed_devtype = CUBEB_DEVICE_TYPE_UNKNOWN;
context->collection_changed_callback = NULL;
context->collection_changed_user_ptr = NULL;
context->devtype_device_count = 0;
if (context->devtype_device_array) {
delete [] context->devtype_device_array;
context->devtype_device_array = NULL;
}
context->devtype_device_array.clear();
}
return ret;
}

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

@ -9,16 +9,10 @@
#define _DEFAULT_SOURCE
#define _BSD_SOURCE
#define _POSIX_SOURCE
#include <algorithm>
#include <dlfcn.h>
#include <limits>
#include <stdio.h>
#include <sys/time.h>
#include <assert.h>
#include <string.h>
#include <limits.h>
#include <poll.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include <math.h>

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

@ -11,6 +11,7 @@
#include <stdint.h>
#include <string.h>
#include <assert.h>
#include <mutex>
#include <type_traits>
#if defined(WIN32)
#include "cubeb_utils_win.h"
@ -23,6 +24,7 @@ template<typename T>
void PodCopy(T * destination, const T * source, size_t count)
{
static_assert(std::is_trivial<T>::value, "Requires trivial type");
assert(destination && source);
memcpy(destination, source, count * sizeof(T));
}
@ -31,6 +33,7 @@ template<typename T>
void PodMove(T * destination, const T * source, size_t count)
{
static_assert(std::is_trivial<T>::value, "Requires trivial type");
assert(destination && source);
memmove(destination, source, count * sizeof(T));
}
@ -39,6 +42,7 @@ template<typename T>
void PodZero(T * destination, size_t count)
{
static_assert(std::is_trivial<T>::value, "Requires trivial type");
assert(destination);
memset(destination, 0, count * sizeof(T));
}
@ -198,18 +202,6 @@ private:
size_t length_;
};
struct auto_lock {
explicit auto_lock(owned_critical_section & lock)
: lock(lock)
{
lock.enter();
}
~auto_lock()
{
lock.leave();
}
private:
owned_critical_section & lock;
};
using auto_lock = std::lock_guard<owned_critical_section>;
#endif /* CUBEB_UTILS */

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

@ -48,7 +48,7 @@ public:
#endif
}
void enter()
void lock()
{
#ifndef NDEBUG
int r =
@ -59,7 +59,7 @@ public:
#endif
}
void leave()
void unlock()
{
#ifndef NDEBUG
int r =

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

@ -29,7 +29,7 @@ public:
DeleteCriticalSection(&critical_section);
}
void enter()
void lock()
{
EnterCriticalSection(&critical_section);
#ifndef NDEBUG
@ -38,7 +38,7 @@ public:
#endif
}
void leave()
void unlock()
{
#ifndef NDEBUG
/* GetCurrentThreadId cannot return 0: it is not a the valid thread id */

Разница между файлами не показана из-за своего большого размера Загрузить разницу