summaryrefslogtreecommitdiffstats
path: root/media/libcubeb/src/cubeb_pulse.c
diff options
context:
space:
mode:
Diffstat (limited to 'media/libcubeb/src/cubeb_pulse.c')
-rw-r--r--media/libcubeb/src/cubeb_pulse.c488
1 files changed, 129 insertions, 359 deletions
diff --git a/media/libcubeb/src/cubeb_pulse.c b/media/libcubeb/src/cubeb_pulse.c
index 846ba426a..4f474452d 100644
--- a/media/libcubeb/src/cubeb_pulse.c
+++ b/media/libcubeb/src/cubeb_pulse.c
@@ -7,14 +7,12 @@
#undef NDEBUG
#include <assert.h>
#include <dlfcn.h>
-#include <pulse/pulseaudio.h>
-#include <stdio.h>
#include <stdlib.h>
+#include <pulse/pulseaudio.h>
#include <string.h>
-#include "cubeb-internal.h"
#include "cubeb/cubeb.h"
-#include "cubeb_mixer.h"
-#include "cubeb_strings.h"
+#include "cubeb-internal.h"
+#include <stdio.h>
#ifdef DISABLE_LIBPULSE_DLOPEN
#define WRAP(x) x
@@ -22,14 +20,13 @@
#define WRAP(x) cubeb_##x
#define LIBPULSE_API_VISIT(X) \
X(pa_channel_map_can_balance) \
- X(pa_channel_map_init) \
+ X(pa_channel_map_init_auto) \
X(pa_context_connect) \
X(pa_context_disconnect) \
X(pa_context_drain) \
X(pa_context_get_server_info) \
X(pa_context_get_sink_info_by_name) \
X(pa_context_get_sink_info_list) \
- X(pa_context_get_sink_input_info) \
X(pa_context_get_source_info_list) \
X(pa_context_get_state) \
X(pa_context_new) \
@@ -84,50 +81,33 @@
X(pa_context_set_subscribe_callback) \
X(pa_context_subscribe) \
X(pa_mainloop_api_once) \
- X(pa_get_library_version) \
- X(pa_channel_map_init_auto) \
#define MAKE_TYPEDEF(x) static typeof(x) * cubeb_##x;
LIBPULSE_API_VISIT(MAKE_TYPEDEF);
#undef MAKE_TYPEDEF
#endif
-#if PA_CHECK_VERSION(2, 0, 0)
-static int has_pulse_v2 = 0;
-#endif
-
static struct cubeb_ops const pulse_ops;
-struct cubeb_default_sink_info {
- pa_channel_map channel_map;
- uint32_t sample_spec_rate;
- pa_sink_flags_t flags;
-};
-
struct cubeb {
struct cubeb_ops const * ops;
void * libpulse;
pa_threaded_mainloop * mainloop;
pa_context * context;
- struct cubeb_default_sink_info * default_sink_info;
+ pa_sink_info * default_sink_info;
char * context_name;
int error;
- cubeb_device_collection_changed_callback output_collection_changed_callback;
- void * output_collection_changed_user_ptr;
- cubeb_device_collection_changed_callback input_collection_changed_callback;
- void * input_collection_changed_user_ptr;
- cubeb_strings * device_ids;
+ cubeb_device_collection_changed_callback collection_changed_callback;
+ void * collection_changed_user_ptr;
};
struct cubeb_stream {
- /* Note: Must match cubeb_stream layout in cubeb.c. */
cubeb * context;
- void * user_ptr;
- /**/
pa_stream * output_stream;
pa_stream * input_stream;
cubeb_data_callback data_callback;
cubeb_state_callback state_callback;
+ void * user_ptr;
pa_time_event * drain_timer;
pa_sample_spec output_sample_spec;
pa_sample_spec input_sample_spec;
@@ -144,24 +124,6 @@ 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)
{
@@ -169,10 +131,8 @@ sink_info_callback(pa_context * context, const pa_sink_info * info, int eol, voi
cubeb * ctx = u;
if (!eol) {
free(ctx->default_sink_info);
- ctx->default_sink_info = malloc(sizeof(struct cubeb_default_sink_info));
- memcpy(&ctx->default_sink_info->channel_map, &info->channel_map, sizeof(pa_channel_map));
- ctx->default_sink_info->sample_spec_rate = info->sample_spec.rate;
- ctx->default_sink_info->flags = info->flags;
+ ctx->default_sink_info = malloc(sizeof(pa_sink_info));
+ memcpy(ctx->default_sink_info, info, sizeof(pa_sink_info));
}
WRAP(pa_threaded_mainloop_signal)(ctx->mainloop, 0);
}
@@ -180,11 +140,7 @@ sink_info_callback(pa_context * context, const pa_sink_info * info, int eol, voi
static void
server_info_callback(pa_context * context, const pa_server_info * info, void * u)
{
- pa_operation * o;
- o = WRAP(pa_context_get_sink_info_by_name)(context, info->default_sink_name, sink_info_callback, u);
- if (o) {
- WRAP(pa_operation_unref)(o);
- }
+ WRAP(pa_context_get_sink_info_by_name)(context, info->default_sink_name, sink_info_callback, u);
}
static void
@@ -511,81 +467,12 @@ stream_update_timing_info(cubeb_stream * stm)
return r;
}
-static pa_channel_position_t
-cubeb_channel_to_pa_channel(cubeb_channel channel)
-{
- switch (channel) {
- case CHANNEL_FRONT_LEFT:
- return PA_CHANNEL_POSITION_FRONT_LEFT;
- case CHANNEL_FRONT_RIGHT:
- return PA_CHANNEL_POSITION_FRONT_RIGHT;
- case CHANNEL_FRONT_CENTER:
- return PA_CHANNEL_POSITION_FRONT_CENTER;
- case CHANNEL_LOW_FREQUENCY:
- return PA_CHANNEL_POSITION_LFE;
- case CHANNEL_BACK_LEFT:
- return PA_CHANNEL_POSITION_REAR_LEFT;
- case CHANNEL_BACK_RIGHT:
- return PA_CHANNEL_POSITION_REAR_RIGHT;
- case CHANNEL_FRONT_LEFT_OF_CENTER:
- return PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER;
- case CHANNEL_FRONT_RIGHT_OF_CENTER:
- return PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER;
- case CHANNEL_BACK_CENTER:
- return PA_CHANNEL_POSITION_REAR_CENTER;
- case CHANNEL_SIDE_LEFT:
- return PA_CHANNEL_POSITION_SIDE_LEFT;
- case CHANNEL_SIDE_RIGHT:
- return PA_CHANNEL_POSITION_SIDE_RIGHT;
- case CHANNEL_TOP_CENTER:
- return PA_CHANNEL_POSITION_TOP_CENTER;
- case CHANNEL_TOP_FRONT_LEFT:
- return PA_CHANNEL_POSITION_TOP_FRONT_LEFT;
- case CHANNEL_TOP_FRONT_CENTER:
- return PA_CHANNEL_POSITION_TOP_FRONT_CENTER;
- case CHANNEL_TOP_FRONT_RIGHT:
- return PA_CHANNEL_POSITION_TOP_FRONT_RIGHT;
- case CHANNEL_TOP_BACK_LEFT:
- return PA_CHANNEL_POSITION_TOP_REAR_LEFT;
- case CHANNEL_TOP_BACK_CENTER:
- return PA_CHANNEL_POSITION_TOP_REAR_CENTER;
- case CHANNEL_TOP_BACK_RIGHT:
- return PA_CHANNEL_POSITION_TOP_REAR_RIGHT;
- default:
- return PA_CHANNEL_POSITION_INVALID;
- }
-}
-
-static void
-layout_to_channel_map(cubeb_channel_layout layout, pa_channel_map * cm)
-{
- assert(cm && layout != CUBEB_LAYOUT_UNDEFINED);
-
- WRAP(pa_channel_map_init)(cm);
-
- uint32_t channels = 0;
- cubeb_channel_layout channelMap = layout;
- for (uint32_t i = 0 ; channelMap != 0; ++i) {
- uint32_t channel = (channelMap & 1) << i;
- if (channel != 0) {
- cm->map[channels] = cubeb_channel_to_pa_channel(channel);
- channels++;
- }
- channelMap = channelMap >> 1;
- }
- unsigned int channels_from_layout = cubeb_channel_layout_nb_channels(layout);
- assert(channels_from_layout <= UINT8_MAX);
- cm->channels = (uint8_t) channels_from_layout;
-}
-
static void pulse_context_destroy(cubeb * ctx);
static void pulse_destroy(cubeb * ctx);
static int
pulse_context_init(cubeb * ctx)
{
- int r;
-
if (ctx->context) {
assert(ctx->error == 1);
pulse_context_destroy(ctx);
@@ -599,9 +486,9 @@ pulse_context_init(cubeb * ctx)
WRAP(pa_context_set_state_callback)(ctx->context, context_state_callback, ctx);
WRAP(pa_threaded_mainloop_lock)(ctx->mainloop);
- r = WRAP(pa_context_connect)(ctx->context, NULL, 0, NULL);
+ WRAP(pa_context_connect)(ctx->context, NULL, 0, NULL);
- if (r < 0 || wait_until_context_ready(ctx) != 0) {
+ if (wait_until_context_ready(ctx) != 0) {
WRAP(pa_threaded_mainloop_unlock)(ctx->mainloop);
pulse_context_destroy(ctx);
ctx->context = NULL;
@@ -615,25 +502,18 @@ pulse_context_init(cubeb * ctx)
return 0;
}
-static int pulse_subscribe_notifications(cubeb * context,
- pa_subscription_mask_t mask);
-
/*static*/ int
pulse_init(cubeb ** context, char const * context_name)
{
void * libpulse = NULL;
cubeb * ctx;
- pa_operation * o;
*context = NULL;
#ifndef DISABLE_LIBPULSE_DLOPEN
libpulse = dlopen("libpulse.so.0", RTLD_LAZY);
if (!libpulse) {
- libpulse = dlopen("libpulse.so", RTLD_LAZY);
- if (!libpulse) {
- return CUBEB_ERROR;
- }
+ return CUBEB_ERROR;
}
#define LOAD(x) { \
@@ -648,20 +528,11 @@ pulse_init(cubeb ** context, char const * context_name)
#undef LOAD
#endif
-#if PA_CHECK_VERSION(2, 0, 0)
- const char* version = WRAP(pa_get_library_version)();
- has_pulse_v2 = strtol(version, NULL, 10) >= 2;
-#endif
-
ctx = calloc(1, sizeof(*ctx));
assert(ctx);
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;
@@ -674,20 +545,10 @@ pulse_init(cubeb ** context, char const * context_name)
return CUBEB_ERROR;
}
- /* server_info_callback performs a second async query, which is
- responsible for initializing default_sink_info and signalling the
- mainloop to end the wait. */
WRAP(pa_threaded_mainloop_lock)(ctx->mainloop);
- o = WRAP(pa_context_get_server_info)(ctx->context, server_info_callback, ctx);
- if (o) {
- operation_wait(ctx, NULL, o);
- WRAP(pa_operation_unref)(o);
- }
+ WRAP(pa_context_get_server_info)(ctx->context, server_info_callback, ctx);
WRAP(pa_threaded_mainloop_unlock)(ctx->mainloop);
- /* Update `default_sink_info` when the default device changes. */
- pulse_subscribe_notifications(ctx, PA_SUBSCRIPTION_MASK_SERVER);
-
*context = ctx;
return CUBEB_OK;
@@ -706,8 +567,11 @@ pulse_get_max_channel_count(cubeb * ctx, uint32_t * max_channels)
(void)ctx;
assert(ctx && max_channels);
- if (!ctx->default_sink_info)
- return CUBEB_ERROR;
+ WRAP(pa_threaded_mainloop_lock)(ctx->mainloop);
+ while (!ctx->default_sink_info) {
+ WRAP(pa_threaded_mainloop_wait)(ctx->mainloop);
+ }
+ WRAP(pa_threaded_mainloop_unlock)(ctx->mainloop);
*max_channels = ctx->default_sink_info->channel_map.channels;
@@ -720,10 +584,13 @@ pulse_get_preferred_sample_rate(cubeb * ctx, uint32_t * rate)
assert(ctx && rate);
(void)ctx;
- if (!ctx->default_sink_info)
- return CUBEB_ERROR;
+ WRAP(pa_threaded_mainloop_lock)(ctx->mainloop);
+ while (!ctx->default_sink_info) {
+ WRAP(pa_threaded_mainloop_wait)(ctx->mainloop);
+ }
+ WRAP(pa_threaded_mainloop_unlock)(ctx->mainloop);
- *rate = ctx->default_sink_info->sample_spec_rate;
+ *rate = ctx->default_sink_info->sample_spec.rate;
return CUBEB_OK;
}
@@ -758,7 +625,9 @@ pulse_context_destroy(cubeb * ctx)
static void
pulse_destroy(cubeb * ctx)
{
- free(ctx->context_name);
+ if (ctx->context_name) {
+ free(ctx->context_name);
+ }
if (ctx->context) {
pulse_context_destroy(ctx);
}
@@ -768,14 +637,12 @@ 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);
}
- free(ctx->default_sink_info);
+ if (ctx->default_sink_info) {
+ free(ctx->default_sink_info);
+ }
free(ctx);
}
@@ -798,25 +665,6 @@ to_pulse_format(cubeb_sample_format format)
}
}
-static cubeb_channel_layout
-pulse_default_layout_for_channels(uint32_t ch)
-{
- assert (ch > 0 && ch <= 8);
- switch (ch) {
- case 1: return CUBEB_LAYOUT_MONO;
- case 2: return CUBEB_LAYOUT_STEREO;
- case 3: return CUBEB_LAYOUT_3F;
- case 4: return CUBEB_LAYOUT_QUAD;
- case 5: return CUBEB_LAYOUT_3F2;
- case 6: return CUBEB_LAYOUT_3F_LFE |
- CHANNEL_SIDE_LEFT | CHANNEL_SIDE_RIGHT;
- case 7: return CUBEB_LAYOUT_3F3R_LFE;
- case 8: return CUBEB_LAYOUT_3F4_LFE;
- }
- // Never get here!
- return CUBEB_LAYOUT_UNDEFINED;
-}
-
static int
create_pa_stream(cubeb_stream * stm,
pa_stream ** pa_stm,
@@ -824,39 +672,15 @@ create_pa_stream(cubeb_stream * stm,
char const * stream_name)
{
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_nb_channels(stream_params->layout) == stream_params->channels))));
- if (stream_params->prefs & CUBEB_STREAM_PREF_LOOPBACK) {
- return CUBEB_ERROR_NOT_SUPPORTED;
- }
*pa_stm = NULL;
pa_sample_spec ss;
ss.format = to_pulse_format(stream_params->format);
if (ss.format == PA_SAMPLE_INVALID)
return CUBEB_ERROR_INVALID_FORMAT;
ss.rate = stream_params->rate;
- if (stream_params->channels > UINT8_MAX)
- return CUBEB_ERROR_INVALID_FORMAT;
- ss.channels = (uint8_t) stream_params->channels;
-
- if (stream_params->layout == CUBEB_LAYOUT_UNDEFINED) {
- pa_channel_map cm;
- if (stream_params->channels <= 8 &&
- !WRAP(pa_channel_map_init_auto)(&cm, stream_params->channels, PA_CHANNEL_MAP_DEFAULT)) {
- LOG("Layout undefined and PulseAudio's default layout has not been configured, guess one.");
- layout_to_channel_map(pulse_default_layout_for_channels(stream_params->channels), &cm);
- *pa_stm = WRAP(pa_stream_new)(stm->context->context, stream_name, &ss, &cm);
- } else {
- LOG("Layout undefined, PulseAudio will use its default.");
- *pa_stm = WRAP(pa_stream_new)(stm->context->context, stream_name, &ss, NULL);
- }
- } else {
- pa_channel_map cm;
- layout_to_channel_map(stream_params->layout, &cm);
- *pa_stm = WRAP(pa_stream_new)(stm->context->context, stream_name, &ss, &cm);
- }
+ ss.channels = stream_params->channels;
+
+ *pa_stm = WRAP(pa_stream_new)(stm->context->context, stream_name, &ss, NULL);
return (*pa_stm == NULL) ? CUBEB_ERROR : CUBEB_OK;
}
@@ -929,7 +753,7 @@ pulse_stream_init(cubeb * context,
battr = set_buffering_attribute(latency_frames, &stm->output_sample_spec);
WRAP(pa_stream_connect_playback)(stm->output_stream,
- (char const *) output_device,
+ output_device,
&battr,
PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_INTERPOLATE_TIMING |
PA_STREAM_START_CORKED | PA_STREAM_ADJUST_LATENCY,
@@ -952,7 +776,7 @@ pulse_stream_init(cubeb * context,
battr = set_buffering_attribute(latency_frames, &stm->input_sample_spec);
WRAP(pa_stream_connect_record)(stm->input_stream,
- (char const *) input_device,
+ input_device,
&battr,
PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_INTERPOLATE_TIMING |
PA_STREAM_START_CORKED | PA_STREAM_ADJUST_LATENCY);
@@ -972,7 +796,7 @@ pulse_stream_init(cubeb * context,
return CUBEB_ERROR;
}
- if (g_cubeb_log_level) {
+ if (g_log_level) {
if (output_stream_params){
const pa_buffer_attr * output_att;
output_att = WRAP(pa_stream_get_buffer_attr)(stm->output_stream);
@@ -989,7 +813,6 @@ pulse_stream_init(cubeb * context,
}
*stream = stm;
- LOG("Cubeb stream (%p) init successful.", *stream);
return CUBEB_OK;
}
@@ -1021,7 +844,6 @@ pulse_stream_destroy(cubeb_stream * stm)
}
WRAP(pa_threaded_mainloop_unlock)(stm->context->mainloop);
- LOG("Cubeb stream (%p) destroyed successfully.", stm);
free(stm);
}
@@ -1053,7 +875,6 @@ pulse_stream_start(cubeb_stream * stm)
WRAP(pa_threaded_mainloop_unlock)(stm->context->mainloop);
}
- LOG("Cubeb stream (%p) started successfully.", stm);
return CUBEB_OK;
}
@@ -1069,7 +890,6 @@ pulse_stream_stop(cubeb_stream * stm)
WRAP(pa_threaded_mainloop_unlock)(stm->context->mainloop);
stream_cork(stm, CORK | NOTIFY);
- LOG("Cubeb stream (%p) stopped successfully.", stm);
return CUBEB_OK;
}
@@ -1142,7 +962,6 @@ pulse_stream_set_volume(cubeb_stream * stm, float volume)
pa_volume_t vol;
pa_cvolume cvol;
const pa_sample_spec * ss;
- cubeb * ctx;
if (!stm->output_stream) {
return CUBEB_ERROR;
@@ -1150,11 +969,13 @@ pulse_stream_set_volume(cubeb_stream * stm, float volume)
WRAP(pa_threaded_mainloop_lock)(stm->context->mainloop);
+ while (!stm->context->default_sink_info) {
+ WRAP(pa_threaded_mainloop_wait)(stm->context->mainloop);
+ }
+
/* if the pulse daemon is configured to use flat volumes,
* apply our own gain instead of changing the input volume on the sink. */
- ctx = stm->context;
- if (ctx->default_sink_info &&
- (ctx->default_sink_info->flags & PA_SINK_FLAT_VOLUME)) {
+ if (stm->context->default_sink_info->flags & PA_SINK_FLAT_VOLUME) {
stm->volume = volume;
} else {
ss = WRAP(pa_stream_get_sample_spec)(stm->output_stream);
@@ -1164,40 +985,46 @@ pulse_stream_set_volume(cubeb_stream * stm, float volume)
index = WRAP(pa_stream_get_index)(stm->output_stream);
- op = WRAP(pa_context_set_sink_input_volume)(ctx->context,
+ op = WRAP(pa_context_set_sink_input_volume)(stm->context->context,
index, &cvol, volume_success,
stm);
if (op) {
- operation_wait(ctx, stm->output_stream, op);
+ operation_wait(stm->context, stm->output_stream, op);
WRAP(pa_operation_unref)(op);
}
}
- WRAP(pa_threaded_mainloop_unlock)(ctx->mainloop);
+ WRAP(pa_threaded_mainloop_unlock)(stm->context->mainloop);
return CUBEB_OK;
}
-struct sink_input_info_result {
- pa_cvolume * cvol;
- pa_threaded_mainloop * mainloop;
-};
-
-static void
-sink_input_info_cb(pa_context * c, pa_sink_input_info const * i, int eol, void * u)
+static int
+pulse_stream_set_panning(cubeb_stream * stream, float panning)
{
- struct sink_input_info_result * r = u;
- if (!eol) {
- *r->cvol = i->volume;
+ const pa_channel_map * map;
+ pa_cvolume vol;
+
+ if (!stream->output_stream) {
+ return CUBEB_ERROR;
}
- WRAP(pa_threaded_mainloop_signal)(r->mainloop, 0);
+
+ map = WRAP(pa_stream_get_channel_map)(stream->output_stream);
+
+ if (!WRAP(pa_channel_map_can_balance)(map)) {
+ return CUBEB_ERROR;
+ }
+
+ WRAP(pa_cvolume_set_balance)(&vol, map, panning);
+
+ return CUBEB_OK;
}
typedef struct {
char * default_sink_name;
char * default_source_name;
- cubeb_device_info * devinfo;
+ cubeb_device_info ** devinfo;
uint32_t max;
uint32_t count;
cubeb * context;
@@ -1226,7 +1053,7 @@ pulse_ensure_dev_list_data_list_size (pulse_dev_list_data * list_data)
if (list_data->count == list_data->max) {
list_data->max += 8;
list_data->devinfo = realloc(list_data->devinfo,
- sizeof(cubeb_device_info) * list_data->max);
+ sizeof(cubeb_device_info *) * list_data->max);
}
}
@@ -1235,47 +1062,33 @@ pulse_get_state_from_sink_port(pa_sink_port_info * info)
{
if (info != NULL) {
#if PA_CHECK_VERSION(2, 0, 0)
- if (has_pulse_v2 && info->available == PA_PORT_AVAILABLE_NO)
+ if (info->available == PA_PORT_AVAILABLE_NO)
return CUBEB_DEVICE_STATE_UNPLUGGED;
else /*if (info->available == PA_PORT_AVAILABLE_YES) + UNKNOWN */
#endif
return CUBEB_DEVICE_STATE_ENABLED;
}
- return CUBEB_DEVICE_STATE_ENABLED;
+ return CUBEB_DEVICE_STATE_DISABLED;
}
static void
pulse_sink_info_cb(pa_context * context, const pa_sink_info * info,
- int eol, void * user_data)
+ int eol, void * user_data)
{
pulse_dev_list_data * list_data = user_data;
cubeb_device_info * devinfo;
- char const * prop = NULL;
- char const * device_id = NULL;
+ const char * prop;
(void)context;
- if (eol) {
- WRAP(pa_threaded_mainloop_signal)(list_data->context->mainloop, 0);
- return;
- }
-
- if (info == NULL)
+ if (eol || info == NULL)
return;
- device_id = info->name;
- if (intern_device_id(list_data->context, &device_id) != CUBEB_OK) {
- assert(NULL);
- 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 = calloc(1, sizeof(cubeb_device_info));
- devinfo->device_id = device_id;
- devinfo->devid = (cubeb_devid) devinfo->device_id;
+ devinfo->device_id = strdup(info->name);
+ devinfo->devid = devinfo->device_id;
devinfo->friendly_name = strdup(info->description);
prop = WRAP(pa_proplist_gets)(info->proplist, "sysfs.path");
if (prop)
@@ -1286,8 +1099,7 @@ pulse_sink_info_cb(pa_context * context, const pa_sink_info * info,
devinfo->type = CUBEB_DEVICE_TYPE_OUTPUT;
devinfo->state = pulse_get_state_from_sink_port(info->active_port);
- devinfo->preferred = (strcmp(info->name, list_data->default_sink_name) == 0) ?
- CUBEB_DEVICE_PREF_ALL : CUBEB_DEVICE_PREF_NONE;
+ devinfo->preferred = strcmp(info->name, list_data->default_sink_name) == 0;
devinfo->format = CUBEB_DEVICE_FMT_ALL;
devinfo->default_format = pulse_format_to_cubeb_format(info->sample_spec.format);
@@ -1299,7 +1111,10 @@ pulse_sink_info_cb(pa_context * context, const pa_sink_info * info,
devinfo->latency_lo = 0;
devinfo->latency_hi = 0;
- list_data->count += 1;
+ pulse_ensure_dev_list_data_list_size (list_data);
+ list_data->devinfo[list_data->count++] = devinfo;
+
+ WRAP(pa_threaded_mainloop_signal)(list_data->context->mainloop, 0);
}
static cubeb_device_state
@@ -1307,14 +1122,14 @@ pulse_get_state_from_source_port(pa_source_port_info * info)
{
if (info != NULL) {
#if PA_CHECK_VERSION(2, 0, 0)
- if (has_pulse_v2 && info->available == PA_PORT_AVAILABLE_NO)
+ if (info->available == PA_PORT_AVAILABLE_NO)
return CUBEB_DEVICE_STATE_UNPLUGGED;
else /*if (info->available == PA_PORT_AVAILABLE_YES) + UNKNOWN */
#endif
return CUBEB_DEVICE_STATE_ENABLED;
}
- return CUBEB_DEVICE_STATE_ENABLED;
+ return CUBEB_DEVICE_STATE_DISABLED;
}
static void
@@ -1323,28 +1138,17 @@ pulse_source_info_cb(pa_context * context, const pa_source_info * info,
{
pulse_dev_list_data * list_data = user_data;
cubeb_device_info * devinfo;
- char const * prop = NULL;
- char const * device_id = NULL;
+ const char * prop;
(void)context;
- if (eol) {
- WRAP(pa_threaded_mainloop_signal)(list_data->context->mainloop, 0);
- return;
- }
-
- device_id = info->name;
- if (intern_device_id(list_data->context, &device_id) != CUBEB_OK) {
- assert(NULL);
+ if (eol)
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 = calloc(1, sizeof(cubeb_device_info));
- devinfo->device_id = device_id;
- devinfo->devid = (cubeb_devid) devinfo->device_id;
+ devinfo->device_id = strdup(info->name);
+ devinfo->devid = devinfo->device_id;
devinfo->friendly_name = strdup(info->description);
prop = WRAP(pa_proplist_gets)(info->proplist, "sysfs.path");
if (prop)
@@ -1355,8 +1159,7 @@ pulse_source_info_cb(pa_context * context, const pa_source_info * info,
devinfo->type = CUBEB_DEVICE_TYPE_INPUT;
devinfo->state = pulse_get_state_from_source_port(info->active_port);
- devinfo->preferred = (strcmp(info->name, list_data->default_source_name) == 0) ?
- CUBEB_DEVICE_PREF_ALL : CUBEB_DEVICE_PREF_NONE;
+ devinfo->preferred = strcmp(info->name, list_data->default_source_name) == 0;
devinfo->format = CUBEB_DEVICE_FMT_ALL;
devinfo->default_format = pulse_format_to_cubeb_format(info->sample_spec.format);
@@ -1368,7 +1171,10 @@ pulse_source_info_cb(pa_context * context, const pa_source_info * info,
devinfo->latency_lo = 0;
devinfo->latency_hi = 0;
- list_data->count += 1;
+ pulse_ensure_dev_list_data_list_size (list_data);
+ list_data->devinfo[list_data->count++] = devinfo;
+
+ WRAP(pa_threaded_mainloop_signal)(list_data->context->mainloop, 0);
}
static void
@@ -1380,20 +1186,19 @@ pulse_server_info_cb(pa_context * c, const pa_server_info * i, void * userdata)
free(list_data->default_sink_name);
free(list_data->default_source_name);
- list_data->default_sink_name =
- i->default_sink_name ? strdup(i->default_sink_name) : NULL;
- list_data->default_source_name =
- i->default_source_name ? strdup(i->default_source_name) : NULL;
+ list_data->default_sink_name = strdup(i->default_sink_name);
+ list_data->default_source_name = strdup(i->default_source_name);
WRAP(pa_threaded_mainloop_signal)(list_data->context->mainloop, 0);
}
static int
pulse_enumerate_devices(cubeb * context, cubeb_device_type type,
- cubeb_device_collection * collection)
+ cubeb_device_collection ** collection)
{
pulse_dev_list_data user_data = { NULL, NULL, NULL, 0, 0, context };
pa_operation * o;
+ uint32_t i;
WRAP(pa_threaded_mainloop_lock)(context->mainloop);
@@ -1424,26 +1229,15 @@ pulse_enumerate_devices(cubeb * context, cubeb_device_type type,
WRAP(pa_threaded_mainloop_unlock)(context->mainloop);
- collection->device = user_data.devinfo;
- collection->count = user_data.count;
+ *collection = malloc(sizeof(cubeb_device_collection) +
+ sizeof(cubeb_device_info *) * (user_data.count > 0 ? user_data.count - 1 : 0));
+ (*collection)->count = user_data.count;
+ for (i = 0; i < user_data.count; i++)
+ (*collection)->device[i] = user_data.devinfo[i];
free(user_data.default_sink_name);
free(user_data.default_source_name);
- 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);
+ free(user_data.devinfo);
return CUBEB_OK;
}
@@ -1491,40 +1285,29 @@ pulse_subscribe_callback(pa_context * ctx,
cubeb * context = userdata;
switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) {
- case PA_SUBSCRIPTION_EVENT_SERVER:
- if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_CHANGE) {
- LOG("Server changed %d", index);
- WRAP(pa_context_get_server_info)(context->context, server_info_callback, context);
- }
- break;
case PA_SUBSCRIPTION_EVENT_SOURCE:
case PA_SUBSCRIPTION_EVENT_SINK:
- if (g_cubeb_log_level) {
+ if (g_log_level) {
if ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE &&
(t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
- LOG("Removing source index %d", index);
+ LOG("Removing sink index %d", index);
} else if ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE &&
(t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) {
- LOG("Adding source index %d", index);
+ LOG("Adding sink index %d", index);
}
if ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK &&
(t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
- LOG("Removing sink index %d", index);
+ LOG("Removing source index %d", index);
} else if ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK &&
(t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) {
- LOG("Adding sink index %d", index);
+ LOG("Adding source index %d", index);
}
}
if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE ||
(t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) {
- if ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE) {
- context->input_collection_changed_callback(context, context->input_collection_changed_user_ptr);
- }
- if ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK) {
- context->output_collection_changed_callback(context, context->output_collection_changed_user_ptr);
- }
+ context->collection_changed_callback(context, context->collection_changed_user_ptr);
}
break;
}
@@ -1540,15 +1323,34 @@ subscribe_success(pa_context *c, int success, void *userdata)
}
static int
-pulse_subscribe_notifications(cubeb * context, pa_subscription_mask_t mask) {
+pulse_register_device_collection_changed(cubeb * context,
+ cubeb_device_type devtype,
+ cubeb_device_collection_changed_callback collection_changed_callback,
+ void * user_ptr)
+{
+ context->collection_changed_callback = collection_changed_callback;
+ context->collection_changed_user_ptr = user_ptr;
+
WRAP(pa_threaded_mainloop_lock)(context->mainloop);
- WRAP(pa_context_set_subscribe_callback)(context->context, pulse_subscribe_callback, context);
+ pa_subscription_mask_t mask;
+ if (context->collection_changed_callback == NULL) {
+ // Unregister subscription
+ WRAP(pa_context_set_subscribe_callback)(context->context, NULL, NULL);
+ mask = PA_SUBSCRIPTION_MASK_NULL;
+ } else {
+ WRAP(pa_context_set_subscribe_callback)(context->context, pulse_subscribe_callback, context);
+ if (devtype == CUBEB_DEVICE_TYPE_INPUT)
+ mask = PA_SUBSCRIPTION_MASK_SOURCE;
+ else if (devtype == CUBEB_DEVICE_TYPE_OUTPUT)
+ mask = PA_SUBSCRIPTION_MASK_SINK;
+ else
+ mask = PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE;
+ }
pa_operation * o;
o = WRAP(pa_context_subscribe)(context->context, mask, subscribe_success, context);
if (o == NULL) {
- WRAP(pa_threaded_mainloop_unlock)(context->mainloop);
LOG("Context subscribe failed");
return CUBEB_ERROR;
}
@@ -1560,37 +1362,6 @@ pulse_subscribe_notifications(cubeb * context, pa_subscription_mask_t mask) {
return CUBEB_OK;
}
-static int
-pulse_register_device_collection_changed(cubeb * context,
- cubeb_device_type devtype,
- cubeb_device_collection_changed_callback collection_changed_callback,
- void * user_ptr)
-{
- if (devtype & CUBEB_DEVICE_TYPE_INPUT) {
- context->input_collection_changed_callback = collection_changed_callback;
- context->input_collection_changed_user_ptr = user_ptr;
- }
- if (devtype & CUBEB_DEVICE_TYPE_OUTPUT) {
- context->output_collection_changed_callback = collection_changed_callback;
- context->output_collection_changed_user_ptr = user_ptr;
- }
-
- pa_subscription_mask_t mask = PA_SUBSCRIPTION_MASK_NULL;
- if (context->input_collection_changed_callback) {
- /* Input added or removed */
- mask |= PA_SUBSCRIPTION_MASK_SOURCE;
- }
- if (context->output_collection_changed_callback) {
- /* Output added or removed */
- mask |= PA_SUBSCRIPTION_MASK_SINK;
- }
- /* Default device changed, this is always registered in order to update the
- * `default_sink_info` when the default device changes. */
- mask |= PA_SUBSCRIPTION_MASK_SERVER;
-
- return pulse_subscribe_notifications(context, mask);
-}
-
static struct cubeb_ops const pulse_ops = {
.init = pulse_init,
.get_backend_id = pulse_get_backend_id,
@@ -1598,16 +1369,15 @@ static struct cubeb_ops const pulse_ops = {
.get_min_latency = pulse_get_min_latency,
.get_preferred_sample_rate = pulse_get_preferred_sample_rate,
.enumerate_devices = pulse_enumerate_devices,
- .device_collection_destroy = pulse_device_collection_destroy,
.destroy = pulse_destroy,
.stream_init = pulse_stream_init,
.stream_destroy = pulse_stream_destroy,
.stream_start = pulse_stream_start,
.stream_stop = pulse_stream_stop,
- .stream_reset_default_device = NULL,
.stream_get_position = pulse_stream_get_position,
.stream_get_latency = pulse_stream_get_latency,
.stream_set_volume = pulse_stream_set_volume,
+ .stream_set_panning = pulse_stream_set_panning,
.stream_get_current_device = pulse_stream_get_current_device,
.stream_device_destroy = pulse_stream_device_destroy,
.stream_register_device_changed_callback = NULL,