blob: ad2647ade6b18519196c1a8b661e7869e3c303c8 [file] [log] [blame]
Simon Wilson15f60a82012-04-24 20:56:32 -07001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "audio_hw_primary"
18/*#define LOG_NDEBUG 0*/
19
20#include <errno.h>
21#include <pthread.h>
22#include <stdint.h>
23#include <stdlib.h>
24#include <sys/time.h>
25
26#include <cutils/log.h>
27#include <cutils/properties.h>
28#include <cutils/str_parms.h>
29
30#include <hardware/audio.h>
31#include <hardware/hardware.h>
32
33#include <system/audio.h>
34
35#include <tinyalsa/asoundlib.h>
36
37#include <audio_utils/resampler.h>
38
39#include "audio_route.h"
40
41#define PCM_CARD 0
Simon Wilson56d84e22012-08-17 13:55:27 -070042#define PCM_CARD_SPDIF 1
43#define PCM_TOTAL 2
44
Simon Wilson15f60a82012-04-24 20:56:32 -070045#define PCM_DEVICE 0
46
47struct pcm_config pcm_config = {
48 .channels = 2,
49 .rate = 44100,
Glenn Kastenb9366272012-07-18 14:06:12 -070050 .period_size = 512,
51 .period_count = 2,
Simon Wilson15f60a82012-04-24 20:56:32 -070052 .format = PCM_FORMAT_S16_LE,
53};
54
55struct audio_device {
56 struct audio_hw_device hw_device;
57
58 pthread_mutex_t lock; /* see note below on mutex acquisition order */
59 unsigned int devices;
Simon Wilson15f60a82012-04-24 20:56:32 -070060 bool mic_mute;
61 struct audio_route *ar;
Eric Laurent87532032012-07-16 13:53:20 -070062 audio_source_t input_source;
63 int cur_route_id; /* current route ID: combination of input source
64 * and output device IDs */
Simon Wilson15f60a82012-04-24 20:56:32 -070065};
66
67struct stream_out {
68 struct audio_stream_out stream;
69
70 pthread_mutex_t lock; /* see note below on mutex acquisition order */
Simon Wilson56d84e22012-08-17 13:55:27 -070071 struct pcm *pcm[PCM_TOTAL];
72 bool standby; /* true if all PCMs are inactive */
Eric Laurent87532032012-07-16 13:53:20 -070073 unsigned int device;
Simon Wilson15f60a82012-04-24 20:56:32 -070074
75 struct audio_device *dev;
76};
77
78struct stream_in {
79 struct audio_stream_in stream;
80
81 pthread_mutex_t lock; /* see note below on mutex acquisition order */
82 struct pcm *pcm;
83 bool standby;
84
85 unsigned int requested_rate;
86 struct resampler_itfe *resampler;
87 struct resampler_buffer_provider buf_provider;
88 int16_t *buffer;
89 size_t frames_in;
90 int read_status;
Eric Laurent87532032012-07-16 13:53:20 -070091 audio_source_t input_source;
Simon Wilson15f60a82012-04-24 20:56:32 -070092
93 struct audio_device *dev;
94};
95
Eric Laurent87532032012-07-16 13:53:20 -070096enum {
97 OUT_DEVICE_SPEAKER,
98 OUT_DEVICE_HEADSET,
99 OUT_DEVICE_HEADPHONES,
100 OUT_DEVICE_BT_SCO,
101 OUT_DEVICE_SPEAKER_AND_HEADSET,
102 OUT_DEVICE_TAB_SIZE, /* number of rows in route_configs[][] */
103 OUT_DEVICE_NONE,
104 OUT_DEVICE_INVALID,
105 OUT_DEVICE_CNT
106};
107
108enum {
109 IN_SOURCE_MIC,
110 IN_SOURCE_CAMCORDER,
111 IN_SOURCE_VOICE_RECOGNITION,
112 IN_SOURCE_VOICE_COMMUNICATION,
113 IN_SOURCE_TAB_SIZE, /* number of lines in route_configs[][] */
114 IN_SOURCE_NONE,
115 IN_SOURCE_INVALID,
116 IN_SOURCE_CNT
117};
118
119int get_output_device_id(unsigned int device)
120{
121 device &= AUDIO_DEVICE_OUT_ALL;
122
123 if (device == 0)
124 return OUT_DEVICE_NONE;
125
126 if (popcount(device) == 2) {
127 if ((device == (AUDIO_DEVICE_OUT_SPEAKER |
128 AUDIO_DEVICE_OUT_WIRED_HEADSET)) ||
129 (device == (AUDIO_DEVICE_OUT_SPEAKER |
130 AUDIO_DEVICE_OUT_WIRED_HEADPHONE)))
131 return OUT_DEVICE_SPEAKER_AND_HEADSET;
132 else
133 return OUT_DEVICE_INVALID;
134 }
135
136 if (popcount(device) != 1)
137 return OUT_DEVICE_INVALID;
138
139 switch (device) {
140 case AUDIO_DEVICE_OUT_SPEAKER:
141 return OUT_DEVICE_SPEAKER;
142 case AUDIO_DEVICE_OUT_WIRED_HEADSET:
143 return OUT_DEVICE_HEADSET;
144 case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
145 return OUT_DEVICE_HEADPHONES;
146 case AUDIO_DEVICE_OUT_BLUETOOTH_SCO:
147 case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
148 case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
149 return OUT_DEVICE_BT_SCO;
150 default:
151 return OUT_DEVICE_INVALID;
152 }
153}
154
155int get_input_source_id(audio_source_t source)
156{
157 switch (source) {
158 case AUDIO_SOURCE_DEFAULT:
159 return IN_SOURCE_NONE;
160 case AUDIO_SOURCE_MIC:
161 return IN_SOURCE_MIC;
162 case AUDIO_SOURCE_CAMCORDER:
163 return IN_SOURCE_CAMCORDER;
164 case AUDIO_SOURCE_VOICE_RECOGNITION:
165 return IN_SOURCE_VOICE_RECOGNITION;
166 case AUDIO_SOURCE_VOICE_COMMUNICATION:
167 return IN_SOURCE_VOICE_COMMUNICATION;
168 default:
169 return IN_SOURCE_INVALID;
170 }
171}
172
173struct route_config {
174 const char * const output_route;
175 const char * const input_route;
176 /* TODO add other properties here: es305 presets... */
177};
178
179const struct route_config media_speaker = {
180 "media-speaker",
181 "media-main-mic"
182};
183
184const struct route_config media_headphones = {
185 "media-headphones",
186 "media-main-mic"
187};
188
189const struct route_config media_headset = {
190 "media-headphones",
191 "media-headset-mic"
192};
193
194const struct route_config camcorder_speaker = {
195 "media-speaker",
196 "media-second-mic"
197};
198
199const struct route_config camcorder_headphones = {
200 "media-headphones",
201 "media-second-mic"
202};
203
204const struct route_config voice_rec_speaker = {
205 "voice-rec-speaker",
206 "voice-rec-main-mic"
207};
208
209const struct route_config voice_rec_headphones = {
210 "voice-rec-headphones",
211 "voice-rec-main-mic"
212};
213
214const struct route_config voice_rec_headset = {
215 "voice-rec-headphones",
216 "voice-rec-headset-mic"
217};
218
219const struct route_config communication_speaker = {
220 "communication-speaker",
221 "communication-main-mic"
222};
223
224const struct route_config communication_headphones = {
225 "communication-headphones",
226 "communication-main-mic"
227};
228
229const struct route_config communication_headset = {
230 "communication-headphones",
231 "communication-headset-mic"
232};
233
234const struct route_config speaker_and_headphones = {
235 "speaker-and-headphones",
236 "main-mic"
237};
238
239const struct route_config bluetooth_sco = {
240 "bt-sco-headset",
241 "bt-sco-mic"
242};
243
244const struct route_config * const route_configs[IN_SOURCE_TAB_SIZE]
245 [OUT_DEVICE_TAB_SIZE] = {
246 { /* IN_SOURCE_MIC */
247 &media_speaker, /* OUT_DEVICE_SPEAKER */
248 &media_headset, /* OUT_DEVICE_HEADSET */
249 &media_headphones, /* OUT_DEVICE_HEADPHONES */
250 &bluetooth_sco, /* OUT_DEVICE_BT_SCO */
251 &speaker_and_headphones /* OUT_DEVICE_SPEAKER_AND_HEADSET */
252 },
253 { /* IN_SOURCE_CAMCORDER */
254 &camcorder_speaker, /* OUT_DEVICE_SPEAKER */
255 &camcorder_headphones, /* OUT_DEVICE_HEADSET */
256 &camcorder_headphones, /* OUT_DEVICE_HEADPHONES */
257 &bluetooth_sco, /* OUT_DEVICE_BT_SCO */
258 &speaker_and_headphones /* OUT_DEVICE_SPEAKER_AND_HEADSET */
259 },
260 { /* IN_SOURCE_VOICE_RECOGNITION */
261 &voice_rec_speaker, /* OUT_DEVICE_SPEAKER */
262 &voice_rec_headset, /* OUT_DEVICE_HEADSET */
263 &voice_rec_headphones, /* OUT_DEVICE_HEADPHONES */
264 &bluetooth_sco, /* OUT_DEVICE_BT_SCO */
265 &speaker_and_headphones /* OUT_DEVICE_SPEAKER_AND_HEADSET */
266 },
267 { /* IN_SOURCE_VOICE_COMMUNICATION */
268 &communication_speaker, /* OUT_DEVICE_SPEAKER */
269 &communication_headset, /* OUT_DEVICE_HEADSET */
270 &communication_headphones, /* OUT_DEVICE_HEADPHONES */
271 &bluetooth_sco, /* OUT_DEVICE_BT_SCO */
272 &speaker_and_headphones /* OUT_DEVICE_SPEAKER_AND_HEADSET */
273 }
274};
275
Simon Wilson15f60a82012-04-24 20:56:32 -0700276/**
277 * NOTE: when multiple mutexes have to be acquired, always respect the
278 * following order: hw device > in stream > out stream
279 */
280
281/* Helper functions */
282
283static void select_devices(struct audio_device *adev)
284{
Eric Laurent87532032012-07-16 13:53:20 -0700285 int output_device_id = get_output_device_id(adev->devices);
286 int input_source_id = get_input_source_id(adev->input_source);
Simon Wilsonc4006be2012-08-17 11:23:38 -0700287 const char *output_route = NULL;
288 const char *input_route = NULL;
Eric Laurent87532032012-07-16 13:53:20 -0700289 int new_route_id;
Simon Wilson15f60a82012-04-24 20:56:32 -0700290
Simon Wilsonc4006be2012-08-17 11:23:38 -0700291 reset_mixer_state(adev->ar);
292
Eric Laurent87532032012-07-16 13:53:20 -0700293 if (output_device_id == OUT_DEVICE_INVALID ||
294 input_source_id == IN_SOURCE_INVALID) {
295 ALOGV("select_devices() invalid device %#x or source %d",
296 adev->devices, adev->input_source);
297 return;
298 }
Simon Wilson15f60a82012-04-24 20:56:32 -0700299
Eric Laurent87532032012-07-16 13:53:20 -0700300 new_route_id = (1 << (input_source_id + OUT_DEVICE_CNT)) + (1 << output_device_id);
301 if (new_route_id == adev->cur_route_id)
302 return;
303 adev->cur_route_id = new_route_id;
Simon Wilson15f60a82012-04-24 20:56:32 -0700304
Eric Laurent87532032012-07-16 13:53:20 -0700305 if (input_source_id != IN_SOURCE_NONE) {
306 if (output_device_id != OUT_DEVICE_NONE) {
307 input_route =
308 route_configs[input_source_id][output_device_id]->input_route;
309 output_route =
310 route_configs[input_source_id][output_device_id]->output_route;
311 } else {
312 input_route =
313 route_configs[input_source_id][OUT_DEVICE_SPEAKER]->input_route;
314 }
315 } else {
316 if (output_device_id != OUT_DEVICE_NONE) {
317 output_route =
318 route_configs[IN_SOURCE_MIC][output_device_id]->output_route;
319 }
320 }
321
322 ALOGV("select_devices() devices %#x input src %d output route %s input route %s",
323 adev->devices, adev->input_source,
Simon Wilsonc4006be2012-08-17 11:23:38 -0700324 output_route ? output_route : "none",
325 input_route ? input_route : "none");
Eric Laurent87532032012-07-16 13:53:20 -0700326
Simon Wilsonc4006be2012-08-17 11:23:38 -0700327 if (output_route)
328 audio_route_apply_path(adev->ar, output_route);
329 if (input_route)
330 audio_route_apply_path(adev->ar, input_route);
Simon Wilson15f60a82012-04-24 20:56:32 -0700331
332 update_mixer_state(adev->ar);
333
Simon Wilson15f60a82012-04-24 20:56:32 -0700334}
335
336/* must be called with hw device and output stream mutexes locked */
337static int start_output_stream(struct stream_out *out)
338{
339 struct audio_device *adev = out->dev;
340
Simon Wilson56d84e22012-08-17 13:55:27 -0700341 if (out->device & (AUDIO_DEVICE_OUT_SPEAKER |
342 AUDIO_DEVICE_OUT_WIRED_HEADSET |
343 AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
344 AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
345 out->pcm[PCM_CARD] = pcm_open(PCM_CARD, PCM_DEVICE,
346 PCM_OUT, &pcm_config);
Simon Wilson15f60a82012-04-24 20:56:32 -0700347
Simon Wilson56d84e22012-08-17 13:55:27 -0700348 if (out->pcm[PCM_CARD] && !pcm_is_ready(out->pcm[PCM_CARD])) {
349 ALOGE("pcm_open(PCM_CARD) failed: %s",
350 pcm_get_error(out->pcm[PCM_CARD]));
351 pcm_close(out->pcm[PCM_CARD]);
352 return -ENOMEM;
353 }
354 }
355
356 if (out->device & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) {
357 out->pcm[PCM_CARD_SPDIF] = pcm_open(PCM_CARD_SPDIF, PCM_DEVICE,
358 PCM_OUT, &pcm_config);
359
360 if (out->pcm[PCM_CARD_SPDIF] &&
361 !pcm_is_ready(out->pcm[PCM_CARD_SPDIF])) {
362 ALOGE("pcm_open(PCM_CARD_SPDIF) failed: %s",
363 pcm_get_error(out->pcm[PCM_CARD_SPDIF]));
364 pcm_close(out->pcm[PCM_CARD_SPDIF]);
365 return -ENOMEM;
366 }
Simon Wilson15f60a82012-04-24 20:56:32 -0700367 }
368
Eric Laurent87532032012-07-16 13:53:20 -0700369 adev->devices &= ~AUDIO_DEVICE_OUT_ALL;
370 adev->devices |= out->device;
371 select_devices(adev);
372
Simon Wilson15f60a82012-04-24 20:56:32 -0700373 return 0;
374}
375
376/* must be called with hw device and input stream mutexes locked */
377static int start_input_stream(struct stream_in *in)
378{
379 struct audio_device *adev = in->dev;
380
381 in->pcm = pcm_open(PCM_CARD, PCM_DEVICE, PCM_IN, &pcm_config);
382
383 if (in->pcm && !pcm_is_ready(in->pcm)) {
384 ALOGE("pcm_open() failed: %s", pcm_get_error(in->pcm));
385 pcm_close(in->pcm);
386 return -ENOMEM;
387 }
388
389 /* if no supported sample rate is available, use the resampler */
390 if (in->resampler)
391 in->resampler->reset(in->resampler);
392
Eric Laurentf4231822012-08-22 16:06:38 -0700393 in->frames_in = 0;
Eric Laurent87532032012-07-16 13:53:20 -0700394 adev->input_source = in->input_source;
395 select_devices(adev);
396
Simon Wilson15f60a82012-04-24 20:56:32 -0700397 return 0;
398}
399
400static size_t get_input_buffer_size(unsigned int sample_rate,
401 audio_format_t format,
402 unsigned int channel_count)
403{
404 size_t size;
405
406 /*
407 * take resampling into account and return the closest majoring
408 * multiple of 16 frames, as audioflinger expects audio buffers to
409 * be a multiple of 16 frames
410 */
411 size = (pcm_config.period_size * sample_rate) / pcm_config.rate;
412 size = ((size + 15) / 16) * 16;
413
414 return size * channel_count * audio_bytes_per_sample(format);
415}
416
417static int get_next_buffer(struct resampler_buffer_provider *buffer_provider,
418 struct resampler_buffer* buffer)
419{
420 struct stream_in *in;
Eric Laurentd7abdd02012-07-27 14:54:41 -0700421 size_t i;
Simon Wilson15f60a82012-04-24 20:56:32 -0700422
423 if (buffer_provider == NULL || buffer == NULL)
424 return -EINVAL;
425
426 in = (struct stream_in *)((char *)buffer_provider -
427 offsetof(struct stream_in, buf_provider));
428
429 if (in->pcm == NULL) {
430 buffer->raw = NULL;
431 buffer->frame_count = 0;
432 in->read_status = -ENODEV;
433 return -ENODEV;
434 }
435
436 if (in->frames_in == 0) {
437 in->read_status = pcm_read(in->pcm,
438 (void*)in->buffer,
Eric Laurentd7abdd02012-07-27 14:54:41 -0700439 pcm_frames_to_bytes(in->pcm, pcm_config.period_size));
Simon Wilson15f60a82012-04-24 20:56:32 -0700440 if (in->read_status != 0) {
441 ALOGE("get_next_buffer() pcm_read error %d", in->read_status);
442 buffer->raw = NULL;
443 buffer->frame_count = 0;
444 return in->read_status;
445 }
Eric Laurentd7abdd02012-07-27 14:54:41 -0700446
Simon Wilson15f60a82012-04-24 20:56:32 -0700447 in->frames_in = pcm_config.period_size;
Eric Laurentd7abdd02012-07-27 14:54:41 -0700448
449 /* Do stereo to mono conversion in place by discarding right channel */
450 for (i = 1; i < in->frames_in; i++)
451 in->buffer[i] = in->buffer[i * 2];
Simon Wilson15f60a82012-04-24 20:56:32 -0700452 }
453
454 buffer->frame_count = (buffer->frame_count > in->frames_in) ?
455 in->frames_in : buffer->frame_count;
Eric Laurentd7abdd02012-07-27 14:54:41 -0700456 buffer->i16 = in->buffer + (pcm_config.period_size - in->frames_in);
Simon Wilson15f60a82012-04-24 20:56:32 -0700457
458 return in->read_status;
459
460}
461
462static void release_buffer(struct resampler_buffer_provider *buffer_provider,
463 struct resampler_buffer* buffer)
464{
465 struct stream_in *in;
466
467 if (buffer_provider == NULL || buffer == NULL)
468 return;
469
470 in = (struct stream_in *)((char *)buffer_provider -
471 offsetof(struct stream_in, buf_provider));
472
473 in->frames_in -= buffer->frame_count;
474}
475
476/* read_frames() reads frames from kernel driver, down samples to capture rate
477 * if necessary and output the number of frames requested to the buffer specified */
478static ssize_t read_frames(struct stream_in *in, void *buffer, ssize_t frames)
479{
480 ssize_t frames_wr = 0;
Eric Laurentd7abdd02012-07-27 14:54:41 -0700481 size_t frame_size = audio_stream_frame_size(&in->stream.common);
Simon Wilson15f60a82012-04-24 20:56:32 -0700482
483 while (frames_wr < frames) {
484 size_t frames_rd = frames - frames_wr;
485 if (in->resampler != NULL) {
486 in->resampler->resample_from_provider(in->resampler,
487 (int16_t *)((char *)buffer +
Eric Laurentd7abdd02012-07-27 14:54:41 -0700488 frames_wr * frame_size),
Simon Wilson15f60a82012-04-24 20:56:32 -0700489 &frames_rd);
490 } else {
491 struct resampler_buffer buf = {
492 { raw : NULL, },
493 frame_count : frames_rd,
494 };
495 get_next_buffer(&in->buf_provider, &buf);
496 if (buf.raw != NULL) {
497 memcpy((char *)buffer +
Eric Laurentd7abdd02012-07-27 14:54:41 -0700498 frames_wr * frame_size,
Simon Wilson15f60a82012-04-24 20:56:32 -0700499 buf.raw,
Eric Laurentd7abdd02012-07-27 14:54:41 -0700500 buf.frame_count * frame_size);
Simon Wilson15f60a82012-04-24 20:56:32 -0700501 frames_rd = buf.frame_count;
502 }
503 release_buffer(&in->buf_provider, &buf);
504 }
505 /* in->read_status is updated by getNextBuffer() also called by
506 * in->resampler->resample_from_provider() */
507 if (in->read_status != 0)
508 return in->read_status;
509
510 frames_wr += frames_rd;
511 }
512 return frames_wr;
513}
514
515/* API functions */
516
517static uint32_t out_get_sample_rate(const struct audio_stream *stream)
518{
519 return pcm_config.rate;
520}
521
522static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate)
523{
524 return -ENOSYS;
525}
526
527static size_t out_get_buffer_size(const struct audio_stream *stream)
528{
529 return pcm_config.period_size *
530 audio_stream_frame_size((struct audio_stream *)stream);
531}
532
Glenn Kastenca1414b2012-06-25 10:38:47 -0700533static audio_channel_mask_t out_get_channels(const struct audio_stream *stream)
Simon Wilson15f60a82012-04-24 20:56:32 -0700534{
535 return AUDIO_CHANNEL_OUT_STEREO;
536}
537
538static audio_format_t out_get_format(const struct audio_stream *stream)
539{
540 return AUDIO_FORMAT_PCM_16_BIT;
541}
542
543static int out_set_format(struct audio_stream *stream, audio_format_t format)
544{
545 return -ENOSYS;
546}
547
Simon Wilson459d5bd2012-08-21 12:18:07 -0700548static int do_out_standby(struct stream_out *out)
Simon Wilson15f60a82012-04-24 20:56:32 -0700549{
Simon Wilson56d84e22012-08-17 13:55:27 -0700550 int i;
Simon Wilson15f60a82012-04-24 20:56:32 -0700551
Simon Wilson15f60a82012-04-24 20:56:32 -0700552 if (!out->standby) {
Simon Wilson56d84e22012-08-17 13:55:27 -0700553 for (i = 0; i < PCM_TOTAL; i++) {
554 if (out->pcm[i]) {
555 pcm_close(out->pcm[i]);
556 out->pcm[i] = NULL;
557 }
558 }
Eric Laurent87532032012-07-16 13:53:20 -0700559
560 out->dev->devices &= ~AUDIO_DEVICE_OUT_ALL;
561 select_devices(out->dev);
562
Simon Wilson15f60a82012-04-24 20:56:32 -0700563 out->standby = true;
564 }
565
Simon Wilson459d5bd2012-08-21 12:18:07 -0700566 return 0;
567}
568
569static int out_standby(struct audio_stream *stream)
570{
571 struct stream_out *out = (struct stream_out *)stream;
572 int ret;
573
574 pthread_mutex_lock(&out->dev->lock);
575 pthread_mutex_lock(&out->lock);
576
577 ret = do_out_standby(out);
578
Simon Wilson15f60a82012-04-24 20:56:32 -0700579 pthread_mutex_unlock(&out->lock);
580 pthread_mutex_unlock(&out->dev->lock);
581
Simon Wilson459d5bd2012-08-21 12:18:07 -0700582 return ret;
Simon Wilson15f60a82012-04-24 20:56:32 -0700583}
584
585static int out_dump(const struct audio_stream *stream, int fd)
586{
587 return 0;
588}
589
590static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
591{
592 struct stream_out *out = (struct stream_out *)stream;
593 struct audio_device *adev = out->dev;
594 struct str_parms *parms;
595 char value[32];
596 int ret;
597 unsigned int val;
598
599 parms = str_parms_create_str(kvpairs);
600
601 ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING,
602 value, sizeof(value));
603 pthread_mutex_lock(&adev->lock);
Eric Laurent87532032012-07-16 13:53:20 -0700604 pthread_mutex_lock(&out->lock);
Simon Wilson15f60a82012-04-24 20:56:32 -0700605 if (ret >= 0) {
606 val = atoi(value);
Eric Laurent87532032012-07-16 13:53:20 -0700607 if ((out->device != val) && (val != 0)) {
Simon Wilson459d5bd2012-08-21 12:18:07 -0700608 /* Force standby if moving to/from SPDIF or if the output
609 * device changes when in SPDIF mode */
610 if (((val & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET) ^
611 (adev->devices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET)) ||
612 (adev->devices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET)) {
613 do_out_standby(out);
614 }
615
Eric Laurent87532032012-07-16 13:53:20 -0700616 out->device = val;
617 if (!out->standby) {
618 adev->devices &= ~AUDIO_DEVICE_OUT_ALL;
619 adev->devices |= out->device;
620 select_devices(adev);
621 }
Simon Wilson15f60a82012-04-24 20:56:32 -0700622 }
623 }
Eric Laurent87532032012-07-16 13:53:20 -0700624 pthread_mutex_unlock(&out->lock);
Simon Wilson15f60a82012-04-24 20:56:32 -0700625 pthread_mutex_unlock(&adev->lock);
626
627 str_parms_destroy(parms);
628 return ret;
629}
630
631static char * out_get_parameters(const struct audio_stream *stream, const char *keys)
632{
633 return strdup("");
634}
635
636static uint32_t out_get_latency(const struct audio_stream_out *stream)
637{
638 return (pcm_config.period_size * pcm_config.period_count * 1000) /
639 pcm_config.rate;
640}
641
642static int out_set_volume(struct audio_stream_out *stream, float left,
643 float right)
644{
645 return -ENOSYS;
646}
647
648static ssize_t out_write(struct audio_stream_out *stream, const void* buffer,
649 size_t bytes)
650{
651 int ret;
652 struct stream_out *out = (struct stream_out *)stream;
653 struct audio_device *adev = out->dev;
Simon Wilson56d84e22012-08-17 13:55:27 -0700654 int i;
Simon Wilson15f60a82012-04-24 20:56:32 -0700655
656 /*
657 * acquiring hw device mutex systematically is useful if a low
658 * priority thread is waiting on the output stream mutex - e.g.
659 * executing out_set_parameters() while holding the hw device
660 * mutex
661 */
662 pthread_mutex_lock(&adev->lock);
663 pthread_mutex_lock(&out->lock);
664 if (out->standby) {
665 ret = start_output_stream(out);
666 if (ret != 0) {
667 pthread_mutex_unlock(&adev->lock);
668 goto exit;
669 }
670 out->standby = false;
671 }
672 pthread_mutex_unlock(&adev->lock);
673
Simon Wilson56d84e22012-08-17 13:55:27 -0700674 /* Write to all active PCMs */
675 for (i = 0; i < PCM_TOTAL; i++)
676 if (out->pcm[i])
677 pcm_write(out->pcm[i], (void *)buffer, bytes);
Simon Wilson15f60a82012-04-24 20:56:32 -0700678
679exit:
680 pthread_mutex_unlock(&out->lock);
681
682 if (ret != 0) {
683 usleep(bytes * 1000000 / audio_stream_frame_size(&stream->common) /
684 out_get_sample_rate(&stream->common));
685 }
686
687 return bytes;
688}
689
690static int out_get_render_position(const struct audio_stream_out *stream,
691 uint32_t *dsp_frames)
692{
693 return -EINVAL;
694}
695
696static int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
697{
698 return 0;
699}
700
701static int out_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
702{
703 return 0;
704}
705
706static int out_get_next_write_timestamp(const struct audio_stream_out *stream,
707 int64_t *timestamp)
708{
709 return -EINVAL;
710}
711
712/** audio_stream_in implementation **/
713static uint32_t in_get_sample_rate(const struct audio_stream *stream)
714{
715 struct stream_in *in = (struct stream_in *)stream;
716
717 return in->requested_rate;
718}
719
720static int in_set_sample_rate(struct audio_stream *stream, uint32_t rate)
721{
722 return 0;
723}
724
Eric Laurentd7abdd02012-07-27 14:54:41 -0700725static audio_channel_mask_t in_get_channels(const struct audio_stream *stream)
726{
727 return AUDIO_CHANNEL_IN_MONO;
728}
729
730
Simon Wilson15f60a82012-04-24 20:56:32 -0700731static size_t in_get_buffer_size(const struct audio_stream *stream)
732{
733 struct stream_in *in = (struct stream_in *)stream;
734
735 return get_input_buffer_size(in->requested_rate,
736 AUDIO_FORMAT_PCM_16_BIT,
Eric Laurentd7abdd02012-07-27 14:54:41 -0700737 popcount(in_get_channels(stream)));
Simon Wilson15f60a82012-04-24 20:56:32 -0700738}
739
740static audio_format_t in_get_format(const struct audio_stream *stream)
741{
742 return AUDIO_FORMAT_PCM_16_BIT;
743}
744
745static int in_set_format(struct audio_stream *stream, audio_format_t format)
746{
747 return -ENOSYS;
748}
749
750static int in_standby(struct audio_stream *stream)
751{
752 struct stream_in *in = (struct stream_in *)stream;
753
754 pthread_mutex_lock(&in->dev->lock);
755 pthread_mutex_lock(&in->lock);
756
757 if (!in->standby) {
758 pcm_close(in->pcm);
759 in->pcm = NULL;
Eric Laurent87532032012-07-16 13:53:20 -0700760 in->dev->input_source = AUDIO_SOURCE_DEFAULT;
761 select_devices(in->dev);
Simon Wilson15f60a82012-04-24 20:56:32 -0700762 in->standby = true;
763 }
764
765 pthread_mutex_unlock(&in->lock);
766 pthread_mutex_unlock(&in->dev->lock);
767
768 return 0;
769}
770
771static int in_dump(const struct audio_stream *stream, int fd)
772{
773 return 0;
774}
775
776static int in_set_parameters(struct audio_stream *stream, const char *kvpairs)
777{
778 struct stream_in *in = (struct stream_in *)stream;
779 struct audio_device *adev = in->dev;
780 struct str_parms *parms;
781 char value[32];
782 int ret;
783 unsigned int val;
Eric Laurent87532032012-07-16 13:53:20 -0700784 bool apply_now = false;
Simon Wilson15f60a82012-04-24 20:56:32 -0700785
786 parms = str_parms_create_str(kvpairs);
787
Eric Laurent87532032012-07-16 13:53:20 -0700788 ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_INPUT_SOURCE,
Simon Wilson15f60a82012-04-24 20:56:32 -0700789 value, sizeof(value));
Eric Laurent87532032012-07-16 13:53:20 -0700790
Simon Wilson15f60a82012-04-24 20:56:32 -0700791 pthread_mutex_lock(&adev->lock);
Eric Laurent87532032012-07-16 13:53:20 -0700792 pthread_mutex_lock(&in->lock);
Simon Wilson15f60a82012-04-24 20:56:32 -0700793 if (ret >= 0) {
794 val = atoi(value);
Eric Laurent87532032012-07-16 13:53:20 -0700795 /* no audio source uses val == 0 */
796 if ((in->input_source != val) && (val != 0)) {
797 in->input_source = val;
798 apply_now = !in->standby;
Simon Wilson15f60a82012-04-24 20:56:32 -0700799 }
800 }
Eric Laurent87532032012-07-16 13:53:20 -0700801
Eric Laurent87532032012-07-16 13:53:20 -0700802 if (apply_now) {
Eric Laurent87532032012-07-16 13:53:20 -0700803 adev->input_source = in->input_source;
804 select_devices(adev);
805 }
806
807 pthread_mutex_unlock(&in->lock);
Simon Wilson15f60a82012-04-24 20:56:32 -0700808 pthread_mutex_unlock(&adev->lock);
809
810 str_parms_destroy(parms);
811 return ret;
812}
813
814static char * in_get_parameters(const struct audio_stream *stream,
815 const char *keys)
816{
817 return strdup("");
818}
819
820static int in_set_gain(struct audio_stream_in *stream, float gain)
821{
822 return 0;
823}
824
825static ssize_t in_read(struct audio_stream_in *stream, void* buffer,
826 size_t bytes)
827{
828 int ret = 0;
829 struct stream_in *in = (struct stream_in *)stream;
830 struct audio_device *adev = in->dev;
831 size_t frames_rq = bytes / audio_stream_frame_size(&stream->common);
832
833 /*
834 * acquiring hw device mutex systematically is useful if a low
835 * priority thread is waiting on the input stream mutex - e.g.
836 * executing in_set_parameters() while holding the hw device
837 * mutex
838 */
839 pthread_mutex_lock(&adev->lock);
840 pthread_mutex_lock(&in->lock);
841 if (in->standby) {
842 ret = start_input_stream(in);
843 if (ret == 0)
844 in->standby = 0;
845 }
846 pthread_mutex_unlock(&adev->lock);
847
848 if (ret < 0)
849 goto exit;
850
851 /*if (in->num_preprocessors != 0)
852 ret = process_frames(in, buffer, frames_rq);
Eric Laurentd7abdd02012-07-27 14:54:41 -0700853 else */
854 ret = read_frames(in, buffer, frames_rq);
Simon Wilson15f60a82012-04-24 20:56:32 -0700855
856 if (ret > 0)
857 ret = 0;
858
859 /*
860 * Instead of writing zeroes here, we could trust the hardware
861 * to always provide zeroes when muted.
862 */
863 if (ret == 0 && adev->mic_mute)
864 memset(buffer, 0, bytes);
865
866exit:
867 if (ret < 0)
868 usleep(bytes * 1000000 / audio_stream_frame_size(&stream->common) /
869 in_get_sample_rate(&stream->common));
870
871 pthread_mutex_unlock(&in->lock);
872 return bytes;
873}
874
875static uint32_t in_get_input_frames_lost(struct audio_stream_in *stream)
876{
877 return 0;
878}
879
880static int in_add_audio_effect(const struct audio_stream *stream,
881 effect_handle_t effect)
882{
883 return 0;
884}
885
886static int in_remove_audio_effect(const struct audio_stream *stream,
887 effect_handle_t effect)
888{
889 return 0;
890}
891
892
893static int adev_open_output_stream(struct audio_hw_device *dev,
894 audio_io_handle_t handle,
895 audio_devices_t devices,
896 audio_output_flags_t flags,
897 struct audio_config *config,
898 struct audio_stream_out **stream_out)
899{
900 struct audio_device *adev = (struct audio_device *)dev;
901 struct stream_out *out;
902 int ret;
903
904 out = (struct stream_out *)calloc(1, sizeof(struct stream_out));
905 if (!out)
906 return -ENOMEM;
907
908 out->stream.common.get_sample_rate = out_get_sample_rate;
909 out->stream.common.set_sample_rate = out_set_sample_rate;
910 out->stream.common.get_buffer_size = out_get_buffer_size;
911 out->stream.common.get_channels = out_get_channels;
912 out->stream.common.get_format = out_get_format;
913 out->stream.common.set_format = out_set_format;
914 out->stream.common.standby = out_standby;
915 out->stream.common.dump = out_dump;
916 out->stream.common.set_parameters = out_set_parameters;
917 out->stream.common.get_parameters = out_get_parameters;
918 out->stream.common.add_audio_effect = out_add_audio_effect;
919 out->stream.common.remove_audio_effect = out_remove_audio_effect;
920 out->stream.get_latency = out_get_latency;
921 out->stream.set_volume = out_set_volume;
922 out->stream.write = out_write;
923 out->stream.get_render_position = out_get_render_position;
924 out->stream.get_next_write_timestamp = out_get_next_write_timestamp;
925
926 out->dev = adev;
927
928 config->format = out_get_format(&out->stream.common);
929 config->channel_mask = out_get_channels(&out->stream.common);
930 config->sample_rate = out_get_sample_rate(&out->stream.common);
931
932 out->standby = true;
933
934 *stream_out = &out->stream;
935 return 0;
936
937err_open:
938 free(out);
939 *stream_out = NULL;
940 return ret;
941}
942
943static void adev_close_output_stream(struct audio_hw_device *dev,
944 struct audio_stream_out *stream)
945{
946 out_standby(&stream->common);
947 free(stream);
948}
949
950static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
951{
952 return 0;
953}
954
955static char * adev_get_parameters(const struct audio_hw_device *dev,
956 const char *keys)
957{
958 return strdup("");
959}
960
961static int adev_init_check(const struct audio_hw_device *dev)
962{
963 return 0;
964}
965
966static int adev_set_voice_volume(struct audio_hw_device *dev, float volume)
967{
968 return -ENOSYS;
969}
970
971static int adev_set_master_volume(struct audio_hw_device *dev, float volume)
972{
973 return -ENOSYS;
974}
975
976static int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode)
977{
978 return 0;
979}
980
981static int adev_set_mic_mute(struct audio_hw_device *dev, bool state)
982{
983 struct audio_device *adev = (struct audio_device *)dev;
984
985 adev->mic_mute = state;
986
987 return 0;
988}
989
990static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state)
991{
992 struct audio_device *adev = (struct audio_device *)dev;
993
994 *state = adev->mic_mute;
995
996 return 0;
997}
998
999static size_t adev_get_input_buffer_size(const struct audio_hw_device *dev,
1000 const struct audio_config *config)
1001{
1002
1003 return get_input_buffer_size(config->sample_rate, config->format,
1004 popcount(config->channel_mask));
1005}
1006
1007static int adev_open_input_stream(struct audio_hw_device *dev,
1008 audio_io_handle_t handle,
1009 audio_devices_t devices,
1010 struct audio_config *config,
1011 struct audio_stream_in **stream_in)
1012{
1013 struct audio_device *adev = (struct audio_device *)dev;
1014 struct stream_in *in;
1015 int ret;
1016
1017 *stream_in = NULL;
1018
Eric Laurentd7abdd02012-07-27 14:54:41 -07001019 /* Respond with a request for mono if a different format is given. */
1020 if (config->channel_mask != AUDIO_CHANNEL_IN_MONO) {
1021 config->channel_mask = AUDIO_CHANNEL_IN_MONO;
Simon Wilson15f60a82012-04-24 20:56:32 -07001022 return -EINVAL;
1023 }
1024
1025 in = (struct stream_in *)calloc(1, sizeof(struct stream_in));
1026 if (!in)
1027 return -ENOMEM;
1028
1029 in->stream.common.get_sample_rate = in_get_sample_rate;
1030 in->stream.common.set_sample_rate = in_set_sample_rate;
1031 in->stream.common.get_buffer_size = in_get_buffer_size;
1032 in->stream.common.get_channels = in_get_channels;
1033 in->stream.common.get_format = in_get_format;
1034 in->stream.common.set_format = in_set_format;
1035 in->stream.common.standby = in_standby;
1036 in->stream.common.dump = in_dump;
1037 in->stream.common.set_parameters = in_set_parameters;
1038 in->stream.common.get_parameters = in_get_parameters;
1039 in->stream.common.add_audio_effect = in_add_audio_effect;
1040 in->stream.common.remove_audio_effect = in_remove_audio_effect;
1041 in->stream.set_gain = in_set_gain;
1042 in->stream.read = in_read;
1043 in->stream.get_input_frames_lost = in_get_input_frames_lost;
1044
1045 in->dev = adev;
1046 in->standby = true;
1047 in->requested_rate = config->sample_rate;
Eric Laurent87532032012-07-16 13:53:20 -07001048 in->input_source = AUDIO_SOURCE_DEFAULT;
Simon Wilson15f60a82012-04-24 20:56:32 -07001049
Eric Laurentd7abdd02012-07-27 14:54:41 -07001050 in->buffer = malloc(pcm_config.period_size * pcm_config.channels
1051 * audio_stream_frame_size(&in->stream.common));
1052
Simon Wilson15f60a82012-04-24 20:56:32 -07001053 if (!in->buffer) {
1054 ret = -ENOMEM;
1055 goto err_malloc;
1056 }
1057
1058 if (in->requested_rate != pcm_config.rate) {
1059 in->buf_provider.get_next_buffer = get_next_buffer;
1060 in->buf_provider.release_buffer = release_buffer;
1061
1062 ret = create_resampler(pcm_config.rate,
1063 in->requested_rate,
Eric Laurentd7abdd02012-07-27 14:54:41 -07001064 1,
Simon Wilson15f60a82012-04-24 20:56:32 -07001065 RESAMPLER_QUALITY_DEFAULT,
1066 &in->buf_provider,
1067 &in->resampler);
1068 if (ret != 0) {
1069 ret = -EINVAL;
1070 goto err_resampler;
1071 }
1072 }
1073
1074 *stream_in = &in->stream;
1075 return 0;
1076
1077err_resampler:
1078 free(in->buffer);
1079err_malloc:
1080 free(in);
1081 return ret;
1082}
1083
1084static void adev_close_input_stream(struct audio_hw_device *dev,
1085 struct audio_stream_in *stream)
1086{
1087 struct stream_in *in = (struct stream_in *)stream;
1088
1089 in_standby(&stream->common);
1090 if (in->resampler) {
1091 release_resampler(in->resampler);
1092 in->resampler = NULL;
1093 }
1094 free(in->buffer);
1095 free(stream);
1096}
1097
1098static int adev_dump(const audio_hw_device_t *device, int fd)
1099{
1100 return 0;
1101}
1102
1103static int adev_close(hw_device_t *device)
1104{
1105 struct audio_device *adev = (struct audio_device *)device;
1106
1107 audio_route_free(adev->ar);
1108
1109 free(device);
1110 return 0;
1111}
1112
1113static uint32_t adev_get_supported_devices(const struct audio_hw_device *dev)
1114{
1115 return (/* OUT */
1116 AUDIO_DEVICE_OUT_SPEAKER |
1117 AUDIO_DEVICE_OUT_WIRED_HEADSET |
1118 AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
Simon Wilson56d84e22012-08-17 13:55:27 -07001119 AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET |
Simon Wilson15f60a82012-04-24 20:56:32 -07001120 /*AUDIO_DEVICE_OUT_ALL_SCO |*/
1121 AUDIO_DEVICE_OUT_DEFAULT |
1122 /* IN */
1123 AUDIO_DEVICE_IN_BUILTIN_MIC |
1124 AUDIO_DEVICE_IN_WIRED_HEADSET |
1125 AUDIO_DEVICE_IN_BACK_MIC |
1126 /*AUDIO_DEVICE_IN_ALL_SCO |*/
1127 AUDIO_DEVICE_IN_DEFAULT);
1128}
1129
1130static int adev_open(const hw_module_t* module, const char* name,
1131 hw_device_t** device)
1132{
1133 struct audio_device *adev;
1134 int ret;
1135
1136 if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0)
1137 return -EINVAL;
1138
1139 adev = calloc(1, sizeof(struct audio_device));
1140 if (!adev)
1141 return -ENOMEM;
1142
1143 adev->hw_device.common.tag = HARDWARE_DEVICE_TAG;
1144 adev->hw_device.common.version = AUDIO_DEVICE_API_VERSION_1_0;
1145 adev->hw_device.common.module = (struct hw_module_t *) module;
1146 adev->hw_device.common.close = adev_close;
1147
1148 adev->hw_device.get_supported_devices = adev_get_supported_devices;
1149 adev->hw_device.init_check = adev_init_check;
1150 adev->hw_device.set_voice_volume = adev_set_voice_volume;
1151 adev->hw_device.set_master_volume = adev_set_master_volume;
1152 adev->hw_device.set_mode = adev_set_mode;
1153 adev->hw_device.set_mic_mute = adev_set_mic_mute;
1154 adev->hw_device.get_mic_mute = adev_get_mic_mute;
1155 adev->hw_device.set_parameters = adev_set_parameters;
1156 adev->hw_device.get_parameters = adev_get_parameters;
1157 adev->hw_device.get_input_buffer_size = adev_get_input_buffer_size;
1158 adev->hw_device.open_output_stream = adev_open_output_stream;
1159 adev->hw_device.close_output_stream = adev_close_output_stream;
1160 adev->hw_device.open_input_stream = adev_open_input_stream;
1161 adev->hw_device.close_input_stream = adev_close_input_stream;
1162 adev->hw_device.dump = adev_dump;
1163
1164 adev->ar = audio_route_init();
Eric Laurent87532032012-07-16 13:53:20 -07001165 adev->input_source = AUDIO_SOURCE_DEFAULT;
1166 /* adev->cur_route_id initial value is 0 and such that first device
1167 * selection is always applied by select_devices() */
Simon Wilson15f60a82012-04-24 20:56:32 -07001168
1169 *device = &adev->hw_device.common;
1170
1171 return 0;
1172}
1173
1174static struct hw_module_methods_t hal_module_methods = {
1175 .open = adev_open,
1176};
1177
1178struct audio_module HAL_MODULE_INFO_SYM = {
1179 .common = {
1180 .tag = HARDWARE_MODULE_TAG,
1181 .module_api_version = AUDIO_MODULE_API_VERSION_0_1,
1182 .hal_api_version = HARDWARE_HAL_API_VERSION,
1183 .id = AUDIO_HARDWARE_MODULE_ID,
1184 .name = "Manta audio HW HAL",
1185 .author = "The Android Open Source Project",
1186 .methods = &hal_module_methods,
1187 },
1188};