update for beta release
[framework/uifw/e17.git] / src / modules / mixer / sink.c
1 #include "pa.h"
2
3
4 /** Makes a bit mask from a channel position. \since 0.9.16 */
5 #define PA_CHANNEL_POSITION_MASK(f) ((pa_channel_position_mask_t) (1ULL << (f)))
6
7
8 #define PA_CHANNEL_POSITION_MASK_LEFT                                   \
9     (PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_FRONT_LEFT)           \
10      | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_REAR_LEFT)          \
11      | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER) \
12      | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_SIDE_LEFT)          \
13      | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_FRONT_LEFT)     \
14      | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_REAR_LEFT))     \
15
16 #define PA_CHANNEL_POSITION_MASK_RIGHT                                  \
17     (PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_FRONT_RIGHT)          \
18      | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_REAR_RIGHT)         \
19      | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER) \
20      | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_SIDE_RIGHT)         \
21      | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_FRONT_RIGHT)    \
22      | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_REAR_RIGHT))
23
24 #define PA_CHANNEL_POSITION_MASK_CENTER                                 \
25     (PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_FRONT_CENTER)         \
26      | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_REAR_CENTER)        \
27      | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_CENTER)         \
28      | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_FRONT_CENTER)   \
29      | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_REAR_CENTER))
30
31 #define PA_CHANNEL_POSITION_MASK_FRONT                                  \
32     (PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_FRONT_LEFT)           \
33      | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_FRONT_RIGHT)        \
34      | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_FRONT_CENTER)       \
35      | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER) \
36      | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER) \
37      | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_FRONT_LEFT)     \
38      | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_FRONT_RIGHT)    \
39      | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_FRONT_CENTER))
40
41 #define PA_CHANNEL_POSITION_MASK_REAR                                   \
42     (PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_REAR_LEFT)            \
43      | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_REAR_RIGHT)         \
44      | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_REAR_CENTER)        \
45      | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_REAR_LEFT)      \
46      | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_REAR_RIGHT)     \
47      | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_REAR_CENTER))
48
49 #define PA_CHANNEL_POSITION_MASK_SIDE_OR_TOP_CENTER                     \
50     (PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_SIDE_LEFT)            \
51      | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_SIDE_RIGHT)         \
52      | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_CENTER))
53
54 #define PA_CHANNEL_POSITION_MASK_TOP                                    \
55     (PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_CENTER)           \
56      | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_FRONT_LEFT)     \
57      | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_FRONT_RIGHT)    \
58      | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_FRONT_CENTER)   \
59      | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_REAR_LEFT)      \
60      | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_REAR_RIGHT)     \
61      | PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_REAR_CENTER))
62
63 #define PA_CHANNEL_POSITION_MASK_ALL            \
64     ((pa_channel_position_mask_t) (PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_MAX)-1))
65
66 const char *const channel_name_table[PA_CHANNEL_POSITION_MAX] = {
67     [PA_CHANNEL_POSITION_MONO] = _("Mono"),
68
69     [PA_CHANNEL_POSITION_FRONT_CENTER] = _("Front Center"),
70     [PA_CHANNEL_POSITION_FRONT_LEFT] = _("Front Left"),
71     [PA_CHANNEL_POSITION_FRONT_RIGHT] = _("Front Right"),
72
73     [PA_CHANNEL_POSITION_REAR_CENTER] = _("Rear Center"),
74     [PA_CHANNEL_POSITION_REAR_LEFT] = _("Rear Left"),
75     [PA_CHANNEL_POSITION_REAR_RIGHT] = _("Rear Right"),
76
77     [PA_CHANNEL_POSITION_LFE] = _("Subwoofer"),
78
79     [PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER] = _("Front Left-of-center"),
80     [PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER] = _("Front Right-of-center"),
81
82     [PA_CHANNEL_POSITION_SIDE_LEFT] = _("Side Left"),
83     [PA_CHANNEL_POSITION_SIDE_RIGHT] = _("Side Right"),
84
85     [PA_CHANNEL_POSITION_AUX0] = _("Auxiliary 0"),
86     [PA_CHANNEL_POSITION_AUX1] = _("Auxiliary 1"),
87     [PA_CHANNEL_POSITION_AUX2] = _("Auxiliary 2"),
88     [PA_CHANNEL_POSITION_AUX3] = _("Auxiliary 3"),
89     [PA_CHANNEL_POSITION_AUX4] = _("Auxiliary 4"),
90     [PA_CHANNEL_POSITION_AUX5] = _("Auxiliary 5"),
91     [PA_CHANNEL_POSITION_AUX6] = _("Auxiliary 6"),
92     [PA_CHANNEL_POSITION_AUX7] = _("Auxiliary 7"),
93     [PA_CHANNEL_POSITION_AUX8] = _("Auxiliary 8"),
94     [PA_CHANNEL_POSITION_AUX9] = _("Auxiliary 9"),
95     [PA_CHANNEL_POSITION_AUX10] = _("Auxiliary 10"),
96     [PA_CHANNEL_POSITION_AUX11] = _("Auxiliary 11"),
97     [PA_CHANNEL_POSITION_AUX12] = _("Auxiliary 12"),
98     [PA_CHANNEL_POSITION_AUX13] = _("Auxiliary 13"),
99     [PA_CHANNEL_POSITION_AUX14] = _("Auxiliary 14"),
100     [PA_CHANNEL_POSITION_AUX15] = _("Auxiliary 15"),
101     [PA_CHANNEL_POSITION_AUX16] = _("Auxiliary 16"),
102     [PA_CHANNEL_POSITION_AUX17] = _("Auxiliary 17"),
103     [PA_CHANNEL_POSITION_AUX18] = _("Auxiliary 18"),
104     [PA_CHANNEL_POSITION_AUX19] = _("Auxiliary 19"),
105     [PA_CHANNEL_POSITION_AUX20] = _("Auxiliary 20"),
106     [PA_CHANNEL_POSITION_AUX21] = _("Auxiliary 21"),
107     [PA_CHANNEL_POSITION_AUX22] = _("Auxiliary 22"),
108     [PA_CHANNEL_POSITION_AUX23] = _("Auxiliary 23"),
109     [PA_CHANNEL_POSITION_AUX24] = _("Auxiliary 24"),
110     [PA_CHANNEL_POSITION_AUX25] = _("Auxiliary 25"),
111     [PA_CHANNEL_POSITION_AUX26] = _("Auxiliary 26"),
112     [PA_CHANNEL_POSITION_AUX27] = _("Auxiliary 27"),
113     [PA_CHANNEL_POSITION_AUX28] = _("Auxiliary 28"),
114     [PA_CHANNEL_POSITION_AUX29] = _("Auxiliary 29"),
115     [PA_CHANNEL_POSITION_AUX30] = _("Auxiliary 30"),
116     [PA_CHANNEL_POSITION_AUX31] = _("Auxiliary 31"),
117
118     [PA_CHANNEL_POSITION_TOP_CENTER] = _("Top Center"),
119
120     [PA_CHANNEL_POSITION_TOP_FRONT_CENTER] = _("Top Front Center"),
121     [PA_CHANNEL_POSITION_TOP_FRONT_LEFT] = _("Top Front Left"),
122     [PA_CHANNEL_POSITION_TOP_FRONT_RIGHT] = _("Top Front Right"),
123
124     [PA_CHANNEL_POSITION_TOP_REAR_CENTER] = _("Top Rear Center"),
125     [PA_CHANNEL_POSITION_TOP_REAR_LEFT] = _("Top Rear Left"),
126     [PA_CHANNEL_POSITION_TOP_REAR_RIGHT] = _("Top Rear Right")
127 };
128
129 static Eina_Bool on_left(pa_channel_position_t p) {
130     return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_LEFT);
131 }
132
133 static Eina_Bool on_right(pa_channel_position_t p) {
134     return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_RIGHT);
135 }
136 #if 0
137 static Eina_Bool on_center(pa_channel_position_t p) {
138     return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_CENTER);
139 }
140
141 static Eina_Bool on_lfe(pa_channel_position_t p) {
142     return p == PA_CHANNEL_POSITION_LFE;
143 }
144 #endif
145 static Eina_Bool on_front(pa_channel_position_t p) {
146     return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_FRONT);
147 }
148
149 static Eina_Bool on_rear(pa_channel_position_t p) {
150     return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_REAR);
151 }
152
153 static void
154 pulse_sink_port_info_free(Pulse_Sink_Port_Info *pi)
155 {
156    if (!pi) return;
157    eina_stringshare_del(pi->name);
158    eina_stringshare_del(pi->description);
159    free(pi);
160 }
161
162 void
163 pulse_sink_free(Pulse_Sink *sink)
164 {
165    Pulse_Sink_Port_Info *pi;
166    if (!sink) return;
167    if (!sink->deleted)
168      {
169         sink->deleted = EINA_TRUE;
170         if (sink->source)
171           {
172              eina_hash_del_by_key(pulse_sources, (uintptr_t*)&sink->index);
173              return;
174           }
175         else
176           {
177              eina_hash_del_by_key(pulse_sinks, (uintptr_t*)&sink->index);
178              return;
179           }
180      }
181    eina_stringshare_del(sink->name);
182    eina_stringshare_del(sink->description);
183    EINA_LIST_FREE(sink->ports, pi)
184      pulse_sink_port_info_free(pi);
185    eina_stringshare_del(sink->active_port);
186    free(sink);
187 }
188
189 const Eina_List *
190 pulse_sink_ports_get(Pulse_Sink *sink)
191 {
192    EINA_SAFETY_ON_NULL_RETURN_VAL(sink, NULL);
193    return sink->ports;
194 }
195
196 const char *
197 pulse_sink_port_active_get(Pulse_Sink *sink)
198 {
199    EINA_SAFETY_ON_NULL_RETURN_VAL(sink, NULL);
200    return sink->active_port;
201 }
202
203 const char *
204 pulse_sink_name_get(Pulse_Sink *sink)
205 {
206    EINA_SAFETY_ON_NULL_RETURN_VAL(sink, NULL);
207
208    return sink->name;
209 }
210
211 const char *
212 pulse_sink_desc_get(Pulse_Sink *sink)
213 {
214    EINA_SAFETY_ON_NULL_RETURN_VAL(sink, NULL);
215
216    return sink->description;
217 }
218
219 uint32_t
220 pulse_sink_idx_get(Pulse_Sink *sink)
221 {
222    EINA_SAFETY_ON_NULL_RETURN_VAL(sink, 0);
223
224    return sink->index;
225 }
226
227 Eina_Bool
228 pulse_sink_muted_get(Pulse_Sink *sink)
229 {
230    EINA_SAFETY_ON_NULL_RETURN_VAL(sink, EINA_FALSE);
231
232    return sink->mute;
233 }
234
235 uint8_t
236 pulse_sink_channels_count(Pulse_Sink *sink)
237 {
238    EINA_SAFETY_ON_NULL_RETURN_VAL(sink, 0);
239
240    return sink->volume.channels;
241 }
242
243 double
244 pulse_sink_avg_get_pct(Pulse_Sink *sink)
245 {
246    double avg;
247    int x;
248
249    EINA_SAFETY_ON_NULL_RETURN_VAL(sink, -1.0);
250
251    for (avg = 0, x = 0; x < sink->volume.channels; x++)
252      avg += sink->volume.values[x];
253    avg /= sink->volume.channels;
254
255    if (avg <= PA_VOLUME_MUTED) return 0.0;
256
257    if (avg == PA_VOLUME_NORM) return 100.0;
258
259    return (avg * 100 + PA_VOLUME_NORM / 2) / PA_VOLUME_NORM;
260 }
261
262 Eina_List *
263 pulse_sink_channel_names_get(Pulse_Sink *sink)
264 {
265    Eina_List *ret = NULL;
266    unsigned int x;
267    
268    EINA_SAFETY_ON_NULL_RETURN_VAL(sink, NULL);
269    for (x = 0; x < sink->volume.channels; x++)
270       ret = eina_list_append(ret, pulse_sink_channel_id_get_name(sink, x));
271    return ret;
272 }
273
274 unsigned int
275 pulse_sink_channel_name_get_id(Pulse_Sink *sink, const char *name)
276 {
277    unsigned int x;
278    
279    EINA_SAFETY_ON_NULL_RETURN_VAL(sink, UINT_MAX);
280    EINA_SAFETY_ON_NULL_RETURN_VAL(name, UINT_MAX);
281    for (x = 0; x < sink->channel_map.channels; x++)
282      {
283         if (!strcmp(name, channel_name_table[sink->channel_map.map[x]]))
284            return x;
285      }
286    return UINT_MAX;
287 }
288
289 const char *
290 pulse_sink_channel_id_get_name(Pulse_Sink *sink, unsigned int id)
291 {
292    EINA_SAFETY_ON_NULL_RETURN_VAL(sink, NULL);
293    EINA_SAFETY_ON_TRUE_RETURN_VAL(id >= sink->channel_map.channels, NULL);
294    return eina_stringshare_add(channel_name_table[sink->channel_map.map[id]]);
295 }
296
297 double
298 pulse_sink_channel_volume_get(Pulse_Sink *sink, unsigned int id)
299 {
300    EINA_SAFETY_ON_NULL_RETURN_VAL(sink, -1);
301    EINA_SAFETY_ON_TRUE_RETURN_VAL(id >= sink->channel_map.channels, -1);
302    return (sink->volume.values[id] * 100 + PA_VOLUME_NORM / 2) / PA_VOLUME_NORM;
303 }
304
305 float
306 pulse_sink_channel_balance_get(Pulse_Sink *sink, unsigned int id)
307 {
308    EINA_SAFETY_ON_NULL_RETURN_VAL(sink, -1.0);
309    EINA_SAFETY_ON_TRUE_RETURN_VAL(id >= sink->channel_map.channels, -1.0);
310
311    if (on_left(sink->channel_map.map[id])) return 0.0;
312    if (on_right(sink->channel_map.map[id])) return 1.0;
313    return 0.5;
314 }
315
316 float
317 pulse_sink_channel_depth_get(Pulse_Sink *sink, unsigned int id)
318 {
319    EINA_SAFETY_ON_NULL_RETURN_VAL(sink, -1.0);
320    EINA_SAFETY_ON_TRUE_RETURN_VAL(id >= sink->channel_map.channels, -1.0);
321
322    if (on_rear(sink->channel_map.map[id])) return 0.0;
323    if (on_front(sink->channel_map.map[id])) return 1.0;
324    return 0.5;
325 }
326
327 float
328 pulse_sink_balance_get(Pulse_Sink *sink)
329 {
330     int c;
331     float l, r;
332     pa_volume_t left = 0, right = 0;
333     unsigned n_left = 0, n_right = 0;
334
335     for (c = 0; c < sink->channel_map.channels; c++) {
336         if (on_left(sink->channel_map.map[c])) {
337             left += sink->volume.values[c];
338             n_left++;
339         } else if (on_right(sink->channel_map.map[c])) {
340             right += sink->volume.values[c];
341             n_right++;
342         }
343     }
344
345     if (n_left <= 0)
346         l = PA_VOLUME_NORM;
347     else
348         l = left / n_left;
349
350     if (n_right <= 0)
351         r = PA_VOLUME_NORM;
352     else
353         r = right / n_right;
354     l /= (float)PA_VOLUME_NORM;
355     r /= (float)PA_VOLUME_NORM;
356     return r - l;
357 }