blob: a77340b4a5d93c2a4d1fe5d54f50843f9ab90e00 [file] [log] [blame]
Alexandre Lision8af73cb2013-12-10 14:11:20 -05001/* $Id$ */
2/*
3 * Copyright (C) 2012-2012 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2010-2012 Regis Montoya (aka r3gis - www.r3gis.fr)
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20/* This file is the implementation of Android OpenSL ES audio device.
21 * The original code was originally part of CSipSimple
22 * (http://code.google.com/p/csipsimple/) and was kindly donated
23 * by Regis Montoya.
24 */
25
26#include <pjmedia-audiodev/audiodev_imp.h>
27#include <pj/assert.h>
28#include <pj/log.h>
29#include <pj/os.h>
30#include <pj/string.h>
31#include <pjmedia/errno.h>
32
33#if defined(PJMEDIA_AUDIO_DEV_HAS_OPENSL) && PJMEDIA_AUDIO_DEV_HAS_OPENSL != 0
34
35#include <SLES/OpenSLES.h>
36
37#ifdef __ANDROID__
38 #include <SLES/OpenSLES_Android.h>
39 #include <SLES/OpenSLES_AndroidConfiguration.h>
40 #include <sys/system_properties.h>
41 #include <android/api-level.h>
42
43 #define W_SLBufferQueueItf SLAndroidSimpleBufferQueueItf
44 #define W_SLBufferQueueState SLAndroidSimpleBufferQueueState
45 #define W_SL_IID_BUFFERQUEUE SL_IID_ANDROIDSIMPLEBUFFERQUEUE
46#else
47 #define W_SLBufferQueueItf SLBufferQueueItf
48 #define W_SLBufferQueueState SLBufferQueueState
49 #define W_SL_IID_BUFFERQUEUE SL_IID_BUFFERQUEUE
50#endif
51
52#define THIS_FILE "opensl_dev.c"
53#define DRIVER_NAME "OpenSL"
54
55#define NUM_BUFFERS 2
56
57struct opensl_aud_factory
58{
59 pjmedia_aud_dev_factory base;
60 pj_pool_factory *pf;
61 pj_pool_t *pool;
62
63 SLObjectItf engineObject;
64 SLEngineItf engineEngine;
65 SLObjectItf outputMixObject;
66};
67
68/*
69 * Sound stream descriptor.
70 * This struct may be used for both unidirectional or bidirectional sound
71 * streams.
72 */
73struct opensl_aud_stream
74{
75 pjmedia_aud_stream base;
76 pj_pool_t *pool;
77 pj_str_t name;
78 pjmedia_dir dir;
79 pjmedia_aud_param param;
80
81 void *user_data;
82 pj_bool_t quit_flag;
83 pjmedia_aud_rec_cb rec_cb;
84 pjmedia_aud_play_cb play_cb;
85
86 pj_timestamp play_timestamp;
87 pj_timestamp rec_timestamp;
88
89 pj_bool_t rec_thread_initialized;
90 pj_thread_desc rec_thread_desc;
91 pj_thread_t *rec_thread;
92
93 pj_bool_t play_thread_initialized;
94 pj_thread_desc play_thread_desc;
95 pj_thread_t *play_thread;
96
97 /* Player */
98 SLObjectItf playerObj;
99 SLPlayItf playerPlay;
100 SLVolumeItf playerVol;
101 unsigned playerBufferSize;
102 char *playerBuffer[NUM_BUFFERS];
103 int playerBufIdx;
104
105 /* Recorder */
106 SLObjectItf recordObj;
107 SLRecordItf recordRecord;
108 unsigned recordBufferSize;
109 char *recordBuffer[NUM_BUFFERS];
110 int recordBufIdx;
111
112 W_SLBufferQueueItf playerBufQ;
113 W_SLBufferQueueItf recordBufQ;
114};
115
116/* Factory prototypes */
117static pj_status_t opensl_init(pjmedia_aud_dev_factory *f);
118static pj_status_t opensl_destroy(pjmedia_aud_dev_factory *f);
119static pj_status_t opensl_refresh(pjmedia_aud_dev_factory *f);
120static unsigned opensl_get_dev_count(pjmedia_aud_dev_factory *f);
121static pj_status_t opensl_get_dev_info(pjmedia_aud_dev_factory *f,
122 unsigned index,
123 pjmedia_aud_dev_info *info);
124static pj_status_t opensl_default_param(pjmedia_aud_dev_factory *f,
125 unsigned index,
126 pjmedia_aud_param *param);
127static pj_status_t opensl_create_stream(pjmedia_aud_dev_factory *f,
128 const pjmedia_aud_param *param,
129 pjmedia_aud_rec_cb rec_cb,
130 pjmedia_aud_play_cb play_cb,
131 void *user_data,
132 pjmedia_aud_stream **p_aud_strm);
133
134/* Stream prototypes */
135static pj_status_t strm_get_param(pjmedia_aud_stream *strm,
136 pjmedia_aud_param *param);
137static pj_status_t strm_get_cap(pjmedia_aud_stream *strm,
138 pjmedia_aud_dev_cap cap,
139 void *value);
140static pj_status_t strm_set_cap(pjmedia_aud_stream *strm,
141 pjmedia_aud_dev_cap cap,
142 const void *value);
143static pj_status_t strm_start(pjmedia_aud_stream *strm);
144static pj_status_t strm_stop(pjmedia_aud_stream *strm);
145static pj_status_t strm_destroy(pjmedia_aud_stream *strm);
146
147static pjmedia_aud_dev_factory_op opensl_op =
148{
149 &opensl_init,
150 &opensl_destroy,
151 &opensl_get_dev_count,
152 &opensl_get_dev_info,
153 &opensl_default_param,
154 &opensl_create_stream,
155 &opensl_refresh
156};
157
158static pjmedia_aud_stream_op opensl_strm_op =
159{
160 &strm_get_param,
161 &strm_get_cap,
162 &strm_set_cap,
163 &strm_start,
164 &strm_stop,
165 &strm_destroy
166};
167
168/* This callback is called every time a buffer finishes playing. */
169void bqPlayerCallback(W_SLBufferQueueItf bq, void *context)
170{
171 struct opensl_aud_stream *stream = (struct opensl_aud_stream*) context;
172 SLresult result;
173 int status;
174
175 pj_assert(context != NULL);
176 pj_assert(bq == stream->playerBufQ);
177
178 if (stream->play_thread_initialized == 0 || !pj_thread_is_registered())
179 {
180 pj_bzero(stream->play_thread_desc, sizeof(pj_thread_desc));
181 status = pj_thread_register("opensl_play", stream->play_thread_desc,
182 &stream->play_thread);
183 stream->play_thread_initialized = 1;
184 PJ_LOG(5, (THIS_FILE, "Player thread started"));
185 }
186
187 if (!stream->quit_flag) {
188 pjmedia_frame frame;
189 char * buf;
190
191 frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
192 frame.buf = buf = stream->playerBuffer[stream->playerBufIdx++];
193 frame.size = stream->playerBufferSize;
194 frame.timestamp.u64 = stream->play_timestamp.u64;
195 frame.bit_info = 0;
196
197 status = (*stream->play_cb)(stream->user_data, &frame);
198 if (status != PJ_SUCCESS || frame.type != PJMEDIA_FRAME_TYPE_AUDIO)
199 pj_bzero(buf, stream->playerBufferSize);
200
201 stream->play_timestamp.u64 += stream->param.samples_per_frame /
202 stream->param.channel_count;
203
204 result = (*bq)->Enqueue(bq, buf, stream->playerBufferSize);
205 if (result != SL_RESULT_SUCCESS) {
206 PJ_LOG(3, (THIS_FILE, "Unable to enqueue next player buffer !!! %d",
207 result));
208 }
209
210 stream->playerBufIdx %= NUM_BUFFERS;
211 }
212}
213
214/* This callback handler is called every time a buffer finishes recording */
215void bqRecorderCallback(W_SLBufferQueueItf bq, void *context)
216{
217 struct opensl_aud_stream *stream = (struct opensl_aud_stream*) context;
218 SLresult result;
219 int status;
220
221 pj_assert(context != NULL);
222 pj_assert(bq == stream->recordBufQ);
223
224 if (stream->rec_thread_initialized == 0 || !pj_thread_is_registered())
225 {
226 pj_bzero(stream->rec_thread_desc, sizeof(pj_thread_desc));
227 status = pj_thread_register("opensl_rec", stream->rec_thread_desc,
228 &stream->rec_thread);
229 stream->rec_thread_initialized = 1;
230 PJ_LOG(5, (THIS_FILE, "Recorder thread started"));
231 }
232
233 if (!stream->quit_flag) {
234 pjmedia_frame frame;
235 char *buf;
236
237 frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
238 frame.buf = buf = stream->recordBuffer[stream->recordBufIdx++];
239 frame.size = stream->recordBufferSize;
240 frame.timestamp.u64 = stream->rec_timestamp.u64;
241 frame.bit_info = 0;
242
243 status = (*stream->rec_cb)(stream->user_data, &frame);
244
245 stream->rec_timestamp.u64 += stream->param.samples_per_frame /
246 stream->param.channel_count;
247
248 /* And now enqueue next buffer */
249 result = (*bq)->Enqueue(bq, buf, stream->recordBufferSize);
250 if (result != SL_RESULT_SUCCESS) {
251 PJ_LOG(3, (THIS_FILE, "Unable to enqueue next record buffer !!! %d",
252 result));
253 }
254
255 stream->recordBufIdx %= NUM_BUFFERS;
256 }
257}
258
259pj_status_t opensl_to_pj_error(SLresult code)
260{
261 switch(code) {
262 case SL_RESULT_SUCCESS:
263 return PJ_SUCCESS;
264 case SL_RESULT_PRECONDITIONS_VIOLATED:
265 case SL_RESULT_PARAMETER_INVALID:
266 case SL_RESULT_CONTENT_CORRUPTED:
267 case SL_RESULT_FEATURE_UNSUPPORTED:
268 return PJMEDIA_EAUD_INVOP;
269 case SL_RESULT_MEMORY_FAILURE:
270 case SL_RESULT_BUFFER_INSUFFICIENT:
271 return PJ_ENOMEM;
272 case SL_RESULT_RESOURCE_ERROR:
273 case SL_RESULT_RESOURCE_LOST:
274 case SL_RESULT_CONTROL_LOST:
275 return PJMEDIA_EAUD_NOTREADY;
276 case SL_RESULT_CONTENT_UNSUPPORTED:
277 return PJ_ENOTSUP;
278 default:
279 return PJMEDIA_EAUD_ERR;
280 }
281}
282
283/* Init Android audio driver. */
284pjmedia_aud_dev_factory* pjmedia_opensl_factory(pj_pool_factory *pf)
285{
286 struct opensl_aud_factory *f;
287 pj_pool_t *pool;
288
289 pool = pj_pool_create(pf, "opensles", 256, 256, NULL);
290 f = PJ_POOL_ZALLOC_T(pool, struct opensl_aud_factory);
291 f->pf = pf;
292 f->pool = pool;
293 f->base.op = &opensl_op;
294
295 return &f->base;
296}
297
298/* API: Init factory */
299static pj_status_t opensl_init(pjmedia_aud_dev_factory *f)
300{
301 struct opensl_aud_factory *pa = (struct opensl_aud_factory*)f;
302 SLresult result;
303
304 /* Create engine */
305 result = slCreateEngine(&pa->engineObject, 0, NULL, 0, NULL, NULL);
306 if (result != SL_RESULT_SUCCESS) {
307 PJ_LOG(3, (THIS_FILE, "Cannot create engine %d ", result));
308 return opensl_to_pj_error(result);
309 }
310
311 /* Realize the engine */
312 result = (*pa->engineObject)->Realize(pa->engineObject, SL_BOOLEAN_FALSE);
313 if (result != SL_RESULT_SUCCESS) {
314 PJ_LOG(3, (THIS_FILE, "Cannot realize engine"));
315 opensl_destroy(f);
316 return opensl_to_pj_error(result);
317 }
318
319 /* Get the engine interface, which is needed in order to create
320 * other objects.
321 */
322 result = (*pa->engineObject)->GetInterface(pa->engineObject,
323 SL_IID_ENGINE,
324 &pa->engineEngine);
325 if (result != SL_RESULT_SUCCESS) {
326 PJ_LOG(3, (THIS_FILE, "Cannot get engine interface"));
327 opensl_destroy(f);
328 return opensl_to_pj_error(result);
329 }
330
331 /* Create output mix */
332 result = (*pa->engineEngine)->CreateOutputMix(pa->engineEngine,
333 &pa->outputMixObject,
334 0, NULL, NULL);
335 if (result != SL_RESULT_SUCCESS) {
336 PJ_LOG(3, (THIS_FILE, "Cannot create output mix"));
337 opensl_destroy(f);
338 return opensl_to_pj_error(result);
339 }
340
341 /* Realize the output mix */
342 result = (*pa->outputMixObject)->Realize(pa->outputMixObject,
343 SL_BOOLEAN_FALSE);
344 if (result != SL_RESULT_SUCCESS) {
345 PJ_LOG(3, (THIS_FILE, "Cannot realize output mix"));
346 opensl_destroy(f);
347 return opensl_to_pj_error(result);
348 }
349
350 PJ_LOG(4,(THIS_FILE, "OpenSL sound library initialized"));
351 return PJ_SUCCESS;
352}
353
354/* API: Destroy factory */
355static pj_status_t opensl_destroy(pjmedia_aud_dev_factory *f)
356{
357 struct opensl_aud_factory *pa = (struct opensl_aud_factory*)f;
358 pj_pool_t *pool;
359
360 PJ_LOG(4,(THIS_FILE, "OpenSL sound library shutting down.."));
361
362 /* Destroy Output Mix object */
363 if (pa->outputMixObject) {
364 (*pa->outputMixObject)->Destroy(pa->outputMixObject);
365 pa->outputMixObject = NULL;
366 }
367
368 /* Destroy engine object, and invalidate all associated interfaces */
369 if (pa->engineObject) {
370 (*pa->engineObject)->Destroy(pa->engineObject);
371 pa->engineObject = NULL;
372 pa->engineEngine = NULL;
373 }
374
375 pool = pa->pool;
376 pa->pool = NULL;
377 pj_pool_release(pool);
378
379 return PJ_SUCCESS;
380}
381
382/* API: refresh the list of devices */
383static pj_status_t opensl_refresh(pjmedia_aud_dev_factory *f)
384{
385 PJ_UNUSED_ARG(f);
386 return PJ_SUCCESS;
387}
388
389/* API: Get device count. */
390static unsigned opensl_get_dev_count(pjmedia_aud_dev_factory *f)
391{
392 PJ_UNUSED_ARG(f);
393 return 1;
394}
395
396/* API: Get device info. */
397static pj_status_t opensl_get_dev_info(pjmedia_aud_dev_factory *f,
398 unsigned index,
399 pjmedia_aud_dev_info *info)
400{
401 PJ_UNUSED_ARG(f);
402
403 pj_bzero(info, sizeof(*info));
404
405 pj_ansi_strcpy(info->name, "OpenSL ES Audio");
406 info->default_samples_per_sec = 8000;
407 info->caps = PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING;
408 info->input_count = 1;
409 info->output_count = 1;
410
411 return PJ_SUCCESS;
412}
413
414/* API: fill in with default parameter. */
415static pj_status_t opensl_default_param(pjmedia_aud_dev_factory *f,
416 unsigned index,
417 pjmedia_aud_param *param)
418{
419
420 pjmedia_aud_dev_info adi;
421 pj_status_t status;
422
423 status = opensl_get_dev_info(f, index, &adi);
424 if (status != PJ_SUCCESS)
425 return status;
426
427 pj_bzero(param, sizeof(*param));
428 if (adi.input_count && adi.output_count) {
429 param->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;
430 param->rec_id = index;
431 param->play_id = index;
432 } else if (adi.input_count) {
433 param->dir = PJMEDIA_DIR_CAPTURE;
434 param->rec_id = index;
435 param->play_id = PJMEDIA_AUD_INVALID_DEV;
436 } else if (adi.output_count) {
437 param->dir = PJMEDIA_DIR_PLAYBACK;
438 param->play_id = index;
439 param->rec_id = PJMEDIA_AUD_INVALID_DEV;
440 } else {
441 return PJMEDIA_EAUD_INVDEV;
442 }
443
444 param->clock_rate = adi.default_samples_per_sec;
445 param->channel_count = 1;
446 param->samples_per_frame = adi.default_samples_per_sec * 20 / 1000;
447 param->bits_per_sample = 16;
448 param->input_latency_ms = PJMEDIA_SND_DEFAULT_REC_LATENCY;
449 param->output_latency_ms = PJMEDIA_SND_DEFAULT_PLAY_LATENCY;
450
451 return PJ_SUCCESS;
452}
453
454/* API: create stream */
455static pj_status_t opensl_create_stream(pjmedia_aud_dev_factory *f,
456 const pjmedia_aud_param *param,
457 pjmedia_aud_rec_cb rec_cb,
458 pjmedia_aud_play_cb play_cb,
459 void *user_data,
460 pjmedia_aud_stream **p_aud_strm)
461{
462 /* Audio sink for recorder and audio source for player */
463#ifdef __ANDROID__
464 SLDataLocator_AndroidSimpleBufferQueue loc_bq =
465 { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, NUM_BUFFERS };
466#else
467 SLDataLocator_BufferQueue loc_bq =
468 { SL_DATALOCATOR_BUFFERQUEUE, NUM_BUFFERS };
469#endif
470 struct opensl_aud_factory *pa = (struct opensl_aud_factory*)f;
471 pj_pool_t *pool;
472 struct opensl_aud_stream *stream;
473 pj_status_t status = PJ_SUCCESS;
474 int i, bufferSize;
475 SLresult result;
476 SLDataFormat_PCM format_pcm;
477
478 /* Only supports for mono channel for now */
479 PJ_ASSERT_RETURN(param->channel_count == 1, PJ_EINVAL);
480 PJ_ASSERT_RETURN(play_cb && rec_cb && p_aud_strm, PJ_EINVAL);
481
482 PJ_LOG(4,(THIS_FILE, "Creating OpenSL stream"));
483
484 pool = pj_pool_create(pa->pf, "openslstrm", 1024, 1024, NULL);
485 if (!pool)
486 return PJ_ENOMEM;
487
488 stream = PJ_POOL_ZALLOC_T(pool, struct opensl_aud_stream);
489 stream->pool = pool;
490 pj_strdup2_with_null(pool, &stream->name, "OpenSL");
491 stream->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;
492 pj_memcpy(&stream->param, param, sizeof(*param));
493 stream->user_data = user_data;
494 stream->rec_cb = rec_cb;
495 stream->play_cb = play_cb;
496 bufferSize = param->samples_per_frame * param->bits_per_sample / 8;
497
498 /* Configure audio PCM format */
499 format_pcm.formatType = SL_DATAFORMAT_PCM;
500 format_pcm.numChannels = param->channel_count;
501 /* Here samples per sec should be supported else we will get an error */
502 format_pcm.samplesPerSec = (SLuint32) param->clock_rate * 1000;
503 format_pcm.bitsPerSample = (SLuint16) param->bits_per_sample;
504 format_pcm.containerSize = (SLuint16) param->bits_per_sample;
505 format_pcm.channelMask = SL_SPEAKER_FRONT_CENTER;
506 format_pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
507
508 if (stream->dir & PJMEDIA_DIR_PLAYBACK) {
509 /* Audio source */
510 SLDataSource audioSrc = {&loc_bq, &format_pcm};
511 /* Audio sink */
512 SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX,
513 pa->outputMixObject};
514 SLDataSink audioSnk = {&loc_outmix, NULL};
515 /* Audio interface */
516#ifdef __ANDROID__
517 int numIface = 3;
518 const SLInterfaceID ids[3] = {SL_IID_BUFFERQUEUE,
519 SL_IID_VOLUME,
520 SL_IID_ANDROIDCONFIGURATION};
521 const SLboolean req[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE,
522 SL_BOOLEAN_TRUE};
523 SLAndroidConfigurationItf playerConfig;
524 SLint32 streamType = SL_ANDROID_STREAM_VOICE;
525#else
526 int numIface = 2;
527 const SLInterfaceID ids[2] = {SL_IID_BUFFERQUEUE,
528 SL_IID_VOLUME};
529 const SLboolean req[2] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
530#endif
531
532 /* Create audio player */
533 result = (*pa->engineEngine)->CreateAudioPlayer(pa->engineEngine,
534 &stream->playerObj,
535 &audioSrc, &audioSnk,
536 numIface, ids, req);
537 if (result != SL_RESULT_SUCCESS) {
538 PJ_LOG(3, (THIS_FILE, "Cannot create audio player: %d", result));
539 goto on_error;
540 }
541
542#ifdef __ANDROID__
543 /* Set Android configuration */
544 result = (*stream->playerObj)->GetInterface(stream->playerObj,
545 SL_IID_ANDROIDCONFIGURATION,
546 &playerConfig);
547 if (result == SL_RESULT_SUCCESS && playerConfig) {
548 result = (*playerConfig)->SetConfiguration(
549 playerConfig, SL_ANDROID_KEY_STREAM_TYPE,
550 &streamType, sizeof(SLint32));
551 }
552 if (result != SL_RESULT_SUCCESS) {
553 PJ_LOG(4, (THIS_FILE, "Warning: Unable to set android "
554 "player configuration"));
555 }
556#endif
557
558 /* Realize the player */
559 result = (*stream->playerObj)->Realize(stream->playerObj,
560 SL_BOOLEAN_FALSE);
561 if (result != SL_RESULT_SUCCESS) {
562 PJ_LOG(3, (THIS_FILE, "Cannot realize player : %d", result));
563 goto on_error;
564 }
565
566 /* Get the play interface */
567 result = (*stream->playerObj)->GetInterface(stream->playerObj,
568 SL_IID_PLAY,
569 &stream->playerPlay);
570 if (result != SL_RESULT_SUCCESS) {
571 PJ_LOG(3, (THIS_FILE, "Cannot get play interface"));
572 goto on_error;
573 }
574
575 /* Get the buffer queue interface */
576 result = (*stream->playerObj)->GetInterface(stream->playerObj,
577 SL_IID_BUFFERQUEUE,
578 &stream->playerBufQ);
579 if (result != SL_RESULT_SUCCESS) {
580 PJ_LOG(3, (THIS_FILE, "Cannot get buffer queue interface"));
581 goto on_error;
582 }
583
584 /* Get the volume interface */
585 result = (*stream->playerObj)->GetInterface(stream->playerObj,
586 SL_IID_VOLUME,
587 &stream->playerVol);
588
589 /* Register callback on the buffer queue */
590 result = (*stream->playerBufQ)->RegisterCallback(stream->playerBufQ,
591 bqPlayerCallback,
592 (void *)stream);
593 if (result != SL_RESULT_SUCCESS) {
594 PJ_LOG(3, (THIS_FILE, "Cannot register player callback"));
595 goto on_error;
596 }
597
598 stream->playerBufferSize = bufferSize;
599 for (i = 0; i < NUM_BUFFERS; i++) {
600 stream->playerBuffer[i] = (char *)
601 pj_pool_alloc(stream->pool,
602 stream->playerBufferSize);
603 }
604 }
605
606 if (stream->dir & PJMEDIA_DIR_CAPTURE) {
607 /* Audio source */
608 SLDataLocator_IODevice loc_dev = {SL_DATALOCATOR_IODEVICE,
609 SL_IODEVICE_AUDIOINPUT,
610 SL_DEFAULTDEVICEID_AUDIOINPUT,
611 NULL};
612 SLDataSource audioSrc = {&loc_dev, NULL};
613 /* Audio sink */
614 SLDataSink audioSnk = {&loc_bq, &format_pcm};
615 /* Audio interface */
616#ifdef __ANDROID__
617 int numIface = 2;
618 const SLInterfaceID ids[2] = {W_SL_IID_BUFFERQUEUE,
619 SL_IID_ANDROIDCONFIGURATION};
620 const SLboolean req[2] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
621 SLAndroidConfigurationItf recorderConfig;
622#else
623 int numIface = 1;
624 const SLInterfaceID ids[1] = {W_SL_IID_BUFFERQUEUE};
625 const SLboolean req[1] = {SL_BOOLEAN_TRUE};
626#endif
627
628 /* Create audio recorder
629 * (requires the RECORD_AUDIO permission)
630 */
631 result = (*pa->engineEngine)->CreateAudioRecorder(pa->engineEngine,
632 &stream->recordObj,
633 &audioSrc, &audioSnk,
634 numIface, ids, req);
635 if (result != SL_RESULT_SUCCESS) {
636 PJ_LOG(3, (THIS_FILE, "Cannot create recorder: %d", result));
637 goto on_error;
638 }
639
640#ifdef __ANDROID__
641 /* Set Android configuration */
642 result = (*stream->recordObj)->GetInterface(stream->recordObj,
643 SL_IID_ANDROIDCONFIGURATION,
644 &recorderConfig);
645 if (result == SL_RESULT_SUCCESS) {
646 SLint32 streamType = SL_ANDROID_RECORDING_PRESET_GENERIC;
647#if __ANDROID_API__ >= 14
648 char sdk_version[PROP_VALUE_MAX];
649 pj_str_t pj_sdk_version;
650 int sdk_v;
651
652 __system_property_get("ro.build.version.sdk", sdk_version);
653 pj_sdk_version = pj_str(sdk_version);
654 sdk_v = pj_strtoul(&pj_sdk_version);
655 if (sdk_v >= 14)
656 streamType = SL_ANDROID_RECORDING_PRESET_VOICE_COMMUNICATION;
657 PJ_LOG(4, (THIS_FILE, "Recording stream type %d, SDK : %d",
658 streamType, sdk_v));
659#endif
660 result = (*recorderConfig)->SetConfiguration(
661 recorderConfig, SL_ANDROID_KEY_RECORDING_PRESET,
662 &streamType, sizeof(SLint32));
663 }
664 if (result != SL_RESULT_SUCCESS) {
665 PJ_LOG(4, (THIS_FILE, "Warning: Unable to set android "
666 "recorder configuration"));
667 }
668#endif
669
670 /* Realize the recorder */
671 result = (*stream->recordObj)->Realize(stream->recordObj,
672 SL_BOOLEAN_FALSE);
673 if (result != SL_RESULT_SUCCESS) {
674 PJ_LOG(3, (THIS_FILE, "Cannot realize recorder : %d", result));
675 goto on_error;
676 }
677
678 /* Get the record interface */
679 result = (*stream->recordObj)->GetInterface(stream->recordObj,
680 SL_IID_RECORD,
681 &stream->recordRecord);
682 if (result != SL_RESULT_SUCCESS) {
683 PJ_LOG(3, (THIS_FILE, "Cannot get record interface"));
684 goto on_error;
685 }
686
687 /* Get the buffer queue interface */
688 result = (*stream->recordObj)->GetInterface(
689 stream->recordObj, W_SL_IID_BUFFERQUEUE,
690 &stream->recordBufQ);
691 if (result != SL_RESULT_SUCCESS) {
692 PJ_LOG(3, (THIS_FILE, "Cannot get recorder buffer queue iface"));
693 goto on_error;
694 }
695
696 /* Register callback on the buffer queue */
697 result = (*stream->recordBufQ)->RegisterCallback(stream->recordBufQ,
698 bqRecorderCallback,
699 (void *) stream);
700 if (result != SL_RESULT_SUCCESS) {
701 PJ_LOG(3, (THIS_FILE, "Cannot register recorder callback"));
702 goto on_error;
703 }
704
705 stream->recordBufferSize = bufferSize;
706 for (i = 0; i < NUM_BUFFERS; i++) {
707 stream->recordBuffer[i] = (char *)
708 pj_pool_alloc(stream->pool,
709 stream->recordBufferSize);
710 }
711
712 }
713
714 if (param->flags & PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING) {
715 strm_set_cap(&stream->base, PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING,
716 &param->output_vol);
717 }
718
719 /* Done */
720 stream->base.op = &opensl_strm_op;
721 *p_aud_strm = &stream->base;
722 return PJ_SUCCESS;
723
724on_error:
725 strm_destroy(&stream->base);
726 return status;
727}
728
729/* API: Get stream parameters */
730static pj_status_t strm_get_param(pjmedia_aud_stream *s,
731 pjmedia_aud_param *pi)
732{
733 struct opensl_aud_stream *strm = (struct opensl_aud_stream*)s;
734 PJ_ASSERT_RETURN(strm && pi, PJ_EINVAL);
735 pj_memcpy(pi, &strm->param, sizeof(*pi));
736
737 if (strm_get_cap(s, PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING,
738 &pi->output_vol) == PJ_SUCCESS)
739 {
740 pi->flags |= PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING;
741 }
742
743 return PJ_SUCCESS;
744}
745
746/* API: get capability */
747static pj_status_t strm_get_cap(pjmedia_aud_stream *s,
748 pjmedia_aud_dev_cap cap,
749 void *pval)
750{
751 struct opensl_aud_stream *strm = (struct opensl_aud_stream*)s;
752 pj_status_t status = PJMEDIA_EAUD_INVCAP;
753
754 PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
755
756 if (cap==PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING &&
757 (strm->param.dir & PJMEDIA_DIR_PLAYBACK))
758 {
759 if (strm->playerVol) {
760 SLresult res;
761 SLmillibel vol, mvol;
762
763 res = (*strm->playerVol)->GetMaxVolumeLevel(strm->playerVol,
764 &mvol);
765 if (res == SL_RESULT_SUCCESS) {
766 res = (*strm->playerVol)->GetVolumeLevel(strm->playerVol,
767 &vol);
768 if (res == SL_RESULT_SUCCESS) {
769 *(int *)pval = ((int)vol - SL_MILLIBEL_MIN) * 100 /
770 ((int)mvol - SL_MILLIBEL_MIN);
771 return PJ_SUCCESS;
772 }
773 }
774 }
775 }
776
777 return status;
778}
779
780/* API: set capability */
781static pj_status_t strm_set_cap(pjmedia_aud_stream *s,
782 pjmedia_aud_dev_cap cap,
783 const void *value)
784{
785 struct opensl_aud_stream *strm = (struct opensl_aud_stream*)s;
786
787 PJ_ASSERT_RETURN(s && value, PJ_EINVAL);
788
789 if (cap==PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING &&
790 (strm->param.dir & PJMEDIA_DIR_PLAYBACK))
791 {
792 if (strm->playerVol) {
793 SLresult res;
794 SLmillibel vol, mvol;
795
796 res = (*strm->playerVol)->GetMaxVolumeLevel(strm->playerVol,
797 &mvol);
798 if (res == SL_RESULT_SUCCESS) {
799 vol = (SLmillibel)(*(int *)value *
800 ((int)mvol - SL_MILLIBEL_MIN) / 100 + SL_MILLIBEL_MIN);
801 res = (*strm->playerVol)->SetVolumeLevel(strm->playerVol,
802 vol);
803 if (res == SL_RESULT_SUCCESS)
804 return PJ_SUCCESS;
805 }
806 }
807 }
808
809 return PJMEDIA_EAUD_INVCAP;
810}
811
812/* API: start stream. */
813static pj_status_t strm_start(pjmedia_aud_stream *s)
814{
815 struct opensl_aud_stream *stream = (struct opensl_aud_stream*)s;
816 int i;
817 SLresult result = SL_RESULT_SUCCESS;
818
819 PJ_LOG(4, (THIS_FILE, "Starting %s stream..", stream->name.ptr));
820 stream->quit_flag = 0;
821
822 if (stream->recordBufQ && stream->recordRecord) {
823 /* Enqueue an empty buffer to be filled by the recorder
824 * (for streaming recording, we need to enqueue at least 2 empty
825 * buffers to start things off)
826 */
827 for (i = 0; i < NUM_BUFFERS; i++) {
828 result = (*stream->recordBufQ)->Enqueue(stream->recordBufQ,
829 stream->recordBuffer[i],
830 stream->recordBufferSize);
831 /* The most likely other result is SL_RESULT_BUFFER_INSUFFICIENT,
832 * which for this code would indicate a programming error
833 */
834 pj_assert(result == SL_RESULT_SUCCESS);
835 }
836
837 result = (*stream->recordRecord)->SetRecordState(
838 stream->recordRecord, SL_RECORDSTATE_RECORDING);
839 if (result != SL_RESULT_SUCCESS) {
840 PJ_LOG(3, (THIS_FILE, "Cannot start recorder"));
841 goto on_error;
842 }
843 }
844
845 if (stream->playerPlay && stream->playerBufQ) {
846 /* Set the player's state to playing */
847 result = (*stream->playerPlay)->SetPlayState(stream->playerPlay,
848 SL_PLAYSTATE_PLAYING);
849 if (result != SL_RESULT_SUCCESS) {
850 PJ_LOG(3, (THIS_FILE, "Cannot start player"));
851 goto on_error;
852 }
853
854 for (i = 0; i < NUM_BUFFERS; i++) {
855 pj_bzero(stream->playerBuffer[i], stream->playerBufferSize/100);
856 result = (*stream->playerBufQ)->Enqueue(stream->playerBufQ,
857 stream->playerBuffer[i],
858 stream->playerBufferSize/100);
859 pj_assert(result == SL_RESULT_SUCCESS);
860 }
861 }
862
863 PJ_LOG(4, (THIS_FILE, "%s stream started", stream->name.ptr));
864 return PJ_SUCCESS;
865
866on_error:
867 if (result != SL_RESULT_SUCCESS)
868 strm_stop(&stream->base);
869 return opensl_to_pj_error(result);
870}
871
872/* API: stop stream. */
873static pj_status_t strm_stop(pjmedia_aud_stream *s)
874{
875 struct opensl_aud_stream *stream = (struct opensl_aud_stream*)s;
876
877 if (stream->quit_flag)
878 return PJ_SUCCESS;
879
880 PJ_LOG(4, (THIS_FILE, "Stopping stream"));
881
882 stream->quit_flag = 1;
883
884 if (stream->recordBufQ && stream->recordRecord) {
885 /* Stop recording and clear buffer queue */
886 (*stream->recordRecord)->SetRecordState(stream->recordRecord,
887 SL_RECORDSTATE_STOPPED);
888 (*stream->recordBufQ)->Clear(stream->recordBufQ);
889 }
890
891 if (stream->playerBufQ && stream->playerPlay) {
892 /* Wait until the PCM data is done playing, the buffer queue callback
893 * will continue to queue buffers until the entire PCM data has been
894 * played. This is indicated by waiting for the count member of the
895 * SLBufferQueueState to go to zero.
896 */
897/*
898 SLresult result;
899 W_SLBufferQueueState state;
900
901 result = (*stream->playerBufQ)->GetState(stream->playerBufQ, &state);
902 while (state.count) {
903 (*stream->playerBufQ)->GetState(stream->playerBufQ, &state);
904 } */
905 /* Stop player */
906 (*stream->playerPlay)->SetPlayState(stream->playerPlay,
907 SL_PLAYSTATE_STOPPED);
908 }
909
910 PJ_LOG(4,(THIS_FILE, "OpenSL stream stopped"));
911
912 return PJ_SUCCESS;
913
914}
915
916/* API: destroy stream. */
917static pj_status_t strm_destroy(pjmedia_aud_stream *s)
918{
919 struct opensl_aud_stream *stream = (struct opensl_aud_stream*)s;
920
921 /* Stop the stream */
922 strm_stop(s);
923
924 if (stream->playerObj) {
925 /* Destroy the player */
926 (*stream->playerObj)->Destroy(stream->playerObj);
927 /* Invalidate all associated interfaces */
928 stream->playerObj = NULL;
929 stream->playerPlay = NULL;
930 stream->playerBufQ = NULL;
931 stream->playerVol = NULL;
932 }
933
934 if (stream->recordObj) {
935 /* Destroy the recorder */
936 (*stream->recordObj)->Destroy(stream->recordObj);
937 /* Invalidate all associated interfaces */
938 stream->recordObj = NULL;
939 stream->recordRecord = NULL;
940 stream->recordBufQ = NULL;
941 }
942
943 pj_pool_release(stream->pool);
944 PJ_LOG(4, (THIS_FILE, "OpenSL stream destroyed"));
945
946 return PJ_SUCCESS;
947}
948
949#endif /* PJMEDIA_AUDIO_DEV_HAS_OPENSL */