aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Farrugia <mark.farrugia@fiberdyne.com.au>2019-04-01 11:58:08 +1100
committerMark Farrugia <mark.farrugia@fiberdyne.com.au>2019-04-01 11:58:59 +1100
commit92c383e87fffd5fd22c553e30b9fc94f2cb5f9c0 (patch)
tree28d2621bb423b302ced5475514f03cb06b917715
parentc22d65351d533a2077caae117e3baf5558d20963 (diff)
Add 'internal' streams for routing, revamp stream finalisation
Uses the ALSA internal PCM API to create streams purely used for internal routing purposes. Adds the 'try_complete' functions for both streams and routes in an attempt to standardize the finalization of a stream or route object. Signed-off-by: Mark Farrugia <mark.farrugia@fiberdyne.com.au>
-rw-r--r--configfs.c43
-rw-r--r--core.c103
-rw-r--r--core.h21
-rw-r--r--sound/avirt.h2
4 files changed, 140 insertions, 29 deletions
diff --git a/configfs.c b/configfs.c
index bc10efb..2751d66 100644
--- a/configfs.c
+++ b/configfs.c
@@ -59,6 +59,7 @@
if ((tmp > INT_MAX) || (tmp == 0)) \
return -ERANGE; \
s->channels = tmp; \
+ snd_avirt_##type##_try_complete(s); \
return count; \
} \
CONFIGFS_ATTR(cfg_snd_avirt_##type##_, channels);
@@ -140,12 +141,30 @@ static ssize_t cfg_snd_avirt_stream_map_show(struct config_item *item,
static ssize_t cfg_snd_avirt_stream_map_store(struct config_item *item,
const char *page, size_t count)
{
- char *split;
+ char *map;
+ struct snd_avirt_audiopath *audiopath;
struct snd_avirt_stream *stream =
snd_avirt_stream_from_config_item(item);
- split = strsep((char **)&page, "\n");
- snd_avirt_stream_set_map(stream, split);
+ map = strsep((char **)&page, "\n");
+
+ /* If already sealed, we cannot create the stream */
+ if (snd_avirt_streams_sealed()) {
+ D_ERRORK("Streams already sealed. Cannot set map: '%s'", map);
+ return -EPERM;
+ }
+
+ if (!strcmp(stream->map, map))
+ return -1;
+
+ audiopath = snd_avirt_audiopath_get(map);
+ if (!audiopath) {
+ D_ERRORK("Cannot find Audio Path uid: '%s'!", stream->map);
+ }
+
+ memcpy(stream->map, (char *)map, strlen(map));
+
+ snd_avirt_stream_try_complete(stream);
return count;
}
@@ -304,7 +323,8 @@ static struct config_item_type cfg_snd_avirt_route_type = {
static struct config_item *
cfg_snd_avirt_stream_make_item(struct config_group *group, const char *name)
{
- char *split;
+ char *split, *stream_name;
+ bool internal = false;
int direction;
struct snd_avirt_stream *stream;
@@ -326,16 +346,23 @@ cfg_snd_avirt_stream_make_item(struct config_group *group, const char *name)
}
// Get stream name, and create PCM for stream
- split = strsep((char **)&name, "\n");
- stream = snd_avirt_stream_create(split, direction);
+ stream_name = strsep((char **)&name, "\n");
+
+ // If internal, get internal
+ split = strstr(stream_name, "__internal");
+ if (split) {
+ stream_name = strsep((char **)&stream_name, "__");
+ internal = true;
+ }
+
+ // Finally, create stream
+ stream = snd_avirt_stream_create(stream_name, direction, internal);
if (IS_ERR(stream))
return ERR_PTR(PTR_ERR(stream));
config_item_init_type_name(&stream->item, name,
&cfg_snd_avirt_stream_type);
- D_INFOK("Make stream: %s", stream->name);
-
return &stream->item;
}
diff --git a/core.c b/core.c
index 41d6b40..d66ee2a 100644
--- a/core.c
+++ b/core.c
@@ -77,8 +77,14 @@ static struct snd_pcm *snd_avirt_pcm_create(struct snd_avirt_stream *stream)
capture = true;
}
- err = snd_pcm_new(core.card, stream->name, stream->device, playback,
- capture, &pcm);
+ if (stream->internal) {
+ err = snd_pcm_new_internal(core.card, stream->name,
+ stream->device, playback, capture,
+ &pcm);
+ } else {
+ err = snd_pcm_new(core.card, stream->name, stream->device,
+ playback, capture, &pcm);
+ }
if (err < 0) {
D_ERRORK("Failed to create PCM device for stream: '%s'",
@@ -122,29 +128,56 @@ static struct snd_avirt_route *snd_avirt_route_get(const char *uid)
return NULL;
}
-int snd_avirt_stream_set_map(struct snd_avirt_stream *stream, const char *map)
+/**
+ * int snd_avirt_route_try_complete - Set up remaining parameters for a route.
+ * Channels, sink, and source Audio Paths
+ * should be set when calling this function.
+ * @stream: The route to attempt to finalize parameters for.
+ * @return: 0 on success, negative ERRNO on failure
+ */
+int snd_avirt_route_try_complete(struct snd_avirt_route *route)
+{
+ return 0;
+}
+
+/**
+ * int snd_avirt_stream_try_complete - Set up remaining parameters for a stream.
+ * Channels and map should be set when
+ * calling this function.
+ * @stream: The stream to attempt to finalize parameters for.
+ * @return: 0 on success, negative ERRNO on failure
+ */
+int snd_avirt_stream_try_complete(struct snd_avirt_stream *stream)
{
struct snd_avirt_audiopath *audiopath;
+ struct snd_avirt_route *route;
struct snd_pcm_ops *pcm_ops_ap;
- /* If already sealed, we cannot create the stream */
- if (snd_avirt_streams_sealed()) {
- D_ERRORK("Streams already sealed. Cannot set map: '%s'", map);
+ if (snd_avirt_streams_sealed())
return -EPERM;
- }
- if (!strcmp(stream->map, map))
- return -1;
+ if ((stream->channels == 0) || (!strcmp(stream->map, "none")))
+ return -EPERM;
- memcpy(stream->map, (char *)map, strlen(map));
- audiopath = snd_avirt_audiopath_get(map);
+ audiopath = snd_avirt_audiopath_get(stream->map);
if (!audiopath) {
D_ERRORK("Cannot find Audio Path uid: '%s'!", stream->map);
- return -EFAULT;
}
/* Check for any routes that have been created for this stream */
- stream->route = snd_avirt_route_get(stream->name);
+ route = snd_avirt_route_get(stream->name);
+ if (route) {
+ if (audiopath == route->endpoint_ap[SND_AVIRT_ROUTE_SOURCE])
+ route->endpoint_stream[SND_AVIRT_ROUTE_SOURCE] = stream;
+ else if (audiopath == route->endpoint_ap[SND_AVIRT_ROUTE_SINK])
+ route->endpoint_stream[SND_AVIRT_ROUTE_SINK] = stream;
+ else {
+ D_INFOK("Cannot set route. Audio Path not compatible");
+ return -EPERM;
+ }
+
+ stream->route = route;
+ }
/* Set up PCM ops */
if (!stream->direction)
@@ -348,11 +381,21 @@ int snd_avirt_audiopath_set_private_data(struct snd_avirt_audiopath *ap,
{
int err = 0;
snd_avirt_route_endpoint endpoint = SND_AVIRT_ROUTE_SOURCE;
- struct snd_avirt_private_data *avirt_private_data = pcm->private_data;
+ struct snd_avirt_stream *stream;
+ struct snd_avirt_private_data *avirt_private_data;
+
+ stream = snd_avirt_stream_find_by_device(pcm->device);
+ if (IS_ERR_VALUE(stream) || !stream)
+ goto exit_err;
err = snd_avirt_route_endpoint_pos(pcm, ap->uid, &endpoint);
if (err == -2)
goto exit_err;
+
+ if (stream->internal && stream->route)
+ pcm = stream->route->endpoint_stream[!endpoint]->pcm;
+
+ avirt_private_data = pcm->private_data;
if (!avirt_private_data)
goto exit_err;
@@ -361,6 +404,8 @@ int snd_avirt_audiopath_set_private_data(struct snd_avirt_audiopath *ap,
return 0;
exit_err:
+ D_ERRORK("Error setting private data for ap:%s, stream:%s, endpoint:%d",
+ ap->uid, pcm->name, endpoint);
return -1;
}
EXPORT_SYMBOL_GPL(snd_avirt_audiopath_set_private_data);
@@ -376,17 +421,29 @@ void *snd_avirt_audiopath_get_private_data(struct snd_avirt_audiopath *ap,
{
int err = 0;
snd_avirt_route_endpoint endpoint = SND_AVIRT_ROUTE_SOURCE;
- struct snd_avirt_private_data *avirt_private_data = pcm->private_data;
+ struct snd_avirt_stream *stream;
+ struct snd_avirt_private_data *avirt_private_data;
+
+ stream = snd_avirt_stream_find_by_device(pcm->device);
+ if (IS_ERR_VALUE(stream) || !stream)
+ return NULL;
err = snd_avirt_route_endpoint_pos(pcm, ap->uid, &endpoint);
if (err == -2)
goto exit_err;
+
+ if (stream->internal && stream->route)
+ pcm = stream->route->endpoint_stream[!endpoint]->pcm;
+
+ avirt_private_data = pcm->private_data;
if (!avirt_private_data)
goto exit_err;
return avirt_private_data->ap_private_data[endpoint];
exit_err:
+ D_ERRORK("Error getting private data for ap:%s, stream:%s, endpoint:%d",
+ ap->uid, pcm->name, endpoint);
return NULL;
}
EXPORT_SYMBOL_GPL(snd_avirt_audiopath_get_private_data);
@@ -485,10 +542,11 @@ struct snd_avirt_route *snd_avirt_route_create(const char *uid, int direction)
* @name: The name designated to the audio stream
* @direction: The PCM direction (SNDRV_PCM_STREAM_PLAYBACK or
* SNDRV_PCM_STREAM_CAPTURE)
+ * @internal: Whether the PCM should be internal or not
* @return: The newly created audio stream if successful, or an error pointer
*/
struct snd_avirt_stream *snd_avirt_stream_create(const char *name,
- int direction)
+ int direction, bool internal)
{
struct snd_avirt_stream *stream;
@@ -505,6 +563,7 @@ struct snd_avirt_stream *snd_avirt_stream_create(const char *name,
strncpy(stream->map, "none", MAX_NAME_LEN);
stream->channels = 0;
stream->direction = direction;
+ stream->internal = internal;
stream->device = core.stream_count++;
/* Initialize PCM ops table for this stream.
@@ -516,7 +575,12 @@ struct snd_avirt_stream *snd_avirt_stream_create(const char *name,
}
memcpy(stream->pcm_ops, &pcm_ops_avirt, sizeof(struct snd_pcm_ops));
- D_INFOK("name:%s device:%d", name, stream->device);
+ if (stream->internal) {
+ D_INFOK("name:%s device:%d internal:%d", name, stream->device,
+ stream->internal);
+ } else {
+ D_INFOK("name:%s device:%d", name, stream->device);
+ }
return stream;
}
@@ -540,9 +604,8 @@ int snd_avirt_streams_seal(void)
0)
continue;
- D_INFOK("Do configure for AP: %s streams:%d cb:%p",
- ap_obj->path->uid, stream_array.count,
- ap_obj->path->configure);
+ D_INFOK("Do configure for AP: %s streams:%d", ap_obj->path->uid,
+ stream_array.count);
ap_obj->path->configure(core.card, &stream_array);
}
diff --git a/core.h b/core.h
index f915c04..38fee35 100644
--- a/core.h
+++ b/core.h
@@ -99,10 +99,29 @@ struct snd_avirt_stream *snd_avirt_stream_find_by_device(unsigned int device);
* @name: The name designated to the audio stream
* @direction: The PCM direction (SNDRV_PCM_STREAM_PLAYBACK or
* SNDRV_PCM_STREAM_CAPTURE)
+ * @internal: Whether the PCM should be internal or not
* @return: The newly created audio stream if successful, or an error pointer
*/
struct snd_avirt_stream *snd_avirt_stream_create(const char *name,
- int direction);
+ int direction, bool internal);
+
+/**
+ * int snd_avirt_route_try_complete - Set up remaining parameters for a route.
+ * Channels, sink, and source Audio Paths
+ * should be set when calling this function.
+ * @stream: The route to attempt to finalize parameters for.
+ * @return: 0 on success, negative ERRNO on failure
+ */
+int snd_avirt_route_try_complete(struct snd_avirt_route *route);
+
+/**
+ * int snd_avirt_stream_try_complete - Set up remaining parameters for a stream.
+ * Channels and map should be set when
+ * calling this function.
+ * @stream: The stream to attempt to finalize parameters for.
+ * @return: 0 on success, negative ERRNO on failure
+ */
+int snd_avirt_stream_try_complete(struct snd_avirt_stream *stream);
/**
* snd_avirt_stream_set_map - Set Audio Path mapping for a given stream
* @stream: The stream to assign the mapping to.
diff --git a/sound/avirt.h b/sound/avirt.h
index ecb0a21..9259d83 100644
--- a/sound/avirt.h
+++ b/sound/avirt.h
@@ -63,6 +63,7 @@ struct snd_avirt_route {
unsigned int channels; /* Route stream channel count */
unsigned int direction; /* Route stream direction */
struct snd_avirt_audiopath *endpoint_ap[2]; /* Source/sink */
+ struct snd_avirt_stream *endpoint_stream[2]; /* Router PCM */
struct config_item item; /* configfs item reference */
};
@@ -91,6 +92,7 @@ struct snd_avirt_stream {
unsigned int channels; /* Stream channel count */
unsigned int device; /* Stream PCM device no. */
unsigned int direction; /* Stream direction */
+ bool internal; /* Stream is internal only? */
struct snd_pcm *pcm; /* ALSA PCM */
struct snd_pcm_ops *pcm_ops; /* ALSA PCM ops */
struct snd_avirt_route *route; /* Associated route, if any */