diff --git a/.alsa-lib.metadata b/.alsa-lib.metadata index 87f4cb1..056632a 100644 --- a/.alsa-lib.metadata +++ b/.alsa-lib.metadata @@ -1 +1 @@ -9cd50f4b5f07d5e7213dd1277b8673e677804cf8 SOURCES/alsa-lib-1.0.27.2.tar.bz2 +3130b50835ce5e9ce061dd7916eac1121e1a83e3 SOURCES/alsa-lib-1.0.28.tar.bz2 diff --git a/.gitignore b/.gitignore index c09ef3b..fb23555 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/alsa-lib-1.0.27.2.tar.bz2 +SOURCES/alsa-lib-1.0.28.tar.bz2 diff --git a/SOURCES/alsa-lib-1.0.28-post.patch b/SOURCES/alsa-lib-1.0.28-post.patch new file mode 100644 index 0000000..c9472df --- /dev/null +++ b/SOURCES/alsa-lib-1.0.28-post.patch @@ -0,0 +1,2820 @@ +From 7a748af4db17cb0b26d19e5f9939d277128ec94b Mon Sep 17 00:00:00 2001 +From: Tanu Kaskinen +Date: Thu, 26 Jun 2014 13:30:25 +0300 +Subject: [PATCH 01/35] ucm: Document PlaybackPCMIsDummy and CapturePCMIsDummy + values + +At least PulseAudio needs special handling for dummy devices. To allow +that to happen automatically, the UCM configuration should contain the +information about which PCMs are dummy. + +Signed-off-by: Tanu Kaskinen +Acked-by: Liam Girdwood +Signed-off-by: Takashi Iwai +--- + include/use-case.h | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/include/use-case.h b/include/use-case.h +index 4e13249..f30168f 100644 +--- a/include/use-case.h ++++ b/include/use-case.h +@@ -258,7 +258,17 @@ int snd_use_case_get_list(snd_use_case_mgr_t *uc_mgr, + * Recommended names for values: + * TQ - Tone Quality + * PlaybackPCM - full PCM playback device name ++ * PlaybackPCMIsDummy - Valid values: "yes" and "no". If set to "yes", the ++ * PCM named by the PlaybackPCM value is a dummy device, ++ * meaning that opening it enables an audio path in the ++ * hardware, but writing to the PCM device has no ++ * effect. + * CapturePCM - full PCM capture device name ++ * CapturePCMIsDummy - Valid values: "yes" and "no". If set to "yes", the ++ * PCM named by the CapturePCM value is a dummy device, ++ * meaning that opening it enables an audio path in the ++ * hardware, but reading from the PCM device has no ++ * effect. + * PlaybackRate - playback device sample rate + * PlaybackChannels - playback device channel count + * PlaybackCTL - playback control device name +-- +1.9.3 + + +From 27cc710b5784cb3ab68cff2a9d9daf9fa479149e Mon Sep 17 00:00:00 2001 +From: "Alexander E. Patrakov" +Date: Tue, 1 Jul 2014 00:40:48 +0600 +Subject: [PATCH 02/35] ICE1712: add surround71 pcm definition + +The M-Audio Delta 1010 card has 7.1 analog output, but no ready-made pcm +definition to use it. + +Signed-off-by: Alexander E. Patrakov +Reported-and-tested-by: Matt Zagrabelny +Signed-off-by: Takashi Iwai +--- + src/conf/cards/ICE1712.conf | 22 ++++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +diff --git a/src/conf/cards/ICE1712.conf b/src/conf/cards/ICE1712.conf +index 398fa7a..db62684 100644 +--- a/src/conf/cards/ICE1712.conf ++++ b/src/conf/cards/ICE1712.conf +@@ -78,6 +78,7 @@ ICE1712.pcm.surround40.0 { + + + ++ + + ICE1712.pcm.surround51.0 { + @args [ CARD ] +@@ -98,6 +99,27 @@ ICE1712.pcm.surround51.0 { + slave.channels 10 + } + ++ICE1712.pcm.surround71.0 { ++ @args [ CARD ] ++ @args.CARD { ++ type string ++ } ++ type route ++ ttable.0.0 1 ++ ttable.1.1 1 ++ ttable.2.2 1 ++ ttable.3.3 1 ++ ttable.4.4 1 ++ ttable.5.5 1 ++ ttable.6.6 1 ++ ttable.7.7 1 ++ slave.pcm { ++ type hw ++ card $CARD ++ } ++ slave.channels 10 ++} ++ + + + ICE1712.pcm.iec958.0 { +-- +1.9.3 + + +From ea865bba4615d906144ae5d4f72a4aad2baffe1f Mon Sep 17 00:00:00 2001 +From: Anssi Hannula +Date: Tue, 8 Jul 2014 11:19:20 +0300 +Subject: [PATCH 03/35] USB-Audio: Add second S/PDIF device on Phiree U2 + +Phiree U2 has an unusual configuration. It only has S/PDIF output, but +there are still two devices presented: +- device 0: PCM audio, subject to volume control +- device 1: non-PCM data (passthrough), not subject to volume control + +It looks like the AES bits are set according to the selected device, +since outputting PCM data via device 1 will not work (silence). + +Currently only the device 0 is shown via the "iec958" alias, and the +second device is not accessible via hinted aliases. + +Simply provide access to both of these devices via the "iec958" alias. + +Reported-by: touc @ XBMC forum +Signed-off-by: Anssi Hannula +Signed-off-by: Takashi Iwai +--- + src/conf/cards/USB-Audio.conf | 40 ++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 40 insertions(+) + +diff --git a/src/conf/cards/USB-Audio.conf b/src/conf/cards/USB-Audio.conf +index ce3ae01..77a48b9 100644 +--- a/src/conf/cards/USB-Audio.conf ++++ b/src/conf/cards/USB-Audio.conf +@@ -52,6 +52,11 @@ USB-Audio.pcm.iec958_device { + "USB Device 0x46d:0x992" 999 + } + ++# Second iec958 device number, if any. ++USB-Audio.pcm.iec958_2_device { ++ "PHIREE U2" 1 # 0 = PCM S/PDIF, 1 = non-PCM S/PDIF ++} ++ + + # If a device requires non-standard definitions for front, surround40, + # surround51, surround71 or iec958, they can be defined here. +@@ -422,4 +427,39 @@ USB-Audio.pcm.iec958.0 { + } + } + ++USB-Audio.pcm.iec958.1 { ++ @args [ CARD AES0 AES1 AES2 AES3 ] ++ @args.CARD { type string } ++ @args.AES0 { type integer } ++ @args.AES1 { type integer } ++ @args.AES2 { type integer } ++ @args.AES3 { type integer } ++ @func refer ++ name { ++ @func concat ++ strings [ ++ "cards.USB-Audio." ++ { @func card_name card $CARD } ++ ".pcm.iec958_2:CARD=" $CARD ++ ",AES0=" $AES0 ",AES1=" $AES1 ",AES2=" $AES2 ",AES3=" $AES3 ++ ] ++ } ++ default { ++ # FIXME: we cannot set the AES parameters ++ type hw ++ card $CARD ++ device { ++ @func refer ++ name { ++ @func concat ++ strings [ ++ "cards.USB-Audio.pcm.iec958_2_device." ++ { @func card_name card $CARD } ++ ] ++ } ++ default 999 ++ } ++ } ++} ++ + # vim: ft=alsaconf +-- +1.9.3 + + +From 035f196bcdc1e9903ed52ad1859dc23d3aa74e72 Mon Sep 17 00:00:00 2001 +From: Shengjiu Wang +Date: Mon, 14 Jul 2014 16:55:48 +0800 +Subject: [PATCH 04/35] pcm: rate: fix hw_ptr exceed the boundary + +For long time test case, the hw_ptr will exceed the boundary, then cause +the avail size wrong. + +Signed-off-by: Shengjiu Wang +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_rate.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/src/pcm/pcm_rate.c b/src/pcm/pcm_rate.c +index 7f667d4..2563d82 100644 +--- a/src/pcm/pcm_rate.c ++++ b/src/pcm/pcm_rate.c +@@ -574,6 +574,8 @@ static inline void snd_pcm_rate_sync_hwptr(snd_pcm_t *pcm) + rate->hw_ptr = + (slave_hw_ptr / rate->gen.slave->period_size) * pcm->period_size + + rate->ops.input_frames(rate->obj, slave_hw_ptr % rate->gen.slave->period_size); ++ ++ rate->hw_ptr %= pcm->boundary; + } + + static int snd_pcm_rate_hwsync(snd_pcm_t *pcm) +-- +1.9.3 + + +From 85e4704151677b8fcc5ccfc396071828e9ec1b8e Mon Sep 17 00:00:00 2001 +From: Mark Brown +Date: Tue, 8 Jul 2014 16:52:32 +0200 +Subject: [PATCH 05/35] pcm: Provide a CLOCK_MONOTONIC_RAW timestamp type + +For applications which need to synchronise with external timebases such +as broadcast TV applications the kernel monotonic time is not optimal as +it includes adjustments from NTP and so may still include discontinuities +due to that. A raw monotonic time which does not include any adjustments +is available in the kernel from getrawmonotonic() so provide userspace with +a new timestamp type SNDRV_PCM_TSTAMP_TYPE_MONOTONIC_RAW which provides +timestamps based on this as an option. + +Reported-by: Daniel Thompson +Signed-off-by: Mark Brown +Signed-off-by: Takashi Iwai +--- + 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 1774a5c..9061cdd 100644 +--- a/include/sound/asound.h ++++ b/include/sound/asound.h +@@ -457,7 +457,8 @@ struct snd_xfern { + enum { + SNDRV_PCM_TSTAMP_TYPE_GETTIMEOFDAY = 0, /* gettimeofday equivalent */ + SNDRV_PCM_TSTAMP_TYPE_MONOTONIC, /* posix_clock_monotonic equivalent */ +- SNDRV_PCM_TSTAMP_TYPE_LAST = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC, ++ SNDRV_PCM_TSTAMP_TYPE_MONOTONIC_RAW, /* monotonic_raw (no NTP) */ ++ SNDRV_PCM_TSTAMP_TYPE_LAST = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC_RAW, + }; + + /* channel positions */ +-- +1.9.3 + + +From 5250a8e212fd927735cfc27612b060c31dc3a230 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Thu, 10 Jul 2014 14:22:33 +0200 +Subject: [PATCH 06/35] Add timestamp type to sw_params (internal only) + +This patch is just the udpate of sound/asound.h taken from the kernel +commit. The API changes and PCM structure changes will follow after +this. + +Signed-off-by: Takashi Iwai +--- + include/sound/asound.h | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/include/sound/asound.h b/include/sound/asound.h +index 9061cdd..552f41b 100644 +--- a/include/sound/asound.h ++++ b/include/sound/asound.h +@@ -136,7 +136,7 @@ struct snd_hwdep_dsp_image { + * * + *****************************************************************************/ + +-#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 11) ++#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 12) + + typedef unsigned long snd_pcm_uframes_t; + typedef signed long snd_pcm_sframes_t; +@@ -386,7 +386,9 @@ struct snd_pcm_sw_params { + snd_pcm_uframes_t silence_threshold; /* min distance from noise for silence filling */ + snd_pcm_uframes_t silence_size; /* silence block size */ + snd_pcm_uframes_t boundary; /* pointers wrap point */ +- unsigned char reserved[64]; /* reserved for future */ ++ unsigned int tstamp_type; /* timestamp type */ ++ int pads; /* alignment, reserved */ ++ unsigned char reserved[56]; /* reserved for future */ + }; + + struct snd_pcm_channel_info { +-- +1.9.3 + + +From 0d393c29a272b6fc97e9fca3252fb1c58f86e75b Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Thu, 10 Jul 2014 14:26:37 +0200 +Subject: [PATCH 07/35] pcm: Add sw_params API functions to get/set timestamp + type + +For obtaining / changing the timestamp type, add the corresponding +sw_params accessor API functions together with the public definitions +of timestamp types. + +This patch only adds the functions and defines but doesn't bring the +functional changes yet. + +Signed-off-by: Takashi Iwai +--- + include/pcm.h | 9 +++++++++ + src/pcm/pcm.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++ + src/pcm/pcm_local.h | 1 + + src/pcm/pcm_params.c | 1 + + 4 files changed, 64 insertions(+) + +diff --git a/include/pcm.h b/include/pcm.h +index 95b8aed..11e9f0d 100644 +--- a/include/pcm.h ++++ b/include/pcm.h +@@ -317,6 +317,13 @@ typedef enum _snd_pcm_tstamp { + SND_PCM_TSTAMP_LAST = SND_PCM_TSTAMP_ENABLE + } snd_pcm_tstamp_t; + ++typedef enum _snd_pcm_tstamp_type { ++ SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY = 0, /** gettimeofday equivalent */ ++ SND_PCM_TSTAMP_TYPE_MONOTONIC, /** posix_clock_monotonic equivalent */ ++ SND_PCM_TSTAMP_TYPE_MONOTONIC_RAW, /** monotonic_raw (no NTP) */ ++ SND_PCM_TSTAMP_TYPE_LAST = SND_PCM_TSTAMP_TYPE_MONOTONIC_RAW, ++} snd_pcm_tstamp_type_t; ++ + /** Unsigned frames quantity */ + typedef unsigned long snd_pcm_uframes_t; + /** Signed frames quantity */ +@@ -844,6 +851,8 @@ int snd_pcm_sw_params_get_boundary(const snd_pcm_sw_params_t *params, snd_pcm_uf + + int snd_pcm_sw_params_set_tstamp_mode(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_tstamp_t val); + int snd_pcm_sw_params_get_tstamp_mode(const snd_pcm_sw_params_t *params, snd_pcm_tstamp_t *val); ++int snd_pcm_sw_params_set_tstamp_type(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_tstamp_type_t val); ++int snd_pcm_sw_params_get_tstamp_type(const snd_pcm_sw_params_t *params, snd_pcm_tstamp_type_t *val); + int snd_pcm_sw_params_set_avail_min(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val); + int snd_pcm_sw_params_get_avail_min(const snd_pcm_sw_params_t *params, snd_pcm_uframes_t *val); + int snd_pcm_sw_params_set_period_event(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, int val); +diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c +index 7e46014..8984443 100644 +--- a/src/pcm/pcm.c ++++ b/src/pcm/pcm.c +@@ -1483,6 +1483,7 @@ int snd_pcm_poll_descriptors_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsign + #define XRUN(v) [SND_PCM_XRUN_##v] = #v + #define SILENCE(v) [SND_PCM_SILENCE_##v] = #v + #define TSTAMP(v) [SND_PCM_TSTAMP_##v] = #v ++#define TSTAMP_TYPE(v) [SND_PCM_TSTAMP_TYPE_##v] = #v + #define ACCESS(v) [SND_PCM_ACCESS_##v] = #v + #define START(v) [SND_PCM_START_##v] = #v + #define HW_PARAM(v) [SND_PCM_HW_PARAM_##v] = #v +@@ -1680,6 +1681,12 @@ static const char *const snd_pcm_tstamp_mode_names[] = { + TSTAMP(NONE), + TSTAMP(ENABLE), + }; ++ ++static const char *const snd_pcm_tstamp_type_names[] = { ++ TSTAMP_TYPE(GETTIMEOFDAY), ++ TSTAMP_TYPE(MONOTONIC), ++ TSTAMP_TYPE(MONOTONIC_RAW), ++}; + #endif + + /** +@@ -1826,6 +1833,18 @@ const char *snd_pcm_tstamp_mode_name(snd_pcm_tstamp_t mode) + } + + /** ++ * \brief get name of PCM tstamp type setting ++ * \param mode PCM tstamp type ++ * \return ascii name of PCM tstamp type setting ++ */ ++const char *snd_pcm_tstamp_type_name(snd_pcm_tstamp_t type) ++{ ++ if (type > SND_PCM_TSTAMP_TYPE_LAST) ++ return NULL; ++ return snd_pcm_tstamp_type_names[type]; ++} ++ ++/** + * \brief get name of PCM state + * \param state PCM state + * \return ascii name of PCM state +@@ -1899,6 +1918,7 @@ int snd_pcm_dump_sw_setup(snd_pcm_t *pcm, snd_output_t *out) + return -EIO; + } + snd_output_printf(out, " tstamp_mode : %s\n", snd_pcm_tstamp_mode_name(pcm->tstamp_mode)); ++ snd_output_printf(out, " tstamp_type : %s\n", snd_pcm_tstamp_type_name(pcm->tstamp_mode)); + snd_output_printf(out, " period_step : %d\n", pcm->period_step); + snd_output_printf(out, " avail_min : %ld\n", pcm->avail_min); + snd_output_printf(out, " period_event : %i\n", pcm->period_event); +@@ -5591,6 +5611,7 @@ int snd_pcm_sw_params_current(snd_pcm_t *pcm, snd_pcm_sw_params_t *params) + return -EIO; + } + params->tstamp_mode = pcm->tstamp_mode; ++ params->tstamp_type = pcm->tstamp_type; + params->period_step = pcm->period_step; + params->sleep_min = 0; + params->avail_min = pcm->avail_min; +@@ -5613,6 +5634,7 @@ int snd_pcm_sw_params_current(snd_pcm_t *pcm, snd_pcm_sw_params_t *params) + int snd_pcm_sw_params_dump(snd_pcm_sw_params_t *params, snd_output_t *out) + { + snd_output_printf(out, "tstamp_mode: %s\n", snd_pcm_tstamp_mode_name(params->tstamp_mode)); ++ snd_output_printf(out, "tstamp_type: %s\n", snd_pcm_tstamp_type_name(params->tstamp_type)); + snd_output_printf(out, "period_step: %u\n", params->period_step); + snd_output_printf(out, "avail_min: %lu\n", params->avail_min); + snd_output_printf(out, "start_threshold: %ld\n", params->start_threshold); +@@ -5811,6 +5833,37 @@ int snd_pcm_sw_params_get_tstamp_mode(const snd_pcm_sw_params_t *params, snd_pcm + } + + /** ++ * \brief Set timestamp type inside a software configuration container ++ * \param pcm PCM handle ++ * \param params Software configuration container ++ * \param val Timestamp type ++ * \return 0 otherwise a negative error code ++ */ ++int snd_pcm_sw_params_set_tstamp_type(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_tstamp_type_t val) ++{ ++ assert(pcm && params); ++ if (CHECK_SANITY(val > SND_PCM_TSTAMP_TYPE_LAST)) { ++ SNDMSG("invalid tstamp_type value %d", val); ++ return -EINVAL; ++ } ++ params->tstamp_type = val; ++ return 0; ++} ++ ++/** ++ * \brief Get timestamp type from a software configuration container ++ * \param params Software configuration container ++ * \param val Returned timestamp type ++ * \return 0 otherwise a negative error code ++ */ ++int snd_pcm_sw_params_get_tstamp_type(const snd_pcm_sw_params_t *params, snd_pcm_tstamp_type_t *val) ++{ ++ assert(params && val); ++ *val = params->tstamp_type; ++ return 0; ++} ++ ++/** + * \brief (DEPRECATED) Set minimum number of ticks to sleep inside a software configuration container + * \param pcm PCM handle + * \param params Software configuration container +diff --git a/src/pcm/pcm_local.h b/src/pcm/pcm_local.h +index 8a6c743..3ed7e1a 100644 +--- a/src/pcm/pcm_local.h ++++ b/src/pcm/pcm_local.h +@@ -202,6 +202,7 @@ struct _snd_pcm { + unsigned int period_time; /* period duration */ + snd_interval_t periods; + snd_pcm_tstamp_t tstamp_mode; /* timestamp mode */ ++ snd_pcm_tstamp_type_t tstamp_type; /* timestamp type */ + unsigned int period_step; + snd_pcm_uframes_t avail_min; /* min avail frames for wakeup */ + int period_event; +diff --git a/src/pcm/pcm_params.c b/src/pcm/pcm_params.c +index 0b66e8c..4adbefa 100644 +--- a/src/pcm/pcm_params.c ++++ b/src/pcm/pcm_params.c +@@ -2258,6 +2258,7 @@ static int snd_pcm_sw_params_default(snd_pcm_t *pcm, snd_pcm_sw_params_t *params + assert(pcm && params); + assert(pcm->setup); + params->tstamp_mode = SND_PCM_TSTAMP_NONE; ++ params->tstamp_type = pcm->tstamp_type; + params->period_step = 1; + params->sleep_min = 0; + params->avail_min = pcm->period_size; +-- +1.9.3 + + +From 9b716075de4f2f7f15e428ee7efaa8960ef45b9c Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Thu, 10 Jul 2014 14:32:50 +0200 +Subject: [PATCH 08/35] pcm: Implement timestamp type setup in hw plugin + +This patch implements the support for sw_params timestamp type in PCM +hw layer. As gettimestamp() is still unchanged, the resultant +timstamps may be still with CLOCK_MONOTONIC even if you pass monotonic +raw type. More fixes will follow. + +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_hw.c | 37 ++++++++++++++++++++++++++++++++----- + 1 file changed, 32 insertions(+), 5 deletions(-) + +diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c +index ed83197..bafa8de 100644 +--- a/src/pcm/pcm_hw.c ++++ b/src/pcm/pcm_hw.c +@@ -304,7 +304,8 @@ static int snd_pcm_hw_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) + + if (params->info != ~0U) { + params->info &= ~0xf0000000; +- params->info |= (pcm->monotonic ? SND_PCM_INFO_MONOTONIC : 0); ++ if (pcm->tstamp_type != SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY) ++ params->info |= SND_PCM_INFO_MONOTONIC; + } + + return 0; +@@ -328,7 +329,8 @@ static int snd_pcm_hw_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) + return err; + } + params->info &= ~0xf0000000; +- params->info |= (pcm->monotonic ? SND_PCM_INFO_MONOTONIC : 0); ++ if (pcm->tstamp_type != SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY) ++ params->info |= SND_PCM_INFO_MONOTONIC; + err = sync_ptr(hw, 0); + if (err < 0) + return err; +@@ -435,6 +437,7 @@ static int snd_pcm_hw_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params) + int old_period_event = sw_get_period_event(params); + sw_set_period_event(params, 0); + if ((snd_pcm_tstamp_t) params->tstamp_mode == pcm->tstamp_mode && ++ (snd_pcm_tstamp_type_t) params->tstamp_type == pcm->tstamp_type && + params->period_step == pcm->period_step && + params->start_threshold == pcm->start_threshold && + params->stop_threshold == pcm->stop_threshold && +@@ -444,11 +447,33 @@ static int snd_pcm_hw_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params) + hw->mmap_control->avail_min = params->avail_min; + return sync_ptr(hw, 0); + } ++ if (params->tstamp_type == SND_PCM_TSTAMP_TYPE_MONOTONIC_RAW && ++ hw->version < SNDRV_PROTOCOL_VERSION(2, 0, 12)) { ++ SYSMSG("Kernel doesn't support SND_PCM_TSTAMP_TYPE_MONOTONIC_RAW"); ++ return -EINVAL; ++ } ++ if (params->tstamp_type == SND_PCM_TSTAMP_TYPE_MONOTONIC && ++ hw->version < SNDRV_PROTOCOL_VERSION(2, 0, 5)) { ++ SYSMSG("Kernel doesn't support SND_PCM_TSTAMP_TYPE_MONOTONIC"); ++ return -EINVAL; ++ } + if (ioctl(fd, SNDRV_PCM_IOCTL_SW_PARAMS, params) < 0) { + err = -errno; + SYSMSG("SNDRV_PCM_IOCTL_SW_PARAMS failed (%i)", err); + return err; + } ++ if ((snd_pcm_tstamp_type_t) params->tstamp_type != pcm->tstamp_type) { ++ if (hw->version < SNDRV_PROTOCOL_VERSION(2, 0, 12)) { ++ int on = (snd_pcm_tstamp_type_t) params->tstamp_type == ++ SND_PCM_TSTAMP_TYPE_MONOTONIC; ++ if (ioctl(fd, SNDRV_PCM_IOCTL_TSTAMP, &on) < 0) { ++ err = -errno; ++ SNDMSG("TSTAMP failed\n"); ++ return err; ++ } ++ } ++ pcm->tstamp_type = params->tstamp_type; ++ } + sw_set_period_event(params, old_period_event); + hw->mmap_control->avail_min = params->avail_min; + if (hw->period_event != old_period_event) { +@@ -1381,7 +1406,8 @@ int snd_pcm_hw_open_fd(snd_pcm_t **pcmp, const char *name, + int fd, int mmap_emulation ATTRIBUTE_UNUSED, + int sync_ptr_ioctl) + { +- int ver, mode, monotonic = 0; ++ int ver, mode; ++ snd_pcm_tstamp_type_t tstamp_type = SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY; + long fmode; + snd_pcm_t *pcm = NULL; + snd_pcm_hw_t *hw = NULL; +@@ -1429,7 +1455,7 @@ int snd_pcm_hw_open_fd(snd_pcm_t **pcmp, const char *name, + SNDMSG("TTSTAMP failed\n"); + return ret; + } +- monotonic = 1; ++ tstamp_type = SND_PCM_TSTAMP_TYPE_MONOTONIC; + } + } else + #endif +@@ -1471,7 +1497,8 @@ int snd_pcm_hw_open_fd(snd_pcm_t **pcmp, const char *name, + pcm->private_data = hw; + pcm->poll_fd = fd; + pcm->poll_events = info.stream == SND_PCM_STREAM_PLAYBACK ? POLLOUT : POLLIN; +- pcm->monotonic = monotonic; ++ pcm->tstamp_type = tstamp_type; ++ pcm->monotonic = tstamp_type != SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY; + + ret = snd_pcm_hw_mmap_status(pcm); + if (ret < 0) { +-- +1.9.3 + + +From 65ff6fdafb705b5e2e6d4b9a94a80e5de89f5de1 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Thu, 10 Jul 2014 14:37:49 +0200 +Subject: [PATCH 09/35] pcm: Implement timestamp type handling in all plugins + +Now all PCM plugins do support the proper timestamp type or pass it +over slaves. The internal monotonic flag is dropped and replaced with +tstamp_type in all places. + +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_adpcm.c | 2 +- + src/pcm/pcm_alaw.c | 2 +- + src/pcm/pcm_copy.c | 2 +- + src/pcm/pcm_direct.c | 4 ++-- + src/pcm/pcm_direct.h | 2 +- + src/pcm/pcm_dmix.c | 8 ++++---- + src/pcm/pcm_dshare.c | 8 ++++---- + src/pcm/pcm_dsnoop.c | 4 ++-- + src/pcm/pcm_file.c | 6 +++--- + src/pcm/pcm_generic.c | 2 +- + src/pcm/pcm_hooks.c | 2 +- + src/pcm/pcm_hw.c | 1 - + src/pcm/pcm_iec958.c | 2 +- + src/pcm/pcm_ioplug.c | 9 ++++++--- + src/pcm/pcm_ladspa.c | 2 +- + src/pcm/pcm_lfloat.c | 2 +- + src/pcm/pcm_linear.c | 2 +- + src/pcm/pcm_local.h | 45 +++++++++++++++++++++++++++++---------------- + src/pcm/pcm_meter.c | 2 +- + src/pcm/pcm_mmap_emul.c | 2 +- + src/pcm/pcm_mulaw.c | 2 +- + src/pcm/pcm_multi.c | 2 +- + src/pcm/pcm_null.c | 2 +- + src/pcm/pcm_plug.c | 2 +- + src/pcm/pcm_rate.c | 4 ++-- + src/pcm/pcm_route.c | 2 +- + src/pcm/pcm_share.c | 6 +++--- + src/pcm/pcm_softvol.c | 2 +- + 28 files changed, 73 insertions(+), 58 deletions(-) + +diff --git a/src/pcm/pcm_adpcm.c b/src/pcm/pcm_adpcm.c +index 6f0e7c4..1a83c5a 100644 +--- a/src/pcm/pcm_adpcm.c ++++ b/src/pcm/pcm_adpcm.c +@@ -579,7 +579,7 @@ int snd_pcm_adpcm_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sfor + pcm->private_data = adpcm; + pcm->poll_fd = slave->poll_fd; + pcm->poll_events = slave->poll_events; +- pcm->monotonic = slave->monotonic; ++ pcm->tstamp_type = slave->tstamp_type; + snd_pcm_set_hw_ptr(pcm, &adpcm->plug.hw_ptr, -1, 0); + snd_pcm_set_appl_ptr(pcm, &adpcm->plug.appl_ptr, -1, 0); + *pcmp = pcm; +diff --git a/src/pcm/pcm_alaw.c b/src/pcm/pcm_alaw.c +index 1b1bab8..db759e3 100644 +--- a/src/pcm/pcm_alaw.c ++++ b/src/pcm/pcm_alaw.c +@@ -453,7 +453,7 @@ int snd_pcm_alaw_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sform + pcm->private_data = alaw; + pcm->poll_fd = slave->poll_fd; + pcm->poll_events = slave->poll_events; +- pcm->monotonic = slave->monotonic; ++ pcm->tstamp_type = slave->tstamp_type; + snd_pcm_set_hw_ptr(pcm, &alaw->plug.hw_ptr, -1, 0); + snd_pcm_set_appl_ptr(pcm, &alaw->plug.appl_ptr, -1, 0); + *pcmp = pcm; +diff --git a/src/pcm/pcm_copy.c b/src/pcm/pcm_copy.c +index 56a1f6b..66d3a47 100644 +--- a/src/pcm/pcm_copy.c ++++ b/src/pcm/pcm_copy.c +@@ -209,7 +209,7 @@ int snd_pcm_copy_open(snd_pcm_t **pcmp, const char *name, snd_pcm_t *slave, int + pcm->private_data = copy; + pcm->poll_fd = slave->poll_fd; + pcm->poll_events = slave->poll_events; +- pcm->monotonic = slave->monotonic; ++ pcm->tstamp_type = slave->tstamp_type; + snd_pcm_set_hw_ptr(pcm, ©->plug.hw_ptr, -1, 0); + snd_pcm_set_appl_ptr(pcm, ©->plug.appl_ptr, -1, 0); + *pcmp = pcm; +diff --git a/src/pcm/pcm_direct.c b/src/pcm/pcm_direct.c +index 5416cf7..8e37bcb 100644 +--- a/src/pcm/pcm_direct.c ++++ b/src/pcm/pcm_direct.c +@@ -840,6 +840,7 @@ static void save_slave_setting(snd_pcm_direct_t *dmix, snd_pcm_t *spcm) + COPY_SLAVE(period_time); + COPY_SLAVE(periods); + COPY_SLAVE(tstamp_mode); ++ COPY_SLAVE(tstamp_type); + COPY_SLAVE(period_step); + COPY_SLAVE(avail_min); + COPY_SLAVE(start_threshold); +@@ -857,7 +858,6 @@ static void save_slave_setting(snd_pcm_direct_t *dmix, snd_pcm_t *spcm) + COPY_SLAVE(buffer_time); + COPY_SLAVE(sample_bits); + COPY_SLAVE(frame_bits); +- COPY_SLAVE(monotonic); + } + + #undef COPY_SLAVE +@@ -1204,6 +1204,7 @@ static void copy_slave_setting(snd_pcm_direct_t *dmix, snd_pcm_t *spcm) + COPY_SLAVE(period_time); + COPY_SLAVE(periods); + COPY_SLAVE(tstamp_mode); ++ COPY_SLAVE(tstamp_type); + COPY_SLAVE(period_step); + COPY_SLAVE(avail_min); + COPY_SLAVE(start_threshold); +@@ -1221,7 +1222,6 @@ static void copy_slave_setting(snd_pcm_direct_t *dmix, snd_pcm_t *spcm) + COPY_SLAVE(buffer_time); + COPY_SLAVE(sample_bits); + COPY_SLAVE(frame_bits); +- COPY_SLAVE(monotonic); + + spcm->info &= ~SND_PCM_INFO_PAUSE; + spcm->boundary = recalc_boundary_size(dmix->shmptr->s.boundary, spcm->buffer_size); +diff --git a/src/pcm/pcm_direct.h b/src/pcm/pcm_direct.h +index 5ae39c0..9b1ddbc 100644 +--- a/src/pcm/pcm_direct.h ++++ b/src/pcm/pcm_direct.h +@@ -85,8 +85,8 @@ typedef struct { + unsigned int period_size; + unsigned int period_time; + snd_interval_t periods; +- unsigned int monotonic; + snd_pcm_tstamp_t tstamp_mode; ++ snd_pcm_tstamp_type_t tstamp_type; + unsigned int period_step; + unsigned int sleep_min; /* not used */ + unsigned int avail_min; +diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c +index 4aa6d4e..7c53509 100644 +--- a/src/pcm/pcm_dmix.c ++++ b/src/pcm/pcm_dmix.c +@@ -428,7 +428,7 @@ static int snd_pcm_dmix_sync_ptr(snd_pcm_t *pcm) + dmix->avail_max = avail; + if (avail >= pcm->stop_threshold) { + snd_timer_stop(dmix->timer); +- gettimestamp(&dmix->trigger_tstamp, pcm->monotonic); ++ gettimestamp(&dmix->trigger_tstamp, pcm->tstamp_type); + if (dmix->state == SND_PCM_STATE_RUNNING) { + dmix->state = SND_PCM_STATE_XRUN; + return -EPIPE; +@@ -477,7 +477,7 @@ static int snd_pcm_dmix_status(snd_pcm_t *pcm, snd_pcm_status_t * status) + memset(status, 0, sizeof(*status)); + status->state = snd_pcm_dmix_state(pcm); + status->trigger_tstamp = dmix->trigger_tstamp; +- gettimestamp(&status->tstamp, pcm->monotonic); ++ gettimestamp(&status->tstamp, pcm->tstamp_type); + status->avail = snd_pcm_mmap_playback_avail(pcm); + status->avail_max = status->avail > dmix->avail_max ? status->avail : dmix->avail_max; + dmix->avail_max = 0; +@@ -596,7 +596,7 @@ static int snd_pcm_dmix_start(snd_pcm_t *pcm) + return err; + snd_pcm_dmix_sync_area(pcm); + } +- gettimestamp(&dmix->trigger_tstamp, pcm->monotonic); ++ gettimestamp(&dmix->trigger_tstamp, pcm->tstamp_type); + return 0; + } + +@@ -1104,7 +1104,7 @@ int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name, + + pcm->poll_fd = dmix->poll_fd; + pcm->poll_events = POLLIN; /* it's different than other plugins */ +- pcm->monotonic = spcm->monotonic; ++ pcm->tstamp_type = spcm->tstamp_type; + pcm->mmap_rw = 1; + snd_pcm_set_hw_ptr(pcm, &dmix->hw_ptr, -1, 0); + snd_pcm_set_appl_ptr(pcm, &dmix->appl_ptr, -1, 0); +diff --git a/src/pcm/pcm_dshare.c b/src/pcm/pcm_dshare.c +index f2d1103..b985172 100644 +--- a/src/pcm/pcm_dshare.c ++++ b/src/pcm/pcm_dshare.c +@@ -195,7 +195,7 @@ static int snd_pcm_dshare_sync_ptr(snd_pcm_t *pcm) + dshare->avail_max = avail; + if (avail >= pcm->stop_threshold) { + snd_timer_stop(dshare->timer); +- gettimestamp(&dshare->trigger_tstamp, pcm->monotonic); ++ gettimestamp(&dshare->trigger_tstamp, pcm->tstamp_type); + if (dshare->state == SND_PCM_STATE_RUNNING) { + dshare->state = SND_PCM_STATE_XRUN; + return -EPIPE; +@@ -226,7 +226,7 @@ static int snd_pcm_dshare_status(snd_pcm_t *pcm, snd_pcm_status_t * status) + memset(status, 0, sizeof(*status)); + status->state = snd_pcm_state(dshare->spcm); + status->trigger_tstamp = dshare->trigger_tstamp; +- gettimestamp(&status->tstamp, pcm->monotonic); ++ gettimestamp(&status->tstamp, pcm->tstamp_type); + status->avail = snd_pcm_mmap_playback_avail(pcm); + status->avail_max = status->avail > dshare->avail_max ? status->avail : dshare->avail_max; + dshare->avail_max = 0; +@@ -346,7 +346,7 @@ static int snd_pcm_dshare_start(snd_pcm_t *pcm) + return err; + snd_pcm_dshare_sync_area(pcm); + } +- gettimestamp(&dshare->trigger_tstamp, pcm->monotonic); ++ gettimestamp(&dshare->trigger_tstamp, pcm->tstamp_type); + return 0; + } + +@@ -792,7 +792,7 @@ int snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name, + + pcm->poll_fd = dshare->poll_fd; + pcm->poll_events = POLLIN; /* it's different than other plugins */ +- pcm->monotonic = spcm->monotonic; ++ pcm->tstamp_type = spcm->tstamp_type; + pcm->mmap_rw = 1; + snd_pcm_set_hw_ptr(pcm, &dshare->hw_ptr, -1, 0); + snd_pcm_set_appl_ptr(pcm, &dshare->appl_ptr, -1, 0); +diff --git a/src/pcm/pcm_dsnoop.c b/src/pcm/pcm_dsnoop.c +index 7637914..0f9c9df 100644 +--- a/src/pcm/pcm_dsnoop.c ++++ b/src/pcm/pcm_dsnoop.c +@@ -159,7 +159,7 @@ static int snd_pcm_dsnoop_sync_ptr(snd_pcm_t *pcm) + if (pcm->stop_threshold >= pcm->boundary) /* don't care */ + return 0; + if ((avail = snd_pcm_mmap_capture_hw_avail(pcm)) >= pcm->stop_threshold) { +- gettimestamp(&dsnoop->trigger_tstamp, pcm->monotonic); ++ gettimestamp(&dsnoop->trigger_tstamp, pcm->tstamp_type); + dsnoop->state = SND_PCM_STATE_XRUN; + dsnoop->avail_max = avail; + return -EPIPE; +@@ -690,7 +690,7 @@ int snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name, + + pcm->poll_fd = dsnoop->poll_fd; + pcm->poll_events = POLLIN; /* it's different than other plugins */ +- pcm->monotonic = spcm->monotonic; ++ pcm->tstamp_type = spcm->tstamp_type; + pcm->mmap_rw = 1; + snd_pcm_set_hw_ptr(pcm, &dsnoop->hw_ptr, -1, 0); + snd_pcm_set_appl_ptr(pcm, &dsnoop->appl_ptr, -1, 0); +diff --git a/src/pcm/pcm_file.c b/src/pcm/pcm_file.c +index b139f7f..a0b8bf4 100644 +--- a/src/pcm/pcm_file.c ++++ b/src/pcm/pcm_file.c +@@ -781,10 +781,10 @@ int snd_pcm_file_open(snd_pcm_t **pcmp, const char *name, + pcm->poll_fd = slave->poll_fd; + pcm->poll_events = slave->poll_events; + pcm->mmap_shadow = 1; ++ pcm->tstamp_type = SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY; + #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) +- pcm->monotonic = clock_gettime(CLOCK_MONOTONIC, ×pec) == 0; +-#else +- pcm->monotonic = 0; ++ if (clock_gettime(CLOCK_MONOTONIC, ×pec) == 0) ++ pcm->tstamp_type = SND_PCM_TSTAMP_TYPE_MONOTONIC; + #endif + pcm->stream = stream; + snd_pcm_link_hw_ptr(pcm, slave); +diff --git a/src/pcm/pcm_generic.c b/src/pcm/pcm_generic.c +index f068ee2..9b60591 100644 +--- a/src/pcm/pcm_generic.c ++++ b/src/pcm/pcm_generic.c +@@ -294,7 +294,7 @@ int snd_pcm_generic_real_htimestamp(snd_pcm_t *pcm, snd_pcm_uframes_t *avail, + if (ok && (snd_pcm_uframes_t)avail1 == *avail) + break; + *avail = avail1; +- gettimestamp(tstamp, pcm->monotonic); ++ gettimestamp(tstamp, pcm->tstamp_type); + ok = 1; + } + return 0; +diff --git a/src/pcm/pcm_hooks.c b/src/pcm/pcm_hooks.c +index f837282..0b93c64 100644 +--- a/src/pcm/pcm_hooks.c ++++ b/src/pcm/pcm_hooks.c +@@ -240,7 +240,7 @@ int snd_pcm_hooks_open(snd_pcm_t **pcmp, const char *name, snd_pcm_t *slave, int + pcm->poll_fd = slave->poll_fd; + pcm->poll_events = slave->poll_events; + pcm->mmap_shadow = 1; +- pcm->monotonic = slave->monotonic; ++ pcm->tstamp_type = slave->tstamp_type; + snd_pcm_link_hw_ptr(pcm, slave); + snd_pcm_link_appl_ptr(pcm, slave); + *pcmp = pcm; +diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c +index bafa8de..74cff67 100644 +--- a/src/pcm/pcm_hw.c ++++ b/src/pcm/pcm_hw.c +@@ -1498,7 +1498,6 @@ int snd_pcm_hw_open_fd(snd_pcm_t **pcmp, const char *name, + pcm->poll_fd = fd; + pcm->poll_events = info.stream == SND_PCM_STREAM_PLAYBACK ? POLLOUT : POLLIN; + pcm->tstamp_type = tstamp_type; +- pcm->monotonic = tstamp_type != SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY; + + ret = snd_pcm_hw_mmap_status(pcm); + if (ret < 0) { +diff --git a/src/pcm/pcm_iec958.c b/src/pcm/pcm_iec958.c +index 0c61fc1..38c4ce7 100644 +--- a/src/pcm/pcm_iec958.c ++++ b/src/pcm/pcm_iec958.c +@@ -534,7 +534,7 @@ int snd_pcm_iec958_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sfo + pcm->private_data = iec; + pcm->poll_fd = slave->poll_fd; + pcm->poll_events = slave->poll_events; +- pcm->monotonic = slave->monotonic; ++ pcm->tstamp_type = slave->tstamp_type; + snd_pcm_set_hw_ptr(pcm, &iec->plug.hw_ptr, -1, 0); + snd_pcm_set_appl_ptr(pcm, &iec->plug.appl_ptr, -1, 0); + *pcmp = pcm; +diff --git a/src/pcm/pcm_ioplug.c b/src/pcm/pcm_ioplug.c +index c1c3a98..85a8891 100644 +--- a/src/pcm/pcm_ioplug.c ++++ b/src/pcm/pcm_ioplug.c +@@ -448,7 +448,7 @@ static int snd_pcm_ioplug_start(snd_pcm_t *pcm) + if (err < 0) + return err; + +- gettimestamp(&io->trigger_tstamp, pcm->monotonic); ++ gettimestamp(&io->trigger_tstamp, pcm->tstamp_type); + io->data->state = SND_PCM_STATE_RUNNING; + + return 0; +@@ -463,7 +463,7 @@ static int snd_pcm_ioplug_drop(snd_pcm_t *pcm) + + io->data->callback->stop(io->data); + +- gettimestamp(&io->trigger_tstamp, pcm->monotonic); ++ gettimestamp(&io->trigger_tstamp, pcm->tstamp_type); + io->data->state = SND_PCM_STATE_SETUP; + + return 0; +@@ -1069,7 +1069,10 @@ int snd_pcm_ioplug_reinit_status(snd_pcm_ioplug_t *ioplug) + { + ioplug->pcm->poll_fd = ioplug->poll_fd; + ioplug->pcm->poll_events = ioplug->poll_events; +- ioplug->pcm->monotonic = (ioplug->flags & SND_PCM_IOPLUG_FLAG_MONOTONIC) != 0; ++ if (ioplug->flags & SND_PCM_IOPLUG_FLAG_MONOTONIC) ++ ioplug->pcm->tstamp_type = SND_PCM_TSTAMP_TYPE_MONOTONIC; ++ else ++ ioplug->pcm->tstamp_type = SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY; + ioplug->pcm->mmap_rw = ioplug->mmap_rw; + return 0; + } +diff --git a/src/pcm/pcm_ladspa.c b/src/pcm/pcm_ladspa.c +index 7d1e3df..631ee0f 100644 +--- a/src/pcm/pcm_ladspa.c ++++ b/src/pcm/pcm_ladspa.c +@@ -1641,7 +1641,7 @@ int snd_pcm_ladspa_open(snd_pcm_t **pcmp, const char *name, + pcm->private_data = ladspa; + pcm->poll_fd = slave->poll_fd; + pcm->poll_events = slave->poll_events; +- pcm->monotonic = slave->monotonic; ++ pcm->tstamp_type = slave->tstamp_type; + snd_pcm_set_hw_ptr(pcm, &ladspa->plug.hw_ptr, -1, 0); + snd_pcm_set_appl_ptr(pcm, &ladspa->plug.appl_ptr, -1, 0); + *pcmp = pcm; +diff --git a/src/pcm/pcm_lfloat.c b/src/pcm/pcm_lfloat.c +index bbf72c2..324282f 100644 +--- a/src/pcm/pcm_lfloat.c ++++ b/src/pcm/pcm_lfloat.c +@@ -412,7 +412,7 @@ int snd_pcm_lfloat_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sfo + pcm->private_data = lfloat; + pcm->poll_fd = slave->poll_fd; + pcm->poll_events = slave->poll_events; +- pcm->monotonic = slave->monotonic; ++ pcm->tstamp_type = slave->tstamp_type; + snd_pcm_set_hw_ptr(pcm, &lfloat->plug.hw_ptr, -1, 0); + snd_pcm_set_appl_ptr(pcm, &lfloat->plug.appl_ptr, -1, 0); + *pcmp = pcm; +diff --git a/src/pcm/pcm_linear.c b/src/pcm/pcm_linear.c +index 7aa8941..3d5bbb8 100644 +--- a/src/pcm/pcm_linear.c ++++ b/src/pcm/pcm_linear.c +@@ -484,7 +484,7 @@ int snd_pcm_linear_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sfo + pcm->private_data = linear; + pcm->poll_fd = slave->poll_fd; + pcm->poll_events = slave->poll_events; +- pcm->monotonic = slave->monotonic; ++ pcm->tstamp_type = slave->tstamp_type; + snd_pcm_set_hw_ptr(pcm, &linear->plug.hw_ptr, -1, 0); + snd_pcm_set_appl_ptr(pcm, &linear->plug.appl_ptr, -1, 0); + *pcmp = pcm; +diff --git a/src/pcm/pcm_local.h b/src/pcm/pcm_local.h +index 3ed7e1a..2206afe 100644 +--- a/src/pcm/pcm_local.h ++++ b/src/pcm/pcm_local.h +@@ -191,7 +191,6 @@ struct _snd_pcm { + int poll_fd; + unsigned short poll_events; + int setup: 1, +- monotonic: 1, + compat: 1; + snd_pcm_access_t access; /* access mode */ + snd_pcm_format_t format; /* SND_PCM_FORMAT_* */ +@@ -960,26 +959,40 @@ typedef union snd_tmp_double { + } snd_tmp_double_t; + + /* get the current timestamp */ +-static inline void gettimestamp(snd_htimestamp_t *tstamp, int monotonic) ++#ifdef HAVE_CLOCK_GETTIME ++static inline void gettimestamp(snd_htimestamp_t *tstamp, ++ snd_pcm_tstamp_type_t tstamp_type) + { +-#if defined(HAVE_CLOCK_GETTIME) +-#if defined(CLOCK_MONOTONIC) +- if (monotonic) { +- clock_gettime(CLOCK_MONOTONIC, tstamp); +- } else { +-#endif +- clock_gettime(CLOCK_REALTIME, tstamp); +-#else +- struct timeval tv; ++ clockid_t id; + +- gettimeofday(&tv, 0); +- tstamp->tv_sec = tv.tv_sec; +- tstamp->tv_nsec = tv.tv_usec * 1000L; ++ switch (tstamp_type) { ++#ifdef CLOCK_MONOTONIC_RAW ++ case SND_PCM_TSTAMP_TYPE_MONOTONIC_RAW: ++ id = CLOCK_MONOTONIC_RAW; ++ break; + #endif +-#if defined(HAVE_CLOCK_GETTIME) +- } ++#ifdef CLOCK_MONOTONIC ++ case SND_PCM_TSTAMP_TYPE_MONOTONIC: ++ id = CLOCK_MONOTONIC; ++ break; + #endif ++ default: ++ id = CLOCK_REALTIME; ++ break; ++ } ++ clock_gettime(id, tstamp); ++} ++#else /* HAVE_CLOCK_GETTIME */ ++static inline void gettimestamp(snd_htimestamp_t *tstamp, ++ snd_pcm_tstamp_type_t tstamp_type) ++{ ++ struct timeval tv; ++ ++ gettimeofday(&tv, 0); ++ tstamp->tv_sec = tv.tv_sec; ++ tstamp->tv_nsec = tv.tv_usec * 1000L; + } ++#endif /* HAVE_CLOCK_GETTIME */ + + snd_pcm_chmap_query_t ** + _snd_pcm_make_single_query_chmaps(const snd_pcm_chmap_t *src); +diff --git a/src/pcm/pcm_meter.c b/src/pcm/pcm_meter.c +index 676fbef..034f582 100644 +--- a/src/pcm/pcm_meter.c ++++ b/src/pcm/pcm_meter.c +@@ -591,7 +591,7 @@ int snd_pcm_meter_open(snd_pcm_t **pcmp, const char *name, unsigned int frequenc + pcm->private_data = meter; + pcm->poll_fd = slave->poll_fd; + pcm->poll_events = slave->poll_events; +- pcm->monotonic = slave->monotonic; ++ pcm->tstamp_type = slave->tstamp_type; + snd_pcm_link_hw_ptr(pcm, slave); + snd_pcm_link_appl_ptr(pcm, slave); + *pcmp = pcm; +diff --git a/src/pcm/pcm_mmap_emul.c b/src/pcm/pcm_mmap_emul.c +index 63789bc..b2b15ef 100644 +--- a/src/pcm/pcm_mmap_emul.c ++++ b/src/pcm/pcm_mmap_emul.c +@@ -428,7 +428,7 @@ int __snd_pcm_mmap_emul_open(snd_pcm_t **pcmp, const char *name, + pcm->private_data = map; + pcm->poll_fd = slave->poll_fd; + pcm->poll_events = slave->poll_events; +- pcm->monotonic = slave->monotonic; ++ pcm->tstamp_type = slave->tstamp_type; + snd_pcm_set_hw_ptr(pcm, &map->hw_ptr, -1, 0); + snd_pcm_set_appl_ptr(pcm, &map->appl_ptr, -1, 0); + *pcmp = pcm; +diff --git a/src/pcm/pcm_mulaw.c b/src/pcm/pcm_mulaw.c +index 7adce38..011b2a5 100644 +--- a/src/pcm/pcm_mulaw.c ++++ b/src/pcm/pcm_mulaw.c +@@ -467,7 +467,7 @@ int snd_pcm_mulaw_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sfor + pcm->private_data = mulaw; + pcm->poll_fd = slave->poll_fd; + pcm->poll_events = slave->poll_events; +- pcm->monotonic = slave->monotonic; ++ pcm->tstamp_type = slave->tstamp_type; + snd_pcm_set_hw_ptr(pcm, &mulaw->plug.hw_ptr, -1, 0); + snd_pcm_set_appl_ptr(pcm, &mulaw->plug.appl_ptr, -1, 0); + *pcmp = pcm; +diff --git a/src/pcm/pcm_multi.c b/src/pcm/pcm_multi.c +index a84e0ce..4b8299e 100644 +--- a/src/pcm/pcm_multi.c ++++ b/src/pcm/pcm_multi.c +@@ -1077,7 +1077,7 @@ int snd_pcm_multi_open(snd_pcm_t **pcmp, const char *name, + pcm->private_data = multi; + pcm->poll_fd = multi->slaves[master_slave].pcm->poll_fd; + pcm->poll_events = multi->slaves[master_slave].pcm->poll_events; +- pcm->monotonic = multi->slaves[master_slave].pcm->monotonic; ++ pcm->tstamp_type = multi->slaves[master_slave].pcm->tstamp_type; + snd_pcm_link_hw_ptr(pcm, multi->slaves[master_slave].pcm); + snd_pcm_link_appl_ptr(pcm, multi->slaves[master_slave].pcm); + *pcmp = pcm; +diff --git a/src/pcm/pcm_null.c b/src/pcm/pcm_null.c +index 655261f..f11a102 100644 +--- a/src/pcm/pcm_null.c ++++ b/src/pcm/pcm_null.c +@@ -100,7 +100,7 @@ static int snd_pcm_null_status(snd_pcm_t *pcm, snd_pcm_status_t * status) + memset(status, 0, sizeof(*status)); + status->state = null->state; + status->trigger_tstamp = null->trigger_tstamp; +- gettimestamp(&status->tstamp, pcm->monotonic); ++ gettimestamp(&status->tstamp, pcm->tstamp_type); + status->avail = snd_pcm_null_avail_update(pcm); + status->avail_max = pcm->buffer_size; + return 0; +diff --git a/src/pcm/pcm_plug.c b/src/pcm/pcm_plug.c +index 7a6c2b9..5639b9e 100644 +--- a/src/pcm/pcm_plug.c ++++ b/src/pcm/pcm_plug.c +@@ -1127,7 +1127,7 @@ int snd_pcm_plug_open(snd_pcm_t **pcmp, + pcm->poll_fd = slave->poll_fd; + pcm->poll_events = slave->poll_events; + pcm->mmap_shadow = 1; +- pcm->monotonic = slave->monotonic; ++ pcm->tstamp_type = slave->tstamp_type; + snd_pcm_link_hw_ptr(pcm, slave); + snd_pcm_link_appl_ptr(pcm, slave); + *pcmp = pcm; +diff --git a/src/pcm/pcm_rate.c b/src/pcm/pcm_rate.c +index 2563d82..5e811bb 100644 +--- a/src/pcm/pcm_rate.c ++++ b/src/pcm/pcm_rate.c +@@ -1069,7 +1069,7 @@ static int snd_pcm_rate_start(snd_pcm_t *pcm) + if (snd_pcm_state(rate->gen.slave) != SND_PCM_STATE_PREPARED) + return -EBADFD; + +- gettimestamp(&rate->trigger_tstamp, pcm->monotonic); ++ gettimestamp(&rate->trigger_tstamp, pcm->tstamp_type); + + avail = snd_pcm_mmap_playback_hw_avail(rate->gen.slave); + if (avail == 0) { +@@ -1372,7 +1372,7 @@ int snd_pcm_rate_open(snd_pcm_t **pcmp, const char *name, + pcm->poll_fd = slave->poll_fd; + pcm->poll_events = slave->poll_events; + pcm->mmap_rw = 1; +- pcm->monotonic = slave->monotonic; ++ pcm->tstamp_type = slave->tstamp_type; + snd_pcm_set_hw_ptr(pcm, &rate->hw_ptr, -1, 0); + snd_pcm_set_appl_ptr(pcm, &rate->appl_ptr, -1, 0); + *pcmp = pcm; +diff --git a/src/pcm/pcm_route.c b/src/pcm/pcm_route.c +index 751e36f..2f0be38 100644 +--- a/src/pcm/pcm_route.c ++++ b/src/pcm/pcm_route.c +@@ -1122,7 +1122,7 @@ int snd_pcm_route_open(snd_pcm_t **pcmp, const char *name, + pcm->private_data = route; + pcm->poll_fd = slave->poll_fd; + pcm->poll_events = slave->poll_events; +- pcm->monotonic = slave->monotonic; ++ pcm->tstamp_type = slave->tstamp_type; + snd_pcm_set_hw_ptr(pcm, &route->plug.hw_ptr, -1, 0); + snd_pcm_set_appl_ptr(pcm, &route->plug.appl_ptr, -1, 0); + err = route_load_ttable(&route->params, pcm->stream, tt_ssize, ttable, tt_cused, tt_sused); +diff --git a/src/pcm/pcm_share.c b/src/pcm/pcm_share.c +index 118ab26..9770544 100644 +--- a/src/pcm/pcm_share.c ++++ b/src/pcm/pcm_share.c +@@ -971,7 +971,7 @@ static int snd_pcm_share_start(snd_pcm_t *pcm) + } + slave->running_count++; + _snd_pcm_share_update(pcm); +- gettimestamp(&share->trigger_tstamp, pcm->monotonic); ++ gettimestamp(&share->trigger_tstamp, pcm->tstamp_type); + _end: + Pthread_mutex_unlock(&slave->mutex); + return err; +@@ -1126,7 +1126,7 @@ static void _snd_pcm_share_stop(snd_pcm_t *pcm, snd_pcm_state_t state) + return; + } + #endif +- gettimestamp(&share->trigger_tstamp, pcm->monotonic); ++ gettimestamp(&share->trigger_tstamp, pcm->tstamp_type); + if (pcm->stream == SND_PCM_STREAM_CAPTURE) { + snd_pcm_areas_copy(pcm->stopped_areas, 0, + pcm->running_areas, 0, +@@ -1526,7 +1526,7 @@ int snd_pcm_share_open(snd_pcm_t **pcmp, const char *name, const char *sname, + pcm->private_data = share; + pcm->poll_fd = share->client_socket; + pcm->poll_events = stream == SND_PCM_STREAM_PLAYBACK ? POLLOUT : POLLIN; +- pcm->monotonic = slave->pcm->monotonic; ++ pcm->tstamp_type = slave->pcm->tstamp_type; + snd_pcm_set_hw_ptr(pcm, &share->hw_ptr, -1, 0); + snd_pcm_set_appl_ptr(pcm, &share->appl_ptr, -1, 0); + +diff --git a/src/pcm/pcm_softvol.c b/src/pcm/pcm_softvol.c +index 5da9204..c6cfd88 100644 +--- a/src/pcm/pcm_softvol.c ++++ b/src/pcm/pcm_softvol.c +@@ -903,7 +903,7 @@ int snd_pcm_softvol_open(snd_pcm_t **pcmp, const char *name, + * an extra buffer. + */ + pcm->mmap_shadow = 1; +- pcm->monotonic = slave->monotonic; ++ pcm->tstamp_type = slave->tstamp_type; + snd_pcm_set_hw_ptr(pcm, &svol->plug.hw_ptr, -1, 0); + snd_pcm_set_appl_ptr(pcm, &svol->plug.appl_ptr, -1, 0); + *pcmp = pcm; +-- +1.9.3 + + +From 52444bd43afbadb8637f5fac3fe5fd90575ee216 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Mon, 14 Jul 2014 18:12:49 +0200 +Subject: [PATCH 10/35] test/audio_time: Set timestamp type explicitly + +Signed-off-by: Takashi Iwai +--- + test/audio_time.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/test/audio_time.c b/test/audio_time.c +index 03817c7..7435db6 100644 +--- a/test/audio_time.c ++++ b/test/audio_time.c +@@ -57,6 +57,7 @@ void gettimestamp(snd_pcm_t *handle, snd_htimestamp_t *timestamp, + #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 ++#define TSTAMP_TYPE SND_PCM_TSTAMP_TYPE_MONOTONIC + + + int main(void) +@@ -128,6 +129,12 @@ int main(void) + goto _exit; + } + ++ err = snd_pcm_sw_params_set_tstamp_type(handle_p, swparams_p, TSTAMP_TYPE); ++ if (err < 0) { ++ printf("Unable to set tstamp type : %s\n", snd_strerror(err)); ++ goto _exit; ++ } ++ + /* write the sw parameters */ + err = snd_pcm_sw_params(handle_p, swparams_p); + if (err < 0) { +@@ -177,6 +184,12 @@ int main(void) + goto _exit; + } + ++ err = snd_pcm_sw_params_set_tstamp_type(handle_c, swparams_c, TSTAMP_TYPE); ++ if (err < 0) { ++ printf("Unable to set tstamp type : %s\n", snd_strerror(err)); ++ goto _exit; ++ } ++ + /* write the sw parameters */ + err = snd_pcm_sw_params(handle_c, swparams_c); + if (err < 0) { +-- +1.9.3 + + +From de63b942acf520a25ff469cf338a99eb3da65570 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Mon, 21 Jul 2014 16:30:54 +0200 +Subject: [PATCH 11/35] pcm: route: Use get/put labels for all 3 byte formats + +So far, use_getput flag is set only when the src or dest format is +24bit physical width. But, also 18 and 20 bit physical width formats +should set the flag, too. This patch makes the check broader to cover +all 3 bytes formats. + +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_route.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/src/pcm/pcm_route.c b/src/pcm/pcm_route.c +index 2f0be38..72c198c 100644 +--- a/src/pcm/pcm_route.c ++++ b/src/pcm/pcm_route.c +@@ -644,8 +644,10 @@ static int snd_pcm_route_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) + } + if (err < 0) + return err; +- route->params.use_getput = snd_pcm_format_physical_width(src_format) == 24 || +- snd_pcm_format_physical_width(dst_format) == 24; ++ /* 3 bytes formats? */ ++ route->params.use_getput = ++ (snd_pcm_format_physical_width(src_format) + 7) / 3 == 3 || ++ (snd_pcm_format_physical_width(dst_format) + 7) / 3 == 3; + route->params.get_idx = snd_pcm_linear_get_index(src_format, SND_PCM_FORMAT_S16); + route->params.put_idx = snd_pcm_linear_put32_index(SND_PCM_FORMAT_S32, dst_format); + route->params.conv_idx = snd_pcm_linear_convert_index(src_format, dst_format); +-- +1.9.3 + + +From 55c53625212702debf55c719ec62f6c81c780927 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Wed, 16 Jul 2014 17:48:34 +0200 +Subject: [PATCH 12/35] pcm: Fill sw_params proto field + +Fill the new proto field introduced to sw_params with the current PCM +protocol version. This makes tstamp_type evaluated properly in the +kernel. + +Signed-off-by: Takashi Iwai +--- + include/sound/asound.h | 4 ++-- + src/pcm/pcm.c | 1 + + src/pcm/pcm_params.c | 1 + + 3 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/include/sound/asound.h b/include/sound/asound.h +index 552f41b..c819df4 100644 +--- a/include/sound/asound.h ++++ b/include/sound/asound.h +@@ -386,8 +386,8 @@ struct snd_pcm_sw_params { + snd_pcm_uframes_t silence_threshold; /* min distance from noise for silence filling */ + snd_pcm_uframes_t silence_size; /* silence block size */ + snd_pcm_uframes_t boundary; /* pointers wrap point */ +- unsigned int tstamp_type; /* timestamp type */ +- int pads; /* alignment, reserved */ ++ unsigned int proto; /* protocol version */ ++ unsigned int tstamp_type; /* timestamp type (req. proto >= 2.0.12) */ + unsigned char reserved[56]; /* reserved for future */ + }; + +diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c +index 8984443..1399a5b 100644 +--- a/src/pcm/pcm.c ++++ b/src/pcm/pcm.c +@@ -5610,6 +5610,7 @@ int snd_pcm_sw_params_current(snd_pcm_t *pcm, snd_pcm_sw_params_t *params) + SNDMSG("PCM not set up"); + return -EIO; + } ++ params->proto = SNDRV_PCM_VERSION; + params->tstamp_mode = pcm->tstamp_mode; + params->tstamp_type = pcm->tstamp_type; + params->period_step = pcm->period_step; +diff --git a/src/pcm/pcm_params.c b/src/pcm/pcm_params.c +index 4adbefa..6e57904 100644 +--- a/src/pcm/pcm_params.c ++++ b/src/pcm/pcm_params.c +@@ -2257,6 +2257,7 @@ static int snd_pcm_sw_params_default(snd_pcm_t *pcm, snd_pcm_sw_params_t *params + { + assert(pcm && params); + assert(pcm->setup); ++ params->proto = SNDRV_PCM_VERSION; + params->tstamp_mode = SND_PCM_TSTAMP_NONE; + params->tstamp_type = pcm->tstamp_type; + params->period_step = 1; +-- +1.9.3 + + +From fd84adc63e307572d05274be44c782a787087cda Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Tue, 22 Jul 2014 11:55:40 +0200 +Subject: [PATCH 13/35] pcm: route: Use get32 for multi-source route + calculation + +The PCM route plugin can assign the destination value from average of +multiple sources with attenuation. This requires the read of each +channel value, sums and writes the resultant value in the requested +format. + +Currently, get_labels is used for reading source values while +put32_labels is used for writing the dest value. This is, however, +a buggy implementation; get_labels gives the value as is only with +endianness and signedness conversions, but put32_labels assumes that +the value is normalized to 32bit int and it shifts down to the dest +format. In addition, the current code lacks get_labels entries for +the 24bit formats, as Shengjiu Wang spotted out. + +For fixing these bugs, this patch replaces the read with +get32_labels and use always 64bit int for sum. This simplifies the +code a lot and drops many lines. + +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_route.c | 128 +++++++++------------------------------------------ + src/pcm/plugin_ops.h | 81 -------------------------------- + 2 files changed, 23 insertions(+), 186 deletions(-) + +diff --git a/src/pcm/pcm_route.c b/src/pcm/pcm_route.c +index 72c198c..5dac7eb 100644 +--- a/src/pcm/pcm_route.c ++++ b/src/pcm/pcm_route.c +@@ -60,7 +60,7 @@ typedef struct { + typedef struct snd_pcm_route_ttable_dst snd_pcm_route_ttable_dst_t; + + typedef struct { +- enum {UINT32=0, UINT64=1, FLOAT=2} sum_idx; ++ enum {UINT64, FLOAT} sum_idx; + unsigned int get_idx; + unsigned int put_idx; + unsigned int conv_idx; +@@ -233,55 +233,34 @@ static void snd_pcm_route_convert1_many(const snd_pcm_channel_area_t *dst_area, + const snd_pcm_route_ttable_dst_t* ttable, + const snd_pcm_route_params_t *params) + { +-#define GETS_LABELS ++#define GET32_LABELS + #define PUT32_LABELS + #include "plugin_ops.h" +-#undef GETS_LABELS ++#undef GET32_LABELS + #undef PUT32_LABELS +- static void *const zero_labels[3] = { +- &&zero_int32, &&zero_int64, ++ static void *const zero_labels[2] = { ++ &&zero_int64, + #if SND_PCM_PLUGIN_ROUTE_FLOAT + &&zero_float + #endif + }; + /* sum_type att */ +- static void *const add_labels[3 * 2] = { +- &&add_int32_noatt, &&add_int32_att, ++ static void *const add_labels[2 * 2] = { + &&add_int64_noatt, &&add_int64_att, + #if SND_PCM_PLUGIN_ROUTE_FLOAT + &&add_float_noatt, &&add_float_att + #endif + }; +- /* sum_type att shift */ +- static void *const norm_labels[3 * 2 * 4] = { +- 0, +- &&norm_int32_8_noatt, +- &&norm_int32_16_noatt, +- &&norm_int32_24_noatt, +- 0, +- &&norm_int32_8_att, +- &&norm_int32_16_att, +- &&norm_int32_24_att, +- &&norm_int64_0_noatt, +- &&norm_int64_8_noatt, +- &&norm_int64_16_noatt, +- &&norm_int64_24_noatt, +- &&norm_int64_0_att, +- &&norm_int64_8_att, +- &&norm_int64_16_att, +- &&norm_int64_24_att, ++ /* sum_type att */ ++ static void *const norm_labels[2 * 2] = { ++ &&norm_int64_noatt, ++ &&norm_int64_att, + #if SND_PCM_PLUGIN_ROUTE_FLOAT +- &&norm_float_0, +- &&norm_float_8, +- &&norm_float_16, +- &&norm_float_24, +- &&norm_float_0, +- &&norm_float_8, +- &&norm_float_16, +- &&norm_float_24, ++ &&norm_float, ++ &&norm_float, + #endif + }; +- void *zero, *get, *add, *norm, *put32; ++ void *zero, *get32, *add, *norm, *put32; + int nsrcs = ttable->nsrcs; + char *dst; + int dst_step; +@@ -323,9 +302,9 @@ static void snd_pcm_route_convert1_many(const snd_pcm_channel_area_t *dst_area, + } + + zero = zero_labels[params->sum_idx]; +- get = gets_labels[params->get_idx]; ++ get32 = get32_labels[params->get_idx]; + add = add_labels[params->sum_idx * 2 + ttable->att]; +- norm = norm_labels[params->sum_idx * 8 + ttable->att * 4 + 4 - params->src_size]; ++ norm = norm_labels[params->sum_idx * 2 + ttable->att]; + put32 = put32_labels[params->put_idx]; + dst = snd_pcm_channel_area_addr(dst_area, dst_offset); + dst_step = snd_pcm_channel_area_step(dst_area); +@@ -336,9 +315,6 @@ static void snd_pcm_route_convert1_many(const snd_pcm_channel_area_t *dst_area, + + /* Zero sum */ + goto *zero; +- zero_int32: +- sum.as_sint32 = 0; +- goto zero_end; + zero_int64: + sum.as_sint64 = 0; + goto zero_end; +@@ -352,21 +328,14 @@ static void snd_pcm_route_convert1_many(const snd_pcm_channel_area_t *dst_area, + const char *src = srcs[srcidx]; + + /* Get sample */ +- goto *get; +-#define GETS_END after_get ++ goto *get32; ++#define GET32_END after_get + #include "plugin_ops.h" +-#undef GETS_END ++#undef GET32_END + after_get: + + /* Sum */ + goto *add; +- add_int32_att: +- sum.as_sint32 += sample * ttp->as_int; +- goto after_sum; +- add_int32_noatt: +- if (ttp->as_int) +- sum.as_sint32 += sample; +- goto after_sum; + add_int64_att: + sum.as_sint64 += (int64_t) sample * ttp->as_int; + goto after_sum; +@@ -390,48 +359,10 @@ static void snd_pcm_route_convert1_many(const snd_pcm_channel_area_t *dst_area, + + /* Normalization */ + goto *norm; +- norm_int32_8_att: +- sum.as_sint64 = sum.as_sint32; +- norm_int64_8_att: +- sum.as_sint64 <<= 8; +- norm_int64_0_att: ++ norm_int64_att: + div(sum.as_sint64); +- goto norm_int; +- +- norm_int32_16_att: +- sum.as_sint64 = sum.as_sint32; +- norm_int64_16_att: +- sum.as_sint64 <<= 16; +- div(sum.as_sint64); +- goto norm_int; +- +- norm_int32_24_att: +- sum.as_sint64 = sum.as_sint32; +- norm_int64_24_att: +- sum.as_sint64 <<= 24; +- div(sum.as_sint64); +- goto norm_int; +- +- norm_int32_8_noatt: +- sum.as_sint64 = sum.as_sint32; +- norm_int64_8_noatt: +- sum.as_sint64 <<= 8; +- goto norm_int; +- +- norm_int32_16_noatt: +- sum.as_sint64 = sum.as_sint32; +- norm_int64_16_noatt: +- sum.as_sint64 <<= 16; +- goto norm_int; +- +- norm_int32_24_noatt: +- sum.as_sint64 = sum.as_sint32; +- norm_int64_24_noatt: +- sum.as_sint64 <<= 24; +- goto norm_int; +- +- norm_int64_0_noatt: +- norm_int: ++ /* fallthru */ ++ norm_int64_noatt: + if (sum.as_sint64 > (int64_t)0x7fffffff) + sample = 0x7fffffff; /* maximum positive value */ + else if (sum.as_sint64 < -(int64_t)0x80000000) +@@ -441,16 +372,6 @@ static void snd_pcm_route_convert1_many(const snd_pcm_channel_area_t *dst_area, + goto after_norm; + + #if SND_PCM_PLUGIN_ROUTE_FLOAT +- norm_float_8: +- sum.as_float *= 1 << 8; +- goto norm_float; +- norm_float_16: +- sum.as_float *= 1 << 16; +- goto norm_float; +- norm_float_24: +- sum.as_float *= 1 << 24; +- goto norm_float; +- norm_float_0: + norm_float: + sum.as_float = rint(sum.as_float); + if (sum.as_float > (int64_t)0x7fffffff) +@@ -648,7 +569,7 @@ static int snd_pcm_route_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) + route->params.use_getput = + (snd_pcm_format_physical_width(src_format) + 7) / 3 == 3 || + (snd_pcm_format_physical_width(dst_format) + 7) / 3 == 3; +- route->params.get_idx = snd_pcm_linear_get_index(src_format, SND_PCM_FORMAT_S16); ++ route->params.get_idx = snd_pcm_linear_get32_index(src_format, SND_PCM_FORMAT_S32); + route->params.put_idx = snd_pcm_linear_put32_index(SND_PCM_FORMAT_S32, dst_format); + route->params.conv_idx = snd_pcm_linear_convert_index(src_format, dst_format); + route->params.src_size = snd_pcm_format_width(src_format) / 8; +@@ -656,10 +577,7 @@ static int snd_pcm_route_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) + #if SND_PCM_PLUGIN_ROUTE_FLOAT + route->params.sum_idx = FLOAT; + #else +- if (snd_pcm_format_width(src_format) == 32) +- route->params.sum_idx = UINT64; +- else +- route->params.sum_idx = UINT32; ++ route->params.sum_idx = UINT64; + #endif + return 0; + } +diff --git a/src/pcm/plugin_ops.h b/src/pcm/plugin_ops.h +index 21535c9..eb8c2c4 100644 +--- a/src/pcm/plugin_ops.h ++++ b/src/pcm/plugin_ops.h +@@ -668,87 +668,6 @@ getu_1234_C321: sample = bswap_32(as_u32c(src) ^ 0x80); goto GETU_END; + } + #endif + +-#ifdef GETS_LABELS +-/* width endswap sign_toggle */ +-static void *const gets_labels[4 * 2 * 2] = { +- &&gets_1_1, /* 8h -> 8h */ +- &&gets_1_9, /* 8h ^> 8h */ +- &&gets_1_1, /* 8s -> 8h */ +- &&gets_1_9, /* 8s ^> 8h */ +- &&gets_12_12, /* 16h -> 16h */ +- &&gets_12_92, /* 16h ^> 16h */ +- &&gets_12_21, /* 16s -> 16h */ +- &&gets_12_A1, /* 16s ^> 16h */ +- &&gets_0123_0123, /* 24h -> 24h */ +- &&gets_0123_0923, /* 24h ^> 24h */ +- &&gets_1230_0321, /* 24s -> 24h */ +- &&gets_1230_0B21, /* 24s ^> 24h */ +- &&gets_1234_1234, /* 32h -> 32h */ +- &&gets_1234_9234, /* 32h ^> 32h */ +- &&gets_1234_4321, /* 32s -> 32h */ +- &&gets_1234_C321, /* 32s ^> 32h */ +-}; +-#endif +- +-#ifdef GETS_END +-while (0) { +-gets_1_1: sample = as_s8c(src); goto GETS_END; +-gets_1_9: sample = (int8_t)(as_s8c(src) ^ 0x80); goto GETS_END; +-gets_12_12: sample = as_s16c(src); goto GETS_END; +-gets_12_92: sample = (int16_t)(as_s16c(src) ^ 0x8000); goto GETS_END; +-gets_12_21: sample = (int16_t)bswap_16(as_s16c(src)); goto GETS_END; +-gets_12_A1: sample = (int16_t)bswap_16(as_s16c(src) ^ 0x80); goto GETS_END; +-gets_0123_0123: sample = sx24((int32_t)(as_s32c(src) << 8) >> 8); goto GETS_END; +-gets_0123_0923: sample = sx24((int32_t)((as_s32c(src) ^ 0x800000) << 8) >> 8); goto GETS_END; +-gets_1230_0321: sample = sx24((int32_t)(bswap_32(as_s32c(src)) << 8) >> 8); goto GETS_END; +-gets_1230_0B21: sample = sx24((int32_t)(bswap_32(as_s32c(src) ^ 0x8000) << 8) >> 8); goto GETS_END; +-gets_1234_1234: sample = as_s32c(src); goto GETS_END; +-gets_1234_9234: sample = (int32_t)(as_s32c(src) ^ 0x80000000); goto GETS_END; +-gets_1234_4321: sample = (int32_t)bswap_32(as_s32c(src)); goto GETS_END; +-gets_1234_C321: sample = (int32_t)bswap_32(as_s32c(src) ^ 0x80); goto GETS_END; +-} +-#endif +- +-#ifdef PUT_LABELS +-/* width endswap sign_toggle */ +-static void *const put_labels[4 * 2 * 2] = { +- &&put_1_1, /* 8h -> 8h */ +- &&put_1_9, /* 8h ^> 8h */ +- &&put_1_1, /* 8h -> 8s */ +- &&put_1_9, /* 8h ^> 8s */ +- &&put_12_12, /* 16h -> 16h */ +- &&put_12_92, /* 16h ^> 16h */ +- &&put_12_21, /* 16h -> 16s */ +- &&put_12_29, /* 16h ^> 16s */ +- &&put_0123_0123, /* 24h -> 24h */ +- &&put_0123_0923, /* 24h ^> 24h */ +- &&put_0123_3210, /* 24h -> 24s */ +- &&put_0123_3290, /* 24h ^> 24s */ +- &&put_1234_1234, /* 32h -> 32h */ +- &&put_1234_9234, /* 32h ^> 32h */ +- &&put_1234_4321, /* 32h -> 32s */ +- &&put_1234_4329, /* 32h ^> 32s */ +-}; +-#endif +- +-#ifdef PUT_END +-put_1_1: as_s8(dst) = sample; goto PUT_END; +-put_1_9: as_u8(dst) = sample ^ 0x80; goto PUT_END; +-put_12_12: as_s16(dst) = sample; goto PUT_END; +-put_12_92: as_u16(dst) = sample ^ 0x8000; goto PUT_END; +-put_12_21: as_s16(dst) = bswap_16(sample); goto PUT_END; +-put_12_29: as_u16(dst) = bswap_16(sample) ^ 0x80; goto PUT_END; +-/* this always writes the unused byte in 24-bit formats as 0x00 */ +-put_0123_0123: as_s32(dst) = sx24(sample & 0x00ffffff); goto PUT_END; +-put_0123_0923: as_u32(dst) = sx24((sample & 0x00ffffff) ^ 0x800000); goto PUT_END; +-put_0123_3210: as_s32(dst) = sx24s(bswap_32(sample) & 0xffffff00); goto PUT_END; +-put_0123_3290: as_u32(dst) = sx24s((bswap_32(sample) & 0xffffff00) ^ 0x8000); goto PUT_END; +-put_1234_1234: as_s32(dst) = sample; goto PUT_END; +-put_1234_9234: as_u32(dst) = sample ^ 0x80000000; goto PUT_END; +-put_1234_4321: as_s32(dst) = bswap_32(sample); goto PUT_END; +-put_1234_4329: as_u32(dst) = bswap_32(sample) ^ 0x80; goto PUT_END; +-#endif +- + #ifdef PUT32F_LABELS + /* type (0 = float, 1 = float64), endswap */ + static void *const put32float_labels[2 * 2] = { +-- +1.9.3 + + +From 7a5646f58ba2e8154a274a5ae0f8ec963f331f97 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Tue, 22 Jul 2014 12:20:50 +0200 +Subject: [PATCH 14/35] pcm: Drop snd_pcm_linear_{get|put}32_index() + +These are identical with snd_pcm_linear_{get|put}_index(). + +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_lfloat.c | 4 ++-- + src/pcm/pcm_linear.c | 44 ++++---------------------------------------- + src/pcm/pcm_plugin.h | 4 ---- + src/pcm/pcm_route.c | 4 ++-- + 4 files changed, 8 insertions(+), 48 deletions(-) + +diff --git a/src/pcm/pcm_lfloat.c b/src/pcm/pcm_lfloat.c +index 324282f..2f3e578 100644 +--- a/src/pcm/pcm_lfloat.c ++++ b/src/pcm/pcm_lfloat.c +@@ -286,11 +286,11 @@ static int snd_pcm_lfloat_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) + err = INTERNAL(snd_pcm_hw_params_get_format)(params, &dst_format); + } + if (snd_pcm_format_linear(src_format)) { +- lfloat->int32_idx = snd_pcm_linear_get32_index(src_format, SND_PCM_FORMAT_S32); ++ lfloat->int32_idx = snd_pcm_linear_get_index(src_format, SND_PCM_FORMAT_S32); + lfloat->float32_idx = snd_pcm_lfloat_put_s32_index(dst_format); + lfloat->func = snd_pcm_lfloat_convert_integer_float; + } else { +- lfloat->int32_idx = snd_pcm_linear_put32_index(SND_PCM_FORMAT_S32, dst_format); ++ lfloat->int32_idx = snd_pcm_linear_put_index(SND_PCM_FORMAT_S32, dst_format); + lfloat->float32_idx = snd_pcm_lfloat_get_s32_index(src_format); + lfloat->func = snd_pcm_lfloat_convert_float_integer; + } +diff --git a/src/pcm/pcm_linear.c b/src/pcm/pcm_linear.c +index 3d5bbb8..9a92abd 100644 +--- a/src/pcm/pcm_linear.c ++++ b/src/pcm/pcm_linear.c +@@ -107,11 +107,6 @@ int snd_pcm_linear_get_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_f + } + } + +-int snd_pcm_linear_get32_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format) +-{ +- return snd_pcm_linear_get_index(src_format, dst_format); +-} +- + int snd_pcm_linear_put_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format) + { + int sign, width, pwidth, endian; +@@ -143,37 +138,6 @@ int snd_pcm_linear_put_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_f + } + } + +-int snd_pcm_linear_put32_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format) +-{ +- int sign, width, pwidth, endian; +- sign = (snd_pcm_format_signed(src_format) != +- snd_pcm_format_signed(dst_format)); +-#ifdef SND_LITTLE_ENDIAN +- endian = snd_pcm_format_big_endian(dst_format); +-#else +- endian = snd_pcm_format_little_endian(dst_format); +-#endif +- if (endian < 0) +- endian = 0; +- pwidth = snd_pcm_format_physical_width(dst_format); +- width = snd_pcm_format_width(dst_format); +- if (pwidth == 24) { +- switch (width) { +- case 24: +- width = 0; break; +- case 20: +- width = 1; break; +- case 18: +- default: +- width = 2; break; +- } +- return width * 4 + endian * 2 + sign + 16; +- } else { +- width = width / 8 - 1; +- return width * 4 + endian * 2 + sign; +- } +-} +- + void snd_pcm_linear_convert(const snd_pcm_channel_area_t *dst_areas, snd_pcm_uframes_t dst_offset, + const snd_pcm_channel_area_t *src_areas, snd_pcm_uframes_t src_offset, + unsigned int channels, snd_pcm_uframes_t frames, +@@ -342,11 +306,11 @@ static int snd_pcm_linear_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) + snd_pcm_format_physical_width(linear->sformat) == 24); + if (linear->use_getput) { + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { +- linear->get_idx = snd_pcm_linear_get32_index(format, SND_PCM_FORMAT_S32); +- linear->put_idx = snd_pcm_linear_put32_index(SND_PCM_FORMAT_S32, linear->sformat); ++ linear->get_idx = snd_pcm_linear_get_index(format, SND_PCM_FORMAT_S32); ++ linear->put_idx = snd_pcm_linear_put_index(SND_PCM_FORMAT_S32, linear->sformat); + } else { +- linear->get_idx = snd_pcm_linear_get32_index(linear->sformat, SND_PCM_FORMAT_S32); +- linear->put_idx = snd_pcm_linear_put32_index(SND_PCM_FORMAT_S32, format); ++ linear->get_idx = snd_pcm_linear_get_index(linear->sformat, SND_PCM_FORMAT_S32); ++ linear->put_idx = snd_pcm_linear_put_index(SND_PCM_FORMAT_S32, format); + } + } else { + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) +diff --git a/src/pcm/pcm_plugin.h b/src/pcm/pcm_plugin.h +index 19e82c3..b0a3e18 100644 +--- a/src/pcm/pcm_plugin.h ++++ b/src/pcm/pcm_plugin.h +@@ -86,8 +86,6 @@ snd_pcm_sframes_t snd_pcm_plugin_undo_write_generic + /* make local functions really local */ + #define snd_pcm_linear_get_index snd1_pcm_linear_get_index + #define snd_pcm_linear_put_index snd1_pcm_linear_put_index +-#define snd_pcm_linear_get32_index snd1_pcm_linear_get32_index +-#define snd_pcm_linear_put32_index snd1_pcm_linear_put32_index + #define snd_pcm_linear_convert_index snd1_pcm_linear_convert_index + #define snd_pcm_linear_convert snd1_pcm_linear_convert + #define snd_pcm_linear_getput snd1_pcm_linear_getput +@@ -100,8 +98,6 @@ snd_pcm_sframes_t snd_pcm_plugin_undo_write_generic + + int snd_pcm_linear_get_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format); + int snd_pcm_linear_put_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format); +-int snd_pcm_linear_get32_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format); +-int snd_pcm_linear_put32_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format); + int snd_pcm_linear_convert_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format); + + void snd_pcm_linear_convert(const snd_pcm_channel_area_t *dst_areas, snd_pcm_uframes_t dst_offset, +diff --git a/src/pcm/pcm_route.c b/src/pcm/pcm_route.c +index 5dac7eb..e7de9b5 100644 +--- a/src/pcm/pcm_route.c ++++ b/src/pcm/pcm_route.c +@@ -569,8 +569,8 @@ static int snd_pcm_route_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) + route->params.use_getput = + (snd_pcm_format_physical_width(src_format) + 7) / 3 == 3 || + (snd_pcm_format_physical_width(dst_format) + 7) / 3 == 3; +- route->params.get_idx = snd_pcm_linear_get32_index(src_format, SND_PCM_FORMAT_S32); +- route->params.put_idx = snd_pcm_linear_put32_index(SND_PCM_FORMAT_S32, dst_format); ++ route->params.get_idx = snd_pcm_linear_get_index(src_format, SND_PCM_FORMAT_S32); ++ route->params.put_idx = snd_pcm_linear_put_index(SND_PCM_FORMAT_S32, dst_format); + route->params.conv_idx = snd_pcm_linear_convert_index(src_format, dst_format); + route->params.src_size = snd_pcm_format_width(src_format) / 8; + route->params.dst_sfmt = dst_format; +-- +1.9.3 + + +From f6b879e7cc87d83343f5004369146881d1d1e335 Mon Sep 17 00:00:00 2001 +From: Shengjiu Wang +Date: Wed, 23 Jul 2014 15:09:58 +0800 +Subject: [PATCH 15/35] pcm: pcm_local.h: include to enable + CLOCK_MONOTONIC + +CLOCK_MONITONIC is defined in , add before +. + +Signed-off-by: Shengjiu Wang +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_local.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/pcm/pcm_local.h b/src/pcm/pcm_local.h +index 2206afe..80bbe59 100644 +--- a/src/pcm/pcm_local.h ++++ b/src/pcm/pcm_local.h +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + #include + + #define _snd_mask sndrv_mask +-- +1.9.3 + + +From 87df9f3b7a650418b9aef943ac246549c132672a Mon Sep 17 00:00:00 2001 +From: Jurgen Kramer +Date: Sat, 9 Aug 2014 12:09:21 +0200 +Subject: [PATCH 16/35] pcm: Fix DSD formats userland usability + +Support for DSD sample formats has been added a while ago. This patch makes +those sample formats beter usable from userland (e.g. aplay). + +[These implementation details have been forgotten in the previous DSD + support patch -- tiwai] + +Signed-off-by: Takashi Iwai +--- + include/sound/asound.h | 4 +++- + src/pcm/pcm_misc.c | 4 ++++ + 2 files changed, 7 insertions(+), 1 deletion(-) + +diff --git a/include/sound/asound.h b/include/sound/asound.h +index c819df4..5194524 100644 +--- a/include/sound/asound.h ++++ b/include/sound/asound.h +@@ -214,7 +214,9 @@ typedef int __bitwise snd_pcm_format_t; + #define SNDRV_PCM_FORMAT_G723_24_1B ((__force snd_pcm_format_t) 45) /* 1 sample in 1 byte */ + #define SNDRV_PCM_FORMAT_G723_40 ((__force snd_pcm_format_t) 46) /* 8 Samples in 5 bytes */ + #define SNDRV_PCM_FORMAT_G723_40_1B ((__force snd_pcm_format_t) 47) /* 1 sample in 1 byte */ +-#define SNDRV_PCM_FORMAT_LAST SNDRV_PCM_FORMAT_G723_40_1B ++#define SNDRV_PCM_FORMAT_DSD_U8 ((__force snd_pcm_format_t) 48) /* 8 1-bit samples in 1 byte */ ++#define SNDRV_PCM_FORMAT_DSD_U16_LE ((__force snd_pcm_format_t) 49) /* 16 1-bit samples in 2 bytes */ ++#define SNDRV_PCM_FORMAT_LAST SNDRV_PCM_FORMAT_DSD_U16_LE + + #ifdef SNDRV_LITTLE_ENDIAN + #define SNDRV_PCM_FORMAT_S16 SNDRV_PCM_FORMAT_S16_LE +diff --git a/src/pcm/pcm_misc.c b/src/pcm/pcm_misc.c +index d52160c..44bb89c 100644 +--- a/src/pcm/pcm_misc.c ++++ b/src/pcm/pcm_misc.c +@@ -195,11 +195,13 @@ int snd_pcm_format_width(snd_pcm_format_t format) + switch (format) { + case SNDRV_PCM_FORMAT_S8: + case SNDRV_PCM_FORMAT_U8: ++ case SNDRV_PCM_FORMAT_DSD_U8: + return 8; + case SNDRV_PCM_FORMAT_S16_LE: + case SNDRV_PCM_FORMAT_S16_BE: + case SNDRV_PCM_FORMAT_U16_LE: + case SNDRV_PCM_FORMAT_U16_BE: ++ case SNDRV_PCM_FORMAT_DSD_U16_LE: + return 16; + case SNDRV_PCM_FORMAT_S18_3LE: + case SNDRV_PCM_FORMAT_S18_3BE: +@@ -253,11 +255,13 @@ int snd_pcm_format_physical_width(snd_pcm_format_t format) + switch (format) { + case SNDRV_PCM_FORMAT_S8: + case SNDRV_PCM_FORMAT_U8: ++ case SNDRV_PCM_FORMAT_DSD_U8: + return 8; + case SNDRV_PCM_FORMAT_S16_LE: + case SNDRV_PCM_FORMAT_S16_BE: + case SNDRV_PCM_FORMAT_U16_LE: + case SNDRV_PCM_FORMAT_U16_BE: ++ case SNDRV_PCM_FORMAT_DSD_U16_LE: + return 16; + case SNDRV_PCM_FORMAT_S18_3LE: + case SNDRV_PCM_FORMAT_S18_3BE: +-- +1.9.3 + + +From 717ae3dd90c37f3a5ea9809370bdf56e2590a1c4 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Mon, 11 Aug 2014 11:51:29 +0200 +Subject: [PATCH 17/35] Sync include/sound/asound.h with 3.17-rc1 kernel + +Signed-off-by: Takashi Iwai +--- + include/sound/asound.h | 13 +++++++++---- + 1 file changed, 9 insertions(+), 4 deletions(-) + +diff --git a/include/sound/asound.h b/include/sound/asound.h +index 5194524..32168f7 100644 +--- a/include/sound/asound.h ++++ b/include/sound/asound.h +@@ -93,9 +93,12 @@ enum { + SNDRV_HWDEP_IFACE_SB_RC, /* SB Extigy/Audigy2NX remote control */ + SNDRV_HWDEP_IFACE_HDA, /* HD-audio */ + SNDRV_HWDEP_IFACE_USB_STREAM, /* direct access to usb stream */ ++ SNDRV_HWDEP_IFACE_FW_DICE, /* TC DICE FireWire device */ ++ SNDRV_HWDEP_IFACE_FW_FIREWORKS, /* Echo Audio Fireworks based device */ ++ SNDRV_HWDEP_IFACE_FW_BEBOB, /* BridgeCo BeBoB based device */ + + /* Don't forget to change the following: */ +- SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_USB_STREAM ++ SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_FW_BEBOB + }; + + struct snd_hwdep_info { +@@ -214,8 +217,8 @@ typedef int __bitwise snd_pcm_format_t; + #define SNDRV_PCM_FORMAT_G723_24_1B ((__force snd_pcm_format_t) 45) /* 1 sample in 1 byte */ + #define SNDRV_PCM_FORMAT_G723_40 ((__force snd_pcm_format_t) 46) /* 8 Samples in 5 bytes */ + #define SNDRV_PCM_FORMAT_G723_40_1B ((__force snd_pcm_format_t) 47) /* 1 sample in 1 byte */ +-#define SNDRV_PCM_FORMAT_DSD_U8 ((__force snd_pcm_format_t) 48) /* 8 1-bit samples in 1 byte */ +-#define SNDRV_PCM_FORMAT_DSD_U16_LE ((__force snd_pcm_format_t) 49) /* 16 1-bit samples in 2 bytes */ ++#define SNDRV_PCM_FORMAT_DSD_U8 ((__force snd_pcm_format_t) 48) /* DSD, 1-byte samples DSD (x8) */ ++#define SNDRV_PCM_FORMAT_DSD_U16_LE ((__force snd_pcm_format_t) 49) /* DSD, 2-byte samples DSD (x16), little endian */ + #define SNDRV_PCM_FORMAT_LAST SNDRV_PCM_FORMAT_DSD_U16_LE + + #ifdef SNDRV_LITTLE_ENDIAN +@@ -461,7 +464,7 @@ struct snd_xfern { + enum { + SNDRV_PCM_TSTAMP_TYPE_GETTIMEOFDAY = 0, /* gettimeofday equivalent */ + SNDRV_PCM_TSTAMP_TYPE_MONOTONIC, /* posix_clock_monotonic equivalent */ +- SNDRV_PCM_TSTAMP_TYPE_MONOTONIC_RAW, /* monotonic_raw (no NTP) */ ++ SNDRV_PCM_TSTAMP_TYPE_MONOTONIC_RAW, /* monotonic_raw (no NTP) */ + SNDRV_PCM_TSTAMP_TYPE_LAST = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC_RAW, + }; + +@@ -820,6 +823,8 @@ typedef int __bitwise snd_ctl_elem_iface_t; + #define SNDRV_CTL_POWER_D3hot (SNDRV_CTL_POWER_D3|0x0000) /* Off, with power */ + #define SNDRV_CTL_POWER_D3cold (SNDRV_CTL_POWER_D3|0x0001) /* Off, without power */ + ++#define SNDRV_CTL_ELEM_ID_NAME_MAXLEN 44 ++ + struct snd_ctl_elem_id { + unsigned int numid; /* numeric identifier, zero = invalid */ + snd_ctl_elem_iface_t iface; /* interface identifier */ +-- +1.9.3 + + +From e8e54811339b13d6df648bb48b35157d9fba352c Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Mon, 11 Aug 2014 11:55:03 +0200 +Subject: [PATCH 18/35] pcm: Add missing signed and endianess definitions for + DSD formats + +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_misc.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/src/pcm/pcm_misc.c b/src/pcm/pcm_misc.c +index 44bb89c..24d52f9 100644 +--- a/src/pcm/pcm_misc.c ++++ b/src/pcm/pcm_misc.c +@@ -62,6 +62,8 @@ int snd_pcm_format_signed(snd_pcm_format_t format) + case SNDRV_PCM_FORMAT_U20_3BE: + case SNDRV_PCM_FORMAT_U18_3LE: + case SNDRV_PCM_FORMAT_U18_3BE: ++ case SNDRV_PCM_FORMAT_DSD_U8: ++ case SNDRV_PCM_FORMAT_DSD_U16_LE: + return 0; + default: + return -EINVAL; +@@ -150,6 +152,8 @@ int snd_pcm_format_little_endian(snd_pcm_format_t format) + case SNDRV_PCM_FORMAT_U24_3BE: + case SNDRV_PCM_FORMAT_U20_3BE: + case SNDRV_PCM_FORMAT_U18_3BE: ++ case SNDRV_PCM_FORMAT_DSD_U8: ++ case SNDRV_PCM_FORMAT_DSD_U16_LE: + return 0; + default: + return -EINVAL; +-- +1.9.3 + + +From dfc3bf97bf45bd78d498d20fcf930541350f836d Mon Sep 17 00:00:00 2001 +From: Takashi Sakamoto +Date: Mon, 18 Aug 2014 18:45:17 +0900 +Subject: [PATCH 19/35] Sync enum snd_hwdep_iface_t with + include/asound/asound.h + +Some members in this enumerated type has not updated for 9 years, although +kernel-drivers added them during this period. This commit adds them following +to a commit 87df9f3 'sync include/asound/asound.h with 3.17-rc1 kernel'. + +Signed-off-by: Takashi Sakamoto +Signed-off-by: Takashi Iwai +--- + include/hwdep.h | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/include/hwdep.h b/include/hwdep.h +index ab12822..6496fa2 100644 +--- a/include/hwdep.h ++++ b/include/hwdep.h +@@ -68,8 +68,13 @@ typedef enum _snd_hwdep_iface { + SND_HWDEP_IFACE_USX2Y_PCM, /**< Tascam US122, US224 & US428 raw USB PCM */ + SND_HWDEP_IFACE_PCXHR, /**< Digigram PCXHR */ + SND_HWDEP_IFACE_SB_RC, /**< SB Extigy/Audigy2NX remote control */ +- +- SND_HWDEP_IFACE_LAST = SND_HWDEP_IFACE_SB_RC /**< last known hwdep interface */ ++ SND_HWDEP_IFACE_HDA, /**< HD-audio */ ++ SND_HWDEP_IFACE_USB_STREAM, /**< direct access to usb stream */ ++ SND_HWDEP_IFACE_FW_DICE, /**< TC DICE FireWire device */ ++ SND_HWDEP_IFACE_FW_FIREWORKS, /**< Echo Audio Fireworks based device */ ++ SND_HWDEP_IFACE_FW_BEBOB, /**< BridgeCo BeBoB based device */ ++ ++ SND_HWDEP_IFACE_LAST = SND_HWDEP_IFACE_FW_BEBOB /**< last known hwdep interface */ + } snd_hwdep_iface_t; + + /** open for reading */ +-- +1.9.3 + + +From b9f58dcc6f91fde42e6dd2bb831d6063855512a7 Mon Sep 17 00:00:00 2001 +From: Jurgen Kramer +Date: Fri, 22 Aug 2014 10:15:10 +0200 +Subject: [PATCH 20/35] pcm: 2nd round of pcm_misc DSD fixes + +Functions 'snd_pcm_format_silence_64' and 'snd_pcm_format_size' also need to be +able to handle the DSD smaple format. + +Changes from v1: +- Correct silence pattern for DSD + +Signed-off-by: Jurgen Kramer +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_misc.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/src/pcm/pcm_misc.c b/src/pcm/pcm_misc.c +index 24d52f9..46fc771 100644 +--- a/src/pcm/pcm_misc.c ++++ b/src/pcm/pcm_misc.c +@@ -317,11 +317,13 @@ ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples) + switch (format) { + case SNDRV_PCM_FORMAT_S8: + case SNDRV_PCM_FORMAT_U8: ++ case SNDRV_PCM_FORMAT_DSD_U8: + return samples; + case SNDRV_PCM_FORMAT_S16_LE: + case SNDRV_PCM_FORMAT_S16_BE: + case SNDRV_PCM_FORMAT_U16_LE: + case SNDRV_PCM_FORMAT_U16_BE: ++ case SNDRV_PCM_FORMAT_DSD_U16_LE: + return samples * 2; + case SNDRV_PCM_FORMAT_S18_3LE: + case SNDRV_PCM_FORMAT_S18_3BE: +@@ -390,6 +392,9 @@ u_int64_t snd_pcm_format_silence_64(snd_pcm_format_t format) + return 0; + case SNDRV_PCM_FORMAT_U8: + return 0x8080808080808080ULL; ++ case SNDRV_PCM_FORMAT_DSD_U8: ++ case SNDRV_PCM_FORMAT_DSD_U16_LE: ++ return 0x6969696969696969ULL; + #ifdef SNDRV_LITTLE_ENDIAN + case SNDRV_PCM_FORMAT_U16_LE: + return 0x8000800080008000ULL; +-- +1.9.3 + + +From 5f1960e3d8d56aa63afe2c37c6a3f4aa03571627 Mon Sep 17 00:00:00 2001 +From: Dmitry Voytik +Date: Fri, 22 Aug 2014 14:17:10 +0400 +Subject: [PATCH 21/35] doc: fix cross-compiling example + +Simplest way to configure cross-compilation with configure +script is to pass '--host' option. +Passing just '--target' doesn't work. + +Signed-off-by: Dmitry Voytik +Signed-off-by: Takashi Iwai +--- + INSTALL | 9 +++------ + 1 file changed, 3 insertions(+), 6 deletions(-) + +diff --git a/INSTALL b/INSTALL +index 91a8648..47086e3 100644 +--- a/INSTALL ++++ b/INSTALL +@@ -78,16 +78,13 @@ When you would like to cross-compile ALSA library (e.g. compile on + i686 host but for arm architecture) you will need to call ./configure + script with additional parameters: + +-CC=arm-linux-gcc ./configure --target=arm-linux ++CC=arm-linux-gcc ./configure --host=arm-linux + +-In this example host where the library is build is guessed (should be +-given with --host=platform) and target for which is the library build is +-Linux on ARM architecture. You should omit setting 'CC' variable and +-cross-compiler will be guessed too. ++You can omit setting 'CC' variable and cross-compiler will be guessed too. + + So simplest version would be: + +-./configure --target=arm-linux ++./configure --host=arm-linux + + For platform names in the form cpu-vendor-os (or aliases for this) + you should look in 'config.guess' script. Target and all paths +-- +1.9.3 + + +From 99a2254f5f2a085b81efcc80950033a2b6110ecd Mon Sep 17 00:00:00 2001 +From: "Alexander E. Patrakov" +Date: Sun, 31 Aug 2014 22:23:47 +0600 +Subject: [PATCH 22/35] pcm: fix snd_pcm_mmap_hw_avail() near the boundary + +This function returned incorrect results when hw.ptr was near the +boundary and hw.appl_ptr was near zero. Here "incorrect" means "greater +than the boundary". + +The result was incorrect, because it was used as a return value of +various *_rewindable() functions and also as the delay for ioplug. + +Signed-off-by: Alexander E. Patrakov +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_local.h | 8 +------- + 1 file changed, 1 insertion(+), 7 deletions(-) + +diff --git a/src/pcm/pcm_local.h b/src/pcm/pcm_local.h +index 80bbe59..74ebd60 100644 +--- a/src/pcm/pcm_local.h ++++ b/src/pcm/pcm_local.h +@@ -461,13 +461,7 @@ static inline snd_pcm_sframes_t snd_pcm_mmap_capture_hw_avail(snd_pcm_t *pcm) + + static inline snd_pcm_sframes_t snd_pcm_mmap_hw_avail(snd_pcm_t *pcm) + { +- snd_pcm_sframes_t avail; +- avail = *pcm->hw.ptr - *pcm->appl.ptr; +- if (pcm->stream == SND_PCM_STREAM_PLAYBACK) +- avail += pcm->buffer_size; +- if (avail < 0) +- avail += pcm->boundary; +- return pcm->buffer_size - avail; ++ return pcm->buffer_size - snd_pcm_mmap_avail(pcm); + } + + static inline const snd_pcm_channel_area_t *snd_pcm_mmap_areas(snd_pcm_t *pcm) +-- +1.9.3 + + +From 622b1b6bdbb34baca885b65643d4796057574eb7 Mon Sep 17 00:00:00 2001 +From: "Alexander E. Patrakov" +Date: Tue, 2 Sep 2014 01:29:36 +0600 +Subject: [PATCH 23/35] pcm: fix return value of snd_pcm_share_slave_avail + +The return value was wrong for playback if slave->hw_ptr was near the +boundary and *pcm->appl.ptr was near zero. The wrong result was greater +than the boundary. + +Signed-off-by: Alexander E. Patrakov +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_share.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/src/pcm/pcm_share.c b/src/pcm/pcm_share.c +index 9770544..c301c7a 100644 +--- a/src/pcm/pcm_share.c ++++ b/src/pcm/pcm_share.c +@@ -128,6 +128,8 @@ static snd_pcm_uframes_t snd_pcm_share_slave_avail(snd_pcm_share_slave_t *slave) + avail += pcm->buffer_size; + if (avail < 0) + avail += pcm->boundary; ++ else if ((snd_pcm_uframes_t) avail >= pcm->boundary) ++ avail -= pcm->boundary; + return avail; + } + +-- +1.9.3 + + +From e59ffbf30ec13f7f1615ba266ec2f3e770801d6f Mon Sep 17 00:00:00 2001 +From: Jurgen Kramer +Date: Wed, 10 Sep 2014 09:00:28 +0200 +Subject: [PATCH 24/35] pcm: add new 32-bit DSD sample format + +Add the new DSD_U32_LE sample format to alsa-lib. + +NB include/pcm.h and include/sound/asound.h are updated so a new sync with the +kernel headers is not needed + +Signed-off-by: Jurgen Kramer +Signed-off-by: Takashi Iwai +--- + include/pcm.h | 4 +++- + include/sound/asound.h | 3 ++- + src/pcm/pcm.c | 2 ++ + src/pcm/pcm_misc.c | 6 ++++++ + 4 files changed, 13 insertions(+), 2 deletions(-) + +diff --git a/include/pcm.h b/include/pcm.h +index 11e9f0d..db88ad5 100644 +--- a/include/pcm.h ++++ b/include/pcm.h +@@ -211,7 +211,9 @@ typedef enum _snd_pcm_format { + SND_PCM_FORMAT_DSD_U8, + /* Direct Stream Digital (DSD) in 2-byte samples (x16) */ + SND_PCM_FORMAT_DSD_U16_LE, +- SND_PCM_FORMAT_LAST = SND_PCM_FORMAT_DSD_U16_LE, ++ /* Direct Stream Digital (DSD) in 4-byte samples (x32) */ ++ SND_PCM_FORMAT_DSD_U32_LE, ++ SND_PCM_FORMAT_LAST = SND_PCM_FORMAT_DSD_U32_LE, + + #if __BYTE_ORDER == __LITTLE_ENDIAN + /** Signed 16 bit CPU endian */ +diff --git a/include/sound/asound.h b/include/sound/asound.h +index 32168f7..6ee5867 100644 +--- a/include/sound/asound.h ++++ b/include/sound/asound.h +@@ -219,7 +219,8 @@ typedef int __bitwise snd_pcm_format_t; + #define SNDRV_PCM_FORMAT_G723_40_1B ((__force snd_pcm_format_t) 47) /* 1 sample in 1 byte */ + #define SNDRV_PCM_FORMAT_DSD_U8 ((__force snd_pcm_format_t) 48) /* DSD, 1-byte samples DSD (x8) */ + #define SNDRV_PCM_FORMAT_DSD_U16_LE ((__force snd_pcm_format_t) 49) /* DSD, 2-byte samples DSD (x16), little endian */ +-#define SNDRV_PCM_FORMAT_LAST SNDRV_PCM_FORMAT_DSD_U16_LE ++#define SNDRV_PCM_FORMAT_DSD_U32_LE ((__force snd_pcm_format_t) 50) /* DSD, 4-byte samples DSD (x32), little endian */ ++#define SNDRV_PCM_FORMAT_LAST SNDRV_PCM_FORMAT_DSD_U32_LE + + #ifdef SNDRV_LITTLE_ENDIAN + #define SNDRV_PCM_FORMAT_S16 SNDRV_PCM_FORMAT_S16_LE +diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c +index 1399a5b..2e24338 100644 +--- a/src/pcm/pcm.c ++++ b/src/pcm/pcm.c +@@ -1565,6 +1565,7 @@ static const char *const snd_pcm_format_names[] = { + FORMAT(G723_40_1B), + FORMAT(DSD_U8), + FORMAT(DSD_U16_LE), ++ FORMAT(DSD_U32_LE), + }; + + static const char *const snd_pcm_format_aliases[SND_PCM_FORMAT_LAST+1] = { +@@ -1624,6 +1625,7 @@ static const char *const snd_pcm_format_descriptions[] = { + FORMATD(G723_40_1B, "G.723 (ADPCM) 40 kbit/s, 1 sample in 1 byte"), + FORMATD(DSD_U8, "Direct Stream Digital, 1-byte (x8), oldest bit in MSB"), + FORMATD(DSD_U16_LE, "Direct Stream Digital, 2-byte (x16), little endian, oldest bits in MSB"), ++ FORMATD(DSD_U32_LE, "Direct Stream Digital, 4-byte (x32), little endian, oldest bits in MSB"), + }; + + static const char *const snd_pcm_type_names[] = { +diff --git a/src/pcm/pcm_misc.c b/src/pcm/pcm_misc.c +index 46fc771..9272179 100644 +--- a/src/pcm/pcm_misc.c ++++ b/src/pcm/pcm_misc.c +@@ -64,6 +64,7 @@ int snd_pcm_format_signed(snd_pcm_format_t format) + case SNDRV_PCM_FORMAT_U18_3BE: + case SNDRV_PCM_FORMAT_DSD_U8: + case SNDRV_PCM_FORMAT_DSD_U16_LE: ++ case SNDRV_PCM_FORMAT_DSD_U32_LE: + return 0; + default: + return -EINVAL; +@@ -154,6 +155,7 @@ int snd_pcm_format_little_endian(snd_pcm_format_t format) + case SNDRV_PCM_FORMAT_U18_3BE: + case SNDRV_PCM_FORMAT_DSD_U8: + case SNDRV_PCM_FORMAT_DSD_U16_LE: ++ case SNDRV_PCM_FORMAT_DSD_U32_LE: + return 0; + default: + return -EINVAL; +@@ -232,6 +234,7 @@ int snd_pcm_format_width(snd_pcm_format_t format) + case SNDRV_PCM_FORMAT_U32_BE: + case SNDRV_PCM_FORMAT_FLOAT_LE: + case SNDRV_PCM_FORMAT_FLOAT_BE: ++ case SNDRV_PCM_FORMAT_DSD_U32_LE: + return 32; + case SNDRV_PCM_FORMAT_FLOAT64_LE: + case SNDRV_PCM_FORMAT_FLOAT64_BE: +@@ -292,6 +295,7 @@ int snd_pcm_format_physical_width(snd_pcm_format_t format) + case SNDRV_PCM_FORMAT_FLOAT_BE: + case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE: + case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE: ++ case SNDRV_PCM_FORMAT_DSD_U32_LE: + return 32; + case SNDRV_PCM_FORMAT_FLOAT64_LE: + case SNDRV_PCM_FORMAT_FLOAT64_BE: +@@ -348,6 +352,7 @@ ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples) + case SNDRV_PCM_FORMAT_U32_BE: + case SNDRV_PCM_FORMAT_FLOAT_LE: + case SNDRV_PCM_FORMAT_FLOAT_BE: ++ case SNDRV_PCM_FORMAT_DSD_U32_LE: + return samples * 4; + case SNDRV_PCM_FORMAT_FLOAT64_LE: + case SNDRV_PCM_FORMAT_FLOAT64_BE: +@@ -394,6 +399,7 @@ u_int64_t snd_pcm_format_silence_64(snd_pcm_format_t format) + return 0x8080808080808080ULL; + case SNDRV_PCM_FORMAT_DSD_U8: + case SNDRV_PCM_FORMAT_DSD_U16_LE: ++ case SNDRV_PCM_FORMAT_DSD_U32_LE: + return 0x6969696969696969ULL; + #ifdef SNDRV_LITTLE_ENDIAN + case SNDRV_PCM_FORMAT_U16_LE: +-- +1.9.3 + + +From 9a56a673a6cd7343a9345921e2b1cbbb43fb725f Mon Sep 17 00:00:00 2001 +From: "Alexander E. Patrakov" +Date: Sun, 14 Sep 2014 00:30:13 +0600 +Subject: [PATCH 25/35] dmix: actually rewind when running or being drained + +Signed-off-by: Alexander E. Patrakov +Signed-off-by: Jaroslav Kysela +--- + src/pcm/pcm_dmix.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c +index 7c53509..73cbe3f 100644 +--- a/src/pcm/pcm_dmix.c ++++ b/src/pcm/pcm_dmix.c +@@ -669,11 +669,15 @@ static snd_pcm_sframes_t snd_pcm_dmix_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t f + snd_pcm_direct_t *dmix = pcm->private_data; + snd_pcm_uframes_t slave_appl_ptr, slave_size; + snd_pcm_uframes_t appl_ptr, size, transfer, result; ++ int err; + const snd_pcm_channel_area_t *src_areas, *dst_areas; + + if (dmix->state == SND_PCM_STATE_RUNNING || +- dmix->state == SND_PCM_STATE_DRAINING) +- return snd_pcm_dmix_hwsync(pcm); ++ dmix->state == SND_PCM_STATE_DRAINING) { ++ err = snd_pcm_dmix_hwsync(pcm); ++ if (err < 0) ++ return err; ++ } + + if (dmix->last_appl_ptr < dmix->appl_ptr) + size = dmix->appl_ptr - dmix->last_appl_ptr; +-- +1.9.3 + + +From 9a43dc15b2979ed6d8850b033b594fbef829c991 Mon Sep 17 00:00:00 2001 +From: "Alexander E. Patrakov" +Date: Sun, 14 Sep 2014 00:30:14 +0600 +Subject: [PATCH 26/35] pcm: express the rewind size limitation logic better + +There are a few places where the argument of the .rewind or .forward +callback is checked against the same value as returned by .rewindable or +.forwardable. Express this "don't rewind more than rewindable" logic +explicitly, so that the future fixes to the rewindable size can go to +one function instead of two. + +While at it, take advantage of the fact that snd_pcm_mmap_avail() cannot +return negative values (except due to integer overflow, which is AFAICS +impossible given the current boundary choice). + +Signed-off-by: Alexander E. Patrakov +Signed-off-by: Jaroslav Kysela +--- + src/pcm/pcm_dmix.c | 4 +--- + src/pcm/pcm_dshare.c | 6 ++---- + src/pcm/pcm_dsnoop.c | 6 ++---- + src/pcm/pcm_plugin.c | 4 ++-- + 4 files changed, 7 insertions(+), 13 deletions(-) + +diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c +index 73cbe3f..ffde12a 100644 +--- a/src/pcm/pcm_dmix.c ++++ b/src/pcm/pcm_dmix.c +@@ -751,9 +751,7 @@ static snd_pcm_sframes_t snd_pcm_dmix_forward(snd_pcm_t *pcm, snd_pcm_uframes_t + { + snd_pcm_sframes_t avail; + +- avail = snd_pcm_mmap_playback_avail(pcm); +- if (avail < 0) +- return 0; ++ avail = snd_pcm_dmix_forwardable(pcm); + if (frames > (snd_pcm_uframes_t)avail) + frames = avail; + snd_pcm_mmap_appl_forward(pcm, frames); +diff --git a/src/pcm/pcm_dshare.c b/src/pcm/pcm_dshare.c +index b985172..f1a1a1d 100644 +--- a/src/pcm/pcm_dshare.c ++++ b/src/pcm/pcm_dshare.c +@@ -419,7 +419,7 @@ static snd_pcm_sframes_t snd_pcm_dshare_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t + { + snd_pcm_sframes_t avail; + +- avail = snd_pcm_mmap_playback_hw_avail(pcm); ++ avail = snd_pcm_dshare_rewindable(pcm); + if (avail < 0) + return 0; + if (frames > (snd_pcm_uframes_t)avail) +@@ -437,9 +437,7 @@ static snd_pcm_sframes_t snd_pcm_dshare_forward(snd_pcm_t *pcm, snd_pcm_uframes_ + { + snd_pcm_sframes_t avail; + +- avail = snd_pcm_mmap_playback_avail(pcm); +- if (avail < 0) +- return 0; ++ avail = snd_pcm_dshare_forwardable(pcm); + if (frames > (snd_pcm_uframes_t)avail) + frames = avail; + snd_pcm_mmap_appl_forward(pcm, frames); +diff --git a/src/pcm/pcm_dsnoop.c b/src/pcm/pcm_dsnoop.c +index 0f9c9df..e56e402 100644 +--- a/src/pcm/pcm_dsnoop.c ++++ b/src/pcm/pcm_dsnoop.c +@@ -342,9 +342,7 @@ static snd_pcm_sframes_t snd_pcm_dsnoop_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t + { + snd_pcm_sframes_t avail; + +- avail = snd_pcm_mmap_capture_avail(pcm); +- if (avail < 0) +- return 0; ++ avail = snd_pcm_dsnoop_rewindable(pcm); + if (frames > (snd_pcm_uframes_t)avail) + frames = avail; + snd_pcm_mmap_appl_backward(pcm, frames); +@@ -360,7 +358,7 @@ static snd_pcm_sframes_t snd_pcm_dsnoop_forward(snd_pcm_t *pcm, snd_pcm_uframes_ + { + snd_pcm_sframes_t avail; + +- avail = snd_pcm_mmap_capture_hw_avail(pcm); ++ avail = snd_pcm_dsnoop_forwardable(pcm); + if (avail < 0) + return 0; + if (frames > (snd_pcm_uframes_t)avail) +diff --git a/src/pcm/pcm_plugin.c b/src/pcm/pcm_plugin.c +index 4ddf10c..a607ccf 100644 +--- a/src/pcm/pcm_plugin.c ++++ b/src/pcm/pcm_plugin.c +@@ -204,7 +204,7 @@ static snd_pcm_sframes_t snd_pcm_plugin_rewindable(snd_pcm_t *pcm) + snd_pcm_sframes_t snd_pcm_plugin_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames) + { + snd_pcm_plugin_t *plugin = pcm->private_data; +- snd_pcm_sframes_t n = snd_pcm_mmap_hw_avail(pcm); ++ snd_pcm_sframes_t n = snd_pcm_plugin_rewindable(pcm); + snd_pcm_sframes_t sframes; + + if ((snd_pcm_uframes_t)n < frames) +@@ -232,7 +232,7 @@ static snd_pcm_sframes_t snd_pcm_plugin_forwardable(snd_pcm_t *pcm) + snd_pcm_sframes_t snd_pcm_plugin_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) + { + snd_pcm_plugin_t *plugin = pcm->private_data; +- snd_pcm_sframes_t n = snd_pcm_mmap_avail(pcm); ++ snd_pcm_sframes_t n = snd_pcm_plugin_forwardable(pcm); + snd_pcm_sframes_t sframes; + + if ((snd_pcm_uframes_t)n < frames) +-- +1.9.3 + + +From 78c804fc9348e4c29f1c77dd4b6ad586393aa628 Mon Sep 17 00:00:00 2001 +From: "Alexander E. Patrakov" +Date: Sun, 14 Sep 2014 00:30:15 +0600 +Subject: [PATCH 27/35] pcm: handle negative values from snd_pcm_mmap_hw_avail + +Such negative values can happen when an underrun happens and xrun +detection is disabled. Another situation is if the device updated the +pointer before alsa-lib has a chance to detect the xrun. + +The problem is that these negative values could propagate to the +snd_pcm_rewindable return value, where it is specified that negative +returns must be interpreted as error codes and not as negative amount of +samples. + +Signed-off-by: Alexander E. Patrakov +Signed-off-by: Jaroslav Kysela +--- + src/pcm/pcm_dmix.c | 2 +- + src/pcm/pcm_dshare.c | 4 +--- + src/pcm/pcm_hw.c | 2 +- + src/pcm/pcm_ioplug.c | 2 +- + src/pcm/pcm_local.h | 18 ++++++++++++++++++ + src/pcm/pcm_plugin.c | 2 +- + 6 files changed, 23 insertions(+), 7 deletions(-) + +diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c +index ffde12a..babde6a 100644 +--- a/src/pcm/pcm_dmix.c ++++ b/src/pcm/pcm_dmix.c +@@ -661,7 +661,7 @@ static int snd_pcm_dmix_pause(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int enable ATTRIB + + static snd_pcm_sframes_t snd_pcm_dmix_rewindable(snd_pcm_t *pcm) + { +- return snd_pcm_mmap_hw_avail(pcm); ++ return snd_pcm_mmap_playback_hw_rewindable(pcm); + } + + static snd_pcm_sframes_t snd_pcm_dmix_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +diff --git a/src/pcm/pcm_dshare.c b/src/pcm/pcm_dshare.c +index f1a1a1d..020e6f7 100644 +--- a/src/pcm/pcm_dshare.c ++++ b/src/pcm/pcm_dshare.c +@@ -412,7 +412,7 @@ static int snd_pcm_dshare_pause(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int enable ATTR + + static snd_pcm_sframes_t snd_pcm_dshare_rewindable(snd_pcm_t *pcm) + { +- return snd_pcm_mmap_playback_hw_avail(pcm); ++ return snd_pcm_mmap_playback_hw_rewindable(pcm); + } + + static snd_pcm_sframes_t snd_pcm_dshare_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +@@ -420,8 +420,6 @@ static snd_pcm_sframes_t snd_pcm_dshare_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t + snd_pcm_sframes_t avail; + + avail = snd_pcm_dshare_rewindable(pcm); +- if (avail < 0) +- return 0; + if (frames > (snd_pcm_uframes_t)avail) + frames = avail; + snd_pcm_mmap_appl_backward(pcm, frames); +diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c +index 74cff67..c34b766 100644 +--- a/src/pcm/pcm_hw.c ++++ b/src/pcm/pcm_hw.c +@@ -659,7 +659,7 @@ static int snd_pcm_hw_pause(snd_pcm_t *pcm, int enable) + + static snd_pcm_sframes_t snd_pcm_hw_rewindable(snd_pcm_t *pcm) + { +- return snd_pcm_mmap_hw_avail(pcm); ++ return snd_pcm_mmap_hw_rewindable(pcm); + } + + static snd_pcm_sframes_t snd_pcm_hw_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +diff --git a/src/pcm/pcm_ioplug.c b/src/pcm/pcm_ioplug.c +index 85a8891..fe9347c 100644 +--- a/src/pcm/pcm_ioplug.c ++++ b/src/pcm/pcm_ioplug.c +@@ -503,7 +503,7 @@ static int snd_pcm_ioplug_pause(snd_pcm_t *pcm, int enable) + + static snd_pcm_sframes_t snd_pcm_ioplug_rewindable(snd_pcm_t *pcm) + { +- return snd_pcm_mmap_hw_avail(pcm); ++ return snd_pcm_mmap_hw_rewindable(pcm); + } + + static snd_pcm_sframes_t snd_pcm_ioplug_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +diff --git a/src/pcm/pcm_local.h b/src/pcm/pcm_local.h +index 74ebd60..394505f 100644 +--- a/src/pcm/pcm_local.h ++++ b/src/pcm/pcm_local.h +@@ -464,6 +464,24 @@ static inline snd_pcm_sframes_t snd_pcm_mmap_hw_avail(snd_pcm_t *pcm) + return pcm->buffer_size - snd_pcm_mmap_avail(pcm); + } + ++static inline snd_pcm_sframes_t snd_pcm_mmap_playback_hw_rewindable(snd_pcm_t *pcm) ++{ ++ snd_pcm_sframes_t ret = snd_pcm_mmap_playback_hw_avail(pcm); ++ return (ret >= 0) ? ret : 0; ++} ++ ++static inline snd_pcm_sframes_t snd_pcm_mmap_capture_hw_rewindable(snd_pcm_t *pcm) ++{ ++ snd_pcm_sframes_t ret = snd_pcm_mmap_capture_hw_avail(pcm); ++ return (ret >= 0) ? ret : 0; ++} ++ ++static inline snd_pcm_uframes_t snd_pcm_mmap_hw_rewindable(snd_pcm_t *pcm) ++{ ++ snd_pcm_sframes_t ret = snd_pcm_mmap_hw_avail(pcm); ++ return (ret >= 0) ? ret : 0; ++} ++ + static inline const snd_pcm_channel_area_t *snd_pcm_mmap_areas(snd_pcm_t *pcm) + { + if (pcm->stopped_areas && +diff --git a/src/pcm/pcm_plugin.c b/src/pcm/pcm_plugin.c +index a607ccf..c19e2f1 100644 +--- a/src/pcm/pcm_plugin.c ++++ b/src/pcm/pcm_plugin.c +@@ -198,7 +198,7 @@ static int snd_pcm_plugin_reset(snd_pcm_t *pcm) + + static snd_pcm_sframes_t snd_pcm_plugin_rewindable(snd_pcm_t *pcm) + { +- return snd_pcm_mmap_hw_avail(pcm); ++ return snd_pcm_mmap_hw_rewindable(pcm); + } + + snd_pcm_sframes_t snd_pcm_plugin_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +-- +1.9.3 + + +From 0889e9470667dd68d5a0ce47a10a8c6d61b7bc79 Mon Sep 17 00:00:00 2001 +From: "Alexander E. Patrakov" +Date: Sun, 14 Sep 2014 00:30:16 +0600 +Subject: [PATCH 28/35] pcm, rate: use the snd_pcm_mmap_hw_avail function + +instead of the open-coded equivalent + +Signed-off-by: Alexander E. Patrakov +Signed-off-by: Jaroslav Kysela +--- + src/pcm/pcm_rate.c | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/src/pcm/pcm_rate.c b/src/pcm/pcm_rate.c +index 5e811bb..b436a8e 100644 +--- a/src/pcm/pcm_rate.c ++++ b/src/pcm/pcm_rate.c +@@ -593,10 +593,7 @@ static int snd_pcm_rate_hwsync(snd_pcm_t *pcm) + static int snd_pcm_rate_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) + { + snd_pcm_rate_hwsync(pcm); +- if (pcm->stream == SND_PCM_STREAM_PLAYBACK) +- *delayp = snd_pcm_mmap_playback_hw_avail(pcm); +- else +- *delayp = snd_pcm_mmap_capture_hw_avail(pcm); ++ *delayp = snd_pcm_mmap_hw_avail(pcm); + return 0; + } + +-- +1.9.3 + + +From 4fafa468d4bb4618cfde7183f820d8fdd373dcb1 Mon Sep 17 00:00:00 2001 +From: "Alexander E. Patrakov" +Date: Sun, 14 Sep 2014 00:30:17 +0600 +Subject: [PATCH 29/35] pcm, null: use the snd_pcm_mmap_avail function + +instead of the open-coded equivalent + +Signed-off-by: Alexander E. Patrakov +Signed-off-by: Jaroslav Kysela +--- + src/pcm/pcm_null.c | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/src/pcm/pcm_null.c b/src/pcm/pcm_null.c +index f11a102..0529820 100644 +--- a/src/pcm/pcm_null.c ++++ b/src/pcm/pcm_null.c +@@ -86,10 +86,7 @@ static snd_pcm_sframes_t snd_pcm_null_avail_update(snd_pcm_t *pcm) + if (null->state == SND_PCM_STATE_PREPARED) { + /* it is required to return the correct avail count for */ + /* the prepared stream, otherwise the start is not called */ +- if (pcm->stream == SND_PCM_STREAM_PLAYBACK) +- return snd_pcm_mmap_playback_avail(pcm); +- else +- return snd_pcm_mmap_capture_avail(pcm); ++ return snd_pcm_mmap_avail(pcm); + } + return pcm->buffer_size; + } +-- +1.9.3 + + +From ff9d213ff80f6fe0456565d4f524366443217174 Mon Sep 17 00:00:00 2001 +From: "Alexander E. Patrakov" +Date: Sun, 14 Sep 2014 00:30:18 +0600 +Subject: [PATCH 30/35] rate: handle negative values from + snd_pcm_mmap_playback_hw_avail + +Such negative returns are possible during an underrun if xrun detection +is disabled. + +So, don't store the result in an unsigned variable (where it will +overflow), and postpone the trigger in such case, too. + +Signed-off-by: Alexander E. Patrakov +Signed-off-by: Jaroslav Kysela +--- + src/pcm/pcm_rate.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/pcm/pcm_rate.c b/src/pcm/pcm_rate.c +index b436a8e..736d558 100644 +--- a/src/pcm/pcm_rate.c ++++ b/src/pcm/pcm_rate.c +@@ -1058,7 +1058,7 @@ static snd_pcm_state_t snd_pcm_rate_state(snd_pcm_t *pcm) + static int snd_pcm_rate_start(snd_pcm_t *pcm) + { + snd_pcm_rate_t *rate = pcm->private_data; +- snd_pcm_uframes_t avail; ++ snd_pcm_sframes_t avail; + + if (pcm->stream == SND_PCM_STREAM_CAPTURE) + return snd_pcm_start(rate->gen.slave); +@@ -1069,7 +1069,7 @@ static int snd_pcm_rate_start(snd_pcm_t *pcm) + gettimestamp(&rate->trigger_tstamp, pcm->tstamp_type); + + avail = snd_pcm_mmap_playback_hw_avail(rate->gen.slave); +- if (avail == 0) { ++ if (avail <= 0) { + /* postpone the trigger since we have no data committed yet */ + rate->start_pending = 1; + return 0; +-- +1.9.3 + + +From e5e1af83881e4dbe20749a314703db7d0fd091c7 Mon Sep 17 00:00:00 2001 +From: "Alexander E. Patrakov" +Date: Sun, 14 Sep 2014 00:30:19 +0600 +Subject: [PATCH 31/35] dsnoop: rewindable and forwardable logic was swapped + +Signed-off-by: Alexander E. Patrakov +Signed-off-by: Jaroslav Kysela +--- + src/pcm/pcm_dsnoop.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/src/pcm/pcm_dsnoop.c b/src/pcm/pcm_dsnoop.c +index e56e402..8333eef 100644 +--- a/src/pcm/pcm_dsnoop.c ++++ b/src/pcm/pcm_dsnoop.c +@@ -335,7 +335,7 @@ static int snd_pcm_dsnoop_pause(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int enable ATTR + + static snd_pcm_sframes_t snd_pcm_dsnoop_rewindable(snd_pcm_t *pcm) + { +- return snd_pcm_mmap_capture_avail(pcm); ++ return snd_pcm_mmap_capture_hw_avail(pcm); + } + + static snd_pcm_sframes_t snd_pcm_dsnoop_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +@@ -351,7 +351,7 @@ static snd_pcm_sframes_t snd_pcm_dsnoop_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t + + static snd_pcm_sframes_t snd_pcm_dsnoop_forwardable(snd_pcm_t *pcm) + { +- return snd_pcm_mmap_capture_hw_avail(pcm); ++ return snd_pcm_mmap_capture_avail(pcm); + } + + static snd_pcm_sframes_t snd_pcm_dsnoop_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) +@@ -359,8 +359,6 @@ static snd_pcm_sframes_t snd_pcm_dsnoop_forward(snd_pcm_t *pcm, snd_pcm_uframes_ + snd_pcm_sframes_t avail; + + avail = snd_pcm_dsnoop_forwardable(pcm); +- if (avail < 0) +- return 0; + if (frames > (snd_pcm_uframes_t)avail) + frames = avail; + snd_pcm_mmap_appl_forward(pcm, frames); +-- +1.9.3 + + +From 650b8c975cd5c3f7dca6e78e74db587b57bcdfd8 Mon Sep 17 00:00:00 2001 +From: Jaroslav Kysela +Date: Tue, 16 Sep 2014 09:00:39 +0200 +Subject: [PATCH 35/35] pcm route: Fix the bad condition (always false) + +--- + src/pcm/pcm_route.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/pcm/pcm_route.c b/src/pcm/pcm_route.c +index e7de9b5..2a437e8 100644 +--- a/src/pcm/pcm_route.c ++++ b/src/pcm/pcm_route.c +@@ -1147,7 +1147,7 @@ static int _snd_pcm_route_load_ttable(snd_config_t *tt, snd_pcm_route_ttable_ent + snd_config_iterator_t j, jnext; + long cchannel; + const char *id; +- if (!snd_config_get_id(in, &id) < 0) ++ if (snd_config_get_id(in, &id) < 0) + continue; + err = safe_strtol(id, &cchannel); + if (err < 0 || +-- +1.9.3 + diff --git a/SPECS/alsa-lib.spec b/SPECS/alsa-lib.spec index b4c85b9..19ac289 100644 --- a/SPECS/alsa-lib.spec +++ b/SPECS/alsa-lib.spec @@ -4,8 +4,8 @@ Summary: The Advanced Linux Sound Architecture (ALSA) library Name: alsa-lib -Version: 1.0.27.2 -Release: 3%{?prever_dot}%{?dist} +Version: 1.0.28 +Release: 2%{?prever_dot}%{?dist} License: LGPLv2+ Group: System Environment/Libraries URL: http://www.alsa-project.org/ @@ -17,6 +17,7 @@ Source12: modprobe-dist-oss.conf Patch0: alsa-lib-1.0.24-config.patch Patch2: alsa-lib-1.0.14-glibc-open.patch Patch4: alsa-lib-1.0.16-no-dox-date.patch +Patch5: alsa-lib-1.0.28-post.patch BuildRequires: doxygen Requires(post): /sbin/ldconfig, coreutils @@ -47,6 +48,7 @@ against the ALSA libraries and interfaces. %patch0 -p1 -b .config %patch2 -p1 -b .glibc-open %patch4 -p1 -b .no-dox-date +%patch5 -p1 -b .post %build %configure --disable-aload --with-plugindir=%{_libdir}/alsa-lib --disable-alisp @@ -111,6 +113,13 @@ find %{buildroot} -name '*.la' -exec rm -f {} ';' %{_datadir}/aclocal/alsa.m4 %changelog +* Tue Sep 16 2014 Jaroslav Kysela - 1.0.28-2 +- Fix minor coverity bug + +* Mon Sep 15 2014 Jaroslav Kysela - 1.0.28-1 +- Updated to 1.0.28 +- Resolves: rhbz#1112204 + * Fri Jan 24 2014 Daniel Mach - 1.0.27.2-3 - Mass rebuild 2014-01-24