mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-24 17:20:36 +00:00
ext/alsaspdif/alsaspdifsink.c: Fix sample rate and clocking.
Original commit message from CVS: Patch by: Michael Kötter <m dot koetter at oraise dot de> * ext/alsaspdif/alsaspdifsink.c: (alsaspdifsink_set_caps), (alsaspdifsink_get_time), (alsaspdifsink_open), (alsaspdifsink_set_params), (alsaspdifsink_delay), (plugin_init): Fix sample rate and clocking. Remove buffer_time and period_time as this seems to break on some hardware. Fixes #485462.
This commit is contained in:
parent
03d8e595a0
commit
610f0bde4c
2 changed files with 80 additions and 93 deletions
11
ChangeLog
11
ChangeLog
|
@ -1,3 +1,14 @@
|
||||||
|
2007-11-15 Wim Taymans <wim.taymans@gmail.com>
|
||||||
|
|
||||||
|
Patch by: Michael Kötter <m dot koetter at oraise dot de>
|
||||||
|
|
||||||
|
* ext/alsaspdif/alsaspdifsink.c: (alsaspdifsink_set_caps),
|
||||||
|
(alsaspdifsink_get_time), (alsaspdifsink_open),
|
||||||
|
(alsaspdifsink_set_params), (alsaspdifsink_delay), (plugin_init):
|
||||||
|
Fix sample rate and clocking.
|
||||||
|
Remove buffer_time and period_time as this seems to break on some
|
||||||
|
hardware. Fixes #485462.
|
||||||
|
|
||||||
2007-11-15 Wim Taymans <wim.taymans@gmail.com>
|
2007-11-15 Wim Taymans <wim.taymans@gmail.com>
|
||||||
|
|
||||||
Patch by: Wouter Cloetens <wouter at mind dot be>
|
Patch by: Wouter Cloetens <wouter at mind dot be>
|
||||||
|
|
|
@ -50,6 +50,8 @@ GST_DEBUG_CATEGORY_STATIC (alsaspdifsink_debug);
|
||||||
/* Size in bytes of an ALSA PCM frame (4, for this case). */
|
/* Size in bytes of an ALSA PCM frame (4, for this case). */
|
||||||
#define ALSASPDIFSINK_BYTES_PER_FRAME ((AC3_BITS / 8) * AC3_CHANNELS)
|
#define ALSASPDIFSINK_BYTES_PER_FRAME ((AC3_BITS / 8) * AC3_CHANNELS)
|
||||||
|
|
||||||
|
#define IEC958_SAMPLES_PER_FRAME (IEC958_FRAME_SIZE / ALSASPDIFSINK_BYTES_PER_FRAME)
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
/* The duration of a single IEC958 frame. */
|
/* The duration of a single IEC958 frame. */
|
||||||
#define IEC958_FRAME_DURATION (32 * GST_MSECOND)
|
#define IEC958_FRAME_DURATION (32 * GST_MSECOND)
|
||||||
|
@ -127,6 +129,8 @@ static void alsaspdifsink_finalize (GObject * object);
|
||||||
static GstStateChangeReturn alsaspdifsink_change_state (GstElement * element,
|
static GstStateChangeReturn alsaspdifsink_change_state (GstElement * element,
|
||||||
GstStateChange transition);
|
GstStateChange transition);
|
||||||
static int alsaspdifsink_find_pcm_device (AlsaSPDIFSink * sink);
|
static int alsaspdifsink_find_pcm_device (AlsaSPDIFSink * sink);
|
||||||
|
static gboolean alsaspdifsink_set_params (AlsaSPDIFSink * sink);
|
||||||
|
static snd_pcm_sframes_t alsaspdifsink_delay (AlsaSPDIFSink * sink);
|
||||||
|
|
||||||
/* Alsa error handler to suppress messages from within the ALSA library */
|
/* Alsa error handler to suppress messages from within the ALSA library */
|
||||||
static void ignore_alsa_err (const char *file, int line, const char *function,
|
static void ignore_alsa_err (const char *file, int line, const char *function,
|
||||||
|
@ -275,6 +279,12 @@ alsaspdifsink_set_caps (GstBaseSink * bsink, GstCaps * caps)
|
||||||
&sink->rate))
|
&sink->rate))
|
||||||
sink->rate = 48000;
|
sink->rate = 48000;
|
||||||
|
|
||||||
|
if (!alsaspdifsink_set_params (sink)) {
|
||||||
|
GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE,
|
||||||
|
("Cannot set ALSA hardware parameters"), GST_ERROR_SYSTEM);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,22 +299,31 @@ alsaspdifsink_provide_clock (GstElement * elem)
|
||||||
static GstClockTime
|
static GstClockTime
|
||||||
alsaspdifsink_get_time (GstClock * clock, gpointer user_data)
|
alsaspdifsink_get_time (GstClock * clock, gpointer user_data)
|
||||||
{
|
{
|
||||||
|
GstClockTime result;
|
||||||
|
snd_pcm_sframes_t raw, delay, samples;
|
||||||
AlsaSPDIFSink *sink = ALSASPDIFSINK (user_data);
|
AlsaSPDIFSink *sink = ALSASPDIFSINK (user_data);
|
||||||
|
|
||||||
return sink->frames * sink->rate / 1536;
|
raw = samples = sink->frames * IEC958_SAMPLES_PER_FRAME;
|
||||||
|
delay = alsaspdifsink_delay (sink);
|
||||||
|
|
||||||
|
if (samples > delay)
|
||||||
|
samples -= delay;
|
||||||
|
else
|
||||||
|
samples = 0;
|
||||||
|
|
||||||
|
result = gst_util_uint64_scale_int (samples, GST_SECOND, sink->rate);
|
||||||
|
GST_LOG_OBJECT (sink,
|
||||||
|
"Samples raw: %d, delay: %d, real: %d, Time: %" GST_TIME_FORMAT, raw,
|
||||||
|
delay, samples, GST_TIME_ARGS (result));
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
alsaspdifsink_open (AlsaSPDIFSink * sink)
|
alsaspdifsink_open (AlsaSPDIFSink * sink)
|
||||||
{
|
{
|
||||||
char *pcm_name = sink->device;
|
char *pcm_name = sink->device;
|
||||||
snd_pcm_hw_params_t *params;
|
int err;
|
||||||
snd_pcm_sw_params_t *sw_params;
|
|
||||||
unsigned int rate, buffer_time, period_time, tmp;
|
|
||||||
snd_pcm_uframes_t avail_min;
|
|
||||||
int err, step;
|
|
||||||
char devstr[256]; /* Storage for local 'default' device string */
|
char devstr[256]; /* Storage for local 'default' device string */
|
||||||
GstClockTime time;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Try and open our default iec958 device. Fall back to searching on card x
|
* Try and open our default iec958 device. Fall back to searching on card x
|
||||||
|
@ -333,28 +352,44 @@ alsaspdifsink_open (AlsaSPDIFSink * sink)
|
||||||
pcm_name);
|
pcm_name);
|
||||||
|
|
||||||
err = alsaspdifsink_find_pcm_device (sink);
|
err = alsaspdifsink_find_pcm_device (sink);
|
||||||
if (err == 0 && sink->pcm == NULL) {
|
if (err == 0 && sink->pcm == NULL)
|
||||||
GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE,
|
goto open_failed;
|
||||||
("Could not open IEC958/SPDIF output device"), GST_ERROR_SYSTEM);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (err < 0)
|
||||||
|
goto failed;
|
||||||
|
|
||||||
if (err < 0) {
|
return TRUE;
|
||||||
|
|
||||||
|
/* ERRORS */
|
||||||
|
open_failed:
|
||||||
|
{
|
||||||
|
GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE,
|
||||||
|
("Could not open IEC958/SPDIF output device"), GST_ERROR_SYSTEM);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
failed:
|
||||||
|
{
|
||||||
GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE,
|
GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE,
|
||||||
("snd_pcm_open: %s", snd_strerror (err)), GST_ERROR_SYSTEM);
|
("snd_pcm_open: %s", snd_strerror (err)), GST_ERROR_SYSTEM);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
alsaspdifsink_set_params (AlsaSPDIFSink * sink)
|
||||||
|
{
|
||||||
|
snd_pcm_hw_params_t *params;
|
||||||
|
unsigned int rate;
|
||||||
|
int err;
|
||||||
|
|
||||||
snd_pcm_hw_params_malloc (¶ms);
|
snd_pcm_hw_params_malloc (¶ms);
|
||||||
snd_pcm_sw_params_malloc (&sw_params);
|
|
||||||
|
|
||||||
err = snd_pcm_hw_params_any (sink->pcm, params);
|
err = snd_pcm_hw_params_any (sink->pcm, params);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE,
|
GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE,
|
||||||
("Broken configuration for this PCM: "
|
("Broken configuration for this PCM: "
|
||||||
"no configurations available"), GST_ERROR_SYSTEM);
|
"no configurations available"), GST_ERROR_SYSTEM);
|
||||||
goto __close;
|
goto __error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set interleaved access. */
|
/* Set interleaved access. */
|
||||||
|
@ -363,12 +398,13 @@ alsaspdifsink_open (AlsaSPDIFSink * sink)
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE,
|
GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE,
|
||||||
("Access type not available"), GST_ERROR_SYSTEM);
|
("Access type not available"), GST_ERROR_SYSTEM);
|
||||||
goto __close;
|
goto __error;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = snd_pcm_hw_params_set_format (sink->pcm, params, AC3_FORMAT_BE);
|
err = snd_pcm_hw_params_set_format (sink->pcm, params, AC3_FORMAT_BE);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
/* Try LE output and swap data */
|
/* Try LE output and swap data */
|
||||||
|
GST_DEBUG_OBJECT (sink, "PCM format S16_BE not supported, trying S16_LE");
|
||||||
err = snd_pcm_hw_params_set_format (sink->pcm, params, AC3_FORMAT_LE);
|
err = snd_pcm_hw_params_set_format (sink->pcm, params, AC3_FORMAT_LE);
|
||||||
sink->need_swap = TRUE;
|
sink->need_swap = TRUE;
|
||||||
} else
|
} else
|
||||||
|
@ -377,102 +413,44 @@ alsaspdifsink_open (AlsaSPDIFSink * sink)
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE,
|
GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE,
|
||||||
("Sample format not available"), GST_ERROR_SYSTEM);
|
("Sample format not available"), GST_ERROR_SYSTEM);
|
||||||
goto __close;
|
goto __error;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = snd_pcm_hw_params_set_channels (sink->pcm, params, AC3_CHANNELS);
|
err = snd_pcm_hw_params_set_channels (sink->pcm, params, AC3_CHANNELS);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE,
|
GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE,
|
||||||
("Channels count not available"), GST_ERROR_SYSTEM);
|
("Channels count not available"), GST_ERROR_SYSTEM);
|
||||||
goto __close;
|
goto __error;
|
||||||
}
|
}
|
||||||
|
|
||||||
rate = sink->rate;
|
rate = sink->rate;
|
||||||
|
GST_DEBUG_OBJECT (sink, "Setting S/PDIF sample rate: %d", rate);
|
||||||
err = snd_pcm_hw_params_set_rate_near (sink->pcm, params, &rate, 0);
|
err = snd_pcm_hw_params_set_rate_near (sink->pcm, params, &rate, 0);
|
||||||
if (err < 0) {
|
if (err != 0) {
|
||||||
GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE,
|
GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE,
|
||||||
("Rate not available"), GST_ERROR_SYSTEM);
|
("Rate not available"), GST_ERROR_SYSTEM);
|
||||||
goto __close;
|
goto __error;
|
||||||
}
|
|
||||||
|
|
||||||
buffer_time = 500000;
|
|
||||||
err = snd_pcm_hw_params_set_buffer_time_near (sink->pcm, params,
|
|
||||||
&buffer_time, 0);
|
|
||||||
if (err < 0) {
|
|
||||||
GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE,
|
|
||||||
("Buffer time not available"), GST_ERROR_SYSTEM);
|
|
||||||
goto __close;
|
|
||||||
}
|
|
||||||
time = buffer_time * 1000;
|
|
||||||
GST_DEBUG_OBJECT (sink, "buffer size set to %" GST_TIME_FORMAT,
|
|
||||||
GST_TIME_ARGS (time));
|
|
||||||
|
|
||||||
step = 2;
|
|
||||||
period_time = 10000 * 2;
|
|
||||||
do {
|
|
||||||
period_time /= 2;
|
|
||||||
tmp = period_time;
|
|
||||||
|
|
||||||
err = snd_pcm_hw_params_set_period_time_near (sink->pcm, params, &tmp, 0);
|
|
||||||
if (err < 0) {
|
|
||||||
GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE,
|
|
||||||
("Period time not available"), GST_ERROR_SYSTEM);
|
|
||||||
goto __close;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tmp == period_time) {
|
|
||||||
period_time /= 3;
|
|
||||||
tmp = period_time;
|
|
||||||
err = snd_pcm_hw_params_set_period_time_near (sink->pcm, params, &tmp, 0);
|
|
||||||
if (tmp == period_time) {
|
|
||||||
period_time = 10000 * 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (buffer_time == period_time && period_time > 10000);
|
|
||||||
|
|
||||||
if (buffer_time == period_time) {
|
|
||||||
GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE,
|
|
||||||
("Buffer time and period time match, could not use"), GST_ERROR_SYSTEM);
|
|
||||||
goto __close;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err = snd_pcm_hw_params (sink->pcm, params);
|
err = snd_pcm_hw_params (sink->pcm, params);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE,
|
GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE,
|
||||||
("PCM hw_params failed: %s", snd_strerror (err)), GST_ERROR_SYSTEM);
|
("PCM hw_params failed: %s", snd_strerror (err)), GST_ERROR_SYSTEM);
|
||||||
goto __close;
|
goto __error;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = snd_pcm_sw_params_current (sink->pcm, sw_params);
|
|
||||||
if (err < 0) {
|
|
||||||
GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE,
|
|
||||||
("Cannot retrieve software params"), GST_ERROR_SYSTEM);
|
|
||||||
goto __close;
|
|
||||||
}
|
|
||||||
|
|
||||||
avail_min = 48000 * 0.15;
|
|
||||||
err = snd_pcm_sw_params_set_avail_min (sink->pcm, sw_params, avail_min);
|
|
||||||
if (err < 0) {
|
|
||||||
GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE,
|
|
||||||
("Cannot set avail min"), GST_ERROR_SYSTEM);
|
|
||||||
goto __close;
|
|
||||||
}
|
|
||||||
snd_pcm_sw_params_get_avail_min (sw_params, &avail_min);
|
|
||||||
GST_DEBUG_OBJECT (sink, "Avail min set to:%lu frames", avail_min);
|
|
||||||
|
|
||||||
snd_pcm_hw_params_free (params);
|
snd_pcm_hw_params_free (params);
|
||||||
snd_pcm_sw_params_free (sw_params);
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
__close:
|
/* ERRORS */
|
||||||
snd_pcm_hw_params_free (params);
|
__error:
|
||||||
snd_pcm_sw_params_free (sw_params);
|
{
|
||||||
snd_pcm_close (sink->pcm);
|
snd_pcm_hw_params_free (params);
|
||||||
sink->pcm = NULL;
|
return FALSE;
|
||||||
return FALSE;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
alsaspdifsink_close (AlsaSPDIFSink * sink)
|
alsaspdifsink_close (AlsaSPDIFSink * sink)
|
||||||
{
|
{
|
||||||
|
@ -700,9 +678,8 @@ alsaspdifsink_get_times (GstBaseSink * bsink, GstBuffer * buffer,
|
||||||
*end = GST_CLOCK_TIME_NONE;
|
*end = GST_CLOCK_TIME_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
static snd_pcm_sframes_t
|
||||||
static GstClockTime
|
alsaspdifsink_delay (AlsaSPDIFSink * sink)
|
||||||
alsaspdifsink_current_delay (AlsaSPDIFSink * sink)
|
|
||||||
{
|
{
|
||||||
snd_pcm_sframes_t delay;
|
snd_pcm_sframes_t delay;
|
||||||
int err;
|
int err;
|
||||||
|
@ -712,9 +689,10 @@ alsaspdifsink_current_delay (AlsaSPDIFSink * sink)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ALSASPDIFSINK_TIME_PER_FRAMES (sink, delay);
|
return delay;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
static void
|
static void
|
||||||
generate_iec958_zero_frame (guchar * buffer)
|
generate_iec958_zero_frame (guchar * buffer)
|
||||||
{
|
{
|
||||||
|
@ -850,11 +828,9 @@ plugin_init (GstPlugin * plugin)
|
||||||
GST_TYPE_ALSASPDIFSINK)) {
|
GST_TYPE_ALSASPDIFSINK)) {
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
|
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
|
||||||
GST_VERSION_MINOR,
|
GST_VERSION_MINOR,
|
||||||
"alsaspdif",
|
"alsaspdif",
|
||||||
|
|
Loading…
Reference in a new issue