pulse: Port to the new multichannel caps

This commit is contained in:
Sebastian Dröge 2012-01-04 10:27:09 +01:00
parent d239f10888
commit dc049d1f1f
3 changed files with 116 additions and 111 deletions

View file

@ -101,13 +101,17 @@ GType gst_pulsesink_get_type (void);
#define _PULSE_SINK_CAPS_COMMON \ #define _PULSE_SINK_CAPS_COMMON \
"audio/x-raw, " \ "audio/x-raw, " \
"format = (string) " FORMATS ", " \ "format = (string) " FORMATS ", " \
"layout = (string) interleaved, " \
"rate = (int) [ 1, MAX ], " \ "rate = (int) [ 1, MAX ], " \
"channels = (int) [ 1, 32 ];" \ "channels = (int) [ 1, 32 ];" \
"audio/x-alaw, " \ "audio/x-alaw, " \
"layout = (string) interleaved, " \
"rate = (int) [ 1, MAX], " \ "rate = (int) [ 1, MAX], " \
"channels = (int) [ 1, 32 ];" \ "channels = (int) [ 1, 32 ];" \
"audio/x-mulaw, " \ "audio/x-mulaw, " \
"rate = (int) [ 1, MAX], " "channels = (int) [ 1, 32 ];" "layout = (string) interleaved, " \
"rate = (int) [ 1, MAX], " \
"channels = (int) [ 1, 32 ];"
#define _PULSE_SINK_CAPS_1_0 \ #define _PULSE_SINK_CAPS_1_0 \
"audio/x-ac3, framed = (boolean) true;" \ "audio/x-ac3, framed = (boolean) true;" \

View file

@ -116,6 +116,7 @@ static GstStaticPadTemplate pad_template = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_ALWAYS, GST_PAD_ALWAYS,
GST_STATIC_CAPS ("audio/x-raw, " GST_STATIC_CAPS ("audio/x-raw, "
"format = (string) " FORMATS ", " "format = (string) " FORMATS ", "
"layout = (string) interleaved, "
"rate = (int) [ 1, MAX ], " "rate = (int) [ 1, MAX ], "
"channels = (int) [ 1, 32 ];" "channels = (int) [ 1, 32 ];"
"audio/x-alaw, " "audio/x-alaw, "
@ -1136,22 +1137,48 @@ server_dead:
} }
static gboolean static gboolean
gst_pulsesrc_create_stream (GstPulseSrc * pulsesrc, GstCaps * caps) gst_pulsesrc_create_stream (GstPulseSrc * pulsesrc, GstCaps ** caps)
{ {
pa_channel_map channel_map; pa_channel_map channel_map;
const pa_channel_map *m;
GstStructure *s; GstStructure *s;
gboolean need_channel_layout = FALSE; gboolean need_channel_layout = FALSE;
GstAudioRingBufferSpec spec; GstAudioRingBufferSpec spec;
const gchar *name; const gchar *name;
s = gst_caps_get_structure (*caps, 0);
gst_structure_get_int (s, "channels", &spec.info.channels);
if (!gst_structure_has_field (s, "channel-mask")) {
if (spec.info.channels == 1) {
pa_channel_map_init_mono (&channel_map);
} else if (spec.info.channels == 2) {
gst_structure_set (s, "channel-mask", GST_TYPE_BITMASK,
GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_LEFT) |
GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_RIGHT), NULL);
pa_channel_map_init_stereo (&channel_map);
} else {
need_channel_layout = TRUE;
gst_structure_set (s, "channel-mask", GST_TYPE_BITMASK,
G_GUINT64_CONSTANT (0), NULL);
}
}
memset (&spec, 0, sizeof (GstAudioRingBufferSpec)); memset (&spec, 0, sizeof (GstAudioRingBufferSpec));
spec.latency_time = GST_SECOND; spec.latency_time = GST_SECOND;
if (!gst_audio_ring_buffer_parse_caps (&spec, caps)) if (!gst_audio_ring_buffer_parse_caps (&spec, *caps))
goto invalid_caps; goto invalid_caps;
/* Keep the refcount of the caps at 1 to make them writable */ /* Keep the refcount of the caps at 1 to make them writable */
gst_caps_unref (spec.caps); gst_caps_unref (spec.caps);
if (!need_channel_layout
&& !gst_pulse_gst_to_channel_map (&channel_map, &spec)) {
need_channel_layout = TRUE;
gst_structure_set (s, "channel-mask", GST_TYPE_BITMASK,
G_GUINT64_CONSTANT (0), NULL);
memset (spec.info.position, 0xff, sizeof (spec.info.position));
}
if (!gst_pulse_fill_sample_spec (&spec, &pulsesrc->sample_spec)) if (!gst_pulse_fill_sample_spec (&spec, &pulsesrc->sample_spec))
goto invalid_spec; goto invalid_spec;
@ -1160,17 +1187,6 @@ gst_pulsesrc_create_stream (GstPulseSrc * pulsesrc, GstCaps * caps)
if (!pulsesrc->context) if (!pulsesrc->context)
goto bad_context; goto bad_context;
s = gst_caps_get_structure (caps, 0);
if (!gst_structure_has_field (s, "channel-layout") ||
!gst_pulse_gst_to_channel_map (&channel_map, &spec)) {
if (spec.info.channels == 1)
pa_channel_map_init_mono (&channel_map);
else if (spec.info.channels == 2)
pa_channel_map_init_stereo (&channel_map);
else
need_channel_layout = TRUE;
}
name = "Record Stream"; name = "Record Stream";
if (pulsesrc->proplist) { if (pulsesrc->proplist) {
if (!(pulsesrc->stream = pa_stream_new_with_proplist (pulsesrc->context, if (!(pulsesrc->stream = pa_stream_new_with_proplist (pulsesrc->context,
@ -1184,14 +1200,14 @@ gst_pulsesrc_create_stream (GstPulseSrc * pulsesrc, GstCaps * caps)
(need_channel_layout) ? NULL : &channel_map))) (need_channel_layout) ? NULL : &channel_map)))
goto create_failed; goto create_failed;
if (need_channel_layout) { m = pa_stream_get_channel_map (pulsesrc->stream);
const pa_channel_map *m = pa_stream_get_channel_map (pulsesrc->stream); gst_pulse_channel_map_to_gst (m, &spec);
gst_audio_channel_positions_to_valid_order (spec.info.position,
spec.info.channels);
gst_caps_unref (*caps);
*caps = gst_audio_info_to_caps (&spec.info);
gst_pulse_channel_map_to_gst (m, &spec); GST_DEBUG_OBJECT (pulsesrc, "Caps are %" GST_PTR_FORMAT, *caps);
caps = spec.caps;
}
GST_DEBUG_OBJECT (pulsesrc, "Caps are %" GST_PTR_FORMAT, caps);
pa_stream_set_state_callback (pulsesrc->stream, gst_pulsesrc_stream_state_cb, pa_stream_set_state_callback (pulsesrc->stream, gst_pulsesrc_stream_state_cb,
pulsesrc); pulsesrc);
@ -1292,7 +1308,7 @@ gst_pulsesrc_negotiate (GstBaseSrc * basesrc)
result = TRUE; result = TRUE;
} else if (gst_caps_is_fixed (caps)) { } else if (gst_caps_is_fixed (caps)) {
/* yay, fixed caps, use those then */ /* yay, fixed caps, use those then */
result = gst_pulsesrc_create_stream (pulsesrc, caps); result = gst_pulsesrc_create_stream (pulsesrc, &caps);
if (result) if (result)
result = gst_base_src_set_caps (basesrc, caps); result = gst_base_src_set_caps (basesrc, caps);
} }
@ -1321,6 +1337,16 @@ gst_pulsesrc_prepare (GstAudioSrc * asrc, GstAudioRingBufferSpec * spec)
pa_threaded_mainloop_lock (pulsesrc->mainloop); pa_threaded_mainloop_lock (pulsesrc->mainloop);
{
GstAudioRingBufferSpec s = *spec;
const pa_channel_map *m;
m = pa_stream_get_channel_map (pulsesrc->stream);
gst_pulse_channel_map_to_gst (m, &s);
gst_audio_ring_buffer_set_channel_positions (GST_AUDIO_BASE_SRC
(pulsesrc)->ringbuffer, s.info.position);
}
/* enable event notifications */ /* enable event notifications */
GST_LOG_OBJECT (pulsesrc, "subscribing to context events"); GST_LOG_OBJECT (pulsesrc, "subscribing to context events");
if (!(o = pa_context_subscribe (pulsesrc->context, if (!(o = pa_context_subscribe (pulsesrc->context,

View file

@ -24,7 +24,6 @@
#endif #endif
#include "pulseutil.h" #include "pulseutil.h"
#include <gst/audio/multichannel.h>
#ifdef HAVE_UNISTD_H #ifdef HAVE_UNISTD_H
# include <unistd.h> /* getpid on UNIX */ # include <unistd.h> /* getpid on UNIX */
@ -33,60 +32,39 @@
# include <process.h> /* getpid on win32 */ # include <process.h> /* getpid on win32 */
#endif #endif
static const pa_channel_position_t gst_pos_to_pa[GST_AUDIO_CHANNEL_POSITION_NUM] static const struct
= { {
[GST_AUDIO_CHANNEL_POSITION_FRONT_MONO] = PA_CHANNEL_POSITION_MONO, GstAudioChannelPosition gst_pos;
[GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT] = PA_CHANNEL_POSITION_FRONT_LEFT, pa_channel_position_t pa_pos;
[GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT] = PA_CHANNEL_POSITION_FRONT_RIGHT, } gst_pa_pos_table[] = {
[GST_AUDIO_CHANNEL_POSITION_REAR_CENTER] = PA_CHANNEL_POSITION_REAR_CENTER, {
[GST_AUDIO_CHANNEL_POSITION_REAR_LEFT] = PA_CHANNEL_POSITION_REAR_LEFT, GST_AUDIO_CHANNEL_POSITION_MONO, PA_CHANNEL_POSITION_MONO}, {
[GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT] = PA_CHANNEL_POSITION_REAR_RIGHT, GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_LEFT}, {
[GST_AUDIO_CHANNEL_POSITION_LFE] = PA_CHANNEL_POSITION_LFE, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, PA_CHANNEL_POSITION_FRONT_RIGHT}, {
[GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER] = PA_CHANNEL_POSITION_FRONT_CENTER, GST_AUDIO_CHANNEL_POSITION_REAR_CENTER, PA_CHANNEL_POSITION_REAR_CENTER}, {
[GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER] = GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_LEFT}, {
PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER, GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT, PA_CHANNEL_POSITION_REAR_RIGHT}, {
[GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER] = GST_AUDIO_CHANNEL_POSITION_LFE1, PA_CHANNEL_POSITION_LFE}, {
PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER, GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_FRONT_CENTER}, {
[GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT] = PA_CHANNEL_POSITION_SIDE_LEFT, GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER,
[GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT] = PA_CHANNEL_POSITION_SIDE_RIGHT, PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER}, {
[GST_AUDIO_CHANNEL_POSITION_TOP_CENTER] = PA_CHANNEL_POSITION_TOP_CENTER, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER,
[GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_LEFT] = PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER}, {
PA_CHANNEL_POSITION_TOP_FRONT_LEFT, GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_LEFT}, {
[GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_RIGHT] = GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT, PA_CHANNEL_POSITION_SIDE_RIGHT}, {
PA_CHANNEL_POSITION_TOP_FRONT_RIGHT, GST_AUDIO_CHANNEL_POSITION_TOP_CENTER, PA_CHANNEL_POSITION_TOP_CENTER}, {
[GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_CENTER] = GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_LEFT,
PA_CHANNEL_POSITION_TOP_FRONT_CENTER, PA_CHANNEL_POSITION_TOP_FRONT_LEFT}, {
[GST_AUDIO_CHANNEL_POSITION_TOP_REAR_LEFT] = GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_RIGHT,
PA_CHANNEL_POSITION_TOP_REAR_LEFT, PA_CHANNEL_POSITION_TOP_FRONT_RIGHT}, {
[GST_AUDIO_CHANNEL_POSITION_TOP_REAR_RIGHT] = GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_CENTER,
PA_CHANNEL_POSITION_TOP_REAR_RIGHT, PA_CHANNEL_POSITION_TOP_FRONT_CENTER}, {
[GST_AUDIO_CHANNEL_POSITION_TOP_REAR_CENTER] = GST_AUDIO_CHANNEL_POSITION_TOP_REAR_LEFT, PA_CHANNEL_POSITION_TOP_REAR_LEFT}, {
PA_CHANNEL_POSITION_TOP_REAR_CENTER, GST_AUDIO_CHANNEL_POSITION_TOP_REAR_RIGHT,
[GST_AUDIO_CHANNEL_POSITION_NONE] = PA_CHANNEL_POSITION_INVALID PA_CHANNEL_POSITION_TOP_REAR_RIGHT}, {
}; GST_AUDIO_CHANNEL_POSITION_TOP_REAR_CENTER,
PA_CHANNEL_POSITION_TOP_REAR_CENTER}, {
/* All index are increased by one because PA_CHANNEL_POSITION_INVALID == -1 */ GST_AUDIO_CHANNEL_POSITION_NONE, PA_CHANNEL_POSITION_INVALID}
static const GstAudioChannelPosition
pa_to_gst_pos[GST_AUDIO_CHANNEL_POSITION_NUM]
= {
[PA_CHANNEL_POSITION_MONO + 1] = GST_AUDIO_CHANNEL_POSITION_FRONT_MONO,
[PA_CHANNEL_POSITION_FRONT_LEFT + 1] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
[PA_CHANNEL_POSITION_FRONT_RIGHT + 1] =
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
[PA_CHANNEL_POSITION_REAR_CENTER + 1] =
GST_AUDIO_CHANNEL_POSITION_REAR_CENTER,
[PA_CHANNEL_POSITION_REAR_LEFT + 1] = GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
[PA_CHANNEL_POSITION_REAR_RIGHT + 1] = GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
[PA_CHANNEL_POSITION_LFE + 1] = GST_AUDIO_CHANNEL_POSITION_LFE,
[PA_CHANNEL_POSITION_FRONT_CENTER + 1] =
GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
[PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER + 1] =
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER,
[PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER + 1] =
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER,
[PA_CHANNEL_POSITION_SIDE_LEFT + 1] = GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
[PA_CHANNEL_POSITION_SIDE_RIGHT + 1] = GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT,
[PA_CHANNEL_POSITION_INVALID + 1] = GST_AUDIO_CHANNEL_POSITION_NONE,
}; };
static gboolean static gboolean
@ -235,29 +213,30 @@ pa_channel_map *
gst_pulse_gst_to_channel_map (pa_channel_map * map, gst_pulse_gst_to_channel_map (pa_channel_map * map,
const GstAudioRingBufferSpec * spec) const GstAudioRingBufferSpec * spec)
{ {
int i; gint i, j;
GstAudioChannelPosition *pos; gint channels;
const GstAudioChannelPosition *pos;
pa_channel_map_init (map); pa_channel_map_init (map);
if (!(pos = channels = GST_AUDIO_INFO_CHANNELS (&spec->info);
gst_audio_get_channel_positions (gst_caps_get_structure (spec->caps, pos = spec->info.position;
0)))) {
for (j = 0; j < channels; j++) {
for (i = 0; i < G_N_ELEMENTS (gst_pa_pos_table); i++) {
if (pos[j] == gst_pa_pos_table[i].gst_pos) {
map->map[j] = gst_pa_pos_table[i].pa_pos;
break;
}
}
if (i == G_N_ELEMENTS (gst_pa_pos_table))
return NULL;
}
if (j != spec->info.channels) {
return NULL; return NULL;
} }
for (i = 0; i < spec->info.channels; i++) {
if (pos[i] == GST_AUDIO_CHANNEL_POSITION_NONE) {
/* no valid mappings for these channels */
g_free (pos);
return NULL;
} else if (pos[i] < GST_AUDIO_CHANNEL_POSITION_NUM)
map->map[i] = gst_pos_to_pa[pos[i]];
else
map->map[i] = PA_CHANNEL_POSITION_INVALID;
}
g_free (pos);
map->channels = spec->info.channels; map->channels = spec->info.channels;
if (!pa_channel_map_valid (map)) { if (!pa_channel_map_valid (map)) {
@ -271,30 +250,30 @@ GstAudioRingBufferSpec *
gst_pulse_channel_map_to_gst (const pa_channel_map * map, gst_pulse_channel_map_to_gst (const pa_channel_map * map,
GstAudioRingBufferSpec * spec) GstAudioRingBufferSpec * spec)
{ {
int i; gint i, j;
GstAudioChannelPosition *pos;
gboolean invalid = FALSE; gboolean invalid = FALSE;
gint channels; gint channels;
GstAudioChannelPosition *pos;
channels = GST_AUDIO_INFO_CHANNELS (&spec->info); channels = GST_AUDIO_INFO_CHANNELS (&spec->info);
g_return_val_if_fail (map->channels == channels, NULL); g_return_val_if_fail (map->channels == channels, NULL);
pos = g_new0 (GstAudioChannelPosition, channels + 1); pos = spec->info.position;
for (i = 0; i < channels; i++) { for (j = 0; j < channels; j++) {
if (map->map[i] == PA_CHANNEL_POSITION_INVALID) { for (i = 0; j < channels && i < G_N_ELEMENTS (gst_pa_pos_table); i++) {
invalid = TRUE; if (map->map[j] == gst_pa_pos_table[i].pa_pos) {
break; pos[j] = gst_pa_pos_table[i].gst_pos;
} else if ((int) map->map[i] < (int) GST_AUDIO_CHANNEL_POSITION_NUM) { break;
pos[i] = pa_to_gst_pos[map->map[i] + 1]; }
} else {
invalid = TRUE;
break;
} }
if (i == G_N_ELEMENTS (gst_pa_pos_table))
return NULL;
} }
if (!invalid && !gst_audio_check_channel_positions (pos, channels)) if (!invalid
&& !gst_audio_check_valid_channel_positions (pos, channels, FALSE))
invalid = TRUE; invalid = TRUE;
if (invalid) { if (invalid) {
@ -302,10 +281,6 @@ gst_pulse_channel_map_to_gst (const pa_channel_map * map,
pos[i] = GST_AUDIO_CHANNEL_POSITION_NONE; pos[i] = GST_AUDIO_CHANNEL_POSITION_NONE;
} }
gst_audio_set_channel_positions (gst_caps_get_structure (spec->caps, 0), pos);
g_free (pos);
return spec; return spec;
} }