Message ID | 20240624131127.498605-2-perex@perex.cz (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | ALSA: pcm: reinvent the stream synchronization ID API | expand |
On 6/24/2024 3:07 PM, Jaroslav Kysela wrote: > Until the commit e11f0f90a626 ("ALSA: pcm: remove SNDRV_PCM_IOCTL1_INFO > internal command"), there was a possibility to pass information > about the synchronized streams to the user space. The mentioned > commit removed blindly the appropriate code with an irrelevant comment. > > The revert may be appropriate, but since this API was lost for several > years without any complains, it's time to improve it. The hardware > parameters may change the used stream clock source (e.g. USB hardware) > so move this synchronization ID to hw_params as read-only field. > > It seems that pipewire can benefit from this API (disable adaptive > resampling for perfectly synchronized PCM streams) now. > > Note that the contents of ID is not supposed to be used for direct > comparison with a specific byte sequence. The "empty" case is when > all bytes are zero (driver does not offer this information) > and all other cases must be only used for equal comparison among > PCM streams (including different sound cards) if they are using > identical hardware clock. > > Cc: Takashi Sakamoto <takaswie@kernel.org> > Signed-off-by: Jaroslav Kysela <perex@perex.cz> > --- (...) > > @@ -420,7 +420,8 @@ struct snd_pcm_hw_params { > unsigned int rate_num; /* R: rate numerator */ > unsigned int rate_den; /* R: rate denominator */ > snd_pcm_uframes_t fifo_size; /* R: chip FIFO size in frames */ > - unsigned char reserved[64]; /* reserved for future */ > + unsigned char sync[16]; /* R: synchronization ID (perfect sync - one clock source) */ If it is introduced as new API, can't this be done better? Maybe like: struct sync { char cardnum[4]; char id[12]; }; or maybe just: struct sync { u32 cardnum; char id[12]; }; or something like that? It is bit hard to follow in next patch all this params->sync + 4 and memset/strncpy. And having named fields would help. Thanks, Amadeusz
On 24. 06. 24 15:38, Amadeusz Sławiński wrote: > On 6/24/2024 3:07 PM, Jaroslav Kysela wrote: >> Until the commit e11f0f90a626 ("ALSA: pcm: remove SNDRV_PCM_IOCTL1_INFO >> internal command"), there was a possibility to pass information >> about the synchronized streams to the user space. The mentioned >> commit removed blindly the appropriate code with an irrelevant comment. >> >> The revert may be appropriate, but since this API was lost for several >> years without any complains, it's time to improve it. The hardware >> parameters may change the used stream clock source (e.g. USB hardware) >> so move this synchronization ID to hw_params as read-only field. >> >> It seems that pipewire can benefit from this API (disable adaptive >> resampling for perfectly synchronized PCM streams) now. >> >> Note that the contents of ID is not supposed to be used for direct >> comparison with a specific byte sequence. The "empty" case is when >> all bytes are zero (driver does not offer this information) >> and all other cases must be only used for equal comparison among >> PCM streams (including different sound cards) if they are using >> identical hardware clock. >> >> Cc: Takashi Sakamoto <takaswie@kernel.org> >> Signed-off-by: Jaroslav Kysela <perex@perex.cz> >> --- > > (...) > >> >> @@ -420,7 +420,8 @@ struct snd_pcm_hw_params { >> unsigned int rate_num; /* R: rate numerator */ >> unsigned int rate_den; /* R: rate denominator */ >> snd_pcm_uframes_t fifo_size; /* R: chip FIFO size in frames */ >> - unsigned char reserved[64]; /* reserved for future */ >> + unsigned char sync[16]; /* R: synchronization ID (perfect sync - one clock source) */ > > If it is introduced as new API, can't this be done better? Maybe like: > struct sync { > char cardnum[4]; > char id[12]; > }; > or maybe just: > struct sync { > u32 cardnum; > char id[12]; > }; > or something like that? It is bit hard to follow in next patch all this > params->sync + 4 and memset/strncpy. And having named fields would help.0 The ID may be not related to one sound card. Multiple cards can share one clock source. It's internal kernel ID generation scheme which may be changed later when there's another demand in future. The applications should handle this as 16-byte blob which is used only for equal comparison among multiple PCM streams. Jaroslav
On 6/24/2024 3:56 PM, Jaroslav Kysela wrote: > On 24. 06. 24 15:38, Amadeusz Sławiński wrote: >> On 6/24/2024 3:07 PM, Jaroslav Kysela wrote: >>> Until the commit e11f0f90a626 ("ALSA: pcm: remove SNDRV_PCM_IOCTL1_INFO >>> internal command"), there was a possibility to pass information >>> about the synchronized streams to the user space. The mentioned >>> commit removed blindly the appropriate code with an irrelevant comment. >>> >>> The revert may be appropriate, but since this API was lost for several >>> years without any complains, it's time to improve it. The hardware >>> parameters may change the used stream clock source (e.g. USB hardware) >>> so move this synchronization ID to hw_params as read-only field. >>> >>> It seems that pipewire can benefit from this API (disable adaptive >>> resampling for perfectly synchronized PCM streams) now. >>> >>> Note that the contents of ID is not supposed to be used for direct >>> comparison with a specific byte sequence. The "empty" case is when >>> all bytes are zero (driver does not offer this information) >>> and all other cases must be only used for equal comparison among >>> PCM streams (including different sound cards) if they are using >>> identical hardware clock. >>> >>> Cc: Takashi Sakamoto <takaswie@kernel.org> >>> Signed-off-by: Jaroslav Kysela <perex@perex.cz> >>> --- >> >> (...) >> >>> @@ -420,7 +420,8 @@ struct snd_pcm_hw_params { >>> unsigned int rate_num; /* R: rate numerator */ >>> unsigned int rate_den; /* R: rate denominator */ >>> snd_pcm_uframes_t fifo_size; /* R: chip FIFO size in frames */ >>> - unsigned char reserved[64]; /* reserved for future */ >>> + unsigned char sync[16]; /* R: synchronization ID (perfect >>> sync - one clock source) */ >> >> If it is introduced as new API, can't this be done better? Maybe like: >> struct sync { >> char cardnum[4]; >> char id[12]; >> }; >> or maybe just: >> struct sync { >> u32 cardnum; >> char id[12]; >> }; >> or something like that? It is bit hard to follow in next patch all this >> params->sync + 4 and memset/strncpy. And having named fields would help.0 > > The ID may be not related to one sound card. Multiple cards can share > one clock source. It's internal kernel ID generation scheme which may be > changed later when there's another demand in future. The applications > should handle this as 16-byte blob which is used only for equal > comparison among multiple PCM streams. Ah, yes rereading it few more times it makes sense. Thanks, Amadeusz
diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 3edd7a7346da..dbce137d8806 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -93,6 +93,7 @@ struct snd_pcm_ops { #define SNDRV_PCM_IOCTL1_CHANNEL_INFO 2 /* 3 is absent slot. */ #define SNDRV_PCM_IOCTL1_FIFO_SIZE 4 +#define SNDRV_PCM_IOCTL1_SYNC_ID 5 #define SNDRV_PCM_TRIGGER_STOP 0 #define SNDRV_PCM_TRIGGER_START 1 @@ -401,7 +402,7 @@ struct snd_pcm_runtime { snd_pcm_uframes_t silence_start; /* starting pointer to silence area */ snd_pcm_uframes_t silence_filled; /* already filled part of silence area */ - union snd_pcm_sync_id sync; /* hardware synchronization ID */ + unsigned char sync[16]; /* hardware synchronization ID */ /* -- mmap -- */ struct snd_pcm_mmap_status *status; diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h index 628d46a0da92..8bf7e8a0eb6f 100644 --- a/include/uapi/sound/asound.h +++ b/include/uapi/sound/asound.h @@ -142,7 +142,7 @@ struct snd_hwdep_dsp_image { * * *****************************************************************************/ -#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 17) +#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 18) typedef unsigned long snd_pcm_uframes_t; typedef signed long snd_pcm_sframes_t; @@ -334,7 +334,7 @@ union snd_pcm_sync_id { unsigned char id[16]; unsigned short id16[8]; unsigned int id32[4]; -}; +} __attribute__((deprecated)); struct snd_pcm_info { unsigned int device; /* RO/WR (control): device number */ @@ -348,7 +348,7 @@ struct snd_pcm_info { int dev_subclass; /* SNDRV_PCM_SUBCLASS_* */ unsigned int subdevices_count; unsigned int subdevices_avail; - union snd_pcm_sync_id sync; /* hardware synchronization ID */ + unsigned char pad1[16]; /* was: hardware synchronization ID */ unsigned char reserved[64]; /* reserved for future... */ }; @@ -420,7 +420,8 @@ struct snd_pcm_hw_params { unsigned int rate_num; /* R: rate numerator */ unsigned int rate_den; /* R: rate denominator */ snd_pcm_uframes_t fifo_size; /* R: chip FIFO size in frames */ - unsigned char reserved[64]; /* reserved for future */ + unsigned char sync[16]; /* R: synchronization ID (perfect sync - one clock source) */ + unsigned char reserved[48]; /* reserved for future */ }; enum { diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 6f73b3c2c205..a6d59ee9eb52 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -525,10 +525,8 @@ void snd_pcm_set_sync(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; - runtime->sync.id32[0] = substream->pcm->card->number; - runtime->sync.id32[1] = -1; - runtime->sync.id32[2] = -1; - runtime->sync.id32[3] = -1; + *(__u32 *)runtime->sync = cpu_to_le32(substream->pcm->card->number); + memset(runtime->sync + 4, 0xff, sizeof(runtime->sync) - 4); } EXPORT_SYMBOL(snd_pcm_set_sync); @@ -1810,6 +1808,25 @@ static int snd_pcm_lib_ioctl_fifo_size(struct snd_pcm_substream *substream, return 0; } +/** + * is sync id (clock id) empty? + */ +static inline bool pcm_sync_empty(const unsigned char *sync) +{ + return sync[0] == 0 && sync[1] == 0 && sync[2] == 0 && sync[3] == 0 && + sync[4] == 0 && sync[5] == 0 && sync[6] == 0 && sync[7] == 0; +} + +static int snd_pcm_lib_ioctl_sync_id(struct snd_pcm_substream *substream, + void *arg) +{ + struct snd_pcm_hw_params *params = arg; + + if (pcm_sync_empty(params->sync)) + memcpy(params->sync, substream->runtime->sync, sizeof(params->sync)); + return 0; +} + /** * snd_pcm_lib_ioctl - a generic PCM ioctl callback * @substream: the pcm substream instance @@ -1831,6 +1848,8 @@ int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream, return snd_pcm_lib_ioctl_channel_info(substream, arg); case SNDRV_PCM_IOCTL1_FIFO_SIZE: return snd_pcm_lib_ioctl_fifo_size(substream, arg); + case SNDRV_PCM_IOCTL1_SYNC_ID: + return snd_pcm_lib_ioctl_sync_id(substream, arg); } return -ENXIO; } diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 521ba56392a0..8be566df4d69 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -533,6 +533,12 @@ static int fixup_unreferenced_params(struct snd_pcm_substream *substream, SNDRV_PCM_INFO_MMAP_VALID); } + err = snd_pcm_ops_ioctl(substream, + SNDRV_PCM_IOCTL1_SYNC_ID, + params); + if (err < 0) + return err; + return 0; } diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index e7f097cae574..773725dbdfbd 100644 --- a/sound/pci/emu10k1/p16v.c +++ b/sound/pci/emu10k1/p16v.c @@ -174,10 +174,9 @@ static int snd_p16v_pcm_open_playback_channel(struct snd_pcm_substream *substrea if (err < 0) return err; - runtime->sync.id32[0] = substream->pcm->card->number; - runtime->sync.id32[1] = 'P'; - runtime->sync.id32[2] = 16; - runtime->sync.id32[3] = 'V'; + *(__u32 *)runtime->sync = cpu_to_le32(substream->pcm->card->number); + memset(runtime->sync + 4, 0, sizeof(runtime->sync) - 4); + strncpy(runtime->sync + 4, "P16V", 4); return 0; }
Until the commit e11f0f90a626 ("ALSA: pcm: remove SNDRV_PCM_IOCTL1_INFO internal command"), there was a possibility to pass information about the synchronized streams to the user space. The mentioned commit removed blindly the appropriate code with an irrelevant comment. The revert may be appropriate, but since this API was lost for several years without any complains, it's time to improve it. The hardware parameters may change the used stream clock source (e.g. USB hardware) so move this synchronization ID to hw_params as read-only field. It seems that pipewire can benefit from this API (disable adaptive resampling for perfectly synchronized PCM streams) now. Note that the contents of ID is not supposed to be used for direct comparison with a specific byte sequence. The "empty" case is when all bytes are zero (driver does not offer this information) and all other cases must be only used for equal comparison among PCM streams (including different sound cards) if they are using identical hardware clock. Cc: Takashi Sakamoto <takaswie@kernel.org> Signed-off-by: Jaroslav Kysela <perex@perex.cz> --- include/sound/pcm.h | 3 ++- include/uapi/sound/asound.h | 9 +++++---- sound/core/pcm_lib.c | 27 +++++++++++++++++++++++---- sound/core/pcm_native.c | 6 ++++++ sound/pci/emu10k1/p16v.c | 7 +++---- 5 files changed, 39 insertions(+), 13 deletions(-)