summaryrefslogtreecommitdiff
path: root/modules/opensles/recorder.c
diff options
context:
space:
mode:
Diffstat (limited to 'modules/opensles/recorder.c')
-rw-r--r--modules/opensles/recorder.c224
1 files changed, 224 insertions, 0 deletions
diff --git a/modules/opensles/recorder.c b/modules/opensles/recorder.c
new file mode 100644
index 0000000..6301451
--- /dev/null
+++ b/modules/opensles/recorder.c
@@ -0,0 +1,224 @@
+/**
+ * @file opensles/recorder.c OpenSLES audio driver -- recording
+ *
+ * Copyright (C) 2010 Creytiv.com
+ */
+#include <re.h>
+#include <baresip.h>
+#include <pthread.h>
+#include <SLES/OpenSLES.h>
+#include "SLES/OpenSLES_Android.h"
+#include "opensles.h"
+
+
+#define DEBUG_MODULE "opensles/recorder"
+#define DEBUG_LEVEL 5
+#include <re_dbg.h>
+
+
+struct ausrc_st {
+ struct ausrc *as; /* inheritance */
+ int16_t buf[160];
+ pthread_t thread;
+ bool run;
+ ausrc_read_h *rh;
+ void *arg;
+
+ SLObjectItf recObject;
+ SLRecordItf recRecord;
+ SLAndroidSimpleBufferQueueItf recBufferQueue;
+};
+
+
+static void ausrc_destructor(void *arg)
+{
+ struct ausrc_st *st = arg;
+
+ if (st->run) {
+ st->run = false;
+ pthread_join(st->thread, NULL);
+ }
+
+ if (st->recObject != NULL)
+ (*st->recObject)->Destroy(st->recObject);
+
+ mem_deref(st->as);
+}
+
+
+static void *record_thread(void *arg)
+{
+ uint64_t now, ts = tmr_jiffies();
+ struct ausrc_st *st = arg;
+ SLresult r;
+
+ while (st->run) {
+
+ (void)sys_usleep(4000);
+
+ now = tmr_jiffies();
+
+ if (ts > now)
+ continue;
+#if 1
+ if (now > ts + 100) {
+ debug("opensles: cpu lagging behind (%u ms)\n",
+ now - ts);
+ }
+#endif
+
+ r = (*st->recBufferQueue)->Enqueue(st->recBufferQueue,
+ st->buf, sizeof(st->buf));
+ if (r != SL_RESULT_SUCCESS) {
+ DEBUG_WARNING("Enqueue: r = %d\n", r);
+ }
+
+ ts += 20;
+ }
+
+ return NULL;
+}
+
+
+static void bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq, void *context)
+{
+ struct ausrc_st *st = context;
+ (void)bq;
+
+ st->rh((void *)st->buf, sizeof(st->buf), st->arg);
+}
+
+
+static int createAudioRecorder(struct ausrc_st *st, struct ausrc_prm *prm)
+{
+ SLDataLocator_IODevice loc_dev = {SL_DATALOCATOR_IODEVICE,
+ SL_IODEVICE_AUDIOINPUT,
+ SL_DEFAULTDEVICEID_AUDIOINPUT,
+ NULL};
+ SLDataSource audioSrc = {&loc_dev, NULL};
+
+ SLDataLocator_AndroidSimpleBufferQueue loc_bq = {
+ SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2
+ };
+ SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM, prm->ch,
+ prm->srate * 1000,
+ SL_PCMSAMPLEFORMAT_FIXED_16,
+ SL_PCMSAMPLEFORMAT_FIXED_16,
+ SL_SPEAKER_FRONT_CENTER,
+ SL_BYTEORDER_LITTLEENDIAN};
+ SLDataSink audioSnk = {&loc_bq, &format_pcm};
+ const SLInterfaceID id[1] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE};
+ const SLboolean req[1] = {SL_BOOLEAN_TRUE};
+ SLresult r;
+
+ r = (*engineEngine)->CreateAudioRecorder(engineEngine,
+ &st->recObject,
+ &audioSrc,
+ &audioSnk, 1, id, req);
+ if (SL_RESULT_SUCCESS != r) {
+ DEBUG_WARNING("CreateAudioRecorder failed: r = %d\n", r);
+ return ENODEV;
+ }
+
+ r = (*st->recObject)->Realize(st->recObject, SL_BOOLEAN_FALSE);
+ if (SL_RESULT_SUCCESS != r) {
+ DEBUG_WARNING("recorder: Realize r = %d\n", r);
+ return ENODEV;
+ }
+
+ r = (*st->recObject)->GetInterface(st->recObject, SL_IID_RECORD,
+ &st->recRecord);
+ if (SL_RESULT_SUCCESS != r)
+ return ENODEV;
+
+ r = (*st->recObject)->GetInterface(st->recObject,
+ SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
+ &st->recBufferQueue);
+ if (SL_RESULT_SUCCESS != r)
+ return ENODEV;
+
+ r = (*st->recBufferQueue)->RegisterCallback(st->recBufferQueue,
+ bqRecorderCallback,
+ st);
+ if (SL_RESULT_SUCCESS != r)
+ return ENODEV;
+
+ return 0;
+}
+
+
+static int startRecording(struct ausrc_st *st)
+{
+ SLresult r;
+
+ (*st->recRecord)->SetRecordState(st->recRecord,
+ SL_RECORDSTATE_STOPPED);
+ (*st->recBufferQueue)->Clear(st->recBufferQueue);
+
+#if 0
+ r = (*st->recBufferQueue)->Enqueue(st->recBufferQueue,
+ st->buf, sizeof(st->buf));
+ if (SL_RESULT_SUCCESS != r)
+ return ENODEV;
+#endif
+
+ r = (*st->recRecord)->SetRecordState(st->recRecord,
+ SL_RECORDSTATE_RECORDING);
+ if (SL_RESULT_SUCCESS != r)
+ return ENODEV;
+
+ return 0;
+}
+
+
+int opensles_recorder_alloc(struct ausrc_st **stp, struct ausrc *as,
+ struct media_ctx **ctx,
+ struct ausrc_prm *prm, const char *device,
+ ausrc_read_h *rh, ausrc_error_h *errh, void *arg)
+{
+ struct ausrc_st *st;
+ int err;
+ (void)ctx;
+ (void)device;
+ (void)errh;
+
+ if (!stp || !as || !prm || !rh)
+ return EINVAL;
+
+ st = mem_zalloc(sizeof(*st), ausrc_destructor);
+ if (!st)
+ return ENOMEM;
+
+ st->as = mem_ref(as);
+ st->rh = rh;
+ st->arg = arg;
+
+ err = createAudioRecorder(st, prm);
+ if (err) {
+ DEBUG_WARNING("failed to create recorder\n");
+ goto out;
+ }
+
+ err = startRecording(st);
+ if (err) {
+ DEBUG_WARNING("failed to start recorder\n");
+ goto out;
+ }
+
+ st->run = true;
+
+ err = pthread_create(&st->thread, NULL, record_thread, st);
+ if (err) {
+ st->run = false;
+ goto out;
+ }
+
+ out:
+
+ if (err)
+ mem_deref(st);
+ else
+ *stp = st;
+
+ return err;
+}