Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(113)

Side by Side Diff: linux/audio_output_alsa.cc

Issue 6299025: dmazzoni's fixes to ALSA for speech_synthesis (Closed) Base URL: ssh://git@gitrw.chromium.org:9222/speech_synthesis.git@master
Patch Set: Created 9 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | tts_service.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. 1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 // 4 //
5 // Implementation of audio output using the Linux ALSA interface. 5 // Implementation of audio output using the Linux ALSA interface.
6 6
7 #include <fcntl.h> 7 #include <fcntl.h>
8 #include <stdio.h> 8 #include <stdio.h>
9 9
10 #include <alsa/asoundlib.h> 10 #include <alsa/asoundlib.h>
11 11
12 #include "audio_output.h" 12 #include "audio_output.h"
13 #include "log.h" 13 #include "log.h"
14 #include "threading.h" 14 #include "threading.h"
15 15
16 namespace {
17
18 bool isDeviceReady() {
19 snd_ctl_card_info_t *card_info;
20 snd_ctl_card_info_alloca(&card_info);
21
22 snd_pcm_info_t *pcm_info;
23 snd_pcm_info_alloca(&pcm_info);
24
25 int valid_playback_devices = 0;
26 int card_index = -1;
27
28 while(snd_card_next(&card_index) == 0 && card_index >= 0) {
29 char card_name[20];
30 snprintf(card_name, sizeof(card_name), "hw:%d", card_index);
31 LOG(INFO) << "Checking ALSA sound card " << card_name;
32
33 snd_ctl_t *ctl;
34 if(snd_ctl_open(&ctl, card_name, 0) < 0)
35 continue;
36
37 snd_ctl_card_info(ctl, card_info);
38
39 int dev_index = -1;
40 while (snd_ctl_pcm_next_device(ctl, &dev_index) == 0 && dev_index >= 0) {
41 char device_name[30];
42 snprintf(device_name, sizeof(device_name),
43 "hw:%d,%d", card_index, dev_index);
44 LOG(INFO) << "Checking ALSA sound device " << device_name;
45
46 /* Obtain info about this particular device */
47 snd_pcm_info_set_device(pcm_info, dev_index);
48 snd_pcm_info_set_subdevice(pcm_info, 0);
49 snd_pcm_info_set_stream(pcm_info, SND_PCM_STREAM_PLAYBACK);
50 if (snd_ctl_pcm_info(ctl, pcm_info) >= 0) {
51 LOG(INFO) << " Valid playback device: " << device_name;
52 valid_playback_devices++;
53 }
54 }
55 snd_ctl_close(ctl);
56 }
57
58 LOG(INFO) << "Total valid playback devices: " << valid_playback_devices;
59 if (valid_playback_devices == 0) {
60 return false;
61 }
62 return true;
63 }
64
65 }
66
16 namespace speech_synthesis { 67 namespace speech_synthesis {
17 68
18 class LinuxAlsaAudioOutput : public AudioOutput, public Runnable { 69 class LinuxAlsaAudioOutput : public AudioOutput, public Runnable {
19 public: 70 public:
20 explicit LinuxAlsaAudioOutput(Threading* threading) 71 explicit LinuxAlsaAudioOutput(Threading* threading)
21 : threading_(threading), 72 : threading_(threading),
22 provider_(NULL) { 73 provider_(NULL) {
23 } 74 }
24 75
25 bool Init(AudioProvider *provider) { 76 bool Init(AudioProvider *provider) {
26 if (!provider) { 77 if (!provider) {
27 LOG(ERROR) << "An AudioProvider is required.\n"; 78 LOG(ERROR) << "An AudioProvider is required.\n";
28 return false; 79 return false;
29 } 80 }
30 81
31 if (provider_) { 82 if (provider_) {
32 return true; 83 return true;
33 } 84 }
34 85
86 if (!isDeviceReady()) {
87 return false;
88 }
89
35 int err; 90 int err;
36 if ((err = snd_pcm_open(&pcm_out_handle_, 91 if ((err = snd_pcm_open(&pcm_out_handle_,
37 "plughw:0,0", 92 "default",
38 SND_PCM_STREAM_PLAYBACK, 93 SND_PCM_STREAM_PLAYBACK,
39 0)) < 0) { 94 0)) < 0) {
40 LOG(INFO) << "Can't open wave output: " << snd_strerror(err) << "\n"; 95 LOG(INFO) << "Can't open wave output: " << snd_strerror(err) << "\n";
41 return false; 96 return false;
42 } 97 }
43 98
44 snd_pcm_hw_params_t *hw_params; 99 sample_rate_ = 44100;
45 if ((err = snd_pcm_hw_params_malloc(&hw_params)) < 0) { 100 channel_count_ = 1;
46 LOG(INFO) << "Can't alloc sound hardware struct " << 101 int soft_resample = 1;
47 snd_strerror(err) << "\n"; 102 unsigned int latency_us = 50000;
103 if ((err = snd_pcm_set_params(pcm_out_handle_,
104 SND_PCM_FORMAT_S16_LE,
105 SND_PCM_ACCESS_RW_INTERLEAVED,
106 channel_count_,
107 sample_rate_,
108 soft_resample,
109 latency_us)) < 0) {
110 LOG(INFO) << "Can't set pcm parameters " << snd_strerror(err);
48 return false; 111 return false;
49 } 112 }
50 113
51 if ((err = snd_pcm_hw_params_any(pcm_out_handle_, hw_params)) < 0) { 114 snd_pcm_uframes_t buffer_size = 0;
52 LOG(INFO) << "Can't init sound hardware struct: " << 115 snd_pcm_uframes_t period_size = 0;
53 snd_strerror(err) << "\n"; 116 if ((err = snd_pcm_get_params(pcm_out_handle_, &buffer_size, &period_size))
117 < 0) {
118 LOG(INFO) << "Can't get pcm parameters: " << snd_strerror(err);
54 return false; 119 return false;
55 } 120 }
56 121
57 if ((err = snd_pcm_hw_params_set_access( 122 chunk_size_ = period_size;
58 pcm_out_handle_, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { 123 total_buffer_size_ = buffer_size;
59 LOG(INFO) << "Can't set access: " << snd_strerror(err) << "\n";
60 return false;
61 }
62
63 if ((err = snd_pcm_hw_params_set_format(pcm_out_handle_,
64 hw_params,
65 SND_PCM_FORMAT_S16_LE)) < 0) {
66 LOG(INFO) << "Can't set 16-bit: " << snd_strerror(err) << "\n";
67 return false;
68 }
69
70 if ((err = snd_pcm_hw_params_set_rate(pcm_out_handle_,
71 hw_params,
72 44100,
73 0)) < 0) {
74 LOG(INFO) << "Can't set rate to 44100: " << snd_strerror(err) << "\n";
75 return false;
76 }
77
78 if ((err = snd_pcm_hw_params_set_channels(pcm_out_handle_,
79 hw_params,
80 1)) < 0) {
81 LOG(INFO) << "Can't set channels to 1: " << snd_strerror(err) << "\n";
82 return false;
83 }
84
85 int dir = 0;
86 snd_pcm_uframes_t desired_period = 512;
87 if ((err = snd_pcm_hw_params_set_period_size_near(
88 pcm_out_handle_, hw_params, &desired_period, &dir)) < 0) {
89 LOG(INFO) << "Can't set period size: " << snd_strerror(err) << "\n";
90 return false;
91 }
92
93 snd_pcm_uframes_t period_size;
94 snd_pcm_hw_params_get_period_size(hw_params, &period_size, &dir);
95 chunk_size_ = static_cast<int>(period_size);
96
97 snd_pcm_uframes_t desired_buffer_size = period_size * 4;
98 if ((err = snd_pcm_hw_params_set_buffer_size(
99 pcm_out_handle_, hw_params, desired_buffer_size)) < 0) {
100 LOG(INFO) << "Can't set buffer size: " << snd_strerror(err) << "\n";
101 return false;
102 }
103
104 snd_pcm_uframes_t buffer_size;
105 snd_pcm_hw_params_get_buffer_size(hw_params, &buffer_size);
106 total_buffer_size_ = static_cast<int>(buffer_size);
107
108 unsigned int rate;
109 snd_pcm_hw_params_get_rate(hw_params, &rate, &dir);
110 sample_rate_ = rate;
111
112 unsigned int channels;
113 snd_pcm_hw_params_get_channels(hw_params, &channels);
114 channel_count_ = channels;
115
116 if ((err = snd_pcm_hw_params(pcm_out_handle_, hw_params)) < 0) {
117 LOG(INFO) << "Can't set hardware params: " << snd_strerror(err) << "\n";
118 return false;
119 }
120
121 snd_pcm_hw_params_free(hw_params);
122 124
123 if ((err = snd_pcm_prepare(pcm_out_handle_)) < 0) { 125 if ((err = snd_pcm_prepare(pcm_out_handle_)) < 0) {
124 LOG(INFO) << "Can't prepare: " << snd_strerror(err) << "\n"; 126 LOG(INFO) << "Can't prepare: " << snd_strerror(err) << "\n";
125 return false; 127 return false;
126 } 128 }
127 129
128 keep_running_ = true; 130 keep_running_ = true;
129 provider_ = provider; 131 provider_ = provider;
130 return true; 132 return true;
131 } 133 }
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
178 if (!provider_->FillAudioBuffer(chunk, chunk_size)) { 180 if (!provider_->FillAudioBuffer(chunk, chunk_size)) {
179 LOG(INFO) << "Could not fill audio buffer\n"; 181 LOG(INFO) << "Could not fill audio buffer\n";
180 break; 182 break;
181 } 183 }
182 184
183 int err = snd_pcm_writei(pcm_out_handle_, 185 int err = snd_pcm_writei(pcm_out_handle_,
184 static_cast<void *>(chunk), 186 static_cast<void *>(chunk),
185 static_cast<snd_pcm_uframes_t>(chunk_size)); 187 static_cast<snd_pcm_uframes_t>(chunk_size));
186 if (err < 0) { 188 if (err < 0) {
187 LOG(INFO) << "Write error: " << err << snd_strerror(err) << "\n"; 189 LOG(INFO) << "Write error: " << err << snd_strerror(err) << "\n";
188 return; 190 do {
191 sleep(1);
192 LOG(INFO) << "Attempting to recover audio";
193 } while (keep_running_ &&
194 0 != snd_pcm_recover(pcm_out_handle_, err, 0));
189 } 195 }
190 } 196 }
191 197
192 delete[] chunk; 198 delete[] chunk;
193 } 199 }
194 200
195 private: 201 private:
196 volatile bool keep_running_; 202 volatile bool keep_running_;
197 Threading* threading_; 203 Threading* threading_;
198 AudioProvider* provider_; 204 AudioProvider* provider_;
199 Thread* thread_; 205 Thread* thread_;
200 snd_pcm_t *pcm_out_handle_; 206 snd_pcm_t *pcm_out_handle_;
201 int sample_rate_; 207 int sample_rate_;
202 int channel_count_; 208 int channel_count_;
203 int chunk_size_; 209 int chunk_size_;
204 int total_buffer_size_; 210 int total_buffer_size_;
205 }; 211 };
206 212
207 AudioOutput* AudioOutput::Create(Threading* threading) { 213 AudioOutput* AudioOutput::Create(Threading* threading) {
208 return new LinuxAlsaAudioOutput(threading); 214 return new LinuxAlsaAudioOutput(threading);
209 } 215 }
210 216
211 } // namespace speech_synthesis 217 } // namespace speech_synthesis
212 218
OLDNEW
« no previous file with comments | « no previous file | tts_service.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698