diff --git a/Makefile.am b/Makefile.am index c484d4da..ff4c963a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -16,7 +16,7 @@ SUBDIRS += alsalisp endif endif SUBDIRS += test utils -EXTRA_DIST=ChangeLog INSTALL TODO NOTES configure gitcompile libtool \ +EXTRA_DIST=README.md ChangeLog INSTALL TODO NOTES configure gitcompile libtool \ depcomp version MEMORY-LEAK m4/attributes.m4 AUTOMAKE_OPTIONS=foreign diff --git a/include/pcm.h b/include/pcm.h index 5b078231..e300b951 100644 --- a/include/pcm.h +++ b/include/pcm.h @@ -350,6 +350,20 @@ typedef enum _snd_pcm_tstamp_type { SND_PCM_TSTAMP_TYPE_LAST = SND_PCM_TSTAMP_TYPE_MONOTONIC_RAW, } snd_pcm_tstamp_type_t; +typedef enum _snd_pcm_audio_tstamp_type { + /** + * first definition for backwards compatibility only, + * maps to wallclock/link time for HDAudio playback and DEFAULT/DMA time for everything else + */ + SND_PCM_AUDIO_TSTAMP_TYPE_COMPAT = 0, + SND_PCM_AUDIO_TSTAMP_TYPE_DEFAULT = 1, /**< DMA time, reported as per hw_ptr */ + SND_PCM_AUDIO_TSTAMP_TYPE_LINK = 2, /**< link time reported by sample or wallclock counter, reset on startup */ + SND_PCM_AUDIO_TSTAMP_TYPE_LINK_ABSOLUTE = 3, /**< link time reported by sample or wallclock counter, not reset on startup */ + SND_PCM_AUDIO_TSTAMP_TYPE_LINK_ESTIMATED = 4, /**< link time estimated indirectly */ + SND_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED = 5, /**< link time synchronized with system time */ + SND_PCM_AUDIO_TSTAMP_TYPE_LAST = SND_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED +} snd_pcm_audio_tstamp_type_t; + typedef struct _snd_pcm_audio_tstamp_config { /* 5 of max 16 bits used */ unsigned int type_requested:4; diff --git a/include/sound/uapi/asoc.h b/include/sound/uapi/asoc.h index 4efb4ec4..f32c5697 100644 --- a/include/sound/uapi/asoc.h +++ b/include/sound/uapi/asoc.h @@ -169,16 +169,22 @@ #define SND_SOC_TPLG_LNK_FLGBIT_VOICE_WAKEUP (1 << 3) /* DAI topology BCLK parameter - * For the backwards capability, by default codec is bclk master + * For the backwards capability, by default codec is bclk provider */ -#define SND_SOC_TPLG_BCLK_CM 0 /* codec is bclk master */ -#define SND_SOC_TPLG_BCLK_CS 1 /* codec is bclk slave */ +#define SND_SOC_TPLG_BCLK_CP 0 /* codec is bclk provider */ +#define SND_SOC_TPLG_BCLK_CC 1 /* codec is bclk consumer */ +/* keep previous definitions for compatibility */ +#define SND_SOC_TPLG_BCLK_CM SND_SOC_TPLG_BCLK_CP +#define SND_SOC_TPLG_BCLK_CS SND_SOC_TPLG_BCLK_CC /* DAI topology FSYNC parameter - * For the backwards capability, by default codec is fsync master + * For the backwards capability, by default codec is fsync provider */ -#define SND_SOC_TPLG_FSYNC_CM 0 /* codec is fsync master */ -#define SND_SOC_TPLG_FSYNC_CS 1 /* codec is fsync slave */ +#define SND_SOC_TPLG_FSYNC_CP 0 /* codec is fsync provider */ +#define SND_SOC_TPLG_FSYNC_CC 1 /* codec is fsync consumer */ +/* keep previous definitions for compatibility */ +#define SND_SOC_TPLG_FSYNC_CM SND_SOC_TPLG_FSYNC_CP +#define SND_SOC_TPLG_FSYNC_CS SND_SOC_TPLG_FSYNC_CC /* * Block Header. @@ -335,8 +341,8 @@ struct snd_soc_tplg_hw_config { __u8 clock_gated; /* SND_SOC_TPLG_DAI_CLK_GATE_ value */ __u8 invert_bclk; /* 1 for inverted BCLK, 0 for normal */ __u8 invert_fsync; /* 1 for inverted frame clock, 0 for normal */ - __u8 bclk_master; /* SND_SOC_TPLG_BCLK_ value */ - __u8 fsync_master; /* SND_SOC_TPLG_FSYNC_ value */ + __u8 bclk_provider; /* SND_SOC_TPLG_BCLK_ value */ + __u8 fsync_provider; /* SND_SOC_TPLG_FSYNC_ value */ __u8 mclk_direction; /* SND_SOC_TPLG_MCLK_ value */ __le16 reserved; /* for 32bit alignment */ __le32 mclk_rate; /* MCLK or SYSCLK freqency in Hz */ diff --git a/include/topology.h b/include/topology.h index 1f52e66e..d1feee4d 100644 --- a/include/topology.h +++ b/include/topology.h @@ -658,8 +658,8 @@ extern "C" { * * id "1" # used for binding to the config * format "I2S" # physical audio format. - * bclk "master" # Platform is master of bit clock - * fsync "slave" # Platform is slave of fsync + * bclk "codec_provider" # Codec provides the bit clock + * fsync "codec_consumer" # Codec follows the fsync * } * * @@ -1028,8 +1028,8 @@ struct snd_tplg_hw_config_template { unsigned char clock_gated; /* SND_SOC_TPLG_DAI_CLK_GATE_ value */ unsigned char invert_bclk; /* 1 for inverted BCLK, 0 for normal */ unsigned char invert_fsync; /* 1 for inverted frame clock, 0 for normal */ - unsigned char bclk_master; /* SND_SOC_TPLG_BCLK_ value */ - unsigned char fsync_master; /* SND_SOC_TPLG_FSYNC_ value */ + unsigned char bclk_provider; /* SND_SOC_TPLG_BCLK_ value */ + unsigned char fsync_provider; /* SND_SOC_TPLG_FSYNC_ value */ unsigned char mclk_direction; /* SND_SOC_TPLG_MCLK_ value */ unsigned short reserved; /* for 32bit alignment */ unsigned int mclk_rate; /* MCLK or SYSCLK freqency in Hz */ diff --git a/src/conf.c b/src/conf.c index 7df2b4e7..3c943db2 100644 --- a/src/conf.c +++ b/src/conf.c @@ -887,7 +887,7 @@ static inline int get_hexachar(input_t *input) if (c >= '0' && c <= '9') num |= (c - '0') << 0; else if (c >= 'a' && c <= 'f') num |= (c - 'a') << 0; else if (c >= 'A' && c <= 'F') num |= (c - 'A') << 0; - return c; + return num; } static int get_quotedchar(input_t *input) @@ -1970,11 +1970,14 @@ int _snd_config_load_with_include(snd_config_t *config, snd_input_t *in, SNDERR("%s:%d:%d:%s", fd->name ? fd->name : "_toplevel_", fd->line, fd->column, str); goto _end; } - if (get_char(&input) != LOCAL_UNEXPECTED_EOF) { + err = get_char(&input); + fd = input.current; + if (err != LOCAL_UNEXPECTED_EOF) { SNDERR("%s:%d:%d:Unexpected }", fd->name ? fd->name : "", fd->line, fd->column); err = -EINVAL; goto _end; } + err = 0; _end: while (fd->next) { fd_next = fd->next; diff --git a/src/conf/cards/USB-Audio.conf b/src/conf/cards/USB-Audio.conf index 9b64af3c..b1b74b02 100644 --- a/src/conf/cards/USB-Audio.conf +++ b/src/conf/cards/USB-Audio.conf @@ -39,6 +39,7 @@ USB-Audio.pcm.iec958_device { # "NoiseBlaster 3000" 42 "USB Sound Blaster HD" 1 "Xonar U7" 1 + "Xonar U7 MKII" 1 "ASUS XONAR U5" 1 "XONAR U5" 1 "XONAR SOUND CARD" 1 diff --git a/src/confmisc.c b/src/confmisc.c index eb8218c1..3ce95c7a 100644 --- a/src/confmisc.c +++ b/src/confmisc.c @@ -419,7 +419,6 @@ int snd_func_concat(snd_config_t **dst, snd_config_t *root, snd_config_t *src, tmp = realloc(res, len + len1 + 1); if (tmp == NULL) { free(ptr); - free(res); err = -ENOMEM; goto __error; } @@ -440,8 +439,8 @@ int snd_func_concat(snd_config_t **dst, snd_config_t *root, snd_config_t *src, err = snd_config_get_id(src, &id); if (err >= 0) err = snd_config_imake_string(dst, id, res); - free(res); __error: + free(res); return err; } #ifndef DOC_HIDDEN diff --git a/src/dlmisc.c b/src/dlmisc.c index c9517c55..1dd91356 100644 --- a/src/dlmisc.c +++ b/src/dlmisc.c @@ -42,13 +42,11 @@ #ifndef PIC struct snd_dlsym_link *snd_dlsym_start = NULL; #endif -#ifdef DL_ORIGIN_AVAILABLE static int snd_plugin_dir_set = 0; static char *snd_plugin_dir = NULL; #endif -#endif -#if defined(DL_ORIGIN_AVAILABLE) && defined(HAVE_LIBPTHREAD) +#ifdef HAVE_LIBPTHREAD static pthread_mutex_t snd_dlpath_mutex = PTHREAD_MUTEX_INITIALIZER; static inline void snd_dlpath_lock(void) @@ -442,12 +440,10 @@ void snd_dlobj_cache_cleanup(void) free(c); } snd_dlobj_unlock(); -#ifdef DL_ORIGIN_AVAILABLE snd_dlpath_lock(); snd_plugin_dir_set = 0; free(snd_plugin_dir); snd_plugin_dir = NULL; snd_dlpath_unlock(); -#endif } #endif diff --git a/src/pcm/pcm_ioplug.c b/src/pcm/pcm_ioplug.c index a437ca32..e141b1f9 100644 --- a/src/pcm/pcm_ioplug.c +++ b/src/pcm/pcm_ioplug.c @@ -107,16 +107,35 @@ static int snd_pcm_ioplug_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *i return snd_pcm_channel_info_shm(pcm, info, -1); } +static int snd_pcm_ioplug_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) +{ + ioplug_priv_t *io = pcm->private_data; + + if (io->data->version >= 0x010001 && + io->data->callback->delay) + return io->data->callback->delay(io->data, delayp); + else { + snd_pcm_ioplug_hw_ptr_update(pcm); + *delayp = snd_pcm_mmap_delay(pcm); + } + return 0; +} + static int snd_pcm_ioplug_status(snd_pcm_t *pcm, snd_pcm_status_t * status) { ioplug_priv_t *io = pcm->private_data; + snd_pcm_sframes_t sd; memset(status, 0, sizeof(*status)); snd_pcm_ioplug_hw_ptr_update(pcm); status->state = io->data->state; status->trigger_tstamp = io->trigger_tstamp; + gettimestamp(&status->tstamp, pcm->tstamp_type); status->avail = snd_pcm_mmap_avail(pcm); status->avail_max = io->avail_max; + if (snd_pcm_ioplug_delay(pcm, &sd) < 0) + sd = snd_pcm_mmap_delay(pcm); + status->delay = sd; return 0; } @@ -132,20 +151,6 @@ static int snd_pcm_ioplug_hwsync(snd_pcm_t *pcm) return 0; } -static int snd_pcm_ioplug_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) -{ - ioplug_priv_t *io = pcm->private_data; - - if (io->data->version >= 0x010001 && - io->data->callback->delay) - return io->data->callback->delay(io->data, delayp); - else { - snd_pcm_ioplug_hw_ptr_update(pcm); - *delayp = snd_pcm_mmap_hw_avail(pcm); - } - return 0; -} - static int snd_pcm_ioplug_reset(snd_pcm_t *pcm) { ioplug_priv_t *io = pcm->private_data; diff --git a/src/pcm/pcm_local.h b/src/pcm/pcm_local.h index fe77e50d..bec5a408 100644 --- a/src/pcm/pcm_local.h +++ b/src/pcm/pcm_local.h @@ -444,7 +444,7 @@ static inline int __snd_pcm_start(snd_pcm_t *pcm) static inline snd_pcm_state_t __snd_pcm_state(snd_pcm_t *pcm) { if (!pcm->fast_ops->state) - return -ENOSYS; + return SND_PCM_STATE_OPEN; return pcm->fast_ops->state(pcm->fast_op_arg); } diff --git a/src/pcm/pcm_mmap.c b/src/pcm/pcm_mmap.c index 9600c383..9cbaae05 100644 --- a/src/pcm/pcm_mmap.c +++ b/src/pcm/pcm_mmap.c @@ -183,7 +183,7 @@ snd_pcm_sframes_t snd_pcm_mmap_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_ufram * \brief Read interleaved frames from a PCM using direct buffer (mmap) * \param pcm PCM handle * \param buffer frames containing buffer - * \param size frames to be written + * \param size frames to be read * \return a positive number of frames actually read otherwise a * negative error code * \retval -EBADFD PCM is not in the right state (#SND_PCM_STATE_PREPARED or #SND_PCM_STATE_RUNNING) diff --git a/src/pcm/pcm_multi.c b/src/pcm/pcm_multi.c index 53c414d5..5fa09b9b 100644 --- a/src/pcm/pcm_multi.c +++ b/src/pcm/pcm_multi.c @@ -1323,7 +1323,6 @@ int _snd_pcm_multi_open(snd_pcm_t **pcmp, const char *name, err = -ENOMEM; goto _free; } - idx = 0; for (idx = 0; idx < channels_count; ++idx) channels_sidx[idx] = -1; idx = 0; diff --git a/src/pcm/pcm_plugin.c b/src/pcm/pcm_plugin.c index 5739cfc2..7ed6f25a 100644 --- a/src/pcm/pcm_plugin.c +++ b/src/pcm/pcm_plugin.c @@ -142,12 +142,6 @@ static int snd_pcm_plugin_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) int err = snd_pcm_delay(plugin->gen.slave, &sd); if (err < 0) return err; - if (pcm->stream == SND_PCM_STREAM_CAPTURE && - pcm->access != SND_PCM_ACCESS_RW_INTERLEAVED && - pcm->access != SND_PCM_ACCESS_RW_NONINTERLEAVED) { - sd += snd_pcm_mmap_capture_avail(pcm); - } - *delayp = sd; return 0; } @@ -460,101 +454,121 @@ snd_pcm_plugin_mmap_commit(snd_pcm_t *pcm, return xfer > 0 ? xfer : err; } -static snd_pcm_sframes_t snd_pcm_plugin_avail_update(snd_pcm_t *pcm) +static snd_pcm_sframes_t +snd_pcm_plugin_sync_hw_ptr_capture(snd_pcm_t *pcm, + snd_pcm_sframes_t slave_size) { snd_pcm_plugin_t *plugin = pcm->private_data; snd_pcm_t *slave = plugin->gen.slave; - snd_pcm_sframes_t slave_size; + const snd_pcm_channel_area_t *areas; + snd_pcm_uframes_t xfer, hw_offset, size; int err; - slave_size = snd_pcm_avail_update(slave); + xfer = snd_pcm_mmap_capture_avail(pcm); + size = pcm->buffer_size - xfer; + areas = snd_pcm_mmap_areas(pcm); + hw_offset = snd_pcm_mmap_hw_offset(pcm); + while (size > 0 && slave_size > 0) { + snd_pcm_uframes_t frames = size; + snd_pcm_uframes_t cont = pcm->buffer_size - hw_offset; + const snd_pcm_channel_area_t *slave_areas; + snd_pcm_uframes_t slave_offset; + snd_pcm_uframes_t slave_frames = ULONG_MAX; + snd_pcm_sframes_t result; + /* As mentioned in the ALSA API (see pcm/pcm.c:942): + * The function #snd_pcm_avail_update() + * have to be called before any mmap begin+commit operation. + * Otherwise the snd_pcm_areas_copy will not called a second time. + * But this is needed, if the ring buffer wrap is reached and + * there is more data available. + */ + slave_size = snd_pcm_avail_update(slave); + result = snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames); + if (result < 0) { + err = result; + goto error; + } + if (frames > cont) + frames = cont; + frames = (plugin->read)(pcm, areas, hw_offset, frames, + slave_areas, slave_offset, &slave_frames); + result = snd_pcm_mmap_commit(slave, slave_offset, slave_frames); + if (result > 0 && (snd_pcm_uframes_t)result != slave_frames) { + snd_pcm_sframes_t res; + res = plugin->undo_read(slave, areas, hw_offset, frames, slave_frames - result); + if (res < 0) { + err = res; + goto error; + } + frames -= res; + } + if (result <= 0) { + err = result; + goto error; + } + snd_pcm_mmap_hw_forward(pcm, frames); + if (frames == cont) + hw_offset = 0; + else + hw_offset += frames; + size -= frames; + slave_size -= slave_frames; + xfer += frames; + } + return (snd_pcm_sframes_t)xfer; +error: + return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; +} + +static snd_pcm_sframes_t snd_pcm_plugin_sync_hw_ptr(snd_pcm_t *pcm, + snd_pcm_uframes_t slave_hw_ptr, + snd_pcm_sframes_t slave_size) +{ if (pcm->stream == SND_PCM_STREAM_CAPTURE && pcm->access != SND_PCM_ACCESS_RW_INTERLEAVED && pcm->access != SND_PCM_ACCESS_RW_NONINTERLEAVED) - goto _capture; - *pcm->hw.ptr = *slave->hw.ptr; + return snd_pcm_plugin_sync_hw_ptr_capture(pcm, slave_size); + *pcm->hw.ptr = slave_hw_ptr; return slave_size; - _capture: - { - const snd_pcm_channel_area_t *areas; - snd_pcm_uframes_t xfer, hw_offset, size; - - xfer = snd_pcm_mmap_capture_avail(pcm); - size = pcm->buffer_size - xfer; - areas = snd_pcm_mmap_areas(pcm); - hw_offset = snd_pcm_mmap_hw_offset(pcm); - while (size > 0 && slave_size > 0) { - snd_pcm_uframes_t frames = size; - snd_pcm_uframes_t cont = pcm->buffer_size - hw_offset; - const snd_pcm_channel_area_t *slave_areas; - snd_pcm_uframes_t slave_offset; - snd_pcm_uframes_t slave_frames = ULONG_MAX; - snd_pcm_sframes_t result; - /* As mentioned in the ALSA API (see pcm/pcm.c:942): - * The function #snd_pcm_avail_update() - * have to be called before any mmap begin+commit operation. - * Otherwise the snd_pcm_areas_copy will not called a second time. - * But this is needed, if the ring buffer wrap is reached and - * there is more data available. - */ - slave_size = snd_pcm_avail_update(slave); - result = snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames); - if (result < 0) { - err = result; - goto error; - } - if (frames > cont) - frames = cont; - frames = (plugin->read)(pcm, areas, hw_offset, frames, - slave_areas, slave_offset, &slave_frames); - result = snd_pcm_mmap_commit(slave, slave_offset, slave_frames); - if (result > 0 && (snd_pcm_uframes_t)result != slave_frames) { - snd_pcm_sframes_t res; - - res = plugin->undo_read(slave, areas, hw_offset, frames, slave_frames - result); - if (res < 0) { - err = res; - goto error; - } - frames -= res; - } - if (result <= 0) { - err = result; - goto error; - } - snd_pcm_mmap_hw_forward(pcm, frames); - if (frames == cont) - hw_offset = 0; - else - hw_offset += frames; - size -= frames; - slave_size -= slave_frames; - xfer += frames; - } - return (snd_pcm_sframes_t)xfer; +} - error: - return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; - } +static snd_pcm_sframes_t snd_pcm_plugin_avail_update(snd_pcm_t *pcm) +{ + snd_pcm_plugin_t *plugin = pcm->private_data; + snd_pcm_t *slave = plugin->gen.slave; + snd_pcm_sframes_t slave_size; + + slave_size = snd_pcm_avail_update(slave); + return snd_pcm_plugin_sync_hw_ptr(pcm, *slave->hw.ptr, slave_size); } static int snd_pcm_plugin_status(snd_pcm_t *pcm, snd_pcm_status_t * status) { snd_pcm_plugin_t *plugin = pcm->private_data; - snd_pcm_sframes_t err, avail; - - /* sync with the latest hw and appl ptrs */ - avail = snd_pcm_plugin_avail_update(pcm); - if (avail < 0) - return avail; + snd_pcm_sframes_t err, diff; err = snd_pcm_status(plugin->gen.slave, status); if (err < 0) return err; - status->appl_ptr = *pcm->appl.ptr; - status->hw_ptr = *pcm->hw.ptr; - status->avail = avail; - status->delay = snd_pcm_mmap_delay(pcm); + snd_pcm_plugin_sync_hw_ptr(pcm, status->hw_ptr, status->avail); + /* + * For capture stream, the situation is more complicated, because + * snd_pcm_plugin_avail_update() commits the data to the slave pcm. + * It means that the slave appl_ptr is updated. Calculate diff and + * update the delay and avail. + * + * This resolves the data inconsistency for immediate calls: + * snd_pcm_avail_update() + * snd_pcm_status() + */ + if (pcm->stream == SND_PCM_STREAM_CAPTURE) { + status->appl_ptr = *pcm->appl.ptr; + diff = pcm_frame_diff(status->appl_ptr, *pcm->appl.ptr, pcm->boundary); + status->avail += diff; + status->delay += diff; + } else { + assert(status->appl_ptr == *pcm->appl.ptr); + } return 0; } diff --git a/src/pcm/pcm_rate.c b/src/pcm/pcm_rate.c index 5bf7dbb9..770aafea 100644 --- a/src/pcm/pcm_rate.c +++ b/src/pcm/pcm_rate.c @@ -561,17 +561,16 @@ snd_pcm_rate_read_areas1(snd_pcm_t *pcm, static inline void snd_pcm_rate_sync_hwptr0(snd_pcm_t *pcm, snd_pcm_uframes_t slave_hw_ptr) { - snd_pcm_rate_t *rate = pcm->private_data; - - snd_pcm_sframes_t slave_hw_ptr_diff = slave_hw_ptr - rate->last_slave_hw_ptr; + snd_pcm_rate_t *rate; + snd_pcm_sframes_t slave_hw_ptr_diff; snd_pcm_sframes_t last_slave_hw_ptr_frac; if (pcm->stream != SND_PCM_STREAM_PLAYBACK) return; - if (slave_hw_ptr_diff < 0) - slave_hw_ptr_diff += rate->gen.slave->boundary; /* slave boundary wraparound */ - else if (slave_hw_ptr_diff == 0) + rate = pcm->private_data; + slave_hw_ptr_diff = pcm_frame_diff(slave_hw_ptr, rate->last_slave_hw_ptr, rate->gen.slave->boundary); + if (slave_hw_ptr_diff == 0) return; last_slave_hw_ptr_frac = rate->last_slave_hw_ptr % rate->gen.slave->period_size; /* While handling fraction part fo slave period, rounded value will be @@ -612,11 +611,7 @@ static snd_pcm_uframes_t snd_pcm_rate_playback_internal_delay(snd_pcm_t *pcm) { snd_pcm_rate_t *rate = pcm->private_data; - if (rate->appl_ptr < rate->last_commit_ptr) { - return rate->appl_ptr - rate->last_commit_ptr + pcm->boundary; - } else { - return rate->appl_ptr - rate->last_commit_ptr; - } + return pcm_frame_diff(rate->appl_ptr, rate->last_commit_ptr, pcm->boundary); } static int snd_pcm_rate_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) @@ -637,7 +632,7 @@ static int snd_pcm_rate_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) + snd_pcm_rate_playback_internal_delay(pcm); } else { *delayp = rate->ops.output_frames(rate->obj, slave_delay) - + snd_pcm_mmap_capture_hw_avail(pcm); + + snd_pcm_mmap_capture_delay(pcm); } return 0; } @@ -746,7 +741,6 @@ static int snd_pcm_rate_commit_area(snd_pcm_t *pcm, snd_pcm_rate_t *rate, if (result < 0) return result; __partial: - xfer = 0; cont = slave_frames; if (cont > slave_size) cont = slave_size; @@ -846,7 +840,6 @@ static int snd_pcm_rate_grab_next_period(snd_pcm_t *pcm, snd_pcm_uframes_t hw_of if (result < 0) return result; __partial: - xfer = 0; cont = slave_frames; if (cont > rate->gen.slave->period_size) cont = rate->gen.slave->period_size; @@ -928,10 +921,7 @@ static int snd_pcm_rate_sync_playback_area(snd_pcm_t *pcm, snd_pcm_uframes_t app if (slave_size < 0) return slave_size; - if (appl_ptr < rate->last_commit_ptr) - xfer = appl_ptr - rate->last_commit_ptr + pcm->boundary; - else - xfer = appl_ptr - rate->last_commit_ptr; + xfer = pcm_frame_diff(appl_ptr, rate->last_commit_ptr, pcm->boundary); while (xfer >= pcm->period_size && (snd_pcm_uframes_t)slave_size >= rate->gen.slave->period_size) { err = snd_pcm_rate_commit_next_period(pcm, rate->last_commit_ptr % pcm->buffer_size); @@ -966,29 +956,18 @@ static snd_pcm_sframes_t snd_pcm_rate_mmap_commit(snd_pcm_t *pcm, return size; } -static snd_pcm_sframes_t snd_pcm_rate_avail_update(snd_pcm_t *pcm) +static snd_pcm_sframes_t snd_pcm_rate_avail_update_capture(snd_pcm_t *pcm, + snd_pcm_sframes_t slave_size) { snd_pcm_rate_t *rate = pcm->private_data; snd_pcm_t *slave = rate->gen.slave; - snd_pcm_sframes_t slave_size; - - slave_size = snd_pcm_avail_update(slave); - if (slave_size < 0) - return slave_size; - - if (pcm->stream == SND_PCM_STREAM_CAPTURE) - goto _capture; - snd_pcm_rate_sync_hwptr(pcm); - snd_pcm_rate_sync_playback_area(pcm, rate->appl_ptr); - return snd_pcm_mmap_avail(pcm); - _capture: { snd_pcm_uframes_t xfer, hw_offset, size; xfer = snd_pcm_mmap_capture_avail(pcm); size = pcm->buffer_size - xfer; hw_offset = snd_pcm_mmap_hw_offset(pcm); while (size >= pcm->period_size && - (snd_pcm_uframes_t)slave_size >= rate->gen.slave->period_size) { + (snd_pcm_uframes_t)slave_size >= slave->period_size) { int err = snd_pcm_rate_grab_next_period(pcm, hw_offset); if (err < 0) return err; @@ -996,13 +975,29 @@ static snd_pcm_sframes_t snd_pcm_rate_avail_update(snd_pcm_t *pcm) return (snd_pcm_sframes_t)xfer; xfer += pcm->period_size; size -= pcm->period_size; - slave_size -= rate->gen.slave->period_size; + slave_size -= slave->period_size; hw_offset += pcm->period_size; hw_offset %= pcm->buffer_size; snd_pcm_mmap_hw_forward(pcm, pcm->period_size); } return (snd_pcm_sframes_t)xfer; - } +} + +static snd_pcm_sframes_t snd_pcm_rate_avail_update(snd_pcm_t *pcm) +{ + snd_pcm_rate_t *rate = pcm->private_data; + snd_pcm_sframes_t slave_size; + + slave_size = snd_pcm_avail_update(rate->gen.slave); + if (slave_size < 0) + return slave_size; + + if (pcm->stream == SND_PCM_STREAM_CAPTURE) + return snd_pcm_rate_avail_update_capture(pcm, slave_size); + + snd_pcm_rate_sync_hwptr(pcm); + snd_pcm_rate_sync_playback_area(pcm, rate->appl_ptr); + return snd_pcm_mmap_avail(pcm); } static int snd_pcm_rate_htimestamp(snd_pcm_t *pcm, @@ -1060,9 +1055,7 @@ static int snd_pcm_rate_drain(snd_pcm_t *pcm) sw_params.avail_min = 1; snd_pcm_sw_params(rate->gen.slave, &sw_params); - size = rate->appl_ptr - rate->last_commit_ptr; - if (size > pcm->boundary) - size -= pcm->boundary; + size = pcm_frame_diff(rate->appl_ptr, rate->last_commit_ptr, pcm->boundary); ofs = rate->last_commit_ptr % pcm->buffer_size; while (size > 0) { snd_pcm_uframes_t psize, spsize; @@ -1164,12 +1157,8 @@ static int snd_pcm_rate_status(snd_pcm_t *pcm, snd_pcm_status_t * status) status->avail = snd_pcm_mmap_playback_avail(pcm); status->avail_max = rate->ops.input_frames(rate->obj, status->avail_max); } else { - /* FIXME: Maybe possible to somthing similar to - * snd_pcm_rate_playback_internal_delay() - * for the capture case. - */ status->delay = rate->ops.output_frames(rate->obj, status->delay) - + snd_pcm_mmap_capture_hw_avail(pcm); + + snd_pcm_mmap_capture_delay(pcm); status->avail = snd_pcm_mmap_capture_avail(pcm); status->avail_max = rate->ops.output_frames(rate->obj, status->avail_max); } diff --git a/src/rawmidi/rawmidi_virt.c b/src/rawmidi/rawmidi_virt.c index 2c4c27f5..884b8ff8 100644 --- a/src/rawmidi/rawmidi_virt.c +++ b/src/rawmidi/rawmidi_virt.c @@ -315,7 +315,7 @@ int snd_rawmidi_virtual_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp, int merge, int mode) { int err; - snd_rawmidi_t *rmidi; + snd_rawmidi_t *rmidi = NULL; snd_rawmidi_virtual_t *virt = NULL; struct pollfd pfd; @@ -392,6 +392,7 @@ int snd_rawmidi_virtual_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp, free(*inputp); if (outputp) free(*outputp); + free(rmidi); return err; } diff --git a/src/timer/timer_query_hw.c b/src/timer/timer_query_hw.c index dad228c8..d8bac6e7 100644 --- a/src/timer/timer_query_hw.c +++ b/src/timer/timer_query_hw.c @@ -104,7 +104,7 @@ int snd_timer_query_hw_open(snd_timer_query_t **handle, const char *name, int mo close(fd); return -SND_ERROR_INCOMPATIBLE_VERSION; } - tmr = (snd_timer_query_t *) calloc(1, sizeof(snd_timer_t)); + tmr = (snd_timer_query_t *) calloc(1, sizeof(snd_timer_query_t)); if (tmr == NULL) { close(fd); return -ENOMEM; diff --git a/src/topology/dapm.c b/src/topology/dapm.c index 92dc01aa..f6a84a60 100644 --- a/src/topology/dapm.c +++ b/src/topology/dapm.c @@ -836,6 +836,7 @@ int tplg_add_widget_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t) default: SNDERR("widget %s: invalid type %d for ctl %d", wt->name, ct->type, i); + ret = -EINVAL; break; } diff --git a/src/topology/data.c b/src/topology/data.c index c2931bd2..5633cdc3 100644 --- a/src/topology/data.c +++ b/src/topology/data.c @@ -860,7 +860,7 @@ static int parse_tuple_set(snd_config_t *cfg, } if ((type == SND_SOC_TPLG_TUPLE_TYPE_WORD - && tuple_val > UINT_MAX) + /* && tuple_val > UINT_MAX */) || (type == SND_SOC_TPLG_TUPLE_TYPE_SHORT && tuple_val > USHRT_MAX) || (type == SND_SOC_TPLG_TUPLE_TYPE_BYTE diff --git a/src/topology/pcm.c b/src/topology/pcm.c index 191b7a0a..a473b59b 100644 --- a/src/topology/pcm.c +++ b/src/topology/pcm.c @@ -1411,6 +1411,7 @@ int tplg_parse_hw_config(snd_tplg_t *tplg, snd_config_t *cfg, snd_config_t *n; const char *id, *val = NULL; int ret, ival; + bool provider_legacy; elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_HW_CONFIG); if (!elem) @@ -1451,8 +1452,15 @@ int tplg_parse_hw_config(snd_tplg_t *tplg, snd_config_t *cfg, continue; } - if (strcmp(id, "bclk") == 0 || - strcmp(id, "bclk_master") == 0) { + provider_legacy = false; + if (strcmp(id, "bclk_master") == 0) { + SNDERR("deprecated option %s, please use 'bclk'\n", id); + provider_legacy = true; + } + + if (provider_legacy || + strcmp(id, "bclk") == 0) { + if (snd_config_get_string(n, &val) < 0) return -EINVAL; @@ -1462,11 +1470,19 @@ int tplg_parse_hw_config(snd_tplg_t *tplg, snd_config_t *cfg, */ SNDERR("deprecated bclk value '%s'", val); - hw_cfg->bclk_master = SND_SOC_TPLG_BCLK_CS; + hw_cfg->bclk_provider = SND_SOC_TPLG_BCLK_CC; } else if (!strcmp(val, "codec_slave")) { - hw_cfg->bclk_master = SND_SOC_TPLG_BCLK_CS; + SNDERR("deprecated bclk value '%s', use 'codec_consumer'", val); + + hw_cfg->bclk_provider = SND_SOC_TPLG_BCLK_CC; + } else if (!strcmp(val, "codec_consumer")) { + hw_cfg->bclk_provider = SND_SOC_TPLG_BCLK_CC; } else if (!strcmp(val, "codec_master")) { - hw_cfg->bclk_master = SND_SOC_TPLG_BCLK_CM; + SNDERR("deprecated bclk value '%s', use 'codec_provider", val); + + hw_cfg->bclk_provider = SND_SOC_TPLG_BCLK_CP; + } else if (!strcmp(val, "codec_provider")) { + hw_cfg->bclk_provider = SND_SOC_TPLG_BCLK_CP; } continue; } @@ -1488,8 +1504,15 @@ int tplg_parse_hw_config(snd_tplg_t *tplg, snd_config_t *cfg, continue; } - if (strcmp(id, "fsync") == 0 || - strcmp(id, "fsync_master") == 0) { + provider_legacy = false; + if (strcmp(id, "fsync_master") == 0) { + SNDERR("deprecated option %s, please use 'fsync'\n", id); + provider_legacy = true; + } + + if (provider_legacy || + strcmp(id, "fsync") == 0) { + if (snd_config_get_string(n, &val) < 0) return -EINVAL; @@ -1499,11 +1522,19 @@ int tplg_parse_hw_config(snd_tplg_t *tplg, snd_config_t *cfg, */ SNDERR("deprecated fsync value '%s'", val); - hw_cfg->fsync_master = SND_SOC_TPLG_FSYNC_CS; + hw_cfg->fsync_provider = SND_SOC_TPLG_FSYNC_CC; } else if (!strcmp(val, "codec_slave")) { - hw_cfg->fsync_master = SND_SOC_TPLG_FSYNC_CS; + SNDERR("deprecated fsync value '%s', use 'codec_consumer'", val); + + hw_cfg->fsync_provider = SND_SOC_TPLG_FSYNC_CC; + } else if (!strcmp(val, "codec_consumer")) { + hw_cfg->fsync_provider = SND_SOC_TPLG_FSYNC_CC; } else if (!strcmp(val, "codec_master")) { - hw_cfg->fsync_master = SND_SOC_TPLG_FSYNC_CM; + SNDERR("deprecated fsync value '%s', use 'codec_provider'", val); + + hw_cfg->fsync_provider = SND_SOC_TPLG_FSYNC_CP; + } else if (!strcmp(val, "codec_provider")) { + hw_cfg->fsync_provider = SND_SOC_TPLG_FSYNC_CP; } continue; } @@ -1623,19 +1654,19 @@ int tplg_save_hw_config(snd_tplg_t *tplg ATTRIBUTE_UNUSED, if (err >= 0 && hc->fmt) err = tplg_save_printf(dst, pfx, "\tformat '%s'\n", get_audio_hw_format_name(hc->fmt)); - if (err >= 0 && hc->bclk_master) + if (err >= 0 && hc->bclk_provider) err = tplg_save_printf(dst, pfx, "\tbclk '%s'\n", - hc->bclk_master == SND_SOC_TPLG_BCLK_CS ? - "codec_slave" : "codec_master"); + hc->bclk_provider == SND_SOC_TPLG_BCLK_CC ? + "codec_consumer" : "codec_provider"); if (err >= 0 && hc->bclk_rate) err = tplg_save_printf(dst, pfx, "\tbclk_freq %u\n", hc->bclk_rate); if (err >= 0 && hc->invert_bclk) err = tplg_save_printf(dst, pfx, "\tbclk_invert 1\n"); - if (err >= 0 && hc->fsync_master) - err = tplg_save_printf(dst, pfx, "\tfsync_master '%s'\n", - hc->fsync_master == SND_SOC_TPLG_FSYNC_CS ? - "codec_slave" : "codec_master"); + if (err >= 0 && hc->fsync_provider) + err = tplg_save_printf(dst, pfx, "\tfsync_provider '%s'\n", + hc->fsync_provider == SND_SOC_TPLG_FSYNC_CC ? + "codec_consumer" : "codec_provider"); if (err >= 0 && hc->fsync_rate) err = tplg_save_printf(dst, pfx, "\tfsync_freq %u\n", hc->fsync_rate); @@ -1791,8 +1822,8 @@ static int set_link_hw_config(struct snd_soc_tplg_hw_config *cfg, cfg->clock_gated = tpl->clock_gated; cfg->invert_bclk = tpl->invert_bclk; cfg->invert_fsync = tpl->invert_fsync; - cfg->bclk_master = tpl->bclk_master; - cfg->fsync_master = tpl->fsync_master; + cfg->bclk_provider = tpl->bclk_provider; + cfg->fsync_provider = tpl->fsync_provider; cfg->mclk_direction = tpl->mclk_direction; cfg->reserved = tpl->reserved; cfg->mclk_rate = tpl->mclk_rate; @@ -1989,7 +2020,7 @@ next: pt->playback = pcm->playback; pt->capture = pcm->capture; pt->compress = pcm->compress; - tplg_log(tplg, 'D', pos, "pcm: playback %d capture %d compress", + tplg_log(tplg, 'D', pos, "pcm: playback %d capture %d compress %d", pt->playback, pt->capture, pt->compress); pt->num_streams = pcm->num_streams; pt->flag_mask = pcm->flag_mask; @@ -2174,8 +2205,8 @@ next: hw->clock_gated = link->hw_config[i].clock_gated; hw->invert_bclk = link->hw_config[i].invert_bclk; hw->invert_fsync = link->hw_config[i].invert_fsync; - hw->bclk_master = link->hw_config[i].bclk_master; - hw->fsync_master = link->hw_config[i].fsync_master; + hw->bclk_provider = link->hw_config[i].bclk_provider; + hw->fsync_provider = link->hw_config[i].fsync_provider; hw->mclk_direction = link->hw_config[i].mclk_direction; hw->mclk_rate = link->hw_config[i].mclk_rate; hw->bclk_rate = link->hw_config[i].bclk_rate; diff --git a/src/topology/save.c b/src/topology/save.c index c7a5a801..fecbc6a5 100644 --- a/src/topology/save.c +++ b/src/topology/save.c @@ -133,6 +133,8 @@ static int tplg_pprint_integer(snd_config_t *n, char **ret) if (llval < INT_MIN || llval > UINT_MAX) return snd_config_get_ascii(n, ret); lval = llval; + } else { + lval = 0; } err = tplg_nice_value_format(buf, sizeof(buf), (unsigned int)lval); if (err < 0) @@ -178,29 +180,28 @@ static snd_config_t *sort_config(const char *id, snd_config_t *src) } if (array <= 0) qsort(a, count, sizeof(a[0]), _compar); - if (snd_config_make_compound(&dst, id, count == 1)) { - free(a); - return NULL; - } + if (snd_config_make_compound(&dst, id, count == 1)) + goto lerr; for (index = 0; index < count; index++) { snd_config_t *s = a[index]; const char *id2; if (snd_config_get_id(s, &id2)) { snd_config_delete(dst); - free(a); - return NULL; + goto lerr; } s = sort_config(id2, s); if (s == NULL || snd_config_add(dst, s)) { if (s) snd_config_delete(s); snd_config_delete(dst); - free(a); - return NULL; + goto lerr; } } free(a); return dst; +lerr: + free(a); + return NULL; } static int tplg_check_quoted(const unsigned char *p) diff --git a/src/ucm/main.c b/src/ucm/main.c index 3871d5aa..754b967e 100644 --- a/src/ucm/main.c +++ b/src/ucm/main.c @@ -666,7 +666,7 @@ static int get_list0(struct list_head *list, } return cnt; __fail: - snd_use_case_free_list((const char **)res, cnt); + snd_use_case_free_list(*result, cnt); return -ENOMEM; } @@ -724,7 +724,7 @@ static int get_list20(struct list_head *list, } return cnt; __fail: - snd_use_case_free_list((const char **)res, cnt); + snd_use_case_free_list(*result, cnt); return -ENOMEM; } diff --git a/src/ucm/parser.c b/src/ucm/parser.c index 75b78826..c8bee1f2 100644 --- a/src/ucm/parser.c +++ b/src/ucm/parser.c @@ -1575,7 +1575,7 @@ static int parse_verb_file(snd_use_case_mgr_t *uc_mgr, /* in-place evaluation */ err = uc_mgr_evaluate_inplace(uc_mgr, cfg); if (err < 0) - return err; + goto _err; /* parse master config sections */ snd_config_for_each(i, next, cfg) { diff --git a/src/ucm/ucm_subs.c b/src/ucm/ucm_subs.c index f608bb09..df6d736f 100644 --- a/src/ucm/ucm_subs.c +++ b/src/ucm/ucm_subs.c @@ -417,11 +417,12 @@ int uc_mgr_substitute_tree(snd_use_case_mgr_t *uc_mgr, snd_config_t *node) if (err < 0) return err; err = snd_config_set_id(node, s); - free(s); if (err < 0) { uc_error("unable to set substituted id '%s' (old id '%s')", s, id); + free(s); return err; } + free(s); } if (snd_config_get_type(node) != SND_CONFIG_TYPE_COMPOUND) { if (snd_config_get_type(node) == SND_CONFIG_TYPE_STRING) { diff --git a/test/audio_time.c b/test/audio_time.c index 530922d9..e4d4a944 100644 --- a/test/audio_time.c +++ b/test/audio_time.c @@ -32,7 +32,7 @@ static void usage(char *command) "-d, --delay add delay \n" "-D, --device=NAME select PCM by name \n" "-p, --playback playback tstamps \n" - "-t, --ts_type=TYPE Default(0),link(1),link_estimated(2),synchronized(3) \n" + "-t, --ts_type=TYPE Compat(0),default(1),link(2),link_absolute(3),link_estimated(4),link_synchronized(5) \n" "-r, --report show audio timestamp and accuracy validity\n" , command); } @@ -201,17 +201,17 @@ int main(int argc, char *argv[]) goto _exit; } - if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, 0)) + if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, SND_PCM_AUDIO_TSTAMP_TYPE_COMPAT)) printf("Playback supports audio compat timestamps\n"); - if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, 1)) + if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, SND_PCM_AUDIO_TSTAMP_TYPE_DEFAULT)) printf("Playback supports audio default timestamps\n"); - if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, 2)) + if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, SND_PCM_AUDIO_TSTAMP_TYPE_LINK)) printf("Playback supports audio link timestamps\n"); - if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, 3)) + if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, SND_PCM_AUDIO_TSTAMP_TYPE_LINK_ABSOLUTE)) printf("Playback supports audio link absolute timestamps\n"); - if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, 4)) + if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, SND_PCM_AUDIO_TSTAMP_TYPE_LINK_ESTIMATED)) printf("Playback supports audio link estimated timestamps\n"); - if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, 5)) + if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_p, SND_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED)) printf("Playback supports audio link synchronized timestamps\n"); snd_pcm_sw_params_alloca(&swparams_p); @@ -269,17 +269,17 @@ int main(int argc, char *argv[]) goto _exit; } - if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, 0)) + if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, SND_PCM_AUDIO_TSTAMP_TYPE_COMPAT)) printf("Capture supports audio compat timestamps\n"); - if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, 1)) + if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, SND_PCM_AUDIO_TSTAMP_TYPE_DEFAULT)) printf("Capture supports audio default timestamps\n"); - if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, 2)) + if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, SND_PCM_AUDIO_TSTAMP_TYPE_LINK)) printf("Capture supports audio link timestamps\n"); - if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, 3)) + if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, SND_PCM_AUDIO_TSTAMP_TYPE_LINK_ABSOLUTE)) printf("Capture supports audio link absolute timestamps\n"); - if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, 4)) + if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, SND_PCM_AUDIO_TSTAMP_TYPE_LINK_ESTIMATED)) printf("Capture supports audio link estimated timestamps\n"); - if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, 5)) + if (snd_pcm_hw_params_supports_audio_ts_type(hwparams_c, SND_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED)) printf("Capture supports audio link synchronized timestamps\n"); snd_pcm_sw_params_alloca(&swparams_c);