2 * KMix -- KDE's full featured mini mixer
5 * Copyright (C) 1996-2000 Christian Esken <esken@kde.org>
6 * 2000 Brian Hanson <bhanson@hotmail.com>
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.
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.
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.
23 #include <sys/types.h>
27 #include <sys/audioio.h>
32 #include "mixer_sun.h"
35 //======================================================================
36 // CONSTANT/ENUM DEFINITIONS
37 //======================================================================
40 // Mixer Device Numbers
42 // Note: We can't just use the Sun port #defines because :
43 // 1) Some logical devices don't correspond to ports (master&recmon)
44 // 2) The play and record port definitions reuse the same values
48 MIXERDEV_MASTER_VOLUME
,
49 MIXERDEV_INTERNAL_SPEAKER
,
52 MIXERDEV_RECORD_MONITOR
,
56 // Insert new devices before this marker
59 const int numDevs
= MIXERDEV_END_MARKER
;
62 // Device name strings
64 const char* MixerDevNames
[] =
66 I18N_NOOP("Master Volume"),
67 I18N_NOOP("Internal Speaker"),
68 I18N_NOOP("Headphone"),
69 I18N_NOOP("Line Out"),
70 I18N_NOOP("Record Monitor"),
71 I18N_NOOP("Microphone"),
77 // Channel types (this specifies which icon to display)
79 const MixDevice::ChannelType MixerChannelTypes
[] =
81 MixDevice::VOLUME
, // MASTER_VOLUME
82 MixDevice::AUDIO
, // INTERNAL_SPEAKER
83 MixDevice::EXTERNAL
, // HEADPHONE (we really need an icon for this)
84 MixDevice::EXTERNAL
, // LINE_OUT
85 MixDevice::RECMONITOR
, // RECORD_MONITOR
86 MixDevice::MICROPHONE
, // MICROPHONE
87 MixDevice::EXTERNAL
, // LINE_IN
92 // Mapping from device numbers to Sun port mask values
94 const uint_t MixerSunPortMasks
[] =
96 0, // MASTER_VOLUME - no associated port
100 0, // RECORD_MONITOR - no associated port
107 //======================================================================
108 // FUNCTION/METHOD DEFINITIONS
109 //======================================================================
112 //======================================================================
113 // FUNCTION : SUN_getMixer
114 // DESCRIPTION : Creates and returns a new mixer object.
115 //======================================================================
116 Mixer_Backend
* SUN_getMixer( Mixer
*mixer
, int devnum
)
118 Mixer_Backend
*l_mixer
;
119 l_mixer
= new Mixer_SUN( mixer
, devnum
);
124 //======================================================================
125 // FUNCTION : Mixer::Mixer
126 // DESCRIPTION : Class constructor.
127 //======================================================================
128 Mixer_SUN::Mixer_SUN(int devnum
) : Mixer_Backend(mixer
, devnum
)
134 //======================================================================
135 // FUNCTION : Mixer::Mixer
136 // DESCRIPTION : Class destructor.
137 //======================================================================
138 Mixer_SUN::~Mixer_SUN()
143 //======================================================================
144 // FUNCTION : Mixer::open
145 // DESCRIPTION : Initialize the mixer and open the hardware driver.
146 //======================================================================
147 int Mixer_SUN::open()
150 // We don't support multiple devices
153 return Mixer::ERR_OPEN
;
156 // Open the mixer hardware driver
158 QCString
audiodev(getenv("AUDIODEV"));
159 if(audiodev
.isNull())
160 audiodev
= "/dev/audio";
162 _udi
= audiodev
; // use device name as UDI. Doesn't matter as we only use it for hotplugging/unplugging.
163 if ( ( fd
= ::open( audiodev
.data(), O_RDWR
) ) < 0 )
165 if ( errno
== EACCES
)
166 return Mixer::ERR_PERM
;
168 return Mixer::ERR_OPEN
;
173 // Mixer is open. Now define all of the mix devices.
176 for ( int idx
= 0; idx
< numDevs
; idx
++ )
178 Volume
vol( 2, AUDIO_MAX_GAIN
);
181 MixDevice
* md
= new MixDevice( _mixer
, id
,
182 QString(MixerDevNames
[idx
]), MixerChannelTypes
[idx
]);
183 md
->addPlaybackVolume(vol
);
184 md
->setRecSource( isRecsrcHW( idx
) );
185 m_mixDevices
.append( md
);
188 m_mixerName
= "SUN Audio Mixer";
195 //======================================================================
196 // FUNCTION : Mixer::close
197 // DESCRIPTION : Close the hardware driver.
198 //======================================================================
199 int Mixer_SUN::close()
201 _pollingTimer
->stop();
203 int l_i_ret
= ::close( fd
);
204 m_mixDevices
.clear();
208 //======================================================================
209 // FUNCTION : Mixer::errorText
210 // DESCRIPTION : Convert an error code enum to a text string.
211 //======================================================================
212 QString
Mixer_SUN::errorText( int mixer_error
)
217 case Mixer::ERR_PERM
:
219 "kmix: You do not have permission to access the mixer device.\n"
220 "Ask your system administrator to fix /dev/audioctl to allow access."
224 errmsg
= Mixer_Backend::errorText( mixer_error
);
230 //======================================================================
231 // FUNCTION : Mixer::readVolumeFromHW
232 // DESCRIPTION : Read the audio information from the driver.
233 //======================================================================
234 int Mixer_SUN::readVolumeFromHW( const QString
& id
, MixDevice
*md
)
236 audio_info_t audioinfo
;
237 uint_t devMask
= MixerSunPortMasks
[devnum
];
239 Volume
& volume
= md
->playbackVolume();
240 int devnum
= id2num(id
);
242 // Read the current audio information from the driver
244 if ( ioctl( fd
, AUDIO_GETINFO
, &audioinfo
) < 0 )
246 return( Mixer::ERR_READ
);
251 // Extract the appropriate fields based on the requested device
255 case MIXERDEV_MASTER_VOLUME
:
256 volume
.setSwitchActivated( audioinfo
.output_muted
);
257 GainBalanceToVolume( audioinfo
.play
.gain
,
258 audioinfo
.play
.balance
,
262 case MIXERDEV_RECORD_MONITOR
:
264 volume
.setAllVolumes( audioinfo
.monitor_gain
);
267 case MIXERDEV_INTERNAL_SPEAKER
:
268 case MIXERDEV_HEADPHONE
:
269 case MIXERDEV_LINE_OUT
:
270 md
->setMuted( (audioinfo
.play
.port
& devMask
) ? false : true );
271 GainBalanceToVolume( audioinfo
.play
.gain
,
272 audioinfo
.play
.balance
,
276 case MIXERDEV_MICROPHONE
:
277 case MIXERDEV_LINE_IN
:
279 md
->setMuted( (audioinfo
.record
.port
& devMask
) ? false : true );
280 GainBalanceToVolume( audioinfo
.record
.gain
,
281 audioinfo
.record
.balance
,
286 return Mixer::ERR_READ
;
292 //======================================================================
293 // FUNCTION : Mixer::writeVolumeToHW
294 // DESCRIPTION : Write the specified audio settings to the hardware.
295 //======================================================================
296 int Mixer_SUN::writeVolumeToHW( const QString
& id
, MixDevice
*md
)
302 Volume
& volume
= md
->playbackVolume();
303 int devnum
= id2num(id
);
305 // Convert the Volume(left vol, right vol) to the Gain/Balance Sun uses
307 VolumeToGainBalance( volume
, gain
, balance
);
308 mute
= md
->isMuted() ? 1 : 0;
311 // Read the current audio settings from the hardware
313 audio_info_t audioinfo
;
314 if ( ioctl( fd
, AUDIO_GETINFO
, &audioinfo
) < 0 )
316 return( Mixer::ERR_READ
);
320 // Now, based on the devnum that we are writing to, update the appropriate
321 // volume field and twiddle the appropriate bitmask to enable/mute the
322 // device as necessary.
326 case MIXERDEV_MASTER_VOLUME
:
327 audioinfo
.play
.gain
= gain
;
328 audioinfo
.play
.balance
= balance
;
329 audioinfo
.output_muted
= mute
;
332 case MIXERDEV_RECORD_MONITOR
:
333 audioinfo
.monitor_gain
= gain
;
334 // no mute or balance for record monitor
337 case MIXERDEV_INTERNAL_SPEAKER
:
338 case MIXERDEV_HEADPHONE
:
339 case MIXERDEV_LINE_OUT
:
340 audioinfo
.play
.gain
= gain
;
341 audioinfo
.play
.balance
= balance
;
343 audioinfo
.play
.port
&= ~MixerSunPortMasks
[devnum
];
345 audioinfo
.play
.port
|= MixerSunPortMasks
[devnum
];
348 case MIXERDEV_MICROPHONE
:
349 case MIXERDEV_LINE_IN
:
351 audioinfo
.record
.gain
= gain
;
352 audioinfo
.record
.balance
= balance
;
354 audioinfo
.record
.port
&= ~MixerSunPortMasks
[devnum
];
356 audioinfo
.record
.port
|= MixerSunPortMasks
[devnum
];
360 return Mixer::ERR_READ
;
364 // Now that we've updated the audioinfo struct, write it back to the hardware
366 if ( ioctl( fd
, AUDIO_SETINFO
, &audioinfo
) < 0 )
368 return( Mixer::ERR_WRITE
);
376 //======================================================================
377 // FUNCTION : Mixer::setRecsrcHW
379 //======================================================================
380 void Mixer_SUN::setRecsrcHW( const QString
& /*id*/, bool /* on */ )
385 //======================================================================
386 // FUNCTION : Mixer::isRecsrcHW
387 // DESCRIPTION : Returns true if the specified device is a record source.
388 //======================================================================
389 bool Mixer_SUN::isRecsrcHW( const QString
& id
)
391 int devnum
= id2num(id
);
394 case MIXERDEV_MICROPHONE
:
395 case MIXERDEV_LINE_IN
:
404 //======================================================================
405 // FUNCTION : Mixer::VolumeToGainBalance
406 // DESCRIPTION : Converts a Volume(left vol + right vol) into the
407 // Gain/Balance values used by Sun.
408 //======================================================================
409 void Mixer_SUN::VolumeToGainBalance( Volume
& volume
, uint_t
& gain
, uchar_t
& balance
)
411 if ( ( volume
.count() == 1 ) ||
412 ( volume
[Volume::LEFT
] == volume
[Volume::RIGHT
] ) )
414 gain
= volume
[Volume::LEFT
];
415 balance
= AUDIO_MID_BALANCE
;
419 if ( volume
[Volume::LEFT
] > volume
[Volume::RIGHT
] )
421 gain
= volume
[Volume::LEFT
];
422 balance
= AUDIO_LEFT_BALANCE
+
423 ( AUDIO_MID_BALANCE
- AUDIO_LEFT_BALANCE
) *
424 volume
[Volume::RIGHT
] / volume
[Volume::LEFT
];
428 gain
= volume
[Volume::RIGHT
];
429 balance
= AUDIO_RIGHT_BALANCE
-
430 ( AUDIO_RIGHT_BALANCE
- AUDIO_MID_BALANCE
) *
431 volume
[Volume::LEFT
] / volume
[Volume::RIGHT
];
436 //======================================================================
437 // FUNCTION : Mixer::GainBalanceToVolume
438 // DESCRIPTION : Converts Gain/Balance returned by Sun driver to the
439 // Volume(left vol + right vol) format used by kmix.
440 //======================================================================
441 void Mixer_SUN::GainBalanceToVolume( uint_t
& gain
, uchar_t
& balance
, Volume
& volume
)
443 if ( volume
.count() == 1 )
445 volume
.setVolume( Volume::LEFT
, gain
);
449 if ( balance
<= AUDIO_MID_BALANCE
)
451 volume
.setVolume( Volume::LEFT
, gain
);
452 volume
.setVolume( Volume::RIGHT
, gain
*
453 ( balance
- AUDIO_LEFT_BALANCE
) /
454 ( AUDIO_MID_BALANCE
- AUDIO_LEFT_BALANCE
) );
458 volume
.setVolume( Volume::RIGHT
, gain
);
459 volume
.setVolume( Volume::LEFT
, gain
*
460 ( AUDIO_RIGHT_BALANCE
- balance
) /
461 ( AUDIO_RIGHT_BALANCE
- AUDIO_MID_BALANCE
) );
466 QString
SUN_getDriverName() {
470 QString
Mixer_SUN::getDriverName()