Initial import pulseaudio modules for mfld, which handles stream policy check on...
[adaptation/intel_mfld/pulseaudio-modules-mfld-blackbay.git] / src / module-stream-policy-mfld.c
1 /*
2  * module-stream-policy-mfld -- PulseAudio module for stream policy check
3  * on mfld platform
4  * Copyright (c) 2012, Intel Corporation.
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms and conditions of the GNU Lesser General Public License,
8  * version 2.1, as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.
13  * See the GNU Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with this program; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St - Fifth Floor, Boston,
18  * MA 02110-1301 USA.
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <pulsecore/core.h>
27 #include <pulsecore/module.h>
28 #include <pulsecore/core-util.h>
29 #include <pulsecore/log.h>
30 #include <pulsecore/sink-input.h>
31 #include <pulsecore/namereg.h>
32 #include "module-stream-policy-mfld-symdef.h"
33
34 PA_MODULE_AUTHOR("vivian zhang");
35 PA_MODULE_DESCRIPTION("stream policy check on MFLD platform");
36 PA_MODULE_VERSION(PACKAGE_VERSION);
37 PA_MODULE_LOAD_ONCE(TRUE);
38
39 struct userdata {
40     pa_core *core;
41     pa_module *module;
42     pa_hook_slot *sink_input_new_hook_slot;
43 };
44
45 /* DEFINEs */
46 #define POLICY_AUTO         "auto"
47 #define POLICY_PHONE        "phone"
48 #define POLICY_ALL          "all"
49 #define SINK_ALSA           "alsa_output.0.analog-stereo"
50 #define SINK_COMBINED       "combined"
51 #define BLUEZ_API           "bluez"
52
53 /* Get sink by name */
54 static pa_sink* get_sink_by_name (pa_core *c, const char* sink_name)
55 {
56     pa_sink *s = NULL;
57     uint32_t idx;
58
59     if (c == NULL || sink_name == NULL) {
60         pa_log_warn ("input param is null");
61         return NULL;
62     }
63     PA_IDXSET_FOREACH(s, c->sinks, idx) {
64         if (pa_streq (s->name, sink_name)) {
65             return s;
66         }
67     }
68     return NULL;
69 }
70
71 /* check if this sink is bluez */
72 static pa_bool_t check_is_bluez (pa_sink* sink)
73 {
74     const char* api_name = NULL;
75     if (sink == NULL) {
76         pa_log_warn ("input param sink is null");
77         return FALSE;
78     }
79     api_name = pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_API);
80     if (api_name) {
81         if (pa_streq (api_name, BLUEZ_API)) {
82             pa_log_debug("[MFLD] [%s] exists and it is [%s]...TRUE", PA_PROP_DEVICE_API, api_name);
83             return TRUE;
84         }
85     }
86     return FALSE;
87 }
88
89 /* Get bt sink if available */
90 static pa_sink* get_bt_sink (pa_core *c)
91 {
92     pa_sink *s = NULL;
93     uint32_t idx;
94     const char* api_name = NULL;
95
96     if (c == NULL) {
97         pa_log_warn ("input param is null");
98         return NULL;
99     }
100     PA_IDXSET_FOREACH(s, c->sinks, idx) {
101         if (check_is_bluez (s)) {
102             pa_log_debug ("[POLICY][%s] return [%p] for [%s]\n", __func__, s, s->name);
103             return s;
104         }
105     }
106     return NULL;
107 }
108
109 /* Called when new sink-input is creating */
110 static pa_hook_result_t sink_input_new_hook_callback(pa_core *c, pa_sink_input_new_data *new_data, struct userdata *u)
111 {
112     const char *policy = NULL;
113     pa_sink* sink = NULL;
114     pa_sink* bt_sink = NULL;
115     pa_sink* def = NULL;
116
117     pa_assert(c);
118     pa_assert(new_data);
119     pa_assert(u);
120     if (!new_data->proplist) {
121         pa_log_debug("[MFLD] New stream lacks property data.");
122         return PA_HOOK_OK;
123     }
124     /* If sink-input has already sink, skip */
125     if (new_data->sink) {
126         /* sink-input with filter role will be also here because sink is already set */
127         pa_log_debug("[MFLD] Sink already set");
128         return PA_HOOK_OK;
129     }
130
131     /* If no policy exists, skip */
132     if (!(policy = pa_proplist_gets(new_data->proplist, PA_PROP_MEDIA_POLICY)))
133         return PA_HOOK_OK;
134
135     pa_log_debug("[MFLD] Policy for stream [%s] = [%s]",
136             pa_strnull(pa_proplist_gets(new_data->proplist, PA_PROP_MEDIA_NAME)), policy);
137         /* If policy == all */
138     if (pa_streq(policy, POLICY_ALL)) {
139         pa_log_debug("[MFLD] Change policy to auto");
140         pa_proplist_sets(new_data->proplist, PA_PROP_MEDIA_POLICY, POLICY_AUTO);
141
142         /* check bt_sink */
143         bt_sink = get_bt_sink(c);
144         if (bt_sink)
145             sink = get_sink_by_name(c, SINK_COMBINED);
146         else {
147             /* check default sink */
148             def = pa_namereg_get_default_sink(c);
149             if (def && strstr(def->name,"alsa_")) {
150                 pa_log_debug("[MFLD] default sink is %s, set to default", def->name);
151                 sink = def;
152             } else {
153                 pa_log_debug("[MFLD] set sink to alsa speaker");
154                 sink = get_sink_by_name(c, SINK_ALSA);
155             }
156         }
157         new_data->sink = sink;
158     }
159     return PA_HOOK_OK;
160 }
161
162 int pa__init(pa_module *m)
163 {
164     struct userdata *u;
165     pa_assert(m);
166     m->userdata = u = pa_xnew0(struct userdata, 1);
167     u->core = m->core;
168     u->module = m;
169     /* A little bit later than module-stream-restore and before module-policy */
170     u->sink_input_new_hook_slot =
171             pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_NEW], PA_HOOK_EARLY+6, (pa_hook_cb_t) sink_input_new_hook_callback, u);
172
173     pa_log_info("[MFLD] stream policy check module is loaded\n");
174     return 0;
175 }
176
177 void pa__done(pa_module *m)
178 {
179     struct userdata* u;
180     pa_assert(m);
181     if (!(u = m->userdata))
182         return;
183     if (u->sink_input_new_hook_slot)
184         pa_hook_slot_free(u->sink_input_new_hook_slot);
185     pa_xfree(u);
186 }