2
* KMix -- KDE's full featured mini mixer
5
* Copyright (C) 1996-2000 Christian Esken
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., 675 Mass Ave, Cambridge, MA 02139, USA.
26
#include <sys/ioctl.h>
27
#include <sys/types.h>
30
// Linux section, by Christian Esken
31
#if defined(__linux__)
32
#include <sys/soundcard.h>
33
// FreeBSD section, according to Sebestyen Zoltan
34
#elif defined(__FreeBSD__)
35
#include "machine/soundcard.h"
36
// NetBSD section, according to Lennart Augustsson <augustss@cs.chalmers.se>
37
#elif defined(__NetBSD__)
38
#include <soundcard.h>
39
// BSDI section, according to <tom@foo.toetag.com>
40
#elif defined(__bsdi__)
41
#include <sys/soundcard.h>
43
#elif defined(_UNIXWARE)
44
#include <sys/soundcard.h>
47
#include "mixer_oss.h"
51
const char* MixerDevNames[32]={
52
I18N_NOOP("Volume"), I18N_NOOP("Bass"), I18N_NOOP("Treble"),
53
I18N_NOOP("Synth"), I18N_NOOP("Pcm"), I18N_NOOP("Speaker"),
54
I18N_NOOP("Line"), I18N_NOOP("Microphone"), I18N_NOOP("CD"),
55
I18N_NOOP("Mix"), I18N_NOOP("Pcm2"), I18N_NOOP("RecMon"),
56
I18N_NOOP("IGain"), I18N_NOOP("OGain"), I18N_NOOP("Line1"),
57
I18N_NOOP("Line2"), I18N_NOOP("Line3"), I18N_NOOP("Digital1"),
58
I18N_NOOP("Digital2"), I18N_NOOP("Digital3"), I18N_NOOP("PhoneIn"),
59
I18N_NOOP("PhoneOut"), I18N_NOOP("Video"), I18N_NOOP("Radio"),
60
I18N_NOOP("Monitor"), I18N_NOOP("3D-depth"), I18N_NOOP("3D-center"),
61
I18N_NOOP("unknown"), I18N_NOOP("unknown"), I18N_NOOP("unknown"),
62
I18N_NOOP("unknown") , I18N_NOOP("unused") };
64
const MixDevice::ChannelType MixerChannelTypes[32] = {
65
MixDevice::VOLUME, MixDevice::BASS, MixDevice::TREBLE, MixDevice::MIDI,
66
MixDevice::AUDIO, MixDevice::EXTERNAL, MixDevice::EXTERNAL, MixDevice::MICROPHONE,
67
MixDevice::CD, MixDevice::VOLUME, MixDevice::AUDIO, MixDevice::RECMONITOR,
68
MixDevice::VOLUME, MixDevice::RECMONITOR, MixDevice::EXTERNAL, MixDevice::EXTERNAL,
69
MixDevice::EXTERNAL, MixDevice::AUDIO, MixDevice::AUDIO, MixDevice::AUDIO,
70
MixDevice::EXTERNAL, MixDevice::EXTERNAL, MixDevice::EXTERNAL, MixDevice::EXTERNAL,
71
MixDevice::EXTERNAL, MixDevice::VOLUME, MixDevice::VOLUME, MixDevice::UNKNOWN,
72
MixDevice::UNKNOWN, MixDevice::UNKNOWN, MixDevice::UNKNOWN, MixDevice::UNKNOWN };
74
Mixer* OSS_getMixer( int device, int card )
77
l_mixer = new Mixer_OSS( device, card );
78
l_mixer->setupMixer();
82
Mixer* OSS_getMixerSet( MixSet set, int device, int card )
85
l_mixer = new Mixer_OSS( device, card );
86
l_mixer->setupMixer( set );
91
Mixer_OSS::Mixer_OSS(int device, int card) : Mixer(device, card)
93
if( device == -1 ) m_devnum = 0;
94
if( card == -1 ) m_cardnum = 0;
97
int Mixer_OSS::openMixer()
99
if ( m_cardnum!=0 ) return Mixer::ERR_OPEN; // OSS doesn't support different card numbers
100
release(); // To be sure, release mixer before (re-)opening
102
if ((m_fd= ::open( deviceName( m_devnum ).latin1(), O_RDWR)) < 0)
104
if ( errno == EACCES )
105
return Mixer::ERR_PERM;
107
return Mixer::ERR_OPEN;
111
int devmask, recmask, i_recsrc, stereodevs;
112
// Mixer is open. Now define properties
113
if (ioctl(m_fd, SOUND_MIXER_READ_DEVMASK, &devmask) == -1)
114
return Mixer::ERR_READ;
115
if (ioctl(m_fd, SOUND_MIXER_READ_RECMASK, &recmask) == -1)
116
return Mixer::ERR_READ;
117
if (ioctl(m_fd, SOUND_MIXER_READ_RECSRC, &i_recsrc) == -1)
118
return Mixer::ERR_READ;
119
if (ioctl(m_fd, SOUND_MIXER_READ_STEREODEVS, &stereodevs) == -1)
120
return Mixer::ERR_READ;
122
return Mixer::ERR_NODEV;
125
if( m_mixDevices.isEmpty() )
128
while( devmask && idx < MAX_MIXDEVS )
130
if( devmask & ( 1 << idx ) ) // device active?
132
Volume vol( stereodevs & ( 1 << idx ) ? 2 : 1, maxVolume);
133
readVolumeFromHW( idx, vol );
135
new MixDevice( idx, vol, recmask & ( 1 << idx ),
136
QString(MixerDevNames[idx]),
137
MixerChannelTypes[idx]);
138
md->setRecsrc( isRecsrcHW( idx ) );
139
m_mixDevices.append( md );
145
for( unsigned int idx = 0; idx < m_mixDevices.count(); idx++ )
147
MixDevice* md = m_mixDevices.at( idx );
149
return ERR_INCOMPATIBLESET;
150
writeVolumeToHW( idx, md->getVolume() );
153
#if !defined(__FreeBSD__)
154
struct mixer_info l_mix_info;
155
if (ioctl(m_fd, SOUND_MIXER_INFO, &l_mix_info) != -1)
157
m_mixerName = l_mix_info.name;
162
m_mixerName = "OSS Audio Mixer";
169
int Mixer_OSS::releaseMixer()
171
int l_i_ret = ::close(m_fd);
176
QString Mixer_OSS::deviceName(int devnum)
180
return QString("/dev/mixer");
184
QString devname("/dev/mixer");
185
devname += ('0'+devnum);
190
QString Mixer_OSS::errorText(int mixer_error)
196
l_s_errmsg = i18n("kmix: You do not have permission to access the mixer device.\n" \
197
"Login as root and do a 'chmod a+rw /dev/mixer*' to allow the access.");
200
l_s_errmsg = i18n("kmix: Mixer cannot be found.\n" \
201
"Please check that the soundcard is installed and the\n" \
202
"soundcard driver is loaded.\n" \
203
"On Linux you might need to use 'insmod' to load the driver.\n" \
204
"Use 'soundon' when using commercial OSS.");
207
l_s_errmsg = Mixer::errorText(mixer_error);
213
bool Mixer_OSS::setRecsrcHW( int devnum, bool on )
215
int i_recsrc, oldrecsrc;
216
if (ioctl(m_fd, SOUND_MIXER_READ_RECSRC, &i_recsrc) == -1)
217
errormsg(Mixer::ERR_READ);
219
oldrecsrc = i_recsrc = on ?
220
(i_recsrc | (1 << devnum )) :
221
(i_recsrc & ~(1 << devnum ));
223
// Change status of record source(s)
224
if (ioctl(m_fd, SOUND_MIXER_WRITE_RECSRC, &i_recsrc) == -1)
225
errormsg (Mixer::ERR_WRITE);
226
// Re-read status of record source(s). Just in case, OSS does not like
227
// my settings. And with this line mix->recsrc gets its new value. :-)
228
if (ioctl(m_fd, SOUND_MIXER_READ_RECSRC, &i_recsrc) == -1)
229
errormsg(Mixer::ERR_READ);
231
// PORTING: Hint: Do not forget to set i_recsrc to the new valid
232
// record source mask.
234
return i_recsrc == oldrecsrc;
237
bool Mixer_OSS::isRecsrcHW( int devnum )
240
if (ioctl(m_fd, SOUND_MIXER_READ_RECSRC, &i_recsrc) == -1)
241
errormsg(Mixer::ERR_READ);
243
return i_recsrc & (1 << devnum );
247
int Mixer_OSS::readVolumeFromHW( int devnum, Volume &vol )
249
if( vol.isMuted() ) return 0; // Don't alter volume when muted
252
if (ioctl(m_fd, MIXER_READ( devnum ), &volume) == -1)
254
/* Oops, can't read mixer */
255
return(Mixer::ERR_READ);
259
vol.setVolume( Volume::LEFT, (volume & 0x7f));
260
if( vol.channels() > 1 )
261
vol.setVolume( Volume::RIGHT, ((volume>>8) & 0x7f));
268
int Mixer_OSS::writeVolumeToHW( int devnum, Volume vol )
271
if( vol.isMuted() ) volume = 0;
273
if ( vol.channels() > 1 )
274
volume = vol[ Volume::LEFT ] + ((vol[ Volume::RIGHT ])<<8);
276
volume = vol[ Volume::LEFT ];
278
if (ioctl(m_fd, MIXER_WRITE( devnum ), &volume) == -1)
279
return Mixer::ERR_WRITE;