aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/cubeb_pulse.c
diff options
context:
space:
mode:
authorJean-Yves Avenard <[email protected]>2018-03-19 14:57:07 +0100
committerPaul Adenot <[email protected]>2018-03-19 14:57:07 +0100
commit789eaaa3b0d77b55e110353972d6713889f510ea (patch)
treefbeb48958ab83c329193f37c54133c9bc68aac4a /src/cubeb_pulse.c
parentc88a484e1aac878419946334c49d35d6948beec7 (diff)
downloadcubeb-789eaaa3b0d77b55e110353972d6713889f510ea.tar.gz
cubeb-789eaaa3b0d77b55e110353972d6713889f510ea.zip
Multi-channels support for windows/mac/linux (#426)
* Add QUAD and QUAD_LFE layouts. * Remove dual mono layout. It makes no sense to have a case for those as the data structure used (a bitmask) do not allow to represent this channel layout (a channel can only be present once). As such it was a non-functional layout * Fix up cubeb_pulse compilation using C++ keyword. * Remove the concept of preferred layout. Channel layout is derived by the content being played. The concept of preferred layout is meaningless. Either we have a layout defined, or we don't. There's no in-between. So we remove it. * Remove CHANNEL_MONO concept. * Add cubeb_sample_size convenience method. * Rework cubeb_mixer. This completely replace the existing remixer which had serious limitations: 1- Had no memory bound checks 2- Could only downmix 5.1 and 7.1 to stereo. This mixer allows to convert from any sane layout to any other and work directly on interleaved samples. This cubeb_mixer doesn't have an API compatible with the previous one. This commit is non-fonctional, and was split for ease of review. * Fix remixing on mac, windows and pulse backend. * Make cubeb_mixer creation infallible. Rather than ignore nonsensical layouts, we attempt to play it according to the stream channels count instead. The audio data will be played as-is, dropping the extra channels or inserting silence where needed. * User proper sample size when calculating offsets. Should the user data be of a different type to what the AudioUnit output is set to, we would have written outside the end of our allocated buffer. * Fix input mixing and clarify frames vs samples terminology * If a layout is unknown or invalid, always treat it as plain stereo or mono.
Diffstat (limited to 'src/cubeb_pulse.c')
-rw-r--r--src/cubeb_pulse.c127
1 files changed, 55 insertions, 72 deletions
diff --git a/src/cubeb_pulse.c b/src/cubeb_pulse.c
index 1cac5ea..079fd69 100644
--- a/src/cubeb_pulse.c
+++ b/src/cubeb_pulse.c
@@ -7,14 +7,14 @@
#undef NDEBUG
#include <assert.h>
#include <dlfcn.h>
-#include <stdlib.h>
#include <pulse/pulseaudio.h>
+#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
-#include "cubeb/cubeb.h"
#include "cubeb-internal.h"
+#include "cubeb/cubeb.h"
#include "cubeb_mixer.h"
#include "cubeb_strings.h"
-#include <stdio.h>
#ifdef DISABLE_LIBPULSE_DLOPEN
#define WRAP(x) x
@@ -511,44 +511,45 @@ stream_update_timing_info(cubeb_stream * stm)
static pa_channel_position_t
cubeb_channel_to_pa_channel(cubeb_channel channel)
{
- assert(channel != CHANNEL_INVALID);
-
- // This variable may be used for multiple times, so we should avoid to
- // 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 pa_channel_position_t map[CHANNEL_MAX] = {
- // PA_CHANNEL_POSITION_INVALID, // CHANNEL_INVALID
- PA_CHANNEL_POSITION_MONO, // CHANNEL_MONO
- PA_CHANNEL_POSITION_FRONT_LEFT, // CHANNEL_LEFT
- PA_CHANNEL_POSITION_FRONT_RIGHT, // CHANNEL_RIGHT
- PA_CHANNEL_POSITION_FRONT_CENTER, // CHANNEL_CENTER
- PA_CHANNEL_POSITION_SIDE_LEFT, // CHANNEL_LS
- PA_CHANNEL_POSITION_SIDE_RIGHT, // CHANNEL_RS
- PA_CHANNEL_POSITION_REAR_LEFT, // CHANNEL_RLS
- PA_CHANNEL_POSITION_REAR_CENTER, // CHANNEL_RCENTER
- PA_CHANNEL_POSITION_REAR_RIGHT, // CHANNEL_RRS
- PA_CHANNEL_POSITION_LFE // CHANNEL_LFE
- };
-
- return map[channel];
-}
-
-static cubeb_channel
-pa_channel_to_cubeb_channel(pa_channel_position_t channel)
-{
- assert(channel != PA_CHANNEL_POSITION_INVALID);
- switch(channel) {
- case PA_CHANNEL_POSITION_MONO: return CHANNEL_MONO;
- case PA_CHANNEL_POSITION_FRONT_LEFT: return CHANNEL_LEFT;
- case PA_CHANNEL_POSITION_FRONT_RIGHT: return CHANNEL_RIGHT;
- case PA_CHANNEL_POSITION_FRONT_CENTER: return CHANNEL_CENTER;
- case PA_CHANNEL_POSITION_SIDE_LEFT: return CHANNEL_LS;
- case PA_CHANNEL_POSITION_SIDE_RIGHT: return CHANNEL_RS;
- case PA_CHANNEL_POSITION_REAR_LEFT: return CHANNEL_RLS;
- case PA_CHANNEL_POSITION_REAR_CENTER: return CHANNEL_RCENTER;
- case PA_CHANNEL_POSITION_REAR_RIGHT: return CHANNEL_RRS;
- case PA_CHANNEL_POSITION_LFE: return CHANNEL_LFE;
- default: return CHANNEL_INVALID;
+ 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;
}
}
@@ -558,21 +559,18 @@ layout_to_channel_map(cubeb_channel_layout layout, pa_channel_map * cm)
assert(cm && layout != CUBEB_LAYOUT_UNDEFINED);
WRAP(pa_channel_map_init)(cm);
- cm->channels = CUBEB_CHANNEL_LAYOUT_MAPS[layout].channels;
- for (uint8_t i = 0 ; i < cm->channels ; ++i) {
- cm->map[i] = cubeb_channel_to_pa_channel(CHANNEL_INDEX_TO_ORDER[layout][i]);
- }
-}
-static cubeb_channel_layout
-channel_map_to_layout(pa_channel_map * cm)
-{
- cubeb_channel_map cubeb_map;
- cubeb_map.channels = cm->channels;
- for (uint32_t i = 0 ; i < cm->channels ; ++i) {
- cubeb_map.map[i] = pa_channel_to_cubeb_channel(cm->map[i]);
+ 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;
}
- return cubeb_channel_map_to_layout(&cubeb_map);
+ cm->channels = cubeb_channel_layout_nb_channels(layout);
}
static void pulse_context_destroy(cubeb * ctx);
@@ -715,20 +713,6 @@ pulse_get_preferred_sample_rate(cubeb * ctx, uint32_t * rate)
}
static int
-pulse_get_preferred_channel_layout(cubeb * ctx, cubeb_channel_layout * layout)
-{
- assert(ctx && layout);
- (void)ctx;
-
- if (!ctx->default_sink_info)
- return CUBEB_ERROR;
-
- *layout = channel_map_to_layout(&ctx->default_sink_info->channel_map);
-
- return CUBEB_OK;
-}
-
-static int
pulse_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * latency_frames)
{
(void)ctx;
@@ -808,7 +792,7 @@ create_pa_stream(cubeb_stream * stm,
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))));
+ cubeb_channel_layout_nb_channels(stream_params->layout) == stream_params->channels))));
if (stream_params->prefs & CUBEB_STREAM_PREF_LOOPBACK) {
return CUBEB_ERROR_NOT_SUPPORTED;
}
@@ -1279,7 +1263,7 @@ pulse_sink_info_cb(pa_context * context, const pa_sink_info * info,
device_id = info->name;
if (intern_device_id(list_data->context, &device_id) != CUBEB_OK) {
- assert(false);
+ assert(NULL);
return;
}
@@ -1348,7 +1332,7 @@ pulse_source_info_cb(pa_context * context, const pa_source_info * info,
device_id = info->name;
if (intern_device_id(list_data->context, &device_id) != CUBEB_OK) {
- assert(false);
+ assert(NULL);
return;
}
@@ -1588,7 +1572,6 @@ static struct cubeb_ops const pulse_ops = {
.get_max_channel_count = pulse_get_max_channel_count,
.get_min_latency = pulse_get_min_latency,
.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 = pulse_device_collection_destroy,
.destroy = pulse_destroy,