mm_sound_plugin_codec_wave: Set client pid to PulseAudio property
[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         int source_type;
49 } mm_sound_handle_t;
50
51 static struct {
52         uint32_t handle_count;  /* use amotic operations */
53         GList *handles;
54         pthread_mutex_t lock;
55
56         int state;
57         pa_threaded_mainloop *mainloop;
58         pa_context *context;
59 } mm_sound_handle_mgr;
60
61 #define CHECK_HANDLE_RANGE(x) \
62         do { \
63                 if (x == 0) { \
64                         debug_msg("invalid handle(%d)", x); \
65                         return MM_ERROR_INVALID_ARGUMENT; \
66                 } \
67         } while (0);
68
69 #define ATOMIC_INC(l, x) \
70         do { \
71                 pthread_mutex_lock(l); \
72                 x = x + 1; \
73                 if (x == 0) \
74                 x = x + 1; \
75                 pthread_mutex_unlock(l); \
76         } while (0);
77
78 // phandle(ret), GList, userdata, coimpare func
79 #define GET_HANDLE_DATA(p, l, u, func) \
80         do { \
81                 GList* list = 0; \
82                 list = g_list_find_custom(l, u, func); \
83                 if (list != 0) \
84                         p = (mm_sound_handle_t*)list->data; \
85                 else \
86                         p = NULL; \
87         } while (0);
88
89 #define PA_SIMPLE_SAMPLES_PER_PERIOD_DEFAULT                            1536    /* frames */
90 #define PA_SIMPLE_PERIODS_PER_BUFFER_FASTMODE                           4
91 #define PA_SIMPLE_PERIODS_PER_BUFFER_DEFAULT                            6
92 #define PA_SIMPLE_PERIODS_PER_BUFFER_VOIP                                       2
93 #define PA_SIMPLE_PERIODS_PER_BUFFER_PLAYBACK                           8
94 #define PA_SIMPLE_PERIODS_PER_BUFFER_CAPTURE                            12
95 #define PA_SIMPLE_PERIODS_PER_BUFFER_VIDEO                                      10
96
97 #define PA_SIMPLE_PERIOD_TIME_FOR_ULOW_LATENCY_MSEC                     20
98 #define PA_SIMPLE_PERIOD_TIME_FOR_LOW_LATENCY_MSEC                      25
99 #define PA_SIMPLE_PERIOD_TIME_FOR_MID_LATENCY_MSEC                      50
100 #define PA_SIMPLE_PERIOD_TIME_FOR_HIGH_LATENCY_MSEC                     75
101 #define PA_SIMPLE_PERIOD_TIME_FOR_VOIP_LATENCY_MSEC                     20
102
103 __attribute__ ((constructor))
104 void __mm_sound_pa_init(void)
105 {
106         memset(&mm_sound_handle_mgr, 0, sizeof(mm_sound_handle_mgr));
107         mm_sound_handle_mgr.state = FALSE;
108
109         mm_sound_handle_mgr.handles = g_list_alloc();
110         mm_sound_handle_mgr.handle_count = 1;
111         pthread_mutex_init(&mm_sound_handle_mgr.lock, NULL);
112 }
113
114 __attribute__ ((destructor))
115 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(%p),  context(%p)", 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,
146                                         int *size, char *stream_type, int stream_index)
147 {
148         pa_simple *s = NULL;
149         pa_channel_map maps;
150         pa_buffer_attr attr;
151
152         int prop_vol_type = 0;
153         int prop_gain_type = VOLUME_GAIN_DEFAULT;
154
155         int err = MM_ERROR_SOUND_INTERNAL;
156         int period_time = PA_SIMPLE_PERIOD_TIME_FOR_MID_LATENCY_MSEC;
157         int samples_per_period = PA_SIMPLE_SAMPLES_PER_PERIOD_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         if (stream_index != -1) {
189                 char stream_index_s[11];
190                 debug_msg("Set stream index [%d]", stream_index);
191
192                 snprintf(stream_index_s, sizeof(stream_index_s) - 1, "%d", stream_index);
193                 debug_msg("stream_index[%d] converted to string[%s]", stream_index, stream_index_s);
194                 pa_proplist_sets(proplist, PA_PROP_MEDIA_PARENT_ID, stream_index_s);
195         }
196         /* Set stream type */
197         pa_proplist_sets(proplist, PA_PROP_MEDIA_ROLE, stream_type);
198
199         memset(&attr, '\0', sizeof(attr));
200
201         switch (handle_mode) {
202         case HANDLE_MODE_OUTPUT:
203                 period_time = PA_SIMPLE_PERIOD_TIME_FOR_MID_LATENCY_MSEC;
204                 samples_per_period = (ss->rate * period_time) / 1000;
205                 attr.prebuf = -1;
206                 attr.minreq = -1;
207                 attr.tlength = (ss->rate / 10) * pa_sample_size(ss) * ss->channels;
208                 attr.maxlength = -1;
209                 attr.fragsize = 0;
210
211                 s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_PLAYBACK, NULL, "PLAYBACK", ss, channel_map, &attr,
212                                                                    proplist, &err);
213                 break;
214
215         default:
216                 err = MM_ERROR_SOUND_INTERNAL;
217                 goto fail;
218                 break;
219         }
220
221         if (!s) {
222                 debug_error("Open pulseaudio handle has failed - %s", pa_strerror(err));
223                 if (!strncmp(pa_strerror(err), "Access denied by security check", strlen(pa_strerror(err))))
224                         err = MM_ERROR_SOUND_PERMISSION_DENIED;
225                 else
226                         err = MM_ERROR_SOUND_INTERNAL;
227                 goto fail;
228         }
229
230         handle = (mm_sound_handle_t *) malloc(sizeof(mm_sound_handle_t));
231         memset(handle, 0, sizeof(mm_sound_handle_t));
232         handle->mode = mode;
233         handle->volume_type = prop_vol_type;
234         handle->gain_type = prop_gain_type;
235         handle->rate = ss->rate;
236         handle->channels = ss->channels;
237         handle->s = s;
238         handle->period = samples_per_period * sample_size;
239         *size = handle->period;
240         handle->handle = mm_sound_handle_mgr.handle_count;
241         ATOMIC_INC(&mm_sound_handle_mgr.lock, mm_sound_handle_mgr.handle_count);        // 0 is not used
242
243         mm_sound_handle_mgr.handles = g_list_append(mm_sound_handle_mgr.handles, handle);
244
245         if (handle->handle == 0) {
246                 debug_msg("out of range. handle(%d)", handle->handle);
247                 goto fail;
248         }
249
250         debug_msg
251                 ("created handle[%d]. mode(%d), volumetype(%d), gain(%d), rate(%d), channels(%d), format(%d), s(%p), source_type(%d)",
252                  handle->handle, handle->mode, handle->volume_type, handle->gain_type, handle->rate, handle->channels, ss->format,
253                  handle->s, handle->source_type);
254
255         if (proplist)
256                 pa_proplist_free(proplist);
257
258         return handle->handle;
259
260  fail:
261         if (proplist)
262                 pa_proplist_free(proplist);
263
264         if (handle)
265                 free(handle);
266
267         return err;
268
269 }
270
271 EXPORT_API
272 int mm_sound_pa_write(const int handle, void *buf, const int size)
273 {
274         mm_sound_handle_t *phandle = NULL;
275         int err = MM_ERROR_NONE;
276
277         if (buf == NULL)
278                 return MM_ERROR_INVALID_ARGUMENT;
279
280         if (size < 0)
281                 return MM_ERROR_INVALID_ARGUMENT;
282         else if (size == 0)
283                 return MM_ERROR_NONE;
284
285         CHECK_HANDLE_RANGE(handle);
286         GET_HANDLE_DATA(phandle, mm_sound_handle_mgr.handles, &handle, __mm_sound_handle_comparefunc);
287
288         if (phandle == NULL) {
289                 debug_msg("phandle is null");
290                 return MM_ERROR_SOUND_INTERNAL;
291         }
292
293         if (0 > pa_simple_write(phandle->s, buf, size, &err)) {
294                 debug_error("pa_simple_write() failed with %s", pa_strerror(err));
295                 return MM_ERROR_SOUND_INTERNAL;
296         }
297
298         return size;
299
300 }
301
302 EXPORT_API
303 int mm_sound_pa_close(const int handle)
304 {
305         mm_sound_handle_t *phandle = NULL;
306         int err = MM_ERROR_NONE;
307
308         CHECK_HANDLE_RANGE(handle);
309         GET_HANDLE_DATA(phandle, mm_sound_handle_mgr.handles, &handle, __mm_sound_handle_comparefunc);
310         if (phandle == NULL) {
311                 debug_msg("phandle is null");
312                 return MM_ERROR_SOUND_INTERNAL;
313         }
314
315         debug_msg("phandle(%p) s(%p), handle(%d), rate(%d), ch(%d)",
316                           phandle, phandle->s, phandle->handle, phandle->rate, phandle->channels);
317
318         switch (phandle->mode) {
319         case HANDLE_MODE_OUTPUT:
320                 if (0 > pa_simple_flush(phandle->s, &err)) {
321                         err = MM_ERROR_SOUND_INTERNAL;
322                         debug_msg("pa_simple_flush() failed with %s", pa_strerror(err));
323                 }
324                 break;
325         default:
326                 break;
327         }
328
329         pa_simple_free(phandle->s);
330         phandle->s = NULL;
331
332         debug_msg("leave: handle[%d]", handle);
333
334         mm_sound_handle_mgr.handles = g_list_remove(mm_sound_handle_mgr.handles, phandle);
335         if (phandle != NULL) {
336                 free(phandle);
337                 phandle = NULL;
338         }
339
340         return err;
341
342 }
343
344 EXPORT_API
345 int mm_sound_pa_drain(const int handle)
346 {
347         mm_sound_handle_t *phandle = NULL;
348         int err = MM_ERROR_NONE;
349
350         CHECK_HANDLE_RANGE(handle);
351         GET_HANDLE_DATA(phandle, mm_sound_handle_mgr.handles, &handle, __mm_sound_handle_comparefunc);
352         if (phandle == NULL)
353                 return MM_ERROR_SOUND_INTERNAL;
354
355         if (0 > pa_simple_drain(phandle->s, &err)) {
356                 debug_error("pa_simple_drain() failed with %s", pa_strerror(err));
357                 err = MM_ERROR_SOUND_INTERNAL;
358         }
359
360         return err;
361 }