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.

754 lines
30KB

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