Final polisihing for KDE4:
[kdemultimedia.git] / kmix / mixer_sun.cpp
blobc2422b697808aadf51d7c22cc1a65794c37ecfdc
1 /*
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>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <sys/file.h>
27 #include <sys/audioio.h>
28 #include <errno.h>
29 #include <unistd.h>
30 #include <stdlib.h>
32 #include "mixer_sun.h"
33 #include "mixer.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
46 enum MixerDevs
48 MIXERDEV_MASTER_VOLUME,
49 MIXERDEV_INTERNAL_SPEAKER,
50 MIXERDEV_HEADPHONE,
51 MIXERDEV_LINE_OUT,
52 MIXERDEV_RECORD_MONITOR,
53 MIXERDEV_MICROPHONE,
54 MIXERDEV_LINE_IN,
55 MIXERDEV_CD,
56 // Insert new devices before this marker
57 MIXERDEV_END_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"),
72 I18N_NOOP("Line In"),
73 I18N_NOOP("CD")
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
88 MixDevice::CD // CD
92 // Mapping from device numbers to Sun port mask values
94 const uint_t MixerSunPortMasks[] =
96 0, // MASTER_VOLUME - no associated port
97 AUDIO_SPEAKER,
98 AUDIO_HEADPHONE,
99 AUDIO_LINE_OUT,
100 0, // RECORD_MONITOR - no associated port
101 AUDIO_MICROPHONE,
102 AUDIO_LINE_IN,
103 AUDIO_CD
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 );
120 return l_mixer;
124 //======================================================================
125 // FUNCTION : Mixer::Mixer
126 // DESCRIPTION : Class constructor.
127 //======================================================================
128 Mixer_SUN::Mixer_SUN(int devnum) : Mixer_Backend(mixer, devnum)
130 if ( devnum == -1 )
131 m_devnum = 0;
134 //======================================================================
135 // FUNCTION : Mixer::Mixer
136 // DESCRIPTION : Class destructor.
137 //======================================================================
138 Mixer_SUN::~Mixer_SUN()
140 close();
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
152 if ( m_devnum !=0 )
153 return Mixer::ERR_OPEN;
156 // Open the mixer hardware driver
158 QCString audiodev(getenv("AUDIODEV"));
159 if(audiodev.isNull())
160 audiodev = "/dev/audio";
161 audiodev += "ctl";
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;
167 else
168 return Mixer::ERR_OPEN;
170 else
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 );
179 QString id;
180 id.setNum(idx);
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";
189 m_isOpen = true;
191 return 0;
195 //======================================================================
196 // FUNCTION : Mixer::close
197 // DESCRIPTION : Close the hardware driver.
198 //======================================================================
199 int Mixer_SUN::close()
201 _pollingTimer->stop();
202 m_isOpen = false;
203 int l_i_ret = ::close( fd );
204 m_mixDevices.clear();
205 return l_i_ret;
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 )
214 QString errmsg;
215 switch (mixer_error)
217 case Mixer::ERR_PERM:
218 errmsg = i18n(
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."
222 break;
223 default:
224 errmsg = Mixer_Backend::errorText( mixer_error );
226 return errmsg;
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 );
248 else
251 // Extract the appropriate fields based on the requested device
253 switch ( devnum )
255 case MIXERDEV_MASTER_VOLUME :
256 volume.setSwitchActivated( audioinfo.output_muted );
257 GainBalanceToVolume( audioinfo.play.gain,
258 audioinfo.play.balance,
259 volume );
260 break;
262 case MIXERDEV_RECORD_MONITOR :
263 md->setMuted(false);
264 volume.setAllVolumes( audioinfo.monitor_gain );
265 break;
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,
273 volume );
274 break;
276 case MIXERDEV_MICROPHONE :
277 case MIXERDEV_LINE_IN :
278 case MIXERDEV_CD :
279 md->setMuted( (audioinfo.record.port & devMask) ? false : true );
280 GainBalanceToVolume( audioinfo.record.gain,
281 audioinfo.record.balance,
282 volume );
283 break;
285 default :
286 return Mixer::ERR_READ;
288 return 0;
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 )
298 uint_t gain;
299 uchar_t balance;
300 uchar_t mute;
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.
324 switch ( devnum )
326 case MIXERDEV_MASTER_VOLUME :
327 audioinfo.play.gain = gain;
328 audioinfo.play.balance = balance;
329 audioinfo.output_muted = mute;
330 break;
332 case MIXERDEV_RECORD_MONITOR :
333 audioinfo.monitor_gain = gain;
334 // no mute or balance for record monitor
335 break;
337 case MIXERDEV_INTERNAL_SPEAKER :
338 case MIXERDEV_HEADPHONE :
339 case MIXERDEV_LINE_OUT :
340 audioinfo.play.gain = gain;
341 audioinfo.play.balance = balance;
342 if ( mute )
343 audioinfo.play.port &= ~MixerSunPortMasks[devnum];
344 else
345 audioinfo.play.port |= MixerSunPortMasks[devnum];
346 break;
348 case MIXERDEV_MICROPHONE :
349 case MIXERDEV_LINE_IN :
350 case MIXERDEV_CD :
351 audioinfo.record.gain = gain;
352 audioinfo.record.balance = balance;
353 if ( mute )
354 audioinfo.record.port &= ~MixerSunPortMasks[devnum];
355 else
356 audioinfo.record.port |= MixerSunPortMasks[devnum];
357 break;
359 default :
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 );
370 else
372 return 0;
376 //======================================================================
377 // FUNCTION : Mixer::setRecsrcHW
378 // DESCRIPTION :
379 //======================================================================
380 void Mixer_SUN::setRecsrcHW( const QString& /*id*/, bool /* on */ )
382 return;
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);
392 switch ( devnum )
394 case MIXERDEV_MICROPHONE :
395 case MIXERDEV_LINE_IN :
396 case MIXERDEV_CD :
397 return true;
399 default :
400 return false;
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;
417 else
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];
426 else
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 );
447 else
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 ) );
456 else
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() {
467 return "SUNAudio";
470 QString Mixer_SUN::getDriverName()
472 return "SUNAudio";