drumstick  1.0.2
alsaclient.cpp
Go to the documentation of this file.
00001 /*
00002     MIDI Sequencer C++ library
00003     Copyright (C) 2006-2015, Pedro Lopez-Cabanillas <plcl@users.sf.net>
00004 
00005     This library is free software; you can redistribute it and/or modify
00006     it under the terms of the GNU General Public License as published by
00007     the Free Software Foundation; either version 2 of the License, or
00008     (at your option) any later version.
00009 
00010     This library is distributed in the hope that it will be useful,
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013     GNU General Public License for more details.
00014 
00015     You should have received a copy of the GNU General Public License along
00016     with this program; if not, write to the Free Software Foundation, Inc.,
00017     51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00018 */
00019 
00020 #include "alsaclient.h"
00021 #include "alsaqueue.h"
00022 #include "alsaevent.h"
00023 #include <QFile>
00024 #include <QRegExp>
00025 #include <QThread>
00026 #include <QReadLocker>
00027 #include <QWriteLocker>
00028 #if defined(RTKIT_SUPPORT)
00029 #include <QDBusConnection>
00030 #include <QDBusInterface>
00031 #include <sys/types.h>
00032 #include <sys/syscall.h>
00033 #include <sys/resource.h>
00034 #endif
00035 #include <pthread.h>
00036 
00037 #ifndef RLIMIT_RTTIME
00038 #define RLIMIT_RTTIME 15
00039 #endif
00040 
00041 #ifndef SCHED_RESET_ON_FORK
00042 #define SCHED_RESET_ON_FORK 0x40000000
00043 #endif
00044 
00045 #ifndef DEFAULT_INPUT_TIMEOUT
00046 #define DEFAULT_INPUT_TIMEOUT 500
00047 #endif
00048 
00066 namespace drumstick {
00067 
00329 class MidiClient::SequencerInputThread: public QThread
00330 {
00331 public:
00332     SequencerInputThread(MidiClient *seq, int timeout)
00333         : QThread(),
00334         m_MidiClient(seq),
00335         m_Wait(timeout),
00336         m_Stopped(false),
00337         m_RealTime(true) {}
00338     virtual ~SequencerInputThread() {}
00339     virtual void run();
00340     bool stopped();
00341     void stop();
00342     void setRealtimePriority();
00343 
00344     MidiClient *m_MidiClient;
00345     int m_Wait;
00346     bool m_Stopped;
00347     bool m_RealTime;
00348     QReadWriteLock m_mutex;
00349 };
00350 
00351 class MidiClient::MidiClientPrivate
00352 {
00353 public:
00354     MidiClientPrivate() :
00355         m_eventsEnabled(false),
00356         m_BlockMode(false),
00357         m_NeedRefreshClientList(true),
00358         m_OpenMode(SND_SEQ_OPEN_DUPLEX),
00359         m_DeviceName("default"),
00360         m_SeqHandle(0),
00361         m_Thread(0),
00362         m_Queue(0),
00363         m_handler(0)
00364     { }
00365 
00366     bool m_eventsEnabled;
00367     bool m_BlockMode;
00368     bool m_NeedRefreshClientList;
00369     int  m_OpenMode;
00370     QString m_DeviceName;
00371     snd_seq_t* m_SeqHandle;
00372     QPointer<SequencerInputThread> m_Thread;
00373     QPointer<MidiQueue> m_Queue;
00374     SequencerEventHandler* m_handler;
00375 
00376     ClientInfo m_Info;
00377     ClientInfoList m_ClientList;
00378     MidiPortList m_Ports;
00379     PortInfoList m_OutputsAvail;
00380     PortInfoList m_InputsAvail;
00381     QObjectList m_listeners;
00382     SystemInfo m_sysInfo;
00383     PoolInfo m_poolInfo;
00384 };
00385 
00401 MidiClient::MidiClient( QObject* parent ) :
00402     QObject(parent),
00403     d(new MidiClientPrivate)
00404 { }
00405 
00411 MidiClient::~MidiClient()
00412 {
00413     stopSequencerInput();
00414     detachAllPorts();
00415     if (d->m_Queue != 0)
00416         delete d->m_Queue;
00417     close();
00418     freeClients();
00419     if (d->m_Thread != 0)
00420         delete d->m_Thread;
00421     delete d;
00422 }
00423 
00424 
00428 snd_seq_t*
00429 MidiClient::getHandle()
00430 {
00431     return d->m_SeqHandle;
00432 }
00433 
00437 bool MidiClient::isOpened()
00438 {
00439     return (d->m_SeqHandle != NULL);
00440 }
00441 
00445 QString MidiClient::getDeviceName()
00446 {
00447     return d->m_DeviceName;
00448 }
00449 
00453 int MidiClient::getOpenMode()
00454 {
00455     return d->m_OpenMode;
00456 }
00457 
00461 bool MidiClient::getBlockMode()
00462 {
00463     return d->m_BlockMode;
00464 }
00465 
00469 bool MidiClient::getEventsEnabled() const
00470 {
00471     return d->m_eventsEnabled;
00472 }
00473 
00477 void MidiClient::setHandler(SequencerEventHandler* handler)
00478 {
00479     d->m_handler = handler;
00480 }
00481 
00482 
00491 void MidiClient::setRealTimeInput(bool enable)
00492 {
00493     if (d->m_Thread == 0) {
00494         d->m_Thread = new SequencerInputThread(this, DEFAULT_INPUT_TIMEOUT);
00495         d->m_Thread->m_RealTime = enable;
00496     }
00497 }
00498 
00504 bool MidiClient::realTimeInputEnabled()
00505 {
00506     if (d->m_Thread == 0)
00507         return true;
00508     return d->m_Thread->m_RealTime;
00509 }
00510 
00531 void
00532 MidiClient::open( const QString deviceName,
00533                   const int openMode,
00534                   const bool blockMode)
00535 {
00536     CHECK_ERROR( snd_seq_open( &d->m_SeqHandle, deviceName.toLocal8Bit().data(),
00537                               openMode, blockMode ? 0 : SND_SEQ_NONBLOCK ) );
00538     CHECK_WARNING( snd_seq_get_client_info( d->m_SeqHandle, d->m_Info.m_Info ) );
00539     d->m_DeviceName = deviceName;
00540     d->m_OpenMode = openMode;
00541     d->m_BlockMode = blockMode;
00542 }
00543 
00564 void
00565 MidiClient::open( snd_config_t* conf,
00566                   const QString deviceName,
00567                   const int openMode,
00568                   const bool blockMode )
00569 {
00570     CHECK_ERROR( snd_seq_open_lconf( &d->m_SeqHandle,
00571                                      deviceName.toLocal8Bit().data(),
00572                                      openMode,
00573                                      blockMode ? 0 : SND_SEQ_NONBLOCK,
00574                                      conf ));
00575     CHECK_WARNING( snd_seq_get_client_info(d->m_SeqHandle, d->m_Info.m_Info));
00576     d->m_DeviceName = deviceName;
00577     d->m_OpenMode = openMode;
00578     d->m_BlockMode = blockMode;
00579 }
00580 
00588 void
00589 MidiClient::close()
00590 {
00591     if (d->m_SeqHandle != NULL) {
00592         stopSequencerInput();
00593         CHECK_WARNING(snd_seq_close(d->m_SeqHandle));
00594         d->m_SeqHandle = NULL;
00595     }
00596 }
00597 
00606 size_t
00607 MidiClient::getOutputBufferSize()
00608 {
00609     return snd_seq_get_output_buffer_size(d->m_SeqHandle);
00610 }
00611 
00620 void
00621 MidiClient::setOutputBufferSize(size_t newSize)
00622 {
00623     if (getOutputBufferSize() != newSize) {
00624         CHECK_WARNING(snd_seq_set_output_buffer_size(d->m_SeqHandle, newSize));
00625     }
00626 }
00627 
00636 size_t
00637 MidiClient::getInputBufferSize()
00638 {
00639     return snd_seq_get_input_buffer_size(d->m_SeqHandle);
00640 }
00641 
00650 void
00651 MidiClient::setInputBufferSize(size_t newSize)
00652 {
00653     if (getInputBufferSize() != newSize) {
00654         CHECK_WARNING(snd_seq_set_input_buffer_size(d->m_SeqHandle, newSize));
00655     }
00656 }
00657 
00667 void
00668 MidiClient::setBlockMode(bool newValue)
00669 {
00670     if (d->m_BlockMode != newValue)
00671     {
00672         d->m_BlockMode = newValue;
00673         if (d->m_SeqHandle != NULL)
00674         {
00675             CHECK_WARNING(snd_seq_nonblock(d->m_SeqHandle, d->m_BlockMode ? 0 : 1));
00676         }
00677     }
00678 }
00679 
00688 int
00689 MidiClient::getClientId()
00690 {
00691     return CHECK_WARNING(snd_seq_client_id(d->m_SeqHandle));
00692 }
00693 
00698 snd_seq_type_t
00699 MidiClient::getSequencerType()
00700 {
00701     return snd_seq_type(d->m_SeqHandle);
00702 }
00703 
00724 void
00725 MidiClient::doEvents()
00726 {
00727     do {
00728         int err = 0;
00729         snd_seq_event_t* evp = NULL;
00730         SequencerEvent* event = NULL;
00731         err = snd_seq_event_input(d->m_SeqHandle, &evp);
00732         if ((err >= 0) && (evp != NULL)) {
00733             switch (evp->type) {
00734 
00735             case SND_SEQ_EVENT_NOTE:
00736                 event = new NoteEvent(evp);
00737                 break;
00738 
00739             case SND_SEQ_EVENT_NOTEON:
00740                 event = new NoteOnEvent(evp);
00741                 break;
00742 
00743             case SND_SEQ_EVENT_NOTEOFF:
00744                 event = new NoteOffEvent(evp);
00745                 break;
00746 
00747             case SND_SEQ_EVENT_KEYPRESS:
00748                 event = new KeyPressEvent(evp);
00749                 break;
00750 
00751             case SND_SEQ_EVENT_CONTROLLER:
00752             case SND_SEQ_EVENT_CONTROL14:
00753             case SND_SEQ_EVENT_REGPARAM:
00754             case SND_SEQ_EVENT_NONREGPARAM:
00755                 event = new ControllerEvent(evp);
00756                 break;
00757 
00758             case SND_SEQ_EVENT_PGMCHANGE:
00759                 event = new ProgramChangeEvent(evp);
00760                 break;
00761 
00762             case SND_SEQ_EVENT_CHANPRESS:
00763                 event = new ChanPressEvent(evp);
00764                 break;
00765 
00766             case SND_SEQ_EVENT_PITCHBEND:
00767                 event = new PitchBendEvent(evp);
00768                 break;
00769 
00770             case SND_SEQ_EVENT_SYSEX:
00771                 event = new SysExEvent(evp);
00772                 break;
00773 
00774             case SND_SEQ_EVENT_PORT_SUBSCRIBED:
00775             case SND_SEQ_EVENT_PORT_UNSUBSCRIBED:
00776                 event = new SubscriptionEvent(evp);
00777                 break;
00778 
00779             case SND_SEQ_EVENT_PORT_CHANGE:
00780             case SND_SEQ_EVENT_PORT_EXIT:
00781             case SND_SEQ_EVENT_PORT_START:
00782                 event = new PortEvent(evp);
00783                 d->m_NeedRefreshClientList = true;
00784                 break;
00785 
00786             case SND_SEQ_EVENT_CLIENT_CHANGE:
00787             case SND_SEQ_EVENT_CLIENT_EXIT:
00788             case SND_SEQ_EVENT_CLIENT_START:
00789                 event = new ClientEvent(evp);
00790                 d->m_NeedRefreshClientList = true;
00791                 break;
00792 
00793             case SND_SEQ_EVENT_SONGPOS:
00794             case SND_SEQ_EVENT_SONGSEL:
00795             case SND_SEQ_EVENT_QFRAME:
00796             case SND_SEQ_EVENT_TIMESIGN:
00797             case SND_SEQ_EVENT_KEYSIGN:
00798                 event = new ValueEvent(evp);
00799                 break;
00800 
00801             case SND_SEQ_EVENT_SETPOS_TICK:
00802             case SND_SEQ_EVENT_SETPOS_TIME:
00803             case SND_SEQ_EVENT_QUEUE_SKEW:
00804                 event = new QueueControlEvent(evp);
00805                 break;
00806 
00807             case SND_SEQ_EVENT_TEMPO:
00808                 event = new TempoEvent(evp);
00809                 break;
00810 
00811             default:
00812                 event = new SequencerEvent(evp);
00813                 break;
00814             }
00815             // first, process the callback (if any)
00816             if (d->m_handler != NULL) {
00817                 d->m_handler->handleSequencerEvent(event->clone());
00818             } else {
00819                 // second, process the event listeners
00820                 if (d->m_eventsEnabled) {
00821                    QObjectList::Iterator it;
00822                     for(it=d->m_listeners.begin(); it!=d->m_listeners.end(); ++it) {
00823                         QObject* sub = (*it);
00824                         QCoreApplication::postEvent(sub, event->clone());
00825                     }
00826                 } else {
00827                     // finally, process signals
00828                     emit eventReceived(event->clone());
00829                 }
00830             }
00831             delete event;
00832         }
00833     }
00834     while (snd_seq_event_input_pending(d->m_SeqHandle, 0) > 0);
00835 }
00836 
00840 void
00841 MidiClient::startSequencerInput()
00842 {
00843     if (d->m_Thread == 0) {
00844         d->m_Thread = new SequencerInputThread(this, DEFAULT_INPUT_TIMEOUT);
00845     }
00846     d->m_Thread->start( d->m_Thread->m_RealTime ?
00847             QThread::TimeCriticalPriority : QThread::InheritPriority );
00848 }
00849 
00853 void
00854 MidiClient::stopSequencerInput()
00855 {
00856     int counter = 0;
00857     if (d->m_Thread != 0) {
00858         if (d->m_Thread->isRunning()) {
00859             d->m_Thread->stop();
00860             while (!d->m_Thread->wait(500) && (counter < 10)) {
00861                 counter++;
00862             }
00863             if (!d->m_Thread->isFinished()) {
00864                 d->m_Thread->terminate();
00865             }
00866         }
00867         delete d->m_Thread;
00868     }
00869 }
00870 
00874 void
00875 MidiClient::readClients()
00876 {
00877     ClientInfo cInfo;
00878     freeClients();
00879     cInfo.setClient(-1);
00880     while (snd_seq_query_next_client(d->m_SeqHandle, cInfo.m_Info) >= 0) {
00881         cInfo.readPorts(this);
00882         d->m_ClientList.append(cInfo);
00883     }
00884     d->m_NeedRefreshClientList = false;
00885 }
00886 
00890 void
00891 MidiClient::freeClients()
00892 {
00893     d->m_ClientList.clear();
00894 }
00895 
00900 ClientInfoList
00901 MidiClient::getAvailableClients()
00902 {
00903     if (d->m_NeedRefreshClientList)
00904         readClients();
00905     ClientInfoList lst = d->m_ClientList; // copy
00906     return lst;
00907 }
00908 
00913 ClientInfo&
00914 MidiClient::getThisClientInfo()
00915 {
00916     snd_seq_get_client_info(d->m_SeqHandle, d->m_Info.m_Info);
00917     return d->m_Info;
00918 }
00919 
00927 void
00928 MidiClient::setThisClientInfo(const ClientInfo& val)
00929 {
00930     d->m_Info = val;
00931     snd_seq_set_client_info(d->m_SeqHandle, d->m_Info.m_Info);
00932 }
00933 
00937 void
00938 MidiClient::applyClientInfo()
00939 {
00940     if (d->m_SeqHandle != NULL) {
00941         snd_seq_set_client_info(d->m_SeqHandle, d->m_Info.m_Info);
00942     }
00943 }
00944 
00949 QString
00950 MidiClient::getClientName()
00951 {
00952     return d->m_Info.getName();
00953 }
00954 
00960 QString
00961 MidiClient::getClientName(const int clientId)
00962 {
00963     ClientInfoList::Iterator it;
00964     if (d->m_NeedRefreshClientList)
00965         readClients();
00966     for (it = d->m_ClientList.begin(); it != d->m_ClientList.end(); ++it) {
00967         if ((*it).getClientId() == clientId) {
00968             return (*it).getName();
00969         }
00970     }
00971     return QString();
00972 }
00973 
00978 void
00979 MidiClient::setClientName(QString const& newName)
00980 {
00981     if (newName != d->m_Info.getName()) {
00982         d->m_Info.setName(newName);
00983         applyClientInfo();
00984     }
00985 }
00986 
00991 MidiPortList
00992 MidiClient::getMidiPorts() const
00993 {
00994     return d->m_Ports;
00995 }
00996 
01001 MidiPort*
01002 MidiClient::createPort()
01003 {
01004     MidiPort* port = new MidiPort(this);
01005     port->attach(this);
01006     return port;
01007 }
01008 
01013 void
01014 MidiClient::portAttach(MidiPort* port)
01015 {
01016     if (d->m_SeqHandle != NULL) {
01017         CHECK_ERROR(snd_seq_create_port(d->m_SeqHandle, port->m_Info.m_Info));
01018         d->m_Ports.push_back(port);
01019     }
01020 }
01021 
01026 void
01027 MidiClient::portDetach(MidiPort* port)
01028 {
01029     if (d->m_SeqHandle != NULL) {
01030         if(port->getPortInfo()->getClient() == getClientId())
01031         {
01032             return;
01033         }
01034         CHECK_ERROR(snd_seq_delete_port(d->m_SeqHandle, port->getPortInfo()->getPort()));
01035         port->setMidiClient(NULL);
01036 
01037         MidiPortList::iterator it;
01038         for(it = d->m_Ports.begin(); it != d->m_Ports.end(); ++it)
01039         {
01040             if ((*it)->getPortInfo()->getPort() == port->getPortInfo()->getPort())
01041             {
01042                 d->m_Ports.erase(it);
01043                 break;
01044             }
01045         }
01046     }
01047 }
01048 
01052 void MidiClient::detachAllPorts()
01053 {
01054     if (d->m_SeqHandle != NULL) {
01055         MidiPortList::iterator it;
01056         for (it = d->m_Ports.begin(); it != d->m_Ports.end(); ++it) {
01057             CHECK_ERROR(snd_seq_delete_port(d->m_SeqHandle, (*it)->getPortInfo()->getPort()));
01058             (*it)->setMidiClient(NULL);
01059             d->m_Ports.erase(it);
01060         }
01061     }
01062 }
01063 
01068 void
01069 MidiClient::addEventFilter(int evtype)
01070 {
01071     snd_seq_set_client_event_filter(d->m_SeqHandle, evtype);
01072 }
01073 
01079 bool
01080 MidiClient::getBroadcastFilter()
01081 {
01082     return d->m_Info.getBroadcastFilter();
01083 }
01084 
01090 void
01091 MidiClient::setBroadcastFilter(bool newValue)
01092 {
01093     d->m_Info.setBroadcastFilter(newValue);
01094     applyClientInfo();
01095 }
01096 
01102 bool
01103 MidiClient::getErrorBounce()
01104 {
01105     return d->m_Info.getErrorBounce();
01106 }
01107 
01113 void
01114 MidiClient::setErrorBounce(bool newValue)
01115 {
01116     d->m_Info.setErrorBounce(newValue);
01117     applyClientInfo();
01118 }
01119 
01131 void
01132 MidiClient::output(SequencerEvent* ev, bool async, int timeout)
01133 {
01134     int npfds;
01135     pollfd* pfds;
01136     if (async) {
01137         CHECK_WARNING(snd_seq_event_output(d->m_SeqHandle, ev->getHandle()));
01138     } else {
01139         npfds = snd_seq_poll_descriptors_count(d->m_SeqHandle, POLLOUT);
01140         pfds = (pollfd*) alloca(npfds * sizeof(pollfd));
01141         snd_seq_poll_descriptors(d->m_SeqHandle, pfds, npfds, POLLOUT);
01142         while (snd_seq_event_output(d->m_SeqHandle, ev->getHandle()) < 0)
01143         {
01144             poll(pfds, npfds, timeout);
01145         }
01146     }
01147 }
01148 
01160 void MidiClient::outputDirect(SequencerEvent* ev, bool async, int timeout)
01161 {
01162     int npfds;
01163     pollfd* pfds;
01164     if (async) {
01165         CHECK_WARNING(snd_seq_event_output_direct(d->m_SeqHandle, ev->getHandle()));
01166     } else {
01167         npfds = snd_seq_poll_descriptors_count(d->m_SeqHandle, POLLOUT);
01168         pfds = (pollfd*) alloca(npfds * sizeof(pollfd));
01169         snd_seq_poll_descriptors(d->m_SeqHandle, pfds, npfds, POLLOUT);
01170         while (snd_seq_event_output_direct(d->m_SeqHandle, ev->getHandle()) < 0)
01171         {
01172             poll(pfds, npfds, timeout);
01173         }
01174     }
01175 }
01176 
01185 void
01186 MidiClient::outputBuffer(SequencerEvent* ev)
01187 {
01188     CHECK_WARNING(snd_seq_event_output_buffer(d->m_SeqHandle, ev->getHandle()));
01189 }
01190 
01202 void MidiClient::drainOutput(bool async, int timeout)
01203 {
01204     int npfds;
01205     pollfd* pfds;
01206     if (async) {
01207         CHECK_WARNING(snd_seq_drain_output(d->m_SeqHandle));
01208     } else {
01209         npfds = snd_seq_poll_descriptors_count(d->m_SeqHandle, POLLOUT);
01210         pfds = (pollfd*) alloca(npfds * sizeof(pollfd));
01211         snd_seq_poll_descriptors(d->m_SeqHandle, pfds, npfds, POLLOUT);
01212         while (snd_seq_drain_output(d->m_SeqHandle) < 0)
01213         {
01214             poll(pfds, npfds, timeout);
01215         }
01216     }
01217 }
01218 
01224 void
01225 MidiClient::synchronizeOutput()
01226 {
01227     snd_seq_sync_output_queue(d->m_SeqHandle);
01228 }
01229 
01235 MidiQueue*
01236 MidiClient::getQueue()
01237 {
01238     if (d->m_Queue == NULL) {
01239         createQueue();
01240     }
01241     return d->m_Queue;
01242 }
01243 
01248 MidiQueue*
01249 MidiClient::createQueue()
01250 {
01251     if (d->m_Queue != NULL) {
01252         delete d->m_Queue;
01253     }
01254     d->m_Queue = new MidiQueue(this, this);
01255     return d->m_Queue;
01256 }
01257 
01264 MidiQueue*
01265 MidiClient::createQueue(QString const& queueName )
01266 {
01267     if (d->m_Queue != NULL) {
01268         delete d->m_Queue;
01269     }
01270     d->m_Queue = new MidiQueue(this, queueName, this);
01271     return d->m_Queue;
01272 }
01273 
01281 MidiQueue*
01282 MidiClient::useQueue(int queue_id)
01283 {
01284     if (d->m_Queue != NULL) {
01285         delete d->m_Queue;
01286     }
01287     d->m_Queue = new MidiQueue(this, queue_id, this);
01288     return d->m_Queue;
01289 }
01290 
01298 MidiQueue*
01299 MidiClient::useQueue(const QString& name)
01300 {
01301     if (d->m_Queue != NULL) {
01302         delete d->m_Queue;
01303     }
01304     int queue_id = getQueueId(name);
01305     if ( queue_id >= 0) {
01306        d->m_Queue = new MidiQueue(this, queue_id, this);
01307     }
01308     return d->m_Queue;
01309 }
01310 
01317 MidiQueue*
01318 MidiClient::useQueue(MidiQueue* queue)
01319 {
01320     if (d->m_Queue != NULL) {
01321         delete d->m_Queue;
01322     }
01323     queue->setParent(this);
01324     d->m_Queue = queue;
01325     return d->m_Queue;
01326 }
01327 
01332 QList<int>
01333 MidiClient::getAvailableQueues()
01334 {
01335     int q, err, max;
01336     QList<int> queues;
01337     snd_seq_queue_info_t* qinfo;
01338     snd_seq_queue_info_alloca(&qinfo);
01339     max = getSystemInfo().getMaxQueues();
01340     for ( q = 0; q < max; ++q ) {
01341         err = snd_seq_get_queue_info(d->m_SeqHandle, q, qinfo);
01342         if (err == 0) {
01343             queues.append(q);
01344         }
01345     }
01346     return queues;
01347 }
01348 
01356 PortInfoList
01357 MidiClient::filterPorts(unsigned int filter)
01358 {
01359     PortInfoList result;
01360     ClientInfoList::ConstIterator itc;
01361     PortInfoList::ConstIterator itp;
01362 
01363     if (d->m_NeedRefreshClientList)
01364         readClients();
01365 
01366     for (itc = d->m_ClientList.constBegin(); itc != d->m_ClientList.constEnd(); ++itc) {
01367         ClientInfo ci = (*itc);
01368         if ((ci.getClientId() == SND_SEQ_CLIENT_SYSTEM) ||
01369             (ci.getClientId() == d->m_Info.getClientId()))
01370             continue;
01371         PortInfoList lstPorts = ci.getPorts();
01372         for(itp = lstPorts.constBegin(); itp != lstPorts.constEnd(); ++itp) {
01373             PortInfo pi = (*itp);
01374             unsigned int cap = pi.getCapability();
01375             if ( ((filter & cap) != 0) &&
01376                  ((SND_SEQ_PORT_CAP_NO_EXPORT & cap) == 0) ) {
01377                 result.append(pi);
01378             }
01379         }
01380     }
01381     return result;
01382 }
01383 
01387 void
01388 MidiClient::updateAvailablePorts()
01389 {
01390     d->m_InputsAvail.clear();
01391     d->m_OutputsAvail.clear();
01392     d->m_InputsAvail = filterPorts( SND_SEQ_PORT_CAP_READ |
01393                                  SND_SEQ_PORT_CAP_SUBS_READ );
01394     d->m_OutputsAvail = filterPorts( SND_SEQ_PORT_CAP_WRITE |
01395                                   SND_SEQ_PORT_CAP_SUBS_WRITE );
01396 }
01397 
01402 PortInfoList
01403 MidiClient::getAvailableInputs()
01404 {
01405     d->m_NeedRefreshClientList = true;
01406     updateAvailablePorts();
01407     return d->m_InputsAvail;
01408 }
01409 
01414 PortInfoList
01415 MidiClient::getAvailableOutputs()
01416 {
01417     d->m_NeedRefreshClientList = true;
01418     updateAvailablePorts();
01419     return d->m_OutputsAvail;
01420 }
01421 
01428 void
01429 MidiClient::addListener(QObject* listener)
01430 {
01431     d->m_listeners.append(listener);
01432 }
01433 
01439 void
01440 MidiClient::removeListener(QObject* listener)
01441 {
01442     d->m_listeners.removeAll(listener);
01443 }
01444 
01451 void
01452 MidiClient::setEventsEnabled(bool bEnabled)
01453 {
01454     if (bEnabled != d->m_eventsEnabled) {
01455         d->m_eventsEnabled = bEnabled;
01456     }
01457 }
01458 
01463 SystemInfo&
01464 MidiClient::getSystemInfo()
01465 {
01466     snd_seq_system_info(d->m_SeqHandle, d->m_sysInfo.m_Info);
01467     return d->m_sysInfo;
01468 }
01469 
01474 PoolInfo&
01475 MidiClient::getPoolInfo()
01476 {
01477     snd_seq_get_client_pool(d->m_SeqHandle, d->m_poolInfo.m_Info);
01478     return d->m_poolInfo;
01479 }
01480 
01485 void
01486 MidiClient::setPoolInfo(const PoolInfo& info)
01487 {
01488     d->m_poolInfo = info;
01489     CHECK_WARNING(snd_seq_set_client_pool(d->m_SeqHandle, d->m_poolInfo.m_Info));
01490 }
01491 
01496 void
01497 MidiClient::resetPoolInput()
01498 {
01499     CHECK_WARNING(snd_seq_reset_pool_input(d->m_SeqHandle));
01500 }
01501 
01506 void
01507 MidiClient::resetPoolOutput()
01508 {
01509     CHECK_WARNING(snd_seq_reset_pool_output(d->m_SeqHandle));
01510 }
01511 
01516 void
01517 MidiClient::setPoolInput(int size)
01518 {
01519     CHECK_WARNING(snd_seq_set_client_pool_input(d->m_SeqHandle, size));
01520 }
01521 
01526 void
01527 MidiClient::setPoolOutput(int size)
01528 {
01529     CHECK_WARNING(snd_seq_set_client_pool_output(d->m_SeqHandle, size));
01530 }
01531 
01536 void
01537 MidiClient::setPoolOutputRoom(int size)
01538 {
01539     CHECK_WARNING(snd_seq_set_client_pool_output_room(d->m_SeqHandle, size));
01540 }
01541 
01546 void
01547 MidiClient::dropInput()
01548 {
01549     CHECK_WARNING(snd_seq_drop_input(d->m_SeqHandle));
01550 }
01551 
01556 void
01557 MidiClient::dropInputBuffer()
01558 {
01559     CHECK_WARNING(snd_seq_drop_input_buffer(d->m_SeqHandle));
01560 }
01561 
01569 void
01570 MidiClient::dropOutput()
01571 {
01572     CHECK_WARNING(snd_seq_drop_output(d->m_SeqHandle));
01573 }
01574 
01582 void
01583 MidiClient::dropOutputBuffer()
01584 {
01585     CHECK_WARNING(snd_seq_drop_output_buffer(d->m_SeqHandle));
01586 }
01587 
01594 void
01595 MidiClient::removeEvents(const RemoveEvents* spec)
01596 {
01597     CHECK_WARNING(snd_seq_remove_events(d->m_SeqHandle, spec->m_Info));
01598 }
01599 
01604 SequencerEvent*
01605 MidiClient::extractOutput()
01606 {
01607     snd_seq_event_t* ev;
01608     if (CHECK_WARNING(snd_seq_extract_output(d->m_SeqHandle, &ev) == 0)) {
01609         return new SequencerEvent(ev);
01610     }
01611     return NULL;
01612 }
01613 
01619 int
01620 MidiClient::outputPending()
01621 {
01622     return snd_seq_event_output_pending(d->m_SeqHandle);
01623 }
01624 
01638 int
01639 MidiClient::inputPending(bool fetch)
01640 {
01641     return snd_seq_event_input_pending(d->m_SeqHandle, fetch ? 1 : 0);
01642 }
01643 
01650 int
01651 MidiClient::getQueueId(const QString& name)
01652 {
01653     return snd_seq_query_named_queue(d->m_SeqHandle, name.toLocal8Bit().data());
01654 }
01655 
01661 int
01662 MidiClient::getPollDescriptorsCount(short events)
01663 {
01664     return snd_seq_poll_descriptors_count(d->m_SeqHandle, events);
01665 }
01666 
01680 int
01681 MidiClient::pollDescriptors( struct pollfd *pfds, unsigned int space,
01682                              short events )
01683 {
01684     return snd_seq_poll_descriptors(d->m_SeqHandle, pfds, space, events);
01685 }
01686 
01693 unsigned short
01694 MidiClient::pollDescriptorsRevents(struct pollfd *pfds, unsigned int nfds)
01695 {
01696     unsigned short revents;
01697     CHECK_WARNING( snd_seq_poll_descriptors_revents( d->m_SeqHandle,
01698                                                      pfds, nfds,
01699                                                      &revents ));
01700     return revents;
01701 }
01702 
01707 const char *
01708 MidiClient::_getDeviceName()
01709 {
01710     return snd_seq_name(d->m_SeqHandle);
01711 }
01712 
01717 void
01718 MidiClient::_setClientName(const char *name)
01719 {
01720     CHECK_WARNING(snd_seq_set_client_name(d->m_SeqHandle, name));
01721 }
01722 
01730 int
01731 MidiClient::createSimplePort( const char *name,
01732                               unsigned int caps,
01733                               unsigned int type )
01734 {
01735     return CHECK_WARNING( snd_seq_create_simple_port( d->m_SeqHandle,
01736                                                       name, caps, type ));
01737 }
01738 
01743 void
01744 MidiClient::deleteSimplePort(int port)
01745 {
01746     CHECK_WARNING( snd_seq_delete_simple_port( d->m_SeqHandle, port ));
01747 }
01748 
01755 void
01756 MidiClient::connectFrom(int myport, int client, int port)
01757 {
01758     CHECK_WARNING( snd_seq_connect_from(d->m_SeqHandle, myport, client, port ));
01759 }
01760 
01767 void
01768 MidiClient::connectTo(int myport, int client, int port)
01769 {
01770     CHECK_WARNING( snd_seq_connect_to(d->m_SeqHandle, myport, client, port ));
01771 }
01772 
01779 void
01780 MidiClient::disconnectFrom(int myport, int client, int port)
01781 {
01782     CHECK_WARNING( snd_seq_disconnect_from(d->m_SeqHandle, myport, client, port ));
01783 }
01784 
01791 void
01792 MidiClient::disconnectTo(int myport, int client, int port)
01793 {
01794     CHECK_WARNING( snd_seq_disconnect_to(d->m_SeqHandle, myport, client, port ));
01795 }
01796 
01808 bool
01809 MidiClient::parseAddress( const QString& straddr, snd_seq_addr& addr )
01810 {
01811     bool ok(false);
01812     QString testClient, testPort;
01813     ClientInfoList::ConstIterator cit;
01814     int pos = straddr.indexOf(':');
01815     if (pos > -1) {
01816         testClient = straddr.left(pos);
01817         testPort = straddr.mid(pos+1);
01818     } else {
01819         testClient = straddr;
01820         testPort = '0';
01821     }
01822     addr.client = testClient.toInt(&ok);
01823     if (ok)
01824         addr.port = testPort.toInt(&ok);
01825     if (!ok) {
01826         if (d->m_NeedRefreshClientList)
01827             readClients();
01828         for ( cit = d->m_ClientList.constBegin();
01829               cit != d->m_ClientList.constEnd(); ++cit ) {
01830             ClientInfo ci = *cit;
01831             if (testClient.compare(ci.getName(), Qt::CaseInsensitive) == 0) {
01832                 addr.client = ci.getClientId();
01833                 addr.port = testPort.toInt(&ok);
01834                 return ok;
01835             }
01836         }
01837     }
01838     return ok;
01839 }
01840 
01845 bool
01846 MidiClient::SequencerInputThread::stopped()
01847 {
01848     QReadLocker locker(&m_mutex);
01849     return m_Stopped;
01850 }
01851 
01855 void
01856 MidiClient::SequencerInputThread::stop()
01857 {
01858     QWriteLocker locker(&m_mutex);
01859     m_Stopped = true;
01860 }
01861 
01862 #if defined(RTKIT_SUPPORT)
01863 static pid_t _gettid(void) {
01864     return (pid_t) ::syscall(SYS_gettid);
01865 }
01866 #endif
01867 
01868 void
01869 MidiClient::SequencerInputThread::setRealtimePriority()
01870 {
01871     struct sched_param p;
01872     int rt, policy = SCHED_RR | SCHED_RESET_ON_FORK;
01873     quint32 priority = 6;
01874 #if defined(RTKIT_SUPPORT)
01875     bool ok;
01876     quint32 max_prio;
01877     quint64 thread;
01878     struct rlimit old_limit, new_limit;
01879     long long max_rttime;
01880 #endif
01881 
01882     ::memset(&p, 0, sizeof(p));
01883     p.sched_priority = priority;
01884     rt = ::pthread_setschedparam(::pthread_self(), policy, &p);
01885     if (rt != 0) {
01886 #if defined(RTKIT_SUPPORT)
01887         const QString rtkit_service =
01888                 QLatin1String("org.freedesktop.RealtimeKit1");
01889         const QString rtkit_path =
01890                 QLatin1String("/org/freedesktop/RealtimeKit1");
01891         const QString rtkit_iface = rtkit_service;
01892         thread = _gettid();
01893         QDBusConnection bus = QDBusConnection::systemBus();
01894         QDBusInterface realtimeKit(rtkit_service, rtkit_path, rtkit_iface, bus);
01895         QVariant maxRTPrio = realtimeKit.property("MaxRealtimePriority");
01896         max_prio = maxRTPrio.toUInt(&ok);
01897         if (!ok) {
01898             qWarning() << "invalid property RealtimeKit.MaxRealtimePriority";
01899             return;
01900         }
01901         if (priority > max_prio)
01902             priority = max_prio;
01903         QVariant maxRTNSec = realtimeKit.property("RTTimeNSecMax");
01904         max_rttime = maxRTNSec.toLongLong(&ok);
01905         if (!ok || max_rttime < 0) {
01906             qWarning() << "invalid property RealtimeKit.RTTimeNSecMax";
01907             return;
01908         }
01909         new_limit.rlim_cur = new_limit.rlim_max = max_rttime;
01910         rt = ::getrlimit(RLIMIT_RTTIME, &old_limit);
01911         if (rt < 0) {
01912             qWarning() << "getrlimit() failed. err=" << rt << ::strerror(rt);
01913             return;
01914         }
01915         rt = ::setrlimit(RLIMIT_RTTIME, &new_limit);
01916         if ( rt < 0) {
01917             qWarning() << "setrlimit() failed, err=" << rt << ::strerror(rt);
01918             return;
01919         }
01920         QDBusMessage reply = realtimeKit.call("MakeThreadRealtime", thread, priority);
01921         if (reply.type() == QDBusMessage::ErrorMessage )
01922             qWarning() << "error returned by RealtimeKit.MakeThreadRealtime:"
01923                         << reply.errorMessage();
01924 #else
01925         qWarning() << "pthread_setschedparam() failed, err="
01926                    << rt << ::strerror(rt);
01927 #endif
01928     }
01929 }
01930 
01934 void
01935 MidiClient::SequencerInputThread::run()
01936 {
01937     unsigned long npfd;
01938     pollfd* pfd;
01939     if ( priority() == TimeCriticalPriority )
01940         setRealtimePriority();
01941 
01942     if (m_MidiClient != NULL) {
01943         npfd = snd_seq_poll_descriptors_count(m_MidiClient->getHandle(), POLLIN);
01944         pfd = (pollfd *) alloca(npfd * sizeof(pollfd));
01945         try
01946         {
01947             snd_seq_poll_descriptors(m_MidiClient->getHandle(), pfd, npfd, POLLIN);
01948             while (!stopped() && (m_MidiClient != NULL))
01949             {
01950                 int rt = poll(pfd, npfd, m_Wait);
01951                 if (rt > 0) {
01952                     m_MidiClient->doEvents();
01953                 }
01954             }
01955         }
01956         catch (...)
01957         {
01958             qWarning() << "exception in input thread";
01959         }
01960     }
01961 }
01962 
01966 ClientInfo::ClientInfo()
01967 {
01968     snd_seq_client_info_malloc(&m_Info);
01969 }
01970 
01975 ClientInfo::ClientInfo(const ClientInfo& other)
01976 {
01977     snd_seq_client_info_malloc(&m_Info);
01978     snd_seq_client_info_copy(m_Info, other.m_Info);
01979     m_Ports = other.m_Ports;
01980 }
01981 
01986 ClientInfo::ClientInfo(snd_seq_client_info_t* other)
01987 {
01988     snd_seq_client_info_malloc(&m_Info);
01989     snd_seq_client_info_copy(m_Info, other);
01990 }
01991 
01997 ClientInfo::ClientInfo(MidiClient* seq, int id)
01998 {
01999     snd_seq_client_info_malloc(&m_Info);
02000     snd_seq_get_any_client_info(seq->getHandle(), id, m_Info);
02001 }
02002 
02006 ClientInfo::~ClientInfo()
02007 {
02008     freePorts();
02009     snd_seq_client_info_free(m_Info);
02010 }
02011 
02016 ClientInfo*
02017 ClientInfo::clone()
02018 {
02019     return new ClientInfo(m_Info);
02020 }
02021 
02027 ClientInfo&
02028 ClientInfo::operator=(const ClientInfo& other)
02029 {
02030     snd_seq_client_info_copy(m_Info, other.m_Info);
02031     m_Ports = other.m_Ports;
02032     return *this;
02033 }
02034 
02039 int
02040 ClientInfo::getClientId()
02041 {
02042     return snd_seq_client_info_get_client(m_Info);
02043 }
02044 
02049 snd_seq_client_type_t
02050 ClientInfo::getClientType()
02051 {
02052     return snd_seq_client_info_get_type(m_Info);
02053 }
02054 
02059 QString
02060 ClientInfo::getName()
02061 {
02062     return QString(snd_seq_client_info_get_name(m_Info));
02063 }
02064 
02069 bool
02070 ClientInfo::getBroadcastFilter()
02071 {
02072     return (snd_seq_client_info_get_broadcast_filter(m_Info) != 0);
02073 }
02074 
02079 bool
02080 ClientInfo::getErrorBounce()
02081 {
02082     return (snd_seq_client_info_get_error_bounce(m_Info) != 0);
02083 }
02084 
02090 const unsigned char*
02091 ClientInfo::getEventFilter()
02092 {
02093     return snd_seq_client_info_get_event_filter(m_Info);
02094 }
02095 
02100 int
02101 ClientInfo::getNumPorts()
02102 {
02103     return snd_seq_client_info_get_num_ports(m_Info);
02104 }
02105 
02110 int
02111 ClientInfo::getEventLost()
02112 {
02113     return snd_seq_client_info_get_event_lost(m_Info);
02114 }
02115 
02120 void
02121 ClientInfo::setClient(int client)
02122 {
02123     snd_seq_client_info_set_client(m_Info, client);
02124 }
02125 
02130 void
02131 ClientInfo::setName(QString name)
02132 {
02133     snd_seq_client_info_set_name(m_Info, name.toLocal8Bit().data());
02134 }
02135 
02140 void
02141 ClientInfo::setBroadcastFilter(bool val)
02142 {
02143     snd_seq_client_info_set_broadcast_filter(m_Info, val ? 1 : 0);
02144 }
02145 
02150 void
02151 ClientInfo::setErrorBounce(bool val)
02152 {
02153     snd_seq_client_info_set_error_bounce(m_Info, val ? 1 : 0);
02154 }
02155 
02161 void
02162 ClientInfo::setEventFilter(unsigned char *filter)
02163 {
02164     snd_seq_client_info_set_event_filter(m_Info, filter);
02165 }
02166 
02171 void
02172 ClientInfo::readPorts(MidiClient* seq)
02173 {
02174     PortInfo info;
02175     freePorts();
02176     info.setClient(getClientId());
02177     info.setClientName(getName());
02178     info.setPort(-1);
02179     while (snd_seq_query_next_port(seq->getHandle(), info.m_Info) >= 0) {
02180         info.readSubscribers(seq);
02181         m_Ports.append(info);
02182     }
02183 }
02184 
02188 void
02189 ClientInfo::freePorts()
02190 {
02191     m_Ports.clear();
02192 }
02193 
02198 PortInfoList
02199 ClientInfo::getPorts() const
02200 {
02201     PortInfoList lst = m_Ports; // copy
02202     return lst;
02203 }
02204 
02209 int
02210 ClientInfo::getSizeOfInfo() const
02211 {
02212     return snd_seq_client_info_sizeof();
02213 }
02214 
02215 #if SND_LIB_VERSION > 0x010010
02216 
02221 void
02222 ClientInfo::addFilter(int eventType)
02223 {
02224     snd_seq_client_info_event_filter_add(m_Info, eventType);
02225 }
02226 
02232 bool
02233 ClientInfo::isFiltered(int eventType)
02234 {
02235     return (snd_seq_client_info_event_filter_check(m_Info, eventType) != 0);
02236 }
02237 
02241 void
02242 ClientInfo::clearFilter()
02243 {
02244     snd_seq_client_info_event_filter_clear(m_Info);
02245 }
02246 
02251 void
02252 ClientInfo::removeFilter(int eventType)
02253 {
02254     snd_seq_client_info_event_filter_del(m_Info, eventType);
02255 }
02256 #endif
02257 
02261 SystemInfo::SystemInfo()
02262 {
02263     snd_seq_system_info_malloc(&m_Info);
02264 }
02265 
02270 SystemInfo::SystemInfo(const SystemInfo& other)
02271 {
02272     snd_seq_system_info_malloc(&m_Info);
02273     snd_seq_system_info_copy(m_Info, other.m_Info);
02274 }
02275 
02280 SystemInfo::SystemInfo(snd_seq_system_info_t* other)
02281 {
02282     snd_seq_system_info_malloc(&m_Info);
02283     snd_seq_system_info_copy(m_Info, other);
02284 }
02285 
02290 SystemInfo::SystemInfo(MidiClient* seq)
02291 {
02292     snd_seq_system_info_malloc(&m_Info);
02293     snd_seq_system_info(seq->getHandle(), m_Info);
02294 }
02295 
02299 SystemInfo::~SystemInfo()
02300 {
02301     snd_seq_system_info_free(m_Info);
02302 }
02303 
02308 SystemInfo*
02309 SystemInfo::clone()
02310 {
02311     return new SystemInfo(m_Info);
02312 }
02313 
02319 SystemInfo&
02320 SystemInfo::operator=(const SystemInfo& other)
02321 {
02322     snd_seq_system_info_copy(m_Info, other.m_Info);
02323     return *this;
02324 }
02325 
02330 int SystemInfo::getMaxClients()
02331 {
02332     return snd_seq_system_info_get_clients(m_Info);
02333 }
02334 
02339 int SystemInfo::getMaxPorts()
02340 {
02341     return snd_seq_system_info_get_ports(m_Info);
02342 }
02343 
02348 int SystemInfo::getMaxQueues()
02349 {
02350     return snd_seq_system_info_get_queues(m_Info);
02351 }
02352 
02357 int SystemInfo::getMaxChannels()
02358 {
02359     return snd_seq_system_info_get_channels(m_Info);
02360 }
02361 
02366 int SystemInfo::getCurrentQueues()
02367 {
02368     return snd_seq_system_info_get_cur_queues(m_Info);
02369 }
02370 
02375 int SystemInfo::getCurrentClients()
02376 {
02377     return snd_seq_system_info_get_cur_clients(m_Info);
02378 }
02379 
02384 int SystemInfo::getSizeOfInfo() const
02385 {
02386     return snd_seq_system_info_sizeof();
02387 }
02388 
02392 PoolInfo::PoolInfo()
02393 {
02394     snd_seq_client_pool_malloc(&m_Info);
02395 }
02396 
02401 PoolInfo::PoolInfo(const PoolInfo& other)
02402 {
02403     snd_seq_client_pool_malloc(&m_Info);
02404     snd_seq_client_pool_copy(m_Info, other.m_Info);
02405 }
02406 
02411 PoolInfo::PoolInfo(snd_seq_client_pool_t* other)
02412 {
02413     snd_seq_client_pool_malloc(&m_Info);
02414     snd_seq_client_pool_copy(m_Info, other);
02415 }
02416 
02421 PoolInfo::PoolInfo(MidiClient* seq)
02422 {
02423     snd_seq_client_pool_malloc(&m_Info);
02424     snd_seq_get_client_pool(seq->getHandle(), m_Info);
02425 }
02426 
02430 PoolInfo::~PoolInfo()
02431 {
02432     snd_seq_client_pool_free(m_Info);
02433 }
02434 
02439 PoolInfo*
02440 PoolInfo::clone()
02441 {
02442     return new PoolInfo(m_Info);
02443 }
02444 
02450 PoolInfo& PoolInfo::operator=(const PoolInfo& other)
02451 {
02452     snd_seq_client_pool_copy(m_Info, other.m_Info);
02453     return *this;
02454 }
02455 
02460 int
02461 PoolInfo::getClientId()
02462 {
02463     return snd_seq_client_pool_get_client(m_Info);
02464 }
02465 
02470 int
02471 PoolInfo::getInputFree()
02472 {
02473     return snd_seq_client_pool_get_input_free(m_Info);
02474 }
02475 
02480 int
02481 PoolInfo::getInputPool()
02482 {
02483     return snd_seq_client_pool_get_input_pool(m_Info);
02484 }
02485 
02490 int
02491 PoolInfo::getOutputFree()
02492 {
02493     return snd_seq_client_pool_get_output_free(m_Info);
02494 }
02495 
02500 int
02501 PoolInfo::getOutputPool()
02502 {
02503     return snd_seq_client_pool_get_output_pool(m_Info);
02504 }
02505 
02511 int
02512 PoolInfo::getOutputRoom()
02513 {
02514     return snd_seq_client_pool_get_output_room(m_Info);
02515 }
02516 
02521 void
02522 PoolInfo::setInputPool(int size)
02523 {
02524     snd_seq_client_pool_set_input_pool(m_Info, size);
02525 }
02526 
02531 void
02532 PoolInfo::setOutputPool(int size)
02533 {
02534     snd_seq_client_pool_set_output_pool(m_Info, size);
02535 }
02536 
02543 void
02544 PoolInfo::setOutputRoom(int size)
02545 {
02546     snd_seq_client_pool_set_output_room(m_Info, size);
02547 }
02548 
02553 int
02554 PoolInfo::getSizeOfInfo() const
02555 {
02556     return snd_seq_client_pool_sizeof();
02557 }
02558 
02559 #if SND_LIB_VERSION > 0x010004
02560 
02565 QString
02566 getRuntimeALSALibraryVersion()
02567 {
02568     return QString(snd_asoundlib_version());
02569 }
02570 
02576 int
02577 getRuntimeALSALibraryNumber()
02578 {
02579     QRegExp rx("(\\d+)");
02580     QString str = getRuntimeALSALibraryVersion();
02581     bool ok;
02582     int pos = 0, result = 0, j = 0;
02583     while ((pos = rx.indexIn(str, pos)) != -1 && j < 3) {
02584         int v = rx.cap(1).toInt(&ok);
02585         if (ok) {
02586             result <<= 8;
02587             result += v;
02588         }
02589         pos += rx.matchedLength();
02590         j++;
02591     }
02592     return result;
02593 }
02594 #endif // SND_LIB_VERSION > 0x010004
02595 
02601 QString
02602 getRuntimeALSADriverVersion()
02603 {
02604     QRegExp rx(".*Driver Version.*([\\d\\.]+).*");
02605     QString s;
02606     QFile f("/proc/asound/version");
02607     if (f.open(QFile::ReadOnly)) {
02608         QTextStream str(&f);
02609         if (rx.exactMatch(str.readLine().trimmed()))
02610             s = rx.cap(1);
02611     }
02612     return s;
02613 }
02614 
02620 int
02621 getRuntimeALSADriverNumber()
02622 {
02623     QRegExp rx("(\\d+)");
02624     QString str = getRuntimeALSADriverVersion();
02625     bool ok;
02626     int pos = 0, result = 0, j = 0;
02627     while ((pos = rx.indexIn(str, pos)) != -1 && j < 3) {
02628         int v = rx.cap(1).toInt(&ok);
02629         if (ok) {
02630             result <<= 8;
02631             result += v;
02632         }
02633         pos += rx.matchedLength();
02634         j++;
02635     }
02636     return result;
02637 }
02638 
02639 } /* namespace drumstick */