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

« back to all changes in this revision

Viewing changes to kmix/core/mixer.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) 1996-2004 Christian Esken - esken@kde.org
 
6
 *                    2002 Helio Chissini de Castro - helio@conectiva.com.br
 
7
 *
 
8
 * This program is free software; you can redistribute it and/or
 
9
 * modify it under the terms of the GNU Library General Public
 
10
 * License as published by the Free Software Foundation; either
 
11
 * version 2 of the License, or (at your option) any later version.
 
12
 *
 
13
 * This program is distributed in the hope that it will be useful,
 
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
16
 * Library General Public License for more details.
 
17
 *
 
18
 * You should have received a copy of the GNU Library General Public
 
19
 * License along with this program; if not, write to the Free
 
20
 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
21
 */
 
22
 
 
23
 
 
24
#include <klocale.h>
 
25
#include <kconfig.h>
 
26
#include <kglobal.h>
 
27
#include <kdebug.h>
 
28
 
 
29
#include "core/mixer.h"
 
30
#include "backends/mixer_backend.h"
 
31
#include "backends/kmix-backends.cpp"
 
32
#include "core/volume.h"
 
33
#include "kmixadaptor.h"
 
34
 
 
35
/**
 
36
 * Some general design hints. Hierachy is Mixer->MixDevice->Volume
 
37
 */
 
38
 
 
39
QList<Mixer *> Mixer::s_mixers;
 
40
QString Mixer::_globalMasterCard;
 
41
QString Mixer::_globalMasterCardDevice;
 
42
 
 
43
 
 
44
int Mixer::numDrivers()
 
45
{
 
46
    MixerFactory *factory = g_mixerFactories;
 
47
    int num = 0;
 
48
    while( factory->getMixer!=0 )
 
49
    {
 
50
        num++;
 
51
        factory++;
 
52
    }
 
53
 
 
54
    return num;
 
55
}
 
56
 
 
57
/*
 
58
 * Returns a reference of the current mixer list.
 
59
 */
 
60
QList<Mixer *>& Mixer::mixers()
 
61
{
 
62
    return s_mixers;
 
63
}
 
64
 
 
65
Mixer::Mixer( QString& ref_driverName, int device )
 
66
    : m_balance(0), _mixerBackend(0L), m_dynamic(false)
 
67
{
 
68
   (void)new KMixAdaptor(this);
 
69
    _cardInstance = 0;
 
70
    _mixerBackend = 0;
 
71
    int driverCount = numDrivers();
 
72
    for (int driver=0; driver<driverCount; driver++ ) {
 
73
        QString driverName = Mixer::driverName(driver);
 
74
        if ( driverName == ref_driverName ) {
 
75
            // driver found => retrieve Mixer factory for that driver
 
76
            getMixerFunc *f = g_mixerFactories[driver].getMixer;
 
77
            if( f!=0 ) {
 
78
                _mixerBackend = f( this, device );
 
79
                readSetFromHWforceUpdate();  // enforce an initial update on first readSetFromHW()
 
80
            }
 
81
            break;
 
82
        }
 
83
    }
 
84
}
 
85
 
 
86
 
 
87
 
 
88
Mixer::~Mixer() {
 
89
   // Close the mixer. This might also free memory, depending on the called backend method
 
90
    if ( ! m_dbusName.isEmpty() ) {
 
91
        kDebug(67100) << "Auto-unregistering DBUS object " << m_dbusName;
 
92
    //QDBusConnection::sessionBus().unregisterObject(m_dbusName);
 
93
   }
 
94
   close();
 
95
   delete _mixerBackend;
 
96
}
 
97
 
 
98
 
 
99
/*
 
100
 * Find a Mixer. If there is no mixer with the given id, 0 is returned
 
101
 */
 
102
Mixer* Mixer::findMixer( const QString& mixer_id)
 
103
{
 
104
    Mixer *mixer = 0;
 
105
    int mixerCount = Mixer::mixers().count();
 
106
    for ( int i=0; i<mixerCount; ++i)
 
107
    {
 
108
        if ( ((Mixer::mixers())[i])->id() == mixer_id )
 
109
        {
 
110
            mixer = (Mixer::mixers())[i];
 
111
            break;
 
112
        }
 
113
    }
 
114
    return mixer;
 
115
}
 
116
 
 
117
 
 
118
/**
 
119
 * Set the card instance. Usually this will be 1, but if there is
 
120
 * more than one card with the same name install, then you need
 
121
 * to use 2, 3, ...
 
122
 */
 
123
void Mixer::setCardInstance(int cardInstance)
 
124
{
 
125
    _cardInstance = cardInstance;
 
126
    recreateId();
 
127
}
 
128
 
 
129
void Mixer::recreateId()
 
130
{
 
131
    /* As we use "::" and ":" as separators, the parts %1,%2 and %3 may not
 
132
     * contain it.
 
133
     * %1, the driver name is from the KMix backends, it does not contain colons.
 
134
     * %2, the mixer name, is typically coming from an OS driver. It could contain colons.
 
135
     * %3, the mixer number, is a number: it does not contain colons.
 
136
     */
 
137
    QString mixerName = getBaseName();
 
138
    mixerName.replace(":","_");
 
139
    QString primaryKeyOfMixer = QString("%1::%2:%3")
 
140
            .arg(getDriverName())
 
141
            .arg(mixerName)
 
142
            .arg(_cardInstance);
 
143
    // The following 3 replaces are for not messing up the config file
 
144
    primaryKeyOfMixer.replace("]","_");
 
145
    primaryKeyOfMixer.replace("[","_"); // not strictly necessary, but lets play safe
 
146
    primaryKeyOfMixer.replace(" ","_");
 
147
    primaryKeyOfMixer.replace("=","_");
 
148
    _id = primaryKeyOfMixer;
 
149
}
 
150
 
 
151
 
 
152
 
 
153
 
 
154
void Mixer::volumeSave( KConfig *config )
 
155
{
 
156
    //    kDebug(67100) << "Mixer::volumeSave()";
 
157
    _mixerBackend->readSetFromHW();
 
158
    QString grp("Mixer");
 
159
    grp.append(id());
 
160
    _mixerBackend->m_mixDevices.write( config, grp );
 
161
}
 
162
 
 
163
void Mixer::volumeLoad( KConfig *config )
 
164
{
 
165
   QString grp("Mixer");
 
166
   grp.append(id());
 
167
   if ( ! config->hasGroup(grp) ) {
 
168
      // no such group. Volumes (of this mixer) were never saved beforehand.
 
169
      // Thus don't restore anything (also see Bug #69320 for understanding the real reason)
 
170
      return; // make sure to bail out immediately
 
171
   }
 
172
 
 
173
   // else restore the volumes
 
174
   _mixerBackend->m_mixDevices.read( config, grp );
 
175
 
 
176
   // set new settings
 
177
   //QListIterator<MixDevice*> it( _mixerBackend->m_mixDevices );
 
178
   for(int i=0; i<_mixerBackend->m_mixDevices.count() ; i++ )
 
179
   {
 
180
       MixDevice *md = _mixerBackend->m_mixDevices[i];
 
181
       _mixerBackend->setRecsrcHW( md->id(), md->isRecSource() );
 
182
       _mixerBackend->writeVolumeToHW( md->id(), md );
 
183
       if ( md->isEnum() ) _mixerBackend->setEnumIdHW( md->id(), md->enumId() );
 
184
   }
 
185
}
 
186
 
 
187
 
 
188
/**
 
189
 * Opens the mixer.
 
190
 * Also, starts the polling timer, for polling the Volumes from the Mixer.
 
191
 *
 
192
 * @return 0, if OK. An Mixer::ERR_ error code otherwise
 
193
 */
 
194
bool Mixer::openIfValid() {
 
195
    bool ok = _mixerBackend->openIfValid();
 
196
    if ( ok ) {
 
197
        recreateId(); // Fallback call. Actually recreateId() is supposed to be called later again, via setCardInstance()
 
198
        MixDevice* recommendedMaster = _mixerBackend->recommendedMaster();
 
199
        if ( recommendedMaster != 0 ) {
 
200
            QString recommendedMasterStr = recommendedMaster->id();
 
201
            setLocalMasterMD( recommendedMasterStr );
 
202
            kDebug() << "Mixer::open() detected master: " << recommendedMaster->id();
 
203
        }
 
204
        else {
 
205
            if ( !m_dynamic )
 
206
                kError(67100) << "Mixer::open() no master detected." << endl;
 
207
            QString noMaster = "---no-master-detected---";
 
208
            setLocalMasterMD(noMaster); // no master
 
209
        }
 
210
        connect( _mixerBackend, SIGNAL(controlChanged()), SLOT(controlChangedForwarder()) );
 
211
        connect( _mixerBackend, SIGNAL(controlsReconfigured(const QString&)), SLOT(controlsReconfiguredForwarder(const QString&)) );
 
212
        
 
213
        m_dbusName = "/Mixer" + QString::number(_mixerBackend->m_devnum);
 
214
        kDebug() << "Registering DBUS object " << m_dbusName;
 
215
        bool regResult = QDBusConnection::sessionBus().registerObject(m_dbusName, this);
 
216
        kDebug() << "Registering DBUS object " << m_dbusName << " returns " << regResult;
 
217
    }
 
218
 
 
219
    return ok;
 
220
}
 
221
 
 
222
void Mixer::controlChangedForwarder()
 
223
{
 
224
    emit controlChanged();
 
225
}
 
226
 
 
227
void Mixer::controlsReconfiguredForwarder( const QString& mixer_ID )
 
228
{
 
229
    emit controlsReconfigured(mixer_ID);
 
230
}
 
231
 
 
232
/**
 
233
 * Closes the mixer.
 
234
 * Also, stops the polling timer.
 
235
 *
 
236
 * @return 0 (always)
 
237
 */
 
238
int Mixer::close()
 
239
{
 
240
  return _mixerBackend->close();
 
241
}
 
242
 
 
243
 
 
244
/* ------- WRAPPER METHODS. START ------------------------------ */
 
245
unsigned int Mixer::size() const
 
246
{
 
247
  return _mixerBackend->m_mixDevices.count();
 
248
}
 
249
 
 
250
MixDevice* Mixer::operator[](int num)
 
251
{
 
252
  MixDevice* md =  _mixerBackend->m_mixDevices.at( num );
 
253
  Q_ASSERT( md );
 
254
  return md;
 
255
}
 
256
 
 
257
MixSet Mixer::getMixSet()
 
258
{
 
259
  return _mixerBackend->m_mixDevices;
 
260
}
 
261
 
 
262
 
 
263
/**
 
264
 * Returns the driver name, that handles this Mixer.
 
265
 */
 
266
QString Mixer::getDriverName()
 
267
{
 
268
  QString driverName = _mixerBackend->getDriverName();
 
269
//  kDebug(67100) << "Mixer::getDriverName() = " << driverName << "\n";
 
270
  return driverName;
 
271
}
 
272
 
 
273
bool Mixer::isOpen() const {
 
274
    if ( _mixerBackend == 0 )
 
275
        return false;
 
276
    else
 
277
        return _mixerBackend->isOpen();
 
278
}
 
279
 
 
280
void Mixer::readSetFromHWforceUpdate() const {
 
281
   _mixerBackend->readSetFromHWforceUpdate();
 
282
}
 
283
 
 
284
  /// Returns translated WhatsThis messages for a control.Translates from 
 
285
QString Mixer::translateKernelToWhatsthis(const QString &kernelName)
 
286
{
 
287
   return _mixerBackend->translateKernelToWhatsthis(kernelName);
 
288
}
 
289
 
 
290
/* ------- WRAPPER METHODS. END -------------------------------- */
 
291
 
 
292
 
 
293
 
 
294
 
 
295
void Mixer::setBalance(int balance)
 
296
{
 
297
   if( balance == m_balance ) {
 
298
      // balance unchanged => return
 
299
      return;
 
300
   }
 
301
 
 
302
   m_balance = balance;
 
303
 
 
304
   MixDevice* master = getLocalMasterMD();
 
305
   if ( master == 0 ) {
 
306
      // no master device available => return
 
307
      return;
 
308
   }
 
309
 
 
310
   Volume& volP = master->playbackVolume();
 
311
   setBalanceInternal(volP);
 
312
   Volume& volC = master->captureVolume();
 
313
   setBalanceInternal(volC);
 
314
 
 
315
   _mixerBackend->writeVolumeToHW( master->id(), master );
 
316
   emit newBalance( volP );
 
317
}
 
318
 
 
319
void Mixer::setBalanceInternal(Volume& vol)
 
320
{
 
321
   //_mixerBackend->readVolumeFromHW( master->id(), master );
 
322
 
 
323
   int left = vol[ Volume::LEFT ];
 
324
   int right = vol[ Volume::RIGHT ];
 
325
   int refvol = left > right ? left : right;
 
326
   if( m_balance < 0 ) // balance left
 
327
   {
 
328
      vol.setVolume( Volume::LEFT,  refvol);
 
329
      vol.setVolume( Volume::RIGHT, (m_balance * refvol) / 100 + refvol );
 
330
   }
 
331
   else
 
332
   {
 
333
      vol.setVolume( Volume::LEFT, -(m_balance * refvol) / 100 + refvol );
 
334
      vol.setVolume( Volume::RIGHT,  refvol);
 
335
   }
 
336
}
 
337
 
 
338
// should return a name suitable for a human user to read (on a label, ...)
 
339
QString Mixer::readableName()
 
340
{
 
341
  if ( _mixerBackend->m_mixerName.endsWith(":0"))
 
342
     return _mixerBackend->m_mixerName.left(_mixerBackend->m_mixerName.length() - 2);
 
343
  else
 
344
     return _mixerBackend->m_mixerName;
 
345
}
 
346
 
 
347
 
 
348
QString Mixer::getBaseName()
 
349
{
 
350
  return _mixerBackend->m_mixerName;
 
351
}
 
352
 
 
353
/**
 
354
 * Queries the Driver Factory for a driver.
 
355
 * @par driver Index number. 0 <= driver < numDrivers()
 
356
 */
 
357
QString Mixer::driverName( int driver )
 
358
{
 
359
    getDriverNameFunc *f = g_mixerFactories[driver].getDriverName;
 
360
    if( f!=0 )
 
361
        return f();
 
362
    else
 
363
        return "unknown";
 
364
}
 
365
 
 
366
/* obsoleted by setInstance()
 
367
void Mixer::setID(QString& ref_id)
 
368
{
 
369
  _id = ref_id;
 
370
}
 
371
*/
 
372
 
 
373
QString& Mixer::id()
 
374
{
 
375
  return _id;
 
376
}
 
377
 
 
378
QString& Mixer::udi(){
 
379
    return _mixerBackend->udi();
 
380
}
 
381
void Mixer::setGlobalMaster(QString& ref_card, QString& ref_control)
 
382
{
 
383
  // The value is taken over without checking on existence. This allows the User to define
 
384
  // a MasterCard that is not always available (e.g. it is an USB hotplugging device).
 
385
  // Also you can set the master at any time you like, e.g. after reading the KMix configuration file
 
386
  // and before actually constructing the Mixer instances (hint: this mehtod is static!).
 
387
  _globalMasterCard       = ref_card;
 
388
  _globalMasterCardDevice = ref_control;
 
389
  kDebug() << "Mixer::setGlobalMaster() card=" <<ref_card<< " control=" << ref_control;
 
390
}
 
391
 
 
392
Mixer* Mixer::getGlobalMasterMixerNoFalback()
 
393
{
 
394
   Mixer *mixer = 0;
 
395
   if(Mixer::mixers().count() == 0)
 
396
      return mixer;
 
397
 
 
398
   for (int i=0; i< Mixer::mixers().count(); ++i )
 
399
   {
 
400
      Mixer* mixerTmp = Mixer::mixers()[i];
 
401
      if ( mixerTmp != 0 && mixerTmp->id() == _globalMasterCard ) {
 
402
         //kDebug() << "Mixer::masterCard() found " << _globalMasterCard;
 
403
         mixer = mixerTmp;
 
404
         break;
 
405
      }
 
406
   }
 
407
   return mixer;
 
408
}
 
409
 
 
410
Mixer* Mixer::getGlobalMasterMixer()
 
411
{
 
412
   Mixer *mixer = getGlobalMasterMixerNoFalback();
 
413
   if ( mixer == 0 && Mixer::mixers().count() > 0 ) {
 
414
      // produce fallback
 
415
      mixer = Mixer::mixers()[0];
 
416
      _globalMasterCard = mixer->id();
 
417
      kDebug() << "Mixer::masterCard() fallback to  " << _globalMasterCard;
 
418
   }
 
419
   //kDebug() << "Mixer::masterCard() returns " << mixer->id();
 
420
   return mixer;
 
421
}
 
422
 
 
423
MixDevice* Mixer::getGlobalMasterMD()
 
424
{
 
425
   return getGlobalMasterMD(true);
 
426
}
 
427
 
 
428
MixDevice* Mixer::getGlobalMasterMD(bool fallbackAllowed)
 
429
{
 
430
   MixDevice* md = 0;
 
431
   Mixer *mixer;
 
432
   if ( fallbackAllowed)
 
433
      mixer = Mixer::getGlobalMasterMixer();
 
434
   else
 
435
      mixer = Mixer::getGlobalMasterMixerNoFalback();
 
436
   if ( mixer != 0 ) {
 
437
      for(int i=0; i < mixer->_mixerBackend->m_mixDevices.count() ; i++ )
 
438
      {
 
439
         md = mixer->_mixerBackend->m_mixDevices[i];
 
440
         if ( md->id() == _globalMasterCardDevice ) {
 
441
            //kDebug() << "Mixer::masterCardDevice() found " << _globalMasterCardDevice;
 
442
            break;
 
443
         }
 
444
      }
 
445
   }
 
446
   if ( ! md ) 
 
447
        kDebug() << "Mixer::masterCardDevice() returns 0 (no globalMaster)";
 
448
   return md;
 
449
}
 
450
 
 
451
 
 
452
 
 
453
 
 
454
MixDevice* Mixer::getLocalMasterMD()
 
455
{
 
456
  return find( _masterDevicePK );
 
457
}
 
458
 
 
459
void Mixer::setLocalMasterMD(QString &devPK)
 
460
{
 
461
    _masterDevicePK = devPK;
 
462
}
 
463
 
 
464
 
 
465
 
 
466
/**
 
467
   Used internally by KMix and as DBUS method
 
468
*/
 
469
void Mixer::setRecordSource( const QString& mixdeviceID, bool on )
 
470
{
 
471
   _mixerBackend->setRecsrcHW( mixdeviceID, on );
 
472
}
 
473
 
 
474
 
 
475
 
 
476
 
 
477
 
 
478
MixDevice* Mixer::find(const QString& mixdeviceID)
 
479
{
 
480
   MixDevice *md = 0;
 
481
   for(int i=0; i<_mixerBackend->m_mixDevices.count() ; i++ )
 
482
   {
 
483
       md = _mixerBackend->m_mixDevices[i];
 
484
       if( mixdeviceID == md->id() ) {
 
485
           break;
 
486
       }
 
487
    }
 
488
    return md;
 
489
}
 
490
 
 
491
 
 
492
MixDevice* Mixer::getMixdeviceById( const QString& mixdeviceID )
 
493
{
 
494
   MixDevice* md = 0;
 
495
   int num = _mixerBackend->id2num(mixdeviceID);
 
496
   if ( num!=-1 && num < (int)size() ) {
 
497
      md = (*this)[num];
 
498
   }
 
499
   return md;
 
500
}
 
501
 
 
502
// @dcop
 
503
// Used also by the setMasterVolume() method.
 
504
void Mixer::setVolume( const QString& mixdeviceID, int percentage )
 
505
{
 
506
    MixDevice *md = getMixdeviceById( mixdeviceID );
 
507
    if (!md) return;
 
508
 
 
509
    Volume& volP = md->playbackVolume();
 
510
    Volume& volC = md->captureVolume();
 
511
 
 
512
    // @todo The next call doesn't handle negative volumes correctly.
 
513
    volP.setAllVolumes( (percentage*volP.maxVolume())/100 );
 
514
    volC.setAllVolumes( (percentage*volC.maxVolume())/100 );
 
515
    _mixerBackend->writeVolumeToHW(mixdeviceID, md);
 
516
}
 
517
 
 
518
/**
 
519
   Call this if you have a *reference* to a Volume object and have modified that locally.
 
520
   Pass the MixDevice associated to that Volume to this method for writing back
 
521
   the changed value to the mixer.
 
522
   Hint: Why do we do it this way?
 
523
   - It is fast               (no copying of Volume objects required)
 
524
   - It is easy to understand ( read - modify - commit )
 
525
*/
 
526
void Mixer::commitVolumeChange( MixDevice* md ) {
 
527
  _mixerBackend->writeVolumeToHW(md->id(), md );
 
528
   if (md->isEnum()) _mixerBackend->setEnumIdHW(md->id(), md->enumId() );
 
529
   if ( md->captureVolume().hasSwitch() ) {
 
530
      // Make sure to re-read the hardware, because seting capture might have failed.
 
531
      // This is due to exclusive capture groups.
 
532
      // If we wouldn't do this, KMix might show a Capture Switch disabled, but
 
533
      // in reality the capture switch is still on.
 
534
      //
 
535
      // We also cannot rely on a notification from the driver (SocketNotifier), because
 
536
      // nothing has changed, and so there s nothing to notify.
 
537
      _mixerBackend->readSetFromHWforceUpdate();
 
538
      _mixerBackend->readSetFromHW();
 
539
   }
 
540
}
 
541
 
 
542
// @dcop only
 
543
void Mixer::setMasterVolume( int percentage )
 
544
{
 
545
  MixDevice *master = getLocalMasterMD();
 
546
  if (master != 0 ) {
 
547
    setVolume( master->id(), percentage );
 
548
  }
 
549
}
 
550
 
 
551
// @dcop
 
552
int Mixer::volume( const QString& mixdeviceID )
 
553
{
 
554
  MixDevice *md= getMixdeviceById( mixdeviceID );
 
555
  if (!md) return 0;
 
556
 
 
557
  Volume vol=md->playbackVolume();  // @todo Is hardcoded to PlaybackVolume
 
558
  // @todo This will not work, if minVolume != 0      !!!
 
559
  //       e.g.: minVolume=5 or minVolume=-10
 
560
  // The solution is to check two cases:
 
561
  //     volume < 0 => use minVolume for volumeRange
 
562
  //     volume > 0 => use maxVolume for volumeRange
 
563
  //     If chosen volumeRange==0 => return 0
 
564
  // As this is potentially used often (Sliders, ...), it
 
565
  // should be implemented in the Volume class.
 
566
 
 
567
  // For now we go with "maxVolume()", like in the rest of KMix.
 
568
  long volumeRange = vol.maxVolume(); // -vol.minVolume() ;
 
569
  if ( volumeRange == 0 )
 
570
  {
 
571
    return 0;
 
572
  }
 
573
  else
 
574
  {
 
575
     return ( vol.getVolume( Volume::LEFT )*100) / volumeRange ;
 
576
  }
 
577
}
 
578
 
 
579
// @dcop , especially for use in KMilo
 
580
void Mixer::setAbsoluteVolume( const QString& mixdeviceID, long absoluteVolume ) {
 
581
    MixDevice *md= getMixdeviceById( mixdeviceID );
 
582
    if (!md) return;
 
583
 
 
584
    Volume& volP=md->playbackVolume();
 
585
    Volume& volC=md->captureVolume();
 
586
    volP.setAllVolumes( absoluteVolume );
 
587
    volC.setAllVolumes( absoluteVolume );
 
588
    _mixerBackend->writeVolumeToHW(mixdeviceID, md);
 
589
}
 
590
 
 
591
// @dcop , especially for use in KMilo
 
592
long Mixer::absoluteVolume( const QString& mixdeviceID )
 
593
{
 
594
    MixDevice *md = getMixdeviceById( mixdeviceID );
 
595
    if (!md) return 0;
 
596
 
 
597
    Volume& volP=md->playbackVolume();  // @todo Is hardcoded to PlaybackVolume
 
598
    long avgVolume=volP.getAvgVolume((Volume::ChannelMask)(Volume::MLEFT | Volume::MRIGHT));
 
599
    return avgVolume;
 
600
}
 
601
 
 
602
// @dcop , especially for use in KMilo
 
603
long Mixer::absoluteVolumeMax( const QString& mixdeviceID )
 
604
{
 
605
   MixDevice *md= getMixdeviceById( mixdeviceID );
 
606
   if (!md) return 0;
 
607
 
 
608
   Volume vol=md->playbackVolume();  // @todo Is hardcoded to PlaybackVolume
 
609
   long maxVolume=vol.maxVolume();
 
610
   return maxVolume;
 
611
}
 
612
 
 
613
// @dcop , especially for use in KMilo
 
614
long Mixer::absoluteVolumeMin( const QString& mixdeviceID )
 
615
{
 
616
   MixDevice *md= getMixdeviceById( mixdeviceID );
 
617
   if (!md) return 0;
 
618
 
 
619
   Volume vol=md->playbackVolume();  // @todo Is hardcoded to PlaybackVolume
 
620
   long minVolume=vol.minVolume();
 
621
   return minVolume;
 
622
}
 
623
 
 
624
// @dcop
 
625
int Mixer::masterVolume()
 
626
{
 
627
  int vol = 0;
 
628
  MixDevice *master = getLocalMasterMD();
 
629
  if (master != 0 ) {
 
630
    vol = volume( master->id() );
 
631
  }
 
632
  return vol;
 
633
}
 
634
 
 
635
// @dbus
 
636
QString Mixer::masterDeviceIndex()
 
637
{
 
638
  MixDevice *master = getLocalMasterMD();
 
639
  return master ? master->id() : QString();
 
640
}
 
641
 
 
642
 
 
643
// @dcop
 
644
void Mixer::increaseVolume( const QString& mixdeviceID )
 
645
{
 
646
    MixDevice *md= getMixdeviceById( mixdeviceID );
 
647
    if (md != 0) {
 
648
        Volume& volP=md->playbackVolume();
 
649
        if ( volP.hasVolume() ) {
 
650
           double step = (volP.maxVolume()-volP.minVolume()+1) / 20;
 
651
           if ( step < 1 ) step = 1;
 
652
           volP.changeAllVolumes(step);
 
653
        }
 
654
        
 
655
        Volume& volC=md->captureVolume();
 
656
        if ( volC.hasVolume() ) {
 
657
           double step = (volC.maxVolume()-volC.minVolume()+1) / 20;
 
658
           if ( step < 1 ) step = 1;
 
659
           volC.changeAllVolumes(step);
 
660
        }
 
661
 
 
662
        _mixerBackend->writeVolumeToHW(mixdeviceID, md);
 
663
    }
 
664
 
 
665
  /* see comment at the end of decreaseVolume()
 
666
  int vol=volume(mixdeviceID);
 
667
  setVolume(mixdeviceID, vol+5);
 
668
  */
 
669
}
 
670
 
 
671
// @dcop
 
672
void Mixer::decreaseVolume( const QString& mixdeviceID )
 
673
{
 
674
    MixDevice *md= getMixdeviceById( mixdeviceID );
 
675
    if (md != 0) {
 
676
        Volume& volP=md->playbackVolume();
 
677
        if ( volP.hasVolume() ) {
 
678
           double step = (volP.maxVolume()-volP.minVolume()+1) / 20;
 
679
           if ( step < 1 ) step = 1;
 
680
           volP.changeAllVolumes(-step);
 
681
        }
 
682
        
 
683
        Volume& volC=md->captureVolume();
 
684
        if ( volC.hasVolume() ) {
 
685
           double step = (volC.maxVolume()-volC.minVolume()+1) / 20;
 
686
           if ( step < 1 ) step = 1;
 
687
           volC.changeAllVolumes(-step);
 
688
        }
 
689
    }
 
690
 
 
691
    _mixerBackend->writeVolumeToHW(mixdeviceID, md);
 
692
 
 
693
    /************************************************************
 
694
        It is important, not to implement this method like this:
 
695
    int vol=volume(mixdeviceID);
 
696
    setVolume(mixdeviceID, vol-5);
 
697
        It creates too big rounding errors. If you don't beleive me, then
 
698
        do a decreaseVolume() and increaseVolume() with "vol.maxVolume() == 31".
 
699
    ***********************************************************/
 
700
}
 
701
 
 
702
// @dcop
 
703
void Mixer::setMute( const QString& mixdeviceID, bool on )
 
704
{
 
705
  MixDevice *md= getMixdeviceById( mixdeviceID );
 
706
  if (!md) return;
 
707
 
 
708
  md->setMuted( on );
 
709
 
 
710
     _mixerBackend->writeVolumeToHW(mixdeviceID, md);
 
711
}
 
712
 
 
713
// @dcop
 
714
void Mixer::toggleMute( const QString& mixdeviceID )
 
715
{
 
716
    MixDevice *md= getMixdeviceById( mixdeviceID );
 
717
    if (!md) return;
 
718
 
 
719
    md->setMuted( ! md->isMuted() );
 
720
    _mixerBackend->writeVolumeToHW(mixdeviceID, md);
 
721
}
 
722
 
 
723
// @dcop
 
724
bool Mixer::mute( const QString& mixdeviceID )
 
725
{
 
726
  MixDevice *md= getMixdeviceById( mixdeviceID );
 
727
  if (!md) return true;
 
728
 
 
729
  return md->isMuted();
 
730
}
 
731
 
 
732
bool Mixer::isRecordSource( const QString& mixdeviceID )
 
733
{
 
734
  MixDevice *md= getMixdeviceById( mixdeviceID );
 
735
  if (!md) return false;
 
736
 
 
737
  return md->isRecSource();
 
738
}
 
739
 
 
740
/// @DCOP    WHAT DOES THIS METHOD?!?!?
 
741
bool Mixer::isAvailableDevice( const QString& mixdeviceID )
 
742
{
 
743
  return getMixdeviceById( mixdeviceID );
 
744
}
 
745
 
 
746
void Mixer::setDynamic ( bool dynamic )
 
747
{
 
748
    m_dynamic = dynamic;
 
749
}
 
750
 
 
751
bool Mixer::isDynamic()
 
752
{
 
753
    return m_dynamic;
 
754
}
 
755
 
 
756
bool Mixer::moveStream( const QString id, const QString& destId )
 
757
{
 
758
    // We should really check that id is within our md's....
 
759
    return _mixerBackend->moveStream( id, destId );
 
760
}
 
761
 
 
762
#include "mixer.moc"