mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 10:44:56 +00:00
Bug 1318619 - Update cubeb upstream to 7f74039f92. r=kinetik
MozReview-Commit-ID: HDOkLLKKsm7
This commit is contained in:
parent
dd933addc1
commit
8ca2f49e54
@ -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 */
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user