1 #pragma once 2 3 #include <QHash> 4 #include <QList> 5 #include <QObject> 6 #include <QSharedPointer> 7 #include <QString> 8 #include <memory> 9 10 #include "audio/types.h" 11 #include "engine/sidechain/enginenetworkstream.h" 12 #include "preferences/usersettings.h" 13 #include "soundio/sounddevice.h" 14 #include "soundio/soundmanagerconfig.h" 15 #include "util/cmdlineargs.h" 16 #include "util/types.h" 17 18 class EngineMaster; 19 class AudioOutput; 20 class AudioInput; 21 class AudioSource; 22 class AudioDestination; 23 class ControlObject; 24 class ControlProxy; 25 class SoundDeviceNotFound; 26 27 #define MIXXX_PORTAUDIO_JACK_STRING "JACK Audio Connection Kit" 28 #define MIXXX_PORTAUDIO_ALSA_STRING "ALSA" 29 #define MIXXX_PORTAUDIO_OSS_STRING "OSS" 30 #define MIXXX_PORTAUDIO_ASIO_STRING "ASIO" 31 #define MIXXX_PORTAUDIO_DIRECTSOUND_STRING "Windows DirectSound" 32 #define MIXXX_PORTAUDIO_COREAUDIO_STRING "Core Audio" 33 34 #define SOUNDMANAGER_DISCONNECTED 0 35 #define SOUNDMANAGER_CONNECTING 1 36 #define SOUNDMANAGER_CONNECTED 2 37 38 39 class SoundManager : public QObject { 40 Q_OBJECT 41 public: 42 SoundManager(UserSettingsPointer pConfig, EngineMaster *_master); 43 ~SoundManager() override; 44 45 // Returns a list of all devices we've enumerated that match the provided 46 // filterApi, and have at least one output or input channel if the 47 // bOutputDevices or bInputDevices are set, respectively. 48 QList<SoundDevicePointer> getDeviceList( 49 const QString& filterAPI, bool bOutputDevices, bool bInputDevices) const; 50 51 // Creates a list of sound devices 52 void clearAndQueryDevices(); 53 void queryDevices(); 54 void queryDevicesPortaudio(); 55 void queryDevicesMixxx(); 56 57 // Opens all the devices chosen by the user in the preferences dialog, and 58 // establishes the proper connections between them and the mixing engine. 59 SoundDeviceError setupDevices(); 60 61 // Playermanager will notify us when the number of decks changes. 62 void setConfiguredDeckCount(int count); 63 int getConfiguredDeckCount() const; 64 65 SoundDevicePointer getErrorDevice() const; 66 QString getErrorDeviceName() const; 67 QString getLastErrorMessage(SoundDeviceError err) const; 68 69 // Returns a list of samplerates we will attempt to support for a given API. 70 QList<unsigned int> getSampleRates(const QString& api) const; 71 72 // Convenience overload for SoundManager::getSampleRates(QString) 73 QList<unsigned int> getSampleRates() const; 74 75 // Get a list of host APIs supported by PortAudio. 76 QList<QString> getHostAPIList() const; 77 SoundManagerConfig getConfig() const; 78 SoundDeviceError setConfig(const SoundManagerConfig& config); 79 void checkConfig(); 80 81 void onDeviceOutputCallback(const SINT iFramesPerBuffer); 82 83 // Used by SoundDevices to "push" any audio from their inputs that they have 84 // into the mixing engine. 85 void pushInputBuffers(const QList<AudioInputBuffer>& inputs, 86 const SINT iFramesPerBuffer); 87 88 89 void writeProcess() const; 90 void readProcess() const; 91 92 void registerOutput(const AudioOutput& output, AudioSource* src); 93 void registerInput(const AudioInput& input, AudioDestination* dest); 94 QList<AudioOutput> registeredOutputs() const; 95 QList<AudioInput> registeredInputs() const; 96 getNetworkStream()97 QSharedPointer<EngineNetworkStream> getNetworkStream() const { 98 return m_pNetworkStream; 99 } 100 underflowHappened(int code)101 void underflowHappened(int code) { 102 m_underflowHappened = 1; 103 // Disable the engine warnings by default, because printing a warning is a 104 // locking function that will make the problem worse 105 if (CmdlineArgs::Instance().getDeveloper()) { 106 qWarning() << "underflowHappened code:" << code; 107 } 108 } 109 110 void processUnderflowHappened(); 111 112 signals: 113 void devicesUpdated(); // emitted when pointers to SoundDevices go stale 114 void devicesSetup(); // emitted when the sound devices have been set up 115 void outputRegistered(const AudioOutput& output, AudioSource* src); 116 void inputRegistered(const AudioInput& input, AudioDestination* dest); 117 118 private: 119 // Closes all the devices and empties the list of devices we have. 120 void clearDeviceList(bool sleepAfterClosing); 121 122 // Closes all the open sound devices. Because multiple soundcards might be 123 // open, this method simply runs through the list of all known soundcards 124 // (from PortAudio) and attempts to close them all. Closing a soundcard that 125 // isn't open is safe. 126 void closeDevices(bool sleepAfterClosing); 127 128 void setJACKName() const; 129 130 EngineMaster *m_pMaster; 131 UserSettingsPointer m_pConfig; 132 bool m_paInitialized; 133 mixxx::audio::SampleRate m_jackSampleRate; 134 QList<SoundDevicePointer> m_devices; 135 QList<unsigned int> m_samplerates; 136 QList<CSAMPLE*> m_inputBuffers; 137 138 SoundManagerConfig m_config; 139 SoundDevicePointer m_pErrorDevice; 140 QHash<AudioOutput, AudioSource*> m_registeredSources; 141 QMultiHash<AudioInput, AudioDestination*> m_registeredDestinations; 142 ControlObject* m_pControlObjectSoundStatusCO; 143 ControlObject* m_pControlObjectVinylControlGainCO; 144 145 QSharedPointer<EngineNetworkStream> m_pNetworkStream; 146 147 QAtomicInt m_underflowHappened; 148 int m_underflowUpdateCount; 149 ControlProxy* m_pMasterAudioLatencyOverloadCount; 150 ControlProxy* m_pMasterAudioLatencyOverload; 151 }; 152