fixing bugs after merging scripting and external api
[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 #define _GNU_SOURCE
21
22 #include <stdio.h>
23 #include <string.h>
24
25 #include <pulsecore/pulsecore-config.h>
26
27 #include <pulsecore/card.h>
28 #include <pulsecore/device-port.h>
29 #include <pulsecore/core-util.h>
30
31 #include "classify.h"
32 #include "node.h"
33
34
35 void pa_classify_node_by_card(mir_node        *node,
36                               pa_card         *card,
37                               pa_card_profile *prof,
38                               pa_device_port  *port)
39 {
40     const char *bus;
41     const char *form;
42     /*
43     const char *desc;
44     */
45
46     pa_assert(node);
47     pa_assert(card);
48
49     bus  = pa_proplist_gets(card->proplist, PA_PROP_DEVICE_BUS);
50     form = pa_proplist_gets(card->proplist, PA_PROP_DEVICE_FORM_FACTOR);
51     /*
52     desc = pa_proplist_gets(card->proplist, PA_PROP_DEVICE_DESCRIPTION);
53     */
54
55     node->type = mir_node_type_unknown;
56
57     if (form) {
58         if (!strcasecmp(form, "internal")) {
59             node->location = mir_external;
60             if (port && !strcasecmp(bus, "pci")) {
61                 pa_classify_guess_device_node_type_and_name(node, port->name,
62                                                             port->description);
63             }
64         }
65         else if (!strcasecmp(form, "speaker") || !strcasecmp(form, "car")) {
66             if (node->direction == mir_output) {
67                 node->location = mir_internal;
68                 node->type = mir_speakers;
69             }
70         }
71         else if (!strcasecmp(form, "handset")) {
72             node->location = mir_external;
73             node->type = mir_phone;
74             node->privacy = mir_private;
75         }
76         else if (!strcasecmp(form, "headset")) {
77             node->location = mir_external;
78             if (bus) {
79                 if (!strcasecmp(bus,"usb")) {
80                     node->type = mir_usb_headset;
81                 }
82                 else if (!strcasecmp(bus,"bluetooth")) {
83                     if (prof && !strcmp(prof->name, "a2dp"))
84                         node->type = mir_bluetooth_a2dp;
85                     else
86                         node->type = mir_bluetooth_sco;
87                 }
88                 else {
89                     node->type = mir_wired_headset;
90                 }
91             }
92         }
93         else if (!strcasecmp(form, "headphone")) {
94             if (node->direction == mir_output) {
95                 node->location = mir_external;
96                 if (bus) {
97                     if (!strcasecmp(bus,"usb"))
98                         node->type = mir_usb_headphone;
99                     else if (strcasecmp(bus,"bluetooth"))
100                         node->type = mir_wired_headphone;
101                 }
102             }
103         }
104         else if (!strcasecmp(form, "microphone")) {
105             if (node->direction == mir_input) {
106                 node->location = mir_external;
107                 node->type = mir_microphone;
108             }
109         }
110     }
111     else {
112         if (port && !strcasecmp(bus, "pci")) {
113             pa_classify_guess_device_node_type_and_name(node, port->name,
114                                                         port->description);
115         }
116         else if (prof && !strcasecmp(bus, "bluetooth")) {
117             if (!strcmp(prof->name, "a2dp"))
118                 node->type = mir_bluetooth_a2dp;
119             else if (!strcmp(prof->name, "hsp"))
120                 node->type = mir_bluetooth_sco;
121             else if (!strcmp(prof->name, "hfgw"))
122                 node->type = mir_bluetooth_carkit;
123             else if (!strcmp(prof->name, "a2dp_source"))
124                 node->type = mir_bluetooth_source;
125             else if (!strcmp(prof->name, "a2dp_sink"))
126                 node->type = mir_bluetooth_sink;
127         }
128     }
129
130     if (!node->amname[0]) {
131         if (node->type != mir_node_type_unknown)
132             node->amname = (char *)mir_node_type_str(node->type);
133         else if (port && port->description)
134             node->amname = port->description;
135         else if (port && port->name)
136             node->amname = port->name;
137         else
138             node->amname = node->paname;
139     }
140
141
142     if (node->direction == mir_input)
143         node->privacy = mir_privacy_unknown;
144     else {
145         switch (node->type) {
146             /* public */
147         default:
148         case mir_speakers:
149         case mir_front_speakers:
150         case mir_rear_speakers:
151             node->privacy = mir_public;
152             break;
153             
154             /* private */
155         case mir_phone:
156         case mir_wired_headset:
157         case mir_wired_headphone:
158         case mir_usb_headset:
159         case mir_usb_headphone:
160         case mir_bluetooth_sco:
161         case mir_bluetooth_a2dp:
162             node->privacy = mir_private;
163             break;
164             
165             /* unknown */
166         case mir_null:
167         case mir_jack:
168         case mir_spdif:
169         case mir_hdmi:
170         case mir_bluetooth_sink:
171             node->privacy = mir_privacy_unknown;
172             break;
173         } /* switch */
174     }
175 }
176
177
178 /* data->direction must be set */
179 void pa_classify_guess_device_node_type_and_name(mir_node   *node,
180                                                  const char *name,
181                                                  const char *desc)
182 {
183     pa_assert(node);
184     pa_assert(name);
185     pa_assert(desc);
186
187     if (node->direction == mir_output && strcasestr(name, "headphone")) {
188         node->type = mir_wired_headphone;
189         node->amname = (char *)desc;
190     }
191     else if (strcasestr(name, "headset")) {
192         node->type = mir_wired_headset;
193         node->amname = (char *)desc;
194     }
195     else if (strcasestr(name, "line")) {
196         node->type = mir_jack;
197         node->amname = (char *)desc;
198     }
199     else if (strcasestr(name, "spdif")) {
200         node->type = mir_spdif;
201         node->amname = (char *)desc;
202     }
203     else if (strcasestr(name, "hdmi")) {
204         node->type = mir_hdmi;
205         node->amname = (char *)desc;
206     }
207     else if (node->direction == mir_input && strcasestr(name, "microphone")) {
208         node->type = mir_microphone;
209         node->amname = (char *)desc;
210     }
211     else if (node->direction == mir_output && strcasestr(name,"analog-output"))
212         node->type = mir_speakers;
213     else if (node->direction == mir_input && strcasestr(name, "analog-input"))
214         node->type = mir_jack;
215     else {
216         node->type = mir_node_type_unknown;
217     }
218 }
219
220
221 mir_node_type pa_classify_guess_stream_node_type(pa_proplist *pl)
222 {
223     typedef struct {
224         char *id;
225         mir_node_type type;
226     } map_t;
227
228     static map_t role_map[] = {
229         {"video"    , mir_player    },
230         {"music"    , mir_player    },
231         {"game"     , mir_game      },
232         {"event"    , mir_event     },
233         {"navigator", mir_navigator },
234         {"phone"    , mir_phone     },
235         {"carkit"   , mir_phone     },
236         {"animation", mir_browser   },
237         {"test"     , mir_player    },
238         {"ringtone" , mir_alert     },
239         {"camera"   , mir_camera    },
240         {"system"   , mir_system    },
241         {NULL, mir_node_type_unknown}
242     };
243
244     static map_t bin_map[] = {
245         {"rhytmbox"    , mir_player },
246         {"firefox"     , mir_browser},
247         {"chrome"      , mir_browser},
248         {"sound-juicer", mir_player },
249         {NULL, mir_node_type_unknown}
250     };
251
252
253     mir_node_type  rtype, btype;
254     const char    *role;
255     const char    *bin;
256     map_t         *m;
257
258     pa_assert(pl);
259
260     rtype = btype = mir_node_type_unknown;
261
262     role = pa_proplist_gets(pl, PA_PROP_MEDIA_ROLE);
263     bin  = pa_proplist_gets(pl, PA_PROP_APPLICATION_PROCESS_BINARY);
264
265     if (role) {
266         for (m = role_map;  m->id;  m++) {
267             if (pa_streq(role, m->id))
268                 break;
269         }
270         rtype = m->type;
271     }
272
273     if (rtype != mir_node_type_unknown && rtype != mir_player)
274         return rtype;
275
276     if (bin) {
277         for (m = bin_map;  m->id;  m++) {
278             if (pa_streq(bin, m->id))
279                 break;
280         }
281         btype = m->type;
282     }
283
284     if (btype == mir_node_type_unknown)
285         return rtype;
286
287     return btype;
288 }
289
290 mir_node_type pa_classify_guess_application_class(mir_node *node)
291 {
292     mir_node_type class;
293
294     pa_assert(node);
295
296     if (node->implement == mir_stream)
297         class = node->type;
298     else {
299         if (node->direction == mir_output)
300             class = mir_node_type_unknown;
301         else {
302             switch (node->type) {
303             default:                    class = mir_node_type_unknown;   break;
304             case mir_bluetooth_carkit:  class = mir_phone;               break;
305             case mir_bluetooth_source:  class = mir_player;              break;
306             }
307         }
308     }
309
310     return class;
311 }
312
313
314 pa_bool_t pa_classify_multiplex_stream(mir_node *node)
315 {
316     static pa_bool_t multiplex[mir_application_class_end] = {
317         [ mir_player  ] = TRUE,
318         [ mir_game    ] = TRUE,
319         [ mir_browser ] = TRUE,
320     };
321
322     mir_node_type class;
323
324     pa_assert(node);
325
326     if (node->implement == mir_stream && node->direction == mir_input) {
327         class = node->type;
328
329         if (class > mir_application_class_begin &&
330             class < mir_application_class_end)
331         {
332             return multiplex[class];
333         }
334     }
335
336     return FALSE;
337 }
338
339 const char *pa_classify_loopback_stream(mir_node *node)
340 {
341     const char *role[mir_device_class_end - mir_device_class_begin] = {
342         [ mir_bluetooth_carkit - mir_device_class_begin ] = "phone",
343         [ mir_bluetooth_source - mir_device_class_begin ] = "music" ,
344     };
345
346     int class;
347
348     pa_assert(node);
349
350     if (node->implement == mir_device) {
351         class = node->type;
352
353         if (class >= mir_device_class_begin && class < mir_device_class_end) {
354             return role[class - mir_device_class_begin];
355         }
356     }
357
358     return NULL;
359 }
360