We truncated the diff of some files because they were too big.
If you want to see the full diff for every file, click here.
Changes of Revision 26
pipewire-aptx.changes
Changed
x
1
2
-------------------------------------------------------------------
3
+Fri Apr 14 13:35:34 UTC 2023 - Bjørn Lie <zaitor@opensuse.org>
4
+
5
+- Update to version 0.3.69
6
+
7
+-------------------------------------------------------------------
8
Sat Apr 8 17:49:24 UTC 2023 - Bjørn Lie <zaitor@opensuse.org>
9
10
- Update to version 0.3.68
11
pipewire-aptx.spec
Changed
19
1
2
%define soversion 0_2
3
4
Name: pipewire-aptx
5
-Version: 0.3.68
6
+Version: 0.3.69
7
Release: 0
8
Summary: PipeWire Bluetooth aptX codec plugin
9
License: MIT
10
11
12
BuildRequires: c++_compiler
13
BuildRequires: c_compiler
14
-BuildRequires: meson >= 0.59.0
15
+BuildRequires: meson >= 0.61.1
16
BuildRequires: pkgconfig
17
BuildRequires: pkgconfig(bluez)
18
BuildRequires: pkgconfig(dbus-1)
19
pipewire-0.3.68.tar.gz/NEWS -> pipewire-0.3.69.tar.gz/NEWS
Changed
71
1
2
+# PipeWire 0.3.69 (2023-04-13)
3
+
4
+This is a quick bugfix release that is API and ABI compatible with previous
5
+0.3.x releases.
6
+
7
+## Highlights
8
+ - Reverted the UCM changes, they seem to cause regressions causing audio
9
+ to be muted in some cases.
10
+ - Fix a regression in the scheduler where a driver node might not be marked
11
+ runnable in some cases, like when echo-cancel is used. (#3145)
12
+ - Handle links from the driver to itself. This makes the midi bridge work
13
+ again. (#3153)
14
+ - ALSA rate matching for sources was fixed. It would previously wait too
15
+ long for rate matching and then cause drift. This should reduce
16
+ crackling and stuttering whan capturing in low latency.
17
+ - Fix the GStreamer clock to make cheese video recording work again. (#3149)
18
+ - More fixes and improvements.
19
+
20
+## PipeWire
21
+ - Fix a regression in the scheduler where a driver node might not be marked
22
+ runnable in some cases, like when echo-cancel is used. (#3145)
23
+ - Handle links from the driver to itself. This makes the midi bridge work
24
+ again. (#3153)
25
+ - Some man pages were improved.
26
+ - Fix a potential crash when thread-loop is destroyed before the loop.
27
+ (#3150)
28
+
29
+## Modules
30
+ - A new raw biquad filter was added to filter-chain. You can manually set the
31
+ 6 parameters and you can use this to create custom filters per sample rate.
32
+ (#3139)
33
+ - The echo-canceler now supports different channels for the capture and playback
34
+ streams.
35
+
36
+## SPA
37
+ - A SB Audigy specific profile set was added to make better use of the
38
+ controls. (#2934)
39
+ - More ALSA IRQ based scheduling improvements.
40
+ - ALSA rate matching for sources was fixed. It would previously wait too
41
+ long for rate matching and then cause drift. This should reduce
42
+ crackling and stuttering whan capturing in low latency.
43
+ - The echo-cancel plugin API has a new method to make it possible to have
44
+ different channels for capture, source and playback.
45
+ - Reverted the UCM changes, they seem to cause regressions causing audio
46
+ to be muted in some cases.
47
+
48
+## Bluetooth
49
+ - Many more BAP fixes and improvements. Devices are now created as a set
50
+ and can be combined into one device by the session manager.
51
+
52
+## GStreamer
53
+ - Fix the GStreamer clock to make cheese video recording work again. (#3149)
54
+
55
+
56
+Older versions:
57
+
58
# PipeWire 0.3.68 (2023-04-06)
59
60
This is a bugfix release that is API and ABI compatible with previous
61
62
## GStreamer
63
- Sort the device by priority in deviceprovider. (#3072)
64
65
-
66
-Older versions:
67
-
68
# PipeWire 0.3.67 (2023-03-09)
69
70
This is a bugfix release that is API and ABI compatible with previous
71
pipewire-0.3.68.tar.gz/man/pipewire.conf.5.rst.in -> pipewire-0.3.69.tar.gz/man/pipewire.conf.5.rst.in
Changed
11
1
2
of use, a relaxed format may be used where:
3
4
* ``:`` to delimit keys and values can be substuted by ``=`` or a space.
5
- * ``"`` around keys and string can be omited as long as no special characters
6
- are used in the strings.
7
+ * ``"`` around keys and string can be omited as long as no special characters are used in the strings.
8
* ``,`` to separate objects can be replaced with a whitespace character.
9
* ``#`` can be used to start a comment until the line end
10
11
pipewire-0.3.68.tar.gz/man/pw-cli.1.rst.in -> pipewire-0.3.69.tar.gz/man/pw-cli.1.rst.in
Changed
12
1
2
send-command *object-id*
3
Send a command to an object.
4
5
-
6
-EXAMPLES
7
-========
8
-
9
AUTHORS
10
=======
11
12
pipewire-0.3.68.tar.gz/man/pw-metadata.1.rst.in -> pipewire-0.3.69.tar.gz/man/pw-metadata.1.rst.in
Changed
28
1
2
Keeps running and log the changes to the metadata.
3
4
-d | --delete
5
+ Delete all metadata for *id* or for the specified *key* of object *id*.
6
+ Without any option, all metadata is removed.
7
8
- Delete all metadata for *id* or for the
9
- specified *key* of object *id*
10
+-n | --name
11
+ Metadata name (Default: "default").
12
13
- Without any option, all metadata is removed
14
+EXAMPLES
15
+========
16
+
17
+**pw-metadata**
18
+ Show metadata in default name.
19
+
20
+**pw-metadata** -n settings 0
21
+ Display settings.
22
+
23
+**pw-metadata** -n settings 0 clock.quantum 1024
24
+ Change clock.quantum to 1024.
25
26
AUTHORS
27
=======
28
pipewire-0.3.68.tar.gz/meson.build -> pipewire-0.3.69.tar.gz/meson.build
Changed
8
1
2
project('pipewire', 'c' ,
3
- version : '0.3.68',
4
+ version : '0.3.69',
5
license : 'MIT', 'LGPL-2.1-or-later', 'GPL-2.0-only' ,
6
meson_version : '>= 0.61.1',
7
default_options : 'warning_level=3',
8
pipewire-0.3.68.tar.gz/pipewire-jack/src/pipewire-jack.c -> pipewire-0.3.69.tar.gz/pipewire-jack/src/pipewire-jack.c
Changed
97
1
2
return c->sample_rate == sample_rate;
3
}
4
5
+static inline uint64_t get_time_ns(void)
6
+{
7
+ struct timespec ts;
8
+ clock_gettime(CLOCK_MONOTONIC, &ts);
9
+ return SPA_TIMESPEC_TO_NSEC(&ts);
10
+}
11
+
12
static inline uint32_t cycle_run(struct client *c)
13
{
14
uint64_t cmd;
15
- struct timespec ts;
16
int fd = c->socket_source->fd;
17
struct spa_io_position *pos = c->rt.position;
18
struct pw_node_activation *activation = c->activation;
19
20
if (SPA_UNLIKELY(cmd > 1))
21
pw_log_info("%p: missed %"PRIu64" wakeups", c, cmd - 1);
22
23
- clock_gettime(CLOCK_MONOTONIC, &ts);
24
activation->status = PW_NODE_ACTIVATION_AWAKE;
25
- activation->awake_time = SPA_TIMESPEC_TO_NSEC(&ts);
26
+ activation->awake_time = get_time_ns();
27
28
if (SPA_UNLIKELY(c->first)) {
29
if (c->thread_init_callback)
30
31
32
static inline void signal_sync(struct client *c)
33
{
34
- struct timespec ts;
35
uint64_t cmd, nsec;
36
struct link *l;
37
struct pw_node_activation *activation = c->activation;
38
39
complete_process(c, c->buffer_frames);
40
41
- clock_gettime(CLOCK_MONOTONIC, &ts);
42
- nsec = SPA_TIMESPEC_TO_NSEC(&ts);
43
+ nsec = get_time_ns();
44
activation->status = PW_NODE_ACTIVATION_FINISHED;
45
activation->finish_time = nsec;
46
47
48
{
49
struct client *c = (struct client *) client;
50
struct spa_io_position *pos;
51
- struct timespec ts;
52
uint64_t diff;
53
54
spa_return_val_if_fail(c != NULL, 0);
55
56
if (SPA_UNLIKELY((pos = c->rt.position) == NULL))
57
return 0;
58
59
- clock_gettime(CLOCK_MONOTONIC, &ts);
60
- diff = SPA_TIMESPEC_TO_NSEC(&ts) - pos->clock.nsec;
61
+ diff = get_time_ns() - pos->clock.nsec;
62
return (jack_nframes_t) floor(((double)c->sample_rate * diff) / SPA_NSEC_PER_SEC);
63
}
64
65
SPA_EXPORT
66
jack_nframes_t jack_frame_time (const jack_client_t *client)
67
{
68
- struct timespec ts;
69
- clock_gettime(CLOCK_MONOTONIC, &ts);
70
- return jack_time_to_frames(client, SPA_TIMESPEC_TO_USEC(&ts));
71
+ return jack_time_to_frames(client, jack_get_time());
72
}
73
74
SPA_EXPORT
75
76
SPA_EXPORT
77
jack_time_t jack_get_time(void)
78
{
79
- struct timespec ts;
80
- clock_gettime(CLOCK_MONOTONIC, &ts);
81
- return SPA_TIMESPEC_TO_USEC(&ts);
82
+ return get_time_ns()/SPA_NSEC_PER_USEC;
83
}
84
85
SPA_EXPORT
86
87
running = pos->clock.position - pos->offset;
88
89
if (pos->state == SPA_IO_POSITION_STATE_RUNNING) {
90
- struct timespec ts;
91
- clock_gettime(CLOCK_MONOTONIC, &ts);
92
- uint64_t nsecs = SPA_TIMESPEC_TO_NSEC(&ts) - pos->clock.nsec;
93
+ uint64_t nsecs = get_time_ns() - pos->clock.nsec;
94
running += (uint64_t)floor((((double) c->sample_rate) / SPA_NSEC_PER_SEC) * nsecs);
95
}
96
seg = &pos->segments0;
97
pipewire-0.3.68.tar.gz/spa/include/spa/interfaces/audio/aec.h -> pipewire-0.3.69.tar.gz/spa/include/spa/interfaces/audio/aec.h
Changed
31
1
2
};
3
4
struct spa_audio_aec_methods {
5
-#define SPA_VERSION_AUDIO_AEC_METHODS 2
6
+#define SPA_VERSION_AUDIO_AEC_METHODS 3
7
uint32_t version;
8
9
int (*add_listener) (void *object,
10
11
int (*enum_props) (void* object, int index, struct spa_pod_builder* builder);
12
int (*get_params) (void* object, struct spa_pod_builder* builder);
13
int (*set_params) (void *object, const struct spa_pod *args);
14
+
15
+ /* version 1:3 */
16
+ int (*init2) (void *object, const struct spa_dict *args,
17
+ struct spa_audio_info_raw *play_info,
18
+ struct spa_audio_info_raw *rec_info,
19
+ struct spa_audio_info_raw *out_info);
20
};
21
22
#define spa_audio_aec_method(o,method,version,...) \
23
24
#define spa_audio_aec_enum_props(o,...) spa_audio_aec_method(o, enum_props, 2, __VA_ARGS__)
25
#define spa_audio_aec_get_params(o,...) spa_audio_aec_method(o, get_params, 2, __VA_ARGS__)
26
#define spa_audio_aec_set_params(o,...) spa_audio_aec_method(o, set_params, 2, __VA_ARGS__)
27
+#define spa_audio_aec_init2(o,...) spa_audio_aec_method(o, init2, 3, __VA_ARGS__)
28
29
#ifdef __cplusplus
30
} /* extern "C" */
31
pipewire-0.3.68.tar.gz/spa/plugins/aec/aec-webrtc.cpp -> pipewire-0.3.69.tar.gz/spa/plugins/aec/aec-webrtc.cpp
Changed
150
1
2
3
struct spa_log *log;
4
std::unique_ptr<webrtc::AudioProcessing> apm;
5
- spa_audio_info_raw info;
6
+ spa_audio_info_raw rec_info;
7
+ spa_audio_info_raw out_info;
8
+ spa_audio_info_raw play_info;
9
std::unique_ptr<float *> play_buffer, rec_buffer, out_buffer;
10
};
11
12
13
return default_value;
14
}
15
16
-static int webrtc_init(void *object, const struct spa_dict *args, const struct spa_audio_info_raw *info)
17
+static int webrtc_init2(void *object, const struct spa_dict *args,
18
+ struct spa_audio_info_raw *rec_info, struct spa_audio_info_raw *out_info,
19
+ struct spa_audio_info_raw *play_info)
20
{
21
auto impl = static_cast<struct impl_data*>(object);
22
+ int res;
23
24
bool extended_filter = webrtc_get_spa_bool(args, "webrtc.extended_filter", true);
25
bool delay_agnostic = webrtc_get_spa_bool(args, "webrtc.delay_agnostic", true);
26
27
config.Set<webrtc::ExperimentalNs>(new webrtc::ExperimentalNs(experimental_ns));
28
29
webrtc::ProcessingConfig pconfig = {{
30
- webrtc::StreamConfig(info->rate, info->channels, false), /* input stream */
31
- webrtc::StreamConfig(info->rate, info->channels, false), /* output stream */
32
- webrtc::StreamConfig(info->rate, info->channels, false), /* reverse input stream */
33
- webrtc::StreamConfig(info->rate, info->channels, false), /* reverse output stream */
34
+ webrtc::StreamConfig(rec_info->rate, rec_info->channels, false), /* input stream */
35
+ webrtc::StreamConfig(out_info->rate, out_info->channels, false), /* output stream */
36
+ webrtc::StreamConfig(play_info->rate, play_info->channels, false), /* reverse input stream */
37
+ webrtc::StreamConfig(play_info->rate, play_info->channels, false), /* reverse output stream */
38
}};
39
40
auto apm = std::unique_ptr<webrtc::AudioProcessing>(webrtc::AudioProcessing::Create(config));
41
- if (apm->Initialize(pconfig) != webrtc::AudioProcessing::kNoError) {
42
- spa_log_error(impl->log, "Error initialising webrtc audio processing module");
43
- return -1;
44
+ if ((res = apm->Initialize(pconfig)) != webrtc::AudioProcessing::kNoError) {
45
+ spa_log_error(impl->log, "Error initialising webrtc audio processing module: %d", res);
46
+ return -EINVAL;
47
}
48
49
apm->high_pass_filter()->Enable(high_pass_filter);
50
51
apm->gain_control()->set_mode(webrtc::GainControl::kAdaptiveDigital);
52
apm->gain_control()->Enable(gain_control);
53
impl->apm = std::move(apm);
54
- impl->info = *info;
55
- impl->play_buffer = std::make_unique<float *>(info->channels);
56
- impl->rec_buffer = std::make_unique<float *>(info->channels);
57
- impl->out_buffer = std::make_unique<float *>(info->channels);
58
+ impl->rec_info = *rec_info;
59
+ impl->out_info = *out_info;
60
+ impl->play_info = *play_info;
61
+ impl->play_buffer = std::make_unique<float *>(play_info->channels);
62
+ impl->rec_buffer = std::make_unique<float *>(rec_info->channels);
63
+ impl->out_buffer = std::make_unique<float *>(out_info->channels);
64
return 0;
65
}
66
67
+static int webrtc_init(void *object, const struct spa_dict *args,
68
+ const struct spa_audio_info_raw *info)
69
+{
70
+ int res;
71
+ struct spa_audio_info_raw rec_info = *info;
72
+ struct spa_audio_info_raw out_info = *info;
73
+ struct spa_audio_info_raw play_info = *info;
74
+ res = webrtc_init2(object, args, &rec_info, &out_info, &play_info);
75
+ if (rec_info.channels != out_info.channels)
76
+ res = -EINVAL;
77
+ return res;
78
+}
79
+
80
static int webrtc_run(void *object, const float *rec, const float *play, float *out, uint32_t n_samples)
81
{
82
auto impl = static_cast<struct impl_data*>(object);
83
- webrtc::StreamConfig config =
84
- webrtc::StreamConfig(impl->info.rate, impl->info.channels, false);
85
- unsigned int num_blocks = n_samples * 1000 / impl->info.rate / 10;
86
+ int res;
87
+
88
+ webrtc::StreamConfig play_config =
89
+ webrtc::StreamConfig(impl->play_info.rate, impl->play_info.channels, false);
90
+ webrtc::StreamConfig rec_config =
91
+ webrtc::StreamConfig(impl->rec_info.rate, impl->rec_info.channels, false);
92
+ webrtc::StreamConfig out_config =
93
+ webrtc::StreamConfig(impl->out_info.rate, impl->out_info.channels, false);
94
+ unsigned int num_blocks = n_samples * 1000 / impl->play_info.rate / 10;
95
96
- if (n_samples * 1000 / impl->info.rate % 10 != 0) {
97
+ if (n_samples * 1000 / impl->play_info.rate % 10 != 0) {
98
spa_log_error(impl->log, "Buffers must be multiples of 10ms in length (currently %u samples)", n_samples);
99
- return -1;
100
+ return -EINVAL;
101
}
102
103
for (size_t i = 0; i < num_blocks; i ++) {
104
- for (size_t j = 0; j < impl->info.channels; j++) {
105
- impl->play_bufferj = const_cast<float *>(playj) + config.num_frames() * i;
106
- impl->rec_bufferj = const_cast<float *>(recj) + config.num_frames() * i;
107
- impl->out_bufferj = outj + config.num_frames() * i;
108
- }
109
+ for (size_t j = 0; j < impl->play_info.channels; j++)
110
+ impl->play_bufferj = const_cast<float *>(playj) + play_config.num_frames() * i;
111
+ for (size_t j = 0; j < impl->rec_info.channels; j++)
112
+ impl->rec_bufferj = const_cast<float *>(recj) + rec_config.num_frames() * i;
113
+ for (size_t j = 0; j < impl->out_info.channels; j++)
114
+ impl->out_bufferj = outj + out_config.num_frames() * i;
115
+
116
/* FIXME: ProcessReverseStream may change the playback buffer, in which
117
* case we should use that, if we ever expose the intelligibility
118
* enhancer */
119
- if (impl->apm->ProcessReverseStream(impl->play_buffer.get(), config, config, impl->play_buffer.get()) !=
120
+ if ((res = impl->apm->ProcessReverseStream(impl->play_buffer.get(),
121
+ play_config, play_config, impl->play_buffer.get())) !=
122
webrtc::AudioProcessing::kNoError) {
123
- spa_log_error(impl->log, "Processing reverse stream failed");
124
+ spa_log_error(impl->log, "Processing reverse stream failed: %d", res);
125
}
126
127
// Extra delay introduced by multiple frames
128
impl->apm->set_stream_delay_ms((num_blocks - 1) * 10);
129
130
- if (impl->apm->ProcessStream(impl->rec_buffer.get(), config, config, impl->out_buffer.get()) !=
131
+ if ((res = impl->apm->ProcessStream(impl->rec_buffer.get(),
132
+ rec_config, out_config, impl->out_buffer.get())) !=
133
webrtc::AudioProcessing::kNoError) {
134
- spa_log_error(impl->log, "Processing stream failed");
135
+ spa_log_error(impl->log, "Processing stream failed: %d", res);
136
}
137
}
138
-
139
return 0;
140
}
141
142
143
.add_listener = NULL,
144
.init = webrtc_init,
145
.run = webrtc_run,
146
+ .init2 = webrtc_init2,
147
};
148
149
static int impl_get_interface(struct spa_handle *handle, const char *type, void **interface)
150
pipewire-0.3.68.tar.gz/spa/plugins/alsa/acp/acp.c -> pipewire-0.3.69.tar.gz/spa/plugins/alsa/acp/acp.c
Changed
131
1
2
devstr, NULL, &m->sample_spec,
3
&m->channel_map, SND_PCM_STREAM_PLAYBACK,
4
&try_period_size, &try_buffer_size,
5
- 0, NULL, NULL, NULL, NULL, false))) {
6
+ 0, NULL, NULL, false))) {
7
pa_alsa_init_proplist_pcm(NULL, m->output_proplist, m->output_pcm);
8
pa_proplist_setf(m->output_proplist, "clock.name", "api.alsa.%u", index);
9
pa_alsa_close(&m->output_pcm);
10
11
devstr, NULL, &m->sample_spec,
12
&m->channel_map, SND_PCM_STREAM_CAPTURE,
13
&try_period_size, &try_buffer_size,
14
- 0, NULL, NULL, NULL, NULL, false))) {
15
+ 0, NULL, NULL, false))) {
16
pa_alsa_init_proplist_pcm(NULL, m->input_proplist, m->input_pcm);
17
pa_proplist_setf(m->input_proplist, "clock.name", "api.alsa.%u", index);
18
pa_alsa_close(&m->input_pcm);
19
20
pa_dynarray_append(&impl->out.devices, dev);
21
}
22
if (impl->use_ucm) {
23
- if (m->ucm_context.ucm_device) {
24
- pa_alsa_ucm_add_port(NULL, &m->ucm_context,
25
+ if (m->ucm_context.ucm_devices) {
26
+ pa_alsa_ucm_add_ports_combination(NULL, &m->ucm_context,
27
true, impl->ports, ap, NULL);
28
pa_alsa_ucm_add_ports(&dev->ports, m->proplist, &m->ucm_context,
29
true, impl, dev->pcm_handle, impl->profile_set->ignore_dB);
30
31
}
32
33
if (impl->use_ucm) {
34
- if (m->ucm_context.ucm_device) {
35
- pa_alsa_ucm_add_port(NULL, &m->ucm_context,
36
+ if (m->ucm_context.ucm_devices) {
37
+ pa_alsa_ucm_add_ports_combination(NULL, &m->ucm_context,
38
false, impl->ports, ap, NULL);
39
pa_alsa_ucm_add_ports(&dev->ports, m->proplist, &m->ucm_context,
40
false, impl, dev->pcm_handle, impl->profile_set->ignore_dB);
41
42
static int report_jack_state(snd_mixer_elem_t *melem, unsigned int mask)
43
{
44
pa_card *impl = snd_mixer_elem_get_callback_private(melem);
45
- snd_hctl_elem_t **_elem = snd_mixer_elem_get_private(melem), *elem;
46
+ snd_hctl_elem_t *elem = snd_mixer_elem_get_private(melem);
47
snd_ctl_elem_value_t *elem_value;
48
bool plugged_in, any_input_port_available;
49
void *state;
50
51
enum acp_available active_available = ACP_AVAILABLE_UNKNOWN;
52
size_t size;
53
54
- pa_assert(_elem);
55
- elem = *_elem;
56
#if 0
57
/* Changing the jack state may cause a port change, and a port change will
58
* make the sink or source change the mixer settings. If there are multiple
59
60
static int hdmi_eld_changed(snd_mixer_elem_t *melem, unsigned int mask)
61
{
62
pa_card *impl = snd_mixer_elem_get_callback_private(melem);
63
- snd_hctl_elem_t **_elem = snd_mixer_elem_get_private(melem), *elem;
64
- int device;
65
+ snd_hctl_elem_t *elem = snd_mixer_elem_get_private(melem);
66
+ int device = snd_hctl_elem_get_device(elem);
67
const char *old_monitor_name;
68
pa_device_port *p;
69
pa_hdmi_eld eld;
70
bool changed = false;
71
72
- pa_assert(_elem);
73
- elem = *_elem;
74
- device = snd_hctl_elem_get_device(elem);
75
-
76
if (mask == SND_CTL_EVENT_MASK_REMOVE)
77
return 0;
78
79
80
* will be NULL, but the UCM device enable sequence will still need to be
81
* executed. */
82
if (dev->active_port && dev->ucm_context) {
83
- if ((res = pa_alsa_ucm_set_port(dev->ucm_context, dev->active_port)) < 0)
84
+ if ((res = pa_alsa_ucm_set_port(dev->ucm_context, dev->active_port,
85
+ dev->direction == PA_ALSA_DIRECTION_OUTPUT)) < 0)
86
return res;
87
}
88
89
90
/* if UCM is available for this card then update the verb */
91
if (impl->use_ucm && !(np->profile.flags & ACP_PROFILE_PRO)) {
92
if ((res = pa_alsa_ucm_set_profile(&impl->ucm, impl,
93
- np->profile.flags & ACP_PROFILE_OFF ? NULL : np, op)) < 0) {
94
+ np->profile.flags & ACP_PROFILE_OFF ? NULL : np->profile.name,
95
+ op ? op->profile.name : NULL)) < 0) {
96
return res;
97
}
98
}
99
100
PA_IDXSET_FOREACH(am, np->output_mappings, idx) {
101
if (impl->use_ucm) {
102
/* Update ports priorities */
103
- if (am->ucm_context.ucm_device) {
104
- pa_alsa_ucm_add_port(am->output.ports, &am->ucm_context,
105
+ if (am->ucm_context.ucm_devices) {
106
+ pa_alsa_ucm_add_ports_combination(am->output.ports, &am->ucm_context,
107
true, impl->ports, np, NULL);
108
}
109
}
110
111
PA_IDXSET_FOREACH(am, np->input_mappings, idx) {
112
if (impl->use_ucm) {
113
/* Update ports priorities */
114
- if (am->ucm_context.ucm_device) {
115
- pa_alsa_ucm_add_port(am->input.ports, &am->ucm_context,
116
+ if (am->ucm_context.ucm_devices) {
117
+ pa_alsa_ucm_add_ports_combination(am->input.ports, &am->ucm_context,
118
false, impl->ports, np, NULL);
119
}
120
}
121
122
mixer_volume_init(impl, d);
123
124
sync_mixer(d, p);
125
- res = pa_alsa_ucm_set_port(d->ucm_context, p);
126
+ res = pa_alsa_ucm_set_port(d->ucm_context, p,
127
+ dev->direction == ACP_DIRECTION_PLAYBACK);
128
} else {
129
pa_alsa_port_data *data;
130
131
pipewire-0.3.68.tar.gz/spa/plugins/alsa/acp/alsa-mixer.c -> pipewire-0.3.69.tar.gz/spa/plugins/alsa/acp/alsa-mixer.c
Changed
10
1
2
handle = pa_alsa_open_by_template(
3
m->device_strings, dev_id, NULL, &try_ss,
4
&try_map, mode, &try_period_size,
5
- &try_buffer_size, 0, NULL, NULL, NULL, NULL, exact_channels);
6
+ &try_buffer_size, 0, NULL, NULL, exact_channels);
7
if (handle && !exact_channels && m->channel_map.channels != try_map.channels) {
8
char bufPA_CHANNEL_MAP_SNPRINT_MAX;
9
pa_log_debug("Channel map for mapping '%s' permanently changed to '%s'", m->name,
10
pipewire-0.3.68.tar.gz/spa/plugins/alsa/acp/alsa-mixer.h -> pipewire-0.3.69.tar.gz/spa/plugins/alsa/acp/alsa-mixer.h
Changed
20
1
2
pa_alsa_device output;
3
pa_alsa_device input;
4
5
- /* ucm device context */
6
+ /* ucm device context*/
7
pa_alsa_ucm_mapping_context ucm_context;
8
};
9
10
11
pa_idxset *input_mappings;
12
pa_idxset *output_mappings;
13
14
- /* ucm device context */
15
- pa_alsa_ucm_profile_context ucm_context;
16
-
17
struct {
18
pa_dynarray devices;
19
} out;
20
pipewire-0.3.68.tar.gz/spa/plugins/alsa/acp/alsa-ucm.c -> pipewire-0.3.69.tar.gz/spa/plugins/alsa/acp/alsa-ucm.c
Changed
201
1
2
3
4
static void ucm_port_data_init(pa_alsa_ucm_port_data *port, pa_alsa_ucm_config *ucm, pa_device_port *core_port,
5
- pa_alsa_ucm_device *device);
6
+ pa_alsa_ucm_device **devices, unsigned n_devices);
7
static void ucm_port_data_free(pa_device_port *port);
8
+static void ucm_port_update_available(pa_alsa_ucm_port_data *port);
9
10
static struct ucm_type types = {
11
{"None", PA_DEVICE_PORT_TYPE_UNKNOWN},
12
13
return (char *)value;
14
}
15
16
+static int ucm_device_exists(pa_idxset *idxset, pa_alsa_ucm_device *dev) {
17
+ pa_alsa_ucm_device *d;
18
+ uint32_t idx;
19
+
20
+ PA_IDXSET_FOREACH(d, idxset, idx)
21
+ if (d == dev)
22
+ return 1;
23
+
24
+ return 0;
25
+}
26
+
27
static void ucm_add_devices_to_idxset(
28
pa_idxset *idxset,
29
pa_alsa_ucm_device *me,
30
31
n_confdev = snd_use_case_get_list(uc_mgr, id, &devices);
32
pa_xfree(id);
33
34
- device->conflicting_devices = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
35
if (n_confdev <= 0)
36
pa_log_debug("No %s for device %s", "_conflictingdevs", device_name);
37
else {
38
+ device->conflicting_devices = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
39
ucm_add_devices_to_idxset(device->conflicting_devices, device, verb->devices, devices, n_confdev);
40
snd_use_case_free_list(devices, n_confdev);
41
}
42
43
n_suppdev = snd_use_case_get_list(uc_mgr, id, &devices);
44
pa_xfree(id);
45
46
- device->supported_devices = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
47
if (n_suppdev <= 0)
48
pa_log_debug("No %s for device %s", "_supporteddevs", device_name);
49
else {
50
+ device->supported_devices = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
51
ucm_add_devices_to_idxset(device->supported_devices, device, verb->devices, devices, n_suppdev);
52
snd_use_case_free_list(devices, n_suppdev);
53
}
54
55
};
56
57
/* Create a property list for this ucm modifier */
58
-static int ucm_get_modifier_property(
59
- pa_alsa_ucm_modifier *modifier,
60
- snd_use_case_mgr_t *uc_mgr,
61
- pa_alsa_ucm_verb *verb,
62
- const char *modifier_name) {
63
+static int ucm_get_modifier_property(pa_alsa_ucm_modifier *modifier, snd_use_case_mgr_t *uc_mgr, const char *modifier_name) {
64
const char *value;
65
char *id;
66
int i;
67
- const char **devices;
68
- int n_confdev, n_suppdev;
69
70
for (i = 0; itemi.id; i++) {
71
int err;
72
73
}
74
75
id = pa_sprintf_malloc("%s/%s", "_conflictingdevs", modifier_name);
76
- n_confdev = snd_use_case_get_list(uc_mgr, id, &devices);
77
+ modifier->n_confdev = snd_use_case_get_list(uc_mgr, id, &modifier->conflicting_devices);
78
pa_xfree(id);
79
-
80
- modifier->conflicting_devices = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
81
- if (n_confdev <= 0)
82
+ if (modifier->n_confdev < 0)
83
pa_log_debug("No %s for modifier %s", "_conflictingdevs", modifier_name);
84
- else {
85
- ucm_add_devices_to_idxset(modifier->conflicting_devices, NULL, verb->devices, devices, n_confdev);
86
- snd_use_case_free_list(devices, n_confdev);
87
- }
88
89
id = pa_sprintf_malloc("%s/%s", "_supporteddevs", modifier_name);
90
- n_suppdev = snd_use_case_get_list(uc_mgr, id, &devices);
91
+ modifier->n_suppdev = snd_use_case_get_list(uc_mgr, id, &modifier->supported_devices);
92
pa_xfree(id);
93
-
94
- modifier->supported_devices = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
95
- if (n_suppdev <= 0)
96
+ if (modifier->n_suppdev < 0)
97
pa_log_debug("No %s for modifier %s", "_supporteddevs", modifier_name);
98
- else {
99
- ucm_add_devices_to_idxset(modifier->supported_devices, NULL, verb->devices, devices, n_suppdev);
100
- snd_use_case_free_list(devices, n_suppdev);
101
- }
102
103
return 0;
104
};
105
106
return 0;
107
};
108
109
-static long ucm_device_status(pa_alsa_ucm_config *ucm, pa_alsa_ucm_device *dev) {
110
- const char *dev_name = pa_proplist_gets(dev->proplist, PA_ALSA_PROP_UCM_NAME);
111
- char *devstatus;
112
- long status = 0;
113
-
114
- devstatus = pa_sprintf_malloc("_devstatus/%s", dev_name);
115
- if (snd_use_case_geti(ucm->ucm_mgr, devstatus, &status) < 0) {
116
- pa_log_debug("Failed to get status for UCM device %s", dev_name);
117
- status = -1;
118
- }
119
- pa_xfree(devstatus);
120
-
121
- return status;
122
-}
123
-
124
-static int ucm_device_disable(pa_alsa_ucm_config *ucm, pa_alsa_ucm_device *dev) {
125
- const char *dev_name = pa_proplist_gets(dev->proplist, PA_ALSA_PROP_UCM_NAME);
126
-
127
- /* If any of dev's conflicting devices is enabled, trying to disable
128
- * dev gives an error despite the fact that it's already disabled.
129
- * Check that dev is enabled to avoid this error. */
130
- if (ucm_device_status(ucm, dev) == 0) {
131
- pa_log_debug("UCM device %s is already disabled", dev_name);
132
- return 0;
133
- }
134
-
135
- pa_log_debug("Disabling UCM device %s", dev_name);
136
- if (snd_use_case_set(ucm->ucm_mgr, "_disdev", dev_name) < 0) {
137
- pa_log("Failed to disable UCM device %s", dev_name);
138
- return -1;
139
- }
140
-
141
- return 0;
142
-}
143
-
144
-static int ucm_device_enable(pa_alsa_ucm_config *ucm, pa_alsa_ucm_device *dev) {
145
- const char *dev_name = pa_proplist_gets(dev->proplist, PA_ALSA_PROP_UCM_NAME);
146
-
147
- /* We don't need to enable devices that are already enabled */
148
- if (ucm_device_status(ucm, dev) > 0) {
149
- pa_log_debug("UCM device %s is already enabled", dev_name);
150
- return 0;
151
- }
152
-
153
- pa_log_debug("Enabling UCM device %s", dev_name);
154
- if (snd_use_case_set(ucm->ucm_mgr, "_enadev", dev_name) < 0) {
155
- pa_log("Failed to enable UCM device %s", dev_name);
156
- return -1;
157
- }
158
-
159
- return 0;
160
-}
161
-
162
static int ucm_get_modifiers(pa_alsa_ucm_verb *verb, snd_use_case_mgr_t *uc_mgr) {
163
const char **mod_list;
164
int num_mod, i;
165
166
return 0;
167
};
168
169
-static long ucm_modifier_status(pa_alsa_ucm_config *ucm, pa_alsa_ucm_modifier *mod) {
170
- const char *mod_name = pa_proplist_gets(mod->proplist, PA_ALSA_PROP_UCM_NAME);
171
- char *modstatus;
172
- long status = 0;
173
-
174
- modstatus = pa_sprintf_malloc("_modstatus/%s", mod_name);
175
- if (snd_use_case_geti(ucm->ucm_mgr, modstatus, &status) < 0) {
176
- pa_log_debug("Failed to get status for UCM modifier %s", mod_name);
177
- status = -1;
178
- }
179
- pa_xfree(modstatus);
180
-
181
- return status;
182
-}
183
-
184
-static int ucm_modifier_disable(pa_alsa_ucm_config *ucm, pa_alsa_ucm_modifier *mod) {
185
- const char *mod_name = pa_proplist_gets(mod->proplist, PA_ALSA_PROP_UCM_NAME);
186
-
187
- /* We don't need to disable modifiers that are already disabled */
188
- if (ucm_modifier_status(ucm, mod) == 0) {
189
- pa_log_debug("UCM modifier %s is already disabled", mod_name);
190
- return 0;
191
- }
192
-
193
- pa_log_debug("Disabling UCM modifier %s", mod_name);
194
- if (snd_use_case_set(ucm->ucm_mgr, "_dismod", mod_name) < 0) {
195
- pa_log("Failed to disable UCM modifier %s", mod_name);
196
- return -1;
197
- }
198
-
199
- return 0;
200
-}
201
pipewire-0.3.68.tar.gz/spa/plugins/alsa/acp/alsa-ucm.h -> pipewire-0.3.69.tar.gz/spa/plugins/alsa/acp/alsa-ucm.h
Changed
78
1
2
typedef struct pa_alsa_ucm_device pa_alsa_ucm_device;
3
typedef struct pa_alsa_ucm_config pa_alsa_ucm_config;
4
typedef struct pa_alsa_ucm_mapping_context pa_alsa_ucm_mapping_context;
5
-typedef struct pa_alsa_ucm_profile_context pa_alsa_ucm_profile_context;
6
typedef struct pa_alsa_ucm_port_data pa_alsa_ucm_port_data;
7
typedef struct pa_alsa_ucm_volume pa_alsa_ucm_volume;
8
9
int pa_alsa_ucm_query_profiles(pa_alsa_ucm_config *ucm, int card_index);
10
pa_alsa_profile_set* pa_alsa_ucm_add_profile_set(pa_alsa_ucm_config *ucm, pa_channel_map *default_channel_map);
11
-int pa_alsa_ucm_set_profile(pa_alsa_ucm_config *ucm, pa_card *card, pa_alsa_profile *new_profile, pa_alsa_profile *old_profile);
12
+int pa_alsa_ucm_set_profile(pa_alsa_ucm_config *ucm, pa_card *card, const char *new_profile, const char *old_profile);
13
14
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);
15
16
17
pa_card *card,
18
snd_pcm_t *pcm_handle,
19
bool ignore_dB);
20
-void pa_alsa_ucm_add_port(
21
+void pa_alsa_ucm_add_ports_combination(
22
pa_hashmap *hash,
23
pa_alsa_ucm_mapping_context *context,
24
bool is_sink,
25
pa_hashmap *ports,
26
pa_card_profile *cp,
27
pa_core *core);
28
-int pa_alsa_ucm_set_port(pa_alsa_ucm_mapping_context *context, pa_device_port *port);
29
+int pa_alsa_ucm_set_port(pa_alsa_ucm_mapping_context *context, pa_device_port *port, bool is_sink);
30
31
void pa_alsa_ucm_free(pa_alsa_ucm_config *ucm);
32
void pa_alsa_ucm_mapping_context_free(pa_alsa_ucm_mapping_context *context);
33
34
35
pa_proplist *proplist;
36
37
- pa_idxset *conflicting_devices;
38
- pa_idxset *supported_devices;
39
+ int n_confdev;
40
+ int n_suppdev;
41
+
42
+ const char **conflicting_devices;
43
+ const char **supported_devices;
44
45
pa_direction_t action_direction;
46
47
48
pa_alsa_ucm_config *ucm;
49
pa_direction_t direction;
50
51
- pa_alsa_ucm_device *ucm_device;
52
- pa_alsa_ucm_modifier *ucm_modifier;
53
-};
54
-
55
-struct pa_alsa_ucm_profile_context {
56
- pa_alsa_ucm_verb *verb;
57
+ pa_idxset *ucm_devices;
58
+ pa_idxset *ucm_modifiers;
59
};
60
61
struct pa_alsa_ucm_port_data {
62
pa_alsa_ucm_config *ucm;
63
pa_device_port *core_port;
64
65
- pa_alsa_ucm_device *device;
66
+ /* A single port will be associated with multiple devices if it represents
67
+ * a combination of devices. */
68
+ pa_dynarray *devices; /* pa_alsa_ucm_device */
69
70
- /* verb name -> pa_alsa_path for volume control */
71
+ /* profile name -> pa_alsa_path for volume control */
72
pa_hashmap *paths;
73
- /* Current path, set when activating verb */
74
+ /* Current path, set when activating profile */
75
pa_alsa_path *path;
76
77
/* ELD info */
78
pipewire-0.3.68.tar.gz/spa/plugins/alsa/acp/alsa-util.c -> pipewire-0.3.69.tar.gz/spa/plugins/alsa/acp/alsa-util.c
Changed
201
1
2
snd_pcm_uframes_t tsched_size,
3
bool *use_mmap,
4
bool *use_tsched,
5
- pa_sample_format_t **query_supported_formats,
6
- unsigned int **query_supported_rates,
7
pa_alsa_profile_set *ps,
8
pa_alsa_mapping **mapping) {
9
10
11
tsched_size,
12
use_mmap,
13
use_tsched,
14
- query_supported_formats,
15
- query_supported_rates,
16
m);
17
18
if (pcm_handle) {
19
20
tsched_size,
21
use_mmap,
22
use_tsched,
23
- query_supported_formats,
24
- query_supported_rates,
25
m);
26
27
if (pcm_handle) {
28
29
tsched_size,
30
use_mmap,
31
use_tsched,
32
- query_supported_formats,
33
- query_supported_rates,
34
false);
35
pa_xfree(d);
36
37
38
snd_pcm_uframes_t tsched_size,
39
bool *use_mmap,
40
bool *use_tsched,
41
- pa_sample_format_t **query_supported_formats,
42
- unsigned int **query_supported_rates,
43
pa_alsa_mapping *m) {
44
45
snd_pcm_t *pcm_handle;
46
47
tsched_size,
48
use_mmap,
49
use_tsched,
50
- query_supported_formats,
51
- query_supported_rates,
52
pa_channel_map_valid(&m->channel_map) /* Query the channel count if we don't know what we want */);
53
54
if (!pcm_handle)
55
56
snd_pcm_uframes_t tsched_size,
57
bool *use_mmap,
58
bool *use_tsched,
59
- pa_sample_format_t **query_supported_formats,
60
- unsigned int **query_supported_rates,
61
bool require_exact_channel_number) {
62
63
int err;
64
65
pa_log_info("ALSA device open '%s' %s: %p", d,
66
mode == SND_PCM_STREAM_CAPTURE ? "capture" : "playback", pcm_handle);
67
68
- if (query_supported_formats)
69
- *query_supported_formats = pa_alsa_get_supported_formats(pcm_handle, ss->format);
70
-
71
- if (query_supported_rates)
72
- *query_supported_rates = pa_alsa_get_supported_rates(pcm_handle, ss->rate);
73
-
74
if ((err = pa_alsa_set_hw_params(
75
pcm_handle,
76
ss,
77
78
snd_pcm_uframes_t tsched_size,
79
bool *use_mmap,
80
bool *use_tsched,
81
- pa_sample_format_t **query_supported_formats,
82
- unsigned int **query_supported_rates,
83
bool require_exact_channel_number) {
84
85
snd_pcm_t *pcm_handle;
86
87
tsched_size,
88
use_mmap,
89
use_tsched,
90
- query_supported_formats,
91
- query_supported_rates,
92
require_exact_channel_number);
93
94
pa_xfree(d);
95
96
97
return pa_sprintf_malloc("Audio%i", i);
98
}
99
-#endif
100
-
101
-static void dump_supported_rates(unsigned int* values)
102
-{
103
- pa_strbuf *buf;
104
- char *str;
105
- int i;
106
-
107
- buf = pa_strbuf_new();
108
-
109
- for (i = 0; valuesi; i++) {
110
- pa_strbuf_printf(buf, " %u", valuesi);
111
- }
112
-
113
- str = pa_strbuf_to_string_free(buf);
114
- pa_log_debug("Supported rates:%s", str);
115
- pa_xfree(str);
116
-}
117
118
unsigned int *pa_alsa_get_supported_rates(snd_pcm_t *pcm, unsigned int fallback_rate) {
119
static unsigned int all_rates = { 8000, 11025, 12000,
120
121
32000, 44100, 48000,
122
64000, 88200, 96000,
123
128000, 176400, 192000,
124
- 352800, 384000,
125
- 705600, 768000 };
126
+ 384000 };
127
bool supportedPA_ELEMENTSOF(all_rates) = { false, };
128
snd_pcm_hw_params_t *hwparams;
129
unsigned int i, j, n, *rates = NULL;
130
131
rates1 = 0;
132
}
133
134
- dump_supported_rates(rates);
135
return rates;
136
}
137
138
pa_sample_format_t *pa_alsa_get_supported_formats(snd_pcm_t *pcm, pa_sample_format_t fallback_format) {
139
- static const snd_pcm_format_t format_trans_to_pcm = {
140
- PA_SAMPLE_U8 = SND_PCM_FORMAT_U8,
141
- PA_SAMPLE_ALAW = SND_PCM_FORMAT_A_LAW,
142
- PA_SAMPLE_ULAW = SND_PCM_FORMAT_MU_LAW,
143
- PA_SAMPLE_S16LE = SND_PCM_FORMAT_S16_LE,
144
- PA_SAMPLE_S16BE = SND_PCM_FORMAT_S16_BE,
145
- PA_SAMPLE_FLOAT32LE = SND_PCM_FORMAT_FLOAT_LE,
146
- PA_SAMPLE_FLOAT32BE = SND_PCM_FORMAT_FLOAT_BE,
147
- PA_SAMPLE_S32LE = SND_PCM_FORMAT_S32_LE,
148
- PA_SAMPLE_S32BE = SND_PCM_FORMAT_S32_BE,
149
- PA_SAMPLE_S24LE = SND_PCM_FORMAT_S24_3LE,
150
- PA_SAMPLE_S24BE = SND_PCM_FORMAT_S24_3BE,
151
- PA_SAMPLE_S24_32LE = SND_PCM_FORMAT_S24_LE,
152
- PA_SAMPLE_S24_32BE = SND_PCM_FORMAT_S24_BE,
153
+ static const snd_pcm_format_t format_trans_to_pa = {
154
+ SND_PCM_FORMAT_U8 = PA_SAMPLE_U8,
155
+ SND_PCM_FORMAT_A_LAW = PA_SAMPLE_ALAW,
156
+ SND_PCM_FORMAT_MU_LAW = PA_SAMPLE_ULAW,
157
+ SND_PCM_FORMAT_S16_LE = PA_SAMPLE_S16LE,
158
+ SND_PCM_FORMAT_S16_BE = PA_SAMPLE_S16BE,
159
+ SND_PCM_FORMAT_FLOAT_LE = PA_SAMPLE_FLOAT32LE,
160
+ SND_PCM_FORMAT_FLOAT_BE = PA_SAMPLE_FLOAT32BE,
161
+ SND_PCM_FORMAT_S32_LE = PA_SAMPLE_S32LE,
162
+ SND_PCM_FORMAT_S32_BE = PA_SAMPLE_S32BE,
163
+ SND_PCM_FORMAT_S24_3LE = PA_SAMPLE_S24LE,
164
+ SND_PCM_FORMAT_S24_3BE = PA_SAMPLE_S24BE,
165
+ SND_PCM_FORMAT_S24_LE = PA_SAMPLE_S24_32LE,
166
+ SND_PCM_FORMAT_S24_BE = PA_SAMPLE_S24_32BE,
167
};
168
- static const pa_sample_format_t all_formats = {
169
- PA_SAMPLE_U8,
170
- PA_SAMPLE_ALAW,
171
- PA_SAMPLE_ULAW,
172
- PA_SAMPLE_S16LE,
173
- PA_SAMPLE_S16BE,
174
- PA_SAMPLE_FLOAT32LE,
175
- PA_SAMPLE_FLOAT32BE,
176
- PA_SAMPLE_S32LE,
177
- PA_SAMPLE_S32BE,
178
- PA_SAMPLE_S24LE,
179
- PA_SAMPLE_S24BE,
180
- PA_SAMPLE_S24_32LE,
181
- PA_SAMPLE_S24_32BE,
182
+ static const snd_pcm_format_t all_formats = {
183
+ SND_PCM_FORMAT_U8,
184
+ SND_PCM_FORMAT_A_LAW,
185
+ SND_PCM_FORMAT_MU_LAW,
186
+ SND_PCM_FORMAT_S16_LE,
187
+ SND_PCM_FORMAT_S16_BE,
188
+ SND_PCM_FORMAT_FLOAT_LE,
189
+ SND_PCM_FORMAT_FLOAT_BE,
190
+ SND_PCM_FORMAT_S32_LE,
191
+ SND_PCM_FORMAT_S32_BE,
192
+ SND_PCM_FORMAT_S24_3LE,
193
+ SND_PCM_FORMAT_S24_3BE,
194
+ SND_PCM_FORMAT_S24_LE,
195
+ SND_PCM_FORMAT_S24_BE,
196
};
197
bool supportedPA_ELEMENTSOF(all_formats) = {
198
false,
199
200
}
201
pipewire-0.3.68.tar.gz/spa/plugins/alsa/acp/alsa-util.h -> pipewire-0.3.69.tar.gz/spa/plugins/alsa/acp/alsa-util.h
Changed
37
1
2
snd_pcm_uframes_t tsched_size,
3
bool *use_mmap, /* modified at return */
4
bool *use_tsched, /* modified at return */
5
- pa_sample_format_t **query_supported_formats, /* modified at return */
6
- unsigned int **query_supported_rates, /* modified at return */
7
pa_alsa_profile_set *ps,
8
pa_alsa_mapping **mapping); /* modified at return */
9
#endif
10
11
snd_pcm_uframes_t tsched_size,
12
bool *use_mmap, /* modified at return */
13
bool *use_tsched, /* modified at return */
14
- pa_sample_format_t **query_supported_formats, /* modified at return */
15
- unsigned int **query_supported_rates, /* modified at return */
16
pa_alsa_mapping *mapping);
17
18
/* Opens the explicit ALSA device */
19
20
snd_pcm_uframes_t tsched_size,
21
bool *use_mmap, /* modified at return */
22
bool *use_tsched, /* modified at return */
23
- pa_sample_format_t **query_supported_formats, /* modified at return */
24
- unsigned int **query_supported_rates, /* modified at return */
25
bool require_exact_channel_number);
26
27
/* Opens the explicit ALSA device with a fallback list */
28
29
snd_pcm_uframes_t tsched_size,
30
bool *use_mmap, /* modified at return */
31
bool *use_tsched, /* modified at return */
32
- pa_sample_format_t **query_supported_formats, /* modified at return */
33
- unsigned int **query_supported_rates, /* modified at return */
34
bool require_exact_channel_number);
35
36
#if 0
37
pipewire-0.3.68.tar.gz/spa/plugins/alsa/acp/compat.h -> pipewire-0.3.69.tar.gz/spa/plugins/alsa/acp/compat.h
Changed
23
1
2
#define PA_LIKELY(x) (__builtin_expect(!!(x),1))
3
#define PA_UNLIKELY(x) (__builtin_expect(!!(x),0))
4
#define PA_PRINTF_FUNC(fmt, arg1) __attribute__((format(printf, fmt, arg1)))
5
-#define PA_UNUSED __attribute__ ((unused))
6
#else
7
#define PA_LIKELY(x) (x)
8
#define PA_UNLIKELY(x) (x)
9
#define PA_PRINTF_FUNC(fmt, arg1)
10
-#define PA_UNUSED
11
#endif
12
13
#define PA_MIN(a,b) \
14
15
PA_AVAILABLE_YES = 2,
16
} pa_available_t;
17
18
-#define PA_RATE_MAX (48000U*16U)
19
+#define PA_RATE_MAX (48000U*8U)
20
21
typedef enum pa_sample_format {
22
PA_SAMPLE_U8, /**< Unsigned 8 Bit PCM */
23
pipewire-0.3.68.tar.gz/spa/plugins/alsa/acp/idxset.h -> pipewire-0.3.69.tar.gz/spa/plugins/alsa/acp/idxset.h
Changed
126
1
2
return count;
3
}
4
5
-static inline pa_idxset_item *pa_idxset_search(pa_idxset *s, uint32_t *idx)
6
+static inline void *pa_idxset_search(pa_idxset *s, uint32_t *idx)
7
{
8
pa_idxset_item *item;
9
for (item = pa_array_get_unchecked(&s->array, *idx, pa_idxset_item);
10
pa_array_check(&s->array, item); item++, (*idx)++) {
11
if (item->ptr != NULL)
12
- return item;
13
- }
14
- *idx = PA_IDXSET_INVALID;
15
- return NULL;
16
-}
17
-
18
-static inline pa_idxset_item *pa_idxset_reverse_search(pa_idxset *s, uint32_t *idx)
19
-{
20
- pa_idxset_item *item;
21
- for (item = pa_array_get_unchecked(&s->array, *idx, pa_idxset_item);
22
- pa_array_check(&s->array, item); item--, (*idx)--) {
23
- if (item->ptr != NULL)
24
- return item;
25
+ return item->ptr;
26
}
27
*idx = PA_IDXSET_INVALID;
28
return NULL;
29
30
31
static inline void *pa_idxset_next(pa_idxset *s, uint32_t *idx)
32
{
33
- pa_idxset_item *item;
34
(*idx)++;;
35
- item = pa_idxset_search(s, idx);
36
- return item ? item->ptr : NULL;
37
+ return pa_idxset_search(s, idx);
38
}
39
40
static inline void* pa_idxset_first(pa_idxset *s, uint32_t *idx)
41
{
42
uint32_t i = 0;
43
- pa_idxset_item *item = pa_idxset_search(s, &i);
44
+ void *ptr = pa_idxset_search(s, &i);
45
if (idx)
46
*idx = i;
47
- return item ? item->ptr : NULL;
48
-}
49
-
50
-static inline void* pa_idxset_last(pa_idxset *s, uint32_t *idx)
51
-{
52
- uint32_t i = pa_array_get_len(&s->array, pa_idxset_item) - 1;
53
- pa_idxset_item *item = pa_idxset_reverse_search(s, &i);
54
- if (idx)
55
- *idx = i;
56
- return item ? item->ptr : NULL;
57
-}
58
-
59
-static inline void* pa_idxset_steal_last(pa_idxset *s, uint32_t *idx)
60
-{
61
- uint32_t i = pa_array_get_len(&s->array, pa_idxset_item) - 1;
62
- void *ptr = NULL;
63
- pa_idxset_item *item = pa_idxset_reverse_search(s, &i);
64
- if (idx)
65
- *idx = i;
66
- if (item) {
67
- ptr = item->ptr;
68
- item->ptr = NULL;
69
- pa_array_remove(&s->array, item);
70
- }
71
return ptr;
72
}
73
74
static inline void* pa_idxset_get_by_data(pa_idxset*s, const void *p, uint32_t *idx)
75
{
76
pa_idxset_item *item = pa_idxset_find(s, p);
77
- if (item == NULL) {
78
- if (idx)
79
- *idx = PA_IDXSET_INVALID;
80
+ if (item == NULL)
81
return NULL;
82
- }
83
if (idx)
84
*idx = item - (pa_idxset_item*)s->array.data;
85
return item->ptr;
86
}
87
88
-static inline bool pa_idxset_contains(pa_idxset *s, const void *p)
89
-{
90
- return pa_idxset_get_by_data(s, p, NULL) == p;
91
-}
92
-
93
-static inline bool pa_idxset_isdisjoint(pa_idxset *s, pa_idxset *t)
94
-{
95
- pa_idxset_item *item;
96
- pa_array_for_each(item, &s->array) {
97
- if (item->ptr && pa_idxset_contains(t, item->ptr))
98
- return false;
99
- }
100
- return true;
101
-}
102
-
103
-static inline bool pa_idxset_issubset(pa_idxset *s, pa_idxset *t)
104
-{
105
- pa_idxset_item *item;
106
- pa_array_for_each(item, &s->array) {
107
- if (item->ptr && !pa_idxset_contains(t, item->ptr))
108
- return false;
109
- }
110
- return true;
111
-}
112
-
113
-static inline bool pa_idxset_issuperset(pa_idxset *s, pa_idxset *t)
114
-{
115
- return pa_idxset_issubset(t, s);
116
-}
117
-
118
-static inline bool pa_idxset_equals(pa_idxset *s, pa_idxset *t)
119
-{
120
- return pa_idxset_issubset(s, t) && pa_idxset_issuperset(s, t);
121
-}
122
-
123
static inline void* pa_idxset_get_by_index(pa_idxset*s, uint32_t idx)
124
{
125
pa_idxset_item *item;
126
pipewire-0.3.68.tar.gz/spa/plugins/alsa/alsa-pcm.c -> pipewire-0.3.69.tar.gz/spa/plugins/alsa/alsa-pcm.c
Changed
201
1
2
is_batch = snd_pcm_hw_params_is_batch(params) &&
3
!state->disable_batch;
4
5
+ /* no period size specified. If we are batch or not using timers,
6
+ * use the graph duration as the period */
7
+ if (period_size == 0 && (is_batch || state->disable_tsched))
8
+ period_size = state->position ? state->position->clock.duration : DEFAULT_PERIOD;
9
+
10
if (is_batch) {
11
if (period_size == 0)
12
- period_size = state->position ? state->position->clock.duration : DEFAULT_PERIOD;
13
- if (period_size == 0)
14
period_size = DEFAULT_PERIOD;
15
/* batch devices get their hw pointers updated every period. Make
16
* the period smaller and add one period of headroom. Limit the
17
18
}
19
20
state->headroom = state->default_headroom;
21
- /* If tsched is disabled, we know the pointers are updated when we wake
22
- * up, so we don't need the additional headroom */
23
- if (is_batch && !state->disable_tsched)
24
- state->headroom += period_size;
25
+ if (!state->disable_tsched) {
26
+ /* When using timers, we might miss the pointer update for batch
27
+ * devices so add some extra headroom. With IRQ, we know the pointers
28
+ * are updated when we wake up and we don't need the headroom. */
29
+ if (is_batch)
30
+ state->headroom += period_size;
31
+ /* Add 32 extra samples of headroom to handle jitter in capture.
32
+ * For IRQ, we don't need this because when we wake up, we have
33
+ * exactly enough samples to read or write. */
34
+ if (state->stream == SND_PCM_STREAM_CAPTURE)
35
+ state->headroom = SPA_MAX(state->headroom, 32u);
36
+ }
37
38
state->max_delay = state->buffer_frames / 2;
39
if (spa_strstartswith(state->props.device, "a52") ||
40
41
*delay = state->buffer_frames - avail;
42
} else {
43
*delay = avail;
44
- *target = SPA_MAX(*target, state->read_size);
45
- if (state->matching)
46
- *target += 32;
47
+ *target = SPA_MAX(*target, state->read_size + state->headroom);
48
}
49
*target = SPA_CLAMP(*target, state->min_delay, state->max_delay);
50
return 0;
51
52
double err, corr;
53
int32_t diff;
54
55
- if (state->stream == SND_PCM_STREAM_PLAYBACK)
56
- err = delay - target;
57
- else
58
- err = target - delay;
59
+ if (state->disable_tsched && !follower) {
60
+ err = (int64_t)(current_time - state->next_time);
61
+ err = err / 1e9 * state->rate;
62
+ } else {
63
+ if (state->stream == SND_PCM_STREAM_PLAYBACK)
64
+ err = delay - target;
65
+ else
66
+ err = target - delay;
67
+ }
68
69
if (SPA_UNLIKELY(state->dll.bw == 0.0)) {
70
spa_dll_set_bw(&state->dll, SPA_DLL_BW_MAX, state->threshold, state->rate);
71
72
state->alsa_sync = true;
73
state->alsa_sync_warning = false;
74
}
75
- if (err > state->max_error) {
76
- err = state->max_error;
77
+ if (err > state->max_resync) {
78
state->alsa_sync = true;
79
- } else if (err < -state->max_error) {
80
- err = -state->max_error;
81
+ if (err > state->max_error)
82
+ err = state->max_error;
83
+ } else if (err < -state->max_resync) {
84
state->alsa_sync = true;
85
+ if (err < -state->max_error)
86
+ err = -state->max_error;
87
}
88
89
if (!follower || state->matching)
90
91
state->clock->next_nsec = state->next_time;
92
}
93
94
- spa_log_trace_fp(state->log, "%p: follower:%d %"PRIu64" %f %ld %f %f %u",
95
- state, follower, current_time, corr, delay, err, state->threshold * corr,
96
+ spa_log_trace_fp(state->log, "%p: follower:%d %"PRIu64" %f %ld %ld %f %f %u",
97
+ state, follower, current_time, corr, delay, target, err, state->threshold * corr,
98
state->threshold);
99
100
return 0;
101
102
return -EIO;
103
state->threshold = SPA_SCALE32_UP(state->duration, state->rate, state->rate_denom);
104
state->max_error = SPA_MAX(256.0f, state->threshold / 2.0f);
105
+ state->max_resync = SPA_MIN(state->threshold, state->max_error);
106
state->resample = ((uint32_t)state->rate != state->rate_denom) || state->matching;
107
state->alsa_sync = true;
108
}
109
110
int res;
111
struct spa_io_buffers *io;
112
113
- if (SPA_UNLIKELY(delay < target)) {
114
- spa_log_trace(state->log, "%p: early wakeup %ld %ld", state, delay, target);
115
+ if (SPA_UNLIKELY(delay < state->read_size)) {
116
+ spa_log_trace(state->log, "%p: early wakeup %ld %ld %d", state, delay, target,
117
+ state->read_size);
118
state->next_time = current_time + (target - delay) * SPA_NSEC_PER_SEC /
119
state->rate;
120
return -EAGAIN;
121
}
122
123
- if (SPA_UNLIKELY(res = update_time(state, current_time, delay, target, false)) < 0)
124
+ if (SPA_UNLIKELY((res = update_time(state, current_time, delay, target, false)) < 0))
125
return res;
126
127
if ((res = spa_alsa_read(state)) < 0)
128
129
return 0;
130
}
131
132
+static uint64_t get_time_ns(struct state *state)
133
+{
134
+ struct timespec now;
135
+ if (spa_system_clock_gettime(state->data_system, CLOCK_MONOTONIC, &now) < 0)
136
+ return 0;
137
+ return SPA_TIMESPEC_TO_NSEC(&now);
138
+}
139
+
140
static void alsa_wakeup_event(struct spa_source *source)
141
{
142
struct state *state = source->data;
143
144
int err;
145
unsigned short revents;
146
147
+ current_time = get_time_ns(state);
148
+
149
for (int i = 0; i < state->n_fds; i++) {
150
state->pfdsi.revents = state->sourcei.rmask;
151
/* Reset so that we only handle all our sources' events once */
152
153
spa_log_trace_fp(state->log, "Woken up with no work to do");
154
return;
155
}
156
- } else if (SPA_LIKELY(state->started)) {
157
- if (SPA_UNLIKELY((res = spa_system_timerfd_read(state->data_system,
158
+ } else {
159
+ if (SPA_LIKELY(state->started)) {
160
+ if (SPA_UNLIKELY((res = spa_system_timerfd_read(state->data_system,
161
state->timerfd, &expire)) < 0)) {
162
/* we can get here when the timer is changed since the last
163
- * timerfd wakeup, for example by do_reassign_follower() executed
164
- * in the same epoll wakeup cycle */
165
- if (res != -EAGAIN)
166
- spa_log_warn(state->log, "%p: error reading timerfd: %s",
167
- state, spa_strerror(res));
168
- return;
169
+ * timerfd wakeup, for example by do_reassign_follower() executed
170
+ * in the same epoll wakeup cycle */
171
+ if (res != -EAGAIN)
172
+ spa_log_warn(state->log, "%p: error reading timerfd: %s",
173
+ state, spa_strerror(res));
174
+ return;
175
+ }
176
}
177
+ current_time = state->next_time;
178
}
179
180
if (SPA_UNLIKELY((res = check_position_config(state)) < 0)) {
181
182
return;
183
}
184
185
- current_time = state->next_time;
186
-
187
if (SPA_UNLIKELY(get_status(state, current_time, &delay, &target) < 0)) {
188
spa_log_error(state->log, "get_status error");
189
state->next_time += state->threshold * 1e9 / state->rate;
190
191
192
#ifndef FASTPATH
193
if (SPA_UNLIKELY(spa_log_level_topic_enabled(state->log, SPA_LOG_TOPIC_DEFAULT, SPA_LOG_LEVEL_TRACE))) {
194
- struct timespec now;
195
- uint64_t nsec;
196
- if (spa_system_clock_gettime(state->data_system, CLOCK_MONOTONIC, &now) < 0)
197
- return;
198
- nsec = SPA_TIMESPEC_TO_NSEC(&now);
199
+ uint64_t nsec = get_time_ns(state);
200
spa_log_trace_fp(state->log, "%p: wakeup %lu %lu %"PRIu64" %"PRIu64" %"PRIi64
201
pipewire-0.3.68.tar.gz/spa/plugins/alsa/alsa-pcm.h -> pipewire-0.3.69.tar.gz/spa/plugins/alsa/alsa-pcm.h
Changed
9
1
2
3
struct spa_dll dll;
4
double max_error;
5
+ double max_resync;
6
7
struct spa_latency_info latency2;
8
struct spa_process_latency_info process_latency;
9
pipewire-0.3.69.tar.gz/spa/plugins/alsa/mixer/paths/audigy-analog-output-mirror.conf
Added
58
1
2
+; Mixer path for the Sound Blaster Audigy series, which uses the EMU10K2 DSP.
3
+; We target 'Wave' and other non-'PCM' controls as a special case for when
4
+; the device's stereo-to-all-speakers mirroring mode is in use. (For example,
5
+; the Analog Stereo Output profile.)
6
+; https://docs.kernel.org/sound/cards/audigy-mixer.html
7
+;
8
+; See analog-output.conf.common for an explanation on the directives
9
+
10
+General
11
+priority = 99
12
+description-key = analog-output
13
+
14
+Element Master
15
+switch = mute
16
+volume = merge
17
+override-map.1 = all
18
+override-map.2 = all-left,all-right
19
+
20
+Element Wave
21
+volume = merge
22
+override-map.1 = all
23
+override-map.2 = all-left,all-right
24
+
25
+# The following elements also exist in analog-output.conf. We list them here
26
+# instead of including that file, for ideal positioning of the Wave element:
27
+# Placing Wave below the Master element prevents Master from reaching its
28
+# loudest until the user raises the unified volume control to maximum.
29
+# (This should reduce the chance of a surprise speaker blow-out.)
30
+# Placing Wave above the per-channel elements yields even steps at low volume.
31
+
32
+Element Front
33
+volume = merge
34
+override-map.1 = all-front
35
+override-map.2 = front-left,front-right
36
+
37
+Element Surround
38
+volume = merge
39
+override-map.1 = all-rear
40
+override-map.2 = rear-left,rear-right
41
+
42
+Element Side
43
+volume = merge
44
+override-map.1 = all-side
45
+override-map.2 = side-left,side-right
46
+
47
+Element Center
48
+volume = merge
49
+override-map.1 = all-center
50
+override-map.2 = all-center,all-center
51
+
52
+Element LFE
53
+volume = merge
54
+override-map.1 = lfe
55
+override-map.2 = lfe,lfe
56
+
57
+.include analog-output.conf.common
58
pipewire-0.3.69.tar.gz/spa/plugins/alsa/mixer/paths/audigy-analog-output.conf
Added
46
1
2
+; Mixer path for the Sound Blaster Audigy series, which uses the EMU10K2 DSP.
3
+; We target 'PCM Front' and similarly named controls instead of 'Front' et al.
4
+; because the latter affect volume only in the device's stereo-to-all-speakers
5
+; mirroring mode, which is not used by most profiles.
6
+; https://docs.kernel.org/sound/cards/audigy-mixer.html
7
+;
8
+; See analog-output.conf.common for an explanation on the directives
9
+
10
+General
11
+priority = 99
12
+description-key = analog-output
13
+
14
+Element Master
15
+switch = mute
16
+volume = merge
17
+override-map.1 = all
18
+override-map.2 = all-left,all-right
19
+
20
+Element PCM Front
21
+volume = merge
22
+override-map.1 = all-front
23
+override-map.2 = front-left,front-right
24
+
25
+Element PCM Surround
26
+volume = merge
27
+override-map.1 = all-rear
28
+override-map.2 = rear-left,rear-right
29
+
30
+Element PCM Side
31
+volume = merge
32
+override-map.1 = all-side
33
+override-map.2 = side-left,side-right
34
+
35
+Element PCM Center
36
+volume = merge
37
+override-map.1 = all-center
38
+override-map.2 = all-center,all-center
39
+
40
+Element PCM LFE
41
+volume = merge
42
+override-map.1 = lfe
43
+override-map.2 = lfe,lfe
44
+
45
+.include analog-output.conf.common
46
pipewire-0.3.68.tar.gz/spa/plugins/alsa/mixer/profile-sets/audigy.conf -> pipewire-0.3.69.tar.gz/spa/plugins/alsa/mixer/profile-sets/audigy.conf
Changed
85
1
2
3
; Creative Sound Blaster Audigy product line
4
;
5
-; These are just copies of the mappings we find in default.conf, with the
6
-; small change of making analog-stereo and analog-mono non-fallback mappings.
7
-; This is needed because these cards only support duplex profiles with mono
8
-; inputs, and in the default configuration, with stereo being a fallback
9
+; These are copies of the mappings we find in default.conf, but with analog
10
+; mixer paths targeting appropriate Audigy driver controls, and the small
11
+; change of making analog-stereo and analog-mono non-fallback mappings.
12
+; The latter is needed because these cards only support duplex profiles with
13
+; mono inputs, and in the default configuration, with stereo being a fallback
14
; mapping, the mono mapping is never tried.
15
;
16
; See default.conf for an explanation on the directives used here.
17
18
Mapping analog-stereo
19
device-strings = hw:%f
20
channel-map = front-left,front-right
21
-paths-output = analog-output analog-output-lineout analog-output-speaker analog-output-headphones analog-output-headphones-2
22
+paths-output = audigy-analog-output-mirror analog-output-lineout analog-output-speaker analog-output-headphones analog-output-headphones-2
23
paths-input = analog-input-front-mic analog-input-rear-mic analog-input-internal-mic analog-input-dock-mic analog-input analog-input-mic analog-input-linein analog-input-aux analog-input-video analog-input-tvtuner analog-input-fm analog-input-mic-line analog-input-headphone-mic analog-input-headset-mic
24
priority = 1
25
26
27
Mapping analog-mono
28
device-strings = hw:%f
29
channel-map = mono
30
-paths-output = analog-output analog-output-lineout analog-output-speaker analog-output-headphones analog-output-headphones-2 analog-output-mono
31
+paths-output = audigy-analog-output-mirror analog-output-lineout analog-output-speaker analog-output-headphones analog-output-headphones-2 analog-output-mono
32
paths-input = analog-input-front-mic analog-input-rear-mic analog-input-internal-mic analog-input-dock-mic analog-input analog-input-mic analog-input-linein analog-input-aux analog-input-video analog-input-tvtuner analog-input-fm analog-input-mic-line analog-input-headset-mic
33
priority = 1
34
35
-# The rest of these are identical to what's in default.conf
36
Mapping analog-surround-21
37
device-strings = surround21:%f
38
channel-map = front-left,front-right,lfe
39
-paths-output = analog-output analog-output-lineout analog-output-speaker
40
+paths-output = audigy-analog-output analog-output-lineout analog-output-speaker
41
priority = 13
42
direction = output
43
44
Mapping analog-surround-40
45
device-strings = surround40:%f
46
channel-map = front-left,front-right,rear-left,rear-right
47
-paths-output = analog-output analog-output-lineout analog-output-speaker
48
+paths-output = audigy-analog-output analog-output-lineout analog-output-speaker
49
priority = 12
50
direction = output
51
52
Mapping analog-surround-41
53
device-strings = surround41:%f
54
channel-map = front-left,front-right,rear-left,rear-right,lfe
55
-paths-output = analog-output analog-output-lineout analog-output-speaker
56
+paths-output = audigy-analog-output analog-output-lineout analog-output-speaker
57
priority = 13
58
direction = output
59
60
Mapping analog-surround-50
61
device-strings = surround50:%f
62
channel-map = front-left,front-right,rear-left,rear-right,front-center
63
-paths-output = analog-output analog-output-lineout analog-output-speaker
64
+paths-output = audigy-analog-output analog-output-lineout analog-output-speaker
65
priority = 12
66
direction = output
67
68
Mapping analog-surround-51
69
device-strings = surround51:%f
70
channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe
71
-paths-output = analog-output analog-output-lineout analog-output-speaker
72
+paths-output = audigy-analog-output analog-output-lineout analog-output-speaker
73
priority = 13
74
direction = output
75
76
77
device-strings = surround71:%f
78
channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe,side-left,side-right
79
description = Analog Surround 7.1
80
-paths-output = analog-output analog-output-lineout analog-output-speaker
81
+paths-output = audigy-analog-output analog-output-lineout analog-output-speaker
82
priority = 12
83
direction = output
84
85
pipewire-0.3.68.tar.gz/spa/plugins/bluez5/backend-native.c -> pipewire-0.3.69.tar.gz/spa/plugins/bluez5/backend-native.c
Changed
17
1
2
rfcomm_send_reply(rfcomm, "OK");
3
} else if (sscanf(buf, "AT+BIEV=%u,%u", &indicator, &indicator_value) == 2) {
4
process_hfp_hf_indicator(rfcomm, indicator, indicator_value);
5
+ rfcomm_send_reply(rfcomm, "OK");
6
} else if (sscanf(buf, "AT+XAPL=%04x-%04x-%*^,,%u", &xapl_vendor, &xapl_product, &xapl_features) == 3) {
7
if (xapl_features & SPA_BT_HFP_HF_XAPL_FEATURE_BATTERY_REPORTING) {
8
/* claim, that we support battery status reports */
9
10
process_iphoneaccev_indicator(rfcomm, key, value);
11
buf += r;
12
}
13
+ rfcomm_send_reply(rfcomm, "OK");
14
} else if (spa_strstartswith(buf, "AT+APLSIRI?")) {
15
// This command is sent when we activate Apple extensions
16
rfcomm_send_reply(rfcomm, "OK");
17
pipewire-0.3.68.tar.gz/spa/plugins/bluez5/bap-codec-caps.h -> pipewire-0.3.69.tar.gz/spa/plugins/bluez5/bap-codec-caps.h
Changed
29
1
2
3
#define LC3_MAX_CHANNELS 28
4
5
-typedef struct {
6
- uint8_t rate;
7
- uint8_t frame_duration;
8
- uint32_t channels;
9
- uint16_t framelen;
10
- uint8_t n_blks;
11
-} __attribute__ ((packed)) bap_lc3_t;
12
-
13
#define BT_ISO_QOS_CIG_UNSET 0xff
14
#define BT_ISO_QOS_CIS_UNSET 0xff
15
16
17
#define BT_ISO_QOS_TARGET_LATENCY_BALANCED 0x02
18
#define BT_ISO_QOS_TARGET_LATENCY_RELIABILITY 0x03
19
20
+struct __attribute__((packed)) ltv {
21
+ uint8_t len;
22
+ uint8_t type;
23
+ uint8_t value;
24
+};
25
+
26
struct bap_endpoint_qos {
27
uint8_t framing;
28
uint8_t phy;
29
pipewire-0.3.68.tar.gz/spa/plugins/bluez5/bap-codec-lc3.c -> pipewire-0.3.69.tar.gz/spa/plugins/bluez5/bap-codec-lc3.c
Changed
201
1
2
unsigned int codesize;
3
};
4
5
-struct __attribute__((packed)) ltv {
6
- uint8_t len;
7
- uint8_t type;
8
- uint8_t value;
9
-};
10
-
11
struct pac_data {
12
const uint8_t *data;
13
size_t size;
14
};
15
16
+typedef struct {
17
+ uint8_t rate;
18
+ uint8_t frame_duration;
19
+ uint32_t channels;
20
+ uint16_t framelen;
21
+ uint8_t n_blks;
22
+} bap_lc3_t;
23
+
24
static int write_ltv(uint8_t *dest, uint8_t type, void* value, size_t len)
25
{
26
struct ltv *ltv = (struct ltv *)dest;
27
28
data += write_ltv_uint8(data, LC3_TYPE_DUR, LC3_DUR_ANY);
29
data += write_ltv_uint8(data, LC3_TYPE_CHAN, LC3_CHAN_1 | LC3_CHAN_2);
30
data += write_ltv(data, LC3_TYPE_FRAMELEN, framelen, sizeof(framelen));
31
+ /* XXX: we support only one frame block -> max 2 frames per SDU */
32
data += write_ltv_uint8(data, LC3_TYPE_BLKS, 2);
33
34
return data - caps;
35
36
return pac + 1;
37
}
38
39
-static bool parse_capabilities(bap_lc3_t *conf, const uint8_t *data, size_t data_size)
40
+static uint8_t get_num_channels(uint32_t channels)
41
+{
42
+ uint8_t num;
43
+
44
+ if (channels == 0)
45
+ return 1; /* MONO */
46
+
47
+ for (num = 0; channels; channels >>= 1)
48
+ if (channels & 0x1)
49
+ ++num;
50
+
51
+ return num;
52
+}
53
+
54
+static bool select_config(bap_lc3_t *conf, const struct pac_data *pac)
55
{
56
+ const uint8_t *data = pac->data;
57
+ size_t data_size = pac->size;
58
uint16_t framelen_min = 0, framelen_max = 0;
59
+ int max_frames = -1;
60
61
if (!data_size)
62
return false;
63
64
65
conf->frame_duration = 0xFF;
66
67
+ /* XXX: we always use one frame block */
68
+ conf->n_blks = 1;
69
+
70
while (data_size > 0) {
71
struct ltv *ltv = (struct ltv *)data;
72
73
74
spa_return_val_if_fail(ltv->len == 2, false);
75
{
76
uint8_t channels = ltv->value0;
77
- /* Only mono or stereo streams are currently supported,
78
- * in both case Audio location is defined as both Front Left
79
- * and Front Right, difference is done by the n_blks parameter.
80
- */
81
- if ((channels & LC3_CHAN_2) || (channels & LC3_CHAN_1))
82
+ /* XXX: we hardcode mono or stereo stream */
83
+ if (channels & LC3_CHAN_2)
84
conf->channels = LC3_CONFIG_CHNL_FR | LC3_CONFIG_CHNL_FL;
85
+ else if (channels & LC3_CHAN_1)
86
+ conf->channels = 0; /* mono (omit Audio_Channel_Allocation) */
87
else
88
return false;
89
}
90
91
break;
92
case LC3_TYPE_BLKS:
93
spa_return_val_if_fail(ltv->len == 2, false);
94
- conf->n_blks = ltv->value0;
95
- if (!conf->n_blks)
96
- return false;
97
+ max_frames = ltv->value0;
98
break;
99
default:
100
return false;
101
102
data += ltv->len + 1;
103
}
104
105
+ /* Default: 1 per channel (BAP v1.0.1 Sec 4.3.1) */
106
+ if (max_frames < 0)
107
+ max_frames = get_num_channels(conf->channels);
108
+ if (max_frames < get_num_channels(conf->channels))
109
+ return false;
110
+
111
if (framelen_min < LC3_MIN_FRAME_BYTES || framelen_max > LC3_MAX_FRAME_BYTES)
112
return false;
113
if (conf->frame_duration == 0xFF || !conf->rate)
114
return false;
115
- if (!conf->channels)
116
- conf->channels = LC3_CONFIG_CHNL_FL;
117
118
+ /* BAP v1.0.1 Table 5.2; high-reliability */
119
switch (conf->rate) {
120
case LC3_CONFIG_FREQ_48KHZ:
121
if (conf->frame_duration == LC3_CONFIG_DURATION_7_5)
122
- conf->framelen = 117;
123
+ conf->framelen = 117; /* 48_5_2 */
124
else
125
- conf->framelen = 120;
126
+ conf->framelen = 120; /* 48_4_2 */
127
break;
128
case LC3_CONFIG_FREQ_24KHZ:
129
if (conf->frame_duration == LC3_CONFIG_DURATION_7_5)
130
- conf->framelen = 45;
131
+ conf->framelen = 45; /* 24_1_2 */
132
else
133
- conf->framelen = 60;
134
+ conf->framelen = 60; /* 24_2_2 */
135
break;
136
case LC3_CONFIG_FREQ_16KHZ:
137
if (conf->frame_duration == LC3_CONFIG_DURATION_7_5)
138
- conf->framelen = 30;
139
+ conf->framelen = 30; /* 16_1_2 */
140
else
141
- conf->framelen = 40;
142
+ conf->framelen = 40; /* 16_2_2 */
143
break;
144
case LC3_CONFIG_FREQ_8KHZ:
145
if (conf->frame_duration == LC3_CONFIG_DURATION_7_5)
146
- conf->framelen = 26;
147
+ conf->framelen = 26; /* 8_1_2 */
148
else
149
- conf->framelen = 30;
150
+ conf->framelen = 30; /* 8_2_2 */
151
break;
152
default:
153
return false;
154
155
156
conf->frame_duration = 0xFF;
157
158
+ /* Absent Codec_Frame_Blocks_Per_SDU means 0x1 (BAP v1.0.1 Sec 4.3.2) */
159
+ conf->n_blks = 1;
160
+
161
while (data_size > 0) {
162
struct ltv *ltv = (struct ltv *)data;
163
164
165
case LC3_TYPE_BLKS:
166
spa_return_val_if_fail(ltv->len == 2, false);
167
conf->n_blks = ltv->value0;
168
- if (!conf->n_blks)
169
+ /* XXX: we only support 1 frame block for now */
170
+ if (conf->n_blks != 1)
171
return false;
172
break;
173
default:
174
175
bap_lc3_t conf1, conf2;
176
int res1, res2;
177
178
- res1 = parse_capabilities(&conf1, pac1->data, pac1->size) ? (int)sizeof(bap_lc3_t) : -EINVAL;
179
- res2 = parse_capabilities(&conf2, pac2->data, pac2->size) ? (int)sizeof(bap_lc3_t) : -EINVAL;
180
+ res1 = select_config(&conf1, pac1) ? (int)sizeof(bap_lc3_t) : -EINVAL;
181
+ res2 = select_config(&conf2, pac2) ? (int)sizeof(bap_lc3_t) : -EINVAL;
182
183
return conf_cmp(&conf1, res1, &conf2, res2);
184
}
185
186
187
qsort(pacs, npacs, sizeof(struct pac_data), pac_cmp);
188
189
- if (!parse_capabilities(&conf, pacs0.data, pacs0.size))
190
+ if (!select_config(&conf, &pacs0))
191
return -ENOTSUP;
192
193
data += write_ltv_uint8(data, LC3_TYPE_FREQ, conf.rate);
194
data += write_ltv_uint8(data, LC3_TYPE_DUR, conf.frame_duration);
195
- data += write_ltv_uint32(data, LC3_TYPE_CHAN, htobl(conf.channels));
196
+
197
+ /* Indicate MONO with absent Audio_Channel_Allocation (BAP v1.0.1 Sec. 4.3.2) */
198
+ if (conf.channels != 0)
199
+ data += write_ltv_uint32(data, LC3_TYPE_CHAN, htobl(conf.channels));
200
+
201
pipewire-0.3.68.tar.gz/spa/plugins/bluez5/bluez5-dbus.c -> pipewire-0.3.69.tar.gz/spa/plugins/bluez5/bluez5-dbus.c
Changed
201
1
2
#include <sys/stat.h>
3
#include <sys/socket.h>
4
#include <fcntl.h>
5
+#include <limits.h>
6
7
#include <bluetooth/bluetooth.h>
8
9
10
#include "iso-io.h"
11
#include "defs.h"
12
13
+#include "bap-codec-caps.h"
14
+
15
static struct spa_log_topic log_topic = SPA_LOG_TOPIC(0, "spa.bluez5");
16
#undef SPA_LOG_TOPIC_DEFAULT
17
#define SPA_LOG_TOPIC_DEFAULT &log_topic
18
19
spa_list_init(&d->remote_endpoint_list);
20
spa_list_init(&d->transport_list);
21
spa_list_init(&d->codec_switch_list);
22
+ spa_list_init(&d->set_membership_list);
23
24
spa_hook_list_init(&d->listener_list);
25
26
27
struct spa_bt_media_codec_switch *sw;
28
struct spa_bt_transport *t, *tt;
29
struct spa_bt_monitor *monitor = device->monitor;
30
+ struct spa_bt_set_membership *s;
31
32
spa_log_debug(monitor->log, "%p", device);
33
34
35
spa_list_consume(sw, &device->codec_switch_list, device_link)
36
media_codec_switch_free(sw);
37
38
+ spa_list_consume(s, &device->set_membership_list, link) {
39
+ spa_list_remove(&s->link);
40
+ spa_list_remove(&s->others);
41
+ free(s->path);
42
+ free(s);
43
+ }
44
+
45
spa_list_remove(&device->link);
46
free(device->path);
47
free(device->alias);
48
49
free(device);
50
}
51
52
+static struct spa_bt_set_membership *device_set_find(struct spa_bt_monitor *monitor, const char *path)
53
+{
54
+ struct spa_bt_device *d;
55
+
56
+ spa_list_for_each(d, &monitor->device_list, link) {
57
+ struct spa_bt_set_membership *s;
58
+
59
+ spa_list_for_each(s, &d->set_membership_list, link) {
60
+ if (spa_streq(s->path, path))
61
+ return s;
62
+ }
63
+ }
64
+
65
+ return NULL;
66
+}
67
+
68
+static int device_add_device_set(struct spa_bt_device *device, const char *path, uint8_t rank)
69
+{
70
+ struct spa_bt_monitor *monitor = device->monitor;
71
+ struct spa_bt_set_membership *s, *set;
72
+
73
+ spa_list_for_each(s, &device->set_membership_list, link) {
74
+ if (spa_streq(s->path, path)) {
75
+ if (rank)
76
+ s->rank = rank;
77
+ return 0;
78
+ }
79
+ }
80
+
81
+ s = calloc(1, sizeof(struct spa_bt_set_membership));
82
+ if (s == NULL)
83
+ return -ENOMEM;
84
+
85
+ s->path = strdup(path);
86
+ if (!s->path) {
87
+ free(s);
88
+ return -ENOMEM;
89
+ }
90
+
91
+ s->device = device;
92
+ s->rank = rank;
93
+
94
+ spa_list_init(&s->others);
95
+
96
+ /* Join with other set members, if any */
97
+ set = device_set_find(monitor, path);
98
+ if (set)
99
+ spa_list_append(&set->others, &s->others);
100
+
101
+ spa_list_append(&device->set_membership_list, &s->link);
102
+
103
+ spa_log_debug(monitor->log, "device %p: add %s to device set %s", device,
104
+ device->path, path);
105
+
106
+ return 1;
107
+}
108
+
109
+static bool device_remove_device_set(struct spa_bt_device *device, const char *path)
110
+{
111
+ struct spa_bt_monitor *monitor = device->monitor;
112
+ struct spa_bt_set_membership *s;
113
+
114
+ spa_list_for_each(s, &device->set_membership_list, link) {
115
+ if (spa_streq(s->path, path)) {
116
+ spa_log_debug(monitor->log,
117
+ "device %p: remove %s from device set %s", device,
118
+ device->path, path);
119
+ spa_list_remove(&s->link);
120
+ spa_list_remove(&s->others);
121
+ free(s->path);
122
+ free(s);
123
+ return true;
124
+ }
125
+ }
126
+
127
+ return false;
128
+}
129
+
130
int spa_bt_format_vendor_product_id(uint16_t source_id, uint16_t vendor_id, uint16_t product_id,
131
char *vendor_str, int vendor_str_size, char *product_str, int product_str_size)
132
{
133
134
int spa_bt_device_check_profiles(struct spa_bt_device *device, bool force)
135
{
136
struct spa_bt_monitor *monitor = device->monitor;
137
+ struct spa_bt_set_membership *s, *set;
138
uint32_t connected_profiles = device->connected_profiles;
139
uint32_t connectable_profiles =
140
device->adapter ? adapter_connectable_profiles(device->adapter) : 0;
141
142
SPA_BT_PROFILE_HEADSET_AUDIO_GATEWAY,
143
};
144
bool direction_connected = false;
145
+ bool set_connected = true;
146
bool all_connected;
147
size_t i;
148
149
150
151
all_connected = (device->profiles & connected_profiles) == device->profiles;
152
153
- spa_log_debug(monitor->log, "device %p: profiles %08x %08x connectable:%08x added:%d all:%d dir:%d",
154
+ spa_list_for_each(set, &device->set_membership_list, link)
155
+ spa_bt_for_each_set_member(s, set)
156
+ if ((s->device->connected_profiles & s->device->profiles) != s->device->profiles)
157
+ set_connected = false;
158
+
159
+ spa_log_debug(monitor->log, "device %p: profiles %08x %08x connectable:%08x added:%d all:%d dir:%d set:%d",
160
device, device->profiles, connected_profiles, connectable_profiles,
161
- device->added, all_connected, direction_connected);
162
+ device->added, all_connected, direction_connected, set_connected);
163
164
if (connected_profiles == 0 && spa_list_is_empty(&device->codec_switch_list)) {
165
device_stop_timer(device);
166
device_connected(monitor, device, BT_DEVICE_DISCONNECTED);
167
- } else if (force || direction_connected || all_connected) {
168
+ } else if (force || ((direction_connected || all_connected) && set_connected)) {
169
device_stop_timer(device);
170
device_connected(monitor, device, BT_DEVICE_CONNECTED);
171
} else {
172
173
}
174
}
175
176
+static void device_update_set_status(struct spa_bt_device *device, bool force, const char *path);
177
+
178
int spa_bt_device_connect_profile(struct spa_bt_device *device, enum spa_bt_profile profile)
179
{
180
uint32_t prev_connected = device->connected_profiles;
181
device->connected_profiles |= profile;
182
+ if ((prev_connected ^ device->connected_profiles) & SPA_BT_PROFILE_BAP_DUPLEX)
183
+ device_update_set_status(device, true, NULL);
184
spa_bt_device_check_profiles(device, false);
185
if (device->connected_profiles != prev_connected)
186
spa_bt_device_emit_profiles_changed(device, device->profiles, prev_connected);
187
188
spa_log_debug(monitor->log, "hw-volume-profiles:%08x", (int)device->hw_volume_profiles);
189
}
190
191
+static bool device_set_update_leader(struct spa_bt_set_membership *set)
192
+{
193
+ struct spa_bt_set_membership *s, *leader;
194
+ int min_rank = INT_MAX;
195
+ int leader_rank = INT_MAX;
196
+
197
+ leader = NULL;
198
+
199
+ spa_bt_for_each_set_member(s, set) {
200
+ if (!(s->device->connected_profiles & SPA_BT_PROFILE_BAP_DUPLEX))
201
pipewire-0.3.68.tar.gz/spa/plugins/bluez5/bluez5-device.c -> pipewire-0.3.69.tar.gz/spa/plugins/bluez5/bluez5-device.c
Changed
201
1
2
3
#define DEVICE_ID_SOURCE 0
4
#define DEVICE_ID_SINK 1
5
+#define DEVICE_ID_SOURCE_SET 2
6
+#define DEVICE_ID_SINK_SET 3
7
#define DYNAMIC_NODE_ID_FLAG 0x1000
8
9
static struct spa_i18n *_i18n;
10
11
bool a2dp_duplex;
12
};
13
14
+struct device_set_member {
15
+ struct impl *impl;
16
+ struct spa_bt_transport *transport;
17
+ struct spa_hook listener;
18
+};
19
+
20
+struct device_set {
21
+ struct impl *impl;
22
+ char *path;
23
+ bool leader;
24
+ uint32_t sinks;
25
+ uint32_t sources;
26
+ struct device_set_member sinkSPA_AUDIO_MAX_CHANNELS;
27
+ struct device_set_member sourceSPA_AUDIO_MAX_CHANNELS;
28
+};
29
+
30
struct impl {
31
struct spa_handle handle;
32
struct spa_device device;
33
34
unsigned int save_profile:1;
35
uint32_t prev_bt_connected_profiles;
36
37
+ struct device_set device_set;
38
+
39
const struct media_codec **supported_codecs;
40
size_t supported_codec_count;
41
42
43
struct spa_dict_item setting_itemsMAX_SETTINGS;
44
struct spa_dict setting_dict;
45
46
- struct node nodes2;
47
+ struct node nodes4;
48
};
49
50
static void init_node(struct impl *this, struct node *node, uint32_t id)
51
52
struct spa_bt_transport_volume *t_volume;
53
float prev_hw_volume;
54
55
- if (!node->transport || !spa_bt_transport_volume_enabled(node->transport))
56
+ if (!node->active || !node->transport || !spa_bt_transport_volume_enabled(node->transport))
57
return false;
58
59
/* PW is the controller for remote device. */
60
61
info.info.raw.channels * sizeof(uint32_t));
62
}
63
64
+static const char *get_channel_name(uint32_t channel)
65
+{
66
+ int i;
67
+ for (i = 0; spa_type_audio_channeli.name; i++) {
68
+ if (spa_type_audio_channeli.type == channel)
69
+ return spa_debug_type_short_name(spa_type_audio_channeli.name);
70
+ }
71
+ return NULL;
72
+}
73
+
74
+static int channel_position_cmp(const void *pa, const void *pb)
75
+{
76
+ uint32_t a = *(uint32_t *)pa, b = *(uint32_t *)pb;
77
+ return (int)a - (int)b;
78
+}
79
+
80
+static void emit_device_set_node(struct impl *this, uint32_t id)
81
+{
82
+ struct spa_bt_device *device = this->bt_dev;
83
+ struct node *node = &this->nodesid;
84
+ struct spa_device_object_info info;
85
+ struct spa_dict_item items7;
86
+ char str_id32, members_json8192, channels_json512;
87
+ struct device_set_member *members;
88
+ uint32_t n_members;
89
+ uint32_t n_items = 0;
90
+ struct spa_strbuf json;
91
+ unsigned int i;
92
+
93
+ itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_API_BLUEZ5_ADDRESS, device->address);
94
+ itemsn_items++ = SPA_DICT_ITEM_INIT("api.bluez5.set", this->device_set.path);
95
+ itemsn_items++ = SPA_DICT_ITEM_INIT("api.bluez5.set.leader", "true");
96
+ snprintf(str_id, sizeof(str_id), "%d", id);
97
+ itemsn_items++ = SPA_DICT_ITEM_INIT("card.profile.device", str_id);
98
+
99
+ if (id == DEVICE_ID_SOURCE_SET) {
100
+ itemsn_items++ = SPA_DICT_ITEM_INIT("media.class", "Audio/Source");
101
+ members = this->device_set.source;
102
+ n_members = this->device_set.sources;
103
+ } else if (id == DEVICE_ID_SINK_SET) {
104
+ itemsn_items++ = SPA_DICT_ITEM_INIT("media.class", "Audio/Sink");
105
+ members = this->device_set.sink;
106
+ n_members = this->device_set.sinks;
107
+ } else {
108
+ spa_assert_not_reached();
109
+ }
110
+
111
+ node->impl = this;
112
+ node->active = true;
113
+ node->transport = NULL;
114
+ node->a2dp_duplex = false;
115
+ node->offload_acquired = false;
116
+ node->mute = false;
117
+ node->save = false;
118
+ node->latency_offset = 0;
119
+
120
+ /* Form channel map from members */
121
+ node->n_channels = 0;
122
+ for (i = 0; i < n_members; ++i) {
123
+ struct spa_bt_transport *t = membersi.transport;
124
+ unsigned int j;
125
+
126
+ for (j = 0; j < t->n_channels; ++j) {
127
+ unsigned int k;
128
+
129
+ if (!get_channel_name(t->channelsj))
130
+ continue;
131
+
132
+ for (k = 0; k < node->n_channels; ++k) {
133
+ if (node->channelsk == t->channelsj)
134
+ break;
135
+ }
136
+ if (k == node->n_channels && node->n_channels < SPA_AUDIO_MAX_CHANNELS)
137
+ node->channelsnode->n_channels++ = t->channelsj;
138
+ }
139
+ }
140
+
141
+ qsort(node->channels, node->n_channels, sizeof(uint32_t), channel_position_cmp);
142
+
143
+ for (i = 0; i < node->n_channels; ++i) {
144
+ /* Session manager will override this, so put in some safe number */
145
+ node->volumesi = node->soft_volumesi = 0.064;
146
+ }
147
+
148
+ /* Produce member info json */
149
+ spa_strbuf_init(&json, members_json, sizeof(members_json));
150
+ spa_strbuf_append(&json, "");
151
+ for (i = 0; i < n_members; ++i) {
152
+ struct spa_bt_transport *t = membersi.transport;
153
+ char object_path512;
154
+ unsigned int j;
155
+ int member_id = (id == DEVICE_ID_SINK_SET) ? DEVICE_ID_SINK : DEVICE_ID_SOURCE;
156
+
157
+ if (i > 0)
158
+ spa_strbuf_append(&json, ",");
159
+ spa_scnprintf(object_path, sizeof(object_path), "%s/%s-%d",
160
+ this->device_set.path, t->device->address, member_id);
161
+ spa_strbuf_append(&json, "{\"object.path\":\"%s\",\"channels\":", object_path);
162
+ for (j = 0; j < t->n_channels; ++j) {
163
+ if (j > 0)
164
+ spa_strbuf_append(&json, ",");
165
+ spa_strbuf_append(&json, "\"%s\"", get_channel_name(t->channelsj));
166
+ }
167
+ spa_strbuf_append(&json, "}");
168
+ }
169
+ spa_strbuf_append(&json, "");
170
+ json.bufferSPA_MIN(json.pos, json.maxsize-1) = 0;
171
+ itemsn_items++ = SPA_DICT_ITEM_INIT("api.bluez5.set.members", members_json);
172
+
173
+ spa_strbuf_init(&json, channels_json, sizeof(channels_json));
174
+ spa_strbuf_append(&json, "");
175
+ for (i = 0; i < node->n_channels; ++i) {
176
+ if (i > 0)
177
+ spa_strbuf_append(&json, ",");
178
+ spa_strbuf_append(&json, "\"%s\"", get_channel_name(node->channelsi));
179
+ }
180
+ spa_strbuf_append(&json, "");
181
+ json.bufferSPA_MIN(json.pos, json.maxsize-1) = 0;
182
+ itemsn_items++ = SPA_DICT_ITEM_INIT("api.bluez5.set.channels", channels_json);
183
+
184
+ /* Emit */
185
+ info = SPA_DEVICE_OBJECT_INFO_INIT();
186
+ info.type = SPA_TYPE_INTERFACE_Node;
187
+ info.factory_name = (id == DEVICE_ID_SOURCE_SET) ? "source" : "sink";
188
+ info.change_mask = SPA_DEVICE_OBJECT_CHANGE_MASK_PROPS;
189
+ info.props = &SPA_DICT_INIT(items, n_items);
190
+
191
+ spa_device_emit_object_info(&this->hooks, id, &info);
192
+
193
+ emit_node_props(this, &this->nodesid, true);
194
+}
195
+
196
static void emit_node(struct impl *this, struct spa_bt_transport *t,
197
uint32_t id, const char *factory_name, bool a2dp_duplex)
198
{
199
struct spa_bt_device *device = this->bt_dev;
200
struct spa_device_object_info info;
201
pipewire-0.3.68.tar.gz/spa/plugins/bluez5/defs.h -> pipewire-0.3.69.tar.gz/spa/plugins/bluez5/defs.h
Changed
62
1
2
#define BLUEZ_PROFILE_INTERFACE BLUEZ_SERVICE ".Profile1"
3
#define BLUEZ_ADAPTER_INTERFACE BLUEZ_SERVICE ".Adapter1"
4
#define BLUEZ_DEVICE_INTERFACE BLUEZ_SERVICE ".Device1"
5
+#define BLUEZ_DEVICE_SET_INTERFACE BLUEZ_SERVICE ".DeviceSet1"
6
#define BLUEZ_MEDIA_INTERFACE BLUEZ_SERVICE ".Media1"
7
#define BLUEZ_MEDIA_ENDPOINT_INTERFACE BLUEZ_SERVICE ".MediaEndpoint1"
8
#define BLUEZ_MEDIA_TRANSPORT_INTERFACE BLUEZ_SERVICE ".MediaTransport1"
9
10
/** Profile configuration changed */
11
void (*profiles_changed) (void *data, uint32_t prev_profiles, uint32_t prev_connected);
12
13
+ /** Device set configuration changed */
14
+ void (*device_set_changed) (void *data);
15
+
16
/** Device freed */
17
void (*destroy) (void *data);
18
};
19
20
struct media_codec;
21
22
+struct spa_bt_set_membership {
23
+ struct spa_list link;
24
+ struct spa_list others;
25
+ struct spa_bt_device *device;
26
+ char *path;
27
+ uint8_t rank;
28
+ bool leader;
29
+};
30
+
31
+#define spa_bt_for_each_set_member(s, set) \
32
+ for ((s) = (set); (s); (s) = spa_list_next((s), others), (s) = (s) != (set) ? (s) : NULL)
33
+
34
struct spa_bt_device {
35
struct spa_list link;
36
struct spa_bt_monitor *monitor;
37
38
struct spa_list remote_endpoint_list;
39
struct spa_list transport_list;
40
struct spa_list codec_switch_list;
41
+ struct spa_list set_membership_list;
42
uint8_t battery;
43
int has_battery;
44
45
46
#define spa_bt_device_emit_connected(d,...) spa_bt_device_emit(d, connected, 0, __VA_ARGS__)
47
#define spa_bt_device_emit_codec_switched(d,...) spa_bt_device_emit(d, codec_switched, 0, __VA_ARGS__)
48
#define spa_bt_device_emit_profiles_changed(d,...) spa_bt_device_emit(d, profiles_changed, 0, __VA_ARGS__)
49
+#define spa_bt_device_emit_device_set_changed(d) spa_bt_device_emit(d, device_set_changed, 0)
50
#define spa_bt_device_emit_destroy(d) spa_bt_device_emit(d, destroy, 0)
51
#define spa_bt_device_add_listener(d,listener,events,data) \
52
spa_hook_list_append(&(d)->listener_list, listener, events, data)
53
54
unsigned int latency_us;
55
uint8_t bap_cig;
56
uint8_t bap_cis;
57
+ uint32_t bap_location;
58
+ uint32_t bap_interval;
59
60
struct spa_bt_iso_io *iso_io;
61
struct spa_bt_sco_io *sco_io;
62
pipewire-0.3.68.tar.gz/spa/plugins/bluez5/iso-io.c -> pipewire-0.3.69.tar.gz/spa/plugins/bluez5/iso-io.c
Changed
120
1
2
#include <spa/utils/result.h>
3
#include <spa/node/io.h>
4
5
-#include <bluetooth/bluetooth.h>
6
-
7
#include "config.h"
8
#include "iso-io.h"
9
10
11
#undef SPA_LOG_TOPIC_DEFAULT
12
#define SPA_LOG_TOPIC_DEFAULT &log_topic
13
14
-#define IDLE_TIME (100 * SPA_NSEC_PER_MSEC)
15
+#define IDLE_TIME (200 * SPA_NSEC_PER_MSEC)
16
17
struct group {
18
struct spa_log *log;
19
20
21
if (!stream->sink)
22
continue;
23
- if (stream->idle)
24
- continue;
25
- if (group->paused) {
26
+ if (stream->idle || group->paused) {
27
+ stream->this.resync = true;
28
stream->this.size = 0;
29
continue;
30
}
31
32
set_timeout(group, group->next);
33
}
34
35
-static struct group *group_create(int fd, struct spa_log *log, struct spa_loop *data_loop,
36
- struct spa_system *data_system)
37
+static struct group *group_create(uint8_t cig, uint32_t interval,
38
+ struct spa_log *log, struct spa_loop *data_loop, struct spa_system *data_system)
39
{
40
-#if defined(HAVE_BLUETOOTH_BAP) && defined(BT_ISO_QOS)
41
struct group *group;
42
- struct bt_iso_qos qos;
43
- socklen_t len;
44
-
45
- len = sizeof(qos);
46
- if (getsockopt(fd, SOL_BLUETOOTH, BT_ISO_QOS, &qos, &len) < 0)
47
- return NULL;
48
49
- if (qos.out.interval <= 5000) {
50
+ if (interval <= 5000) {
51
errno = EINVAL;
52
return NULL;
53
}
54
55
56
spa_log_topic_init(log, &log_topic);
57
58
- group->cig = qos.cig;
59
+ group->cig = cig;
60
group->log = log;
61
group->data_loop = data_loop;
62
group->data_system = data_system;
63
- group->duration = qos.out.interval * SPA_NSEC_PER_USEC;
64
+ group->duration = interval * SPA_NSEC_PER_USEC;
65
66
spa_list_init(&group->streams);
67
68
69
spa_loop_add_source(group->data_loop, &group->source);
70
71
return group;
72
-#else
73
- errno = EOPNOTSUPP;
74
- return NULL;
75
-#endif
76
}
77
78
static int do_remove_source(struct spa_loop *loop, bool async, uint32_t seq,
79
80
stream->fd = fd;
81
stream->sink = sink;
82
stream->group = group;
83
+ stream->idle = true;
84
stream->this.duration = group->duration;
85
86
stream_link(group, stream);
87
88
return stream;
89
}
90
91
-struct spa_bt_iso_io *spa_bt_iso_io_create(int fd, bool sink, struct spa_log *log,
92
- struct spa_loop *data_loop, struct spa_system *data_system)
93
+struct spa_bt_iso_io *spa_bt_iso_io_create(int fd, bool sink, uint8_t cig, uint32_t interval,
94
+ struct spa_log *log, struct spa_loop *data_loop, struct spa_system *data_system)
95
{
96
struct stream *stream;
97
struct group *group;
98
99
- group = group_create(fd, log, data_loop, data_system);
100
+ group = group_create(cig, interval, log, data_loop, data_system);
101
if (group == NULL)
102
return NULL;
103
104
105
else if (enabled && !was_enabled)
106
set_timers(stream->group);
107
108
+ stream->idle = true;
109
+ stream->this.resync = true;
110
+
111
if (pull == NULL) {
112
stream->this.size = 0;
113
return;
114
}
115
-
116
- /* Pull data now for the next interval */
117
- stream->this.now = stream->group->next;
118
- stream->pull(&stream->this);
119
}
120
pipewire-0.3.68.tar.gz/spa/plugins/bluez5/iso-io.h -> pipewire-0.3.69.tar.gz/spa/plugins/bluez5/iso-io.h
Changed
31
1
2
*/
3
struct spa_bt_iso_io
4
{
5
- uint64_t now;
6
- uint64_t duration;
7
+ uint64_t now; /**< Reference time position of next packet (read-only) */
8
+ uint64_t duration; /**< ISO interval duration in ns (read-only) */
9
+ bool resync; /**< Resync position for next packet; (pull callback sets to
10
+ * false when done) */
11
12
- uint32_t timestamp;
13
- uint8_t buf4096;
14
- size_t size;
15
+ uint32_t timestamp; /**< Packet timestamp (set by pull callback) */
16
+ uint8_t buf4096; /**< Packet data (set by pull callback) */
17
+ size_t size; /**< Packet size (set by pull callback) */
18
19
void *user_data;
20
};
21
22
typedef void (*spa_bt_iso_io_pull_t)(struct spa_bt_iso_io *io);
23
24
-struct spa_bt_iso_io *spa_bt_iso_io_create(int fd, bool sink, struct spa_log *log,
25
- struct spa_loop *data_loop, struct spa_system *data_system);
26
+struct spa_bt_iso_io *spa_bt_iso_io_create(int fd, bool sink, uint8_t cig, uint32_t interval,
27
+ struct spa_log *log, struct spa_loop *data_loop, struct spa_system *data_system);
28
struct spa_bt_iso_io *spa_bt_iso_io_attach(struct spa_bt_iso_io *io, int fd, bool sink);
29
void spa_bt_iso_io_destroy(struct spa_bt_iso_io *io);
30
void spa_bt_iso_io_set_cb(struct spa_bt_iso_io *io, spa_bt_iso_io_pull_t pull, void *user_data);
31
pipewire-0.3.68.tar.gz/spa/plugins/bluez5/media-sink.c -> pipewire-0.3.69.tar.gz/spa/plugins/bluez5/media-sink.c
Changed
201
1
2
#define BUFFER_SIZE (8192*8)
3
#define RATE_CTL_DIFF_MAX 0.005
4
5
+/* Wait for two cycles before trying to sync ISO. On start/driver reassign,
6
+ * first cycle may have strange number of samples. */
7
+#define RESYNC_CYCLES 2
8
+
9
struct buffer {
10
uint32_t id;
11
#define BUFFER_FLAG_OUT (1<<0)
12
13
unsigned int following:1;
14
unsigned int is_output:1;
15
unsigned int flush_pending:1;
16
+ unsigned int iso_pending:1;
17
18
unsigned int is_duplex:1;
19
+ unsigned int is_internal:1;
20
21
struct spa_source source;
22
int timerfd;
23
24
25
int need_flush;
26
bool fragment;
27
- bool resync;
28
- bool have_iso_packet;
29
+ uint32_t resync;
30
uint32_t block_size;
31
uint8_t bufferBUFFER_SIZE;
32
uint32_t buffer_used;
33
34
bool following;
35
36
if (this->position != info->position || this->clock != info->clock)
37
- this->resync = true;
38
+ this->resync = RESYNC_CYCLES;
39
40
this->position = info->position;
41
this->clock = info->clock;
42
43
{
44
struct port *port = &this->port;
45
uint64_t t, duration_ns;
46
+ bool resampling;
47
48
if (!this->process_rate || !this->process_duration) {
49
if (this->position) {
50
51
/ port->current_format.info.raw.rate);
52
53
/* Account for resampling delay */
54
- if (port->rate_match && this->clock && SPA_FLAG_IS_SET(port->rate_match->flags, SPA_IO_RATE_MATCH_FLAG_ACTIVE))
55
+ resampling = (port->current_format.info.raw.rate != this->process_rate) || this->following;
56
+ if (port->rate_match && this->clock && resampling) {
57
t -= (uint64_t)port->rate_match->delay * SPA_NSEC_PER_SEC
58
/ this->clock->rate.denom;
59
+ t += SPA_NSEC_PER_SEC / port->current_format.info.raw.rate;
60
+ }
61
62
return t;
63
}
64
65
if (!this->flush_timer_source.loop && !this->transport->iso_io)
66
return -EIO;
67
68
+ if (this->transport->iso_io && !this->iso_pending)
69
+ return 0;
70
+
71
total_frames = 0;
72
again:
73
written = 0;
74
75
if (this->transport->iso_io) {
76
struct spa_bt_iso_io *iso_io = this->transport->iso_io;
77
78
- if (this->need_flush && !this->have_iso_packet) {
79
+ if (this->need_flush) {
80
size_t avail = SPA_MIN(this->buffer_used, sizeof(iso_io->buf));
81
82
spa_log_trace(this->log, "%p: ISO put fd:%d size:%u sn:%u ts:%u now:%"PRIu64,
83
84
memcpy(iso_io->buf, this->buffer, avail);
85
iso_io->size = avail;
86
iso_io->timestamp = this->timestamp;
87
- this->have_iso_packet = true;
88
+ this->iso_pending = false;
89
90
reset_buffer(this);
91
}
92
93
struct port *port = &this->port;
94
const double period = 0.1 * SPA_NSEC_PER_SEC;
95
uint64_t duration_ns;
96
- double value, target, err;
97
-
98
- this->have_iso_packet = false;
99
+ double value, target, err, max_err;
100
101
if (this->resync || !this->position) {
102
spa_bt_rate_control_init(&port->ratectl, 0);
103
104
value = (int64_t)iso_io->now - (int64_t)get_reference_time(this, &duration_ns);
105
target = iso_io->duration * 3/2;
106
err = value - target;
107
+ max_err = iso_io->duration;
108
109
- if (err > iso_io->duration) {
110
- uint32_t req = err * port->current_format.info.raw.rate / SPA_NSEC_PER_SEC;
111
-
112
- spa_log_debug(this->log, "%p: ISO sync reset frames:%u", this, (unsigned int)req);
113
-
114
- spa_bt_rate_control_init(&port->ratectl, 0);
115
- drop_frames(this, req);
116
- } else if (-err > iso_io->duration) {
117
- uint32_t req = -err * port->current_format.info.raw.rate / SPA_NSEC_PER_SEC;
118
+ if (err > max_err || (iso_io->resync && err > 0)) {
119
+ unsigned int req = err * port->current_format.info.raw.rate / SPA_NSEC_PER_SEC;
120
121
- spa_log_debug(this->log, "%p: ISO sync skip flush frames:%u", this, (unsigned int)req);
122
- return;
123
+ if (req > 0) {
124
+ spa_bt_rate_control_init(&port->ratectl, 0);
125
+ drop_frames(this, req);
126
+ spa_log_debug(this->log, "%p: ISO sync skip frames:%u resync:%d",
127
+ this, req, iso_io->resync);
128
+ }
129
+ } else if (-err > max_err || (iso_io->resync && -err > 0)) {
130
+ unsigned int req = -err * port->current_format.info.raw.rate / SPA_NSEC_PER_SEC;
131
+ static const uint8_t empty8192 = {0};
132
+
133
+ if (req > 0) {
134
+ spa_bt_rate_control_init(&port->ratectl, 0);
135
+ req = SPA_MIN(req, sizeof(empty) / port->frame_size);
136
+ add_data(this, empty, req * port->frame_size);
137
+ spa_log_debug(this->log, "%p: ISO sync pad frames:%u resync:%d",
138
+ this, req, iso_io->resync);
139
+ }
140
} else {
141
spa_bt_rate_control_update(&port->ratectl, err, 0,
142
iso_io->duration, period, RATE_CTL_DIFF_MAX);
143
144
port->ratectl.corr);
145
}
146
147
+ iso_io->resync = false;
148
+
149
done:
150
+ this->iso_pending = true;
151
flush_data(this, this->current_time);
152
}
153
154
155
this->flush_source.rmask = 0;
156
spa_loop_add_source(this->data_loop, &this->flush_source);
157
158
- this->resync = true;
159
-
160
+ this->resync = RESYNC_CYCLES;
161
this->flush_pending = false;
162
+ this->iso_pending = false;
163
164
this->transport_started = true;
165
166
167
{
168
struct spa_dict_item node_info_items = {
169
{ SPA_KEY_DEVICE_API, "bluez5" },
170
- { SPA_KEY_MEDIA_CLASS, this->is_output ? "Audio/Sink" : "Stream/Input/Audio" },
171
+ { SPA_KEY_MEDIA_CLASS, this->is_internal ? "Audio/Sink/Internal" :
172
+ this->is_output ? "Audio/Sink" : "Stream/Input/Audio" },
173
{ "media.name", ((this->transport && this->transport->device->name) ?
174
this->transport->device->name : this->codec->bap ? "BAP" : "A2DP" ) },
175
{ SPA_KEY_NODE_DRIVER, this->is_output ? "true" : "false" },
176
177
178
if (io->status == SPA_STATUS_HAVE_DATA && io->buffer_id < port->n_buffers) {
179
struct buffer *b = &port->buffersio->buffer_id;
180
+ struct spa_data *d = b->buf->datas;
181
+ unsigned int frames;
182
183
if (!SPA_FLAG_IS_SET(b->flags, BUFFER_FLAG_OUT)) {
184
spa_log_warn(this->log, "%p: buffer %u in use", this, io->buffer_id);
185
186
return -EINVAL;
187
}
188
189
- spa_log_trace(this->log, "%p: queue buffer %u", this, io->buffer_id);
190
+ frames = d ? d0.chunk->size / port->frame_size : 0;
191
+ spa_log_trace(this->log, "%p: queue buffer %u frames:%u", this, io->buffer_id, frames);
192
193
spa_list_append(&port->ready, &b->link);
194
SPA_FLAG_CLEAR(b->flags, BUFFER_FLAG_OUT);
195
196
}
197
198
this->process_time = this->current_time;
199
- this->resync = false;
200
+ if (this->resync)
201
pipewire-0.3.68.tar.gz/spa/plugins/bluez5/media-source.c -> pipewire-0.3.69.tar.gz/spa/plugins/bluez5/media-source.c
Changed
28
1
2
3
unsigned int is_input:1;
4
unsigned int is_duplex:1;
5
+ unsigned int is_internal:1;
6
unsigned int use_duplex_source:1;
7
8
unsigned int node_latency;
9
10
11
struct spa_dict_item node_info_items = {
12
{ SPA_KEY_DEVICE_API, "bluez5" },
13
- { SPA_KEY_MEDIA_CLASS, this->is_input ? "Audio/Source" : "Stream/Output/Audio" },
14
+ { SPA_KEY_MEDIA_CLASS, this->is_internal ? "Audio/Source/Internal" :
15
+ this->is_input ? "Audio/Source" : "Stream/Output/Audio" },
16
{ SPA_KEY_NODE_LATENCY, this->is_input ? "" : latency },
17
{ "media.name", ((this->transport && this->transport->device->name) ?
18
this->transport->device->name : this->codec->bap ? "BAP" : "A2DP") },
19
20
this->is_input = spa_streq(str, "input");
21
if ((str = spa_dict_lookup(info, "api.bluez5.a2dp-duplex")) != NULL)
22
this->is_duplex = spa_atob(str);
23
+ if ((str = spa_dict_lookup(info, "api.bluez5.internal")) != NULL)
24
+ this->is_internal = spa_atob(str);
25
}
26
27
if (this->transport == NULL) {
28
pipewire-0.3.68.tar.gz/src/gst/gstpipewireclock.c -> pipewire-0.3.69.tar.gz/src/gst/gstpipewireclock.c
Changed
15
1
2
void
3
gst_pipewire_clock_reset (GstPipeWireClock * clock, GstClockTime time)
4
{
5
+#if 0
6
GstClockTimeDiff time_offset;
7
8
if (clock->last_time >= time)
9
10
"reset clock to %" GST_TIME_FORMAT ", last %" GST_TIME_FORMAT
11
", offset %" GST_STIME_FORMAT, GST_TIME_ARGS (time),
12
GST_TIME_ARGS (clock->last_time), GST_STIME_ARGS (time_offset));
13
+#endif
14
}
15
pipewire-0.3.68.tar.gz/src/modules/module-echo-cancel.c -> pipewire-0.3.69.tar.gz/src/modules/module-echo-cancel.c
Changed
201
1
2
struct spa_hook core_proxy_listener;
3
struct spa_hook core_listener;
4
5
- struct spa_audio_info_raw info;
6
+ struct spa_audio_info_raw rec_info;
7
+ struct spa_audio_info_raw out_info;
8
+ struct spa_audio_info_raw play_info;
9
10
struct pw_properties *capture_props;
11
struct pw_stream *capture;
12
13
if (impl->wav_file == NULL) {
14
struct wav_file_info info;
15
16
- info.info.info.raw = impl->info;
17
- info.info.info.raw.channels *= 3;
18
+ spa_zero(info);
19
info.info.media_type = SPA_MEDIA_TYPE_audio;
20
info.info.media_subtype = SPA_MEDIA_SUBTYPE_raw;
21
+ info.info.info.raw.format = SPA_AUDIO_FORMAT_F32P;
22
+ info.info.info.raw.rate = impl->rec_info.rate;
23
+ info.info.info.raw.channels = impl->play_info.channels +
24
+ impl->rec_info.channels + impl->out_info.channels;
25
26
impl->wav_file = wav_file_open(impl->wav_path,
27
"w", &info);
28
29
impl->wav_path);
30
}
31
if (impl->wav_file) {
32
- uint32_t i, c = impl->info.channels;
33
- const float *datac * 3;
34
+ uint32_t i, n, c = impl->play_info.channels +
35
+ impl->rec_info.channels + impl->out_info.channels;
36
+ const float *datac;
37
+
38
+ for (i = n = 0; i < impl->play_info.channels; i++)
39
+ datan++ = playi;
40
+ for (i = 0; i < impl->rec_info.channels; i++)
41
+ datan++ = reci;
42
+ for (i = 0; i < impl->out_info.channels; i++)
43
+ datan++ = outi;
44
45
- for (i = 0; i < c; i++) {
46
- datai = playi;
47
- datai + c = reci;
48
- datai + 2*c = outi;
49
- }
50
wav_file_write(impl->wav_file, (void*)data, n_samples);
51
} else {
52
spa_zero(impl->wav_path);
53
54
{
55
struct pw_buffer *cout;
56
struct pw_buffer *pout = NULL;
57
- float rec_bufimpl->info.channelsimpl->aec_blocksize / sizeof(float);
58
- float play_bufimpl->info.channelsimpl->aec_blocksize / sizeof(float);
59
- float play_delayed_bufimpl->info.channelsimpl->aec_blocksize / sizeof(float);
60
- float out_bufimpl->info.channelsimpl->aec_blocksize / sizeof(float);
61
- const float *recimpl->info.channels;
62
- const float *playimpl->info.channels;
63
- const float *play_delayedimpl->info.channels;
64
- float *outimpl->info.channels;
65
+ float rec_bufimpl->rec_info.channelsimpl->aec_blocksize / sizeof(float);
66
+ float play_bufimpl->play_info.channelsimpl->aec_blocksize / sizeof(float);
67
+ float play_delayed_bufimpl->play_info.channelsimpl->aec_blocksize / sizeof(float);
68
+ float out_bufimpl->out_info.channelsimpl->aec_blocksize / sizeof(float);
69
+ const float *recimpl->rec_info.channels;
70
+ const float *playimpl->play_info.channels;
71
+ const float *play_delayedimpl->play_info.channels;
72
+ float *outimpl->out_info.channels;
73
struct spa_data *dd;
74
uint32_t i, size;
75
uint32_t rindex, pindex, oindex, pdindex, avail;
76
- int32_t stride = 0;
77
78
if (impl->playback != NULL && (pout = pw_stream_dequeue_buffer(impl->playback)) == NULL) {
79
pw_log_debug("out of playback buffers: %m");
80
81
size = impl->aec_blocksize;
82
83
/* First read a block from the playback and capture ring buffers */
84
-
85
spa_ringbuffer_get_read_index(&impl->rec_ring, &rindex);
86
- spa_ringbuffer_get_read_index(&impl->play_ring, &pindex);
87
- spa_ringbuffer_get_read_index(&impl->play_delayed_ring, &pdindex);
88
89
- for (i = 0; i < impl->info.channels; i++) {
90
+ for (i = 0; i < impl->rec_info.channels; i++) {
91
/* captured samples, with echo from sink */
92
reci = &rec_bufi0;
93
- /* echo from sink */
94
- playi = &play_bufi0;
95
- /* echo from sink delayed */
96
- play_delayedi = &play_delayed_bufi0;
97
- /* filtered samples, without echo from sink */
98
- outi = &out_bufi0;
99
100
- stride = 0;
101
spa_ringbuffer_read_data(&impl->rec_ring, impl->rec_bufferi,
102
impl->rec_ringsize, rindex % impl->rec_ringsize,
103
(void*)reci, size);
104
105
- stride = 0;
106
+ }
107
+ spa_ringbuffer_read_update(&impl->rec_ring, rindex + size);
108
+
109
+ for (i = 0; i < impl->out_info.channels; i++) {
110
+ /* filtered samples, without echo from sink */
111
+ outi = &out_bufi0;
112
+ }
113
+
114
+ spa_ringbuffer_get_read_index(&impl->play_ring, &pindex);
115
+ spa_ringbuffer_get_read_index(&impl->play_delayed_ring, &pdindex);
116
+
117
+ for (i = 0; i < impl->play_info.channels; i++) {
118
+ /* echo from sink */
119
+ playi = &play_bufi0;
120
+ /* echo from sink delayed */
121
+ play_delayedi = &play_delayed_bufi0;
122
+
123
spa_ringbuffer_read_data(&impl->play_ring, impl->play_bufferi,
124
impl->play_ringsize, pindex % impl->play_ringsize,
125
(void *)playi, size);
126
127
- stride = 0;
128
spa_ringbuffer_read_data(&impl->play_delayed_ring, impl->play_bufferi,
129
impl->play_ringsize, pdindex % impl->play_ringsize,
130
(void *)play_delayedi, size);
131
132
133
dd->chunk->offset = 0;
134
dd->chunk->size = size;
135
- dd->chunk->stride = stride;
136
+ dd->chunk->stride = sizeof(float);
137
}
138
}
139
-
140
- spa_ringbuffer_read_update(&impl->rec_ring, rindex + size);
141
spa_ringbuffer_read_update(&impl->play_ring, pindex + size);
142
spa_ringbuffer_read_update(&impl->play_delayed_ring, pdindex + size);
143
144
145
/* don't run the canceller until play_buffer has been filled,
146
* copy silence to output in the meantime */
147
silence_size = SPA_MIN(size, delay_left * sizeof(float));
148
- for (i = 0; i < impl->info.channels; i++)
149
+ for (i = 0; i < impl->out_info.channels; i++)
150
memset(outi, 0, silence_size);
151
impl->current_delay += silence_size / sizeof(float);
152
pw_log_debug("current_delay %d", impl->current_delay);
153
154
if (silence_size != size) {
155
- const float *pdimpl->info.channels;
156
- float *oimpl->info.channels;
157
+ const float *pdimpl->play_info.channels;
158
+ float *oimpl->out_info.channels;
159
160
- for (i = 0; i < impl->info.channels; i++) {
161
+ for (i = 0; i < impl->play_info.channels; i++)
162
pdi = play_delayedi + delay_left;
163
+ for (i = 0; i < impl->out_info.channels; i++)
164
oi = outi + delay_left;
165
- }
166
+
167
aec_run(impl, rec, pd, o, size / sizeof(float) - delay_left);
168
}
169
} else {
170
171
avail += drop;
172
}
173
174
- for (i = 0; i < impl->info.channels; i++) {
175
+ for (i = 0; i < impl->out_info.channels; i++) {
176
/* captured samples, with echo from sink */
177
spa_ringbuffer_write_data(&impl->out_ring, impl->out_bufferi,
178
impl->out_ringsize, oindex % impl->out_ringsize,
179
180
break;
181
}
182
183
- for (i = 0; i < impl->info.channels; i++) {
184
+ for (i = 0; i < impl->out_info.channels; i++) {
185
dd = &cout->buffer->datasi;
186
spa_ringbuffer_read_data(&impl->out_ring, impl->out_bufferi,
187
impl->out_ringsize, oindex % impl->out_ringsize,
188
(void *)dd->data, size);
189
dd->chunk->offset = 0;
190
dd->chunk->size = size;
191
- dd->chunk->stride = 0;
192
+ dd->chunk->stride = sizeof(float);
193
}
194
195
pw_stream_queue_buffer(impl->source, cout);
196
197
pw_log_debug("Setting AEC block size to %u", impl->aec_blocksize);
198
}
199
200
- for (i = 0; i < impl->info.channels; i++) {
201
pipewire-0.3.68.tar.gz/src/modules/module-filter-chain.c -> pipewire-0.3.69.tar.gz/src/modules/module-filter-chain.c
Changed
95
1
2
*
3
* All biquad filters have an input port "In" and an output port "Out". They have
4
* a "Freq", "Q" and "Gain" control. Their meaning depends on the particular biquad that
5
- * is used. The following labels can be used:
6
+ * is used. The biquads also have "b0", "b1", "b2", "a0", "a1" and "a2" ports that
7
+ * are read-only except for the bq_raw biquad, which can configure default values
8
+ * depending on the graph rate and change those at runtime.
9
+ *
10
+ * The following labels can be used:
11
*
12
* - `bq_lowpass` a lowpass filter.
13
* - `bq_highpass` a highpass filter.
14
15
* - `bq_peaking` a peaking filter.
16
* - `bq_notch` a notch filter.
17
* - `bq_allpass` an allpass filter.
18
+ * - `bq_raw` a raw biquad filter. You need a config section to specify coefficients
19
+ * per sample rate. The coefficients of the sample rate closest to the
20
+ * graph rate are selected:
21
+ *
22
+ *\code{.unparsed}
23
+ * filter.graph = {
24
+ * nodes =
25
+ * {
26
+ * type = builtin
27
+ * name = ...
28
+ * label = bq_raw
29
+ * config = {
30
+ * coefficients =
31
+ * { rate = 44100, b0=.., b1=.., b2=.., a0=.., a1=.., a2=.. },
32
+ * { rate = 48000, b0=.., b1=.., b2=.., a0=.., a1=.., a2=.. },
33
+ * { rate = 192000, b0=.., b1=.., b2=.., a0=.., a1=.., a2=.. }
34
+ *
35
+ * }
36
+ * ...
37
+ * }
38
+ * }
39
+ * ...
40
+ * }
41
+ *\endcode
42
*
43
* ### Convolver
44
*
45
46
node->control_changed = false;
47
}
48
49
+static void update_props_param(struct impl *impl)
50
+{
51
+ struct graph *graph = &impl->graph;
52
+ uint8_t buffer1024;
53
+ struct spa_pod_dynamic_builder b;
54
+ const struct spa_pod *params1;
55
+
56
+ spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096);
57
+ params0 = get_props_param(graph, &b.b);
58
+
59
+ pw_stream_update_params(impl->capture, params, 1);
60
+ spa_pod_dynamic_builder_clean(&b);
61
+}
62
+
63
static void param_props_changed(struct impl *impl, const struct spa_pod *param)
64
{
65
struct spa_pod_object *obj = (struct spa_pod_object *) param;
66
67
changed += parse_params(graph, &prop->value);
68
}
69
if (changed > 0) {
70
- uint8_t buffer1024;
71
- struct spa_pod_dynamic_builder b;
72
- const struct spa_pod *params1;
73
struct node *node;
74
75
spa_list_for_each(node, &graph->node_list, link)
76
node_control_changed(node);
77
78
- spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096);
79
- params0 = get_props_param(graph, &b.b);
80
-
81
- pw_stream_update_params(impl->capture, params, 1);
82
- spa_pod_dynamic_builder_clean(&b);
83
+ update_props_param(impl);
84
}
85
}
86
87
88
d->control_changed(node->hndli);
89
}
90
}
91
+ update_props_param(impl);
92
return 0;
93
error:
94
graph_cleanup(graph);
95
pipewire-0.3.68.tar.gz/src/modules/module-filter-chain/builtin_plugin.c -> pipewire-0.3.69.tar.gz/src/modules/module-filter-chain/builtin_plugin.c
Changed
201
1
2
unsigned long rate;
3
float *port64;
4
5
+ int type;
6
struct biquad bq;
7
float freq;
8
float Q;
9
float gain;
10
+ float b0, b1, b2;
11
+ float a0, a1, a2;
12
};
13
14
static void *builtin_instantiate(const struct fc_descriptor * Descriptor,
15
16
.cleanup = builtin_cleanup,
17
};
18
19
+/** biquads */
20
+static int bq_type_from_name(const char *name)
21
+{
22
+ if (spa_streq(name, "bq_lowpass"))
23
+ return BQ_LOWPASS;
24
+ if (spa_streq(name, "bq_highpass"))
25
+ return BQ_HIGHPASS;
26
+ if (spa_streq(name, "bq_bandpass"))
27
+ return BQ_BANDPASS;
28
+ if (spa_streq(name, "bq_lowshelf"))
29
+ return BQ_LOWSHELF;
30
+ if (spa_streq(name, "bq_highshelf"))
31
+ return BQ_HIGHSHELF;
32
+ if (spa_streq(name, "bq_peaking"))
33
+ return BQ_PEAKING;
34
+ if (spa_streq(name, "bq_notch"))
35
+ return BQ_NOTCH;
36
+ if (spa_streq(name, "bq_allpass"))
37
+ return BQ_ALLPASS;
38
+ if (spa_streq(name, "bq_raw"))
39
+ return BQ_NONE;
40
+ return BQ_NONE;
41
+}
42
+
43
+static void bq_raw_update(struct builtin *impl, float b0, float b1, float b2,
44
+ float a0, float a1, float a2)
45
+{
46
+ struct biquad *bq = &impl->bq;
47
+ impl->b0 = b0;
48
+ impl->b1 = b1;
49
+ impl->b2 = b2;
50
+ impl->a0 = a0;
51
+ impl->a1 = a1;
52
+ impl->a2 = a2;
53
+ if (a0 != 0.0f)
54
+ a0 = 1.0f / a0;
55
+ bq->b0 = impl->b0 * a0;
56
+ bq->b1 = impl->b1 * a0;
57
+ bq->b2 = impl->b2 * a0;
58
+ bq->a1 = impl->a1 * a0;
59
+ bq->a2 = impl->a2 * a0;
60
+ bq->x1 = bq->x2 = bq->y1 = bq->y2 = 0.0;
61
+}
62
+
63
+/*
64
+ * config = {
65
+ * coefficients =
66
+ * { rate = 44100, b0=.., b1=.., b2=.., a0=.., a1=.., a2=.. },
67
+ * { rate = 48000, b0=.., b1=.., b2=.., a0=.., a1=.., a2=.. },
68
+ * { rate = 192000, b0=.., b1=.., b2=.., a0=.., a1=.., a2=.. }
69
+ *
70
+ * }
71
+ */
72
+static void *bq_instantiate(const struct fc_descriptor * Descriptor,
73
+ unsigned long SampleRate, int index, const char *config)
74
+{
75
+ struct builtin *impl;
76
+ struct spa_json it4;
77
+ const char *val;
78
+ char key256;
79
+ uint32_t best_rate = 0;
80
+
81
+ impl = calloc(1, sizeof(*impl));
82
+ if (impl == NULL)
83
+ return NULL;
84
+
85
+ impl->rate = SampleRate;
86
+ impl->b0 = impl->a0 = 1.0f;
87
+ impl->type = bq_type_from_name(Descriptor->name);
88
+
89
+ if (config == NULL)
90
+ goto error;
91
+
92
+ spa_json_init(&it0, config, strlen(config));
93
+ if (spa_json_enter_object(&it0, &it1) <= 0)
94
+ goto error;
95
+
96
+ while (spa_json_get_string(&it1, key, sizeof(key)) > 0) {
97
+ if (spa_streq(key, "coefficients")) {
98
+ if (spa_json_enter_array(&it1, &it2) <= 0) {
99
+ pw_log_error("biquads:coefficients require an array");
100
+ goto error;
101
+ }
102
+ while (spa_json_enter_object(&it2, &it3) > 0) {
103
+ int32_t rate = 0;
104
+ float b0 = 1.0f, b1 = 0.0f, b2 = 0.0f;
105
+ float a0 = 1.0f, a1 = 0.0f, a2 = 0.0f;
106
+
107
+ while (spa_json_get_string(&it3, key, sizeof(key)) > 0) {
108
+ if (spa_streq(key, "rate")) {
109
+ if (spa_json_get_int(&it3, &rate) <= 0) {
110
+ pw_log_error("biquads:rate requires a number");
111
+ goto error;
112
+ }
113
+ }
114
+ else if (spa_streq(key, "b0")) {
115
+ if (spa_json_get_float(&it3, &b0) <= 0) {
116
+ pw_log_error("biquads:b0 requires a float");
117
+ goto error;
118
+ }
119
+ }
120
+ else if (spa_streq(key, "b1")) {
121
+ if (spa_json_get_float(&it3, &b1) <= 0) {
122
+ pw_log_error("biquads:b1 requires a float");
123
+ goto error;
124
+ }
125
+ }
126
+ else if (spa_streq(key, "b2")) {
127
+ if (spa_json_get_float(&it3, &b2) <= 0) {
128
+ pw_log_error("biquads:b2 requires a float");
129
+ goto error;
130
+ }
131
+ }
132
+ else if (spa_streq(key, "a0")) {
133
+ if (spa_json_get_float(&it3, &a0) <= 0) {
134
+ pw_log_error("biquads:a0 requires a float");
135
+ goto error;
136
+ }
137
+ }
138
+ else if (spa_streq(key, "a1")) {
139
+ if (spa_json_get_float(&it3, &a1) <= 0) {
140
+ pw_log_error("biquads:a1 requires a float");
141
+ goto error;
142
+ }
143
+ }
144
+ else if (spa_streq(key, "a2")) {
145
+ if (spa_json_get_float(&it3, &a2) <= 0) {
146
+ pw_log_error("biquads:a0 requires a float");
147
+ goto error;
148
+ }
149
+ }
150
+ else if (spa_json_next(&it1, &val) < 0)
151
+ break;
152
+ }
153
+ if (labs((long)rate - (long)SampleRate) <
154
+ labs((long)best_rate - (long)SampleRate)) {
155
+ best_rate = rate;
156
+ bq_raw_update(impl, b0, b1, b2, a0, a1, a2);
157
+ }
158
+ }
159
+ }
160
+ else if (spa_json_next(&it1, &val) < 0)
161
+ break;
162
+ }
163
+
164
+ return impl;
165
+error:
166
+ free(impl);
167
+ errno = EINVAL;
168
+ return NULL;
169
+}
170
+
171
+#define BQ_NUM_PORTS 11
172
static struct fc_port bq_ports = {
173
{ .index = 0,
174
.name = "Out",
175
176
.flags = FC_PORT_INPUT | FC_PORT_CONTROL,
177
.def = 0.0f, .min = -120.0f, .max = 20.0f,
178
},
179
+ { .index = 5,
180
+ .name = "b0",
181
+ .flags = FC_PORT_INPUT | FC_PORT_CONTROL,
182
+ .def = 1.0f, .min = -10.0f, .max = 10.0f,
183
+ },
184
+ { .index = 6,
185
+ .name = "b1",
186
+ .flags = FC_PORT_INPUT | FC_PORT_CONTROL,
187
+ .def = 0.0f, .min = -10.0f, .max = 10.0f,
188
+ },
189
+ { .index = 7,
190
+ .name = "b2",
191
+ .flags = FC_PORT_INPUT | FC_PORT_CONTROL,
192
+ .def = 0.0f, .min = -10.0f, .max = 10.0f,
193
+ },
194
+ { .index = 8,
195
+ .name = "a0",
196
+ .flags = FC_PORT_INPUT | FC_PORT_CONTROL,
197
+ .def = 1.0f, .min = -10.0f, .max = 10.0f,
198
+ },
199
+ { .index = 9,
200
+ .name = "a1",
201
pipewire-0.3.68.tar.gz/src/pipewire/context.c -> pipewire-0.3.69.tar.gz/src/pipewire/context.c
Changed
50
1
2
3
pw_impl_link_prepare(l);
4
5
- if (!l->prepared || t->visited)
6
+ if (!l->prepared || (t != n && t->visited))
7
continue;
8
9
if (!l->passive)
10
t->runnable = true;
11
- t->visited = true;
12
- spa_list_append(&queue, &t->sort_link);
13
+
14
+ if (!t->visited) {
15
+ t->visited = true;
16
+ spa_list_append(&queue, &t->sort_link);
17
+ }
18
}
19
}
20
spa_list_for_each(p, &n->output_ports, link) {
21
22
23
pw_impl_link_prepare(l);
24
25
- if (!l->prepared || t->visited)
26
+ if (!l->prepared || (t != n && t->visited))
27
continue;
28
29
if (!l->passive)
30
t->runnable = true;
31
- t->visited = true;
32
- spa_list_append(&queue, &t->sort_link);
33
+
34
+ if (!t->visited) {
35
+ t->visited = true;
36
+ spa_list_append(&queue, &t->sort_link);
37
+ }
38
}
39
}
40
/* now go through all the nodes that have the same group and
41
42
spa_list_consume(n, nodes, sort_link) {
43
spa_list_remove(&n->sort_link);
44
45
+ driver->runnable |= n->runnable;
46
+
47
pw_log_debug(" follower: %p %s runnable:%u driver-runnable:%u", n, n->name,
48
n->runnable, driver->runnable);
49
pw_impl_node_set_driver(n, driver);
50
pipewire-0.3.68.tar.gz/src/pipewire/thread-loop.c -> pipewire-0.3.69.tar.gz/src/pipewire/thread-loop.c
Changed
9
1
2
3
pw_thread_loop_stop(loop);
4
5
+ pw_loop_set_callbacks(loop->loop, NULL, NULL);
6
spa_hook_remove(&loop->hook);
7
8
spa_hook_list_clean(&loop->listener_list);
9