From c22d65351d533a2077caae117e3baf5558d20963 Mon Sep 17 00:00:00 2001 From: Mark Farrugia Date: Wed, 27 Mar 2019 17:47:26 +1100 Subject: Rework routing system - Add 'route' to snd_avirt_stream, remove from audio path - Add route checking - ensure that source ap and ink ap have compatible hw params - Add private data support for both source and sink Audio Paths, to ensure that the PCM can hold multiple private data(s). - Add ability to use copy_kernel and exttriggers from AVIRT instead of from Audio Paths - Reintroduce pcm_trigger and pcm_prepare, so that they may be called appropriately from AVIRT, rather than child Audio Paths. Signed-off-by: Mark Farrugia --- pcm.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 87 insertions(+), 16 deletions(-) (limited to 'pcm.c') diff --git a/pcm.c b/pcm.c index fc01953..32456cd 100644 --- a/pcm.c +++ b/pcm.c @@ -15,20 +15,57 @@ #define D_PRINTK(fmt, args...) DDEBUG(D_LOGNAME, fmt, ##args) #define D_ERRORK(fmt, args...) DERROR(D_LOGNAME, fmt, ##args) +#define AUDIOPATH_PCM_CB(ap, cb, ops, substream, ...) \ + (((ap)->ops->cb) ? (ap)->ops->cb((substream), ##__VA_ARGS__) : 0) + +#define DO_AUDIOPATH_PCM_ROUTE_CBS(ap, cb, ops, substream, ...) \ + ({ \ + int __err = 0, __endpoint = substream->stream; \ + struct snd_avirt_stream *__stream = \ + snd_avirt_stream_find_by_device( \ + substream->pcm->device); \ + if (!IS_ERR_VALUE(__stream) && __stream) { \ + struct snd_avirt_audiopath *__endpoint_ap; \ + if (__stream->route) { \ + __endpoint_ap = \ + __stream->route \ + ->endpoint_ap[__endpoint]; \ + if ((__endpoint_ap)) { \ + __err = AUDIOPATH_PCM_CB( \ + __endpoint_ap, cb, ops, \ + (substream), ##__VA_ARGS__); \ + } \ + } \ + } \ + (__err); \ + }) /** - * DO_AUDIOPATH_CB - Used to call into an Audio Path's ALSA PCM callback from - * AVIRT, where AVIRT's own callback must be attended to first. + * DO_AUDIOPATH_PCM_CBS - Call an Audio Path's ALSA PCM callbacks from AVIRT. + * If the Audio Path has routing enabled, then we call the appropriate + * from/to Audio Path's ALSA PCM callbacks */ -#define DO_AUDIOPATH_CB(ap, callback, substream, ...) \ - ((!substream->stream) ? \ - (((ap)->pcm_playback_ops->callback) ? \ - (ap)->pcm_playback_ops->callback((substream), \ - ##__VA_ARGS__) : \ - 0) : \ - (((ap)->pcm_capture_ops->callback) ? \ - (ap)->pcm_capture_ops->callback((substream), \ - ##__VA_ARGS__) : \ - 0)) +#define DO_AUDIOPATH_PCM_CBS(ap, cb, substream, ...) \ + ({ \ + int __err = 0; \ + if (substream->stream) { \ + __err = AUDIOPATH_PCM_CB((ap), cb, pcm_capture_ops, \ + (substream), ##__VA_ARGS__); \ + if (__err >= 0) { \ + __err = DO_AUDIOPATH_PCM_ROUTE_CBS( \ + (ap), cb, pcm_playback_ops, \ + (substream), ##__VA_ARGS__); \ + } \ + } else { \ + __err = AUDIOPATH_PCM_CB((ap), cb, pcm_playback_ops, \ + (substream), ##__VA_ARGS__); \ + if (__err >= 0) { \ + __err = DO_AUDIOPATH_PCM_ROUTE_CBS( \ + (ap), cb, pcm_capture_ops, \ + (substream), ##__VA_ARGS__); \ + } \ + } \ + (__err); \ + }) #define PRIVATE_DATA(substream) \ ((struct snd_avirt_private_data *)substream->private_data) @@ -82,8 +119,8 @@ static int pcm_open(struct snd_pcm_substream *substream) hw->channels_min = chans; hw->channels_max = chans; - // Do additional Audio Path 'open' callback - return DO_AUDIOPATH_CB(audiopath, open, substream); + // Do additional Audio Path 'open' callbacks + return DO_AUDIOPATH_PCM_CBS(audiopath, open, substream); } /** @@ -97,11 +134,43 @@ static int pcm_open(struct snd_pcm_substream *substream) static int pcm_close(struct snd_pcm_substream *substream) { // Do additional Audio Path 'close' callback - return DO_AUDIOPATH_CB( + return DO_AUDIOPATH_PCM_CBS( (struct snd_avirt_audiopath *)PRIVATE_DATA(substream)->audiopath, close, substream); } +/** + * pcm_close - Implements 'close' callback for PCM middle layer + * @substream: pointer to ALSA PCM substream + * + * This is called when a PCM substream is closed. + * + * Returns 0 on success or error code otherwise. + */ +static int pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + // Do additional Audio Path 'trigger' callback + return DO_AUDIOPATH_PCM_CBS( + (struct snd_avirt_audiopath *)PRIVATE_DATA(substream)->audiopath, + trigger, substream, cmd); +} + +/** + * pcm_close - Implements 'close' callback for PCM middle layer + * @substream: pointer to ALSA PCM substream + * + * This is called when a PCM substream is closed. + * + * Returns 0 on success or error code otherwise. + */ +static int pcm_prepare(struct snd_pcm_substream *substream) +{ + // Do additional Audio Path 'prepare' callback + return DO_AUDIOPATH_PCM_CBS( + (struct snd_avirt_audiopath *)PRIVATE_DATA(substream)->audiopath, + prepare, substream); +} + /** * pcm_hw_params - Implements 'hw_params' callback for PCM middle layer * @substream: pointer to ALSA PCM substream @@ -149,7 +218,7 @@ static int pcm_hw_free(struct snd_pcm_substream *substream) int err; // Do additional Audio Path 'hw_free' callback - err = DO_AUDIOPATH_CB( + err = DO_AUDIOPATH_PCM_CBS( (struct snd_avirt_audiopath *)PRIVATE_DATA(substream)->audiopath, hw_free, substream); if (err < 0) @@ -165,6 +234,8 @@ static int pcm_hw_free(struct snd_pcm_substream *substream) struct snd_pcm_ops pcm_ops_avirt = { .open = pcm_open, .close = pcm_close, + .prepare = pcm_prepare, + .trigger = pcm_trigger, .ioctl = snd_pcm_lib_ioctl, .hw_params = pcm_hw_params, .hw_free = pcm_hw_free, -- cgit 1.2.3-korg