summaryrefslogtreecommitdiffstats
path: root/meta/recipes-multimedia/pulseaudio/pulseaudio/0003-card-move-profile-selection-after-pa_card_new.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta/recipes-multimedia/pulseaudio/pulseaudio/0003-card-move-profile-selection-after-pa_card_new.patch')
-rw-r--r--meta/recipes-multimedia/pulseaudio/pulseaudio/0003-card-move-profile-selection-after-pa_card_new.patch373
1 files changed, 218 insertions, 155 deletions
diff --git a/meta/recipes-multimedia/pulseaudio/pulseaudio/0003-card-move-profile-selection-after-pa_card_new.patch b/meta/recipes-multimedia/pulseaudio/pulseaudio/0003-card-move-profile-selection-after-pa_card_new.patch
index 0e7780154d..e0f424bbcc 100644
--- a/meta/recipes-multimedia/pulseaudio/pulseaudio/0003-card-move-profile-selection-after-pa_card_new.patch
+++ b/meta/recipes-multimedia/pulseaudio/pulseaudio/0003-card-move-profile-selection-after-pa_card_new.patch
@@ -1,61 +1,62 @@
1From 13e85dd1763e99d21a60323671b9a5df08bdae75 Mon Sep 17 00:00:00 2001 1From 0b98309fdbcd36fa92ab53e33c51b485b905e294 Mon Sep 17 00:00:00 2001
2From: Tanu Kaskinen <tanuk@iki.fi> 2From: Tanu Kaskinen <tanuk@iki.fi>
3Date: Fri, 23 Oct 2015 12:59:53 +0300 3Date: Fri, 23 Oct 2015 12:59:53 +0300
4Subject: [PATCH 3/4] card: move profile selection after pa_card_new() 4Subject: [PATCH 3/5] card: move profile selection after pa_card_new()
5 5
6I want module-alsa-card to set the availability of unavailable 6I want module-alsa-card to set the availability of unavailable
7profiles before the initial card profile gets selected, so that the 7profiles before the initial card profile gets selected, so that the
8selection logic can use correct availability information. 8selection logic can use correct availability information.
9module-alsa-card initializes the jack state after calling 9module-alsa-card initializes the jack state after calling
10pa_card_new(), however, and the profile selection happens in 10pa_card_new(), however, and the profile selection happens in
11pa_card_new(). This patch solves that by introducing pa_card_put() and 11pa_card_new(). This patch solves that by moving parts of pa_card_new()
12moving the profile selection code there. 12to pa_card_choose_initial_profile() and pa_card_put().
13
14pa_card_choose_initial_profile() applies the profile selection policy,
15so module-alsa-card can first call pa_card_new(), then initialize the
16jack state, and then call pa_card_choose_initial_profile(). After that
17module-alsa-card can still override the profile selection policy, in
18case module-alsa-card was loaded with the "profile" argument. Finally,
19pa_card_put() finalizes the card creation.
13 20
14An alternative solution would have been to move the jack 21An alternative solution would have been to move the jack
15initialization to happen before pa_card_new() and use pa_card_new_data 22initialization to happen before pa_card_new() and use pa_card_new_data
16instead of pa_card in the jack initialization code, but I disliked 23instead of pa_card in the jack initialization code, but I disliked
17that idea (I want to get rid of the "new data" pattern eventually). 24that idea (I want to get rid of the "new data" pattern eventually).
18 25
19The CARD_NEW hook is used when applying the initial profile policy, so
20that was moved to pa_card_put(). That required changing the hook data
21from pa_card_new_data to pa_card. module-card-restore now uses
22pa_card_set_profile() instead of pa_card_new_data_set_profile(). That
23required adding a state variable to pa_card, because
24pa_card_set_profile() needs to distinguish between setting the initial
25profile and setting the profile in other situations.
26
27The order in which the initial profile policy is applied is reversed 26The order in which the initial profile policy is applied is reversed
28in this patch. Previously the first one to set it won, now the last 27in this patch. Previously the first one to set it won, now the last
29one to set it wins. I think this is better, because if you have N 28one to set it wins. I think this is better, because if you have N
30parties that want to set the profile, we avoid checking N times 29parties that want to set the profile, we avoid checking N times
31whether someone else has already set the profile. 30whether someone else has already set the profile.
32 31
33http://bugzilla.yoctoproject.org/show_bug.cgi?id=8448 32Upstream-Status: Accepted [expected in 10.0]
34
35Signed-off-by: Jussi Kukkonen <jussi.kukkonen@intel.com>
36
37Rebased on 8.0.
38
39Upstream-Status: Denied [The patch set needs some work to be accepted.
40The review thread:
41http://thread.gmane.org/gmane.comp.audio.pulseaudio.general/24301]
42 33
43Signed-off-by: Tanu Kaskinen <tanuk@iki.fi> 34Signed-off-by: Tanu Kaskinen <tanuk@iki.fi>
44--- 35---
45 src/modules/alsa/module-alsa-card.c | 19 +++---- 36 src/modules/alsa/module-alsa-card.c | 32 +++++----
46 src/modules/bluetooth/module-bluez4-device.c | 18 +++---- 37 src/modules/bluetooth/module-bluez4-device.c | 31 +++++----
47 src/modules/bluetooth/module-bluez5-device.c | 1 + 38 src/modules/bluetooth/module-bluez5-device.c | 2 +
48 src/modules/macosx/module-coreaudio-device.c | 1 + 39 src/modules/macosx/module-coreaudio-device.c | 2 +
49 src/modules/module-card-restore.c | 24 +++++---- 40 src/modules/module-card-restore.c | 36 +++++++---
50 src/pulsecore/card.c | 81 +++++++++++++++------------- 41 src/pulsecore/card.c | 99 +++++++++++++++++-----------
51 src/pulsecore/card.h | 7 +++ 42 src/pulsecore/card.h | 9 +++
52 7 files changed, 86 insertions(+), 65 deletions(-) 43 src/pulsecore/core.h | 1 +
44 8 files changed, 143 insertions(+), 69 deletions(-)
53 45
54diff --git a/src/modules/alsa/module-alsa-card.c b/src/modules/alsa/module-alsa-card.c 46diff --git a/src/modules/alsa/module-alsa-card.c b/src/modules/alsa/module-alsa-card.c
55index 9e8cde2..fe240f0 100644 47index d761683..1976230 100644
56--- a/src/modules/alsa/module-alsa-card.c 48--- a/src/modules/alsa/module-alsa-card.c
57+++ b/src/modules/alsa/module-alsa-card.c 49+++ b/src/modules/alsa/module-alsa-card.c
58@@ -770,15 +770,6 @@ int pa__init(pa_module *m) { 50@@ -671,7 +671,7 @@ int pa__init(pa_module *m) {
51 struct userdata *u;
52 pa_reserve_wrapper *reserve = NULL;
53 const char *description;
54- const char *profile = NULL;
55+ const char *profile_str = NULL;
56 char *fn = NULL;
57 bool namereg_fail = false;
58
59@@ -799,16 +799,6 @@ int pa__init(pa_module *m) {
59 goto fail; 60 goto fail;
60 } 61 }
61 62
@@ -64,6 +65,7 @@ index 9e8cde2..fe240f0 100644
64- pa_card_new_data_set_profile(&data, profile); 65- pa_card_new_data_set_profile(&data, profile);
65- else { 66- else {
66- pa_log("No such profile: %s", profile); 67- pa_log("No such profile: %s", profile);
68- pa_card_new_data_done(&data);
67- goto fail; 69- goto fail;
68- } 70- }
69- } 71- }
@@ -71,28 +73,47 @@ index 9e8cde2..fe240f0 100644
71 u->card = pa_card_new(m->core, &data); 73 u->card = pa_card_new(m->core, &data);
72 pa_card_new_data_done(&data); 74 pa_card_new_data_done(&data);
73 75
74@@ -789,6 +780,16 @@ int pa__init(pa_module *m) { 76@@ -822,6 +812,26 @@ int pa__init(pa_module *m) {
75 u->card->set_profile = card_set_profile; 77 (pa_hook_cb_t) card_suspend_changed, u);
76 78
77 init_jacks(u); 79 init_jacks(u);
78+ pa_card_put(u->card);
79+ 80+
80+ if ((profile = pa_modargs_get_value(u->modargs, "profile", NULL))) { 81+ pa_card_choose_initial_profile(u->card);
81+ u->card->active_profile = pa_hashmap_get(u->card->profiles, profile); 82+
82+ if (!u->card->active_profile) { 83+ /* If the "profile" modarg is given, we have to override whatever the usual
83+ pa_log("No such profile: %s", profile); 84+ * policy chose in pa_card_choose_initial_profile(). */
85+ profile_str = pa_modargs_get_value(u->modargs, "profile", NULL);
86+ if (profile_str) {
87+ pa_card_profile *profile;
88+
89+ profile = pa_hashmap_get(u->card->profiles, profile_str);
90+ if (!profile) {
91+ pa_log("No such profile: %s", profile_str);
84+ goto fail; 92+ goto fail;
85+ } 93+ }
94+
95+ pa_card_set_profile(u->card, profile, false);
86+ } 96+ }
87+ 97+
98+ pa_card_put(u->card);
99+
88 init_profile(u); 100 init_profile(u);
89 init_eld_ctls(u); 101 init_eld_ctls(u);
90 102
91diff --git a/src/modules/bluetooth/module-bluez4-device.c b/src/modules/bluetooth/module-bluez4-device.c 103diff --git a/src/modules/bluetooth/module-bluez4-device.c b/src/modules/bluetooth/module-bluez4-device.c
92index dd18217..5d0d3db 100644 104index a2de525..13fb7ab 100644
93--- a/src/modules/bluetooth/module-bluez4-device.c 105--- a/src/modules/bluetooth/module-bluez4-device.c
94+++ b/src/modules/bluetooth/module-bluez4-device.c 106+++ b/src/modules/bluetooth/module-bluez4-device.c
95@@ -2304,15 +2304,6 @@ static int add_card(struct userdata *u) { 107@@ -2238,7 +2238,7 @@ static int add_card(struct userdata *u) {
108 pa_bluez4_profile_t *d;
109 pa_bluez4_form_factor_t ff;
110 char *n;
111- const char *default_profile;
112+ const char *profile_str;
113 const pa_bluez4_device *device;
114 const pa_bluez4_uuid *uuid;
115
116@@ -2298,16 +2298,6 @@ static int add_card(struct userdata *u) {
96 *d = PA_BLUEZ4_PROFILE_OFF; 117 *d = PA_BLUEZ4_PROFILE_OFF;
97 pa_hashmap_put(data.profiles, p->name, p); 118 pa_hashmap_put(data.profiles, p->name, p);
98 119
@@ -101,6 +122,7 @@ index dd18217..5d0d3db 100644
101- pa_card_new_data_set_profile(&data, default_profile); 122- pa_card_new_data_set_profile(&data, default_profile);
102- else { 123- else {
103- pa_log("Profile '%s' not valid or not supported by device.", default_profile); 124- pa_log("Profile '%s' not valid or not supported by device.", default_profile);
125- pa_card_new_data_done(&data);
104- return -1; 126- return -1;
105- } 127- }
106- } 128- }
@@ -108,127 +130,126 @@ index dd18217..5d0d3db 100644
108 u->card = pa_card_new(u->core, &data); 130 u->card = pa_card_new(u->core, &data);
109 pa_card_new_data_done(&data); 131 pa_card_new_data_done(&data);
110 132
111@@ -2323,6 +2314,15 @@ static int add_card(struct userdata *u) { 133@@ -2319,6 +2309,25 @@ static int add_card(struct userdata *u) {
112
113 u->card->userdata = u; 134 u->card->userdata = u;
114 u->card->set_profile = card_set_profile; 135 u->card->set_profile = card_set_profile;
115+ pa_card_put(u->card); 136
137+ pa_card_choose_initial_profile(u->card);
138+
139+ /* If the "profile" modarg is given, we have to override whatever the usual
140+ * policy chose in pa_card_choose_initial_profile(). */
141+ profile_str = pa_modargs_get_value(u->modargs, "profile", NULL);
142+ if (profile_str) {
143+ pa_card_profile *profile;
116+ 144+
117+ if ((default_profile = pa_modargs_get_value(u->modargs, "profile", NULL))) { 145+ profile = pa_hashmap_get(u->card->profiles, profile_str);
118+ u->card->active_profile = pa_hashmap_get(u->card->profiles, default_profile); 146+ if (!profile) {
119+ if (!u->card->active_profile) { 147+ pa_log("No such profile: %s", profile_str);
120+ pa_log("Profile '%s' not valid or not supported by device.", default_profile);
121+ return -1; 148+ return -1;
122+ } 149+ }
150+
151+ pa_card_set_profile(u->card, profile, false);
123+ } 152+ }
124 153+
154+ pa_card_put(u->card);
155+
125 d = PA_CARD_PROFILE_DATA(u->card->active_profile); 156 d = PA_CARD_PROFILE_DATA(u->card->active_profile);
126 157
158 if (*d != PA_BLUEZ4_PROFILE_OFF && (!device->transports[*d] ||
127diff --git a/src/modules/bluetooth/module-bluez5-device.c b/src/modules/bluetooth/module-bluez5-device.c 159diff --git a/src/modules/bluetooth/module-bluez5-device.c b/src/modules/bluetooth/module-bluez5-device.c
128index b015c67..7b90a31 100644 160index 84e6d55..498d0e1 100644
129--- a/src/modules/bluetooth/module-bluez5-device.c 161--- a/src/modules/bluetooth/module-bluez5-device.c
130+++ b/src/modules/bluetooth/module-bluez5-device.c 162+++ b/src/modules/bluetooth/module-bluez5-device.c
131@@ -1959,6 +1959,7 @@ static int add_card(struct userdata *u) { 163@@ -1953,6 +1953,8 @@ static int add_card(struct userdata *u) {
132 164
133 u->card->userdata = u; 165 u->card->userdata = u;
134 u->card->set_profile = set_profile_cb; 166 u->card->set_profile = set_profile_cb;
167+ pa_card_choose_initial_profile(u->card);
135+ pa_card_put(u->card); 168+ pa_card_put(u->card);
136 169
137 p = PA_CARD_PROFILE_DATA(u->card->active_profile); 170 p = PA_CARD_PROFILE_DATA(u->card->active_profile);
138 u->profile = *p; 171 u->profile = *p;
139diff --git a/src/modules/macosx/module-coreaudio-device.c b/src/modules/macosx/module-coreaudio-device.c 172diff --git a/src/modules/macosx/module-coreaudio-device.c b/src/modules/macosx/module-coreaudio-device.c
140index 0c92d42..7190ee9 100644 173index 6c9e55d..d91c656 100644
141--- a/src/modules/macosx/module-coreaudio-device.c 174--- a/src/modules/macosx/module-coreaudio-device.c
142+++ b/src/modules/macosx/module-coreaudio-device.c 175+++ b/src/modules/macosx/module-coreaudio-device.c
143@@ -807,6 +807,7 @@ int pa__init(pa_module *m) { 176@@ -821,6 +821,8 @@ int pa__init(pa_module *m) {
144 pa_card_new_data_done(&card_new_data); 177 pa_card_new_data_done(&card_new_data);
145 u->card->userdata = u; 178 u->card->userdata = u;
146 u->card->set_profile = card_set_profile; 179 u->card->set_profile = card_set_profile;
180+ pa_card_choose_initial_profile(u->card);
147+ pa_card_put(u->card); 181+ pa_card_put(u->card);
148 182
149 u->rtpoll = pa_rtpoll_new(); 183 u->rtpoll = pa_rtpoll_new();
150 pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll); 184 pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll);
151diff --git a/src/modules/module-card-restore.c b/src/modules/module-card-restore.c 185diff --git a/src/modules/module-card-restore.c b/src/modules/module-card-restore.c
152index f906843..dce6674 100644 186index 7545aa5..718a0dd 100644
153--- a/src/modules/module-card-restore.c 187--- a/src/modules/module-card-restore.c
154+++ b/src/modules/module-card-restore.c 188+++ b/src/modules/module-card-restore.c
155@@ -515,34 +515,38 @@ static pa_hook_result_t port_offset_change_callback(pa_core *c, pa_device_port * 189@@ -551,16 +551,6 @@ static pa_hook_result_t card_new_hook_callback(pa_core *c, pa_card_new_data *new
156 return PA_HOOK_OK; 190 if (!(e = entry_read(u, new_data->name)))
157 }
158
159-static pa_hook_result_t card_new_hook_callback(pa_core *c, pa_card_new_data *new_data, struct userdata *u) {
160+static pa_hook_result_t card_new_hook_callback(pa_core *c, pa_card *card, struct userdata *u) {
161 struct entry *e;
162 void *state;
163 pa_device_port *p;
164 struct port_info *p_info;
165
166- pa_assert(new_data);
167+ pa_assert(c);
168+ pa_assert(card);
169+ pa_assert(u);
170
171- if (!(e = entry_read(u, new_data->name)))
172+ if (!(e = entry_read(u, card->name)))
173 return PA_HOOK_OK; 191 return PA_HOOK_OK;
174 192
175 if (e->profile[0]) { 193- if (e->profile[0]) {
176- if (!new_data->active_profile) { 194- if (!new_data->active_profile) {
177- pa_card_new_data_set_profile(new_data, e->profile); 195- pa_card_new_data_set_profile(new_data, e->profile);
178- pa_log_info("Restored profile '%s' for card %s.", new_data->active_profile, new_data->name); 196- pa_log_info("Restored profile '%s' for card %s.", new_data->active_profile, new_data->name);
179- new_data->save_profile = true; 197- new_data->save_profile = true;
180+ pa_card_profile *profile; 198-
199- } else
200- pa_log_debug("Not restoring profile for card %s, because already set.", new_data->name);
201- }
202-
203 /* Always restore the latency offsets because their
204 * initial value is always 0 */
205
206@@ -590,6 +580,30 @@ static pa_hook_result_t card_new_hook_callback(pa_core *c, pa_card_new_data *new
207 return PA_HOOK_OK;
208 }
181 209
210+static pa_hook_result_t card_choose_initial_profile_callback(pa_core *core, pa_card *card, struct userdata *u) {
211+ struct entry *e;
212+
213+ if (!(e = entry_read(u, card->name)))
214+ return PA_HOOK_OK;
215+
216+ if (e->profile[0]) {
217+ pa_card_profile *profile;
218+
182+ profile = pa_hashmap_get(card->profiles, e->profile); 219+ profile = pa_hashmap_get(card->profiles, e->profile);
183+ if (profile) { 220+ if (profile) {
221+ pa_log_info("Restoring profile '%s' for card %s.", card->active_profile->name, card->name);
184+ pa_card_set_profile(card, profile, true); 222+ pa_card_set_profile(card, profile, true);
185+ pa_log_info("Restored profile '%s' for card %s.", card->active_profile->name, card->name); 223+ } else {
186 } else
187- pa_log_debug("Not restoring profile for card %s, because already set.", new_data->name);
188+ pa_log_debug("Tried to restore profile %s for card %s, but the card doesn't have such profile.", 224+ pa_log_debug("Tried to restore profile %s for card %s, but the card doesn't have such profile.",
189+ e->profile, card->name); 225+ e->profile, card->name);
190 } 226+ }
191 227+ }
192 /* Always restore the latency offsets because their 228+
193 * initial value is always 0 */ 229+ entry_free(e);
194 230+
195- pa_log_info("Restoring port latency offsets for card %s.", new_data->name); 231+ return PA_HOOK_OK;
196+ pa_log_info("Restoring port latency offsets for card %s.", card->name); 232+}
197 233+
198 PA_HASHMAP_FOREACH(p_info, e->ports, state) 234 static pa_hook_result_t card_preferred_port_changed_callback(pa_core *core, pa_card_preferred_port_changed_hook_data *data,
199- if ((p = pa_hashmap_get(new_data->ports, p_info->name))) { 235 struct userdata *u) {
200+ if ((p = pa_hashmap_get(card->ports, p_info->name))) { 236 struct entry *e;
201 p->latency_offset = p_info->offset; 237@@ -634,6 +648,8 @@ int pa__init(pa_module*m) {
202 if (!p->preferred_profile && p_info->profile) 238 u->module = m;
203 pa_device_port_set_preferred_profile(p, p_info->profile); 239
240 pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_CARD_NEW], PA_HOOK_EARLY, (pa_hook_cb_t) card_new_hook_callback, u);
241+ pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_CARD_CHOOSE_INITIAL_PROFILE], PA_HOOK_NORMAL,
242+ (pa_hook_cb_t) card_choose_initial_profile_callback, u);
243 pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_CARD_PUT], PA_HOOK_NORMAL, (pa_hook_cb_t) card_put_hook_callback, u);
244 pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_CARD_PREFERRED_PORT_CHANGED], PA_HOOK_NORMAL, (pa_hook_cb_t) card_preferred_port_changed_callback, u);
245 pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_CARD_PROFILE_CHANGED], PA_HOOK_NORMAL, (pa_hook_cb_t) card_profile_changed_callback, u);
204diff --git a/src/pulsecore/card.c b/src/pulsecore/card.c 246diff --git a/src/pulsecore/card.c b/src/pulsecore/card.c
205index f92ac87..1a6e705 100644 247index 0ac70b9..a0c3d93 100644
206--- a/src/pulsecore/card.c 248--- a/src/pulsecore/card.c
207+++ b/src/pulsecore/card.c 249+++ b/src/pulsecore/card.c
208@@ -148,6 +148,7 @@ pa_card *pa_card_new(pa_core *core, pa_card_new_data *data) { 250@@ -176,38 +176,56 @@ pa_card *pa_card_new(pa_core *core, pa_card_new_data *data) {
209 pa_assert(!pa_hashmap_isempty(data->profiles)); 251 c->preferred_input_port = data->preferred_input_port;
210 252 c->preferred_output_port = data->preferred_output_port;
211 c = pa_xnew0(pa_card, 1);
212+ c->state = PA_CARD_STATE_INIT;
213
214 if (!(name = pa_namereg_register(core, data->name, PA_NAMEREG_CARD, c, data->namereg_fail))) {
215 pa_xfree(c);
216@@ -156,12 +157,6 @@ pa_card *pa_card_new(pa_core *core, pa_card_new_data *data) {
217
218 pa_card_new_data_set_name(data, name);
219
220- if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_CARD_NEW], data) < 0) {
221- pa_xfree(c);
222- pa_namereg_unregister(core, name);
223- return NULL;
224- }
225-
226 c->core = core;
227 c->name = pa_xstrdup(data->name);
228 c->proplist = pa_proplist_copy(data->proplist);
229@@ -184,38 +179,43 @@ pa_card *pa_card_new(pa_core *core, pa_card_new_data *data) {
230 PA_HASHMAP_FOREACH(port, c->ports, state)
231 port->card = c;
232 253
233- if (data->active_profile) 254- if (data->active_profile)
234- if ((c->active_profile = pa_hashmap_get(c->profiles, data->active_profile))) 255- if ((c->active_profile = pa_hashmap_get(c->profiles, data->active_profile)))
@@ -252,50 +273,85 @@ index f92ac87..1a6e705 100644
252- PA_HASHMAP_FOREACH(profile, c->profiles, state) 273- PA_HASHMAP_FOREACH(profile, c->profiles, state)
253- if (!c->active_profile || profile->priority > c->active_profile->priority) 274- if (!c->active_profile || profile->priority > c->active_profile->priority)
254- c->active_profile = profile; 275- c->active_profile = profile;
255- } 276+void pa_card_choose_initial_profile(pa_card *card) {
256- pa_assert(c->active_profile);
257+void pa_card_put(pa_card *card) {
258+ pa_card_profile *profile; 277+ pa_card_profile *profile;
259+ void *state; 278+ void *state;
279+ pa_card_profile *best = NULL;
260+ 280+
261+ pa_assert(card); 281+ pa_assert(card);
262+ 282+
283+ /* By default, pick the highest priority profile that is not unavailable,
284+ * or if all profiles are unavailable, pick the profile with the highest
285+ * priority regardless of its availability. */
286+
263+ PA_HASHMAP_FOREACH(profile, card->profiles, state) { 287+ PA_HASHMAP_FOREACH(profile, card->profiles, state) {
264+ if (profile->available == PA_AVAILABLE_NO) 288+ if (profile->available == PA_AVAILABLE_NO)
265+ continue; 289+ continue;
266+ 290+
267+ if (!card->active_profile || profile->priority > card->active_profile->priority) 291+ if (!best || profile->priority > best->priority)
268+ card->active_profile = profile; 292+ best = profile;
293+ }
294+
295+ if (!best) {
296+ PA_HASHMAP_FOREACH(profile, card->profiles, state) {
297+ if (!best || profile->priority > best->priority)
298+ best = profile;
299 }
300- pa_assert(c->active_profile);
269 } 301 }
302+ pa_assert(best);
270 303
271- pa_device_init_description(c->proplist, c); 304- pa_device_init_description(c->proplist, c);
272- pa_device_init_icon(c->proplist, true); 305- pa_device_init_icon(c->proplist, true);
273- pa_device_init_intended_roles(c->proplist); 306- pa_device_init_intended_roles(c->proplist);
274+ /* If all profiles are unavailable, then we still need to pick one */ 307+ card->active_profile = best;
275+ if (!card->active_profile) { 308+ card->save_profile = false;
276+ PA_HASHMAP_FOREACH(profile, card->profiles, state)
277+ if (!card->active_profile || profile->priority > card->active_profile->priority)
278+ card->active_profile = profile;
279+ }
280+ pa_assert(card->active_profile);
281 309
282- pa_assert_se(pa_idxset_put(core->cards, c, &c->index) >= 0); 310- pa_assert_se(pa_idxset_put(core->cards, c, &c->index) >= 0);
283+ pa_hook_fire(&card->core->hooks[PA_CORE_HOOK_CARD_NEW], card); 311+ /* Let policy modules override the default. */
312+ pa_hook_fire(&card->core->hooks[PA_CORE_HOOK_CARD_CHOOSE_INITIAL_PROFILE], card);
313+}
284 314
285- pa_log_info("Created %u \"%s\"", c->index, c->name); 315- pa_log_info("Created %u \"%s\"", c->index, c->name);
286- pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_CARD|PA_SUBSCRIPTION_EVENT_NEW, c->index); 316- pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_CARD|PA_SUBSCRIPTION_EVENT_NEW, c->index);
287+ pa_assert_se(pa_idxset_put(card->core->cards, card, &card->index) >= 0); 317+void pa_card_put(pa_card *card) {
288+ card->state = PA_CARD_STATE_LINKED; 318+ pa_assert(card);
289 319
290- pa_hook_fire(&core->hooks[PA_CORE_HOOK_CARD_PUT], c); 320- pa_hook_fire(&core->hooks[PA_CORE_HOOK_CARD_PUT], c);
291- return c; 321- return c;
322+ pa_assert_se(pa_idxset_put(card->core->cards, card, &card->index) >= 0);
323+ card->linked = true;
324+
292+ pa_log_info("Created %u \"%s\"", card->index, card->name); 325+ pa_log_info("Created %u \"%s\"", card->index, card->name);
293+ pa_hook_fire(&card->core->hooks[PA_CORE_HOOK_CARD_PUT], card); 326+ pa_hook_fire(&card->core->hooks[PA_CORE_HOOK_CARD_PUT], card);
294+ pa_subscription_post(card->core, PA_SUBSCRIPTION_EVENT_CARD|PA_SUBSCRIPTION_EVENT_NEW, card->index); 327+ pa_subscription_post(card->core, PA_SUBSCRIPTION_EVENT_CARD|PA_SUBSCRIPTION_EVENT_NEW, card->index);
295 } 328 }
296 329
297 void pa_card_free(pa_card *c) { 330 void pa_card_free(pa_card *c) {
298@@ -306,20 +306,27 @@ int pa_card_set_profile(pa_card *c, pa_card_profile *profile, bool save) { 331@@ -218,15 +236,15 @@ void pa_card_free(pa_card *c) {
332
333 core = c->core;
334
335- pa_hook_fire(&core->hooks[PA_CORE_HOOK_CARD_UNLINK], c);
336-
337- pa_namereg_unregister(core, c->name);
338-
339- pa_idxset_remove_by_data(c->core->cards, c, NULL);
340+ if (c->linked) {
341+ pa_hook_fire(&core->hooks[PA_CORE_HOOK_CARD_UNLINK], c);
342
343- pa_log_info("Freed %u \"%s\"", c->index, c->name);
344+ pa_idxset_remove_by_data(c->core->cards, c, NULL);
345+ pa_log_info("Freed %u \"%s\"", c->index, c->name);
346+ pa_subscription_post(c->core, PA_SUBSCRIPTION_EVENT_CARD|PA_SUBSCRIPTION_EVENT_REMOVE, c->index);
347+ }
348
349- pa_subscription_post(c->core, PA_SUBSCRIPTION_EVENT_CARD|PA_SUBSCRIPTION_EVENT_REMOVE, c->index);
350+ pa_namereg_unregister(core, c->name);
351
352 pa_assert(pa_idxset_isempty(c->sinks));
353 pa_idxset_free(c->sinks, NULL);
354@@ -298,20 +316,27 @@ int pa_card_set_profile(pa_card *c, pa_card_profile *profile, bool save) {
299 return 0; 355 return 0;
300 } 356 }
301 357
@@ -307,7 +363,7 @@ index f92ac87..1a6e705 100644
307+ * be probably good to change this so that also the initial profile can be 363+ * be probably good to change this so that also the initial profile can be
308+ * set up in set_profile(), but if set_profile() fails, that would need 364+ * set up in set_profile(), but if set_profile() fails, that would need
309+ * some better handling than what we do here currently. */ 365+ * some better handling than what we do here currently. */
310+ if (c->state != PA_CARD_STATE_INIT && (r = c->set_profile(c, profile)) < 0) 366+ if (c->linked && (r = c->set_profile(c, profile)) < 0)
311 return r; 367 return r;
312 368
313- pa_subscription_post(c->core, PA_SUBSCRIPTION_EVENT_CARD|PA_SUBSCRIPTION_EVENT_CHANGE, c->index); 369- pa_subscription_post(c->core, PA_SUBSCRIPTION_EVENT_CARD|PA_SUBSCRIPTION_EVENT_CHANGE, c->index);
@@ -321,7 +377,7 @@ index f92ac87..1a6e705 100644
321 update_port_preferred_profile(c); 377 update_port_preferred_profile(c);
322 378
323- pa_hook_fire(&c->core->hooks[PA_CORE_HOOK_CARD_PROFILE_CHANGED], c); 379- pa_hook_fire(&c->core->hooks[PA_CORE_HOOK_CARD_PROFILE_CHANGED], c);
324+ if (c->state != PA_CARD_STATE_INIT) { 380+ if (c->linked) {
325+ pa_log_info("Changed profile of card %u \"%s\" to %s", c->index, c->name, profile->name); 381+ pa_log_info("Changed profile of card %u \"%s\" to %s", c->index, c->name, profile->name);
326+ pa_hook_fire(&c->core->hooks[PA_CORE_HOOK_CARD_PROFILE_CHANGED], c); 382+ pa_hook_fire(&c->core->hooks[PA_CORE_HOOK_CARD_PROFILE_CHANGED], c);
327+ pa_subscription_post(c->core, PA_SUBSCRIPTION_EVENT_CARD|PA_SUBSCRIPTION_EVENT_CHANGE, c->index); 383+ pa_subscription_post(c->core, PA_SUBSCRIPTION_EVENT_CARD|PA_SUBSCRIPTION_EVENT_CHANGE, c->index);
@@ -330,37 +386,44 @@ index f92ac87..1a6e705 100644
330 return 0; 386 return 0;
331 } 387 }
332diff --git a/src/pulsecore/card.h b/src/pulsecore/card.h 388diff --git a/src/pulsecore/card.h b/src/pulsecore/card.h
333index fff9057..a944301 100644 389index d4970e3..fd1fe0a 100644
334--- a/src/pulsecore/card.h 390--- a/src/pulsecore/card.h
335+++ b/src/pulsecore/card.h 391+++ b/src/pulsecore/card.h
336@@ -34,6 +34,11 @@ typedef enum pa_available { 392@@ -86,6 +86,8 @@ struct pa_card {
337 PA_AVAILABLE_YES = 2, 393
338 } pa_available_t; 394 pa_suspend_cause_t suspend_cause;
339 395
340+typedef enum pa_card_state { 396+ bool linked;
341+ PA_CARD_STATE_INIT,
342+ PA_CARD_STATE_LINKED,
343+} pa_card_state_t;
344+ 397+
345 struct pa_card_profile { 398 void *userdata;
346 pa_card *card; 399
347 char *name; 400 int (*set_profile)(pa_card *c, pa_card_profile *profile);
348@@ -66,6 +71,7 @@ struct pa_card_profile { 401@@ -128,6 +130,13 @@ void pa_card_new_data_set_preferred_port(pa_card_new_data *data, pa_direction_t
349
350 struct pa_card {
351 uint32_t index;
352+ pa_card_state_t state;
353 pa_core *core;
354
355 char *name;
356@@ -120,6 +126,7 @@ void pa_card_new_data_set_profile(pa_card_new_data *data, const char *profile);
357 void pa_card_new_data_done(pa_card_new_data *data); 402 void pa_card_new_data_done(pa_card_new_data *data);
358 403
359 pa_card *pa_card_new(pa_core *c, pa_card_new_data *data); 404 pa_card *pa_card_new(pa_core *c, pa_card_new_data *data);
405+
406+/* Select the initial card profile according to the configured policies. This
407+ * must be called between pa_card_new() and pa_card_put(), after the port and
408+ * profile availablities have been initialized. */
409+void pa_card_choose_initial_profile(pa_card *card);
410+
360+void pa_card_put(pa_card *c); 411+void pa_card_put(pa_card *c);
361 void pa_card_free(pa_card *c); 412 void pa_card_free(pa_card *c);
362 413
363 void pa_card_add_profile(pa_card *c, pa_card_profile *profile); 414 void pa_card_add_profile(pa_card *c, pa_card_profile *profile);
415diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h
416index 00d7f2f..802111b 100644
417--- a/src/pulsecore/core.h
418+++ b/src/pulsecore/core.h
419@@ -118,6 +118,7 @@ typedef enum pa_core_hook {
420 PA_CORE_HOOK_CLIENT_PROPLIST_CHANGED,
421 PA_CORE_HOOK_CLIENT_SEND_EVENT,
422 PA_CORE_HOOK_CARD_NEW,
423+ PA_CORE_HOOK_CARD_CHOOSE_INITIAL_PROFILE,
424 PA_CORE_HOOK_CARD_PUT,
425 PA_CORE_HOOK_CARD_UNLINK,
426 PA_CORE_HOOK_CARD_PREFERRED_PORT_CHANGED,
364-- 427--
3652.7.0 4282.8.1
366 429