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.

633 lines
25KB

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