The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
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.

634 lines
25KB

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