00001 #include <cstdio>
00002 #include <cstdlib>
00003 #include <fcntl.h>
00004 #include <sys/time.h>
00005 #include <unistd.h>
00006 #include <time.h>
00007
00008 #include <sys/ioctl.h>
00009 #include <cerrno>
00010 #include <cstring>
00011
00012 #include <iostream>
00013 #include "config.h"
00014
00015 #if HAVE_SYS_SOUNDCARD_H
00016 #include <sys/soundcard.h>
00017 #elif HAVE_SOUNDCARD_H
00018 #include <soundcard.h>
00019 #endif
00020
00021 using namespace std;
00022
00023 #define LOC QString("AOOSS: ")
00024
00025 #include "mythcorecontext.h"
00026 #include "audiooutputoss.h"
00027 #include "mythmiscutil.h"
00028
00029 AudioOutputOSS::AudioOutputOSS(const AudioSettings &settings) :
00030 AudioOutputBase(settings),
00031 audiofd(-1), numbadioctls(0),
00032 mixerfd(-1), control(SOUND_MIXER_VOLUME)
00033 {
00034
00035 InitSettings(settings);
00036 if (settings.init)
00037 Reconfigure(settings);
00038 }
00039
00040 AudioOutputOSS::~AudioOutputOSS()
00041 {
00042 KillAudio();
00043 }
00044
00045 AudioOutputSettings* AudioOutputOSS::GetOutputSettings(bool )
00046 {
00047 AudioOutputSettings *settings = new AudioOutputSettings();
00048
00049 QByteArray device = main_device.toAscii();
00050 audiofd = open(device.constData(), O_WRONLY | O_NONBLOCK);
00051
00052 AudioFormat fmt;
00053 int rate, formats = 0;
00054
00055 if (audiofd < 0)
00056 {
00057 VBERRENO(QString("Error opening audio device (%1)").arg(main_device));
00058 delete settings;
00059 return NULL;
00060 }
00061
00062 while ((rate = settings->GetNextRate()))
00063 {
00064 int rate2 = rate;
00065 if(ioctl(audiofd, SNDCTL_DSP_SPEED, &rate2) >= 0
00066 && rate2 == rate)
00067 settings->AddSupportedRate(rate);
00068 }
00069
00070 if(ioctl(audiofd, SNDCTL_DSP_GETFMTS, &formats) < 0)
00071 VBERRENO("Error retrieving formats");
00072 else
00073 {
00074 int ofmt;
00075
00076 while ((fmt = settings->GetNextFormat()))
00077 {
00078 switch (fmt)
00079 {
00080 case FORMAT_U8: ofmt = AFMT_U8; break;
00081 case FORMAT_S16: ofmt = AFMT_S16_NE; break;
00082 default: continue;
00083 }
00084
00085 if (formats & ofmt)
00086 settings->AddSupportedFormat(fmt);
00087 }
00088 }
00089
00090 #if defined(AFMT_AC3)
00091
00092 settings->setPassthrough(((formats & AFMT_AC3) != 0) - 1);
00093 #endif
00094
00095 for (int i = 1; i <= 2; i++)
00096 {
00097 int channel = i;
00098
00099 if (ioctl(audiofd, SNDCTL_DSP_CHANNELS, &channel) >= 0 &&
00100 channel == i)
00101 {
00102 settings->AddSupportedChannels(i);
00103 }
00104 }
00105
00106 close(audiofd);
00107 audiofd = -1;
00108
00109 return settings;
00110 }
00111
00112 bool AudioOutputOSS::OpenDevice()
00113 {
00114 numbadioctls = 0;
00115
00116 MythTimer timer;
00117 timer.start();
00118
00119 VBAUDIO(QString("Opening OSS audio device '%1'.").arg(main_device));
00120
00121 while (timer.elapsed() < 2000 && audiofd == -1)
00122 {
00123 QByteArray device = main_device.toAscii();
00124 audiofd = open(device.constData(), O_WRONLY);
00125 if (audiofd < 0 && errno != EAGAIN && errno != EINTR)
00126 {
00127 if (errno == EBUSY)
00128 {
00129 VBWARN(QString("Something is currently using: %1.")
00130 .arg(main_device));
00131 return false;
00132 }
00133 VBERRENO(QString("Error opening audio device (%1)")
00134 .arg(main_device));
00135 }
00136 if (audiofd < 0)
00137 usleep(50);
00138 }
00139
00140 if (audiofd == -1)
00141 {
00142 VBERRENO(QString("Error opening audio device (%1)").arg(main_device));
00143 return false;
00144 }
00145
00146 fcntl(audiofd, F_SETFL, fcntl(audiofd, F_GETFL) & ~O_NONBLOCK);
00147
00148 bool err = false;
00149 int format;
00150
00151 switch (output_format)
00152 {
00153 case FORMAT_U8: format = AFMT_U8; break;
00154 case FORMAT_S16: format = AFMT_S16_NE; break;
00155 default:
00156 VBERROR(QString("Unknown sample format: %1").arg(output_format));
00157 close(audiofd);
00158 audiofd = -1;
00159 return false;
00160 }
00161
00162 #if defined(AFMT_AC3) && defined(SNDCTL_DSP_GETFMTS)
00163 if (passthru)
00164 {
00165 int format_support = 0;
00166 if (!ioctl(audiofd, SNDCTL_DSP_GETFMTS, &format_support) &&
00167 (format_support & AFMT_AC3))
00168 {
00169 format = AFMT_AC3;
00170 }
00171 }
00172 #endif
00173
00174 if (channels > 2)
00175 {
00176 if (ioctl(audiofd, SNDCTL_DSP_CHANNELS, &channels) < 0 ||
00177 ioctl(audiofd, SNDCTL_DSP_SPEED, &samplerate) < 0 ||
00178 ioctl(audiofd, SNDCTL_DSP_SETFMT, &format) < 0)
00179 err = true;
00180 }
00181 else
00182 {
00183 int stereo = channels - 1;
00184 if (ioctl(audiofd, SNDCTL_DSP_STEREO, &stereo) < 0 ||
00185 ioctl(audiofd, SNDCTL_DSP_SPEED, &samplerate) < 0 ||
00186 ioctl(audiofd, SNDCTL_DSP_SETFMT, &format) < 0)
00187 err = true;
00188 }
00189
00190 if (err)
00191 {
00192 VBERRENO(QString("Unable to set audio device (%1) to %2 kHz, %3 bits, "
00193 "%4 channels")
00194 .arg(main_device).arg(samplerate)
00195 .arg(AudioOutputSettings::FormatToBits(output_format))
00196 .arg(channels));
00197
00198 close(audiofd);
00199 audiofd = -1;
00200 return false;
00201 }
00202
00203 audio_buf_info info;
00204 ioctl(audiofd, SNDCTL_DSP_GETOSPACE, &info);
00205
00206 fragment_size = info.fragsize - (info.fragsize % output_bytes_per_frame);
00207
00208 soundcard_buffer_size = info.bytes;
00209
00210 int caps;
00211
00212 if (ioctl(audiofd, SNDCTL_DSP_GETCAPS, &caps) == 0)
00213 {
00214 if (!(caps & DSP_CAP_REALTIME))
00215 VBWARN("The audio device cannot report buffer state "
00216 "accurately! audio/video sync will be bad, continuing...");
00217 }
00218 else
00219 VBERRENO("Unable to get audio card capabilities");
00220
00221
00222 if (internal_vol)
00223 VolumeInit();
00224
00225
00226 return true;
00227 }
00228
00229 void AudioOutputOSS::CloseDevice()
00230 {
00231 if (audiofd != -1)
00232 close(audiofd);
00233
00234 audiofd = -1;
00235
00236 VolumeCleanup();
00237 }
00238
00239
00240 void AudioOutputOSS::WriteAudio(uchar *aubuf, int size)
00241 {
00242 if (audiofd < 0)
00243 return;
00244
00245 uchar *tmpbuf;
00246 int written = 0, lw = 0;
00247
00248 tmpbuf = aubuf;
00249
00250 while ((written < size) &&
00251 ((lw = write(audiofd, tmpbuf, size - written)) > 0))
00252 {
00253 written += lw;
00254 tmpbuf += lw;
00255 }
00256
00257 if (lw < 0)
00258 {
00259 VBERRENO(QString("Error writing to audio device (%1)")
00260 .arg(main_device));
00261 return;
00262 }
00263 }
00264
00265
00266 int AudioOutputOSS::GetBufferedOnSoundcard(void) const
00267 {
00268 int soundcard_buffer=0;
00269
00270 #ifdef SNDCTL_DSP_GETODELAY
00271 ioctl(audiofd, SNDCTL_DSP_GETODELAY, &soundcard_buffer);
00272 #endif
00273 return soundcard_buffer;
00274 }
00275
00276 void AudioOutputOSS::VolumeInit()
00277 {
00278 mixerfd = -1;
00279
00280 QString device = gCoreContext->GetSetting("MixerDevice", "/dev/mixer");
00281 if (device.toLower() == "software")
00282 return;
00283
00284 QByteArray dev = device.toAscii();
00285 mixerfd = open(dev.constData(), O_RDONLY);
00286
00287 QString controlLabel = gCoreContext->GetSetting("MixerControl", "PCM");
00288
00289 if (controlLabel == "Master")
00290 control = SOUND_MIXER_VOLUME;
00291 else
00292 control = SOUND_MIXER_PCM;
00293
00294 if (mixerfd < 0)
00295 {
00296 VBERROR(QString("Unable to open mixer: '%1'").arg(device));
00297 return;
00298 }
00299
00300 if (set_initial_vol)
00301 {
00302 int tmpVol;
00303 int volume = gCoreContext->GetNumSetting("MasterMixerVolume", 80);
00304 tmpVol = (volume << 8) + volume;
00305 int ret = ioctl(mixerfd, MIXER_WRITE(SOUND_MIXER_VOLUME), &tmpVol);
00306 if (ret < 0)
00307 VBERROR(QString("Error Setting initial Master Volume") + ENO);
00308
00309 volume = gCoreContext->GetNumSetting("PCMMixerVolume", 80);
00310 tmpVol = (volume << 8) + volume;
00311 ret = ioctl(mixerfd, MIXER_WRITE(SOUND_MIXER_PCM), &tmpVol);
00312 if (ret < 0)
00313 VBERROR(QString("Error setting initial PCM Volume") + ENO);
00314 }
00315 }
00316
00317 void AudioOutputOSS::VolumeCleanup()
00318 {
00319 if (mixerfd >= 0)
00320 {
00321 close(mixerfd);
00322 mixerfd = -1;
00323 }
00324 }
00325
00326 int AudioOutputOSS::GetVolumeChannel(int channel) const
00327 {
00328 int volume=0;
00329 int tmpVol=0;
00330
00331 if (mixerfd <= 0)
00332 return 100;
00333
00334 int ret = ioctl(mixerfd, MIXER_READ(control), &tmpVol);
00335 if (ret < 0)
00336 {
00337 VBERROR(QString("Error reading volume for channel %1").arg(channel));
00338 return 0;
00339 }
00340
00341 if (channel == 0)
00342 volume = tmpVol & 0xff;
00343 else if (channel == 1)
00344 volume = (tmpVol >> 8) & 0xff;
00345 else
00346 VBERROR("Invalid channel. Only stereo volume supported");
00347
00348 return volume;
00349 }
00350
00351 void AudioOutputOSS::SetVolumeChannel(int channel, int volume)
00352 {
00353 if (channel > 1)
00354 {
00355
00356 VBERROR(QString("Error setting channel %1. Only 2 ch volume supported")
00357 .arg(channel));
00358 return;
00359 }
00360
00361 if (volume > 100)
00362 volume = 100;
00363 if (volume < 0)
00364 volume = 0;
00365
00366 if (mixerfd >= 0)
00367 {
00368 int tmpVol = 0;
00369 if (channel == 0)
00370 tmpVol = (GetVolumeChannel(1) << 8) + volume;
00371 else
00372 tmpVol = (volume << 8) + GetVolumeChannel(0);
00373
00374 int ret = ioctl(mixerfd, MIXER_WRITE(control), &tmpVol);
00375 if (ret < 0)
00376 VBERROR(QString("Error setting volume on channel %1").arg(channel));
00377 }
00378 }
00379