mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
alsa: add enumeration of iec958 format
For hdmi and iec958 devices, enumerate the iec958 formats and codecs. Initially only PCM is supported as a codec but with a property or an init option, the list of codecs can be dynamically configured.
This commit is contained in:
parent
8147772cf5
commit
9dfe35b17c
4 changed files with 267 additions and 71 deletions
|
|
@ -100,7 +100,7 @@ static int impl_node_enum_params(void *object, int seq,
|
|||
struct state *this = object;
|
||||
struct spa_pod *param;
|
||||
struct spa_pod_builder b = { 0 };
|
||||
uint8_t buffer[1024];
|
||||
uint8_t buffer[2048];
|
||||
struct spa_result_node_params result;
|
||||
uint32_t count = 0;
|
||||
|
||||
|
|
@ -169,6 +169,17 @@ static int impl_node_enum_params(void *object, int seq,
|
|||
SPA_PROP_INFO_name, SPA_POD_String("Latency offset (ns)"),
|
||||
SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Long(0, 0, INT64_MAX));
|
||||
break;
|
||||
case 7:
|
||||
if (this->is_iec958 || this->is_hdmi) {
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_PropInfo, id,
|
||||
SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_iec958Codecs),
|
||||
SPA_PROP_INFO_name, SPA_POD_String("Enabled IEC958 (S/PDIF) codecs"),
|
||||
SPA_PROP_INFO_type, SPA_POD_Id(SPA_AUDIO_IEC958_CODEC_UNKNOWN),
|
||||
SPA_PROP_INFO_container, SPA_POD_Id(SPA_TYPE_Array));
|
||||
break;
|
||||
}
|
||||
SPA_FALLTHROUGH
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -177,18 +188,30 @@ static int impl_node_enum_params(void *object, int seq,
|
|||
case SPA_PARAM_Props:
|
||||
{
|
||||
struct props *p = &this->props;
|
||||
struct spa_pod_frame f;
|
||||
uint32_t codecs[16], n_codecs;
|
||||
|
||||
switch (result.index) {
|
||||
case 0:
|
||||
param = spa_pod_builder_add_object(&b,
|
||||
SPA_TYPE_OBJECT_Props, id,
|
||||
spa_pod_builder_push_object(&b, &f,
|
||||
SPA_TYPE_OBJECT_Props, id);
|
||||
spa_pod_builder_add(&b,
|
||||
SPA_PROP_device, SPA_POD_Stringn(p->device, sizeof(p->device)),
|
||||
SPA_PROP_deviceName, SPA_POD_Stringn(p->device_name, sizeof(p->device_name)),
|
||||
SPA_PROP_cardName, SPA_POD_Stringn(p->card_name, sizeof(p->card_name)),
|
||||
SPA_PROP_minLatency, SPA_POD_Int(p->min_latency),
|
||||
SPA_PROP_maxLatency, SPA_POD_Int(p->max_latency),
|
||||
SPA_PROP_START_CUSTOM, SPA_POD_Bool(p->use_chmap),
|
||||
SPA_PROP_latencyOffsetNsec, SPA_POD_Long(this->process_latency.ns));
|
||||
SPA_PROP_latencyOffsetNsec, SPA_POD_Long(this->process_latency.ns),
|
||||
0);
|
||||
|
||||
n_codecs = spa_alsa_get_iec958_codecs(this, codecs, SPA_N_ELEMENTS(codecs));
|
||||
if (n_codecs > 0) {
|
||||
spa_pod_builder_prop(&b, SPA_PROP_iec958Codecs, 0);
|
||||
spa_pod_builder_array(&b, sizeof(uint32_t), SPA_TYPE_Id,
|
||||
n_codecs, codecs);
|
||||
}
|
||||
param = spa_pod_builder_pop(&b, &f);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
|
|
@ -296,6 +319,7 @@ static int impl_node_set_param(void *object, uint32_t id, uint32_t flags,
|
|||
{
|
||||
struct props *p = &this->props;
|
||||
struct spa_process_latency_info info;
|
||||
struct spa_pod *iec958_codecs = NULL;
|
||||
|
||||
if (param == NULL) {
|
||||
reset_props(p);
|
||||
|
|
@ -310,8 +334,17 @@ static int impl_node_set_param(void *object, uint32_t id, uint32_t flags,
|
|||
SPA_PROP_minLatency, SPA_POD_OPT_Int(&p->min_latency),
|
||||
SPA_PROP_maxLatency, SPA_POD_OPT_Int(&p->max_latency),
|
||||
SPA_PROP_latencyOffsetNsec, SPA_POD_OPT_Long(&info.ns),
|
||||
SPA_PROP_START_CUSTOM, SPA_POD_OPT_Bool(&p->use_chmap));
|
||||
SPA_PROP_START_CUSTOM, SPA_POD_OPT_Bool(&p->use_chmap),
|
||||
SPA_PROP_iec958Codecs, SPA_POD_OPT_Pod(&iec958_codecs));
|
||||
|
||||
if (iec958_codecs != NULL) {
|
||||
uint32_t i, codecs[16], n_codecs;
|
||||
n_codecs = spa_pod_copy_array(iec958_codecs, SPA_TYPE_Id,
|
||||
codecs, SPA_N_ELEMENTS(codecs));
|
||||
this->iec958_codecs = 0;
|
||||
for (i = 0; i < n_codecs; i++)
|
||||
this->iec958_codecs |= 1ULL << codecs[i];
|
||||
}
|
||||
handle_process_latency(this, &info);
|
||||
break;
|
||||
}
|
||||
|
|
@ -916,6 +949,8 @@ impl_init(const struct spa_handle_factory *factory,
|
|||
this->process_latency.rate = atoi(s);
|
||||
} else if (spa_streq(k, "latency.internal.ns")) {
|
||||
this->process_latency.ns = atoi(s);
|
||||
} else if (spa_streq(k, "iec958.codecs")) {
|
||||
spa_alsa_parse_iec958_codecs(&this->iec958_codecs, s, strlen(s));
|
||||
} else if (spa_streq(k, "api.alsa.period-size")) {
|
||||
this->default_period_size = atoi(s);
|
||||
} else if (spa_streq(k, "api.alsa.headroom")) {
|
||||
|
|
|
|||
|
|
@ -22,6 +22,12 @@ int spa_alsa_init(struct state *state)
|
|||
|
||||
snd_config_update_free_global();
|
||||
|
||||
if (state->stream == SND_PCM_STREAM_PLAYBACK) {
|
||||
state->is_iec958 = spa_strstartswith(state->props.device, "iec958");
|
||||
state->is_hdmi = spa_strstartswith(state->props.device, "hdmi");
|
||||
state->iec958_codecs |= 1ULL << SPA_AUDIO_IEC958_CODEC_PCM;
|
||||
}
|
||||
|
||||
if (state->open_ucm) {
|
||||
char card_name[64];
|
||||
const char *alibpref = NULL;
|
||||
|
|
@ -57,6 +63,7 @@ int spa_alsa_init(struct state *state)
|
|||
free((void*)alibpref);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -313,40 +320,21 @@ static void sanitize_map(snd_pcm_chmap_t* map)
|
|||
}
|
||||
}
|
||||
|
||||
int
|
||||
spa_alsa_enum_format(struct state *state, int seq, uint32_t start, uint32_t num,
|
||||
const struct spa_pod *filter)
|
||||
static int enum_pcm_formats(struct state *state, uint32_t index, uint32_t *next,
|
||||
struct spa_pod **result, struct spa_pod_builder *b)
|
||||
{
|
||||
int err, dir;
|
||||
size_t i, j;
|
||||
snd_pcm_t *hndl;
|
||||
snd_pcm_hw_params_t *params;
|
||||
snd_pcm_chmap_query_t **maps;
|
||||
struct spa_pod_frame f[2];
|
||||
snd_pcm_format_mask_t *fmask;
|
||||
snd_pcm_access_mask_t *amask;
|
||||
snd_pcm_chmap_query_t **maps;
|
||||
size_t i, j;
|
||||
int err, dir;
|
||||
unsigned int min, max;
|
||||
unsigned int rrate, rchannels;
|
||||
uint8_t buffer[4096];
|
||||
struct spa_pod_builder b = { 0 };
|
||||
struct spa_pod_choice *choice;
|
||||
struct spa_pod *fmt;
|
||||
int res;
|
||||
bool opened;
|
||||
struct spa_pod_frame f[2];
|
||||
struct spa_result_node_params result;
|
||||
uint32_t count = 0, rate;
|
||||
|
||||
opened = state->opened;
|
||||
if ((err = spa_alsa_open(state)) < 0)
|
||||
return err;
|
||||
|
||||
result.id = SPA_PARAM_EnumFormat;
|
||||
result.next = start;
|
||||
|
||||
next:
|
||||
result.index = result.next++;
|
||||
|
||||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
uint32_t rate;
|
||||
|
||||
hndl = state->hndl;
|
||||
snd_pcm_hw_params_alloca(¶ms);
|
||||
|
|
@ -371,8 +359,8 @@ spa_alsa_enum_format(struct state *state, int seq, uint32_t start, uint32_t num,
|
|||
}
|
||||
}
|
||||
|
||||
spa_pod_builder_push_object(&b, &f[0], SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat);
|
||||
spa_pod_builder_add(&b,
|
||||
spa_pod_builder_push_object(b, &f[0], SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat);
|
||||
spa_pod_builder_add(b,
|
||||
SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio),
|
||||
SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw),
|
||||
0);
|
||||
|
|
@ -383,10 +371,10 @@ spa_alsa_enum_format(struct state *state, int seq, uint32_t start, uint32_t num,
|
|||
snd_pcm_access_mask_alloca(&amask);
|
||||
snd_pcm_hw_params_get_access_mask(params, amask);
|
||||
|
||||
spa_pod_builder_prop(&b, SPA_FORMAT_AUDIO_format, 0);
|
||||
spa_pod_builder_prop(b, SPA_FORMAT_AUDIO_format, 0);
|
||||
|
||||
spa_pod_builder_push_choice(&b, &f[1], SPA_CHOICE_None, 0);
|
||||
choice = (struct spa_pod_choice*)spa_pod_builder_frame(&b, &f[1]);
|
||||
spa_pod_builder_push_choice(b, &f[1], SPA_CHOICE_None, 0);
|
||||
choice = (struct spa_pod_choice*)spa_pod_builder_frame(b, &f[1]);
|
||||
|
||||
for (i = 1, j = 0; i < SPA_N_ELEMENTS(format_info); i++) {
|
||||
const struct format_info *fi = &format_info[i];
|
||||
|
|
@ -397,15 +385,15 @@ spa_alsa_enum_format(struct state *state, int seq, uint32_t start, uint32_t num,
|
|||
fi->spa_pformat != SPA_AUDIO_FORMAT_UNKNOWN &&
|
||||
(state->default_format == 0 || state->default_format == fi->spa_pformat)) {
|
||||
if (j++ == 0)
|
||||
spa_pod_builder_id(&b, fi->spa_pformat);
|
||||
spa_pod_builder_id(&b, fi->spa_pformat);
|
||||
spa_pod_builder_id(b, fi->spa_pformat);
|
||||
spa_pod_builder_id(b, fi->spa_pformat);
|
||||
}
|
||||
if ((snd_pcm_access_mask_test(amask, SND_PCM_ACCESS_MMAP_INTERLEAVED) ||
|
||||
snd_pcm_access_mask_test(amask, SND_PCM_ACCESS_RW_INTERLEAVED)) &&
|
||||
(state->default_format == 0 || state->default_format == fi->spa_format)) {
|
||||
if (j++ == 0)
|
||||
spa_pod_builder_id(&b, fi->spa_format);
|
||||
spa_pod_builder_id(&b, fi->spa_format);
|
||||
spa_pod_builder_id(b, fi->spa_format);
|
||||
spa_pod_builder_id(b, fi->spa_format);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -440,7 +428,7 @@ spa_alsa_enum_format(struct state *state, int seq, uint32_t start, uint32_t num,
|
|||
}
|
||||
if (j > 1)
|
||||
choice->body.type = SPA_CHOICE_Enum;
|
||||
spa_pod_builder_pop(&b, &f[1]);
|
||||
spa_pod_builder_pop(b, &f[1]);
|
||||
|
||||
CHECK(snd_pcm_hw_params_get_rate_min(params, &min, &dir), "get_rate_min");
|
||||
CHECK(snd_pcm_hw_params_get_rate_max(params, &max, &dir), "get_rate_max");
|
||||
|
|
@ -452,20 +440,20 @@ spa_alsa_enum_format(struct state *state, int seq, uint32_t start, uint32_t num,
|
|||
max = state->default_rate;
|
||||
}
|
||||
|
||||
spa_pod_builder_prop(&b, SPA_FORMAT_AUDIO_rate, 0);
|
||||
spa_pod_builder_prop(b, SPA_FORMAT_AUDIO_rate, 0);
|
||||
|
||||
spa_pod_builder_push_choice(&b, &f[1], SPA_CHOICE_None, 0);
|
||||
choice = (struct spa_pod_choice*)spa_pod_builder_frame(&b, &f[1]);
|
||||
spa_pod_builder_push_choice(b, &f[1], SPA_CHOICE_None, 0);
|
||||
choice = (struct spa_pod_choice*)spa_pod_builder_frame(b, &f[1]);
|
||||
|
||||
rate = state->position ? state->position->clock.rate.denom : DEFAULT_RATE;
|
||||
|
||||
spa_pod_builder_int(&b, SPA_CLAMP(rate, min, max));
|
||||
spa_pod_builder_int(b, SPA_CLAMP(rate, min, max));
|
||||
if (min != max) {
|
||||
spa_pod_builder_int(&b, min);
|
||||
spa_pod_builder_int(&b, max);
|
||||
spa_pod_builder_int(b, min);
|
||||
spa_pod_builder_int(b, max);
|
||||
choice->body.type = SPA_CHOICE_Range;
|
||||
}
|
||||
spa_pod_builder_pop(&b, &f[1]);
|
||||
spa_pod_builder_pop(b, &f[1]);
|
||||
|
||||
CHECK(snd_pcm_hw_params_get_channels_min(params, &min), "get_channels_min");
|
||||
CHECK(snd_pcm_hw_params_get_channels_max(params, &max), "get_channels_max");
|
||||
|
|
@ -480,55 +468,55 @@ spa_alsa_enum_format(struct state *state, int seq, uint32_t start, uint32_t num,
|
|||
min = SPA_MIN(min, SPA_AUDIO_MAX_CHANNELS);
|
||||
max = SPA_MIN(max, SPA_AUDIO_MAX_CHANNELS);
|
||||
|
||||
spa_pod_builder_prop(&b, SPA_FORMAT_AUDIO_channels, 0);
|
||||
spa_pod_builder_prop(b, SPA_FORMAT_AUDIO_channels, 0);
|
||||
|
||||
if (state->props.use_chmap && (maps = snd_pcm_query_chmaps(hndl)) != NULL) {
|
||||
uint32_t channel;
|
||||
snd_pcm_chmap_t* map;
|
||||
|
||||
skip_channels:
|
||||
if (maps[result.index] == NULL) {
|
||||
if (maps[index] == NULL) {
|
||||
snd_pcm_free_chmaps(maps);
|
||||
goto enum_end;
|
||||
return 0;
|
||||
}
|
||||
map = &maps[result.index]->map;
|
||||
map = &maps[index]->map;
|
||||
|
||||
spa_log_debug(state->log, "map %d channels (%d %d)", map->channels, min, max);
|
||||
|
||||
if (map->channels < min || map->channels > max) {
|
||||
result.index = result.next++;
|
||||
index = (*next)++;
|
||||
goto skip_channels;
|
||||
}
|
||||
|
||||
sanitize_map(map);
|
||||
spa_pod_builder_int(&b, map->channels);
|
||||
spa_pod_builder_int(b, map->channels);
|
||||
|
||||
spa_pod_builder_prop(&b, SPA_FORMAT_AUDIO_position, 0);
|
||||
spa_pod_builder_push_array(&b, &f[1]);
|
||||
spa_pod_builder_prop(b, SPA_FORMAT_AUDIO_position, 0);
|
||||
spa_pod_builder_push_array(b, &f[1]);
|
||||
for (j = 0; j < map->channels; j++) {
|
||||
spa_log_debug(state->log, NAME" %p: position %zd %d", state, j, map->pos[j]);
|
||||
channel = chmap_position_to_channel(map->pos[j]);
|
||||
spa_pod_builder_id(&b, channel);
|
||||
spa_pod_builder_id(b, channel);
|
||||
}
|
||||
spa_pod_builder_pop(&b, &f[1]);
|
||||
spa_pod_builder_pop(b, &f[1]);
|
||||
|
||||
snd_pcm_free_chmaps(maps);
|
||||
}
|
||||
else {
|
||||
const struct channel_map *map = NULL;
|
||||
|
||||
if (result.index > 0)
|
||||
goto enum_end;
|
||||
if (index > 0)
|
||||
return 0;
|
||||
|
||||
spa_pod_builder_push_choice(&b, &f[1], SPA_CHOICE_None, 0);
|
||||
choice = (struct spa_pod_choice*)spa_pod_builder_frame(&b, &f[1]);
|
||||
spa_pod_builder_int(&b, max);
|
||||
spa_pod_builder_push_choice(b, &f[1], SPA_CHOICE_None, 0);
|
||||
choice = (struct spa_pod_choice*)spa_pod_builder_frame(b, &f[1]);
|
||||
spa_pod_builder_int(b, max);
|
||||
if (min != max) {
|
||||
spa_pod_builder_int(&b, min);
|
||||
spa_pod_builder_int(&b, max);
|
||||
spa_pod_builder_int(b, min);
|
||||
spa_pod_builder_int(b, max);
|
||||
choice->body.type = SPA_CHOICE_Range;
|
||||
}
|
||||
spa_pod_builder_pop(&b, &f[1]);
|
||||
spa_pod_builder_pop(b, &f[1]);
|
||||
|
||||
if (min == max) {
|
||||
if (state->default_pos.channels == min)
|
||||
|
|
@ -537,17 +525,147 @@ skip_channels:
|
|||
map = &default_map[min];
|
||||
}
|
||||
if (map) {
|
||||
spa_pod_builder_prop(&b, SPA_FORMAT_AUDIO_position, 0);
|
||||
spa_pod_builder_push_array(&b, &f[1]);
|
||||
spa_pod_builder_prop(b, SPA_FORMAT_AUDIO_position, 0);
|
||||
spa_pod_builder_push_array(b, &f[1]);
|
||||
for (j = 0; j < map->channels; j++) {
|
||||
spa_log_debug(state->log, NAME" %p: position %zd %d", state, j, map->pos[j]);
|
||||
spa_pod_builder_id(&b, map->pos[j]);
|
||||
spa_pod_builder_id(b, map->pos[j]);
|
||||
}
|
||||
spa_pod_builder_pop(&b, &f[1]);
|
||||
spa_pod_builder_pop(b, &f[1]);
|
||||
}
|
||||
}
|
||||
*result = spa_pod_builder_pop(b, &f[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
fmt = spa_pod_builder_pop(&b, &f[0]);
|
||||
static int enum_iec958_formats(struct state *state, uint32_t index, uint32_t *next,
|
||||
struct spa_pod **result, struct spa_pod_builder *b)
|
||||
{
|
||||
int err, dir;
|
||||
snd_pcm_t *hndl;
|
||||
snd_pcm_hw_params_t *params;
|
||||
struct spa_pod_frame f[2];
|
||||
struct spa_pod_choice *choice;
|
||||
unsigned int rmin, rmax;
|
||||
unsigned int chmin, chmax;
|
||||
|
||||
if ((index & 0xffff) > 0)
|
||||
return 0;
|
||||
|
||||
if (!(state->is_iec958 || state->is_hdmi))
|
||||
return 0;
|
||||
if (state->iec958_codecs == 0)
|
||||
return 0;
|
||||
|
||||
hndl = state->hndl;
|
||||
snd_pcm_hw_params_alloca(¶ms);
|
||||
CHECK(snd_pcm_hw_params_any(hndl, params), "Broken configuration: no configurations available");
|
||||
|
||||
CHECK(snd_pcm_hw_params_set_rate_resample(hndl, params, 0), "set_rate_resample");
|
||||
|
||||
spa_pod_builder_push_object(b, &f[0], SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat);
|
||||
spa_pod_builder_add(b,
|
||||
SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio),
|
||||
SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_iec958),
|
||||
0);
|
||||
|
||||
CHECK(snd_pcm_hw_params_get_channels_min(params, &chmin), "get_channels_min");
|
||||
CHECK(snd_pcm_hw_params_get_channels_max(params, &chmax), "get_channels_max");
|
||||
spa_log_debug(state->log, "channels (%d %d)", chmin, chmax);
|
||||
|
||||
CHECK(snd_pcm_hw_params_get_rate_min(params, &rmin, &dir), "get_rate_min");
|
||||
CHECK(snd_pcm_hw_params_get_rate_max(params, &rmax, &dir), "get_rate_max");
|
||||
spa_log_debug(state->log, "rate (%d %d)", rmin, rmax);
|
||||
|
||||
if (state->default_rate != 0) {
|
||||
if (rmin < state->default_rate)
|
||||
rmin = state->default_rate;
|
||||
if (rmax > state->default_rate)
|
||||
rmax = state->default_rate;
|
||||
}
|
||||
|
||||
spa_pod_builder_prop(b, SPA_FORMAT_AUDIO_iec958Codec, 0);
|
||||
spa_pod_builder_push_choice(b, &f[1], SPA_CHOICE_Enum, 0);
|
||||
if (chmax >= 2) {
|
||||
spa_pod_builder_id(b, SPA_AUDIO_IEC958_CODEC_PCM);
|
||||
spa_pod_builder_id(b, SPA_AUDIO_IEC958_CODEC_PCM);
|
||||
|
||||
if (state->iec958_codecs & (1ULL << SPA_AUDIO_IEC958_CODEC_DTS))
|
||||
spa_pod_builder_id(b, SPA_AUDIO_IEC958_CODEC_DTS);
|
||||
if (state->iec958_codecs & (1ULL << SPA_AUDIO_IEC958_CODEC_AC3))
|
||||
spa_pod_builder_id(b, SPA_AUDIO_IEC958_CODEC_AC3);
|
||||
if (state->iec958_codecs & (1ULL << SPA_AUDIO_IEC958_CODEC_MPEG))
|
||||
spa_pod_builder_id(b, SPA_AUDIO_IEC958_CODEC_MPEG);
|
||||
if (state->iec958_codecs & (1ULL << SPA_AUDIO_IEC958_CODEC_MPEG2_AAC))
|
||||
spa_pod_builder_id(b, SPA_AUDIO_IEC958_CODEC_MPEG2_AAC);
|
||||
|
||||
if (rmax >= 48000 * 4 &&
|
||||
(state->iec958_codecs & (1ULL << SPA_AUDIO_IEC958_CODEC_EAC3)))
|
||||
spa_pod_builder_id(b, SPA_AUDIO_IEC958_CODEC_EAC3);
|
||||
}
|
||||
if (chmax >= 8) {
|
||||
if (state->iec958_codecs & (1ULL << SPA_AUDIO_IEC958_CODEC_TRUEHD))
|
||||
spa_pod_builder_id(b, SPA_AUDIO_IEC958_CODEC_TRUEHD);
|
||||
if (state->iec958_codecs & (1ULL << SPA_AUDIO_IEC958_CODEC_DTSHD))
|
||||
spa_pod_builder_id(b, SPA_AUDIO_IEC958_CODEC_DTSHD);
|
||||
}
|
||||
spa_pod_builder_pop(b, &f[1]);
|
||||
|
||||
spa_pod_builder_prop(b, SPA_FORMAT_AUDIO_rate, 0);
|
||||
spa_pod_builder_push_choice(b, &f[1], SPA_CHOICE_None, 0);
|
||||
choice = (struct spa_pod_choice*)spa_pod_builder_frame(b, &f[1]);
|
||||
|
||||
spa_pod_builder_int(b, SPA_CLAMP(DEFAULT_RATE, rmin, rmax));
|
||||
if (rmin != rmax) {
|
||||
spa_pod_builder_int(b, rmin);
|
||||
spa_pod_builder_int(b, rmax);
|
||||
choice->body.type = SPA_CHOICE_Range;
|
||||
}
|
||||
spa_pod_builder_pop(b, &f[1]);
|
||||
|
||||
(*next)++;
|
||||
*result = spa_pod_builder_pop(b, &f[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
spa_alsa_enum_format(struct state *state, int seq, uint32_t start, uint32_t num,
|
||||
const struct spa_pod *filter)
|
||||
{
|
||||
uint8_t buffer[4096];
|
||||
struct spa_pod_builder b = { 0 };
|
||||
struct spa_pod *fmt;
|
||||
int err, res;
|
||||
bool opened;
|
||||
struct spa_result_node_params result;
|
||||
uint32_t count = 0;
|
||||
|
||||
opened = state->opened;
|
||||
if ((err = spa_alsa_open(state)) < 0)
|
||||
return err;
|
||||
|
||||
result.id = SPA_PARAM_EnumFormat;
|
||||
result.next = start;
|
||||
|
||||
next:
|
||||
result.index = result.next++;
|
||||
|
||||
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||
|
||||
if (result.index < 0x10000) {
|
||||
if ((res = enum_pcm_formats(state, result.index, &result.next, &fmt, &b)) != 1) {
|
||||
result.next = 0x10000;
|
||||
goto next;
|
||||
}
|
||||
}
|
||||
else if (result.index < 0x20000) {
|
||||
if ((res = enum_iec958_formats(state, result.index, &result.next, &fmt, &b)) != 1) {
|
||||
result.next = 0x20000;
|
||||
goto next;
|
||||
}
|
||||
}
|
||||
else
|
||||
goto enum_end;
|
||||
|
||||
if (spa_pod_filter(&b, &result.param, fmt, filter) < 0)
|
||||
goto next;
|
||||
|
|
|
|||
|
|
@ -185,6 +185,10 @@ struct state {
|
|||
unsigned int planar:1;
|
||||
unsigned int freewheel:1;
|
||||
unsigned int open_ucm:1;
|
||||
unsigned int is_iec958:1;
|
||||
unsigned int is_hdmi:1;
|
||||
|
||||
uint64_t iec958_codecs;
|
||||
|
||||
int64_t sample_count;
|
||||
|
||||
|
|
@ -262,6 +266,44 @@ static inline void spa_alsa_parse_position(struct channel_map *map, const char *
|
|||
}
|
||||
}
|
||||
|
||||
static inline uint32_t spa_alsa_iec958_codec_from_name(const char *name)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; spa_type_audio_iec958_codec[i].name; i++) {
|
||||
if (strcmp(name, spa_debug_type_short_name(spa_type_audio_iec958_codec[i].name)) == 0)
|
||||
return spa_type_audio_iec958_codec[i].type;
|
||||
}
|
||||
return SPA_AUDIO_IEC958_CODEC_UNKNOWN;
|
||||
}
|
||||
|
||||
static inline void spa_alsa_parse_iec958_codecs(uint64_t *codecs, const char *val, size_t len)
|
||||
{
|
||||
struct spa_json it[2];
|
||||
char v[256];
|
||||
|
||||
spa_json_init(&it[0], val, len);
|
||||
if (spa_json_enter_array(&it[0], &it[1]) <= 0)
|
||||
spa_json_init(&it[1], val, len);
|
||||
|
||||
*codecs = 0;
|
||||
while (spa_json_get_string(&it[1], v, sizeof(v)) > 0)
|
||||
*codecs |= 1ULL << spa_alsa_iec958_codec_from_name(v);
|
||||
}
|
||||
|
||||
static inline uint32_t spa_alsa_get_iec958_codecs(struct state *state, uint32_t *codecs,
|
||||
uint32_t max_codecs)
|
||||
{
|
||||
uint64_t mask = state->iec958_codecs;
|
||||
uint32_t i = 0, j = 0;
|
||||
while (mask && i < max_codecs) {
|
||||
if (mask & 1)
|
||||
codecs[i++] = j;
|
||||
mask >>= 1;
|
||||
j++;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -111,6 +111,7 @@ rules = [
|
|||
#api.alsa.disable-mmap = false
|
||||
#api.alsa.disable-batch = false
|
||||
#api.alsa.use-chmap = false
|
||||
#iec958.codecs = [ PCM DTS AC3 MPEG MPEG2-AAC EAC3 TrueHD DTS-HD ]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue