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.

1946 lines
69KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2022 - Raw Material Software Limited
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. The code included in this file is provided under the terms of the ISC license
  8. http://www.isc.org/downloads/software-support-policy/isc-license. Permission
  9. To use, copy, modify, and/or distribute this software for any purpose with or
  10. without fee is hereby granted provided that the above copyright notice and
  11. this permission notice appear in all copies.
  12. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  13. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  14. DISCLAIMED.
  15. ==============================================================================
  16. */
  17. namespace juce
  18. {
  19. template <typename Setup>
  20. static auto getSetupInfo (Setup& s, bool isInput)
  21. {
  22. struct SetupInfo
  23. {
  24. // double brackets so that we get the expression type, i.e. a (possibly const) reference
  25. decltype ((s.inputDeviceName)) name;
  26. decltype ((s.inputChannels)) channels;
  27. decltype ((s.useDefaultInputChannels)) useDefault;
  28. };
  29. return isInput ? SetupInfo { s.inputDeviceName, s.inputChannels, s.useDefaultInputChannels }
  30. : SetupInfo { s.outputDeviceName, s.outputChannels, s.useDefaultOutputChannels };
  31. }
  32. static auto tie (const AudioDeviceManager::AudioDeviceSetup& s)
  33. {
  34. return std::tie (s.outputDeviceName,
  35. s.inputDeviceName,
  36. s.sampleRate,
  37. s.bufferSize,
  38. s.inputChannels,
  39. s.useDefaultInputChannels,
  40. s.outputChannels,
  41. s.useDefaultOutputChannels);
  42. }
  43. bool AudioDeviceManager::AudioDeviceSetup::operator== (const AudioDeviceManager::AudioDeviceSetup& other) const
  44. {
  45. return tie (*this) == tie (other);
  46. }
  47. bool AudioDeviceManager::AudioDeviceSetup::operator!= (const AudioDeviceManager::AudioDeviceSetup& other) const
  48. {
  49. return tie (*this) != tie (other);
  50. }
  51. //==============================================================================
  52. class AudioDeviceManager::CallbackHandler final : public AudioIODeviceCallback,
  53. public MidiInputCallback,
  54. public AudioIODeviceType::Listener
  55. {
  56. public:
  57. CallbackHandler (AudioDeviceManager& adm) noexcept : owner (adm) {}
  58. private:
  59. void audioDeviceIOCallbackWithContext (const float* const* ins,
  60. int numIns,
  61. float* const* outs,
  62. int numOuts,
  63. int numSamples,
  64. const AudioIODeviceCallbackContext& context) override
  65. {
  66. owner.audioDeviceIOCallbackInt (ins, numIns, outs, numOuts, numSamples, context);
  67. }
  68. void audioDeviceAboutToStart (AudioIODevice* device) override
  69. {
  70. owner.audioDeviceAboutToStartInt (device);
  71. }
  72. void audioDeviceStopped() override
  73. {
  74. owner.audioDeviceStoppedInt();
  75. }
  76. void audioDeviceError (const String& message) override
  77. {
  78. owner.audioDeviceErrorInt (message);
  79. }
  80. void handleIncomingMidiMessage (MidiInput* source, const MidiMessage& message) override
  81. {
  82. owner.handleIncomingMidiMessageInt (source, message);
  83. }
  84. void audioDeviceListChanged() override
  85. {
  86. owner.audioDeviceListChanged();
  87. }
  88. AudioDeviceManager& owner;
  89. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CallbackHandler)
  90. };
  91. //==============================================================================
  92. AudioDeviceManager::AudioDeviceManager()
  93. {
  94. callbackHandler.reset (new CallbackHandler (*this));
  95. }
  96. AudioDeviceManager::~AudioDeviceManager()
  97. {
  98. currentAudioDevice.reset();
  99. defaultMidiOutput.reset();
  100. }
  101. //==============================================================================
  102. void AudioDeviceManager::createDeviceTypesIfNeeded()
  103. {
  104. if (availableDeviceTypes.size() == 0)
  105. {
  106. OwnedArray<AudioIODeviceType> types;
  107. createAudioDeviceTypes (types);
  108. for (auto* t : types)
  109. addAudioDeviceType (std::unique_ptr<AudioIODeviceType> (t));
  110. types.clear (false);
  111. for (auto* type : availableDeviceTypes)
  112. type->scanForDevices();
  113. pickCurrentDeviceTypeWithDevices();
  114. }
  115. }
  116. void AudioDeviceManager::pickCurrentDeviceTypeWithDevices()
  117. {
  118. const auto deviceTypeHasDevices = [] (const AudioIODeviceType* ptr)
  119. {
  120. return ! ptr->getDeviceNames (true) .isEmpty()
  121. || ! ptr->getDeviceNames (false).isEmpty();
  122. };
  123. if (auto* type = findType (currentDeviceType))
  124. if (deviceTypeHasDevices (type))
  125. return;
  126. const auto iter = std::find_if (availableDeviceTypes.begin(),
  127. availableDeviceTypes.end(),
  128. deviceTypeHasDevices);
  129. if (iter != availableDeviceTypes.end())
  130. currentDeviceType = (*iter)->getTypeName();
  131. }
  132. const OwnedArray<AudioIODeviceType>& AudioDeviceManager::getAvailableDeviceTypes()
  133. {
  134. scanDevicesIfNeeded();
  135. return availableDeviceTypes;
  136. }
  137. void AudioDeviceManager::updateCurrentSetup()
  138. {
  139. if (currentAudioDevice != nullptr)
  140. {
  141. currentSetup.sampleRate = currentAudioDevice->getCurrentSampleRate();
  142. currentSetup.bufferSize = currentAudioDevice->getCurrentBufferSizeSamples();
  143. currentSetup.inputChannels = currentAudioDevice->getActiveInputChannels();
  144. currentSetup.outputChannels = currentAudioDevice->getActiveOutputChannels();
  145. }
  146. }
  147. void AudioDeviceManager::audioDeviceListChanged()
  148. {
  149. if (currentAudioDevice != nullptr)
  150. {
  151. auto currentDeviceStillAvailable = [&]
  152. {
  153. auto currentTypeName = currentAudioDevice->getTypeName();
  154. auto currentDeviceName = currentAudioDevice->getName();
  155. for (auto* deviceType : availableDeviceTypes)
  156. {
  157. if (currentTypeName == deviceType->getTypeName())
  158. {
  159. for (auto& deviceName : deviceType->getDeviceNames (true))
  160. if (currentDeviceName == deviceName)
  161. return true;
  162. for (auto& deviceName : deviceType->getDeviceNames (false))
  163. if (currentDeviceName == deviceName)
  164. return true;
  165. }
  166. }
  167. return false;
  168. }();
  169. if (! currentDeviceStillAvailable)
  170. {
  171. closeAudioDevice();
  172. if (auto e = createStateXml())
  173. initialiseFromXML (*e, true, preferredDeviceName, &currentSetup);
  174. else
  175. initialiseDefault (preferredDeviceName, &currentSetup);
  176. }
  177. updateCurrentSetup();
  178. }
  179. sendChangeMessage();
  180. }
  181. void AudioDeviceManager::midiDeviceListChanged()
  182. {
  183. openLastRequestedMidiDevices (midiDeviceInfosFromXml, defaultMidiOutputDeviceInfo);
  184. sendChangeMessage();
  185. }
  186. //==============================================================================
  187. static void addIfNotNull (OwnedArray<AudioIODeviceType>& list, AudioIODeviceType* const device)
  188. {
  189. if (device != nullptr)
  190. list.add (device);
  191. }
  192. void AudioDeviceManager::createAudioDeviceTypes (OwnedArray<AudioIODeviceType>& list)
  193. {
  194. addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_WASAPI (WASAPIDeviceMode::shared));
  195. addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_WASAPI (WASAPIDeviceMode::exclusive));
  196. addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_WASAPI (WASAPIDeviceMode::sharedLowLatency));
  197. addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_DirectSound());
  198. addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_ASIO());
  199. addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_CoreAudio());
  200. addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_iOSAudio());
  201. addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_Bela());
  202. addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_ALSA());
  203. addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_JACK());
  204. addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_Oboe());
  205. addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_OpenSLES());
  206. addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_Android());
  207. }
  208. void AudioDeviceManager::addAudioDeviceType (std::unique_ptr<AudioIODeviceType> newDeviceType)
  209. {
  210. if (newDeviceType != nullptr)
  211. {
  212. jassert (lastDeviceTypeConfigs.size() == availableDeviceTypes.size());
  213. availableDeviceTypes.add (newDeviceType.release());
  214. lastDeviceTypeConfigs.add (new AudioDeviceSetup());
  215. availableDeviceTypes.getLast()->addListener (callbackHandler.get());
  216. }
  217. }
  218. void AudioDeviceManager::removeAudioDeviceType (AudioIODeviceType* deviceTypeToRemove)
  219. {
  220. if (deviceTypeToRemove != nullptr)
  221. {
  222. jassert (lastDeviceTypeConfigs.size() == availableDeviceTypes.size());
  223. auto index = availableDeviceTypes.indexOf (deviceTypeToRemove);
  224. if (auto removed = std::unique_ptr<AudioIODeviceType> (availableDeviceTypes.removeAndReturn (index)))
  225. {
  226. removed->removeListener (callbackHandler.get());
  227. lastDeviceTypeConfigs.remove (index, true);
  228. }
  229. }
  230. }
  231. static bool deviceListContains (AudioIODeviceType* type, bool isInput, const String& name)
  232. {
  233. for (auto& deviceName : type->getDeviceNames (isInput))
  234. if (deviceName.trim().equalsIgnoreCase (name.trim()))
  235. return true;
  236. return false;
  237. }
  238. //==============================================================================
  239. String AudioDeviceManager::initialise (const int numInputChannelsNeeded,
  240. const int numOutputChannelsNeeded,
  241. const XmlElement* const xml,
  242. const bool selectDefaultDeviceOnFailure,
  243. const String& preferredDefaultDeviceName,
  244. const AudioDeviceSetup* preferredSetupOptions)
  245. {
  246. scanDevicesIfNeeded();
  247. pickCurrentDeviceTypeWithDevices();
  248. numInputChansNeeded = numInputChannelsNeeded;
  249. numOutputChansNeeded = numOutputChannelsNeeded;
  250. preferredDeviceName = preferredDefaultDeviceName;
  251. if (xml != nullptr && xml->hasTagName ("DEVICESETUP"))
  252. return initialiseFromXML (*xml, selectDefaultDeviceOnFailure,
  253. preferredDeviceName, preferredSetupOptions);
  254. return initialiseDefault (preferredDeviceName, preferredSetupOptions);
  255. }
  256. String AudioDeviceManager::initialiseDefault (const String& preferredDefaultDeviceName,
  257. const AudioDeviceSetup* preferredSetupOptions)
  258. {
  259. AudioDeviceSetup setup;
  260. if (preferredSetupOptions != nullptr)
  261. {
  262. setup = *preferredSetupOptions;
  263. }
  264. else if (preferredDefaultDeviceName.isNotEmpty())
  265. {
  266. const auto nameMatches = [&preferredDefaultDeviceName] (const String& name)
  267. {
  268. return name.matchesWildcard (preferredDefaultDeviceName, true);
  269. };
  270. struct WildcardMatch
  271. {
  272. String value;
  273. bool successful;
  274. };
  275. const auto getWildcardMatch = [&nameMatches] (const StringArray& names)
  276. {
  277. const auto iter = std::find_if (names.begin(), names.end(), nameMatches);
  278. return WildcardMatch { iter != names.end() ? *iter : String(), iter != names.end() };
  279. };
  280. struct WildcardMatches
  281. {
  282. WildcardMatch input, output;
  283. };
  284. const auto getMatchesForType = [&getWildcardMatch] (const AudioIODeviceType* type)
  285. {
  286. return WildcardMatches { getWildcardMatch (type->getDeviceNames (true)),
  287. getWildcardMatch (type->getDeviceNames (false)) };
  288. };
  289. struct SearchResult
  290. {
  291. String type, input, output;
  292. };
  293. const auto result = [&]
  294. {
  295. // First, look for a device type with an input and output which matches the preferred name
  296. for (auto* type : availableDeviceTypes)
  297. {
  298. const auto matches = getMatchesForType (type);
  299. if (matches.input.successful && matches.output.successful)
  300. return SearchResult { type->getTypeName(), matches.input.value, matches.output.value };
  301. }
  302. // No device type has matching ins and outs, so fall back to a device where either the
  303. // input or output match
  304. for (auto* type : availableDeviceTypes)
  305. {
  306. const auto matches = getMatchesForType (type);
  307. if (matches.input.successful || matches.output.successful)
  308. return SearchResult { type->getTypeName(), matches.input.value, matches.output.value };
  309. }
  310. // No devices match the query, so just use the default devices from the current type
  311. return SearchResult { currentDeviceType, {}, {} };
  312. }();
  313. currentDeviceType = result.type;
  314. setup.inputDeviceName = result.input;
  315. setup.outputDeviceName = result.output;
  316. }
  317. insertDefaultDeviceNames (setup);
  318. return setAudioDeviceSetup (setup, false);
  319. }
  320. String AudioDeviceManager::initialiseFromXML (const XmlElement& xml,
  321. bool selectDefaultDeviceOnFailure,
  322. const String& preferredDefaultDeviceName,
  323. const AudioDeviceSetup* preferredSetupOptions)
  324. {
  325. lastExplicitSettings.reset (new XmlElement (xml));
  326. String error;
  327. AudioDeviceSetup setup;
  328. if (preferredSetupOptions != nullptr)
  329. setup = *preferredSetupOptions;
  330. if (xml.getStringAttribute ("audioDeviceName").isNotEmpty())
  331. {
  332. setup.inputDeviceName = setup.outputDeviceName
  333. = xml.getStringAttribute ("audioDeviceName");
  334. }
  335. else
  336. {
  337. setup.inputDeviceName = xml.getStringAttribute ("audioInputDeviceName");
  338. setup.outputDeviceName = xml.getStringAttribute ("audioOutputDeviceName");
  339. }
  340. currentDeviceType = xml.getStringAttribute ("deviceType");
  341. if (findType (currentDeviceType) == nullptr)
  342. {
  343. if (auto* type = findType (setup.inputDeviceName, setup.outputDeviceName))
  344. currentDeviceType = type->getTypeName();
  345. else if (auto* firstType = availableDeviceTypes.getFirst())
  346. currentDeviceType = firstType->getTypeName();
  347. }
  348. setup.bufferSize = xml.getIntAttribute ("audioDeviceBufferSize", setup.bufferSize);
  349. setup.sampleRate = xml.getDoubleAttribute ("audioDeviceRate", setup.sampleRate);
  350. setup.inputChannels .parseString (xml.getStringAttribute ("audioDeviceInChans", "11"), 2);
  351. setup.outputChannels.parseString (xml.getStringAttribute ("audioDeviceOutChans", "11"), 2);
  352. setup.useDefaultInputChannels = ! xml.hasAttribute ("audioDeviceInChans");
  353. setup.useDefaultOutputChannels = ! xml.hasAttribute ("audioDeviceOutChans");
  354. error = setAudioDeviceSetup (setup, true);
  355. if (error.isNotEmpty() && selectDefaultDeviceOnFailure)
  356. error = initialise (numInputChansNeeded, numOutputChansNeeded, nullptr, false, preferredDefaultDeviceName);
  357. enabledMidiInputs.clear();
  358. const auto midiInputs = [&]
  359. {
  360. Array<MidiDeviceInfo> result;
  361. for (auto* c : xml.getChildWithTagNameIterator ("MIDIINPUT"))
  362. result.add ({ c->getStringAttribute ("name"), c->getStringAttribute ("identifier") });
  363. return result;
  364. }();
  365. const MidiDeviceInfo defaultOutputDeviceInfo (xml.getStringAttribute ("defaultMidiOutput"),
  366. xml.getStringAttribute ("defaultMidiOutputDevice"));
  367. openLastRequestedMidiDevices (midiInputs, defaultOutputDeviceInfo);
  368. return error;
  369. }
  370. void AudioDeviceManager::openLastRequestedMidiDevices (const Array<MidiDeviceInfo>& desiredInputs, const MidiDeviceInfo& defaultOutput)
  371. {
  372. const auto openDeviceIfAvailable = [&] (const Array<MidiDeviceInfo>& devices,
  373. const MidiDeviceInfo& deviceToOpen,
  374. auto&& doOpen)
  375. {
  376. const auto iterWithMatchingIdentifier = std::find_if (devices.begin(), devices.end(), [&] (const auto& x)
  377. {
  378. return x.identifier == deviceToOpen.identifier;
  379. });
  380. if (iterWithMatchingIdentifier != devices.end())
  381. {
  382. doOpen (deviceToOpen.identifier);
  383. return;
  384. }
  385. const auto iterWithMatchingName = std::find_if (devices.begin(), devices.end(), [&] (const auto& x)
  386. {
  387. return x.name == deviceToOpen.name;
  388. });
  389. if (iterWithMatchingName != devices.end())
  390. doOpen (iterWithMatchingName->identifier);
  391. };
  392. midiDeviceInfosFromXml = desiredInputs;
  393. const auto inputs = MidiInput::getAvailableDevices();
  394. for (const auto& info : midiDeviceInfosFromXml)
  395. openDeviceIfAvailable (inputs, info, [&] (const auto identifier) { setMidiInputDeviceEnabled (identifier, true); });
  396. const auto outputs = MidiOutput::getAvailableDevices();
  397. openDeviceIfAvailable (outputs, defaultOutput, [&] (const auto identifier) { setDefaultMidiOutputDevice (identifier); });
  398. }
  399. String AudioDeviceManager::initialiseWithDefaultDevices (int numInputChannelsNeeded,
  400. int numOutputChannelsNeeded)
  401. {
  402. lastExplicitSettings.reset();
  403. return initialise (numInputChannelsNeeded, numOutputChannelsNeeded,
  404. nullptr, false, {}, nullptr);
  405. }
  406. void AudioDeviceManager::insertDefaultDeviceNames (AudioDeviceSetup& setup) const
  407. {
  408. enum class Direction { out, in };
  409. if (auto* type = getCurrentDeviceTypeObject())
  410. {
  411. // We avoid selecting a device pair that doesn't share a matching sample rate, if possible.
  412. // If not, other parts of the AudioDeviceManager and AudioIODevice classes should generate
  413. // an appropriate error message when opening or starting these devices.
  414. const auto getDevicesToTestForMatchingSampleRate = [&setup, type, this] (Direction dir)
  415. {
  416. const auto isInput = dir == Direction::in;
  417. const auto info = getSetupInfo (setup, isInput);
  418. if (! info.name.isEmpty())
  419. return StringArray { info.name };
  420. const auto numChannelsNeeded = isInput ? numInputChansNeeded : numOutputChansNeeded;
  421. auto deviceNames = numChannelsNeeded > 0 ? type->getDeviceNames (isInput) : StringArray {};
  422. deviceNames.move (type->getDefaultDeviceIndex (isInput), 0);
  423. return deviceNames;
  424. };
  425. std::map<std::pair<Direction, String>, Array<double>> sampleRatesCache;
  426. const auto getSupportedSampleRates = [&sampleRatesCache, type] (Direction dir, const String& deviceName)
  427. {
  428. const auto key = std::make_pair (dir, deviceName);
  429. auto& entry = [&]() -> auto&
  430. {
  431. auto it = sampleRatesCache.find (key);
  432. if (it != sampleRatesCache.end())
  433. return it->second;
  434. auto& elem = sampleRatesCache[key];
  435. auto tempDevice = rawToUniquePtr (type->createDevice ((dir == Direction::in) ? "" : deviceName,
  436. (dir == Direction::in) ? deviceName : ""));
  437. if (tempDevice != nullptr)
  438. elem = tempDevice->getAvailableSampleRates();
  439. return elem;
  440. }();
  441. return entry;
  442. };
  443. const auto validate = [&getSupportedSampleRates] (const String& outputDeviceName, const String& inputDeviceName)
  444. {
  445. jassert (! outputDeviceName.isEmpty() && ! inputDeviceName.isEmpty());
  446. const auto outputSampleRates = getSupportedSampleRates (Direction::out, outputDeviceName);
  447. const auto inputSampleRates = getSupportedSampleRates (Direction::in, inputDeviceName);
  448. return std::any_of (inputSampleRates.begin(),
  449. inputSampleRates.end(),
  450. [&] (auto inputSampleRate) { return outputSampleRates.contains (inputSampleRate); });
  451. };
  452. auto outputsToTest = getDevicesToTestForMatchingSampleRate (Direction::out);
  453. auto inputsToTest = getDevicesToTestForMatchingSampleRate (Direction::in);
  454. // We set default device names, so in case no in-out pair passes the validation, we still
  455. // produce the same result as before
  456. if (setup.outputDeviceName.isEmpty() && ! outputsToTest.isEmpty())
  457. setup.outputDeviceName = outputsToTest[0];
  458. if (setup.inputDeviceName.isEmpty() && ! inputsToTest.isEmpty())
  459. setup.inputDeviceName = inputsToTest[0];
  460. // We check all possible in-out pairs until the first validation pass. If no pair passes we
  461. // leave the setup unchanged.
  462. for (const auto& out : outputsToTest)
  463. {
  464. for (const auto& in : inputsToTest)
  465. {
  466. if (validate (out, in))
  467. {
  468. setup.outputDeviceName = out;
  469. setup.inputDeviceName = in;
  470. return;
  471. }
  472. }
  473. }
  474. }
  475. }
  476. std::unique_ptr<XmlElement> AudioDeviceManager::createStateXml() const
  477. {
  478. if (lastExplicitSettings != nullptr)
  479. return std::make_unique<XmlElement> (*lastExplicitSettings);
  480. return {};
  481. }
  482. //==============================================================================
  483. void AudioDeviceManager::scanDevicesIfNeeded()
  484. {
  485. if (listNeedsScanning)
  486. {
  487. listNeedsScanning = false;
  488. createDeviceTypesIfNeeded();
  489. for (auto* type : availableDeviceTypes)
  490. type->scanForDevices();
  491. }
  492. }
  493. AudioIODeviceType* AudioDeviceManager::findType (const String& typeName)
  494. {
  495. scanDevicesIfNeeded();
  496. for (auto* type : availableDeviceTypes)
  497. if (type->getTypeName() == typeName)
  498. return type;
  499. return {};
  500. }
  501. AudioIODeviceType* AudioDeviceManager::findType (const String& inputName, const String& outputName)
  502. {
  503. scanDevicesIfNeeded();
  504. for (auto* type : availableDeviceTypes)
  505. if ((inputName.isNotEmpty() && deviceListContains (type, true, inputName))
  506. || (outputName.isNotEmpty() && deviceListContains (type, false, outputName)))
  507. return type;
  508. return {};
  509. }
  510. AudioDeviceManager::AudioDeviceSetup AudioDeviceManager::getAudioDeviceSetup() const
  511. {
  512. return currentSetup;
  513. }
  514. void AudioDeviceManager::getAudioDeviceSetup (AudioDeviceSetup& setup) const
  515. {
  516. setup = currentSetup;
  517. }
  518. void AudioDeviceManager::deleteCurrentDevice()
  519. {
  520. currentAudioDevice.reset();
  521. currentSetup.inputDeviceName.clear();
  522. currentSetup.outputDeviceName.clear();
  523. }
  524. void AudioDeviceManager::setCurrentAudioDeviceType (const String& type, bool treatAsChosenDevice)
  525. {
  526. for (int i = 0; i < availableDeviceTypes.size(); ++i)
  527. {
  528. if (availableDeviceTypes.getUnchecked (i)->getTypeName() == type
  529. && currentDeviceType != type)
  530. {
  531. if (currentAudioDevice != nullptr)
  532. {
  533. closeAudioDevice();
  534. Thread::sleep (1500); // allow a moment for OS devices to sort themselves out, to help
  535. // avoid things like DirectSound/ASIO clashes
  536. }
  537. currentDeviceType = type;
  538. AudioDeviceSetup s (*lastDeviceTypeConfigs.getUnchecked (i));
  539. insertDefaultDeviceNames (s);
  540. setAudioDeviceSetup (s, treatAsChosenDevice);
  541. sendChangeMessage();
  542. break;
  543. }
  544. }
  545. }
  546. AudioWorkgroup AudioDeviceManager::getDeviceAudioWorkgroup() const
  547. {
  548. return currentAudioDevice != nullptr ? currentAudioDevice->getWorkgroup() : AudioWorkgroup{};
  549. }
  550. AudioIODeviceType* AudioDeviceManager::getCurrentDeviceTypeObject() const
  551. {
  552. for (auto* type : availableDeviceTypes)
  553. if (type->getTypeName() == currentDeviceType)
  554. return type;
  555. return availableDeviceTypes.getFirst();
  556. }
  557. static void updateSetupChannels (AudioDeviceManager::AudioDeviceSetup& setup, int defaultNumIns, int defaultNumOuts)
  558. {
  559. auto updateChannels = [] (const String& deviceName, BigInteger& channels, int defaultNumChannels)
  560. {
  561. if (deviceName.isEmpty())
  562. {
  563. channels.clear();
  564. }
  565. else if (defaultNumChannels != -1)
  566. {
  567. channels.clear();
  568. channels.setRange (0, defaultNumChannels, true);
  569. }
  570. };
  571. updateChannels (setup.inputDeviceName, setup.inputChannels, setup.useDefaultInputChannels ? defaultNumIns : -1);
  572. updateChannels (setup.outputDeviceName, setup.outputChannels, setup.useDefaultOutputChannels ? defaultNumOuts : -1);
  573. }
  574. String AudioDeviceManager::setAudioDeviceSetup (const AudioDeviceSetup& newSetup,
  575. bool treatAsChosenDevice)
  576. {
  577. jassert (&newSetup != &currentSetup); // this will have no effect
  578. if (newSetup != currentSetup)
  579. sendChangeMessage();
  580. else if (currentAudioDevice != nullptr)
  581. return {};
  582. stopDevice();
  583. if (getCurrentDeviceTypeObject() == nullptr
  584. || (newSetup.inputDeviceName.isEmpty() && newSetup.outputDeviceName.isEmpty()))
  585. {
  586. deleteCurrentDevice();
  587. if (treatAsChosenDevice)
  588. updateXml();
  589. return {};
  590. }
  591. String error;
  592. const auto needsNewDevice = currentSetup.inputDeviceName != newSetup.inputDeviceName
  593. || currentSetup.outputDeviceName != newSetup.outputDeviceName
  594. || currentAudioDevice == nullptr;
  595. if (needsNewDevice)
  596. {
  597. deleteCurrentDevice();
  598. scanDevicesIfNeeded();
  599. auto* type = getCurrentDeviceTypeObject();
  600. for (const auto isInput : { false, true })
  601. {
  602. const auto name = getSetupInfo (newSetup, isInput).name;
  603. if (name.isNotEmpty() && ! deviceListContains (type, isInput, name))
  604. return "No such device: " + name;
  605. }
  606. currentAudioDevice.reset (type->createDevice (newSetup.outputDeviceName, newSetup.inputDeviceName));
  607. if (currentAudioDevice == nullptr)
  608. error = "Can't open the audio device!\n\n"
  609. "This may be because another application is currently using the same device - "
  610. "if so, you should close any other applications and try again!";
  611. else
  612. error = currentAudioDevice->getLastError();
  613. if (error.isNotEmpty())
  614. {
  615. deleteCurrentDevice();
  616. return error;
  617. }
  618. }
  619. currentSetup = newSetup;
  620. if (! currentSetup.useDefaultInputChannels) numInputChansNeeded = currentSetup.inputChannels.countNumberOfSetBits();
  621. if (! currentSetup.useDefaultOutputChannels) numOutputChansNeeded = currentSetup.outputChannels.countNumberOfSetBits();
  622. updateSetupChannels (currentSetup, numInputChansNeeded, numOutputChansNeeded);
  623. if (currentSetup.inputChannels.isZero() && currentSetup.outputChannels.isZero())
  624. {
  625. if (treatAsChosenDevice)
  626. updateXml();
  627. return {};
  628. }
  629. currentSetup.sampleRate = chooseBestSampleRate (currentSetup.sampleRate);
  630. currentSetup.bufferSize = chooseBestBufferSize (currentSetup.bufferSize);
  631. error = currentAudioDevice->open (currentSetup.inputChannels,
  632. currentSetup.outputChannels,
  633. currentSetup.sampleRate,
  634. currentSetup.bufferSize);
  635. if (error.isEmpty())
  636. {
  637. currentDeviceType = currentAudioDevice->getTypeName();
  638. currentAudioDevice->start (callbackHandler.get());
  639. error = currentAudioDevice->getLastError();
  640. }
  641. if (error.isEmpty())
  642. {
  643. updateCurrentSetup();
  644. for (int i = 0; i < availableDeviceTypes.size(); ++i)
  645. if (availableDeviceTypes.getUnchecked (i)->getTypeName() == currentDeviceType)
  646. *(lastDeviceTypeConfigs.getUnchecked (i)) = currentSetup;
  647. if (treatAsChosenDevice)
  648. updateXml();
  649. }
  650. else
  651. {
  652. deleteCurrentDevice();
  653. }
  654. return error;
  655. }
  656. double AudioDeviceManager::chooseBestSampleRate (double rate) const
  657. {
  658. jassert (currentAudioDevice != nullptr);
  659. auto rates = currentAudioDevice->getAvailableSampleRates();
  660. if (rate > 0 && rates.contains (rate))
  661. return rate;
  662. rate = currentAudioDevice->getCurrentSampleRate();
  663. if (rate > 0 && rates.contains (rate))
  664. return rate;
  665. double lowestAbove44 = 0.0;
  666. for (int i = rates.size(); --i >= 0;)
  667. {
  668. auto sr = rates[i];
  669. if (sr >= 44100.0 && (lowestAbove44 < 1.0 || sr < lowestAbove44))
  670. lowestAbove44 = sr;
  671. }
  672. if (lowestAbove44 > 0.0)
  673. return lowestAbove44;
  674. return rates[0];
  675. }
  676. int AudioDeviceManager::chooseBestBufferSize (int bufferSize) const
  677. {
  678. jassert (currentAudioDevice != nullptr);
  679. if (bufferSize > 0 && currentAudioDevice->getAvailableBufferSizes().contains (bufferSize))
  680. return bufferSize;
  681. return currentAudioDevice->getDefaultBufferSize();
  682. }
  683. void AudioDeviceManager::stopDevice()
  684. {
  685. if (currentAudioDevice != nullptr)
  686. currentAudioDevice->stop();
  687. testSound.reset();
  688. }
  689. void AudioDeviceManager::closeAudioDevice()
  690. {
  691. stopDevice();
  692. currentAudioDevice.reset();
  693. loadMeasurer.reset();
  694. }
  695. void AudioDeviceManager::restartLastAudioDevice()
  696. {
  697. if (currentAudioDevice == nullptr)
  698. {
  699. if (currentSetup.inputDeviceName.isEmpty()
  700. && currentSetup.outputDeviceName.isEmpty())
  701. {
  702. // This method will only reload the last device that was running
  703. // before closeAudioDevice() was called - you need to actually open
  704. // one first, with setAudioDeviceSetup().
  705. jassertfalse;
  706. return;
  707. }
  708. AudioDeviceSetup s (currentSetup);
  709. setAudioDeviceSetup (s, false);
  710. }
  711. }
  712. void AudioDeviceManager::updateXml()
  713. {
  714. lastExplicitSettings.reset (new XmlElement ("DEVICESETUP"));
  715. lastExplicitSettings->setAttribute ("deviceType", currentDeviceType);
  716. lastExplicitSettings->setAttribute ("audioOutputDeviceName", currentSetup.outputDeviceName);
  717. lastExplicitSettings->setAttribute ("audioInputDeviceName", currentSetup.inputDeviceName);
  718. if (currentAudioDevice != nullptr)
  719. {
  720. lastExplicitSettings->setAttribute ("audioDeviceRate", currentAudioDevice->getCurrentSampleRate());
  721. if (currentAudioDevice->getDefaultBufferSize() != currentAudioDevice->getCurrentBufferSizeSamples())
  722. lastExplicitSettings->setAttribute ("audioDeviceBufferSize", currentAudioDevice->getCurrentBufferSizeSamples());
  723. if (! currentSetup.useDefaultInputChannels)
  724. lastExplicitSettings->setAttribute ("audioDeviceInChans", currentSetup.inputChannels.toString (2));
  725. if (! currentSetup.useDefaultOutputChannels)
  726. lastExplicitSettings->setAttribute ("audioDeviceOutChans", currentSetup.outputChannels.toString (2));
  727. }
  728. for (auto& input : enabledMidiInputs)
  729. {
  730. auto* child = lastExplicitSettings->createNewChildElement ("MIDIINPUT");
  731. child->setAttribute ("name", input->getName());
  732. child->setAttribute ("identifier", input->getIdentifier());
  733. }
  734. if (midiDeviceInfosFromXml.size() > 0)
  735. {
  736. // Add any midi devices that have been enabled before, but which aren't currently
  737. // open because the device has been disconnected.
  738. auto availableMidiDevices = MidiInput::getAvailableDevices();
  739. for (auto& d : midiDeviceInfosFromXml)
  740. {
  741. if (! availableMidiDevices.contains (d))
  742. {
  743. auto* child = lastExplicitSettings->createNewChildElement ("MIDIINPUT");
  744. child->setAttribute ("name", d.name);
  745. child->setAttribute ("identifier", d.identifier);
  746. }
  747. }
  748. }
  749. if (defaultMidiOutputDeviceInfo != MidiDeviceInfo())
  750. {
  751. lastExplicitSettings->setAttribute ("defaultMidiOutput", defaultMidiOutputDeviceInfo.name);
  752. lastExplicitSettings->setAttribute ("defaultMidiOutputDevice", defaultMidiOutputDeviceInfo.identifier);
  753. }
  754. }
  755. //==============================================================================
  756. void AudioDeviceManager::addAudioCallback (AudioIODeviceCallback* newCallback)
  757. {
  758. {
  759. const ScopedLock sl (audioCallbackLock);
  760. if (callbacks.contains (newCallback))
  761. return;
  762. }
  763. if (currentAudioDevice != nullptr && newCallback != nullptr)
  764. newCallback->audioDeviceAboutToStart (currentAudioDevice.get());
  765. const ScopedLock sl (audioCallbackLock);
  766. callbacks.add (newCallback);
  767. }
  768. void AudioDeviceManager::removeAudioCallback (AudioIODeviceCallback* callbackToRemove)
  769. {
  770. if (callbackToRemove != nullptr)
  771. {
  772. bool needsDeinitialising = currentAudioDevice != nullptr;
  773. {
  774. const ScopedLock sl (audioCallbackLock);
  775. needsDeinitialising = needsDeinitialising && callbacks.contains (callbackToRemove);
  776. callbacks.removeFirstMatchingValue (callbackToRemove);
  777. }
  778. if (needsDeinitialising)
  779. callbackToRemove->audioDeviceStopped();
  780. }
  781. }
  782. void AudioDeviceManager::audioDeviceIOCallbackInt (const float* const* inputChannelData,
  783. int numInputChannels,
  784. float* const* outputChannelData,
  785. int numOutputChannels,
  786. int numSamples,
  787. const AudioIODeviceCallbackContext& context)
  788. {
  789. const ScopedLock sl (audioCallbackLock);
  790. inputLevelGetter->updateLevel (inputChannelData, numInputChannels, numSamples);
  791. if (callbacks.size() > 0)
  792. {
  793. AudioProcessLoadMeasurer::ScopedTimer timer (loadMeasurer, numSamples);
  794. tempBuffer.setSize (jmax (1, numOutputChannels), jmax (1, numSamples), false, false, true);
  795. callbacks.getUnchecked (0)->audioDeviceIOCallbackWithContext (inputChannelData,
  796. numInputChannels,
  797. outputChannelData,
  798. numOutputChannels,
  799. numSamples,
  800. context);
  801. auto* const* tempChans = tempBuffer.getArrayOfWritePointers();
  802. for (int i = callbacks.size(); --i > 0;)
  803. {
  804. callbacks.getUnchecked (i)->audioDeviceIOCallbackWithContext (inputChannelData,
  805. numInputChannels,
  806. tempChans,
  807. numOutputChannels,
  808. numSamples,
  809. context);
  810. for (int chan = 0; chan < numOutputChannels; ++chan)
  811. {
  812. if (auto* src = tempChans [chan])
  813. if (auto* dst = outputChannelData [chan])
  814. for (int j = 0; j < numSamples; ++j)
  815. dst[j] += src[j];
  816. }
  817. }
  818. }
  819. else
  820. {
  821. for (int i = 0; i < numOutputChannels; ++i)
  822. zeromem (outputChannelData[i], (size_t) numSamples * sizeof (float));
  823. }
  824. if (testSound != nullptr)
  825. {
  826. auto numSamps = jmin (numSamples, testSound->getNumSamples() - testSoundPosition);
  827. auto* src = testSound->getReadPointer (0, testSoundPosition);
  828. for (int i = 0; i < numOutputChannels; ++i)
  829. if (auto* dst = outputChannelData [i])
  830. for (int j = 0; j < numSamps; ++j)
  831. dst[j] += src[j];
  832. testSoundPosition += numSamps;
  833. if (testSoundPosition >= testSound->getNumSamples())
  834. testSound.reset();
  835. }
  836. outputLevelGetter->updateLevel (outputChannelData, numOutputChannels, numSamples);
  837. }
  838. void AudioDeviceManager::audioDeviceAboutToStartInt (AudioIODevice* const device)
  839. {
  840. loadMeasurer.reset (device->getCurrentSampleRate(),
  841. device->getCurrentBufferSizeSamples());
  842. updateCurrentSetup();
  843. {
  844. const ScopedLock sl (audioCallbackLock);
  845. for (int i = callbacks.size(); --i >= 0;)
  846. callbacks.getUnchecked (i)->audioDeviceAboutToStart (device);
  847. }
  848. sendChangeMessage();
  849. }
  850. void AudioDeviceManager::audioDeviceStoppedInt()
  851. {
  852. sendChangeMessage();
  853. const ScopedLock sl (audioCallbackLock);
  854. loadMeasurer.reset();
  855. for (int i = callbacks.size(); --i >= 0;)
  856. callbacks.getUnchecked (i)->audioDeviceStopped();
  857. }
  858. void AudioDeviceManager::audioDeviceErrorInt (const String& message)
  859. {
  860. const ScopedLock sl (audioCallbackLock);
  861. for (int i = callbacks.size(); --i >= 0;)
  862. callbacks.getUnchecked (i)->audioDeviceError (message);
  863. }
  864. double AudioDeviceManager::getCpuUsage() const
  865. {
  866. return loadMeasurer.getLoadAsProportion();
  867. }
  868. //==============================================================================
  869. void AudioDeviceManager::setMidiInputDeviceEnabled (const String& identifier, bool enabled)
  870. {
  871. if (enabled != isMidiInputDeviceEnabled (identifier))
  872. {
  873. if (enabled)
  874. {
  875. if (auto midiIn = MidiInput::openDevice (identifier, callbackHandler.get()))
  876. {
  877. enabledMidiInputs.push_back (std::move (midiIn));
  878. enabledMidiInputs.back()->start();
  879. }
  880. }
  881. else
  882. {
  883. auto removePredicate = [identifier] (const std::unique_ptr<MidiInput>& in) { return in->getIdentifier() == identifier; };
  884. enabledMidiInputs.erase (std::remove_if (std::begin (enabledMidiInputs), std::end (enabledMidiInputs), removePredicate),
  885. std::end (enabledMidiInputs));
  886. }
  887. updateXml();
  888. sendChangeMessage();
  889. }
  890. }
  891. bool AudioDeviceManager::isMidiInputDeviceEnabled (const String& identifier) const
  892. {
  893. for (auto& mi : enabledMidiInputs)
  894. if (mi->getIdentifier() == identifier)
  895. return true;
  896. return false;
  897. }
  898. void AudioDeviceManager::addMidiInputDeviceCallback (const String& identifier, MidiInputCallback* callbackToAdd)
  899. {
  900. removeMidiInputDeviceCallback (identifier, callbackToAdd);
  901. if (identifier.isEmpty() || isMidiInputDeviceEnabled (identifier))
  902. {
  903. const ScopedLock sl (midiCallbackLock);
  904. midiCallbacks.add ({ identifier, callbackToAdd });
  905. }
  906. }
  907. void AudioDeviceManager::removeMidiInputDeviceCallback (const String& identifier, MidiInputCallback* callbackToRemove)
  908. {
  909. for (int i = midiCallbacks.size(); --i >= 0;)
  910. {
  911. auto& mc = midiCallbacks.getReference (i);
  912. if (mc.callback == callbackToRemove && mc.deviceIdentifier == identifier)
  913. {
  914. const ScopedLock sl (midiCallbackLock);
  915. midiCallbacks.remove (i);
  916. }
  917. }
  918. }
  919. void AudioDeviceManager::handleIncomingMidiMessageInt (MidiInput* source, const MidiMessage& message)
  920. {
  921. if (! message.isActiveSense())
  922. {
  923. const ScopedLock sl (midiCallbackLock);
  924. for (auto& mc : midiCallbacks)
  925. if (mc.deviceIdentifier.isEmpty() || mc.deviceIdentifier == source->getIdentifier())
  926. mc.callback->handleIncomingMidiMessage (source, message);
  927. }
  928. }
  929. //==============================================================================
  930. void AudioDeviceManager::setDefaultMidiOutputDevice (const String& identifier)
  931. {
  932. if (defaultMidiOutputDeviceInfo.identifier != identifier)
  933. {
  934. std::unique_ptr<MidiOutput> oldMidiPort;
  935. Array<AudioIODeviceCallback*> oldCallbacks;
  936. {
  937. const ScopedLock sl (audioCallbackLock);
  938. oldCallbacks.swapWith (callbacks);
  939. }
  940. if (currentAudioDevice != nullptr)
  941. for (int i = oldCallbacks.size(); --i >= 0;)
  942. oldCallbacks.getUnchecked (i)->audioDeviceStopped();
  943. std::swap (oldMidiPort, defaultMidiOutput);
  944. if (identifier.isNotEmpty())
  945. defaultMidiOutput = MidiOutput::openDevice (identifier);
  946. if (defaultMidiOutput != nullptr)
  947. defaultMidiOutputDeviceInfo = defaultMidiOutput->getDeviceInfo();
  948. else
  949. defaultMidiOutputDeviceInfo = {};
  950. if (currentAudioDevice != nullptr)
  951. for (auto* c : oldCallbacks)
  952. c->audioDeviceAboutToStart (currentAudioDevice.get());
  953. {
  954. const ScopedLock sl (audioCallbackLock);
  955. oldCallbacks.swapWith (callbacks);
  956. }
  957. updateXml();
  958. sendSynchronousChangeMessage();
  959. }
  960. }
  961. //==============================================================================
  962. AudioDeviceManager::LevelMeter::LevelMeter() noexcept : level() {}
  963. void AudioDeviceManager::LevelMeter::updateLevel (const float* const* channelData, int numChannels, int numSamples) noexcept
  964. {
  965. if (getReferenceCount() <= 1)
  966. return;
  967. auto localLevel = level.get();
  968. if (numChannels > 0)
  969. {
  970. for (int j = 0; j < numSamples; ++j)
  971. {
  972. float s = 0;
  973. for (int i = 0; i < numChannels; ++i)
  974. s += std::abs (channelData[i][j]);
  975. s /= (float) numChannels;
  976. const float decayFactor = 0.99992f;
  977. if (s > localLevel)
  978. localLevel = s;
  979. else if (localLevel > 0.001f)
  980. localLevel *= decayFactor;
  981. else
  982. localLevel = 0;
  983. }
  984. }
  985. else
  986. {
  987. localLevel = 0;
  988. }
  989. level = localLevel;
  990. }
  991. double AudioDeviceManager::LevelMeter::getCurrentLevel() const noexcept
  992. {
  993. jassert (getReferenceCount() > 1);
  994. return level.get();
  995. }
  996. void AudioDeviceManager::playTestSound()
  997. {
  998. { // cunningly nested to swap, unlock and delete in that order.
  999. std::unique_ptr<AudioBuffer<float>> oldSound;
  1000. {
  1001. const ScopedLock sl (audioCallbackLock);
  1002. std::swap (oldSound, testSound);
  1003. }
  1004. }
  1005. testSoundPosition = 0;
  1006. if (currentAudioDevice != nullptr)
  1007. {
  1008. auto sampleRate = currentAudioDevice->getCurrentSampleRate();
  1009. auto soundLength = (int) sampleRate;
  1010. double frequency = 440.0;
  1011. float amplitude = 0.5f;
  1012. auto phasePerSample = MathConstants<double>::twoPi / (sampleRate / frequency);
  1013. std::unique_ptr<AudioBuffer<float>> newSound (new AudioBuffer<float> (1, soundLength));
  1014. for (int i = 0; i < soundLength; ++i)
  1015. newSound->setSample (0, i, amplitude * (float) std::sin (i * phasePerSample));
  1016. newSound->applyGainRamp (0, 0, soundLength / 10, 0.0f, 1.0f);
  1017. newSound->applyGainRamp (0, soundLength - soundLength / 4, soundLength / 4, 1.0f, 0.0f);
  1018. {
  1019. const ScopedLock sl (audioCallbackLock);
  1020. std::swap (testSound, newSound);
  1021. }
  1022. }
  1023. }
  1024. int AudioDeviceManager::getXRunCount() const noexcept
  1025. {
  1026. auto deviceXRuns = (currentAudioDevice != nullptr ? currentAudioDevice->getXRunCount() : -1);
  1027. return jmax (0, deviceXRuns) + loadMeasurer.getXRunCount();
  1028. }
  1029. //==============================================================================
  1030. // Deprecated
  1031. void AudioDeviceManager::setMidiInputEnabled (const String& name, const bool enabled)
  1032. {
  1033. for (auto& device : MidiInput::getAvailableDevices())
  1034. {
  1035. if (device.name == name)
  1036. {
  1037. setMidiInputDeviceEnabled (device.identifier, enabled);
  1038. return;
  1039. }
  1040. }
  1041. }
  1042. bool AudioDeviceManager::isMidiInputEnabled (const String& name) const
  1043. {
  1044. for (auto& device : MidiInput::getAvailableDevices())
  1045. if (device.name == name)
  1046. return isMidiInputDeviceEnabled (device.identifier);
  1047. return false;
  1048. }
  1049. void AudioDeviceManager::addMidiInputCallback (const String& name, MidiInputCallback* callbackToAdd)
  1050. {
  1051. if (name.isEmpty())
  1052. {
  1053. addMidiInputDeviceCallback ({}, callbackToAdd);
  1054. }
  1055. else
  1056. {
  1057. for (auto& device : MidiInput::getAvailableDevices())
  1058. {
  1059. if (device.name == name)
  1060. {
  1061. addMidiInputDeviceCallback (device.identifier, callbackToAdd);
  1062. return;
  1063. }
  1064. }
  1065. }
  1066. }
  1067. void AudioDeviceManager::removeMidiInputCallback (const String& name, MidiInputCallback* callbackToRemove)
  1068. {
  1069. if (name.isEmpty())
  1070. {
  1071. removeMidiInputDeviceCallback ({}, callbackToRemove);
  1072. }
  1073. else
  1074. {
  1075. for (auto& device : MidiInput::getAvailableDevices())
  1076. {
  1077. if (device.name == name)
  1078. {
  1079. removeMidiInputDeviceCallback (device.identifier, callbackToRemove);
  1080. return;
  1081. }
  1082. }
  1083. }
  1084. }
  1085. void AudioDeviceManager::setDefaultMidiOutput (const String& name)
  1086. {
  1087. for (auto& device : MidiOutput::getAvailableDevices())
  1088. {
  1089. if (device.name == name)
  1090. {
  1091. setDefaultMidiOutputDevice (device.identifier);
  1092. return;
  1093. }
  1094. }
  1095. }
  1096. //==============================================================================
  1097. //==============================================================================
  1098. #if JUCE_UNIT_TESTS
  1099. class AudioDeviceManagerTests final : public UnitTest
  1100. {
  1101. public:
  1102. AudioDeviceManagerTests() : UnitTest ("AudioDeviceManager", UnitTestCategories::audio) {}
  1103. void runTest() override
  1104. {
  1105. beginTest ("When the AudioDeviceSetup has non-empty device names, initialise uses the requested devices");
  1106. {
  1107. AudioDeviceManager manager;
  1108. initialiseManager (manager);
  1109. expectEquals (manager.getAvailableDeviceTypes().size(), 2);
  1110. AudioDeviceManager::AudioDeviceSetup setup;
  1111. setup.outputDeviceName = "z";
  1112. setup.inputDeviceName = "c";
  1113. expect (manager.initialise (2, 2, nullptr, true, String{}, &setup).isEmpty());
  1114. const auto& newSetup = manager.getAudioDeviceSetup();
  1115. expectEquals (newSetup.outputDeviceName, setup.outputDeviceName);
  1116. expectEquals (newSetup.inputDeviceName, setup.inputDeviceName);
  1117. expectEquals (newSetup.outputChannels.countNumberOfSetBits(), 2);
  1118. expectEquals (newSetup.inputChannels.countNumberOfSetBits(), 2);
  1119. }
  1120. beginTest ("When the AudioDeviceSetup has empty device names, initialise picks suitable default devices");
  1121. {
  1122. AudioDeviceManager manager;
  1123. initialiseManager (manager);
  1124. AudioDeviceManager::AudioDeviceSetup setup;
  1125. expect (manager.initialise (2, 2, nullptr, true, String{}, &setup).isEmpty());
  1126. const auto& newSetup = manager.getAudioDeviceSetup();
  1127. expectEquals (newSetup.outputDeviceName, String ("x"));
  1128. expectEquals (newSetup.inputDeviceName, String ("a"));
  1129. expectEquals (newSetup.outputChannels.countNumberOfSetBits(), 2);
  1130. expectEquals (newSetup.inputChannels.countNumberOfSetBits(), 2);
  1131. }
  1132. beginTest ("When the preferred device name matches an input and an output on the same type, that type is used");
  1133. {
  1134. AudioDeviceManager manager;
  1135. initialiseManagerWithDifferentDeviceNames (manager);
  1136. expect (manager.initialise (2, 2, nullptr, true, "bar *").isEmpty());
  1137. expectEquals (manager.getCurrentAudioDeviceType(), String ("bar"));
  1138. const auto& newSetup = manager.getAudioDeviceSetup();
  1139. expectEquals (newSetup.outputDeviceName, String ("bar out a"));
  1140. expectEquals (newSetup.inputDeviceName, String ("bar in a"));
  1141. expectEquals (newSetup.outputChannels.countNumberOfSetBits(), 2);
  1142. expectEquals (newSetup.inputChannels.countNumberOfSetBits(), 2);
  1143. expect (manager.getCurrentAudioDevice() != nullptr);
  1144. }
  1145. beginTest ("When the preferred device name matches either an input and an output, but not both, that type is used");
  1146. {
  1147. AudioDeviceManager manager;
  1148. initialiseManagerWithDifferentDeviceNames (manager);
  1149. expect (manager.initialise (2, 2, nullptr, true, "bar out b").isEmpty());
  1150. expectEquals (manager.getCurrentAudioDeviceType(), String ("bar"));
  1151. const auto& newSetup = manager.getAudioDeviceSetup();
  1152. expectEquals (newSetup.outputDeviceName, String ("bar out b"));
  1153. expectEquals (newSetup.inputDeviceName, String ("bar in a"));
  1154. expectEquals (newSetup.outputChannels.countNumberOfSetBits(), 2);
  1155. expectEquals (newSetup.inputChannels.countNumberOfSetBits(), 2);
  1156. expect (manager.getCurrentAudioDevice() != nullptr);
  1157. }
  1158. beginTest ("When the preferred device name does not match any inputs or outputs, defaults are used");
  1159. {
  1160. AudioDeviceManager manager;
  1161. initialiseManagerWithDifferentDeviceNames (manager);
  1162. expect (manager.initialise (2, 2, nullptr, true, "unmatchable").isEmpty());
  1163. expectEquals (manager.getCurrentAudioDeviceType(), String ("foo"));
  1164. const auto& newSetup = manager.getAudioDeviceSetup();
  1165. expectEquals (newSetup.outputDeviceName, String ("foo out a"));
  1166. expectEquals (newSetup.inputDeviceName, String ("foo in a"));
  1167. expectEquals (newSetup.outputChannels.countNumberOfSetBits(), 2);
  1168. expectEquals (newSetup.inputChannels.countNumberOfSetBits(), 2);
  1169. expect (manager.getCurrentAudioDevice() != nullptr);
  1170. }
  1171. beginTest ("When first device type has no devices, a device type with devices is used instead");
  1172. {
  1173. AudioDeviceManager manager;
  1174. initialiseManagerWithEmptyDeviceType (manager);
  1175. AudioDeviceManager::AudioDeviceSetup setup;
  1176. expect (manager.initialise (2, 2, nullptr, true, {}, &setup).isEmpty());
  1177. const auto& newSetup = manager.getAudioDeviceSetup();
  1178. expectEquals (newSetup.outputDeviceName, String ("x"));
  1179. expectEquals (newSetup.inputDeviceName, String ("a"));
  1180. expectEquals (newSetup.outputChannels.countNumberOfSetBits(), 2);
  1181. expectEquals (newSetup.inputChannels.countNumberOfSetBits(), 2);
  1182. }
  1183. beginTest ("If a device type has been explicitly set to a type with devices, "
  1184. "initialisation should respect this choice");
  1185. {
  1186. AudioDeviceManager manager;
  1187. initialiseManagerWithEmptyDeviceType (manager);
  1188. manager.setCurrentAudioDeviceType (mockBName, true);
  1189. AudioDeviceManager::AudioDeviceSetup setup;
  1190. expect (manager.initialise (2, 2, nullptr, true, {}, &setup).isEmpty());
  1191. expectEquals (manager.getCurrentAudioDeviceType(), mockBName);
  1192. }
  1193. beginTest ("If a device type has been explicitly set to a type without devices, "
  1194. "initialisation should pick a type with devices instead");
  1195. {
  1196. AudioDeviceManager manager;
  1197. initialiseManagerWithEmptyDeviceType (manager);
  1198. manager.setCurrentAudioDeviceType (emptyName, true);
  1199. AudioDeviceManager::AudioDeviceSetup setup;
  1200. expect (manager.initialise (2, 2, nullptr, true, {}, &setup).isEmpty());
  1201. expectEquals (manager.getCurrentAudioDeviceType(), mockAName);
  1202. }
  1203. beginTest ("Carry out a long sequence of configuration changes");
  1204. {
  1205. AudioDeviceManager manager;
  1206. initialiseManagerWithEmptyDeviceType (manager);
  1207. initialiseWithDefaultDevices (manager);
  1208. disableInputChannelsButLeaveDeviceOpen (manager);
  1209. selectANewInputDevice (manager);
  1210. disableInputDevice (manager);
  1211. reenableInputDeviceWithNoChannels (manager);
  1212. enableInputChannels (manager);
  1213. disableInputChannelsButLeaveDeviceOpen (manager);
  1214. switchDeviceType (manager);
  1215. enableInputChannels (manager);
  1216. closeDeviceByRequestingEmptyNames (manager);
  1217. }
  1218. beginTest ("AudioDeviceManager updates its current settings before notifying callbacks when device restarts itself");
  1219. {
  1220. AudioDeviceManager manager;
  1221. auto deviceType = std::make_unique<MockDeviceType> ("foo",
  1222. StringArray { "foo in a", "foo in b" },
  1223. StringArray { "foo out a", "foo out b" });
  1224. auto* ptr = deviceType.get();
  1225. manager.addAudioDeviceType (std::move (deviceType));
  1226. AudioDeviceManager::AudioDeviceSetup setup;
  1227. setup.sampleRate = 48000.0;
  1228. setup.bufferSize = 256;
  1229. setup.inputDeviceName = "foo in a";
  1230. setup.outputDeviceName = "foo out a";
  1231. setup.useDefaultInputChannels = true;
  1232. setup.useDefaultOutputChannels = true;
  1233. manager.setAudioDeviceSetup (setup, true);
  1234. const auto currentSetup = manager.getAudioDeviceSetup();
  1235. expectEquals (currentSetup.sampleRate, setup.sampleRate);
  1236. expectEquals (currentSetup.bufferSize, setup.bufferSize);
  1237. MockCallback callback;
  1238. manager.addAudioCallback (&callback);
  1239. constexpr auto newSr = 10000.0;
  1240. constexpr auto newBs = 1024;
  1241. auto numCalls = 0;
  1242. // Compilers disagree about whether newSr and newBs need to be captured
  1243. callback.aboutToStart = [&]
  1244. {
  1245. ++numCalls;
  1246. const auto current = manager.getAudioDeviceSetup();
  1247. expectEquals (current.sampleRate, newSr);
  1248. expectEquals (current.bufferSize, newBs);
  1249. };
  1250. ptr->restartDevices (newSr, newBs);
  1251. expectEquals (numCalls, 1);
  1252. }
  1253. }
  1254. private:
  1255. void initialiseWithDefaultDevices (AudioDeviceManager& manager)
  1256. {
  1257. manager.initialiseWithDefaultDevices (2, 2);
  1258. const auto& setup = manager.getAudioDeviceSetup();
  1259. expectEquals (setup.inputChannels.countNumberOfSetBits(), 2);
  1260. expectEquals (setup.outputChannels.countNumberOfSetBits(), 2);
  1261. expect (setup.useDefaultInputChannels);
  1262. expect (setup.useDefaultOutputChannels);
  1263. expect (manager.getCurrentAudioDevice() != nullptr);
  1264. }
  1265. void disableInputChannelsButLeaveDeviceOpen (AudioDeviceManager& manager)
  1266. {
  1267. auto setup = manager.getAudioDeviceSetup();
  1268. setup.inputChannels.clear();
  1269. setup.useDefaultInputChannels = false;
  1270. expect (manager.setAudioDeviceSetup (setup, true).isEmpty());
  1271. const auto newSetup = manager.getAudioDeviceSetup();
  1272. expectEquals (newSetup.inputChannels.countNumberOfSetBits(), 0);
  1273. expectEquals (newSetup.outputChannels.countNumberOfSetBits(), 2);
  1274. expect (! newSetup.useDefaultInputChannels);
  1275. expect (newSetup.useDefaultOutputChannels);
  1276. expectEquals (newSetup.inputDeviceName, setup.inputDeviceName);
  1277. expectEquals (newSetup.outputDeviceName, setup.outputDeviceName);
  1278. expect (manager.getCurrentAudioDevice() != nullptr);
  1279. }
  1280. void selectANewInputDevice (AudioDeviceManager& manager)
  1281. {
  1282. auto setup = manager.getAudioDeviceSetup();
  1283. setup.inputDeviceName = "b";
  1284. expect (manager.setAudioDeviceSetup (setup, true).isEmpty());
  1285. const auto newSetup = manager.getAudioDeviceSetup();
  1286. expectEquals (newSetup.inputChannels.countNumberOfSetBits(), 0);
  1287. expectEquals (newSetup.outputChannels.countNumberOfSetBits(), 2);
  1288. expect (! newSetup.useDefaultInputChannels);
  1289. expect (newSetup.useDefaultOutputChannels);
  1290. expectEquals (newSetup.inputDeviceName, setup.inputDeviceName);
  1291. expectEquals (newSetup.outputDeviceName, setup.outputDeviceName);
  1292. expect (manager.getCurrentAudioDevice() != nullptr);
  1293. }
  1294. void disableInputDevice (AudioDeviceManager& manager)
  1295. {
  1296. auto setup = manager.getAudioDeviceSetup();
  1297. setup.inputDeviceName = "";
  1298. expect (manager.setAudioDeviceSetup (setup, true).isEmpty());
  1299. const auto newSetup = manager.getAudioDeviceSetup();
  1300. expectEquals (newSetup.inputChannels.countNumberOfSetBits(), 0);
  1301. expectEquals (newSetup.outputChannels.countNumberOfSetBits(), 2);
  1302. expect (! newSetup.useDefaultInputChannels);
  1303. expect (newSetup.useDefaultOutputChannels);
  1304. expectEquals (newSetup.inputDeviceName, setup.inputDeviceName);
  1305. expectEquals (newSetup.outputDeviceName, setup.outputDeviceName);
  1306. expect (manager.getCurrentAudioDevice() != nullptr);
  1307. }
  1308. void reenableInputDeviceWithNoChannels (AudioDeviceManager& manager)
  1309. {
  1310. auto setup = manager.getAudioDeviceSetup();
  1311. setup.inputDeviceName = "a";
  1312. expect (manager.setAudioDeviceSetup (setup, true).isEmpty());
  1313. const auto newSetup = manager.getAudioDeviceSetup();
  1314. expectEquals (newSetup.inputChannels.countNumberOfSetBits(), 0);
  1315. expectEquals (newSetup.outputChannels.countNumberOfSetBits(), 2);
  1316. expect (! newSetup.useDefaultInputChannels);
  1317. expect (newSetup.useDefaultOutputChannels);
  1318. expectEquals (newSetup.inputDeviceName, setup.inputDeviceName);
  1319. expectEquals (newSetup.outputDeviceName, setup.outputDeviceName);
  1320. expect (manager.getCurrentAudioDevice() != nullptr);
  1321. }
  1322. void enableInputChannels (AudioDeviceManager& manager)
  1323. {
  1324. auto setup = manager.getAudioDeviceSetup();
  1325. setup.inputDeviceName = manager.getCurrentDeviceTypeObject()->getDeviceNames (true)[0];
  1326. setup.inputChannels = 3;
  1327. setup.useDefaultInputChannels = false;
  1328. expect (manager.setAudioDeviceSetup (setup, true).isEmpty());
  1329. const auto newSetup = manager.getAudioDeviceSetup();
  1330. expectEquals (newSetup.inputChannels.countNumberOfSetBits(), 2);
  1331. expectEquals (newSetup.outputChannels.countNumberOfSetBits(), 2);
  1332. expect (! newSetup.useDefaultInputChannels);
  1333. expect (newSetup.useDefaultOutputChannels);
  1334. expectEquals (newSetup.inputDeviceName, setup.inputDeviceName);
  1335. expectEquals (newSetup.outputDeviceName, setup.outputDeviceName);
  1336. expect (manager.getCurrentAudioDevice() != nullptr);
  1337. }
  1338. void switchDeviceType (AudioDeviceManager& manager)
  1339. {
  1340. const auto oldSetup = manager.getAudioDeviceSetup();
  1341. expectEquals (manager.getCurrentAudioDeviceType(), String (mockAName));
  1342. manager.setCurrentAudioDeviceType (mockBName, true);
  1343. expectEquals (manager.getCurrentAudioDeviceType(), String (mockBName));
  1344. const auto newSetup = manager.getAudioDeviceSetup();
  1345. expect (newSetup.outputDeviceName.isNotEmpty());
  1346. // We had no channels enabled, which means we don't need to open a new input device
  1347. expect (newSetup.inputDeviceName.isEmpty());
  1348. expectEquals (newSetup.inputChannels.countNumberOfSetBits(), 0);
  1349. expectEquals (newSetup.outputChannels.countNumberOfSetBits(), 2);
  1350. expect (manager.getCurrentAudioDevice() != nullptr);
  1351. }
  1352. void closeDeviceByRequestingEmptyNames (AudioDeviceManager& manager)
  1353. {
  1354. auto setup = manager.getAudioDeviceSetup();
  1355. setup.inputDeviceName = "";
  1356. setup.outputDeviceName = "";
  1357. expect (manager.setAudioDeviceSetup (setup, true).isEmpty());
  1358. const auto newSetup = manager.getAudioDeviceSetup();
  1359. expectEquals (newSetup.inputChannels.countNumberOfSetBits(), 2);
  1360. expectEquals (newSetup.outputChannels.countNumberOfSetBits(), 2);
  1361. expect (newSetup.inputDeviceName.isEmpty());
  1362. expect (newSetup.outputDeviceName.isEmpty());
  1363. expect (manager.getCurrentAudioDevice() == nullptr);
  1364. }
  1365. const String mockAName = "mockA";
  1366. const String mockBName = "mockB";
  1367. const String emptyName = "empty";
  1368. struct Restartable
  1369. {
  1370. virtual ~Restartable() = default;
  1371. virtual void restart (double newSr, int newBs) = 0;
  1372. };
  1373. class MockDevice final : public AudioIODevice,
  1374. private Restartable
  1375. {
  1376. public:
  1377. MockDevice (ListenerList<Restartable>& l, String typeNameIn, String outNameIn, String inNameIn)
  1378. : AudioIODevice ("mock", typeNameIn), listeners (l), outName (outNameIn), inName (inNameIn)
  1379. {
  1380. listeners.add (this);
  1381. }
  1382. ~MockDevice() override
  1383. {
  1384. listeners.remove (this);
  1385. }
  1386. StringArray getOutputChannelNames() override { return { "o1", "o2", "o3" }; }
  1387. StringArray getInputChannelNames() override { return { "i1", "i2", "i3" }; }
  1388. Array<double> getAvailableSampleRates() override { return { 44100.0, 48000.0 }; }
  1389. Array<int> getAvailableBufferSizes() override { return { 128, 256 }; }
  1390. int getDefaultBufferSize() override { return 128; }
  1391. String open (const BigInteger& inputs, const BigInteger& outputs, double sr, int bs) override
  1392. {
  1393. inChannels = inputs;
  1394. outChannels = outputs;
  1395. sampleRate = sr;
  1396. blockSize = bs;
  1397. on = true;
  1398. return {};
  1399. }
  1400. void close() override { on = false; }
  1401. bool isOpen() override { return on; }
  1402. void start (AudioIODeviceCallback* c) override
  1403. {
  1404. callback = c;
  1405. callback->audioDeviceAboutToStart (this);
  1406. playing = true;
  1407. }
  1408. void stop() override
  1409. {
  1410. playing = false;
  1411. callback->audioDeviceStopped();
  1412. }
  1413. bool isPlaying() override { return playing; }
  1414. String getLastError() override { return {}; }
  1415. int getCurrentBufferSizeSamples() override { return blockSize; }
  1416. double getCurrentSampleRate() override { return sampleRate; }
  1417. int getCurrentBitDepth() override { return 16; }
  1418. BigInteger getActiveOutputChannels() const override { return outChannels; }
  1419. BigInteger getActiveInputChannels() const override { return inChannels; }
  1420. int getOutputLatencyInSamples() override { return 0; }
  1421. int getInputLatencyInSamples() override { return 0; }
  1422. private:
  1423. void restart (double newSr, int newBs) override
  1424. {
  1425. stop();
  1426. close();
  1427. open (inChannels, outChannels, newSr, newBs);
  1428. start (callback);
  1429. }
  1430. ListenerList<Restartable>& listeners;
  1431. AudioIODeviceCallback* callback = nullptr;
  1432. String outName, inName;
  1433. BigInteger outChannels, inChannels;
  1434. double sampleRate = 0.0;
  1435. int blockSize = 0;
  1436. bool on = false, playing = false;
  1437. };
  1438. class MockDeviceType final : public AudioIODeviceType
  1439. {
  1440. public:
  1441. explicit MockDeviceType (String kind)
  1442. : MockDeviceType (std::move (kind), { "a", "b", "c" }, { "x", "y", "z" }) {}
  1443. MockDeviceType (String kind, StringArray inputNames, StringArray outputNames)
  1444. : AudioIODeviceType (std::move (kind)),
  1445. inNames (std::move (inputNames)),
  1446. outNames (std::move (outputNames)) {}
  1447. ~MockDeviceType() override
  1448. {
  1449. // A Device outlived its DeviceType!
  1450. jassert (listeners.isEmpty());
  1451. }
  1452. void scanForDevices() override {}
  1453. StringArray getDeviceNames (bool isInput) const override
  1454. {
  1455. return getNames (isInput);
  1456. }
  1457. int getDefaultDeviceIndex (bool) const override { return 0; }
  1458. int getIndexOfDevice (AudioIODevice* device, bool isInput) const override
  1459. {
  1460. return getNames (isInput).indexOf (device->getName());
  1461. }
  1462. bool hasSeparateInputsAndOutputs() const override { return true; }
  1463. AudioIODevice* createDevice (const String& outputName, const String& inputName) override
  1464. {
  1465. if (inNames.contains (inputName) || outNames.contains (outputName))
  1466. return new MockDevice (listeners, getTypeName(), outputName, inputName);
  1467. return nullptr;
  1468. }
  1469. // Call this to emulate the device restarting itself with new settings.
  1470. // This might happen e.g. when a user changes the ASIO settings.
  1471. void restartDevices (double newSr, int newBs)
  1472. {
  1473. listeners.call ([&] (auto& l) { return l.restart (newSr, newBs); });
  1474. }
  1475. private:
  1476. const StringArray& getNames (bool isInput) const { return isInput ? inNames : outNames; }
  1477. const StringArray inNames, outNames;
  1478. ListenerList<Restartable> listeners;
  1479. };
  1480. class MockCallback final : public AudioIODeviceCallback
  1481. {
  1482. public:
  1483. std::function<void()> callback;
  1484. std::function<void()> aboutToStart;
  1485. std::function<void()> stopped;
  1486. std::function<void()> error;
  1487. void audioDeviceIOCallbackWithContext (const float* const*,
  1488. int,
  1489. float* const*,
  1490. int,
  1491. int,
  1492. const AudioIODeviceCallbackContext&) override
  1493. {
  1494. NullCheckedInvocation::invoke (callback);
  1495. }
  1496. void audioDeviceAboutToStart (AudioIODevice*) override { NullCheckedInvocation::invoke (aboutToStart); }
  1497. void audioDeviceStopped() override { NullCheckedInvocation::invoke (stopped); }
  1498. void audioDeviceError (const String&) override { NullCheckedInvocation::invoke (error); }
  1499. };
  1500. void initialiseManager (AudioDeviceManager& manager)
  1501. {
  1502. manager.addAudioDeviceType (std::make_unique<MockDeviceType> (mockAName));
  1503. manager.addAudioDeviceType (std::make_unique<MockDeviceType> (mockBName));
  1504. }
  1505. void initialiseManagerWithEmptyDeviceType (AudioDeviceManager& manager)
  1506. {
  1507. manager.addAudioDeviceType (std::make_unique<MockDeviceType> (emptyName, StringArray{}, StringArray{}));
  1508. initialiseManager (manager);
  1509. }
  1510. void initialiseManagerWithDifferentDeviceNames (AudioDeviceManager& manager)
  1511. {
  1512. manager.addAudioDeviceType (std::make_unique<MockDeviceType> ("foo",
  1513. StringArray { "foo in a", "foo in b" },
  1514. StringArray { "foo out a", "foo out b" }));
  1515. manager.addAudioDeviceType (std::make_unique<MockDeviceType> ("bar",
  1516. StringArray { "bar in a", "bar in b" },
  1517. StringArray { "bar out a", "bar out b" }));
  1518. }
  1519. };
  1520. static AudioDeviceManagerTests audioDeviceManagerTests;
  1521. #endif
  1522. } // namespace juce