Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

614 lines
24KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2013 - Raw Material Software Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. const char* const openSLTypeName = "Android OpenSL";
  18. bool isOpenSLAvailable()
  19. {
  20. DynamicLibrary library;
  21. return library.open ("libOpenSLES.so");
  22. }
  23. //==============================================================================
  24. class OpenSLAudioIODevice : public AudioIODevice,
  25. public Thread
  26. {
  27. public:
  28. OpenSLAudioIODevice (const String& deviceName)
  29. : AudioIODevice (deviceName, openSLTypeName),
  30. Thread ("OpenSL"),
  31. callback (nullptr), sampleRate (0), deviceOpen (false),
  32. inputBuffer (2, 2), outputBuffer (2, 2)
  33. {
  34. // OpenSL has piss-poor support for determining latency, so the only way I can find to
  35. // get a number for this is by asking the AudioTrack/AudioRecord classes..
  36. AndroidAudioIODevice javaDevice (String::empty);
  37. // this is a total guess about how to calculate the latency, but seems to vaguely agree
  38. // with the devices I've tested.. YMMV
  39. inputLatency = ((javaDevice.minBufferSizeIn * 2) / 3);
  40. outputLatency = ((javaDevice.minBufferSizeOut * 2) / 3);
  41. const int longestLatency = jmax (inputLatency, outputLatency);
  42. const int totalLatency = inputLatency + outputLatency;
  43. inputLatency = ((longestLatency * inputLatency) / totalLatency) & ~15;
  44. outputLatency = ((longestLatency * outputLatency) / totalLatency) & ~15;
  45. }
  46. ~OpenSLAudioIODevice()
  47. {
  48. close();
  49. }
  50. bool openedOk() const { return engine.outputMixObject != nullptr; }
  51. StringArray getOutputChannelNames() override
  52. {
  53. StringArray s;
  54. s.add ("Left");
  55. s.add ("Right");
  56. return s;
  57. }
  58. StringArray getInputChannelNames() override
  59. {
  60. StringArray s;
  61. s.add ("Audio Input");
  62. return s;
  63. }
  64. Array<double> getAvailableSampleRates() override
  65. {
  66. static const double rates[] = { 8000.0, 16000.0, 32000.0, 44100.0, 48000.0 };
  67. return Array<double> (rates, numElementsInArray (rates));
  68. }
  69. Array<int> getAvailableBufferSizes() override
  70. {
  71. static const int sizes[] = { 256, 512, 768, 1024, 1280, 1600 }; // must all be multiples of the block size
  72. return Array<int> (sizes, numElementsInArray (sizes));
  73. }
  74. String open (const BigInteger& inputChannels,
  75. const BigInteger& outputChannels,
  76. double requestedSampleRate,
  77. int bufferSize) override
  78. {
  79. close();
  80. lastError.clear();
  81. sampleRate = (int) requestedSampleRate;
  82. int preferredBufferSize = (bufferSize <= 0) ? getDefaultBufferSize() : bufferSize;
  83. activeOutputChans = outputChannels;
  84. activeOutputChans.setRange (2, activeOutputChans.getHighestBit(), false);
  85. numOutputChannels = activeOutputChans.countNumberOfSetBits();
  86. activeInputChans = inputChannels;
  87. activeInputChans.setRange (1, activeInputChans.getHighestBit(), false);
  88. numInputChannels = activeInputChans.countNumberOfSetBits();
  89. actualBufferSize = preferredBufferSize;
  90. inputBuffer.setSize (jmax (1, numInputChannels), actualBufferSize);
  91. outputBuffer.setSize (jmax (1, numOutputChannels), actualBufferSize);
  92. outputBuffer.clear();
  93. recorder = engine.createRecorder (numInputChannels, sampleRate);
  94. player = engine.createPlayer (numOutputChannels, sampleRate);
  95. startThread (8);
  96. deviceOpen = true;
  97. return lastError;
  98. }
  99. void close() override
  100. {
  101. stop();
  102. stopThread (6000);
  103. deviceOpen = false;
  104. recorder = nullptr;
  105. player = nullptr;
  106. }
  107. int getDefaultBufferSize() override { return 1024; }
  108. int getOutputLatencyInSamples() override { return outputLatency; }
  109. int getInputLatencyInSamples() override { return inputLatency; }
  110. bool isOpen() override { return deviceOpen; }
  111. int getCurrentBufferSizeSamples() override { return actualBufferSize; }
  112. int getCurrentBitDepth() override { return 16; }
  113. double getCurrentSampleRate() override { return sampleRate; }
  114. BigInteger getActiveOutputChannels() const override { return activeOutputChans; }
  115. BigInteger getActiveInputChannels() const override { return activeInputChans; }
  116. String getLastError() override { return lastError; }
  117. bool isPlaying() override { return callback != nullptr; }
  118. void start (AudioIODeviceCallback* newCallback) override
  119. {
  120. stop();
  121. if (deviceOpen && callback != newCallback)
  122. {
  123. if (newCallback != nullptr)
  124. newCallback->audioDeviceAboutToStart (this);
  125. setCallback (newCallback);
  126. }
  127. }
  128. void stop() override
  129. {
  130. if (AudioIODeviceCallback* const oldCallback = setCallback (nullptr))
  131. oldCallback->audioDeviceStopped();
  132. }
  133. void run() override
  134. {
  135. if (recorder != nullptr) recorder->start();
  136. if (player != nullptr) player->start();
  137. while (! threadShouldExit())
  138. {
  139. if (player != nullptr) player->writeBuffer (outputBuffer, *this);
  140. if (recorder != nullptr) recorder->readNextBlock (inputBuffer, *this);
  141. const ScopedLock sl (callbackLock);
  142. if (callback != nullptr)
  143. {
  144. callback->audioDeviceIOCallback (numInputChannels > 0 ? inputBuffer.getArrayOfReadPointers() : nullptr, numInputChannels,
  145. numOutputChannels > 0 ? outputBuffer.getArrayOfWritePointers() : nullptr, numOutputChannels,
  146. actualBufferSize);
  147. }
  148. else
  149. {
  150. outputBuffer.clear();
  151. }
  152. }
  153. }
  154. private:
  155. //==================================================================================================
  156. CriticalSection callbackLock;
  157. AudioIODeviceCallback* callback;
  158. int actualBufferSize, sampleRate;
  159. int inputLatency, outputLatency;
  160. bool deviceOpen;
  161. String lastError;
  162. BigInteger activeOutputChans, activeInputChans;
  163. int numInputChannels, numOutputChannels;
  164. AudioSampleBuffer inputBuffer, outputBuffer;
  165. struct Player;
  166. struct Recorder;
  167. AudioIODeviceCallback* setCallback (AudioIODeviceCallback* const newCallback)
  168. {
  169. const ScopedLock sl (callbackLock);
  170. AudioIODeviceCallback* const oldCallback = callback;
  171. callback = newCallback;
  172. return oldCallback;
  173. }
  174. //==================================================================================================
  175. struct Engine
  176. {
  177. Engine()
  178. : engineObject (nullptr), engineInterface (nullptr), outputMixObject (nullptr)
  179. {
  180. if (library.open ("libOpenSLES.so"))
  181. {
  182. typedef SLresult (*CreateEngineFunc) (SLObjectItf*, SLuint32, const SLEngineOption*, SLuint32, const SLInterfaceID*, const SLboolean*);
  183. if (CreateEngineFunc createEngine = (CreateEngineFunc) library.getFunction ("slCreateEngine"))
  184. {
  185. check (createEngine (&engineObject, 0, nullptr, 0, nullptr, nullptr));
  186. SLInterfaceID* SL_IID_ENGINE = (SLInterfaceID*) library.getFunction ("SL_IID_ENGINE");
  187. SL_IID_ANDROIDSIMPLEBUFFERQUEUE = (SLInterfaceID*) library.getFunction ("SL_IID_ANDROIDSIMPLEBUFFERQUEUE");
  188. SL_IID_PLAY = (SLInterfaceID*) library.getFunction ("SL_IID_PLAY");
  189. SL_IID_RECORD = (SLInterfaceID*) library.getFunction ("SL_IID_RECORD");
  190. check ((*engineObject)->Realize (engineObject, SL_BOOLEAN_FALSE));
  191. check ((*engineObject)->GetInterface (engineObject, *SL_IID_ENGINE, &engineInterface));
  192. check ((*engineInterface)->CreateOutputMix (engineInterface, &outputMixObject, 0, nullptr, nullptr));
  193. check ((*outputMixObject)->Realize (outputMixObject, SL_BOOLEAN_FALSE));
  194. }
  195. }
  196. }
  197. ~Engine()
  198. {
  199. if (outputMixObject != nullptr) (*outputMixObject)->Destroy (outputMixObject);
  200. if (engineObject != nullptr) (*engineObject)->Destroy (engineObject);
  201. }
  202. Player* createPlayer (const int numChannels, const int sampleRate)
  203. {
  204. if (numChannels <= 0)
  205. return nullptr;
  206. ScopedPointer<Player> player (new Player (numChannels, sampleRate, *this));
  207. return player->openedOk() ? player.release() : nullptr;
  208. }
  209. Recorder* createRecorder (const int numChannels, const int sampleRate)
  210. {
  211. if (numChannels <= 0)
  212. return nullptr;
  213. ScopedPointer<Recorder> recorder (new Recorder (numChannels, sampleRate, *this));
  214. return recorder->openedOk() ? recorder.release() : nullptr;
  215. }
  216. SLObjectItf engineObject;
  217. SLEngineItf engineInterface;
  218. SLObjectItf outputMixObject;
  219. SLInterfaceID* SL_IID_ANDROIDSIMPLEBUFFERQUEUE;
  220. SLInterfaceID* SL_IID_PLAY;
  221. SLInterfaceID* SL_IID_RECORD;
  222. private:
  223. DynamicLibrary library;
  224. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Engine)
  225. };
  226. //==================================================================================================
  227. struct BufferList
  228. {
  229. BufferList (const int numChannels_)
  230. : numChannels (numChannels_), bufferSpace (numChannels_ * numSamples * numBuffers), nextBlock (0)
  231. {
  232. }
  233. int16* waitForFreeBuffer (Thread& threadToCheck)
  234. {
  235. while (numBlocksOut.get() == numBuffers)
  236. {
  237. dataArrived.wait (1);
  238. if (threadToCheck.threadShouldExit())
  239. return nullptr;
  240. }
  241. return getNextBuffer();
  242. }
  243. int16* getNextBuffer()
  244. {
  245. if (++nextBlock == numBuffers)
  246. nextBlock = 0;
  247. return bufferSpace + nextBlock * numChannels * numSamples;
  248. }
  249. void bufferReturned() { --numBlocksOut; dataArrived.signal(); }
  250. void bufferSent() { ++numBlocksOut; dataArrived.signal(); }
  251. int getBufferSizeBytes() const { return numChannels * numSamples * sizeof (int16); }
  252. const int numChannels;
  253. enum { numSamples = 256, numBuffers = 16 };
  254. private:
  255. HeapBlock<int16> bufferSpace;
  256. int nextBlock;
  257. Atomic<int> numBlocksOut;
  258. WaitableEvent dataArrived;
  259. };
  260. //==================================================================================================
  261. struct Player
  262. {
  263. Player (int numChannels, int sampleRate, Engine& engine)
  264. : playerObject (nullptr), playerPlay (nullptr), playerBufferQueue (nullptr),
  265. bufferList (numChannels)
  266. {
  267. jassert (numChannels == 2);
  268. SLDataFormat_PCM pcmFormat =
  269. {
  270. SL_DATAFORMAT_PCM,
  271. numChannels,
  272. sampleRate * 1000, // (sample rate units are millihertz)
  273. SL_PCMSAMPLEFORMAT_FIXED_16,
  274. SL_PCMSAMPLEFORMAT_FIXED_16,
  275. SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT,
  276. SL_BYTEORDER_LITTLEENDIAN
  277. };
  278. SLDataLocator_AndroidSimpleBufferQueue bufferQueue = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, bufferList.numBuffers };
  279. SLDataSource audioSrc = { &bufferQueue, &pcmFormat };
  280. SLDataLocator_OutputMix outputMix = { SL_DATALOCATOR_OUTPUTMIX, engine.outputMixObject };
  281. SLDataSink audioSink = { &outputMix, nullptr };
  282. // (SL_IID_BUFFERQUEUE is not guaranteed to remain future-proof, so use SL_IID_ANDROIDSIMPLEBUFFERQUEUE)
  283. const SLInterfaceID interfaceIDs[] = { *engine.SL_IID_ANDROIDSIMPLEBUFFERQUEUE };
  284. const SLboolean flags[] = { SL_BOOLEAN_TRUE };
  285. check ((*engine.engineInterface)->CreateAudioPlayer (engine.engineInterface, &playerObject, &audioSrc, &audioSink,
  286. 1, interfaceIDs, flags));
  287. check ((*playerObject)->Realize (playerObject, SL_BOOLEAN_FALSE));
  288. check ((*playerObject)->GetInterface (playerObject, *engine.SL_IID_PLAY, &playerPlay));
  289. check ((*playerObject)->GetInterface (playerObject, *engine.SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &playerBufferQueue));
  290. check ((*playerBufferQueue)->RegisterCallback (playerBufferQueue, staticCallback, this));
  291. }
  292. ~Player()
  293. {
  294. if (playerPlay != nullptr)
  295. check ((*playerPlay)->SetPlayState (playerPlay, SL_PLAYSTATE_STOPPED));
  296. if (playerBufferQueue != nullptr)
  297. check ((*playerBufferQueue)->Clear (playerBufferQueue));
  298. if (playerObject != nullptr)
  299. (*playerObject)->Destroy (playerObject);
  300. }
  301. bool openedOk() const noexcept { return playerBufferQueue != nullptr; }
  302. void start()
  303. {
  304. jassert (openedOk());
  305. check ((*playerPlay)->SetPlayState (playerPlay, SL_PLAYSTATE_PLAYING));
  306. }
  307. void writeBuffer (const AudioSampleBuffer& buffer, Thread& thread)
  308. {
  309. jassert (buffer.getNumChannels() == bufferList.numChannels);
  310. jassert (buffer.getNumSamples() < bufferList.numSamples * bufferList.numBuffers);
  311. int offset = 0;
  312. int numSamples = buffer.getNumSamples();
  313. while (numSamples > 0)
  314. {
  315. int16* const destBuffer = bufferList.waitForFreeBuffer (thread);
  316. if (destBuffer == nullptr)
  317. break;
  318. for (int i = 0; i < bufferList.numChannels; ++i)
  319. {
  320. typedef AudioData::Pointer <AudioData::Int16, AudioData::LittleEndian, AudioData::Interleaved, AudioData::NonConst> DstSampleType;
  321. typedef AudioData::Pointer <AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::Const> SrcSampleType;
  322. DstSampleType dstData (destBuffer + i, bufferList.numChannels);
  323. SrcSampleType srcData (buffer.getReadPointer (i, offset));
  324. dstData.convertSamples (srcData, bufferList.numSamples);
  325. }
  326. check ((*playerBufferQueue)->Enqueue (playerBufferQueue, destBuffer, bufferList.getBufferSizeBytes()));
  327. bufferList.bufferSent();
  328. numSamples -= bufferList.numSamples;
  329. offset += bufferList.numSamples;
  330. }
  331. }
  332. private:
  333. SLObjectItf playerObject;
  334. SLPlayItf playerPlay;
  335. SLAndroidSimpleBufferQueueItf playerBufferQueue;
  336. BufferList bufferList;
  337. static void staticCallback (SLAndroidSimpleBufferQueueItf queue, void* context)
  338. {
  339. jassert (queue == static_cast <Player*> (context)->playerBufferQueue); (void) queue;
  340. static_cast <Player*> (context)->bufferList.bufferReturned();
  341. }
  342. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Player)
  343. };
  344. //==================================================================================================
  345. struct Recorder
  346. {
  347. Recorder (int numChannels, int sampleRate, Engine& engine)
  348. : recorderObject (nullptr), recorderRecord (nullptr), recorderBufferQueue (nullptr),
  349. bufferList (numChannels)
  350. {
  351. jassert (numChannels == 1); // STEREO doesn't always work!!
  352. SLDataFormat_PCM pcmFormat =
  353. {
  354. SL_DATAFORMAT_PCM,
  355. numChannels,
  356. sampleRate * 1000, // (sample rate units are millihertz)
  357. SL_PCMSAMPLEFORMAT_FIXED_16,
  358. SL_PCMSAMPLEFORMAT_FIXED_16,
  359. (numChannels == 1) ? SL_SPEAKER_FRONT_CENTER : (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT),
  360. SL_BYTEORDER_LITTLEENDIAN
  361. };
  362. SLDataLocator_IODevice ioDevice = { SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT, SL_DEFAULTDEVICEID_AUDIOINPUT, nullptr };
  363. SLDataSource audioSrc = { &ioDevice, nullptr };
  364. SLDataLocator_AndroidSimpleBufferQueue bufferQueue = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, bufferList.numBuffers };
  365. SLDataSink audioSink = { &bufferQueue, &pcmFormat };
  366. const SLInterfaceID interfaceIDs[] = { *engine.SL_IID_ANDROIDSIMPLEBUFFERQUEUE };
  367. const SLboolean flags[] = { SL_BOOLEAN_TRUE };
  368. if (check ((*engine.engineInterface)->CreateAudioRecorder (engine.engineInterface, &recorderObject, &audioSrc,
  369. &audioSink, 1, interfaceIDs, flags)))
  370. {
  371. if (check ((*recorderObject)->Realize (recorderObject, SL_BOOLEAN_FALSE)))
  372. {
  373. check ((*recorderObject)->GetInterface (recorderObject, *engine.SL_IID_RECORD, &recorderRecord));
  374. check ((*recorderObject)->GetInterface (recorderObject, *engine.SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &recorderBufferQueue));
  375. check ((*recorderBufferQueue)->RegisterCallback (recorderBufferQueue, staticCallback, this));
  376. check ((*recorderRecord)->SetRecordState (recorderRecord, SL_RECORDSTATE_STOPPED));
  377. for (int i = bufferList.numBuffers; --i >= 0;)
  378. {
  379. int16* const buffer = bufferList.getNextBuffer();
  380. jassert (buffer != nullptr);
  381. enqueueBuffer (buffer);
  382. }
  383. }
  384. }
  385. }
  386. ~Recorder()
  387. {
  388. if (recorderRecord != nullptr)
  389. check ((*recorderRecord)->SetRecordState (recorderRecord, SL_RECORDSTATE_STOPPED));
  390. if (recorderBufferQueue != nullptr)
  391. check ((*recorderBufferQueue)->Clear (recorderBufferQueue));
  392. if (recorderObject != nullptr)
  393. (*recorderObject)->Destroy (recorderObject);
  394. }
  395. bool openedOk() const noexcept { return recorderBufferQueue != nullptr; }
  396. void start()
  397. {
  398. jassert (openedOk());
  399. check ((*recorderRecord)->SetRecordState (recorderRecord, SL_RECORDSTATE_RECORDING));
  400. }
  401. void readNextBlock (AudioSampleBuffer& buffer, Thread& thread)
  402. {
  403. jassert (buffer.getNumChannels() == bufferList.numChannels);
  404. jassert (buffer.getNumSamples() < bufferList.numSamples * bufferList.numBuffers);
  405. jassert ((buffer.getNumSamples() % bufferList.numSamples) == 0);
  406. int offset = 0;
  407. int numSamples = buffer.getNumSamples();
  408. while (numSamples > 0)
  409. {
  410. int16* const srcBuffer = bufferList.waitForFreeBuffer (thread);
  411. if (srcBuffer == nullptr)
  412. break;
  413. for (int i = 0; i < bufferList.numChannels; ++i)
  414. {
  415. typedef AudioData::Pointer <AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::NonConst> DstSampleType;
  416. typedef AudioData::Pointer <AudioData::Int16, AudioData::LittleEndian, AudioData::Interleaved, AudioData::Const> SrcSampleType;
  417. DstSampleType dstData (buffer.getWritePointer (i, offset));
  418. SrcSampleType srcData (srcBuffer + i, bufferList.numChannels);
  419. dstData.convertSamples (srcData, bufferList.numSamples);
  420. }
  421. enqueueBuffer (srcBuffer);
  422. numSamples -= bufferList.numSamples;
  423. offset += bufferList.numSamples;
  424. }
  425. }
  426. private:
  427. SLObjectItf recorderObject;
  428. SLRecordItf recorderRecord;
  429. SLAndroidSimpleBufferQueueItf recorderBufferQueue;
  430. BufferList bufferList;
  431. void enqueueBuffer (int16* buffer)
  432. {
  433. check ((*recorderBufferQueue)->Enqueue (recorderBufferQueue, buffer, bufferList.getBufferSizeBytes()));
  434. bufferList.bufferSent();
  435. }
  436. static void staticCallback (SLAndroidSimpleBufferQueueItf queue, void* context)
  437. {
  438. jassert (queue == static_cast <Recorder*> (context)->recorderBufferQueue); (void) queue;
  439. static_cast <Recorder*> (context)->bufferList.bufferReturned();
  440. }
  441. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Recorder)
  442. };
  443. //==============================================================================
  444. Engine engine;
  445. ScopedPointer<Player> player;
  446. ScopedPointer<Recorder> recorder;
  447. //==============================================================================
  448. static bool check (const SLresult result)
  449. {
  450. jassert (result == SL_RESULT_SUCCESS);
  451. return result == SL_RESULT_SUCCESS;
  452. }
  453. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenSLAudioIODevice)
  454. };
  455. //==============================================================================
  456. class OpenSLAudioDeviceType : public AudioIODeviceType
  457. {
  458. public:
  459. OpenSLAudioDeviceType() : AudioIODeviceType (openSLTypeName) {}
  460. //==============================================================================
  461. void scanForDevices() {}
  462. StringArray getDeviceNames (bool wantInputNames) const { return StringArray (openSLTypeName); }
  463. int getDefaultDeviceIndex (bool forInput) const { return 0; }
  464. int getIndexOfDevice (AudioIODevice* device, bool asInput) const { return device != nullptr ? 0 : -1; }
  465. bool hasSeparateInputsAndOutputs() const { return false; }
  466. AudioIODevice* createDevice (const String& outputDeviceName,
  467. const String& inputDeviceName)
  468. {
  469. ScopedPointer<OpenSLAudioIODevice> dev;
  470. if (outputDeviceName.isNotEmpty() || inputDeviceName.isNotEmpty())
  471. {
  472. dev = new OpenSLAudioIODevice (outputDeviceName.isNotEmpty() ? outputDeviceName
  473. : inputDeviceName);
  474. if (! dev->openedOk())
  475. dev = nullptr;
  476. }
  477. return dev.release();
  478. }
  479. private:
  480. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenSLAudioDeviceType)
  481. };
  482. //==============================================================================
  483. AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_OpenSLES()
  484. {
  485. return isOpenSLAvailable() ? new OpenSLAudioDeviceType() : nullptr;
  486. }