tizen beta release
[platform/core/multimedia/avsystem.git] / avsys-audio-pasimple.c
1 /*
2  * avsystem
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Jonghyuk Choi <jhchoi.choi@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 <stdlib.h>
23 #include <string.h>
24
25 #include "avsys-audio-pasimple.h"
26 #include "avsys-types.h"
27 #include "avsys-error.h"
28 #include "avsys-debug.h"
29
30 #define PA_SIMPLE_SAMPLES_PER_PERIOD_DEFAULT                            1536    /* frames */
31 #define PA_SIMPLE_PERIODS_PER_BUFFER_FASTMODE                           4
32 #define PA_SIMPLE_PERIODS_PER_BUFFER_DEFAULT                            6
33 #define PA_SIMPLE_PERIODS_PER_BUFFER_PLAYBACK                           8
34 #define PA_SIMPLE_PERIODS_PER_BUFFER_CAPTURE                            12
35 #define PA_SIMPLE_PERIODS_PER_BUFFER_VIDEO                                      10
36
37 #define PA_SIMPLE_PERIOD_TIME_FOR_ULOW_LATENCY_MSEC                     20
38 #define PA_SIMPLE_PERIOD_TIME_FOR_LOW_LATENCY_MSEC                      25
39 #define PA_SIMPLE_PERIOD_TIME_FOR_MID_LATENCY_MSEC                      50
40 #define PA_SIMPLE_PERIOD_TIME_FOR_HIGH_LATENCY_MSEC                     75
41
42 #define MSEC_TO_SAMPLE(samplerate,period_time)          (samplerate*period_time/1000)
43
44 #define CHECK_VALID_HANDLE(handle) \
45 do { \
46         if (handle == NULL) { \
47                 return AVSYS_STATE_ERR_NULL_POINTER; \
48         } \
49         device = (avsys_audio_pasimple_handle_t *)handle->device; \
50                 if (device == NULL) { \
51                         return AVSYS_STATE_ERR_NULL_POINTER; \
52                 } \
53         if (device->pasimple_handle == NULL) { \
54                 return AVSYS_STATE_ERR_NULL_POINTER; \
55         } \
56 } while (0)
57
58 #define SET_PA_ATTR(pt,spp,ppb,pb,mr,tl,ml,fs)  \
59 do { \
60         period_time = pt; \
61         samples_per_period = spp; \
62         periods_per_buffer = ppb; \
63         attr.prebuf = pb; \
64         attr.minreq = mr; \
65         attr.tlength = tl; \
66         attr.maxlength = ml; \
67         attr.fragsize = fs; \
68 } while (0)
69
70 int avsys_audio_pasimple_open_device(const int mode, const unsigned int format, const unsigned int channel, const unsigned int samplerate, avsys_audio_handle_t *handle, int policy)
71 {
72         pa_simple *s = NULL;
73         pa_sample_spec ss;
74         avsys_audio_pasimple_handle_t *device = NULL;
75         pa_buffer_attr attr;
76         int err = AVSYS_STATE_SUCCESS;
77         int period_time = PA_SIMPLE_PERIOD_TIME_FOR_MID_LATENCY_MSEC;
78
79         int samples_per_period = PA_SIMPLE_SAMPLES_PER_PERIOD_DEFAULT;
80         int periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_DEFAULT;
81
82         avsys_info(AVAUDIO, ">>>[%s] mode=%d, format=%d, channel=%d, samplerate=%d\n", __func__, mode, format, channel, samplerate);
83         avsys_assert(handle != NULL);
84
85         if (channel < 1 || channel > 2)
86                 return AVSYS_STATE_ERR_DEVICE_NOT_SUPPORT;
87
88         device = (avsys_audio_pasimple_handle_t *)malloc(sizeof(avsys_audio_pasimple_handle_t));
89         if (device == NULL) {
90                 avsys_critical(AVAUDIO, "PA Simple handle alloc fail\n");
91                 return AVSYS_STATE_ERR_ALLOCATION;
92         }
93
94         ss.rate = samplerate;
95         ss.channels = channel;
96
97         switch (format) {
98         case AVSYS_AUDIO_FORMAT_8BIT:
99                 ss.format = PA_SAMPLE_U8;
100                 device->samplesize = 1 * channel;
101                 break;
102         case AVSYS_AUDIO_FORMAT_16BIT:
103
104                 ss.format = PA_SAMPLE_S16LE;
105                 device->samplesize = 2 * channel;
106                 break;
107         default:
108                 free(device);
109                 avsys_error(AVAUDIO, "Invalid format\n");
110                 return AVSYS_STATE_ERR_DEVICE_NOT_SUPPORT;
111         }
112         handle->device = (void *)device;
113
114         pa_proplist *proplist = pa_proplist_new();
115
116         /* Set policy property */
117         avsys_info(AVAUDIO, ">>>[%s] policy=[%d], vol_type=[%d]\n", __func__, policy, handle->gain_setting.vol_type);
118         if (policy == AVSYS_AUDIO_HANDLE_ROUTE_HANDSET_ONLY) {
119                 avsys_info(AVAUDIO, ": set media plicy to PHONE\n");
120                 pa_proplist_sets(proplist, PA_PROP_MEDIA_POLICY, "phone");
121         } else {
122                 /* AVSYS_AUDIO_HANDLE_ROUTE_FOLLOWING_POLICY */
123                 /* check stream type (vol type) */
124                 if (handle->gain_setting.vol_type == AVSYS_AUDIO_VOLUME_TYPE_NOTIFICATION ||
125                         handle->gain_setting.vol_type == AVSYS_AUDIO_VOLUME_TYPE_ALARM) {
126                         avsys_info(AVAUDIO, ": set media plicy to ALL\n");
127                         pa_proplist_sets(proplist, PA_PROP_MEDIA_POLICY, "all");
128                 } else {
129                         avsys_info(AVAUDIO, ": set media plicy to AUTO\n");
130                         pa_proplist_sets(proplist, PA_PROP_MEDIA_POLICY, "auto");
131                 }
132         }
133
134         handle->handle_route = policy;
135
136         memset(&attr, '\0', sizeof(attr));
137
138         switch (mode) {
139         case AVSYS_AUDIO_MODE_INPUT:
140                 SET_PA_ATTR(PA_SIMPLE_PERIOD_TIME_FOR_MID_LATENCY_MSEC,
141                                         MSEC_TO_SAMPLE(samplerate,period_time),
142                                         PA_SIMPLE_PERIODS_PER_BUFFER_DEFAULT,
143                                         0, -1, -1, -1, samples_per_period * device->samplesize);
144
145                 s = pa_simple_new_proplist(NULL, "AVSYSTEM", PA_STREAM_RECORD, NULL, "CAPTURE", &ss, NULL, &attr, proplist, &err);
146                 break;
147
148         case AVSYS_AUDIO_MODE_INPUT_LOW_LATENCY:
149                 SET_PA_ATTR(PA_SIMPLE_PERIOD_TIME_FOR_ULOW_LATENCY_MSEC,
150                                         MSEC_TO_SAMPLE(samplerate,period_time),
151                                         PA_SIMPLE_PERIODS_PER_BUFFER_FASTMODE,
152                                         0, -1, -1, -1, samples_per_period * device->samplesize);
153
154                 s = pa_simple_new_proplist(NULL, "AVSYSTEM", PA_STREAM_RECORD, NULL, "LOW LATENCY CAPTURE", &ss, NULL, &attr, proplist, &err);
155                 break;
156
157         case AVSYS_AUDIO_MODE_INPUT_HIGH_LATENCY:
158                 SET_PA_ATTR(PA_SIMPLE_PERIOD_TIME_FOR_HIGH_LATENCY_MSEC,
159                                         MSEC_TO_SAMPLE(samplerate,period_time),
160                                         PA_SIMPLE_PERIODS_PER_BUFFER_CAPTURE,
161                                         0, -1, -1, -1, samples_per_period * device->samplesize);
162
163                 s = pa_simple_new_proplist(NULL, "AVSYSTEM", PA_STREAM_RECORD, NULL, "HIGH LATENCY CAPTURE", &ss, NULL, &attr, proplist, &err);
164                 break;
165
166         case AVSYS_AUDIO_MODE_OUTPUT:   /* mid latency playback for normal audio case. */
167                 SET_PA_ATTR(PA_SIMPLE_PERIOD_TIME_FOR_MID_LATENCY_MSEC,
168                                                 MSEC_TO_SAMPLE(samplerate,period_time),
169                                                 PA_SIMPLE_PERIODS_PER_BUFFER_DEFAULT,
170                                                 -1, -1, periods_per_buffer * samples_per_period * device->samplesize, attr.tlength, 0);
171
172                 s = pa_simple_new_proplist(NULL, "AVSYSTEM", PA_STREAM_PLAYBACK, NULL, "PLAYBACK", &ss, NULL, &attr, proplist, &err);
173                 break;
174
175         case AVSYS_AUDIO_MODE_OUTPUT_LOW_LATENCY:       /* This is special case for touch sound playback */
176                 SET_PA_ATTR(PA_SIMPLE_PERIOD_TIME_FOR_LOW_LATENCY_MSEC,
177                                         MSEC_TO_SAMPLE(samplerate,period_time),
178                                         PA_SIMPLE_PERIODS_PER_BUFFER_FASTMODE,
179                                         samples_per_period * device->samplesize, -1, samples_per_period * device->samplesize + 3430, (uint32_t)-1, 0);
180
181                 s = pa_simple_new_proplist(NULL,"AVSYSTEM", PA_STREAM_PLAYBACK, NULL, "LOW LATENCY PLAYBACK", &ss, NULL, &attr, proplist, &err);
182                 break;
183         case AVSYS_AUDIO_MODE_OUTPUT_CLOCK: /* high latency playback - lager buffer size */
184                 SET_PA_ATTR(PA_SIMPLE_PERIOD_TIME_FOR_HIGH_LATENCY_MSEC,
185                                         MSEC_TO_SAMPLE(samplerate,period_time),
186                                         PA_SIMPLE_PERIODS_PER_BUFFER_PLAYBACK,
187                                         (uint32_t) -1, (uint32_t) -1, periods_per_buffer * samples_per_period * device->samplesize, (uint32_t)-1, 0);
188
189                 s = pa_simple_new_proplist(NULL, "AVSYSTEM", PA_STREAM_PLAYBACK, NULL, "HIGH LATENCY PLAYBACK", &ss, NULL, &attr, proplist, &err);
190                 break;
191
192         case AVSYS_AUDIO_MODE_OUTPUT_VIDEO:     /* low latency playback */
193                 SET_PA_ATTR(PA_SIMPLE_PERIOD_TIME_FOR_LOW_LATENCY_MSEC,
194                                         MSEC_TO_SAMPLE(samplerate,period_time),
195                                         PA_SIMPLE_PERIODS_PER_BUFFER_VIDEO,
196                                         4*(samples_per_period * device->samplesize), samples_per_period * device->samplesize, periods_per_buffer * samples_per_period * device->samplesize, (uint32_t)-1, 0);
197
198                 s = pa_simple_new_proplist(NULL, "AVSYSTEM", PA_STREAM_PLAYBACK, NULL, "LOW LATENCY PLAYBACK", &ss, NULL, &attr, proplist, &err);
199                 break;
200
201         case AVSYS_AUDIO_MODE_OUTPUT_AP_CALL:
202 #if defined(_MMFW_I386_ALL_SIMULATOR)
203                 avsys_warning(AVAUDIO, "Does not support AP call mode at i386 simulator\n");
204                 s = NULL;
205 #else
206                 SET_PA_ATTR(PA_SIMPLE_PERIOD_TIME_FOR_LOW_LATENCY_MSEC,
207                                         MSEC_TO_SAMPLE(samplerate,period_time),
208                                         PA_SIMPLE_PERIODS_PER_BUFFER_DEFAULT,
209                                         (uint32_t) -1, (uint32_t) -1, periods_per_buffer * samples_per_period * device->samplesize, attr.tlength, 0);
210
211
212                 s = pa_simple_new_proplist(NULL, "AVSYSTEM", PA_STREAM_PLAYBACK, NULL, "VoIP PLAYBACK", &ss, NULL, &attr, proplist, &err);
213 #endif
214                 break;
215         case AVSYS_AUDIO_MODE_INPUT_AP_CALL:
216 #if defined(_MMFW_I386_ALL_SIMULATOR)
217                 avsys_warning(AVAUDIO, "Does not support AP call mode at i386 simulator\n");
218                 s = NULL;
219 #else
220                 SET_PA_ATTR(PA_SIMPLE_PERIOD_TIME_FOR_LOW_LATENCY_MSEC,
221                                         MSEC_TO_SAMPLE(samplerate,period_time),
222                                         PA_SIMPLE_PERIODS_PER_BUFFER_DEFAULT,
223                                         0, (uint32_t) -1, (uint32_t) -1, (uint32_t) -1, samples_per_period * device->samplesize);
224
225                 s = pa_simple_new_proplist(NULL, "AVSYSTEM", PA_STREAM_RECORD, NULL, "VoIP CAPTURE", &ss, NULL, &attr, proplist, &err);
226 #endif
227                 break;
228         case AVSYS_AUDIO_MODE_CALL_OUT:
229         case AVSYS_AUDIO_MODE_CALL_IN:
230                 //TODO
231                 avsys_error(AVAUDIO, "Does not support call device handling\n");
232                 avsys_assert_r(0);
233                 break;
234         default:
235                 avsys_critical_r(AVAUDIO, "Invalid open mode %d\n", mode);
236                 avsys_assert_r(0);
237                 return AVSYS_STATE_ERR_INVALID_MODE;
238                 break;
239         }
240
241         if (!s) {
242                 avsys_error_r(AVAUDIO, "Open pulseaudio handle has failed - %s\n", pa_strerror(err));
243                 err = AVSYS_STATE_ERR_INTERNAL;
244                 goto fail;
245         }
246
247         avsys_info(AVAUDIO, "Samples(per period) : %d\t Periods(per buffer) : %d\n", samples_per_period, periods_per_buffer);
248
249         device->pasimple_handle = (void *)s;
250         device->mode = mode;
251         device->period_frames = samples_per_period;
252         device->buffer_frames = periods_per_buffer * device->period_frames;
253         device->periods_per_buffer = periods_per_buffer;
254         handle->period = device->period_frames * device->samplesize;
255         handle->msec_per_period = period_time;
256         if (0 > pa_simple_get_stream_index(s, &handle->stream_index, &err)) {
257                 avsys_error(AVAUDIO, "Can not get stream index %s\n", pa_strerror(err));
258                 err = AVSYS_STATE_ERR_INVALID_HANDLE;
259         }
260
261 fail:
262         if (proplist)
263                 pa_proplist_free(proplist);
264
265         return err;
266 }
267
268 int avsys_audio_pasimple_close_device(avsys_audio_handle_t *handle)
269 {
270         int err = 0;
271         avsys_audio_pasimple_handle_t *device = NULL;
272         pa_simple *s = NULL;
273
274         avsys_info(AVAUDIO, "%s\n", __func__);
275
276         avsys_assert(handle != NULL);
277         CHECK_VALID_HANDLE(handle);
278
279         switch (handle->mode) {
280         case AVSYS_AUDIO_MODE_CALL_OUT:
281         case AVSYS_AUDIO_MODE_CALL_IN:
282                 avsys_warning(AVAUDIO, "Unsupported close mode in pa function\n");
283                 return AVSYS_STATE_ERR_INVALID_MODE;
284         case AVSYS_AUDIO_MODE_OUTPUT_AP_CALL:
285         case AVSYS_AUDIO_MODE_INPUT_AP_CALL:
286 #if defined(_MMFW_I386_ALL_SIMULATOR)
287                 avsys_warning(AVAUDIO, "Skip close call device in SDK");
288                 return AVSYS_STATE_SUCCESS;
289 #endif
290         default:
291                 break;
292         }
293
294         s = (pa_simple *)device->pasimple_handle;
295         avsys_assert(s != NULL);
296
297         switch (handle->mode) {
298         case AVSYS_AUDIO_MODE_OUTPUT:
299         case AVSYS_AUDIO_MODE_OUTPUT_CLOCK:
300         case AVSYS_AUDIO_MODE_OUTPUT_LOW_LATENCY:
301         case AVSYS_AUDIO_MODE_OUTPUT_AP_CALL:
302         case AVSYS_AUDIO_MODE_OUTPUT_VIDEO:
303                 if (0 > pa_simple_flush(s, &err)) {
304                         avsys_error(AVAUDIO, "pa_simple_flush() failed with %s\n", pa_strerror(err));
305                 }
306                 break;
307         default:
308                 break;
309         }
310
311         pa_simple_free(s);
312
313         device->pasimple_handle = NULL;
314         free(device);
315
316         return AVSYS_STATE_SUCCESS;
317 }
318
319 int avsys_audio_pasimple_write(avsys_audio_handle_t *handle, const void *buf, int size)
320 {
321         pa_simple *s = NULL;
322         avsys_audio_pasimple_handle_t *device = NULL;
323         int err = 0;
324
325         if (buf == NULL)
326                         return AVSYS_STATE_ERR_NULL_POINTER;
327         CHECK_VALID_HANDLE(handle);
328
329         if (size < 0)
330                 return AVSYS_STATE_ERR_INVALID_PARAMETER;
331         else if (size == 0)
332                 return 0;
333
334         s = (pa_simple *)device->pasimple_handle;
335
336         if (0 > pa_simple_write(s, buf, size, &err)) {
337                 avsys_error(AVAUDIO, "pa_simple_write() failed with %s\n", pa_strerror(err));
338                 return AVSYS_STATE_ERR_INTERNAL;
339         }
340
341         return size;
342 }
343
344 int avsys_audio_pasimple_read(avsys_audio_handle_t *handle, void *buf, int size)
345 {
346         pa_simple *s = NULL;
347         avsys_audio_pasimple_handle_t *device = NULL;
348         int err = 0;
349
350         if (buf == NULL)
351                         return AVSYS_STATE_ERR_NULL_POINTER;
352         CHECK_VALID_HANDLE(handle);
353
354         if (size < 0)
355                 return AVSYS_STATE_ERR_INVALID_PARAMETER;
356         else if (size == 0)
357                 return 0;
358
359         s = (pa_simple *)device->pasimple_handle;
360
361         if (0 > pa_simple_read(s, buf, size, &err)) {
362                 avsys_error(AVAUDIO, "pa_simple_read() failed with %s\n", pa_strerror(err));
363                 return AVSYS_STATE_ERR_INTERNAL;
364         }
365
366         return size;
367 }
368
369 int avsys_audio_pasimple_reset(avsys_audio_handle_t *handle)
370 {
371         pa_simple *s = NULL;
372         avsys_audio_pasimple_handle_t *device = NULL;
373         int err = 0;
374
375         CHECK_VALID_HANDLE(handle);
376
377         if (handle->mode == AVSYS_AUDIO_MODE_INPUT || handle->mode == AVSYS_AUDIO_MODE_INPUT_LOW_LATENCY) {
378                 avsys_warning(AVAUDIO, "Skip pa_simple_flush() when input mode\n");
379                 return AVSYS_STATE_SUCCESS;
380         }
381
382         s = (pa_simple *)device->pasimple_handle;
383
384         if (0 > pa_simple_flush(s, &err)) {
385                 avsys_error(AVAUDIO, "pa_simple_flush() failed with %s\n", pa_strerror(err));
386                 return AVSYS_STATE_ERR_INTERNAL;
387         }
388
389         return AVSYS_STATE_SUCCESS;
390 }
391
392 int avsys_audio_pasimple_drain(avsys_audio_handle_t *handle)
393 {
394         pa_simple *s = NULL;
395         avsys_audio_pasimple_handle_t *device = NULL;
396         int err = 0;
397
398         CHECK_VALID_HANDLE(handle);
399
400         s = (pa_simple *)device->pasimple_handle;
401
402         if (0 > pa_simple_drain(s, &err)) {
403                 avsys_error(AVAUDIO, "pa_simple_drain() failed with %s\n", pa_strerror(err));
404                 return AVSYS_STATE_ERR_INTERNAL;
405         }
406
407         return AVSYS_STATE_SUCCESS;
408 }
409
410 int avsys_audio_pasimple_set_volume(avsys_audio_handle_t *handle, int volume)
411 {
412         pa_simple *s = NULL;
413         avsys_audio_pasimple_handle_t *device = NULL;
414         int err = 0;
415
416         CHECK_VALID_HANDLE(handle);
417
418         s = (pa_simple *)device->pasimple_handle;
419
420         if (0 > pa_simple_set_volume(s, volume, &err)) {
421                 avsys_error(AVAUDIO, "pa_simple_set_volume() failed with %s\n", pa_strerror(err));
422                 return AVSYS_STATE_ERR_INTERNAL;
423         }
424
425         return AVSYS_STATE_SUCCESS;
426 }
427
428 #define USEC_TO_SAMPLE(usec, rate)      ((usec*rate)/1000000)
429 #define SAMPLES_TO_USEC(samples,rate)   ((samples*1000000)/rate)
430 #define BYTES_TO_USEC(bytes,size_per_sample,rate)       ((bytes*1000000)/(size_per_sample*rate))
431
432 int avsys_audio_pasimple_delay(avsys_audio_handle_t *handle, int *delay)
433 {
434         pa_simple *s = NULL;
435         avsys_audio_pasimple_handle_t *device = NULL;
436         int err = 0;
437         pa_usec_t latency_time = 0;
438         unsigned int latency_frames = 0;
439
440         if (delay == NULL) {
441                 return AVSYS_STATE_ERR_NULL_POINTER;
442         }
443         CHECK_VALID_HANDLE(handle);
444
445         s = (pa_simple *)device->pasimple_handle;
446
447         latency_time = pa_simple_get_latency(s, &err);
448         if (err > 0 && latency_time == 0) {
449                 avsys_error(AVAUDIO, "pa_simple_get_latency() failed with %s\n", pa_strerror(err));
450                 return AVSYS_STATE_ERR_INTERNAL;
451         }
452         /* convert time to sample */
453         latency_frames = USEC_TO_SAMPLE(latency_time, handle->samplerate);
454         *delay = latency_frames;
455
456         return AVSYS_STATE_SUCCESS;
457 }
458
459 int avsys_audio_pasimple_get_period_buffer_time(avsys_audio_handle_t *handle, unsigned int *period_time, unsigned int *buffer_time)
460 {
461         avsys_audio_pasimple_handle_t *device = NULL;
462
463         if ((period_time == NULL) || (buffer_time == NULL))
464                 return AVSYS_STATE_ERR_INTERNAL;
465
466         CHECK_VALID_HANDLE(handle);
467
468         *period_time = SAMPLES_TO_USEC(device->period_frames,handle->samplerate);
469         *buffer_time = *period_time * device->periods_per_buffer;
470
471         avsys_info(AVAUDIO, "[%s][%d] period = %d, buffer = %d\n", __func__, __LINE__, *period_time, *buffer_time);
472
473         return AVSYS_STATE_SUCCESS;
474 }
475