blob: e53ad5d71c901a779d2d489a2585cf445f47a48f [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>
Mark Salyzyn40421cb2014-04-17 13:45:20 -070028#include <inttypes.h>
The Android Open Source Project5738f832012-12-12 16:00:35 -080029#include <pthread.h>
30#include <stdint.h>
31#include <sys/time.h>
32#include <sys/socket.h>
33#include <sys/un.h>
34#include <sys/poll.h>
35#include <sys/errno.h>
36#include <sys/stat.h>
37#include <unistd.h>
38#include <fcntl.h>
39#include <cutils/str_parms.h>
40#include <cutils/sockets.h>
41
42#include <system/audio.h>
43#include <hardware/audio.h>
44
45#include <hardware/hardware.h>
46#include "audio_a2dp_hw.h"
Mike J. Chen5cd8bff2014-01-31 18:16:59 -080047#include "bt_utils.h"
The Android Open Source Project5738f832012-12-12 16:00:35 -080048
49#define LOG_TAG "audio_a2dp_hw"
50/* #define LOG_NDEBUG 0 */
Mark Salyzyn40421cb2014-04-17 13:45:20 -070051#include <log/log.h>
The Android Open Source Project5738f832012-12-12 16:00:35 -080052
53/*****************************************************************************
54** Constants & Macros
55******************************************************************************/
56
57#define CTRL_CHAN_RETRY_COUNT 3
58#define USEC_PER_SEC 1000000L
59
60#define CASE_RETURN_STR(const) case const: return #const;
61
62#define FNLOG() ALOGV("%s", __FUNCTION__);
63#define DEBUG(fmt, ...) ALOGV("%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
64#define INFO(fmt, ...) ALOGI("%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
65#define ERROR(fmt, ...) ALOGE("%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
66
67#define ASSERTC(cond, msg, val) if (!(cond)) {ERROR("### ASSERT : %s line %d %s (%d) ###", __FILE__, __LINE__, msg, val);}
68
69/*****************************************************************************
70** Local type definitions
71******************************************************************************/
72
73typedef enum {
74 AUDIO_A2DP_STATE_STARTING,
75 AUDIO_A2DP_STATE_STARTED,
76 AUDIO_A2DP_STATE_STOPPING,
77 AUDIO_A2DP_STATE_STOPPED,
78 AUDIO_A2DP_STATE_SUSPENDED, /* need explicit set param call to resume (suspend=false) */
79 AUDIO_A2DP_STATE_STANDBY /* allows write to autoresume */
80} a2dp_state_t;
81
82struct a2dp_stream_out;
83
84struct a2dp_audio_device {
85 struct audio_hw_device device;
86 struct a2dp_stream_out *output;
87};
88
89struct a2dp_config {
90 uint32_t rate;
91 uint32_t channel_flags;
92 int format;
93};
94
95/* move ctrl_fd outside output stream and keep open until HAL unloaded ? */
96
97struct a2dp_stream_out {
98 struct audio_stream_out stream;
99 pthread_mutex_t lock;
100 int ctrl_fd;
101 int audio_fd;
102 size_t buffer_sz;
103 a2dp_state_t state;
104 struct a2dp_config cfg;
105};
106
107struct a2dp_stream_in {
108 struct audio_stream_in stream;
109};
110
111/*****************************************************************************
112** Static variables
113******************************************************************************/
114
115/*****************************************************************************
116** Static functions
117******************************************************************************/
118
119static size_t out_get_buffer_size(const struct audio_stream *stream);
120
121/*****************************************************************************
122** Externs
123******************************************************************************/
124
125/*****************************************************************************
126** Functions
127******************************************************************************/
128
129/*****************************************************************************
130** Miscellaneous helper functions
131******************************************************************************/
132
133static const char* dump_a2dp_ctrl_event(char event)
134{
135 switch(event)
136 {
137 CASE_RETURN_STR(A2DP_CTRL_CMD_NONE)
138 CASE_RETURN_STR(A2DP_CTRL_CMD_CHECK_READY)
139 CASE_RETURN_STR(A2DP_CTRL_CMD_START)
140 CASE_RETURN_STR(A2DP_CTRL_CMD_STOP)
141 CASE_RETURN_STR(A2DP_CTRL_CMD_SUSPEND)
142 default:
143 return "UNKNOWN MSG ID";
144 }
145}
146
147/* logs timestamp with microsec precision
148 pprev is optional in case a dedicated diff is required */
149static void ts_log(char *tag, int val, struct timespec *pprev_opt)
150{
151 struct timespec now;
152 static struct timespec prev = {0,0};
153 unsigned long long now_us;
154 unsigned long long diff_us;
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800155 UNUSED(tag);
156 UNUSED(val);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800157
158 clock_gettime(CLOCK_MONOTONIC, &now);
159
160 now_us = now.tv_sec*USEC_PER_SEC + now.tv_nsec/1000;
161
162 if (pprev_opt)
163 {
164 diff_us = (now.tv_sec - prev.tv_sec) * USEC_PER_SEC + (now.tv_nsec - prev.tv_nsec)/1000;
165 *pprev_opt = now;
166 DEBUG("[%s] ts %08lld, *diff %08lld, val %d", tag, now_us, diff_us, val);
167 }
168 else
169 {
170 diff_us = (now.tv_sec - prev.tv_sec) * USEC_PER_SEC + (now.tv_nsec - prev.tv_nsec)/1000;
171 prev = now;
172 DEBUG("[%s] ts %08lld, diff %08lld, val %d", tag, now_us, diff_us, val);
173 }
174}
175
176static int calc_audiotime(struct a2dp_config cfg, int bytes)
177{
178 int chan_count = popcount(cfg.channel_flags);
179
180 ASSERTC(cfg.format == AUDIO_FORMAT_PCM_16_BIT,
181 "unsupported sample sz", cfg.format);
182
183 return bytes*(1000000/(chan_count*2))/cfg.rate;
184}
185
186/*****************************************************************************
187**
188** bluedroid stack adaptation
189**
190*****************************************************************************/
191
192static int skt_connect(struct a2dp_stream_out *out, char *path)
193{
194 int ret;
195 int skt_fd;
196 struct sockaddr_un remote;
197 int len;
198
Kévin PETIT22c6e502014-02-12 17:24:01 +0000199 INFO("connect to %s (sz %zu)", path, out->buffer_sz);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800200
201 skt_fd = socket(AF_LOCAL, SOCK_STREAM, 0);
202
203 if(socket_local_client_connect(skt_fd, path,
204 ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM) < 0)
205 {
206 ERROR("failed to connect (%s)", strerror(errno));
207 close(skt_fd);
208 return -1;
209 }
210
211 len = out->buffer_sz;
212 ret = setsockopt(skt_fd, SOL_SOCKET, SO_SNDBUF, (char*)&len, (int)sizeof(len));
213
214 /* only issue warning if failed */
215 if (ret < 0)
216 ERROR("setsockopt failed (%s)", strerror(errno));
217
218 INFO("connected to stack fd = %d", skt_fd);
219
220 return skt_fd;
221}
222
223static int skt_write(int fd, const void *p, size_t len)
224{
225 int sent;
226 struct pollfd pfd;
227
228 FNLOG();
229
230 pfd.fd = fd;
231 pfd.events = POLLOUT;
232
233 /* poll for 500 ms */
234
235 /* send time out */
236 if (poll(&pfd, 1, 500) == 0)
237 return 0;
238
239 ts_log("skt_write", len, NULL);
240
241 if ((sent = send(fd, p, len, MSG_NOSIGNAL)) == -1)
242 {
243 ERROR("write failed with errno=%d\n", errno);
244 return -1;
245 }
246
247 return sent;
248}
249
250static int skt_disconnect(int fd)
251{
252 INFO("fd %d", fd);
253
254 if (fd != AUDIO_SKT_DISCONNECTED)
255 {
256 shutdown(fd, SHUT_RDWR);
257 close(fd);
258 }
259 return 0;
260}
261
262
263
264/*****************************************************************************
265**
266** AUDIO CONTROL PATH
267**
268*****************************************************************************/
269
270static int a2dp_command(struct a2dp_stream_out *out, char cmd)
271{
272 char ack;
273
274 DEBUG("A2DP COMMAND %s", dump_a2dp_ctrl_event(cmd));
275
276 /* send command */
277 if (send(out->ctrl_fd, &cmd, 1, MSG_NOSIGNAL) == -1)
278 {
279 ERROR("cmd failed (%s)", strerror(errno));
280 skt_disconnect(out->ctrl_fd);
281 out->ctrl_fd = AUDIO_SKT_DISCONNECTED;
282 return -1;
283 }
284
285 /* wait for ack byte */
286 if (recv(out->ctrl_fd, &ack, 1, MSG_NOSIGNAL) < 0)
287 {
288 ERROR("ack failed (%s)", strerror(errno));
Nitin Srivastav1b170892014-02-21 18:33:14 +0530289 if (errno == EINTR)
290 {
291 /* retry again */
292 if (recv(out->ctrl_fd, &ack, 1, MSG_NOSIGNAL) < 0)
293 {
294 ERROR("ack failed (%s)", strerror(errno));
295 skt_disconnect(out->ctrl_fd);
296 out->ctrl_fd = AUDIO_SKT_DISCONNECTED;
297 return -1;
298 }
299 }
300 else
301 {
302 skt_disconnect(out->ctrl_fd);
303 out->ctrl_fd = AUDIO_SKT_DISCONNECTED;
304 return -1;
305
306 }
The Android Open Source Project5738f832012-12-12 16:00:35 -0800307 }
308
309 DEBUG("A2DP COMMAND %s DONE STATUS %d", dump_a2dp_ctrl_event(cmd), ack);
310
311 if (ack != A2DP_CTRL_ACK_SUCCESS)
312 return -1;
313
314 return 0;
315}
316
317/*****************************************************************************
318**
319** AUDIO DATA PATH
320**
321*****************************************************************************/
322
323static void a2dp_stream_out_init(struct a2dp_stream_out *out)
324{
325 pthread_mutexattr_t lock_attr;
326
327 FNLOG();
328
329 pthread_mutexattr_init(&lock_attr);
330 pthread_mutexattr_settype(&lock_attr, PTHREAD_MUTEX_RECURSIVE);
331 pthread_mutex_init(&out->lock, &lock_attr);
332
333 out->ctrl_fd = AUDIO_SKT_DISCONNECTED;
334 out->audio_fd = AUDIO_SKT_DISCONNECTED;
335 out->state = AUDIO_A2DP_STATE_STOPPED;
336
337 out->cfg.channel_flags = AUDIO_STREAM_DEFAULT_CHANNEL_FLAG;
338 out->cfg.format = AUDIO_STREAM_DEFAULT_FORMAT;
339 out->cfg.rate = AUDIO_STREAM_DEFAULT_RATE;
340
341 /* manages max capacity of socket pipe */
342 out->buffer_sz = AUDIO_STREAM_OUTPUT_BUFFER_SZ;
343}
344
345static int start_audio_datapath(struct a2dp_stream_out *out)
346{
347 int oldstate = out->state;
348
349 INFO("state %d", out->state);
350
351 if (out->ctrl_fd == AUDIO_SKT_DISCONNECTED)
352 return -1;
353
354 out->state = AUDIO_A2DP_STATE_STARTING;
355
356 if (a2dp_command(out, A2DP_CTRL_CMD_START) < 0)
357 {
358 ERROR("audiopath start failed");
359
360 out->state = oldstate;
361 return -1;
362 }
363
364 /* connect socket if not yet connected */
365 if (out->audio_fd == AUDIO_SKT_DISCONNECTED)
366 {
367 out->audio_fd = skt_connect(out, A2DP_DATA_PATH);
368
369 if (out->audio_fd < 0)
370 {
371 out->state = oldstate;
372 return -1;
373 }
374
375 out->state = AUDIO_A2DP_STATE_STARTED;
376 }
377
378 return 0;
379}
380
381
382static int stop_audio_datapath(struct a2dp_stream_out *out)
383{
384 int oldstate = out->state;
385
386 INFO("state %d", out->state);
387
388 if (out->ctrl_fd == AUDIO_SKT_DISCONNECTED)
389 return -1;
390
391 /* prevent any stray output writes from autostarting the stream
392 while stopping audiopath */
393 out->state = AUDIO_A2DP_STATE_STOPPING;
394
395 if (a2dp_command(out, A2DP_CTRL_CMD_STOP) < 0)
396 {
397 ERROR("audiopath stop failed");
398 out->state = oldstate;
399 return -1;
400 }
401
402 out->state = AUDIO_A2DP_STATE_STOPPED;
403
404 /* disconnect audio path */
405 skt_disconnect(out->audio_fd);
406 out->audio_fd = AUDIO_SKT_DISCONNECTED;
407
408 return 0;
409}
410
411static int suspend_audio_datapath(struct a2dp_stream_out *out, bool standby)
412{
413 INFO("state %d", out->state);
414
415 if (out->ctrl_fd == AUDIO_SKT_DISCONNECTED)
416 return -1;
417
418 if (out->state == AUDIO_A2DP_STATE_STOPPING)
419 return -1;
420
421 if (a2dp_command(out, A2DP_CTRL_CMD_SUSPEND) < 0)
422 return -1;
423
424 if (standby)
425 out->state = AUDIO_A2DP_STATE_STANDBY;
426 else
427 out->state = AUDIO_A2DP_STATE_SUSPENDED;
428
429 /* disconnect audio path */
430 skt_disconnect(out->audio_fd);
431
432 out->audio_fd = AUDIO_SKT_DISCONNECTED;
433
434 return 0;
435}
436
437static int check_a2dp_ready(struct a2dp_stream_out *out)
438{
439 INFO("state %d", out->state);
440
441 if (a2dp_command(out, A2DP_CTRL_CMD_CHECK_READY) < 0)
442 {
443 ERROR("check a2dp ready failed");
444 return -1;
445 }
446 return 0;
447}
448
449
450/*****************************************************************************
451**
452** audio output callbacks
453**
454*****************************************************************************/
455
456static ssize_t out_write(struct audio_stream_out *stream, const void* buffer,
457 size_t bytes)
458{
459 struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
460 int sent;
461
Mark Salyzyn40421cb2014-04-17 13:45:20 -0700462 DEBUG("write %zu bytes (fd %d)", bytes, out->audio_fd);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800463
464 if (out->state == AUDIO_A2DP_STATE_SUSPENDED)
465 {
466 DEBUG("stream suspended");
467 return -1;
468 }
469
470 /* only allow autostarting if we are in stopped or standby */
471 if ((out->state == AUDIO_A2DP_STATE_STOPPED) ||
472 (out->state == AUDIO_A2DP_STATE_STANDBY))
473 {
474 pthread_mutex_lock(&out->lock);
475
476 if (start_audio_datapath(out) < 0)
477 {
478 /* emulate time this write represents to avoid very fast write
479 failures during transition periods or remote suspend */
480
481 int us_delay = calc_audiotime(out->cfg, bytes);
482
483 DEBUG("emulate a2dp write delay (%d us)", us_delay);
484
485 usleep(us_delay);
486 pthread_mutex_unlock(&out->lock);
487 return -1;
488 }
489
490 pthread_mutex_unlock(&out->lock);
491 }
492 else if (out->state != AUDIO_A2DP_STATE_STARTED)
493 {
494 ERROR("stream not in stopped or standby");
495 return -1;
496 }
497
498 sent = skt_write(out->audio_fd, buffer, bytes);
499
500 if (sent == -1)
501 {
502 skt_disconnect(out->audio_fd);
503 out->audio_fd = AUDIO_SKT_DISCONNECTED;
504 out->state = AUDIO_A2DP_STATE_STOPPED;
505 }
506
Mark Salyzyn40421cb2014-04-17 13:45:20 -0700507 DEBUG("wrote %d bytes out of %zu bytes", sent, bytes);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800508 return sent;
509}
510
511
512static uint32_t out_get_sample_rate(const struct audio_stream *stream)
513{
514 struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
515
Mark Salyzyn40421cb2014-04-17 13:45:20 -0700516 DEBUG("rate %" PRIu32, out->cfg.rate);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800517
518 return out->cfg.rate;
519}
520
521static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate)
522{
523 struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
524
Mark Salyzyn40421cb2014-04-17 13:45:20 -0700525 DEBUG("out_set_sample_rate : %" PRIu32, rate);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800526
527 if (rate != AUDIO_STREAM_DEFAULT_RATE)
528 {
529 ERROR("only rate %d supported", AUDIO_STREAM_DEFAULT_RATE);
530 return -1;
531 }
532
533 out->cfg.rate = rate;
534
535 return 0;
536}
537
538static size_t out_get_buffer_size(const struct audio_stream *stream)
539{
540 struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
541
Mark Salyzyn40421cb2014-04-17 13:45:20 -0700542 DEBUG("buffer_size : %zu", out->buffer_sz);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800543
544 return out->buffer_sz;
545}
546
547static uint32_t out_get_channels(const struct audio_stream *stream)
548{
549 struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
550
Mark Salyzyn40421cb2014-04-17 13:45:20 -0700551 DEBUG("channels 0x%" PRIx32, out->cfg.channel_flags);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800552
553 return out->cfg.channel_flags;
554}
555
556static audio_format_t out_get_format(const struct audio_stream *stream)
557{
558 struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
559 DEBUG("format 0x%x", out->cfg.format);
560 return out->cfg.format;
561}
562
563static int out_set_format(struct audio_stream *stream, audio_format_t format)
564{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800565 UNUSED(format);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800566 struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
567 DEBUG("setting format not yet supported (0x%x)", format);
568 return -ENOSYS;
569}
570
571static int out_standby(struct audio_stream *stream)
572{
573 struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800574 int retVal = 0;
575
576 FNLOG();
577
578 pthread_mutex_lock(&out->lock);
579
580 if (out->state == AUDIO_A2DP_STATE_STARTED)
581 retVal = suspend_audio_datapath(out, true);
582 else
583 retVal = 0;
584 pthread_mutex_unlock (&out->lock);
585
586 return retVal;
587}
588
589static int out_dump(const struct audio_stream *stream, int fd)
590{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800591 UNUSED(fd);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800592 struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
593 FNLOG();
594 return 0;
595}
596
597static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
598{
599 struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
600 struct str_parms *parms;
601 char keyval[16];
Eric Laurent3efd2322014-03-25 18:36:27 -0700602 int retval;
603 int status = 0;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800604
605 INFO("state %d", out->state);
606
607 pthread_mutex_lock(&out->lock);
608
609 parms = str_parms_create_str(kvpairs);
610
611 /* dump params */
612 str_parms_dump(parms);
613
614 retval = str_parms_get_str(parms, "closing", keyval, sizeof(keyval));
615
616 if (retval >= 0)
617 {
618 if (strcmp(keyval, "true") == 0)
619 {
620 DEBUG("stream closing, disallow any writes");
621 out->state = AUDIO_A2DP_STATE_STOPPING;
622 }
623 }
624
625 retval = str_parms_get_str(parms, "A2dpSuspended", keyval, sizeof(keyval));
626
627 if (retval >= 0)
628 {
629 if (strcmp(keyval, "true") == 0)
630 {
631 if (out->state == AUDIO_A2DP_STATE_STARTED)
Eric Laurent3efd2322014-03-25 18:36:27 -0700632 status = suspend_audio_datapath(out, false);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800633 }
634 else
635 {
636 /* Do not start the streaming automatically. If the phone was streaming
637 * prior to being suspended, the next out_write shall trigger the
638 * AVDTP start procedure */
639 if (out->state == AUDIO_A2DP_STATE_SUSPENDED)
640 out->state = AUDIO_A2DP_STATE_STANDBY;
641 /* Irrespective of the state, return 0 */
The Android Open Source Project5738f832012-12-12 16:00:35 -0800642 }
643 }
644
645 pthread_mutex_unlock(&out->lock);
646 str_parms_destroy(parms);
647
Eric Laurent3efd2322014-03-25 18:36:27 -0700648 return status;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800649}
650
651static char * out_get_parameters(const struct audio_stream *stream, const char *keys)
652{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800653 UNUSED(keys);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800654 struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
655
656 FNLOG();
657
658 /* add populating param here */
659
660 return strdup("");
661}
662
663static uint32_t out_get_latency(const struct audio_stream_out *stream)
664{
665 int latency_us;
666
667 struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
668
669 FNLOG();
670
671 latency_us = ((out->buffer_sz * 1000 ) /
672 audio_stream_frame_size(&out->stream.common) /
673 out->cfg.rate) * 1000;
674
675
676 return (latency_us / 1000) + 200;
677}
678
679static int out_set_volume(struct audio_stream_out *stream, float left,
680 float right)
681{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800682 UNUSED(stream);
683 UNUSED(left);
684 UNUSED(right);
685
The Android Open Source Project5738f832012-12-12 16:00:35 -0800686 FNLOG();
687
688 /* volume controlled in audioflinger mixer (digital) */
689
690 return -ENOSYS;
691}
692
693
694
695static int out_get_render_position(const struct audio_stream_out *stream,
696 uint32_t *dsp_frames)
697{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800698 UNUSED(stream);
699 UNUSED(dsp_frames);
700
The Android Open Source Project5738f832012-12-12 16:00:35 -0800701 FNLOG();
702 return -EINVAL;
703}
704
705static int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
706{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800707 UNUSED(stream);
708 UNUSED(effect);
709
The Android Open Source Project5738f832012-12-12 16:00:35 -0800710 FNLOG();
711 return 0;
712}
713
714static int out_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
715{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800716 UNUSED(stream);
717 UNUSED(effect);
718
The Android Open Source Project5738f832012-12-12 16:00:35 -0800719 FNLOG();
720 return 0;
721}
722
723/*
724 * AUDIO INPUT STREAM
725 */
726
727static uint32_t in_get_sample_rate(const struct audio_stream *stream)
728{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800729 UNUSED(stream);
730
The Android Open Source Project5738f832012-12-12 16:00:35 -0800731 FNLOG();
732 return 8000;
733}
734
735static int in_set_sample_rate(struct audio_stream *stream, uint32_t rate)
736{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800737 UNUSED(stream);
738 UNUSED(rate);
739
The Android Open Source Project5738f832012-12-12 16:00:35 -0800740 FNLOG();
741 return 0;
742}
743
744static size_t in_get_buffer_size(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 320;
750}
751
752static uint32_t in_get_channels(const struct audio_stream *stream)
753{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800754 UNUSED(stream);
755
The Android Open Source Project5738f832012-12-12 16:00:35 -0800756 FNLOG();
757 return AUDIO_CHANNEL_IN_MONO;
758}
759
760static audio_format_t in_get_format(const struct audio_stream *stream)
761{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800762 UNUSED(stream);
763
The Android Open Source Project5738f832012-12-12 16:00:35 -0800764 FNLOG();
765 return AUDIO_FORMAT_PCM_16_BIT;
766}
767
768static int in_set_format(struct audio_stream *stream, audio_format_t format)
769{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800770 UNUSED(stream);
771 UNUSED(format);
772
The Android Open Source Project5738f832012-12-12 16:00:35 -0800773 FNLOG();
774 return 0;
775}
776
777static int in_standby(struct audio_stream *stream)
778{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800779 UNUSED(stream);
780
The Android Open Source Project5738f832012-12-12 16:00:35 -0800781 FNLOG();
782 return 0;
783}
784
785static int in_dump(const struct audio_stream *stream, int fd)
786{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800787 UNUSED(stream);
788 UNUSED(fd);
789
The Android Open Source Project5738f832012-12-12 16:00:35 -0800790 FNLOG();
791 return 0;
792}
793
794static int in_set_parameters(struct audio_stream *stream, const char *kvpairs)
795{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800796 UNUSED(stream);
797 UNUSED(kvpairs);
798
The Android Open Source Project5738f832012-12-12 16:00:35 -0800799 FNLOG();
800 return 0;
801}
802
803static char * in_get_parameters(const struct audio_stream *stream,
804 const char *keys)
805{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800806 UNUSED(stream);
807 UNUSED(keys);
808
The Android Open Source Project5738f832012-12-12 16:00:35 -0800809 FNLOG();
810 return strdup("");
811}
812
813static int in_set_gain(struct audio_stream_in *stream, float gain)
814{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800815 UNUSED(stream);
816 UNUSED(gain);
817
The Android Open Source Project5738f832012-12-12 16:00:35 -0800818 FNLOG();
819 return 0;
820}
821
822static ssize_t in_read(struct audio_stream_in *stream, void* buffer,
823 size_t bytes)
824{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800825 UNUSED(stream);
826 UNUSED(buffer);
827 UNUSED(bytes);
828
The Android Open Source Project5738f832012-12-12 16:00:35 -0800829 FNLOG();
830 return bytes;
831}
832
833static uint32_t in_get_input_frames_lost(struct audio_stream_in *stream)
834{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800835 UNUSED(stream);
836
The Android Open Source Project5738f832012-12-12 16:00:35 -0800837 FNLOG();
838 return 0;
839}
840
841static int in_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
842{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800843 UNUSED(stream);
844 UNUSED(effect);
845
The Android Open Source Project5738f832012-12-12 16:00:35 -0800846 FNLOG();
847 return 0;
848}
849
850static int in_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
851{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800852 UNUSED(stream);
853 UNUSED(effect);
854
The Android Open Source Project5738f832012-12-12 16:00:35 -0800855 FNLOG();
856
857 return 0;
858}
859
860static int adev_open_output_stream(struct audio_hw_device *dev,
861 audio_io_handle_t handle,
862 audio_devices_t devices,
863 audio_output_flags_t flags,
864 struct audio_config *config,
865 struct audio_stream_out **stream_out)
866
867{
868 struct a2dp_audio_device *a2dp_dev = (struct a2dp_audio_device *)dev;
869 struct a2dp_stream_out *out;
870 int ret = 0;
871 int i;
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800872 UNUSED(handle);
873 UNUSED(devices);
874 UNUSED(flags);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800875
876 INFO("opening output");
877
878 out = (struct a2dp_stream_out *)calloc(1, sizeof(struct a2dp_stream_out));
879
880 if (!out)
881 return -ENOMEM;
882
883 out->stream.common.get_sample_rate = out_get_sample_rate;
884 out->stream.common.set_sample_rate = out_set_sample_rate;
885 out->stream.common.get_buffer_size = out_get_buffer_size;
886 out->stream.common.get_channels = out_get_channels;
887 out->stream.common.get_format = out_get_format;
888 out->stream.common.set_format = out_set_format;
889 out->stream.common.standby = out_standby;
890 out->stream.common.dump = out_dump;
891 out->stream.common.set_parameters = out_set_parameters;
892 out->stream.common.get_parameters = out_get_parameters;
893 out->stream.common.add_audio_effect = out_add_audio_effect;
894 out->stream.common.remove_audio_effect = out_remove_audio_effect;
895 out->stream.get_latency = out_get_latency;
896 out->stream.set_volume = out_set_volume;
897 out->stream.write = out_write;
898 out->stream.get_render_position = out_get_render_position;
899
900 /* initialize a2dp specifics */
901 a2dp_stream_out_init(out);
902
903 /* set output config values */
904 if (config)
905 {
906 config->format = out_get_format((const struct audio_stream *)&out->stream);
907 config->sample_rate = out_get_sample_rate((const struct audio_stream *)&out->stream);
908 config->channel_mask = out_get_channels((const struct audio_stream *)&out->stream);
909 }
910 *stream_out = &out->stream;
911 a2dp_dev->output = out;
912
913 /* retry logic to catch any timing variations on control channel */
914 for (i = 0; i < CTRL_CHAN_RETRY_COUNT; i++)
915 {
916 /* connect control channel if not already connected */
917 if ((out->ctrl_fd = skt_connect(out, A2DP_CTRL_PATH)) > 0)
918 {
919 /* success, now check if stack is ready */
920 if (check_a2dp_ready(out) == 0)
921 break;
922
923 ERROR("error : a2dp not ready, wait 250 ms and retry");
924 usleep(250000);
925 skt_disconnect(out->ctrl_fd);
926 }
927
928 /* ctrl channel not ready, wait a bit */
929 usleep(250000);
930 }
931
932 if (out->ctrl_fd == AUDIO_SKT_DISCONNECTED)
933 {
934 ERROR("ctrl socket failed to connect (%s)", strerror(errno));
935 ret = -1;
936 goto err_open;
937 }
938
939 DEBUG("success");
940 return 0;
941
942err_open:
943 free(out);
944 *stream_out = NULL;
Nitin Srivastavae67bf202014-01-31 15:51:24 +0530945 a2dp_dev->output = NULL;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800946 ERROR("failed");
947 return ret;
948}
949
950static void adev_close_output_stream(struct audio_hw_device *dev,
951 struct audio_stream_out *stream)
952{
953 struct a2dp_audio_device *a2dp_dev = (struct a2dp_audio_device *)dev;
954 struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream;
955
956 INFO("closing output (state %d)", out->state);
957
958 if ((out->state == AUDIO_A2DP_STATE_STARTED) || (out->state == AUDIO_A2DP_STATE_STOPPING))
959 stop_audio_datapath(out);
960
961 skt_disconnect(out->ctrl_fd);
962 free(stream);
963 a2dp_dev->output = NULL;
964
965 DEBUG("done");
966}
967
968static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
969{
970 struct a2dp_audio_device *a2dp_dev = (struct a2dp_audio_device *)dev;
971 struct a2dp_stream_out *out = a2dp_dev->output;
972 int retval = 0;
973
974 if (out == NULL)
Nitin Srivastavae67bf202014-01-31 15:51:24 +0530975 {
976 ERROR("ERROR: set param called even when stream out is null");
The Android Open Source Project5738f832012-12-12 16:00:35 -0800977 return retval;
Nitin Srivastavae67bf202014-01-31 15:51:24 +0530978 }
The Android Open Source Project5738f832012-12-12 16:00:35 -0800979 INFO("state %d", out->state);
980
981 retval = out->stream.common.set_parameters((struct audio_stream *)out, kvpairs);
982
983 return retval;
984}
985
986static char * adev_get_parameters(const struct audio_hw_device *dev,
987 const char *keys)
988{
989 struct str_parms *parms;
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800990 UNUSED(dev);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800991
992 FNLOG();
993
994 parms = str_parms_create_str(keys);
995
996 str_parms_dump(parms);
997
998 str_parms_destroy(parms);
999
1000 return strdup("");
1001}
1002
1003static int adev_init_check(const struct audio_hw_device *dev)
1004{
1005 struct a2dp_audio_device *a2dp_dev = (struct a2dp_audio_device*)dev;
1006
1007 FNLOG();
1008
1009 return 0;
1010}
1011
1012static int adev_set_voice_volume(struct audio_hw_device *dev, float volume)
1013{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -08001014 UNUSED(dev);
1015 UNUSED(volume);
1016
The Android Open Source Project5738f832012-12-12 16:00:35 -08001017 FNLOG();
1018
1019 return -ENOSYS;
1020}
1021
1022static int adev_set_master_volume(struct audio_hw_device *dev, float volume)
1023{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -08001024 UNUSED(dev);
1025 UNUSED(volume);
1026
The Android Open Source Project5738f832012-12-12 16:00:35 -08001027 FNLOG();
1028
1029 return -ENOSYS;
1030}
1031
1032static int adev_set_mode(struct audio_hw_device *dev, int mode)
1033{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -08001034 UNUSED(dev);
1035 UNUSED(mode);
1036
The Android Open Source Project5738f832012-12-12 16:00:35 -08001037 FNLOG();
1038
1039 return 0;
1040}
1041
1042static int adev_set_mic_mute(struct audio_hw_device *dev, bool state)
1043{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -08001044 UNUSED(dev);
1045 UNUSED(state);
1046
The Android Open Source Project5738f832012-12-12 16:00:35 -08001047 FNLOG();
1048
1049 return -ENOSYS;
1050}
1051
1052static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state)
1053{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -08001054 UNUSED(dev);
1055 UNUSED(state);
1056
The Android Open Source Project5738f832012-12-12 16:00:35 -08001057 FNLOG();
1058
1059 return -ENOSYS;
1060}
1061
1062static size_t adev_get_input_buffer_size(const struct audio_hw_device *dev,
1063 const struct audio_config *config)
1064{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -08001065 UNUSED(dev);
1066 UNUSED(config);
1067
The Android Open Source Project5738f832012-12-12 16:00:35 -08001068 FNLOG();
1069
1070 return 320;
1071}
1072
1073static int adev_open_input_stream(struct audio_hw_device *dev,
1074 audio_io_handle_t handle,
1075 audio_devices_t devices,
1076 struct audio_config *config,
1077 struct audio_stream_in **stream_in)
1078{
1079 struct a2dp_audio_device *ladev = (struct a2dp_audio_device *)dev;
1080 struct a2dp_stream_in *in;
1081 int ret;
Mike J. Chen5cd8bff2014-01-31 18:16:59 -08001082 UNUSED(handle);
1083 UNUSED(devices);
1084 UNUSED(config);
The Android Open Source Project5738f832012-12-12 16:00:35 -08001085
1086 FNLOG();
1087
1088 in = (struct a2dp_stream_in *)calloc(1, sizeof(struct a2dp_stream_in));
1089
1090 if (!in)
1091 return -ENOMEM;
1092
1093 in->stream.common.get_sample_rate = in_get_sample_rate;
1094 in->stream.common.set_sample_rate = in_set_sample_rate;
1095 in->stream.common.get_buffer_size = in_get_buffer_size;
1096 in->stream.common.get_channels = in_get_channels;
1097 in->stream.common.get_format = in_get_format;
1098 in->stream.common.set_format = in_set_format;
1099 in->stream.common.standby = in_standby;
1100 in->stream.common.dump = in_dump;
1101 in->stream.common.set_parameters = in_set_parameters;
1102 in->stream.common.get_parameters = in_get_parameters;
1103 in->stream.common.add_audio_effect = in_add_audio_effect;
1104 in->stream.common.remove_audio_effect = in_remove_audio_effect;
1105 in->stream.set_gain = in_set_gain;
1106 in->stream.read = in_read;
1107 in->stream.get_input_frames_lost = in_get_input_frames_lost;
1108
1109 *stream_in = &in->stream;
1110 return 0;
1111
1112err_open:
1113 free(in);
1114 *stream_in = NULL;
1115 return ret;
1116}
1117
1118static void adev_close_input_stream(struct audio_hw_device *dev,
1119 struct audio_stream_in *in)
1120{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -08001121 UNUSED(dev);
1122 UNUSED(in);
1123
The Android Open Source Project5738f832012-12-12 16:00:35 -08001124 FNLOG();
1125
1126 return;
1127}
1128
1129static int adev_dump(const audio_hw_device_t *device, int fd)
1130{
Mike J. Chen5cd8bff2014-01-31 18:16:59 -08001131 UNUSED(device);
1132 UNUSED(fd);
1133
The Android Open Source Project5738f832012-12-12 16:00:35 -08001134 FNLOG();
1135
1136 return 0;
1137}
1138
1139static int adev_close(hw_device_t *device)
1140{
1141 FNLOG();
1142
1143 free(device);
1144 return 0;
1145}
1146
1147static int adev_open(const hw_module_t* module, const char* name,
1148 hw_device_t** device)
1149{
1150 struct a2dp_audio_device *adev;
1151 int ret;
1152
1153 INFO(" adev_open in A2dp_hw module");
1154 FNLOG();
1155
1156 if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0)
1157 {
1158 ERROR("interface %s not matching [%s]", name, AUDIO_HARDWARE_INTERFACE);
1159 return -EINVAL;
1160 }
1161
1162 adev = calloc(1, sizeof(struct a2dp_audio_device));
1163
1164 if (!adev)
1165 return -ENOMEM;
1166
1167 adev->device.common.tag = HARDWARE_DEVICE_TAG;
Eric Laurent9a445032014-03-20 18:01:09 -07001168 adev->device.common.version = AUDIO_DEVICE_API_VERSION_2_0;
The Android Open Source Project5738f832012-12-12 16:00:35 -08001169 adev->device.common.module = (struct hw_module_t *) module;
1170 adev->device.common.close = adev_close;
1171
1172 adev->device.init_check = adev_init_check;
1173 adev->device.set_voice_volume = adev_set_voice_volume;
1174 adev->device.set_master_volume = adev_set_master_volume;
1175 adev->device.set_mode = adev_set_mode;
1176 adev->device.set_mic_mute = adev_set_mic_mute;
1177 adev->device.get_mic_mute = adev_get_mic_mute;
1178 adev->device.set_parameters = adev_set_parameters;
1179 adev->device.get_parameters = adev_get_parameters;
1180 adev->device.get_input_buffer_size = adev_get_input_buffer_size;
1181 adev->device.open_output_stream = adev_open_output_stream;
1182 adev->device.close_output_stream = adev_close_output_stream;
1183 adev->device.open_input_stream = adev_open_input_stream;
1184 adev->device.close_input_stream = adev_close_input_stream;
1185 adev->device.dump = adev_dump;
1186
1187 adev->output = NULL;
1188
1189
1190 *device = &adev->device.common;
1191
1192 return 0;
1193}
1194
1195static struct hw_module_methods_t hal_module_methods = {
1196 .open = adev_open,
1197};
1198
1199struct audio_module HAL_MODULE_INFO_SYM = {
1200 .common = {
1201 .tag = HARDWARE_MODULE_TAG,
1202 .version_major = 1,
1203 .version_minor = 0,
1204 .id = AUDIO_HARDWARE_MODULE_ID,
1205 .name = "A2DP Audio HW HAL",
1206 .author = "The Android Open Source Project",
1207 .methods = &hal_module_methods,
1208 },
1209};
1210