summaryrefslogtreecommitdiffstats
path: root/pcm.c
diff options
context:
space:
mode:
authorMark Farrugia <mark.farrugia@fiberdyne.com.au>2019-03-27 17:47:26 +1100
committerMark Farrugia <mark.farrugia@fiberdyne.com.au>2019-03-27 17:49:12 +1100
commitc22d65351d533a2077caae117e3baf5558d20963 (patch)
treee61b7162bbbe6939eeb1afddaf53001aba683dab /pcm.c
parent07068446e60502bbd4b7b3a5df16a6246183e1ed (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.c103
1 files changed, 87 insertions, 16 deletions
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,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,