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.

780 lines
31KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2016 - ROLI Ltd.
  5. Permission is granted to use this software under the terms of the ISC license
  6. http://www.isc.org/downloads/software-support-policy/isc-license/
  7. Permission to use, copy, modify, and/or distribute this software for any
  8. purpose with or without fee is hereby granted, provided that the above
  9. copyright notice and this permission notice appear in all copies.
  10. THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD
  11. TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
  12. FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
  13. OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
  14. USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  15. TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
  16. OF THIS SOFTWARE.
  17. -----------------------------------------------------------------------------
  18. To release a closed-source product which uses other parts of JUCE not
  19. licensed under the ISC terms, commercial licenses are available: visit
  20. www.juce.com for more information.
  21. ==============================================================================
  22. */
  23. #undef check
  24. const char* const openSLTypeName = "Android OpenSL";
  25. bool isOpenSLAvailable()
  26. {
  27. DynamicLibrary library;
  28. return library.open ("libOpenSLES.so");
  29. }
  30. //==============================================================================
  31. class OpenSLAudioIODevice : public AudioIODevice,
  32. private Thread
  33. {
  34. public:
  35. OpenSLAudioIODevice (const String& deviceName)
  36. : AudioIODevice (deviceName, openSLTypeName),
  37. Thread ("OpenSL"),
  38. callback (nullptr), sampleRate (0), deviceOpen (false),
  39. inputBuffer (2, 2), outputBuffer (2, 2)
  40. {
  41. // OpenSL has piss-poor support for determining latency, so the only way I can find to
  42. // get a number for this is by asking the AudioTrack/AudioRecord classes..
  43. AndroidAudioIODevice javaDevice (deviceName);
  44. // this is a total guess about how to calculate the latency, but seems to vaguely agree
  45. // with the devices I've tested.. YMMV
  46. inputLatency = (javaDevice.minBufferSizeIn * 2) / 3;
  47. outputLatency = (javaDevice.minBufferSizeOut * 2) / 3;
  48. const int64 longestLatency = jmax (inputLatency, outputLatency);
  49. const int64 totalLatency = inputLatency + outputLatency;
  50. inputLatency = (int) ((longestLatency * inputLatency) / totalLatency) & ~15;
  51. outputLatency = (int) ((longestLatency * outputLatency) / totalLatency) & ~15;
  52. }
  53. ~OpenSLAudioIODevice()
  54. {
  55. close();
  56. }
  57. bool openedOk() const { return engine.outputMixObject != nullptr; }
  58. StringArray getOutputChannelNames() override
  59. {
  60. StringArray s;
  61. s.add ("Left");
  62. s.add ("Right");
  63. return s;
  64. }
  65. StringArray getInputChannelNames() override
  66. {
  67. StringArray s;
  68. s.add ("Audio Input");
  69. return s;
  70. }
  71. Array<double> getAvailableSampleRates() override
  72. {
  73. static const double rates[] = { 8000.0, 16000.0, 32000.0, 44100.0, 48000.0 };
  74. Array<double> retval (rates, numElementsInArray (rates));
  75. // make sure the native sample rate is pafrt of the list
  76. double native = getNativeSampleRate();
  77. if (native != 0.0 && ! retval.contains (native))
  78. retval.add (native);
  79. return retval;
  80. }
  81. Array<int> getAvailableBufferSizes() override
  82. {
  83. // we need to offer the lowest possible buffer size which
  84. // is the native buffer size
  85. const int defaultNumMultiples = 8;
  86. const int nativeBufferSize = getNativeBufferSize();
  87. Array<int> retval;
  88. for (int i = 1; i < defaultNumMultiples; ++i)
  89. retval.add (i * nativeBufferSize);
  90. return retval;
  91. }
  92. String open (const BigInteger& inputChannels,
  93. const BigInteger& outputChannels,
  94. double requestedSampleRate,
  95. int bufferSize) override
  96. {
  97. close();
  98. lastError.clear();
  99. sampleRate = (int) requestedSampleRate;
  100. int preferredBufferSize = (bufferSize <= 0) ? getDefaultBufferSize() : bufferSize;
  101. activeOutputChans = outputChannels;
  102. activeOutputChans.setRange (2, activeOutputChans.getHighestBit(), false);
  103. numOutputChannels = activeOutputChans.countNumberOfSetBits();
  104. activeInputChans = inputChannels;
  105. activeInputChans.setRange (1, activeInputChans.getHighestBit(), false);
  106. numInputChannels = activeInputChans.countNumberOfSetBits();
  107. actualBufferSize = preferredBufferSize;
  108. inputBuffer.setSize (jmax (1, numInputChannels), actualBufferSize);
  109. outputBuffer.setSize (jmax (1, numOutputChannels), actualBufferSize);
  110. outputBuffer.clear();
  111. const int audioBuffersToEnqueue = hasLowLatencyAudioPath() ? buffersToEnqueueForLowLatency
  112. : buffersToEnqueueSlowAudio;
  113. DBG ("OpenSL: numInputChannels = " << numInputChannels
  114. << ", numOutputChannels = " << numOutputChannels
  115. << ", nativeBufferSize = " << getNativeBufferSize()
  116. << ", nativeSampleRate = " << getNativeSampleRate()
  117. << ", actualBufferSize = " << actualBufferSize
  118. << ", audioBuffersToEnqueue = " << audioBuffersToEnqueue
  119. << ", sampleRate = " << sampleRate);
  120. if (numInputChannels > 0)
  121. {
  122. if (! RuntimePermissions::isGranted (RuntimePermissions::recordAudio))
  123. {
  124. // If you hit this assert, you probably forgot to get RuntimePermissions::recordAudio
  125. // before trying to open an audio input device. This is not going to work!
  126. jassertfalse;
  127. lastError = "Error opening OpenSL input device: the app was not granted android.permission.RECORD_AUDIO";
  128. }
  129. else
  130. {
  131. recorder = engine.createRecorder (numInputChannels, sampleRate,
  132. audioBuffersToEnqueue, actualBufferSize);
  133. if (recorder == nullptr)
  134. lastError = "Error opening OpenSL input device: creating Recorder failed.";
  135. }
  136. }
  137. if (numOutputChannels > 0)
  138. {
  139. player = engine.createPlayer (numOutputChannels, sampleRate,
  140. audioBuffersToEnqueue, actualBufferSize);
  141. if (player == nullptr)
  142. lastError = "Error opening OpenSL input device: creating Player failed.";
  143. }
  144. // pre-fill buffers
  145. for (int i = 0; i < audioBuffersToEnqueue; ++i)
  146. processBuffers();
  147. startThread (8);
  148. deviceOpen = true;
  149. return lastError;
  150. }
  151. void close() override
  152. {
  153. stop();
  154. stopThread (6000);
  155. deviceOpen = false;
  156. recorder = nullptr;
  157. player = nullptr;
  158. }
  159. int getOutputLatencyInSamples() override { return outputLatency; }
  160. int getInputLatencyInSamples() override { return inputLatency; }
  161. bool isOpen() override { return deviceOpen; }
  162. int getCurrentBufferSizeSamples() override { return actualBufferSize; }
  163. int getCurrentBitDepth() override { return 16; }
  164. BigInteger getActiveOutputChannels() const override { return activeOutputChans; }
  165. BigInteger getActiveInputChannels() const override { return activeInputChans; }
  166. String getLastError() override { return lastError; }
  167. bool isPlaying() override { return callback != nullptr; }
  168. int getDefaultBufferSize() override
  169. {
  170. // Only on a Pro-Audio device will we set the lowest possible buffer size
  171. // by default. We need to be more conservative on other devices
  172. // as they may be low-latency, but still have a crappy CPU.
  173. return (isProAudioDevice() ? 1 : 6)
  174. * defaultBufferSizeIsMultipleOfNative * getNativeBufferSize();
  175. }
  176. double getCurrentSampleRate() override
  177. {
  178. return (sampleRate == 0.0 ? getNativeSampleRate() : sampleRate);
  179. }
  180. void start (AudioIODeviceCallback* newCallback) override
  181. {
  182. stop();
  183. if (deviceOpen && callback != newCallback)
  184. {
  185. if (newCallback != nullptr)
  186. newCallback->audioDeviceAboutToStart (this);
  187. setCallback (newCallback);
  188. }
  189. }
  190. void stop() override
  191. {
  192. if (AudioIODeviceCallback* const oldCallback = setCallback (nullptr))
  193. oldCallback->audioDeviceStopped();
  194. }
  195. bool setAudioPreprocessingEnabled (bool enable) override
  196. {
  197. return recorder != nullptr && recorder->setAudioPreprocessingEnabled (enable);
  198. }
  199. private:
  200. //==============================================================================
  201. CriticalSection callbackLock;
  202. AudioIODeviceCallback* callback;
  203. int actualBufferSize, sampleRate;
  204. int inputLatency, outputLatency;
  205. bool deviceOpen;
  206. String lastError;
  207. BigInteger activeOutputChans, activeInputChans;
  208. int numInputChannels, numOutputChannels;
  209. AudioSampleBuffer inputBuffer, outputBuffer;
  210. struct Player;
  211. struct Recorder;
  212. enum
  213. {
  214. // The number of buffers to enqueue needs to be at least two for the audio to use the low-latency
  215. // audio path (see "Performance" section in ndk/docs/Additional_library_docs/opensles/index.html)
  216. buffersToEnqueueForLowLatency = 2,
  217. buffersToEnqueueSlowAudio = 4,
  218. defaultBufferSizeIsMultipleOfNative = 1
  219. };
  220. //==============================================================================
  221. static String audioManagerGetProperty (const String& property)
  222. {
  223. const LocalRef<jstring> jProperty (javaString (property));
  224. const LocalRef<jstring> text ((jstring) android.activity.callObjectMethod (JuceAppActivity.audioManagerGetProperty,
  225. jProperty.get()));
  226. if (text.get() != 0)
  227. return juceString (text);
  228. return String();
  229. }
  230. static bool androidHasSystemFeature (const String& property)
  231. {
  232. const LocalRef<jstring> jProperty (javaString (property));
  233. return android.activity.callBooleanMethod (JuceAppActivity.hasSystemFeature, jProperty.get());
  234. }
  235. static double getNativeSampleRate()
  236. {
  237. return audioManagerGetProperty ("android.media.property.OUTPUT_SAMPLE_RATE").getDoubleValue();
  238. }
  239. static int getNativeBufferSize()
  240. {
  241. const int val = audioManagerGetProperty ("android.media.property.OUTPUT_FRAMES_PER_BUFFER").getIntValue();
  242. return val > 0 ? val : 512;
  243. }
  244. static bool isProAudioDevice()
  245. {
  246. return androidHasSystemFeature ("android.hardware.audio.pro");
  247. }
  248. static bool hasLowLatencyAudioPath()
  249. {
  250. return androidHasSystemFeature ("android.hardware.audio.low_latency");
  251. }
  252. //==============================================================================
  253. AudioIODeviceCallback* setCallback (AudioIODeviceCallback* const newCallback)
  254. {
  255. const ScopedLock sl (callbackLock);
  256. AudioIODeviceCallback* const oldCallback = callback;
  257. callback = newCallback;
  258. return oldCallback;
  259. }
  260. void processBuffers()
  261. {
  262. if (recorder != nullptr)
  263. recorder->readNextBlock (inputBuffer, *this);
  264. {
  265. const ScopedLock sl (callbackLock);
  266. if (callback != nullptr)
  267. callback->audioDeviceIOCallback (numInputChannels > 0 ? inputBuffer.getArrayOfReadPointers() : nullptr, numInputChannels,
  268. numOutputChannels > 0 ? outputBuffer.getArrayOfWritePointers() : nullptr, numOutputChannels,
  269. actualBufferSize);
  270. else
  271. outputBuffer.clear();
  272. }
  273. if (player != nullptr)
  274. player->writeBuffer (outputBuffer, *this);
  275. }
  276. void run() override
  277. {
  278. setThreadToAudioPriority();
  279. if (recorder != nullptr) recorder->start();
  280. if (player != nullptr) player->start();
  281. while (! threadShouldExit())
  282. processBuffers();
  283. }
  284. void setThreadToAudioPriority()
  285. {
  286. // see android.os.Process.THREAD_PRIORITY_AUDIO
  287. const int THREAD_PRIORITY_AUDIO = -16;
  288. jint priority = THREAD_PRIORITY_AUDIO;
  289. if (priority != android.activity.callIntMethod (JuceAppActivity.setCurrentThreadPriority, (jint) priority))
  290. DBG ("Unable to set audio thread priority: priority is still " << priority);
  291. }
  292. //==============================================================================
  293. struct Engine
  294. {
  295. Engine()
  296. : engineObject (nullptr), engineInterface (nullptr), outputMixObject (nullptr)
  297. {
  298. if (library.open ("libOpenSLES.so"))
  299. {
  300. typedef SLresult (*CreateEngineFunc) (SLObjectItf*, SLuint32, const SLEngineOption*,
  301. SLuint32, const SLInterfaceID*, const SLboolean*);
  302. if (CreateEngineFunc createEngine = (CreateEngineFunc) library.getFunction ("slCreateEngine"))
  303. {
  304. check (createEngine (&engineObject, 0, nullptr, 0, nullptr, nullptr));
  305. SLInterfaceID* SL_IID_ENGINE = (SLInterfaceID*) library.getFunction ("SL_IID_ENGINE");
  306. SL_IID_ANDROIDSIMPLEBUFFERQUEUE = (SLInterfaceID*) library.getFunction ("SL_IID_ANDROIDSIMPLEBUFFERQUEUE");
  307. SL_IID_PLAY = (SLInterfaceID*) library.getFunction ("SL_IID_PLAY");
  308. SL_IID_RECORD = (SLInterfaceID*) library.getFunction ("SL_IID_RECORD");
  309. SL_IID_ANDROIDCONFIGURATION = (SLInterfaceID*) library.getFunction ("SL_IID_ANDROIDCONFIGURATION");
  310. check ((*engineObject)->Realize (engineObject, SL_BOOLEAN_FALSE));
  311. check ((*engineObject)->GetInterface (engineObject, *SL_IID_ENGINE, &engineInterface));
  312. check ((*engineInterface)->CreateOutputMix (engineInterface, &outputMixObject, 0, nullptr, nullptr));
  313. check ((*outputMixObject)->Realize (outputMixObject, SL_BOOLEAN_FALSE));
  314. }
  315. }
  316. }
  317. ~Engine()
  318. {
  319. if (outputMixObject != nullptr) (*outputMixObject)->Destroy (outputMixObject);
  320. if (engineObject != nullptr) (*engineObject)->Destroy (engineObject);
  321. }
  322. Player* createPlayer (const int numChannels, const int sampleRate, const int numBuffers, const int bufferSize)
  323. {
  324. if (numChannels <= 0)
  325. return nullptr;
  326. ScopedPointer<Player> player (new Player (numChannels, sampleRate, *this, numBuffers, bufferSize));
  327. return player->openedOk() ? player.release() : nullptr;
  328. }
  329. Recorder* createRecorder (const int numChannels, const int sampleRate, const int numBuffers, const int bufferSize)
  330. {
  331. if (numChannels <= 0)
  332. return nullptr;
  333. ScopedPointer<Recorder> recorder (new Recorder (numChannels, sampleRate, *this, numBuffers, bufferSize));
  334. return recorder->openedOk() ? recorder.release() : nullptr;
  335. }
  336. SLObjectItf engineObject;
  337. SLEngineItf engineInterface;
  338. SLObjectItf outputMixObject;
  339. SLInterfaceID* SL_IID_ANDROIDSIMPLEBUFFERQUEUE;
  340. SLInterfaceID* SL_IID_PLAY;
  341. SLInterfaceID* SL_IID_RECORD;
  342. SLInterfaceID* SL_IID_ANDROIDCONFIGURATION;
  343. private:
  344. DynamicLibrary library;
  345. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Engine)
  346. };
  347. //==============================================================================
  348. struct BufferList
  349. {
  350. BufferList (const int numChannels_, const int numBuffers_, const int numSamples_)
  351. : numChannels (numChannels_), numBuffers (numBuffers_), numSamples (numSamples_),
  352. bufferSpace (numChannels_ * numSamples * numBuffers), nextBlock (0)
  353. {
  354. }
  355. int16* waitForFreeBuffer (Thread& threadToCheck) noexcept
  356. {
  357. while (numBlocksOut.get() == numBuffers)
  358. {
  359. dataArrived.wait (1);
  360. if (threadToCheck.threadShouldExit())
  361. return nullptr;
  362. }
  363. return getNextBuffer();
  364. }
  365. int16* getNextBuffer() noexcept
  366. {
  367. if (++nextBlock == numBuffers)
  368. nextBlock = 0;
  369. return bufferSpace + nextBlock * numChannels * numSamples;
  370. }
  371. void bufferReturned() noexcept { --numBlocksOut; dataArrived.signal(); }
  372. void bufferSent() noexcept { ++numBlocksOut; dataArrived.signal(); }
  373. int getBufferSizeBytes() const noexcept { return numChannels * numSamples * sizeof (int16); }
  374. const int numChannels, numBuffers, numSamples;
  375. private:
  376. HeapBlock<int16> bufferSpace;
  377. int nextBlock;
  378. Atomic<int> numBlocksOut;
  379. WaitableEvent dataArrived;
  380. };
  381. //==============================================================================
  382. struct Player
  383. {
  384. Player (int numChannels, int sampleRate, Engine& engine, int playerNumBuffers, int playerBufferSize)
  385. : playerObject (nullptr), playerPlay (nullptr), playerBufferQueue (nullptr),
  386. bufferList (numChannels, playerNumBuffers, playerBufferSize)
  387. {
  388. SLDataFormat_PCM pcmFormat =
  389. {
  390. SL_DATAFORMAT_PCM,
  391. (SLuint32) numChannels,
  392. (SLuint32) (sampleRate * 1000),
  393. SL_PCMSAMPLEFORMAT_FIXED_16,
  394. SL_PCMSAMPLEFORMAT_FIXED_16,
  395. (numChannels == 1) ? SL_SPEAKER_FRONT_CENTER : (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT),
  396. SL_BYTEORDER_LITTLEENDIAN
  397. };
  398. SLDataLocator_AndroidSimpleBufferQueue bufferQueue = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
  399. static_cast<SLuint32> (bufferList.numBuffers) };
  400. SLDataSource audioSrc = { &bufferQueue, &pcmFormat };
  401. SLDataLocator_OutputMix outputMix = { SL_DATALOCATOR_OUTPUTMIX, engine.outputMixObject };
  402. SLDataSink audioSink = { &outputMix, nullptr };
  403. // (SL_IID_BUFFERQUEUE is not guaranteed to remain future-proof, so use SL_IID_ANDROIDSIMPLEBUFFERQUEUE)
  404. const SLInterfaceID interfaceIDs[] = { *engine.SL_IID_ANDROIDSIMPLEBUFFERQUEUE };
  405. const SLboolean flags[] = { SL_BOOLEAN_TRUE };
  406. check ((*engine.engineInterface)->CreateAudioPlayer (engine.engineInterface, &playerObject, &audioSrc, &audioSink,
  407. 1, interfaceIDs, flags));
  408. check ((*playerObject)->Realize (playerObject, SL_BOOLEAN_FALSE));
  409. check ((*playerObject)->GetInterface (playerObject, *engine.SL_IID_PLAY, &playerPlay));
  410. check ((*playerObject)->GetInterface (playerObject, *engine.SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &playerBufferQueue));
  411. check ((*playerBufferQueue)->RegisterCallback (playerBufferQueue, staticCallback, this));
  412. }
  413. ~Player()
  414. {
  415. if (playerPlay != nullptr)
  416. check ((*playerPlay)->SetPlayState (playerPlay, SL_PLAYSTATE_STOPPED));
  417. if (playerBufferQueue != nullptr)
  418. check ((*playerBufferQueue)->Clear (playerBufferQueue));
  419. if (playerObject != nullptr)
  420. (*playerObject)->Destroy (playerObject);
  421. }
  422. bool openedOk() const noexcept { return playerBufferQueue != nullptr; }
  423. void start()
  424. {
  425. jassert (openedOk());
  426. check ((*playerPlay)->SetPlayState (playerPlay, SL_PLAYSTATE_PLAYING));
  427. }
  428. void writeBuffer (const AudioSampleBuffer& buffer, Thread& thread) noexcept
  429. {
  430. jassert (buffer.getNumChannels() == bufferList.numChannels);
  431. jassert (buffer.getNumSamples() < bufferList.numSamples * bufferList.numBuffers);
  432. int offset = 0;
  433. int numSamples = buffer.getNumSamples();
  434. while (numSamples > 0)
  435. {
  436. if (int16* const destBuffer = bufferList.waitForFreeBuffer (thread))
  437. {
  438. for (int i = 0; i < bufferList.numChannels; ++i)
  439. {
  440. typedef AudioData::Pointer<AudioData::Int16, AudioData::LittleEndian, AudioData::Interleaved, AudioData::NonConst> DstSampleType;
  441. typedef AudioData::Pointer<AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::Const> SrcSampleType;
  442. DstSampleType dstData (destBuffer + i, bufferList.numChannels);
  443. SrcSampleType srcData (buffer.getReadPointer (i, offset));
  444. dstData.convertSamples (srcData, bufferList.numSamples);
  445. }
  446. enqueueBuffer (destBuffer);
  447. numSamples -= bufferList.numSamples;
  448. offset += bufferList.numSamples;
  449. }
  450. else
  451. {
  452. break;
  453. }
  454. }
  455. }
  456. private:
  457. SLObjectItf playerObject;
  458. SLPlayItf playerPlay;
  459. SLAndroidSimpleBufferQueueItf playerBufferQueue;
  460. BufferList bufferList;
  461. void enqueueBuffer (int16* buffer) noexcept
  462. {
  463. check ((*playerBufferQueue)->Enqueue (playerBufferQueue, buffer, bufferList.getBufferSizeBytes()));
  464. bufferList.bufferSent();
  465. }
  466. static void staticCallback (SLAndroidSimpleBufferQueueItf queue, void* context) noexcept
  467. {
  468. jassert (queue == static_cast<Player*> (context)->playerBufferQueue); ignoreUnused (queue);
  469. static_cast<Player*> (context)->bufferList.bufferReturned();
  470. }
  471. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Player)
  472. };
  473. //==============================================================================
  474. struct Recorder
  475. {
  476. Recorder (int numChannels, int sampleRate, Engine& engine, const int numBuffers, const int numSamples)
  477. : recorderObject (nullptr), recorderRecord (nullptr),
  478. recorderBufferQueue (nullptr), configObject (nullptr),
  479. bufferList (numChannels, numBuffers, numSamples)
  480. {
  481. SLDataFormat_PCM pcmFormat =
  482. {
  483. SL_DATAFORMAT_PCM,
  484. (SLuint32) numChannels,
  485. (SLuint32) (sampleRate * 1000), // (sample rate units are millihertz)
  486. SL_PCMSAMPLEFORMAT_FIXED_16,
  487. SL_PCMSAMPLEFORMAT_FIXED_16,
  488. (numChannels == 1) ? SL_SPEAKER_FRONT_CENTER : (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT),
  489. SL_BYTEORDER_LITTLEENDIAN
  490. };
  491. SLDataLocator_IODevice ioDevice = { SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT, SL_DEFAULTDEVICEID_AUDIOINPUT, nullptr };
  492. SLDataSource audioSrc = { &ioDevice, nullptr };
  493. SLDataLocator_AndroidSimpleBufferQueue bufferQueue = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
  494. static_cast<SLuint32> (bufferList.numBuffers) };
  495. SLDataSink audioSink = { &bufferQueue, &pcmFormat };
  496. const SLInterfaceID interfaceIDs[] = { *engine.SL_IID_ANDROIDSIMPLEBUFFERQUEUE };
  497. const SLboolean flags[] = { SL_BOOLEAN_TRUE };
  498. if (check ((*engine.engineInterface)->CreateAudioRecorder (engine.engineInterface, &recorderObject, &audioSrc,
  499. &audioSink, 1, interfaceIDs, flags)))
  500. {
  501. if (check ((*recorderObject)->Realize (recorderObject, SL_BOOLEAN_FALSE)))
  502. {
  503. check ((*recorderObject)->GetInterface (recorderObject, *engine.SL_IID_RECORD, &recorderRecord));
  504. check ((*recorderObject)->GetInterface (recorderObject, *engine.SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &recorderBufferQueue));
  505. // not all android versions seem to have a config object
  506. SLresult result = (*recorderObject)->GetInterface (recorderObject,
  507. *engine.SL_IID_ANDROIDCONFIGURATION, &configObject);
  508. if (result != SL_RESULT_SUCCESS)
  509. configObject = nullptr;
  510. check ((*recorderBufferQueue)->RegisterCallback (recorderBufferQueue, staticCallback, this));
  511. check ((*recorderRecord)->SetRecordState (recorderRecord, SL_RECORDSTATE_STOPPED));
  512. }
  513. }
  514. }
  515. ~Recorder()
  516. {
  517. if (recorderRecord != nullptr)
  518. check ((*recorderRecord)->SetRecordState (recorderRecord, SL_RECORDSTATE_STOPPED));
  519. if (recorderBufferQueue != nullptr)
  520. check ((*recorderBufferQueue)->Clear (recorderBufferQueue));
  521. if (recorderObject != nullptr)
  522. (*recorderObject)->Destroy (recorderObject);
  523. }
  524. bool openedOk() const noexcept { return recorderBufferQueue != nullptr; }
  525. void start()
  526. {
  527. jassert (openedOk());
  528. check ((*recorderRecord)->SetRecordState (recorderRecord, SL_RECORDSTATE_RECORDING));
  529. }
  530. void readNextBlock (AudioSampleBuffer& buffer, Thread& thread)
  531. {
  532. jassert (buffer.getNumChannels() == bufferList.numChannels);
  533. jassert (buffer.getNumSamples() < bufferList.numSamples * bufferList.numBuffers);
  534. jassert ((buffer.getNumSamples() % bufferList.numSamples) == 0);
  535. int offset = 0;
  536. int numSamples = buffer.getNumSamples();
  537. while (numSamples > 0)
  538. {
  539. if (int16* const srcBuffer = bufferList.waitForFreeBuffer (thread))
  540. {
  541. for (int i = 0; i < bufferList.numChannels; ++i)
  542. {
  543. typedef AudioData::Pointer<AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::NonConst> DstSampleType;
  544. typedef AudioData::Pointer<AudioData::Int16, AudioData::LittleEndian, AudioData::Interleaved, AudioData::Const> SrcSampleType;
  545. DstSampleType dstData (buffer.getWritePointer (i, offset));
  546. SrcSampleType srcData (srcBuffer + i, bufferList.numChannels);
  547. dstData.convertSamples (srcData, bufferList.numSamples);
  548. }
  549. enqueueBuffer (srcBuffer);
  550. numSamples -= bufferList.numSamples;
  551. offset += bufferList.numSamples;
  552. }
  553. else
  554. {
  555. break;
  556. }
  557. }
  558. }
  559. bool setAudioPreprocessingEnabled (bool enable)
  560. {
  561. SLuint32 mode = enable ? SL_ANDROID_RECORDING_PRESET_GENERIC
  562. : SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION;
  563. return configObject != nullptr
  564. && check ((*configObject)->SetConfiguration (configObject, SL_ANDROID_KEY_RECORDING_PRESET, &mode, sizeof (mode)));
  565. }
  566. private:
  567. SLObjectItf recorderObject;
  568. SLRecordItf recorderRecord;
  569. SLAndroidSimpleBufferQueueItf recorderBufferQueue;
  570. SLAndroidConfigurationItf configObject;
  571. BufferList bufferList;
  572. void enqueueBuffer (int16* buffer) noexcept
  573. {
  574. check ((*recorderBufferQueue)->Enqueue (recorderBufferQueue, buffer, bufferList.getBufferSizeBytes()));
  575. bufferList.bufferSent();
  576. }
  577. static void staticCallback (SLAndroidSimpleBufferQueueItf queue, void* context) noexcept
  578. {
  579. jassert (queue == static_cast<Recorder*> (context)->recorderBufferQueue); ignoreUnused (queue);
  580. static_cast<Recorder*> (context)->bufferList.bufferReturned();
  581. }
  582. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Recorder)
  583. };
  584. //==============================================================================
  585. Engine engine;
  586. ScopedPointer<Player> player;
  587. ScopedPointer<Recorder> recorder;
  588. //==============================================================================
  589. static bool check (const SLresult result) noexcept
  590. {
  591. jassert (result == SL_RESULT_SUCCESS);
  592. return result == SL_RESULT_SUCCESS;
  593. }
  594. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenSLAudioIODevice)
  595. };
  596. //==============================================================================
  597. class OpenSLAudioDeviceType : public AudioIODeviceType
  598. {
  599. public:
  600. OpenSLAudioDeviceType() : AudioIODeviceType (openSLTypeName) {}
  601. //==============================================================================
  602. void scanForDevices() override {}
  603. StringArray getDeviceNames (bool wantInputNames) const override { return StringArray (openSLTypeName); }
  604. int getDefaultDeviceIndex (bool forInput) const override { return 0; }
  605. int getIndexOfDevice (AudioIODevice* device, bool asInput) const override { return device != nullptr ? 0 : -1; }
  606. bool hasSeparateInputsAndOutputs() const override { return false; }
  607. AudioIODevice* createDevice (const String& outputDeviceName,
  608. const String& inputDeviceName) override
  609. {
  610. ScopedPointer<OpenSLAudioIODevice> dev;
  611. if (outputDeviceName.isNotEmpty() || inputDeviceName.isNotEmpty())
  612. {
  613. dev = new OpenSLAudioIODevice (outputDeviceName.isNotEmpty() ? outputDeviceName
  614. : inputDeviceName);
  615. if (! dev->openedOk())
  616. dev = nullptr;
  617. }
  618. return dev.release();
  619. }
  620. private:
  621. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenSLAudioDeviceType)
  622. };
  623. //==============================================================================
  624. AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_OpenSLES()
  625. {
  626. return isOpenSLAvailable() ? new OpenSLAudioDeviceType() : nullptr;
  627. }