calssification: more heuristics to guess bluetooth device classes
[profile/ivi/pulseaudio-module-murphy-ivi.git] / murphy / switch.c
1 /*
2  * module-murphy-ivi -- PulseAudio module for providing audio routing support
3  * Copyright (c) 2012, Intel Corporation.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms and conditions of the GNU Lesser General Public License,
7  * version 2.1, as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.
12  * See the GNU Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with this program; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St - Fifth Floor, Boston,
17  * MA 02110-1301 USA.
18  *
19  */
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <errno.h>
24
25 #include <pulsecore/pulsecore-config.h>
26 #include <pulsecore/core-util.h>
27 #include <pulsecore/namereg.h>
28
29 #include <pulsecore/card.h>
30 #include <pulsecore/sink.h>
31 #include <pulsecore/device-port.h>
32 #include <pulsecore/source.h>
33 #include <pulsecore/sink-input.h>
34 #include <pulsecore/source-output.h>
35
36 #include "switch.h"
37 #include "node.h"
38 #include "multiplex.h"
39 #include "loopback.h"
40 #include "discover.h"
41 #include "utils.h"
42 #include "classify.h"
43
44 static pa_bool_t setup_explicit_link_from_stream_to_device(struct userdata *,
45                                                            mir_node *,
46                                                            mir_node *);
47 static pa_bool_t teardown_explicit_link_from_stream_to_device(struct userdata*,
48                                                               mir_node *,
49                                                               mir_node *);
50
51 static pa_bool_t setup_default_link_from_stream_to_device(struct userdata *,
52                                                           mir_node *,
53                                                           mir_node *);
54 static pa_bool_t setup_default_link_from_device_to_device(struct userdata *,
55                                                           mir_node *,
56                                                           mir_node *);
57
58 static pa_sink *setup_device_output(struct userdata *, mir_node *);
59
60 static pa_bool_t set_profile(struct userdata *, mir_node *);
61 static pa_bool_t set_port(struct userdata *, mir_node *);
62
63
64 pa_bool_t mir_switch_setup_link(struct userdata *u,
65                                 mir_node *from,
66                                 mir_node *to,
67                                 pa_bool_t explicit)
68 {
69     pa_core *core;
70
71     pa_assert(u);
72     pa_assert(to);
73     pa_assert_se((core = u->core));
74     pa_assert(!from || from->direction == mir_input);
75     pa_assert(to->direction == mir_output);
76
77     if (explicit) {
78         /*
79          * links for explic routes
80          */
81         pa_assert(from);
82
83         switch (from->implement) {
84
85         case mir_stream:
86             switch (to->implement) {
87
88             case mir_stream:
89                 pa_log_debug("routing to streams is not implemented yet");
90                 break;
91
92             case mir_device:
93                 if (!setup_explicit_link_from_stream_to_device(u, from, to))
94                     return FALSE;
95                 break;
96
97             default:
98                 pa_log("%s: can't setup link: invalid sink node "
99                        "implement", __FILE__);
100                 return FALSE;
101             }
102             break;
103
104         case mir_device:
105             pa_log_debug("input device routing is not implemented yet");
106             break;
107
108         default:
109             pa_log("%s: can't setup link: invalid source node "
110                    "implement", __FILE__);
111             return FALSE;
112         }
113     }
114     else {
115         /*
116          * links for default routes
117          */
118         switch (to->implement) {
119
120         case mir_stream:
121             pa_log_debug("routing to a stream is not implemented yet");
122             break;
123
124         case mir_device:
125             if (!from) /* prerouting */
126                 return (!explicit && setup_device_output(u, to) != NULL);
127             else {
128                 switch (from->implement) {
129
130                 case mir_stream:
131                     if (!setup_default_link_from_stream_to_device(u, from, to))
132                         return FALSE;
133                     break;
134
135                 case mir_device:
136                     if (!setup_default_link_from_device_to_device(u, from, to))
137                         return FALSE;
138                     break;
139
140                 default:
141                     pa_log("%s: can't setup link: invalid source node "
142                            "implement", __FILE__);
143                     return FALSE;
144                 }
145             }
146             break;
147
148         default:
149             pa_log("%s: can't setup link: invalid sink node "
150                    "implement", __FILE__);
151             return FALSE;
152         }
153     }
154
155     pa_log_debug("link %s => %s is established", from->amname, to->amname);
156
157     return TRUE;
158 }
159
160 pa_bool_t mir_switch_teardown_link(struct userdata *u,
161                                    mir_node        *from,
162                                    mir_node        *to)
163 {
164     pa_core *core;
165
166     pa_assert(u);
167     pa_assert(from);
168     pa_assert(to);
169     pa_assert_se((core = u->core));
170     pa_assert(from->direction == mir_input);
171     pa_assert(to->direction == mir_output);
172
173
174     switch (from->implement) {
175
176     case mir_stream:
177         switch (to->implement) {
178             
179         case mir_stream: /* stream -> stream */
180             pa_log_debug("routing to streams is not implemented yet");
181             break;
182             
183         case mir_device: /* stream -> device */
184             if (!teardown_explicit_link_from_stream_to_device(u, from, to))
185                 return FALSE;
186             break;
187             
188         default:
189             pa_log("%s: can't teardown link: invalid sink node "
190                    "implement", __FILE__);
191             return FALSE;
192         }
193         break;
194         
195     case mir_device: /* device -> stream | device->device */
196         pa_log_debug("input device routing is not implemented yet");
197         break;
198         
199     default:
200         pa_log("%s: can't teardown link: invalid source node "
201                "implement", __FILE__);
202         return FALSE;
203     }
204
205     pa_log_debug("link %s => %s is torn down", from->amname, to->amname);
206
207     return TRUE;
208 }
209
210 static pa_bool_t setup_explicit_link_from_stream_to_device(struct userdata *u,
211                                                            mir_node *from,
212                                                            mir_node *to)
213 {
214     pa_core       *core;
215     pa_sink       *sink;
216     pa_sink_input *sinp;
217     pa_muxnode    *mux;
218
219     pa_assert(u);
220     pa_assert(from);
221     pa_assert(to);
222     pa_assert((core = u->core));
223
224     if (!(sink = setup_device_output(u, to)))
225         return FALSE;
226
227     if (!set_profile(u, from) || !set_port(u, from)) {
228         pa_log("can't route from '%s'", from->amname);
229         return FALSE;
230     }
231
232     if ((mux = from->mux)) {
233         sinp = pa_idxset_get_by_index(core->sink_inputs, mux->defstream_index);
234
235         if (sinp && sinp->sink == sink) {
236             if (!pa_multiplex_remove_default_route(core, mux, TRUE))
237                 return FALSE;
238         }
239         else if (pa_multiplex_duplicate_route(core, mux, NULL, sink)) {
240             pa_log_debug("multiplex route %s => %s already exists",
241                          from->amname, to->amname);
242             return TRUE;
243         }
244         else {
245             if (!pa_multiplex_add_explicit_route(core, mux, sink, from->type))
246                 return FALSE;
247         }
248     }
249     else {
250         if ((sinp = pa_idxset_get_by_index(core->sink_inputs, from->paidx))) {
251             if (sinp->sink == sink)
252                 pa_log_debug("direct route already exists. nothing to do");
253             else {
254                 pa_log_debug("direct route: sink-input.%u -> sink.%u",
255                              sinp->index, sink->index);
256
257                 if (pa_sink_input_move_to(sinp, sink, FALSE) < 0)
258                     return FALSE;
259             }
260         }
261     }
262
263     pa_log_debug("link %s => %s is established", from->amname, to->amname);
264
265     return TRUE;
266 }
267
268
269 static pa_bool_t teardown_explicit_link_from_stream_to_device(struct userdata *u,
270                                                               mir_node *from,
271                                                               mir_node *to)
272 {
273     pa_core       *core;
274     pa_sink       *sink;
275     pa_sink_input *sinp;
276     pa_muxnode    *mux;
277
278     pa_assert(u);
279     pa_assert(from);
280     pa_assert(to);
281     pa_assert((core = u->core));
282
283     if ((mux = from->mux)) {
284         if (!(sink = pa_idxset_get_by_index(core->sinks, to->paidx))) {
285             pa_log_debug("can't find sink.%u", to->paidx);
286             return FALSE;
287         }
288
289         if (!pa_multiplex_remove_explicit_route(core, mux, sink)) {
290             pa_log_debug("can't remove multiplex route on mux %u", mux->module_index);
291             return FALSE;
292         }
293     }
294     else {
295         if (!(sinp = pa_idxset_get_by_index(core->sink_inputs, from->paidx))) {
296             pa_log_debug("can't find source.%u", from->paidx);
297             return FALSE;
298         }
299
300         if (!(sink = pa_utils_get_null_sink(u))) {
301             pa_log_debug("can't remove direct route: no null sink");
302             return FALSE;
303         }
304
305         if (pa_sink_input_move_to(sinp, sink, FALSE) < 0)
306             return FALSE;
307     }
308
309     pa_log_debug("link %s => %s is torn down", from->amname, to->amname);
310
311     return TRUE;
312 }
313
314
315 static pa_bool_t setup_default_link_from_stream_to_device(struct userdata *u,
316                                                           mir_node *from,
317                                                           mir_node *to)
318 {
319     pa_core       *core;
320     pa_sink       *sink;
321     pa_sink_input *sinp;
322     pa_muxnode    *mux;
323     int            n;
324
325     pa_assert(u);
326     pa_assert(from);
327     pa_assert(to);
328     pa_assert((core = u->core));
329
330     if (!(sink = setup_device_output(u, to)))
331         return FALSE;
332
333     if (!set_profile(u, from) || !set_port(u, from)) {
334         pa_log("can't route from '%s'", from->amname);
335         return FALSE;
336     }
337
338     if ((mux = from->mux)) {
339         if (mux->defstream_index == PA_IDXSET_INVALID) {
340             if ((n = pa_multiplex_no_of_routes(core, mux)) < 0)
341                 return FALSE;
342             else if (n > 0) {
343                 pa_log_debug("currently mux %u has no default route",
344                              mux->module_index);
345                 return TRUE;
346             }
347             sinp = NULL;
348         }
349         else {
350             sinp = pa_idxset_get_by_index(core->sink_inputs,
351                                           mux->defstream_index);
352         }
353
354         if (!sinp) {
355             /*
356              * we supposed to have a default stream but the sink-input
357              * on the combine side is not existing any more. This can
358              * happen, for instance, if the sink, where it was connected,
359              * died for some reason.
360              */
361             pa_log_debug("supposed to have a default stream on multiplex "
362                          "%u but non was found. Trying to make one",
363                          mux->module_index);
364             if (pa_multiplex_duplicate_route(core, mux, sinp, sink)) {
365                 pa_log_debug("the default stream on mux %u would be a "
366                              "duplicate to an explicit route. "
367                              "Removing it ...", mux->module_index);
368                 mux->defstream_index = PA_IDXSET_INVALID;
369                 return TRUE; /* the routing is a success */
370             }
371
372             if (!pa_multiplex_add_default_route(core, mux,sink, from->type)) {
373                 pa_log_debug("failed to add default route on mux %d",
374                              mux->module_index);
375                 mux->defstream_index = PA_IDXSET_INVALID;
376                 return FALSE;
377             }
378         }
379         else if (pa_multiplex_duplicate_route(core, mux, sinp, sink)) {
380             pa_log_debug("the default stream on mux %u would be a duplicate "
381                          "to an explicit route. Removing it ...",
382                          mux->module_index);
383             return TRUE;        /* the routing is a success */
384         }
385             
386         if (sinp) {
387             pa_log_debug("multiplex route: sink-input.%d -> (sink.%d - "
388                          "sink-input.%d) -> sink.%d", from->paidx,
389                          mux->sink_index, sinp->index, sink->index);
390         }
391         else {
392             pa_log_debug("multiplex route: sink-input.%d -> (sink.%d - "
393                          "sink-input) -> sink.%d", from->paidx,
394                          mux->sink_index, sink->index);
395         }
396
397         if (!pa_multiplex_change_default_route(core, mux, sink))
398             return FALSE;
399     }
400     else {
401         if (from->paidx == PA_IDXSET_INVALID) {
402             pa_log_debug("can't route '%s': no sink-input", to->amname);
403             return FALSE;
404         }
405
406         if (!(sinp = pa_idxset_get_by_index(core->sink_inputs, from->paidx))) {
407             pa_log_debug("can't find sink input for '%s'", from->amname);
408             return FALSE;
409         }
410
411         pa_log_debug("direct route: sink-input.%d -> sink.%d",
412                      sinp->index, sink->index);
413
414         if (pa_sink_input_move_to(sinp, sink, FALSE) < 0)
415             return FALSE;
416     }
417
418     return TRUE;
419 }
420
421 static pa_bool_t setup_default_link_from_device_to_device(struct userdata *u,
422                                                           mir_node *from,
423                                                           mir_node *to)
424 {
425     pa_core       *core;
426     pa_sink       *sink;
427     pa_sink_input *sinp;
428     pa_muxnode    *mux;
429     pa_loopnode   *loop;
430     mir_node_type  type;
431     int            n;
432
433     pa_assert(u);
434     pa_assert(from);
435     pa_assert(to);
436     pa_assert((core = u->core));
437
438     if (!(loop = from->loop)) {
439         pa_log_debug("source is not looped back");
440         return FALSE;
441     }
442
443     if (!(sink = setup_device_output(u, to)))
444         return FALSE;
445
446     if ((mux = from->mux)) {
447         if (mux->defstream_index == PA_IDXSET_INVALID) {
448             if ((n = pa_multiplex_no_of_routes(core, mux)) < 0)
449                 return FALSE;
450             else if (n > 0) {
451                 pa_log_debug("currently mux %u has no default route",
452                              mux->module_index);
453                 return TRUE;
454             }
455             sinp = NULL;
456         }
457         else {
458             sinp = pa_idxset_get_by_index(core->sink_inputs,
459                                           mux->defstream_index);
460         }
461
462         if (!sinp) {
463             /*
464              * we supposed to have a default stream but the sink-input
465              * on the combine side is not existing any more. This can
466              * happen, for instance, if the sink, where it was connected,
467              * died for some reason.
468              */
469             pa_log_debug("supposed to have a default stream on multiplex "
470                          "%u but non was found. Trying to make one",
471                          mux->module_index);
472             if (pa_multiplex_duplicate_route(core, mux, sinp, sink)) {
473                 pa_log_debug("the default stream on mux %u would be a "
474                              "duplicate to an explicit route. "
475                              "Removing it ...", mux->module_index);
476                 mux->defstream_index = PA_IDXSET_INVALID;
477                 return TRUE; /* the routing is a success */
478             }
479
480             type = pa_classify_guess_application_class(from);
481
482             if (!pa_multiplex_add_default_route(core, mux,sink, type)) {
483                 pa_log_debug("failed to add default route on mux %d",
484                              mux->module_index);
485                 mux->defstream_index = PA_IDXSET_INVALID;
486                 return FALSE;
487             }
488         }
489         else if (pa_multiplex_duplicate_route(core, mux, sinp, sink)) {
490             pa_log_debug("the default stream on mux %u would be a duplicate "
491                          "to an explicit route. Removing it ...",
492                          mux->module_index);
493             return TRUE;        /* the routing is a success */
494         }
495             
496         if (sinp) {
497             pa_log_debug("multiplex route: source.%d -> "
498                          "(source-output - sink-input %d) -> (sink.%d - "
499                          "sink-input.%d) -> sink.%d", from->paidx,
500                          loop->sink_input_index,
501                          mux->sink_index, sinp->index, sink->index);
502         }
503         else {
504             pa_log_debug("multiplex route: source.%d -> "
505                          "(source-output - sink-input.%d) -> (sink.%d - "
506                          "sink-input) -> sink.%d", from->paidx,
507                          loop->sink_input_index, 
508                          mux->sink_index, sink->index);
509         }
510
511         if (!pa_multiplex_change_default_route(core, mux, sink))
512             return FALSE;
513     }
514     else {
515         sinp = pa_idxset_get_by_index(core->sink_inputs,
516                                       loop->sink_input_index);
517
518         if (!sinp) {
519             pa_log_debug("can't find looped back sink input for '%s'",
520                          from->amname);
521             return FALSE;
522         }
523
524         pa_log_debug("loopback route: source.%d -> (source-output - "
525                      "sink-input.%d) -> sink.%d",
526                      from->paidx, sinp->index, sink->index);
527
528         if (pa_sink_input_move_to(sinp, sink, FALSE) < 0)
529             return FALSE;
530     }
531
532     return TRUE;
533 }
534
535 static pa_sink *setup_device_output(struct userdata *u, mir_node *node)
536 {
537     pa_core *core;
538     pa_sink *sink;
539
540     pa_assert(u);
541     pa_assert(node);
542     pa_assert_se((core = u->core));
543
544     if (!set_profile(u, node) || !set_port(u, node)) {
545         pa_log("can't route to '%s'", node->amname);
546         return NULL;
547     }
548
549     if (node->paidx == PA_IDXSET_INVALID) {
550         pa_log_debug("can't route to '%s': no sink", node->amname);
551         return NULL;
552     }
553
554     if (!(sink = pa_idxset_get_by_index(core->sinks, node->paidx))) {
555         pa_log_debug("can't route to '%s': cant find sink", node->amname);
556         return NULL;
557     }
558
559     return sink;
560 }
561
562
563 static pa_bool_t set_profile(struct userdata *u, mir_node *node)
564 {
565     pa_core         *core;
566     pa_card         *card;
567     pa_card_profile *prof;
568
569     pa_assert(u);
570     pa_assert(node);
571     pa_assert_se((core = u->core));
572
573     if (node->implement != mir_device)
574         return TRUE;
575
576     if (node->type == mir_bluetooth_a2dp ||
577         node->type == mir_bluetooth_sco)
578     {
579         card = pa_idxset_get_by_index(core->cards, node->pacard.index);
580
581         if (!card) {
582             pa_log("can't find card for '%s'", node->amname);
583             return FALSE;
584         }
585
586         pa_assert_se(prof = card->active_profile);
587     
588         if (!pa_streq(node->pacard.profile, prof->name)) {
589             pa_log_debug("changing profile '%s' => '%s'",
590                          prof->name, node->pacard.profile);
591
592             if (u->state.profile) {
593                 pa_log("nested profile setting is not allowed. won't change "
594                        "'%s' => '%s'", prof->name, node->pacard.profile);
595                 return FALSE;
596             }
597
598             u->state.profile = node->pacard.profile;
599
600             pa_card_set_profile(card, node->pacard.profile, FALSE);
601
602             u->state.profile = NULL;            
603         }
604     }
605
606     return TRUE;
607 }
608
609
610
611 static pa_bool_t set_port(struct userdata *u, mir_node *node)
612 {
613     pa_core   *core;
614     pa_sink   *sink;
615     pa_source *source;
616     pa_device_port *port;
617     mir_node  *oldnode;
618     void      *data  = NULL;
619     uint32_t   paidx = PA_IDXSET_INVALID;
620
621     pa_assert(u);
622     pa_assert(node);
623     pa_assert(node->paname);
624     pa_assert_se((core = u->core));
625
626     if (node->direction != mir_input && node->direction != mir_output)
627         return FALSE;
628
629     if (node->implement != mir_device)
630         return TRUE;
631
632     if (!node->paport)
633         return TRUE;
634
635     if (node->direction == mir_input) {
636         source = pa_namereg_get(core, node->paname, PA_NAMEREG_SOURCE);
637         
638         if (!(data = source)) {
639             pa_log("can't set port for '%s': source not found",
640                    node->paname);
641             return FALSE;
642         }
643         
644         if ((port = source->active_port) && pa_streq(node->paport, port->name))
645             return TRUE;
646
647         if (pa_source_set_port(source, node->paport, FALSE) < 0)
648             return FALSE;
649
650         paidx = source->index;
651     }
652
653     if (node->direction == mir_output) {
654         sink = pa_namereg_get(core, node->paname, PA_NAMEREG_SINK);
655         
656         if (!(data = sink)) {
657             pa_log("can't set port for '%s': sink not found",
658                    node->paname);
659             return FALSE;
660         }
661
662         if ((port = sink->active_port) && pa_streq(node->paport, port->name))
663             return TRUE;
664
665         if (pa_sink_set_port(sink, node->paport, FALSE) < 0)
666             return FALSE;
667
668         paidx = sink->index;
669     }
670
671     if ((oldnode = pa_discover_remove_node_from_ptr_hash(u, data)))
672         oldnode->paidx = PA_IDXSET_INVALID;
673
674     node->paidx = paidx;
675     pa_discover_add_node_to_ptr_hash(u, data, node);
676
677
678     return TRUE;
679 }
680
681
682
683 /*
684  * Local Variables:
685  * c-basic-offset: 4
686  * indent-tabs-mode: nil
687  * End:
688  *
689  */