mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
When api.alsa.split-enable=true for ACP device, instruct UCM to not use alsa-lib plugins for SplitPCM devices. Grab the information from UCM for the intended channel remapping, and add the splitting information to the nodes emitted. Session manager can then look at that, and load nodes to do the channel splitting.
317 lines
11 KiB
C
317 lines
11 KiB
C
#ifndef fooalsaucmhfoo
|
|
#define fooalsaucmhfoo
|
|
|
|
/***
|
|
This file is part of PulseAudio.
|
|
|
|
Copyright 2011 Wolfson Microelectronics PLC
|
|
Author Margarita Olaya <magi@slimlogic.co.uk>
|
|
Copyright 2012 Feng Wei <wei.feng@freescale.com>, Freescale Ltd.
|
|
|
|
PulseAudio is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU Lesser General Public License as published
|
|
by the Free Software Foundation; either version 2.1 of the License,
|
|
or (at your option) any later version.
|
|
|
|
PulseAudio is distributed in the hope that it will be useful, but
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
|
along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
|
|
***/
|
|
|
|
#ifdef HAVE_ALSA_UCM
|
|
#include <alsa/use-case.h>
|
|
#else
|
|
typedef void snd_use_case_mgr_t;
|
|
#endif
|
|
|
|
#include "compat.h"
|
|
|
|
#include "alsa-mixer.h"
|
|
|
|
/** For devices: List of verbs, devices or modifiers available */
|
|
#define PA_ALSA_PROP_UCM_NAME "alsa.ucm.name"
|
|
|
|
/** For devices: List of supported devices per verb*/
|
|
#define PA_ALSA_PROP_UCM_DESCRIPTION "alsa.ucm.description"
|
|
|
|
/** For devices: Playback device name e.g PlaybackPCM */
|
|
#define PA_ALSA_PROP_UCM_SINK "alsa.ucm.sink"
|
|
|
|
/** For devices: Capture device name e.g CapturePCM*/
|
|
#define PA_ALSA_PROP_UCM_SOURCE "alsa.ucm.source"
|
|
|
|
/** For devices: Playback roles */
|
|
#define PA_ALSA_PROP_UCM_PLAYBACK_ROLES "alsa.ucm.playback.roles"
|
|
|
|
/** For devices: Playback control device name */
|
|
#define PA_ALSA_PROP_UCM_PLAYBACK_CTL_DEVICE "alsa.ucm.playback.ctldev"
|
|
|
|
/** For devices: Playback control volume ID string. e.g PlaybackVolume */
|
|
#define PA_ALSA_PROP_UCM_PLAYBACK_VOLUME "alsa.ucm.playback.volume"
|
|
|
|
/** For devices: Playback switch e.g PlaybackSwitch */
|
|
#define PA_ALSA_PROP_UCM_PLAYBACK_SWITCH "alsa.ucm.playback.switch"
|
|
|
|
/** For devices: Playback mixer device name */
|
|
#define PA_ALSA_PROP_UCM_PLAYBACK_MIXER_DEVICE "alsa.ucm.playback.mixer.device"
|
|
|
|
/** For devices: Playback mixer identifier */
|
|
#define PA_ALSA_PROP_UCM_PLAYBACK_MIXER_ELEM "alsa.ucm.playback.mixer.element"
|
|
|
|
/** For devices: Playback mixer master identifier */
|
|
#define PA_ALSA_PROP_UCM_PLAYBACK_MASTER_ELEM "alsa.ucm.playback.master.element"
|
|
|
|
/** For devices: Playback mixer master type */
|
|
#define PA_ALSA_PROP_UCM_PLAYBACK_MASTER_TYPE "alsa.ucm.playback.master.type"
|
|
|
|
/** For devices: Playback mixer master identifier */
|
|
#define PA_ALSA_PROP_UCM_PLAYBACK_MASTER_ID "alsa.ucm.playback.master.id"
|
|
|
|
/** For devices: Playback mixer master type */
|
|
#define PA_ALSA_PROP_UCM_PLAYBACK_MASTER_TYPE "alsa.ucm.playback.master.type"
|
|
|
|
/** For devices: Playback priority */
|
|
#define PA_ALSA_PROP_UCM_PLAYBACK_PRIORITY "alsa.ucm.playback.priority"
|
|
|
|
/** For devices: Playback rate */
|
|
#define PA_ALSA_PROP_UCM_PLAYBACK_RATE "alsa.ucm.playback.rate"
|
|
|
|
/** For devices: Playback channels */
|
|
#define PA_ALSA_PROP_UCM_PLAYBACK_CHANNELS "alsa.ucm.playback.channels"
|
|
|
|
/** For devices: Capture roles */
|
|
#define PA_ALSA_PROP_UCM_CAPTURE_ROLES "alsa.ucm.capture.roles"
|
|
|
|
/** For devices: Capture control device name */
|
|
#define PA_ALSA_PROP_UCM_CAPTURE_CTL_DEVICE "alsa.ucm.capture.ctldev"
|
|
|
|
/** For devices: Capture controls volume ID string. e.g CaptureVolume */
|
|
#define PA_ALSA_PROP_UCM_CAPTURE_VOLUME "alsa.ucm.capture.volume"
|
|
|
|
/** For devices: Capture switch e.g CaptureSwitch */
|
|
#define PA_ALSA_PROP_UCM_CAPTURE_SWITCH "alsa.ucm.capture.switch"
|
|
|
|
/** For devices: Capture mixer device name */
|
|
#define PA_ALSA_PROP_UCM_CAPTURE_MIXER_DEVICE "alsa.ucm.capture.mixer.device"
|
|
|
|
/** For devices: Capture mixer identifier */
|
|
#define PA_ALSA_PROP_UCM_CAPTURE_MIXER_ELEM "alsa.ucm.capture.mixer.element"
|
|
|
|
/** For devices: Capture mixer identifier */
|
|
#define PA_ALSA_PROP_UCM_CAPTURE_MASTER_ELEM "alsa.ucm.capture.master.element"
|
|
|
|
/** For devices: Capture mixer identifier */
|
|
#define PA_ALSA_PROP_UCM_CAPTURE_MASTER_TYPE "alsa.ucm.capture.master.type"
|
|
|
|
/** For devices: Capture mixer identifier */
|
|
#define PA_ALSA_PROP_UCM_CAPTURE_MASTER_ID "alsa.ucm.capture.master.id"
|
|
|
|
/** For devices: Capture mixer identifier */
|
|
#define PA_ALSA_PROP_UCM_CAPTURE_MASTER_TYPE "alsa.ucm.capture.master.type"
|
|
|
|
/** For devices: Capture priority */
|
|
#define PA_ALSA_PROP_UCM_CAPTURE_PRIORITY "alsa.ucm.capture.priority"
|
|
|
|
/** For devices: Capture rate */
|
|
#define PA_ALSA_PROP_UCM_CAPTURE_RATE "alsa.ucm.capture.rate"
|
|
|
|
/** For devices: Capture channels */
|
|
#define PA_ALSA_PROP_UCM_CAPTURE_CHANNELS "alsa.ucm.capture.channels"
|
|
|
|
/** For devices: Quality of Service */
|
|
#define PA_ALSA_PROP_UCM_QOS "alsa.ucm.qos"
|
|
|
|
/** For devices: The modifier (if any) that this device corresponds to */
|
|
#define PA_ALSA_PROP_UCM_MODIFIER "alsa.ucm.modifier"
|
|
|
|
/* Corresponds to the "JackCTL" UCM value. */
|
|
#define PA_ALSA_PROP_UCM_JACK_DEVICE "alsa.ucm.jack_device"
|
|
|
|
/* Corresponds to the "JackControl" UCM value. */
|
|
#define PA_ALSA_PROP_UCM_JACK_CONTROL "alsa.ucm.jack_control"
|
|
|
|
/* Corresponds to the "JackHWMute" UCM value. */
|
|
#define PA_ALSA_PROP_UCM_JACK_HW_MUTE "alsa.ucm.jack_hw_mute"
|
|
|
|
typedef struct pa_alsa_ucm_verb pa_alsa_ucm_verb;
|
|
typedef struct pa_alsa_ucm_modifier pa_alsa_ucm_modifier;
|
|
typedef struct pa_alsa_ucm_device pa_alsa_ucm_device;
|
|
typedef struct pa_alsa_ucm_config pa_alsa_ucm_config;
|
|
typedef struct pa_alsa_ucm_mapping_context pa_alsa_ucm_mapping_context;
|
|
typedef struct pa_alsa_ucm_profile_context pa_alsa_ucm_profile_context;
|
|
typedef struct pa_alsa_ucm_port_data pa_alsa_ucm_port_data;
|
|
typedef struct pa_alsa_ucm_volume pa_alsa_ucm_volume;
|
|
typedef struct pa_alsa_ucm_split pa_alsa_ucm_split;
|
|
|
|
int pa_alsa_ucm_query_profiles(pa_alsa_ucm_config *ucm, int card_index);
|
|
pa_alsa_profile_set* pa_alsa_ucm_add_profile_set(pa_alsa_ucm_config *ucm, pa_channel_map *default_channel_map);
|
|
int pa_alsa_ucm_set_profile(pa_alsa_ucm_config *ucm, pa_card *card, pa_alsa_profile *new_profile, pa_alsa_profile *old_profile);
|
|
|
|
int pa_alsa_ucm_get_verb(snd_use_case_mgr_t *uc_mgr, const char *verb_name, const char *verb_desc, pa_alsa_ucm_verb **p_verb);
|
|
|
|
void pa_alsa_ucm_add_ports(
|
|
pa_hashmap **hash,
|
|
pa_proplist *proplist,
|
|
pa_alsa_ucm_mapping_context *context,
|
|
bool is_sink,
|
|
pa_card *card,
|
|
snd_pcm_t *pcm_handle,
|
|
bool ignore_dB);
|
|
void pa_alsa_ucm_add_port(
|
|
pa_hashmap *hash,
|
|
pa_alsa_ucm_mapping_context *context,
|
|
bool is_sink,
|
|
pa_hashmap *ports,
|
|
pa_card_profile *cp,
|
|
pa_core *core);
|
|
int pa_alsa_ucm_set_port(pa_alsa_ucm_mapping_context *context, pa_device_port *port);
|
|
|
|
void pa_alsa_ucm_free(pa_alsa_ucm_config *ucm);
|
|
void pa_alsa_ucm_mapping_context_free(pa_alsa_ucm_mapping_context *context);
|
|
|
|
void pa_alsa_ucm_roled_stream_begin(pa_alsa_ucm_config *ucm, const char *role, pa_direction_t dir);
|
|
void pa_alsa_ucm_roled_stream_end(pa_alsa_ucm_config *ucm, const char *role, pa_direction_t dir);
|
|
|
|
/* UCM - Use Case Manager is available on some audio cards */
|
|
|
|
struct pa_alsa_ucm_split {
|
|
/* UCM SplitPCM channel remapping */
|
|
bool leader;
|
|
int hw_channels;
|
|
int channels;
|
|
int idx[PA_CHANNELS_MAX];
|
|
enum snd_pcm_chmap_position pos[PA_CHANNELS_MAX];
|
|
};
|
|
|
|
struct pa_alsa_ucm_device {
|
|
PA_LLIST_FIELDS(pa_alsa_ucm_device);
|
|
|
|
pa_proplist *proplist;
|
|
|
|
pa_device_port_type_t type;
|
|
|
|
unsigned playback_priority;
|
|
unsigned capture_priority;
|
|
|
|
unsigned playback_rate;
|
|
unsigned capture_rate;
|
|
|
|
unsigned playback_channels;
|
|
unsigned capture_channels;
|
|
|
|
/* These may be different per verb, so we store this as a hashmap of verb -> volume_control. We might eventually want to
|
|
* make this a hashmap of verb -> per-verb-device-properties-struct. */
|
|
pa_hashmap *playback_volumes;
|
|
pa_hashmap *capture_volumes;
|
|
|
|
pa_alsa_mapping *playback_mapping;
|
|
pa_alsa_mapping *capture_mapping;
|
|
|
|
pa_idxset *conflicting_devices;
|
|
pa_idxset *supported_devices;
|
|
|
|
/* One device may be part of multiple ports, since each device has
|
|
* a dedicated port, and in addition to that we sometimes generate ports
|
|
* that represent combinations of devices. */
|
|
pa_dynarray *ucm_ports; /* struct ucm_port */
|
|
|
|
pa_alsa_jack *jack;
|
|
pa_dynarray *hw_mute_jacks; /* pa_alsa_jack */
|
|
pa_available_t available;
|
|
|
|
char *eld_mixer_device_name;
|
|
int eld_device;
|
|
|
|
pa_alsa_ucm_split *playback_split;
|
|
pa_alsa_ucm_split *capture_split;
|
|
};
|
|
|
|
void pa_alsa_ucm_device_update_available(pa_alsa_ucm_device *device);
|
|
|
|
struct pa_alsa_ucm_modifier {
|
|
PA_LLIST_FIELDS(pa_alsa_ucm_modifier);
|
|
|
|
pa_proplist *proplist;
|
|
|
|
pa_idxset *conflicting_devices;
|
|
pa_idxset *supported_devices;
|
|
|
|
pa_direction_t action_direction;
|
|
|
|
char *media_role;
|
|
|
|
/* Non-NULL if the modifier has its own PlaybackPCM/CapturePCM */
|
|
pa_alsa_mapping *playback_mapping;
|
|
pa_alsa_mapping *capture_mapping;
|
|
|
|
/* Count how many role matched streams are running */
|
|
int enabled_counter;
|
|
};
|
|
|
|
struct pa_alsa_ucm_verb {
|
|
PA_LLIST_FIELDS(pa_alsa_ucm_verb);
|
|
|
|
pa_proplist *proplist;
|
|
unsigned priority;
|
|
|
|
PA_LLIST_HEAD(pa_alsa_ucm_device, devices);
|
|
PA_LLIST_HEAD(pa_alsa_ucm_modifier, modifiers);
|
|
};
|
|
|
|
struct pa_alsa_ucm_config {
|
|
pa_sample_spec default_sample_spec;
|
|
pa_channel_map default_channel_map;
|
|
unsigned default_fragment_size_msec;
|
|
unsigned default_n_fragments;
|
|
bool split_enable;
|
|
|
|
snd_use_case_mgr_t *ucm_mgr;
|
|
pa_alsa_ucm_verb *active_verb;
|
|
char *alib_prefix;
|
|
|
|
pa_hashmap *mixers;
|
|
PA_LLIST_HEAD(pa_alsa_ucm_verb, verbs);
|
|
PA_LLIST_HEAD(pa_alsa_jack, jacks);
|
|
};
|
|
|
|
struct pa_alsa_ucm_mapping_context {
|
|
pa_alsa_ucm_config *ucm;
|
|
pa_direction_t direction;
|
|
|
|
pa_alsa_ucm_device *ucm_device;
|
|
pa_alsa_ucm_modifier *ucm_modifier;
|
|
};
|
|
|
|
struct pa_alsa_ucm_profile_context {
|
|
pa_alsa_ucm_verb *verb;
|
|
};
|
|
|
|
struct pa_alsa_ucm_port_data {
|
|
pa_alsa_ucm_config *ucm;
|
|
pa_device_port *core_port;
|
|
|
|
pa_alsa_ucm_device *device;
|
|
|
|
/* verb name -> pa_alsa_path for volume control */
|
|
pa_hashmap *paths;
|
|
/* Current path, set when activating verb */
|
|
pa_alsa_path *path;
|
|
|
|
/* ELD info */
|
|
char *eld_mixer_device_name;
|
|
int eld_device; /* PCM device number */
|
|
};
|
|
|
|
long pa_alsa_ucm_port_device_status(pa_alsa_ucm_port_data *data);
|
|
|
|
struct pa_alsa_ucm_volume {
|
|
char *mixer_elem; /* mixer element identifier */
|
|
char *master_elem; /* master mixer element identifier */
|
|
char *master_type;
|
|
};
|
|
|
|
#endif
|