00001 #include <cstdio>
00002 #include <cstdlib>
00003 #include <sys/time.h>
00004 #include <time.h>
00005 #include "config.h"
00006
00007 using namespace std;
00008
00009 #include "mythcontext.h"
00010 #include "audiooutputalsa.h"
00011
00012 #define LOC QString("ALSA: ")
00013 #define LOC_WARN QString("ALSA, Warning: ")
00014 #define LOC_ERR QString("ALSA, Error: ")
00015
00016 AudioOutputALSA::AudioOutputALSA(
00017 QString laudio_main_device, QString laudio_passthru_device,
00018 int laudio_bits, int laudio_channels,
00019 int laudio_samplerate, AudioOutputSource lsource,
00020 bool lset_initial_vol, bool laudio_passthru) :
00021 AudioOutputBase(laudio_main_device, laudio_passthru_device,
00022 laudio_bits, laudio_channels,
00023 laudio_samplerate, lsource,
00024 lset_initial_vol, laudio_passthru),
00025 pcm_handle(NULL), numbadioctls(0),
00026 killAudioLock(false), mixer_handle(NULL),
00027 mixer_control(QString::null), volume_range_multiplier(1.0f),
00028 playback_vol_min(0), playback_vol_max(1)
00029 {
00030
00031 Reconfigure(laudio_bits, laudio_channels,
00032 laudio_samplerate, laudio_passthru);
00033 }
00034
00035 AudioOutputALSA::~AudioOutputALSA()
00036 {
00037 KillAudio();
00038 }
00039
00040 bool AudioOutputALSA::OpenDevice()
00041 {
00042 snd_pcm_format_t format;
00043 unsigned int buffer_time, period_time;
00044 int err;
00045
00046 if (pcm_handle != NULL)
00047 CloseDevice();
00048
00049 pcm_handle = NULL;
00050 numbadioctls = 0;
00051
00052 QString real_device = (audio_passthru) ?
00053 audio_passthru_device : audio_main_device;
00054
00055 VERBOSE(VB_GENERAL, QString("Opening ALSA audio device '%1'.")
00056 .arg(real_device));
00057
00058 err = snd_pcm_open(&pcm_handle, real_device,
00059 SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
00060
00061 if (err < 0)
00062 {
00063 Error(QString("snd_pcm_open(%1): %2")
00064 .arg(real_device).arg(snd_strerror(err)));
00065
00066 if (pcm_handle)
00067 CloseDevice();
00068 return false;
00069 }
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084 if (source == AUDIOOUTPUT_TELEPHONY)
00085 {
00086 fragment_size = 320;
00087 buffer_time = 80000;
00088 period_time = buffer_time / 4;
00089 }
00090 else
00091 {
00092 fragment_size = 6144;
00093 buffer_time = 500000;
00094 period_time = buffer_time / 4;
00095 }
00096
00097 if (audio_bits == 8)
00098 format = SND_PCM_FORMAT_S8;
00099 else if (audio_bits == 16)
00100
00101
00102 #ifdef WORDS_BIGENDIAN
00103 format = SND_PCM_FORMAT_S16;
00104 #else
00105 format = SND_PCM_FORMAT_S16_LE;
00106 #endif
00107 else if (audio_bits == 24)
00108 #ifdef WORDS_BIGENDIAN
00109 format = SND_PCM_FORMAT_S24;
00110 #else
00111 format = SND_PCM_FORMAT_S24_LE;
00112 #endif
00113 else
00114 {
00115 Error(QString("Unknown sample format: %1 bits.").arg(audio_bits));
00116 return false;
00117 }
00118
00119 err = SetParameters(pcm_handle,
00120 format, audio_channels, audio_samplerate, buffer_time,
00121 period_time);
00122 if (err < 0)
00123 {
00124 Error("Unable to set ALSA parameters");
00125 CloseDevice();
00126 return false;
00127 }
00128
00129
00130
00131 audio_buffer_unused = soundcard_buffer_size - (fragment_size * 4);
00132
00133 if (internal_vol)
00134 OpenMixer(set_initial_vol);
00135
00136
00137 return true;
00138 }
00139
00140 void AudioOutputALSA::CloseDevice()
00141 {
00142 CloseMixer();
00143 if (pcm_handle != NULL)
00144 {
00145 snd_pcm_close(pcm_handle);
00146 pcm_handle = NULL;
00147 }
00148 }
00149
00150
00151 void AudioOutputALSA::WriteAudio(unsigned char *aubuf, int size)
00152 {
00153 unsigned char *tmpbuf;
00154 int lw = 0;
00155 int frames = size / audio_bytes_per_sample;
00156
00157 if (pcm_handle == NULL)
00158 {
00159 VERBOSE(VB_IMPORTANT, QString("WriteAudio() called with pcm_handle == NULL!"));
00160 return;
00161 }
00162
00163 tmpbuf = aubuf;
00164
00165 VERBOSE(VB_AUDIO|VB_TIMESTAMP,
00166 QString("WriteAudio: Preparing %1 bytes (%2 frames)")
00167 .arg(size).arg(frames));
00168
00169 while (frames > 0)
00170 {
00171 lw = pcm_write_func(pcm_handle, tmpbuf, frames);
00172
00173 if (lw >= 0)
00174 {
00175 if (lw < frames)
00176 VERBOSE(VB_AUDIO, QString("WriteAudio: short write %1 bytes (ok)")
00177 .arg(lw * audio_bytes_per_sample));
00178
00179 frames -= lw;
00180 tmpbuf += lw * audio_bytes_per_sample;
00181 }
00182 else if (lw == -EAGAIN)
00183 {
00184 VERBOSE(VB_AUDIO, QString("WriteAudio: device is blocked - waiting"));
00185
00186 snd_pcm_wait(pcm_handle, 10);
00187 }
00188 else if (lw == -EPIPE &&
00189 snd_pcm_state(pcm_handle) == SND_PCM_STATE_XRUN)
00190 {
00191 VERBOSE(VB_IMPORTANT, "WriteAudio: buffer underrun");
00192
00193 if ((lw = snd_pcm_prepare(pcm_handle)) < 0)
00194 {
00195 Error(QString("WriteAudio: unable to recover from xrun: %1")
00196 .arg(snd_strerror(lw)));
00197 return;
00198 }
00199 }
00200 else if (lw == -ESTRPIPE)
00201 {
00202 VERBOSE(VB_IMPORTANT, "WriteAudio: device is suspended");
00203
00204 while ((lw = snd_pcm_resume(pcm_handle)) == -EAGAIN)
00205 usleep(200);
00206
00207 if (lw < 0)
00208 {
00209 VERBOSE(VB_IMPORTANT, "WriteAudio: resume failed");
00210
00211 if ((lw = snd_pcm_prepare(pcm_handle)) < 0)
00212 {
00213 Error(QString("WriteAudio: unable to recover from suspend: %1")
00214 .arg(snd_strerror(lw)));
00215 return;
00216 }
00217 }
00218 }
00219 else if (lw == -EBADFD)
00220 {
00221 VERBOSE(VB_IMPORTANT,
00222 QString("WriteAudio: device is in a bad state (state = %1)")
00223 .arg(snd_pcm_state(pcm_handle)));
00224 return;
00225 }
00226 else
00227 {
00228 VERBOSE(VB_IMPORTANT, QString("pcm_write_func: %1 (%2)")
00229 .arg(snd_strerror(lw)).arg(lw));
00230 VERBOSE(VB_IMPORTANT, QString("WriteAudio: snd_pcm_state == %1")
00231 .arg(snd_pcm_state(pcm_handle)));
00232
00233
00234 return;
00235 }
00236 }
00237 }
00238
00239 inline int AudioOutputALSA::getBufferedOnSoundcard(void)
00240 {
00241 if (pcm_handle == NULL)
00242 {
00243 VERBOSE(VB_IMPORTANT, QString("getBufferedOnSoundcard() called with pcm_handle == NULL!"));
00244 return 0;
00245 }
00246
00247
00248
00249
00250 snd_pcm_sframes_t delay = 0;
00251
00252 snd_pcm_state_t state = snd_pcm_state(pcm_handle);
00253 if (state == SND_PCM_STATE_RUNNING ||
00254 state == SND_PCM_STATE_DRAINING)
00255 {
00256 snd_pcm_delay(pcm_handle, &delay);
00257 }
00258
00259 if (delay < 0)
00260 delay = 0;
00261
00262 int buffered = delay * audio_bytes_per_sample;
00263
00264 return buffered;
00265 }
00266
00267
00268 inline int AudioOutputALSA::getSpaceOnSoundcard(void)
00269 {
00270 if (pcm_handle == NULL)
00271 {
00272 VERBOSE(VB_IMPORTANT, QString("getSpaceOnSoundcard() called with pcm_handle == NULL!"));
00273 return 0;
00274 }
00275
00276 snd_pcm_sframes_t avail, delay;
00277
00278 snd_pcm_state_t state = snd_pcm_state(pcm_handle);
00279 if (state == SND_PCM_STATE_RUNNING ||
00280 state == SND_PCM_STATE_DRAINING)
00281 {
00282 snd_pcm_delay(pcm_handle, &delay);
00283 }
00284
00285 avail = snd_pcm_avail_update(pcm_handle);
00286 if (avail < 0 ||
00287 (snd_pcm_uframes_t)avail > (snd_pcm_uframes_t)soundcard_buffer_size)
00288 avail = soundcard_buffer_size;
00289
00290 int space = (avail * audio_bytes_per_sample) - audio_buffer_unused;
00291
00292 if (space < 0)
00293 space = 0;
00294
00295 return space;
00296 }
00297
00298
00299 int AudioOutputALSA::SetParameters(snd_pcm_t *handle,
00300 snd_pcm_format_t format, unsigned int channels,
00301 unsigned int rate, unsigned int buffer_time,
00302 unsigned int period_time)
00303 {
00304 int err, dir;
00305 snd_pcm_hw_params_t *params;
00306 snd_pcm_sw_params_t *swparams;
00307 snd_pcm_uframes_t buffer_size;
00308 snd_pcm_uframes_t period_size;
00309
00310 VERBOSE(VB_AUDIO, QString("in SetParameters(format=%1, channels=%2, "
00311 "rate=%3, buffer_time=%4, period_time=%5)")
00312 .arg(format).arg(channels).arg(rate).arg(buffer_time).arg(period_time));
00313
00314 if (handle == NULL)
00315 {
00316 VERBOSE(VB_IMPORTANT, QString("SetParameters() called with handle == NULL!"));
00317 return 0;
00318 }
00319
00320 snd_pcm_hw_params_alloca(¶ms);
00321 snd_pcm_sw_params_alloca(&swparams);
00322
00323
00324 if ((err = snd_pcm_hw_params_any(handle, params)) < 0)
00325 {
00326 Error(QString("Broken configuration for playback; no configurations"
00327 " available: %1").arg(snd_strerror(err)));
00328 return err;
00329 }
00330
00331
00332 pcm_write_func = &snd_pcm_mmap_writei;
00333 err = snd_pcm_hw_params_set_access(
00334 handle, params, SND_PCM_ACCESS_MMAP_INTERLEAVED);
00335 if (err < 0)
00336 {
00337 VERBOSE(VB_GENERAL, LOC_WARN +
00338 "mmap not available, attempting to fall back to slow writes.");
00339 QString old_err = snd_strerror(err);
00340 pcm_write_func = &snd_pcm_writei;
00341 err = snd_pcm_hw_params_set_access(
00342 handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
00343 if (err < 0)
00344 {
00345 Error("Interleaved sound types MMAP & RW are not available");
00346 VERBOSE(VB_IMPORTANT,
00347 QString("MMAP Error: %1\n\t\t\tRW Error: %2")
00348 .arg(old_err).arg(snd_strerror(err)));
00349 return err;
00350 }
00351 }
00352
00353
00354 if ((err = snd_pcm_hw_params_set_format(handle, params, format)) < 0)
00355 {
00356 Error(QString("Sample format not available: %1")
00357 .arg(snd_strerror(err)));
00358 return err;
00359 }
00360
00361
00362 if ((err = snd_pcm_hw_params_set_channels(handle, params, channels)) < 0)
00363 {
00364 Error(QString("Channels count (%1) not available: %2")
00365 .arg(channels).arg(snd_strerror(err)));
00366 return err;
00367 }
00368
00369
00370 unsigned int rrate = rate;
00371 if ((err = snd_pcm_hw_params_set_rate_near(handle, params, &rrate, 0)) < 0)
00372 {
00373 Error(QString("Samplerate (%1Hz) not available: %2")
00374 .arg(rate).arg(snd_strerror(err)));
00375 return err;
00376 }
00377
00378 if (rrate != rate)
00379 {
00380 Error(QString("Rate doesn't match (requested %1Hz, got %2Hz)")
00381 .arg(rate).arg(rrate));
00382 return -EINVAL;
00383 }
00384
00385
00386 if ((err = snd_pcm_hw_params_set_buffer_time_near(handle, params,
00387 &buffer_time, &dir)) < 0)
00388 {
00389 Error(QString("Unable to set buffer time %1 for playback: %2")
00390 .arg(buffer_time).arg(snd_strerror(err)));
00391 return err;
00392 }
00393
00394 if ((err = snd_pcm_hw_params_get_buffer_size(params, &buffer_size)) < 0)
00395 {
00396 Error(QString("Unable to get buffer size for playback: %1")
00397 .arg(snd_strerror(err)));
00398 return err;
00399 } else {
00400 VERBOSE(VB_AUDIO, QString("get_buffer_size returned %1").arg(buffer_size));
00401 }
00402 soundcard_buffer_size = buffer_size * audio_bytes_per_sample;
00403
00404
00405 if ((err = snd_pcm_hw_params_set_period_time_near(
00406 handle, params, &period_time, &dir)) < 0)
00407 {
00408 Error(QString("Unable to set period time %1 for playback: %2")
00409 .arg(period_time).arg(snd_strerror(err)));
00410 return err;
00411 } else {
00412 VERBOSE(VB_AUDIO, QString("set_period_time_near returned %1").arg(period_time));
00413 }
00414
00415 if ((err = snd_pcm_hw_params_get_period_size(params, &period_size,
00416 &dir)) < 0) {
00417 Error(QString("Unable to get period size for playback: %1")
00418 .arg(snd_strerror(err)));
00419 return err;
00420 } else {
00421 VERBOSE(VB_AUDIO, QString("get_period_size returned %1").arg(period_size));
00422 }
00423
00424
00425 if ((err = snd_pcm_hw_params(handle, params)) < 0) {
00426 Error(QString("Unable to set hw params for playback: %1")
00427 .arg(snd_strerror(err)));
00428 return err;
00429 }
00430
00431
00432 if ((err = snd_pcm_sw_params_current(handle, swparams)) < 0)
00433 {
00434 Error(QString("Unable to determine current swparams for playback:"
00435 " %1").arg(snd_strerror(err)));
00436 return err;
00437 }
00438
00439 if ((err = snd_pcm_sw_params_set_start_threshold(handle, swparams,
00440 period_size)) < 0)
00441 {
00442 Error(QString("Unable to set start threshold mode for playback: %1")
00443 .arg(snd_strerror(err)));
00444 return err;
00445 }
00446
00447
00448 if ((err = snd_pcm_sw_params_set_avail_min(handle, swparams,
00449 period_size)) < 0)
00450 {
00451 Error(QString("Unable to set avail min for playback: %1")
00452 .arg(snd_strerror(err)));
00453 return err;
00454 }
00455
00456
00457 if ((err = snd_pcm_sw_params_set_xfer_align(handle, swparams, 1)) < 0)
00458 {
00459 Error(QString("Unable to set transfer align for playback: %1")
00460 .arg(snd_strerror(err)));
00461 return err;
00462 }
00463
00464
00465 if ((err = snd_pcm_sw_params(handle, swparams)) < 0)
00466 {
00467 Error(QString("Unable to set sw params for playback: %1")
00468 .arg(snd_strerror(err)));
00469 return err;
00470 }
00471
00472 if ((err = snd_pcm_prepare(handle)) < 0)
00473 Error(QString("Initial pcm prepare err %1 %2")
00474 .arg(err).arg(snd_strerror(err)));
00475
00476 return 0;
00477 }
00478
00479
00480 int AudioOutputALSA::GetVolumeChannel(int channel)
00481 {
00482 long actual_volume, volume;
00483
00484 if (mixer_handle == NULL)
00485 return 100;
00486
00487 snd_mixer_selem_id_t *sid;
00488 snd_mixer_selem_id_alloca(&sid);
00489 snd_mixer_selem_id_set_index(sid, 0);
00490 snd_mixer_selem_id_set_name(sid, mixer_control.ascii());
00491
00492 snd_mixer_elem_t *elem = snd_mixer_find_selem(mixer_handle, sid);
00493 if (!elem)
00494 {
00495 VERBOSE(VB_IMPORTANT, QString("Mixer unable to find control %1")
00496 .arg(mixer_control));
00497 return 100;
00498 }
00499
00500 snd_mixer_selem_channel_id_t chan = (snd_mixer_selem_channel_id_t) channel;
00501 if (!snd_mixer_selem_has_playback_channel(elem, chan))
00502 {
00503 snd_mixer_selem_id_set_index(sid, channel);
00504 if ((elem = snd_mixer_find_selem(mixer_handle, sid)) == NULL)
00505 {
00506 VERBOSE(VB_IMPORTANT, QString("Mixer unable to find control %1 %2")
00507 .arg(mixer_control).arg(channel));
00508 return 100;
00509 }
00510 }
00511
00512 GetVolumeRange(elem);
00513
00514 snd_mixer_selem_get_playback_volume(elem, (snd_mixer_selem_channel_id_t)channel,
00515 &actual_volume);
00516 volume = (int)((actual_volume - playback_vol_min) *
00517 volume_range_multiplier);
00518
00519 return volume;
00520 }
00521 void AudioOutputALSA::SetVolumeChannel(int channel, int volume)
00522 {
00523 SetCurrentVolume(mixer_control, channel, volume);
00524 }
00525
00526 void AudioOutputALSA::SetCurrentVolume(QString control, int channel, int volume)
00527 {
00528 VERBOSE(VB_AUDIO, QString("Setting %1 volume to %2")
00529 .arg(control).arg(volume));
00530
00531 if (!mixer_handle)
00532 return;
00533
00534 snd_mixer_selem_id_t *sid;
00535 snd_mixer_selem_id_alloca(&sid);
00536 snd_mixer_selem_id_set_index(sid, 0);
00537 snd_mixer_selem_id_set_name(sid, control.ascii());
00538
00539 snd_mixer_elem_t *elem = snd_mixer_find_selem(mixer_handle, sid);
00540 if (!elem)
00541 {
00542 VERBOSE(VB_IMPORTANT, QString("Mixer unable to find control %1")
00543 .arg(control));
00544 return;
00545 }
00546
00547 snd_mixer_selem_channel_id_t chan = (snd_mixer_selem_channel_id_t) channel;
00548 if (!snd_mixer_selem_has_playback_channel(elem, chan))
00549 {
00550 snd_mixer_selem_id_set_index(sid, channel);
00551 if ((elem = snd_mixer_find_selem(mixer_handle, sid)) == NULL)
00552 {
00553 VERBOSE(VB_IMPORTANT,
00554 QString("mixer unable to find control %1 %2")
00555 .arg(control).arg(channel));
00556 return;
00557 }
00558 }
00559
00560 GetVolumeRange(elem);
00561
00562 int set_vol = (int)(volume / volume_range_multiplier +
00563 playback_vol_min + 0.5);
00564
00565 int err = snd_mixer_selem_set_playback_volume(elem, chan, set_vol);
00566 if (err < 0)
00567 {
00568 VERBOSE(VB_IMPORTANT, QString("mixer set channel %1 err %2: %3")
00569 .arg(channel).arg(err).arg(snd_strerror(err)));
00570 }
00571 else
00572 {
00573 VERBOSE(VB_AUDIO, QString("channel %1 vol set to %2")
00574 .arg(channel).arg(set_vol));
00575 }
00576
00577 if (snd_mixer_selem_has_playback_switch(elem))
00578 {
00579 int unmute = (0 != set_vol);
00580 if (snd_mixer_selem_has_playback_switch_joined(elem))
00581 {
00582
00583 for (int i = 0; i < audio_channels; i++)
00584 {
00585 if (0 != GetVolumeChannel(i))
00586 unmute = 1;
00587 }
00588 }
00589
00590 err = snd_mixer_selem_set_playback_switch(elem, chan, unmute);
00591 if (err < 0)
00592 {
00593 VERBOSE(VB_IMPORTANT, LOC_ERR +
00594 QString("Mixer set playback switch %1 err %2: %3")
00595 .arg(channel).arg(err).arg(snd_strerror(err)));
00596 }
00597 else
00598 {
00599 VERBOSE(VB_AUDIO, LOC +
00600 QString("channel %1 playback switch set to %2")
00601 .arg(channel).arg(unmute));
00602 }
00603 }
00604 }
00605
00606 void AudioOutputALSA::OpenMixer(bool setstartingvolume)
00607 {
00608 int volume;
00609
00610 mixer_control = gContext->GetSetting("MixerControl", "PCM");
00611
00612 SetupMixer();
00613
00614 if (mixer_handle != NULL && setstartingvolume)
00615 {
00616 volume = gContext->GetNumSetting("MasterMixerVolume", 80);
00617 SetCurrentVolume("Master", 0, volume);
00618 SetCurrentVolume("Master", 1, volume);
00619
00620 volume = gContext->GetNumSetting("PCMMixerVolume", 80);
00621 SetCurrentVolume("PCM", 0, volume);
00622 SetCurrentVolume("PCM", 1, volume);
00623 }
00624 }
00625
00626 void AudioOutputALSA::CloseMixer(void)
00627 {
00628 if (mixer_handle != NULL)
00629 snd_mixer_close(mixer_handle);
00630 mixer_handle = NULL;
00631 }
00632
00633 void AudioOutputALSA::SetupMixer(void)
00634 {
00635 int err;
00636
00637 QString alsadevice = gContext->GetSetting("MixerDevice", "default");
00638 QString device = alsadevice.remove(QString("ALSA:"));
00639
00640 if (mixer_handle != NULL)
00641 CloseMixer();
00642
00643 VERBOSE(VB_AUDIO, QString("Opening mixer %1").arg(device));
00644
00645
00646 if ((err = snd_mixer_open(&mixer_handle, 0)) < 0)
00647 {
00648 Warn(QString("Mixer device open error %1: %2")
00649 .arg(err).arg(snd_strerror(err)));
00650 mixer_handle = NULL;
00651 return;
00652 }
00653
00654 if ((err = snd_mixer_attach(mixer_handle, device.ascii())) < 0)
00655 {
00656 Warn(QString("Mixer attach error %1: %2"
00657 "\n\t\t\tCheck Mixer Name in Setup: '%3'")
00658 .arg(err).arg(snd_strerror(err)).arg(device));
00659 CloseMixer();
00660 return;
00661 }
00662
00663 if ((err = snd_mixer_selem_register(mixer_handle, NULL, NULL)) < 0)
00664 {
00665 Warn(QString("Mixer register error %1: %2")
00666 .arg(err).arg(snd_strerror(err)));
00667 CloseMixer();
00668 return;
00669 }
00670
00671 if ((err = snd_mixer_load(mixer_handle)) < 0)
00672 {
00673 Warn(QString("Mixer load error %1: %2")
00674 .arg(err).arg(snd_strerror(err)));
00675 CloseMixer();
00676 return;
00677 }
00678 }
00679
00680 void AudioOutputALSA::GetVolumeRange(snd_mixer_elem_t *elem)
00681 {
00682 snd_mixer_selem_get_playback_volume_range(elem, &playback_vol_min,
00683 &playback_vol_max);
00684 volume_range_multiplier = (100.0 / (float)(playback_vol_max -
00685 playback_vol_min));
00686
00687 VERBOSE(VB_AUDIO, QString("Volume range is %1 to %2, mult=%3")
00688 .arg(playback_vol_min).arg(playback_vol_max)
00689 .arg(volume_range_multiplier));
00690 }
00691