mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-03 09:01:54 -05:00
alsa: fix for format changes
Add exclusive option Add channel mapping
This commit is contained in:
parent
4acfb88cb7
commit
9955e32030
1 changed files with 156 additions and 32 deletions
|
|
@ -68,6 +68,7 @@ typedef struct {
|
||||||
struct pw_remote *remote;
|
struct pw_remote *remote;
|
||||||
struct spa_hook remote_listener;
|
struct spa_hook remote_listener;
|
||||||
|
|
||||||
|
uint32_t flags;
|
||||||
struct pw_stream *stream;
|
struct pw_stream *stream;
|
||||||
struct spa_hook stream_listener;
|
struct spa_hook stream_listener;
|
||||||
|
|
||||||
|
|
@ -400,9 +401,9 @@ static int snd_pcm_pipewire_prepare(snd_pcm_ioplug_t *io)
|
||||||
PW_DIRECTION_OUTPUT :
|
PW_DIRECTION_OUTPUT :
|
||||||
PW_DIRECTION_INPUT,
|
PW_DIRECTION_INPUT,
|
||||||
pw->target,
|
pw->target,
|
||||||
|
pw->flags |
|
||||||
PW_STREAM_FLAG_AUTOCONNECT |
|
PW_STREAM_FLAG_AUTOCONNECT |
|
||||||
PW_STREAM_FLAG_MAP_BUFFERS |
|
PW_STREAM_FLAG_MAP_BUFFERS |
|
||||||
// PW_STREAM_FLAG_EXCLUSIVE |
|
|
||||||
PW_STREAM_FLAG_RT_PROCESS,
|
PW_STREAM_FLAG_RT_PROCESS,
|
||||||
params, 1);
|
params, 1);
|
||||||
|
|
||||||
|
|
@ -451,51 +452,97 @@ static int snd_pcm_pipewire_stop(snd_pcm_ioplug_t *io)
|
||||||
}
|
}
|
||||||
|
|
||||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||||
#define _FORMAT_LE(fmt) SPA_AUDIO_FORMAT_ ## fmt ## _OE
|
#define _FORMAT_LE(p, fmt) p ? SPA_AUDIO_FORMAT_UNKNOWN : SPA_AUDIO_FORMAT_ ## fmt ## _OE
|
||||||
#define _FORMAT_BE(fmt) SPA_AUDIO_FORMAT_ ## fmt
|
#define _FORMAT_BE(p, fmt) p ? SPA_AUDIO_FORMAT_ ## fmt ## P : SPA_AUDIO_FORMAT_ ## fmt
|
||||||
#elif __BYTE_ORDER == __LITTLE_ENDIAN
|
#elif __BYTE_ORDER == __LITTLE_ENDIAN
|
||||||
#define _FORMAT_LE(fmt) SPA_AUDIO_FORMAT_ ## fmt
|
#define _FORMAT_LE(p, fmt) p ? SPA_AUDIO_FORMAT_ ## fmt ## P : SPA_AUDIO_FORMAT_ ## fmt
|
||||||
#define _FORMAT_BE(fmt) SPA_AUDIO_FORMAT_ ## fmt ## _OE
|
#define _FORMAT_BE(p, fmt) p ? SPA_AUDIO_FORMAT_UNKNOWN : SPA_AUDIO_FORMAT_ ## fmt ## _OE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static int set_default_channels(struct spa_audio_info_raw *info)
|
||||||
|
{
|
||||||
|
switch (info->channels) {
|
||||||
|
case 1:
|
||||||
|
info->position[0] = SPA_AUDIO_CHANNEL_MONO;
|
||||||
|
return 1;
|
||||||
|
case 8:
|
||||||
|
info->position[6] = SPA_AUDIO_CHANNEL_SL;
|
||||||
|
info->position[7] = SPA_AUDIO_CHANNEL_SR;
|
||||||
|
/* Fall through */
|
||||||
|
case 6:
|
||||||
|
info->position[4] = SPA_AUDIO_CHANNEL_RL;
|
||||||
|
info->position[5] = SPA_AUDIO_CHANNEL_RR;
|
||||||
|
/* Fall through */
|
||||||
|
case 4:
|
||||||
|
info->position[3] = SPA_AUDIO_CHANNEL_LFE;
|
||||||
|
/* Fall through */
|
||||||
|
case 3:
|
||||||
|
/* Fall through */
|
||||||
|
info->position[2] = SPA_AUDIO_CHANNEL_FC;
|
||||||
|
case 2:
|
||||||
|
info->position[0] = SPA_AUDIO_CHANNEL_FL;
|
||||||
|
info->position[1] = SPA_AUDIO_CHANNEL_FR;
|
||||||
|
return 1;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int snd_pcm_pipewire_hw_params(snd_pcm_ioplug_t * io,
|
static int snd_pcm_pipewire_hw_params(snd_pcm_ioplug_t * io,
|
||||||
snd_pcm_hw_params_t * params)
|
snd_pcm_hw_params_t * params)
|
||||||
{
|
{
|
||||||
snd_pcm_pipewire_t *pw = io->private_data;
|
snd_pcm_pipewire_t *pw = io->private_data;
|
||||||
|
bool planar;
|
||||||
|
|
||||||
|
pw_log_debug("hw_params");
|
||||||
|
|
||||||
|
switch(io->access) {
|
||||||
|
case SND_PCM_ACCESS_MMAP_INTERLEAVED:
|
||||||
|
case SND_PCM_ACCESS_RW_INTERLEAVED:
|
||||||
|
planar = false;
|
||||||
|
break;
|
||||||
|
case SND_PCM_ACCESS_MMAP_NONINTERLEAVED:
|
||||||
|
case SND_PCM_ACCESS_RW_NONINTERLEAVED:
|
||||||
|
planar = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
SNDERR("PipeWire: invalid access: %d\n", io->access);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
switch(io->format) {
|
switch(io->format) {
|
||||||
case SND_PCM_FORMAT_U8:
|
case SND_PCM_FORMAT_U8:
|
||||||
pw->format.format = SPA_AUDIO_FORMAT_U8;
|
pw->format.format = planar ? SPA_AUDIO_FORMAT_U8P : SPA_AUDIO_FORMAT_U8;
|
||||||
break;
|
break;
|
||||||
case SND_PCM_FORMAT_S16_LE:
|
case SND_PCM_FORMAT_S16_LE:
|
||||||
pw->format.format = _FORMAT_LE(S16);
|
pw->format.format = _FORMAT_LE(planar, S16);
|
||||||
break;
|
break;
|
||||||
case SND_PCM_FORMAT_S16_BE:
|
case SND_PCM_FORMAT_S16_BE:
|
||||||
pw->format.format = _FORMAT_BE(S16);
|
pw->format.format = _FORMAT_BE(planar, S16);
|
||||||
break;
|
break;
|
||||||
case SND_PCM_FORMAT_S24_LE:
|
case SND_PCM_FORMAT_S24_LE:
|
||||||
pw->format.format = _FORMAT_LE(S24_32);
|
pw->format.format = _FORMAT_LE(planar, S24_32);
|
||||||
break;
|
break;
|
||||||
case SND_PCM_FORMAT_S24_BE:
|
case SND_PCM_FORMAT_S24_BE:
|
||||||
pw->format.format = _FORMAT_BE(S24_32);
|
pw->format.format = _FORMAT_BE(planar, S24_32);
|
||||||
break;
|
break;
|
||||||
case SND_PCM_FORMAT_S32_LE:
|
case SND_PCM_FORMAT_S32_LE:
|
||||||
pw->format.format = _FORMAT_LE(S32);
|
pw->format.format = _FORMAT_LE(planar, S32);
|
||||||
break;
|
break;
|
||||||
case SND_PCM_FORMAT_S32_BE:
|
case SND_PCM_FORMAT_S32_BE:
|
||||||
pw->format.format = _FORMAT_BE(S32);
|
pw->format.format = _FORMAT_BE(planar, S32);
|
||||||
break;
|
break;
|
||||||
case SND_PCM_FORMAT_S24_3LE:
|
case SND_PCM_FORMAT_S24_3LE:
|
||||||
pw->format.format = _FORMAT_LE(S24);
|
pw->format.format = _FORMAT_LE(planar, S24);
|
||||||
break;
|
break;
|
||||||
case SND_PCM_FORMAT_S24_3BE:
|
case SND_PCM_FORMAT_S24_3BE:
|
||||||
pw->format.format = _FORMAT_BE(S24);
|
pw->format.format = _FORMAT_BE(planar, S24);
|
||||||
break;
|
break;
|
||||||
case SND_PCM_FORMAT_FLOAT_LE:
|
case SND_PCM_FORMAT_FLOAT_LE:
|
||||||
pw->format.format = _FORMAT_LE(F32);
|
pw->format.format = _FORMAT_LE(planar, F32);
|
||||||
break;
|
break;
|
||||||
case SND_PCM_FORMAT_FLOAT_BE:
|
case SND_PCM_FORMAT_FLOAT_BE:
|
||||||
pw->format.format = _FORMAT_BE(F32);
|
pw->format.format = _FORMAT_BE(planar, F32);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
SNDERR("PipeWire: invalid format: %d\n", io->format);
|
SNDERR("PipeWire: invalid format: %d\n", io->format);
|
||||||
|
|
@ -504,24 +551,88 @@ static int snd_pcm_pipewire_hw_params(snd_pcm_ioplug_t * io,
|
||||||
pw->format.channels = io->channels;
|
pw->format.channels = io->channels;
|
||||||
pw->format.rate = io->rate;
|
pw->format.rate = io->rate;
|
||||||
|
|
||||||
switch(io->access) {
|
set_default_channels(&pw->format);
|
||||||
case SND_PCM_ACCESS_MMAP_INTERLEAVED:
|
|
||||||
case SND_PCM_ACCESS_RW_INTERLEAVED:
|
|
||||||
pw->format.layout = SPA_AUDIO_LAYOUT_INTERLEAVED;
|
|
||||||
break;
|
|
||||||
case SND_PCM_ACCESS_MMAP_NONINTERLEAVED:
|
|
||||||
case SND_PCM_ACCESS_RW_NONINTERLEAVED:
|
|
||||||
pw->format.layout = SPA_AUDIO_LAYOUT_NON_INTERLEAVED;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
SNDERR("PipeWire: invalid access: %d\n", io->access);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
pw->sample_bits = snd_pcm_format_physical_width(io->format);
|
pw->sample_bits = snd_pcm_format_physical_width(io->format);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct chmap_info {
|
||||||
|
enum snd_pcm_chmap_position pos;
|
||||||
|
enum spa_audio_channel channel;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct chmap_info chmap_info[] = {
|
||||||
|
[SND_CHMAP_UNKNOWN] = { SND_CHMAP_UNKNOWN, SPA_AUDIO_CHANNEL_UNKNOWN },
|
||||||
|
[SND_CHMAP_NA] = { SND_CHMAP_NA, SPA_AUDIO_CHANNEL_NA },
|
||||||
|
[SND_CHMAP_MONO] = { SND_CHMAP_MONO, SPA_AUDIO_CHANNEL_MONO },
|
||||||
|
[SND_CHMAP_FL] = { SND_CHMAP_FL, SPA_AUDIO_CHANNEL_FL },
|
||||||
|
[SND_CHMAP_FR] = { SND_CHMAP_FR, SPA_AUDIO_CHANNEL_FR },
|
||||||
|
[SND_CHMAP_RL] = { SND_CHMAP_RL, SPA_AUDIO_CHANNEL_RL },
|
||||||
|
[SND_CHMAP_RR] = { SND_CHMAP_RR, SPA_AUDIO_CHANNEL_RR },
|
||||||
|
[SND_CHMAP_FC] = { SND_CHMAP_FC, SPA_AUDIO_CHANNEL_FC },
|
||||||
|
[SND_CHMAP_LFE] = { SND_CHMAP_LFE, SPA_AUDIO_CHANNEL_LFE },
|
||||||
|
[SND_CHMAP_SL] = { SND_CHMAP_SL, SPA_AUDIO_CHANNEL_SL },
|
||||||
|
[SND_CHMAP_SR] = { SND_CHMAP_SR, SPA_AUDIO_CHANNEL_SR },
|
||||||
|
[SND_CHMAP_RC] = { SND_CHMAP_RC, SPA_AUDIO_CHANNEL_RC },
|
||||||
|
[SND_CHMAP_FLC] = { SND_CHMAP_FLC, SPA_AUDIO_CHANNEL_FLC },
|
||||||
|
[SND_CHMAP_FRC] = { SND_CHMAP_FRC, SPA_AUDIO_CHANNEL_FRC },
|
||||||
|
[SND_CHMAP_RLC] = { SND_CHMAP_RLC, SPA_AUDIO_CHANNEL_RLC },
|
||||||
|
[SND_CHMAP_RRC] = { SND_CHMAP_RRC, SPA_AUDIO_CHANNEL_RRC },
|
||||||
|
[SND_CHMAP_FLW] = { SND_CHMAP_FLW, SPA_AUDIO_CHANNEL_FLW },
|
||||||
|
[SND_CHMAP_FRW] = { SND_CHMAP_FRW, SPA_AUDIO_CHANNEL_FRW },
|
||||||
|
[SND_CHMAP_FLH] = { SND_CHMAP_FLH, SPA_AUDIO_CHANNEL_FLH },
|
||||||
|
[SND_CHMAP_FCH] = { SND_CHMAP_FCH, SPA_AUDIO_CHANNEL_FCH },
|
||||||
|
[SND_CHMAP_FRH] = { SND_CHMAP_FRH, SPA_AUDIO_CHANNEL_FRH },
|
||||||
|
[SND_CHMAP_TC] = { SND_CHMAP_TC, SPA_AUDIO_CHANNEL_TC },
|
||||||
|
[SND_CHMAP_TFL] = { SND_CHMAP_TFL, SPA_AUDIO_CHANNEL_TFL },
|
||||||
|
[SND_CHMAP_TFR] = { SND_CHMAP_TFR, SPA_AUDIO_CHANNEL_TFR },
|
||||||
|
[SND_CHMAP_TFC] = { SND_CHMAP_TFC, SPA_AUDIO_CHANNEL_TFC },
|
||||||
|
[SND_CHMAP_TRL] = { SND_CHMAP_TRL, SPA_AUDIO_CHANNEL_TRL },
|
||||||
|
[SND_CHMAP_TRR] = { SND_CHMAP_TRR, SPA_AUDIO_CHANNEL_TRR },
|
||||||
|
[SND_CHMAP_TRC] = { SND_CHMAP_TRC, SPA_AUDIO_CHANNEL_TRC },
|
||||||
|
[SND_CHMAP_TFLC] = { SND_CHMAP_TFLC, SPA_AUDIO_CHANNEL_TFLC },
|
||||||
|
[SND_CHMAP_TFRC] = { SND_CHMAP_TFRC, SPA_AUDIO_CHANNEL_TFRC },
|
||||||
|
[SND_CHMAP_TSL] = { SND_CHMAP_TSL, SPA_AUDIO_CHANNEL_TSL },
|
||||||
|
[SND_CHMAP_TSR] = { SND_CHMAP_TSR, SPA_AUDIO_CHANNEL_TSR },
|
||||||
|
[SND_CHMAP_LLFE] = { SND_CHMAP_LLFE, SPA_AUDIO_CHANNEL_LLFE },
|
||||||
|
[SND_CHMAP_RLFE] = { SND_CHMAP_RLFE, SPA_AUDIO_CHANNEL_RLFE },
|
||||||
|
[SND_CHMAP_BC] = { SND_CHMAP_BC, SPA_AUDIO_CHANNEL_BC },
|
||||||
|
[SND_CHMAP_BLC] = { SND_CHMAP_BLC, SPA_AUDIO_CHANNEL_BLC },
|
||||||
|
[SND_CHMAP_BRC] = { SND_CHMAP_BRC, SPA_AUDIO_CHANNEL_BRC },
|
||||||
|
};
|
||||||
|
|
||||||
|
static enum snd_pcm_chmap_position channel_to_chmap(enum spa_audio_channel channel)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < SPA_N_ELEMENTS(chmap_info); i++)
|
||||||
|
if (chmap_info[i].channel == channel)
|
||||||
|
return chmap_info[i].pos;
|
||||||
|
return SND_CHMAP_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int snd_pcm_pipewire_set_chmap(snd_pcm_ioplug_t * io,
|
||||||
|
const snd_pcm_chmap_t * map)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static snd_pcm_chmap_t * snd_pcm_pipewire_get_chmap(snd_pcm_ioplug_t * io)
|
||||||
|
{
|
||||||
|
snd_pcm_pipewire_t *pw = io->private_data;
|
||||||
|
snd_pcm_chmap_t *map;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
map = calloc(1, sizeof(snd_pcm_chmap_t) +
|
||||||
|
pw->format.channels * sizeof(unsigned int));
|
||||||
|
map->channels = pw->format.channels;
|
||||||
|
for (i = 0; i < pw->format.channels; i++)
|
||||||
|
map->pos[i] = channel_to_chmap(pw->format.position[i]);
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
static snd_pcm_ioplug_callback_t pipewire_pcm_callback = {
|
static snd_pcm_ioplug_callback_t pipewire_pcm_callback = {
|
||||||
.close = snd_pcm_pipewire_close,
|
.close = snd_pcm_pipewire_close,
|
||||||
.start = snd_pcm_pipewire_start,
|
.start = snd_pcm_pipewire_start,
|
||||||
|
|
@ -530,6 +641,8 @@ static snd_pcm_ioplug_callback_t pipewire_pcm_callback = {
|
||||||
.prepare = snd_pcm_pipewire_prepare,
|
.prepare = snd_pcm_pipewire_prepare,
|
||||||
.poll_revents = snd_pcm_pipewire_poll_revents,
|
.poll_revents = snd_pcm_pipewire_poll_revents,
|
||||||
.hw_params = snd_pcm_pipewire_hw_params,
|
.hw_params = snd_pcm_pipewire_hw_params,
|
||||||
|
.set_chmap = snd_pcm_pipewire_set_chmap,
|
||||||
|
.get_chmap = snd_pcm_pipewire_get_chmap,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int pipewire_set_hw_constraint(snd_pcm_pipewire_t *pw)
|
static int pipewire_set_hw_constraint(snd_pcm_pipewire_t *pw)
|
||||||
|
|
@ -564,6 +677,8 @@ static int pipewire_set_hw_constraint(snd_pcm_pipewire_t *pw)
|
||||||
1, MAX_CHANNELS)) < 0 ||
|
1, MAX_CHANNELS)) < 0 ||
|
||||||
(err = snd_pcm_ioplug_set_param_minmax(&pw->io, SND_PCM_IOPLUG_HW_RATE,
|
(err = snd_pcm_ioplug_set_param_minmax(&pw->io, SND_PCM_IOPLUG_HW_RATE,
|
||||||
1, MAX_RATE)) < 0 ||
|
1, MAX_RATE)) < 0 ||
|
||||||
|
(err = snd_pcm_ioplug_set_param_minmax(&pw->io, SND_PCM_IOPLUG_HW_PERIOD_BYTES,
|
||||||
|
128, 64*1024)) < 0 ||
|
||||||
(err = snd_pcm_ioplug_set_param_minmax(&pw->io, SND_PCM_IOPLUG_HW_PERIODS,
|
(err = snd_pcm_ioplug_set_param_minmax(&pw->io, SND_PCM_IOPLUG_HW_PERIODS,
|
||||||
2, 64)) < 0)
|
2, 64)) < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
@ -634,7 +749,9 @@ static int snd_pcm_pipewire_open(snd_pcm_t **pcmp, const char *name,
|
||||||
const char *node_name,
|
const char *node_name,
|
||||||
const char *playback_node,
|
const char *playback_node,
|
||||||
const char *capture_node,
|
const char *capture_node,
|
||||||
snd_pcm_stream_t stream, int mode)
|
snd_pcm_stream_t stream,
|
||||||
|
int mode,
|
||||||
|
uint32_t flags)
|
||||||
{
|
{
|
||||||
snd_pcm_pipewire_t *pw;
|
snd_pcm_pipewire_t *pw;
|
||||||
int err;
|
int err;
|
||||||
|
|
@ -648,10 +765,11 @@ static int snd_pcm_pipewire_open(snd_pcm_t **pcmp, const char *name,
|
||||||
|
|
||||||
str = getenv("PIPEWIRE_NODE");
|
str = getenv("PIPEWIRE_NODE");
|
||||||
|
|
||||||
pw_log_debug("open %s %d %d '%s'", name, stream, mode, str);
|
pw_log_debug("open %s %d %d %08x '%s'", name, stream, mode, flags, str);
|
||||||
|
|
||||||
pw->fd = -1;
|
pw->fd = -1;
|
||||||
pw->io.poll_fd = -1;
|
pw->io.poll_fd = -1;
|
||||||
|
pw->flags = flags;
|
||||||
|
|
||||||
if (node_name == NULL)
|
if (node_name == NULL)
|
||||||
err = asprintf(&pw->node_name,
|
err = asprintf(&pw->node_name,
|
||||||
|
|
@ -718,6 +836,7 @@ SND_PCM_PLUGIN_DEFINE_FUNC(pipewire)
|
||||||
const char *server_name = NULL;
|
const char *server_name = NULL;
|
||||||
const char *playback_node = NULL;
|
const char *playback_node = NULL;
|
||||||
const char *capture_node = NULL;
|
const char *capture_node = NULL;
|
||||||
|
uint32_t flags = 0;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
pw_init(NULL, NULL);
|
pw_init(NULL, NULL);
|
||||||
|
|
@ -745,11 +864,16 @@ SND_PCM_PLUGIN_DEFINE_FUNC(pipewire)
|
||||||
snd_config_get_string(n, &capture_node);
|
snd_config_get_string(n, &capture_node);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (strcmp(id, "exclusive") == 0) {
|
||||||
|
if (snd_config_get_bool(n))
|
||||||
|
flags |= PW_STREAM_FLAG_EXCLUSIVE;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
SNDERR("Unknown field %s", id);
|
SNDERR("Unknown field %s", id);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = snd_pcm_pipewire_open(pcmp, name, node_name, playback_node, capture_node, stream, mode);
|
err = snd_pcm_pipewire_open(pcmp, name, node_name, playback_node, capture_node, stream, mode, flags);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue