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