From 4bdbb5827614c1ef94178abc2a228c177c2afda3 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 4 Apr 2017 19:44:00 +0200 Subject: [PATCH] alsa: implement enum_format --- spa/plugins/alsa/alsa-sink.c | 49 +----------------- spa/plugins/alsa/alsa-source.c | 49 +----------------- spa/plugins/alsa/alsa-utils.c | 93 ++++++++++++++++++++++++++++++++++ spa/plugins/alsa/alsa-utils.h | 19 +++++++ 4 files changed, 114 insertions(+), 96 deletions(-) diff --git a/spa/plugins/alsa/alsa-sink.c b/spa/plugins/alsa/alsa-sink.c index db67b80d0..78fffe2c1 100644 --- a/spa/plugins/alsa/alsa-sink.c +++ b/spa/plugins/alsa/alsa-sink.c @@ -48,18 +48,6 @@ update_state (SpaALSASink *this, SpaNodeState state) this->node.state = state; } -#define PROP(f,key,type,...) \ - SPA_POD_PROP (f,key,0,type,1,__VA_ARGS__) -#define PROP_MM(f,key,type,...) \ - SPA_POD_PROP (f,key,SPA_POD_PROP_RANGE_MIN_MAX,type,3,__VA_ARGS__) -#define PROP_U_MM(f,key,type,...) \ - SPA_POD_PROP (f,key,SPA_POD_PROP_FLAG_UNSET | \ - SPA_POD_PROP_RANGE_MIN_MAX,type,3,__VA_ARGS__) -#define PROP_U_EN(f,key,type,n,...) \ - SPA_POD_PROP (f,key,SPA_POD_PROP_FLAG_UNSET | \ - SPA_POD_PROP_RANGE_ENUM,type,n,__VA_ARGS__) - - static SpaResult spa_alsa_sink_node_get_props (SpaNode *node, SpaProps **props) @@ -268,11 +256,6 @@ spa_alsa_sink_node_port_enum_formats (SpaNode *node, uint32_t index) { SpaALSASink *this; - SpaResult res; - SpaFormat *fmt; - uint8_t buffer[1024]; - SpaPODBuilder b = { NULL, }; - SpaPODFrame f[2]; spa_return_val_if_fail (node != NULL, SPA_RESULT_INVALID_ARGUMENTS); spa_return_val_if_fail (format != NULL, SPA_RESULT_INVALID_ARGUMENTS); @@ -281,37 +264,7 @@ spa_alsa_sink_node_port_enum_formats (SpaNode *node, spa_return_val_if_fail (CHECK_PORT (this, direction, port_id), SPA_RESULT_INVALID_PORT); -next: - spa_pod_builder_init (&b, buffer, sizeof (buffer)); - - switch (index++) { - case 0: - spa_pod_builder_format (&b, &f[0], this->type.format, - this->type.media_type.audio, this->type.media_subtype.raw, - PROP_U_EN (&f[1], this->type.format_audio.format, SPA_POD_TYPE_ID, 3, this->type.audio_format.S16, - this->type.audio_format.S16, - this->type.audio_format.S32), - PROP_U_MM (&f[1], this->type.format_audio.rate, SPA_POD_TYPE_INT, 44100, 1, INT32_MAX), - PROP_U_MM (&f[1], this->type.format_audio.channels, SPA_POD_TYPE_INT, 2, 1, INT32_MAX)); - break; - case 1: - spa_pod_builder_format (&b, &f[0], this->type.format, - this->type.media_type.audio, this->type.media_subtype_audio.aac, - SPA_POD_TYPE_NONE); - break; - default: - return SPA_RESULT_ENUM_END; - } - fmt = SPA_POD_BUILDER_DEREF (&b, f[0].ref, SpaFormat); - - spa_pod_builder_init (&b, this->format_buffer, sizeof (this->format_buffer)); - - if ((res = spa_format_filter (fmt, filter, &b)) != SPA_RESULT_OK) - goto next; - - *format = SPA_POD_BUILDER_DEREF (&b, 0, SpaFormat); - - return SPA_RESULT_OK; + return spa_alsa_enum_format (this, format, filter, index); } static SpaResult diff --git a/spa/plugins/alsa/alsa-source.c b/spa/plugins/alsa/alsa-source.c index 64edb051d..be96e9441 100644 --- a/spa/plugins/alsa/alsa-source.c +++ b/spa/plugins/alsa/alsa-source.c @@ -48,19 +48,6 @@ reset_alsa_props (SpaALSAProps *props) props->min_latency = default_min_latency; } -#define PROP(f,key,type,...) \ - SPA_POD_PROP (f,key,0,type,1,__VA_ARGS__) -#define PROP_MM(f,key,type,...) \ - SPA_POD_PROP (f,key,SPA_POD_PROP_RANGE_MIN_MAX,type,3,__VA_ARGS__) -#define PROP_U_MM(f,key,type,...) \ - SPA_POD_PROP (f,key,SPA_POD_PROP_FLAG_UNSET | \ - SPA_POD_PROP_RANGE_MIN_MAX,type,3,__VA_ARGS__) -#define PROP_EN(f,key,type,n,...) \ - SPA_POD_PROP (f,key,SPA_POD_PROP_RANGE_ENUM,type,n,__VA_ARGS__) -#define PROP_U_EN(f,key,type,n,...) \ - SPA_POD_PROP (f,key,SPA_POD_PROP_FLAG_UNSET | \ - SPA_POD_PROP_RANGE_ENUM,type,n,__VA_ARGS__) - static SpaResult spa_alsa_source_node_get_props (SpaNode *node, SpaProps **props) @@ -305,11 +292,6 @@ spa_alsa_source_node_port_enum_formats (SpaNode *node, uint32_t index) { SpaALSASource *this; - SpaResult res; - SpaFormat *fmt; - uint8_t buffer[1024]; - SpaPODBuilder b = { NULL, }; - SpaPODFrame f[2]; spa_return_val_if_fail (node != NULL, SPA_RESULT_INVALID_ARGUMENTS); spa_return_val_if_fail (format != NULL, SPA_RESULT_INVALID_ARGUMENTS); @@ -318,36 +300,7 @@ spa_alsa_source_node_port_enum_formats (SpaNode *node, spa_return_val_if_fail (CHECK_PORT (this, direction, port_id), SPA_RESULT_INVALID_PORT); -next: - spa_pod_builder_init (&b, buffer, sizeof (buffer)); - - switch (index++) { - case 0: - spa_pod_builder_format (&b, &f[0], this->type.format, - this->type.media_type.audio, this->type.media_subtype.raw, - PROP_U_EN (&f[1], this->type.format_audio.format, SPA_POD_TYPE_ID, 3, this->type.audio_format.S16, - this->type.audio_format.S16, - this->type.audio_format.S32), - PROP_U_MM (&f[1], this->type.format_audio.rate, SPA_POD_TYPE_INT, 44100, 1, INT32_MAX), - PROP_U_MM (&f[1], this->type.format_audio.channels, SPA_POD_TYPE_INT, 2, 1, INT32_MAX)); - break; - case 1: - spa_pod_builder_format (&b, &f[0], this->type.format, - this->type.media_type.audio, this->type.media_subtype_audio.aac, - SPA_POD_TYPE_NONE); - default: - return SPA_RESULT_ENUM_END; - } - fmt = SPA_POD_BUILDER_DEREF (&b, f[0].ref, SpaFormat); - - spa_pod_builder_init (&b, this->format_buffer, sizeof (this->format_buffer)); - - if ((res = spa_format_filter (fmt, filter, &b)) != SPA_RESULT_OK) - goto next; - - *format = SPA_MEMBER (this->format_buffer, 0, SpaFormat); - - return SPA_RESULT_OK; + return spa_alsa_enum_format (this, format, filter, index); } static void diff --git a/spa/plugins/alsa/alsa-utils.c b/spa/plugins/alsa/alsa-utils.c index 673bb7595..c3f8a03ea 100644 --- a/spa/plugins/alsa/alsa-utils.c +++ b/spa/plugins/alsa/alsa-utils.c @@ -110,6 +110,98 @@ spa_alsa_format_to_alsa (Type *map, uint32_t format) return SND_PCM_FORMAT_UNKNOWN; } +SpaResult +spa_alsa_enum_format (SpaALSAState *state, + SpaFormat **format, + const SpaFormat *filter, + uint32_t index) +{ + snd_pcm_t *hndl; + snd_pcm_hw_params_t *params; + snd_pcm_format_mask_t *fmask; + int err, i, j, dir; + unsigned int min, max; + SpaPODBuilder b = { NULL, }; + SpaPODFrame f[2]; + SpaPODProp *prop; + + if (index == 1) + return SPA_RESULT_ENUM_END; + + if ((err = spa_alsa_open (state)) < 0) + return SPA_RESULT_ERROR; + + hndl = state->hndl; + snd_pcm_hw_params_alloca (¶ms); + CHECK (snd_pcm_hw_params_any (hndl, params), "Broken configuration: no configurations available"); + + spa_pod_builder_init (&b, state->format_buffer, sizeof (state->format_buffer)); + + spa_pod_builder_push_format (&b, &f[0], state->type.format, + state->type.media_type.audio, + state->type.media_subtype.raw); + + snd_pcm_format_mask_alloca (&fmask); + snd_pcm_hw_params_get_format_mask (params, fmask); + + spa_pod_builder_push_prop (&b, &f[1], + state->type.format_audio.format, + SPA_POD_PROP_RANGE_NONE); + prop = SPA_POD_BUILDER_DEREF (&b, f[1].ref, SpaPODProp); + + for (i = 1, j = 0; i < SPA_N_ELEMENTS (format_info); i++) { + const FormatInfo *fi = &format_info[i]; + + if (snd_pcm_format_mask_test (fmask, fi->format)) { + uint32_t f = *SPA_MEMBER (&state->type, fi->format_offset, uint32_t); + if (j++ == 0) + spa_pod_builder_id (&b, f); + spa_pod_builder_id (&b, f); + } + } + if (j > 1) + prop->body.flags |= SPA_POD_PROP_RANGE_ENUM | SPA_POD_PROP_FLAG_UNSET; + 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"); + + spa_pod_builder_push_prop (&b, &f[1], + state->type.format_audio.rate, + SPA_POD_PROP_RANGE_NONE); + prop = SPA_POD_BUILDER_DEREF (&b, f[1].ref, SpaPODProp); + + spa_pod_builder_int (&b, SPA_CLAMP (44100, min, max)); + if (min != max) { + spa_pod_builder_int (&b, min); + spa_pod_builder_int (&b, max); + prop->body.flags |= SPA_POD_PROP_RANGE_MIN_MAX | SPA_POD_PROP_FLAG_UNSET; + } + 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"); + + spa_pod_builder_push_prop (&b, &f[1], + state->type.format_audio.channels, + SPA_POD_PROP_RANGE_NONE); + prop = SPA_POD_BUILDER_DEREF (&b, f[1].ref, SpaPODProp); + + spa_pod_builder_int (&b, SPA_CLAMP (2, min, max)); + if (min != max) { + spa_pod_builder_int (&b, min); + spa_pod_builder_int (&b, max); + prop->body.flags |= SPA_POD_PROP_RANGE_MIN_MAX | SPA_POD_PROP_FLAG_UNSET; + } + spa_pod_builder_pop (&b, &f[1]); + + spa_pod_builder_pop (&b, &f[0]); + + *format = SPA_POD_BUILDER_DEREF (&b, f[0].ref, SpaFormat); + + return SPA_RESULT_OK; +} + int spa_alsa_set_format (SpaALSAState *state, SpaAudioInfo *fmt, SpaPortFormatFlags flags) { @@ -135,6 +227,7 @@ spa_alsa_set_format (SpaALSAState *state, SpaAudioInfo *fmt, SpaPortFormatFlags /* set the interleaved read/write format */ CHECK (snd_pcm_hw_params_set_access(hndl, params, SND_PCM_ACCESS_MMAP_INTERLEAVED), "set_access"); + /* disable ALSA wakeups, we use a timer */ if (snd_pcm_hw_params_can_disable_period_wakeup (params)) CHECK (snd_pcm_hw_params_set_period_wakeup (hndl, params, 0), "set_period_wakeup"); diff --git a/spa/plugins/alsa/alsa-utils.h b/spa/plugins/alsa/alsa-utils.h index 0afe77a19..d6fd37920 100644 --- a/spa/plugins/alsa/alsa-utils.h +++ b/spa/plugins/alsa/alsa-utils.h @@ -162,6 +162,25 @@ struct _SpaALSAState { int64_t last_monotonic; }; +#define PROP(f,key,type,...) \ + SPA_POD_PROP (f,key,0,type,1,__VA_ARGS__) +#define PROP_MM(f,key,type,...) \ + SPA_POD_PROP (f,key,SPA_POD_PROP_RANGE_MIN_MAX,type,3,__VA_ARGS__) +#define PROP_U_MM(f,key,type,...) \ + SPA_POD_PROP (f,key,SPA_POD_PROP_FLAG_UNSET | \ + SPA_POD_PROP_RANGE_MIN_MAX,type,3,__VA_ARGS__) +#define PROP_EN(f,key,type,n,...) \ + SPA_POD_PROP (f,key,SPA_POD_PROP_RANGE_ENUM,type,n,__VA_ARGS__) +#define PROP_U_EN(f,key,type,n,...) \ + SPA_POD_PROP (f,key,SPA_POD_PROP_FLAG_UNSET | \ + SPA_POD_PROP_RANGE_ENUM,type,n,__VA_ARGS__) + +SpaResult +spa_alsa_enum_format (SpaALSAState *state, + SpaFormat **format, + const SpaFormat *filter, + uint32_t index); + int spa_alsa_set_format (SpaALSAState *state, SpaAudioInfo *info, SpaPortFormatFlags flags);