/* * KMix -- KDE's full featured mini mixer * * Copyright 2006-2007 Christian Esken * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the Free * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "core/kmixdevicemanager.h" #include #include #include #include #include #include #include KMixDeviceManager* KMixDeviceManager::s_KMixDeviceManager = 0; KMixDeviceManager::KMixDeviceManager() { } KMixDeviceManager::~KMixDeviceManager() { } KMixDeviceManager* KMixDeviceManager::instance() { if ( s_KMixDeviceManager == 0 ) { s_KMixDeviceManager = new KMixDeviceManager(); } return s_KMixDeviceManager; } void KMixDeviceManager::initHotplug() { connect (Solid::DeviceNotifier::instance(), SIGNAL(deviceAdded(QString)), SLOT(pluggedSlot(QString)) ); connect (Solid::DeviceNotifier::instance(), SIGNAL(deviceRemoved(QString)), SLOT(unpluggedSlot(QString)) ); } QString KMixDeviceManager::getUDI_ALSA(int num) { QList dl = Solid::Device::listFromType(Solid::DeviceInterface::AudioInterface); QString numString; numString.setNum(num); bool found = false; QString udi; QString devHandle; foreach ( const Solid::Device &device, dl ) { // std::cout << "Coldplug udi = '" << device.udi().toUtf8().data() << "'\n"; // LEAK audiohw leaks, but Solid does not document whether it is its own or "my" Object. const Solid::AudioInterface *audiohw = device.as(); if (audiohw != 0) { if (audiohw->deviceType() & ( Solid::AudioInterface::AudioControl)) { switch (audiohw->driver()) { case Solid::AudioInterface::Alsa: devHandle = audiohw->driverHandle().toList().first().toString(); if ( numString == devHandle ) { found = true; udi = device.udi(); } break; default: break; } // driver type } // is an audio control // If I delete audiohw, kmix crashes. If I do not, there is a definite leak according to valgrind: // ==24561== 4,958 (1,200 direct, 3,758 indirect) bytes in 25 blocks are definitely lost in loss record 1,882 of 1,918 // ==24561== at 0x4C27D49: operator new(unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so) // ==24561== by 0x5665462: ??? (in /usr/lib64/libsolid.so.4.11.3) // ==24561== by 0x565EC57: ??? (in /usr/lib64/libsolid.so.4.11.3) // ==24561== by 0x563610B: Solid::Device::asDeviceInterface(Solid::DeviceInterface::Type const&) const (in /usr/lib64/libsolid.so.4.11.3) // ==24561== by 0x4EB7DA6: Solid::AudioInterface const* Solid::Device::as() const (device.h:254) // ==24561== by 0x4EB6F6F: KMixDeviceManager::getUDI_ALSA(int) (kmixdevicemanager.cpp:70) // ==24561== by 0x4E6C809: Mixer_ALSA::open() (mixer_alsa9.cpp:139) // ==24561== by 0x4E6334E: Mixer_Backend::openIfValid() (mixer_backend.cpp:84) // ==24561== by 0x4EBD4F9: Mixer::openIfValid(int) (mixer.cpp:268) // ==24561== by 0x4EB5F10: MixerToolBox::possiblyAddMixer(Mixer*) (mixertoolbox.cpp:310) // ==24561== by 0x4EB57AE: MixerToolBox::initMixerInternal(MixerToolBox::MultiDriverMode, QList, QString&) (mixertoolbox.cpp:165) // ==24561== by 0x4EB52B6: MixerToolBox::initMixer(MixerToolBox::MultiDriverMode, QList, QString&) (mixertoolbox.cpp:85) // ==24561== by 0x4EB5267: MixerToolBox::initMixer(bool, QList, QString&) (mixertoolbox.cpp:80) // ==24561== by 0x4E7ED75: KMixWindow::KMixWindow(bool) (kmix.cpp:96) // ==24561== by 0x4E8A7CF: KMixApp::newInstance() (KMixApp.cpp:112) // ==24561== by 0x5B30A7E: KUniqueApplication::Private::_k_newInstanceNoFork() (in /usr/lib64/libkdeui.so.5.11.3) // ==24561== by 0x774A11D: QObject::event(QEvent*) (in /usr/lib64/libQtCore.so.4.8.5) // ==24561== by 0x61338A2: QApplication::event(QEvent*) (in /usr/lib64/libQtGui.so.4.8.5) // ==24561== by 0x612E8AB: QApplicationPrivate::notify_helper(QObject*, QEvent*) (in /usr/lib64/libQtGui.so.4.8.5) // ==24561== by 0x6134E6F: QApplication::notify(QObject*, QEvent*) (in /usr/lib64/libQtGui.so.4.8.5) // The data seems to be "static" device info from Solid, so I will leave it alone. // delete audiohw; } if (found) { break; } } // foreach return udi; } QString KMixDeviceManager::getUDI_OSS(const QString& devname) { QList dl = Solid::Device::listFromType(Solid::DeviceInterface::AudioInterface); bool found = false; QString udi; QString devHandle; foreach ( const Solid::Device &device, dl ) { // std::cout << "Coldplug udi = '" << device.udi().toUtf8().data() << "'\n"; const Solid::AudioInterface *audiohw = device.as(); if (audiohw && (audiohw->deviceType() & ( Solid::AudioInterface::AudioControl))) { switch (audiohw->driver()) { case Solid::AudioInterface::OpenSoundSystem: devHandle = audiohw->driverHandle().toString(); // std::cout << ">>> Coldplugged OSS ='" << devHandle.toUtf8().data() << "'\n"; if ( devname == devHandle ) { found = true; // std::cout << ">>> Match!!! Coldplugged OSS ='" << devHandle.toUtf8().data() << "'\n"; udi = device.udi(); } break; default: break; } // driver type } // is an audio control if ( found) break; } // foreach return udi; } void KMixDeviceManager::pluggedSlot(const QString& udi) { // std::cout << "Plugged udi='" << udi.toUtf8().data() << "'\n"; Solid::Device device(udi); Solid::AudioInterface *audiohw = device.as(); if (audiohw && (audiohw->deviceType() & ( Solid::AudioInterface::AudioControl))) { QString dev; QRegExp devExpr( QLatin1String( "^\\D+(\\d+)$" )); switch (audiohw->driver()) { case Solid::AudioInterface::Alsa: if ( _hotpluggingBackend == "ALSA" || _hotpluggingBackend == "*" ) { dev = audiohw->driverHandle().toList().first().toString(); emit plugged("ALSA", udi, dev); } break; case Solid::AudioInterface::OpenSoundSystem: if ( _hotpluggingBackend == "OSS" || _hotpluggingBackend == "*" ) { dev = audiohw->driverHandle().toString(); if ( devExpr.indexIn(dev) > -1 ) { dev = devExpr.cap(1); // Get device number from device name (e.g "/dev/mixer1" or "/dev/sound/mixer2") } else { dev = '0'; // "/dev/mixer" or "/dev/sound/mixer" } emit plugged("OSS", udi, dev); } break; default: kError(67100) << "Plugged UNKNOWN Audio device (ignored)"; break; } } } void KMixDeviceManager::unpluggedSlot(const QString& udi) { // std::cout << "Unplugged udi='" << udi.toUtf8().data() << "'\n"; // Solid::Device device(udi); // At this point the device has already been unplugged by the user. Solid doesn't know anything about the // device except the UDI (not even device.as() is possible). Thus I'll forward any // unplugging action (could e.g. also be HID or mass storage). The receiver of the signal has to deal with it, // but a simple UDI matching is enough. emit unplugged(udi); } #include "moc_kmixdevicemanager.cpp"