]> git.tdb.fi Git - ext/openal.git/blob - alc/backends/opensl.cpp
Import OpenAL Soft 1.23.1 sources
[ext/openal.git] / alc / backends / opensl.cpp
1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /* This is an OpenAL backend for Android using the native audio APIs based on
18  * OpenSL ES 1.0.1. It is based on source code for the native-audio sample app
19  * bundled with NDK.
20  */
21
22 #include "config.h"
23
24 #include "opensl.h"
25
26 #include <stdlib.h>
27 #include <jni.h>
28
29 #include <new>
30 #include <array>
31 #include <cstring>
32 #include <thread>
33 #include <functional>
34
35 #include "albit.h"
36 #include "alnumeric.h"
37 #include "core/device.h"
38 #include "core/helpers.h"
39 #include "core/logging.h"
40 #include "opthelpers.h"
41 #include "ringbuffer.h"
42 #include "threads.h"
43
44 #include <SLES/OpenSLES.h>
45 #include <SLES/OpenSLES_Android.h>
46 #include <SLES/OpenSLES_AndroidConfiguration.h>
47
48
49 namespace {
50
51 /* Helper macros */
52 #define EXTRACT_VCALL_ARGS(...)  __VA_ARGS__))
53 #define VCALL(obj, func)  ((*(obj))->func((obj), EXTRACT_VCALL_ARGS
54 #define VCALL0(obj, func)  ((*(obj))->func((obj) EXTRACT_VCALL_ARGS
55
56
57 constexpr char opensl_device[] = "OpenSL";
58
59
60 constexpr SLuint32 GetChannelMask(DevFmtChannels chans) noexcept
61 {
62     switch(chans)
63     {
64     case DevFmtMono: return SL_SPEAKER_FRONT_CENTER;
65     case DevFmtStereo: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
66     case DevFmtQuad: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT |
67         SL_SPEAKER_BACK_LEFT | SL_SPEAKER_BACK_RIGHT;
68     case DevFmtX51: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT |
69         SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY | SL_SPEAKER_SIDE_LEFT |
70         SL_SPEAKER_SIDE_RIGHT;
71     case DevFmtX61: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT |
72         SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY | SL_SPEAKER_BACK_CENTER |
73         SL_SPEAKER_SIDE_LEFT | SL_SPEAKER_SIDE_RIGHT;
74     case DevFmtX71:
75     case DevFmtX3D71: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT |
76         SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY | SL_SPEAKER_BACK_LEFT |
77         SL_SPEAKER_BACK_RIGHT | SL_SPEAKER_SIDE_LEFT | SL_SPEAKER_SIDE_RIGHT;
78     case DevFmtX714: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT |
79         SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY | SL_SPEAKER_BACK_LEFT |
80         SL_SPEAKER_BACK_RIGHT | SL_SPEAKER_SIDE_LEFT | SL_SPEAKER_SIDE_RIGHT |
81         SL_SPEAKER_TOP_FRONT_LEFT | SL_SPEAKER_TOP_FRONT_RIGHT | SL_SPEAKER_TOP_BACK_LEFT |
82         SL_SPEAKER_TOP_BACK_RIGHT;
83     case DevFmtAmbi3D:
84         break;
85     }
86     return 0;
87 }
88
89 #ifdef SL_ANDROID_DATAFORMAT_PCM_EX
90 constexpr SLuint32 GetTypeRepresentation(DevFmtType type) noexcept
91 {
92     switch(type)
93     {
94     case DevFmtUByte:
95     case DevFmtUShort:
96     case DevFmtUInt:
97         return SL_ANDROID_PCM_REPRESENTATION_UNSIGNED_INT;
98     case DevFmtByte:
99     case DevFmtShort:
100     case DevFmtInt:
101         return SL_ANDROID_PCM_REPRESENTATION_SIGNED_INT;
102     case DevFmtFloat:
103         return SL_ANDROID_PCM_REPRESENTATION_FLOAT;
104     }
105     return 0;
106 }
107 #endif
108
109 constexpr SLuint32 GetByteOrderEndianness() noexcept
110 {
111     if(al::endian::native == al::endian::little)
112         return SL_BYTEORDER_LITTLEENDIAN;
113     return SL_BYTEORDER_BIGENDIAN;
114 }
115
116 constexpr const char *res_str(SLresult result) noexcept
117 {
118     switch(result)
119     {
120     case SL_RESULT_SUCCESS: return "Success";
121     case SL_RESULT_PRECONDITIONS_VIOLATED: return "Preconditions violated";
122     case SL_RESULT_PARAMETER_INVALID: return "Parameter invalid";
123     case SL_RESULT_MEMORY_FAILURE: return "Memory failure";
124     case SL_RESULT_RESOURCE_ERROR: return "Resource error";
125     case SL_RESULT_RESOURCE_LOST: return "Resource lost";
126     case SL_RESULT_IO_ERROR: return "I/O error";
127     case SL_RESULT_BUFFER_INSUFFICIENT: return "Buffer insufficient";
128     case SL_RESULT_CONTENT_CORRUPTED: return "Content corrupted";
129     case SL_RESULT_CONTENT_UNSUPPORTED: return "Content unsupported";
130     case SL_RESULT_CONTENT_NOT_FOUND: return "Content not found";
131     case SL_RESULT_PERMISSION_DENIED: return "Permission denied";
132     case SL_RESULT_FEATURE_UNSUPPORTED: return "Feature unsupported";
133     case SL_RESULT_INTERNAL_ERROR: return "Internal error";
134     case SL_RESULT_UNKNOWN_ERROR: return "Unknown error";
135     case SL_RESULT_OPERATION_ABORTED: return "Operation aborted";
136     case SL_RESULT_CONTROL_LOST: return "Control lost";
137 #ifdef SL_RESULT_READONLY
138     case SL_RESULT_READONLY: return "ReadOnly";
139 #endif
140 #ifdef SL_RESULT_ENGINEOPTION_UNSUPPORTED
141     case SL_RESULT_ENGINEOPTION_UNSUPPORTED: return "Engine option unsupported";
142 #endif
143 #ifdef SL_RESULT_SOURCE_SINK_INCOMPATIBLE
144     case SL_RESULT_SOURCE_SINK_INCOMPATIBLE: return "Source/Sink incompatible";
145 #endif
146     }
147     return "Unknown error code";
148 }
149
150 inline void PrintErr(SLresult res, const char *str)
151 {
152     if(res != SL_RESULT_SUCCESS) UNLIKELY
153         ERR("%s: %s\n", str, res_str(res));
154 }
155
156
157 struct OpenSLPlayback final : public BackendBase {
158     OpenSLPlayback(DeviceBase *device) noexcept : BackendBase{device} { }
159     ~OpenSLPlayback() override;
160
161     void process(SLAndroidSimpleBufferQueueItf bq) noexcept;
162     static void processC(SLAndroidSimpleBufferQueueItf bq, void *context) noexcept
163     { static_cast<OpenSLPlayback*>(context)->process(bq); }
164
165     int mixerProc();
166
167     void open(const char *name) override;
168     bool reset() override;
169     void start() override;
170     void stop() override;
171     ClockLatency getClockLatency() override;
172
173     /* engine interfaces */
174     SLObjectItf mEngineObj{nullptr};
175     SLEngineItf mEngine{nullptr};
176
177     /* output mix interfaces */
178     SLObjectItf mOutputMix{nullptr};
179
180     /* buffer queue player interfaces */
181     SLObjectItf mBufferQueueObj{nullptr};
182
183     RingBufferPtr mRing{nullptr};
184     al::semaphore mSem;
185
186     std::mutex mMutex;
187
188     uint mFrameSize{0};
189
190     std::atomic<bool> mKillNow{true};
191     std::thread mThread;
192
193     DEF_NEWDEL(OpenSLPlayback)
194 };
195
196 OpenSLPlayback::~OpenSLPlayback()
197 {
198     if(mBufferQueueObj)
199         VCALL0(mBufferQueueObj,Destroy)();
200     mBufferQueueObj = nullptr;
201
202     if(mOutputMix)
203         VCALL0(mOutputMix,Destroy)();
204     mOutputMix = nullptr;
205
206     if(mEngineObj)
207         VCALL0(mEngineObj,Destroy)();
208     mEngineObj = nullptr;
209     mEngine = nullptr;
210 }
211
212
213 /* this callback handler is called every time a buffer finishes playing */
214 void OpenSLPlayback::process(SLAndroidSimpleBufferQueueItf) noexcept
215 {
216     /* A note on the ringbuffer usage: The buffer queue seems to hold on to the
217      * pointer passed to the Enqueue method, rather than copying the audio.
218      * Consequently, the ringbuffer contains the audio that is currently queued
219      * and waiting to play. This process() callback is called when a buffer is
220      * finished, so we simply move the read pointer up to indicate the space is
221      * available for writing again, and wake up the mixer thread to mix and
222      * queue more audio.
223      */
224     mRing->readAdvance(1);
225
226     mSem.post();
227 }
228
229 int OpenSLPlayback::mixerProc()
230 {
231     SetRTPriority();
232     althrd_setname(MIXER_THREAD_NAME);
233
234     SLPlayItf player;
235     SLAndroidSimpleBufferQueueItf bufferQueue;
236     SLresult result{VCALL(mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
237         &bufferQueue)};
238     PrintErr(result, "bufferQueue->GetInterface SL_IID_ANDROIDSIMPLEBUFFERQUEUE");
239     if(SL_RESULT_SUCCESS == result)
240     {
241         result = VCALL(mBufferQueueObj,GetInterface)(SL_IID_PLAY, &player);
242         PrintErr(result, "bufferQueue->GetInterface SL_IID_PLAY");
243     }
244
245     const size_t frame_step{mDevice->channelsFromFmt()};
246
247     if(SL_RESULT_SUCCESS != result)
248         mDevice->handleDisconnect("Failed to get playback buffer: 0x%08x", result);
249
250     while(SL_RESULT_SUCCESS == result && !mKillNow.load(std::memory_order_acquire)
251         && mDevice->Connected.load(std::memory_order_acquire))
252     {
253         if(mRing->writeSpace() == 0)
254         {
255             SLuint32 state{0};
256
257             result = VCALL(player,GetPlayState)(&state);
258             PrintErr(result, "player->GetPlayState");
259             if(SL_RESULT_SUCCESS == result && state != SL_PLAYSTATE_PLAYING)
260             {
261                 result = VCALL(player,SetPlayState)(SL_PLAYSTATE_PLAYING);
262                 PrintErr(result, "player->SetPlayState");
263             }
264             if(SL_RESULT_SUCCESS != result)
265             {
266                 mDevice->handleDisconnect("Failed to start playback: 0x%08x", result);
267                 break;
268             }
269
270             if(mRing->writeSpace() == 0)
271             {
272                 mSem.wait();
273                 continue;
274             }
275         }
276
277         std::unique_lock<std::mutex> dlock{mMutex};
278         auto data = mRing->getWriteVector();
279         mDevice->renderSamples(data.first.buf,
280             static_cast<uint>(data.first.len)*mDevice->UpdateSize, frame_step);
281         if(data.second.len > 0)
282             mDevice->renderSamples(data.second.buf,
283                 static_cast<uint>(data.second.len)*mDevice->UpdateSize, frame_step);
284
285         size_t todo{data.first.len + data.second.len};
286         mRing->writeAdvance(todo);
287         dlock.unlock();
288
289         for(size_t i{0};i < todo;i++)
290         {
291             if(!data.first.len)
292             {
293                 data.first = data.second;
294                 data.second.buf = nullptr;
295                 data.second.len = 0;
296             }
297
298             result = VCALL(bufferQueue,Enqueue)(data.first.buf, mDevice->UpdateSize*mFrameSize);
299             PrintErr(result, "bufferQueue->Enqueue");
300             if(SL_RESULT_SUCCESS != result)
301             {
302                 mDevice->handleDisconnect("Failed to queue audio: 0x%08x", result);
303                 break;
304             }
305
306             data.first.len--;
307             data.first.buf += mDevice->UpdateSize*mFrameSize;
308         }
309     }
310
311     return 0;
312 }
313
314
315 void OpenSLPlayback::open(const char *name)
316 {
317     if(!name)
318         name = opensl_device;
319     else if(strcmp(name, opensl_device) != 0)
320         throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%s\" not found",
321             name};
322
323     /* There's only one device, so if it's already open, there's nothing to do. */
324     if(mEngineObj) return;
325
326     // create engine
327     SLresult result{slCreateEngine(&mEngineObj, 0, nullptr, 0, nullptr, nullptr)};
328     PrintErr(result, "slCreateEngine");
329     if(SL_RESULT_SUCCESS == result)
330     {
331         result = VCALL(mEngineObj,Realize)(SL_BOOLEAN_FALSE);
332         PrintErr(result, "engine->Realize");
333     }
334     if(SL_RESULT_SUCCESS == result)
335     {
336         result = VCALL(mEngineObj,GetInterface)(SL_IID_ENGINE, &mEngine);
337         PrintErr(result, "engine->GetInterface");
338     }
339     if(SL_RESULT_SUCCESS == result)
340     {
341         result = VCALL(mEngine,CreateOutputMix)(&mOutputMix, 0, nullptr, nullptr);
342         PrintErr(result, "engine->CreateOutputMix");
343     }
344     if(SL_RESULT_SUCCESS == result)
345     {
346         result = VCALL(mOutputMix,Realize)(SL_BOOLEAN_FALSE);
347         PrintErr(result, "outputMix->Realize");
348     }
349
350     if(SL_RESULT_SUCCESS != result)
351     {
352         if(mOutputMix)
353             VCALL0(mOutputMix,Destroy)();
354         mOutputMix = nullptr;
355
356         if(mEngineObj)
357             VCALL0(mEngineObj,Destroy)();
358         mEngineObj = nullptr;
359         mEngine = nullptr;
360
361         throw al::backend_exception{al::backend_error::DeviceError,
362             "Failed to initialize OpenSL device: 0x%08x", result};
363     }
364
365     mDevice->DeviceName = name;
366 }
367
368 bool OpenSLPlayback::reset()
369 {
370     SLresult result;
371
372     if(mBufferQueueObj)
373         VCALL0(mBufferQueueObj,Destroy)();
374     mBufferQueueObj = nullptr;
375
376     mRing = nullptr;
377
378 #if 0
379     if(!mDevice->Flags.get<FrequencyRequest>())
380     {
381         /* FIXME: Disabled until I figure out how to get the Context needed for
382          * the getSystemService call.
383          */
384         JNIEnv *env = Android_GetJNIEnv();
385         jobject jctx = Android_GetContext();
386
387         /* Get necessary stuff for using java.lang.Integer,
388          * android.content.Context, and android.media.AudioManager.
389          */
390         jclass int_cls = JCALL(env,FindClass)("java/lang/Integer");
391         jmethodID int_parseint = JCALL(env,GetStaticMethodID)(int_cls,
392             "parseInt", "(Ljava/lang/String;)I"
393         );
394         TRACE("Integer: %p, parseInt: %p\n", int_cls, int_parseint);
395
396         jclass ctx_cls = JCALL(env,FindClass)("android/content/Context");
397         jfieldID ctx_audsvc = JCALL(env,GetStaticFieldID)(ctx_cls,
398             "AUDIO_SERVICE", "Ljava/lang/String;"
399         );
400         jmethodID ctx_getSysSvc = JCALL(env,GetMethodID)(ctx_cls,
401             "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;"
402         );
403         TRACE("Context: %p, AUDIO_SERVICE: %p, getSystemService: %p\n",
404               ctx_cls, ctx_audsvc, ctx_getSysSvc);
405
406         jclass audmgr_cls = JCALL(env,FindClass)("android/media/AudioManager");
407         jfieldID audmgr_prop_out_srate = JCALL(env,GetStaticFieldID)(audmgr_cls,
408             "PROPERTY_OUTPUT_SAMPLE_RATE", "Ljava/lang/String;"
409         );
410         jmethodID audmgr_getproperty = JCALL(env,GetMethodID)(audmgr_cls,
411             "getProperty", "(Ljava/lang/String;)Ljava/lang/String;"
412         );
413         TRACE("AudioManager: %p, PROPERTY_OUTPUT_SAMPLE_RATE: %p, getProperty: %p\n",
414               audmgr_cls, audmgr_prop_out_srate, audmgr_getproperty);
415
416         const char *strchars;
417         jstring strobj;
418
419         /* Now make the calls. */
420         //AudioManager audMgr = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
421         strobj = JCALL(env,GetStaticObjectField)(ctx_cls, ctx_audsvc);
422         jobject audMgr = JCALL(env,CallObjectMethod)(jctx, ctx_getSysSvc, strobj);
423         strchars = JCALL(env,GetStringUTFChars)(strobj, nullptr);
424         TRACE("Context.getSystemService(%s) = %p\n", strchars, audMgr);
425         JCALL(env,ReleaseStringUTFChars)(strobj, strchars);
426
427         //String srateStr = audMgr.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE);
428         strobj = JCALL(env,GetStaticObjectField)(audmgr_cls, audmgr_prop_out_srate);
429         jstring srateStr = JCALL(env,CallObjectMethod)(audMgr, audmgr_getproperty, strobj);
430         strchars = JCALL(env,GetStringUTFChars)(strobj, nullptr);
431         TRACE("audMgr.getProperty(%s) = %p\n", strchars, srateStr);
432         JCALL(env,ReleaseStringUTFChars)(strobj, strchars);
433
434         //int sampleRate = Integer.parseInt(srateStr);
435         sampleRate = JCALL(env,CallStaticIntMethod)(int_cls, int_parseint, srateStr);
436
437         strchars = JCALL(env,GetStringUTFChars)(srateStr, nullptr);
438         TRACE("Got system sample rate %uhz (%s)\n", sampleRate, strchars);
439         JCALL(env,ReleaseStringUTFChars)(srateStr, strchars);
440
441         if(!sampleRate) sampleRate = device->Frequency;
442         else sampleRate = maxu(sampleRate, MIN_OUTPUT_RATE);
443     }
444 #endif
445
446     mDevice->FmtChans = DevFmtStereo;
447     mDevice->FmtType = DevFmtShort;
448
449     setDefaultWFXChannelOrder();
450     mFrameSize = mDevice->frameSizeFromFmt();
451
452
453     const std::array<SLInterfaceID,2> ids{{ SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION }};
454     const std::array<SLboolean,2> reqs{{ SL_BOOLEAN_TRUE, SL_BOOLEAN_FALSE }};
455
456     SLDataLocator_OutputMix loc_outmix{};
457     loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
458     loc_outmix.outputMix = mOutputMix;
459
460     SLDataSink audioSnk{};
461     audioSnk.pLocator = &loc_outmix;
462     audioSnk.pFormat = nullptr;
463
464     SLDataLocator_AndroidSimpleBufferQueue loc_bufq{};
465     loc_bufq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
466     loc_bufq.numBuffers = mDevice->BufferSize / mDevice->UpdateSize;
467
468     SLDataSource audioSrc{};
469 #ifdef SL_ANDROID_DATAFORMAT_PCM_EX
470     SLAndroidDataFormat_PCM_EX format_pcm_ex{};
471     format_pcm_ex.formatType = SL_ANDROID_DATAFORMAT_PCM_EX;
472     format_pcm_ex.numChannels = mDevice->channelsFromFmt();
473     format_pcm_ex.sampleRate = mDevice->Frequency * 1000;
474     format_pcm_ex.bitsPerSample = mDevice->bytesFromFmt() * 8;
475     format_pcm_ex.containerSize = format_pcm_ex.bitsPerSample;
476     format_pcm_ex.channelMask = GetChannelMask(mDevice->FmtChans);
477     format_pcm_ex.endianness = GetByteOrderEndianness();
478     format_pcm_ex.representation = GetTypeRepresentation(mDevice->FmtType);
479
480     audioSrc.pLocator = &loc_bufq;
481     audioSrc.pFormat = &format_pcm_ex;
482
483     result = VCALL(mEngine,CreateAudioPlayer)(&mBufferQueueObj, &audioSrc, &audioSnk, ids.size(),
484         ids.data(), reqs.data());
485     if(SL_RESULT_SUCCESS != result)
486 #endif
487     {
488         /* Alter sample type according to what SLDataFormat_PCM can support. */
489         switch(mDevice->FmtType)
490         {
491         case DevFmtByte: mDevice->FmtType = DevFmtUByte; break;
492         case DevFmtUInt: mDevice->FmtType = DevFmtInt; break;
493         case DevFmtFloat:
494         case DevFmtUShort: mDevice->FmtType = DevFmtShort; break;
495         case DevFmtUByte:
496         case DevFmtShort:
497         case DevFmtInt:
498             break;
499         }
500
501         SLDataFormat_PCM format_pcm{};
502         format_pcm.formatType = SL_DATAFORMAT_PCM;
503         format_pcm.numChannels = mDevice->channelsFromFmt();
504         format_pcm.samplesPerSec = mDevice->Frequency * 1000;
505         format_pcm.bitsPerSample = mDevice->bytesFromFmt() * 8;
506         format_pcm.containerSize = format_pcm.bitsPerSample;
507         format_pcm.channelMask = GetChannelMask(mDevice->FmtChans);
508         format_pcm.endianness = GetByteOrderEndianness();
509
510         audioSrc.pLocator = &loc_bufq;
511         audioSrc.pFormat = &format_pcm;
512
513         result = VCALL(mEngine,CreateAudioPlayer)(&mBufferQueueObj, &audioSrc, &audioSnk, ids.size(),
514             ids.data(), reqs.data());
515         PrintErr(result, "engine->CreateAudioPlayer");
516     }
517     if(SL_RESULT_SUCCESS == result)
518     {
519         /* Set the stream type to "media" (games, music, etc), if possible. */
520         SLAndroidConfigurationItf config;
521         result = VCALL(mBufferQueueObj,GetInterface)(SL_IID_ANDROIDCONFIGURATION, &config);
522         PrintErr(result, "bufferQueue->GetInterface SL_IID_ANDROIDCONFIGURATION");
523         if(SL_RESULT_SUCCESS == result)
524         {
525             SLint32 streamType = SL_ANDROID_STREAM_MEDIA;
526             result = VCALL(config,SetConfiguration)(SL_ANDROID_KEY_STREAM_TYPE, &streamType,
527                 sizeof(streamType));
528             PrintErr(result, "config->SetConfiguration");
529         }
530
531         /* Clear any error since this was optional. */
532         result = SL_RESULT_SUCCESS;
533     }
534     if(SL_RESULT_SUCCESS == result)
535     {
536         result = VCALL(mBufferQueueObj,Realize)(SL_BOOLEAN_FALSE);
537         PrintErr(result, "bufferQueue->Realize");
538     }
539     if(SL_RESULT_SUCCESS == result)
540     {
541         const uint num_updates{mDevice->BufferSize / mDevice->UpdateSize};
542         mRing = RingBuffer::Create(num_updates, mFrameSize*mDevice->UpdateSize, true);
543     }
544
545     if(SL_RESULT_SUCCESS != result)
546     {
547         if(mBufferQueueObj)
548             VCALL0(mBufferQueueObj,Destroy)();
549         mBufferQueueObj = nullptr;
550
551         return false;
552     }
553
554     return true;
555 }
556
557 void OpenSLPlayback::start()
558 {
559     mRing->reset();
560
561     SLAndroidSimpleBufferQueueItf bufferQueue;
562     SLresult result{VCALL(mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
563         &bufferQueue)};
564     PrintErr(result, "bufferQueue->GetInterface");
565     if(SL_RESULT_SUCCESS == result)
566     {
567         result = VCALL(bufferQueue,RegisterCallback)(&OpenSLPlayback::processC, this);
568         PrintErr(result, "bufferQueue->RegisterCallback");
569     }
570     if(SL_RESULT_SUCCESS != result)
571         throw al::backend_exception{al::backend_error::DeviceError,
572             "Failed to register callback: 0x%08x", result};
573
574     try {
575         mKillNow.store(false, std::memory_order_release);
576         mThread = std::thread(std::mem_fn(&OpenSLPlayback::mixerProc), this);
577     }
578     catch(std::exception& e) {
579         throw al::backend_exception{al::backend_error::DeviceError,
580             "Failed to start mixing thread: %s", e.what()};
581     }
582 }
583
584 void OpenSLPlayback::stop()
585 {
586     if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable())
587         return;
588
589     mSem.post();
590     mThread.join();
591
592     SLPlayItf player;
593     SLresult result{VCALL(mBufferQueueObj,GetInterface)(SL_IID_PLAY, &player)};
594     PrintErr(result, "bufferQueue->GetInterface");
595     if(SL_RESULT_SUCCESS == result)
596     {
597         result = VCALL(player,SetPlayState)(SL_PLAYSTATE_STOPPED);
598         PrintErr(result, "player->SetPlayState");
599     }
600
601     SLAndroidSimpleBufferQueueItf bufferQueue;
602     result = VCALL(mBufferQueueObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &bufferQueue);
603     PrintErr(result, "bufferQueue->GetInterface");
604     if(SL_RESULT_SUCCESS == result)
605     {
606         result = VCALL0(bufferQueue,Clear)();
607         PrintErr(result, "bufferQueue->Clear");
608     }
609     if(SL_RESULT_SUCCESS == result)
610     {
611         result = VCALL(bufferQueue,RegisterCallback)(nullptr, nullptr);
612         PrintErr(result, "bufferQueue->RegisterCallback");
613     }
614     if(SL_RESULT_SUCCESS == result)
615     {
616         SLAndroidSimpleBufferQueueState state;
617         do {
618             std::this_thread::yield();
619             result = VCALL(bufferQueue,GetState)(&state);
620         } while(SL_RESULT_SUCCESS == result && state.count > 0);
621         PrintErr(result, "bufferQueue->GetState");
622
623         mRing->reset();
624     }
625 }
626
627 ClockLatency OpenSLPlayback::getClockLatency()
628 {
629     ClockLatency ret;
630
631     std::lock_guard<std::mutex> _{mMutex};
632     ret.ClockTime = GetDeviceClockTime(mDevice);
633     ret.Latency  = std::chrono::seconds{mRing->readSpace() * mDevice->UpdateSize};
634     ret.Latency /= mDevice->Frequency;
635
636     return ret;
637 }
638
639
640 struct OpenSLCapture final : public BackendBase {
641     OpenSLCapture(DeviceBase *device) noexcept : BackendBase{device} { }
642     ~OpenSLCapture() override;
643
644     void process(SLAndroidSimpleBufferQueueItf bq) noexcept;
645     static void processC(SLAndroidSimpleBufferQueueItf bq, void *context) noexcept
646     { static_cast<OpenSLCapture*>(context)->process(bq); }
647
648     void open(const char *name) override;
649     void start() override;
650     void stop() override;
651     void captureSamples(al::byte *buffer, uint samples) override;
652     uint availableSamples() override;
653
654     /* engine interfaces */
655     SLObjectItf mEngineObj{nullptr};
656     SLEngineItf mEngine;
657
658     /* recording interfaces */
659     SLObjectItf mRecordObj{nullptr};
660
661     RingBufferPtr mRing{nullptr};
662     uint mSplOffset{0u};
663
664     uint mFrameSize{0};
665
666     DEF_NEWDEL(OpenSLCapture)
667 };
668
669 OpenSLCapture::~OpenSLCapture()
670 {
671     if(mRecordObj)
672         VCALL0(mRecordObj,Destroy)();
673     mRecordObj = nullptr;
674
675     if(mEngineObj)
676         VCALL0(mEngineObj,Destroy)();
677     mEngineObj = nullptr;
678     mEngine = nullptr;
679 }
680
681
682 void OpenSLCapture::process(SLAndroidSimpleBufferQueueItf) noexcept
683 {
684     /* A new chunk has been written into the ring buffer, advance it. */
685     mRing->writeAdvance(1);
686 }
687
688
689 void OpenSLCapture::open(const char* name)
690 {
691     if(!name)
692         name = opensl_device;
693     else if(strcmp(name, opensl_device) != 0)
694         throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%s\" not found",
695             name};
696
697     SLresult result{slCreateEngine(&mEngineObj, 0, nullptr, 0, nullptr, nullptr)};
698     PrintErr(result, "slCreateEngine");
699     if(SL_RESULT_SUCCESS == result)
700     {
701         result = VCALL(mEngineObj,Realize)(SL_BOOLEAN_FALSE);
702         PrintErr(result, "engine->Realize");
703     }
704     if(SL_RESULT_SUCCESS == result)
705     {
706         result = VCALL(mEngineObj,GetInterface)(SL_IID_ENGINE, &mEngine);
707         PrintErr(result, "engine->GetInterface");
708     }
709     if(SL_RESULT_SUCCESS == result)
710     {
711         mFrameSize = mDevice->frameSizeFromFmt();
712         /* Ensure the total length is at least 100ms */
713         uint length{maxu(mDevice->BufferSize, mDevice->Frequency/10)};
714         /* Ensure the per-chunk length is at least 10ms, and no more than 50ms. */
715         uint update_len{clampu(mDevice->BufferSize/3, mDevice->Frequency/100,
716             mDevice->Frequency/100*5)};
717         uint num_updates{(length+update_len-1) / update_len};
718
719         mRing = RingBuffer::Create(num_updates, update_len*mFrameSize, false);
720
721         mDevice->UpdateSize = update_len;
722         mDevice->BufferSize = static_cast<uint>(mRing->writeSpace() * update_len);
723     }
724     if(SL_RESULT_SUCCESS == result)
725     {
726         const std::array<SLInterfaceID,2> ids{{ SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION }};
727         const std::array<SLboolean,2> reqs{{ SL_BOOLEAN_TRUE, SL_BOOLEAN_FALSE }};
728
729         SLDataLocator_IODevice loc_dev{};
730         loc_dev.locatorType = SL_DATALOCATOR_IODEVICE;
731         loc_dev.deviceType = SL_IODEVICE_AUDIOINPUT;
732         loc_dev.deviceID = SL_DEFAULTDEVICEID_AUDIOINPUT;
733         loc_dev.device = nullptr;
734
735         SLDataSource audioSrc{};
736         audioSrc.pLocator = &loc_dev;
737         audioSrc.pFormat = nullptr;
738
739         SLDataLocator_AndroidSimpleBufferQueue loc_bq{};
740         loc_bq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
741         loc_bq.numBuffers = mDevice->BufferSize / mDevice->UpdateSize;
742
743         SLDataSink audioSnk{};
744 #ifdef SL_ANDROID_DATAFORMAT_PCM_EX
745         SLAndroidDataFormat_PCM_EX format_pcm_ex{};
746         format_pcm_ex.formatType = SL_ANDROID_DATAFORMAT_PCM_EX;
747         format_pcm_ex.numChannels = mDevice->channelsFromFmt();
748         format_pcm_ex.sampleRate = mDevice->Frequency * 1000;
749         format_pcm_ex.bitsPerSample = mDevice->bytesFromFmt() * 8;
750         format_pcm_ex.containerSize = format_pcm_ex.bitsPerSample;
751         format_pcm_ex.channelMask = GetChannelMask(mDevice->FmtChans);
752         format_pcm_ex.endianness = GetByteOrderEndianness();
753         format_pcm_ex.representation = GetTypeRepresentation(mDevice->FmtType);
754
755         audioSnk.pLocator = &loc_bq;
756         audioSnk.pFormat = &format_pcm_ex;
757         result = VCALL(mEngine,CreateAudioRecorder)(&mRecordObj, &audioSrc, &audioSnk,
758             ids.size(), ids.data(), reqs.data());
759         if(SL_RESULT_SUCCESS != result)
760 #endif
761         {
762             /* Fallback to SLDataFormat_PCM only if it supports the desired
763              * sample type.
764              */
765             if(mDevice->FmtType == DevFmtUByte || mDevice->FmtType == DevFmtShort
766                 || mDevice->FmtType == DevFmtInt)
767             {
768                 SLDataFormat_PCM format_pcm{};
769                 format_pcm.formatType = SL_DATAFORMAT_PCM;
770                 format_pcm.numChannels = mDevice->channelsFromFmt();
771                 format_pcm.samplesPerSec = mDevice->Frequency * 1000;
772                 format_pcm.bitsPerSample = mDevice->bytesFromFmt() * 8;
773                 format_pcm.containerSize = format_pcm.bitsPerSample;
774                 format_pcm.channelMask = GetChannelMask(mDevice->FmtChans);
775                 format_pcm.endianness = GetByteOrderEndianness();
776
777                 audioSnk.pLocator = &loc_bq;
778                 audioSnk.pFormat = &format_pcm;
779                 result = VCALL(mEngine,CreateAudioRecorder)(&mRecordObj, &audioSrc, &audioSnk,
780                     ids.size(), ids.data(), reqs.data());
781             }
782             PrintErr(result, "engine->CreateAudioRecorder");
783         }
784     }
785     if(SL_RESULT_SUCCESS == result)
786     {
787         /* Set the record preset to "generic", if possible. */
788         SLAndroidConfigurationItf config;
789         result = VCALL(mRecordObj,GetInterface)(SL_IID_ANDROIDCONFIGURATION, &config);
790         PrintErr(result, "recordObj->GetInterface SL_IID_ANDROIDCONFIGURATION");
791         if(SL_RESULT_SUCCESS == result)
792         {
793             SLuint32 preset = SL_ANDROID_RECORDING_PRESET_GENERIC;
794             result = VCALL(config,SetConfiguration)(SL_ANDROID_KEY_RECORDING_PRESET, &preset,
795                 sizeof(preset));
796             PrintErr(result, "config->SetConfiguration");
797         }
798
799         /* Clear any error since this was optional. */
800         result = SL_RESULT_SUCCESS;
801     }
802     if(SL_RESULT_SUCCESS == result)
803     {
804         result = VCALL(mRecordObj,Realize)(SL_BOOLEAN_FALSE);
805         PrintErr(result, "recordObj->Realize");
806     }
807
808     SLAndroidSimpleBufferQueueItf bufferQueue;
809     if(SL_RESULT_SUCCESS == result)
810     {
811         result = VCALL(mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &bufferQueue);
812         PrintErr(result, "recordObj->GetInterface");
813     }
814     if(SL_RESULT_SUCCESS == result)
815     {
816         result = VCALL(bufferQueue,RegisterCallback)(&OpenSLCapture::processC, this);
817         PrintErr(result, "bufferQueue->RegisterCallback");
818     }
819     if(SL_RESULT_SUCCESS == result)
820     {
821         const uint chunk_size{mDevice->UpdateSize * mFrameSize};
822         const auto silence = (mDevice->FmtType == DevFmtUByte) ? al::byte{0x80} : al::byte{0};
823
824         auto data = mRing->getWriteVector();
825         std::fill_n(data.first.buf, data.first.len*chunk_size, silence);
826         std::fill_n(data.second.buf, data.second.len*chunk_size, silence);
827         for(size_t i{0u};i < data.first.len && SL_RESULT_SUCCESS == result;i++)
828         {
829             result = VCALL(bufferQueue,Enqueue)(data.first.buf + chunk_size*i, chunk_size);
830             PrintErr(result, "bufferQueue->Enqueue");
831         }
832         for(size_t i{0u};i < data.second.len && SL_RESULT_SUCCESS == result;i++)
833         {
834             result = VCALL(bufferQueue,Enqueue)(data.second.buf + chunk_size*i, chunk_size);
835             PrintErr(result, "bufferQueue->Enqueue");
836         }
837     }
838
839     if(SL_RESULT_SUCCESS != result)
840     {
841         if(mRecordObj)
842             VCALL0(mRecordObj,Destroy)();
843         mRecordObj = nullptr;
844
845         if(mEngineObj)
846             VCALL0(mEngineObj,Destroy)();
847         mEngineObj = nullptr;
848         mEngine = nullptr;
849
850         throw al::backend_exception{al::backend_error::DeviceError,
851             "Failed to initialize OpenSL device: 0x%08x", result};
852     }
853
854     mDevice->DeviceName = name;
855 }
856
857 void OpenSLCapture::start()
858 {
859     SLRecordItf record;
860     SLresult result{VCALL(mRecordObj,GetInterface)(SL_IID_RECORD, &record)};
861     PrintErr(result, "recordObj->GetInterface");
862
863     if(SL_RESULT_SUCCESS == result)
864     {
865         result = VCALL(record,SetRecordState)(SL_RECORDSTATE_RECORDING);
866         PrintErr(result, "record->SetRecordState");
867     }
868     if(SL_RESULT_SUCCESS != result)
869         throw al::backend_exception{al::backend_error::DeviceError,
870             "Failed to start capture: 0x%08x", result};
871 }
872
873 void OpenSLCapture::stop()
874 {
875     SLRecordItf record;
876     SLresult result{VCALL(mRecordObj,GetInterface)(SL_IID_RECORD, &record)};
877     PrintErr(result, "recordObj->GetInterface");
878
879     if(SL_RESULT_SUCCESS == result)
880     {
881         result = VCALL(record,SetRecordState)(SL_RECORDSTATE_PAUSED);
882         PrintErr(result, "record->SetRecordState");
883     }
884 }
885
886 void OpenSLCapture::captureSamples(al::byte *buffer, uint samples)
887 {
888     const uint update_size{mDevice->UpdateSize};
889     const uint chunk_size{update_size * mFrameSize};
890
891     /* Read the desired samples from the ring buffer then advance its read
892      * pointer.
893      */
894     size_t adv_count{0};
895     auto rdata = mRing->getReadVector();
896     for(uint i{0};i < samples;)
897     {
898         const uint rem{minu(samples - i, update_size - mSplOffset)};
899         std::copy_n(rdata.first.buf + mSplOffset*size_t{mFrameSize}, rem*size_t{mFrameSize},
900             buffer + i*size_t{mFrameSize});
901
902         mSplOffset += rem;
903         if(mSplOffset == update_size)
904         {
905             /* Finished a chunk, reset the offset and advance the read pointer. */
906             mSplOffset = 0;
907
908             ++adv_count;
909             rdata.first.len -= 1;
910             if(!rdata.first.len)
911                 rdata.first = rdata.second;
912             else
913                 rdata.first.buf += chunk_size;
914         }
915
916         i += rem;
917     }
918
919     SLAndroidSimpleBufferQueueItf bufferQueue{};
920     if(mDevice->Connected.load(std::memory_order_acquire)) LIKELY
921     {
922         const SLresult result{VCALL(mRecordObj,GetInterface)(SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
923             &bufferQueue)};
924         PrintErr(result, "recordObj->GetInterface");
925         if(SL_RESULT_SUCCESS != result) UNLIKELY
926         {
927             mDevice->handleDisconnect("Failed to get capture buffer queue: 0x%08x", result);
928             bufferQueue = nullptr;
929         }
930     }
931     if(!bufferQueue || adv_count == 0)
932         return;
933
934     /* For each buffer chunk that was fully read, queue another writable buffer
935      * chunk to keep the OpenSL queue full. This is rather convulated, as a
936      * result of the ring buffer holding more elements than are writable at a
937      * given time. The end of the write vector increments when the read pointer
938      * advances, which will "expose" a previously unwritable element. So for
939      * every element that we've finished reading, we queue that many elements
940      * from the end of the write vector.
941      */
942     mRing->readAdvance(adv_count);
943
944     SLresult result{SL_RESULT_SUCCESS};
945     auto wdata = mRing->getWriteVector();
946     if(adv_count > wdata.second.len) LIKELY
947     {
948         auto len1 = std::min(wdata.first.len, adv_count-wdata.second.len);
949         auto buf1 = wdata.first.buf + chunk_size*(wdata.first.len-len1);
950         for(size_t i{0u};i < len1 && SL_RESULT_SUCCESS == result;i++)
951         {
952             result = VCALL(bufferQueue,Enqueue)(buf1 + chunk_size*i, chunk_size);
953             PrintErr(result, "bufferQueue->Enqueue");
954         }
955     }
956     if(wdata.second.len > 0)
957     {
958         auto len2 = std::min(wdata.second.len, adv_count);
959         auto buf2 = wdata.second.buf + chunk_size*(wdata.second.len-len2);
960         for(size_t i{0u};i < len2 && SL_RESULT_SUCCESS == result;i++)
961         {
962             result = VCALL(bufferQueue,Enqueue)(buf2 + chunk_size*i, chunk_size);
963             PrintErr(result, "bufferQueue->Enqueue");
964         }
965     }
966 }
967
968 uint OpenSLCapture::availableSamples()
969 { return static_cast<uint>(mRing->readSpace()*mDevice->UpdateSize - mSplOffset); }
970
971 } // namespace
972
973 bool OSLBackendFactory::init() { return true; }
974
975 bool OSLBackendFactory::querySupport(BackendType type)
976 { return (type == BackendType::Playback || type == BackendType::Capture); }
977
978 std::string OSLBackendFactory::probe(BackendType type)
979 {
980     std::string outnames;
981     switch(type)
982     {
983     case BackendType::Playback:
984     case BackendType::Capture:
985         /* Includes null char. */
986         outnames.append(opensl_device, sizeof(opensl_device));
987         break;
988     }
989     return outnames;
990 }
991
992 BackendPtr OSLBackendFactory::createBackend(DeviceBase *device, BackendType type)
993 {
994     if(type == BackendType::Playback)
995         return BackendPtr{new OpenSLPlayback{device}};
996     if(type == BackendType::Capture)
997         return BackendPtr{new OpenSLCapture{device}};
998     return nullptr;
999 }
1000
1001 BackendFactory &OSLBackendFactory::getFactory()
1002 {
1003     static OSLBackendFactory factory{};
1004     return factory;
1005 }