Bug 1395393 - Update libcubeb to 2e5814de. r=achronop

MozReview-Commit-ID: JWDv93mjAAE

--HG--
extra : rebase_source : 170547b55d8b04838523a255502c58991da8ffdb
extra : amend_source : c7f5e99b69e27c40e5fa6ed9054a57dbdf1c2f1c
This commit is contained in:
Paul Adenot 2017-09-01 17:39:06 +02:00
Родитель 9ed090fe94
Коммит 54e3972626
17 изменённых файлов: 499 добавлений и 170 удалений

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

@ -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 d59010398cee559349ba8f8363a7250b5279aa69 (2017-08-07 22:45:24 +1200)
The git commit ID used was 2e5814de4fd9830d201d61b9d35ed24c2bba6d0f (2017-08-31 13:51:29 +0300)

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

@ -633,3 +633,42 @@ TEST(cubeb, DISABLED_stream_destroy_pending_drain)
{
// This test needs to be implemented.
}
TEST(cubeb, stable_devid)
{
/* Test that the devid field of cubeb_device_info is stable
* (ie. compares equal) over two invocations of
* cubeb_enumerate_devices(). */
int r;
cubeb * ctx;
cubeb_device_collection first;
cubeb_device_collection second;
cubeb_device_type all_devices =
(cubeb_device_type) (CUBEB_DEVICE_TYPE_INPUT | CUBEB_DEVICE_TYPE_OUTPUT);
size_t n;
r = common_init(&ctx, "test_sanity");
ASSERT_EQ(r, CUBEB_OK);
ASSERT_NE(ctx, nullptr);
r = cubeb_enumerate_devices(ctx, all_devices, &first);
if (r == CUBEB_ERROR_NOT_SUPPORTED)
return;
ASSERT_EQ(r, CUBEB_OK);
r = cubeb_enumerate_devices(ctx, all_devices, &second);
ASSERT_EQ(r, CUBEB_OK);
ASSERT_EQ(first.count, second.count);
for (n = 0; n < first.count; n++) {
ASSERT_EQ(first.device[n].devid, second.device[n].devid);
}
r = cubeb_device_collection_destroy(ctx, &first);
ASSERT_EQ(r, CUBEB_OK);
r = cubeb_device_collection_destroy(ctx, &second);
ASSERT_EQ(r, CUBEB_OK);
cubeb_destroy(ctx);
}

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

@ -17,7 +17,6 @@
#include <alsa/asoundlib.h>
#include "cubeb/cubeb.h"
#include "cubeb-internal.h"
#include "cubeb_utils.h"
#define CUBEB_STREAM_MAX 16
#define CUBEB_WATCHDOG_MS 10000

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

@ -63,6 +63,8 @@ void audiounit_stream_stop_internal(cubeb_stream * stm);
void audiounit_stream_start_internal(cubeb_stream * stm);
static void audiounit_close_stream(cubeb_stream *stm);
static int audiounit_setup_stream(cubeb_stream *stm);
static std::vector<AudioObjectID>
audiounit_get_devices_of_type(cubeb_device_type devtype);
extern cubeb_ops const audiounit_ops;
@ -2874,35 +2876,6 @@ int audiounit_stream_register_device_changed_callback(cubeb_stream * stream,
return CUBEB_OK;
}
static OSStatus
audiounit_get_devices(std::vector<AudioObjectID> & devices)
{
OSStatus ret;
UInt32 size = 0;
AudioObjectPropertyAddress adr = { kAudioHardwarePropertyDevices,
kAudioObjectPropertyScopeGlobal,
kAudioObjectPropertyElementMaster };
ret = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &adr, 0, NULL, &size);
if (ret != noErr) {
return ret;
}
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, devices.data());
if (ret != noErr) {
devices.clear();
}
return ret;
}
static char *
audiounit_strref_to_cstr_utf8(CFStringRef strref)
{
@ -3109,22 +3082,30 @@ static int
audiounit_enumerate_devices(cubeb * /* context */, cubeb_device_type type,
cubeb_device_collection * collection)
{
std::vector<AudioObjectID> hwdevs;
uint32_t i;
OSStatus err;
std::vector<AudioObjectID> input_devs;
std::vector<AudioObjectID> output_devs;
err = audiounit_get_devices(hwdevs);
if (err != noErr) {
return CUBEB_ERROR;
// Count number of input and output devices. This is not
// necessarily the same as the count of raw devices supported by the
// system since, for example, with Soundflower installed, some
// devices may report as being both input *and* output and cubeb
// separates those into two different devices.
if (type & CUBEB_DEVICE_TYPE_OUTPUT) {
output_devs = audiounit_get_devices_of_type(CUBEB_DEVICE_TYPE_OUTPUT);
}
auto devices = new cubeb_device_info[hwdevs.size()];
if (type & CUBEB_DEVICE_TYPE_INPUT) {
input_devs = audiounit_get_devices_of_type(CUBEB_DEVICE_TYPE_INPUT);
}
auto devices = new cubeb_device_info[output_devs.size() + input_devs.size()];
collection->count = 0;
if (type & CUBEB_DEVICE_TYPE_OUTPUT) {
for (i = 0; i < hwdevs.size(); i++) {
for (auto dev: output_devs) {
auto device = &devices[collection->count];
auto err = audiounit_create_device_from_hwdev(device, hwdevs[i], CUBEB_DEVICE_TYPE_OUTPUT);
auto err = audiounit_create_device_from_hwdev(device, dev, CUBEB_DEVICE_TYPE_OUTPUT);
if (err != CUBEB_OK) {
continue;
}
@ -3133,9 +3114,9 @@ audiounit_enumerate_devices(cubeb * /* context */, cubeb_device_type type,
}
if (type & CUBEB_DEVICE_TYPE_INPUT) {
for (i = 0; i < hwdevs.size(); i++) {
for (auto dev: input_devs) {
auto device = &devices[collection->count];
auto err = audiounit_create_device_from_hwdev(device, hwdevs[i], CUBEB_DEVICE_TYPE_INPUT);
auto err = audiounit_create_device_from_hwdev(device, dev, CUBEB_DEVICE_TYPE_INPUT);
if (err != CUBEB_OK) {
continue;
}

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

@ -96,6 +96,8 @@ static int cbjack_stream_device_destroy(cubeb_stream * stream,
static int cbjack_stream_get_current_device(cubeb_stream * stm, cubeb_device ** const device);
static int cbjack_enumerate_devices(cubeb * context, cubeb_device_type type,
cubeb_device_collection * collection);
static int cbjack_device_collection_destroy(cubeb * context,
cubeb_device_collection * collection);
static int cbjack_stream_init(cubeb * context, cubeb_stream ** stream, char const * stream_name,
cubeb_devid input_device,
cubeb_stream_params * input_stream_params,
@ -119,7 +121,7 @@ static struct cubeb_ops const cbjack_ops = {
.get_preferred_sample_rate = cbjack_get_preferred_sample_rate,
.get_preferred_channel_layout = NULL,
.enumerate_devices = cbjack_enumerate_devices,
.device_collection_destroy = cubeb_utils_default_device_collection_destroy,
.device_collection_destroy = cbjack_device_collection_destroy,
.destroy = cbjack_destroy,
.stream_init = cbjack_stream_init,
.stream_destroy = cbjack_stream_destroy,
@ -974,6 +976,9 @@ cbjack_stream_device_destroy(cubeb_stream * /*stream*/,
return CUBEB_OK;
}
#define JACK_DEFAULT_IN "JACK capture"
#define JACK_DEFAULT_OUT "JACK playback"
static int
cbjack_enumerate_devices(cubeb * context, cubeb_device_type type,
cubeb_device_collection * collection)
@ -983,20 +988,20 @@ cbjack_enumerate_devices(cubeb * context, cubeb_device_type type,
uint32_t rate;
cbjack_get_preferred_sample_rate(context, &rate);
const char * j_in = "JACK capture";
const char * j_out = "JACK playback";
cubeb_device_info * devices = new cubeb_device_info[2];
reinterpret_cast<cubeb_device_info *>(calloc(2, sizeof(cubeb_device_info)));
if (!devices)
return CUBEB_ERROR;
PodZero(devices, 2);
collection->count = 0;
if (type & CUBEB_DEVICE_TYPE_OUTPUT) {
cubeb_device_info * cur = &devices[collection->count];
cur->device_id = strdup(j_out);
cur->device_id = JACK_DEFAULT_OUT;
cur->devid = (cubeb_devid) cur->device_id;
cur->friendly_name = strdup(j_out);
cur->group_id = strdup(j_out);
cur->vendor_name = strdup(j_out);
cur->friendly_name = JACK_DEFAULT_OUT;
cur->group_id = JACK_DEFAULT_OUT;
cur->vendor_name = JACK_DEFAULT_OUT;
cur->type = CUBEB_DEVICE_TYPE_OUTPUT;
cur->state = CUBEB_DEVICE_STATE_ENABLED;
cur->preferred = CUBEB_DEVICE_PREF_ALL;
@ -1013,11 +1018,11 @@ cbjack_enumerate_devices(cubeb * context, cubeb_device_type type,
if (type & CUBEB_DEVICE_TYPE_INPUT) {
cubeb_device_info * cur = &devices[collection->count];
cur->device_id = strdup(j_in);
cur->device_id = JACK_DEFAULT_IN;
cur->devid = (cubeb_devid) cur->device_id;
cur->friendly_name = strdup(j_in);
cur->group_id = strdup(j_in);
cur->vendor_name = strdup(j_in);
cur->friendly_name = JACK_DEFAULT_IN;
cur->group_id = JACK_DEFAULT_IN;
cur->vendor_name = JACK_DEFAULT_IN;
cur->type = CUBEB_DEVICE_TYPE_INPUT;
cur->state = CUBEB_DEVICE_STATE_ENABLED;
cur->preferred = CUBEB_DEVICE_PREF_ALL;
@ -1036,3 +1041,12 @@ cbjack_enumerate_devices(cubeb * context, cubeb_device_type type,
return CUBEB_OK;
}
static int
cbjack_device_collection_destroy(cubeb * /*ctx*/,
cubeb_device_collection * collection)
{
XASSERT(collection);
delete [] collection->device;
return CUBEB_OK;
}

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

@ -95,6 +95,12 @@ public:
}
}).detach();
}
// Tell the underlying queue the producer thread has changed, so it does not
// assert in debug. This should be called with the thread stopped.
void reset_producer_thread()
{
msg_queue.reset_thread_ids();
}
private:
#ifndef _WIN32
const struct timespec sleep_for = {
@ -128,3 +134,11 @@ void cubeb_async_log(char const * fmt, ...)
cubeb_async_logger::get().push(msg);
va_end(args);
}
void cubeb_async_log_reset_threads()
{
if (!g_cubeb_log_callback) {
return;
}
cubeb_async_logger::get().reset_producer_thread();
}

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

@ -23,6 +23,7 @@ extern "C" {
extern cubeb_log_level g_cubeb_log_level;
extern cubeb_log_callback g_cubeb_log_callback PRINTF_FORMAT(1, 2);
void cubeb_async_log(const char * fmt, ...);
void cubeb_async_log_reset_threads();
#ifdef __cplusplus
}

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

@ -13,7 +13,7 @@
#include "cubeb/cubeb.h"
#include "cubeb-internal.h"
#include "cubeb_mixer.h"
#include "cubeb_utils.h"
#include "cubeb_strings.h"
#include <stdio.h>
#ifdef DISABLE_LIBPULSE_DLOPEN
@ -102,6 +102,7 @@ struct cubeb {
int error;
cubeb_device_collection_changed_callback collection_changed_callback;
void * collection_changed_user_ptr;
cubeb_strings * device_ids;
};
struct cubeb_stream {
@ -127,6 +128,24 @@ enum cork_state {
NOTIFY = 1 << 1
};
static int
intern_device_id(cubeb * ctx, char const ** id)
{
char const * interned;
assert(ctx);
assert(id);
interned = cubeb_strings_intern(ctx->device_ids, *id);
if (!interned) {
return CUBEB_ERROR;
}
*id = interned;
return CUBEB_OK;
}
static void
sink_info_callback(pa_context * context, const pa_sink_info * info, int eol, void * u)
{
@ -608,6 +627,10 @@ pulse_init(cubeb ** context, char const * context_name)
ctx->ops = &pulse_ops;
ctx->libpulse = libpulse;
if (cubeb_strings_init(&ctx->device_ids) != CUBEB_OK) {
pulse_destroy(ctx);
return CUBEB_ERROR;
}
ctx->mainloop = WRAP(pa_threaded_mainloop_new)();
ctx->default_sink_info = NULL;
@ -717,6 +740,10 @@ pulse_destroy(cubeb * ctx)
WRAP(pa_threaded_mainloop_free)(ctx->mainloop);
}
if (ctx->device_ids) {
cubeb_strings_destroy(ctx->device_ids);
}
if (ctx->libpulse) {
dlclose(ctx->libpulse);
}
@ -752,8 +779,8 @@ create_pa_stream(cubeb_stream * stm,
assert(stm && stream_params);
assert(&stm->input_stream == pa_stm || (&stm->output_stream == pa_stm &&
(stream_params->layout == CUBEB_LAYOUT_UNDEFINED ||
stream_params->layout != CUBEB_LAYOUT_UNDEFINED &&
CUBEB_CHANNEL_LAYOUT_MAPS[stream_params->layout].channels == stream_params->channels)));
(stream_params->layout != CUBEB_LAYOUT_UNDEFINED &&
CUBEB_CHANNEL_LAYOUT_MAPS[stream_params->layout].channels == stream_params->channels))));
*pa_stm = NULL;
pa_sample_spec ss;
ss.format = to_pulse_format(stream_params->format);
@ -1203,18 +1230,25 @@ pulse_sink_info_cb(pa_context * context, const pa_sink_info * info,
{
pulse_dev_list_data * list_data = user_data;
cubeb_device_info * devinfo;
const char * prop;
char const * prop = NULL;
char const * device_id = NULL;
(void)context;
if (eol || info == NULL)
return;
device_id = info->name;
if (intern_device_id(list_data->context, &device_id) != CUBEB_OK) {
assert(false);
return;
}
pulse_ensure_dev_list_data_list_size(list_data);
devinfo = &list_data->devinfo[list_data->count];
memset(devinfo, 0, sizeof(cubeb_device_info));
devinfo->device_id = strdup(info->name);
devinfo->device_id = device_id;
devinfo->devid = (cubeb_devid) devinfo->device_id;
devinfo->friendly_name = strdup(info->description);
prop = WRAP(pa_proplist_gets)(info->proplist, "sysfs.path");
@ -1265,18 +1299,25 @@ pulse_source_info_cb(pa_context * context, const pa_source_info * info,
{
pulse_dev_list_data * list_data = user_data;
cubeb_device_info * devinfo;
const char * prop;
char const * prop = NULL;
char const * device_id = NULL;
(void)context;
if (eol)
return;
device_id = info->name;
if (intern_device_id(list_data->context, &device_id) != CUBEB_OK) {
assert(false);
return;
}
pulse_ensure_dev_list_data_list_size(list_data);
devinfo = &list_data->devinfo[list_data->count];
memset(devinfo, 0, sizeof(cubeb_device_info));
devinfo->device_id = strdup(info->name);
devinfo->device_id = device_id;
devinfo->devid = (cubeb_devid) devinfo->device_id;
devinfo->friendly_name = strdup(info->description);
prop = WRAP(pa_proplist_gets)(info->proplist, "sysfs.path");
@ -1364,6 +1405,21 @@ pulse_enumerate_devices(cubeb * context, cubeb_device_type type,
return CUBEB_OK;
}
static int
pulse_device_collection_destroy(cubeb * ctx, cubeb_device_collection * collection)
{
size_t n;
for (n = 0; n < collection->count; n++) {
free((void *) collection->device[n].friendly_name);
free((void *) collection->device[n].vendor_name);
free((void *) collection->device[n].group_id);
}
free(collection->device);
return CUBEB_OK;
}
static int
pulse_stream_get_current_device(cubeb_stream * stm, cubeb_device ** const device)
{
@ -1493,7 +1549,7 @@ static struct cubeb_ops const pulse_ops = {
.get_preferred_sample_rate = pulse_get_preferred_sample_rate,
.get_preferred_channel_layout = pulse_get_preferred_channel_layout,
.enumerate_devices = pulse_enumerate_devices,
.device_collection_destroy = cubeb_utils_default_device_collection_destroy,
.device_collection_destroy = pulse_device_collection_destroy,
.destroy = pulse_destroy,
.stream_init = pulse_stream_init,
.stream_destroy = pulse_stream_destroy,

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

@ -226,6 +226,17 @@ public:
{
return storage_capacity() - 1;
}
/**
* Reset the consumer and producer thread identifier, in case the thread are
* being changed. This has to be externally synchronized. This is no-op when
* asserts are disabled.
*/
void reset_thread_ids()
{
#ifndef NDEBUG
consumer_id = producer_id = std::thread::id();
#endif
}
private:
/** Return true if the ring buffer is empty.
*

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

@ -0,0 +1,155 @@
/*
* Copyright © 2011 Mozilla Foundation
*
* This program is made available under an ISC-style license. See the
* accompanying file LICENSE for details.
*/
#include "cubeb_strings.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#define CUBEB_STRINGS_INLINE_COUNT 4
struct cubeb_strings {
uint32_t size;
uint32_t count;
char ** data;
char * small_store[CUBEB_STRINGS_INLINE_COUNT];
};
int
cubeb_strings_init(cubeb_strings ** strings)
{
cubeb_strings* strs = NULL;
if (!strings) {
return CUBEB_ERROR;
}
strs = calloc(1, sizeof(cubeb_strings));
assert(strs);
if (!strs) {
return CUBEB_ERROR;
}
strs->size = sizeof(strs->small_store) / sizeof(strs->small_store[0]);
strs->count = 0;
strs->data = strs->small_store;
*strings = strs;
return CUBEB_OK;
}
void
cubeb_strings_destroy(cubeb_strings * strings)
{
char ** sp = NULL;
char ** se = NULL;
if (!strings) {
return;
}
sp = strings->data;
se = sp + strings->count;
for ( ; sp != se; sp++) {
if (*sp) {
free(*sp);
}
}
if (strings->data != strings->small_store) {
free(strings->data);
}
free(strings);
}
/** Look for string in string storage.
@param strings Opaque pointer to interned string storage.
@param s String to look up.
@retval Read-only string or NULL if not found. */
static char const *
cubeb_strings_lookup(cubeb_strings * strings, char const * s)
{
char ** sp = NULL;
char ** se = NULL;
if (!strings || !s) {
return NULL;
}
sp = strings->data;
se = sp + strings->count;
for ( ; sp != se; sp++) {
if (*sp && strcmp(*sp, s) == 0) {
return *sp;
}
}
return NULL;
}
static char const *
cubeb_strings_push(cubeb_strings * strings, char const * s)
{
char * is = NULL;
if (strings->count == strings->size) {
char ** new_data;
uint32_t value_size = sizeof(char const *);
uint32_t new_size = strings->size * 2;
if (!new_size || value_size > (uint32_t)-1 / new_size) {
// overflow
return NULL;
}
if (strings->small_store == strings->data) {
// First time heap allocation.
new_data = malloc(new_size * value_size);
if (new_data) {
memcpy(new_data, strings->small_store, sizeof(strings->small_store));
}
} else {
new_data = realloc(strings->data, new_size * value_size);
}
if (!new_data) {
// out of memory
return NULL;
}
strings->size = new_size;
strings->data = new_data;
}
is = strdup(s);
strings->data[strings->count++] = is;
return is;
}
char const *
cubeb_strings_intern(cubeb_strings * strings, char const * s)
{
char const * is = NULL;
if (!strings || !s) {
return NULL;
}
is = cubeb_strings_lookup(strings, s);
if (is) {
return is;
}
return cubeb_strings_push(strings, s);
}

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

@ -0,0 +1,44 @@
/*
* Copyright © 2011 Mozilla Foundation
*
* This program is made available under an ISC-style license. See the
* accompanying file LICENSE for details.
*/
#ifndef CUBEB_STRINGS_H
#define CUBEB_STRINGS_H
#include "cubeb/cubeb.h"
#if defined(__cplusplus)
extern "C" {
#endif
/** Opaque handle referencing interned string storage. */
typedef struct cubeb_strings cubeb_strings;
/** Initialize an interned string structure.
@param strings An out param where an opaque pointer to the
interned string storage will be returned.
@retval CUBEB_OK in case of success.
@retval CUBEB_ERROR in case of error. */
CUBEB_EXPORT int cubeb_strings_init(cubeb_strings ** strings);
/** Destroy an interned string structure freeing all associated memory.
@param strings An opaque pointer to the interned string storage to
destroy. */
CUBEB_EXPORT void cubeb_strings_destroy(cubeb_strings * strings);
/** Add string to internal storage.
@param strings Opaque pointer to interned string storage.
@param s String to add to storage.
@retval CUBEB_OK
@retval CUBEB_ERROR
*/
CUBEB_EXPORT char const * cubeb_strings_intern(cubeb_strings * strings, char const * s);
#if defined(__cplusplus)
}
#endif
#endif // !CUBEB_STRINGS_H

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

@ -1,38 +0,0 @@
/*
* Copyright © 2016 Mozilla Foundation
*
* This program is made available under an ISC-style license. See the
* accompanying file LICENSE for details.
*/
#include "cubeb_utils.h"
#include "cubeb_assert.h"
#include <stdlib.h>
static void
device_info_destroy(cubeb_device_info * info)
{
XASSERT(info);
free((void *) info->device_id);
free((void *) info->friendly_name);
free((void *) info->group_id);
free((void *) info->vendor_name);
}
int
cubeb_utils_default_device_collection_destroy(cubeb * context,
cubeb_device_collection * collection)
{
uint32_t i;
XASSERT(collection);
(void) context;
for (i = 0; i < collection->count; i++)
device_info_destroy(&collection->device[i]);
free(collection->device);
return CUBEB_OK;
}

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

@ -336,17 +336,4 @@ private:
using auto_lock = std::lock_guard<owned_critical_section>;
#endif // __cplusplus
// C language helpers
#ifdef __cplusplus
extern "C" {
#endif
int cubeb_utils_default_device_collection_destroy(cubeb * context,
cubeb_device_collection * collection);
#ifdef __cplusplus
}
#endif
#endif /* CUBEB_UTILS */

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

@ -30,6 +30,7 @@
#include "cubeb-internal.h"
#include "cubeb_mixer.h"
#include "cubeb_resampler.h"
#include "cubeb_strings.h"
#include "cubeb_utils.h"
#ifndef PKEY_Device_FriendlyName
@ -173,6 +174,7 @@ static std::unique_ptr<wchar_t const []> utf8_to_wstr(char const * str);
struct cubeb {
cubeb_ops const * ops = &wasapi_ops;
cubeb_strings * device_ids;
};
class wasapi_endpoint_notification_client;
@ -382,6 +384,23 @@ private:
};
namespace {
char const *
intern_device_id(cubeb * ctx, wchar_t const * id)
{
XASSERT(id);
char const * tmp = wstr_to_utf8(id);
if (!tmp)
return nullptr;
char const * interned = cubeb_strings_intern(ctx->device_ids, tmp);
free((void *) tmp);
return interned;
}
bool has_input(cubeb_stream * stm)
{
return stm->input_stream_params.rate != 0;
@ -427,25 +446,25 @@ channel_layout_to_mask(cubeb_channel_layout layout)
// allocate it in stack, or it will be created and removed repeatedly.
// Use static to allocate this local variable in data space instead of stack.
static DWORD map[CUBEB_LAYOUT_MAX] = {
0, // CUBEB_LAYOUT_UNDEFINED
MASK_DUAL_MONO, // CUBEB_LAYOUT_DUAL_MONO
MASK_DUAL_MONO_LFE, // CUBEB_LAYOUT_DUAL_MONO_LFE
MASK_MONO, // CUBEB_LAYOUT_MONO
MASK_MONO_LFE, // CUBEB_LAYOUT_MONO_LFE
MASK_STEREO, // CUBEB_LAYOUT_STEREO
MASK_STEREO_LFE, // CUBEB_LAYOUT_STEREO_LFE
MASK_3F, // CUBEB_LAYOUT_3F
MASK_3F_LFE, // CUBEB_LAYOUT_3F_LFE
MASK_2F1, // CUBEB_LAYOUT_2F1
MASK_2F1_LFE, // CUBEB_LAYOUT_2F1_LFE
MASK_3F1, // CUBEB_LAYOUT_3F1
MASK_3F1_LFE, // CUBEB_LAYOUT_3F1_LFE
MASK_2F2, // CUBEB_LAYOUT_2F2
MASK_2F2_LFE, // CUBEB_LAYOUT_2F2_LFE
MASK_3F2, // CUBEB_LAYOUT_3F2
MASK_3F2_LFE, // CUBEB_LAYOUT_3F2_LFE
MASK_3F3R_LFE, // CUBEB_LAYOUT_3F3R_LFE
MASK_3F4_LFE, // CUBEB_LAYOUT_3F4_LFE
KSAUDIO_SPEAKER_DIRECTOUT, // CUBEB_LAYOUT_UNDEFINED
MASK_DUAL_MONO, // CUBEB_LAYOUT_DUAL_MONO
MASK_DUAL_MONO_LFE, // CUBEB_LAYOUT_DUAL_MONO_LFE
MASK_MONO, // CUBEB_LAYOUT_MONO
MASK_MONO_LFE, // CUBEB_LAYOUT_MONO_LFE
MASK_STEREO, // CUBEB_LAYOUT_STEREO
MASK_STEREO_LFE, // CUBEB_LAYOUT_STEREO_LFE
MASK_3F, // CUBEB_LAYOUT_3F
MASK_3F_LFE, // CUBEB_LAYOUT_3F_LFE
MASK_2F1, // CUBEB_LAYOUT_2F1
MASK_2F1_LFE, // CUBEB_LAYOUT_2F1_LFE
MASK_3F1, // CUBEB_LAYOUT_3F1
MASK_3F1_LFE, // CUBEB_LAYOUT_3F1_LFE
MASK_2F2, // CUBEB_LAYOUT_2F2
MASK_2F2_LFE, // CUBEB_LAYOUT_2F2_LFE
MASK_3F2, // CUBEB_LAYOUT_3F2
MASK_3F2_LFE, // CUBEB_LAYOUT_3F2_LFE
MASK_3F3R_LFE, // CUBEB_LAYOUT_3F3R_LFE
MASK_3F4_LFE, // CUBEB_LAYOUT_3F4_LFE
};
return map[layout];
}
@ -1153,6 +1172,10 @@ int wasapi_init(cubeb ** context, char const * context_name)
cubeb * ctx = new cubeb();
ctx->ops = &wasapi_ops;
if (cubeb_strings_init(&ctx->device_ids) != CUBEB_OK) {
free(ctx);
return CUBEB_ERROR;
}
*context = ctx;
@ -1220,6 +1243,10 @@ bool stop_and_join_render_thread(cubeb_stream * stm)
void wasapi_destroy(cubeb * context)
{
if (context->device_ids) {
cubeb_strings_destroy(context->device_ids);
}
delete context;
}
@ -1407,8 +1434,6 @@ waveformatex_update_derived_properties(WAVEFORMATEX * format)
static void
handle_channel_layout(cubeb_stream * stm, EDataFlow direction, com_heap_ptr<WAVEFORMATEX> & mix_format, const cubeb_stream_params * stream_params)
{
// The CUBEB_LAYOUT_UNDEFINED can be used for input but it's not allowed for output.
XASSERT(direction == eCapture || stream_params->layout != CUBEB_LAYOUT_UNDEFINED);
com_ptr<IAudioClient> & audio_client = (direction == eRender) ? stm->output_client : stm->input_client;
XASSERT(audio_client);
/* The docs say that GetMixFormat is always of type WAVEFORMATEXTENSIBLE [1],
@ -1972,6 +1997,7 @@ int wasapi_stream_start(cubeb_stream * stm)
return CUBEB_ERROR;
}
cubeb_async_log_reset_threads();
stm->thread = (HANDLE) _beginthreadex(NULL, 512 * 1024, wasapi_stream_render_loop, stm, STACK_SIZE_PARAM_IS_A_RESERVATION, NULL);
if (stm->thread == NULL) {
LOG("could not create WASAPI render thread.");
@ -2174,8 +2200,8 @@ wasapi_is_default_device(EDataFlow flow, ERole role, LPCWSTR device_id,
return ret;
}
static int
wasapi_create_device(cubeb_device_info * ret, IMMDeviceEnumerator * enumerator, IMMDevice * dev)
int
wasapi_create_device(cubeb * ctx, cubeb_device_info& ret, IMMDeviceEnumerator * enumerator, IMMDevice * dev)
{
com_ptr<IMMEndpoint> endpoint;
com_ptr<IMMDevice> devnode;
@ -2204,19 +2230,23 @@ wasapi_create_device(cubeb_device_info * ret, IMMDeviceEnumerator * enumerator,
if (FAILED(hr)) return CUBEB_ERROR;
com_heap_ptr<wchar_t> device_id(tmp);
char const * device_id_intern = intern_device_id(ctx, device_id.get());
if (!device_id_intern) {
return CUBEB_ERROR;
}
hr = dev->OpenPropertyStore(STGM_READ, propstore.receive());
if (FAILED(hr)) return CUBEB_ERROR;
hr = dev->GetState(&state);
if (FAILED(hr)) return CUBEB_ERROR;
XASSERT(ret);
ret->device_id = wstr_to_utf8(device_id.get());
ret->devid = reinterpret_cast<cubeb_devid>(ret->device_id);
ret.device_id = device_id_intern;
ret.devid = reinterpret_cast<cubeb_devid>(ret.device_id);
prop_variant namevar;
hr = propstore->GetValue(PKEY_Device_FriendlyName, &namevar);
if (SUCCEEDED(hr))
ret->friendly_name = wstr_to_utf8(namevar.pwszVal);
ret.friendly_name = wstr_to_utf8(namevar.pwszVal);
devnode = wasapi_get_device_node(enumerator, dev);
if (devnode) {
@ -2227,60 +2257,60 @@ wasapi_create_device(cubeb_device_info * ret, IMMDeviceEnumerator * enumerator,
prop_variant instancevar;
hr = ps->GetValue(PKEY_Device_InstanceId, &instancevar);
if (SUCCEEDED(hr)) {
ret->group_id = wstr_to_utf8(instancevar.pwszVal);
ret.group_id = wstr_to_utf8(instancevar.pwszVal);
}
}
ret->preferred = CUBEB_DEVICE_PREF_NONE;
ret.preferred = CUBEB_DEVICE_PREF_NONE;
if (wasapi_is_default_device(flow, eConsole, device_id.get(), enumerator))
ret->preferred = (cubeb_device_pref)(ret->preferred | CUBEB_DEVICE_PREF_MULTIMEDIA);
ret.preferred = (cubeb_device_pref)(ret.preferred | CUBEB_DEVICE_PREF_MULTIMEDIA);
if (wasapi_is_default_device(flow, eCommunications, device_id.get(), enumerator))
ret->preferred = (cubeb_device_pref)(ret->preferred | CUBEB_DEVICE_PREF_VOICE);
ret.preferred = (cubeb_device_pref)(ret.preferred | CUBEB_DEVICE_PREF_VOICE);
if (wasapi_is_default_device(flow, eConsole, device_id.get(), enumerator))
ret->preferred = (cubeb_device_pref)(ret->preferred | CUBEB_DEVICE_PREF_NOTIFICATION);
ret.preferred = (cubeb_device_pref)(ret.preferred | CUBEB_DEVICE_PREF_NOTIFICATION);
if (flow == eRender) ret->type = CUBEB_DEVICE_TYPE_OUTPUT;
else if (flow == eCapture) ret->type = CUBEB_DEVICE_TYPE_INPUT;
if (flow == eRender) ret.type = CUBEB_DEVICE_TYPE_OUTPUT;
else if (flow == eCapture) ret.type = CUBEB_DEVICE_TYPE_INPUT;
switch (state) {
case DEVICE_STATE_ACTIVE:
ret->state = CUBEB_DEVICE_STATE_ENABLED;
ret.state = CUBEB_DEVICE_STATE_ENABLED;
break;
case DEVICE_STATE_UNPLUGGED:
ret->state = CUBEB_DEVICE_STATE_UNPLUGGED;
ret.state = CUBEB_DEVICE_STATE_UNPLUGGED;
break;
default:
ret->state = CUBEB_DEVICE_STATE_DISABLED;
ret.state = CUBEB_DEVICE_STATE_DISABLED;
break;
};
ret->format = static_cast<cubeb_device_fmt>(CUBEB_DEVICE_FMT_F32NE | CUBEB_DEVICE_FMT_S16NE);
ret->default_format = CUBEB_DEVICE_FMT_F32NE;
ret.format = static_cast<cubeb_device_fmt>(CUBEB_DEVICE_FMT_F32NE | CUBEB_DEVICE_FMT_S16NE);
ret.default_format = CUBEB_DEVICE_FMT_F32NE;
prop_variant fmtvar;
hr = propstore->GetValue(PKEY_AudioEngine_DeviceFormat, &fmtvar);
if (SUCCEEDED(hr) && fmtvar.vt == VT_BLOB) {
if (fmtvar.blob.cbSize == sizeof(PCMWAVEFORMAT)) {
const PCMWAVEFORMAT * pcm = reinterpret_cast<const PCMWAVEFORMAT *>(fmtvar.blob.pBlobData);
ret->max_rate = ret->min_rate = ret->default_rate = pcm->wf.nSamplesPerSec;
ret->max_channels = pcm->wf.nChannels;
ret.max_rate = ret.min_rate = ret.default_rate = pcm->wf.nSamplesPerSec;
ret.max_channels = pcm->wf.nChannels;
} else if (fmtvar.blob.cbSize >= sizeof(WAVEFORMATEX)) {
WAVEFORMATEX* wfx = reinterpret_cast<WAVEFORMATEX*>(fmtvar.blob.pBlobData);
if (fmtvar.blob.cbSize >= sizeof(WAVEFORMATEX) + wfx->cbSize ||
wfx->wFormatTag == WAVE_FORMAT_PCM) {
ret->max_rate = ret->min_rate = ret->default_rate = wfx->nSamplesPerSec;
ret->max_channels = wfx->nChannels;
ret.max_rate = ret.min_rate = ret.default_rate = wfx->nSamplesPerSec;
ret.max_channels = wfx->nChannels;
}
}
}
if (SUCCEEDED(dev->Activate(__uuidof(IAudioClient), CLSCTX_INPROC_SERVER, NULL, client.receive_vpp())) &&
SUCCEEDED(client->GetDevicePeriod(&def_period, &min_period))) {
ret->latency_lo = hns_to_frames(ret->default_rate, min_period);
ret->latency_hi = hns_to_frames(ret->default_rate, def_period);
ret.latency_lo = hns_to_frames(ret.default_rate, min_period);
ret.latency_hi = hns_to_frames(ret.default_rate, def_period);
} else {
ret->latency_lo = 0;
ret->latency_hi = 0;
ret.latency_lo = 0;
ret.latency_hi = 0;
}
return CUBEB_OK;
@ -2323,11 +2353,11 @@ wasapi_enumerate_devices(cubeb * context, cubeb_device_type type,
LOG("IMMDeviceCollection::GetCount() failed: %lx", hr);
return CUBEB_ERROR;
}
cubeb_device_info * devices =
(cubeb_device_info *) calloc(cc, sizeof(cubeb_device_info));
if (!devices) {
cubeb_device_info * devices = new cubeb_device_info[cc];
if (!devices)
return CUBEB_ERROR;
}
PodZero(devices, cc);
out->count = 0;
for (i = 0; i < cc; i++) {
com_ptr<IMMDevice> dev;
@ -2336,8 +2366,8 @@ wasapi_enumerate_devices(cubeb * context, cubeb_device_type type,
LOG("IMMDeviceCollection::Item(%u) failed: %lx", i-1, hr);
continue;
}
auto cur = &devices[out->count];
if (wasapi_create_device(cur, enumerator.get(), dev.get()) == CUBEB_OK) {
if (wasapi_create_device(context, devices[out->count],
enumerator.get(), dev.get()) == CUBEB_OK) {
out->count += 1;
}
}
@ -2346,6 +2376,21 @@ wasapi_enumerate_devices(cubeb * context, cubeb_device_type type,
return CUBEB_OK;
}
static int
wasapi_device_collection_destroy(cubeb * /*ctx*/, cubeb_device_collection * collection)
{
XASSERT(collection);
for (size_t n = 0; n < collection->count; n++) {
cubeb_device_info& dev = collection->device[n];
delete [] dev.friendly_name;
delete [] dev.group_id;
}
delete [] collection->device;
return CUBEB_OK;
}
cubeb_ops const wasapi_ops = {
/*.init =*/ wasapi_init,
/*.get_backend_id =*/ wasapi_get_backend_id,
@ -2354,7 +2399,7 @@ cubeb_ops const wasapi_ops = {
/*.get_preferred_sample_rate =*/ wasapi_get_preferred_sample_rate,
/*.get_preferred_channel_layout =*/ wasapi_get_preferred_channel_layout,
/*.enumerate_devices =*/ wasapi_enumerate_devices,
/*.device_collection_destroy =*/ cubeb_utils_default_device_collection_destroy,
/*.device_collection_destroy =*/ wasapi_device_collection_destroy,
/*.destroy =*/ wasapi_destroy,
/*.stream_init =*/ wasapi_stream_init,
/*.stream_destroy =*/ wasapi_stream_destroy,

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

@ -19,7 +19,6 @@
#include <math.h>
#include "cubeb/cubeb.h"
#include "cubeb-internal.h"
#include "cubeb_utils.h"
/* This is missing from the MinGW headers. Use a safe fallback. */
#if !defined(MEMORY_ALLOCATION_ALIGNMENT)
@ -1017,6 +1016,26 @@ winmm_enumerate_devices(cubeb * context, cubeb_device_type type,
return CUBEB_OK;
}
static int
winmm_device_collection_destroy(cubeb * ctx,
cubeb_device_collection * collection)
{
uint32_t i;
XASSERT(collection);
(void) ctx;
for (i = 0; i < collection->count; i++) {
free((void *) collection->device[i].device_id);
free((void *) collection->device[i].friendly_name);
free((void *) collection->device[i].group_id);
free((void *) collection->device[i].vendor_name);
}
free(collection->device);
return CUBEB_OK;
}
static struct cubeb_ops const winmm_ops = {
/*.init =*/ winmm_init,
/*.get_backend_id =*/ winmm_get_backend_id,
@ -1025,7 +1044,7 @@ static struct cubeb_ops const winmm_ops = {
/*.get_preferred_sample_rate =*/ winmm_get_preferred_sample_rate,
/*.get_preferred_channel_layout =*/ NULL,
/*.enumerate_devices =*/ winmm_enumerate_devices,
/*.device_collection_destroy =*/ cubeb_utils_default_device_collection_destroy,
/*.device_collection_destroy =*/ winmm_device_collection_destroy,
/*.destroy =*/ winmm_destroy,
/*.stream_init =*/ winmm_stream_init,
/*.stream_destroy =*/ winmm_stream_destroy,

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

@ -13,6 +13,7 @@ SOURCES += [
'cubeb_log.cpp',
'cubeb_mixer.cpp',
'cubeb_panner.cpp',
'cubeb_strings.c',
'cubeb_utils.c'
]

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

@ -30,7 +30,8 @@ cp $1/src/cubeb_resampler_internal.h src
cp $1/src/cubeb_ring_array.h src
cp $1/src/cubeb_ringbuffer.h src
cp $1/src/cubeb_sndio.c src
cp $1/src/cubeb_utils.c src
cp $1/src/cubeb_strings.c src
cp $1/src/cubeb_strings.h src
cp $1/src/cubeb_utils.h src
cp $1/src/cubeb_utils_unix.h src
cp $1/src/cubeb_utils_win.h src