hardware/libaudio
リビジョン | cea954f274111f7b63a6d79f3dc697a24297b0c3 (tree) |
---|---|
日時 | 2016-08-05 18:21:00 |
作者 | Chih-Wei Huang <cwhuang@linu...> |
コミッター | Chih-Wei Huang |
audio_hw: search sound card more properly
Scan /dev/snd/ to find the appropriate sound card.
Ignore IntelHDMI since it's handled by another HAL.
@@ -17,7 +17,9 @@ | ||
17 | 17 | #define LOG_TAG "audio_hw_primary" |
18 | 18 | /*#define LOG_NDEBUG 0*/ |
19 | 19 | |
20 | +#include <dirent.h> | |
20 | 21 | #include <errno.h> |
22 | +#include <fcntl.h> | |
21 | 23 | #include <pthread.h> |
22 | 24 | #include <stdint.h> |
23 | 25 | #include <stdlib.h> |
@@ -32,6 +34,8 @@ | ||
32 | 34 | |
33 | 35 | #include <system/audio.h> |
34 | 36 | |
37 | +#include <linux/ioctl.h> | |
38 | +#include <sound/asound.h> | |
35 | 39 | #include <tinyalsa/asoundlib.h> |
36 | 40 | |
37 | 41 | #include <audio_utils/resampler.h> |
@@ -173,30 +177,62 @@ static void release_buffer(struct resampler_buffer_provider *buffer_provider, | ||
173 | 177 | |
174 | 178 | /* Helper functions */ |
175 | 179 | |
176 | -static int select_card(int d) | |
180 | +struct snd_pcm_info *select_card(unsigned int device __unused, unsigned int flags) | |
177 | 181 | { |
178 | - int i; | |
179 | - char dname[32]; | |
180 | - for (i = 0; i < 3; ++i) { | |
181 | - sprintf(dname, "/dev/snd/pcmC%dD0%c", i, (d == PCM_IN) ? 'c' : 'p'); | |
182 | - if (!access(dname, R_OK | W_OK)) { | |
183 | - ALOGD("found %s %s", (d == PCM_IN) ? "in" : "out", dname); | |
184 | - return i; | |
182 | + static struct snd_pcm_info *cached_info[2]; | |
183 | + int d = !!(flags & PCM_IN); | |
184 | + if (!cached_info[d]) { | |
185 | + struct dirent **namelist; | |
186 | + char path[PATH_MAX] = "/dev/snd/"; | |
187 | + int n = scandir(path, &namelist, NULL, alphasort); | |
188 | + if (n >= 0) { | |
189 | + int i, fd; | |
190 | + struct snd_pcm_info *info = malloc(sizeof(*info)); | |
191 | + for (i = 0; i < n; i++) { | |
192 | + struct dirent *de = namelist[i]; | |
193 | + if (!cached_info[d] && !strncmp(de->d_name, "pcmC", 4)) { | |
194 | + strcpy(path + 9, de->d_name); | |
195 | + if ((fd = open(path, O_RDWR)) >= 0) { | |
196 | + if (!ioctl(fd, SNDRV_PCM_IOCTL_INFO, info)) { | |
197 | + if (info->stream == d && /* ignore IntelHDMI */ | |
198 | + !strstr((const char *)info->id, "IntelHDMI")) { | |
199 | + ALOGD("found audio %s at %s\ncard: %d/%d id: %s\nname: %s\nsubname: %s\nstream: %d", | |
200 | + d ? "in" : "out", path, | |
201 | + info->card, info->device, info->id, | |
202 | + info->name, info->subname, info->stream); | |
203 | + cached_info[d] = info; | |
204 | + } | |
205 | + } else { | |
206 | + ALOGV("can't get info of %s", path); | |
207 | + } | |
208 | + close(fd); | |
209 | + } | |
210 | + } | |
211 | + free(de); | |
212 | + } | |
213 | + free(namelist); | |
214 | + if (!cached_info[d]) { | |
215 | + free(info); | |
216 | + } | |
185 | 217 | } |
186 | 218 | } |
187 | - ALOGE("no pcm card found!"); | |
188 | - return -1; | |
219 | + return cached_info[d]; | |
189 | 220 | } |
190 | 221 | |
191 | -struct pcm *my_pcm_open(unsigned int card, unsigned int device, unsigned int flags, struct pcm_config *config) | |
222 | +struct pcm *my_pcm_open(unsigned int device, unsigned int flags, struct pcm_config *config) | |
192 | 223 | { |
193 | - struct pcm *pcm = pcm_open(card, device, flags, config); | |
224 | + struct snd_pcm_info *info = select_card(device, flags); | |
225 | + if (!info) { | |
226 | + ALOGE("unable to find a sound card"); | |
227 | + return NULL; | |
228 | + } | |
229 | + struct pcm *pcm = pcm_open(info->card, info->device, flags, config); | |
194 | 230 | if (pcm && !pcm_is_ready(pcm)) { |
195 | 231 | ALOGE("my_pcm_open(%d) failed: %s", flags, pcm_get_error(pcm)); |
196 | 232 | pcm_close(pcm); |
197 | - ALOGI("my_pcm_open: re-try 44100 on card %d", card); | |
233 | + ALOGI("my_pcm_open: re-try 44100 on card %d/%d", info->card, info->device); | |
198 | 234 | config->rate = 44100; |
199 | - pcm = pcm_open(card, device, flags, config); | |
235 | + pcm = pcm_open(info->card, info->device, flags, config); | |
200 | 236 | } |
201 | 237 | return pcm; |
202 | 238 | } |
@@ -317,13 +353,10 @@ static int start_output_stream(struct stream_out *out) | ||
317 | 353 | pthread_mutex_unlock(&in->lock); |
318 | 354 | } |
319 | 355 | |
320 | - ret = select_card(PCM_OUT); | |
321 | - if (ret < 0) { | |
356 | + out->pcm = my_pcm_open(device, PCM_OUT | PCM_NORESTART, out->pcm_config); | |
357 | + if (!out->pcm) { | |
322 | 358 | return -ENODEV; |
323 | - } | |
324 | - out->pcm = my_pcm_open(ret, device, PCM_OUT | PCM_NORESTART, out->pcm_config); | |
325 | - | |
326 | - if (out->pcm && !pcm_is_ready(out->pcm)) { | |
359 | + } else if (!pcm_is_ready(out->pcm)) { | |
327 | 360 | ALOGE("pcm_open(out) failed: %s", pcm_get_error(out->pcm)); |
328 | 361 | pcm_close(out->pcm); |
329 | 362 | return -ENOMEM; |
@@ -389,13 +422,10 @@ static int start_input_stream(struct stream_in *in) | ||
389 | 422 | pthread_mutex_unlock(&out->lock); |
390 | 423 | } |
391 | 424 | |
392 | - ret = select_card(PCM_IN); | |
393 | - if (ret < 0) { | |
425 | + in->pcm = my_pcm_open(device, PCM_IN, in->pcm_config); | |
426 | + if (!in->pcm) { | |
394 | 427 | return -ENODEV; |
395 | - } | |
396 | - in->pcm = my_pcm_open(ret, device, PCM_IN, in->pcm_config); | |
397 | - | |
398 | - if (in->pcm && !pcm_is_ready(in->pcm)) { | |
428 | + } else if (!pcm_is_ready(in->pcm)) { | |
399 | 429 | ALOGE("pcm_open(in) failed: %s", pcm_get_error(in->pcm)); |
400 | 430 | pcm_close(in->pcm); |
401 | 431 | return -ENOMEM; |
@@ -1028,6 +1058,9 @@ static int adev_open_output_stream(struct audio_hw_device *dev, | ||
1028 | 1058 | struct stream_out *out; |
1029 | 1059 | int ret; |
1030 | 1060 | |
1061 | + if (!select_card(0, PCM_OUT)) | |
1062 | + return -ENODEV; | |
1063 | + | |
1031 | 1064 | out = (struct stream_out *)calloc(1, sizeof(struct stream_out)); |
1032 | 1065 | if (!out) |
1033 | 1066 | return -ENOMEM; |