Accepting request 141191 from multimedia:libs

- backport fixes from upstream tree:
  0031-pcm-support-for-audio-timestamps.patch
  0032-pcm-fix-64-bit-SNDRV_PCM_IOCTL_STATUS-ABI-breakage.patch
  0033-PCM-Fix-memory-leak-for-pcm-empty-and-asym-plugins.patch
  0034-Reduce-compilation-warnings.patch
  0035-PCM-Avoid-busy-loop-in-snd_pcm_write_areas-with-rate.patch (forwarded request 141190 from tiwai)

OBS-URL: https://build.opensuse.org/request/show/141191
OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/alsa?expand=0&rev=127
This commit is contained in:
Stephan Kulow 2012-11-14 08:11:39 +00:00 committed by Git OBS Bridge
commit efddd76699
7 changed files with 766 additions and 0 deletions

View File

@ -0,0 +1,272 @@
From cf40ea169aad366b222283f431addafea6327149 Mon Sep 17 00:00:00 2001
From: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Date: Tue, 12 Jun 2012 14:36:40 -0500
Subject: [PATCH 31/35] pcm: support for audio timestamps
add new snd_pcm_status_get_audio_htstamp() routine to
query the audio timestamps provided by the kernel.
This change provides applications with better ways
to track elapsed time. Before this patch, applications
would subtract queued samples (delay) from written samples,
resulting in a 1-2 sample error.
Also add snd_pcm_hw_params_supports_audio_wallclock_ts()
to query what the hardware supports.
TODO: check protocol compatibility?
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
include/pcm.h | 2 ++
include/sound/asound.h | 7 ++++--
src/pcm/pcm.c | 31 +++++++++++++++++++++++
test/audio_time.c | 68 ++++++++++++++++++++++++++++++++++++++++++--------
4 files changed, 96 insertions(+), 12 deletions(-)
diff --git a/include/pcm.h b/include/pcm.h
index 290593b..1ce91e7 100644
--- a/include/pcm.h
+++ b/include/pcm.h
@@ -631,6 +631,7 @@ int snd_pcm_hw_params_is_half_duplex(const snd_pcm_hw_params_t *params);
int snd_pcm_hw_params_is_joint_duplex(const snd_pcm_hw_params_t *params);
int snd_pcm_hw_params_can_sync_start(const snd_pcm_hw_params_t *params);
int snd_pcm_hw_params_can_disable_period_wakeup(const snd_pcm_hw_params_t *params);
+int snd_pcm_hw_params_supports_audio_wallclock_ts(const snd_pcm_hw_params_t *params);
int snd_pcm_hw_params_get_rate_numden(const snd_pcm_hw_params_t *params,
unsigned int *rate_num,
unsigned int *rate_den);
@@ -939,6 +940,7 @@ void snd_pcm_status_get_trigger_tstamp(const snd_pcm_status_t *obj, snd_timestam
void snd_pcm_status_get_trigger_htstamp(const snd_pcm_status_t *obj, snd_htimestamp_t *ptr);
void snd_pcm_status_get_tstamp(const snd_pcm_status_t *obj, snd_timestamp_t *ptr);
void snd_pcm_status_get_htstamp(const snd_pcm_status_t *obj, snd_htimestamp_t *ptr);
+void snd_pcm_status_get_audio_htstamp(const snd_pcm_status_t *obj, snd_htimestamp_t *ptr);
snd_pcm_sframes_t snd_pcm_status_get_delay(const snd_pcm_status_t *obj);
snd_pcm_uframes_t snd_pcm_status_get_avail(const snd_pcm_status_t *obj);
snd_pcm_uframes_t snd_pcm_status_get_avail_max(const snd_pcm_status_t *obj);
diff --git a/include/sound/asound.h b/include/sound/asound.h
index e24d144..16d03e8 100644
--- a/include/sound/asound.h
+++ b/include/sound/asound.h
@@ -160,7 +160,7 @@ enum {
* *
*****************************************************************************/
-#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 10)
+#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 11)
typedef unsigned long sndrv_pcm_uframes_t;
typedef long sndrv_pcm_sframes_t;
@@ -285,6 +285,7 @@ enum sndrv_pcm_subformat {
#define SNDRV_PCM_INFO_JOINT_DUPLEX 0x00200000 /* playback and capture stream are somewhat correlated */
#define SNDRV_PCM_INFO_SYNC_START 0x00400000 /* pcm support some kind of sync go */
#define SNDRV_PCM_INFO_NO_PERIOD_WAKEUP 0x00800000 /* period wakeup can be disabled */
+#define SNDRV_PCM_INFO_HAS_WALL_CLOCK 0x01000000 /* has audio wall clock for audio/system time sync */
enum sndrv_pcm_state {
SNDRV_PCM_STATE_OPEN = 0, /* stream is open */
@@ -426,7 +427,8 @@ struct sndrv_pcm_status {
sndrv_pcm_uframes_t avail_max; /* max frames available on hw since last status */
sndrv_pcm_uframes_t overrange; /* count of ADC (capture) overrange detections from last status */
int suspended_state; /* suspended stream state */
- unsigned char reserved[60]; /* must be filled with zero */
+ struct timespec audio_tstamp; /* from sample counter or wall clock */
+ unsigned char reserved[60-sizeof(struct timespec)]; /* must be filled with zero */
};
struct sndrv_pcm_mmap_status {
@@ -435,6 +437,7 @@ struct sndrv_pcm_mmap_status {
sndrv_pcm_uframes_t hw_ptr; /* RO: hw ptr (0...boundary-1) */
struct timespec tstamp; /* Timestamp */
int suspended_state; /* RO: suspended stream state */
+ struct timespec audio_tstamp; /* from sample counter or wall clock */
};
struct sndrv_pcm_mmap_control {
diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c
index 65c7646..5880057 100644
--- a/src/pcm/pcm.c
+++ b/src/pcm/pcm.c
@@ -3124,6 +3124,26 @@ int snd_pcm_hw_params_can_disable_period_wakeup(const snd_pcm_hw_params_t *param
}
/**
+ * \brief Check if hardware supports audio wallclock timestamps
+ * \param params Configuration space
+ * \retval 0 Hardware doesn't support audio wallclock timestamps
+ * \retval 1 Hardware supports audio wallclock timestamps
+ *
+ * This function should only be called when the configuration space
+ * contains a single configuration. Call #snd_pcm_hw_params to choose
+ * a single configuration from the configuration space.
+ */
+int snd_pcm_hw_params_supports_audio_wallclock_ts(const snd_pcm_hw_params_t *params)
+{
+ assert(params);
+ if (CHECK_SANITY(params->info == ~0U)) {
+ SNDMSG("invalid PCM info field");
+ return 0; /* FIXME: should be a negative error? */
+ }
+ return !!(params->info & SNDRV_PCM_INFO_HAS_WALL_CLOCK);
+}
+
+/**
* \brief Get rate exact info from a configuration space
* \param params Configuration space
* \param rate_num Pointer to returned rate numerator
@@ -6214,6 +6234,17 @@ void snd_pcm_status_get_htstamp(const snd_pcm_status_t *obj, snd_htimestamp_t *p
use_default_symbol_version(__snd_pcm_status_get_htstamp, snd_pcm_status_get_htstamp, ALSA_0.9.0rc8);
/**
+ * \brief Get "now" hi-res audio timestamp from a PCM status container
+ * \param obj pointer to #snd_pcm_status_t
+ * \param ptr Pointer to returned timestamp
+ */
+void snd_pcm_status_get_audio_htstamp(const snd_pcm_status_t *obj, snd_htimestamp_t *ptr)
+{
+ assert(obj && ptr);
+ *ptr = obj->audio_tstamp;
+}
+
+/**
* \brief Get delay from a PCM status container (see #snd_pcm_delay)
* \return Delay in frames
*
diff --git a/test/audio_time.c b/test/audio_time.c
index a910783..03817c7 100644
--- a/test/audio_time.c
+++ b/test/audio_time.c
@@ -33,6 +33,7 @@ long long timediff(snd_htimestamp_t t1, snd_htimestamp_t t2)
void gettimestamp(snd_pcm_t *handle, snd_htimestamp_t *timestamp,
snd_htimestamp_t *trigger_timestamp,
+ snd_htimestamp_t *audio_timestamp,
snd_pcm_uframes_t *avail, snd_pcm_sframes_t *delay)
{
int err;
@@ -45,6 +46,7 @@ void gettimestamp(snd_pcm_t *handle, snd_htimestamp_t *timestamp,
}
snd_pcm_status_get_trigger_htstamp(status, trigger_timestamp);
snd_pcm_status_get_htstamp(status, timestamp);
+ snd_pcm_status_get_audio_htstamp(status, audio_timestamp);
*avail = snd_pcm_status_get_avail(status);
*delay = snd_pcm_status_get_delay(status);
}
@@ -53,6 +55,7 @@ void gettimestamp(snd_pcm_t *handle, snd_htimestamp_t *timestamp,
#define PCM_LINK /* sync start for playback and capture */
#define TRACK_CAPTURE /* dump capture timing info */
#define TRACK_PLAYBACK /* dump playback timing info */
+#define TRACK_SAMPLE_COUNTS /* show difference between sample counters and audiotimestamps returned by driver */
#define PLAYBACK_BUFFERS 4
@@ -65,9 +68,13 @@ int main(void)
snd_pcm_sframes_t frames;
snd_htimestamp_t tstamp_c, tstamp_p;
snd_htimestamp_t trigger_tstamp_c, trigger_tstamp_p;
+ snd_htimestamp_t audio_tstamp_c, audio_tstamp_p;
unsigned char buffer_p[PERIOD*4*4];
unsigned char buffer_c[PERIOD*4*4];
+ snd_pcm_hw_params_t *hwparams_p;
+ snd_pcm_hw_params_t *hwparams_c;
+
snd_pcm_sw_params_t *swparams_p;
snd_pcm_sw_params_t *swparams_c;
@@ -94,6 +101,18 @@ int main(void)
goto _exit;
}
+ snd_pcm_hw_params_alloca(&hwparams_p);
+ /* get the current hwparams */
+ err = snd_pcm_hw_params_current(handle_p, hwparams_p);
+ if (err < 0) {
+ printf("Unable to determine current hwparams_p: %s\n", snd_strerror(err));
+ goto _exit;
+ }
+ if (snd_pcm_hw_params_supports_audio_wallclock_ts(hwparams_p))
+ printf("Playback relies on audio wallclock timestamps\n");
+ else
+ printf("Playback relies on audio sample counter timestamps\n");
+
snd_pcm_sw_params_alloca(&swparams_p);
/* get the current swparams */
err = snd_pcm_sw_params_current(handle_p, swparams_p);
@@ -131,6 +150,18 @@ int main(void)
goto _exit;
}
+ snd_pcm_hw_params_alloca(&hwparams_c);
+ /* get the current hwparams */
+ err = snd_pcm_hw_params_current(handle_c, hwparams_c);
+ if (err < 0) {
+ printf("Unable to determine current hwparams_c: %s\n", snd_strerror(err));
+ goto _exit;
+ }
+ if (snd_pcm_hw_params_supports_audio_wallclock_ts(hwparams_c))
+ printf("Capture relies on audio wallclock timestamps\n");
+ else
+ printf("Capture relies on audio sample counter timestamps\n");
+
snd_pcm_sw_params_alloca(&swparams_c);
/* get the current swparams */
err = snd_pcm_sw_params_current(handle_c, swparams_c);
@@ -202,26 +233,43 @@ int main(void)
frame_count_p += frames;
#if defined(TRACK_PLAYBACK)
- gettimestamp(handle_p, &tstamp_p, &trigger_tstamp_p, &avail_p, &delay_p);
+ gettimestamp(handle_p, &tstamp_p, &trigger_tstamp_p, &audio_tstamp_p, &avail_p, &delay_p);
+#if defined(TRACK_SAMPLE_COUNTS)
curr_count_p = frame_count_p - delay_p; /* written minus queued */
- printf("playback: systime: %lli nsec, sample time %lli nsec \tsystime delta %lli \n",
- timediff(tstamp_p,trigger_tstamp_p),
- (long long)round(((float)curr_count_p * 1000000000.0 / 48000.0)),
- timediff(tstamp_p, trigger_tstamp_p) - (long long)round((double)curr_count_p * 1000000000.0 / 48000.0)
+ printf("playback: curr_count %lli driver count %lli, delta %lli\n",
+ (long long)curr_count_p * 1000000000LL / 48000 ,
+ timestamp2ns(audio_tstamp_p),
+ (long long)curr_count_p * 1000000000LL / 48000 - timestamp2ns(audio_tstamp_p)
+ );
+#endif
+
+ printf("playback: systime: %lli nsec, audio time %lli nsec, \tsystime delta %lli\n",
+ timediff(tstamp_p, trigger_tstamp_p),
+ timestamp2ns(audio_tstamp_p),
+ timediff(tstamp_p, trigger_tstamp_p) - timestamp2ns(audio_tstamp_p)
);
#endif
#if defined(TRACK_CAPTURE)
- gettimestamp(handle_c, &tstamp_c, &trigger_tstamp_c, &avail_c, &delay_c);
+ gettimestamp(handle_c, &tstamp_c, &trigger_tstamp_c, &audio_tstamp_c, &avail_c, &delay_c);
+#if defined(TRACK_SAMPLE_COUNTS)
curr_count_c = frame_count_c + delay_c; /* read plus queued */
- printf("\t capture: systime: %lli nsec, sample time %lli nsec \tsystime delta %lli \n",
- timediff(tstamp_c,trigger_tstamp_c),
- (long long)round(((float)curr_count_c * 1000000000.0 / 48000.0)),
- timediff(tstamp_c, trigger_tstamp_c) - (long long)round((double)curr_count_c * 1000000000.0 / 48000.0)
+
+ printf("capture: curr_count %lli driver count %lli, delta %lli\n",
+ (long long)curr_count_c * 1000000000LL / 48000 ,
+ timestamp2ns(audio_tstamp_c),
+ (long long)curr_count_c * 1000000000LL / 48000 - timestamp2ns(audio_tstamp_c)
+ );
+#endif
+
+ printf("\t capture: systime: %lli nsec, audio time %lli nsec, \tsystime delta %lli\n",
+ timediff(tstamp_c, trigger_tstamp_c),
+ timestamp2ns(audio_tstamp_c),
+ timediff(tstamp_c, trigger_tstamp_c) - timestamp2ns(audio_tstamp_c)
);
#endif
--
1.8.0

View File

@ -0,0 +1,39 @@
From 2b49df0c554cb9c7fc717dcf82d1b8f5310eef62 Mon Sep 17 00:00:00 2001
From: Clemens Ladisch <clemens@ladisch.de>
Date: Sun, 28 Oct 2012 12:30:29 +0100
Subject: [PATCH 32/35] pcm: fix 64-bit SNDRV_PCM_IOCTL_STATUS ABI breakage
Commit cf40ea169aad (pcm: support for audio timestamps) added the new
audio_tstamp field to struct sndrv_pcm_status. However, struct timespec
requires 64-bit alignment, so the 64-bit compiler would insert
32 bits of padding before this field, which broke SNDRV_PCM_IOCTL_STATUS
with error messages like this:
kernel: unknown ioctl = 0x80984120
To solve this, insert the padding explicitly so that it can be taken
into account when calculating the ABI structure size.
Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
---
include/sound/asound.h | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/include/sound/asound.h b/include/sound/asound.h
index 16d03e8..8fdad91 100644
--- a/include/sound/asound.h
+++ b/include/sound/asound.h
@@ -427,8 +427,9 @@ struct sndrv_pcm_status {
sndrv_pcm_uframes_t avail_max; /* max frames available on hw since last status */
sndrv_pcm_uframes_t overrange; /* count of ADC (capture) overrange detections from last status */
int suspended_state; /* suspended stream state */
+ u_int32_t reserved_alignment; /* must be filled with zero */
struct timespec audio_tstamp; /* from sample counter or wall clock */
- unsigned char reserved[60-sizeof(struct timespec)]; /* must be filled with zero */
+ unsigned char reserved[56-sizeof(struct timespec)]; /* must be filled with zero */
};
struct sndrv_pcm_mmap_status {
--
1.8.0

View File

@ -0,0 +1,34 @@
From edcd677bf2065c560ef578940bab8f0aacddf0e6 Mon Sep 17 00:00:00 2001
From: Jaroslav Kysela <perex@perex.cz>
Date: Tue, 30 Oct 2012 11:43:07 +0100
Subject: [PATCH 33/35] PCM: Fix memory leak for pcm empty and asym plugins
The init-only plugins do not have own pcm handle, so free the references
to open function immediately after open.
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
---
src/pcm/pcm.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c
index 5880057..359d295 100644
--- a/src/pcm/pcm.c
+++ b/src/pcm/pcm.c
@@ -2171,7 +2171,12 @@ static int snd_pcm_open_conf(snd_pcm_t **pcmp, const char *name,
if (open_func) {
err = open_func(pcmp, name, pcm_root, pcm_conf, stream, mode);
if (err >= 0) {
- (*pcmp)->open_func = open_func;
+ if ((*pcmp)->open_func) {
+ /* only init plugin (like empty, asym) */
+ snd_dlobj_cache_put(open_func);
+ } else {
+ (*pcmp)->open_func = open_func;
+ }
err = 0;
} else {
snd_dlobj_cache_put(open_func);
--
1.8.0

View File

@ -0,0 +1,179 @@
From 49dde08641f8c6b480c0d410d4fdb2160752dd9a Mon Sep 17 00:00:00 2001
From: Jaroslav Kysela <perex@perex.cz>
Date: Tue, 30 Oct 2012 13:07:48 +0100
Subject: [PATCH 34/35] Reduce compilation warnings
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
---
src/alisp/alisp.c | 2 +-
src/mixer/simple_none.c | 2 --
src/pcm/pcm_generic.c | 2 +-
src/pcm/pcm_ioplug.c | 2 +-
src/pcm/pcm_ladspa.c | 8 +-------
src/pcm/pcm_mmap_emul.c | 2 --
src/pcm/pcm_route.c | 2 +-
src/pcm/pcm_share.c | 5 +----
src/seq/seqmid.c | 2 +-
9 files changed, 7 insertions(+), 20 deletions(-)
diff --git a/src/alisp/alisp.c b/src/alisp/alisp.c
index 7575f55..5dd5b06 100644
--- a/src/alisp/alisp.c
+++ b/src/alisp/alisp.c
@@ -3256,7 +3256,7 @@ int alsa_lisp(struct alisp_cfg *cfg, struct alisp_instance **_instance)
else
alsa_lisp_free(instance);
- return 0;
+ return retval;
}
void alsa_lisp_free(struct alisp_instance *instance)
diff --git a/src/mixer/simple_none.c b/src/mixer/simple_none.c
index b11e9e8..1c2774a 100644
--- a/src/mixer/simple_none.c
+++ b/src/mixer/simple_none.c
@@ -672,7 +672,6 @@ static int simple_update(snd_mixer_elem_t *melem)
unsigned int caps, pchannels, cchannels;
long pmin, pmax, cmin, cmax;
selem_ctl_t *ctl;
- const char *name;
caps = 0;
pchannels = 0;
@@ -683,7 +682,6 @@ static int simple_update(snd_mixer_elem_t *melem)
cmax = LONG_MIN;
assert(snd_mixer_elem_get_type(melem) == SND_MIXER_ELEM_SIMPLE);
simple = snd_mixer_elem_get_private(melem);
- name = snd_mixer_selem_get_name(melem);
ctl = &simple->ctls[CTL_SINGLE];
if (ctl->elem) {
pchannels = cchannels = ctl->values;
diff --git a/src/pcm/pcm_generic.c b/src/pcm/pcm_generic.c
index 0436439..d56e5d3 100644
--- a/src/pcm/pcm_generic.c
+++ b/src/pcm/pcm_generic.c
@@ -41,7 +41,7 @@ int snd_pcm_generic_close(snd_pcm_t *pcm)
if (generic->close_slave)
err = snd_pcm_close(generic->slave);
free(generic);
- return 0;
+ return err;
}
int snd_pcm_generic_nonblock(snd_pcm_t *pcm, int nonblock)
diff --git a/src/pcm/pcm_ioplug.c b/src/pcm/pcm_ioplug.c
index 9c6275a..a90c844 100644
--- a/src/pcm/pcm_ioplug.c
+++ b/src/pcm/pcm_ioplug.c
@@ -625,7 +625,7 @@ static snd_pcm_sframes_t snd_pcm_ioplug_avail_update(snd_pcm_t *pcm)
snd_pcm_uframes_t avail;
snd_pcm_ioplug_hw_ptr_update(pcm);
- if (io->data->state == SNDRV_PCM_STATE_XRUN)
+ if (io->data->state == SND_PCM_STATE_XRUN)
return -EPIPE;
if (pcm->stream == SND_PCM_STREAM_CAPTURE &&
pcm->access != SND_PCM_ACCESS_RW_INTERLEAVED &&
diff --git a/src/pcm/pcm_ladspa.c b/src/pcm/pcm_ladspa.c
index 31e2875..0a9c52e 100644
--- a/src/pcm/pcm_ladspa.c
+++ b/src/pcm/pcm_ladspa.c
@@ -612,8 +612,7 @@ static int snd_pcm_ladspa_allocate_instances(snd_pcm_t *pcm, snd_pcm_ladspa_t *l
{
struct list_head *list, *pos;
unsigned int depth, idx, count;
- unsigned int in_channel, out_channel;
- unsigned int in_channels, out_channels;
+ unsigned int in_channels;
unsigned int in_ports, out_ports;
snd_pcm_ladspa_instance_t *instance = NULL;
int err;
@@ -622,11 +621,8 @@ static int snd_pcm_ladspa_allocate_instances(snd_pcm_t *pcm, snd_pcm_ladspa_t *l
in_channels = ladspa->channels > 0 ? ladspa->channels :
(pcm->stream == SND_PCM_STREAM_PLAYBACK ? pcm->channels : ladspa->plug.gen.slave->channels);
depth = 0;
- out_channels = 0;
list_for_each(pos, list) {
snd_pcm_ladspa_plugin_t *plugin = list_entry(pos, snd_pcm_ladspa_plugin_t, list);
- if (pos->next == list) /* last entry */
- out_channels = pcm->stream == SND_PCM_STREAM_PLAYBACK ? ladspa->plug.gen.slave->channels : pcm->channels;
in_ports = snd_pcm_ladspa_count_ports(plugin, LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO);
out_ports = snd_pcm_ladspa_count_ports(plugin, LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO);
count = 1;
@@ -636,8 +632,6 @@ static int snd_pcm_ladspa_allocate_instances(snd_pcm_t *pcm, snd_pcm_ladspa_t *l
else
plugin->policy = SND_PCM_LADSPA_POLICY_NONE;
}
- in_channel = 0;
- out_channel = 0;
for (idx = 0; idx < count; idx++) {
instance = (snd_pcm_ladspa_instance_t *)calloc(1, sizeof(snd_pcm_ladspa_instance_t));
if (instance == NULL)
diff --git a/src/pcm/pcm_mmap_emul.c b/src/pcm/pcm_mmap_emul.c
index 236fe69..811cb1c 100644
--- a/src/pcm/pcm_mmap_emul.c
+++ b/src/pcm/pcm_mmap_emul.c
@@ -332,9 +332,7 @@ static snd_pcm_sframes_t snd_pcm_mmap_emul_avail_update(snd_pcm_t *pcm)
{
mmap_emul_t *map = pcm->private_data;
snd_pcm_t *slave = map->gen.slave;
- snd_pcm_sframes_t avail;
- avail = snd_pcm_avail_update(slave);
if (!map->mmap_emul || pcm->stream == SND_PCM_STREAM_PLAYBACK)
map->hw_ptr = *slave->hw.ptr;
else
diff --git a/src/pcm/pcm_route.c b/src/pcm/pcm_route.c
index a3d1695..2beedf6 100644
--- a/src/pcm/pcm_route.c
+++ b/src/pcm/pcm_route.c
@@ -725,7 +725,7 @@ static snd_pcm_chmap_t *snd_pcm_route_get_chmap(snd_pcm_t *pcm)
for (dst = 0; dst < route->params.ndsts; dst++) {
snd_pcm_route_ttable_dst_t *d = &route->params.dsts[dst];
for (src = 0; src < d->nsrcs; src++) {
- int c = d->srcs[src].channel;
+ unsigned int c = d->srcs[src].channel;
if (c < nsrcs && map->pos[c] == SND_CHMAP_NA)
map->pos[c] = slave_map->pos[dst];
}
diff --git a/src/pcm/pcm_share.c b/src/pcm/pcm_share.c
index 56a8685..936e2f9 100644
--- a/src/pcm/pcm_share.c
+++ b/src/pcm/pcm_share.c
@@ -136,18 +136,15 @@ static snd_pcm_uframes_t snd_pcm_share_slave_avail(snd_pcm_share_slave_t *slave)
static snd_pcm_uframes_t _snd_pcm_share_slave_forward(snd_pcm_share_slave_t *slave)
{
struct list_head *i;
- snd_pcm_uframes_t buffer_size, boundary;
- snd_pcm_uframes_t slave_appl_ptr;
+ snd_pcm_uframes_t buffer_size;
snd_pcm_sframes_t frames, safety_frames;
snd_pcm_sframes_t min_frames, max_frames;
snd_pcm_uframes_t avail, slave_avail;
snd_pcm_uframes_t slave_hw_avail;
slave_avail = snd_pcm_share_slave_avail(slave);
- boundary = slave->pcm->boundary;
buffer_size = slave->pcm->buffer_size;
min_frames = slave_avail;
max_frames = 0;
- slave_appl_ptr = *slave->pcm->appl.ptr;
list_for_each(i, &slave->clients) {
snd_pcm_share_t *share = list_entry(i, snd_pcm_share_t, list);
snd_pcm_t *pcm = share->pcm;
diff --git a/src/seq/seqmid.c b/src/seq/seqmid.c
index 2ff7e8d..7d8bf1a 100644
--- a/src/seq/seqmid.c
+++ b/src/seq/seqmid.c
@@ -423,7 +423,7 @@ int snd_seq_parse_address(snd_seq_t *seq, snd_seq_addr_t *addr, const char *arg)
return -EINVAL;
cinfo.client = -1;
while (snd_seq_query_next_client(seq, &cinfo) >= 0) {
- if ((strlen(cinfo.name) == len) &&
+ if ((strlen(cinfo.name) == (size_t)len) &&
! strncmp(arg, cinfo.name, len)) {
addr->client = cinfo.client;
return 0;
--
1.8.0

View File

@ -0,0 +1,222 @@
From 3fd4ab9be0db7c7430ebd258f2717a976381715d Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@suse.de>
Date: Tue, 13 Nov 2012 16:16:26 +0100
Subject: [PATCH 35/35] PCM: Avoid busy loop in snd_pcm_write_areas() with
rate plugin
snd_pcm_write_areas() tries to wait until avail >= avail_min condition
is satisfied. This doesn't work always well when a rate plugin is in
the play.
When a partial data with a smaller size than a period is written, the
rate plugin doesn't transfer the data immediately to the slave PCM,
but kept in an internal buffer and it changes only the hwptr of the
plugin. Thus, the condition "avail < avail_min" is triggered for a
wait check although the underlying slave PCM has enough room. This
results in a call of snd_pcm_wait() which returns immediately after
poll() call, and the snd_pcm_write_areas() loop continues. As a
consequence, it falls into a CPU hog.
This patch fixes that busy loop by introducing a new fast_ops to check
the availability for wait of avail_min. Then a plugin can ask the
slave PCM whether the wait is required (or possible).
A few plugins like multi plugin need a special handling. Otherwise a
generic plugin function can be used.
Reported-by: Trent Piepho <tpiepho@gmail.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
src/pcm/pcm.c | 8 ++++----
src/pcm/pcm_generic.c | 6 ++++++
src/pcm/pcm_generic.h | 4 +++-
src/pcm/pcm_hooks.c | 1 +
src/pcm/pcm_local.h | 11 +++++++++++
src/pcm/pcm_meter.c | 1 +
src/pcm/pcm_mmap_emul.c | 1 +
src/pcm/pcm_multi.c | 8 ++++++++
src/pcm/pcm_plugin.c | 1 +
src/pcm/pcm_rate.c | 1 +
10 files changed, 37 insertions(+), 5 deletions(-)
diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c
index 359d295..f8b68ed 100644
--- a/src/pcm/pcm.c
+++ b/src/pcm/pcm.c
@@ -2357,7 +2357,7 @@ int snd_pcm_open_named_slave(snd_pcm_t **pcmp, const char *name,
*/
int snd_pcm_wait(snd_pcm_t *pcm, int timeout)
{
- if (snd_pcm_mmap_avail(pcm) >= pcm->avail_min) {
+ if (!snd_pcm_may_wait_for_avail_min(pcm, snd_pcm_mmap_avail(pcm))) {
/* check more precisely */
switch (snd_pcm_state(pcm)) {
case SND_PCM_STATE_XRUN:
@@ -6776,14 +6776,14 @@ snd_pcm_sframes_t snd_pcm_write_areas(snd_pcm_t *pcm, const snd_pcm_channel_area
goto _end;
}
if ((state == SND_PCM_STATE_RUNNING &&
- (snd_pcm_uframes_t)avail < pcm->avail_min &&
- size > (snd_pcm_uframes_t)avail)) {
+ size > (snd_pcm_uframes_t)avail &&
+ snd_pcm_may_wait_for_avail_min(pcm, avail))) {
if (pcm->mode & SND_PCM_NONBLOCK) {
err = -EAGAIN;
goto _end;
}
- err = snd_pcm_wait(pcm, -1);
+ err = snd_pcm_wait_nocheck(pcm, -1);
if (err < 0)
break;
goto _again;
diff --git a/src/pcm/pcm_generic.c b/src/pcm/pcm_generic.c
index d56e5d3..5fc4888 100644
--- a/src/pcm/pcm_generic.c
+++ b/src/pcm/pcm_generic.c
@@ -341,4 +341,10 @@ int snd_pcm_generic_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map)
return snd_pcm_set_chmap(generic->slave, map);
}
+int snd_pcm_generic_may_wait_for_avail_min(snd_pcm_t *pcm, snd_pcm_uframes_t avail ATTRIBUTE_UNUSED)
+{
+ snd_pcm_generic_t *generic = pcm->private_data;
+ return snd_pcm_may_wait_for_avail_min(generic->slave, snd_pcm_mmap_avail(generic->slave));
+}
+
#endif /* DOC_HIDDEN */
diff --git a/src/pcm/pcm_generic.h b/src/pcm/pcm_generic.h
index 916c6ec..d189077 100644
--- a/src/pcm/pcm_generic.h
+++ b/src/pcm/pcm_generic.h
@@ -109,6 +109,8 @@ typedef struct {
snd1_pcm_generic_get_chmap
#define snd_pcm_generic_set_chmap \
snd1_pcm_generic_set_chmap
+#define snd_pcm_generic_may_wait_for_avail_min \
+ snd1_pcm_generic_may_wait_for_avail_min
int snd_pcm_generic_close(snd_pcm_t *pcm);
int snd_pcm_generic_nonblock(snd_pcm_t *pcm, int nonblock);
@@ -158,5 +160,5 @@ int snd_pcm_generic_munmap(snd_pcm_t *pcm);
snd_pcm_chmap_query_t **snd_pcm_generic_query_chmaps(snd_pcm_t *pcm);
snd_pcm_chmap_t *snd_pcm_generic_get_chmap(snd_pcm_t *pcm);
int snd_pcm_generic_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map);
-
+int snd_pcm_generic_may_wait_for_avail_min(snd_pcm_t *pcm, snd_pcm_uframes_t avail);
diff --git a/src/pcm/pcm_hooks.c b/src/pcm/pcm_hooks.c
index 0feb4a3..f837282 100644
--- a/src/pcm/pcm_hooks.c
+++ b/src/pcm/pcm_hooks.c
@@ -199,6 +199,7 @@ static const snd_pcm_fast_ops_t snd_pcm_hooks_fast_ops = {
.poll_descriptors_count = snd_pcm_generic_poll_descriptors_count,
.poll_descriptors = snd_pcm_generic_poll_descriptors,
.poll_revents = snd_pcm_generic_poll_revents,
+ .may_wait_for_avail_min = snd_pcm_generic_may_wait_for_avail_min,
};
/**
diff --git a/src/pcm/pcm_local.h b/src/pcm/pcm_local.h
index e7798fd..8cf7c3d 100644
--- a/src/pcm/pcm_local.h
+++ b/src/pcm/pcm_local.h
@@ -177,6 +177,7 @@ typedef struct {
int (*poll_descriptors_count)(snd_pcm_t *pcm);
int (*poll_descriptors)(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space);
int (*poll_revents)(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents);
+ int (*may_wait_for_avail_min)(snd_pcm_t *pcm, snd_pcm_uframes_t avail);
} snd_pcm_fast_ops_t;
struct _snd_pcm {
@@ -984,3 +985,13 @@ _snd_pcm_parse_config_chmaps(snd_config_t *conf);
snd_pcm_chmap_t *
_snd_pcm_choose_fixed_chmap(snd_pcm_t *pcm, snd_pcm_chmap_query_t * const *maps);
+/* return true if the PCM stream may wait to get avail_min space */
+static inline int snd_pcm_may_wait_for_avail_min(snd_pcm_t *pcm, snd_pcm_uframes_t avail)
+{
+ if (avail >= pcm->avail_min)
+ return 0;
+ if (pcm->fast_ops->may_wait_for_avail_min)
+ return pcm->fast_ops->may_wait_for_avail_min(pcm, avail);
+ return 1;
+}
+
diff --git a/src/pcm/pcm_meter.c b/src/pcm/pcm_meter.c
index 42a125e..e60b92d 100644
--- a/src/pcm/pcm_meter.c
+++ b/src/pcm/pcm_meter.c
@@ -545,6 +545,7 @@ static const snd_pcm_fast_ops_t snd_pcm_meter_fast_ops = {
.poll_descriptors_count = snd_pcm_generic_poll_descriptors_count,
.poll_descriptors = snd_pcm_generic_poll_descriptors,
.poll_revents = snd_pcm_generic_poll_revents,
+ .may_wait_for_avail_min = snd_pcm_generic_may_wait_for_avail_min,
};
/**
diff --git a/src/pcm/pcm_mmap_emul.c b/src/pcm/pcm_mmap_emul.c
index 811cb1c..67d2e05 100644
--- a/src/pcm/pcm_mmap_emul.c
+++ b/src/pcm/pcm_mmap_emul.c
@@ -400,6 +400,7 @@ static const snd_pcm_fast_ops_t snd_pcm_mmap_emul_fast_ops = {
.poll_descriptors = snd_pcm_generic_poll_descriptors,
.poll_descriptors_count = snd_pcm_generic_poll_descriptors_count,
.poll_revents = snd_pcm_generic_poll_revents,
+ .may_wait_for_avail_min = snd_pcm_generic_may_wait_for_avail_min,
};
#ifndef DOC_HIDDEN
diff --git a/src/pcm/pcm_multi.c b/src/pcm/pcm_multi.c
index ffb1b53..2db82c0 100644
--- a/src/pcm/pcm_multi.c
+++ b/src/pcm/pcm_multi.c
@@ -739,6 +739,13 @@ static int snd_pcm_multi_mmap(snd_pcm_t *pcm)
return 0;
}
+static int snd_pcm_multi_may_wait_for_avail_min(snd_pcm_t *pcm, snd_pcm_uframes_t avail)
+{
+ snd_pcm_multi_t *multi = pcm->private_data;
+ snd_pcm_t *slave = multi->slaves[multi->master_slave].pcm;
+ return snd_pcm_may_wait_for_avail_min(slave, snd_pcm_mmap_avail(slave));
+}
+
static snd_pcm_chmap_query_t **snd_pcm_multi_query_chmaps(snd_pcm_t *pcm)
{
snd_pcm_multi_t *multi = pcm->private_data;
@@ -937,6 +944,7 @@ static const snd_pcm_fast_ops_t snd_pcm_multi_fast_ops = {
.poll_descriptors_count = snd_pcm_multi_poll_descriptors_count,
.poll_descriptors = snd_pcm_multi_poll_descriptors,
.poll_revents = snd_pcm_multi_poll_revents,
+ .may_wait_for_avail_min = snd_pcm_multi_may_wait_for_avail_min,
};
/**
diff --git a/src/pcm/pcm_plugin.c b/src/pcm/pcm_plugin.c
index d88e117..96218a8 100644
--- a/src/pcm/pcm_plugin.c
+++ b/src/pcm/pcm_plugin.c
@@ -570,6 +570,7 @@ const snd_pcm_fast_ops_t snd_pcm_plugin_fast_ops = {
.poll_descriptors_count = snd_pcm_generic_poll_descriptors_count,
.poll_descriptors = snd_pcm_generic_poll_descriptors,
.poll_revents = snd_pcm_generic_poll_revents,
+ .may_wait_for_avail_min = snd_pcm_generic_may_wait_for_avail_min,
};
#endif
diff --git a/src/pcm/pcm_rate.c b/src/pcm/pcm_rate.c
index 4ba8521..54a3e67 100644
--- a/src/pcm/pcm_rate.c
+++ b/src/pcm/pcm_rate.c
@@ -1234,6 +1234,7 @@ static const snd_pcm_fast_ops_t snd_pcm_rate_fast_ops = {
.poll_descriptors_count = snd_pcm_generic_poll_descriptors_count,
.poll_descriptors = snd_pcm_generic_poll_descriptors,
.poll_revents = snd_pcm_rate_poll_revents,
+ .may_wait_for_avail_min = snd_pcm_generic_may_wait_for_avail_min,
};
static const snd_pcm_ops_t snd_pcm_rate_ops = {
--
1.8.0

View File

@ -1,3 +1,13 @@
-------------------------------------------------------------------
Tue Nov 13 16:39:26 CET 2012 - tiwai@suse.de
- backport fixes from upstream tree:
0031-pcm-support-for-audio-timestamps.patch
0032-pcm-fix-64-bit-SNDRV_PCM_IOCTL_STATUS-ABI-breakage.patch
0033-PCM-Fix-memory-leak-for-pcm-empty-and-asym-plugins.patch
0034-Reduce-compilation-warnings.patch
0035-PCM-Avoid-busy-loop-in-snd_pcm_write_areas-with-rate.patch
------------------------------------------------------------------- -------------------------------------------------------------------
Wed Oct 17 10:05:36 CEST 2012 - tiwai@suse.de Wed Oct 17 10:05:36 CEST 2012 - tiwai@suse.de

View File

@ -82,6 +82,11 @@ Patch26: 0026-PCM-Fill-SND_CHMAP_NA-to-silent-channels-in-route-pl.patch
Patch27: 0027-PCM-Fix-infinite-loop-in-htimestamp-of-dmix-dsnoop-a.patch Patch27: 0027-PCM-Fix-infinite-loop-in-htimestamp-of-dmix-dsnoop-a.patch
Patch28: 0028-test-add-audio_time.patch Patch28: 0028-test-add-audio_time.patch
Patch30: 0030-PCM-Fix-the-invalid-snd_pcm_close-calls-in-rate-plug.patch Patch30: 0030-PCM-Fix-the-invalid-snd_pcm_close-calls-in-rate-plug.patch
Patch31: 0031-pcm-support-for-audio-timestamps.patch
Patch32: 0032-pcm-fix-64-bit-SNDRV_PCM_IOCTL_STATUS-ABI-breakage.patch
Patch33: 0033-PCM-Fix-memory-leak-for-pcm-empty-and-asym-plugins.patch
Patch34: 0034-Reduce-compilation-warnings.patch
Patch35: 0035-PCM-Avoid-busy-loop-in-snd_pcm_write_areas-with-rate.patch
# #
Patch99: alsa-lib-doxygen-avoid-crash-for-11.3.diff Patch99: alsa-lib-doxygen-avoid-crash-for-11.3.diff
Url: http://www.alsa-project.org/ Url: http://www.alsa-project.org/
@ -162,6 +167,11 @@ Architecture.
%patch27 -p1 %patch27 -p1
%patch28 -p1 %patch28 -p1
%patch30 -p1 %patch30 -p1
%patch31 -p1
%patch32 -p1
%patch33 -p1
%patch34 -p1
%patch35 -p1
%if %suse_version == 1130 %if %suse_version == 1130
%patch99 -p1 %patch99 -p1
%endif %endif