| Index: linux/audio_output_alsa.cc
|
| diff --git a/linux/audio_output_alsa.cc b/linux/audio_output_alsa.cc
|
| index dc763ba46024157c64509916161204e043e12c5a..fdf4c6e811c63c7b0c6aea49fa17b7f7662fe98b 100644
|
| --- a/linux/audio_output_alsa.cc
|
| +++ b/linux/audio_output_alsa.cc
|
| @@ -13,6 +13,57 @@
|
| #include "log.h"
|
| #include "threading.h"
|
|
|
| +namespace {
|
| +
|
| +bool isDeviceReady() {
|
| + snd_ctl_card_info_t *card_info;
|
| + snd_ctl_card_info_alloca(&card_info);
|
| +
|
| + snd_pcm_info_t *pcm_info;
|
| + snd_pcm_info_alloca(&pcm_info);
|
| +
|
| + int valid_playback_devices = 0;
|
| + int card_index = -1;
|
| +
|
| + while(snd_card_next(&card_index) == 0 && card_index >= 0) {
|
| + char card_name[20];
|
| + snprintf(card_name, sizeof(card_name), "hw:%d", card_index);
|
| + LOG(INFO) << "Checking ALSA sound card " << card_name;
|
| +
|
| + snd_ctl_t *ctl;
|
| + if(snd_ctl_open(&ctl, card_name, 0) < 0)
|
| + continue;
|
| +
|
| + snd_ctl_card_info(ctl, card_info);
|
| +
|
| + int dev_index = -1;
|
| + while (snd_ctl_pcm_next_device(ctl, &dev_index) == 0 && dev_index >= 0) {
|
| + char device_name[30];
|
| + snprintf(device_name, sizeof(device_name),
|
| + "hw:%d,%d", card_index, dev_index);
|
| + LOG(INFO) << "Checking ALSA sound device " << device_name;
|
| +
|
| + /* Obtain info about this particular device */
|
| + snd_pcm_info_set_device(pcm_info, dev_index);
|
| + snd_pcm_info_set_subdevice(pcm_info, 0);
|
| + snd_pcm_info_set_stream(pcm_info, SND_PCM_STREAM_PLAYBACK);
|
| + if (snd_ctl_pcm_info(ctl, pcm_info) >= 0) {
|
| + LOG(INFO) << " Valid playback device: " << device_name;
|
| + valid_playback_devices++;
|
| + }
|
| + }
|
| + snd_ctl_close(ctl);
|
| + }
|
| +
|
| + LOG(INFO) << "Total valid playback devices: " << valid_playback_devices;
|
| + if (valid_playback_devices == 0) {
|
| + return false;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +}
|
| +
|
| namespace speech_synthesis {
|
|
|
| class LinuxAlsaAudioOutput : public AudioOutput, public Runnable {
|
| @@ -32,93 +83,44 @@ class LinuxAlsaAudioOutput : public AudioOutput, public Runnable {
|
| return true;
|
| }
|
|
|
| + if (!isDeviceReady()) {
|
| + return false;
|
| + }
|
| +
|
| int err;
|
| if ((err = snd_pcm_open(&pcm_out_handle_,
|
| - "plughw:0,0",
|
| + "default",
|
| SND_PCM_STREAM_PLAYBACK,
|
| 0)) < 0) {
|
| LOG(INFO) << "Can't open wave output: " << snd_strerror(err) << "\n";
|
| return false;
|
| }
|
|
|
| - snd_pcm_hw_params_t *hw_params;
|
| - if ((err = snd_pcm_hw_params_malloc(&hw_params)) < 0) {
|
| - LOG(INFO) << "Can't alloc sound hardware struct " <<
|
| - snd_strerror(err) << "\n";
|
| - return false;
|
| - }
|
| -
|
| - if ((err = snd_pcm_hw_params_any(pcm_out_handle_, hw_params)) < 0) {
|
| - LOG(INFO) << "Can't init sound hardware struct: " <<
|
| - snd_strerror(err) << "\n";
|
| - return false;
|
| - }
|
| -
|
| - if ((err = snd_pcm_hw_params_set_access(
|
| - pcm_out_handle_, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
|
| - LOG(INFO) << "Can't set access: " << snd_strerror(err) << "\n";
|
| - return false;
|
| - }
|
| -
|
| - if ((err = snd_pcm_hw_params_set_format(pcm_out_handle_,
|
| - hw_params,
|
| - SND_PCM_FORMAT_S16_LE)) < 0) {
|
| - LOG(INFO) << "Can't set 16-bit: " << snd_strerror(err) << "\n";
|
| - return false;
|
| - }
|
| -
|
| - if ((err = snd_pcm_hw_params_set_rate(pcm_out_handle_,
|
| - hw_params,
|
| - 44100,
|
| - 0)) < 0) {
|
| - LOG(INFO) << "Can't set rate to 44100: " << snd_strerror(err) << "\n";
|
| - return false;
|
| - }
|
| -
|
| - if ((err = snd_pcm_hw_params_set_channels(pcm_out_handle_,
|
| - hw_params,
|
| - 1)) < 0) {
|
| - LOG(INFO) << "Can't set channels to 1: " << snd_strerror(err) << "\n";
|
| - return false;
|
| - }
|
| -
|
| - int dir = 0;
|
| - snd_pcm_uframes_t desired_period = 512;
|
| - if ((err = snd_pcm_hw_params_set_period_size_near(
|
| - pcm_out_handle_, hw_params, &desired_period, &dir)) < 0) {
|
| - LOG(INFO) << "Can't set period size: " << snd_strerror(err) << "\n";
|
| + sample_rate_ = 44100;
|
| + channel_count_ = 1;
|
| + int soft_resample = 1;
|
| + unsigned int latency_us = 50000;
|
| + if ((err = snd_pcm_set_params(pcm_out_handle_,
|
| + SND_PCM_FORMAT_S16_LE,
|
| + SND_PCM_ACCESS_RW_INTERLEAVED,
|
| + channel_count_,
|
| + sample_rate_,
|
| + soft_resample,
|
| + latency_us)) < 0) {
|
| + LOG(INFO) << "Can't set pcm parameters " << snd_strerror(err);
|
| return false;
|
| }
|
|
|
| - snd_pcm_uframes_t period_size;
|
| - snd_pcm_hw_params_get_period_size(hw_params, &period_size, &dir);
|
| - chunk_size_ = static_cast<int>(period_size);
|
| -
|
| - snd_pcm_uframes_t desired_buffer_size = period_size * 4;
|
| - if ((err = snd_pcm_hw_params_set_buffer_size(
|
| - pcm_out_handle_, hw_params, desired_buffer_size)) < 0) {
|
| - LOG(INFO) << "Can't set buffer size: " << snd_strerror(err) << "\n";
|
| - return false;
|
| - }
|
| -
|
| - snd_pcm_uframes_t buffer_size;
|
| - snd_pcm_hw_params_get_buffer_size(hw_params, &buffer_size);
|
| - total_buffer_size_ = static_cast<int>(buffer_size);
|
| -
|
| - unsigned int rate;
|
| - snd_pcm_hw_params_get_rate(hw_params, &rate, &dir);
|
| - sample_rate_ = rate;
|
| -
|
| - unsigned int channels;
|
| - snd_pcm_hw_params_get_channels(hw_params, &channels);
|
| - channel_count_ = channels;
|
| -
|
| - if ((err = snd_pcm_hw_params(pcm_out_handle_, hw_params)) < 0) {
|
| - LOG(INFO) << "Can't set hardware params: " << snd_strerror(err) << "\n";
|
| + snd_pcm_uframes_t buffer_size = 0;
|
| + snd_pcm_uframes_t period_size = 0;
|
| + if ((err = snd_pcm_get_params(pcm_out_handle_, &buffer_size, &period_size))
|
| + < 0) {
|
| + LOG(INFO) << "Can't get pcm parameters: " << snd_strerror(err);
|
| return false;
|
| }
|
|
|
| - snd_pcm_hw_params_free(hw_params);
|
| + chunk_size_ = period_size;
|
| + total_buffer_size_ = buffer_size;
|
|
|
| if ((err = snd_pcm_prepare(pcm_out_handle_)) < 0) {
|
| LOG(INFO) << "Can't prepare: " << snd_strerror(err) << "\n";
|
| @@ -185,7 +187,11 @@ class LinuxAlsaAudioOutput : public AudioOutput, public Runnable {
|
| static_cast<snd_pcm_uframes_t>(chunk_size));
|
| if (err < 0) {
|
| LOG(INFO) << "Write error: " << err << snd_strerror(err) << "\n";
|
| - return;
|
| + do {
|
| + sleep(1);
|
| + LOG(INFO) << "Attempting to recover audio";
|
| + } while (keep_running_ &&
|
| + 0 != snd_pcm_recover(pcm_out_handle_, err, 0));
|
| }
|
| }
|
|
|
|
|