focus_server: Fix bug regarding update of reacquisition information within focus...
[platform/core/multimedia/libmm-sound.git] / mm_sound_pa_client.c
1 /*
2  * libmm-sound
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Seungbae Shin <seungbae.shin@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include <mm_error.h>
27 #include <mm_debug.h>
28
29 #include <mm_sound_pa_client.h>
30
31 #include <glib.h>
32
33 #define MM_SOUND_CHANNEL_MIN                1
34 #define MM_SOUND_CHANNEL_MAX                6
35
36 typedef struct _mm_sound_handle_t {
37     uint32_t handle;
38
39     int mode;
40     int volume_type;
41     int gain_type;
42     int rate;
43     int channels;
44     pa_simple* s;
45
46     int period; /* open api retrun value.*/
47
48     unsigned int stream_idx;
49     int source_type;
50 } mm_sound_handle_t;
51
52 static struct {
53     uint32_t handle_count; /* use amotic operations */
54     GList* handles;
55     pthread_mutex_t lock;
56
57     int state;
58     pa_threaded_mainloop *mainloop;
59     pa_context *context;
60 } mm_sound_handle_mgr;
61
62 #define CHECK_HANDLE_RANGE(x) \
63     do { \
64         if(x == 0) { \
65             debug_msg("invalid handle(%d)", x); \
66             return MM_ERROR_INVALID_ARGUMENT; \
67         } \
68     } while(0);
69
70 #define ATOMIC_INC(l, x) \
71     do { \
72         pthread_mutex_lock(l); \
73         x = x + 1; \
74         if(x == 0) \
75             x = x + 1; \
76         pthread_mutex_unlock(l); \
77     } while(0);
78
79 // phandle(ret), GList, userdata, coimpare func
80 #define GET_HANDLE_DATA(p, l, u, func) \
81     do { \
82         GList* list = 0; \
83         list = g_list_find_custom(l, u, func); \
84         if(list != 0) \
85             p = (mm_sound_handle_t*)list->data; \
86         else \
87             p = NULL; \
88     } while(0);
89
90
91 #define PA_SIMPLE_SAMPLES_PER_PERIOD_DEFAULT                            1536    /* frames */
92 #define PA_SIMPLE_PERIODS_PER_BUFFER_FASTMODE                           4
93 #define PA_SIMPLE_PERIODS_PER_BUFFER_DEFAULT                            6
94 #define PA_SIMPLE_PERIODS_PER_BUFFER_VOIP                                       2
95 #define PA_SIMPLE_PERIODS_PER_BUFFER_PLAYBACK                           8
96 #define PA_SIMPLE_PERIODS_PER_BUFFER_CAPTURE                            12
97 #define PA_SIMPLE_PERIODS_PER_BUFFER_VIDEO                                      10
98
99 #define PA_SIMPLE_PERIOD_TIME_FOR_ULOW_LATENCY_MSEC                     20
100 #define PA_SIMPLE_PERIOD_TIME_FOR_LOW_LATENCY_MSEC                      25
101 #define PA_SIMPLE_PERIOD_TIME_FOR_MID_LATENCY_MSEC                      50
102 #define PA_SIMPLE_PERIOD_TIME_FOR_HIGH_LATENCY_MSEC                     75
103 #define PA_SIMPLE_PERIOD_TIME_FOR_VOIP_LATENCY_MSEC                     20
104
105 __attribute__ ((constructor)) void __mm_sound_pa_init(void)
106 {
107     memset(&mm_sound_handle_mgr, 0, sizeof(mm_sound_handle_mgr));
108     mm_sound_handle_mgr.state = FALSE;
109
110     mm_sound_handle_mgr.handles = g_list_alloc();
111     mm_sound_handle_mgr.handle_count = 1;
112     pthread_mutex_init(&mm_sound_handle_mgr.lock, NULL);
113 }
114
115 __attribute__ ((destructor)) void __mm_sound_pa_deinit(void)
116 {
117      g_list_free(mm_sound_handle_mgr.handles);
118      pthread_mutex_destroy(&mm_sound_handle_mgr.lock);
119      mm_sound_handle_mgr.handle_count = 0;
120
121     if(mm_sound_handle_mgr.state) {
122         debug_msg("mainloop(%x),  context(%x)", mm_sound_handle_mgr.mainloop, mm_sound_handle_mgr.context);
123         pa_threaded_mainloop_stop(mm_sound_handle_mgr.mainloop);
124         pa_context_disconnect(mm_sound_handle_mgr.context);
125         pa_context_unref(mm_sound_handle_mgr.context);
126         pa_threaded_mainloop_free(mm_sound_handle_mgr.mainloop);
127     }
128 }
129
130 gint __mm_sound_handle_comparefunc(gconstpointer a, gconstpointer b)
131 {
132     mm_sound_handle_t* phandle = (mm_sound_handle_t*)a;
133     int* handle = (int*)b;
134
135     if(phandle == NULL)
136         return -1;
137
138     if(phandle->handle == *handle)
139         return 0;
140     else
141         return -1;
142 }
143
144 EXPORT_API
145 int mm_sound_pa_open(MMSoundHandleMode mode, int volume_config, pa_sample_spec* ss, pa_channel_map* channel_map, int* size, char *stream_type, int stream_index)
146 {
147     pa_simple *s = NULL;
148     pa_channel_map maps;
149     pa_buffer_attr attr;
150
151     int prop_vol_type = 0;
152     int prop_gain_type = VOLUME_GAIN_DEFAULT;
153
154     int err = MM_ERROR_SOUND_INTERNAL;
155     int period_time = PA_SIMPLE_PERIOD_TIME_FOR_MID_LATENCY_MSEC;
156     int samples_per_period = PA_SIMPLE_SAMPLES_PER_PERIOD_DEFAULT;
157     int periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_DEFAULT;
158
159     int handle_mode = mode;
160     int sample_size = 0;
161     pa_proplist *proplist = NULL;
162
163     mm_sound_handle_t* handle = NULL;
164
165     if (ss->channels < MM_SOUND_CHANNEL_MIN || ss->channels > MM_SOUND_CHANNEL_MAX)
166         return MM_ERROR_INVALID_ARGUMENT;
167
168     proplist = pa_proplist_new();
169
170     if(channel_map == NULL) {
171         pa_channel_map_init_auto(&maps, ss->channels, PA_CHANNEL_MAP_ALSA);
172         channel_map = &maps;
173     }
174
175     switch(ss->format) {
176         case PA_SAMPLE_U8:
177             sample_size = 1 * ss->channels;
178             break;
179         case PA_SAMPLE_S16LE:
180             sample_size = 2 * ss->channels;
181             break;
182         default :
183             sample_size = 0;
184             debug_error("Invalid sample size (%d)", sample_size);
185             break;
186     }
187
188     /* Set volume type of stream */
189     if(volume_config > 0) {
190         debug_log("setting gain type");
191         prop_vol_type = 0; /* not used, set it system(0) temporarily */
192
193         /* Set gain type of stream */
194         prop_gain_type = (volume_config >> 8) & 0x000000FF;
195
196         pa_proplist_setf(proplist, PA_PROP_MEDIA_TIZEN_GAIN_TYPE, "%d", prop_gain_type);
197     }
198
199     if (stream_index != -1) {
200         char stream_index_s[11];
201         debug_msg("Set stream index [%d]", stream_index);
202
203         snprintf(stream_index_s, sizeof(stream_index_s)-1, "%d", stream_index);
204         debug_msg("stream_index[%d] converted to string[%s]", stream_index, stream_index_s);
205         pa_proplist_sets(proplist, PA_PROP_MEDIA_PARENT_ID, stream_index_s);
206     }
207     /* Set stream type */
208     pa_proplist_sets(proplist, PA_PROP_MEDIA_ROLE, stream_type);
209
210     memset(&attr, '\0', sizeof(attr));
211
212     switch (handle_mode) {
213     case HANDLE_MODE_INPUT:
214         period_time = PA_SIMPLE_PERIOD_TIME_FOR_MID_LATENCY_MSEC;
215         samples_per_period = (ss->rate * period_time) / 1000;
216         periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_DEFAULT;
217         attr.prebuf = 0;
218         attr.minreq = -1;
219         attr.tlength = -1;
220         attr.maxlength = -1;
221         attr.fragsize = samples_per_period * pa_sample_size(ss);
222
223         s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_RECORD, NULL, "CAPTURE", ss, channel_map, &attr, proplist, &err);
224         break;
225
226     case HANDLE_MODE_INPUT_LOW_LATENCY:
227         period_time = PA_SIMPLE_PERIOD_TIME_FOR_ULOW_LATENCY_MSEC;
228         samples_per_period = (ss->rate * period_time) / 1000;
229         periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_FASTMODE;
230         attr.prebuf = 0;
231         attr.minreq = -1;
232         attr.tlength = -1;
233         attr.maxlength = -1;
234         attr.fragsize = samples_per_period * pa_sample_size(ss);
235
236         s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_RECORD, NULL, "LOW LATENCY CAPTURE", ss, channel_map, &attr, proplist, &err);
237         break;
238
239     case HANDLE_MODE_INPUT_HIGH_LATENCY:
240         period_time = PA_SIMPLE_PERIOD_TIME_FOR_HIGH_LATENCY_MSEC;
241         samples_per_period = (ss->rate * period_time) / 1000;
242         periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_CAPTURE;
243         attr.prebuf = 0;
244         attr.minreq = -1;
245         attr.tlength = -1;
246         attr.maxlength = -1;
247         attr.fragsize = samples_per_period * pa_sample_size(ss);
248
249         s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_RECORD, NULL, "HIGH LATENCY CAPTURE", ss, channel_map, &attr, proplist, &err);
250         break;
251
252     case HANDLE_MODE_OUTPUT:
253         period_time = PA_SIMPLE_PERIOD_TIME_FOR_MID_LATENCY_MSEC;
254         samples_per_period = (ss->rate * period_time) / 1000;
255         periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_DEFAULT;
256         attr.prebuf = -1;
257         attr.minreq = -1;
258         attr.tlength = (ss->rate / 10) * pa_sample_size(ss) * ss->channels;
259         attr.maxlength = -1;
260         attr.fragsize = 0;
261
262         s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_PLAYBACK, NULL, "PLAYBACK", ss, channel_map, &attr, proplist, &err);
263         break;
264
265     case HANDLE_MODE_OUTPUT_LOW_LATENCY:
266         period_time = PA_SIMPLE_PERIOD_TIME_FOR_LOW_LATENCY_MSEC;
267         samples_per_period = (ss->rate * period_time) / 1000;
268         periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_FASTMODE;
269         attr.prebuf = (ss->rate / 100) * pa_sample_size(ss) * ss->channels;
270         attr.minreq = -1;
271         attr.tlength = (ss->rate / 10) * pa_sample_size(ss) * ss->channels;
272         attr.maxlength = -1;
273         attr.fragsize = 0;
274         debug_msg("rate(%d), samplesize(%d), ch(%d) format(%d)", ss->rate, pa_sample_size(ss), ss->channels, ss->format);
275
276         debug_msg("prebuf(%d), minreq(%d), tlength(%d), maxlength(%d), fragsize(%d)", attr.prebuf, attr.minreq, attr.tlength, attr.maxlength, attr.fragsize);
277
278         s = pa_simple_new_proplist(NULL,"MM_SOUND_PA_CLIENT", PA_STREAM_PLAYBACK, NULL, "LOW LATENCY PLAYBACK", ss, channel_map, &attr, proplist, &err);
279         break;
280
281     case HANDLE_MODE_OUTPUT_CLOCK:
282         period_time = PA_SIMPLE_PERIOD_TIME_FOR_HIGH_LATENCY_MSEC;
283         samples_per_period = (ss->rate * period_time) / 1000;
284         periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_PLAYBACK;
285         attr.prebuf = -1;
286         attr.minreq = -1;
287         attr.tlength = (uint32_t)-1;
288         attr.maxlength = -1;
289         attr.fragsize = 0;
290
291         s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_PLAYBACK, NULL, "HIGH LATENCY PLAYBACK", ss, channel_map, &attr, proplist, &err);
292         break;
293
294     case HANDLE_MODE_OUTPUT_VIDEO: /* low latency playback */
295         period_time = PA_SIMPLE_PERIOD_TIME_FOR_LOW_LATENCY_MSEC;
296         samples_per_period = (ss->rate * period_time) / 1000;
297         periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_VIDEO;
298         attr.prebuf = 4*(samples_per_period * pa_sample_size(ss));
299         attr.minreq = samples_per_period * pa_sample_size(ss);
300         attr.tlength = periods_per_buffer * samples_per_period * pa_sample_size(ss);
301         attr.maxlength = -1;
302         attr.fragsize = 0;
303
304         s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_PLAYBACK, NULL, "LOW LATENCY PLAYBACK", ss, channel_map, &attr, proplist, &err);
305         break;
306
307     case HANDLE_MODE_OUTPUT_AP_CALL:
308 #if defined(_MMFW_I386_ALL_SIMULATOR)
309         debug_msg("Does not support AP call mode at i386 simulator");
310         s = NULL;
311 #else
312         period_time = PA_SIMPLE_PERIOD_TIME_FOR_VOIP_LATENCY_MSEC;
313         samples_per_period = (ss->rate * period_time) / 1000;
314         periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_VOIP;
315         attr.prebuf = -1;
316         attr.minreq = pa_usec_to_bytes(20*PA_USEC_PER_MSEC, ss);
317         attr.tlength = pa_usec_to_bytes(100*PA_USEC_PER_MSEC, ss);
318         attr.maxlength = -1;
319         attr.fragsize = 0;
320
321         s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_PLAYBACK, NULL, "VoIP PLAYBACK", ss, channel_map, &attr, proplist, &err);
322 #endif
323         break;
324     case HANDLE_MODE_INPUT_AP_CALL:
325 #if defined(_MMFW_I386_ALL_SIMULATOR)
326         debug_msg("Does not support AP call mode at i386 simulator");
327         s = NULL;
328 #else
329         period_time = PA_SIMPLE_PERIOD_TIME_FOR_VOIP_LATENCY_MSEC;
330         samples_per_period = (ss->rate * period_time) / 1000;
331         periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_VOIP;
332         attr.prebuf = 0;
333         attr.minreq = -1;
334         attr.tlength = -1;
335         attr.maxlength = -1;
336         attr.fragsize = samples_per_period * pa_sample_size(ss);
337
338         s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_RECORD, NULL, "VoIP CAPTURE", ss, channel_map, &attr, proplist, &err);
339 #endif
340         break;
341     default:
342         err = MM_ERROR_SOUND_INTERNAL;
343         goto fail;
344         break;
345     }
346
347     if (!s) {
348         debug_error("Open pulseaudio handle has failed - %s", pa_strerror(err));
349         if (!strncmp(pa_strerror(err), "Access denied by security check",strlen(pa_strerror(err)))) {
350             err = MM_ERROR_SOUND_PERMISSION_DENIED;
351         } else {
352             err = MM_ERROR_SOUND_INTERNAL;
353         }
354         goto fail;
355     }
356
357     handle = (mm_sound_handle_t*)malloc(sizeof(mm_sound_handle_t));
358     memset(handle, 0, sizeof(mm_sound_handle_t));
359     handle->mode = mode;
360     handle->volume_type = prop_vol_type;
361     handle->gain_type = prop_gain_type;
362     handle->rate = ss->rate;
363     handle->channels = ss->channels;
364     handle->s = s;
365     handle->period = samples_per_period * sample_size;
366     *size = handle->period;
367     handle->handle = mm_sound_handle_mgr.handle_count;
368     ATOMIC_INC(&mm_sound_handle_mgr.lock, mm_sound_handle_mgr.handle_count); // 0 is not used
369
370     if (0 > pa_simple_get_stream_index(s, &handle->stream_idx, &err)) {
371         debug_msg("Can not get stream index %s", pa_strerror(err));
372         err = MM_ERROR_SOUND_INTERNAL;
373         goto fail;
374     }
375     mm_sound_handle_mgr.handles = g_list_append(mm_sound_handle_mgr.handles, handle);
376
377     if(handle->handle == 0) {
378         debug_msg("out of range. handle(%d)", handle->handle);
379         goto fail;
380     }
381
382     debug_msg("created handle[%d]. mode(%d), volumetype(%d), gain(%d), rate(%d), channels(%d), format(%d), stream_idx(%d), s(%x), source_type(%d)",
383         handle->handle, handle->mode, handle->volume_type, handle->gain_type,
384         handle->rate, handle->channels, ss->format, handle->stream_idx, handle->s, handle->source_type);
385
386     if (proplist)
387         pa_proplist_free(proplist);
388
389     return handle->handle;
390
391 fail:
392     if (proplist)
393         pa_proplist_free(proplist);
394
395     if(handle)
396         free(handle);
397
398     return err;
399
400 }
401
402 EXPORT_API
403 int mm_sound_pa_write(const int handle, void* buf, const int size)
404 {
405     mm_sound_handle_t* phandle = NULL;
406     int err = MM_ERROR_NONE;
407
408     if (buf == NULL)
409         return MM_ERROR_INVALID_ARGUMENT;
410
411     if (size < 0)
412         return MM_ERROR_INVALID_ARGUMENT;
413     else if (size == 0)
414         return MM_ERROR_NONE;
415
416     CHECK_HANDLE_RANGE(handle);
417     GET_HANDLE_DATA(phandle, mm_sound_handle_mgr.handles, &handle, __mm_sound_handle_comparefunc);
418
419 #ifdef __STREAM_DEBUG__
420     debug_msg("phandle(%x) s(%x), handle(%d), rate(%d), ch(%d) stream_idx(%d), buf(%p), size(%d)",
421         phandle, phandle->s, phandle->handle, phandle->rate, phandle->channels, phandle->stream_idx. buf, size);
422 #endif
423
424     if(phandle == NULL) {
425         debug_msg("phandle is null");
426         return MM_ERROR_SOUND_INTERNAL;
427     }
428
429     if (0 > pa_simple_write(phandle->s, buf, size, &err)) {
430         debug_error("pa_simple_write() failed with %s", pa_strerror(err));
431         return MM_ERROR_SOUND_INTERNAL;
432     }
433
434     return size;
435
436 }
437
438 EXPORT_API
439 int mm_sound_pa_close(const int handle)
440 {
441     mm_sound_handle_t* phandle = NULL;
442     int err = MM_ERROR_NONE;
443
444     CHECK_HANDLE_RANGE(handle);
445     GET_HANDLE_DATA(phandle, mm_sound_handle_mgr.handles, &handle, __mm_sound_handle_comparefunc);
446     if(phandle == NULL) {
447         debug_msg("phandle is null");
448         return MM_ERROR_SOUND_INTERNAL;
449     }
450
451     debug_msg("phandle(%x) s(%x), handle(%d), rate(%d), ch(%d) stream_idx(%d)",
452             phandle, phandle->s, phandle->handle, phandle->rate, phandle->channels, phandle->stream_idx);
453
454         switch (phandle->mode) {
455         case HANDLE_MODE_OUTPUT:
456         case HANDLE_MODE_OUTPUT_CLOCK:
457         case HANDLE_MODE_OUTPUT_LOW_LATENCY:
458         case HANDLE_MODE_OUTPUT_AP_CALL:
459         case HANDLE_MODE_OUTPUT_VIDEO:
460                 if (0 > pa_simple_flush(phandle->s, &err)) {
461             err = MM_ERROR_SOUND_INTERNAL;
462                         debug_msg("pa_simple_flush() failed with %s", pa_strerror(err));
463                 }
464                 break;
465         default:
466                 break;
467         }
468
469         pa_simple_free(phandle->s);
470     phandle->s = NULL;
471
472     debug_msg("leave: handle[%d] stream_index[%d]", handle, phandle->stream_idx);
473
474     mm_sound_handle_mgr.handles = g_list_remove(mm_sound_handle_mgr.handles, phandle);
475     if(phandle != NULL) {
476         free(phandle);
477         phandle = NULL;
478     }
479
480     return err;
481
482 }
483
484 EXPORT_API
485 int mm_sound_pa_drain(const int handle)
486 {
487     mm_sound_handle_t* phandle = NULL;
488     int err = MM_ERROR_NONE;
489
490         CHECK_HANDLE_RANGE(handle);
491     GET_HANDLE_DATA(phandle, mm_sound_handle_mgr.handles, &handle, __mm_sound_handle_comparefunc);
492     if(phandle == NULL)
493         return MM_ERROR_SOUND_INTERNAL;
494
495     if (0 > pa_simple_drain(phandle->s, &err)) {
496                 debug_error("pa_simple_drain() failed with %s", pa_strerror(err));
497                 err = MM_ERROR_SOUND_INTERNAL;
498         }
499
500         return err;
501 }
502