diff options
author | Mike Lockwood <lockwood@google.com> | 2014-05-23 12:42:24 -0700 |
---|---|---|
committer | Mike Lockwood <lockwood@google.com> | 2014-06-12 16:16:41 -0700 |
commit | 3e8a242fcbeebea2857fa964ca48624d8433333e (patch) | |
tree | 0ce96caef135499f9bbf1243284d0bf1876bcd83 /audio_a2dp_hw | |
parent | ce24765fe7620c34e8d88ed4f826c8a6917582b2 (diff) | |
download | android_system_bt-3e8a242fcbeebea2857fa964ca48624d8433333e.tar.gz android_system_bt-3e8a242fcbeebea2857fa964ca48624d8433333e.tar.bz2 android_system_bt-3e8a242fcbeebea2857fa964ca48624d8433333e.zip |
More work on A2DP Sink:
Output audio data through A2DP audio HAL rather than playing directly
to native AudioTrack API.
Add separate HAL interface for A2DP sink
Change-Id: I6c6cb6088c350e104b4a7354f328b29c7178e295
Diffstat (limited to 'audio_a2dp_hw')
-rw-r--r-- | audio_a2dp_hw/audio_a2dp_hw.c | 492 | ||||
-rw-r--r-- | audio_a2dp_hw/audio_a2dp_hw.h | 3 |
2 files changed, 330 insertions, 165 deletions
diff --git a/audio_a2dp_hw/audio_a2dp_hw.c b/audio_a2dp_hw/audio_a2dp_hw.c index e53ad5d71..60feabac2 100644 --- a/audio_a2dp_hw/audio_a2dp_hw.c +++ b/audio_a2dp_hw/audio_a2dp_hw.c @@ -79,10 +79,12 @@ typedef enum { AUDIO_A2DP_STATE_STANDBY /* allows write to autoresume */ } a2dp_state_t; +struct a2dp_stream_in; struct a2dp_stream_out; struct a2dp_audio_device { struct audio_hw_device device; + struct a2dp_stream_in *input; struct a2dp_stream_out *output; }; @@ -94,18 +96,23 @@ struct a2dp_config { /* move ctrl_fd outside output stream and keep open until HAL unloaded ? */ -struct a2dp_stream_out { - struct audio_stream_out stream; +struct a2dp_stream_common { pthread_mutex_t lock; int ctrl_fd; int audio_fd; size_t buffer_sz; - a2dp_state_t state; struct a2dp_config cfg; + a2dp_state_t state; +}; + +struct a2dp_stream_out { + struct audio_stream_out stream; + struct a2dp_stream_common common; }; struct a2dp_stream_in { - struct audio_stream_in stream; + struct audio_stream_in stream; + struct a2dp_stream_common common; }; /***************************************************************************** @@ -189,14 +196,14 @@ static int calc_audiotime(struct a2dp_config cfg, int bytes) ** *****************************************************************************/ -static int skt_connect(struct a2dp_stream_out *out, char *path) +static int skt_connect(char *path, size_t buffer_sz) { int ret; int skt_fd; struct sockaddr_un remote; int len; - INFO("connect to %s (sz %zu)", path, out->buffer_sz); + INFO("connect to %s (sz %zu)", path, buffer_sz); skt_fd = socket(AF_LOCAL, SOCK_STREAM, 0); @@ -208,7 +215,7 @@ static int skt_connect(struct a2dp_stream_out *out, char *path) return -1; } - len = out->buffer_sz; + len = buffer_sz; ret = setsockopt(skt_fd, SOL_SOCKET, SO_SNDBUF, (char*)&len, (int)sizeof(len)); /* only issue warning if failed */ @@ -220,6 +227,38 @@ static int skt_connect(struct a2dp_stream_out *out, char *path) return skt_fd; } +static int skt_read(int fd, void *p, size_t len, int us_timeout) +{ + int read; + struct pollfd pfd; + struct timespec ts; + + FNLOG(); + + pfd.fd = fd; + pfd.events = POLLIN; + + ts.tv_sec = us_timeout / 1000000; + ts.tv_nsec = (us_timeout % 1000000) * 1000; + + ts_log("skt_read ppoll", len, NULL); + + /* read time out */ + if (ppoll(&pfd, 1, &ts, NULL) == 0) { + return 0; + } + + ts_log("skt_read recv", len, NULL); + + if ((read = recv(fd, p, len, MSG_NOSIGNAL)) == -1) + { + ERROR("write failed with errno=%d\n", errno); + return -1; + } + + return read; +} + static int skt_write(int fd, const void *p, size_t len) { int sent; @@ -267,44 +306,53 @@ static int skt_disconnect(int fd) ** *****************************************************************************/ -static int a2dp_command(struct a2dp_stream_out *out, char cmd) +static int a2dp_ctrl_receive(struct a2dp_stream_common *common, void* buffer, int length) { - char ack; - - DEBUG("A2DP COMMAND %s", dump_a2dp_ctrl_event(cmd)); - - /* send command */ - if (send(out->ctrl_fd, &cmd, 1, MSG_NOSIGNAL) == -1) - { - ERROR("cmd failed (%s)", strerror(errno)); - skt_disconnect(out->ctrl_fd); - out->ctrl_fd = AUDIO_SKT_DISCONNECTED; - return -1; - } - - /* wait for ack byte */ - if (recv(out->ctrl_fd, &ack, 1, MSG_NOSIGNAL) < 0) + int ret = recv(common->ctrl_fd, buffer, length, MSG_NOSIGNAL); + if (ret < 0) { ERROR("ack failed (%s)", strerror(errno)); if (errno == EINTR) { /* retry again */ - if (recv(out->ctrl_fd, &ack, 1, MSG_NOSIGNAL) < 0) + ret = recv(common->ctrl_fd, buffer, length, MSG_NOSIGNAL); + if (ret < 0) { ERROR("ack failed (%s)", strerror(errno)); - skt_disconnect(out->ctrl_fd); - out->ctrl_fd = AUDIO_SKT_DISCONNECTED; + skt_disconnect(common->ctrl_fd); + common->ctrl_fd = AUDIO_SKT_DISCONNECTED; return -1; } } else { - skt_disconnect(out->ctrl_fd); - out->ctrl_fd = AUDIO_SKT_DISCONNECTED; + skt_disconnect(common->ctrl_fd); + common->ctrl_fd = AUDIO_SKT_DISCONNECTED; return -1; } } + return ret; +} + +static int a2dp_command(struct a2dp_stream_common *common, char cmd) +{ + char ack; + + DEBUG("A2DP COMMAND %s", dump_a2dp_ctrl_event(cmd)); + + /* send command */ + if (send(common->ctrl_fd, &cmd, 1, MSG_NOSIGNAL) == -1) + { + ERROR("cmd failed (%s)", strerror(errno)); + skt_disconnect(common->ctrl_fd); + common->ctrl_fd = AUDIO_SKT_DISCONNECTED; + return -1; + } + + /* wait for ack byte */ + if (a2dp_ctrl_receive(common, &ack, 1) < 0) + return -1; DEBUG("A2DP COMMAND %s DONE STATUS %d", dump_a2dp_ctrl_event(cmd), ack); @@ -314,13 +362,74 @@ static int a2dp_command(struct a2dp_stream_out *out, char cmd) return 0; } +static int check_a2dp_ready(struct a2dp_stream_common *common) +{ + if (a2dp_command(common, A2DP_CTRL_CMD_CHECK_READY) < 0) + { + ERROR("check a2dp ready failed"); + return -1; + } + return 0; +} + +static int a2dp_read_audio_config(struct a2dp_stream_common *common) +{ + char cmd = A2DP_CTRL_GET_AUDIO_CONFIG; + uint32_t sample_rate; + uint8_t channel_count; + + if (a2dp_command(common, A2DP_CTRL_GET_AUDIO_CONFIG) < 0) + { + ERROR("check a2dp ready failed"); + return -1; + } + + if (a2dp_ctrl_receive(common, &sample_rate, 4) < 0) + return -1; + if (a2dp_ctrl_receive(common, &channel_count, 1) < 0) + return -1; + + common->cfg.channel_flags = (channel_count == 1 ? AUDIO_CHANNEL_IN_MONO : AUDIO_CHANNEL_IN_STEREO); + common->cfg.format = AUDIO_STREAM_DEFAULT_FORMAT; + common->cfg.rate = sample_rate; + + INFO("got config %d %d", common->cfg.format, common->cfg.rate); + + return 0; +} + +static void a2dp_open_ctrl_path(struct a2dp_stream_common *common) +{ + int i; + + /* retry logic to catch any timing variations on control channel */ + for (i = 0; i < CTRL_CHAN_RETRY_COUNT; i++) + { + /* connect control channel if not already connected */ + if ((common->ctrl_fd = skt_connect(A2DP_CTRL_PATH, common->buffer_sz)) > 0) + { + /* success, now check if stack is ready */ + if (check_a2dp_ready(common) == 0) + break; + + ERROR("error : a2dp not ready, wait 250 ms and retry"); + usleep(250000); + skt_disconnect(common->ctrl_fd); + common->ctrl_fd = AUDIO_SKT_DISCONNECTED; + } + + /* ctrl channel not ready, wait a bit */ + usleep(250000); + } +} + /***************************************************************************** ** ** AUDIO DATA PATH ** *****************************************************************************/ -static void a2dp_stream_out_init(struct a2dp_stream_out *out) +static void a2dp_stream_common_init(struct a2dp_stream_common *common) { pthread_mutexattr_t lock_attr; @@ -328,124 +437,109 @@ static void a2dp_stream_out_init(struct a2dp_stream_out *out) pthread_mutexattr_init(&lock_attr); pthread_mutexattr_settype(&lock_attr, PTHREAD_MUTEX_RECURSIVE); - pthread_mutex_init(&out->lock, &lock_attr); + pthread_mutex_init(&common->lock, &lock_attr); - out->ctrl_fd = AUDIO_SKT_DISCONNECTED; - out->audio_fd = AUDIO_SKT_DISCONNECTED; - out->state = AUDIO_A2DP_STATE_STOPPED; - - out->cfg.channel_flags = AUDIO_STREAM_DEFAULT_CHANNEL_FLAG; - out->cfg.format = AUDIO_STREAM_DEFAULT_FORMAT; - out->cfg.rate = AUDIO_STREAM_DEFAULT_RATE; + common->ctrl_fd = AUDIO_SKT_DISCONNECTED; + common->audio_fd = AUDIO_SKT_DISCONNECTED; + common->state = AUDIO_A2DP_STATE_STOPPED; /* manages max capacity of socket pipe */ - out->buffer_sz = AUDIO_STREAM_OUTPUT_BUFFER_SZ; + common->buffer_sz = AUDIO_STREAM_OUTPUT_BUFFER_SZ; } -static int start_audio_datapath(struct a2dp_stream_out *out) +static int start_audio_datapath(struct a2dp_stream_common *common) { - int oldstate = out->state; + int oldstate = common->state; - INFO("state %d", out->state); + INFO("state %d", common->state); - if (out->ctrl_fd == AUDIO_SKT_DISCONNECTED) + if (common->ctrl_fd == AUDIO_SKT_DISCONNECTED) { + INFO("AUDIO_SKT_DISCONNECTED"); return -1; + } - out->state = AUDIO_A2DP_STATE_STARTING; + common->state = AUDIO_A2DP_STATE_STARTING; - if (a2dp_command(out, A2DP_CTRL_CMD_START) < 0) + if (a2dp_command(common, A2DP_CTRL_CMD_START) < 0) { ERROR("audiopath start failed"); - out->state = oldstate; + common->state = oldstate; return -1; } /* connect socket if not yet connected */ - if (out->audio_fd == AUDIO_SKT_DISCONNECTED) + if (common->audio_fd == AUDIO_SKT_DISCONNECTED) { - out->audio_fd = skt_connect(out, A2DP_DATA_PATH); - - if (out->audio_fd < 0) + common->audio_fd = skt_connect(A2DP_DATA_PATH, common->buffer_sz); + if (common->audio_fd < 0) { - out->state = oldstate; + common->state = oldstate; return -1; } - out->state = AUDIO_A2DP_STATE_STARTED; + common->state = AUDIO_A2DP_STATE_STARTED; } return 0; } -static int stop_audio_datapath(struct a2dp_stream_out *out) +static int stop_audio_datapath(struct a2dp_stream_common *common) { - int oldstate = out->state; + int oldstate = common->state; - INFO("state %d", out->state); + INFO("state %d", common->state); - if (out->ctrl_fd == AUDIO_SKT_DISCONNECTED) + if (common->ctrl_fd == AUDIO_SKT_DISCONNECTED) return -1; /* prevent any stray output writes from autostarting the stream while stopping audiopath */ - out->state = AUDIO_A2DP_STATE_STOPPING; + common->state = AUDIO_A2DP_STATE_STOPPING; - if (a2dp_command(out, A2DP_CTRL_CMD_STOP) < 0) + if (a2dp_command(common, A2DP_CTRL_CMD_STOP) < 0) { ERROR("audiopath stop failed"); - out->state = oldstate; + common->state = oldstate; return -1; } - out->state = AUDIO_A2DP_STATE_STOPPED; + common->state = AUDIO_A2DP_STATE_STOPPED; /* disconnect audio path */ - skt_disconnect(out->audio_fd); - out->audio_fd = AUDIO_SKT_DISCONNECTED; + skt_disconnect(common->audio_fd); + common->audio_fd = AUDIO_SKT_DISCONNECTED; return 0; } -static int suspend_audio_datapath(struct a2dp_stream_out *out, bool standby) +static int suspend_audio_datapath(struct a2dp_stream_common *common, bool standby) { - INFO("state %d", out->state); + INFO("state %d", common->state); - if (out->ctrl_fd == AUDIO_SKT_DISCONNECTED) + if (common->ctrl_fd == AUDIO_SKT_DISCONNECTED) return -1; - if (out->state == AUDIO_A2DP_STATE_STOPPING) + if (common->state == AUDIO_A2DP_STATE_STOPPING) return -1; - if (a2dp_command(out, A2DP_CTRL_CMD_SUSPEND) < 0) + if (a2dp_command(common, A2DP_CTRL_CMD_SUSPEND) < 0) return -1; if (standby) - out->state = AUDIO_A2DP_STATE_STANDBY; + common->state = AUDIO_A2DP_STATE_STANDBY; else - out->state = AUDIO_A2DP_STATE_SUSPENDED; + common->state = AUDIO_A2DP_STATE_SUSPENDED; /* disconnect audio path */ - skt_disconnect(out->audio_fd); + skt_disconnect(common->audio_fd); - out->audio_fd = AUDIO_SKT_DISCONNECTED; + common->audio_fd = AUDIO_SKT_DISCONNECTED; return 0; } -static int check_a2dp_ready(struct a2dp_stream_out *out) -{ - INFO("state %d", out->state); - - if (a2dp_command(out, A2DP_CTRL_CMD_CHECK_READY) < 0) - { - ERROR("check a2dp ready failed"); - return -1; - } - return 0; -} - /***************************************************************************** ** @@ -459,49 +553,49 @@ static ssize_t out_write(struct audio_stream_out *stream, const void* buffer, struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream; int sent; - DEBUG("write %zu bytes (fd %d)", bytes, out->audio_fd); + DEBUG("write %zu bytes (fd %d)", bytes, out->common.audio_fd); - if (out->state == AUDIO_A2DP_STATE_SUSPENDED) + if (out->common.state == AUDIO_A2DP_STATE_SUSPENDED) { DEBUG("stream suspended"); return -1; } /* only allow autostarting if we are in stopped or standby */ - if ((out->state == AUDIO_A2DP_STATE_STOPPED) || - (out->state == AUDIO_A2DP_STATE_STANDBY)) + if ((out->common.state == AUDIO_A2DP_STATE_STOPPED) || + (out->common.state == AUDIO_A2DP_STATE_STANDBY)) { - pthread_mutex_lock(&out->lock); + pthread_mutex_lock(&out->common.lock); - if (start_audio_datapath(out) < 0) + if (start_audio_datapath(&out->common) < 0) { /* emulate time this write represents to avoid very fast write failures during transition periods or remote suspend */ - int us_delay = calc_audiotime(out->cfg, bytes); + int us_delay = calc_audiotime(out->common.cfg, bytes); DEBUG("emulate a2dp write delay (%d us)", us_delay); usleep(us_delay); - pthread_mutex_unlock(&out->lock); + pthread_mutex_unlock(&out->common.lock); return -1; } - pthread_mutex_unlock(&out->lock); + pthread_mutex_unlock(&out->common.lock); } - else if (out->state != AUDIO_A2DP_STATE_STARTED) + else if (out->common.state != AUDIO_A2DP_STATE_STARTED) { ERROR("stream not in stopped or standby"); return -1; } - sent = skt_write(out->audio_fd, buffer, bytes); + sent = skt_write(out->common.audio_fd, buffer, bytes); if (sent == -1) { - skt_disconnect(out->audio_fd); - out->audio_fd = AUDIO_SKT_DISCONNECTED; - out->state = AUDIO_A2DP_STATE_STOPPED; + skt_disconnect(out->common.audio_fd); + out->common.audio_fd = AUDIO_SKT_DISCONNECTED; + out->common.state = AUDIO_A2DP_STATE_STOPPED; } DEBUG("wrote %d bytes out of %zu bytes", sent, bytes); @@ -513,9 +607,9 @@ static uint32_t out_get_sample_rate(const struct audio_stream *stream) { struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream; - DEBUG("rate %" PRIu32, out->cfg.rate); + DEBUG("rate %" PRIu32,out->common.cfg.rate); - return out->cfg.rate; + return out->common.cfg.rate; } static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate) @@ -530,7 +624,7 @@ static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate) return -1; } - out->cfg.rate = rate; + out->common.cfg.rate = rate; return 0; } @@ -539,25 +633,25 @@ static size_t out_get_buffer_size(const struct audio_stream *stream) { struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream; - DEBUG("buffer_size : %zu", out->buffer_sz); + DEBUG("buffer_size : %zu", out->common.buffer_sz); - return out->buffer_sz; + return out->common.buffer_sz; } static uint32_t out_get_channels(const struct audio_stream *stream) { struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream; - DEBUG("channels 0x%" PRIx32, out->cfg.channel_flags); + DEBUG("channels 0x%" PRIx32, out->common.cfg.channel_flags); - return out->cfg.channel_flags; + return out->common.cfg.channel_flags; } static audio_format_t out_get_format(const struct audio_stream *stream) { struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream; - DEBUG("format 0x%x", out->cfg.format); - return out->cfg.format; + DEBUG("format 0x%x", out->common.cfg.format); + return out->common.cfg.format; } static int out_set_format(struct audio_stream *stream, audio_format_t format) @@ -575,13 +669,13 @@ static int out_standby(struct audio_stream *stream) FNLOG(); - pthread_mutex_lock(&out->lock); + pthread_mutex_lock(&out->common.lock); - if (out->state == AUDIO_A2DP_STATE_STARTED) - retVal = suspend_audio_datapath(out, true); + if (out->common.state == AUDIO_A2DP_STATE_STARTED) + retVal = suspend_audio_datapath(&out->common, true); else retVal = 0; - pthread_mutex_unlock (&out->lock); + pthread_mutex_unlock(&out->common.lock); return retVal; } @@ -602,9 +696,9 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) int retval; int status = 0; - INFO("state %d", out->state); + INFO("state %d", out->common.state); - pthread_mutex_lock(&out->lock); + pthread_mutex_lock(&out->common.lock); parms = str_parms_create_str(kvpairs); @@ -618,7 +712,7 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) if (strcmp(keyval, "true") == 0) { DEBUG("stream closing, disallow any writes"); - out->state = AUDIO_A2DP_STATE_STOPPING; + out->common.state = AUDIO_A2DP_STATE_STOPPING; } } @@ -628,21 +722,21 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) { if (strcmp(keyval, "true") == 0) { - if (out->state == AUDIO_A2DP_STATE_STARTED) - status = suspend_audio_datapath(out, false); + if (out->common.state == AUDIO_A2DP_STATE_STARTED) + status = suspend_audio_datapath(&out->common, false); } else { /* Do not start the streaming automatically. If the phone was streaming * prior to being suspended, the next out_write shall trigger the * AVDTP start procedure */ - if (out->state == AUDIO_A2DP_STATE_SUSPENDED) - out->state = AUDIO_A2DP_STATE_STANDBY; + if (out->common.state == AUDIO_A2DP_STATE_SUSPENDED) + out->common.state = AUDIO_A2DP_STATE_STANDBY; /* Irrespective of the state, return 0 */ } } - pthread_mutex_unlock(&out->lock); + pthread_mutex_unlock(&out->common.lock); str_parms_destroy(parms); return status; @@ -668,9 +762,9 @@ static uint32_t out_get_latency(const struct audio_stream_out *stream) FNLOG(); - latency_us = ((out->buffer_sz * 1000 ) / + latency_us = ((out->common.buffer_sz * 1000 ) / audio_stream_frame_size(&out->stream.common) / - out->cfg.rate) * 1000; + out->common.cfg.rate) * 1000; return (latency_us / 1000) + 200; @@ -726,19 +820,22 @@ static int out_remove_audio_effect(const struct audio_stream *stream, effect_han static uint32_t in_get_sample_rate(const struct audio_stream *stream) { - UNUSED(stream); + struct a2dp_stream_in *in = (struct a2dp_stream_in *)stream; FNLOG(); - return 8000; + return in->common.cfg.rate; } static int in_set_sample_rate(struct audio_stream *stream, uint32_t rate) { - UNUSED(stream); - UNUSED(rate); + struct a2dp_stream_in *in = (struct a2dp_stream_in *)stream; FNLOG(); - return 0; + + if (in->common.cfg.rate > 0 && in->common.cfg.rate == rate) + return 0; + else + return -1; } static size_t in_get_buffer_size(const struct audio_stream *stream) @@ -751,10 +848,10 @@ static size_t in_get_buffer_size(const struct audio_stream *stream) static uint32_t in_get_channels(const struct audio_stream *stream) { - UNUSED(stream); + struct a2dp_stream_in *in = (struct a2dp_stream_in *)stream; FNLOG(); - return AUDIO_CHANNEL_IN_MONO; + return in->common.cfg.channel_flags; } static audio_format_t in_get_format(const struct audio_stream *stream) @@ -771,7 +868,10 @@ static int in_set_format(struct audio_stream *stream, audio_format_t format) UNUSED(format); FNLOG(); - return 0; + if (format == AUDIO_FORMAT_PCM_16_BIT) + return 0; + else + return -1; } static int in_standby(struct audio_stream *stream) @@ -822,12 +922,60 @@ static int in_set_gain(struct audio_stream_in *stream, float gain) static ssize_t in_read(struct audio_stream_in *stream, void* buffer, size_t bytes) { - UNUSED(stream); - UNUSED(buffer); - UNUSED(bytes); + struct a2dp_stream_in *in = (struct a2dp_stream_in *)stream; + int read; - FNLOG(); - return bytes; + DEBUG("read %zu bytes, state: %d", bytes, in->common.state); + + if (in->common.state == AUDIO_A2DP_STATE_SUSPENDED) + { + DEBUG("stream suspended"); + return -1; + } + + int us_delay = calc_audiotime(in->common.cfg, bytes); + + /* only allow autostarting if we are in stopped or standby */ + if ((in->common.state == AUDIO_A2DP_STATE_STOPPED) || + (in->common.state == AUDIO_A2DP_STATE_STANDBY)) + { + pthread_mutex_lock(&in->common.lock); + + if (start_audio_datapath(&in->common) < 0) + { + /* emulate time this write represents to avoid very fast write + failures during transition periods or remote suspend */ + + DEBUG("emulate a2dp read delay (%d us)", us_delay); + + usleep(us_delay); + pthread_mutex_unlock(&in->common.lock); + return -1; + } + + pthread_mutex_unlock(&in->common.lock); + } + else if (in->common.state != AUDIO_A2DP_STATE_STARTED) + { + ERROR("stream not in stopped or standby"); + return -1; + } + + read = skt_read(in->common.audio_fd, buffer, bytes, us_delay); + + if (read == -1) + { + skt_disconnect(in->common.audio_fd); + in->common.audio_fd = AUDIO_SKT_DISCONNECTED; + in->common.state = AUDIO_A2DP_STATE_STOPPED; + } else if (read == 0) { + DEBUG("read time out - return zeros"); + memset(buffer, 0, bytes); + read = bytes; + } + + DEBUG("read %d bytes out of %zu bytes", read, bytes); + return read; } static uint32_t in_get_input_frames_lost(struct audio_stream_in *stream) @@ -898,7 +1046,11 @@ static int adev_open_output_stream(struct audio_hw_device *dev, out->stream.get_render_position = out_get_render_position; /* initialize a2dp specifics */ - a2dp_stream_out_init(out); + a2dp_stream_common_init(&out->common); + + out->common.cfg.channel_flags = AUDIO_STREAM_DEFAULT_CHANNEL_FLAG; + out->common.cfg.format = AUDIO_STREAM_DEFAULT_FORMAT; + out->common.cfg.rate = AUDIO_STREAM_DEFAULT_RATE; /* set output config values */ if (config) @@ -910,26 +1062,8 @@ static int adev_open_output_stream(struct audio_hw_device *dev, *stream_out = &out->stream; a2dp_dev->output = out; - /* retry logic to catch any timing variations on control channel */ - for (i = 0; i < CTRL_CHAN_RETRY_COUNT; i++) - { - /* connect control channel if not already connected */ - if ((out->ctrl_fd = skt_connect(out, A2DP_CTRL_PATH)) > 0) - { - /* success, now check if stack is ready */ - if (check_a2dp_ready(out) == 0) - break; - - ERROR("error : a2dp not ready, wait 250 ms and retry"); - usleep(250000); - skt_disconnect(out->ctrl_fd); - } - - /* ctrl channel not ready, wait a bit */ - usleep(250000); - } - - if (out->ctrl_fd == AUDIO_SKT_DISCONNECTED) + a2dp_open_ctrl_path(&out->common); + if (out->common.ctrl_fd == AUDIO_SKT_DISCONNECTED) { ERROR("ctrl socket failed to connect (%s)", strerror(errno)); ret = -1; @@ -953,12 +1087,12 @@ static void adev_close_output_stream(struct audio_hw_device *dev, struct a2dp_audio_device *a2dp_dev = (struct a2dp_audio_device *)dev; struct a2dp_stream_out *out = (struct a2dp_stream_out *)stream; - INFO("closing output (state %d)", out->state); + INFO("closing output (state %d)", out->common.state); - if ((out->state == AUDIO_A2DP_STATE_STARTED) || (out->state == AUDIO_A2DP_STATE_STOPPING)) - stop_audio_datapath(out); + if ((out->common.state == AUDIO_A2DP_STATE_STARTED) || (out->common.state == AUDIO_A2DP_STATE_STOPPING)) + stop_audio_datapath(&out->common); - skt_disconnect(out->ctrl_fd); + skt_disconnect(out->common.ctrl_fd); free(stream); a2dp_dev->output = NULL; @@ -976,7 +1110,7 @@ static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) ERROR("ERROR: set param called even when stream out is null"); return retval; } - INFO("state %d", out->state); + INFO("state %d", out->common.state); retval = out->stream.common.set_parameters((struct audio_stream *)out, kvpairs); @@ -1076,7 +1210,7 @@ static int adev_open_input_stream(struct audio_hw_device *dev, struct audio_config *config, struct audio_stream_in **stream_in) { - struct a2dp_audio_device *ladev = (struct a2dp_audio_device *)dev; + struct a2dp_audio_device *a2dp_dev = (struct a2dp_audio_device *)dev; struct a2dp_stream_in *in; int ret; UNUSED(handle); @@ -1106,24 +1240,54 @@ static int adev_open_input_stream(struct audio_hw_device *dev, in->stream.read = in_read; in->stream.get_input_frames_lost = in_get_input_frames_lost; + /* initialize a2dp specifics */ + a2dp_stream_common_init(&in->common); + *stream_in = &in->stream; + a2dp_dev->input = in; + + a2dp_open_ctrl_path(&in->common); + if (in->common.ctrl_fd == AUDIO_SKT_DISCONNECTED) + { + ERROR("ctrl socket failed to connect (%s)", strerror(errno)); + ret = -1; + goto err_open; + } + + if (a2dp_read_audio_config(&in->common) < 0) { + ERROR("a2dp_read_audio_config failed (%s)", strerror(errno)); + ret = -1; + goto err_open; + } + + DEBUG("success"); return 0; err_open: free(in); *stream_in = NULL; + a2dp_dev->input = NULL; + ERROR("failed"); return ret; } static void adev_close_input_stream(struct audio_hw_device *dev, - struct audio_stream_in *in) + struct audio_stream_in *stream) { - UNUSED(dev); - UNUSED(in); + struct a2dp_audio_device *a2dp_dev = (struct a2dp_audio_device *)dev; + struct a2dp_stream_in* in = (struct a2dp_stream_in *)stream; + a2dp_state_t state = in->common.state; - FNLOG(); + INFO("closing input (state %d)", state); + + if ((state == AUDIO_A2DP_STATE_STARTED) || (state == AUDIO_A2DP_STATE_STOPPING)) + stop_audio_datapath(&in->common); - return; + skt_disconnect(in->common.ctrl_fd); + free(stream); + a2dp_dev->input = NULL; + + DEBUG("done"); } static int adev_dump(const audio_hw_device_t *device, int fd) diff --git a/audio_a2dp_hw/audio_a2dp_hw.h b/audio_a2dp_hw/audio_a2dp_hw.h index 2015591a1..b4ac85d86 100644 --- a/audio_a2dp_hw/audio_a2dp_hw.h +++ b/audio_a2dp_hw/audio_a2dp_hw.h @@ -46,7 +46,8 @@ typedef enum { A2DP_CTRL_CMD_CHECK_READY, A2DP_CTRL_CMD_START, A2DP_CTRL_CMD_STOP, - A2DP_CTRL_CMD_SUSPEND + A2DP_CTRL_CMD_SUSPEND, + A2DP_CTRL_GET_AUDIO_CONFIG, } tA2DP_CTRL_CMD; typedef enum { |