blob: cd4cdb41df100bfbfa459a693f0dca8350bd16c9 [file] [log] [blame]
The Android Open Source Project5738f832012-12-12 16:00:35 -08001/******************************************************************************
2 *
3 * Copyright (C) 2009-2012 Broadcom Corporation
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 ******************************************************************************/
18
19/*****************************************************************************
20 *
21 * Filename: audio_a2dp_hw.c
22 *
23 * Description: Implements hal for bluedroid a2dp audio device
24 *
25 *****************************************************************************/
26
27#include <errno.h>
28#include <pthread.h>
29#include <stdint.h>
30#include <sys/time.h>
31#include <sys/socket.h>
32#include <sys/un.h>
33#include <sys/poll.h>
34#include <sys/errno.h>
35#include <sys/stat.h>
36#include <unistd.h>
37#include <fcntl.h>
38#include <cutils/str_parms.h>
39#include <cutils/sockets.h>
40
41#include <system/audio.h>
42#include <hardware/audio.h>
43
44#include <hardware/hardware.h>
45#include "audio_a2dp_hw.h"
Mike J. Chen5cd8bff2014-01-31 18:16:59 -080046#include "bt_utils.h"
The Android Open Source Project5738f832012-12-12 16:00:35 -080047
48#define LOG_TAG "audio_a2dp_hw"
49/* #define LOG_NDEBUG 0 */
50#include <cutils/log.h>
51
52/*****************************************************************************
53** Constants & Macros
54******************************************************************************/
55
56#define CTRL_CHAN_RETRY_COUNT 3
57#define USEC_PER_SEC 1000000L
58
59#define CASE_RETURN_STR(const) case const: return #const;
60
61#define FNLOG() ALOGV("%s", __FUNCTION__);
62#define DEBUG(fmt, ...) ALOGV("%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
63#define INFO(fmt, ...) ALOGI("%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
64#define ERROR(fmt, ...) ALOGE("%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
65
66#define ASSERTC(cond, msg, val) if (!(cond)) {ERROR("### ASSERT : %s line %d %s (%d) ###", __FILE__, __LINE__, msg, val);}
67
68/*****************************************************************************
69** Local type definitions
70******************************************************************************/
71
72typedef enum {
73 AUDIO_A2DP_STATE_STARTING,
74 AUDIO_A2DP_STATE_STARTED,
75 AUDIO_A2DP_STATE_STOPPING,
76 AUDIO_A2DP_STATE_STOPPED,
77 AUDIO_A2DP_STATE_SUSPENDED, /* need explicit set param call to resume (suspend=false) */
78 AUDIO_A2DP_STATE_STANDBY /* allows write to autoresume */
79} a2dp_state_t;
80
81struct a2dp_stream_out;
82
83struct a2dp_audio_device {
84 struct audio_hw_device device;
85 struct a2dp_stream_out *output;
86};
87
88struct a2dp_config {
89 uint32_t rate;
90 uint32_t channel_flags;
91 int format;
92};
93
94/* move ctrl_fd outside output stream and keep open until HAL unloaded ? */
95
96struct a2dp_stream_out {
97 struct audio_stream_out stream;
98 pthread_mutex_t lock;
99 int ctrl_fd;
100 int audio_fd;
101 size_t buffer_sz;
102 a2dp_state_t state;
103 struct a2dp_config cfg;
104};
105
106struct a2dp_stream_in {
107 struct audio_stream_in stream;
108};
109
110/*****************************************************************************
111** Static variables
112******************************************************************************/
113
114/*****************************************************************************
115** Static functions
116******************************************************************************/
117
118static size_t out_get_buffer_size(const struct audio_stream *stream);
119
120/*****************************************************************************
121** Externs
122******************************************************************************/
123
124/*****************************************************************************
125** Functions
126******************************************************************************/
127
128/*****************************************************************************
129** Miscellaneous helper functions
130******************************************************************************/
131
132static const char* dump_a2dp_ctrl_event(char event)
133{
134 switch(event)
135 {
136 CASE_RETURN_STR(A2DP_CTRL_CMD_NONE)
137 CASE_RETURN_STR(A2DP_CTRL_CMD_CHECK_READY)
138 CASE_RETURN_STR(A2DP_CTRL_CMD_START)
139 CASE_RETURN_STR(A2DP_CTRL_CMD_STOP)
140 CASE_RETURN_STR(A2DP_CTRL_CMD_SUSPEND)
141 default:
142 return "UNKNOWN MSG ID";
143 }
144}
145
146/* logs timestamp with microsec precision
147 pprev is optional in case a dedicated diff is required */
148static void ts_log(char *tag, int val, struct timespec *pprev_opt)
149{
150 struct timespec now;
151 static struct timespec prev = {0,0};
152 unsigned long long now_us;
153 unsigned long long diff_us;
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800154 UNUSED(tag);
155 UNUSED(val);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800156
157 clock_gettime(CLOCK_MONOTONIC, &now);
158
159 now_us = now.tv_sec*USEC_PER_SEC + now.tv_nsec/1000;
160
161 if (pprev_opt)
162 {
163 diff_us = (now.tv_sec - prev.tv_sec) * USEC_PER_SEC + (now.tv_nsec - prev.tv_nsec)/1000;
164 *pprev_opt = now;
165 DEBUG("[%s] ts %08lld, *diff %08lld, val %d", tag, now_us, diff_us, val);
166 }
167 else
168 {
169 diff_us = (now.tv_sec - prev.tv_sec) * USEC_PER_SEC + (now.tv_nsec - prev.tv_nsec)/1000;
170 prev = now;
171 DEBUG("[%s] ts %08lld, diff %08lld, val %d", tag, now_us, diff_us, val);
172 }
173}
174
175static int calc_audiotime(struct a2dp_config cfg, int bytes)
176{
177 int chan_count = popcount(cfg.channel_flags);
178
179 ASSERTC(cfg.format == AUDIO_FORMAT_PCM_16_BIT,
180 "unsupported sample sz", cfg.format);
181
182 return bytes*(1000000/(chan_count*2))/cfg.rate;
183}
184
185/*****************************************************************************
186**
187** bluedroid stack adaptation
188**
189*****************************************************************************/
190
191static int skt_connect(struct a2dp_stream_out *out, char *path)
192{
193 int ret;
194 int skt_fd;
195 struct sockaddr_un remote;
196 int len;
197
198 INFO("connect to %s (sz %d)", path, out->buffer_sz);
199
200 skt_fd = socket(AF_LOCAL, SOCK_STREAM, 0);
201
202 if(socket_local_client_connect(skt_fd, path,
203 ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM) < 0)
204 {
205 ERROR("failed to connect (%s)", strerror(errno));
206 close(skt_fd);
207 return -1;
208 }
209
210 len = out->buffer_sz;
211 ret = setsockopt(skt_fd, SOL_SOCKET, SO_SNDBUF, (char*)&len, (int)sizeof(len));
212
213 /* only issue warning if failed */
214 if (ret < 0)
215 ERROR("setsockopt failed (%s)", strerror(errno));
216
217 INFO("connected to stack fd = %d", skt_fd);
218
219 return skt_fd;
220}
221
222static int skt_write(int fd, const void *p, size_t len)
223{
224 int sent;
225 struct pollfd pfd;
226
227 FNLOG();
228
229 pfd.fd = fd;
230 pfd.events = POLLOUT;
231
232 /* poll for 500 ms */
233
234 /* send time out */
235 if (poll(&pfd, 1, 500) == 0)
236 return 0;
237
238 ts_log("skt_write", len, NULL);
239
240 if ((sent = send(fd, p, len, MSG_NOSIGNAL)) == -1)
241 {
242 ERROR("write failed with errno=%d\n", errno);
243 return -1;
244 }
245
246 return sent;
247}
248
249static int skt_disconnect(int fd)
250{
251 INFO("fd %d", fd);
252
253 if (fd != AUDIO_SKT_DISCONNECTED)
254 {
255 shutdown(fd, SHUT_RDWR);
256 close(fd);
257 }
258 return 0;
259}
260
261
262
263/*****************************************************************************
264**
265** AUDIO CONTROL PATH
266**
267*****************************************************************************/
268
269static int a2dp_command(struct a2dp_stream_out *out, char cmd)
270{
271 char ack;
272
273 DEBUG("A2DP COMMAND %s", dump_a2dp_ctrl_event(cmd));
274
275 /* send command */
276 if (send(out->ctrl_fd, &cmd, 1, MSG_NOSIGNAL) == -1)
277 {
278 ERROR("cmd failed (%s)", strerror(errno));
279 skt_disconnect(out->ctrl_fd);
280 out->ctrl_fd = AUDIO_SKT_DISCONNECTED;
281 return -1;
282 }
283
284 /* wait for ack byte */
285 if (recv(out->ctrl_fd, &ack, 1, MSG_NOSIGNAL) < 0)
286 {
287 ERROR("ack failed (%s)", strerror(errno));
288 skt_disconnect(out->ctrl_fd);
289 out->ctrl_fd = AUDIO_SKT_DISCONNECTED;
290 return -1;
291 }
292
293 DEBUG("A2DP COMMAND %s DONE STATUS %d", dump_a2dp_ctrl_event(cmd), ack);
294
295 if (ack != A2DP_CTRL_ACK_SUCCESS)
296 return -1;
297
298 return 0;
299}
300
301/*****************************************************************************
302**
303** AUDIO DATA PATH
304**
305*****************************************************************************/
306
307static void a2dp_stream_out_init(struct a2dp_stream_out *out)
308{
309 pthread_mutexattr_t lock_attr;
310
311 FNLOG();
312
313 pthread_mutexattr_init(&lock_attr);
314 pthread_mutexattr_settype(&lock_attr, PTHREAD_MUTEX_RECURSIVE);
315 pthread_mutex_init(&out->lock, &lock_attr);
316
317 out->ctrl_fd = AUDIO_SKT_DISCONNECTED;
318 out->audio_fd = AUDIO_SKT_DISCONNECTED;
319 out->state = AUDIO_A2DP_STATE_STOPPED;
320
321 out->cfg.channel_flags = AUDIO_STREAM_DEFAULT_CHANNEL_FLAG;
322 out->cfg.format = AUDIO_STREAM_DEFAULT_FORMAT;
323 out->cfg.rate = AUDIO_STREAM_DEFAULT_RATE;
324
325 /* manages max capacity of socket pipe */
326 out->buffer_sz = AUDIO_STREAM_OUTPUT_BUFFER_SZ;
327}
328
329static int start_audio_datapath(struct a2dp_stream_out *out)
330{
331 int oldstate = out->state;
332
333 INFO("state %d", out->state);
334
335 if (out->ctrl_fd == AUDIO_SKT_DISCONNECTED)
336 return -1;
337
338 out->state = AUDIO_A2DP_STATE_STARTING;
339
340 if (a2dp_command(out, A2DP_CTRL_CMD_START) < 0)
341 {
342 ERROR("audiopath start failed");
343
344 out->state = oldstate;
345 return -1;
346 }
347
348 /* connect socket if not yet connected */
349 if (out->audio_fd == AUDIO_SKT_DISCONNECTED)
350 {
351 out->audio_fd = skt_connect(out, A2DP_DATA_PATH);
352
353 if (out->audio_fd < 0)
354 {
355 out->state = oldstate;
356 return -1;
357 }
358
359 out->state = AUDIO_A2DP_STATE_STARTED;
360 }
361
362 return 0;
363}
364
365
366static int stop_audio_datapath(struct a2dp_stream_out *out)
367{
368 int oldstate = out->state;
369
370 INFO("state %d", out->state);
371
372 if (out->ctrl_fd == AUDIO_SKT_DISCONNECTED)
373 return -1;
374
375 /* prevent any stray output writes from autostarting the stream
376 while stopping audiopath */
377 out->state = AUDIO_A2DP_STATE_STOPPING;
378
379 if (a2dp_command(out, A2DP_CTRL_CMD_STOP) < 0)
380 {
381 ERROR("audiopath stop failed");
382 out->state = oldstate;
383 return -1;
384 }
385
386 out->state = AUDIO_A2DP_STATE_STOPPED;
387
388 /* disconnect audio path */
389 skt_disconnect(out->audio_fd);
390 out->audio_fd = AUDIO_SKT_DISCONNECTED;
391
392 return 0;
393}
394
395static int suspend_audio_datapath(struct a2dp_stream_out *out, bool standby)
396{
397 INFO("state %d", out->state);
398
399 if (out->ctrl_fd == AUDIO_SKT_DISCONNECTED)
400 return -1;
401
402 if (out->state == AUDIO_A2DP_STATE_STOPPING)
403 return -1;
404
405 if (a2dp_command(out, A2DP_CTRL_CMD_SUSPEND) < 0)
406 return -1;
407
408 if (standby)
409 out->state = AUDIO_A2DP_STATE_STANDBY;
410 else
411 out->state = AUDIO_A2DP_STATE_SUSPENDED;
412
413 /* disconnect audio path */
414 skt_disconnect(out->audio_fd);
415
416 out->audio_fd = AUDIO_SKT_DISCONNECTED;
417
418 return 0;
419}
420
421static int check_a2dp_ready(struct a2dp_stream_out *out)
422{
423 INFO("state %d", out->state);
424
425 if (a2dp_command(out, A2DP_CTRL_CMD_CHECK_READY) < 0)
426 {
427 ERROR("check a2dp ready failed");
428 return -1;
429 }
430 return 0;
431}
432
433
434/*****************************************************************************
435**
436** audio output callbacks
437**
438*****************************************************************************/
439
440static ssize_t out_write(struct audio_stream_out *stream, const void* buffer,
441 size_t bytes)
442{
443 struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
444 int sent;
445
446 DEBUG("write %d bytes (fd %d)", bytes, out->audio_fd);
447
448 if (out->state == AUDIO_A2DP_STATE_SUSPENDED)
449 {
450 DEBUG("stream suspended");
451 return -1;
452 }
453
454 /* only allow autostarting if we are in stopped or standby */
455 if ((out->state == AUDIO_A2DP_STATE_STOPPED) ||
456 (out->state == AUDIO_A2DP_STATE_STANDBY))
457 {
458 pthread_mutex_lock(&out->lock);
459
460 if (start_audio_datapath(out) < 0)
461 {
462 /* emulate time this write represents to avoid very fast write
463 failures during transition periods or remote suspend */
464
465 int us_delay = calc_audiotime(out->cfg, bytes);
466
467 DEBUG("emulate a2dp write delay (%d us)", us_delay);
468
469 usleep(us_delay);
470 pthread_mutex_unlock(&out->lock);
471 return -1;
472 }
473
474 pthread_mutex_unlock(&out->lock);
475 }
476 else if (out->state != AUDIO_A2DP_STATE_STARTED)
477 {
478 ERROR("stream not in stopped or standby");
479 return -1;
480 }
481
482 sent = skt_write(out->audio_fd, buffer, bytes);
483
484 if (sent == -1)
485 {
486 skt_disconnect(out->audio_fd);
487 out->audio_fd = AUDIO_SKT_DISCONNECTED;
488 out->state = AUDIO_A2DP_STATE_STOPPED;
489 }
490
491 DEBUG("wrote %d bytes out of %d bytes", sent, bytes);
492 return sent;
493}
494
495
496static uint32_t out_get_sample_rate(const struct audio_stream *stream)
497{
498 struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
499
500 DEBUG("rate %d", out->cfg.rate);
501
502 return out->cfg.rate;
503}
504
505static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate)
506{
507 struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
508
509 DEBUG("out_set_sample_rate : %d", rate);
510
511 if (rate != AUDIO_STREAM_DEFAULT_RATE)
512 {
513 ERROR("only rate %d supported", AUDIO_STREAM_DEFAULT_RATE);
514 return -1;
515 }
516
517 out->cfg.rate = rate;
518
519 return 0;
520}
521
522static size_t out_get_buffer_size(const struct audio_stream *stream)
523{
524 struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
525
526 DEBUG("buffer_size : %d", out->buffer_sz);
527
528 return out->buffer_sz;
529}
530
531static uint32_t out_get_channels(const struct audio_stream *stream)
532{
533 struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
534
535 DEBUG("channels 0x%x", out->cfg.channel_flags);
536
537 return out->cfg.channel_flags;
538}
539
540static audio_format_t out_get_format(const struct audio_stream *stream)
541{
542 struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
543 DEBUG("format 0x%x", out->cfg.format);
544 return out->cfg.format;
545}
546
547static int out_set_format(struct audio_stream *stream, audio_format_t format)
548{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800549 UNUSED(format);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800550 struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
551 DEBUG("setting format not yet supported (0x%x)", format);
552 return -ENOSYS;
553}
554
555static int out_standby(struct audio_stream *stream)
556{
557 struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800558 int retVal = 0;
559
560 FNLOG();
561
562 pthread_mutex_lock(&out->lock);
563
564 if (out->state == AUDIO_A2DP_STATE_STARTED)
565 retVal = suspend_audio_datapath(out, true);
566 else
567 retVal = 0;
568 pthread_mutex_unlock (&out->lock);
569
570 return retVal;
571}
572
573static int out_dump(const struct audio_stream *stream, int fd)
574{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800575 UNUSED(fd);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800576 struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
577 FNLOG();
578 return 0;
579}
580
581static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
582{
583 struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
584 struct str_parms *parms;
585 char keyval[16];
Zhihai Xuad3fc6e2014-03-25 18:36:27 -0700586 int retval;
587 int status = 0;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800588
589 INFO("state %d", out->state);
590
591 pthread_mutex_lock(&out->lock);
592
593 parms = str_parms_create_str(kvpairs);
594
595 /* dump params */
596 str_parms_dump(parms);
597
598 retval = str_parms_get_str(parms, "closing", keyval, sizeof(keyval));
599
600 if (retval >= 0)
601 {
602 if (strcmp(keyval, "true") == 0)
603 {
604 DEBUG("stream closing, disallow any writes");
605 out->state = AUDIO_A2DP_STATE_STOPPING;
606 }
607 }
608
609 retval = str_parms_get_str(parms, "A2dpSuspended", keyval, sizeof(keyval));
610
611 if (retval >= 0)
612 {
613 if (strcmp(keyval, "true") == 0)
614 {
615 if (out->state == AUDIO_A2DP_STATE_STARTED)
Zhihai Xuad3fc6e2014-03-25 18:36:27 -0700616 status = suspend_audio_datapath(out, false);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800617 }
618 else
619 {
620 /* Do not start the streaming automatically. If the phone was streaming
621 * prior to being suspended, the next out_write shall trigger the
622 * AVDTP start procedure */
623 if (out->state == AUDIO_A2DP_STATE_SUSPENDED)
624 out->state = AUDIO_A2DP_STATE_STANDBY;
625 /* Irrespective of the state, return 0 */
The Android Open Source Project5738f832012-12-12 16:00:35 -0800626 }
627 }
628
629 pthread_mutex_unlock(&out->lock);
630 str_parms_destroy(parms);
631
Zhihai Xuad3fc6e2014-03-25 18:36:27 -0700632 return status;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800633}
634
635static char * out_get_parameters(const struct audio_stream *stream, const char *keys)
636{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800637 UNUSED(keys);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800638 struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
639
640 FNLOG();
641
642 /* add populating param here */
643
644 return strdup("");
645}
646
647static uint32_t out_get_latency(const struct audio_stream_out *stream)
648{
649 int latency_us;
650
651 struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
652
653 FNLOG();
654
655 latency_us = ((out->buffer_sz * 1000 ) /
656 audio_stream_frame_size(&out->stream.common) /
657 out->cfg.rate) * 1000;
658
659
660 return (latency_us / 1000) + 200;
661}
662
663static int out_set_volume(struct audio_stream_out *stream, float left,
664 float right)
665{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800666 UNUSED(stream);
667 UNUSED(left);
668 UNUSED(right);
669
The Android Open Source Project5738f832012-12-12 16:00:35 -0800670 FNLOG();
671
672 /* volume controlled in audioflinger mixer (digital) */
673
674 return -ENOSYS;
675}
676
677
678
679static int out_get_render_position(const struct audio_stream_out *stream,
680 uint32_t *dsp_frames)
681{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800682 UNUSED(stream);
683 UNUSED(dsp_frames);
684
The Android Open Source Project5738f832012-12-12 16:00:35 -0800685 FNLOG();
686 return -EINVAL;
687}
688
689static int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
690{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800691 UNUSED(stream);
692 UNUSED(effect);
693
The Android Open Source Project5738f832012-12-12 16:00:35 -0800694 FNLOG();
695 return 0;
696}
697
698static int out_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
699{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800700 UNUSED(stream);
701 UNUSED(effect);
702
The Android Open Source Project5738f832012-12-12 16:00:35 -0800703 FNLOG();
704 return 0;
705}
706
707/*
708 * AUDIO INPUT STREAM
709 */
710
711static uint32_t in_get_sample_rate(const struct audio_stream *stream)
712{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800713 UNUSED(stream);
714
The Android Open Source Project5738f832012-12-12 16:00:35 -0800715 FNLOG();
716 return 8000;
717}
718
719static int in_set_sample_rate(struct audio_stream *stream, uint32_t rate)
720{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800721 UNUSED(stream);
722 UNUSED(rate);
723
The Android Open Source Project5738f832012-12-12 16:00:35 -0800724 FNLOG();
725 return 0;
726}
727
728static size_t in_get_buffer_size(const struct audio_stream *stream)
729{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800730 UNUSED(stream);
731
The Android Open Source Project5738f832012-12-12 16:00:35 -0800732 FNLOG();
733 return 320;
734}
735
736static uint32_t in_get_channels(const struct audio_stream *stream)
737{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800738 UNUSED(stream);
739
The Android Open Source Project5738f832012-12-12 16:00:35 -0800740 FNLOG();
741 return AUDIO_CHANNEL_IN_MONO;
742}
743
744static audio_format_t in_get_format(const struct audio_stream *stream)
745{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800746 UNUSED(stream);
747
The Android Open Source Project5738f832012-12-12 16:00:35 -0800748 FNLOG();
749 return AUDIO_FORMAT_PCM_16_BIT;
750}
751
752static int in_set_format(struct audio_stream *stream, audio_format_t format)
753{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800754 UNUSED(stream);
755 UNUSED(format);
756
The Android Open Source Project5738f832012-12-12 16:00:35 -0800757 FNLOG();
758 return 0;
759}
760
761static int in_standby(struct audio_stream *stream)
762{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800763 UNUSED(stream);
764
The Android Open Source Project5738f832012-12-12 16:00:35 -0800765 FNLOG();
766 return 0;
767}
768
769static int in_dump(const struct audio_stream *stream, int fd)
770{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800771 UNUSED(stream);
772 UNUSED(fd);
773
The Android Open Source Project5738f832012-12-12 16:00:35 -0800774 FNLOG();
775 return 0;
776}
777
778static int in_set_parameters(struct audio_stream *stream, const char *kvpairs)
779{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800780 UNUSED(stream);
781 UNUSED(kvpairs);
782
The Android Open Source Project5738f832012-12-12 16:00:35 -0800783 FNLOG();
784 return 0;
785}
786
787static char * in_get_parameters(const struct audio_stream *stream,
788 const char *keys)
789{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800790 UNUSED(stream);
791 UNUSED(keys);
792
The Android Open Source Project5738f832012-12-12 16:00:35 -0800793 FNLOG();
794 return strdup("");
795}
796
797static int in_set_gain(struct audio_stream_in *stream, float gain)
798{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800799 UNUSED(stream);
800 UNUSED(gain);
801
The Android Open Source Project5738f832012-12-12 16:00:35 -0800802 FNLOG();
803 return 0;
804}
805
806static ssize_t in_read(struct audio_stream_in *stream, void* buffer,
807 size_t bytes)
808{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800809 UNUSED(stream);
810 UNUSED(buffer);
811 UNUSED(bytes);
812
The Android Open Source Project5738f832012-12-12 16:00:35 -0800813 FNLOG();
814 return bytes;
815}
816
817static uint32_t in_get_input_frames_lost(struct audio_stream_in *stream)
818{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800819 UNUSED(stream);
820
The Android Open Source Project5738f832012-12-12 16:00:35 -0800821 FNLOG();
822 return 0;
823}
824
825static int in_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
826{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800827 UNUSED(stream);
828 UNUSED(effect);
829
The Android Open Source Project5738f832012-12-12 16:00:35 -0800830 FNLOG();
831 return 0;
832}
833
834static int in_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
835{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800836 UNUSED(stream);
837 UNUSED(effect);
838
The Android Open Source Project5738f832012-12-12 16:00:35 -0800839 FNLOG();
840
841 return 0;
842}
843
844static int adev_open_output_stream(struct audio_hw_device *dev,
845 audio_io_handle_t handle,
846 audio_devices_t devices,
847 audio_output_flags_t flags,
848 struct audio_config *config,
849 struct audio_stream_out **stream_out)
850
851{
852 struct a2dp_audio_device *a2dp_dev = (struct a2dp_audio_device *)dev;
853 struct a2dp_stream_out *out;
854 int ret = 0;
855 int i;
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800856 UNUSED(handle);
857 UNUSED(devices);
858 UNUSED(flags);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800859
860 INFO("opening output");
861
862 out = (struct a2dp_stream_out *)calloc(1, sizeof(struct a2dp_stream_out));
863
864 if (!out)
865 return -ENOMEM;
866
867 out->stream.common.get_sample_rate = out_get_sample_rate;
868 out->stream.common.set_sample_rate = out_set_sample_rate;
869 out->stream.common.get_buffer_size = out_get_buffer_size;
870 out->stream.common.get_channels = out_get_channels;
871 out->stream.common.get_format = out_get_format;
872 out->stream.common.set_format = out_set_format;
873 out->stream.common.standby = out_standby;
874 out->stream.common.dump = out_dump;
875 out->stream.common.set_parameters = out_set_parameters;
876 out->stream.common.get_parameters = out_get_parameters;
877 out->stream.common.add_audio_effect = out_add_audio_effect;
878 out->stream.common.remove_audio_effect = out_remove_audio_effect;
879 out->stream.get_latency = out_get_latency;
880 out->stream.set_volume = out_set_volume;
881 out->stream.write = out_write;
882 out->stream.get_render_position = out_get_render_position;
883
884 /* initialize a2dp specifics */
885 a2dp_stream_out_init(out);
886
887 /* set output config values */
888 if (config)
889 {
890 config->format = out_get_format((const struct audio_stream *)&out->stream);
891 config->sample_rate = out_get_sample_rate((const struct audio_stream *)&out->stream);
892 config->channel_mask = out_get_channels((const struct audio_stream *)&out->stream);
893 }
894 *stream_out = &out->stream;
895 a2dp_dev->output = out;
896
897 /* retry logic to catch any timing variations on control channel */
898 for (i = 0; i < CTRL_CHAN_RETRY_COUNT; i++)
899 {
900 /* connect control channel if not already connected */
901 if ((out->ctrl_fd = skt_connect(out, A2DP_CTRL_PATH)) > 0)
902 {
903 /* success, now check if stack is ready */
904 if (check_a2dp_ready(out) == 0)
905 break;
906
907 ERROR("error : a2dp not ready, wait 250 ms and retry");
908 usleep(250000);
909 skt_disconnect(out->ctrl_fd);
910 }
911
912 /* ctrl channel not ready, wait a bit */
913 usleep(250000);
914 }
915
916 if (out->ctrl_fd == AUDIO_SKT_DISCONNECTED)
917 {
918 ERROR("ctrl socket failed to connect (%s)", strerror(errno));
919 ret = -1;
920 goto err_open;
921 }
922
923 DEBUG("success");
924 return 0;
925
926err_open:
927 free(out);
928 *stream_out = NULL;
929 ERROR("failed");
930 return ret;
931}
932
933static void adev_close_output_stream(struct audio_hw_device *dev,
934 struct audio_stream_out *stream)
935{
936 struct a2dp_audio_device *a2dp_dev = (struct a2dp_audio_device *)dev;
937 struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
938
939 INFO("closing output (state %d)", out->state);
940
941 if ((out->state == AUDIO_A2DP_STATE_STARTED) || (out->state == AUDIO_A2DP_STATE_STOPPING))
942 stop_audio_datapath(out);
943
944 skt_disconnect(out->ctrl_fd);
945 free(stream);
946 a2dp_dev->output = NULL;
947
948 DEBUG("done");
949}
950
951static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
952{
953 struct a2dp_audio_device *a2dp_dev = (struct a2dp_audio_device *)dev;
954 struct a2dp_stream_out *out = a2dp_dev->output;
955 int retval = 0;
956
957 if (out == NULL)
958 return retval;
959
960 INFO("state %d", out->state);
961
962 retval = out->stream.common.set_parameters((struct audio_stream *)out, kvpairs);
963
964 return retval;
965}
966
967static char * adev_get_parameters(const struct audio_hw_device *dev,
968 const char *keys)
969{
970 struct str_parms *parms;
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800971 UNUSED(dev);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800972
973 FNLOG();
974
975 parms = str_parms_create_str(keys);
976
977 str_parms_dump(parms);
978
979 str_parms_destroy(parms);
980
981 return strdup("");
982}
983
984static int adev_init_check(const struct audio_hw_device *dev)
985{
986 struct a2dp_audio_device *a2dp_dev = (struct a2dp_audio_device*)dev;
987
988 FNLOG();
989
990 return 0;
991}
992
993static int adev_set_voice_volume(struct audio_hw_device *dev, float volume)
994{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800995 UNUSED(dev);
996 UNUSED(volume);
997
The Android Open Source Project5738f832012-12-12 16:00:35 -0800998 FNLOG();
999
1000 return -ENOSYS;
1001}
1002
1003static int adev_set_master_volume(struct audio_hw_device *dev, float volume)
1004{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -08001005 UNUSED(dev);
1006 UNUSED(volume);
1007
The Android Open Source Project5738f832012-12-12 16:00:35 -08001008 FNLOG();
1009
1010 return -ENOSYS;
1011}
1012
1013static int adev_set_mode(struct audio_hw_device *dev, int mode)
1014{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -08001015 UNUSED(dev);
1016 UNUSED(mode);
1017
The Android Open Source Project5738f832012-12-12 16:00:35 -08001018 FNLOG();
1019
1020 return 0;
1021}
1022
1023static int adev_set_mic_mute(struct audio_hw_device *dev, bool state)
1024{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -08001025 UNUSED(dev);
1026 UNUSED(state);
1027
The Android Open Source Project5738f832012-12-12 16:00:35 -08001028 FNLOG();
1029
1030 return -ENOSYS;
1031}
1032
1033static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state)
1034{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -08001035 UNUSED(dev);
1036 UNUSED(state);
1037
The Android Open Source Project5738f832012-12-12 16:00:35 -08001038 FNLOG();
1039
1040 return -ENOSYS;
1041}
1042
1043static size_t adev_get_input_buffer_size(const struct audio_hw_device *dev,
1044 const struct audio_config *config)
1045{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -08001046 UNUSED(dev);
1047 UNUSED(config);
1048
The Android Open Source Project5738f832012-12-12 16:00:35 -08001049 FNLOG();
1050
1051 return 320;
1052}
1053
1054static int adev_open_input_stream(struct audio_hw_device *dev,
1055 audio_io_handle_t handle,
1056 audio_devices_t devices,
1057 struct audio_config *config,
1058 struct audio_stream_in **stream_in)
1059{
1060 struct a2dp_audio_device *ladev = (struct a2dp_audio_device *)dev;
1061 struct a2dp_stream_in *in;
1062 int ret;
Mike J. Chen5cd8bff2014-01-31 18:16:59 -08001063 UNUSED(handle);
1064 UNUSED(devices);
1065 UNUSED(config);
The Android Open Source Project5738f832012-12-12 16:00:35 -08001066
1067 FNLOG();
1068
1069 in = (struct a2dp_stream_in *)calloc(1, sizeof(struct a2dp_stream_in));
1070
1071 if (!in)
1072 return -ENOMEM;
1073
1074 in->stream.common.get_sample_rate = in_get_sample_rate;
1075 in->stream.common.set_sample_rate = in_set_sample_rate;
1076 in->stream.common.get_buffer_size = in_get_buffer_size;
1077 in->stream.common.get_channels = in_get_channels;
1078 in->stream.common.get_format = in_get_format;
1079 in->stream.common.set_format = in_set_format;
1080 in->stream.common.standby = in_standby;
1081 in->stream.common.dump = in_dump;
1082 in->stream.common.set_parameters = in_set_parameters;
1083 in->stream.common.get_parameters = in_get_parameters;
1084 in->stream.common.add_audio_effect = in_add_audio_effect;
1085 in->stream.common.remove_audio_effect = in_remove_audio_effect;
1086 in->stream.set_gain = in_set_gain;
1087 in->stream.read = in_read;
1088 in->stream.get_input_frames_lost = in_get_input_frames_lost;
1089
1090 *stream_in = &in->stream;
1091 return 0;
1092
1093err_open:
1094 free(in);
1095 *stream_in = NULL;
1096 return ret;
1097}
1098
1099static void adev_close_input_stream(struct audio_hw_device *dev,
1100 struct audio_stream_in *in)
1101{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -08001102 UNUSED(dev);
1103 UNUSED(in);
1104
The Android Open Source Project5738f832012-12-12 16:00:35 -08001105 FNLOG();
1106
1107 return;
1108}
1109
1110static int adev_dump(const audio_hw_device_t *device, int fd)
1111{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -08001112 UNUSED(device);
1113 UNUSED(fd);
1114
The Android Open Source Project5738f832012-12-12 16:00:35 -08001115 FNLOG();
1116
1117 return 0;
1118}
1119
1120static int adev_close(hw_device_t *device)
1121{
1122 FNLOG();
1123
1124 free(device);
1125 return 0;
1126}
1127
1128static int adev_open(const hw_module_t* module, const char* name,
1129 hw_device_t** device)
1130{
1131 struct a2dp_audio_device *adev;
1132 int ret;
1133
1134 INFO(" adev_open in A2dp_hw module");
1135 FNLOG();
1136
1137 if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0)
1138 {
1139 ERROR("interface %s not matching [%s]", name, AUDIO_HARDWARE_INTERFACE);
1140 return -EINVAL;
1141 }
1142
1143 adev = calloc(1, sizeof(struct a2dp_audio_device));
1144
1145 if (!adev)
1146 return -ENOMEM;
1147
1148 adev->device.common.tag = HARDWARE_DEVICE_TAG;
Zhihai Xu45b4faf2014-03-20 18:01:09 -07001149 adev->device.common.version = AUDIO_DEVICE_API_VERSION_2_0;
The Android Open Source Project5738f832012-12-12 16:00:35 -08001150 adev->device.common.module = (struct hw_module_t *) module;
1151 adev->device.common.close = adev_close;
1152
1153 adev->device.init_check = adev_init_check;
1154 adev->device.set_voice_volume = adev_set_voice_volume;
1155 adev->device.set_master_volume = adev_set_master_volume;
1156 adev->device.set_mode = adev_set_mode;
1157 adev->device.set_mic_mute = adev_set_mic_mute;
1158 adev->device.get_mic_mute = adev_get_mic_mute;
1159 adev->device.set_parameters = adev_set_parameters;
1160 adev->device.get_parameters = adev_get_parameters;
1161 adev->device.get_input_buffer_size = adev_get_input_buffer_size;
1162 adev->device.open_output_stream = adev_open_output_stream;
1163 adev->device.close_output_stream = adev_close_output_stream;
1164 adev->device.open_input_stream = adev_open_input_stream;
1165 adev->device.close_input_stream = adev_close_input_stream;
1166 adev->device.dump = adev_dump;
1167
1168 adev->output = NULL;
1169
1170
1171 *device = &adev->device.common;
1172
1173 return 0;
1174}
1175
1176static struct hw_module_methods_t hal_module_methods = {
1177 .open = adev_open,
1178};
1179
1180struct audio_module HAL_MODULE_INFO_SYM = {
1181 .common = {
1182 .tag = HARDWARE_MODULE_TAG,
1183 .version_major = 1,
1184 .version_minor = 0,
1185 .id = AUDIO_HARDWARE_MODULE_ID,
1186 .name = "A2DP Audio HW HAL",
1187 .author = "The Android Open Source Project",
1188 .methods = &hal_module_methods,
1189 },
1190};
1191