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.

juce_android_OpenSL.cpp 24KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615
  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 ? (const float**) inputBuffer.getArrayOfChannels() : nullptr,
  145. numInputChannels,
  146. numOutputChannels > 0 ? outputBuffer.getArrayOfChannels() : nullptr,
  147. numOutputChannels,
  148. actualBufferSize);
  149. }
  150. else
  151. {
  152. outputBuffer.clear();
  153. }
  154. }
  155. }
  156. private:
  157. //==================================================================================================
  158. CriticalSection callbackLock;
  159. AudioIODeviceCallback* callback;
  160. int actualBufferSize, sampleRate;
  161. int inputLatency, outputLatency;
  162. bool deviceOpen;
  163. String lastError;
  164. BigInteger activeOutputChans, activeInputChans;
  165. int numInputChannels, numOutputChannels;
  166. AudioSampleBuffer inputBuffer, outputBuffer;
  167. struct Player;
  168. struct Recorder;
  169. AudioIODeviceCallback* setCallback (AudioIODeviceCallback* const newCallback)
  170. {
  171. const ScopedLock sl (callbackLock);
  172. AudioIODeviceCallback* const oldCallback = callback;
  173. callback = newCallback;
  174. return oldCallback;
  175. }
  176. //==================================================================================================
  177. struct Engine
  178. {
  179. Engine()
  180. : engineObject (nullptr), engineInterface (nullptr), outputMixObject (nullptr)
  181. {
  182. if (library.open ("libOpenSLES.so"))
  183. {
  184. typedef SLresult (*CreateEngineFunc) (SLObjectItf*, SLuint32, const SLEngineOption*, SLuint32, const SLInterfaceID*, const SLboolean*);
  185. if (CreateEngineFunc createEngine = (CreateEngineFunc) library.getFunction ("slCreateEngine"))
  186. {
  187. check (createEngine (&engineObject, 0, nullptr, 0, nullptr, nullptr));
  188. SLInterfaceID* SL_IID_ENGINE = (SLInterfaceID*) library.getFunction ("SL_IID_ENGINE");
  189. SL_IID_ANDROIDSIMPLEBUFFERQUEUE = (SLInterfaceID*) library.getFunction ("SL_IID_ANDROIDSIMPLEBUFFERQUEUE");
  190. SL_IID_PLAY = (SLInterfaceID*) library.getFunction ("SL_IID_PLAY");
  191. SL_IID_RECORD = (SLInterfaceID*) library.getFunction ("SL_IID_RECORD");
  192. check ((*engineObject)->Realize (engineObject, SL_BOOLEAN_FALSE));
  193. check ((*engineObject)->GetInterface (engineObject, *SL_IID_ENGINE, &engineInterface));
  194. check ((*engineInterface)->CreateOutputMix (engineInterface, &outputMixObject, 0, nullptr, nullptr));
  195. check ((*outputMixObject)->Realize (outputMixObject, SL_BOOLEAN_FALSE));
  196. }
  197. }
  198. }
  199. ~Engine()
  200. {
  201. if (outputMixObject != nullptr) (*outputMixObject)->Destroy (outputMixObject);
  202. if (engineObject != nullptr) (*engineObject)->Destroy (engineObject);
  203. }
  204. Player* createPlayer (const int numChannels, const int sampleRate)
  205. {
  206. if (numChannels <= 0)
  207. return nullptr;
  208. ScopedPointer<Player> player (new Player (numChannels, sampleRate, *this));
  209. return player->openedOk() ? player.release() : nullptr;
  210. }
  211. Recorder* createRecorder (const int numChannels, const int sampleRate)
  212. {
  213. if (numChannels <= 0)
  214. return nullptr;
  215. ScopedPointer<Recorder> recorder (new Recorder (numChannels, sampleRate, *this));
  216. return recorder->openedOk() ? recorder.release() : nullptr;
  217. }
  218. SLObjectItf engineObject;
  219. SLEngineItf engineInterface;
  220. SLObjectItf outputMixObject;
  221. SLInterfaceID* SL_IID_ANDROIDSIMPLEBUFFERQUEUE;
  222. SLInterfaceID* SL_IID_PLAY;
  223. SLInterfaceID* SL_IID_RECORD;
  224. private:
  225. DynamicLibrary library;
  226. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Engine)
  227. };
  228. //==================================================================================================
  229. struct BufferList
  230. {
  231. BufferList (const int numChannels_)
  232. : numChannels (numChannels_), bufferSpace (numChannels_ * numSamples * numBuffers), nextBlock (0)
  233. {
  234. }
  235. int16* waitForFreeBuffer (Thread& threadToCheck)
  236. {
  237. while (numBlocksOut.get() == numBuffers)
  238. {
  239. dataArrived.wait (1);
  240. if (threadToCheck.threadShouldExit())
  241. return nullptr;
  242. }
  243. return getNextBuffer();
  244. }
  245. int16* getNextBuffer()
  246. {
  247. if (++nextBlock == numBuffers)
  248. nextBlock = 0;
  249. return bufferSpace + nextBlock * numChannels * numSamples;
  250. }
  251. void bufferReturned() { --numBlocksOut; dataArrived.signal(); }
  252. void bufferSent() { ++numBlocksOut; dataArrived.signal(); }
  253. int getBufferSizeBytes() const { return numChannels * numSamples * sizeof (int16); }
  254. const int numChannels;
  255. enum { numSamples = 256, numBuffers = 16 };
  256. private:
  257. HeapBlock<int16> bufferSpace;
  258. int nextBlock;
  259. Atomic<int> numBlocksOut;
  260. WaitableEvent dataArrived;
  261. };
  262. //==================================================================================================
  263. struct Player
  264. {
  265. Player (int numChannels, int sampleRate, Engine& engine)
  266. : playerObject (nullptr), playerPlay (nullptr), playerBufferQueue (nullptr),
  267. bufferList (numChannels)
  268. {
  269. jassert (numChannels == 2);
  270. SLDataFormat_PCM pcmFormat =
  271. {
  272. SL_DATAFORMAT_PCM,
  273. numChannels,
  274. sampleRate * 1000, // (sample rate units are millihertz)
  275. SL_PCMSAMPLEFORMAT_FIXED_16,
  276. SL_PCMSAMPLEFORMAT_FIXED_16,
  277. SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT,
  278. SL_BYTEORDER_LITTLEENDIAN
  279. };
  280. SLDataLocator_AndroidSimpleBufferQueue bufferQueue = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, bufferList.numBuffers };
  281. SLDataSource audioSrc = { &bufferQueue, &pcmFormat };
  282. SLDataLocator_OutputMix outputMix = { SL_DATALOCATOR_OUTPUTMIX, engine.outputMixObject };
  283. SLDataSink audioSink = { &outputMix, nullptr };
  284. // (SL_IID_BUFFERQUEUE is not guaranteed to remain future-proof, so use SL_IID_ANDROIDSIMPLEBUFFERQUEUE)
  285. const SLInterfaceID interfaceIDs[] = { *engine.SL_IID_ANDROIDSIMPLEBUFFERQUEUE };
  286. const SLboolean flags[] = { SL_BOOLEAN_TRUE };
  287. check ((*engine.engineInterface)->CreateAudioPlayer (engine.engineInterface, &playerObject, &audioSrc, &audioSink,
  288. 1, interfaceIDs, flags));
  289. check ((*playerObject)->Realize (playerObject, SL_BOOLEAN_FALSE));
  290. check ((*playerObject)->GetInterface (playerObject, *engine.SL_IID_PLAY, &playerPlay));
  291. check ((*playerObject)->GetInterface (playerObject, *engine.SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &playerBufferQueue));
  292. check ((*playerBufferQueue)->RegisterCallback (playerBufferQueue, staticCallback, this));
  293. }
  294. ~Player()
  295. {
  296. if (playerPlay != nullptr)
  297. check ((*playerPlay)->SetPlayState (playerPlay, SL_PLAYSTATE_STOPPED));
  298. if (playerBufferQueue != nullptr)
  299. check ((*playerBufferQueue)->Clear (playerBufferQueue));
  300. if (playerObject != nullptr)
  301. (*playerObject)->Destroy (playerObject);
  302. }
  303. bool openedOk() const noexcept { return playerBufferQueue != nullptr; }
  304. void start()
  305. {
  306. jassert (openedOk());
  307. check ((*playerPlay)->SetPlayState (playerPlay, SL_PLAYSTATE_PLAYING));
  308. }
  309. void writeBuffer (const AudioSampleBuffer& buffer, Thread& thread)
  310. {
  311. jassert (buffer.getNumChannels() == bufferList.numChannels);
  312. jassert (buffer.getNumSamples() < bufferList.numSamples * bufferList.numBuffers);
  313. int offset = 0;
  314. int numSamples = buffer.getNumSamples();
  315. while (numSamples > 0)
  316. {
  317. int16* const destBuffer = bufferList.waitForFreeBuffer (thread);
  318. if (destBuffer == nullptr)
  319. break;
  320. for (int i = 0; i < bufferList.numChannels; ++i)
  321. {
  322. typedef AudioData::Pointer <AudioData::Int16, AudioData::LittleEndian, AudioData::Interleaved, AudioData::NonConst> DstSampleType;
  323. typedef AudioData::Pointer <AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::Const> SrcSampleType;
  324. DstSampleType dstData (destBuffer + i, bufferList.numChannels);
  325. SrcSampleType srcData (buffer.getSampleData (i, offset));
  326. dstData.convertSamples (srcData, bufferList.numSamples);
  327. }
  328. check ((*playerBufferQueue)->Enqueue (playerBufferQueue, destBuffer, bufferList.getBufferSizeBytes()));
  329. bufferList.bufferSent();
  330. numSamples -= bufferList.numSamples;
  331. offset += bufferList.numSamples;
  332. }
  333. }
  334. private:
  335. SLObjectItf playerObject;
  336. SLPlayItf playerPlay;
  337. SLAndroidSimpleBufferQueueItf playerBufferQueue;
  338. BufferList bufferList;
  339. static void staticCallback (SLAndroidSimpleBufferQueueItf queue, void* context)
  340. {
  341. jassert (queue == static_cast <Player*> (context)->playerBufferQueue); (void) queue;
  342. static_cast <Player*> (context)->bufferList.bufferReturned();
  343. }
  344. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Player)
  345. };
  346. //==================================================================================================
  347. struct Recorder
  348. {
  349. Recorder (int numChannels, int sampleRate, Engine& engine)
  350. : recorderObject (nullptr), recorderRecord (nullptr), recorderBufferQueue (nullptr),
  351. bufferList (numChannels)
  352. {
  353. jassert (numChannels == 1); // STEREO doesn't always work!!
  354. SLDataFormat_PCM pcmFormat =
  355. {
  356. SL_DATAFORMAT_PCM,
  357. numChannels,
  358. sampleRate * 1000, // (sample rate units are millihertz)
  359. SL_PCMSAMPLEFORMAT_FIXED_16,
  360. SL_PCMSAMPLEFORMAT_FIXED_16,
  361. (numChannels == 1) ? SL_SPEAKER_FRONT_CENTER : (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT),
  362. SL_BYTEORDER_LITTLEENDIAN
  363. };
  364. SLDataLocator_IODevice ioDevice = { SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT, SL_DEFAULTDEVICEID_AUDIOINPUT, nullptr };
  365. SLDataSource audioSrc = { &ioDevice, nullptr };
  366. SLDataLocator_AndroidSimpleBufferQueue bufferQueue = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, bufferList.numBuffers };
  367. SLDataSink audioSink = { &bufferQueue, &pcmFormat };
  368. const SLInterfaceID interfaceIDs[] = { *engine.SL_IID_ANDROIDSIMPLEBUFFERQUEUE };
  369. const SLboolean flags[] = { SL_BOOLEAN_TRUE };
  370. if (check ((*engine.engineInterface)->CreateAudioRecorder (engine.engineInterface, &recorderObject, &audioSrc,
  371. &audioSink, 1, interfaceIDs, flags)))
  372. {
  373. if (check ((*recorderObject)->Realize (recorderObject, SL_BOOLEAN_FALSE)))
  374. {
  375. check ((*recorderObject)->GetInterface (recorderObject, *engine.SL_IID_RECORD, &recorderRecord));
  376. check ((*recorderObject)->GetInterface (recorderObject, *engine.SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &recorderBufferQueue));
  377. check ((*recorderBufferQueue)->RegisterCallback (recorderBufferQueue, staticCallback, this));
  378. check ((*recorderRecord)->SetRecordState (recorderRecord, SL_RECORDSTATE_STOPPED));
  379. for (int i = bufferList.numBuffers; --i >= 0;)
  380. {
  381. int16* const buffer = bufferList.getNextBuffer();
  382. jassert (buffer != nullptr);
  383. enqueueBuffer (buffer);
  384. }
  385. }
  386. }
  387. }
  388. ~Recorder()
  389. {
  390. if (recorderRecord != nullptr)
  391. check ((*recorderRecord)->SetRecordState (recorderRecord, SL_RECORDSTATE_STOPPED));
  392. if (recorderBufferQueue != nullptr)
  393. check ((*recorderBufferQueue)->Clear (recorderBufferQueue));
  394. if (recorderObject != nullptr)
  395. (*recorderObject)->Destroy (recorderObject);
  396. }
  397. bool openedOk() const noexcept { return recorderBufferQueue != nullptr; }
  398. void start()
  399. {
  400. jassert (openedOk());
  401. check ((*recorderRecord)->SetRecordState (recorderRecord, SL_RECORDSTATE_RECORDING));
  402. }
  403. void readNextBlock (AudioSampleBuffer& buffer, Thread& thread)
  404. {
  405. jassert (buffer.getNumChannels() == bufferList.numChannels);
  406. jassert (buffer.getNumSamples() < bufferList.numSamples * bufferList.numBuffers);
  407. jassert ((buffer.getNumSamples() % bufferList.numSamples) == 0);
  408. int offset = 0;
  409. int numSamples = buffer.getNumSamples();
  410. while (numSamples > 0)
  411. {
  412. int16* const srcBuffer = bufferList.waitForFreeBuffer (thread);
  413. if (srcBuffer == nullptr)
  414. break;
  415. for (int i = 0; i < bufferList.numChannels; ++i)
  416. {
  417. typedef AudioData::Pointer <AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::NonConst> DstSampleType;
  418. typedef AudioData::Pointer <AudioData::Int16, AudioData::LittleEndian, AudioData::Interleaved, AudioData::Const> SrcSampleType;
  419. DstSampleType dstData (buffer.getSampleData (i, offset));
  420. SrcSampleType srcData (srcBuffer + i, bufferList.numChannels);
  421. dstData.convertSamples (srcData, bufferList.numSamples);
  422. }
  423. enqueueBuffer (srcBuffer);
  424. numSamples -= bufferList.numSamples;
  425. offset += bufferList.numSamples;
  426. }
  427. }
  428. private:
  429. SLObjectItf recorderObject;
  430. SLRecordItf recorderRecord;
  431. SLAndroidSimpleBufferQueueItf recorderBufferQueue;
  432. BufferList bufferList;
  433. void enqueueBuffer (int16* buffer)
  434. {
  435. check ((*recorderBufferQueue)->Enqueue (recorderBufferQueue, buffer, bufferList.getBufferSizeBytes()));
  436. bufferList.bufferSent();
  437. }
  438. static void staticCallback (SLAndroidSimpleBufferQueueItf queue, void* context)
  439. {
  440. jassert (queue == static_cast <Recorder*> (context)->recorderBufferQueue); (void) queue;
  441. static_cast <Recorder*> (context)->bufferList.bufferReturned();
  442. }
  443. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Recorder)
  444. };
  445. //==============================================================================
  446. Engine engine;
  447. ScopedPointer<Player> player;
  448. ScopedPointer<Recorder> recorder;
  449. //==============================================================================
  450. static bool check (const SLresult result)
  451. {
  452. jassert (result == SL_RESULT_SUCCESS);
  453. return result == SL_RESULT_SUCCESS;
  454. }
  455. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenSLAudioIODevice)
  456. };
  457. //==============================================================================
  458. class OpenSLAudioDeviceType : public AudioIODeviceType
  459. {
  460. public:
  461. OpenSLAudioDeviceType() : AudioIODeviceType (openSLTypeName) {}
  462. //==============================================================================
  463. void scanForDevices() {}
  464. StringArray getDeviceNames (bool wantInputNames) const { return StringArray (openSLTypeName); }
  465. int getDefaultDeviceIndex (bool forInput) const { return 0; }
  466. int getIndexOfDevice (AudioIODevice* device, bool asInput) const { return device != nullptr ? 0 : -1; }
  467. bool hasSeparateInputsAndOutputs() const { return false; }
  468. AudioIODevice* createDevice (const String& outputDeviceName,
  469. const String& inputDeviceName)
  470. {
  471. ScopedPointer<OpenSLAudioIODevice> dev;
  472. if (outputDeviceName.isNotEmpty() || inputDeviceName.isNotEmpty())
  473. {
  474. dev = new OpenSLAudioIODevice (outputDeviceName.isNotEmpty() ? outputDeviceName
  475. : inputDeviceName);
  476. if (! dev->openedOk())
  477. dev = nullptr;
  478. }
  479. return dev.release();
  480. }
  481. private:
  482. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenSLAudioDeviceType)
  483. };
  484. //==============================================================================
  485. AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_OpenSLES()
  486. {
  487. return isOpenSLAvailable() ? new OpenSLAudioDeviceType() : nullptr;
  488. }