25 #include <QReadLocker>
26 #include <QWriteLocker>
27 #if defined(RTKIT_SUPPORT)
28 #include <QDBusConnection>
29 #include <QDBusInterface>
30 #include <sys/types.h>
31 #include <sys/syscall.h>
32 #include <sys/resource.h>
37 #define RLIMIT_RTTIME 15
40 #ifndef SCHED_RESET_ON_FORK
41 #define SCHED_RESET_ON_FORK 0x40000000
44 #ifndef DEFAULT_INPUT_TIMEOUT
45 #define DEFAULT_INPUT_TIMEOUT 500
198 void setRealtimePriority();
204 QReadWriteLock m_mutex;
207 class MidiClient::MidiClientPrivate
210 MidiClientPrivate() :
211 m_eventsEnabled(false),
213 m_NeedRefreshClientList(true),
214 m_OpenMode(SND_SEQ_OPEN_DUPLEX),
215 m_DeviceName(
"default"),
222 bool m_eventsEnabled;
224 bool m_NeedRefreshClientList;
226 QString m_DeviceName;
227 snd_seq_t* m_SeqHandle;
228 QPointer<SequencerInputThread> m_Thread;
229 QPointer<MidiQueue> m_Queue;
237 QObjectList m_listeners;
259 d(new MidiClientPrivate)
275 if (d->m_Thread != 0)
287 return d->m_SeqHandle;
295 return (d->m_SeqHandle != NULL);
303 return d->m_DeviceName;
311 return d->m_OpenMode;
319 return d->m_BlockMode;
327 return d->m_eventsEnabled;
335 d->m_handler = handler;
349 if (d->m_Thread == 0) {
351 d->m_Thread->m_RealTime = enable;
362 if (d->m_Thread == 0)
364 return d->m_Thread->m_RealTime;
390 const bool blockMode)
392 CHECK_ERROR( snd_seq_open( &d->m_SeqHandle, deviceName.toLocal8Bit().data(),
393 openMode, blockMode ? 0 : SND_SEQ_NONBLOCK ) );
394 CHECK_WARNING( snd_seq_get_client_info( d->m_SeqHandle, d->m_Info.m_Info ) );
395 d->m_DeviceName = deviceName;
396 d->m_OpenMode = openMode;
397 d->m_BlockMode = blockMode;
422 const QString deviceName,
424 const bool blockMode )
427 deviceName.toLocal8Bit().data(),
429 blockMode ? 0 : SND_SEQ_NONBLOCK,
431 CHECK_WARNING( snd_seq_get_client_info(d->m_SeqHandle, d->m_Info.m_Info));
432 d->m_DeviceName = deviceName;
433 d->m_OpenMode = openMode;
434 d->m_BlockMode = blockMode;
447 if (d->m_SeqHandle != NULL) {
450 d->m_SeqHandle = NULL;
465 return snd_seq_get_output_buffer_size(d->m_SeqHandle);
480 CHECK_WARNING(snd_seq_set_output_buffer_size(d->m_SeqHandle, newSize));
495 return snd_seq_get_input_buffer_size(d->m_SeqHandle);
510 CHECK_WARNING(snd_seq_set_input_buffer_size(d->m_SeqHandle, newSize));
526 if (d->m_BlockMode != newValue)
528 d->m_BlockMode = newValue;
529 if (d->m_SeqHandle != NULL)
531 CHECK_WARNING(snd_seq_nonblock(d->m_SeqHandle, d->m_BlockMode ? 0 : 1));
557 return snd_seq_type(d->m_SeqHandle);
585 snd_seq_event_t* evp = NULL;
587 err = snd_seq_event_input(d->m_SeqHandle, &evp);
588 if ((err >= 0) && (evp != NULL)) {
591 case SND_SEQ_EVENT_NOTE:
595 case SND_SEQ_EVENT_NOTEON:
599 case SND_SEQ_EVENT_NOTEOFF:
603 case SND_SEQ_EVENT_KEYPRESS:
607 case SND_SEQ_EVENT_CONTROLLER:
608 case SND_SEQ_EVENT_CONTROL14:
609 case SND_SEQ_EVENT_REGPARAM:
610 case SND_SEQ_EVENT_NONREGPARAM:
614 case SND_SEQ_EVENT_PGMCHANGE:
618 case SND_SEQ_EVENT_CHANPRESS:
622 case SND_SEQ_EVENT_PITCHBEND:
626 case SND_SEQ_EVENT_SYSEX:
630 case SND_SEQ_EVENT_PORT_SUBSCRIBED:
631 case SND_SEQ_EVENT_PORT_UNSUBSCRIBED:
635 case SND_SEQ_EVENT_PORT_CHANGE:
636 case SND_SEQ_EVENT_PORT_EXIT:
637 case SND_SEQ_EVENT_PORT_START:
639 d->m_NeedRefreshClientList =
true;
642 case SND_SEQ_EVENT_CLIENT_CHANGE:
643 case SND_SEQ_EVENT_CLIENT_EXIT:
644 case SND_SEQ_EVENT_CLIENT_START:
646 d->m_NeedRefreshClientList =
true;
649 case SND_SEQ_EVENT_SONGPOS:
650 case SND_SEQ_EVENT_SONGSEL:
651 case SND_SEQ_EVENT_QFRAME:
652 case SND_SEQ_EVENT_TIMESIGN:
653 case SND_SEQ_EVENT_KEYSIGN:
657 case SND_SEQ_EVENT_SETPOS_TICK:
658 case SND_SEQ_EVENT_SETPOS_TIME:
659 case SND_SEQ_EVENT_QUEUE_SKEW:
663 case SND_SEQ_EVENT_TEMPO:
672 if (d->m_handler != NULL) {
673 d->m_handler->handleSequencerEvent(event->clone());
676 if (d->m_eventsEnabled) {
677 QObjectList::Iterator it;
678 for(it=d->m_listeners.begin(); it!=d->m_listeners.end(); ++it) {
680 QCoreApplication::postEvent(sub, event->clone());
690 while (snd_seq_event_input_pending(d->m_SeqHandle, 0) > 0);
699 if (d->m_Thread == 0) {
702 d->m_Thread->start( d->m_Thread->m_RealTime ?
703 QThread::TimeCriticalPriority : QThread::InheritPriority );
713 if (d->m_Thread != 0) {
714 if (d->m_Thread->isRunning()) {
716 while (!d->m_Thread->wait(500) && (counter < 10)) {
719 if (!d->m_Thread->isFinished()) {
720 d->m_Thread->terminate();
736 while (snd_seq_query_next_client(d->m_SeqHandle, cInfo.m_Info) >= 0) {
738 d->m_ClientList.append(cInfo);
740 d->m_NeedRefreshClientList =
false;
749 d->m_ClientList.clear();
759 if (d->m_NeedRefreshClientList)
772 snd_seq_get_client_info(d->m_SeqHandle, d->m_Info.m_Info);
787 snd_seq_set_client_info(d->m_SeqHandle, d->m_Info.m_Info);
796 if (d->m_SeqHandle != NULL) {
797 snd_seq_set_client_info(d->m_SeqHandle, d->m_Info.m_Info);
808 return d->m_Info.getName();
819 ClientInfoList::Iterator it;
820 if (d->m_NeedRefreshClientList)
822 for (it = d->m_ClientList.begin(); it != d->m_ClientList.end(); ++it) {
823 if ((*it).getClientId() == clientId) {
824 return (*it).getName();
837 if (newName != d->m_Info.getName()) {
838 d->m_Info.setName(newName);
872 if (d->m_SeqHandle != NULL) {
873 CHECK_ERROR(snd_seq_create_port(d->m_SeqHandle, port->m_Info.m_Info));
874 d->m_Ports.push_back(port);
885 if (d->m_SeqHandle != NULL) {
893 MidiPortList::iterator it;
894 for(it = d->m_Ports.begin(); it != d->m_Ports.end(); ++it)
898 d->m_Ports.erase(it);
910 if (d->m_SeqHandle != NULL) {
911 MidiPortList::iterator it;
912 for (it = d->m_Ports.begin(); it != d->m_Ports.end(); ++it) {
913 CHECK_ERROR(snd_seq_delete_port(d->m_SeqHandle, (*it)->getPortInfo()->getPort()));
914 (*it)->setMidiClient(NULL);
915 d->m_Ports.erase(it);
927 snd_seq_set_client_event_filter(d->m_SeqHandle, evtype);
938 return d->m_Info.getBroadcastFilter();
949 d->m_Info.setBroadcastFilter(newValue);
961 return d->m_Info.getErrorBounce();
972 d->m_Info.setErrorBounce(newValue);
995 npfds = snd_seq_poll_descriptors_count(d->m_SeqHandle, POLLOUT);
996 pfds = (pollfd*) alloca(npfds *
sizeof(pollfd));
997 snd_seq_poll_descriptors(d->m_SeqHandle, pfds, npfds, POLLOUT);
998 while (snd_seq_event_output(d->m_SeqHandle, ev->
getHandle()) < 0)
1000 poll(pfds, npfds, timeout);
1023 npfds = snd_seq_poll_descriptors_count(d->m_SeqHandle, POLLOUT);
1024 pfds = (pollfd*) alloca(npfds *
sizeof(pollfd));
1025 snd_seq_poll_descriptors(d->m_SeqHandle, pfds, npfds, POLLOUT);
1026 while (snd_seq_event_output_direct(d->m_SeqHandle, ev->
getHandle()) < 0)
1028 poll(pfds, npfds, timeout);
1065 npfds = snd_seq_poll_descriptors_count(d->m_SeqHandle, POLLOUT);
1066 pfds = (pollfd*) alloca(npfds *
sizeof(pollfd));
1067 snd_seq_poll_descriptors(d->m_SeqHandle, pfds, npfds, POLLOUT);
1068 while (snd_seq_drain_output(d->m_SeqHandle) < 0)
1070 poll(pfds, npfds, timeout);
1083 snd_seq_sync_output_queue(d->m_SeqHandle);
1094 if (d->m_Queue == NULL) {
1107 if (d->m_Queue != NULL) {
1123 if (d->m_Queue != NULL) {
1126 d->m_Queue =
new MidiQueue(
this, queueName,
this);
1140 if (d->m_Queue != NULL) {
1143 d->m_Queue =
new MidiQueue(
this, queue_id,
this);
1157 if (d->m_Queue != NULL) {
1161 if ( queue_id >= 0) {
1162 d->m_Queue =
new MidiQueue(
this, queue_id,
this);
1176 if (d->m_Queue != NULL) {
1179 queue->setParent(
this);
1193 snd_seq_queue_info_t* qinfo;
1194 snd_seq_queue_info_alloca(&qinfo);
1196 for ( q = 0; q < max; ++q ) {
1197 err = snd_seq_get_queue_info(d->m_SeqHandle, q, qinfo);
1216 ClientInfoList::ConstIterator itc;
1217 PortInfoList::ConstIterator itp;
1219 if (d->m_NeedRefreshClientList)
1222 for (itc = d->m_ClientList.constBegin(); itc != d->m_ClientList.constEnd(); ++itc) {
1224 if ((ci.
getClientId() == SND_SEQ_CLIENT_SYSTEM) ||
1228 for(itp = lstPorts.constBegin(); itp != lstPorts.constEnd(); ++itp) {
1231 if ( ((filter & cap) != 0) &&
1232 ((SND_SEQ_PORT_CAP_NO_EXPORT & cap) == 0) ) {
1246 d->m_InputsAvail.clear();
1247 d->m_OutputsAvail.clear();
1248 d->m_InputsAvail =
filterPorts( SND_SEQ_PORT_CAP_READ |
1249 SND_SEQ_PORT_CAP_SUBS_READ );
1250 d->m_OutputsAvail =
filterPorts( SND_SEQ_PORT_CAP_WRITE |
1251 SND_SEQ_PORT_CAP_SUBS_WRITE );
1261 d->m_NeedRefreshClientList =
true;
1263 return d->m_InputsAvail;
1273 d->m_NeedRefreshClientList =
true;
1275 return d->m_OutputsAvail;
1287 d->m_listeners.append(listener);
1298 d->m_listeners.removeAll(listener);
1310 if (bEnabled != d->m_eventsEnabled) {
1311 d->m_eventsEnabled = bEnabled;
1322 snd_seq_system_info(d->m_SeqHandle, d->m_sysInfo.m_Info);
1323 return d->m_sysInfo;
1333 snd_seq_get_client_pool(d->m_SeqHandle, d->m_poolInfo.m_Info);
1334 return d->m_poolInfo;
1344 d->m_poolInfo = info;
1345 CHECK_WARNING(snd_seq_set_client_pool(d->m_SeqHandle, d->m_poolInfo.m_Info));
1375 CHECK_WARNING(snd_seq_set_client_pool_input(d->m_SeqHandle, size));
1385 CHECK_WARNING(snd_seq_set_client_pool_output(d->m_SeqHandle, size));
1395 CHECK_WARNING(snd_seq_set_client_pool_output_room(d->m_SeqHandle, size));
1453 CHECK_WARNING(snd_seq_remove_events(d->m_SeqHandle, spec->m_Info));
1463 snd_seq_event_t* ev;
1464 if (
CHECK_WARNING(snd_seq_extract_output(d->m_SeqHandle, &ev) == 0)) {
1478 return snd_seq_event_output_pending(d->m_SeqHandle);
1497 return snd_seq_event_input_pending(d->m_SeqHandle, fetch ? 1 : 0);
1509 return snd_seq_query_named_queue(d->m_SeqHandle, name.toLocal8Bit().data());
1520 return snd_seq_poll_descriptors_count(d->m_SeqHandle, events);
1540 return snd_seq_poll_descriptors(d->m_SeqHandle, pfds, space, events);
1552 unsigned short revents;
1553 CHECK_WARNING( snd_seq_poll_descriptors_revents( d->m_SeqHandle,
1566 return snd_seq_name(d->m_SeqHandle);
1576 CHECK_WARNING(snd_seq_set_client_name(d->m_SeqHandle, name));
1591 return CHECK_WARNING( snd_seq_create_simple_port( d->m_SeqHandle,
1592 name, caps, type ));
1602 CHECK_WARNING( snd_seq_delete_simple_port( d->m_SeqHandle, port ));
1614 CHECK_WARNING( snd_seq_connect_from(d->m_SeqHandle, myport, client, port ));
1626 CHECK_WARNING( snd_seq_connect_to(d->m_SeqHandle, myport, client, port ));
1638 CHECK_WARNING( snd_seq_disconnect_from(d->m_SeqHandle, myport, client, port ));
1650 CHECK_WARNING( snd_seq_disconnect_to(d->m_SeqHandle, myport, client, port ));
1668 QString testClient, testPort;
1669 ClientInfoList::ConstIterator cit;
1670 int pos = straddr.indexOf(
':');
1672 testClient = straddr.left(pos);
1673 testPort = straddr.mid(pos+1);
1675 testClient = straddr;
1678 addr.client = testClient.toInt(&ok);
1680 addr.port = testPort.toInt(&ok);
1682 if (d->m_NeedRefreshClientList)
1684 for ( cit = d->m_ClientList.constBegin();
1685 cit != d->m_ClientList.constEnd(); ++cit ) {
1687 if (testClient.compare(ci.
getName(), Qt::CaseInsensitive) == 0) {
1689 addr.port = testPort.toInt(&ok);
1704 QReadLocker locker(&m_mutex);
1714 QWriteLocker locker(&m_mutex);
1718 #if defined(RTKIT_SUPPORT)
1719 static pid_t _gettid(
void) {
1720 return (pid_t) ::syscall(SYS_gettid);
1725 MidiClient::SequencerInputThread::setRealtimePriority()
1727 struct sched_param p;
1728 int rt, policy = SCHED_RR | SCHED_RESET_ON_FORK;
1729 quint32 priority = 6;
1730 #if defined(RTKIT_SUPPORT)
1734 struct rlimit old_limit, new_limit;
1735 long long max_rttime;
1738 ::memset(&p, 0,
sizeof(p));
1739 p.sched_priority = priority;
1740 rt = ::pthread_setschedparam(::pthread_self(), policy, &p);
1742 #if defined(RTKIT_SUPPORT)
1743 const QString rtkit_service =
1744 QLatin1String(
"org.freedesktop.RealtimeKit1");
1745 const QString rtkit_path =
1746 QLatin1String(
"/org/freedesktop/RealtimeKit1");
1747 const QString rtkit_iface = rtkit_service;
1749 QDBusConnection bus = QDBusConnection::systemBus();
1750 QDBusInterface realtimeKit(rtkit_service, rtkit_path, rtkit_iface, bus);
1751 QVariant maxRTPrio = realtimeKit.property(
"MaxRealtimePriority");
1752 max_prio = maxRTPrio.toUInt(&ok);
1754 qWarning() <<
"invalid property RealtimeKit.MaxRealtimePriority";
1757 if (priority > max_prio)
1758 priority = max_prio;
1759 QVariant maxRTNSec = realtimeKit.property(
"RTTimeNSecMax");
1760 max_rttime = maxRTNSec.toLongLong(&ok);
1761 if (!ok || max_rttime < 0) {
1762 qWarning() <<
"invalid property RealtimeKit.RTTimeNSecMax";
1765 new_limit.rlim_cur = new_limit.rlim_max = max_rttime;
1766 rt = ::getrlimit(RLIMIT_RTTIME, &old_limit);
1768 qWarning() <<
"getrlimit() failed. err=" << rt << ::strerror(rt);
1771 rt = ::setrlimit(RLIMIT_RTTIME, &new_limit);
1773 qWarning() <<
"setrlimit() failed, err=" << rt << ::strerror(rt);
1776 QDBusMessage reply = realtimeKit.call(
"MakeThreadRealtime", thread, priority);
1777 if (reply.type() == QDBusMessage::ErrorMessage )
1778 qWarning() <<
"error returned by RealtimeKit.MakeThreadRealtime:"
1779 << reply.errorMessage();
1782 qWarning() <<
"pthread_setschedparam() failed, err="
1783 << rt << ::strerror(rt);
1795 if ( priority() == TimeCriticalPriority )
1796 setRealtimePriority();
1798 if (m_MidiClient != NULL) {
1799 npfd = snd_seq_poll_descriptors_count(m_MidiClient->getHandle(), POLLIN);
1800 pfd = (pollfd *) alloca(npfd *
sizeof(pollfd));
1803 snd_seq_poll_descriptors(m_MidiClient->getHandle(), pfd, npfd, POLLIN);
1804 while (!stopped() && (m_MidiClient != NULL))
1806 int rt = poll(pfd, npfd, m_Wait);
1808 m_MidiClient->doEvents();
1814 qWarning() <<
"exception in input thread";
1824 snd_seq_client_info_malloc(&m_Info);
1833 snd_seq_client_info_malloc(&m_Info);
1834 snd_seq_client_info_copy(m_Info, other.m_Info);
1835 m_Ports = other.m_Ports;
1844 snd_seq_client_info_malloc(&m_Info);
1845 snd_seq_client_info_copy(m_Info, other);
1855 snd_seq_client_info_malloc(&m_Info);
1856 snd_seq_get_any_client_info(seq->
getHandle(),
id, m_Info);
1865 snd_seq_client_info_free(m_Info);
1886 snd_seq_client_info_copy(m_Info, other.m_Info);
1887 m_Ports = other.m_Ports;
1898 return snd_seq_client_info_get_client(m_Info);
1905 snd_seq_client_type_t
1908 return snd_seq_client_info_get_type(m_Info);
1918 return QString(snd_seq_client_info_get_name(m_Info));
1928 return (snd_seq_client_info_get_broadcast_filter(m_Info) != 0);
1938 return (snd_seq_client_info_get_error_bounce(m_Info) != 0);
1946 const unsigned char*
1949 return snd_seq_client_info_get_event_filter(m_Info);
1959 return snd_seq_client_info_get_num_ports(m_Info);
1969 return snd_seq_client_info_get_event_lost(m_Info);
1979 snd_seq_client_info_set_client(m_Info, client);
1989 snd_seq_client_info_set_name(m_Info, name.toLocal8Bit().data());
1999 snd_seq_client_info_set_broadcast_filter(m_Info, val ? 1 : 0);
2009 snd_seq_client_info_set_error_bounce(m_Info, val ? 1 : 0);
2020 snd_seq_client_info_set_event_filter(m_Info, filter);
2035 while (snd_seq_query_next_port(seq->
getHandle(), info.m_Info) >= 0) {
2037 m_Ports.append(info);
2068 return snd_seq_client_info_sizeof();
2071 #if SND_LIB_VERSION > 0x010010
2078 ClientInfo::addFilter(
int eventType)
2080 snd_seq_client_info_event_filter_add(m_Info, eventType);
2089 ClientInfo::isFiltered(
int eventType)
2091 return (snd_seq_client_info_event_filter_check(m_Info, eventType) != 0);
2098 ClientInfo::clearFilter()
2100 snd_seq_client_info_event_filter_clear(m_Info);
2108 ClientInfo::removeFilter(
int eventType)
2110 snd_seq_client_info_event_filter_del(m_Info, eventType);
2119 snd_seq_system_info_malloc(&m_Info);
2128 snd_seq_system_info_malloc(&m_Info);
2129 snd_seq_system_info_copy(m_Info, other.m_Info);
2138 snd_seq_system_info_malloc(&m_Info);
2139 snd_seq_system_info_copy(m_Info, other);
2148 snd_seq_system_info_malloc(&m_Info);
2149 snd_seq_system_info(seq->
getHandle(), m_Info);
2157 snd_seq_system_info_free(m_Info);
2178 snd_seq_system_info_copy(m_Info, other.m_Info);
2188 return snd_seq_system_info_get_clients(m_Info);
2197 return snd_seq_system_info_get_ports(m_Info);
2206 return snd_seq_system_info_get_queues(m_Info);
2215 return snd_seq_system_info_get_channels(m_Info);
2224 return snd_seq_system_info_get_cur_queues(m_Info);
2233 return snd_seq_system_info_get_cur_clients(m_Info);
2242 return snd_seq_system_info_sizeof();
2250 snd_seq_client_pool_malloc(&m_Info);
2259 snd_seq_client_pool_malloc(&m_Info);
2260 snd_seq_client_pool_copy(m_Info, other.m_Info);
2269 snd_seq_client_pool_malloc(&m_Info);
2270 snd_seq_client_pool_copy(m_Info, other);
2279 snd_seq_client_pool_malloc(&m_Info);
2280 snd_seq_get_client_pool(seq->
getHandle(), m_Info);
2288 snd_seq_client_pool_free(m_Info);
2308 snd_seq_client_pool_copy(m_Info, other.m_Info);
2319 return snd_seq_client_pool_get_client(m_Info);
2329 return snd_seq_client_pool_get_input_free(m_Info);
2339 return snd_seq_client_pool_get_input_pool(m_Info);
2349 return snd_seq_client_pool_get_output_free(m_Info);
2359 return snd_seq_client_pool_get_output_pool(m_Info);
2370 return snd_seq_client_pool_get_output_room(m_Info);
2380 snd_seq_client_pool_set_input_pool(m_Info, size);
2390 snd_seq_client_pool_set_output_pool(m_Info, size);
2402 snd_seq_client_pool_set_output_room(m_Info, size);
2412 return snd_seq_client_pool_sizeof();
2415 #if SND_LIB_VERSION > 0x010004
2422 getRuntimeALSALibraryVersion()
2424 return QString(snd_asoundlib_version());
2433 getRuntimeALSALibraryNumber()
2435 QRegExp rx(
"(\\d+)");
2436 QString str = getRuntimeALSALibraryVersion();
2438 int pos = 0, result = 0, j = 0;
2439 while ((pos = rx.indexIn(str, pos)) != -1 && j < 3) {
2440 int v = rx.cap(1).toInt(&ok);
2445 pos += rx.matchedLength();
2450 #endif // SND_LIB_VERSION > 0x010004
2460 QRegExp rx(
".*Driver Version.*([\\d\\.]+).*");
2462 QFile f(
"/proc/asound/version");
2463 if (f.open(QFile::ReadOnly)) {
2464 QTextStream str(&f);
2465 if (rx.exactMatch(str.readLine().trimmed()))
2479 QRegExp rx(
"(\\d+)");
2482 int pos = 0, result = 0, j = 0;
2483 while ((pos = rx.indexIn(str, pos)) != -1 && j < 3) {
2484 int v = rx.cap(1).toInt(&ok);
2489 pos += rx.matchedLength();