1 /*
2     MIDI Sequencer C++ library
3     Copyright (C) 2006-2021, Pedro Lopez-Cabanillas <plcl@users.sf.net>
4 
5     This library is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 3 of the License, or
8     (at your option) any later version.
9 
10     This library is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14 
15     You should have received a copy of the GNU General Public License
16     along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18 
19 #ifndef DRUMSTICK_ALSATIMER_H
20 #define DRUMSTICK_ALSATIMER_H
21 
22 extern "C" {
23     #include <alsa/asoundlib.h>
24 }
25 
26 #include <QObject>
27 #include <QList>
28 #include <QThread>
29 #include <QReadWriteLock>
30 #include <QPointer>
31 #include "macros.h"
32 
33 namespace drumstick { namespace ALSA {
34 
35 /**
36  * @file alsatimer.h
37  * Classes managing ALSA Timers
38  */
39 
40 class TimerQuery;
41 class TimerId;
42 class TimerGlobalInfo;
43 
44 /**
45  * @addtogroup ALSATimer ALSA Timers
46  * @{
47  *
48  * @class TimerInfo
49  * ALSA Timer information container.
50  *
51  * This class is used to hold properties about ALSA Timers.
52  */
53 class DRUMSTICK_EXPORT TimerInfo
54 {
55     friend class Timer;
56 
57 public:
58     TimerInfo();
59     TimerInfo(const TimerInfo& other);
60     explicit TimerInfo(const snd_timer_info_t* other);
61     virtual ~TimerInfo();
62     TimerInfo* clone();
63     TimerInfo& operator=(const TimerInfo& other);
64     int getSizeOfInfo() const;
65 
66     bool isSlave();
67     int getCard();
68     QString getId();
69     QString getName();
70     long getResolution();
71     long getFrequency();
72 
73 protected:
74     Q_DECL_DEPRECATED long getTicks();
75 
76 private:
77     snd_timer_info_t *m_Info;
78 };
79 
80 /**
81  * ALSA Timer identifier container.
82  *
83  * This class provides an unique identifier for a Timer.
84  */
85 class DRUMSTICK_EXPORT TimerId
86 {
87     friend class TimerQuery;
88     friend class TimerGlobalInfo;
89     friend class QueueTimer;
90 
91 public:
92     TimerId();
93     TimerId(const TimerId& other);
94     explicit TimerId(const snd_timer_id_t *other);
95     TimerId(int cls, int scls, int card, int dev, int sdev);
96     virtual ~TimerId();
97     TimerId* clone();
98     TimerId& operator=(const TimerId& other);
99     int getSizeOfInfo() const;
100 
101     void setClass(int devclass);
102     int getClass();
103     void setSlaveClass(int devsclass);
104     int getSlaveClass();
105     void setCard(int card);
106     int getCard();
107     void setDevice(int device);
108     int getDevice();
109     void setSubdevice(int subdevice);
110     int getSubdevice();
111 
112 private:
113     snd_timer_id_t *m_Info;
114 };
115 
116 /**
117  * List of timer identifiers
118  */
119 typedef QList<TimerId> TimerIdList;
120 
121 /**
122  * Global timer information container.
123  *
124  * This class provides global timer parameters.
125  */
126 class DRUMSTICK_EXPORT TimerGlobalInfo
127 {
128     friend class TimerQuery;
129 
130 public:
131     TimerGlobalInfo();
132     TimerGlobalInfo(const TimerGlobalInfo& other);
133     explicit TimerGlobalInfo(const snd_timer_ginfo_t* other);
134     virtual ~TimerGlobalInfo();
135     TimerGlobalInfo* clone();
136     TimerGlobalInfo& operator=(const TimerGlobalInfo& other);
137     int getSizeOfInfo() const;
138 
139     void setTimerId(const TimerId& tid);
140     TimerId& getTimerId();
141     unsigned int getFlags();
142     int getCard();
143     QString getId();
144     QString getName();
145     unsigned long getResolution();
146     unsigned long getMinResolution();
147     unsigned long getMaxResolution();
148     unsigned int getClients();
149 
150 private:
151     snd_timer_ginfo_t* m_Info;
152     TimerId m_Id;
153 };
154 
155 /**
156  * ALSA Timer inquiry helper.
157  *
158  * This class provides a mechanism to enumerate the available system timers.
159  */
160 class DRUMSTICK_EXPORT TimerQuery
161 {
162 public:
163     TimerQuery(const QString& deviceName, int openMode);
164     TimerQuery(const QString& deviceName, int openMode, snd_config_t* conf);
165     virtual ~TimerQuery();
166     /**
167      * Gets the list of available timers
168      * @return List of TimerId objects
169      */
getTimers()170     TimerIdList getTimers() const { return m_timers; }
171     TimerGlobalInfo& getGlobalInfo();
172     void setGlobalParams(snd_timer_gparams_t* params);
173     void getGlobalParams(snd_timer_gparams_t* params);
174     void getGlobalStatus(snd_timer_gstatus_t* status);
175 
176 protected:
177     void readTimers();
178     void freeTimers();
179 
180 private:
181     snd_timer_query_t *m_Info;
182     TimerIdList m_timers;
183     TimerGlobalInfo m_GlobalInfo;
184 };
185 
186 /**
187  * ALSA Timer parameters container.
188  *
189  * This class provides several parameters about a Timer.
190  */
191 class DRUMSTICK_EXPORT TimerParams
192 {
193     friend class Timer;
194 
195 public:
196     TimerParams();
197     TimerParams(const TimerParams& other);
198     explicit TimerParams(const snd_timer_params_t* other);
199     virtual ~TimerParams();
200     TimerParams* clone();
201     TimerParams& operator=(const TimerParams& other);
202     int getSizeOfInfo() const;
203 
204     void setAutoStart(bool auto_start);
205     bool getAutoStart();
206     void setExclusive(bool exclusive);
207     bool getExclusive();
208     void setEarlyEvent(bool early_event);
209     bool getEarlyEvent();
210     void setTicks(long ticks);
211     long getTicks();
212     void setQueueSize(long queue_size);
213     long getQueueSize();
214     void setFilter(unsigned int filter);
215     unsigned int getFilter();
216 
217 private:
218     snd_timer_params_t* m_Info;
219 };
220 
221 /**
222  * ALSA Timer status container.
223  *
224  * This class provides some status information about a Timer.
225  */
226 class DRUMSTICK_EXPORT TimerStatus
227 {
228     friend class Timer;
229 
230 public:
231     TimerStatus();
232     TimerStatus(const TimerStatus& other);
233     explicit TimerStatus(const snd_timer_status_t* other);
234     virtual ~TimerStatus();
235     TimerStatus* clone();
236     TimerStatus& operator=(const TimerStatus& other);
237     int getSizeOfInfo() const;
238 
239     snd_htimestamp_t getTimestamp();
240     long getResolution();
241     long getLost();
242     long getOverrun();
243     long getQueue();
244 
245 private:
246     snd_timer_status_t* m_Info;
247 };
248 
249 /**
250  * ALSA Timer events handler.
251  *
252  * This abstract class is used to define an interface that other class can
253  * implement to receive timer events.
254  */
255 class DRUMSTICK_EXPORT TimerEventHandler
256 {
257 public:
258     /** Destructor */
259     virtual ~TimerEventHandler() = default;
260     /**
261      * Timer event handler. This method is called when the timer expires.
262      * @param ticks The time in ticks.
263      * @param msecs The time in milliseconds.
264      */
265     virtual void handleTimerEvent(int ticks, int msecs) = 0;
266 };
267 
268 /**
269  * ALSA Timer management.
270  *
271  * This class represents an ALSA timer object.
272  */
273 class DRUMSTICK_EXPORT Timer : public QObject
274 {
275     Q_OBJECT
276 
277 private:
278     /**
279      * This class manages timer events input from ALSA
280      */
281     class TimerInputThread : public QThread
282     {
283     public:
284        /** Constructor */
TimerInputThread(Timer * t,int timeout)285        TimerInputThread(Timer* t, int timeout)
286            : QThread(),
287            m_timer(t),
288            m_Wait(timeout),
289            m_Stopped(false) {}
290        /** Destructor */
291        virtual ~TimerInputThread() = default;
292        void run() override;
293        bool stopped();
294        void stop();
295     private:
296         Timer* m_timer;
297         int m_Wait;
298         bool m_Stopped;
299         QReadWriteLock m_mutex;
300     };
301 
302 public:
303     Timer(int cls, int scls, int card, int dev, int sdev, int openMode, QObject* parent = nullptr);
304     Timer(const QString& deviceName, int openMode, QObject* parent = nullptr);
305     Timer(const QString& deviceName, int openMode, snd_config_t* config, QObject* parent = nullptr);
306     Timer(TimerId& id, int openMode, QObject* parent = nullptr);
307     virtual ~Timer();
308 
309     static TimerId bestGlobalTimerId();
310     static Timer* bestGlobalTimer(int openMode, QObject* parent = nullptr);
311     /**
312      * Gets the ALSA timer object.
313      * @return ALSA timer object pointer.
314      */
getHandle()315     snd_timer_t* getHandle() { return m_Info; }
316     TimerInfo& getTimerInfo();
317     TimerStatus& getTimerStatus();
318     void setTimerParams(const TimerParams& params);
319 
320     void start();
321     void stop();
322     void continueRunning();
323 
324     void addAsyncTimerHandler(snd_async_callback_t callback, void *private_data);
325     int getPollDescriptorsCount();
326     void pollDescriptors(struct pollfd *pfds, unsigned int space);
327     void pollDescriptorsRevents(struct pollfd *pfds, unsigned int nfds, unsigned short *revents);
328     ssize_t read(void *buffer, size_t size);
329     snd_timer_t* getTimerHandle();
330     /**
331      * Sets an event handler providing a method to be called when a timer expires.
332      * @param h A TimerEventHandler instance.
333      */
setHandler(TimerEventHandler * h)334     void setHandler(TimerEventHandler* h) { m_handler = h; }
335     void startEvents();
336     void stopEvents();
337 
338 protected:
339     void doEvents();
340 
341 signals:
342     /**
343      * This signal is emitted when the timer has expired, if there is not an
344      * event hander installed.
345      *
346      * @param ticks The time in ticks.
347      * @param msecs The time in milliseconds.
348      */
349     void timerExpired(int ticks, int msecs);
350 
351 private:
352     snd_timer_t *m_Info;
353     snd_async_handler_t *m_asyncHandler;
354     TimerEventHandler* m_handler;
355     QPointer<TimerInputThread> m_thread;
356     TimerInfo m_TimerInfo;
357     TimerStatus m_TimerStatus;
358     QString m_deviceName;
359     snd_htimestamp_t m_last_time;
360 };
361 
362 /** @} */
363 
364 }} /* namespace drumstick::ALSA */
365 
366 #endif /* DRUMSTICK_ALSATIMER_H */
367