mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-10-31 22:25:35 -04:00
Add sig_bits to stream caps template of C API and parse it. Signed-off-by: Mengdong Lin <mengdong.lin@linux.intel.com> Signed-off-by: Takashi Iwai <tiwai@suse.de>
651 lines
14 KiB
C
651 lines
14 KiB
C
/*
|
|
Copyright(c) 2014-2015 Intel Corporation
|
|
All rights reserved.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of version 2 of the GNU General Public License as
|
|
published by the Free Software Foundation.
|
|
|
|
This program is distributed in the hope that it will be useful, but
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
General Public License for more details.
|
|
|
|
Authors: Mengdong Lin <mengdong.lin@intel.com>
|
|
Yao Jin <yao.jin@intel.com>
|
|
Liam Girdwood <liam.r.girdwood@linux.intel.com>
|
|
*/
|
|
|
|
#include "list.h"
|
|
#include "tplg_local.h"
|
|
|
|
struct tplg_elem *lookup_pcm_dai_stream(struct list_head *base, const char* id)
|
|
{
|
|
struct list_head *pos;
|
|
struct tplg_elem *elem;
|
|
struct snd_soc_tplg_pcm *pcm;
|
|
|
|
list_for_each(pos, base) {
|
|
|
|
elem = list_entry(pos, struct tplg_elem, list);
|
|
if (elem->type != SND_TPLG_TYPE_PCM)
|
|
return NULL;
|
|
|
|
pcm = elem->pcm;
|
|
|
|
if (pcm && !strcmp(pcm->dai_name, id))
|
|
return elem;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* copy referenced caps to the parent (pcm or be dai) */
|
|
static void copy_stream_caps(const char *id,
|
|
struct snd_soc_tplg_stream_caps *caps, struct tplg_elem *ref_elem)
|
|
{
|
|
struct snd_soc_tplg_stream_caps *ref_caps = ref_elem->stream_caps;
|
|
|
|
tplg_dbg("Copy pcm caps (%ld bytes) from '%s' to '%s' \n",
|
|
sizeof(*caps), ref_elem->id, id);
|
|
|
|
*caps = *ref_caps;
|
|
}
|
|
|
|
/* find and copy the referenced stream caps */
|
|
static int tplg_build_stream_caps(snd_tplg_t *tplg,
|
|
const char *id, struct snd_soc_tplg_stream_caps *caps)
|
|
{
|
|
struct tplg_elem *ref_elem = NULL;
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < 2; i++) {
|
|
ref_elem = tplg_elem_lookup(&tplg->pcm_caps_list,
|
|
caps[i].name, SND_TPLG_TYPE_STREAM_CAPS);
|
|
|
|
if (ref_elem != NULL)
|
|
copy_stream_caps(id, &caps[i], ref_elem);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* build FE DAI/PCM configurations */
|
|
int tplg_build_pcm(snd_tplg_t *tplg, unsigned int type)
|
|
{
|
|
struct list_head *base, *pos;
|
|
struct tplg_elem *elem;
|
|
int err = 0;
|
|
|
|
base = &tplg->pcm_list;
|
|
list_for_each(pos, base) {
|
|
|
|
elem = list_entry(pos, struct tplg_elem, list);
|
|
if (elem->type != type) {
|
|
SNDERR("error: invalid elem '%s'\n", elem->id);
|
|
return -EINVAL;
|
|
}
|
|
|
|
err = tplg_build_stream_caps(tplg, elem->id, elem->pcm->caps);
|
|
if (err < 0)
|
|
return err;
|
|
|
|
/* add PCM to manifest */
|
|
tplg->manifest.pcm_elems++;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int tplg_build_stream_cfg(snd_tplg_t *tplg,
|
|
struct snd_soc_tplg_stream *stream, int num_streams)
|
|
{
|
|
struct snd_soc_tplg_stream *strm;
|
|
struct tplg_elem *ref_elem;
|
|
int i;
|
|
|
|
for (i = 0; i < num_streams; i++) {
|
|
strm = stream + i;
|
|
ref_elem = tplg_elem_lookup(&tplg->pcm_config_list,
|
|
strm->name, SND_TPLG_TYPE_STREAM_CONFIG);
|
|
|
|
if (ref_elem && ref_elem->stream_cfg)
|
|
*strm = *ref_elem->stream_cfg;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* build BE/CC DAI link configurations */
|
|
int tplg_build_link_cfg(snd_tplg_t *tplg, unsigned int type)
|
|
{
|
|
struct list_head *base, *pos;
|
|
struct tplg_elem *elem;
|
|
struct snd_soc_tplg_link_config *link;
|
|
int err = 0;
|
|
|
|
switch (type) {
|
|
case SND_TPLG_TYPE_BE:
|
|
base = &tplg->be_list;
|
|
break;
|
|
case SND_TPLG_TYPE_CC:
|
|
base = &tplg->cc_list;
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
list_for_each(pos, base) {
|
|
|
|
elem = list_entry(pos, struct tplg_elem, list);
|
|
if (elem->type != type) {
|
|
SNDERR("error: invalid elem '%s'\n", elem->id);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (type == SND_TPLG_TYPE_BE)
|
|
link = elem->be;
|
|
else
|
|
link = elem->cc;
|
|
|
|
err = tplg_build_stream_cfg(tplg, link->stream,
|
|
link->num_streams);
|
|
if (err < 0)
|
|
return err;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int split_format(struct snd_soc_tplg_stream_caps *caps, char *str)
|
|
{
|
|
char *s = NULL;
|
|
snd_pcm_format_t format;
|
|
int i = 0;
|
|
|
|
s = strtok(str, ",");
|
|
while ((s != NULL) && (i < SND_SOC_TPLG_MAX_FORMATS)) {
|
|
format = snd_pcm_format_value(s);
|
|
if (format == SND_PCM_FORMAT_UNKNOWN) {
|
|
SNDERR("error: unsupported stream format %s\n", s);
|
|
return -EINVAL;
|
|
}
|
|
|
|
caps->formats |= 1 << format;
|
|
s = strtok(NULL, ", ");
|
|
i++;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Parse pcm stream capabilities */
|
|
int tplg_parse_stream_caps(snd_tplg_t *tplg,
|
|
snd_config_t *cfg, void *private ATTRIBUTE_UNUSED)
|
|
{
|
|
struct snd_soc_tplg_stream_caps *sc;
|
|
struct tplg_elem *elem;
|
|
snd_config_iterator_t i, next;
|
|
snd_config_t *n;
|
|
const char *id, *val;
|
|
char *s;
|
|
int err;
|
|
|
|
elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_STREAM_CAPS);
|
|
if (!elem)
|
|
return -ENOMEM;
|
|
|
|
sc = elem->stream_caps;
|
|
sc->size = elem->size;
|
|
elem_copy_text(sc->name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
|
|
|
|
tplg_dbg(" PCM Capabilities: %s\n", elem->id);
|
|
|
|
snd_config_for_each(i, next, cfg) {
|
|
n = snd_config_iterator_entry(i);
|
|
if (snd_config_get_id(n, &id) < 0)
|
|
continue;
|
|
|
|
/* skip comments */
|
|
if (strcmp(id, "comment") == 0)
|
|
continue;
|
|
if (id[0] == '#')
|
|
continue;
|
|
|
|
if (snd_config_get_string(n, &val) < 0)
|
|
return -EINVAL;
|
|
|
|
if (strcmp(id, "formats") == 0) {
|
|
s = strdup(val);
|
|
if (s == NULL)
|
|
return -ENOMEM;
|
|
|
|
err = split_format(sc, s);
|
|
free(s);
|
|
|
|
if (err < 0)
|
|
return err;
|
|
|
|
tplg_dbg("\t\t%s: %s\n", id, val);
|
|
continue;
|
|
}
|
|
|
|
if (strcmp(id, "rate_min") == 0) {
|
|
sc->rate_min = atoi(val);
|
|
tplg_dbg("\t\t%s: %d\n", id, sc->rate_min);
|
|
continue;
|
|
}
|
|
|
|
if (strcmp(id, "rate_max") == 0) {
|
|
sc->rate_max = atoi(val);
|
|
tplg_dbg("\t\t%s: %d\n", id, sc->rate_max);
|
|
continue;
|
|
}
|
|
|
|
if (strcmp(id, "channels_min") == 0) {
|
|
sc->channels_min = atoi(val);
|
|
tplg_dbg("\t\t%s: %d\n", id, sc->channels_min);
|
|
continue;
|
|
}
|
|
|
|
if (strcmp(id, "channels_max") == 0) {
|
|
sc->channels_max = atoi(val);
|
|
tplg_dbg("\t\t%s: %d\n", id, sc->channels_max);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Parse the caps and config of a pcm stream */
|
|
static int tplg_parse_streams(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
|
|
snd_config_t *cfg, void *private)
|
|
{
|
|
snd_config_iterator_t i, next;
|
|
snd_config_t *n;
|
|
struct tplg_elem *elem = private;
|
|
struct snd_soc_tplg_pcm *pcm;
|
|
unsigned int *playback, *capture;
|
|
struct snd_soc_tplg_stream_caps *caps;
|
|
const char *id, *value;
|
|
int stream;
|
|
|
|
snd_config_get_id(cfg, &id);
|
|
|
|
tplg_dbg("\t%s:\n", id);
|
|
|
|
switch (elem->type) {
|
|
case SND_TPLG_TYPE_PCM:
|
|
pcm = elem->pcm;
|
|
playback = &pcm->playback;
|
|
capture = &pcm->capture;
|
|
caps = pcm->caps;
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (strcmp(id, "playback") == 0) {
|
|
stream = SND_SOC_TPLG_STREAM_PLAYBACK;
|
|
*playback = 1;
|
|
} else if (strcmp(id, "capture") == 0) {
|
|
stream = SND_SOC_TPLG_STREAM_CAPTURE;
|
|
*capture = 1;
|
|
} else
|
|
return -EINVAL;
|
|
|
|
snd_config_for_each(i, next, cfg) {
|
|
|
|
n = snd_config_iterator_entry(i);
|
|
|
|
/* get id */
|
|
if (snd_config_get_id(n, &id) < 0)
|
|
continue;
|
|
|
|
if (strcmp(id, "capabilities") == 0) {
|
|
if (snd_config_get_string(n, &value) < 0)
|
|
continue;
|
|
/* store stream caps name, to find and merge
|
|
* the caps in building phase.
|
|
*/
|
|
elem_copy_text(caps[stream].name, value,
|
|
SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
|
|
|
|
tplg_dbg("\t\t%s\n\t\t\t%s\n", id, value);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Parse name and id of a front-end DAI (ie. cpu dai of a FE DAI link) */
|
|
static int tplg_parse_fe_dai(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
|
|
snd_config_t *cfg, void *private)
|
|
{
|
|
struct tplg_elem *elem = private;
|
|
struct snd_soc_tplg_pcm *pcm = elem->pcm;
|
|
snd_config_iterator_t i, next;
|
|
snd_config_t *n;
|
|
const char *id, *value = NULL;
|
|
unsigned long int id_val;
|
|
|
|
snd_config_get_id(cfg, &id);
|
|
tplg_dbg("\t\tFE DAI %s:\n", id);
|
|
elem_copy_text(pcm->dai_name, id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
|
|
|
|
snd_config_for_each(i, next, cfg) {
|
|
|
|
n = snd_config_iterator_entry(i);
|
|
|
|
/* get id */
|
|
if (snd_config_get_id(n, &id) < 0)
|
|
continue;
|
|
|
|
if (strcmp(id, "id") == 0) {
|
|
if (snd_config_get_string(n, &value) < 0)
|
|
continue;
|
|
errno = 0;
|
|
/* no support for negative value */
|
|
id_val = strtoul(value, NULL, 0);
|
|
if ((errno == ERANGE && id_val == ULONG_MAX)
|
|
|| (errno != 0 && id_val == 0)
|
|
|| id_val > UINT_MAX) {
|
|
SNDERR("error: invalid fe dai ID\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
pcm->dai_id = (int) id_val;
|
|
tplg_dbg("\t\t\tindex: %d\n", pcm->dai_id);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Parse pcm (for front end DAI & DAI link) */
|
|
int tplg_parse_pcm(snd_tplg_t *tplg,
|
|
snd_config_t *cfg, void *private ATTRIBUTE_UNUSED)
|
|
{
|
|
struct snd_soc_tplg_pcm *pcm;
|
|
struct tplg_elem *elem;
|
|
snd_config_iterator_t i, next;
|
|
snd_config_t *n;
|
|
const char *id, *val = NULL;
|
|
int err;
|
|
|
|
elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_PCM);
|
|
if (!elem)
|
|
return -ENOMEM;
|
|
|
|
pcm = elem->pcm;
|
|
pcm->size = elem->size;
|
|
elem_copy_text(pcm->pcm_name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
|
|
|
|
tplg_dbg(" PCM: %s\n", elem->id);
|
|
|
|
snd_config_for_each(i, next, cfg) {
|
|
|
|
n = snd_config_iterator_entry(i);
|
|
if (snd_config_get_id(n, &id) < 0)
|
|
continue;
|
|
|
|
/* skip comments */
|
|
if (strcmp(id, "comment") == 0)
|
|
continue;
|
|
if (id[0] == '#')
|
|
continue;
|
|
|
|
if (strcmp(id, "index") == 0) {
|
|
if (snd_config_get_string(n, &val) < 0)
|
|
return -EINVAL;
|
|
|
|
elem->index = atoi(val);
|
|
tplg_dbg("\t%s: %d\n", id, elem->index);
|
|
continue;
|
|
}
|
|
|
|
if (strcmp(id, "id") == 0) {
|
|
if (snd_config_get_string(n, &val) < 0)
|
|
return -EINVAL;
|
|
|
|
pcm->pcm_id = atoi(val);
|
|
tplg_dbg("\t%s: %d\n", id, pcm->pcm_id);
|
|
continue;
|
|
}
|
|
|
|
if (strcmp(id, "pcm") == 0) {
|
|
err = tplg_parse_compound(tplg, n,
|
|
tplg_parse_streams, elem);
|
|
if (err < 0)
|
|
return err;
|
|
continue;
|
|
}
|
|
|
|
if (strcmp(id, "dai") == 0) {
|
|
err = tplg_parse_compound(tplg, n,
|
|
tplg_parse_fe_dai, elem);
|
|
if (err < 0)
|
|
return err;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int tplg_parse_be(snd_tplg_t *tplg,
|
|
snd_config_t *cfg, void *private ATTRIBUTE_UNUSED)
|
|
{
|
|
struct snd_soc_tplg_link_config *link;
|
|
struct tplg_elem *elem;
|
|
snd_config_iterator_t i, next;
|
|
snd_config_t *n;
|
|
const char *id, *val = NULL;
|
|
|
|
elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_BE);
|
|
if (!elem)
|
|
return -ENOMEM;
|
|
|
|
link = elem->be;
|
|
link->size = elem->size;
|
|
|
|
tplg_dbg(" BE: %s\n", elem->id);
|
|
|
|
snd_config_for_each(i, next, cfg) {
|
|
|
|
n = snd_config_iterator_entry(i);
|
|
if (snd_config_get_id(n, &id) < 0)
|
|
continue;
|
|
|
|
/* skip comments */
|
|
if (strcmp(id, "comment") == 0)
|
|
continue;
|
|
if (id[0] == '#')
|
|
continue;
|
|
|
|
if (strcmp(id, "index") == 0) {
|
|
if (snd_config_get_string(n, &val) < 0)
|
|
return -EINVAL;
|
|
|
|
elem->index = atoi(val);
|
|
tplg_dbg("\t%s: %d\n", id, elem->index);
|
|
continue;
|
|
}
|
|
|
|
if (strcmp(id, "id") == 0) {
|
|
if (snd_config_get_string(n, &val) < 0)
|
|
return -EINVAL;
|
|
|
|
link->id = atoi(val);
|
|
tplg_dbg("\t%s: %d\n", id, link->id);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Parse cc */
|
|
int tplg_parse_cc(snd_tplg_t *tplg,
|
|
snd_config_t *cfg, void *private ATTRIBUTE_UNUSED)
|
|
{
|
|
struct snd_soc_tplg_link_config *link;
|
|
struct tplg_elem *elem;
|
|
snd_config_iterator_t i, next;
|
|
snd_config_t *n;
|
|
const char *id, *val = NULL;
|
|
|
|
elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_CC);
|
|
if (!elem)
|
|
return -ENOMEM;
|
|
|
|
link = elem->cc;
|
|
link->size = elem->size;
|
|
|
|
tplg_dbg(" CC: %s\n", elem->id);
|
|
|
|
snd_config_for_each(i, next, cfg) {
|
|
|
|
n = snd_config_iterator_entry(i);
|
|
if (snd_config_get_id(n, &id) < 0)
|
|
continue;
|
|
|
|
/* skip comments */
|
|
if (strcmp(id, "comment") == 0)
|
|
continue;
|
|
if (id[0] == '#')
|
|
continue;
|
|
|
|
if (strcmp(id, "index") == 0) {
|
|
if (snd_config_get_string(n, &val) < 0)
|
|
return -EINVAL;
|
|
|
|
elem->index = atoi(val);
|
|
tplg_dbg("\t%s: %d\n", id, elem->index);
|
|
continue;
|
|
}
|
|
|
|
if (strcmp(id, "id") == 0) {
|
|
if (snd_config_get_string(n, &val) < 0)
|
|
return -EINVAL;
|
|
|
|
link->id = atoi(val);
|
|
tplg_dbg("\t%s: %d\n", id, link->id);
|
|
continue;
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* copy stream object */
|
|
static void tplg_add_stream_object(struct snd_soc_tplg_stream *strm,
|
|
struct snd_tplg_stream_template *strm_tpl)
|
|
{
|
|
elem_copy_text(strm->name, strm_tpl->name,
|
|
SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
|
|
strm->format = strm_tpl->format;
|
|
strm->rate = strm_tpl->rate;
|
|
strm->period_bytes = strm_tpl->period_bytes;
|
|
strm->buffer_bytes = strm_tpl->buffer_bytes;
|
|
strm->channels = strm_tpl->channels;
|
|
}
|
|
|
|
static void tplg_add_stream_caps(struct snd_soc_tplg_stream_caps *caps,
|
|
struct snd_tplg_stream_caps_template *caps_tpl)
|
|
{
|
|
elem_copy_text(caps->name, caps_tpl->name,
|
|
SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
|
|
|
|
caps->formats = caps_tpl->formats;
|
|
caps->rates = caps_tpl->rates;
|
|
caps->rate_min = caps_tpl->rate_min;
|
|
caps->rate_max = caps_tpl->rate_max;
|
|
caps->channels_min = caps_tpl->channels_min;
|
|
caps->channels_max = caps_tpl->channels_max;
|
|
caps->periods_min = caps_tpl->periods_min;
|
|
caps->periods_max = caps_tpl->periods_max;
|
|
caps->period_size_min = caps_tpl->period_size_min;
|
|
caps->period_size_max = caps_tpl->period_size_max;
|
|
caps->buffer_size_min = caps_tpl->buffer_size_min;
|
|
caps->buffer_size_max = caps_tpl->buffer_size_max;
|
|
caps->sig_bits = caps_tpl->sig_bits;
|
|
}
|
|
|
|
int tplg_add_pcm_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t)
|
|
{
|
|
struct snd_tplg_pcm_template *pcm_tpl = t->pcm;
|
|
struct snd_soc_tplg_pcm *pcm;
|
|
struct tplg_elem *elem;
|
|
int i;
|
|
|
|
tplg_dbg("PCM: %s, DAI %s\n", pcm_tpl->pcm_name, pcm_tpl->dai_name);
|
|
|
|
if (pcm_tpl->num_streams > SND_SOC_TPLG_STREAM_CONFIG_MAX)
|
|
return -EINVAL;
|
|
|
|
elem = tplg_elem_new_common(tplg, NULL, pcm_tpl->pcm_name,
|
|
SND_TPLG_TYPE_PCM);
|
|
if (!elem)
|
|
return -ENOMEM;
|
|
|
|
pcm = elem->pcm;
|
|
pcm->size = elem->size;
|
|
|
|
elem_copy_text(pcm->pcm_name, pcm_tpl->pcm_name,
|
|
SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
|
|
elem_copy_text(pcm->dai_name, pcm_tpl->dai_name,
|
|
SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
|
|
pcm->pcm_id = pcm_tpl->pcm_id;
|
|
pcm->dai_id = pcm_tpl->dai_id;
|
|
pcm->playback = pcm_tpl->playback;
|
|
pcm->capture = pcm_tpl->capture;
|
|
pcm->compress = pcm_tpl->compress;
|
|
|
|
for (i = 0; i < 2; i++) {
|
|
if (pcm_tpl->caps[i])
|
|
tplg_add_stream_caps(&pcm->caps[i], pcm_tpl->caps[i]);
|
|
}
|
|
|
|
pcm->num_streams = pcm_tpl->num_streams;
|
|
for (i = 0; i < pcm_tpl->num_streams; i++)
|
|
tplg_add_stream_object(&pcm->stream[i], &pcm_tpl->stream[i]);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int tplg_add_link_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t)
|
|
{
|
|
struct snd_tplg_link_template *link = t->link;
|
|
struct snd_soc_tplg_link_config *lk;
|
|
struct tplg_elem *elem;
|
|
int i;
|
|
|
|
if (t->type != SND_TPLG_TYPE_BE && t->type != SND_TPLG_TYPE_CC)
|
|
return -EINVAL;
|
|
|
|
/* here type can be either BE or CC. */
|
|
elem = tplg_elem_new_common(tplg, NULL, link->name, t->type);
|
|
if (!elem)
|
|
return -ENOMEM;
|
|
|
|
if (t->type == SND_TPLG_TYPE_BE) {
|
|
tplg_dbg("BE Link: %s", link->name);
|
|
lk = elem->be;
|
|
} else {
|
|
tplg_dbg("CC Link: %s", link->name);
|
|
lk = elem->cc;
|
|
}
|
|
|
|
lk->size = elem->size;
|
|
lk->id = link->id;
|
|
lk->num_streams = link->num_streams;
|
|
|
|
for (i = 0; i < link->num_streams; i++)
|
|
tplg_add_stream_object(&lk->stream[i], &link->stream[i]);
|
|
|
|
return 0;
|
|
}
|