#include "hal-log.h"
#include "hal-msg.h"
#include "hal-audio.h"
-#include "../src/shared/util.h"
+#include "hal-utils.h"
#define FIXED_A2DP_PLAYBACK_LATENCY_MS 25
struct timespec *remain);
#endif
-static const audio_codec_get_t audio_codecs[] = {
- codec_sbc,
+static struct {
+ const audio_codec_get_t get_codec;
+ bool loaded;
+} audio_codecs[] = {
+ { .get_codec = codec_aptx, .loaded = false },
+ { .get_codec = codec_sbc, .loaded = false },
};
#define NUM_CODECS (sizeof(audio_codecs) / sizeof(audio_codecs[0]))
goto failed;
}
- if (rsp_len)
- *rsp_len = cmd.len;
+ *rsp_len = cmd.len;
return AUDIO_STATUS_SUCCESS;
return result;
}
-static int ipc_open_stream_cmd(uint8_t endpoint_id, uint16_t *mtu, int *fd,
+static int ipc_open_stream_cmd(uint8_t *endpoint_id, uint16_t *mtu, int *fd,
struct audio_preset **caps)
{
char buf[BLUEZ_AUDIO_MTU];
if (!caps)
return AUDIO_STATUS_FAILED;
- cmd.id = endpoint_id;
+ cmd.id = *endpoint_id;
result = audio_ipc_cmd(AUDIO_SERVICE_ID, AUDIO_OP_OPEN_STREAM,
sizeof(cmd), &cmd, &rsp_len, rsp, fd);
if (result == AUDIO_STATUS_SUCCESS) {
size_t buf_len = sizeof(struct audio_preset) +
rsp->preset[0].len;
+ *endpoint_id = rsp->id;
*mtu = rsp->mtu;
*caps = malloc(buf_len);
memcpy(*caps, &rsp->preset, buf_len);
return result;
}
-static int register_endpoints(void)
+struct register_state {
+ struct audio_endpoint *ep;
+ bool error;
+};
+
+static void register_endpoint(const struct audio_codec *codec,
+ struct register_state *state)
{
- struct audio_endpoint *ep = &audio_endpoints[0];
- size_t i;
+ struct audio_endpoint *ep = state->ep;
- for (i = 0; i < NUM_CODECS; i++, ep++) {
- const struct audio_codec *codec = audio_codecs[i]();
+ /* don't even try to register more endpoints if one failed */
+ if (state->error)
+ return;
- if (!codec)
- return AUDIO_STATUS_FAILED;
+ ep->id = ipc_open_cmd(codec);
- ep->id = ipc_open_cmd(codec);
+ if (!ep->id) {
+ state->error = true;
+ error("Failed to register endpoint");
+ return;
+ }
- if (!ep->id)
- return AUDIO_STATUS_FAILED;
+ ep->codec = codec;
+ ep->codec_data = NULL;
+ ep->fd = -1;
- ep->codec = codec;
- ep->codec_data = NULL;
- ep->fd = -1;
+ state->ep++;
+}
+
+static int register_endpoints(void)
+{
+ struct register_state state;
+ unsigned int i;
+
+ state.ep = &audio_endpoints[0];
+ state.error = false;
+
+ for (i = 0; i < NUM_CODECS; i++) {
+ const struct audio_codec *codec = audio_codecs[i].get_codec();
+
+ if (!audio_codecs[i].loaded)
+ continue;
+
+ register_endpoint(codec, &state);
}
- return AUDIO_STATUS_SUCCESS;
+ return state.error ? AUDIO_STATUS_FAILED : AUDIO_STATUS_SUCCESS;
}
static void unregister_endpoints(void)
}
}
-static bool open_endpoint(struct audio_endpoint *ep,
+static bool open_endpoint(struct audio_endpoint **epp,
struct audio_input_config *cfg)
{
struct audio_preset *preset;
+ struct audio_endpoint *ep = *epp;
const struct audio_codec *codec;
uint16_t mtu;
uint16_t payload_len;
int fd;
+ size_t i;
+ uint8_t ep_id = 0;
+
+ if (ep)
+ ep_id = ep->id;
- if (ipc_open_stream_cmd(ep->id, &mtu, &fd, &preset) !=
+ if (ipc_open_stream_cmd(&ep_id, &mtu, &fd, &preset) !=
AUDIO_STATUS_SUCCESS)
return false;
- DBG("mtu=%u", mtu);
+ DBG("ep_id=%d mtu=%u", ep_id, mtu);
+
+ for (i = 0; i < MAX_AUDIO_ENDPOINTS; i++)
+ if (audio_endpoints[i].id == ep_id) {
+ ep = &audio_endpoints[i];
+ break;
+ }
+
+ if (!ep) {
+ error("Cound not find opened endpoint");
+ goto failed;
+ }
+
+ *epp = ep;
payload_len = mtu;
if (ep->codec->use_rtp)
ep->samples = 0;
ep->resync = false;
- if (ep->codec->update_qos)
- ep->codec->update_qos(ep->codec_data, QOS_POLICY_DEFAULT);
+ ep->codec->update_qos(ep->codec_data, QOS_POLICY_DEFAULT);
return true;
}
frames = bytes / (2 * sizeof(int16_t));
for (i = 0; i < frames; i++) {
- int16_t l = le16_to_cpu(get_unaligned(&input[i * 2]));
- int16_t r = le16_to_cpu(get_unaligned(&input[i * 2 + 1]));
+ int16_t l = get_le16(&input[i * 2]);
+ int16_t r = get_le16(&input[i * 2 + 1]);
- put_unaligned(cpu_to_le16((l + r) / 2), &output[i]);
+ put_le16((l + r) / 2, &output[i]);
}
}
if (diff > MAX_DELAY) {
warn("lag is %jums, resyncing", diff / 1000);
- if (ep->codec->update_qos)
- ep->codec->update_qos(ep->codec_data,
+ ep->codec->update_qos(ep->codec_data,
QOS_POLICY_DECREASE);
ep->resync = true;
}
out->stream.write = out_write;
out->stream.get_render_position = out_get_render_position;
- /* TODO: for now we always use endpoint 0 */
- out->ep = &audio_endpoints[0];
+ /* We want to autoselect opened endpoint */
+ out->ep = NULL;
- if (!open_endpoint(out->ep, &out->cfg))
+ if (!open_endpoint(&out->ep, &out->cfg))
goto fail;
DBG("rate=%d channels=%d format=%d", out->cfg.rate,
static int audio_close(hw_device_t *device)
{
struct a2dp_audio_dev *a2dp_dev = (struct a2dp_audio_dev *)device;
+ unsigned int i;
DBG("");
unregister_endpoints();
+ for (i = 0; i < NUM_CODECS; i++) {
+ const struct audio_codec *codec = audio_codecs[i].get_codec();
+
+ if (!audio_codecs[i].loaded)
+ continue;
+
+ if (codec->unload)
+ codec->unload();
+
+ audio_codecs[i].loaded = false;
+ }
+
shutdown(listen_sk, SHUT_RDWR);
shutdown(audio_sk, SHUT_RDWR);
/* Check if socket is still alive. Empty while loop.*/
while (poll(&pfd, 1, -1) < 0 && errno == EINTR);
- if (pfd.revents & (POLLHUP | POLLERR | POLLNVAL)) {
- info("Audio HAL: Socket closed");
+ info("Audio HAL: Socket closed");
- pthread_mutex_lock(&sk_mutex);
- close(audio_sk);
- audio_sk = -1;
- pthread_mutex_unlock(&sk_mutex);
- }
+ pthread_mutex_lock(&sk_mutex);
+ close(audio_sk);
+ audio_sk = -1;
+ pthread_mutex_unlock(&sk_mutex);
}
/* audio_sk is closed at this point, just cleanup endpoints states */
hw_device_t **device)
{
struct a2dp_audio_dev *a2dp_dev;
+ size_t i;
int err;
DBG("");
a2dp_dev->dev.close_input_stream = audio_close_input_stream;
a2dp_dev->dev.dump = audio_dump;
+ for (i = 0; i < NUM_CODECS; i++) {
+ const struct audio_codec *codec = audio_codecs[i].get_codec();
+
+ if (codec->load && !codec->load())
+ continue;
+
+ audio_codecs[i].loaded = true;
+ }
+
/*
* Note that &a2dp_dev->dev.common is the same pointer as a2dp_dev.
* This results from the structure of following structs:a2dp_audio_dev,