2
* KMix -- KDE's full featured mini mixer
5
* Copyright (C) 2004 Christian Esken <esken@kde.org>
7
* This program is free software; you can redistribute it and/or
8
* modify it under the terms of the GNU Library General Public
9
* License as published by the Free Software Foundation; either
10
* version 2 of the License, or (at your option) any later version.
12
* This program is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
* Library General Public License for more details.
17
* You should have received a copy of the GNU Library General Public
18
* License along with this program; if not, write to the Free
19
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
29
#include <kstandarddirs.h>
31
#include "core/kmixdevicemanager.h"
32
#include "core/mixdevice.h"
33
#include "core/mixer.h"
35
#include "core/mixertoolbox.h"
38
MixerToolBox* MixerToolBox::s_instance = 0;
39
QRegExp MixerToolBox::s_ignoreMixerExpression( QLatin1String( "Modem" ));
40
//KLocale* MixerToolBox::s_whatsthisLocale = 0;
42
/***********************************************************************************
44
This MixerToolBox is linked to the KMix Main Program, the KMix Applet and kmixctrl.
45
As we do not want to link in more than necessary to kmixctrl, you are asked
46
not to put any GUI classes in here.
47
In the case where it is unavoidable, please put them in KMixToolBox.
48
***********************************************************************************/
50
MixerToolBox* MixerToolBox::instance()
52
if ( s_instance == 0 ) {
53
s_instance = new MixerToolBox();
54
// if ( s_ignoreMixerExpression.isEmpty() )
55
// s_ignoreMixerExpression.setPattern("Modem");
62
* Scan for Mixers in the System. This is the method that implicitely fills the
63
* list of Mixer's, which is accessible via the static Mixer::mixer() method.
65
* This is run only once during the initialization phase of KMix. It has the following tasks:
66
* 1) Coldplug scan, to fill the initial mixer list
67
* 2) Rember UDI's, to match them when unplugging a device
68
* 3) Find out, which Backend to use (plugin events of other Backends are ignored).
70
* @par multiDriverMode Whether the Mixer scan should try more all backendends.
71
* 'true' means to scan all backends. 'false' means: After scanning the
72
* current backend the next backend is only scanned if no Mixers were found yet.
73
* @par ref_hwInfoString Here a descripitive text of the scan is returned (Hardware Information)
75
void MixerToolBox::initMixer(bool multiDriverMode, QString& ref_hwInfoString)
77
//kDebug(67100) << "IN MixerToolBox::initMixer()";
79
// Find all mixers and initialize them
80
int drvNum = Mixer::numDrivers();
82
int driverWithMixer = -1;
83
bool multipleDriversActive = false;
85
QString driverInfo = "";
86
QString driverInfoUsed = "";
88
for( int drv1=0; drv1<drvNum; drv1++ )
90
QString driverName = Mixer::driverName(drv1);
91
if ( driverInfo.length() > 0 ) {
94
driverInfo += driverName;
96
/* Run a loop over all drivers. The loop will terminate after the first driver which
97
has mixers. And here is the reason:
98
- If you run ALSA with ALSA-OSS-Emulation enabled, mixers will show up twice: once
99
as native ALSA mixer, once as OSS mixer (emulated by ALSA). This is bad and WILL
100
confuse users. So it is a design decision that we can compile in multiple drivers
101
but we can run only one driver.
102
- For special usage scenarios, people will still want to run both drivers at the
103
same time. We allow them to hack their Config-File, where they can enable a
105
- Another remark: For KMix3.0 or so, we should allow multiple-driver, for allowing
106
addition of special-use drivers, e.g. an Jack-Mixer-Backend, or a CD-Rom volume Backend.
109
bool autodetectionFinished = false;
110
for( int drv=0; drv<drvNum; drv++ )
112
QString driverName = Mixer::driverName(drv);
113
kDebug(67100) << "Looking for mixers with the : " << driverName << " driver";
115
if ( autodetectionFinished ) {
116
// inner loop indicates that we are finished => sane exit from outer loop
120
bool drvInfoAppended = false;
121
// The "19" below is just a "silly" number:
122
// (Old: The loop will break as soon as an error is detected - e.g. on 3rd loop when 2 soundcards are installed)
123
// New: We don't try be that clever anymore. We now blindly scan 20 cards, as the clever
124
// approach doesn't work for the one or other user (e.g. hotplugging might create holes in the list of soundcards).
126
for( int dev=0; dev<=devNumMax; dev++ )
128
Mixer *mixer = new Mixer( driverName, dev );
129
bool mixerAccepted = possiblyAddMixer(mixer);
131
/* Lets decide if the autoprobing shall end (BTW: In multiDriver mode we scan all devices, so no check is necessary) */
132
if ( ! multiDriverMode ) {
133
// In Single-Driver-mode we only need to check after we reached devNumMax
134
if ( dev == devNumMax && Mixer::mixers().count() != 0 )
135
autodetectionFinished = true; // highest device number of driver and a Mixer => finished
140
kDebug(67100) << "Success! Found a mixer with the : " << driverName << " driver";
141
// append driverName (used drivers)
142
if ( !drvInfoAppended )
144
drvInfoAppended = true;
145
if ( Mixer::mixers().count() > 1)
146
driverInfoUsed += " + ";
147
driverInfoUsed += driverName;
150
// Check whether there are mixers in different drivers, so that the user can be warned
151
if ( !multipleDriversActive )
153
if ( driverWithMixer == -1 )
155
// Aha, this is the very first detected device
156
driverWithMixer = drv;
158
else if ( driverWithMixer != drv )
160
// Got him: There are mixers in different drivers
161
multipleDriversActive = true;
163
} // !multipleDriversActive
166
} // loop over sound card devices of current driver
168
if (autodetectionFinished) {
171
} // loop over soundcard drivers
174
// Add a master device (if we haven't defined one yet)
175
if ( Mixer::getGlobalMasterMD(false) == 0 ) {
176
// We have no master card yet. This actually only happens when there was
177
// not one defined in the kmixrc.
178
// So lets just set the first card as master card.
179
if ( Mixer::mixers().count() > 0 ) {
180
QString controlId = Mixer::mixers().first()->getLocalMasterMD()->id();
181
Mixer::setGlobalMaster( Mixer::mixers().first()->id(), controlId);
185
// setGlobalMaster was already set after reading the configuration.
186
// So we must make the local master consistent
187
MixDevice* md = Mixer::getGlobalMasterMD();
188
QString mdID = md->id();
189
md->mixer()->setLocalMasterMD(mdID);
194
if ( Mixer::mixers().count() == 0 )
196
// If there was no mixer found, we assume, that hotplugging will take place
197
// on the preferred driver (this is always the first in the backend list).
198
driverInfoUsed = Mixer::driverName(0);
201
ref_hwInfoString = i18n("Sound drivers supported:");
202
ref_hwInfoString.append(" ").append( driverInfo ).append( "\n").append(i18n("Sound drivers used:")) .append(" ").append(driverInfoUsed);
204
if ( multipleDriversActive )
206
// this will only be possible by hacking the config-file, as it will not be officially supported
207
ref_hwInfoString += "\nExperimental multiple-Driver mode activated";
208
QString allDrivermatch("*");
209
KMixDeviceManager::instance()->setHotpluggingBackends(allDrivermatch);
212
KMixDeviceManager::instance()->setHotpluggingBackends(driverInfoUsed);
215
kDebug(67100) << ref_hwInfoString << endl << "Total number of detected Mixers: " << Mixer::mixers().count();
216
//kDebug(67100) << "OUT MixerToolBox::initMixer()";
220
bool MixerToolBox::possiblyAddMixer(Mixer *mixer)
222
if ( mixer->openIfValid() )
224
if ( (!s_ignoreMixerExpression.isEmpty()) && mixer->id().contains(s_ignoreMixerExpression) ) {
225
// This Mixer should be ignored (default expression is "Modem").
230
// Count mixer nums for every mixer name to identify mixers with equal names.
231
// This is for creating persistent (reusable) primary keys, which can safely
232
// be referenced (especially for config file access, so it is meant to be persistent!).
233
/*int newCardInstanceNum = */ s_mixerNums[mixer->getBaseName()]++;
234
mixer->setCardInstance(s_mixerNums[mixer->getBaseName()]);
236
Mixer::mixers().append( mixer );
237
kDebug(67100) << "Added card " << mixer->id();
240
emit mixerAdded(mixer->id());
251
/* This allows to set an expression form Mixers that should be ignored.
252
The default is "Modem", because most people don't want to control the modem volume. */
253
void MixerToolBox::setMixerIgnoreExpression(const QString& ignoreExpr)
255
s_ignoreMixerExpression.setPattern(ignoreExpr);
258
QString MixerToolBox::mixerIgnoreExpression() const
260
return s_ignoreMixerExpression.pattern( );
263
void MixerToolBox::removeMixer(Mixer *par_mixer)
265
for (int i=0; i<Mixer::mixers().count(); ++i) {
266
Mixer *mixer = (Mixer::mixers())[i];
267
if ( mixer == par_mixer ) {
268
kDebug(67100) << "Removing card " << mixer->id();
269
s_mixerNums[mixer->getBaseName()]--;
270
Mixer::mixers().removeAt(i);
279
* Clean up and free all resources of all found Mixers, which were found in the initMixer() call
281
void MixerToolBox::deinitMixer()
283
//kDebug(67100) << "IN MixerToolBox::deinitMixer()";
285
int mixerCount = Mixer::mixers().count();
286
for ( int i=0; i<mixerCount; ++i)
288
Mixer* mixer = (Mixer::mixers())[i];
289
//kDebug(67100) << "MixerToolBox::deinitMixer() Remove Mixer";
293
Mixer::mixers().clear();
294
// kDebug(67100) << "OUT MixerToolBox::deinitMixer()";
299
KLocale* MixerToolBox::whatsthisControlLocale()
301
if ( s_whatsthisLocale == 0 ) {
302
s_whatsthisLocale = new KLocale("kmix-controls");
304
return s_whatsthisLocale;
309
#include "mixertoolbox.moc"