routing: add loopback support to nodes
[profile/ivi/pulseaudio-module-murphy-ivi.git] / murphy / classify.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
22 #include <pulsecore/pulsecore-config.h>
23
24 #include <pulsecore/card.h>
25 #include <pulsecore/device-port.h>
26 #include <pulsecore/core-util.h>
27
28 #include "classify.h"
29 #include "node.h"
30
31
32 void pa_classify_node_by_card(mir_node        *node,
33                               pa_card         *card,
34                               pa_card_profile *prof,
35                               pa_device_port  *port)
36 {
37     const char *bus;
38     const char *form;
39     
40     pa_assert(node);
41     pa_assert(card);
42
43     bus  = pa_proplist_gets(card->proplist, PA_PROP_DEVICE_BUS);
44     form = pa_proplist_gets(card->proplist, PA_PROP_DEVICE_FORM_FACTOR);
45
46     if (form) {
47         if (!strcasecmp(form, "internal")) {
48             node->location = mir_external;
49             if (port && !strcasecmp(bus, "pci")) {
50                 pa_classify_guess_device_node_type_and_name(node, port->name,
51                                                             port->description);
52             }
53         }
54         else if (!strcasecmp(form, "speaker") || !strcasecmp(form, "car")) {
55             if (node->direction == mir_output) {
56                 node->location = mir_internal;
57                 node->type = mir_speakers;
58             }
59         }
60         else if (!strcasecmp(form, "handset")) {
61             node->location = mir_external;
62             node->type = mir_phone;
63             node->privacy = mir_private;
64         }
65         else if (!strcasecmp(form, "headset")) {
66             node->location = mir_external;
67             if (bus) {
68                 if (!strcasecmp(bus,"usb")) {
69                     node->type = mir_usb_headset;
70                 }
71                 else if (!strcasecmp(bus,"bluetooth")) {
72                     if (prof && !strcmp(prof->name, "a2dp"))
73                         node->type = mir_bluetooth_a2dp;
74                     else 
75                         node->type = mir_bluetooth_sco;
76                 }
77                 else {
78                     node->type = mir_wired_headset;
79                 }
80             }
81         }
82         else if (!strcasecmp(form, "headphone")) {
83             if (node->direction == mir_output) {
84                 node->location = mir_external;
85                 if (bus) {
86                     if (!strcasecmp(bus,"usb"))
87                         node->type = mir_usb_headphone;
88                     else if (strcasecmp(bus,"bluetooth"))
89                         node->type = mir_wired_headphone;
90                 }
91             }
92         }
93         else if (!strcasecmp(form, "microphone")) {
94             if (node->direction == mir_input) {
95                 node->location = mir_external;
96                 node->type = mir_microphone;
97             }
98         }
99     }
100     else {
101         if (port && !strcasecmp(bus, "pci")) {
102             pa_classify_guess_device_node_type_and_name(node, port->name,
103                                                         port->description);
104         }
105     }
106
107     if (!node->amname[0]) {
108         if (node->type != mir_node_type_unknown)
109             node->amname = (char *)mir_node_type_str(node->type);
110         else if (port && port->description)
111             node->amname = port->description;
112         else if (port && port->name)
113             node->amname = port->name;
114         else
115             node->amname = node->paname;
116     }
117
118
119     if (node->direction == mir_input)
120         node->privacy = mir_privacy_unknown;
121     else {
122         switch (node->type) {
123             /* public */
124         default:
125         case mir_speakers:
126         case mir_front_speakers:
127         case mir_rear_speakers:
128             node->privacy = mir_public;
129             break;
130             
131             /* private */
132         case mir_phone:
133         case mir_wired_headset:
134         case mir_wired_headphone:
135         case mir_usb_headset:
136         case mir_usb_headphone:
137         case mir_bluetooth_sco:
138         case mir_bluetooth_a2dp:
139             node->privacy = mir_private;
140             break;
141             
142             /* unknown */
143         case mir_null:
144         case mir_jack:
145         case mir_spdif:
146         case mir_hdmi:
147             node->privacy = mir_privacy_unknown;
148             break;
149         } /* switch */
150     }
151 }
152
153
154 /* data->direction must be set */
155 void pa_classify_guess_device_node_type_and_name(mir_node   *node,
156                                                  const char *name,
157                                                  const char *desc)
158 {
159     pa_assert(node);
160     pa_assert(name);
161     pa_assert(desc);
162
163     if (node->direction == mir_output && strcasestr(name, "headphone")) {
164         node->type = mir_wired_headphone;
165         node->amname = (char *)desc;
166     }
167     else if (strcasestr(name, "headset")) {
168         node->type = mir_wired_headset;
169         node->amname = (char *)desc;
170     }
171     else if (strcasestr(name, "line")) {
172         node->type = mir_jack;
173         node->amname = (char *)desc;
174     }
175     else if (strcasestr(name, "spdif")) {
176         node->type = mir_spdif;
177         node->amname = (char *)desc;
178     }
179     else if (strcasestr(name, "hdmi")) {
180         node->type = mir_hdmi;
181         node->amname = (char *)desc;
182     }
183     else if (node->direction == mir_input && strcasestr(name, "microphone")) {
184         node->type = mir_microphone;
185         node->amname = (char *)desc;
186     }
187     else if (node->direction == mir_output && strcasestr(name,"analog-output"))
188         node->type = mir_speakers;
189     else if (node->direction == mir_input && strcasestr(name, "analog-input"))
190         node->type = mir_jack;
191     else {
192         node->type = mir_node_type_unknown;
193     }
194 }
195
196
197 mir_node_type pa_classify_guess_stream_node_type(pa_proplist *pl)
198 {
199     typedef struct {
200         char *id;
201         mir_node_type type;
202     } map_t;
203
204     static map_t role_map[] = {
205         {"video"    , mir_player   },
206         {"music"    , mir_player   },
207         {"game"     , mir_game     },
208         {"event"    , mir_event    },
209         {"navigator", mir_navigator},
210         {"phone"    , mir_phone    },
211         {"animation", mir_browser  },
212         {"test"     , mir_player   },
213         {NULL, mir_node_type_unknown}
214     };
215
216     static map_t bin_map[] = {
217         {"rhytmbox"    , mir_player },
218         {"firefox"     , mir_browser},
219         {"chrome"      , mir_browser},
220         {"sound-juicer", mir_player },
221         {NULL, mir_node_type_unknown}
222     };
223
224
225     mir_node_type  rtype, btype;
226     const char    *role;
227     const char    *bin;
228     map_t         *m;
229
230     pa_assert(pl);
231
232     rtype = btype = mir_node_type_unknown;
233
234     role = pa_proplist_gets(pl, PA_PROP_MEDIA_ROLE);
235     bin  = pa_proplist_gets(pl, PA_PROP_APPLICATION_PROCESS_BINARY);
236
237     if (role) {
238         for (m = role_map;  m->id;  m++) {
239             if (pa_streq(role, m->id))
240                 break;
241         }
242         rtype = m->type;
243     }
244
245     if (rtype != mir_node_type_unknown && rtype != mir_player)
246         return rtype;
247
248     if (bin) {
249         for (m = bin_map;  m->id;  m++) {
250             if (pa_streq(bin, m->id))
251                 break;
252         }
253         btype = m->type;
254     }
255
256     if (btype == mir_node_type_unknown)
257         return rtype;
258
259     return btype;
260 }
261
262
263 pa_bool_t pa_classify_multiplex_stream(mir_node *node)
264 {
265     static pa_bool_t multiplex[mir_application_class_end] = {
266         [ mir_player  ] = TRUE,
267         [ mir_game    ] = TRUE,
268         [ mir_browser ] = TRUE,
269     };
270
271     mir_node_type class;
272
273     pa_assert(node);
274
275     //return FALSE;
276
277     if (node->implement == mir_stream && node->direction == mir_input) {
278         class = node->type;
279
280         if (class > mir_application_class_begin &&
281             class < mir_application_class_end)
282         {
283             return multiplex[class];
284         }
285     }
286
287     return FALSE;
288 }