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 #include "errorcheck.h"
20 #include <QReadLocker>
21 #include <QWriteLocker>
22 #include <cmath>
23 #include <cstdio>
24 #include <drumstick/alsatimer.h>
25 /**
26 * @file alsatimer.cpp
27 * Implementation of classes managing ALSA Timers
28 */
29
30 namespace drumstick {
31 namespace ALSA {
32
33 /**
34 * @addtogroup ALSATimer
35 * @{
36 *
37 * Timers provide periodic time events to applications, and also to the ALSA
38 * sequencer.
39 *
40 * There are two mechanisms to deliver the timer events. To use the callback
41 * mechanism, a class must be derived from TimerEventHandler, and a instance
42 * of the derived class must be assigned to the Timer instance using
43 * Timer::setHandler(). If the handler is not assigned, then the Timer instance
44 * will generate the signal Timer::timerExpired().
45 *
46 * Classes:
47 *
48 * TimerInfo: ALSA Timer information container.
49 *
50 * This class is used to hold properties about ALSA Timers.
51 *
52 * TimerId: ALSA Timer identifier container.
53 *
54 * This class provides an unique identifier for a Timer.
55 *
56 * TimerGlobalInfo: Global timer information container.
57 *
58 * This class provides global timer parameters.
59 *
60 * TimerQuery: ALSA Timer inquiry helper.
61 *
62 * This class provides a mechanism to enumerate the available system timers.
63 *
64 * TimerParams: ALSA Timer parameters container.
65 *
66 * This class provides several parameters about a Timer.
67 *
68 * TimerStatus: ALSA Timer status container.
69 *
70 * This class provides some status information about a Timer.
71 *
72 * TimerEventHandler: ALSA Timer events handler.
73 *
74 * This abstract class is used to define an interface that other class can
75 * implement to receive timer events.
76 *
77 * Timer: ALSA Timer management.
78 *
79 * This class represents an ALSA timer object.
80 *
81 * @see https://www.alsa-project.org/alsa-doc/alsa-lib/group___timer.html
82 * @}
83 */
84
85 /**
86 * Constructor
87 */
TimerInfo()88 TimerInfo::TimerInfo()
89 {
90 snd_timer_info_malloc(&m_Info);
91 }
92
93 /**
94 * Cosntructor
95 * @param other ALSA timer info object pointer
96 */
TimerInfo(const snd_timer_info_t * other)97 TimerInfo::TimerInfo(const snd_timer_info_t *other)
98 {
99 snd_timer_info_malloc(&m_Info);
100 snd_timer_info_copy(m_Info, other);
101 }
102
103 /**
104 * Copy constructor
105 * @param other Existing TimerInfo object reference
106 */
TimerInfo(const TimerInfo & other)107 TimerInfo::TimerInfo(const TimerInfo& other)
108 {
109 snd_timer_info_malloc(&m_Info);
110 snd_timer_info_copy(m_Info, other.m_Info);
111 }
112
113 /**
114 * Destructor
115 */
~TimerInfo()116 TimerInfo::~TimerInfo()
117 {
118 snd_timer_info_free(m_Info);
119 }
120
121 /**
122 * Copy the current object
123 * @return Pointer to the new object
124 */
125 TimerInfo*
clone()126 TimerInfo::clone()
127 {
128 return new TimerInfo(m_Info);
129 }
130
131 /**
132 * Assignment operator
133 * @param other Existing TimerInfo object reference
134 * @return a reference of this object
135 */
136 TimerInfo&
operator =(const TimerInfo & other)137 TimerInfo::operator=(const TimerInfo& other)
138 {
139 if (this == &other)
140 return *this;
141 snd_timer_info_copy(m_Info, other.m_Info);
142 return *this;
143 }
144
145 /**
146 * Check if the timer is slave (depends on another device)
147 * @return True if the timer is slave
148 */
149 bool
isSlave()150 TimerInfo::isSlave()
151 {
152 return (snd_timer_info_is_slave(m_Info) != 0);
153 }
154
155 /**
156 * Gets the card number
157 * @return Card number
158 */
159 int
getCard()160 TimerInfo::getCard()
161 {
162 return snd_timer_info_get_card(m_Info);
163 }
164
165 /**
166 * Gets the string identifier
167 * @return String identifier
168 */
169 QString
getId()170 TimerInfo::getId()
171 {
172 return QString(snd_timer_info_get_id(m_Info));
173 }
174
175 /**
176 * Gets the timer name
177 * @return Timer name
178 */
179 QString
getName()180 TimerInfo::getName()
181 {
182 return QString(snd_timer_info_get_name(m_Info));
183 }
184
185 /**
186 * Gets the timer resolution (timer period in nanoseconds)
187 * @return Timer resolution in nanos
188 */
189 long
getResolution()190 TimerInfo::getResolution()
191 {
192 return snd_timer_info_get_resolution(m_Info);
193 }
194
195 /**
196 * Gets the timer frequency in Hz
197 * @return Timer frequency in Hz
198 */
199 long
getFrequency()200 TimerInfo::getFrequency()
201 {
202 long res = getResolution();
203 if (res > 0)
204 {
205 return 1000000000L / res;
206 }
207 return 0;
208 }
209
210 /**
211 * Gets the size of the ALSA timer info object
212 * @return Size of the ALSA object
213 */
214 int
getSizeOfInfo() const215 TimerInfo::getSizeOfInfo() const
216 {
217 return snd_timer_info_sizeof();
218 }
219
220 /**
221 * Gets the maximum timer ticks
222 * @return Maximum timer ticks
223 * @deprecated
224 */
225 long
getTicks()226 TimerInfo::getTicks()
227 {
228 return snd_timer_info_get_ticks(m_Info);
229 }
230
231 /**
232 * Constructor
233 */
TimerId()234 TimerId::TimerId()
235 {
236 snd_timer_id_malloc(&m_Info);
237 }
238
239 /**
240 * Constructor
241 * @param other ALSA timer ID object pointer
242 */
TimerId(const snd_timer_id_t * other)243 TimerId::TimerId(const snd_timer_id_t *other)
244 {
245 snd_timer_id_malloc(&m_Info);
246 snd_timer_id_copy(m_Info, other);
247 if (getCard() < 0)
248 setCard(0);
249 if (getDevice() < 0)
250 setDevice(0);
251 if (getSubdevice() < 0)
252 setSubdevice(0);
253 }
254
255 /**
256 * Copy constructor
257 * @param other Existing TimerId object reference
258 */
TimerId(const TimerId & other)259 TimerId::TimerId(const TimerId& other)
260 {
261 snd_timer_id_malloc(&m_Info);
262 snd_timer_id_copy(m_Info, other.m_Info);
263 if (getCard() < 0)
264 setCard(0);
265 if (getDevice() < 0)
266 setDevice(0);
267 if (getSubdevice() < 0)
268 setSubdevice(0);
269 }
270
271 /**
272 * Constructor
273 * @param cls Class
274 * @param scls Subclass
275 * @param card Card
276 * @param dev Device
277 * @param sdev Subdevice
278 */
TimerId(int cls,int scls,int card,int dev,int sdev)279 TimerId::TimerId(int cls, int scls, int card, int dev, int sdev)
280 {
281 snd_timer_id_malloc(&m_Info);
282 setClass(cls);
283 setSlaveClass(scls);
284 setCard(card);
285 setDevice(dev);
286 setSubdevice(sdev);
287 }
288
289 /**
290 * Destructor
291 */
~TimerId()292 TimerId::~TimerId()
293 {
294 snd_timer_id_free(m_Info);
295 }
296
297 /**
298 * Copy the object
299 * @return Pointer to the new object
300 */
301 TimerId*
clone()302 TimerId::clone()
303 {
304 return new TimerId(m_Info);
305 }
306
307 /**
308 * Assignment operator
309 * @param other Existing TimerId object reference
310 * @return This object
311 */
312 TimerId&
operator =(const TimerId & other)313 TimerId::operator=(const TimerId& other)
314 {
315 if (this == &other)
316 return *this;
317 snd_timer_id_copy(m_Info, other.m_Info);
318 if (getCard() < 0)
319 setCard(0);
320 if (getDevice() < 0)
321 setDevice(0);
322 if (getSubdevice() < 0)
323 setSubdevice(0);
324 return *this;
325 }
326
327 /**
328 * Set the class identifier. Existing classes:
329 * <ul>
330 * <li> SND_TIMER_CLASS_SLAVE: slave timer</li>
331 * <li> SND_TIMER_CLASS_GLOBAL: global timer</li>
332 * <li> SND_TIMER_CLASS_CARD: card timer</li>
333 * <li> SND_TIMER_CLASS_PCM: PCM timer</li>
334 * </ul>
335 * @param devclass Class identifier.
336 */
337 void
setClass(int devclass)338 TimerId::setClass(int devclass)
339 {
340 snd_timer_id_set_class(m_Info, devclass);
341 }
342
343 /**
344 * Gets the class identifier.
345 * @return Class identifier
346 * @see setClass()
347 */
348 int
getClass()349 TimerId::getClass()
350 {
351 return snd_timer_id_get_class(m_Info);
352 }
353
354 /**
355 * Sets the Slave class
356 * @param devsclass Slave class
357 */
358 void
setSlaveClass(int devsclass)359 TimerId::setSlaveClass(int devsclass)
360 {
361 snd_timer_id_set_sclass(m_Info, devsclass);
362 }
363
364 /**
365 * Gets the slave class
366 * @return Slave class
367 */
368 int
getSlaveClass()369 TimerId::getSlaveClass()
370 {
371 return snd_timer_id_get_sclass(m_Info);
372 }
373
374 /**
375 * Sets the card number
376 * @param card Card number
377 */
378 void
setCard(int card)379 TimerId::setCard(int card)
380 {
381 snd_timer_id_set_card(m_Info, card);
382 }
383
384 /**
385 * Gets the card number
386 * @return Card number
387 */
388 int
getCard()389 TimerId::getCard()
390 {
391 return snd_timer_id_get_card(m_Info);
392 }
393
394 /**
395 * Sets the device number
396 * @param device Device number
397 */
398 void
setDevice(int device)399 TimerId::setDevice(int device)
400 {
401 snd_timer_id_set_device(m_Info, device);
402 }
403
404 /**
405 * Gets the device number
406 * @return Device number
407 */
408 int
getDevice()409 TimerId::getDevice()
410 {
411 return snd_timer_id_get_device(m_Info);
412 }
413
414 /**
415 * Sets the subdevice number
416 * @param subdevice Subdevice number
417 */
418 void
setSubdevice(int subdevice)419 TimerId::setSubdevice(int subdevice)
420 {
421 snd_timer_id_set_subdevice (m_Info, subdevice);
422 }
423
424 /**
425 * Gets the subdevice number
426 * @return Subdevice number
427 */
428 int
getSubdevice()429 TimerId::getSubdevice()
430 {
431 return snd_timer_id_get_subdevice(m_Info);
432 }
433
434 /**
435 * Gets the size of the ALSA timer ID object
436 * @return Size of the ALSA object
437 */
438 int
getSizeOfInfo() const439 TimerId::getSizeOfInfo() const
440 {
441 return snd_timer_id_sizeof();
442 }
443
444 /**
445 * Constructor
446 * @param deviceName Device name, usually "hw"
447 * @param openMode Open mode (unknown values)
448 */
TimerQuery(const QString & deviceName,int openMode)449 TimerQuery::TimerQuery(const QString& deviceName, int openMode)
450 {
451 DRUMSTICK_ALSA_CHECK_WARNING( snd_timer_query_open( &m_Info,
452 deviceName.toLocal8Bit().data(),
453 openMode ));
454 readTimers();
455 }
456
457 /**
458 * Constructor
459 * @param deviceName Device name, usually "hw"
460 * @param openMode Open mode (unknown values)
461 * @param conf ALSA configuration object pointer
462 */
TimerQuery(const QString & deviceName,int openMode,snd_config_t * conf)463 TimerQuery::TimerQuery( const QString& deviceName, int openMode,
464 snd_config_t* conf )
465 {
466 DRUMSTICK_ALSA_CHECK_WARNING( snd_timer_query_open_lconf( &m_Info,
467 deviceName.toLocal8Bit().data(),
468 openMode, conf ));
469 readTimers();
470 }
471
472 /**
473 * Destructor
474 */
~TimerQuery()475 TimerQuery::~TimerQuery()
476 {
477 freeTimers();
478 snd_timer_query_close(m_Info);
479 }
480
481 /**
482 * Enumerate the available timers storing the results into an internal list
483 */
484 void
readTimers()485 TimerQuery::readTimers()
486 {
487 TimerId tid;
488 snd_timer_id_set_class(tid.m_Info, SND_TIMER_CLASS_NONE);
489 for(;;)
490 {
491 int rc = snd_timer_query_next_device(m_Info, tid.m_Info);
492 if ((rc < 0) || (tid.getClass() < 0)) {
493 break;
494 }
495 m_timers.append(tid);
496 }
497 }
498
499 /**
500 * Release the internal list of timers
501 */
502 void
freeTimers()503 TimerQuery::freeTimers()
504 {
505 m_timers.clear();
506 }
507
508 /**
509 * Get a TimerGlobalInfo object
510 * @return TimerGlobalInfo object reference
511 */
512 TimerGlobalInfo&
getGlobalInfo()513 TimerQuery::getGlobalInfo()
514 {
515 snd_timer_query_info(m_Info, m_GlobalInfo.m_Info);
516 return m_GlobalInfo;
517 }
518
519 /**
520 * Sets the global parameters
521 * @param params Pointer to an ALSA timer global parameters object
522 */
523 void
setGlobalParams(snd_timer_gparams_t * params)524 TimerQuery::setGlobalParams(snd_timer_gparams_t* params)
525 {
526 snd_timer_query_params(m_Info, params);
527 }
528
529 /**
530 * Gets the global timer parameters
531 * @param params Pointer to an ALSA timer global parameters object
532 */
533 void
getGlobalParams(snd_timer_gparams_t * params)534 TimerQuery::getGlobalParams(snd_timer_gparams_t* params)
535 {
536 snd_timer_query_params(m_Info, params);
537 }
538
539 /**
540 * Gets the global timer status
541 * @param status Pointer to an ALSA timer global status object
542 */
543 void
getGlobalStatus(snd_timer_gstatus_t * status)544 TimerQuery::getGlobalStatus(snd_timer_gstatus_t *status)
545 {
546 snd_timer_query_status(m_Info, status);
547 }
548
549 /**
550 * Default constructor
551 */
TimerGlobalInfo()552 TimerGlobalInfo::TimerGlobalInfo()
553 {
554 snd_timer_ginfo_malloc(&m_Info);
555 }
556
557 /**
558 * Constructor
559 * @param other ALSA global info object pointer
560 */
TimerGlobalInfo(const snd_timer_ginfo_t * other)561 TimerGlobalInfo::TimerGlobalInfo(const snd_timer_ginfo_t* other)
562 {
563 snd_timer_ginfo_malloc(&m_Info);
564 snd_timer_ginfo_copy(m_Info, other);
565 }
566
567 /**
568 * Copy constructor
569 * @param other Existing TimerGlobalInfo object reference
570 */
TimerGlobalInfo(const TimerGlobalInfo & other)571 TimerGlobalInfo::TimerGlobalInfo(const TimerGlobalInfo& other)
572 {
573 snd_timer_ginfo_malloc(&m_Info);
574 snd_timer_ginfo_copy(m_Info, other.m_Info);
575 }
576
577 /**
578 * Destructor
579 */
~TimerGlobalInfo()580 TimerGlobalInfo::~TimerGlobalInfo()
581 {
582 snd_timer_ginfo_free(m_Info);
583 }
584
585 /**
586 * Copy the current object
587 * @return Pointer to the new object
588 */
589 TimerGlobalInfo*
clone()590 TimerGlobalInfo::clone()
591 {
592 return new TimerGlobalInfo(m_Info);
593 }
594
595 /**
596 * Assignment operator
597 * @param other Existing TimerGlobalInfo object reference
598 * @return This object
599 */
600 TimerGlobalInfo&
operator =(const TimerGlobalInfo & other)601 TimerGlobalInfo::operator=(const TimerGlobalInfo& other)
602 {
603 if (this == &other)
604 return *this;
605 snd_timer_ginfo_copy(m_Info, other.m_Info);
606 return *this;
607 }
608
609 /**
610 * Sets the timer identifier
611 * @param tid TimerId object reference
612 */
613 void
setTimerId(const TimerId & tid)614 TimerGlobalInfo::setTimerId(const TimerId& tid)
615 {
616 m_Id = tid;
617 snd_timer_ginfo_set_tid (m_Info, m_Id.m_Info);
618 }
619
620 /**
621 * Gets the timer identifier
622 * @return TimerId object reference
623 */
624 TimerId&
getTimerId()625 TimerGlobalInfo::getTimerId()
626 {
627 m_Id = TimerId(snd_timer_ginfo_get_tid (m_Info));
628 return m_Id;
629 }
630
631 /**
632 * Gets the flags
633 * @return Undocumented flags
634 */
635 unsigned int
getFlags()636 TimerGlobalInfo::getFlags()
637 {
638 return snd_timer_ginfo_get_flags (m_Info);
639 }
640
641 /**
642 * Gets the card number
643 * @return Card number
644 */
645 int
getCard()646 TimerGlobalInfo::getCard()
647 {
648 return snd_timer_ginfo_get_card (m_Info);
649 }
650
651 /**
652 * Gets the timer ID string
653 * @return Timer ID string
654 */
655 QString
getId()656 TimerGlobalInfo::getId()
657 {
658 return QString(snd_timer_ginfo_get_id (m_Info));
659 }
660
661 /**
662 * Gets the timer name
663 * @return Timer name
664 */
665 QString
getName()666 TimerGlobalInfo::getName()
667 {
668 return QString(snd_timer_ginfo_get_name (m_Info));
669 }
670
671 /**
672 * Gets the timer resolution in ns
673 * @return Timer resolution in ns
674 */
675 unsigned long
getResolution()676 TimerGlobalInfo::getResolution()
677 {
678 return snd_timer_ginfo_get_resolution (m_Info);
679 }
680
681 /**
682 * Gets timer minimal resolution in ns
683 * @return Minimal resolution in ns
684 */
685 unsigned long
getMinResolution()686 TimerGlobalInfo::getMinResolution()
687 {
688 return snd_timer_ginfo_get_resolution_min (m_Info);
689 }
690
691 /**
692 * Gets timer maximal resolution in ns
693 * @return Maximal resolution in ns
694 */
695 unsigned long
getMaxResolution()696 TimerGlobalInfo::getMaxResolution()
697 {
698 return snd_timer_ginfo_get_resolution_max(m_Info);
699 }
700
701 /**
702 * Gets current timer clients
703 * @return Current clients
704 */
705 unsigned int
getClients()706 TimerGlobalInfo::getClients()
707 {
708 return snd_timer_ginfo_get_clients(m_Info);
709 }
710
711 /**
712 * Gets the size of the ALSA timer global info object
713 * @return Size of the ALSA object
714 */
715 int
getSizeOfInfo() const716 TimerGlobalInfo::getSizeOfInfo() const
717 {
718 return snd_timer_ginfo_sizeof();
719 }
720
721 /**
722 * Default constructor
723 */
TimerParams()724 TimerParams::TimerParams()
725 {
726 snd_timer_params_malloc (&m_Info);
727 }
728
729 /**
730 * Constructor
731 * @param other Pointer to an ALSA timer parameters object
732 */
TimerParams(const snd_timer_params_t * other)733 TimerParams::TimerParams(const snd_timer_params_t *other)
734 {
735 snd_timer_params_malloc (&m_Info);
736 snd_timer_params_copy (m_Info, other);
737 }
738
739 /**
740 * Copy constructor
741 * @param other Existing TimerParams object reference
742 */
TimerParams(const TimerParams & other)743 TimerParams::TimerParams(const TimerParams& other)
744 {
745 snd_timer_params_malloc (&m_Info);
746 snd_timer_params_copy (m_Info, other.m_Info);
747 }
748
749 /**
750 * Destructor
751 * @return
752 */
~TimerParams()753 TimerParams::~TimerParams()
754 {
755 snd_timer_params_free (m_Info);
756 }
757
758 /**
759 * Copy the current object
760 * @return Pointer to the new object
761 */
762 TimerParams*
clone()763 TimerParams::clone()
764 {
765 return new TimerParams(m_Info);
766 }
767
768 /**
769 * Assignment operator
770 * @param other Existing TimerParams object reference
771 * @return This object
772 */
773 TimerParams&
operator =(const TimerParams & other)774 TimerParams::operator=(const TimerParams& other)
775 {
776 if (this == &other)
777 return *this;
778 snd_timer_params_copy (m_Info, other.m_Info);
779 return *this;
780 }
781
782 /**
783 * Sets the automatic start flag
784 * @param auto_start Value for the automatic start flag
785 */
786 void
setAutoStart(bool auto_start)787 TimerParams::setAutoStart(bool auto_start)
788 {
789 snd_timer_params_set_auto_start (m_Info, auto_start ? 1 : 0);
790 }
791
792 /**
793 * Gets the automatic start flag
794 * @return True if the timer starts automatically
795 */
796 bool
getAutoStart()797 TimerParams::getAutoStart()
798 {
799 return (snd_timer_params_get_auto_start (m_Info) != 0);
800 }
801
802 /**
803 * Sets the exclusive flag
804 * @param exclusive True if the timer has the exclusive flag
805 */
806 void
setExclusive(bool exclusive)807 TimerParams::setExclusive(bool exclusive)
808 {
809 snd_timer_params_set_exclusive (m_Info, exclusive ? 1 : 0);
810 }
811
812 /**
813 * Gets the timer's exclusive flag
814 * @return True if the timer has the exclusive flag
815 */
816 bool
getExclusive()817 TimerParams::getExclusive()
818 {
819 return (snd_timer_params_get_exclusive (m_Info) != 0);
820 }
821
822 /**
823 * Sets the timer early event
824 * @param early_event Timer early event
825 */
826 void
setEarlyEvent(bool early_event)827 TimerParams::setEarlyEvent(bool early_event)
828 {
829 snd_timer_params_set_early_event (m_Info, early_event ? 1 : 0);
830 }
831
832 /**
833 * Gets the timer early event
834 * @return Timer early event
835 */
836 bool
getEarlyEvent()837 TimerParams::getEarlyEvent()
838 {
839 return (snd_timer_params_get_early_event (m_Info) != 0);
840 }
841
842 /**
843 * Sets the timer ticks
844 * @param ticks Timer ticks
845 */
846 void
setTicks(long ticks)847 TimerParams::setTicks(long ticks)
848 {
849 snd_timer_params_set_ticks (m_Info, ticks);
850 }
851
852 /**
853 * Gets the timer ticks
854 * @return Timer ticks
855 */
856 long
getTicks()857 TimerParams::getTicks()
858 {
859 return snd_timer_params_get_ticks (m_Info);
860 }
861
862 /**
863 * Sets the queue size (32-1024)
864 * @param queue_size Queue size
865 */
866 void
setQueueSize(long queue_size)867 TimerParams::setQueueSize(long queue_size)
868 {
869 snd_timer_params_set_queue_size (m_Info, queue_size);
870 }
871
872 /**
873 * Gets the queue size
874 * @return Queue size
875 */
876 long
getQueueSize()877 TimerParams::getQueueSize()
878 {
879 return snd_timer_params_get_queue_size (m_Info);
880 }
881
882 /**
883 * Sets the event filter
884 * @param filter Event filter
885 */
886 void
setFilter(unsigned int filter)887 TimerParams::setFilter(unsigned int filter)
888 {
889 snd_timer_params_set_filter (m_Info, filter);
890 }
891
892 /**
893 * Gets the event filter
894 * @return Event filter
895 */
896 unsigned int
getFilter()897 TimerParams::getFilter()
898 {
899 return snd_timer_params_get_filter (m_Info);
900 }
901
902 /**
903 * Gets the size of the ALSA timer parameters object
904 * @return Size of the ALSA object
905 */
906 int
getSizeOfInfo() const907 TimerParams::getSizeOfInfo() const
908 {
909 return snd_timer_params_sizeof();
910 }
911
912 /**
913 * Default constructor
914 */
TimerStatus()915 TimerStatus::TimerStatus()
916 {
917 snd_timer_status_malloc (&m_Info);
918 }
919
920 /**
921 * Constructor
922 * @param other Pointer to an existing ALSA timer status object
923 */
TimerStatus(const snd_timer_status_t * other)924 TimerStatus::TimerStatus(const snd_timer_status_t *other)
925 {
926 snd_timer_status_malloc (&m_Info);
927 snd_timer_status_copy (m_Info, other);
928 }
929
930 /**
931 * Copy constructor
932 * @param other Existing TimerStatus object reference
933 */
TimerStatus(const TimerStatus & other)934 TimerStatus::TimerStatus(const TimerStatus& other)
935 {
936 snd_timer_status_malloc (&m_Info);
937 snd_timer_status_copy (m_Info, other.m_Info);
938 }
939
940 /**
941 * Destructor
942 */
~TimerStatus()943 TimerStatus::~TimerStatus()
944 {
945 snd_timer_status_free (m_Info);
946 }
947
948 /**
949 * Copy the current object
950 * @return Pointer to the new object
951 */
952 TimerStatus*
clone()953 TimerStatus::clone()
954 {
955 return new TimerStatus(m_Info);
956 }
957
958 /**
959 * Assignment operator
960 * @param other Existing TimerStatus object reference
961 * @return This object
962 */
963 TimerStatus&
operator =(const TimerStatus & other)964 TimerStatus::operator=(const TimerStatus& other)
965 {
966 if (this == &other)
967 return *this;
968 snd_timer_status_copy (m_Info, other.m_Info);
969 return *this;
970 }
971
972 /**
973 * Gets the high resolution time-stamp
974 * @return High resolution time-stamp
975 */
976 snd_htimestamp_t
getTimestamp()977 TimerStatus::getTimestamp()
978 {
979 return snd_timer_status_get_timestamp (m_Info);
980 }
981
982 /**
983 * Gets the resolution in us
984 * @return Resolution in us
985 */
986 long
getResolution()987 TimerStatus::getResolution()
988 {
989 return snd_timer_status_get_resolution (m_Info);
990 }
991
992 /**
993 * Gets the master tick lost count
994 * @return Master tick lost count
995 */
996 long
getLost()997 TimerStatus::getLost()
998 {
999 return snd_timer_status_get_lost (m_Info);
1000 }
1001
1002 /**
1003 * Gets the overrun count
1004 * @return Overrun count
1005 */
1006 long
getOverrun()1007 TimerStatus::getOverrun()
1008 {
1009 return snd_timer_status_get_overrun (m_Info);
1010 }
1011
1012 /**
1013 * Gets the count of used queue elements
1014 * @return Count of used queue elements
1015 */
1016 long
getQueue()1017 TimerStatus::getQueue()
1018 {
1019 return snd_timer_status_get_queue (m_Info);
1020 }
1021
1022 /**
1023 * Gets the size of the ALSA timer status object
1024 * @return Size of the ALSA object
1025 */
1026 int
getSizeOfInfo() const1027 TimerStatus::getSizeOfInfo() const
1028 {
1029 return snd_timer_status_sizeof();
1030 }
1031
1032 /**
1033 * Constructor.
1034 * Open flags can be a combination of the following constants:
1035 * <ul>
1036 * <li>SND_TIMER_OPEN_NONBLOCK: non-blocking behavior</li>
1037 * <li>SND_TIMER_OPEN_TREAD: enhanced read, use time-stamps and event notification</li>
1038 * </ul>
1039 * @param deviceName Name of the device
1040 * @param openMode Open mode flags bitmap
1041 * @param parent Optional parent object
1042 */
Timer(const QString & deviceName,int openMode,QObject * parent)1043 Timer::Timer( const QString& deviceName, int openMode, QObject* parent )
1044 : QObject(parent),
1045 m_asyncHandler(nullptr),
1046 m_handler(nullptr),
1047 m_thread(nullptr),
1048 m_deviceName(deviceName)
1049 {
1050 DRUMSTICK_ALSA_CHECK_ERROR( snd_timer_open( &m_Info, m_deviceName.toLocal8Bit().data(),
1051 openMode ));
1052 }
1053
1054 /**
1055 * Constructor.
1056 * Open flags can be a combination of the following constants:
1057 * <ul>
1058 * <li>SND_TIMER_OPEN_NONBLOCK: non-blocking behavior</li>
1059 * <li>SND_TIMER_OPEN_TREAD: enhanced read, use time-stamps and event notification</li>
1060 * </ul>
1061 * @param deviceName Name of the device
1062 * @param openMode Open mode flags bitmap
1063 * @param conf ALSA configuration object pointer
1064 * @param parent Optional parent object
1065 */
Timer(const QString & deviceName,int openMode,snd_config_t * conf,QObject * parent)1066 Timer::Timer( const QString& deviceName, int openMode, snd_config_t* conf,
1067 QObject* parent )
1068 : QObject(parent),
1069 m_asyncHandler(nullptr),
1070 m_handler(nullptr),
1071 m_thread(nullptr),
1072 m_deviceName(deviceName)
1073 {
1074 DRUMSTICK_ALSA_CHECK_ERROR( snd_timer_open_lconf( &m_Info,
1075 m_deviceName.toLocal8Bit().data(),
1076 openMode, conf ));
1077 }
1078
1079 /**
1080 * Constructor
1081 * Open flags can be a combination of the following constants:
1082 * <ul>
1083 * <li>SND_TIMER_OPEN_NONBLOCK: non-blocking behavior</li>
1084 * <li>SND_TIMER_OPEN_TREAD: enhanced read, use time-stamps and event notification</li>
1085 * </ul>
1086 * @param id TimerId object reference
1087 * @param openMode Open mode flags bitmap
1088 * @param parent Optional parent object
1089 */
Timer(TimerId & id,int openMode,QObject * parent)1090 Timer::Timer( TimerId& id, int openMode, QObject* parent )
1091 : QObject(parent),
1092 m_asyncHandler(nullptr),
1093 m_handler(nullptr),
1094 m_thread(nullptr)
1095 {
1096 m_deviceName = QString("hw:CLASS=%1,SCLASS=%2,CARD=%3,DEV=%4,SUBDEV=%5")
1097 .arg(id.getClass())
1098 .arg(id.getSlaveClass())
1099 .arg(id.getCard())
1100 .arg(id.getDevice())
1101 .arg(id.getSubdevice());
1102 DRUMSTICK_ALSA_CHECK_ERROR( snd_timer_open( &m_Info,
1103 m_deviceName.toLocal8Bit().data(),
1104 openMode ));
1105 }
1106
1107 /**
1108 * Constructor.
1109 * Open flags can be a combination of the following constants:
1110 * <ul>
1111 * <li>SND_TIMER_OPEN_NONBLOCK: non-blocking behavior</li>
1112 * <li>SND_TIMER_OPEN_TREAD: enhanced read, use time-stamps and event notification</li>
1113 * </ul>
1114 * @param cls Class
1115 * @param scls Subclass
1116 * @param card Card
1117 * @param dev Device
1118 * @param sdev Subdevice
1119 * @param openMode Open mode flags bitmap
1120 * @param parent Optional parent object
1121 */
Timer(int cls,int scls,int card,int dev,int sdev,int openMode,QObject * parent)1122 Timer::Timer( int cls, int scls, int card, int dev, int sdev,
1123 int openMode, QObject* parent )
1124 : QObject(parent),
1125 m_asyncHandler(nullptr),
1126 m_handler(nullptr),
1127 m_thread(nullptr)
1128 {
1129 m_deviceName = QString("hw:CLASS=%1,SCLASS=%2,CARD=%3,DEV=%4,SUBDEV=%5")
1130 .arg(cls)
1131 .arg(scls)
1132 .arg(card)
1133 .arg(dev)
1134 .arg(sdev);
1135 DRUMSTICK_ALSA_CHECK_ERROR( snd_timer_open( &m_Info,
1136 m_deviceName.toLocal8Bit().data(),
1137 openMode ));
1138 }
1139
1140 /**
1141 * Destructor.
1142 */
~Timer()1143 Timer::~Timer()
1144 {
1145 stopEvents();
1146 if (m_thread != nullptr)
1147 delete m_thread;
1148 DRUMSTICK_ALSA_CHECK_WARNING(snd_timer_close(m_Info));
1149 }
1150
1151 /**
1152 * Adds an asynchronous timer handler function.
1153 * @param callback Function handler
1154 * @param private_data Any data that will be passed to the callback
1155 */
1156 void
addAsyncTimerHandler(snd_async_callback_t callback,void * private_data)1157 Timer::addAsyncTimerHandler(snd_async_callback_t callback, void *private_data)
1158 {
1159 DRUMSTICK_ALSA_CHECK_WARNING(snd_async_add_timer_handler(&m_asyncHandler, m_Info, callback, private_data));
1160 }
1161
1162 /**
1163 * Gets the ALSA timer handle
1164 * @return ALSA timer handle
1165 */
1166 snd_timer_t*
getTimerHandle()1167 Timer::getTimerHandle()
1168 {
1169 return snd_async_handler_get_timer(m_asyncHandler);
1170 }
1171
1172 /**
1173 * Gets the count of poll descriptors
1174 * @return Count of poll descriptors
1175 */
1176 int
getPollDescriptorsCount()1177 Timer::getPollDescriptorsCount()
1178 {
1179 return snd_timer_poll_descriptors_count(m_Info);
1180 }
1181
1182 /**
1183 * Gets poll descriptors
1184 * @param pfds Pointer to a pollfd array
1185 * @param space Number of pollfd elements available
1186 */
1187 void
pollDescriptors(struct pollfd * pfds,unsigned int space)1188 Timer::pollDescriptors(struct pollfd *pfds, unsigned int space)
1189 {
1190 DRUMSTICK_ALSA_CHECK_WARNING(snd_timer_poll_descriptors(m_Info, pfds, space));
1191 }
1192
1193 /**
1194 * Gets returned events from poll descriptors
1195 * @param pfds Pointer to a pollfd array
1196 * @param nfds Number of pollfd elements available
1197 * @param revents Returned events
1198 */
1199 void
pollDescriptorsRevents(struct pollfd * pfds,unsigned int nfds,unsigned short * revents)1200 Timer::pollDescriptorsRevents(struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
1201 {
1202 DRUMSTICK_ALSA_CHECK_WARNING(snd_timer_poll_descriptors_revents(m_Info, pfds, nfds, revents));
1203 }
1204
1205 /**
1206 * Gets the timer info object
1207 * @return TimerInfo object reference
1208 */
1209 TimerInfo&
getTimerInfo()1210 Timer::getTimerInfo()
1211 {
1212 snd_timer_info (m_Info, m_TimerInfo.m_Info);
1213 return m_TimerInfo;
1214 }
1215
1216 /**
1217 * Sets the timer parameters
1218 * @param params TimerParams object reference
1219 */
1220 void
setTimerParams(const TimerParams & params)1221 Timer::setTimerParams(const TimerParams& params)
1222 {
1223 DRUMSTICK_ALSA_CHECK_WARNING( snd_timer_params(m_Info, params.m_Info) );
1224 }
1225
1226 /**
1227 * Gets the timer status
1228 * @return TimerStatus object reference
1229 */
1230 TimerStatus&
getTimerStatus()1231 Timer::getTimerStatus()
1232 {
1233 DRUMSTICK_ALSA_CHECK_WARNING( snd_timer_status(m_Info, m_TimerStatus.m_Info) );
1234 return m_TimerStatus;
1235 }
1236
1237 /**
1238 * Start rolling the timer
1239 */
1240 void
start()1241 Timer::start()
1242 {
1243 DRUMSTICK_ALSA_CHECK_WARNING(snd_timer_start(m_Info));
1244 }
1245
1246 /**
1247 * Stop rolling the timer
1248 */
1249 void
stop()1250 Timer::stop()
1251 {
1252 DRUMSTICK_ALSA_CHECK_WARNING(snd_timer_stop(m_Info));
1253 }
1254
1255 /**
1256 * Continue rolling the timer
1257 */
1258 void
continueRunning()1259 Timer::continueRunning()
1260 {
1261 DRUMSTICK_ALSA_CHECK_WARNING(snd_timer_continue(m_Info));
1262 }
1263
1264 /**
1265 * Read bytes from the timer handle
1266 * @param buffer Buffer to store the input bytes
1267 * @param size Input buffer size in bytes
1268 * @return Bytes read from the timer
1269 */
1270 ssize_t
read(void * buffer,size_t size)1271 Timer::read(void *buffer, size_t size)
1272 {
1273 return snd_timer_read(m_Info, buffer, size);
1274 }
1275
1276 /**
1277 * Internal function to deliver the timer events using one of the two available
1278 * methods:
1279 * <ul>
1280 * <li>TimerEventHandler instance pointer provided in Timer::setHandler()</li>
1281 * <li>A signal Timer::timerExpired() is emitted, otherwise</li>
1282 * </ul>
1283 */
1284 void
doEvents()1285 Timer::doEvents()
1286 {
1287 snd_timer_tread_t tr;
1288 while ( read(&tr, sizeof(tr)) == sizeof(tr) ) {
1289 int msecs = ((tr.tstamp.tv_sec - m_last_time.tv_sec) * 1000) +
1290 round((tr.tstamp.tv_nsec - m_last_time.tv_nsec) / 1000000.0);
1291 m_last_time = tr.tstamp;
1292 if ( m_handler != nullptr )
1293 m_handler->handleTimerEvent(tr.val, msecs);
1294 else
1295 emit timerExpired(tr.val, msecs);
1296 }
1297 }
1298
1299 /**
1300 * Starts the events dispatching thread
1301 */
startEvents()1302 void Timer::startEvents()
1303 {
1304 m_last_time = getTimerStatus().getTimestamp();
1305 if (m_thread == nullptr) {
1306 m_thread = new TimerInputThread(this, 500);
1307 m_thread->start();
1308 }
1309 }
1310
1311 /**
1312 * Stops the events dispatching thread
1313 */
stopEvents()1314 void Timer::stopEvents()
1315 {
1316 int counter = 0;
1317 if (m_thread != nullptr) {
1318 m_thread->stop();
1319 while (!m_thread->wait(500) && (counter < 10)) {
1320 counter++;
1321 }
1322 if (!m_thread->isFinished()) {
1323 m_thread->terminate();
1324 }
1325 delete m_thread;
1326 }
1327 }
1328
1329 /**
1330 * Check and return the best available global TimerId in the system, meaning
1331 * the timer with higher frequency (or lesser period, resolution).
1332 * @return A TimerId object
1333 * @since 0.3.0
1334 */
1335 TimerId
bestGlobalTimerId()1336 Timer::bestGlobalTimerId()
1337 {
1338 TimerId id;
1339 snd_timer_t* timer;
1340 snd_timer_info_t* info;
1341 long res, best_res = LONG_MAX;
1342 char timername[64];
1343 int test_devs[] = {
1344 SND_TIMER_GLOBAL_SYSTEM
1345 , SND_TIMER_GLOBAL_RTC
1346 #ifdef SND_TIMER_GLOBAL_HPET
1347 , SND_TIMER_GLOBAL_HPET
1348 #endif
1349 #ifdef SND_TIMER_GLOBAL_HRTIMER
1350 , SND_TIMER_GLOBAL_HRTIMER
1351 #endif
1352 };
1353 int max_global_timers = sizeof(test_devs)/sizeof(int);
1354 int clas = SND_TIMER_CLASS_GLOBAL;
1355 int scls = SND_TIMER_SCLASS_NONE;
1356 int card = 0;
1357 int dev = SND_TIMER_GLOBAL_SYSTEM;
1358 int sdev = 0;
1359 int err = 0;
1360 int is_slave = 0;
1361 int i;
1362 snd_timer_info_alloca(&info);
1363 // default system timer
1364 id.setClass(clas);
1365 id.setSlaveClass(scls);
1366 id.setCard(card);
1367 id.setDevice(dev);
1368 id.setSubdevice(sdev);
1369 // select a non slave timer with the lowest resolution value
1370 for( i = 0; i < max_global_timers; ++i )
1371 {
1372 dev = test_devs[i];
1373 sprintf( timername, "hw:CLASS=%i,SCLASS=%i,CARD=%i,DEV=%i,SUBDEV=%i",
1374 clas, scls, card, dev, sdev );
1375 err = snd_timer_open(&timer, timername, SND_TIMER_OPEN_NONBLOCK);
1376 if (err < 0) continue;
1377 err = snd_timer_info(timer, info);
1378 if (err == 0) {
1379 is_slave = snd_timer_info_is_slave(info);
1380 res = snd_timer_info_get_resolution(info);
1381 if ((is_slave == 0) && (best_res > res)) {
1382 best_res = res;
1383 id.setDevice(dev);
1384 }
1385 }
1386 snd_timer_close(timer);
1387 }
1388 return id;
1389 }
1390
1391 /**
1392 * Check and return the best available global Timer in the system, meaning
1393 * the timer with higher frequency (or lesser period, resolution).
1394 * @param openMode Open mode flags
1395 * @param parent Optional parent object
1396 * @return A new Timer instance pointer
1397 */
1398 Timer*
bestGlobalTimer(int openMode,QObject * parent)1399 Timer::bestGlobalTimer(int openMode, QObject* parent)
1400 {
1401 TimerId id = bestGlobalTimerId();
1402 return new Timer(id, openMode, parent);
1403 }
1404
1405 /**
1406 * Loop reading and dispatching timer events.
1407 */
1408 void
run()1409 Timer::TimerInputThread::run()
1410 {
1411 int err, count;
1412 struct pollfd *fds;
1413 if (m_timer == nullptr) return;
1414
1415 count = m_timer->getPollDescriptorsCount();
1416 fds = (pollfd *) calloc(count, sizeof(struct pollfd));
1417 if (fds == nullptr) {
1418 qWarning() << "allocation error!";
1419 return;
1420 }
1421 fds->events = POLLIN;
1422 fds->revents = 0;
1423
1424 try {
1425 while (!stopped() && (m_timer != nullptr)) {
1426 m_timer->pollDescriptors(fds, count);
1427 if ((err = poll(fds, count, m_Wait)) < 0) {
1428 qWarning() << "poll error " << err << "(" << strerror(err) << ")";
1429 free(fds);
1430 return;
1431 }
1432 if (err == 0) {
1433 qWarning() << "timer time out";
1434 free(fds);
1435 return;
1436 }
1437 m_timer->doEvents();
1438 }
1439 } catch (...) {
1440 qWarning() << "exception in input thread";
1441 }
1442 free(fds);
1443 }
1444
1445 /**
1446 * Returns the rolling state of the timer thread
1447 * @return The stopped state
1448 */
1449 bool
stopped()1450 Timer::TimerInputThread::stopped()
1451 {
1452 QReadLocker locker(&m_mutex);
1453 return m_Stopped;
1454 }
1455
1456 /**
1457 * Stop the thread
1458 */
1459 void
stop()1460 Timer::TimerInputThread::stop()
1461 {
1462 QWriteLocker locker(&m_mutex);
1463 m_Stopped = true;
1464 }
1465
1466 } // namespace ALSA
1467 } // namespace drumstick
1468
1469