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.

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