~ubuntu-branches/ubuntu/natty/kdemultimedia/natty-proposed

« back to all changes in this revision

Viewing changes to kmix/core/mixertoolbox.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Debian Qt/KDE Maintainers
  • Date: 2011-05-26 02:41:36 UTC
  • mfrom: (0.2.3 upstream)
  • mto: This revision was merged to the branch mainline in revision 108.
  • Revision ID: james.westby@ubuntu.com-20110526024136-jjwsigfy402jhupm
Tags: upstream-4.6.3
ImportĀ upstreamĀ versionĀ 4.6.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * KMix -- KDE's full featured mini mixer
 
3
 *
 
4
 *
 
5
 * Copyright (C) 2004 Christian Esken <esken@kde.org>
 
6
 *
 
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.
 
11
 *
 
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.
 
16
 *
 
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.
 
20
 */
 
21
 
 
22
 
 
23
#include <QDir>
 
24
#include <QWidget>
 
25
#include <QString>
 
26
 
 
27
//#include <kdebug.h>
 
28
#include <klocale.h>
 
29
#include <kstandarddirs.h>
 
30
 
 
31
#include "core/kmixdevicemanager.h"
 
32
#include "core/mixdevice.h"
 
33
#include "core/mixer.h"
 
34
 
 
35
#include "core/mixertoolbox.h"
 
36
 
 
37
 
 
38
MixerToolBox* MixerToolBox::s_instance      = 0;
 
39
QRegExp MixerToolBox::s_ignoreMixerExpression( QLatin1String( "Modem" ));
 
40
//KLocale* MixerToolBox::s_whatsthisLocale = 0;
 
41
 
 
42
/***********************************************************************************
 
43
 Attention:
 
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
 ***********************************************************************************/
 
49
 
 
50
MixerToolBox* MixerToolBox::instance()
 
51
{
 
52
   if ( s_instance == 0 ) {
 
53
      s_instance = new MixerToolBox();
 
54
//      if ( s_ignoreMixerExpression.isEmpty() )
 
55
//          s_ignoreMixerExpression.setPattern("Modem");
 
56
   }
 
57
   return s_instance;
 
58
}
 
59
 
 
60
 
 
61
/**
 
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.
 
64
 *
 
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).
 
69
 *
 
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)
 
74
 */
 
75
void MixerToolBox::initMixer(bool multiDriverMode, QString& ref_hwInfoString)
 
76
{
 
77
   //kDebug(67100) << "IN MixerToolBox::initMixer()";
 
78
 
 
79
   // Find all mixers and initialize them
 
80
   int drvNum = Mixer::numDrivers();
 
81
 
 
82
   int driverWithMixer = -1;
 
83
   bool multipleDriversActive = false;
 
84
 
 
85
   QString driverInfo = "";
 
86
   QString driverInfoUsed = "";
 
87
 
 
88
   for( int drv1=0; drv1<drvNum; drv1++ )
 
89
   {
 
90
      QString driverName = Mixer::driverName(drv1);
 
91
      if ( driverInfo.length() > 0 ) {
 
92
         driverInfo += " + ";
 
93
      }
 
94
      driverInfo += driverName;
 
95
   }
 
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
 
104
         multi-driver mode.
 
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.
 
107
      */
 
108
   
 
109
   bool autodetectionFinished = false;
 
110
   for( int drv=0; drv<drvNum; drv++ )
 
111
   {
 
112
      QString driverName = Mixer::driverName(drv);
 
113
      kDebug(67100) << "Looking for mixers with the : " << driverName << " driver";
 
114
 
 
115
      if ( autodetectionFinished ) {
 
116
         // inner loop indicates that we are finished => sane exit from outer loop
 
117
         break;
 
118
      }
 
119
   
 
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).
 
125
      int devNumMax = 19;
 
126
      for( int dev=0; dev<=devNumMax; dev++ )
 
127
      {
 
128
         Mixer *mixer = new Mixer( driverName, dev );
 
129
         bool mixerAccepted = possiblyAddMixer(mixer);
 
130
   
 
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
 
136
        }
 
137
      
 
138
         if ( mixerAccepted )
 
139
         {
 
140
            kDebug(67100) << "Success! Found a mixer with the : " << driverName << " driver";
 
141
            // append driverName (used drivers)
 
142
            if ( !drvInfoAppended )
 
143
            {
 
144
               drvInfoAppended = true;
 
145
               if (  Mixer::mixers().count() > 1)
 
146
                  driverInfoUsed += " + ";
 
147
               driverInfoUsed += driverName;
 
148
            }
 
149
 
 
150
            // Check whether there are mixers in different drivers, so that the user can be warned
 
151
            if ( !multipleDriversActive )
 
152
            {
 
153
               if ( driverWithMixer == -1 )
 
154
               {
 
155
                  // Aha, this is the very first detected device
 
156
                  driverWithMixer = drv;
 
157
               }
 
158
               else if ( driverWithMixer != drv )
 
159
               {
 
160
                   // Got him: There are mixers in different drivers
 
161
                   multipleDriversActive = true;
 
162
               }
 
163
            } //  !multipleDriversActive
 
164
         } // mixerAccepted
 
165
      
 
166
      } // loop over sound card devices of current driver
 
167
 
 
168
      if (autodetectionFinished) {
 
169
         break;
 
170
      }
 
171
   } // loop over soundcard drivers
 
172
 
 
173
   
 
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);
 
182
      }
 
183
   }
 
184
   else {
 
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);
 
190
   }
 
191
 
 
192
 
 
193
 
 
194
   if ( Mixer::mixers().count() == 0 )
 
195
   {
 
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);
 
199
   }
 
200
 
 
201
   ref_hwInfoString = i18n("Sound drivers supported:");
 
202
   ref_hwInfoString.append(" ").append( driverInfo ).append(    "\n").append(i18n("Sound drivers used:")) .append(" ").append(driverInfoUsed);
 
203
 
 
204
   if ( multipleDriversActive )
 
205
   {
 
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);
 
210
   }
 
211
   else {
 
212
       KMixDeviceManager::instance()->setHotpluggingBackends(driverInfoUsed);
 
213
   }
 
214
 
 
215
   kDebug(67100) << ref_hwInfoString << endl << "Total number of detected Mixers: " << Mixer::mixers().count();
 
216
   //kDebug(67100) << "OUT MixerToolBox::initMixer()";
 
217
 
 
218
}
 
219
 
 
220
bool MixerToolBox::possiblyAddMixer(Mixer *mixer) 
 
221
{
 
222
    if ( mixer->openIfValid() )
 
223
    {
 
224
        if ( (!s_ignoreMixerExpression.isEmpty()) && mixer->id().contains(s_ignoreMixerExpression) ) {
 
225
            // This Mixer should be ignored (default expression is "Modem").
 
226
            delete mixer;
 
227
            mixer = 0;
 
228
            return false;
 
229
        }
 
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()]);
 
235
 
 
236
        Mixer::mixers().append( mixer );
 
237
        kDebug(67100) << "Added card " << mixer->id();
 
238
    
 
239
 
 
240
        emit mixerAdded(mixer->id());
 
241
        return true;
 
242
    } // valid
 
243
    else
 
244
    {
 
245
        delete mixer;
 
246
        mixer = 0;
 
247
        return false;
 
248
    } // invalid
 
249
}
 
250
 
 
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)
 
254
{
 
255
    s_ignoreMixerExpression.setPattern(ignoreExpr);
 
256
}
 
257
 
 
258
QString MixerToolBox::mixerIgnoreExpression() const 
 
259
{
 
260
     return s_ignoreMixerExpression.pattern( );
 
261
}
 
262
 
 
263
void MixerToolBox::removeMixer(Mixer *par_mixer)
 
264
{
 
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);
 
271
            delete mixer;
 
272
        }
 
273
    }
 
274
}
 
275
 
 
276
 
 
277
 
 
278
/*
 
279
 * Clean up and free all resources of all found Mixers, which were found in the initMixer() call
 
280
 */
 
281
void MixerToolBox::deinitMixer()
 
282
{
 
283
   //kDebug(67100) << "IN MixerToolBox::deinitMixer()";
 
284
 
 
285
   int mixerCount = Mixer::mixers().count();
 
286
   for ( int i=0; i<mixerCount; ++i)
 
287
   {
 
288
      Mixer* mixer = (Mixer::mixers())[i];
 
289
      //kDebug(67100) << "MixerToolBox::deinitMixer() Remove Mixer";
 
290
      mixer->close();
 
291
      delete mixer;
 
292
   }
 
293
   Mixer::mixers().clear();
 
294
   // kDebug(67100) << "OUT MixerToolBox::deinitMixer()";
 
295
}
 
296
 
 
297
 
 
298
/*
 
299
KLocale* MixerToolBox::whatsthisControlLocale()
 
300
{
 
301
   if ( s_whatsthisLocale == 0 ) {
 
302
          s_whatsthisLocale = new KLocale("kmix-controls");
 
303
   }
 
304
   return s_whatsthisLocale;
 
305
}
 
306
*/
 
307
 
 
308
 
 
309
#include "mixertoolbox.moc"