mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
Compare commits
42 commits
55257fb010
...
501bfefa5e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
501bfefa5e | ||
|
|
76a31a47c2 | ||
|
|
23c449af5d | ||
|
|
94d0d8bc09 | ||
|
|
0276bb5b06 | ||
|
|
614186a590 | ||
|
|
c6d0b364ab | ||
|
|
8a23b13798 | ||
|
|
3d08c0557f | ||
|
|
68dc45cc62 | ||
|
|
b0e308e0dc | ||
|
|
fe2c62b9b1 | ||
|
|
3febf09b85 | ||
|
|
93495d3a75 | ||
|
|
9f1a149876 | ||
|
|
88c65932d8 | ||
|
|
c8d4de5e77 | ||
|
|
c4244a6cf3 | ||
|
|
f7c3d37969 | ||
|
|
d18670d7bb | ||
|
|
aa0272f6f3 | ||
|
|
78219471ff | ||
|
|
6d74eee874 | ||
|
|
be29ae4ef6 | ||
|
|
5e1e3fca1e | ||
|
|
b8eeb2db45 | ||
|
|
c5533b3c32 | ||
|
|
11f1298f53 | ||
|
|
7177f8269d | ||
|
|
6465a63bf6 | ||
|
|
ae50bb5dc0 | ||
|
|
99bbac9cbf | ||
|
|
f19b075306 | ||
|
|
dbc5c81e4a | ||
|
|
818d1435ce | ||
|
|
8bbca3b8f3 | ||
|
|
9e7cae13df | ||
|
|
13b8c23767 | ||
|
|
eb096bfb62 | ||
|
|
ede13a8cb5 | ||
|
|
f453b1545d | ||
|
|
c94aff8cae |
87 changed files with 1045 additions and 532 deletions
|
|
@ -38,7 +38,7 @@ include:
|
|||
.fedora:
|
||||
variables:
|
||||
# Update this tag when you want to trigger a rebuild
|
||||
FDO_DISTRIBUTION_TAG: '2025-10-15.0'
|
||||
FDO_DISTRIBUTION_TAG: '2025-10-22.0'
|
||||
FDO_DISTRIBUTION_VERSION: '42'
|
||||
FDO_DISTRIBUTION_PACKAGES: >-
|
||||
alsa-lib-devel
|
||||
|
|
@ -48,6 +48,7 @@ include:
|
|||
dbus-devel
|
||||
doxygen
|
||||
fdk-aac-free-devel
|
||||
file
|
||||
findutils
|
||||
gcc
|
||||
gcc-c++
|
||||
|
|
|
|||
|
|
@ -115,10 +115,11 @@ cc_flags = common_flags + [
|
|||
'-Werror=old-style-definition',
|
||||
'-Werror=missing-parameter-type',
|
||||
'-Werror=strict-prototypes',
|
||||
'-DSPA_AUDIO_MAX_CHANNELS=128u',
|
||||
]
|
||||
add_project_arguments(cc.get_supported_arguments(cc_flags), language: 'c')
|
||||
|
||||
cc_flags_native = cc_native.get_supported_arguments(cc_flags)
|
||||
add_project_arguments(cc_native.get_supported_arguments(cc_flags),
|
||||
language: 'c', native: true)
|
||||
|
||||
have_cpp = add_languages('cpp', native: false, required : false)
|
||||
|
||||
|
|
|
|||
|
|
@ -22,9 +22,11 @@ PW_LOG_TOPIC_STATIC(alsa_log_topic, "alsa.ctl");
|
|||
#define VOLUME_MIN ((uint32_t) 0U)
|
||||
#define VOLUME_MAX ((uint32_t) 0x10000U)
|
||||
|
||||
#define MAX_CHANNELS SPA_AUDIO_MAX_CHANNELS
|
||||
|
||||
struct volume {
|
||||
uint32_t channels;
|
||||
long values[SPA_AUDIO_MAX_CHANNELS];
|
||||
long values[MAX_CHANNELS];
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -498,7 +500,7 @@ static struct spa_pod *build_volume_mute(struct spa_pod_builder *b, struct volum
|
|||
spa_pod_builder_push_object(b, &f[0],
|
||||
SPA_TYPE_OBJECT_Props, SPA_PARAM_Props);
|
||||
if (volume) {
|
||||
float volumes[SPA_AUDIO_MAX_CHANNELS];
|
||||
float volumes[MAX_CHANNELS];
|
||||
uint32_t i, n_volumes = 0;
|
||||
|
||||
n_volumes = volume->channels;
|
||||
|
|
@ -850,11 +852,11 @@ static void parse_props(struct global *g, const struct spa_pod *param, bool devi
|
|||
break;
|
||||
case SPA_PROP_channelVolumes:
|
||||
{
|
||||
float volumes[SPA_AUDIO_MAX_CHANNELS];
|
||||
float volumes[MAX_CHANNELS];
|
||||
uint32_t n_volumes, i;
|
||||
|
||||
n_volumes = spa_pod_copy_array(&prop->value, SPA_TYPE_Float,
|
||||
volumes, SPA_AUDIO_MAX_CHANNELS);
|
||||
volumes, SPA_N_ELEMENTS(volumes));
|
||||
|
||||
g->node.channel_volume.channels = n_volumes;
|
||||
for (i = 0; i < n_volumes; i++)
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ PW_LOG_TOPIC_STATIC(alsa_log_topic, "alsa.pcm");
|
|||
#define MAX_BUFFERS 64u
|
||||
|
||||
#define MAX_RATE (48000*8)
|
||||
#define MAX_CHANNELS SPA_AUDIO_MAX_CHANNELS
|
||||
|
||||
#define MIN_PERIOD 64
|
||||
|
||||
|
|
@ -642,7 +643,7 @@ static int snd_pcm_pipewire_pause(snd_pcm_ioplug_t * io, int enable)
|
|||
#define _FORMAT_BE(p, fmt) p ? SPA_AUDIO_FORMAT_UNKNOWN : SPA_AUDIO_FORMAT_ ## fmt ## _OE
|
||||
#endif
|
||||
|
||||
static int set_default_channels(uint32_t channels, uint32_t position[SPA_AUDIO_MAX_CHANNELS])
|
||||
static int set_default_channels(uint32_t channels, uint32_t position[MAX_CHANNELS])
|
||||
{
|
||||
switch (channels) {
|
||||
case 8:
|
||||
|
|
@ -915,12 +916,16 @@ static int snd_pcm_pipewire_set_chmap(snd_pcm_ioplug_t * io,
|
|||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
if (map->channels > MAX_CHANNELS)
|
||||
return -ENOTSUP;
|
||||
|
||||
for (i = 0; i < map->channels; i++) {
|
||||
char buf[8];
|
||||
position[i] = chmap_to_channel(map->pos[i]);
|
||||
pw_log_debug("map %d: %s / %s", i,
|
||||
snd_pcm_chmap_name(map->pos[i]),
|
||||
spa_debug_type_find_short_name(spa_type_audio_channel,
|
||||
position[i]));
|
||||
spa_type_audio_channel_make_short_name(position[i],
|
||||
buf, sizeof(buf), "UNK"));
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -1097,7 +1102,7 @@ struct param_info infos[] = {
|
|||
{ "alsa.rate", SND_PCM_IOPLUG_HW_RATE, TYPE_MIN_MAX,
|
||||
{ 1, MAX_RATE }, 2, collect_int },
|
||||
{ "alsa.channels", SND_PCM_IOPLUG_HW_CHANNELS, TYPE_MIN_MAX,
|
||||
{ 1, SPA_AUDIO_MAX_CHANNELS }, 2, collect_int },
|
||||
{ 1, MAX_CHANNELS }, 2, collect_int },
|
||||
{ "alsa.buffer-bytes", SND_PCM_IOPLUG_HW_BUFFER_BYTES, TYPE_MIN_MAX,
|
||||
{ MIN_BUFFER_BYTES, MAX_BUFFER_BYTES }, 2, collect_int },
|
||||
{ "alsa.period-bytes", SND_PCM_IOPLUG_HW_PERIOD_BYTES, TYPE_MIN_MAX,
|
||||
|
|
|
|||
|
|
@ -578,7 +578,7 @@ static int make_nodes(struct data *data)
|
|||
SPA_PARAM_PORT_CONFIG_direction, SPA_POD_Id(SPA_DIRECTION_OUTPUT),
|
||||
SPA_PARAM_PORT_CONFIG_mode, SPA_POD_Id(SPA_PARAM_PORT_CONFIG_MODE_dsp),
|
||||
SPA_PARAM_PORT_CONFIG_format, SPA_POD_Pod(param));
|
||||
if ((res = spa_node_set_param(data->source_node, SPA_PARAM_PortConfig, 0, param) < 0)) {
|
||||
if ((res = spa_node_set_param(data->source_node, SPA_PARAM_PortConfig, 0, param)) < 0) {
|
||||
printf("can't setup source node %d\n", res);
|
||||
return res;
|
||||
}
|
||||
|
|
@ -647,7 +647,7 @@ static int make_nodes(struct data *data)
|
|||
SPA_PARAM_PORT_CONFIG_format, SPA_POD_Pod(param));
|
||||
|
||||
|
||||
if ((res = spa_node_set_param(data->sink_node, SPA_PARAM_PortConfig, 0, param) < 0)) {
|
||||
if ((res = spa_node_set_param(data->sink_node, SPA_PARAM_PortConfig, 0, param)) < 0) {
|
||||
printf("can't setup sink node %d\n", res);
|
||||
return res;
|
||||
}
|
||||
|
|
@ -987,7 +987,7 @@ int main(int argc, char *argv[])
|
|||
|
||||
setlocale(LC_ALL, "");
|
||||
|
||||
while ((c = getopt_long(argc, argv, "hdmstiac:", long_options, NULL)) != -1) {
|
||||
while ((c = getopt_long(argc, argv, "hd:m:s:t:i:a:c:", long_options, NULL)) != -1) {
|
||||
switch (c) {
|
||||
case 'h':
|
||||
show_help(&data, argv[0], false);
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ spa_format_audio_dsd_parse(const struct spa_pod *format, struct spa_audio_info_d
|
|||
SPA_FORMAT_AUDIO_channels, SPA_POD_OPT_Int(&info->channels),
|
||||
SPA_FORMAT_AUDIO_position, SPA_POD_OPT_Pod(&position));
|
||||
if (position == NULL ||
|
||||
!spa_pod_copy_array(position, SPA_TYPE_Id, info->position, SPA_AUDIO_MAX_CHANNELS))
|
||||
!spa_pod_copy_array(position, SPA_TYPE_Id, info->position, SPA_N_ELEMENTS(info->position)))
|
||||
SPA_FLAG_SET(info->flags, SPA_AUDIO_FLAG_UNPOSITIONED);
|
||||
|
||||
return res;
|
||||
|
|
|
|||
|
|
@ -46,20 +46,61 @@ extern "C" {
|
|||
#endif
|
||||
#endif
|
||||
|
||||
SPA_API_AUDIO_FORMAT_UTILS bool
|
||||
spa_format_audio_ext_valid_size(uint32_t media_subtype, size_t size)
|
||||
{
|
||||
switch (media_subtype) {
|
||||
case SPA_MEDIA_SUBTYPE_raw:
|
||||
return size >= offsetof(struct spa_audio_info, info.raw) &&
|
||||
SPA_AUDIO_INFO_RAW_VALID_SIZE(size - offsetof(struct spa_audio_info, info.raw));
|
||||
|
||||
#define _SPA_FORMAT_AUDIO_EXT_VALID_SIZE_CASE(format) \
|
||||
case SPA_MEDIA_SUBTYPE_ ## format: \
|
||||
return size >= offsetof(struct spa_audio_info, info.format) + sizeof(struct spa_audio_info_ ## format);
|
||||
_SPA_FORMAT_AUDIO_EXT_VALID_SIZE_CASE(dsp)
|
||||
_SPA_FORMAT_AUDIO_EXT_VALID_SIZE_CASE(iec958)
|
||||
_SPA_FORMAT_AUDIO_EXT_VALID_SIZE_CASE(dsd)
|
||||
_SPA_FORMAT_AUDIO_EXT_VALID_SIZE_CASE(mp3)
|
||||
_SPA_FORMAT_AUDIO_EXT_VALID_SIZE_CASE(aac)
|
||||
_SPA_FORMAT_AUDIO_EXT_VALID_SIZE_CASE(vorbis)
|
||||
_SPA_FORMAT_AUDIO_EXT_VALID_SIZE_CASE(wma)
|
||||
_SPA_FORMAT_AUDIO_EXT_VALID_SIZE_CASE(ra)
|
||||
_SPA_FORMAT_AUDIO_EXT_VALID_SIZE_CASE(amr)
|
||||
_SPA_FORMAT_AUDIO_EXT_VALID_SIZE_CASE(alac)
|
||||
_SPA_FORMAT_AUDIO_EXT_VALID_SIZE_CASE(flac)
|
||||
_SPA_FORMAT_AUDIO_EXT_VALID_SIZE_CASE(ape)
|
||||
_SPA_FORMAT_AUDIO_EXT_VALID_SIZE_CASE(ac3)
|
||||
_SPA_FORMAT_AUDIO_EXT_VALID_SIZE_CASE(eac3)
|
||||
_SPA_FORMAT_AUDIO_EXT_VALID_SIZE_CASE(truehd)
|
||||
_SPA_FORMAT_AUDIO_EXT_VALID_SIZE_CASE(dts)
|
||||
_SPA_FORMAT_AUDIO_EXT_VALID_SIZE_CASE(mpegh)
|
||||
#undef _SPA_FORMAT_AUDIO_EXT_VALID_SIZE_CASE
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
SPA_API_AUDIO_FORMAT_UTILS int
|
||||
spa_format_audio_parse(const struct spa_pod *format, struct spa_audio_info *info)
|
||||
spa_format_audio_ext_parse(const struct spa_pod *format, struct spa_audio_info *info, size_t size)
|
||||
{
|
||||
int res;
|
||||
uint32_t media_type, media_subtype;
|
||||
|
||||
if ((res = spa_format_parse(format, &info->media_type, &info->media_subtype)) < 0)
|
||||
if ((res = spa_format_parse(format, &media_type, &media_subtype)) < 0)
|
||||
return res;
|
||||
|
||||
if (info->media_type != SPA_MEDIA_TYPE_audio)
|
||||
if (media_type != SPA_MEDIA_TYPE_audio)
|
||||
return -EINVAL;
|
||||
|
||||
switch (info->media_subtype) {
|
||||
if (!spa_format_audio_ext_valid_size(media_subtype, size))
|
||||
return -EINVAL;
|
||||
|
||||
info->media_type = media_type;
|
||||
info->media_subtype = media_subtype;
|
||||
|
||||
switch (media_subtype) {
|
||||
case SPA_MEDIA_SUBTYPE_raw:
|
||||
return spa_format_audio_raw_parse(format, &info->info.raw);
|
||||
return spa_format_audio_raw_ext_parse(format, &info->info.raw,
|
||||
size - offsetof(struct spa_audio_info, info.raw));
|
||||
case SPA_MEDIA_SUBTYPE_dsp:
|
||||
return spa_format_audio_dsp_parse(format, &info->info.dsp);
|
||||
case SPA_MEDIA_SUBTYPE_iec958:
|
||||
|
|
@ -98,13 +139,25 @@ spa_format_audio_parse(const struct spa_pod *format, struct spa_audio_info *info
|
|||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
SPA_API_AUDIO_FORMAT_UTILS struct spa_pod *
|
||||
spa_format_audio_build(struct spa_pod_builder *builder, uint32_t id,
|
||||
const struct spa_audio_info *info)
|
||||
SPA_API_AUDIO_FORMAT_UTILS int
|
||||
spa_format_audio_parse(const struct spa_pod *format, struct spa_audio_info *info)
|
||||
{
|
||||
return spa_format_audio_ext_parse(format, info, sizeof(*info));
|
||||
}
|
||||
|
||||
SPA_API_AUDIO_FORMAT_UTILS struct spa_pod *
|
||||
spa_format_audio_ext_build(struct spa_pod_builder *builder, uint32_t id,
|
||||
const struct spa_audio_info *info, size_t size)
|
||||
{
|
||||
if (!spa_format_audio_ext_valid_size(info->media_subtype, size)) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (info->media_subtype) {
|
||||
case SPA_MEDIA_SUBTYPE_raw:
|
||||
return spa_format_audio_raw_build(builder, id, &info->info.raw);
|
||||
return spa_format_audio_raw_ext_build(builder, id, &info->info.raw,
|
||||
size - offsetof(struct spa_audio_info, info.raw));
|
||||
case SPA_MEDIA_SUBTYPE_dsp:
|
||||
return spa_format_audio_dsp_build(builder, id, &info->info.dsp);
|
||||
case SPA_MEDIA_SUBTYPE_iec958:
|
||||
|
|
@ -143,6 +196,13 @@ spa_format_audio_build(struct spa_pod_builder *builder, uint32_t id,
|
|||
errno = ENOTSUP;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SPA_API_AUDIO_FORMAT_UTILS struct spa_pod *
|
||||
spa_format_audio_build(struct spa_pod_builder *builder, uint32_t id,
|
||||
const struct spa_audio_info *info)
|
||||
{
|
||||
return spa_format_audio_ext_build(builder, id, info, sizeof(*info));
|
||||
}
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -59,6 +59,8 @@ struct spa_audio_info {
|
|||
struct spa_audio_info_dts dts;
|
||||
struct spa_audio_info_mpegh mpegh;
|
||||
} info;
|
||||
|
||||
/* padding follows here when info has flexible size */
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -28,8 +28,8 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
SPA_API_AUDIO_RAW_JSON int
|
||||
spa_audio_parse_position(const char *str, size_t len,
|
||||
uint32_t *position, uint32_t *n_channels)
|
||||
spa_audio_parse_position_n(const char *str, size_t len,
|
||||
uint32_t *position, uint32_t max_position, uint32_t *n_channels)
|
||||
{
|
||||
struct spa_json iter;
|
||||
char v[256];
|
||||
|
|
@ -38,18 +38,32 @@ spa_audio_parse_position(const char *str, size_t len,
|
|||
if (spa_json_begin_array_relax(&iter, str, len) <= 0)
|
||||
return 0;
|
||||
|
||||
while (spa_json_get_string(&iter, v, sizeof(v)) > 0 &&
|
||||
channels < SPA_AUDIO_MAX_CHANNELS) {
|
||||
position[channels++] = spa_type_audio_channel_from_short_name(v);
|
||||
while (spa_json_get_string(&iter, v, sizeof(v)) > 0) {
|
||||
if (channels < max_position)
|
||||
position[channels] = spa_type_audio_channel_from_short_name(v);
|
||||
channels++;
|
||||
}
|
||||
*n_channels = channels;
|
||||
return channels;
|
||||
}
|
||||
|
||||
SPA_API_AUDIO_RAW_JSON int
|
||||
spa_audio_info_raw_update(struct spa_audio_info_raw *info, const char *key, const char *val, bool force)
|
||||
spa_audio_parse_position(const char *str, size_t len,
|
||||
uint32_t *position, uint32_t *n_channels)
|
||||
{
|
||||
return spa_audio_parse_position_n(str, len, position, SPA_AUDIO_MAX_CHANNELS, n_channels);
|
||||
}
|
||||
|
||||
SPA_API_AUDIO_RAW_JSON int
|
||||
spa_audio_info_raw_ext_update(struct spa_audio_info_raw *info, size_t size,
|
||||
const char *key, const char *val, bool force)
|
||||
{
|
||||
uint32_t v;
|
||||
uint32_t max_position = SPA_AUDIO_INFO_RAW_MAX_POSITION(size);
|
||||
|
||||
if (!SPA_AUDIO_INFO_RAW_VALID_SIZE(size))
|
||||
return -EINVAL;
|
||||
|
||||
if (spa_streq(key, SPA_KEY_AUDIO_FORMAT)) {
|
||||
if (force || info->format == 0)
|
||||
info->format = (enum spa_audio_format)spa_type_audio_format_from_short_name(val);
|
||||
|
|
@ -57,41 +71,88 @@ spa_audio_info_raw_update(struct spa_audio_info_raw *info, const char *key, cons
|
|||
if (spa_atou32(val, &v, 0) && (force || info->rate == 0))
|
||||
info->rate = v;
|
||||
} else if (spa_streq(key, SPA_KEY_AUDIO_CHANNELS)) {
|
||||
if (spa_atou32(val, &v, 0) && (force || info->channels == 0))
|
||||
info->channels = SPA_MIN(v, SPA_AUDIO_MAX_CHANNELS);
|
||||
if (spa_atou32(val, &v, 0) && (force || info->channels == 0)) {
|
||||
if (v > max_position)
|
||||
return -ECHRNG;
|
||||
info->channels = v;
|
||||
}
|
||||
} else if (spa_streq(key, SPA_KEY_AUDIO_POSITION)) {
|
||||
if (force || info->channels == 0) {
|
||||
if (spa_audio_parse_position(val, strlen(val), info->position, &info->channels) > 0)
|
||||
if (spa_audio_parse_position_n(val, strlen(val), info->position,
|
||||
max_position, &v) > 0) {
|
||||
if (v > max_position)
|
||||
return -ECHRNG;
|
||||
info->channels = v;
|
||||
SPA_FLAG_CLEAR(info->flags, SPA_AUDIO_FLAG_UNPOSITIONED);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
SPA_API_AUDIO_RAW_JSON int
|
||||
spa_audio_info_raw_update(struct spa_audio_info_raw *info,
|
||||
const char *key, const char *val, bool force)
|
||||
{
|
||||
return spa_audio_info_raw_ext_update(info, sizeof(*info), key, val, force);
|
||||
}
|
||||
|
||||
SPA_API_AUDIO_RAW_JSON int
|
||||
spa_audio_info_raw_ext_init_dict_keys_va(struct spa_audio_info_raw *info, size_t size,
|
||||
const struct spa_dict *defaults,
|
||||
const struct spa_dict *dict, va_list args)
|
||||
{
|
||||
int res;
|
||||
|
||||
if (!SPA_AUDIO_INFO_RAW_VALID_SIZE(size))
|
||||
return -EINVAL;
|
||||
|
||||
memset(info, 0, size);
|
||||
SPA_FLAG_SET(info->flags, SPA_AUDIO_FLAG_UNPOSITIONED);
|
||||
if (dict) {
|
||||
const char *val, *key;
|
||||
while ((key = va_arg(args, const char *))) {
|
||||
if ((val = spa_dict_lookup(dict, key)) == NULL)
|
||||
continue;
|
||||
if ((res = spa_audio_info_raw_ext_update(info, size,
|
||||
key, val, true)) < 0)
|
||||
return res;
|
||||
}
|
||||
}
|
||||
if (defaults) {
|
||||
const struct spa_dict_item *it;
|
||||
spa_dict_for_each(it, defaults)
|
||||
if ((res = spa_audio_info_raw_ext_update(info, size,
|
||||
it->key, it->value, false)) < 0)
|
||||
return res;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
SPA_API_AUDIO_RAW_JSON int SPA_SENTINEL
|
||||
spa_audio_info_raw_ext_init_dict_keys(struct spa_audio_info_raw *info, size_t size,
|
||||
const struct spa_dict *defaults,
|
||||
const struct spa_dict *dict, ...)
|
||||
{
|
||||
va_list args;
|
||||
int res;
|
||||
va_start(args, dict);
|
||||
res = spa_audio_info_raw_ext_init_dict_keys_va(info, size, defaults, dict, args);
|
||||
va_end(args);
|
||||
return res;
|
||||
}
|
||||
|
||||
SPA_API_AUDIO_RAW_JSON int SPA_SENTINEL
|
||||
spa_audio_info_raw_init_dict_keys(struct spa_audio_info_raw *info,
|
||||
const struct spa_dict *defaults,
|
||||
const struct spa_dict *dict, ...)
|
||||
{
|
||||
spa_zero(*info);
|
||||
SPA_FLAG_SET(info->flags, SPA_AUDIO_FLAG_UNPOSITIONED);
|
||||
if (dict) {
|
||||
const char *val, *key;
|
||||
va_list args;
|
||||
va_start(args, dict);
|
||||
while ((key = va_arg(args, const char *))) {
|
||||
if ((val = spa_dict_lookup(dict, key)) == NULL)
|
||||
continue;
|
||||
spa_audio_info_raw_update(info, key, val, true);
|
||||
}
|
||||
va_end(args);
|
||||
}
|
||||
if (defaults) {
|
||||
const struct spa_dict_item *it;
|
||||
spa_dict_for_each(it, defaults)
|
||||
spa_audio_info_raw_update(info, it->key, it->value, false);
|
||||
}
|
||||
return 0;
|
||||
va_list args;
|
||||
int res;
|
||||
va_start(args, dict);
|
||||
res = spa_audio_info_raw_ext_init_dict_keys_va(info, sizeof(*info), defaults, dict, args);
|
||||
va_end(args);
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -267,12 +267,34 @@ static const struct spa_type_info spa_type_audio_channel[] = {
|
|||
|
||||
SPA_API_AUDIO_RAW_TYPES uint32_t spa_type_audio_channel_from_short_name(const char *name)
|
||||
{
|
||||
return spa_type_from_short_name(name, spa_type_audio_channel, SPA_AUDIO_CHANNEL_UNKNOWN);
|
||||
uint32_t res;
|
||||
if (spa_strstartswith(name, "AUX")) {
|
||||
if (spa_atou32(name+3, &res, 10) && res < 0x1000)
|
||||
res = SPA_AUDIO_CHANNEL_AUX0 + res;
|
||||
else
|
||||
res = SPA_AUDIO_CHANNEL_UNKNOWN;
|
||||
} else {
|
||||
res = spa_type_from_short_name(name, spa_type_audio_channel, SPA_AUDIO_CHANNEL_UNKNOWN);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
SPA_API_AUDIO_RAW_TYPES const char * spa_type_audio_channel_to_short_name(uint32_t type)
|
||||
{
|
||||
return spa_type_to_short_name(type, spa_type_audio_channel, "UNK");
|
||||
}
|
||||
SPA_API_AUDIO_RAW_TYPES const char * spa_type_audio_channel_make_short_name(uint32_t type,
|
||||
char *buf, size_t size, const char *unknown)
|
||||
{
|
||||
if (SPA_AUDIO_CHANNEL_IS_AUX(type)) {
|
||||
snprintf(buf, size, "AUX%u", type - SPA_AUDIO_CHANNEL_AUX0);
|
||||
} else {
|
||||
const char *str = spa_type_to_short_name(type, spa_type_audio_channel, NULL);
|
||||
if (str == NULL)
|
||||
return unknown;
|
||||
snprintf(buf, size, "%.7s", str);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
#define SPA_TYPE_INFO_AudioVolumeRampScale SPA_TYPE_INFO_ENUM_BASE "AudioVolumeRampScale"
|
||||
#define SPA_TYPE_INFO_AUDIO_VOLUME_RAMP_SCALE_BASE SPA_TYPE_INFO_AudioVolumeRampScale ":"
|
||||
|
|
|
|||
|
|
@ -29,10 +29,15 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
SPA_API_AUDIO_RAW_UTILS int
|
||||
spa_format_audio_raw_parse(const struct spa_pod *format, struct spa_audio_info_raw *info)
|
||||
spa_format_audio_raw_ext_parse(const struct spa_pod *format, struct spa_audio_info_raw *info, size_t size)
|
||||
{
|
||||
struct spa_pod *position = NULL;
|
||||
int res;
|
||||
uint32_t max_position = SPA_AUDIO_INFO_RAW_MAX_POSITION(size);
|
||||
|
||||
if (!SPA_AUDIO_INFO_RAW_VALID_SIZE(size))
|
||||
return -EINVAL;
|
||||
|
||||
info->flags = 0;
|
||||
res = spa_pod_parse_object(format,
|
||||
SPA_TYPE_OBJECT_Format, NULL,
|
||||
|
|
@ -40,18 +45,33 @@ spa_format_audio_raw_parse(const struct spa_pod *format, struct spa_audio_info_r
|
|||
SPA_FORMAT_AUDIO_rate, SPA_POD_OPT_Int(&info->rate),
|
||||
SPA_FORMAT_AUDIO_channels, SPA_POD_OPT_Int(&info->channels),
|
||||
SPA_FORMAT_AUDIO_position, SPA_POD_OPT_Pod(&position));
|
||||
if (info->channels > max_position)
|
||||
return -ECHRNG;
|
||||
if (position == NULL ||
|
||||
!spa_pod_copy_array(position, SPA_TYPE_Id, info->position, SPA_AUDIO_MAX_CHANNELS))
|
||||
spa_pod_copy_array(position, SPA_TYPE_Id, info->position, max_position) != info->channels)
|
||||
SPA_FLAG_SET(info->flags, SPA_AUDIO_FLAG_UNPOSITIONED);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
SPA_API_AUDIO_RAW_UTILS int
|
||||
spa_format_audio_raw_parse(const struct spa_pod *format, struct spa_audio_info_raw *info)
|
||||
{
|
||||
return spa_format_audio_raw_ext_parse(format, info, sizeof(*info));
|
||||
}
|
||||
|
||||
SPA_API_AUDIO_RAW_UTILS struct spa_pod *
|
||||
spa_format_audio_raw_build(struct spa_pod_builder *builder, uint32_t id,
|
||||
const struct spa_audio_info_raw *info)
|
||||
spa_format_audio_raw_ext_build(struct spa_pod_builder *builder, uint32_t id,
|
||||
const struct spa_audio_info_raw *info, size_t size)
|
||||
{
|
||||
struct spa_pod_frame f;
|
||||
uint32_t max_position = SPA_AUDIO_INFO_RAW_MAX_POSITION(size);
|
||||
|
||||
if (!SPA_AUDIO_INFO_RAW_VALID_SIZE(size)) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
spa_pod_builder_push_object(builder, &f, SPA_TYPE_OBJECT_Format, id);
|
||||
spa_pod_builder_add(builder,
|
||||
SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio),
|
||||
|
|
@ -66,7 +86,10 @@ spa_format_audio_raw_build(struct spa_pod_builder *builder, uint32_t id,
|
|||
if (info->channels != 0) {
|
||||
spa_pod_builder_add(builder,
|
||||
SPA_FORMAT_AUDIO_channels, SPA_POD_Int(info->channels), 0);
|
||||
if (!SPA_FLAG_IS_SET(info->flags, SPA_AUDIO_FLAG_UNPOSITIONED)) {
|
||||
/* we drop the positions here when we can't read all of them. This is
|
||||
* really a malformed spa_audio_info structure. */
|
||||
if (!SPA_FLAG_IS_SET(info->flags, SPA_AUDIO_FLAG_UNPOSITIONED) &&
|
||||
max_position > info->channels) {
|
||||
spa_pod_builder_add(builder, SPA_FORMAT_AUDIO_position,
|
||||
SPA_POD_Array(sizeof(uint32_t), SPA_TYPE_Id,
|
||||
info->channels, info->position), 0);
|
||||
|
|
@ -75,6 +98,13 @@ spa_format_audio_raw_build(struct spa_pod_builder *builder, uint32_t id,
|
|||
return (struct spa_pod*)spa_pod_builder_pop(builder, &f);
|
||||
}
|
||||
|
||||
SPA_API_AUDIO_RAW_UTILS struct spa_pod *
|
||||
spa_format_audio_raw_build(struct spa_pod_builder *builder, uint32_t id,
|
||||
const struct spa_audio_info_raw *info)
|
||||
{
|
||||
return spa_format_audio_raw_ext_build(builder, id, info, sizeof(*info));
|
||||
}
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -18,7 +18,11 @@ extern "C" {
|
|||
* \{
|
||||
*/
|
||||
|
||||
#define SPA_AUDIO_MAX_CHANNELS 128u
|
||||
/* This is the max number of channels, changing this will change the
|
||||
* size of some helper structures. This value should be at least 64 */
|
||||
#ifndef SPA_AUDIO_MAX_CHANNELS
|
||||
#define SPA_AUDIO_MAX_CHANNELS 64u
|
||||
#endif
|
||||
|
||||
enum spa_audio_format {
|
||||
SPA_AUDIO_FORMAT_UNKNOWN,
|
||||
|
|
@ -259,6 +263,8 @@ enum spa_audio_channel {
|
|||
SPA_AUDIO_CHANNEL_START_Custom = 0x10000,
|
||||
};
|
||||
|
||||
#define SPA_AUDIO_CHANNEL_IS_AUX(ch) ((ch)>=SPA_AUDIO_CHANNEL_START_Aux && (ch)<=SPA_AUDIO_CHANNEL_LAST_Aux)
|
||||
|
||||
enum spa_audio_volume_ramp_scale {
|
||||
SPA_AUDIO_VOLUME_RAMP_INVALID,
|
||||
SPA_AUDIO_VOLUME_RAMP_LINEAR,
|
||||
|
|
@ -269,17 +275,27 @@ enum spa_audio_volume_ramp_scale {
|
|||
#define SPA_AUDIO_FLAG_NONE (0) /*< no valid flag */
|
||||
#define SPA_AUDIO_FLAG_UNPOSITIONED (1 << 0) /*< the position array explicitly
|
||||
* contains unpositioned channels. */
|
||||
/** Audio information description */
|
||||
/** Audio information description. You can assume when you receive this structure
|
||||
* that there is enought padding to accomodate all channel positions in case the
|
||||
* channel count is more than SPA_AUDIO_MAX_CHANNELS. */
|
||||
struct spa_audio_info_raw {
|
||||
enum spa_audio_format format; /*< format, one of enum spa_audio_format */
|
||||
uint32_t flags; /*< extra flags */
|
||||
uint32_t rate; /*< sample rate */
|
||||
uint32_t channels; /*< number of channels */
|
||||
uint32_t channels; /*< number of channels. This can be more than SPA_AUDIO_MAX_CHANNELS
|
||||
* and you may assume there is enough padding for the extra
|
||||
* channel positions. */
|
||||
uint32_t position[SPA_AUDIO_MAX_CHANNELS]; /*< channel position from enum spa_audio_channel */
|
||||
/* padding follows here when channels > SPA_AUDIO_MAX_CHANNELS */
|
||||
};
|
||||
|
||||
#define SPA_AUDIO_INFO_RAW_INIT(...) ((struct spa_audio_info_raw) { __VA_ARGS__ })
|
||||
|
||||
#define SPA_AUDIO_INFO_RAW_MAX_POSITION(size) (((size)-offsetof(struct spa_audio_info_raw,position))/sizeof(uint32_t))
|
||||
|
||||
#define SPA_AUDIO_INFO_RAW_VALID_SIZE(size) ((size) >= offsetof(struct spa_audio_info_raw, position))
|
||||
|
||||
|
||||
#define SPA_KEY_AUDIO_FORMAT "audio.format" /**< an audio format as string,
|
||||
* Ex. "S16LE" */
|
||||
#define SPA_KEY_AUDIO_CHANNEL "audio.channel" /**< an audio channel as string,
|
||||
|
|
|
|||
|
|
@ -54,6 +54,15 @@ SPA_API_JSON void spa_json_init(struct spa_json * iter, const char *data, size_t
|
|||
{
|
||||
*iter = SPA_JSON_INIT(data, size);
|
||||
}
|
||||
|
||||
#define SPA_JSON_INIT_RELAX(type,data,size) \
|
||||
((struct spa_json) { (data), (data)+(size), NULL, (uint32_t)((type) == '[' ? 0x10 : 0x0), 0 })
|
||||
|
||||
SPA_API_JSON void spa_json_init_relax(struct spa_json * iter, char type, const char *data, size_t size)
|
||||
{
|
||||
*iter = SPA_JSON_INIT_RELAX(type, data, size);
|
||||
}
|
||||
|
||||
#define SPA_JSON_ENTER(iter) ((struct spa_json) { (iter)->cur, (iter)->end, (iter), (iter)->state & 0xff0, 0 })
|
||||
|
||||
SPA_API_JSON void spa_json_enter(struct spa_json * iter, struct spa_json * sub)
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ SPA_API_JSON_UTILS int spa_json_begin_container(struct spa_json * iter,
|
|||
spa_json_init(iter, data, size);
|
||||
res = spa_json_enter_container(iter, iter, type);
|
||||
if (res == -EPROTO && relax)
|
||||
spa_json_init(iter, data, size);
|
||||
spa_json_init_relax(iter, type, data, size);
|
||||
else if (res <= 0)
|
||||
return res;
|
||||
return 1;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
|
||||
#undef SPA_AUDIO_MAX_CHANNELS
|
||||
|
||||
#define SPA_API_IMPL SPA_EXPORT
|
||||
#include <spa/utils/defs.h>
|
||||
#include <spa/buffer/alloc.h>
|
||||
|
|
@ -165,9 +167,3 @@
|
|||
#include <spa/utils/string.h>
|
||||
#include <spa/utils/type.h>
|
||||
#include <spa/utils/type-info.h>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -245,7 +245,7 @@ static void init_device(pa_card *impl, pa_alsa_device *dev, pa_alsa_direction_t
|
|||
pa_proplist_update(dev->proplist, PA_UPDATE_REPLACE, m->input_proplist);
|
||||
}
|
||||
if (m->split) {
|
||||
char pos[2048];
|
||||
char pos[PA_CHANNELS_MAX*8];
|
||||
struct spa_strbuf b;
|
||||
int i;
|
||||
|
||||
|
|
@ -1142,8 +1142,9 @@ static int hdmi_eld_changed(snd_mixer_elem_t *melem, unsigned int mask)
|
|||
pa_proplist_unset(p->proplist, ACP_KEY_AUDIO_POSITION_DETECTED);
|
||||
} else {
|
||||
uint32_t positions[eld.lpcm_channels];
|
||||
char position[64];
|
||||
int i = 0, pos = 0;
|
||||
char position[eld.lpcm_channels * 8];
|
||||
struct spa_strbuf b;
|
||||
int i = 0;
|
||||
|
||||
if (eld.speakers & 0x01) {
|
||||
positions[i++] = ACP_CHANNEL_FL;
|
||||
|
|
@ -1172,16 +1173,14 @@ static int hdmi_eld_changed(snd_mixer_elem_t *melem, unsigned int mask)
|
|||
if (eld.speakers & 0x10) {
|
||||
positions[i++] = ACP_CHANNEL_RC;
|
||||
}
|
||||
|
||||
while (i < eld.lpcm_channels)
|
||||
positions[i++] = ACP_CHANNEL_UNKNOWN;
|
||||
|
||||
for (i = 0, pos = 0; i < eld.lpcm_channels; i++) {
|
||||
pos += snprintf(&position[pos], sizeof(position) - pos, "%s,", channel_names[positions[i]]);
|
||||
}
|
||||
|
||||
/* Overwrite trailing , */
|
||||
position[pos - 1] = 0;
|
||||
spa_strbuf_init(&b, position, sizeof(position));
|
||||
spa_strbuf_append(&b, "[");
|
||||
for (i = 0; i < eld.lpcm_channels; i++)
|
||||
spa_strbuf_append(&b, "%s%s", i ? "," : "", channel_names[positions[i]]);
|
||||
spa_strbuf_append(&b, "]");
|
||||
|
||||
changed |= (old_position == NULL) || (!spa_streq(old_position, position));
|
||||
pa_proplist_sets(p->proplist, ACP_KEY_AUDIO_POSITION_DETECTED, position);
|
||||
|
|
|
|||
|
|
@ -27,7 +27,11 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef SPA_AUDIO_MAX_CHANNELS
|
||||
#define PA_CHANNELS_MAX ((int)SPA_AUDIO_MAX_CHANNELS)
|
||||
#else
|
||||
#define PA_CHANNELS_MAX 64
|
||||
#endif
|
||||
|
||||
#define PA_CHANNEL_MAP_SNPRINT_MAX (PA_CHANNELS_MAX * 32)
|
||||
|
||||
|
|
@ -451,7 +455,6 @@ static inline int pa_channel_map_equal(const pa_channel_map *a, const pa_channel
|
|||
|
||||
static inline char* pa_channel_map_snprint(char *s, size_t l, const pa_channel_map *map) {
|
||||
unsigned channel;
|
||||
bool first = true;
|
||||
char *e;
|
||||
if (!pa_channel_map_valid(map)) {
|
||||
pa_snprintf(s, l, "%s", _("(invalid)"));
|
||||
|
|
@ -460,12 +463,10 @@ static inline char* pa_channel_map_snprint(char *s, size_t l, const pa_channel_m
|
|||
*(e = s) = 0;
|
||||
for (channel = 0; channel < map->channels && l > 1; channel++) {
|
||||
l -= pa_snprintf(e, l, "%s%s",
|
||||
first ? "" : ",",
|
||||
channel == 0 ? "" : ",",
|
||||
pa_channel_position_to_string(map->map[channel]));
|
||||
e = strchr(e, 0);
|
||||
first = false;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@
|
|||
extern struct spa_i18n *acp_i18n;
|
||||
|
||||
#define MAX_POLL 16
|
||||
#define MAX_CHANNELS SPA_AUDIO_MAX_CHANNELS
|
||||
|
||||
#define DEFAULT_DEVICE "hw:0"
|
||||
#define DEFAULT_AUTO_PROFILE true
|
||||
|
|
@ -155,12 +156,13 @@ static int emit_node(struct impl *this, struct acp_device *dev)
|
|||
const struct acp_dict_item *it;
|
||||
uint32_t n_items, i;
|
||||
char device_name[128], path[210], channels[16], ch[12], routes[16];
|
||||
char card_index[16], card_name[64], *p;
|
||||
char positions[SPA_AUDIO_MAX_CHANNELS * 12];
|
||||
char card_index[16], card_name[64];
|
||||
char positions[MAX_CHANNELS * 12];
|
||||
char codecs[512];
|
||||
struct spa_device_object_info info;
|
||||
struct acp_card *card = this->card;
|
||||
const char *stream, *card_id, *bus;
|
||||
struct spa_strbuf b;
|
||||
|
||||
info = SPA_DEVICE_OBJECT_INFO_INIT();
|
||||
info.type = SPA_TYPE_INTERFACE_Node;
|
||||
|
|
@ -199,11 +201,13 @@ static int emit_node(struct impl *this, struct acp_device *dev)
|
|||
snprintf(channels, sizeof(channels), "%d", dev->format.channels);
|
||||
items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_AUDIO_CHANNELS, channels);
|
||||
|
||||
p = positions;
|
||||
spa_strbuf_init(&b, positions, sizeof(positions));
|
||||
spa_strbuf_append(&b, "[");
|
||||
for (i = 0; i < dev->format.channels; i++) {
|
||||
p += snprintf(p, 12, "%s%s", i == 0 ? "" : ",",
|
||||
spa_strbuf_append(&b, "%s%s", i == 0 ? " " : ", ",
|
||||
acp_channel_str(ch, sizeof(ch), dev->format.map[i]));
|
||||
}
|
||||
spa_strbuf_append(&b, " ]");
|
||||
items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_AUDIO_POSITION, positions);
|
||||
|
||||
if (dev->n_codecs > 0) {
|
||||
|
|
@ -673,8 +677,8 @@ static int apply_device_props(struct impl *this, struct acp_device *dev, struct
|
|||
struct spa_pod_prop *prop;
|
||||
struct spa_pod_object *obj = (struct spa_pod_object *) props;
|
||||
int changed = 0;
|
||||
float volumes[SPA_AUDIO_MAX_CHANNELS];
|
||||
uint32_t channels[SPA_AUDIO_MAX_CHANNELS];
|
||||
float volumes[MAX_CHANNELS];
|
||||
uint32_t channels[MAX_CHANNELS];
|
||||
uint32_t n_volumes = 0;
|
||||
|
||||
if (!spa_pod_is_object_type(props, SPA_TYPE_OBJECT_Props))
|
||||
|
|
@ -696,13 +700,13 @@ static int apply_device_props(struct impl *this, struct acp_device *dev, struct
|
|||
break;
|
||||
case SPA_PROP_channelVolumes:
|
||||
if ((n_volumes = spa_pod_copy_array(&prop->value, SPA_TYPE_Float,
|
||||
volumes, SPA_AUDIO_MAX_CHANNELS)) > 0) {
|
||||
volumes, SPA_N_ELEMENTS(volumes))) > 0) {
|
||||
changed++;
|
||||
}
|
||||
break;
|
||||
case SPA_PROP_channelMap:
|
||||
if (spa_pod_copy_array(&prop->value, SPA_TYPE_Id,
|
||||
channels, SPA_AUDIO_MAX_CHANNELS) > 0) {
|
||||
channels, SPA_N_ELEMENTS(channels)) > 0) {
|
||||
changed++;
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -163,10 +163,10 @@ static int alsa_set_param(struct state *state, const char *k, const char *s)
|
|||
int fmt_change = 0;
|
||||
if (spa_streq(k, SPA_KEY_AUDIO_CHANNELS)) {
|
||||
state->default_channels = atoi(s);
|
||||
if (state->default_channels > SPA_AUDIO_MAX_CHANNELS) {
|
||||
if (state->default_channels > MAX_CHANNELS) {
|
||||
spa_log_warn(state->log, "%p: %s: %s > %d, clamping",
|
||||
state, k, s, SPA_AUDIO_MAX_CHANNELS);
|
||||
state->default_channels = SPA_AUDIO_MAX_CHANNELS;
|
||||
state, k, s, MAX_CHANNELS);
|
||||
state->default_channels = MAX_CHANNELS;
|
||||
}
|
||||
fmt_change++;
|
||||
} else if (spa_streq(k, SPA_KEY_AUDIO_RATE)) {
|
||||
|
|
@ -240,35 +240,33 @@ static int alsa_set_param(struct state *state, const char *k, const char *s)
|
|||
|
||||
static int position_to_string(struct channel_map *map, char *val, size_t len)
|
||||
{
|
||||
uint32_t i, o = 0;
|
||||
int r;
|
||||
o += snprintf(val, len, "[ ");
|
||||
for (i = 0; i < map->channels; i++) {
|
||||
r = snprintf(val+o, len-o, "%s%s", i == 0 ? "" : ", ",
|
||||
spa_debug_type_find_short_name(spa_type_audio_channel,
|
||||
map->pos[i]));
|
||||
if (r < 0 || o + r >= len)
|
||||
return -ENOSPC;
|
||||
o += r;
|
||||
uint32_t i;
|
||||
char pos[8];
|
||||
struct spa_strbuf b;
|
||||
|
||||
spa_strbuf_init(&b, val, len);
|
||||
spa_strbuf_append(&b, "[");
|
||||
for (i = 0; i < map->n_pos; i++) {
|
||||
spa_strbuf_append(&b, "%s%s", i == 0 ? " " : ", ",
|
||||
spa_type_audio_channel_make_short_name(map->pos[i],
|
||||
pos, sizeof(pos), "UNK"));
|
||||
}
|
||||
if (len > o)
|
||||
o += snprintf(val+o, len-o, " ]");
|
||||
if (spa_strbuf_append(&b, " ]") < 2)
|
||||
return -ENOSPC;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uint32_array_to_string(uint32_t *vals, uint32_t n_vals, char *val, size_t len)
|
||||
{
|
||||
uint32_t i, o = 0;
|
||||
int r;
|
||||
o += snprintf(val, len, "[ ");
|
||||
for (i = 0; i < n_vals; i++) {
|
||||
r = snprintf(val+o, len-o, "%s%d", i == 0 ? "" : ", ", vals[i]);
|
||||
if (r < 0 || o + r >= len)
|
||||
return -ENOSPC;
|
||||
o += r;
|
||||
}
|
||||
if (len > o)
|
||||
o += snprintf(val+o, len-o, " ]");
|
||||
uint32_t i;
|
||||
struct spa_strbuf b;
|
||||
|
||||
spa_strbuf_init(&b, val, len);
|
||||
spa_strbuf_append(&b, "[");
|
||||
for (i = 0; i < n_vals; i++)
|
||||
spa_strbuf_append(&b, "%s%d", i == 0 ? " " : ", ", vals[i]);
|
||||
if (spa_strbuf_append(&b, " ]") < 2)
|
||||
return -ENOSPC;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -775,7 +773,7 @@ static void bind_ctl_event(struct spa_source *source)
|
|||
snd_ctl_elem_id_alloca(&bound_id);
|
||||
snd_ctl_elem_value_alloca(&old_value);
|
||||
|
||||
while ((err = snd_ctl_read(state->ctl, ev) > 0)) {
|
||||
while ((err = snd_ctl_read(state->ctl, ev)) > 0) {
|
||||
bool changed = false;
|
||||
|
||||
if (snd_ctl_event_get_type(ev) != SND_CTL_EVENT_ELEM)
|
||||
|
|
@ -1584,8 +1582,8 @@ static int add_channels(struct state *state, bool all, uint32_t index, uint32_t
|
|||
spa_log_debug(state->log, "channels (%d %d) default:%d all:%d",
|
||||
min, max, state->default_channels, all);
|
||||
|
||||
min = SPA_MIN(min, SPA_AUDIO_MAX_CHANNELS);
|
||||
max = SPA_MIN(max, SPA_AUDIO_MAX_CHANNELS);
|
||||
min = SPA_MIN(min, MAX_CHANNELS);
|
||||
max = SPA_MIN(max, MAX_CHANNELS);
|
||||
|
||||
if (state->default_channels != 0 && !all) {
|
||||
if (min > state->default_channels ||
|
||||
|
|
@ -1645,7 +1643,7 @@ skip_channels:
|
|||
} else {
|
||||
const struct channel_map *map = NULL;
|
||||
spa_pod_builder_int(b, min);
|
||||
if (state->default_pos.channels == min) {
|
||||
if (state->default_pos.n_pos == min) {
|
||||
map = &state->default_pos;
|
||||
spa_log_debug(state->log, "%p: using provided default", state);
|
||||
} else if (min <= 8) {
|
||||
|
|
@ -1655,7 +1653,7 @@ skip_channels:
|
|||
if (map) {
|
||||
spa_pod_builder_prop(b, SPA_FORMAT_AUDIO_position, 0);
|
||||
spa_pod_builder_push_array(b, &f[0]);
|
||||
for (i = 0; i < map->channels; i++) {
|
||||
for (i = 0; i < map->n_pos; i++) {
|
||||
spa_log_debug(state->log, "%p: position %zd %d", state, i, map->pos[i]);
|
||||
spa_pod_builder_id(b, map->pos[i]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
#define MAX_RATES 16
|
||||
#define MAX_CHANNELS SPA_AUDIO_MAX_CHANNELS
|
||||
|
||||
#define DEFAULT_PERIOD 1024u
|
||||
#define DEFAULT_RATE 48000u
|
||||
|
|
@ -71,8 +72,8 @@ struct buffer {
|
|||
#define BW_PERIOD (3 * SPA_NSEC_PER_SEC)
|
||||
|
||||
struct channel_map {
|
||||
uint32_t channels;
|
||||
uint32_t pos[SPA_AUDIO_MAX_CHANNELS];
|
||||
uint32_t n_pos;
|
||||
uint32_t pos[MAX_CHANNELS];
|
||||
};
|
||||
|
||||
struct card {
|
||||
|
|
@ -314,7 +315,7 @@ void spa_alsa_emit_port_info(struct state *state, bool full);
|
|||
|
||||
static inline void spa_alsa_parse_position(struct channel_map *map, const char *val, size_t len)
|
||||
{
|
||||
spa_audio_parse_position(val, len, map->pos, &map->channels);
|
||||
spa_audio_parse_position_n(val, len, map->pos, SPA_N_ELEMENTS(map->pos), &map->n_pos);
|
||||
}
|
||||
|
||||
static inline uint32_t spa_alsa_parse_rates(uint32_t *rates, uint32_t max, const char *val, size_t len)
|
||||
|
|
|
|||
|
|
@ -808,6 +808,7 @@ static int impl_node_set_param(void *object, uint32_t id, uint32_t flags,
|
|||
if (spa_format_audio_parse(param, &info) < 0) {
|
||||
spa_log_error(this->log, "%p: cannot set Format param: "
|
||||
"parsing the POD failed", this);
|
||||
spa_debug_log_pod(this->log, SPA_LOG_LEVEL_ERROR, 0, NULL, param);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (info.media_subtype != SPA_MEDIA_SUBTYPE_raw) {
|
||||
|
|
@ -841,6 +842,7 @@ static int impl_node_set_param(void *object, uint32_t id, uint32_t flags,
|
|||
SPA_PARAM_PORT_CONFIG_format, SPA_POD_OPT_Pod(&format)) < 0) {
|
||||
spa_log_error(this->log, "%p: cannot set PortConfig param: "
|
||||
"parsing the POD failed", this);
|
||||
spa_debug_log_pod(this->log, SPA_LOG_LEVEL_ERROR, 0, NULL, param);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
@ -848,8 +850,12 @@ static int impl_node_set_param(void *object, uint32_t id, uint32_t flags,
|
|||
struct spa_audio_info info;
|
||||
|
||||
spa_zero(info);
|
||||
if ((res = spa_format_audio_parse(format, &info)) < 0)
|
||||
if ((res = spa_format_audio_parse(format, &info)) < 0) {
|
||||
spa_log_error(this->log, "%p: cannot set PortConfig param: "
|
||||
"parsing format failed: %s", this, spa_strerror(res));
|
||||
spa_debug_log_pod(this->log, SPA_LOG_LEVEL_ERROR, 0, NULL, format);
|
||||
return res;
|
||||
}
|
||||
|
||||
if (info.media_subtype == SPA_MEDIA_SUBTYPE_raw) {
|
||||
info.info.raw.rate = 0;
|
||||
|
|
@ -2046,11 +2052,12 @@ static int do_auto_port_config(struct impl *this, const char *str)
|
|||
return -ENOENT;
|
||||
|
||||
if (format.media_subtype == SPA_MEDIA_SUBTYPE_raw) {
|
||||
uint32_t n_pos = SPA_MIN(SPA_N_ELEMENTS(format.info.raw.position), format.info.raw.channels);
|
||||
if (position == POSITION_AUX) {
|
||||
for (i = 0; i < format.info.raw.channels; i++)
|
||||
for (i = 0; i < n_pos; i++)
|
||||
format.info.raw.position[i] = SPA_AUDIO_CHANNEL_START_Aux + i;
|
||||
} else if (position == POSITION_UNKNOWN) {
|
||||
for (i = 0; i < format.info.raw.channels; i++)
|
||||
for (i = 0; i < n_pos; i++)
|
||||
format.info.raw.position[i] = SPA_AUDIO_CHANNEL_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,10 +47,11 @@ SPA_LOG_TOPIC_DEFINE_STATIC(log_topic, "spa.audioconvert");
|
|||
#define DEFAULT_RATE 48000
|
||||
#define DEFAULT_CHANNELS 2
|
||||
|
||||
#define MAX_CHANNELS SPA_AUDIO_MAX_CHANNELS
|
||||
#define MAX_ALIGN FMT_OPS_MAX_ALIGN
|
||||
#define MAX_BUFFERS 32
|
||||
#define MAX_DATAS SPA_AUDIO_MAX_CHANNELS
|
||||
#define MAX_PORTS (SPA_AUDIO_MAX_CHANNELS+1)
|
||||
#define MAX_DATAS MAX_CHANNELS
|
||||
#define MAX_PORTS (MAX_CHANNELS+1)
|
||||
#define MAX_STAGES 64
|
||||
#define MAX_GRAPH 9 /* 8 active + 1 replacement slot */
|
||||
|
||||
|
|
@ -62,7 +63,7 @@ SPA_LOG_TOPIC_DEFINE_STATIC(log_topic, "spa.audioconvert");
|
|||
struct volumes {
|
||||
bool mute;
|
||||
uint32_t n_volumes;
|
||||
float volumes[SPA_AUDIO_MAX_CHANNELS];
|
||||
float volumes[MAX_CHANNELS];
|
||||
};
|
||||
|
||||
static void init_volumes(struct volumes *vol)
|
||||
|
|
@ -70,7 +71,7 @@ static void init_volumes(struct volumes *vol)
|
|||
uint32_t i;
|
||||
vol->mute = DEFAULT_MUTE;
|
||||
vol->n_volumes = 0;
|
||||
for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++)
|
||||
for (i = 0; i < MAX_CHANNELS; i++)
|
||||
vol->volumes[i] = DEFAULT_VOLUME;
|
||||
}
|
||||
|
||||
|
|
@ -91,7 +92,7 @@ struct props {
|
|||
float max_volume;
|
||||
float prev_volume;
|
||||
uint32_t n_channels;
|
||||
uint32_t channel_map[SPA_AUDIO_MAX_CHANNELS];
|
||||
uint32_t channel_map[MAX_CHANNELS];
|
||||
struct volumes channel;
|
||||
struct volumes soft;
|
||||
struct volumes monitor;
|
||||
|
|
@ -112,7 +113,7 @@ static void props_reset(struct props *props)
|
|||
props->min_volume = DEFAULT_MIN_VOLUME;
|
||||
props->max_volume = DEFAULT_MAX_VOLUME;
|
||||
props->n_channels = 0;
|
||||
for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++)
|
||||
for (i = 0; i < MAX_CHANNELS; i++)
|
||||
props->channel_map[i] = SPA_AUDIO_CHANNEL_UNKNOWN;
|
||||
init_volumes(&props->channel);
|
||||
init_volumes(&props->soft);
|
||||
|
|
@ -241,9 +242,9 @@ struct filter_graph {
|
|||
struct spa_filter_graph *graph;
|
||||
struct spa_hook listener;
|
||||
uint32_t n_inputs;
|
||||
uint32_t inputs_position[SPA_AUDIO_MAX_CHANNELS];
|
||||
uint32_t inputs_position[MAX_CHANNELS];
|
||||
uint32_t n_outputs;
|
||||
uint32_t outputs_position[SPA_AUDIO_MAX_CHANNELS];
|
||||
uint32_t outputs_position[MAX_CHANNELS];
|
||||
uint32_t latency;
|
||||
bool removing;
|
||||
bool setup;
|
||||
|
|
@ -423,7 +424,6 @@ static int init_port(struct impl *this, enum spa_direction direction, uint32_t p
|
|||
uint32_t position, bool is_dsp, bool is_monitor, bool is_control)
|
||||
{
|
||||
struct port *port = GET_PORT(this, direction, port_id);
|
||||
const char *name;
|
||||
|
||||
spa_assert(port_id < MAX_PORTS);
|
||||
|
||||
|
|
@ -438,8 +438,7 @@ static int init_port(struct impl *this, enum spa_direction direction, uint32_t p
|
|||
port->latency[SPA_DIRECTION_INPUT] = SPA_LATENCY_INFO(SPA_DIRECTION_INPUT);
|
||||
port->latency[SPA_DIRECTION_OUTPUT] = SPA_LATENCY_INFO(SPA_DIRECTION_OUTPUT);
|
||||
|
||||
name = spa_debug_type_find_short_name(spa_type_audio_channel, position);
|
||||
snprintf(port->position, sizeof(port->position), "%s", name ? name : "UNK");
|
||||
spa_type_audio_channel_make_short_name(position, port->position, sizeof(port->position), "UNK");
|
||||
|
||||
port->info = SPA_PORT_INFO_INIT();
|
||||
port->info.change_mask = port->info_all = SPA_PORT_CHANGE_MASK_FLAGS |
|
||||
|
|
@ -1103,11 +1102,11 @@ static void graph_info(void *object, const struct spa_filter_graph_info *info)
|
|||
else if (spa_streq(k, "n_outputs"))
|
||||
spa_atou32(s, &g->n_outputs, 0);
|
||||
else if (spa_streq(k, "inputs.audio.position"))
|
||||
spa_audio_parse_position(s, strlen(s),
|
||||
g->inputs_position, &g->n_inputs);
|
||||
spa_audio_parse_position_n(s, strlen(s), g->inputs_position,
|
||||
SPA_N_ELEMENTS(g->inputs_position), &g->n_inputs);
|
||||
else if (spa_streq(k, "outputs.audio.position"))
|
||||
spa_audio_parse_position(s, strlen(s),
|
||||
g->outputs_position, &g->n_outputs);
|
||||
spa_audio_parse_position_n(s, strlen(s), g->outputs_position,
|
||||
SPA_N_ELEMENTS(g->outputs_position), &g->n_outputs);
|
||||
else if (spa_streq(k, "latency")) {
|
||||
double latency;
|
||||
if (spa_atod(s, &latency))
|
||||
|
|
@ -1539,8 +1538,6 @@ static int get_ramp_samples(struct impl *this, struct volume_ramp_params *vrp)
|
|||
samples = (vrp->volume_ramp_time * vrp->rate) / 1000;
|
||||
spa_log_info(this->log, "volume ramp samples calculated from time is %d", samples);
|
||||
}
|
||||
if (!samples)
|
||||
samples = -1;
|
||||
return samples;
|
||||
}
|
||||
|
||||
|
|
@ -1551,12 +1548,10 @@ static int get_ramp_step_samples(struct impl *this, struct volume_ramp_params *v
|
|||
if (vrp->volume_ramp_step_samples)
|
||||
samples = vrp->volume_ramp_step_samples;
|
||||
else if (vrp->volume_ramp_step_time) {
|
||||
/* convert the step time which is in nano seconds to seconds */
|
||||
samples = (vrp->volume_ramp_step_time/1000) * (vrp->rate/1000);
|
||||
/* convert the step time which is in nano seconds to seconds, round up */
|
||||
samples = SPA_MAX(1u, vrp->volume_ramp_step_time/1000) * (vrp->rate/1000);
|
||||
spa_log_debug(this->log, "volume ramp step samples calculated from time is %d", samples);
|
||||
}
|
||||
if (!samples)
|
||||
samples = -1;
|
||||
return samples;
|
||||
}
|
||||
|
||||
|
|
@ -1569,76 +1564,52 @@ static float get_volume_at_scale(struct volume_ramp_params *vrp, float value)
|
|||
return 0.0;
|
||||
}
|
||||
|
||||
static struct spa_pod *generate_ramp_up_seq(struct impl *this, struct volume_ramp_params *vrp,
|
||||
static struct spa_pod *generate_ramp_seq(struct impl *this, struct volume_ramp_params *vrp,
|
||||
void *buffer, size_t size)
|
||||
{
|
||||
struct spa_pod_dynamic_builder b;
|
||||
struct spa_pod_frame f[1];
|
||||
float start = vrp->start, end = vrp->end, volume_accum = start;
|
||||
int ramp_samples = get_ramp_samples(this, vrp);
|
||||
int ramp_step_samples = get_ramp_step_samples(this, vrp);
|
||||
float volume_step = ((end - start) / (ramp_samples / ramp_step_samples));
|
||||
uint32_t volume_offs = 0;
|
||||
float start = vrp->start, end = vrp->end;
|
||||
int samples = get_ramp_samples(this, vrp);
|
||||
int step = get_ramp_step_samples(this, vrp);
|
||||
int offs = 0;
|
||||
|
||||
if (samples < 0 || step < 0 || (samples > 0 && step == 0))
|
||||
return NULL;
|
||||
|
||||
spa_pod_dynamic_builder_init(&b, buffer, size, 4096);
|
||||
|
||||
spa_pod_builder_push_sequence(&b.b, &f[0], 0);
|
||||
spa_log_info(this->log, "generating ramp up sequence from %f to %f with a"
|
||||
" step value %f at scale %d", start, end, volume_step, vrp->scale);
|
||||
do {
|
||||
float vas = get_volume_at_scale(vrp, volume_accum);
|
||||
spa_log_trace(this->log, "volume accum %f", vas);
|
||||
spa_pod_builder_control(&b.b, volume_offs, SPA_CONTROL_Properties);
|
||||
spa_pod_builder_add_object(&b.b,
|
||||
SPA_TYPE_OBJECT_Props, 0,
|
||||
SPA_PROP_volume, SPA_POD_Float(vas));
|
||||
volume_accum += volume_step;
|
||||
volume_offs += ramp_step_samples;
|
||||
} while (volume_accum < end);
|
||||
return spa_pod_builder_pop(&b.b, &f[0]);
|
||||
}
|
||||
spa_log_info(this->log, "generating ramp sequence from %f to %f with "
|
||||
"step %d/%d at scale %d", start, end, step, samples, vrp->scale);
|
||||
|
||||
static struct spa_pod *generate_ramp_down_seq(struct impl *this, struct volume_ramp_params *vrp,
|
||||
void *buffer, size_t size)
|
||||
{
|
||||
struct spa_pod_dynamic_builder b;
|
||||
struct spa_pod_frame f[1];
|
||||
int ramp_samples = get_ramp_samples(this, vrp);
|
||||
int ramp_step_samples = get_ramp_step_samples(this, vrp);
|
||||
float start = vrp->start, end = vrp->end, volume_accum = start;
|
||||
float volume_step = ((start - end) / (ramp_samples / ramp_step_samples));
|
||||
uint32_t volume_offs = 0;
|
||||
while (1) {
|
||||
float pos = (samples == 0) ? end :
|
||||
SPA_CLAMP(start + (end - start) * offs / samples,
|
||||
SPA_MIN(start, end), SPA_MAX(start, end));
|
||||
float vas = get_volume_at_scale(vrp, pos);
|
||||
|
||||
spa_pod_dynamic_builder_init(&b, buffer, size, 4096);
|
||||
|
||||
spa_pod_builder_push_sequence(&b.b, &f[0], 0);
|
||||
spa_log_info(this->log, "generating ramp down sequence from %f to %f with a"
|
||||
" step value %f at scale %d", start, end, volume_step, vrp->scale);
|
||||
do {
|
||||
float vas = get_volume_at_scale(vrp, volume_accum);
|
||||
spa_log_trace(this->log, "volume accum %f", vas);
|
||||
spa_pod_builder_control(&b.b, volume_offs, SPA_CONTROL_Properties);
|
||||
spa_log_trace(this->log, "volume %d accum %f", offs, vas);
|
||||
spa_pod_builder_control(&b.b, offs, SPA_CONTROL_Properties);
|
||||
spa_pod_builder_add_object(&b.b,
|
||||
SPA_TYPE_OBJECT_Props, 0,
|
||||
SPA_PROP_volume, SPA_POD_Float(vas));
|
||||
|
||||
volume_accum -= volume_step;
|
||||
volume_offs += ramp_step_samples;
|
||||
} while (volume_accum > end);
|
||||
if (offs >= samples)
|
||||
break;
|
||||
|
||||
offs = SPA_MIN(samples, offs + step);
|
||||
}
|
||||
|
||||
return spa_pod_builder_pop(&b.b, &f[0]);
|
||||
}
|
||||
|
||||
static void generate_volume_ramp(struct impl *this, struct volume_ramp_params *vrp,
|
||||
void *buffer, size_t size)
|
||||
{
|
||||
void *sequence = NULL;
|
||||
if (vrp->start == vrp->end)
|
||||
spa_log_error(this->log, "no change in volume, cannot ramp volume");
|
||||
else if (vrp->end > vrp->start)
|
||||
sequence = generate_ramp_up_seq(this, vrp, buffer, size);
|
||||
else
|
||||
sequence = generate_ramp_down_seq(this, vrp, buffer, size);
|
||||
void *sequence;
|
||||
|
||||
sequence = generate_ramp_seq(this, vrp, buffer, size);
|
||||
if (!sequence)
|
||||
spa_log_error(this->log, "unable to generate sequence");
|
||||
|
||||
|
|
@ -1748,7 +1719,7 @@ static int apply_props(struct impl *this, const struct spa_pod *param)
|
|||
case SPA_PROP_channelVolumes:
|
||||
if (!p->lock_volumes &&
|
||||
(n = spa_pod_copy_array(&prop->value, SPA_TYPE_Float,
|
||||
p->channel.volumes, SPA_AUDIO_MAX_CHANNELS)) > 0) {
|
||||
p->channel.volumes, SPA_N_ELEMENTS(p->channel.volumes))) > 0) {
|
||||
have_channel_volume = true;
|
||||
p->channel.n_volumes = n;
|
||||
changed++;
|
||||
|
|
@ -1756,7 +1727,7 @@ static int apply_props(struct impl *this, const struct spa_pod *param)
|
|||
break;
|
||||
case SPA_PROP_channelMap:
|
||||
if ((n = spa_pod_copy_array(&prop->value, SPA_TYPE_Id,
|
||||
p->channel_map, SPA_AUDIO_MAX_CHANNELS)) > 0) {
|
||||
p->channel_map, SPA_N_ELEMENTS(p->channel_map))) > 0) {
|
||||
p->n_channels = n;
|
||||
changed++;
|
||||
}
|
||||
|
|
@ -1771,7 +1742,7 @@ static int apply_props(struct impl *this, const struct spa_pod *param)
|
|||
case SPA_PROP_softVolumes:
|
||||
if (!p->lock_volumes &&
|
||||
(n = spa_pod_copy_array(&prop->value, SPA_TYPE_Float,
|
||||
p->soft.volumes, SPA_AUDIO_MAX_CHANNELS)) > 0) {
|
||||
p->soft.volumes, SPA_N_ELEMENTS(p->soft.volumes))) > 0) {
|
||||
have_soft_volume = true;
|
||||
p->soft.n_volumes = n;
|
||||
changed++;
|
||||
|
|
@ -1783,7 +1754,7 @@ static int apply_props(struct impl *this, const struct spa_pod *param)
|
|||
break;
|
||||
case SPA_PROP_monitorVolumes:
|
||||
if ((n = spa_pod_copy_array(&prop->value, SPA_TYPE_Float,
|
||||
p->monitor.volumes, SPA_AUDIO_MAX_CHANNELS)) > 0) {
|
||||
p->monitor.volumes, SPA_N_ELEMENTS(p->monitor.volumes))) > 0) {
|
||||
p->monitor.n_volumes = n;
|
||||
changed++;
|
||||
}
|
||||
|
|
@ -1895,10 +1866,11 @@ static int reconfigure_mode(struct impl *this, enum spa_param_port_config_mode m
|
|||
this->dir[SPA_DIRECTION_OUTPUT].n_ports = dir->n_ports + 1;
|
||||
|
||||
for (i = 0; i < dir->n_ports; i++) {
|
||||
init_port(this, direction, i, info->info.raw.position[i], true, false, false);
|
||||
uint32_t pos = info->info.raw.position[i];
|
||||
init_port(this, direction, i, pos, true, false, false);
|
||||
if (this->monitor && direction == SPA_DIRECTION_INPUT)
|
||||
init_port(this, SPA_DIRECTION_OUTPUT, i+1,
|
||||
info->info.raw.position[i], true, true, false);
|
||||
pos, true, true, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -1966,7 +1938,7 @@ static int node_set_param_port_config(struct impl *this, uint32_t flags,
|
|||
return -EINVAL;
|
||||
|
||||
if (info.info.raw.channels == 0 ||
|
||||
info.info.raw.channels > SPA_AUDIO_MAX_CHANNELS)
|
||||
info.info.raw.channels > MAX_CHANNELS)
|
||||
return -EINVAL;
|
||||
|
||||
infop = &info;
|
||||
|
|
@ -2056,22 +2028,24 @@ static int setup_in_convert(struct impl *this)
|
|||
dst_info.info.raw.rate);
|
||||
|
||||
qsort(dst_info.info.raw.position, dst_info.info.raw.channels,
|
||||
sizeof(uint32_t), int32_cmp);
|
||||
sizeof(uint32_t), int32_cmp);
|
||||
|
||||
for (i = 0; i < src_info.info.raw.channels; i++) {
|
||||
for (j = 0; j < dst_info.info.raw.channels; j++) {
|
||||
if (src_info.info.raw.position[i] !=
|
||||
dst_info.info.raw.position[j])
|
||||
uint32_t pi, pj;
|
||||
char b1[8], b2[8];
|
||||
|
||||
pi = src_info.info.raw.position[i];
|
||||
pj = dst_info.info.raw.position[j];
|
||||
if (pi != pj)
|
||||
continue;
|
||||
in->remap[i] = j;
|
||||
if (i != j)
|
||||
remap = true;
|
||||
spa_log_debug(this->log, "%p: channel %d (%d) -> %d (%s -> %s)", this,
|
||||
i, in->remap[i], j,
|
||||
spa_debug_type_find_short_name(spa_type_audio_channel,
|
||||
src_info.info.raw.position[i]),
|
||||
spa_debug_type_find_short_name(spa_type_audio_channel,
|
||||
dst_info.info.raw.position[j]));
|
||||
spa_type_audio_channel_make_short_name(pi, b1, 8, "UNK"),
|
||||
spa_type_audio_channel_make_short_name(pj, b2, 8, "UNK"));
|
||||
dst_info.info.raw.position[j] = -1;
|
||||
break;
|
||||
}
|
||||
|
|
@ -2120,9 +2094,10 @@ static int remap_volumes(struct impl *this, const struct spa_audio_info *info)
|
|||
|
||||
for (i = 0; i < p->n_channels; i++) {
|
||||
for (j = i; j < target; j++) {
|
||||
uint32_t pj = info->info.raw.position[j];
|
||||
spa_log_debug(this->log, "%d %d: %d <-> %d", i, j,
|
||||
p->channel_map[i], info->info.raw.position[j]);
|
||||
if (p->channel_map[i] != info->info.raw.position[j])
|
||||
p->channel_map[i], pj);
|
||||
if (p->channel_map[i] != pj)
|
||||
continue;
|
||||
if (i != j) {
|
||||
SPA_SWAP(p->channel_map[i], p->channel_map[j]);
|
||||
|
|
@ -2153,7 +2128,7 @@ static void set_volume(struct impl *this)
|
|||
{
|
||||
struct volumes *vol;
|
||||
uint32_t i;
|
||||
float volumes[SPA_AUDIO_MAX_CHANNELS];
|
||||
float volumes[MAX_CHANNELS];
|
||||
struct dir *dir = &this->dir[this->direction];
|
||||
|
||||
spa_log_debug(this->log, "%p set volume %f have_format:%d", this, this->props.volume, dir->have_format);
|
||||
|
|
@ -2184,10 +2159,11 @@ static void set_volume(struct impl *this)
|
|||
static char *format_position(char *str, size_t len, uint32_t channels, uint32_t *position)
|
||||
{
|
||||
uint32_t i, idx = 0;
|
||||
char buf[8];
|
||||
for (i = 0; i < channels; i++)
|
||||
idx += snprintf(str + idx, len - idx, "%s%s", i == 0 ? "" : " ",
|
||||
spa_debug_type_find_short_name(spa_type_audio_channel,
|
||||
position[i]));
|
||||
spa_type_audio_channel_make_short_name(position[i],
|
||||
buf, sizeof(buf), "UNK"));
|
||||
return str;
|
||||
}
|
||||
|
||||
|
|
@ -2344,12 +2320,16 @@ static int setup_out_convert(struct impl *this)
|
|||
dst_info.info.raw.rate);
|
||||
|
||||
qsort(src_info.info.raw.position, src_info.info.raw.channels,
|
||||
sizeof(uint32_t), int32_cmp);
|
||||
sizeof(uint32_t), int32_cmp);
|
||||
|
||||
for (i = 0; i < src_info.info.raw.channels; i++) {
|
||||
for (j = 0; j < dst_info.info.raw.channels; j++) {
|
||||
if (src_info.info.raw.position[i] !=
|
||||
dst_info.info.raw.position[j])
|
||||
uint32_t pi, pj;
|
||||
char b1[8], b2[8];
|
||||
|
||||
pi = src_info.info.raw.position[i];
|
||||
pj = dst_info.info.raw.position[j];
|
||||
if (pi != pj)
|
||||
continue;
|
||||
out->remap[i] = j;
|
||||
if (i != j)
|
||||
|
|
@ -2357,10 +2337,9 @@ static int setup_out_convert(struct impl *this)
|
|||
|
||||
spa_log_debug(this->log, "%p: channel %d (%d) -> %d (%s -> %s)", this,
|
||||
i, out->remap[i], j,
|
||||
spa_debug_type_find_short_name(spa_type_audio_channel,
|
||||
src_info.info.raw.position[i]),
|
||||
spa_debug_type_find_short_name(spa_type_audio_channel,
|
||||
dst_info.info.raw.position[j]));
|
||||
spa_type_audio_channel_make_short_name(pi, b1, 8, "UNK"),
|
||||
spa_type_audio_channel_make_short_name(pj, b2, 8, "UNK"));
|
||||
|
||||
dst_info.info.raw.position[j] = -1;
|
||||
break;
|
||||
}
|
||||
|
|
@ -2671,7 +2650,7 @@ static int port_param_enum_formats(struct impl *impl, struct port *port, uint32_
|
|||
}
|
||||
spa_pod_builder_add(b,
|
||||
SPA_FORMAT_AUDIO_channels, SPA_POD_CHOICE_RANGE_Int(
|
||||
DEFAULT_CHANNELS, 1, SPA_AUDIO_MAX_CHANNELS),
|
||||
DEFAULT_CHANNELS, 1, MAX_CHANNELS),
|
||||
0);
|
||||
*param = spa_pod_builder_pop(b, &f[0]);
|
||||
}
|
||||
|
|
@ -3064,7 +3043,7 @@ static int port_set_format(void *object,
|
|||
if (info.info.raw.format == 0 ||
|
||||
(!this->props.resample_disabled && info.info.raw.rate == 0) ||
|
||||
info.info.raw.channels == 0 ||
|
||||
info.info.raw.channels > SPA_AUDIO_MAX_CHANNELS) {
|
||||
info.info.raw.channels > MAX_CHANNELS) {
|
||||
spa_log_error(this->log, "invalid format:%d rate:%d channels:%d",
|
||||
info.info.raw.format, info.info.raw.rate,
|
||||
info.info.raw.channels);
|
||||
|
|
@ -4296,8 +4275,9 @@ impl_init(const struct spa_handle_factory *factory,
|
|||
}
|
||||
else if (spa_streq(k, SPA_KEY_AUDIO_POSITION)) {
|
||||
if (s != NULL)
|
||||
spa_audio_parse_position(s, strlen(s), this->props.channel_map,
|
||||
&this->props.n_channels);
|
||||
spa_audio_parse_position_n(s, strlen(s),
|
||||
this->props.channel_map, SPA_N_ELEMENTS(this->props.channel_map),
|
||||
&this->props.n_channels);
|
||||
}
|
||||
else if (spa_streq(k, SPA_KEY_PORT_IGNORE_LATENCY))
|
||||
this->port_ignore_latency = spa_atob(s);
|
||||
|
|
|
|||
|
|
@ -142,29 +142,29 @@ static uint32_t mask_to_ch(struct channelmix *mix, uint64_t mask)
|
|||
}
|
||||
|
||||
static void distribute_mix(struct channelmix *mix,
|
||||
float matrix[SPA_AUDIO_MAX_CHANNELS][SPA_AUDIO_MAX_CHANNELS],
|
||||
float matrix[MAX_CHANNELS][MAX_CHANNELS],
|
||||
uint64_t mask)
|
||||
{
|
||||
uint32_t i, ch = mask_to_ch(mix, mask);
|
||||
for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++)
|
||||
for (i = 0; i < MAX_CHANNELS; i++)
|
||||
matrix[i][ch]= 1.0f;
|
||||
}
|
||||
static void average_mix(struct channelmix *mix,
|
||||
float matrix[SPA_AUDIO_MAX_CHANNELS][SPA_AUDIO_MAX_CHANNELS],
|
||||
float matrix[MAX_CHANNELS][MAX_CHANNELS],
|
||||
uint64_t mask)
|
||||
{
|
||||
uint32_t i, ch = mask_to_ch(mix, mask);
|
||||
for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++)
|
||||
for (i = 0; i < MAX_CHANNELS; i++)
|
||||
matrix[ch][i]= 1.0f;
|
||||
}
|
||||
static void pair_mix(float matrix[SPA_AUDIO_MAX_CHANNELS][SPA_AUDIO_MAX_CHANNELS])
|
||||
static void pair_mix(float matrix[MAX_CHANNELS][MAX_CHANNELS])
|
||||
{
|
||||
uint32_t i;
|
||||
for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++)
|
||||
for (i = 0; i < MAX_CHANNELS; i++)
|
||||
matrix[i][i]= 1.0f;
|
||||
}
|
||||
static bool match_mix(struct channelmix *mix,
|
||||
float matrix[SPA_AUDIO_MAX_CHANNELS][SPA_AUDIO_MAX_CHANNELS],
|
||||
float matrix[MAX_CHANNELS][MAX_CHANNELS],
|
||||
uint64_t src_mask, uint64_t dst_mask)
|
||||
{
|
||||
bool matched = false;
|
||||
|
|
@ -181,7 +181,7 @@ static bool match_mix(struct channelmix *mix,
|
|||
|
||||
static int make_matrix(struct channelmix *mix)
|
||||
{
|
||||
float matrix[SPA_AUDIO_MAX_CHANNELS][SPA_AUDIO_MAX_CHANNELS] = {{ 0.0f }};
|
||||
float matrix[MAX_CHANNELS][MAX_CHANNELS] = {{ 0.0f }};
|
||||
uint64_t src_mask = mix->src_mask, src_paired;
|
||||
uint64_t dst_mask = mix->dst_mask, dst_paired;
|
||||
uint32_t src_chan = mix->src_chan;
|
||||
|
|
@ -293,7 +293,7 @@ static int make_matrix(struct channelmix *mix)
|
|||
keep &= ~STEREO;
|
||||
} else if (dst_mask & _MASK(MONO)){
|
||||
spa_log_info(mix->log, "assign FC to MONO (%f)", 1.0f);
|
||||
for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++)
|
||||
for (i = 0; i < MAX_CHANNELS; i++)
|
||||
matrix[i][_CH(FC)]= 1.0f;
|
||||
normalize = true;
|
||||
} else {
|
||||
|
|
@ -313,7 +313,7 @@ static int make_matrix(struct channelmix *mix)
|
|||
keep &= ~FRONT;
|
||||
} else if ((dst_mask & _MASK(MONO))){
|
||||
spa_log_info(mix->log, "assign STEREO to MONO (%f)", 1.0f);
|
||||
for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++) {
|
||||
for (i = 0; i < MAX_CHANNELS; i++) {
|
||||
matrix[i][_CH(FL)]= 1.0f;
|
||||
matrix[i][_CH(FR)]= 1.0f;
|
||||
}
|
||||
|
|
@ -352,7 +352,7 @@ static int make_matrix(struct channelmix *mix)
|
|||
_MATRIX(FC,RC) += slev * SQRT1_2;
|
||||
} else if (dst_mask & _MASK(MONO)){
|
||||
spa_log_info(mix->log, "assign RC to MONO (%f)", 1.0f);
|
||||
for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++)
|
||||
for (i = 0; i < MAX_CHANNELS; i++)
|
||||
matrix[i][_CH(RC)]= 1.0f;
|
||||
normalize = true;
|
||||
} else {
|
||||
|
|
@ -398,7 +398,7 @@ static int make_matrix(struct channelmix *mix)
|
|||
_MATRIX(FC,RR)+= slev * SQRT1_2;
|
||||
} else if (dst_mask & _MASK(MONO)){
|
||||
spa_log_info(mix->log, "assign RL+RR to MONO (%f)", 1.0f);
|
||||
for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++) {
|
||||
for (i = 0; i < MAX_CHANNELS; i++) {
|
||||
matrix[i][_CH(RL)]= 1.0f;
|
||||
matrix[i][_CH(RR)]= 1.0f;
|
||||
}
|
||||
|
|
@ -450,7 +450,7 @@ static int make_matrix(struct channelmix *mix)
|
|||
_MATRIX(FC,SR) += slev * SQRT1_2;
|
||||
} else if (dst_mask & _MASK(MONO)){
|
||||
spa_log_info(mix->log, "assign SL+SR to MONO (%f)", 1.0f);
|
||||
for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++) {
|
||||
for (i = 0; i < MAX_CHANNELS; i++) {
|
||||
matrix[i][_CH(SL)]= 1.0f;
|
||||
matrix[i][_CH(SR)]= 1.0f;
|
||||
}
|
||||
|
|
@ -471,7 +471,7 @@ static int make_matrix(struct channelmix *mix)
|
|||
_MATRIX(FC,FRC)+= SQRT1_2;
|
||||
} else if (dst_mask & _MASK(MONO)){
|
||||
spa_log_info(mix->log, "assign FLC+FRC to MONO (%f)", 1.0f);
|
||||
for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++) {
|
||||
for (i = 0; i < MAX_CHANNELS; i++) {
|
||||
matrix[i][_CH(FLC)]= 1.0f;
|
||||
matrix[i][_CH(FRC)]= 1.0f;
|
||||
}
|
||||
|
|
@ -492,7 +492,7 @@ static int make_matrix(struct channelmix *mix)
|
|||
_MATRIX(FR,LFE) += llev * SQRT1_2;
|
||||
} else if ((dst_mask & _MASK(MONO))){
|
||||
spa_log_info(mix->log, "assign LFE to MONO (%f)", 1.0f);
|
||||
for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++)
|
||||
for (i = 0; i < MAX_CHANNELS; i++)
|
||||
matrix[i][_CH(LFE)]= 1.0f;
|
||||
normalize = true;
|
||||
} else {
|
||||
|
|
@ -690,7 +690,7 @@ done:
|
|||
static void impl_channelmix_set_volume(struct channelmix *mix, float volume, bool mute,
|
||||
uint32_t n_channel_volumes, float *channel_volumes)
|
||||
{
|
||||
float volumes[SPA_AUDIO_MAX_CHANNELS];
|
||||
float volumes[MAX_CHANNELS];
|
||||
float vol = mute ? 0.0f : volume, t;
|
||||
uint32_t i, j;
|
||||
uint32_t src_chan = mix->src_chan;
|
||||
|
|
@ -760,8 +760,8 @@ int channelmix_init(struct channelmix *mix)
|
|||
{
|
||||
const struct channelmix_info *info;
|
||||
|
||||
if (mix->src_chan > SPA_AUDIO_MAX_CHANNELS ||
|
||||
mix->dst_chan > SPA_AUDIO_MAX_CHANNELS)
|
||||
if (mix->src_chan > MAX_CHANNELS ||
|
||||
mix->dst_chan > MAX_CHANNELS)
|
||||
return -EINVAL;
|
||||
|
||||
info = find_channelmix_info(mix->src_chan, mix->src_mask, mix->dst_chan, mix->dst_mask,
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#define BUFFER_SIZE 4096
|
||||
#define MAX_TAPS 255u
|
||||
#define MAX_CHANNELS SPA_AUDIO_MAX_CHANNELS
|
||||
|
||||
#define CHANNELMIX_OPS_MAX_ALIGN 16
|
||||
|
||||
|
|
@ -50,8 +51,8 @@ struct channelmix {
|
|||
#define CHANNELMIX_FLAG_EQUAL (1<<2) /**< all values are equal */
|
||||
#define CHANNELMIX_FLAG_COPY (1<<3) /**< 1 on diagonal, can be nxm */
|
||||
uint32_t flags;
|
||||
float matrix_orig[SPA_AUDIO_MAX_CHANNELS][SPA_AUDIO_MAX_CHANNELS];
|
||||
float matrix[SPA_AUDIO_MAX_CHANNELS][SPA_AUDIO_MAX_CHANNELS];
|
||||
float matrix_orig[MAX_CHANNELS][MAX_CHANNELS];
|
||||
float matrix[MAX_CHANNELS][MAX_CHANNELS];
|
||||
|
||||
float freq; /* sample frequency */
|
||||
float lfe_cutoff; /* in Hz, 0 is disabled */
|
||||
|
|
@ -59,7 +60,7 @@ struct channelmix {
|
|||
float rear_delay; /* in ms, 0 is disabled */
|
||||
float widen; /* stereo widen. 0 is disabled */
|
||||
uint32_t hilbert_taps; /* to phase shift, 0 disabled */
|
||||
struct lr4 lr4[SPA_AUDIO_MAX_CHANNELS];
|
||||
struct lr4 lr4[MAX_CHANNELS];
|
||||
|
||||
float buffer_mem[2 * BUFFER_SIZE*2 + CHANNELMIX_OPS_MAX_ALIGN/4];
|
||||
float *buffer[2];
|
||||
|
|
|
|||
|
|
@ -551,7 +551,7 @@ int convert_init(struct convert *conv)
|
|||
const struct dither_info *dinfo;
|
||||
const struct noise_info *ninfo;
|
||||
const struct clear_info *cinfo;
|
||||
uint32_t i, conv_flags, data_size[3];
|
||||
uint32_t i, conv_flags, data_size[4];
|
||||
|
||||
/* we generate int32 bits of random values. With this scale
|
||||
* factor, we bring this in the [-1.0, 1.0] range */
|
||||
|
|
@ -615,15 +615,17 @@ int convert_init(struct convert *conv)
|
|||
data_size[0] = SPA_ROUND_UP(conv->noise_size * sizeof(float), FMT_OPS_MAX_ALIGN);
|
||||
data_size[1] = SPA_ROUND_UP(RANDOM_SIZE * sizeof(uint32_t), FMT_OPS_MAX_ALIGN);
|
||||
data_size[2] = SPA_ROUND_UP(RANDOM_SIZE * sizeof(int32_t), FMT_OPS_MAX_ALIGN);
|
||||
data_size[3] = SPA_ROUND_UP(conv->n_channels * sizeof(struct shaper), FMT_OPS_MAX_ALIGN);
|
||||
|
||||
conv->data = calloc(FMT_OPS_MAX_ALIGN +
|
||||
data_size[0] + data_size[1] + data_size[2], 1);
|
||||
data_size[0] + data_size[1] + data_size[2] + data_size[3], 1);
|
||||
if (conv->data == NULL)
|
||||
return -errno;
|
||||
|
||||
conv->noise = SPA_PTR_ALIGN(conv->data, FMT_OPS_MAX_ALIGN, float);
|
||||
conv->random = SPA_PTROFF(conv->noise, data_size[0], uint32_t);
|
||||
conv->prev = SPA_PTROFF(conv->random, data_size[1], int32_t);
|
||||
conv->shaper = SPA_PTROFF(conv->prev, data_size[2], struct shaper);
|
||||
|
||||
for (i = 0; i < RANDOM_SIZE; i++)
|
||||
conv->random[i] = random();
|
||||
|
|
|
|||
|
|
@ -236,7 +236,7 @@ struct convert {
|
|||
uint32_t noise_size;
|
||||
const float *ns;
|
||||
uint32_t n_ns;
|
||||
struct shaper shaper[64];
|
||||
struct shaper *shaper;
|
||||
|
||||
void (*update_noise) (struct convert *conv, float *noise, uint32_t n_samples);
|
||||
void (*process) (struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ sparesampledumpcoeffs_sources = [
|
|||
sparesampledumpcoeffs = executable(
|
||||
'spa-resample-dump-coeffs',
|
||||
sparesampledumpcoeffs_sources,
|
||||
c_args : [ cc_flags_native, '-DRESAMPLE_DISABLE_PRECOMP' ],
|
||||
c_args : [ '-DRESAMPLE_DISABLE_PRECOMP' ],
|
||||
dependencies : [ spa_dep, mathlib_native ],
|
||||
install : false,
|
||||
native : true,
|
||||
|
|
|
|||
|
|
@ -25,7 +25,8 @@ SPA_LOG_IMPL(logger);
|
|||
|
||||
extern const struct spa_handle_factory test_source_factory;
|
||||
|
||||
#define MAX_PORTS (SPA_AUDIO_MAX_CHANNELS+1)
|
||||
#define MAX_CHANNELS SPA_AUDIO_MAX_CHANNELS
|
||||
#define MAX_PORTS (MAX_CHANNELS+1)
|
||||
|
||||
struct context {
|
||||
struct spa_handle *convert_handle;
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ static int avb_set_param(struct state *state, const char *k, const char *s)
|
|||
state->default_format = spa_type_audio_format_from_short_name(s);
|
||||
fmt_change++;
|
||||
} else if (spa_streq(k, SPA_KEY_AUDIO_POSITION)) {
|
||||
spa_audio_parse_position(s, strlen(s), state->default_pos.pos,
|
||||
spa_audio_parse_position_n(s, strlen(s), state->default_pos.pos,
|
||||
SPA_N_ELEMENTS(state->default_pos.pos),
|
||||
&state->default_pos.channels);
|
||||
fmt_change++;
|
||||
} else if (spa_streq(k, SPA_KEY_AUDIO_ALLOWED_RATES)) {
|
||||
|
|
@ -85,11 +86,12 @@ static int position_to_string(struct channel_map *map, char *val, size_t len)
|
|||
{
|
||||
uint32_t i, o = 0;
|
||||
int r;
|
||||
char pos[8];
|
||||
o += snprintf(val, len, "[ ");
|
||||
for (i = 0; i < map->channels; i++) {
|
||||
r = snprintf(val+o, len-o, "%s%s", i == 0 ? "" : ", ",
|
||||
spa_debug_type_find_short_name(spa_type_audio_channel,
|
||||
map->pos[i]));
|
||||
spa_type_audio_channel_make_short_name(map->pos[i],
|
||||
pos, sizeof(pos), "UNK"));
|
||||
if (r < 0 || o + r >= len)
|
||||
return -ENOSPC;
|
||||
o += r;
|
||||
|
|
|
|||
|
|
@ -109,6 +109,7 @@ static inline char *format_streamid(char *str, size_t size, const uint64_t strea
|
|||
return str;
|
||||
}
|
||||
|
||||
#define MAX_CHANNELS SPA_AUDIO_MAX_CHANNELS
|
||||
#define MAX_BUFFERS 32
|
||||
|
||||
struct buffer {
|
||||
|
|
@ -127,7 +128,7 @@ struct buffer {
|
|||
|
||||
struct channel_map {
|
||||
uint32_t channels;
|
||||
uint32_t pos[SPA_AUDIO_MAX_CHANNELS];
|
||||
uint32_t pos[MAX_CHANNELS];
|
||||
};
|
||||
|
||||
struct port {
|
||||
|
|
|
|||
|
|
@ -200,7 +200,7 @@ static int codec_enum_config(const struct media_codec *codec, uint32_t flags,
|
|||
a2dp_aac_t conf;
|
||||
struct spa_pod_frame f[2];
|
||||
struct spa_pod_choice *choice;
|
||||
uint32_t position[SPA_AUDIO_MAX_CHANNELS];
|
||||
uint32_t position[2];
|
||||
uint32_t i = 0;
|
||||
|
||||
if (caps_size < sizeof(conf))
|
||||
|
|
|
|||
|
|
@ -205,7 +205,7 @@ static int codec_enum_config(const struct media_codec *codec, uint32_t flags,
|
|||
a2dp_aptx_t conf;
|
||||
struct spa_pod_frame f[2];
|
||||
struct spa_pod_choice *choice;
|
||||
uint32_t position[SPA_AUDIO_MAX_CHANNELS];
|
||||
uint32_t position[2];
|
||||
uint32_t i = 0;
|
||||
|
||||
if (caps_size < sizeof(conf))
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ static int codec_enum_config(const struct media_codec *codec, uint32_t flags,
|
|||
a2dp_faststream_t conf;
|
||||
struct spa_pod_frame f[2];
|
||||
struct spa_pod_choice *choice;
|
||||
uint32_t position[SPA_AUDIO_MAX_CHANNELS];
|
||||
uint32_t position[2];
|
||||
uint32_t i = 0;
|
||||
|
||||
if (caps_size < sizeof(conf))
|
||||
|
|
|
|||
|
|
@ -175,7 +175,7 @@ static int codec_enum_config(const struct media_codec *codec, uint32_t flags,
|
|||
a2dp_lc3plus_hr_t conf;
|
||||
struct spa_pod_frame f[2];
|
||||
struct spa_pod_choice *choice;
|
||||
uint32_t position[SPA_AUDIO_MAX_CHANNELS];
|
||||
uint32_t position[2];
|
||||
uint32_t i = 0;
|
||||
|
||||
if (caps_size < sizeof(conf))
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@ static int codec_enum_config(const struct media_codec *codec, uint32_t flags,
|
|||
struct spa_pod_frame f[2];
|
||||
struct spa_pod_choice *choice;
|
||||
uint32_t i = 0;
|
||||
uint32_t position[SPA_AUDIO_MAX_CHANNELS];
|
||||
uint32_t position[2];
|
||||
|
||||
if (caps_size < sizeof(conf))
|
||||
return -EINVAL;
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ static int codec_enum_config(const struct media_codec *codec, uint32_t flags,
|
|||
{
|
||||
a2dp_opus_g_t conf;
|
||||
struct spa_pod_frame f[1];
|
||||
uint32_t position[SPA_AUDIO_MAX_CHANNELS];
|
||||
uint32_t position[2];
|
||||
int channels;
|
||||
|
||||
if (caps_size < sizeof(conf))
|
||||
|
|
|
|||
|
|
@ -58,6 +58,8 @@ static struct spa_log *log;
|
|||
|
||||
#define BITRATE_DUPLEX_BIDI 160000
|
||||
|
||||
#define MAX_CHANNELS SPA_AUDIO_MAX_CHANNELS
|
||||
|
||||
#define OPUS_05_MAX_BYTES (15 * 1024)
|
||||
|
||||
struct props {
|
||||
|
|
@ -251,14 +253,8 @@ static const struct surround_encoder_mapping surround_encoders[] = {
|
|||
static uint32_t bt_channel_from_name(const char *name)
|
||||
{
|
||||
size_t i;
|
||||
enum spa_audio_channel position = SPA_AUDIO_CHANNEL_UNKNOWN;
|
||||
enum spa_audio_channel position = spa_type_audio_channel_from_short_name(name);
|
||||
|
||||
for (i = 0; spa_type_audio_channel[i].name; i++) {
|
||||
if (spa_streq(name, spa_debug_type_short_name(spa_type_audio_channel[i].name))) {
|
||||
position = spa_type_audio_channel[i].type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < SPA_N_ELEMENTS(audio_locations); i++) {
|
||||
if (position == audio_locations[i].position)
|
||||
return audio_locations[i].mask;
|
||||
|
|
@ -313,14 +309,14 @@ static void parse_settings(struct props *props, const struct spa_dict *settings)
|
|||
return;
|
||||
|
||||
if (spa_atou32(spa_dict_lookup(settings, "bluez5.a2dp.opus.pro.channels"), &v, 0))
|
||||
props->channels = SPA_CLAMP(v, 1u, SPA_AUDIO_MAX_CHANNELS);
|
||||
props->channels = SPA_CLAMP(v, 1u, MAX_CHANNELS);
|
||||
if (spa_atou32(spa_dict_lookup(settings, "bluez5.a2dp.opus.pro.max-bitrate"), &v, 0))
|
||||
props->max_bitrate = SPA_MAX(v, (uint32_t)BITRATE_MIN);
|
||||
if (spa_atou32(spa_dict_lookup(settings, "bluez5.a2dp.opus.pro.coupled-streams"), &v, 0))
|
||||
props->coupled_streams = SPA_CLAMP(v, 0u, props->channels / 2);
|
||||
|
||||
if (spa_atou32(spa_dict_lookup(settings, "bluez5.a2dp.opus.pro.bidi.channels"), &v, 0))
|
||||
props->bidi_channels = SPA_CLAMP(v, 0u, SPA_AUDIO_MAX_CHANNELS);
|
||||
props->bidi_channels = SPA_CLAMP(v, 0u, MAX_CHANNELS);
|
||||
if (spa_atou32(spa_dict_lookup(settings, "bluez5.a2dp.opus.pro.bidi.max-bitrate"), &v, 0))
|
||||
props->bidi_max_bitrate = SPA_MAX(v, (uint32_t)BITRATE_MIN);
|
||||
if (spa_atou32(spa_dict_lookup(settings, "bluez5.a2dp.opus.pro.bidi.coupled-streams"), &v, 0))
|
||||
|
|
@ -503,7 +499,7 @@ static int get_mapping(const struct media_codec *codec, const a2dp_opus_05_direc
|
|||
const uint8_t *permutation = NULL;
|
||||
size_t i, j;
|
||||
|
||||
if (channels > SPA_AUDIO_MAX_CHANNELS)
|
||||
if (channels > MAX_CHANNELS)
|
||||
return -EINVAL;
|
||||
if (2 * coupled_streams > channels)
|
||||
return -EINVAL;
|
||||
|
|
@ -542,10 +538,9 @@ static int get_mapping(const struct media_codec *codec, const a2dp_opus_05_direc
|
|||
const struct audio_location loc = audio_locations[i];
|
||||
|
||||
if (location & loc.mask) {
|
||||
if (permutation)
|
||||
positions[permutation[j++]] = loc.position;
|
||||
else
|
||||
positions[j++] = loc.position;
|
||||
uint32_t idx = permutation ? permutation[j] : j;
|
||||
positions[idx] = loc.position;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
for (i = SPA_AUDIO_CHANNEL_START_Aux; j < channels; ++i, ++j)
|
||||
|
|
@ -561,7 +556,7 @@ static int codec_fill_caps(const struct media_codec *codec, uint32_t flags,
|
|||
a2dp_opus_05_t a2dp_opus_05 = {
|
||||
.info = codec->vendor,
|
||||
.main = {
|
||||
.channels = SPA_MIN(255u, SPA_AUDIO_MAX_CHANNELS),
|
||||
.channels = SPA_MIN(255u, MAX_CHANNELS),
|
||||
.frame_duration = (OPUS_05_FRAME_DURATION_25 |
|
||||
OPUS_05_FRAME_DURATION_50 |
|
||||
OPUS_05_FRAME_DURATION_100 |
|
||||
|
|
@ -571,7 +566,7 @@ static int codec_fill_caps(const struct media_codec *codec, uint32_t flags,
|
|||
OPUS_05_INIT_BITRATE(0)
|
||||
},
|
||||
.bidi = {
|
||||
.channels = SPA_MIN(255u, SPA_AUDIO_MAX_CHANNELS),
|
||||
.channels = SPA_MIN(255u, MAX_CHANNELS),
|
||||
.frame_duration = (OPUS_05_FRAME_DURATION_25 |
|
||||
OPUS_05_FRAME_DURATION_50 |
|
||||
OPUS_05_FRAME_DURATION_100 |
|
||||
|
|
@ -771,7 +766,7 @@ static int codec_enum_config(const struct media_codec *codec, uint32_t flags,
|
|||
a2dp_opus_05_t conf;
|
||||
a2dp_opus_05_direction_t *dir;
|
||||
struct spa_pod_frame f[1];
|
||||
uint32_t position[SPA_AUDIO_MAX_CHANNELS];
|
||||
uint32_t position[MAX_CHANNELS];
|
||||
|
||||
if (caps_size < sizeof(conf))
|
||||
return -EINVAL;
|
||||
|
|
@ -835,7 +830,8 @@ static int codec_validate_config(const struct media_codec *codec, uint32_t flags
|
|||
}
|
||||
|
||||
info->info.raw.channels = dir1->channels;
|
||||
if (get_mapping(codec, dir1, surround_encoder, NULL, NULL, NULL, info->info.raw.position) < 0)
|
||||
if (get_mapping(codec, dir1, surround_encoder, NULL, NULL, NULL,
|
||||
info->info.raw.position) < 0)
|
||||
return -EINVAL;
|
||||
if (get_mapping(codec, dir2, surround_encoder, NULL, NULL, NULL, NULL) < 0)
|
||||
return -EINVAL;
|
||||
|
|
|
|||
|
|
@ -346,7 +346,7 @@ static int codec_enum_config(const struct media_codec *codec, uint32_t flags,
|
|||
struct spa_pod_frame f[2];
|
||||
struct spa_pod_choice *choice;
|
||||
uint32_t i = 0;
|
||||
uint32_t position[SPA_AUDIO_MAX_CHANNELS];
|
||||
uint32_t position[2];
|
||||
|
||||
if (caps_size < sizeof(conf))
|
||||
return -EINVAL;
|
||||
|
|
|
|||
|
|
@ -901,12 +901,12 @@ static int codec_caps_preference_cmp(const struct media_codec *codec, uint32_t f
|
|||
return conf_cmp(&conf1, res1, &conf2, res2);
|
||||
}
|
||||
|
||||
static uint8_t channels_to_positions(uint32_t channels, uint32_t *position)
|
||||
static uint8_t channels_to_positions(uint32_t channels, uint32_t *position, uint32_t max_position)
|
||||
{
|
||||
uint32_t n_channels = get_channel_count(channels);
|
||||
uint8_t n_positions = 0;
|
||||
|
||||
spa_assert(n_channels <= SPA_AUDIO_MAX_CHANNELS);
|
||||
spa_assert(n_channels <= max_position);
|
||||
|
||||
if (channels == 0) {
|
||||
position[0] = SPA_AUDIO_CHANNEL_MONO;
|
||||
|
|
@ -932,7 +932,7 @@ static int codec_enum_config(const struct media_codec *codec, uint32_t flags,
|
|||
bap_lc3_t conf;
|
||||
struct spa_pod_frame f[2];
|
||||
struct spa_pod_choice *choice;
|
||||
uint32_t position[SPA_AUDIO_MAX_CHANNELS];
|
||||
uint32_t position[LC3_MAX_CHANNELS];
|
||||
uint32_t i = 0;
|
||||
uint8_t res;
|
||||
|
||||
|
|
@ -990,7 +990,7 @@ static int codec_enum_config(const struct media_codec *codec, uint32_t flags,
|
|||
if (i == 0)
|
||||
return -EINVAL;
|
||||
|
||||
res = channels_to_positions(conf.channels, position);
|
||||
res = channels_to_positions(conf.channels, position, SPA_N_ELEMENTS(position));
|
||||
if (res == 0)
|
||||
return -EINVAL;
|
||||
spa_pod_builder_add(b,
|
||||
|
|
@ -1044,7 +1044,8 @@ static int codec_validate_config(const struct media_codec *codec, uint32_t flags
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
res = channels_to_positions(conf.channels, info->info.raw.position);
|
||||
res = channels_to_positions(conf.channels, info->info.raw.position,
|
||||
SPA_N_ELEMENTS(info->info.raw.position));
|
||||
if (res == 0)
|
||||
return -EINVAL;
|
||||
info->info.raw.channels = res;
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
#include <spa/utils/string.h>
|
||||
#include <spa/utils/json.h>
|
||||
#include <spa-private/dbus-helpers.h>
|
||||
#include <spa/param/audio/raw-utils.h>
|
||||
#include <spa/param/audio/raw-json.h>
|
||||
|
||||
#include "codec-loader.h"
|
||||
|
|
@ -5037,6 +5038,10 @@ static DBusHandlerResult endpoint_set_configuration(DBusConnection *conn,
|
|||
spa_log_error(monitor->log, "invalid transport configuration");
|
||||
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
||||
}
|
||||
if (info.info.raw.channels > MAX_CHANNELS) {
|
||||
spa_log_error(monitor->log, "too many channels in transport");
|
||||
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
||||
}
|
||||
transport->n_channels = info.info.raw.channels;
|
||||
memcpy(transport->channels, info.info.raw.position,
|
||||
transport->n_channels * sizeof(uint32_t));
|
||||
|
|
@ -6850,7 +6855,7 @@ static void parse_bap_locations(struct spa_bt_monitor *this, const struct spa_di
|
|||
const char *key, uint32_t *value)
|
||||
{
|
||||
const char *str;
|
||||
uint32_t position[SPA_AUDIO_MAX_CHANNELS];
|
||||
uint32_t position[MAX_CHANNELS];
|
||||
uint32_t n_channels;
|
||||
uint32_t locations;
|
||||
unsigned int i, j;
|
||||
|
|
@ -6861,7 +6866,8 @@ static void parse_bap_locations(struct spa_bt_monitor *this, const struct spa_di
|
|||
if (spa_atou32(str, value, 0))
|
||||
return;
|
||||
|
||||
if (!spa_audio_parse_position(str, strlen(str), position, &n_channels)) {
|
||||
if (!spa_audio_parse_position_n(str, strlen(str), position,
|
||||
SPA_N_ELEMENTS(position), &n_channels)) {
|
||||
spa_log_error(this->log, "property %s '%s' is not valid position array", key, str);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#include <spa/pod/parser.h>
|
||||
#include <spa/param/param.h>
|
||||
#include <spa/param/audio/raw.h>
|
||||
#include <spa/param/audio/raw-utils.h>
|
||||
#include <spa/param/bluetooth/audio.h>
|
||||
#include <spa/param/bluetooth/type-info.h>
|
||||
#include <spa/debug/pod.h>
|
||||
|
|
@ -38,7 +39,7 @@ SPA_LOG_TOPIC_DEFINE_STATIC(log_topic, "spa.bluez5.device");
|
|||
#undef SPA_LOG_TOPIC_DEFAULT
|
||||
#define SPA_LOG_TOPIC_DEFAULT &log_topic
|
||||
|
||||
#define MAX_NODES (2*SPA_AUDIO_MAX_CHANNELS)
|
||||
#define MAX_NODES (2*MAX_CHANNELS)
|
||||
|
||||
#define DEVICE_ID_SOURCE 0
|
||||
#define DEVICE_ID_SINK 1
|
||||
|
|
@ -99,9 +100,9 @@ struct node {
|
|||
unsigned int offload_acquired:1;
|
||||
uint32_t n_channels;
|
||||
int64_t latency_offset;
|
||||
uint32_t channels[SPA_AUDIO_MAX_CHANNELS];
|
||||
float volumes[SPA_AUDIO_MAX_CHANNELS];
|
||||
float soft_volumes[SPA_AUDIO_MAX_CHANNELS];
|
||||
uint32_t channels[MAX_CHANNELS];
|
||||
float volumes[MAX_CHANNELS];
|
||||
float soft_volumes[MAX_CHANNELS];
|
||||
};
|
||||
|
||||
struct dynamic_node
|
||||
|
|
@ -129,8 +130,8 @@ struct device_set {
|
|||
bool leader;
|
||||
uint32_t sinks;
|
||||
uint32_t sources;
|
||||
struct device_set_member sink[SPA_AUDIO_MAX_CHANNELS];
|
||||
struct device_set_member source[SPA_AUDIO_MAX_CHANNELS];
|
||||
struct device_set_member sink[MAX_CHANNELS];
|
||||
struct device_set_member source[MAX_CHANNELS];
|
||||
};
|
||||
|
||||
struct impl {
|
||||
|
|
@ -182,7 +183,7 @@ static void init_node(struct impl *this, struct node *node, uint32_t id)
|
|||
|
||||
spa_zero(*node);
|
||||
node->id = id;
|
||||
for (i = 0; i < SPA_AUDIO_MAX_CHANNELS; i++) {
|
||||
for (i = 0; i < MAX_CHANNELS; i++) {
|
||||
node->volumes[i] = 1.0f;
|
||||
node->soft_volumes[i] = 1.0f;
|
||||
}
|
||||
|
|
@ -476,6 +477,7 @@ static void get_channels(struct spa_bt_transport *t, bool a2dp_duplex, uint32_t
|
|||
*n_channels = info.info.raw.channels;
|
||||
memcpy(channels, info.info.raw.position,
|
||||
info.info.raw.channels * sizeof(uint32_t));
|
||||
|
||||
}
|
||||
|
||||
static const char *get_channel_name(uint32_t channel)
|
||||
|
|
@ -546,7 +548,7 @@ static void emit_device_set_node(struct impl *this, uint32_t id)
|
|||
if (node->channels[k] == t->channels[j])
|
||||
break;
|
||||
}
|
||||
if (k == node->n_channels && node->n_channels < SPA_AUDIO_MAX_CHANNELS)
|
||||
if (k == node->n_channels && node->n_channels < MAX_CHANNELS)
|
||||
node->channels[node->n_channels++] = t->channels[j];
|
||||
}
|
||||
}
|
||||
|
|
@ -2946,8 +2948,8 @@ static int apply_device_props(struct impl *this, struct node *node, struct spa_p
|
|||
struct spa_pod_prop *prop;
|
||||
struct spa_pod_object *obj = (struct spa_pod_object *) props;
|
||||
int changed = 0;
|
||||
float volumes[SPA_AUDIO_MAX_CHANNELS];
|
||||
uint32_t channels[SPA_AUDIO_MAX_CHANNELS];
|
||||
float volumes[MAX_CHANNELS];
|
||||
uint32_t channels[MAX_CHANNELS];
|
||||
uint32_t n_volumes = 0, SPA_UNUSED n_channels = 0;
|
||||
int64_t latency_offset = 0;
|
||||
|
||||
|
|
@ -2972,11 +2974,11 @@ static int apply_device_props(struct impl *this, struct node *node, struct spa_p
|
|||
break;
|
||||
case SPA_PROP_channelVolumes:
|
||||
n_volumes = spa_pod_copy_array(&prop->value, SPA_TYPE_Float,
|
||||
volumes, SPA_AUDIO_MAX_CHANNELS);
|
||||
volumes, SPA_N_ELEMENTS(volumes));
|
||||
break;
|
||||
case SPA_PROP_channelMap:
|
||||
n_channels = spa_pod_copy_array(&prop->value, SPA_TYPE_Id,
|
||||
channels, SPA_AUDIO_MAX_CHANNELS);
|
||||
channels, SPA_N_ELEMENTS(channels));
|
||||
break;
|
||||
case SPA_PROP_latencyOffsetNsec:
|
||||
if (spa_pod_get_long(&prop->value, &latency_offset) == 0) {
|
||||
|
|
|
|||
|
|
@ -157,6 +157,8 @@ extern "C" {
|
|||
|
||||
#define SPA_BT_NO_BATTERY ((uint8_t)255)
|
||||
|
||||
#define MAX_CHANNELS (SPA_AUDIO_MAX_CHANNELS)
|
||||
|
||||
enum spa_bt_media_direction {
|
||||
SPA_BT_MEDIA_SOURCE,
|
||||
SPA_BT_MEDIA_SINK,
|
||||
|
|
@ -678,7 +680,7 @@ struct spa_bt_transport {
|
|||
struct spa_list bap_transport_linked;
|
||||
|
||||
uint32_t n_channels;
|
||||
uint32_t channels[SPA_AUDIO_MAX_CHANNELS];
|
||||
uint32_t channels[MAX_CHANNELS];
|
||||
|
||||
struct spa_bt_transport_volume volumes[SPA_BT_VOLUME_ID_TERM];
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ static int codec_enum_config(const struct media_codec *codec, uint32_t flags,
|
|||
struct spa_pod_builder *b, struct spa_pod **param)
|
||||
{
|
||||
struct spa_pod_frame f[1];
|
||||
const uint32_t position[SPA_AUDIO_MAX_CHANNELS] = { SPA_AUDIO_CHANNEL_MONO };
|
||||
const uint32_t position[1] = { SPA_AUDIO_CHANNEL_MONO };
|
||||
const int channels = 1;
|
||||
|
||||
spa_assert(caps == NULL && caps_size == 0);
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ static int codec_enum_config(const struct media_codec *codec, uint32_t flags,
|
|||
struct spa_pod_builder *b, struct spa_pod **param)
|
||||
{
|
||||
struct spa_pod_frame f[1];
|
||||
const uint32_t position[SPA_AUDIO_MAX_CHANNELS] = { SPA_AUDIO_CHANNEL_MONO };
|
||||
const uint32_t position[1] = { SPA_AUDIO_CHANNEL_MONO };
|
||||
const int channels = 1;
|
||||
|
||||
spa_assert(caps == NULL && caps_size == 0);
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ static int codec_enum_config(const struct media_codec *codec, uint32_t flags,
|
|||
struct spa_pod_builder *b, struct spa_pod **param)
|
||||
{
|
||||
struct spa_pod_frame f[1];
|
||||
const uint32_t position[SPA_AUDIO_MAX_CHANNELS] = { SPA_AUDIO_CHANNEL_MONO };
|
||||
const uint32_t position[1] = { SPA_AUDIO_CHANNEL_MONO };
|
||||
const int channels = 1;
|
||||
|
||||
spa_assert(caps == NULL && caps_size == 0);
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ static int codec_enum_config(const struct media_codec *codec, uint32_t flags,
|
|||
struct spa_pod_builder *b, struct spa_pod **param)
|
||||
{
|
||||
struct spa_pod_frame f[1];
|
||||
const uint32_t position[SPA_AUDIO_MAX_CHANNELS] = { SPA_AUDIO_CHANNEL_MONO };
|
||||
const uint32_t position[1] = { SPA_AUDIO_CHANNEL_MONO };
|
||||
const int channels = 1;
|
||||
|
||||
spa_assert(caps == NULL && caps_size == 0);
|
||||
|
|
|
|||
|
|
@ -2139,7 +2139,7 @@ static int port_set_format(struct impl *this, struct port *port,
|
|||
|
||||
if (info.info.raw.rate == 0 ||
|
||||
info.info.raw.channels == 0 ||
|
||||
info.info.raw.channels > SPA_AUDIO_MAX_CHANNELS)
|
||||
info.info.raw.channels > MAX_CHANNELS)
|
||||
return -EINVAL;
|
||||
|
||||
if (this->transport && this->transport->iso_io) {
|
||||
|
|
|
|||
|
|
@ -1439,7 +1439,7 @@ static int port_set_format(struct impl *this, struct port *port,
|
|||
|
||||
if (info.info.raw.rate == 0 ||
|
||||
info.info.raw.channels == 0 ||
|
||||
info.info.raw.channels > SPA_AUDIO_MAX_CHANNELS)
|
||||
info.info.raw.channels > MAX_CHANNELS)
|
||||
return -EINVAL;
|
||||
|
||||
port->frame_size = info.info.raw.channels;
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@
|
|||
SPA_LOG_TOPIC_DEFINE_STATIC(log_topic, "spa.filter-graph");
|
||||
|
||||
#define MAX_HNDL 64
|
||||
#define MAX_CHANNELS SPA_AUDIO_MAX_CHANNELS
|
||||
|
||||
#define DEFAULT_RATE 48000
|
||||
|
||||
|
|
@ -154,15 +155,15 @@ struct graph_hndl {
|
|||
struct volume {
|
||||
bool mute;
|
||||
uint32_t n_volumes;
|
||||
float volumes[SPA_AUDIO_MAX_CHANNELS];
|
||||
float volumes[MAX_CHANNELS];
|
||||
|
||||
uint32_t n_ports;
|
||||
struct port *ports[SPA_AUDIO_MAX_CHANNELS];
|
||||
float min[SPA_AUDIO_MAX_CHANNELS];
|
||||
float max[SPA_AUDIO_MAX_CHANNELS];
|
||||
struct port *ports[MAX_CHANNELS];
|
||||
float min[MAX_CHANNELS];
|
||||
float max[MAX_CHANNELS];
|
||||
#define SCALE_LINEAR 0
|
||||
#define SCALE_CUBIC 1
|
||||
int scale[SPA_AUDIO_MAX_CHANNELS];
|
||||
int scale[MAX_CHANNELS];
|
||||
};
|
||||
|
||||
struct graph {
|
||||
|
|
@ -194,9 +195,9 @@ struct graph {
|
|||
|
||||
uint32_t n_inputs;
|
||||
uint32_t n_outputs;
|
||||
uint32_t inputs_position[SPA_AUDIO_MAX_CHANNELS];
|
||||
uint32_t inputs_position[MAX_CHANNELS];
|
||||
uint32_t n_inputs_position;
|
||||
uint32_t outputs_position[SPA_AUDIO_MAX_CHANNELS];
|
||||
uint32_t outputs_position[MAX_CHANNELS];
|
||||
uint32_t n_outputs_position;
|
||||
|
||||
float min_latency;
|
||||
|
|
@ -231,16 +232,18 @@ struct impl {
|
|||
float *discard_data;
|
||||
};
|
||||
|
||||
static inline void print_channels(char *buffer, size_t max_size, uint32_t n_channels, uint32_t *positions)
|
||||
static inline void print_channels(char *buffer, size_t max_size, uint32_t n_positions, uint32_t *positions)
|
||||
{
|
||||
uint32_t i;
|
||||
struct spa_strbuf buf;
|
||||
char pos[8];
|
||||
|
||||
spa_strbuf_init(&buf, buffer, max_size);
|
||||
spa_strbuf_append(&buf, "[");
|
||||
for (i = 0; i < n_channels; i++) {
|
||||
for (i = 0; i < n_positions; i++) {
|
||||
spa_strbuf_append(&buf, "%s%s", i ? "," : "",
|
||||
spa_type_audio_channel_to_short_name(positions[i]));
|
||||
spa_type_audio_channel_make_short_name(positions[i],
|
||||
pos, sizeof(pos), "UNK"));
|
||||
}
|
||||
spa_strbuf_append(&buf, "]");
|
||||
}
|
||||
|
|
@ -256,8 +259,8 @@ static void emit_filter_graph_info(struct impl *impl, bool full)
|
|||
char n_inputs[64], n_outputs[64], latency[64];
|
||||
struct spa_dict_item items[6];
|
||||
struct spa_dict dict = SPA_DICT(items, 0);
|
||||
char in_pos[SPA_AUDIO_MAX_CHANNELS * 8];
|
||||
char out_pos[SPA_AUDIO_MAX_CHANNELS * 8];
|
||||
char in_pos[MAX_CHANNELS * 8];
|
||||
char out_pos[MAX_CHANNELS * 8];
|
||||
|
||||
snprintf(n_inputs, sizeof(n_inputs), "%d", impl->graph.n_inputs);
|
||||
snprintf(n_outputs, sizeof(n_outputs), "%d", impl->graph.n_outputs);
|
||||
|
|
@ -745,10 +748,10 @@ static int impl_set_props(void *object, enum spa_direction direction, const stru
|
|||
case SPA_PROP_channelVolumes:
|
||||
{
|
||||
uint32_t i, n_vols;
|
||||
float vols[SPA_AUDIO_MAX_CHANNELS];
|
||||
float vols[MAX_CHANNELS];
|
||||
|
||||
if ((n_vols = spa_pod_copy_array(&prop->value, SPA_TYPE_Float, vols,
|
||||
SPA_AUDIO_MAX_CHANNELS)) > 0) {
|
||||
SPA_N_ELEMENTS(vols))) > 0) {
|
||||
if (vol->n_volumes != n_vols)
|
||||
do_volume = true;
|
||||
vol->n_volumes = n_vols;
|
||||
|
|
@ -772,7 +775,7 @@ static int impl_set_props(void *object, enum spa_direction direction, const stru
|
|||
}
|
||||
}
|
||||
if (do_volume && vol->n_ports != 0) {
|
||||
float soft_vols[SPA_AUDIO_MAX_CHANNELS];
|
||||
float soft_vols[MAX_CHANNELS];
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < vol->n_volumes; i++)
|
||||
|
|
@ -1264,7 +1267,7 @@ static int parse_volume(struct graph *graph, struct spa_json *json, enum spa_dir
|
|||
spa_log_error(impl->log, "unknown control port %s", control);
|
||||
return -ENOENT;
|
||||
}
|
||||
if (vol->n_ports >= SPA_AUDIO_MAX_CHANNELS) {
|
||||
if (vol->n_ports >= MAX_CHANNELS) {
|
||||
spa_log_error(impl->log, "too many volume controls");
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
|
@ -2118,8 +2121,9 @@ static int load_graph(struct graph *graph, const struct spa_dict *props)
|
|||
spa_log_error(impl->log, "%s expects an array", key);
|
||||
return -EINVAL;
|
||||
}
|
||||
spa_audio_parse_position(val, len, graph->inputs_position,
|
||||
&graph->n_inputs_position);
|
||||
spa_audio_parse_position_n(val, len, graph->inputs_position,
|
||||
SPA_N_ELEMENTS(graph->inputs_position),
|
||||
&graph->n_inputs_position);
|
||||
impl->info.n_inputs = graph->n_inputs_position;
|
||||
}
|
||||
else if (spa_streq("outputs.audio.position", key)) {
|
||||
|
|
@ -2128,8 +2132,9 @@ static int load_graph(struct graph *graph, const struct spa_dict *props)
|
|||
spa_log_error(impl->log, "%s expects an array", key);
|
||||
return -EINVAL;
|
||||
}
|
||||
spa_audio_parse_position(val, len, graph->outputs_position,
|
||||
&graph->n_outputs_position);
|
||||
spa_audio_parse_position_n(val, len, graph->outputs_position,
|
||||
SPA_N_ELEMENTS(graph->outputs_position),
|
||||
&graph->n_outputs_position);
|
||||
impl->info.n_outputs = graph->n_outputs_position;
|
||||
}
|
||||
else if (spa_streq("nodes", key)) {
|
||||
|
|
|
|||
|
|
@ -35,12 +35,13 @@
|
|||
SPA_LOG_TOPIC_DEFINE_STATIC(log_topic, "spa.null-audio-sink");
|
||||
|
||||
#define DEFAULT_CLOCK_NAME "clock.system.monotonic"
|
||||
#define MAX_CHANNELS SPA_AUDIO_MAX_CHANNELS
|
||||
|
||||
struct props {
|
||||
uint32_t format;
|
||||
uint32_t channels;
|
||||
uint32_t rate;
|
||||
uint32_t pos[SPA_AUDIO_MAX_CHANNELS];
|
||||
uint32_t pos[MAX_CHANNELS];
|
||||
char clock_name[64];
|
||||
unsigned int debug:1;
|
||||
unsigned int driver:1;
|
||||
|
|
@ -636,7 +637,7 @@ port_set_format(struct impl *this,
|
|||
|
||||
if (info.info.raw.rate == 0 ||
|
||||
info.info.raw.channels == 0 ||
|
||||
info.info.raw.channels > SPA_AUDIO_MAX_CHANNELS)
|
||||
info.info.raw.channels > MAX_CHANNELS)
|
||||
return -EINVAL;
|
||||
|
||||
if (this->props.format != 0) {
|
||||
|
|
@ -949,7 +950,8 @@ impl_init(const struct spa_handle_factory *factory,
|
|||
} else if (spa_streq(k, SPA_KEY_NODE_DRIVER)) {
|
||||
this->props.driver = spa_atob(s);
|
||||
} else if (spa_streq(k, SPA_KEY_AUDIO_POSITION)) {
|
||||
spa_audio_parse_position(s, strlen(s), this->props.pos, &this->props.channels);
|
||||
spa_audio_parse_position_n(s, strlen(s), this->props.pos,
|
||||
SPA_N_ELEMENTS(this->props.pos), &this->props.channels);
|
||||
} else if (spa_streq(k, "clock.name")) {
|
||||
spa_scnprintf(this->props.clock_name,
|
||||
sizeof(this->props.clock_name),
|
||||
|
|
|
|||
|
|
@ -454,8 +454,7 @@ static int port_set_format(void *object,
|
|||
return -EINVAL;
|
||||
|
||||
if (info.info.raw.format != SPA_AUDIO_FORMAT_S16 ||
|
||||
info.info.raw.channels == 0 ||
|
||||
info.info.raw.channels > SPA_AUDIO_MAX_CHANNELS)
|
||||
info.info.raw.channels == 0)
|
||||
return -EINVAL;
|
||||
|
||||
this->bpf = 2 * info.info.raw.channels;
|
||||
|
|
|
|||
|
|
@ -268,8 +268,7 @@ static int port_set_format(void *object,
|
|||
d->format.format != SPA_AUDIO_FORMAT_F32)
|
||||
return -EINVAL;
|
||||
if (d->format.rate == 0 ||
|
||||
d->format.channels == 0 ||
|
||||
d->format.channels > SPA_AUDIO_MAX_CHANNELS)
|
||||
d->format.channels == 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -649,7 +649,7 @@ handle_video_fields (ConvertData *d)
|
|||
static void
|
||||
set_default_channels (struct spa_pod_builder *b, uint32_t channels)
|
||||
{
|
||||
uint32_t position[SPA_AUDIO_MAX_CHANNELS] = {0};
|
||||
uint32_t position[8] = {0};
|
||||
gboolean ok = TRUE;
|
||||
|
||||
switch (channels) {
|
||||
|
|
|
|||
|
|
@ -231,9 +231,9 @@ PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME);
|
|||
"( stream.props=<properties> ) " \
|
||||
"( stream.rules=<properties> ) "
|
||||
|
||||
#define MAX_CHANNELS SPA_AUDIO_MAX_CHANNELS
|
||||
#define DELAYBUF_MAX_SIZE (20 * sizeof(float) * 96000)
|
||||
|
||||
|
||||
static const struct spa_dict_item module_props[] = {
|
||||
{ PW_KEY_MODULE_AUTHOR, "Wim Taymans <wim.taymans@gmail.com>" },
|
||||
{ PW_KEY_MODULE_DESCRIPTION, "Combine multiple streams into a single stream" },
|
||||
|
|
@ -312,10 +312,10 @@ struct stream {
|
|||
struct spa_latency_info latency;
|
||||
|
||||
struct spa_audio_info_raw info;
|
||||
uint32_t remap[SPA_AUDIO_MAX_CHANNELS];
|
||||
uint32_t remap[MAX_CHANNELS];
|
||||
|
||||
void *delaybuf;
|
||||
struct ringbuffer delay[SPA_AUDIO_MAX_CHANNELS];
|
||||
struct ringbuffer delay[MAX_CHANNELS];
|
||||
|
||||
int64_t delay_samples; /* for main loop */
|
||||
int64_t data_delay_samples; /* for data loop */
|
||||
|
|
@ -326,9 +326,9 @@ struct stream {
|
|||
unsigned int have_latency:1;
|
||||
};
|
||||
|
||||
static void parse_audio_info(const struct pw_properties *props, struct spa_audio_info_raw *info)
|
||||
static int parse_audio_info(const struct pw_properties *props, struct spa_audio_info_raw *info)
|
||||
{
|
||||
spa_audio_info_raw_init_dict_keys(info,
|
||||
return spa_audio_info_raw_init_dict_keys(info,
|
||||
&SPA_DICT_ITEMS(
|
||||
SPA_DICT_ITEM(SPA_KEY_AUDIO_FORMAT, "F32P"),
|
||||
SPA_DICT_ITEM(SPA_KEY_AUDIO_POSITION, DEFAULT_POSITION)),
|
||||
|
|
@ -509,7 +509,7 @@ static void update_latency(struct impl *impl)
|
|||
struct replace_delay_info {
|
||||
struct stream *stream;
|
||||
void *buf;
|
||||
struct ringbuffer delay[SPA_AUDIO_MAX_CHANNELS];
|
||||
struct ringbuffer delay[MAX_CHANNELS];
|
||||
};
|
||||
|
||||
static int do_replace_delay(struct spa_loop *loop, bool async, uint32_t seq,
|
||||
|
|
@ -866,13 +866,15 @@ static int create_stream(struct stream_info *info)
|
|||
|
||||
s->info = impl->info;
|
||||
if ((str = pw_properties_get(info->stream_props, SPA_KEY_AUDIO_POSITION)) != NULL)
|
||||
spa_audio_parse_position(str, strlen(str), s->info.position, &s->info.channels);
|
||||
spa_audio_parse_position_n(str, strlen(str), s->info.position,
|
||||
SPA_N_ELEMENTS(s->info.position), &s->info.channels);
|
||||
if (s->info.channels == 0)
|
||||
s->info = impl->info;
|
||||
|
||||
spa_zero(remap_info);
|
||||
if ((str = pw_properties_get(info->stream_props, "combine.audio.position")) != NULL)
|
||||
spa_audio_parse_position(str, strlen(str), remap_info.position, &remap_info.channels);
|
||||
spa_audio_parse_position_n(str, strlen(str), remap_info.position,
|
||||
SPA_N_ELEMENTS(remap_info.position), &remap_info.channels);
|
||||
if (remap_info.channels == 0)
|
||||
remap_info = s->info;
|
||||
|
||||
|
|
@ -880,7 +882,10 @@ static int create_stream(struct stream_info *info)
|
|||
for (i = 0; i < remap_info.channels; i++) {
|
||||
s->remap[i] = i;
|
||||
for (j = 0; j < tmp_info.channels; j++) {
|
||||
if (tmp_info.position[j] == remap_info.position[i]) {
|
||||
uint32_t pj, pi;
|
||||
pj = tmp_info.position[j];
|
||||
pi = remap_info.position[i];
|
||||
if (pj == pi) {
|
||||
s->remap[i] = j;
|
||||
break;
|
||||
}
|
||||
|
|
@ -1228,7 +1233,7 @@ static void combine_output_process(void *d)
|
|||
struct pw_buffer *in, *out;
|
||||
struct stream *s;
|
||||
bool delay_changed = false;
|
||||
bool mix[SPA_AUDIO_MAX_CHANNELS];
|
||||
bool mix[MAX_CHANNELS];
|
||||
|
||||
if ((out = pw_stream_dequeue_buffer(impl->combine)) == NULL) {
|
||||
pw_log_debug("%p: out of output buffers: %m", impl);
|
||||
|
|
@ -1633,7 +1638,10 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
|
|||
copy_props(props, impl->combine_props, "resample.prefill");
|
||||
copy_props(props, impl->combine_props, "resample.disable");
|
||||
|
||||
parse_audio_info(impl->combine_props, &impl->info);
|
||||
if ((res = parse_audio_info(impl->combine_props, &impl->info)) < 0) {
|
||||
pw_log_error( "can't create format: %s", spa_strerror(res));
|
||||
goto error;
|
||||
}
|
||||
|
||||
copy_props(props, impl->stream_props, PW_KEY_NODE_LOOP_NAME);
|
||||
copy_props(props, impl->stream_props, PW_KEY_NODE_GROUP);
|
||||
|
|
|
|||
|
|
@ -154,6 +154,7 @@ PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME);
|
|||
|
||||
#define DEFAULT_RATE 48000
|
||||
#define DEFAULT_POSITION "[ FL FR ]"
|
||||
#define MAX_CHANNELS SPA_AUDIO_MAX_CHANNELS
|
||||
|
||||
/* Hopefully this is enough for any combination of AEC engine and resampler
|
||||
* input requirement for rate matching */
|
||||
|
|
@ -203,7 +204,7 @@ struct impl {
|
|||
struct spa_hook source_listener;
|
||||
struct spa_audio_info_raw source_info;
|
||||
|
||||
void *rec_buffer[SPA_AUDIO_MAX_CHANNELS];
|
||||
void *rec_buffer[MAX_CHANNELS];
|
||||
uint32_t rec_ringsize;
|
||||
struct spa_ringbuffer rec_ring;
|
||||
|
||||
|
|
@ -215,21 +216,23 @@ struct impl {
|
|||
struct pw_properties *sink_props;
|
||||
struct pw_stream *sink;
|
||||
struct spa_hook sink_listener;
|
||||
void *play_buffer[SPA_AUDIO_MAX_CHANNELS];
|
||||
void *play_buffer[MAX_CHANNELS];
|
||||
uint32_t play_ringsize;
|
||||
struct spa_ringbuffer play_ring;
|
||||
struct spa_ringbuffer play_delayed_ring;
|
||||
struct spa_audio_info_raw sink_info;
|
||||
|
||||
void *out_buffer[SPA_AUDIO_MAX_CHANNELS];
|
||||
void *out_buffer[MAX_CHANNELS];
|
||||
uint32_t out_ringsize;
|
||||
struct spa_ringbuffer out_ring;
|
||||
|
||||
struct spa_audio_aec *aec;
|
||||
uint32_t aec_blocksize;
|
||||
|
||||
unsigned int capture_ready:1;
|
||||
unsigned int sink_ready:1;
|
||||
struct spa_io_position *capture_position;
|
||||
struct spa_io_position *sink_position;
|
||||
uint32_t capture_cycle;
|
||||
uint32_t sink_cycle;
|
||||
|
||||
unsigned int do_disconnect:1;
|
||||
|
||||
|
|
@ -306,13 +309,24 @@ static void process(struct impl *impl)
|
|||
const float *play_delayed[impl->play_info.channels];
|
||||
float *out[impl->out_info.channels];
|
||||
struct spa_data *dd;
|
||||
uint32_t i, size;
|
||||
uint32_t rindex, pindex, oindex, pdindex, avail;
|
||||
uint32_t i;
|
||||
uint32_t rindex, pindex, oindex, pdindex, size;
|
||||
int32_t avail, pavail, pdavail;
|
||||
|
||||
size = impl->aec_blocksize;
|
||||
|
||||
/* First read a block from the playback and capture ring buffers */
|
||||
spa_ringbuffer_get_read_index(&impl->rec_ring, &rindex);
|
||||
/* First read a block from the capture ring buffer */
|
||||
avail = spa_ringbuffer_get_read_index(&impl->rec_ring, &rindex);
|
||||
while (avail >= (int32_t)size * 2) {
|
||||
/* drop samples that are not needed this or next cycle. Note
|
||||
* that samples are kept in the ringbuffer until next cycle if
|
||||
* size is not equal to or divisible by quantum, to avoid
|
||||
* discontinuity */
|
||||
pw_log_debug("avail %d", avail);
|
||||
spa_ringbuffer_read_update(&impl->rec_ring, rindex + size);
|
||||
avail = spa_ringbuffer_get_read_index(&impl->rec_ring, &rindex);
|
||||
pw_log_debug("new avail %d, size %u", avail, size);
|
||||
}
|
||||
|
||||
for (i = 0; i < impl->rec_info.channels; i++) {
|
||||
/* captured samples, with echo from sink */
|
||||
|
|
@ -330,19 +344,34 @@ static void process(struct impl *impl)
|
|||
out[i] = &out_buf[i][0];
|
||||
}
|
||||
|
||||
spa_ringbuffer_get_read_index(&impl->play_ring, &pindex);
|
||||
spa_ringbuffer_get_read_index(&impl->play_delayed_ring, &pdindex);
|
||||
pavail = spa_ringbuffer_get_read_index(&impl->play_ring, &pindex);
|
||||
pdavail = spa_ringbuffer_get_read_index(&impl->play_delayed_ring, &pdindex);
|
||||
|
||||
if (impl->playback != NULL && (pout = pw_stream_dequeue_buffer(impl->playback)) == NULL) {
|
||||
pw_log_debug("out of playback buffers: %m");
|
||||
|
||||
/* playback stream may not yet be in streaming state, drop play
|
||||
* data to avoid introducing additional playback latency */
|
||||
spa_ringbuffer_read_update(&impl->play_ring, pindex + size);
|
||||
spa_ringbuffer_read_update(&impl->play_delayed_ring, pdindex + size);
|
||||
spa_ringbuffer_read_update(&impl->play_ring, pindex + pavail);
|
||||
spa_ringbuffer_read_update(&impl->play_delayed_ring, pdindex + pdavail);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (pavail > avail) {
|
||||
/* drop too old samples from previous graph cycles */
|
||||
pw_log_debug("pavail %d, dropping %d", pavail, pavail - avail);
|
||||
spa_ringbuffer_read_update(&impl->play_ring, pindex + pavail - avail);
|
||||
pavail = spa_ringbuffer_get_read_index(&impl->play_ring, &pindex);
|
||||
pw_log_debug("new pavail %d, avail %d", pavail, avail);
|
||||
}
|
||||
if (pdavail > avail) {
|
||||
/* drop too old samples from previous graph cycles */
|
||||
pw_log_debug("pdavail %d, dropping %d", pdavail, pdavail - avail);
|
||||
spa_ringbuffer_read_update(&impl->play_delayed_ring, pdindex + pdavail - avail);
|
||||
pdavail = spa_ringbuffer_get_read_index(&impl->play_delayed_ring, &pdindex);
|
||||
pw_log_debug("new pdavail %d, avail %d", pdavail, avail);
|
||||
}
|
||||
|
||||
for (i = 0; i < impl->play_info.channels; i++) {
|
||||
/* echo from sink */
|
||||
play[i] = &play_buf[i][0];
|
||||
|
|
@ -430,7 +459,7 @@ static void process(struct impl *impl)
|
|||
* available on the source */
|
||||
|
||||
avail = spa_ringbuffer_get_read_index(&impl->out_ring, &oindex);
|
||||
while (avail >= size) {
|
||||
while (avail >= (int32_t)size) {
|
||||
if ((cout = pw_stream_dequeue_buffer(impl->source)) != NULL) {
|
||||
for (i = 0; i < impl->out_info.channels; i++) {
|
||||
dd = &cout->buffer->datas[i];
|
||||
|
|
@ -453,8 +482,8 @@ static void process(struct impl *impl)
|
|||
}
|
||||
|
||||
done:
|
||||
impl->sink_ready = false;
|
||||
impl->capture_ready = false;
|
||||
impl->capture_cycle = 0;
|
||||
impl->sink_cycle = 0;
|
||||
}
|
||||
|
||||
static void reset_buffers(struct impl *impl)
|
||||
|
|
@ -478,8 +507,8 @@ static void reset_buffers(struct impl *impl)
|
|||
spa_ringbuffer_get_read_index(&impl->play_ring, &index);
|
||||
spa_ringbuffer_read_update(&impl->play_ring, index + (sizeof(float) * (impl->buffer_delay)));
|
||||
|
||||
impl->sink_ready = false;
|
||||
impl->capture_ready = false;
|
||||
impl->capture_cycle = 0;
|
||||
impl->sink_cycle = 0;
|
||||
}
|
||||
|
||||
static void capture_destroy(void *d)
|
||||
|
|
@ -545,8 +574,11 @@ static void capture_process(void *data)
|
|||
spa_ringbuffer_write_update(&impl->rec_ring, index + size);
|
||||
|
||||
if (avail + size >= impl->aec_blocksize) {
|
||||
impl->capture_ready = true;
|
||||
if (impl->sink_ready)
|
||||
if (impl->capture_position)
|
||||
impl->capture_cycle = impl->capture_position->clock.cycle;
|
||||
else
|
||||
pw_log_warn("no capture position");
|
||||
if (impl->capture_cycle == impl->sink_cycle)
|
||||
process(impl);
|
||||
}
|
||||
|
||||
|
|
@ -739,12 +771,26 @@ static void input_param_changed(void *data, uint32_t id, const struct spa_pod* p
|
|||
}
|
||||
}
|
||||
|
||||
static void capture_io_changed(void *data, uint32_t id, void *area, uint32_t size)
|
||||
{
|
||||
struct impl *impl = data;
|
||||
|
||||
switch (id) {
|
||||
case SPA_IO_Position:
|
||||
impl->capture_position = area;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct pw_stream_events capture_events = {
|
||||
PW_VERSION_STREAM_EVENTS,
|
||||
.destroy = capture_destroy,
|
||||
.state_changed = capture_state_changed,
|
||||
.process = capture_process,
|
||||
.param_changed = input_param_changed
|
||||
.param_changed = input_param_changed,
|
||||
.io_changed = capture_io_changed
|
||||
};
|
||||
|
||||
static void source_destroy(void *d)
|
||||
|
|
@ -929,10 +975,15 @@ static void sink_process(void *data)
|
|||
SPA_PTROFF(d->data, offs, void), size);
|
||||
}
|
||||
spa_ringbuffer_write_update(&impl->play_ring, index + size);
|
||||
spa_ringbuffer_get_write_index(&impl->play_delayed_ring, &index);
|
||||
spa_ringbuffer_write_update(&impl->play_delayed_ring, index + size);
|
||||
|
||||
if (avail + size >= impl->aec_blocksize) {
|
||||
impl->sink_ready = true;
|
||||
if (impl->capture_ready)
|
||||
if (impl->sink_position)
|
||||
impl->sink_cycle = impl->sink_position->clock.cycle;
|
||||
else
|
||||
pw_log_warn("no sink position");
|
||||
if (impl->capture_cycle == impl->sink_cycle)
|
||||
process(impl);
|
||||
}
|
||||
|
||||
|
|
@ -954,12 +1005,27 @@ static const struct pw_stream_events playback_events = {
|
|||
.state_changed = playback_state_changed,
|
||||
.param_changed = output_param_changed
|
||||
};
|
||||
|
||||
static void sink_io_changed(void *data, uint32_t id, void *area, uint32_t size)
|
||||
{
|
||||
struct impl *impl = data;
|
||||
|
||||
switch (id) {
|
||||
case SPA_IO_Position:
|
||||
impl->sink_position = area;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct pw_stream_events sink_events = {
|
||||
PW_VERSION_STREAM_EVENTS,
|
||||
.destroy = sink_destroy,
|
||||
.process = sink_process,
|
||||
.state_changed = sink_state_changed,
|
||||
.param_changed = output_param_changed
|
||||
.param_changed = output_param_changed,
|
||||
.io_changed = sink_io_changed
|
||||
};
|
||||
|
||||
#define MAX_PARAMS 512u
|
||||
|
|
@ -1202,9 +1268,9 @@ static const struct pw_impl_module_events module_events = {
|
|||
.destroy = module_destroy,
|
||||
};
|
||||
|
||||
static void parse_audio_info(struct pw_properties *props, struct spa_audio_info_raw *info)
|
||||
static int parse_audio_info(struct pw_properties *props, struct spa_audio_info_raw *info)
|
||||
{
|
||||
spa_audio_info_raw_init_dict_keys(info,
|
||||
return spa_audio_info_raw_init_dict_keys(info,
|
||||
&SPA_DICT_ITEMS(
|
||||
SPA_DICT_ITEM(SPA_KEY_AUDIO_FORMAT, "F32P"),
|
||||
SPA_DICT_ITEM(SPA_KEY_AUDIO_RATE, SPA_STRINGIFY(DEFAULT_RATE)),
|
||||
|
|
@ -1290,7 +1356,10 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
|
|||
if (pw_properties_get(props, "resample.prefill") == NULL)
|
||||
pw_properties_set(props, "resample.prefill", "true");
|
||||
|
||||
parse_audio_info(props, &info);
|
||||
if ((res = parse_audio_info(props, &info)) < 0) {
|
||||
pw_log_error( "can't parse format: %s", spa_strerror(res));
|
||||
goto error;
|
||||
}
|
||||
|
||||
impl->capture_info = info;
|
||||
impl->source_info = info;
|
||||
|
|
@ -1370,21 +1439,21 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
|
|||
}
|
||||
|
||||
if ((str = pw_properties_get(impl->capture_props, SPA_KEY_AUDIO_POSITION)) != NULL) {
|
||||
spa_audio_parse_position(str, strlen(str),
|
||||
impl->capture_info.position, &impl->capture_info.channels);
|
||||
spa_audio_parse_position_n(str, strlen(str), impl->capture_info.position,
|
||||
SPA_N_ELEMENTS(impl->capture_info.position), &impl->capture_info.channels);
|
||||
}
|
||||
if ((str = pw_properties_get(impl->source_props, SPA_KEY_AUDIO_POSITION)) != NULL) {
|
||||
spa_audio_parse_position(str, strlen(str),
|
||||
impl->source_info.position, &impl->source_info.channels);
|
||||
spa_audio_parse_position_n(str, strlen(str), impl->source_info.position,
|
||||
SPA_N_ELEMENTS(impl->source_info.position), &impl->source_info.channels);
|
||||
}
|
||||
if ((str = pw_properties_get(impl->sink_props, SPA_KEY_AUDIO_POSITION)) != NULL) {
|
||||
spa_audio_parse_position(str, strlen(str),
|
||||
impl->sink_info.position, &impl->sink_info.channels);
|
||||
spa_audio_parse_position_n(str, strlen(str), impl->sink_info.position,
|
||||
SPA_N_ELEMENTS(impl->sink_info.position), &impl->sink_info.channels);
|
||||
impl->playback_info = impl->sink_info;
|
||||
}
|
||||
if ((str = pw_properties_get(impl->playback_props, SPA_KEY_AUDIO_POSITION)) != NULL) {
|
||||
spa_audio_parse_position(str, strlen(str),
|
||||
impl->playback_info.position, &impl->playback_info.channels);
|
||||
spa_audio_parse_position_n(str, strlen(str), impl->playback_info.position,
|
||||
SPA_N_ELEMENTS(impl->playback_info.position), &impl->playback_info.channels);
|
||||
if (impl->playback_info.channels != impl->sink_info.channels)
|
||||
impl->playback_info = impl->sink_info;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -298,8 +298,7 @@ static void capture_param_changed(void *data, uint32_t id, const struct spa_pod
|
|||
if (spa_format_audio_raw_parse(param, &info) < 0)
|
||||
return;
|
||||
if (info.rate == 0 ||
|
||||
info.channels == 0 ||
|
||||
info.channels > SPA_AUDIO_MAX_CHANNELS)
|
||||
info.channels == 0)
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
|
@ -468,9 +467,9 @@ static const struct pw_impl_module_events module_events = {
|
|||
.destroy = module_destroy,
|
||||
};
|
||||
|
||||
static void parse_audio_info(struct pw_properties *props, struct spa_audio_info_raw *info)
|
||||
static int parse_audio_info(struct pw_properties *props, struct spa_audio_info_raw *info)
|
||||
{
|
||||
spa_audio_info_raw_init_dict_keys(info,
|
||||
return spa_audio_info_raw_init_dict_keys(info,
|
||||
&SPA_DICT_ITEMS(
|
||||
SPA_DICT_ITEM(SPA_KEY_AUDIO_FORMAT, "F32P"),
|
||||
SPA_DICT_ITEM(SPA_KEY_AUDIO_POSITION, DEFAULT_POSITION)),
|
||||
|
|
@ -574,8 +573,11 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
|
|||
if (pw_properties_get(impl->playback_props, PW_KEY_NODE_DESCRIPTION) == NULL)
|
||||
pw_properties_set(impl->playback_props, PW_KEY_NODE_DESCRIPTION, str);
|
||||
|
||||
parse_audio_info(impl->capture_props, &impl->capture_info);
|
||||
parse_audio_info(impl->playback_props, &impl->playback_info);
|
||||
if ((res = parse_audio_info(impl->capture_props, &impl->capture_info)) < 0 ||
|
||||
(res = parse_audio_info(impl->playback_props, &impl->playback_info)) < 0) {
|
||||
pw_log_error( "can't parse formats: %s", spa_strerror(res));
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!impl->capture_info.rate && !impl->playback_info.rate) {
|
||||
if (pw_properties_get(impl->playback_props, "resample.disable") == NULL)
|
||||
|
|
|
|||
|
|
@ -273,9 +273,9 @@ static const struct pw_impl_module_events module_events = {
|
|||
.destroy = module_destroy,
|
||||
};
|
||||
|
||||
static void parse_audio_info(const struct pw_properties *props, struct spa_audio_info_raw *info)
|
||||
static int parse_audio_info(const struct pw_properties *props, struct spa_audio_info_raw *info)
|
||||
{
|
||||
spa_audio_info_raw_init_dict_keys(info,
|
||||
return spa_audio_info_raw_init_dict_keys(info,
|
||||
&SPA_DICT_ITEMS(
|
||||
SPA_DICT_ITEM(SPA_KEY_AUDIO_FORMAT, DEFAULT_FORMAT),
|
||||
SPA_DICT_ITEM(SPA_KEY_AUDIO_RATE, SPA_STRINGIFY(DEFAULT_RATE)),
|
||||
|
|
@ -395,7 +395,10 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
|
|||
copy_props(impl, props, PW_KEY_NODE_VIRTUAL);
|
||||
copy_props(impl, props, PW_KEY_MEDIA_CLASS);
|
||||
|
||||
parse_audio_info(impl->stream_props, &impl->info);
|
||||
if ((res = parse_audio_info(impl->stream_props, &impl->info)) < 0) {
|
||||
pw_log_error( "can't parse format: %s", spa_strerror(res));
|
||||
goto error;
|
||||
}
|
||||
|
||||
impl->frame_size = calc_frame_size(&impl->info);
|
||||
if (impl->frame_size == 0) {
|
||||
|
|
|
|||
|
|
@ -279,9 +279,9 @@ static const struct pw_impl_module_events module_events = {
|
|||
.destroy = module_destroy,
|
||||
};
|
||||
|
||||
static void parse_audio_info(const struct pw_properties *props, struct spa_audio_info_raw *info)
|
||||
static int parse_audio_info(const struct pw_properties *props, struct spa_audio_info_raw *info)
|
||||
{
|
||||
spa_audio_info_raw_init_dict_keys(info,
|
||||
return spa_audio_info_raw_init_dict_keys(info,
|
||||
&SPA_DICT_ITEMS(
|
||||
SPA_DICT_ITEM(SPA_KEY_AUDIO_FORMAT, DEFAULT_FORMAT),
|
||||
SPA_DICT_ITEM(SPA_KEY_AUDIO_RATE, SPA_STRINGIFY(DEFAULT_RATE)),
|
||||
|
|
@ -401,7 +401,10 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
|
|||
copy_props(impl, props, PW_KEY_NODE_VIRTUAL);
|
||||
copy_props(impl, props, PW_KEY_MEDIA_CLASS);
|
||||
|
||||
parse_audio_info(impl->stream_props, &impl->info);
|
||||
if ((res = parse_audio_info(impl->stream_props, &impl->info)) < 0) {
|
||||
pw_log_error( "can't parse format: %s", spa_strerror(res));
|
||||
goto error;
|
||||
}
|
||||
|
||||
impl->frame_size = calc_frame_size(&impl->info);
|
||||
if (impl->frame_size == 0) {
|
||||
|
|
|
|||
|
|
@ -112,6 +112,7 @@
|
|||
PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME);
|
||||
#define PW_LOG_TOPIC_DEFAULT mod_topic
|
||||
|
||||
#define MAX_CHANNELS SPA_AUDIO_MAX_CHANNELS
|
||||
#define MAX_PORTS 128
|
||||
#define FFADO_RT_PRIORITY_PACKETIZER_RELATIVE 5
|
||||
|
||||
|
|
@ -179,7 +180,7 @@ struct port {
|
|||
struct volume {
|
||||
bool mute;
|
||||
uint32_t n_volumes;
|
||||
float volumes[SPA_AUDIO_MAX_CHANNELS];
|
||||
float volumes[MAX_CHANNELS];
|
||||
};
|
||||
|
||||
struct stream {
|
||||
|
|
@ -760,7 +761,7 @@ static int make_stream_ports(struct stream *s)
|
|||
struct port *port = s->ports[i];
|
||||
char channel[32];
|
||||
|
||||
snprintf(channel, sizeof(channel), "AUX%u", n_channels % SPA_AUDIO_MAX_CHANNELS);
|
||||
snprintf(channel, sizeof(channel), "AUX%u", n_channels);
|
||||
|
||||
switch (port->stream_type) {
|
||||
case ffado_stream_type_audio:
|
||||
|
|
@ -873,9 +874,9 @@ static void parse_props(struct stream *s, const struct spa_pod *param)
|
|||
case SPA_PROP_channelVolumes:
|
||||
{
|
||||
uint32_t n;
|
||||
float vols[SPA_AUDIO_MAX_CHANNELS];
|
||||
float vols[MAX_CHANNELS];
|
||||
if ((n = spa_pod_copy_array(&prop->value, SPA_TYPE_Float,
|
||||
vols, SPA_AUDIO_MAX_CHANNELS)) > 0) {
|
||||
vols, SPA_N_ELEMENTS(vols))) > 0) {
|
||||
s->volume.n_volumes = n;
|
||||
for (n = 0; n < s->volume.n_volumes; n++)
|
||||
s->volume.volumes[n] = vols[n];
|
||||
|
|
@ -1227,8 +1228,9 @@ static int probe_ffado_device(struct impl *impl)
|
|||
impl->source.ports[i] = port;
|
||||
}
|
||||
if (impl->source.info.channels != n_channels) {
|
||||
impl->source.info.channels = n_channels;
|
||||
for (i = 0; i < SPA_MIN(impl->source.info.channels, SPA_AUDIO_MAX_CHANNELS); i++)
|
||||
uint32_t n_pos = SPA_MIN(n_channels, SPA_N_ELEMENTS(impl->source.info.position));
|
||||
impl->source.info.channels = n_pos;
|
||||
for (i = 0; i < n_pos; i++)
|
||||
impl->source.info.position[i] = SPA_AUDIO_CHANNEL_AUX0 + i;
|
||||
}
|
||||
|
||||
|
|
@ -1253,8 +1255,9 @@ static int probe_ffado_device(struct impl *impl)
|
|||
impl->sink.ports[i] = port;
|
||||
}
|
||||
if (impl->sink.info.channels != n_channels) {
|
||||
impl->sink.info.channels = n_channels;
|
||||
for (i = 0; i < SPA_MIN(impl->sink.info.channels, SPA_AUDIO_MAX_CHANNELS); i++)
|
||||
uint32_t n_pos = SPA_MIN(n_channels, SPA_N_ELEMENTS(impl->sink.info.position));
|
||||
impl->sink.info.channels = n_pos;
|
||||
for (i = 0; i < n_pos; i++)
|
||||
impl->sink.info.position[i] = SPA_AUDIO_CHANNEL_AUX0 + i;
|
||||
}
|
||||
|
||||
|
|
@ -1426,9 +1429,9 @@ static void parse_devices(struct impl *impl, const char *val, size_t len)
|
|||
}
|
||||
}
|
||||
|
||||
static void parse_audio_info(const struct pw_properties *props, struct spa_audio_info_raw *info)
|
||||
static int parse_audio_info(const struct pw_properties *props, struct spa_audio_info_raw *info)
|
||||
{
|
||||
spa_audio_info_raw_init_dict_keys(info,
|
||||
return spa_audio_info_raw_init_dict_keys(info,
|
||||
&SPA_DICT_ITEMS(
|
||||
SPA_DICT_ITEM(SPA_KEY_AUDIO_FORMAT, "F32P"),
|
||||
SPA_DICT_ITEM(SPA_KEY_AUDIO_POSITION, DEFAULT_POSITION)),
|
||||
|
|
@ -1579,8 +1582,11 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
|
|||
copy_props(impl, props, PW_KEY_NODE_VIRTUAL);
|
||||
copy_props(impl, props, PW_KEY_NODE_PAUSE_ON_IDLE);
|
||||
|
||||
parse_audio_info(impl->source.props, &impl->source.info);
|
||||
parse_audio_info(impl->sink.props, &impl->sink.info);
|
||||
if ((res = parse_audio_info(impl->source.props, &impl->source.info)) < 0 ||
|
||||
(res = parse_audio_info(impl->sink.props, &impl->sink.info)) < 0) {
|
||||
pw_log_error( "can't parse format: %s", spa_strerror(res));
|
||||
goto error;
|
||||
}
|
||||
|
||||
impl->core = pw_context_get_object(impl->context, PW_TYPE_INTERFACE_Core);
|
||||
if (impl->core == NULL) {
|
||||
|
|
|
|||
|
|
@ -1832,9 +1832,9 @@ static const struct pw_impl_module_events module_events = {
|
|||
.destroy = module_destroy,
|
||||
};
|
||||
|
||||
static void parse_audio_info(struct pw_properties *props, struct spa_audio_info_raw *info)
|
||||
static int parse_audio_info(struct pw_properties *props, struct spa_audio_info_raw *info)
|
||||
{
|
||||
spa_audio_info_raw_init_dict_keys(info,
|
||||
return spa_audio_info_raw_init_dict_keys(info,
|
||||
&SPA_DICT_ITEMS(
|
||||
SPA_DICT_ITEM(SPA_KEY_AUDIO_FORMAT, "F32P")),
|
||||
&props->dict,
|
||||
|
|
@ -1927,8 +1927,11 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
|
|||
copy_props(impl, props, PW_KEY_MEDIA_NAME);
|
||||
copy_props(impl, props, "resample.prefill");
|
||||
|
||||
parse_audio_info(impl->capture_props, &impl->capture_info);
|
||||
parse_audio_info(impl->playback_props, &impl->playback_info);
|
||||
if ((res = parse_audio_info(impl->capture_props, &impl->capture_info)) < 0 ||
|
||||
(res = parse_audio_info(impl->playback_props, &impl->playback_info)) < 0) {
|
||||
pw_log_error( "can't parse format: %s", spa_strerror(res));
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!impl->capture_info.rate && !impl->playback_info.rate) {
|
||||
if (pw_properties_get(impl->playback_props, "resample.disable") == NULL)
|
||||
|
|
|
|||
|
|
@ -115,6 +115,7 @@
|
|||
PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME);
|
||||
#define PW_LOG_TOPIC_DEFAULT mod_topic
|
||||
|
||||
#define MAX_CHANNELS SPA_AUDIO_MAX_CHANNELS
|
||||
#define MAX_PORTS 128
|
||||
|
||||
#define DEFAULT_CLIENT_NAME "PipeWire"
|
||||
|
|
@ -157,7 +158,7 @@ struct port {
|
|||
struct volume {
|
||||
bool mute;
|
||||
uint32_t n_volumes;
|
||||
float volumes[SPA_AUDIO_MAX_CHANNELS];
|
||||
float volumes[MAX_CHANNELS];
|
||||
};
|
||||
|
||||
struct stream {
|
||||
|
|
@ -513,6 +514,7 @@ static void make_stream_ports(struct stream *s)
|
|||
for (i = 0; i < s->n_ports; i++) {
|
||||
struct port *port = s->ports[i];
|
||||
char *link_port = NULL;
|
||||
char pos[8];
|
||||
|
||||
if (port != NULL) {
|
||||
s->ports[i] = NULL;
|
||||
|
|
@ -522,8 +524,8 @@ static void make_stream_ports(struct stream *s)
|
|||
}
|
||||
|
||||
if (i < s->info.channels) {
|
||||
str = spa_debug_type_find_short_name(spa_type_audio_channel,
|
||||
s->info.position[i]);
|
||||
str = spa_type_audio_channel_make_short_name(
|
||||
s->info.position[i], pos, sizeof(pos), NULL);
|
||||
if (str)
|
||||
snprintf(name, sizeof(name), "%s_%s", prefix, str);
|
||||
else
|
||||
|
|
@ -624,9 +626,9 @@ static void parse_props(struct stream *s, const struct spa_pod *param)
|
|||
case SPA_PROP_channelVolumes:
|
||||
{
|
||||
uint32_t n;
|
||||
float vols[SPA_AUDIO_MAX_CHANNELS];
|
||||
float vols[MAX_CHANNELS];
|
||||
if ((n = spa_pod_copy_array(&prop->value, SPA_TYPE_Float,
|
||||
vols, SPA_AUDIO_MAX_CHANNELS)) > 0) {
|
||||
vols, SPA_N_ELEMENTS(vols))) > 0) {
|
||||
s->volume.n_volumes = n;
|
||||
for (n = 0; n < s->volume.n_volumes; n++)
|
||||
s->volume.volumes[n] = vols[n];
|
||||
|
|
@ -1050,9 +1052,9 @@ static const struct pw_impl_module_events module_events = {
|
|||
.destroy = module_destroy,
|
||||
};
|
||||
|
||||
static void parse_audio_info(const struct pw_properties *props, struct spa_audio_info_raw *info)
|
||||
static int parse_audio_info(const struct pw_properties *props, struct spa_audio_info_raw *info)
|
||||
{
|
||||
spa_audio_info_raw_init_dict_keys(info,
|
||||
return spa_audio_info_raw_init_dict_keys(info,
|
||||
&SPA_DICT_ITEMS(
|
||||
SPA_DICT_ITEM(SPA_KEY_AUDIO_FORMAT, "F32P"),
|
||||
SPA_DICT_ITEM(SPA_KEY_AUDIO_POSITION, DEFAULT_POSITION)),
|
||||
|
|
@ -1175,8 +1177,11 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
|
|||
copy_props(impl, props, "jack.connect-audio");
|
||||
copy_props(impl, props, "jack.connect-midi");
|
||||
|
||||
parse_audio_info(impl->source.props, &impl->source.info);
|
||||
parse_audio_info(impl->sink.props, &impl->sink.info);
|
||||
if ((res = parse_audio_info(impl->source.props, &impl->source.info)) < 0 ||
|
||||
(res = parse_audio_info(impl->sink.props, &impl->sink.info)) < 0) {
|
||||
pw_log_error( "can't parse format: %s", spa_strerror(res));
|
||||
goto error;
|
||||
}
|
||||
|
||||
impl->source.n_midi = pw_properties_get_uint32(impl->source.props,
|
||||
"midi.ports", DEFAULT_MIDI_PORTS);
|
||||
|
|
|
|||
|
|
@ -538,8 +538,7 @@ static void param_format_changed(struct impl *impl, const struct spa_pod *param,
|
|||
spa_zero(info);
|
||||
if (param != NULL) {
|
||||
if (spa_format_audio_raw_parse(param, &info) < 0 ||
|
||||
info.channels == 0 ||
|
||||
info.channels > SPA_AUDIO_MAX_CHANNELS)
|
||||
info.channels == 0)
|
||||
return;
|
||||
|
||||
if ((impl->info.format != 0 && impl->info.format != info.format) ||
|
||||
|
|
@ -839,9 +838,9 @@ static const struct pw_impl_module_events module_events = {
|
|||
.destroy = module_destroy,
|
||||
};
|
||||
|
||||
static void parse_audio_info(struct pw_properties *props, struct spa_audio_info_raw *info)
|
||||
static int parse_audio_info(struct pw_properties *props, struct spa_audio_info_raw *info)
|
||||
{
|
||||
spa_audio_info_raw_init_dict_keys(info,
|
||||
return spa_audio_info_raw_init_dict_keys(info,
|
||||
&SPA_DICT_ITEMS(
|
||||
SPA_DICT_ITEM(SPA_KEY_AUDIO_FORMAT, "F32P")),
|
||||
&props->dict,
|
||||
|
|
@ -953,9 +952,12 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
|
|||
if (pw_properties_get(impl->playback_props, PW_KEY_NODE_DESCRIPTION) == NULL)
|
||||
pw_properties_set(impl->playback_props, PW_KEY_NODE_DESCRIPTION, str);
|
||||
|
||||
parse_audio_info(props, &impl->info);
|
||||
parse_audio_info(impl->capture_props, &impl->capture_info);
|
||||
parse_audio_info(impl->playback_props, &impl->playback_info);
|
||||
if ((res = parse_audio_info(props, &impl->info)) < 0 ||
|
||||
(res = parse_audio_info(impl->capture_props, &impl->capture_info)) < 0 ||
|
||||
(res = parse_audio_info(impl->playback_props, &impl->playback_info)) < 0) {
|
||||
pw_log_error( "can't parse formats: %s", spa_strerror(res));
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!impl->capture_info.rate && !impl->playback_info.rate) {
|
||||
if (pw_properties_get(impl->playback_props, "resample.disable") == NULL)
|
||||
|
|
|
|||
|
|
@ -441,11 +441,11 @@ static void make_stream_ports(struct stream *s)
|
|||
}
|
||||
|
||||
if (i < s->info.channels) {
|
||||
str = spa_debug_type_find_short_name(spa_type_audio_channel,
|
||||
s->info.position[i % SPA_AUDIO_MAX_CHANNELS]);
|
||||
str = spa_type_audio_channel_make_short_name(
|
||||
s->info.position[i], name, sizeof(name), "UNK");
|
||||
props = pw_properties_new(
|
||||
PW_KEY_FORMAT_DSP, "32 bit float mono audio",
|
||||
PW_KEY_AUDIO_CHANNEL, str ? str : "UNK",
|
||||
PW_KEY_AUDIO_CHANNEL, str,
|
||||
PW_KEY_PORT_PHYSICAL, "true",
|
||||
NULL);
|
||||
|
||||
|
|
@ -512,9 +512,9 @@ static void parse_props(struct stream *s, const struct spa_pod *param)
|
|||
case SPA_PROP_channelVolumes:
|
||||
{
|
||||
uint32_t n;
|
||||
float vols[SPA_AUDIO_MAX_CHANNELS];
|
||||
float vols[MAX_CHANNELS];
|
||||
if ((n = spa_pod_copy_array(&prop->value, SPA_TYPE_Float,
|
||||
vols, SPA_AUDIO_MAX_CHANNELS)) > 0) {
|
||||
vols, SPA_N_ELEMENTS(vols))) > 0) {
|
||||
s->volume.n_volumes = n;
|
||||
for (n = 0; n < s->volume.n_volumes; n++)
|
||||
s->volume.volumes[n] = vols[n];
|
||||
|
|
@ -863,7 +863,7 @@ static int handle_follower_setup(struct impl *impl, struct nj2_session_params *p
|
|||
}
|
||||
impl->sink.info.rate = peer->params.sample_rate;
|
||||
if ((uint32_t)peer->params.send_audio_channels != impl->sink.info.channels) {
|
||||
impl->sink.info.channels = SPA_MIN(peer->params.send_audio_channels, (int)SPA_AUDIO_MAX_CHANNELS);
|
||||
impl->sink.info.channels = peer->params.send_audio_channels;
|
||||
for (i = 0; i < impl->sink.info.channels; i++)
|
||||
impl->sink.info.position[i] = SPA_AUDIO_CHANNEL_AUX0 + i;
|
||||
}
|
||||
|
|
@ -874,7 +874,7 @@ static int handle_follower_setup(struct impl *impl, struct nj2_session_params *p
|
|||
}
|
||||
impl->source.info.rate = peer->params.sample_rate;
|
||||
if ((uint32_t)peer->params.recv_audio_channels != impl->source.info.channels) {
|
||||
impl->source.info.channels = SPA_MIN(peer->params.recv_audio_channels, (int)SPA_AUDIO_MAX_CHANNELS);
|
||||
impl->source.info.channels = peer->params.recv_audio_channels;
|
||||
for (i = 0; i < impl->source.info.channels; i++)
|
||||
impl->source.info.position[i] = SPA_AUDIO_CHANNEL_AUX0 + i;
|
||||
}
|
||||
|
|
@ -1218,9 +1218,9 @@ static const struct pw_impl_module_events module_events = {
|
|||
.destroy = module_destroy,
|
||||
};
|
||||
|
||||
static void parse_audio_info(const struct pw_properties *props, struct spa_audio_info_raw *info)
|
||||
static int parse_audio_info(const struct pw_properties *props, struct spa_audio_info_raw *info)
|
||||
{
|
||||
spa_audio_info_raw_init_dict_keys(info,
|
||||
return spa_audio_info_raw_init_dict_keys(info,
|
||||
&SPA_DICT_ITEMS(
|
||||
SPA_DICT_ITEM(SPA_KEY_AUDIO_FORMAT, "F32P")),
|
||||
&props->dict,
|
||||
|
|
@ -1336,8 +1336,11 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
|
|||
copy_props(impl, props, "midi.ports");
|
||||
copy_props(impl, props, "audio.ports");
|
||||
|
||||
parse_audio_info(impl->source.props, &impl->source.info);
|
||||
parse_audio_info(impl->sink.props, &impl->sink.info);
|
||||
if ((res = parse_audio_info(impl->source.props, &impl->source.info)) < 0 ||
|
||||
(res = parse_audio_info(impl->sink.props, &impl->sink.info)) < 0) {
|
||||
pw_log_error( "can't parse format: %s", spa_strerror(res));
|
||||
goto error;
|
||||
}
|
||||
|
||||
impl->source.wanted_n_midi = pw_properties_get_int32(impl->source.props,
|
||||
"midi.ports", DEFAULT_MIDI_PORTS);
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ static const struct spa_dict_item module_props[] = {
|
|||
{ PW_KEY_MODULE_VERSION, PACKAGE_VERSION },
|
||||
};
|
||||
|
||||
static void parse_audio_info(const struct pw_properties *props, struct spa_audio_info_raw *info);
|
||||
static int parse_audio_info(const struct pw_properties *props, struct spa_audio_info_raw *info);
|
||||
|
||||
struct port {
|
||||
enum spa_direction direction;
|
||||
|
|
@ -601,12 +601,11 @@ static void make_stream_ports(struct stream *s)
|
|||
}
|
||||
|
||||
if (i < s->info.channels) {
|
||||
str = spa_debug_type_find_short_name(spa_type_audio_channel,
|
||||
s->info.position[i]);
|
||||
|
||||
str = spa_type_audio_channel_make_short_name(
|
||||
s->info.position[i], name, sizeof(name), "UNK");
|
||||
props = pw_properties_new(
|
||||
PW_KEY_FORMAT_DSP, "32 bit float mono audio",
|
||||
PW_KEY_AUDIO_CHANNEL, str ? str : "UNK",
|
||||
PW_KEY_AUDIO_CHANNEL, str,
|
||||
PW_KEY_PORT_PHYSICAL, "true",
|
||||
NULL);
|
||||
|
||||
|
|
@ -677,9 +676,9 @@ static void parse_props(struct stream *s, const struct spa_pod *param)
|
|||
case SPA_PROP_channelVolumes:
|
||||
{
|
||||
uint32_t n;
|
||||
float vols[SPA_AUDIO_MAX_CHANNELS];
|
||||
float vols[MAX_CHANNELS];
|
||||
if ((n = spa_pod_copy_array(&prop->value, SPA_TYPE_Float,
|
||||
vols, SPA_AUDIO_MAX_CHANNELS)) > 0) {
|
||||
vols, SPA_N_ELEMENTS(vols))) > 0) {
|
||||
s->volume.n_volumes = n;
|
||||
for (n = 0; n < s->volume.n_volumes; n++)
|
||||
s->volume.volumes[n] = vols[n];
|
||||
|
|
@ -969,8 +968,11 @@ static int handle_follower_available(struct impl *impl, struct nj2_session_param
|
|||
follower->sink.direction = PW_DIRECTION_INPUT;
|
||||
follower->sink.props = pw_properties_copy(impl->sink_props);
|
||||
|
||||
parse_audio_info(follower->source.props, &follower->source.info);
|
||||
parse_audio_info(follower->sink.props, &follower->sink.info);
|
||||
if ((res = parse_audio_info(follower->source.props, &follower->source.info)) < 0 ||
|
||||
(res = parse_audio_info(follower->sink.props, &follower->sink.info)) < 0) {
|
||||
pw_log_error("can't parse format: %s", spa_strerror(res));
|
||||
return res;
|
||||
}
|
||||
|
||||
follower->source.n_audio = pw_properties_get_uint32(follower->source.props,
|
||||
"audio.ports", follower->source.info.channels ?
|
||||
|
|
@ -1026,14 +1028,14 @@ static int handle_follower_available(struct impl *impl, struct nj2_session_param
|
|||
follower->source.n_ports = peer->params.recv_audio_channels + peer->params.recv_midi_channels;
|
||||
follower->source.info.rate = peer->params.sample_rate;
|
||||
if ((uint32_t)peer->params.recv_audio_channels != follower->source.info.channels) {
|
||||
follower->source.info.channels = SPA_MIN(peer->params.recv_audio_channels, (int)SPA_AUDIO_MAX_CHANNELS);
|
||||
follower->source.info.channels = peer->params.recv_audio_channels;
|
||||
for (i = 0; i < follower->source.info.channels; i++)
|
||||
follower->source.info.position[i] = SPA_AUDIO_CHANNEL_AUX0 + i;
|
||||
}
|
||||
follower->sink.n_ports = peer->params.send_audio_channels + peer->params.send_midi_channels;
|
||||
follower->sink.info.rate = peer->params.sample_rate;
|
||||
if ((uint32_t)peer->params.send_audio_channels != follower->sink.info.channels) {
|
||||
follower->sink.info.channels = SPA_MIN(peer->params.send_audio_channels, (int)SPA_AUDIO_MAX_CHANNELS);
|
||||
follower->sink.info.channels = peer->params.send_audio_channels;
|
||||
for (i = 0; i < follower->sink.info.channels; i++)
|
||||
follower->sink.info.position[i] = SPA_AUDIO_CHANNEL_AUX0 + i;
|
||||
}
|
||||
|
|
@ -1290,9 +1292,9 @@ static const struct pw_impl_module_events module_events = {
|
|||
.destroy = module_destroy,
|
||||
};
|
||||
|
||||
static void parse_audio_info(const struct pw_properties *props, struct spa_audio_info_raw *info)
|
||||
static int parse_audio_info(const struct pw_properties *props, struct spa_audio_info_raw *info)
|
||||
{
|
||||
spa_audio_info_raw_init_dict_keys(info,
|
||||
return spa_audio_info_raw_init_dict_keys(info,
|
||||
&SPA_DICT_ITEMS(
|
||||
SPA_DICT_ITEM(SPA_KEY_AUDIO_FORMAT, "F32P")),
|
||||
&props->dict,
|
||||
|
|
|
|||
|
|
@ -7,10 +7,12 @@
|
|||
#include <opus/opus_custom.h>
|
||||
#endif
|
||||
|
||||
#define MAX_CHANNELS SPA_AUDIO_MAX_CHANNELS
|
||||
|
||||
struct volume {
|
||||
bool mute;
|
||||
uint32_t n_volumes;
|
||||
float volumes[SPA_AUDIO_MAX_CHANNELS];
|
||||
float volumes[MAX_CHANNELS];
|
||||
};
|
||||
|
||||
static inline float bswap_f32(float f)
|
||||
|
|
|
|||
|
|
@ -745,9 +745,9 @@ static const struct pw_impl_module_events module_events = {
|
|||
.destroy = module_destroy,
|
||||
};
|
||||
|
||||
static void parse_audio_info(const struct pw_properties *props, struct spa_audio_info_raw *info)
|
||||
static int parse_audio_info(const struct pw_properties *props, struct spa_audio_info_raw *info)
|
||||
{
|
||||
spa_audio_info_raw_init_dict_keys(info,
|
||||
return spa_audio_info_raw_init_dict_keys(info,
|
||||
&SPA_DICT_ITEMS(
|
||||
SPA_DICT_ITEM(SPA_KEY_AUDIO_FORMAT, DEFAULT_FORMAT),
|
||||
SPA_DICT_ITEM(SPA_KEY_AUDIO_RATE, SPA_STRINGIFY(DEFAULT_RATE)),
|
||||
|
|
@ -896,7 +896,10 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
|
|||
copy_props(impl, props, PW_KEY_TARGET_OBJECT);
|
||||
copy_props(impl, props, "pipe.filename");
|
||||
|
||||
parse_audio_info(impl->stream_props, &impl->info);
|
||||
if ((res = parse_audio_info(impl->stream_props, &impl->info)) < 0) {
|
||||
pw_log_error("can't parse format: %s", spa_strerror(res));
|
||||
goto error;
|
||||
}
|
||||
|
||||
impl->frame_size = calc_frame_size(&impl->info);
|
||||
if (impl->frame_size == 0) {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@
|
|||
|
||||
#include "format.h"
|
||||
|
||||
#define MAX_CHANNELS SPA_AUDIO_MAX_CHANNELS
|
||||
|
||||
static const struct format audio_formats[] = {
|
||||
[SAMPLE_U8] = { SAMPLE_U8, SPA_AUDIO_FORMAT_U8, "u8", 1 },
|
||||
[SAMPLE_ALAW] = { SAMPLE_ALAW, SPA_AUDIO_FORMAT_ALAW, "alaw", 1 },
|
||||
|
|
@ -296,9 +298,9 @@ uint32_t channel_pa2id(enum channel_position channel)
|
|||
return audio_channels[channel].channel;
|
||||
}
|
||||
|
||||
const char *channel_id2name(uint32_t channel)
|
||||
const char *channel_id2name(uint32_t channel, char *buf, size_t size)
|
||||
{
|
||||
return spa_type_audio_channel_to_short_name(channel);
|
||||
return spa_type_audio_channel_make_short_name(channel, buf, size, "UNK");
|
||||
}
|
||||
|
||||
uint32_t channel_name2id(const char *name)
|
||||
|
|
@ -346,9 +348,9 @@ uint32_t channel_paname2id(const char *name, size_t size)
|
|||
}
|
||||
|
||||
|
||||
void channel_map_to_positions(const struct channel_map *map, uint32_t *pos)
|
||||
void channel_map_to_positions(const struct channel_map *map, uint32_t *pos, uint32_t max_pos)
|
||||
{
|
||||
uint32_t i, channels = SPA_MIN(map->channels, SPA_AUDIO_MAX_CHANNELS);
|
||||
uint32_t i, channels = SPA_MIN(map->channels, max_pos);
|
||||
for (i = 0; i < channels; i++)
|
||||
pos[i] = map->map[i];
|
||||
}
|
||||
|
|
@ -448,8 +450,9 @@ void channel_map_parse(const char *str, struct channel_map *map)
|
|||
|
||||
void channel_map_parse_position(const char *str, struct channel_map *map)
|
||||
{
|
||||
uint32_t channels = 0, position[SPA_AUDIO_MAX_CHANNELS];
|
||||
spa_audio_parse_position(str, strlen(str), position, &channels);
|
||||
uint32_t channels = 0, position[CHANNELS_MAX];
|
||||
spa_audio_parse_position_n(str, strlen(str), position,
|
||||
SPA_N_ELEMENTS(position), &channels);
|
||||
positions_to_channel_map(position, channels, map);
|
||||
}
|
||||
|
||||
|
|
@ -532,8 +535,7 @@ int format_parse_param(const struct spa_pod *param, bool collect,
|
|||
info.info.raw.rate = 48000;
|
||||
if (info.info.raw.format == 0 ||
|
||||
info.info.raw.rate == 0 ||
|
||||
info.info.raw.channels == 0 ||
|
||||
info.info.raw.channels > SPA_AUDIO_MAX_CHANNELS)
|
||||
info.info.raw.channels == 0)
|
||||
return -ENOTSUP;
|
||||
}
|
||||
break;
|
||||
|
|
@ -631,8 +633,8 @@ const struct spa_pod *format_build_param(struct spa_pod_builder *b, uint32_t id,
|
|||
SPA_FORMAT_AUDIO_channels, SPA_POD_Int(spec->channels), 0);
|
||||
|
||||
if (map && map->channels == spec->channels) {
|
||||
uint32_t positions[SPA_AUDIO_MAX_CHANNELS];
|
||||
channel_map_to_positions(map, positions);
|
||||
uint32_t positions[spec->channels];
|
||||
channel_map_to_positions(map, positions, spec->channels);
|
||||
spa_pod_builder_add(b, SPA_FORMAT_AUDIO_position,
|
||||
SPA_POD_Array(sizeof(uint32_t), SPA_TYPE_Id,
|
||||
spec->channels, positions), 0);
|
||||
|
|
|
|||
|
|
@ -190,13 +190,13 @@ void sample_spec_fix(struct sample_spec *ss, struct channel_map *map,
|
|||
struct spa_dict *props);
|
||||
|
||||
uint32_t channel_pa2id(enum channel_position channel);
|
||||
const char *channel_id2name(uint32_t channel);
|
||||
const char *channel_id2name(uint32_t channel, char *buf, size_t size);
|
||||
uint32_t channel_name2id(const char *name);
|
||||
enum channel_position channel_id2pa(uint32_t id, uint32_t *aux);
|
||||
const char *channel_id2paname(uint32_t id, uint32_t *aux);
|
||||
uint32_t channel_paname2id(const char *name, size_t size);
|
||||
|
||||
void channel_map_to_positions(const struct channel_map *map, uint32_t *pos);
|
||||
void channel_map_to_positions(const struct channel_map *map, uint32_t *pos, uint32_t max_pos);
|
||||
void channel_map_parse(const char *str, struct channel_map *map);
|
||||
bool channel_map_valid(const struct channel_map *map);
|
||||
void channel_map_parse_position(const char *str, struct channel_map *map);
|
||||
|
|
|
|||
|
|
@ -761,11 +761,13 @@ int message_dump(enum spa_log_level level, const char *prefix, struct message *m
|
|||
case TAG_CHANNEL_MAP:
|
||||
{
|
||||
struct channel_map map;
|
||||
char pos[8];
|
||||
if ((res = read_channel_map(m, &map)) < 0)
|
||||
return res;
|
||||
pw_log(level, "%s %u: channelmap: channels:%u", prefix, o, map.channels);
|
||||
for (i = 0; i < map.channels; i++)
|
||||
pw_log(level, "%s %d: %s", prefix, i, channel_id2name(map.map[i]));
|
||||
pw_log(level, "%s %d: %s", prefix, i,
|
||||
channel_id2name(map.map[i], pos, sizeof(pos)));
|
||||
break;
|
||||
}
|
||||
case TAG_CVOLUME:
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include <spa/utils/list.h>
|
||||
#include <spa/utils/hook.h>
|
||||
#include <spa/utils/string.h>
|
||||
#include <spa/param/audio/raw-utils.h>
|
||||
#include <pipewire/log.h>
|
||||
#include <pipewire/map.h>
|
||||
#include <pipewire/properties.h>
|
||||
|
|
@ -226,14 +227,15 @@ int module_args_to_audioinfo_keys(struct impl *impl, struct pw_properties *props
|
|||
info->channels, map.channels);
|
||||
return -EINVAL;
|
||||
}
|
||||
channel_map_to_positions(&map, info->position);
|
||||
channel_map_to_positions(&map, info->position, SPA_N_ELEMENTS(info->position));
|
||||
pw_properties_set(props, key_channel_map, NULL);
|
||||
} else {
|
||||
if (info->channels == 0)
|
||||
info->channels = impl->defs.sample_spec.channels;
|
||||
|
||||
if (info->channels == impl->defs.channel_map.channels) {
|
||||
channel_map_to_positions(&impl->defs.channel_map, info->position);
|
||||
channel_map_to_positions(&impl->defs.channel_map,
|
||||
info->position, SPA_N_ELEMENTS(info->position));
|
||||
} else if (info->channels == 1) {
|
||||
info->position[0] = SPA_AUDIO_CHANNEL_MONO;
|
||||
} else if (info->channels == 2) {
|
||||
|
|
@ -281,14 +283,14 @@ void audioinfo_to_properties(struct spa_audio_info_raw *info, struct pw_properti
|
|||
if (info->rate)
|
||||
pw_properties_setf(props, SPA_KEY_AUDIO_RATE, "%u", info->rate);
|
||||
if (info->channels) {
|
||||
char *s, *p;
|
||||
char *s, *p, pos[8];
|
||||
|
||||
pw_properties_setf(props, SPA_KEY_AUDIO_CHANNELS, "%u", info->channels);
|
||||
|
||||
p = s = alloca(info->channels * 8);
|
||||
for (i = 0; i < info->channels; i++)
|
||||
p += spa_scnprintf(p, 8, "%s%s", i == 0 ? "" : ", ",
|
||||
channel_id2name(info->position[i]));
|
||||
channel_id2name(info->position[i], pos, sizeof(pos)));
|
||||
pw_properties_setf(props, SPA_KEY_AUDIO_POSITION, "[ %s ]", s);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -295,9 +295,11 @@ static int do_extension_stream_restore_write(struct module *module, struct clien
|
|||
fprintf(f, " ]");
|
||||
}
|
||||
if (map.channels > 0) {
|
||||
char pos[8];
|
||||
fprintf(f, ", \"channels\": [");
|
||||
for (i = 0; i < map.channels; i++)
|
||||
fprintf(f, "%s\"%s\"", (i == 0 ? " ":", "), channel_id2name(map.map[i]));
|
||||
fprintf(f, "%s\"%s\"", (i == 0 ? " ":", "),
|
||||
channel_id2name(map.map[i], pos, sizeof(pos)));
|
||||
fprintf(f, " ]");
|
||||
}
|
||||
if (device_name != NULL && device_name[0] &&
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ int volume_parse_param(const struct spa_pod *param, struct volume_info *info, bo
|
|||
if (monitor)
|
||||
continue;
|
||||
info->volume.channels = spa_pod_copy_array(&prop->value, SPA_TYPE_Float,
|
||||
info->volume.values, CHANNELS_MAX);
|
||||
info->volume.values, SPA_N_ELEMENTS(info->volume.values));
|
||||
SPA_FLAG_UPDATE(info->flags, VOLUME_HW_VOLUME,
|
||||
prop->flags & SPA_POD_PROP_FLAG_HARDWARE);
|
||||
break;
|
||||
|
|
@ -68,7 +68,7 @@ int volume_parse_param(const struct spa_pod *param, struct volume_info *info, bo
|
|||
if (!monitor)
|
||||
continue;
|
||||
info->volume.channels = spa_pod_copy_array(&prop->value, SPA_TYPE_Float,
|
||||
info->volume.values, CHANNELS_MAX);
|
||||
info->volume.values, SPA_N_ELEMENTS(info->volume.values));
|
||||
SPA_FLAG_CLEAR(info->flags, VOLUME_HW_VOLUME);
|
||||
break;
|
||||
case SPA_PROP_volumeBase:
|
||||
|
|
@ -84,7 +84,7 @@ int volume_parse_param(const struct spa_pod *param, struct volume_info *info, bo
|
|||
}
|
||||
case SPA_PROP_channelMap:
|
||||
info->map.channels = spa_pod_copy_array(&prop->value, SPA_TYPE_Id,
|
||||
info->map.map, CHANNELS_MAX);
|
||||
info->map.map, SPA_N_ELEMENTS(info->map.map));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -815,13 +815,14 @@ static int calc_frame_size(struct spa_audio_info_raw *info)
|
|||
case SPA_AUDIO_FORMAT_F64_OE:
|
||||
return res * 8;
|
||||
default:
|
||||
return 0;
|
||||
return -ENOTSUP;
|
||||
}
|
||||
}
|
||||
|
||||
static int parse_audio_info(const struct pw_properties *props, struct spa_audio_info_raw *info)
|
||||
{
|
||||
spa_audio_info_raw_init_dict_keys(info,
|
||||
int res;
|
||||
if ((res = spa_audio_info_raw_init_dict_keys(info,
|
||||
&SPA_DICT_ITEMS(
|
||||
SPA_DICT_ITEM(SPA_KEY_AUDIO_FORMAT, DEFAULT_FORMAT),
|
||||
SPA_DICT_ITEM(SPA_KEY_AUDIO_RATE, SPA_STRINGIFY(DEFAULT_RATE)),
|
||||
|
|
@ -830,7 +831,8 @@ static int parse_audio_info(const struct pw_properties *props, struct spa_audio_
|
|||
SPA_KEY_AUDIO_FORMAT,
|
||||
SPA_KEY_AUDIO_RATE,
|
||||
SPA_KEY_AUDIO_CHANNELS,
|
||||
SPA_KEY_AUDIO_POSITION, NULL);
|
||||
SPA_KEY_AUDIO_POSITION, NULL)) < 0)
|
||||
return res;
|
||||
|
||||
return calc_frame_size(info);
|
||||
}
|
||||
|
|
@ -851,6 +853,7 @@ static int parse_params(struct impl *impl)
|
|||
const char *str;
|
||||
struct spa_json it[1];
|
||||
char value[512];
|
||||
int res;
|
||||
|
||||
pw_properties_fetch_bool(impl->props, "capture", &impl->capture);
|
||||
pw_properties_fetch_bool(impl->props, "playback", &impl->playback);
|
||||
|
|
@ -894,19 +897,20 @@ static int parse_params(struct impl *impl)
|
|||
copy_props(impl, PW_KEY_NODE_VIRTUAL);
|
||||
copy_props(impl, PW_KEY_NODE_NETWORK);
|
||||
|
||||
impl->capture_frame_size = parse_audio_info(impl->capture_props, &impl->capture_info);
|
||||
if (impl->capture_frame_size == 0) {
|
||||
if ((res = parse_audio_info(impl->capture_props, &impl->capture_info)) <= 0) {
|
||||
pw_log_error("unsupported capture audio format:%d channels:%d",
|
||||
impl->capture_info.format, impl->capture_info.channels);
|
||||
return -EINVAL;
|
||||
}
|
||||
impl->capture_frame_size = res;
|
||||
|
||||
impl->playback_frame_size = parse_audio_info(impl->playback_props, &impl->playback_info);
|
||||
if (impl->playback_frame_size == 0) {
|
||||
if ((res = parse_audio_info(impl->playback_props, &impl->playback_info)) <= 0) {
|
||||
pw_log_error("unsupported playback audio format:%d channels:%d",
|
||||
impl->playback_info.format, impl->playback_info.channels);
|
||||
return -EINVAL;
|
||||
}
|
||||
impl->playback_frame_size = res;
|
||||
|
||||
if (impl->capture_info.rate != 0 &&
|
||||
pw_properties_get(impl->capture_props, PW_KEY_NODE_RATE) == NULL)
|
||||
pw_properties_setf(impl->capture_props, PW_KEY_NODE_RATE,
|
||||
|
|
|
|||
|
|
@ -117,6 +117,8 @@ PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME);
|
|||
#define DEFAULT_CHANNELS 2
|
||||
#define DEFAULT_POSITION "[ FL FR ]"
|
||||
|
||||
#define MAX_CHANNELS SPA_AUDIO_MAX_CHANNELS
|
||||
|
||||
#define MODULE_USAGE "( remote.name=<remote> ] " \
|
||||
"( node.latency=<latency as fraction> ] " \
|
||||
"( node.name=<name of the nodes> ] " \
|
||||
|
|
@ -295,10 +297,10 @@ static void stream_param_changed(void *d, uint32_t id, const struct spa_pod *par
|
|||
{
|
||||
struct pa_cvolume volume;
|
||||
uint32_t n;
|
||||
float vols[SPA_AUDIO_MAX_CHANNELS];
|
||||
float vols[MAX_CHANNELS];
|
||||
|
||||
if ((n = spa_pod_copy_array(&prop->value, SPA_TYPE_Float,
|
||||
vols, SPA_AUDIO_MAX_CHANNELS)) > 0) {
|
||||
vols, SPA_N_ELEMENTS(vols))) > 0) {
|
||||
volume.channels = SPA_MIN(PA_CHANNELS_MAX, n);
|
||||
for (n = 0; n < volume.channels; n++)
|
||||
volume.values[n] = pa_sw_volume_from_linear(vols[n]);
|
||||
|
|
@ -752,7 +754,8 @@ static int create_pulse_stream(struct impl *impl)
|
|||
|
||||
map.channels = impl->info.channels;
|
||||
for (i = 0; i < map.channels; i++)
|
||||
map.map[i] = (pa_channel_position_t)channel_id2pa(impl->info.position[i], &aux);
|
||||
map.map[i] = (pa_channel_position_t)channel_id2pa(
|
||||
impl->info.position[i], &aux);
|
||||
|
||||
snprintf(stream_name, sizeof(stream_name), _("Tunnel for %s@%s"),
|
||||
pw_get_user_name(), pw_get_host_name());
|
||||
|
|
@ -832,10 +835,10 @@ do_stream_sync_volumes(struct spa_loop *loop,
|
|||
struct spa_pod_frame f[1];
|
||||
struct spa_pod *param;
|
||||
uint32_t i, channels;
|
||||
float vols[SPA_AUDIO_MAX_CHANNELS];
|
||||
float soft_vols[SPA_AUDIO_MAX_CHANNELS];
|
||||
float vols[MAX_CHANNELS];
|
||||
float soft_vols[MAX_CHANNELS];
|
||||
|
||||
channels = SPA_MIN(impl->volume.channels, SPA_AUDIO_MAX_CHANNELS);
|
||||
channels = SPA_MIN(impl->volume.channels, MAX_CHANNELS);
|
||||
for (i = 0; i < channels; i++) {
|
||||
vols[i] = (float)pa_sw_volume_to_linear(impl->volume.values[i]);
|
||||
soft_vols[i] = 1.0f;
|
||||
|
|
@ -1045,9 +1048,9 @@ static const struct pw_impl_module_events module_events = {
|
|||
.destroy = module_destroy,
|
||||
};
|
||||
|
||||
static void parse_audio_info(const struct pw_properties *props, struct spa_audio_info_raw *info)
|
||||
static int parse_audio_info(const struct pw_properties *props, struct spa_audio_info_raw *info)
|
||||
{
|
||||
spa_audio_info_raw_init_dict_keys(info,
|
||||
return spa_audio_info_raw_init_dict_keys(info,
|
||||
&SPA_DICT_ITEMS(
|
||||
SPA_DICT_ITEM(SPA_KEY_AUDIO_FORMAT, DEFAULT_FORMAT),
|
||||
SPA_DICT_ITEM(SPA_KEY_AUDIO_RATE, SPA_STRINGIFY(DEFAULT_RATE)),
|
||||
|
|
@ -1189,7 +1192,10 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
|
|||
copy_props(impl, props, PW_KEY_NODE_NETWORK);
|
||||
copy_props(impl, props, PW_KEY_MEDIA_CLASS);
|
||||
|
||||
parse_audio_info(impl->stream_props, &impl->info);
|
||||
if ((res = parse_audio_info(impl->stream_props, &impl->info)) < 0) {
|
||||
pw_log_error("can't parse format: %s", spa_strerror(res));
|
||||
goto error;
|
||||
}
|
||||
|
||||
impl->frame_size = calc_frame_size(&impl->info);
|
||||
if (impl->frame_size == 0) {
|
||||
|
|
|
|||
|
|
@ -158,6 +158,7 @@ PW_LOG_TOPIC(mod_topic, "mod." NAME);
|
|||
#define RAOP_LATENCY_MS 250
|
||||
#define DEFAULT_LATENCY_MS 1500
|
||||
|
||||
#define MAX_CHANNELS SPA_AUDIO_MAX_CHANNELS
|
||||
#define VOLUME_MAX 0.0
|
||||
#define VOLUME_MIN -30.0
|
||||
#define VOLUME_MUTE -144.0
|
||||
|
|
@ -1612,11 +1613,11 @@ static void stream_props_changed(struct impl *impl, uint32_t id, const struct sp
|
|||
case SPA_PROP_channelVolumes:
|
||||
{
|
||||
uint32_t i, n_vols;
|
||||
float vols[SPA_AUDIO_MAX_CHANNELS], volume;
|
||||
float soft_vols[SPA_AUDIO_MAX_CHANNELS];
|
||||
float vols[MAX_CHANNELS], volume;
|
||||
float soft_vols[MAX_CHANNELS];
|
||||
|
||||
if ((n_vols = spa_pod_copy_array(&prop->value, SPA_TYPE_Float,
|
||||
vols, SPA_AUDIO_MAX_CHANNELS)) > 0) {
|
||||
vols, SPA_N_ELEMENTS(vols))) > 0) {
|
||||
volume = 0.0f;
|
||||
for (i = 0; i < n_vols; i++) {
|
||||
volume += vols[i];
|
||||
|
|
|
|||
|
|
@ -156,6 +156,7 @@ PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME);
|
|||
#define DEFAULT_LOOP false
|
||||
|
||||
#define MAX_SDP 2048
|
||||
#define MAX_CHANNELS SPA_AUDIO_MAX_CHANNELS
|
||||
|
||||
#define USAGE "( local.ifname=<local interface name to use> ) " \
|
||||
"( sap.ip=<SAP IP address to send announce, default:"DEFAULT_SAP_IP"> ) " \
|
||||
|
|
@ -1404,7 +1405,7 @@ static int parse_sdp_i(struct impl *impl, char *c, struct sdp_info *info)
|
|||
c[strcspn(c, " ")] = '\0';
|
||||
|
||||
uint32_t channels;
|
||||
if (sscanf(c, "%u", &channels) != 1 || channels <= 0 || channels > SPA_AUDIO_MAX_CHANNELS)
|
||||
if (sscanf(c, "%u", &channels) != 1 || channels <= 0 || channels > MAX_CHANNELS)
|
||||
return 0;
|
||||
|
||||
c += strcspn(c, "\0");
|
||||
|
|
|
|||
|
|
@ -334,9 +334,12 @@ static void rtp_opus_deinit(struct impl *impl, enum spa_direction direction)
|
|||
static int rtp_opus_init(struct impl *impl, enum spa_direction direction)
|
||||
{
|
||||
int err;
|
||||
unsigned char mapping[SPA_AUDIO_MAX_CHANNELS];
|
||||
unsigned char mapping[255];
|
||||
uint32_t i;
|
||||
|
||||
if (impl->info.info.opus.channels > 255)
|
||||
return -EINVAL;
|
||||
|
||||
if (impl->psamples >= 2880)
|
||||
impl->psamples = 2880;
|
||||
else if (impl->psamples >= 1920)
|
||||
|
|
|
|||
|
|
@ -569,9 +569,9 @@ static const struct format_info *find_audio_format_info(const struct spa_audio_i
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void parse_audio_info(const struct pw_properties *props, struct spa_audio_info_raw *info)
|
||||
static int parse_audio_info(const struct pw_properties *props, struct spa_audio_info_raw *info)
|
||||
{
|
||||
spa_audio_info_raw_init_dict_keys(info,
|
||||
return spa_audio_info_raw_init_dict_keys(info,
|
||||
&SPA_DICT_ITEMS(
|
||||
SPA_DICT_ITEM(SPA_KEY_AUDIO_FORMAT, DEFAULT_FORMAT),
|
||||
SPA_DICT_ITEM(SPA_KEY_AUDIO_RATE, SPA_STRINGIFY(DEFAULT_RATE)),
|
||||
|
|
@ -675,7 +675,10 @@ struct rtp_stream *rtp_stream_new(struct pw_core *core,
|
|||
|
||||
switch (impl->info.media_subtype) {
|
||||
case SPA_MEDIA_SUBTYPE_raw:
|
||||
parse_audio_info(props, &impl->info.info.raw);
|
||||
if ((res = parse_audio_info(props, &impl->info.info.raw)) < 0) {
|
||||
pw_log_error("can't parse format: %s", spa_strerror(res));
|
||||
goto out;
|
||||
}
|
||||
impl->stream_info = impl->info;
|
||||
impl->format_info = find_audio_format_info(&impl->info);
|
||||
if (impl->format_info == NULL) {
|
||||
|
|
@ -704,7 +707,10 @@ struct rtp_stream *rtp_stream_new(struct pw_core *core,
|
|||
case SPA_MEDIA_SUBTYPE_opus:
|
||||
impl->stream_info.media_type = SPA_MEDIA_TYPE_audio;
|
||||
impl->stream_info.media_subtype = SPA_MEDIA_SUBTYPE_raw;
|
||||
parse_audio_info(props, &impl->stream_info.info.raw);
|
||||
if ((res = parse_audio_info(props, &impl->stream_info.info.raw)) < 0) {
|
||||
pw_log_error("can't parse format: %s", spa_strerror(res));
|
||||
goto out;
|
||||
}
|
||||
impl->stream_info.info.raw.format = SPA_AUDIO_FORMAT_F32;
|
||||
impl->info.info.opus.rate = impl->stream_info.info.raw.rate;
|
||||
impl->info.info.opus.channels = impl->stream_info.info.raw.channels;
|
||||
|
|
|
|||
|
|
@ -503,9 +503,11 @@ static int add_snapcast_stream(struct impl *impl, struct tunnel *t,
|
|||
return -ENOENT;
|
||||
}
|
||||
|
||||
static void parse_audio_info(struct pw_properties *props, struct spa_audio_info_raw *info)
|
||||
static int parse_audio_info(struct pw_properties *props, struct spa_audio_info_raw *info)
|
||||
{
|
||||
spa_audio_info_raw_init_dict_keys(info,
|
||||
int res;
|
||||
|
||||
if ((res = spa_audio_info_raw_init_dict_keys(info,
|
||||
&SPA_DICT_ITEMS(
|
||||
SPA_DICT_ITEM(SPA_KEY_AUDIO_FORMAT, DEFAULT_FORMAT),
|
||||
SPA_DICT_ITEM(SPA_KEY_AUDIO_RATE, SPA_STRINGIFY(DEFAULT_RATE)),
|
||||
|
|
@ -514,12 +516,14 @@ static void parse_audio_info(struct pw_properties *props, struct spa_audio_info_
|
|||
SPA_KEY_AUDIO_FORMAT,
|
||||
SPA_KEY_AUDIO_RATE,
|
||||
SPA_KEY_AUDIO_CHANNELS,
|
||||
SPA_KEY_AUDIO_POSITION, NULL);
|
||||
SPA_KEY_AUDIO_POSITION, NULL)) < 0)
|
||||
return res;
|
||||
|
||||
pw_properties_set(props, PW_KEY_AUDIO_FORMAT,
|
||||
spa_type_audio_format_to_short_name(info->format));
|
||||
pw_properties_setf(props, PW_KEY_AUDIO_RATE, "%d", info->rate);
|
||||
pw_properties_setf(props, PW_KEY_AUDIO_CHANNELS, "%d", info->channels);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int create_stream(struct impl *impl, struct pw_properties *props,
|
||||
|
|
@ -545,7 +549,10 @@ static int create_stream(struct impl *impl, struct pw_properties *props,
|
|||
if ((str = pw_properties_get(props, "capture.props")) == NULL)
|
||||
pw_properties_set(props, "capture.props", "{ media.class = Audio/Sink }");
|
||||
|
||||
parse_audio_info(props, &t->audio_info);
|
||||
if ((res = parse_audio_info(props, &t->audio_info)) < 0) {
|
||||
pw_log_error("Can't parse format: %s", spa_strerror(res));
|
||||
goto done;
|
||||
}
|
||||
|
||||
if ((f = open_memstream(&args, &size)) == NULL) {
|
||||
res = -errno;
|
||||
|
|
|
|||
|
|
@ -185,9 +185,9 @@ static const struct format_info *find_audio_format_info(const struct spa_audio_i
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void parse_audio_info(const struct pw_properties *props, struct spa_audio_info_raw *info)
|
||||
static int parse_audio_info(const struct pw_properties *props, struct spa_audio_info_raw *info)
|
||||
{
|
||||
spa_audio_info_raw_init_dict_keys(info,
|
||||
return spa_audio_info_raw_init_dict_keys(info,
|
||||
&SPA_DICT_ITEMS(
|
||||
SPA_DICT_ITEM(SPA_KEY_AUDIO_FORMAT, DEFAULT_FORMAT),
|
||||
SPA_DICT_ITEM(SPA_KEY_AUDIO_RATE, SPA_STRINGIFY(DEFAULT_RATE)),
|
||||
|
|
@ -274,9 +274,14 @@ struct vban_stream *vban_stream_new(struct pw_core *core,
|
|||
|
||||
switch (impl->info.media_subtype) {
|
||||
case SPA_MEDIA_SUBTYPE_raw:
|
||||
parse_audio_info(props, &impl->info.info.raw);
|
||||
if (SPA_FLAG_IS_SET(impl->info.info.raw.flags, SPA_AUDIO_FLAG_UNPOSITIONED))
|
||||
if ((res = parse_audio_info(props, &impl->info.info.raw)) < 0) {
|
||||
pw_log_error("can't parse format: %s", spa_strerror(res));
|
||||
goto out;
|
||||
}
|
||||
if (SPA_FLAG_IS_SET(impl->info.info.raw.flags, SPA_AUDIO_FLAG_UNPOSITIONED)) {
|
||||
default_layout(impl->info.info.raw.channels, impl->info.info.raw.position);
|
||||
SPA_FLAG_CLEAR(impl->info.info.raw.flags, SPA_AUDIO_FLAG_UNPOSITIONED);
|
||||
}
|
||||
impl->stream_info = impl->info;
|
||||
impl->format_info = find_audio_format_info(&impl->info);
|
||||
if (impl->format_info == NULL) {
|
||||
|
|
|
|||
|
|
@ -188,17 +188,17 @@ static void pw_properties_from_avahi_string(const char *key, const char *value,
|
|||
else if (spa_streq(key, "channel_map")) {
|
||||
struct channel_map channel_map;
|
||||
uint32_t i, pos[CHANNELS_MAX];
|
||||
char *p, *s;
|
||||
char *p, *s, buf[8];
|
||||
|
||||
spa_zero(channel_map);
|
||||
channel_map_parse(value, &channel_map);
|
||||
channel_map_to_positions(&channel_map, pos);
|
||||
channel_map_to_positions(&channel_map, pos, CHANNELS_MAX);
|
||||
|
||||
p = s = alloca(4 + channel_map.channels * 8);
|
||||
p += spa_scnprintf(p, 2, "[");
|
||||
for (i = 0; i < channel_map.channels; i++)
|
||||
p += spa_scnprintf(p, 8, "%s%s", i == 0 ? "" : ",",
|
||||
channel_id2name(pos[i]));
|
||||
channel_id2name(pos[i], buf, sizeof(buf)));
|
||||
p += spa_scnprintf(p, 2, "]");
|
||||
pw_properties_set(props, SPA_KEY_AUDIO_POSITION, s);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -252,7 +252,8 @@ static int update_string(struct pw_properties *props, const char *str, size_t si
|
|||
continue;
|
||||
}
|
||||
/* item changed or added, apply changes later */
|
||||
if ((errno = -add_item(&changes, key, false, val, true) < 0)) {
|
||||
if ((res = add_item(&changes, key, false, val, true)) < 0) {
|
||||
errno = -res;
|
||||
it[0].state = SPA_JSON_ERROR_FLAG;
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -245,24 +245,21 @@ void pw_settings_init(struct pw_context *this)
|
|||
static void expose_settings(struct pw_context *context, struct pw_impl_metadata *metadata)
|
||||
{
|
||||
struct settings *s = &context->settings;
|
||||
uint32_t i, o;
|
||||
char rates[MAX_RATES*16] = "";
|
||||
uint32_t i;
|
||||
char rates[MAX_RATES*16];
|
||||
struct spa_strbuf b;
|
||||
|
||||
pw_impl_metadata_set_propertyf(metadata,
|
||||
PW_ID_CORE, "log.level", "", "%d", s->log_level);
|
||||
pw_impl_metadata_set_propertyf(metadata,
|
||||
PW_ID_CORE, "clock.rate", "", "%d", s->clock_rate);
|
||||
for (i = 0, o = 0; i < s->n_clock_rates; i++) {
|
||||
int r = snprintf(rates+o, sizeof(rates)-o, "%s%d", i == 0 ? "" : ", ",
|
||||
|
||||
spa_strbuf_init(&b, rates, sizeof(rates));
|
||||
for (i = 0; i < s->n_clock_rates; i++)
|
||||
spa_strbuf_append(&b, "%s%d", i == 0 ? "" : ", ",
|
||||
s->clock_rates[i]);
|
||||
if (r < 0 || o + r >= (int)sizeof(rates)) {
|
||||
snprintf(rates, sizeof(rates), "%d", s->clock_rate);
|
||||
break;
|
||||
}
|
||||
o += r;
|
||||
}
|
||||
if (s->n_clock_rates == 0)
|
||||
snprintf(rates, sizeof(rates), "%d", s->clock_rate);
|
||||
spa_strbuf_append(&b, "%d", s->clock_rate);
|
||||
|
||||
pw_impl_metadata_set_propertyf(metadata,
|
||||
PW_ID_CORE, "clock.allowed-rates", "", "[ %s ]", rates);
|
||||
|
|
|
|||
|
|
@ -70,6 +70,8 @@
|
|||
#define DEFAULT_VOLUME 1.0
|
||||
#define DEFAULT_QUALITY 4
|
||||
|
||||
#define MAX_CHANNELS SPA_AUDIO_MAX_CHANNELS
|
||||
|
||||
enum mode {
|
||||
mode_none,
|
||||
mode_playback,
|
||||
|
|
@ -91,7 +93,7 @@ typedef int (*fill_fn)(struct data *d, void *dest, unsigned int n_frames, bool *
|
|||
|
||||
struct channelmap {
|
||||
uint32_t n_channels;
|
||||
uint32_t channels[SPA_AUDIO_MAX_CHANNELS];
|
||||
uint32_t channels[MAX_CHANNELS];
|
||||
};
|
||||
|
||||
struct data {
|
||||
|
|
@ -702,7 +704,8 @@ static int parse_channelmap(const char *channel_map, struct channelmap *map)
|
|||
}
|
||||
}
|
||||
|
||||
spa_audio_parse_position(channel_map, strlen(channel_map), map->channels, &map->n_channels);
|
||||
spa_audio_parse_position_n(channel_map, strlen(channel_map),
|
||||
map->channels, SPA_N_ELEMENTS(map->channels), &map->n_channels);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -744,10 +747,11 @@ static int channelmap_default(struct channelmap *map, int n_channels)
|
|||
static void channelmap_print(struct channelmap *map)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
char pos[8];
|
||||
for (i = 0; i < map->n_channels; i++) {
|
||||
const char *name = spa_type_audio_channel_to_short_name(map->channels[i]);
|
||||
fprintf(stderr, "%s%s", name, i + 1 < map->n_channels ? "," : "");
|
||||
fprintf(stderr, "%s%s", i ? "," : "",
|
||||
spa_type_audio_channel_make_short_name(map->channels[i],
|
||||
pos, sizeof(pos), "UNK"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2344,9 +2348,23 @@ int main(int argc, char *argv[])
|
|||
.rate = data.rate,
|
||||
.channels = data.channels);
|
||||
|
||||
if (data.channelmap.n_channels)
|
||||
memcpy(info.position, data.channelmap.channels, data.channels * sizeof(int));
|
||||
|
||||
if (data.channels > MAX_CHANNELS) {
|
||||
fprintf(stderr, "error: too many channels %d > %d\n",
|
||||
data.channels, MAX_CHANNELS);
|
||||
goto error_bad_file;
|
||||
}
|
||||
if (data.channelmap.n_channels) {
|
||||
if (data.channels > MAX_CHANNELS) {
|
||||
fprintf(stderr, "error: too many channels in channelmap %d > %d\n",
|
||||
data.channelmap.n_channels, MAX_CHANNELS);
|
||||
goto error_bad_file;
|
||||
}
|
||||
uint32_t i;
|
||||
for (i = 0; i < data.channelmap.n_channels; i++)
|
||||
info.position[i] = data.channelmap.channels[i];
|
||||
for (; i < data.channels; i++)
|
||||
info.position[i] = SPA_AUDIO_CHANNEL_AUX0 + i;
|
||||
}
|
||||
params[n_params++] = spa_format_audio_raw_build(&b, SPA_PARAM_EnumFormat, &info);
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -112,6 +112,7 @@ test('test-spa',
|
|||
executable('test-spa',
|
||||
'test-spa-buffer.c',
|
||||
'test-spa-control.c',
|
||||
'test-spa-format.c',
|
||||
'test-spa-json.c',
|
||||
'test-spa-utils.c',
|
||||
'test-spa-log.c',
|
||||
|
|
|
|||
129
test/test-spa-format.c
Normal file
129
test/test-spa-format.c
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2025 Pauli Virtanen */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#include <spa/param/audio/format-utils.h>
|
||||
#include <spa/param/audio/format.h>
|
||||
|
||||
#include "pwtest.h"
|
||||
|
||||
PWTEST(audio_format_sizes)
|
||||
{
|
||||
union {
|
||||
uint8_t buf[1024];
|
||||
struct spa_audio_info align;
|
||||
} data;
|
||||
struct spa_audio_info info;
|
||||
size_t i;
|
||||
|
||||
memset(&info, 0xf3, sizeof(info));
|
||||
info.media_type = SPA_MEDIA_TYPE_audio;
|
||||
info.media_subtype = SPA_MEDIA_SUBTYPE_raw;
|
||||
info.info.raw.channels = 5;
|
||||
info.info.raw.format = SPA_AUDIO_FORMAT_F32P;
|
||||
info.info.raw.rate = 12345;
|
||||
info.info.raw.flags = 0;
|
||||
info.info.raw.position[0] = 1;
|
||||
info.info.raw.position[1] = 2;
|
||||
info.info.raw.position[2] = 3;
|
||||
info.info.raw.position[3] = 4;
|
||||
info.info.raw.position[4] = 5;
|
||||
|
||||
for (i = 0; i < sizeof(data.buf); ++i) {
|
||||
struct spa_pod *pod;
|
||||
uint8_t buf[4096];
|
||||
struct spa_pod_builder b;
|
||||
|
||||
spa_pod_builder_init(&b, buf, sizeof(buf));
|
||||
memcpy(data.buf, &info, sizeof(info));
|
||||
|
||||
pod = spa_format_audio_ext_build(&b, 123, (void *)data.buf, i);
|
||||
if (i < offsetof(struct spa_audio_info, info.raw)
|
||||
+ offsetof(struct spa_audio_info_raw, position))
|
||||
pwtest_bool_true(!pod);
|
||||
else
|
||||
pwtest_bool_true(pod);
|
||||
}
|
||||
|
||||
for (i = 0; i < sizeof(data.buf); ++i) {
|
||||
struct spa_pod *pod;
|
||||
uint8_t buf[4096];
|
||||
struct spa_pod_builder b;
|
||||
int ret;
|
||||
|
||||
spa_pod_builder_init(&b, buf, sizeof(buf));
|
||||
pod = spa_format_audio_ext_build(&b, 123, &info, sizeof(info));
|
||||
pwtest_bool_true(pod);
|
||||
|
||||
memset(data.buf, 0xf3, sizeof(data.buf));
|
||||
|
||||
ret = spa_format_audio_ext_parse(pod, (void *)data.buf, i);
|
||||
if (i < offsetof(struct spa_audio_info, info.raw)
|
||||
+ offsetof(struct spa_audio_info_raw, position)
|
||||
+ info.info.raw.channels*sizeof(uint32_t)) {
|
||||
for (size_t j = i; j < sizeof(data.buf); ++j)
|
||||
pwtest_int_eq(data.buf[j], 0xf3);
|
||||
pwtest_int_lt(ret, 0);
|
||||
} else {
|
||||
pwtest_int_ge(ret, 0);
|
||||
pwtest_bool_true(memcmp(data.buf, &info, SPA_MIN(i, sizeof(info))) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
memset(&info, 0xf3, sizeof(info));
|
||||
info.media_type = SPA_MEDIA_TYPE_audio;
|
||||
info.media_subtype = SPA_MEDIA_SUBTYPE_aac;
|
||||
info.info.aac.rate = 12345;
|
||||
info.info.aac.channels = 6;
|
||||
info.info.aac.bitrate = 54321;
|
||||
info.info.aac.stream_format = SPA_AUDIO_AAC_STREAM_FORMAT_MP4LATM;
|
||||
|
||||
for (i = 0; i < sizeof(data.buf); ++i) {
|
||||
struct spa_pod *pod;
|
||||
uint8_t buf[4096];
|
||||
struct spa_pod_builder b;
|
||||
|
||||
spa_pod_builder_init(&b, buf, sizeof(buf));
|
||||
memcpy(data.buf, &info, sizeof(info));
|
||||
|
||||
pod = spa_format_audio_ext_build(&b, 123, (void *)data.buf, i);
|
||||
if (i < offsetof(struct spa_audio_info, info.raw)
|
||||
+ sizeof(struct spa_audio_info_aac))
|
||||
pwtest_bool_true(!pod);
|
||||
else
|
||||
pwtest_bool_true(pod);
|
||||
}
|
||||
|
||||
for (i = 0; i < sizeof(data.buf); ++i) {
|
||||
struct spa_pod *pod;
|
||||
uint8_t buf[4096];
|
||||
struct spa_pod_builder b;
|
||||
int ret;
|
||||
|
||||
spa_pod_builder_init(&b, buf, sizeof(buf));
|
||||
pod = spa_format_audio_ext_build(&b, 123, &info, sizeof(info));
|
||||
pwtest_bool_true(pod);
|
||||
|
||||
memset(data.buf, 0xf3, sizeof(data.buf));
|
||||
|
||||
ret = spa_format_audio_ext_parse(pod, (void *)data.buf, i);
|
||||
if (i < offsetof(struct spa_audio_info, info.raw)
|
||||
+ sizeof(struct spa_audio_info_aac)) {
|
||||
for (size_t j = i; j < sizeof(data.buf); ++j)
|
||||
pwtest_int_eq(data.buf[j], 0xf3);
|
||||
pwtest_int_lt(ret, 0);
|
||||
} else {
|
||||
pwtest_int_ge(ret, 0);
|
||||
pwtest_bool_true(memcmp(data.buf, &info, SPA_MIN(i, sizeof(info))) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
return PWTEST_PASS;
|
||||
}
|
||||
|
||||
PWTEST_SUITE(spa_format)
|
||||
{
|
||||
pwtest_add(audio_format_sizes, PWTEST_NOARG);
|
||||
|
||||
return PWTEST_PASS;
|
||||
}
|
||||
|
|
@ -609,7 +609,7 @@ static void test_array(const char *str, const char * const vals[])
|
|||
|
||||
spa_json_init(&it[0], str, strlen(str));
|
||||
if (spa_json_enter_array(&it[0], &it[1]) <= 0)
|
||||
spa_json_init(&it[1], str, strlen(str));
|
||||
spa_json_init_relax(&it[1], '[', str, strlen(str));
|
||||
for (i = 0; vals[i]; i++) {
|
||||
pwtest_int_gt(spa_json_get_string(&it[1], val, sizeof(val)), 0);
|
||||
pwtest_str_eq(val, vals[i]);
|
||||
|
|
@ -624,6 +624,7 @@ PWTEST(json_array)
|
|||
test_array("[FL FR]", (const char *[]){ "FL", "FR", NULL });
|
||||
test_array("FL FR", (const char *[]){ "FL", "FR", NULL });
|
||||
test_array("[ FL FR ]", (const char *[]){ "FL", "FR", NULL });
|
||||
test_array("FL FR FC", (const char *[]){ "FL", "FR", "FC", NULL });
|
||||
|
||||
return PWTEST_PASS;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue