diff options
author | Mark Farrugia <mark.farrugia@fiberdyne.com.au> | 2019-03-27 17:47:26 +1100 |
---|---|---|
committer | Mark Farrugia <mark.farrugia@fiberdyne.com.au> | 2019-03-27 17:49:12 +1100 |
commit | c22d65351d533a2077caae117e3baf5558d20963 (patch) | |
tree | e61b7162bbbe6939eeb1afddaf53001aba683dab /pcm.c | |
parent | 07068446e60502bbd4b7b3a5df16a6246183e1ed (diff) |
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 <mark.farrugia@fiberdyne.com.au>
Diffstat (limited to 'pcm.c')
-rw-r--r-- | pcm.c | 103 |
1 files changed, 87 insertions, 16 deletions
@@ -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,12 +134,44 @@ 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 * @hw_params: contains the hardware parameters for the PCM @@ -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, |