cras_a2dp_iodev.c revision dd2f666a53a1090744819bf38cd672b4548aca22
131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao * Use of this source code is governed by a BSD-style license that can be
331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao * found in the LICENSE file.
431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao */
531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao#include <stdint.h>
731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao#include <sys/socket.h>
831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao#include <syslog.h>
9f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao#include <time.h>
1031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
111cbde1fb3f2aad5494f33d49dacaeafebc753ac2Hsin-Yu Chao#include "cras_a2dp_info.h"
1231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao#include "cras_a2dp_iodev.h"
13dd2f666a53a1090744819bf38cd672b4548aca22Hsin-Yu Chao#include "cras_bt_device.h"
1431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao#include "cras_iodev.h"
1531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao#include "cras_iodev_list.h"
1631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao#include "cras_util.h"
17f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao#include "rtp.h"
1831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao#include "utlist.h"
1931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
2038cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao#define PCM_BUF_MAX_SIZE_BYTES 1024
2131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
2231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostruct a2dp_io {
2331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	struct cras_iodev base;
246f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao	struct a2dp_info a2dp;
2531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	struct cras_bt_transport *transport;
2631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
2738cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao	uint8_t pcm_buf[PCM_BUF_MAX_SIZE_BYTES];
2838cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao	int pcm_buf_offset;
2938cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao	int pcm_buf_size;
3031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	int pcm_buf_used;
31f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao
32f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	int bt_queued_frames;
33f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	struct timespec bt_queued_fr_last_update;
3431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao};
3531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
3631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostatic int update_supported_formats(struct cras_iodev *iodev)
3731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{
3831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	struct a2dp_io *a2dpio = (struct a2dp_io *)iodev;
3931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	size_t rate = 0;
4031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	size_t channel;
4131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	a2dp_sbc_t a2dp;
4231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
4331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	cras_bt_transport_configuration(a2dpio->transport, &a2dp,
4431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao					sizeof(a2dp));
4531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
4631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->format->format = SND_PCM_FORMAT_S16_LE;
4731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	channel = (a2dp.channel_mode == SBC_CHANNEL_MODE_MONO) ? 1 : 2;
4831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
4931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	if (a2dp.frequency & SBC_SAMPLING_FREQ_48000)
5031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		rate = 48000;
5131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	else if (a2dp.frequency & SBC_SAMPLING_FREQ_44100)
5231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		rate = 44100;
5331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	else if (a2dp.frequency & SBC_SAMPLING_FREQ_32000)
5431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		rate = 32000;
5531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	else if (a2dp.frequency & SBC_SAMPLING_FREQ_16000)
5631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		rate = 16000;
5731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
58639a342fcc14cf262e11612220079aff45f40ad5Dylan Reid	free(iodev->supported_rates);
5931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->supported_rates = (size_t *)malloc(2 * sizeof(rate));
6031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->supported_rates[0] = rate;
6131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->supported_rates[1] = 0;
6231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
63639a342fcc14cf262e11612220079aff45f40ad5Dylan Reid	free(iodev->supported_channel_counts);
6431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->supported_channel_counts = (size_t *)malloc(2 * sizeof(channel));
6531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->supported_channel_counts[0] = channel;
6631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->supported_channel_counts[1] = 0;
6731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
6831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	return 0;
6931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao}
7031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
71f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao/* Calculates the amount of consumed frames since given time.
72f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao */
73f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chaostatic unsigned long frames_since(struct timespec ts, size_t rate)
74f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao{
75f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	struct timespec te, diff;
76f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao
77f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	clock_gettime(CLOCK_MONOTONIC, &te);
78f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	subtract_timespecs(&te, &ts, &diff);
79f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	return diff.tv_sec * rate + diff.tv_nsec / (1000000000L / rate);
80f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao}
81f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao
82f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao/* Maintains a virtual buffer for transmitted frames, assume this buffer is
83f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao * consumed at the same frame rate at bluetooth device side.
84f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao * Args:
85f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao *    iodev: The a2dp iodev to estimate the queued frames for.
86f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao *    fr: The amount of frames just transmitted.
87f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao */
88f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chaostatic int get_bt_queued_frames(const struct cras_iodev *iodev, int fr)
89f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao{
90f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	unsigned long consumed;
91f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	struct a2dp_io *a2dpio = (struct a2dp_io *)iodev;
92f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao
93f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	/* Calculate consumed frames since last update time, also update
94f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	 * the last update time.
95f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	 */
96f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	consumed = frames_since(a2dpio->bt_queued_fr_last_update,
97f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao				iodev->format->frame_rate);
98f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	clock_gettime(CLOCK_MONOTONIC, &a2dpio->bt_queued_fr_last_update);
99f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao
100f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	if (a2dpio->bt_queued_frames > consumed)
101f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao		a2dpio->bt_queued_frames -= consumed;
102f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	else
103f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao		a2dpio->bt_queued_frames = 0;
104f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao
105f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	a2dpio->bt_queued_frames += fr;
106f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao
107f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	return a2dpio->bt_queued_frames;
108f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao}
109f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao
11031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostatic int frames_queued(const struct cras_iodev *iodev)
11131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{
112f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	size_t format_bytes;
113f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	int frames;
114f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	struct a2dp_io *a2dpio = (struct a2dp_io *)iodev;
115f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao
116f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	format_bytes = cras_get_format_bytes(iodev->format);
117f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao
118f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	frames = a2dpio->pcm_buf_used / format_bytes
119f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao			+ a2dp_queued_frames(&a2dpio->a2dp)
120f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao			+ get_bt_queued_frames(iodev, 0);
121f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao
122f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	return frames;
12331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao}
12431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
125f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao
12631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostatic int open_dev(struct cras_iodev *iodev)
12731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{
128f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	int err = 0, block_size;
129f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	size_t format_bytes;
13031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	struct a2dp_io *a2dpio = (struct a2dp_io *)iodev;
13131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
13231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	err = cras_bt_transport_acquire(a2dpio->transport);
13331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	if (err < 0) {
13431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		syslog(LOG_ERR, "transport_acquire failed");
13531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		return err;
13631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	}
13731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
13831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	/* Assert format is set before opening device. */
13931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	if (iodev->format == NULL)
14031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		return -EINVAL;
14131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->format->format = SND_PCM_FORMAT_S16_LE;
142f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	format_bytes = cras_get_format_bytes(iodev->format);
14331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
144f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	/* Back calculate the max size of a2dp block before encode. */
145f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	block_size = a2dp_block_size(
146f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao			&a2dpio->a2dp,
147f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao			cras_bt_transport_write_mtu(a2dpio->transport) -
148f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao					sizeof(struct rtp_header) -
149f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao					sizeof(struct rtp_payload));
150f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao
151f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	/* Assert pcm_buf_size be multiple of codesize */
152f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	a2dpio->pcm_buf_size = PCM_BUF_MAX_SIZE_BYTES
153f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao			/ a2dp_codesize(&a2dpio->a2dp)
154f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao			* a2dp_codesize(&a2dpio->a2dp);
155f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	iodev->buffer_size = (a2dpio->pcm_buf_size + block_size) / format_bytes;
15631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	if (iodev->used_size > iodev->buffer_size)
15731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		iodev->used_size = iodev->buffer_size;
158f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao
159f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	syslog(LOG_DEBUG, "a2dp iodev buf size %lu, used size %lu",
160f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	       iodev->buffer_size, iodev->used_size);
161f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao
16231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	return 0;
16331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao}
16431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
16531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostatic int close_dev(struct cras_iodev *iodev)
16631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{
16731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	int err;
16831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	struct a2dp_io *a2dpio = (struct a2dp_io *)iodev;
16931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
17031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	if (!a2dpio->transport)
17131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		return 0;
17231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
17331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	err = cras_bt_transport_release(a2dpio->transport);
17431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	if (err < 0)
17531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		syslog(LOG_ERR, "transport_release failed");
17631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
1776f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao	a2dp_drain(&a2dpio->a2dp);
17831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	a2dpio->pcm_buf_used = 0;
17931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	cras_iodev_free_format(iodev);
18031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	return 0;
18131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao}
18231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
18331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostatic int is_open(const struct cras_iodev *iodev)
18431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{
18531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	struct a2dp_io *a2dpio = (struct a2dp_io *)iodev;
18631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	return cras_bt_transport_fd(a2dpio->transport) > 0;
18731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao}
18831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
189cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao/* Flushes queued buffer, including pcm and a2dp buffer.
190cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao */
191cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chaostatic void flush_data(const struct cras_iodev *iodev)
192cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao{
193cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao	int processed;
194cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao	size_t format_bytes;
195cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao	int written = 0;
196cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao	struct a2dp_io *a2dpio;
197cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao
198cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao	a2dpio = (struct a2dp_io *)iodev;
199cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao	format_bytes = cras_get_format_bytes(iodev->format);
200cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao
201cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao	processed = a2dp_write(a2dpio->pcm_buf + a2dpio->pcm_buf_offset,
202cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao		       a2dpio->pcm_buf_used,
203cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao		       &a2dpio->a2dp,
204cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao		       format_bytes,
205cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao		       cras_bt_transport_fd(a2dpio->transport),
206cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao		       cras_bt_transport_write_mtu(a2dpio->transport),
207cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao		       &written);
208cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao
209cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao	if (a2dpio->pcm_buf_used == processed) {
210cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao		a2dpio->pcm_buf_offset = 0;
211cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao		a2dpio->pcm_buf_used = 0;
212cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao	} else {
213cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao		a2dpio->pcm_buf_offset += processed;
214cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao		a2dpio->pcm_buf_used -= processed;
215cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao	}
216cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao
217cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao	if (written == -EAGAIN) {
218cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao		syslog(LOG_ERR, "a2dp_write error");
219cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao		return;
220cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao	}
221cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao	get_bt_queued_frames(iodev,
222cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao			     a2dp_block_size(&a2dpio->a2dp, written)
223cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao				     / format_bytes);
224cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao}
225cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao
22631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostatic int dev_running(const struct cras_iodev *iodev)
22731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{
228cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao	// Flush queued buffer when dev is open.
229cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao	if (is_open(iodev))
230cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao		flush_data(iodev);
231cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao	return 0;
23231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao}
23331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
23431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostatic int delay_frames(const struct cras_iodev *iodev)
23531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{
236f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	return frames_queued(iodev);
23731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao}
23831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
23931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostatic int get_buffer(struct cras_iodev *iodev, uint8_t **dst, unsigned *frames)
24031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{
24131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	size_t format_bytes;
24231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	struct a2dp_io *a2dpio;
24331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	a2dpio = (struct a2dp_io *)iodev;
24431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
24531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	format_bytes = cras_get_format_bytes(iodev->format);
24631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
24731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	if (iodev->direction == CRAS_STREAM_OUTPUT) {
24838cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao		*dst = a2dpio->pcm_buf + a2dpio->pcm_buf_offset
24938cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao				+ a2dpio->pcm_buf_used;
25038cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao		*frames = (a2dpio->pcm_buf_size - a2dpio->pcm_buf_offset -
25138cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao				a2dpio->pcm_buf_used) / format_bytes;
25231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	}
25331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	return 0;
25431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao}
25531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
25631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostatic int put_buffer(struct cras_iodev *iodev, unsigned nwritten)
25731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{
25831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	size_t format_bytes;
25931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	struct a2dp_io *a2dpio = (struct a2dp_io *)iodev;
260f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao
26131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	format_bytes = cras_get_format_bytes(iodev->format);
26231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
26338cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao	if (a2dpio->pcm_buf_used + a2dpio->pcm_buf_offset +
26438cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao			nwritten * format_bytes > a2dpio->pcm_buf_size)
26531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		return -1;
26631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	a2dpio->pcm_buf_used += nwritten * format_bytes;
2676f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao
268cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao	flush_data(iodev);
26931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	return 0;
27031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao}
27131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
2720b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chaostatic void update_active_node(struct cras_iodev *iodev)
2730b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao{
2740b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao}
2750b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao
27631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaovoid free_resources(struct a2dp_io *a2dpio)
27731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{
2780b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao	struct cras_ionode *node;
2790b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao
2800b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao	node = a2dpio->base.active_node;
2810b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao	if (node) {
2820b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao		cras_iodev_rm_node(&a2dpio->base, node);
2830b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao		free(node);
2840b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao	}
28531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	free(a2dpio->base.supported_channel_counts);
28631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	free(a2dpio->base.supported_rates);
2876f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao	destroy_a2dp(&a2dpio->a2dp);
28831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao}
28931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
29031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostruct cras_iodev *a2dp_iodev_create(struct cras_bt_transport *transport)
29131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{
29231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	int err;
29331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	struct a2dp_io *a2dpio;
29431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	struct cras_iodev *iodev;
29531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	struct cras_ionode *node;
2961cbde1fb3f2aad5494f33d49dacaeafebc753ac2Hsin-Yu Chao	a2dp_sbc_t a2dp;
297dd2f666a53a1090744819bf38cd672b4548aca22Hsin-Yu Chao	struct cras_bt_device *device;
29831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
29931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	a2dpio = (struct a2dp_io *)calloc(1, sizeof(*a2dpio));
30031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	if (!a2dpio)
30131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		goto error;
30231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
3031cbde1fb3f2aad5494f33d49dacaeafebc753ac2Hsin-Yu Chao	a2dpio->transport = transport;
3041cbde1fb3f2aad5494f33d49dacaeafebc753ac2Hsin-Yu Chao	cras_bt_transport_configuration(a2dpio->transport, &a2dp,
3051cbde1fb3f2aad5494f33d49dacaeafebc753ac2Hsin-Yu Chao					sizeof(a2dp));
3066f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao	err = init_a2dp(&a2dpio->a2dp, &a2dp);
3076f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao	if (err) {
3086f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao		syslog(LOG_ERR, "Fail to init a2dp");
3096f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao		goto error;
3106f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao	}
3111cbde1fb3f2aad5494f33d49dacaeafebc753ac2Hsin-Yu Chao
31231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev = &a2dpio->base;
31331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
31431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	/* A2DP only does output now */
31531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->direction = CRAS_STREAM_OUTPUT;
31631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
317dd2f666a53a1090744819bf38cd672b4548aca22Hsin-Yu Chao	/* Set iodev's name by bluetooth device's readable name, if
318dd2f666a53a1090744819bf38cd672b4548aca22Hsin-Yu Chao	 * the readable name is not available, use address instead.
319dd2f666a53a1090744819bf38cd672b4548aca22Hsin-Yu Chao	 */
320dd2f666a53a1090744819bf38cd672b4548aca22Hsin-Yu Chao	device = cras_bt_transport_device(transport);
321dd2f666a53a1090744819bf38cd672b4548aca22Hsin-Yu Chao	if (device)
322dd2f666a53a1090744819bf38cd672b4548aca22Hsin-Yu Chao		snprintf(iodev->info.name, sizeof(iodev->info.name), "%s",
323dd2f666a53a1090744819bf38cd672b4548aca22Hsin-Yu Chao				cras_bt_device_name(device));
324dd2f666a53a1090744819bf38cd672b4548aca22Hsin-Yu Chao	else
325dd2f666a53a1090744819bf38cd672b4548aca22Hsin-Yu Chao		snprintf(iodev->info.name, sizeof(iodev->info.name), "%s",
326dd2f666a53a1090744819bf38cd672b4548aca22Hsin-Yu Chao			 cras_bt_transport_object_path(a2dpio->transport));
32731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
32831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->info.name[ARRAY_SIZE(iodev->info.name) - 1] = '\0';
32931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
33031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->open_dev = open_dev;
33131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->is_open = is_open; /* Needed by thread_add_stream */
33231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->frames_queued = frames_queued;
33331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->dev_running = dev_running;
33431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->delay_frames = delay_frames;
33531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->get_buffer = get_buffer;
33631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->put_buffer = put_buffer;
33731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->close_dev = close_dev;
33831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->update_supported_formats = update_supported_formats;
3390b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao	iodev->update_active_node = update_active_node;
340a7892d9129d4cdb25dbd099aa2f5295bd53120dfHsin-Yu Chao	iodev->software_volume_needed = 1;
34131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
34231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	/* Create a dummy ionode */
34331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	node = (struct cras_ionode *)calloc(1, sizeof(*node));
34431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	node->dev = iodev;
34531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	strcpy(node->name, iodev->info.name);
34631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	node->plugged = 1;
34731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	node->priority = 3;
3480b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao	node->type = CRAS_NODE_TYPE_BLUETOOTH;
349b7fb7aad1bb54683361c3beda234e01bcf455becDylan Reid	node->volume = 100;
35031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	gettimeofday(&node->plugged_time, NULL);
35131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
35231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	/* A2DP does output only */
35331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	err = cras_iodev_list_add_output(iodev);
35431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	if (err)
35531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		goto error;
35631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
3570b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao	cras_iodev_add_node(iodev, node);
3580b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao	cras_iodev_set_active_node(iodev, node);
3590b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao
36031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	return iodev;
36131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaoerror:
36231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	if (a2dpio) {
36331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		free_resources(a2dpio);
36431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		free(a2dpio);
36531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	}
36631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	return NULL;
36731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao}
36831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
36931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaovoid a2dp_iodev_destroy(struct cras_iodev *iodev)
37031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{
37131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	int rc;
37231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	struct a2dp_io *a2dpio = (struct a2dp_io *)iodev;
37331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
37431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	/* A2DP does output only */
37531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	rc = cras_iodev_list_rm_output(iodev);
3760fc4865c82dd7a07d978c598ec7f2d108a8a3279Hsin-Yu Chao	if (rc == -EBUSY) {
3770fc4865c82dd7a07d978c598ec7f2d108a8a3279Hsin-Yu Chao		syslog(LOG_ERR, "Failed to remove iodev %s", iodev->info.name);
3780fc4865c82dd7a07d978c598ec7f2d108a8a3279Hsin-Yu Chao		return;
37931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	}
3800fc4865c82dd7a07d978c598ec7f2d108a8a3279Hsin-Yu Chao
3810fc4865c82dd7a07d978c598ec7f2d108a8a3279Hsin-Yu Chao	/* Free resources when device successfully removed. */
3820fc4865c82dd7a07d978c598ec7f2d108a8a3279Hsin-Yu Chao	free_resources(a2dpio);
3830fc4865c82dd7a07d978c598ec7f2d108a8a3279Hsin-Yu Chao	cras_iodev_free_dsp(iodev);
3840fc4865c82dd7a07d978c598ec7f2d108a8a3279Hsin-Yu Chao	free(a2dpio);
38531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao}
386