MythTV  0.26-pre
audiooutputoss.cpp
Go to the documentation of this file.
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     // Set everything up
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 /*digital*/)
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         // Check if drivers supports AC3
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     // align by frame size
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     // Setup volume control
00222     if (internal_vol)
00223         VolumeInit();
00224 
00225     // Device opened successfully
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 //GREG This is needs to be fixed for sure!
00270 #ifdef SNDCTL_DSP_GETODELAY
00271     ioctl(audiofd, SNDCTL_DSP_GETODELAY, &soundcard_buffer); // bytes
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; // left
00343     else if (channel == 1)
00344         volume = (tmpVol >> 8) & 0xff; // right
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         // Don't support more than two channels!
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 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends