|
MythTV
0.26-pre
|
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
1.7.6.1