diff options
author | Benjamin Otte <otte@gnome.org> | 2004-06-09 17:06:40 +0000 |
---|---|---|
committer | Benjamin Otte <otte@gnome.org> | 2004-06-09 17:06:40 +0000 |
commit | 851ad864d06cfd8cf8ac33113436b9e5b955b353 (patch) | |
tree | a08d6f376243356148d4f7d3ecaa14be9b66eccd | |
parent | ad028c8562821235a8303025cb42b983f4a8ac1c (diff) |
ext/alsa/gstalsa.c: handle min <= max correctly
Original commit message from CVS:
* ext/alsa/gstalsa.c: (add_channels):
handle min <= max correctly
* ext/alsa/gstalsa.c: (gst_alsa_fixate_to_mimetype),
(gst_alsa_fixate_field_nearest_int), (gst_alsa_fixate):
add fixation functions so we fixate correctly. No preferring of alaw
anymore because it's the first structure.
* ext/alsa/gstalsa.h:
* ext/alsa/gstalsa.c: (gst_alsa_sw_params_dump),
(gst_alsa_hw_params_dump):
add functions to ease debugging in alsalib
* ext/alsa/gstalsa.c: (gst_alsa_probe_hw_params),
(gst_alsa_set_hw_params), (gst_alsa_set_sw_params),
(gst_alsa_start_audio):
only specify hw params if we really setup a format (fixes #134007 -
or at least works around it)
-rw-r--r-- | ChangeLog | 18 | ||||
-rw-r--r-- | ext/alsa/gstalsa.c | 240 | ||||
-rw-r--r-- | ext/alsa/gstalsa.h | 18 |
3 files changed, 209 insertions, 67 deletions
@@ -1,3 +1,21 @@ +2004-06-09 Benjamin Otte <otte@gnome.org> + + * ext/alsa/gstalsa.c: (add_channels): + handle min <= max correctly + * ext/alsa/gstalsa.c: (gst_alsa_fixate_to_mimetype), + (gst_alsa_fixate_field_nearest_int), (gst_alsa_fixate): + add fixation functions so we fixate correctly. No preferring of alaw + anymore because it's the first structure. + * ext/alsa/gstalsa.h: + * ext/alsa/gstalsa.c: (gst_alsa_sw_params_dump), + (gst_alsa_hw_params_dump): + add functions to ease debugging in alsalib + * ext/alsa/gstalsa.c: (gst_alsa_probe_hw_params), + (gst_alsa_set_hw_params), (gst_alsa_set_sw_params), + (gst_alsa_start_audio): + only specify hw params if we really setup a format (fixes #134007 - + or at least works around it) + 2004-06-09 Wim Taymans <wim@fluendo.com> * ext/ogg/gstoggmux.c: (gst_ogg_mux_init), diff --git a/ext/alsa/gstalsa.c b/ext/alsa/gstalsa.c index 336233c94..96ae070fa 100644 --- a/ext/alsa/gstalsa.c +++ b/ext/alsa/gstalsa.c @@ -31,6 +31,17 @@ #include "gstalsaclock.h" #include "gstalsamixer.h" +#define ALSA_DEBUG_FLUSH(this) G_STMT_START{ \ + gchar *__str; \ + ssize_t __size; \ + __size = snd_output_buffer_string (this->out, &__str); \ + if (__size > 0) { \ + GST_DEBUG_OBJECT (this, "%*s", __size, __str); \ + if (snd_output_flush (this->out) != 0) \ + GST_ERROR_OBJECT (this, "error flushing output buffer"); \ + } \ +}G_STMT_END + /* GObject functions */ static void gst_alsa_class_init (gpointer g_class, gpointer class_data); static void gst_alsa_init (GstAlsa * this); @@ -692,9 +703,20 @@ add_channels (GstStructure * structure, gint min_rate, gint max_rate, min_rate = GST_ALSA_MIN_RATE; max_rate = GST_ALSA_MAX_RATE; } - if (max_rate < 0) { + if (max_rate < 0 || min_rate == max_rate) { gst_structure_set (structure, "rate", G_TYPE_INT, min_rate, NULL); } else { + /* just to be sure */ + if (min_rate > max_rate) { + gint temp; + + GST_ERROR + ("minimum rate > maximum rate (%d > %d), please fix your soundcard drivers", + min_rate, max_rate); + temp = min_rate; + min_rate = max_rate; + max_rate = temp; + } gst_structure_set (structure, "rate", GST_TYPE_INT_RANGE, min_rate, max_rate, NULL); } @@ -702,9 +724,20 @@ add_channels (GstStructure * structure, gint min_rate, gint max_rate, min_channels = 1; max_channels = GST_ALSA_MAX_CHANNELS; } - if (max_channels < 0) { + if (max_channels < 0 || min_channels == max_channels) { gst_structure_set (structure, "channels", G_TYPE_INT, min_channels, NULL); } else { + /* just to be sure */ + if (min_channels > max_channels) { + gint temp; + + GST_ERROR + ("minimum channels > maximum channels (%d > %d), please fix your soundcard drivers", + min_channels, max_channels); + temp = min_channels; + min_channels = max_channels; + max_channels = temp; + } gst_structure_set (structure, "channels", GST_TYPE_INT_RANGE, min_channels, max_channels, NULL); } @@ -828,37 +861,118 @@ gst_alsa_get_caps (GstPad * pad) } } -GstCaps * -gst_alsa_fixate (GstPad * pad, const GstCaps * caps) +static GstCaps * +gst_alsa_fixate_to_mimetype (const GstCaps * caps, const gchar * mime) { - GstCaps *newcaps; - GstStructure *structure; - - newcaps = - gst_caps_new_full (gst_structure_copy (gst_caps_get_structure (caps, 0)), - NULL); - structure = gst_caps_get_structure (newcaps, 0); + GstCaps *try, *result; - if (gst_caps_structure_fixate_field_nearest_int (structure, "rate", 44100)) { - return newcaps; + try = gst_caps_new_simple (mime, NULL); + result = gst_caps_intersect (try, caps); + gst_caps_free (try); + if (gst_caps_is_empty (result)) { + gst_caps_free (result); + return NULL; } - if (gst_caps_structure_fixate_field_nearest_int (structure, "channels", 2)) { - return newcaps; + if (gst_caps_is_subset (caps, result)) { + /* we didn't reduce caps */ + gst_caps_free (result); + return NULL; } - if (strcmp (gst_structure_get_name (structure), "audio/x-raw-int") == 0) { - if (gst_caps_structure_fixate_field_nearest_int (structure, "depth", 16)) { - return newcaps; - } - if (gst_caps_structure_fixate_field_nearest_int (structure, "width", 16)) { - return newcaps; + return result; +} + +static GstCaps * +gst_alsa_fixate_field_nearest_int (const GstCaps * caps, + const gchar * field_name, gint target) +{ + guint i; + GstCaps *result; + GstCaps *smaller = gst_caps_new_empty (); + GstCaps *equal = gst_caps_new_empty (); + GstCaps *bigger = gst_caps_new_empty (); + + /* works like this: we fixate every structure and put them into one of those + * caps depending on what we fixated to. We then return the best caps that is + * not empty in the following order: equal, bigger, smaller + * We also make sure the caps were really reduced. + */ + for (i = 0; i < gst_caps_get_size (caps); i++) { + gint fixated_to; + GstStructure *copy = gst_structure_copy (gst_caps_get_structure (caps, i)); + + gst_caps_structure_fixate_field_nearest_int (copy, field_name, target); + if (gst_structure_get_int (copy, field_name, &fixated_to)) { + if (fixated_to == target) { + gst_caps_append_structure (equal, copy); + } else if (fixated_to > target) { + gst_caps_append_structure (bigger, copy); + } else { + gst_caps_append_structure (smaller, copy); + } + } else { + /* FIXME: what do we do here? Add to all or throw an error? */ + g_return_val_if_reached (NULL); } + } + if (!gst_caps_is_empty (equal)) { + gst_caps_free (bigger); + gst_caps_free (smaller); + result = equal; } else { - if (gst_caps_structure_fixate_field_nearest_int (structure, "width", 32)) { - return newcaps; + gst_caps_free (equal); + if (!gst_caps_is_empty (bigger)) { + gst_caps_free (smaller); + result = bigger; + } else { + gst_caps_free (bigger); + if (gst_caps_is_empty (smaller)) { + gst_caps_free (smaller); + return NULL; + } + result = smaller; } } + if (gst_caps_is_subset (caps, result)) { + /* we didn't reduce caps */ + gst_caps_free (result); + return NULL; + } + return result; +} - gst_caps_free (newcaps); +GstCaps * +gst_alsa_fixate (GstPad * pad, const GstCaps * caps) +{ + GstCaps *result; + const gchar *mime; + + if ((result = gst_alsa_fixate_to_mimetype (caps, "audio/x-raw-int"))) + return result; + if ((result = gst_alsa_fixate_to_mimetype (caps, "audio/x-raw-float"))) + return result; + if ((result = gst_alsa_fixate_to_mimetype (caps, "audio/x-alaw"))) + return result; + if ((result = gst_alsa_fixate_to_mimetype (caps, "audio/x-mulaw"))) + return result; + + /* now we know there's only one mimetype in the caps */ + /* FIXME: I should check this to be really sure I didn't mess up somewhere */ + + if ((result = gst_alsa_fixate_field_nearest_int (caps, "rate", 44100))) + return result; + if ((result = gst_alsa_fixate_field_nearest_int (caps, "channels", 2))) + return result; + + mime = gst_structure_get_name (gst_caps_get_structure (caps, 0)); + if (g_str_equal (mime, "audio/x-raw-int")) { + if ((result = gst_alsa_fixate_field_nearest_int (caps, "width", 16))) + return result; + if ((result = gst_alsa_fixate_field_nearest_int (caps, "depth", 16))) + return result; + } else if (g_str_equal (mime, "audio/x-raw-float")) { + if ((result = gst_alsa_fixate_field_nearest_int (caps, "width", 32))) + return result; + } return NULL; } @@ -1229,6 +1343,20 @@ gst_alsa_open_audio (GstAlsa * this) return TRUE; } +void +gst_alsa_sw_params_dump (GstAlsa * this, snd_pcm_sw_params_t * sw_params) +{ + snd_pcm_sw_params_dump (sw_params, this->out); + ALSA_DEBUG_FLUSH (this); +} + +void +gst_alsa_hw_params_dump (GstAlsa * this, snd_pcm_hw_params_t * hw_params) +{ + snd_pcm_hw_params_dump (hw_params, this->out); + ALSA_DEBUG_FLUSH (this); +} + /* if someone finds an easy way to merge this with _set_hw_params, go ahead */ static gboolean gst_alsa_probe_hw_params (GstAlsa * this, GstAlsaFormat * format) @@ -1246,8 +1374,7 @@ gst_alsa_probe_hw_params (GstAlsa * this, GstAlsaFormat * format) snd_pcm_hw_params_alloca (&hw_params); SIMPLE_ERROR_CHECK (snd_pcm_hw_params_any (this->handle, hw_params)); - snd_pcm_hw_params_dump (hw_params, this->out); - ALSA_DEBUG_FLUSH (this); + gst_alsa_hw_params_dump (this, hw_params); if (GST_ELEMENT (this)->numpads == 1) { SIMPLE_ERROR_CHECK (snd_pcm_hw_params_set_access (this->handle, @@ -1291,34 +1418,27 @@ gst_alsa_set_hw_params (GstAlsa * this) g_return_val_if_fail (this != NULL, FALSE); g_return_val_if_fail (this->handle != NULL, FALSE); - if (this->format) { - GST_INFO ("Preparing format: %s %dHz, %d channels", - snd_pcm_format_name (this->format->format), this->format->rate, - this->format->channels); - } else { - GST_INFO ("Preparing format: (none)"); - } - snd_pcm_hw_params_alloca (&hw_params); ERROR_CHECK (snd_pcm_hw_params_any (this->handle, hw_params), "Broken configuration for this PCM: %s"); - snd_pcm_hw_params_dump (hw_params, this->out); - ALSA_DEBUG_FLUSH (this); + if (this->format) { + GST_INFO ("Preparing format: %s %dHz, %d channels", + snd_pcm_format_name (this->format->format), this->format->rate, + this->format->channels); - if (GST_ELEMENT (this)->numpads == 1) { - ERROR_CHECK (snd_pcm_hw_params_set_access (this->handle, hw_params, this-> - mmap ? SND_PCM_ACCESS_MMAP_INTERLEAVED : - SND_PCM_ACCESS_RW_INTERLEAVED), - "This plugin does not support your harware: %s"); - } else { - ERROR_CHECK (snd_pcm_hw_params_set_access (this->handle, hw_params, this-> - mmap ? SND_PCM_ACCESS_MMAP_NONINTERLEAVED : - SND_PCM_ACCESS_RW_NONINTERLEAVED), - "This plugin does not support your harware: %s"); - } + if (GST_ELEMENT (this)->numpads == 1) { + ERROR_CHECK (snd_pcm_hw_params_set_access (this->handle, hw_params, this-> + mmap ? SND_PCM_ACCESS_MMAP_INTERLEAVED : + SND_PCM_ACCESS_RW_INTERLEAVED), + "This plugin does not support your harware: %s"); + } else { + ERROR_CHECK (snd_pcm_hw_params_set_access (this->handle, hw_params, this-> + mmap ? SND_PCM_ACCESS_MMAP_NONINTERLEAVED : + SND_PCM_ACCESS_RW_NONINTERLEAVED), + "This plugin does not support your harware: %s"); + } - if (this->format) { ERROR_CHECK (snd_pcm_hw_params_set_format (this->handle, hw_params, this->format->format), "Sample format (%s) not available: %s", snd_pcm_format_name (this->format->format)); @@ -1328,14 +1448,18 @@ gst_alsa_set_hw_params (GstAlsa * this) ERROR_CHECK (snd_pcm_hw_params_set_rate (this->handle, hw_params, this->format->rate, 0), "error setting rate (%d): %s", this->format->rate); + ERROR_CHECK (snd_pcm_hw_params_set_periods_near (this->handle, hw_params, + &this->period_count, 0), "error setting period count to %u: %s", + (guint) this->period_count); + ERROR_CHECK (snd_pcm_hw_params_set_period_size_near (this->handle, + hw_params, &this->period_size, 0), + "error setting period size to %u frames: %s", + (guint) this->period_size); + } else { + GST_INFO_OBJECT (this, "Preparing format: (none)"); } + gst_alsa_hw_params_dump (this, hw_params); - ERROR_CHECK (snd_pcm_hw_params_set_periods_near (this->handle, hw_params, - &this->period_count, 0), "error setting period count to %u: %s", - (guint) this->period_count); - ERROR_CHECK (snd_pcm_hw_params_set_period_size_near (this->handle, hw_params, - &this->period_size, 0), "error setting period size to %u frames: %s", - (guint) this->period_size); ERROR_CHECK (snd_pcm_hw_params (this->handle, hw_params), "Could not set hardware parameters: %s"); @@ -1362,12 +1486,16 @@ gst_alsa_set_sw_params (GstAlsa * this) { snd_pcm_sw_params_t *sw_params; + if (!this->format) { + GST_LOG_OBJECT (this, "not setting sw params, we're not negotiated yet"); + return TRUE; + } + snd_pcm_sw_params_alloca (&sw_params); ERROR_CHECK (snd_pcm_sw_params_current (this->handle, sw_params), "Could not get current software parameters: %s"); - snd_pcm_sw_params_dump (sw_params, this->out); - ALSA_DEBUG_FLUSH (this); + gst_alsa_sw_params_dump (this, sw_params); ERROR_CHECK (snd_pcm_sw_params_set_silence_size (this->handle, sw_params, 0), "could not set silence size: %s"); diff --git a/ext/alsa/gstalsa.h b/ext/alsa/gstalsa.h index 8d99faa28..b499b668d 100644 --- a/ext/alsa/gstalsa.h +++ b/ext/alsa/gstalsa.h @@ -35,17 +35,6 @@ GST_DEBUG_CATEGORY_EXTERN (alsa_debug); #define GST_CAT_DEFAULT alsa_debug -#define ALSA_DEBUG_FLUSH(this) G_STMT_START{ \ - gchar *__str; \ - ssize_t __size; \ - __size = snd_output_buffer_string (this->out, &__str); \ - if (__size > 0) { \ - GST_INFO_OBJECT (this, "%*s", __size, __str); \ - if (snd_output_flush (this->out) != 0) \ - GST_ERROR_OBJECT (this, "error flushing output buffer"); \ - } \ -}G_STMT_END - /* error checking for standard alsa functions */ /* NOTE: these functions require a GObject *this and can only be used in functions that return TRUE on success and FALSE on error */ @@ -222,6 +211,13 @@ inline GstClockTime gst_alsa_bytes_to_timestamp (GstAlsa * this, inline guint gst_alsa_timestamp_to_bytes (GstAlsa * this, GstClockTime time); +/* debugging functions (useful in gdb) - require running with --gst-debug=alsa:4 or better */ +void gst_alsa_sw_params_dump (GstAlsa * this, + snd_pcm_sw_params_t * sw_params); +void gst_alsa_hw_params_dump (GstAlsa * this, + snd_pcm_hw_params_t * hw_params); + + G_END_DECLS #endif /* __GST_ALSA_H__ */ |