cras_a2dp_iodev.c revision 639a342fcc14cf262e11612220079aff45f40ad5
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"
1331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao#include "cras_iodev.h"
1431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao#include "cras_iodev_list.h"
1531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao#include "cras_util.h"
16f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao#include "rtp.h"
1731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao#include "utlist.h"
1831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
1938cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao#define PCM_BUF_MAX_SIZE_BYTES 1024
2031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
2131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostruct a2dp_io {
2231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	struct cras_iodev base;
236f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao	struct a2dp_info a2dp;
2431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	struct cras_bt_transport *transport;
2531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
2638cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao	uint8_t pcm_buf[PCM_BUF_MAX_SIZE_BYTES];
2738cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao	int pcm_buf_offset;
2838cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao	int pcm_buf_size;
2931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	int pcm_buf_used;
30f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao
31f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	int bt_queued_frames;
32f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	struct timespec bt_queued_fr_last_update;
3331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao};
3431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
3531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostatic int update_supported_formats(struct cras_iodev *iodev)
3631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{
3731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	struct a2dp_io *a2dpio = (struct a2dp_io *)iodev;
3831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	size_t rate = 0;
3931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	size_t channel;
4031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	a2dp_sbc_t a2dp;
4131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
4231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	cras_bt_transport_configuration(a2dpio->transport, &a2dp,
4331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao					sizeof(a2dp));
4431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
4531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->format->format = SND_PCM_FORMAT_S16_LE;
4631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	channel = (a2dp.channel_mode == SBC_CHANNEL_MODE_MONO) ? 1 : 2;
4731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
4831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	if (a2dp.frequency & SBC_SAMPLING_FREQ_48000)
4931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		rate = 48000;
5031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	else if (a2dp.frequency & SBC_SAMPLING_FREQ_44100)
5131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		rate = 44100;
5231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	else if (a2dp.frequency & SBC_SAMPLING_FREQ_32000)
5331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		rate = 32000;
5431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	else if (a2dp.frequency & SBC_SAMPLING_FREQ_16000)
5531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		rate = 16000;
5631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
57639a342fcc14cf262e11612220079aff45f40ad5Dylan Reid	free(iodev->supported_rates);
5831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->supported_rates = (size_t *)malloc(2 * sizeof(rate));
5931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->supported_rates[0] = rate;
6031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->supported_rates[1] = 0;
6131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
62639a342fcc14cf262e11612220079aff45f40ad5Dylan Reid	free(iodev->supported_channel_counts);
6331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->supported_channel_counts = (size_t *)malloc(2 * sizeof(channel));
6431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->supported_channel_counts[0] = channel;
6531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->supported_channel_counts[1] = 0;
6631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
6731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	return 0;
6831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao}
6931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
70f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao/* Calculates the amount of consumed frames since given time.
71f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao */
72f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chaostatic unsigned long frames_since(struct timespec ts, size_t rate)
73f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao{
74f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	struct timespec te, diff;
75f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao
76f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	clock_gettime(CLOCK_MONOTONIC, &te);
77f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	subtract_timespecs(&te, &ts, &diff);
78f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	return diff.tv_sec * rate + diff.tv_nsec / (1000000000L / rate);
79f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao}
80f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao
81f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao/* Maintains a virtual buffer for transmitted frames, assume this buffer is
82f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao * consumed at the same frame rate at bluetooth device side.
83f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao * Args:
84f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao *    iodev: The a2dp iodev to estimate the queued frames for.
85f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao *    fr: The amount of frames just transmitted.
86f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao */
87f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chaostatic int get_bt_queued_frames(const struct cras_iodev *iodev, int fr)
88f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao{
89f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	unsigned long consumed;
90f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	struct a2dp_io *a2dpio = (struct a2dp_io *)iodev;
91f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao
92f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	/* Calculate consumed frames since last update time, also update
93f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	 * the last update time.
94f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	 */
95f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	consumed = frames_since(a2dpio->bt_queued_fr_last_update,
96f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao				iodev->format->frame_rate);
97f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	clock_gettime(CLOCK_MONOTONIC, &a2dpio->bt_queued_fr_last_update);
98f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao
99f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	if (a2dpio->bt_queued_frames > consumed)
100f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao		a2dpio->bt_queued_frames -= consumed;
101f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	else
102f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao		a2dpio->bt_queued_frames = 0;
103f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao
104f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	a2dpio->bt_queued_frames += fr;
105f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao
106f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	return a2dpio->bt_queued_frames;
107f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao}
108f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao
10931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostatic int frames_queued(const struct cras_iodev *iodev)
11031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{
111f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	size_t format_bytes;
112f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	int frames;
113f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	struct a2dp_io *a2dpio = (struct a2dp_io *)iodev;
114f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao
115f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	format_bytes = cras_get_format_bytes(iodev->format);
116f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao
117f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	frames = a2dpio->pcm_buf_used / format_bytes
118f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao			+ a2dp_queued_frames(&a2dpio->a2dp)
119f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao			+ get_bt_queued_frames(iodev, 0);
120f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao
121f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	return frames;
12231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao}
12331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
124f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao
12531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostatic int open_dev(struct cras_iodev *iodev)
12631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{
127f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	int err = 0, block_size;
128f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	size_t format_bytes;
12931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	struct a2dp_io *a2dpio = (struct a2dp_io *)iodev;
13031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
13131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	err = cras_bt_transport_acquire(a2dpio->transport);
13231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	if (err < 0) {
13331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		syslog(LOG_ERR, "transport_acquire failed");
13431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		return err;
13531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	}
13631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
13731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	/* Assert format is set before opening device. */
13831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	if (iodev->format == NULL)
13931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		return -EINVAL;
14031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->format->format = SND_PCM_FORMAT_S16_LE;
141f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	format_bytes = cras_get_format_bytes(iodev->format);
14231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
143f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	/* Back calculate the max size of a2dp block before encode. */
144f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	block_size = a2dp_block_size(
145f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao			&a2dpio->a2dp,
146f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao			cras_bt_transport_write_mtu(a2dpio->transport) -
147f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao					sizeof(struct rtp_header) -
148f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao					sizeof(struct rtp_payload));
149f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao
150f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	/* Assert pcm_buf_size be multiple of codesize */
151f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	a2dpio->pcm_buf_size = PCM_BUF_MAX_SIZE_BYTES
152f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao			/ a2dp_codesize(&a2dpio->a2dp)
153f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao			* a2dp_codesize(&a2dpio->a2dp);
154f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	iodev->buffer_size = (a2dpio->pcm_buf_size + block_size) / format_bytes;
15531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	if (iodev->used_size > iodev->buffer_size)
15631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		iodev->used_size = iodev->buffer_size;
157f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao
158f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	syslog(LOG_DEBUG, "a2dp iodev buf size %lu, used size %lu",
159f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	       iodev->buffer_size, iodev->used_size);
160f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao
16131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	return 0;
16231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao}
16331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
16431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostatic int close_dev(struct cras_iodev *iodev)
16531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{
16631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	int err;
16731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	struct a2dp_io *a2dpio = (struct a2dp_io *)iodev;
16831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
16931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	if (!a2dpio->transport)
17031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		return 0;
17131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
17231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	err = cras_bt_transport_release(a2dpio->transport);
17331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	if (err < 0)
17431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		syslog(LOG_ERR, "transport_release failed");
17531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
1766f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao	a2dp_drain(&a2dpio->a2dp);
17731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	a2dpio->pcm_buf_used = 0;
17831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	cras_iodev_free_format(iodev);
17931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	return 0;
18031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao}
18131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
18231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostatic int is_open(const struct cras_iodev *iodev)
18331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{
18431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	struct a2dp_io *a2dpio = (struct a2dp_io *)iodev;
18531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	return cras_bt_transport_fd(a2dpio->transport) > 0;
18631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao}
18731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
18831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostatic int dev_running(const struct cras_iodev *iodev)
18931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{
19031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	// TODO(hychao): Track if a2dp iodev is actually playing.
19131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	return is_open(iodev);
19231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao}
19331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
19431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostatic int delay_frames(const struct cras_iodev *iodev)
19531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{
196f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	return frames_queued(iodev);
19731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao}
19831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
19931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostatic int get_buffer(struct cras_iodev *iodev, uint8_t **dst, unsigned *frames)
20031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{
20131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	size_t format_bytes;
20231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	struct a2dp_io *a2dpio;
20331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	a2dpio = (struct a2dp_io *)iodev;
20431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
20531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	format_bytes = cras_get_format_bytes(iodev->format);
20631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
20731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	if (iodev->direction == CRAS_STREAM_OUTPUT) {
20838cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao		*dst = a2dpio->pcm_buf + a2dpio->pcm_buf_offset
20938cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao				+ a2dpio->pcm_buf_used;
21038cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao		*frames = (a2dpio->pcm_buf_size - a2dpio->pcm_buf_offset -
21138cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao				a2dpio->pcm_buf_used) / format_bytes;
21231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	}
21331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	return 0;
21431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao}
21531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
21631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostatic int put_buffer(struct cras_iodev *iodev, unsigned nwritten)
21731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{
21831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	size_t format_bytes;
21938cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao	int written = 0;
22038cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao	int processed;
22131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	struct a2dp_io *a2dpio = (struct a2dp_io *)iodev;
222f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao
22331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	format_bytes = cras_get_format_bytes(iodev->format);
22431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
22538cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao	if (a2dpio->pcm_buf_used + a2dpio->pcm_buf_offset +
22638cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao			nwritten * format_bytes > a2dpio->pcm_buf_size)
22731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		return -1;
22831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	a2dpio->pcm_buf_used += nwritten * format_bytes;
2296f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao
23038cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao	processed = a2dp_write(a2dpio->pcm_buf + a2dpio->pcm_buf_offset,
23138cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao			       a2dpio->pcm_buf_used,
23238cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao			       &a2dpio->a2dp,
23338cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao			       format_bytes,
23438cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao			       cras_bt_transport_fd(a2dpio->transport),
23538cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao			       cras_bt_transport_write_mtu(a2dpio->transport),
23638cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao			       &written);
23738cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao
23838cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao	if (a2dpio->pcm_buf_used == processed) {
23938cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao		a2dpio->pcm_buf_offset = 0;
24038cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao		a2dpio->pcm_buf_used = 0;
24138cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao	} else {
24238cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao		a2dpio->pcm_buf_offset += processed;
24338cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao		a2dpio->pcm_buf_used -= processed;
24438cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao	}
24538cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao
246f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	if (written == -EAGAIN) {
247f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao		syslog(LOG_ERR, "a2dp_write error");
248f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao		return 0;
249f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	}
25038cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao
251f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	get_bt_queued_frames(iodev,
252f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao			     a2dp_block_size(&a2dpio->a2dp, written)
253f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao				     / format_bytes);
25431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	return 0;
25531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao}
25631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
25731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaovoid free_resources(struct a2dp_io *a2dpio)
25831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{
25931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	free(a2dpio->base.supported_channel_counts);
26031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	free(a2dpio->base.supported_rates);
2616f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao	destroy_a2dp(&a2dpio->a2dp);
26231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao}
26331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
26431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostruct cras_iodev *a2dp_iodev_create(struct cras_bt_transport *transport)
26531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{
26631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	int err;
26731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	struct a2dp_io *a2dpio;
26831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	struct cras_iodev *iodev;
26931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	struct cras_ionode *node;
2701cbde1fb3f2aad5494f33d49dacaeafebc753ac2Hsin-Yu Chao	a2dp_sbc_t a2dp;
27131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
27231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	a2dpio = (struct a2dp_io *)calloc(1, sizeof(*a2dpio));
27331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	if (!a2dpio)
27431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		goto error;
27531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
2761cbde1fb3f2aad5494f33d49dacaeafebc753ac2Hsin-Yu Chao	a2dpio->transport = transport;
2771cbde1fb3f2aad5494f33d49dacaeafebc753ac2Hsin-Yu Chao	cras_bt_transport_configuration(a2dpio->transport, &a2dp,
2781cbde1fb3f2aad5494f33d49dacaeafebc753ac2Hsin-Yu Chao					sizeof(a2dp));
2796f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao	err = init_a2dp(&a2dpio->a2dp, &a2dp);
2806f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao	if (err) {
2816f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao		syslog(LOG_ERR, "Fail to init a2dp");
2826f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao		goto error;
2836f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao	}
2841cbde1fb3f2aad5494f33d49dacaeafebc753ac2Hsin-Yu Chao
28531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev = &a2dpio->base;
28631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
28731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	/* A2DP only does output now */
28831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->direction = CRAS_STREAM_OUTPUT;
28931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
29031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	snprintf(iodev->info.name, sizeof(iodev->info.name), "%s",
29131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		 cras_bt_transport_object_path(a2dpio->transport));
29231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
29331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->info.name[ARRAY_SIZE(iodev->info.name) - 1] = '\0';
29431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
29531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->open_dev = open_dev;
29631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->is_open = is_open; /* Needed by thread_add_stream */
29731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->frames_queued = frames_queued;
29831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->dev_running = dev_running;
29931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->delay_frames = delay_frames;
30031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->get_buffer = get_buffer;
30131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->put_buffer = put_buffer;
30231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->close_dev = close_dev;
30331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->update_supported_formats = update_supported_formats;
30431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
30531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	/* Create a dummy ionode */
30631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	node = (struct cras_ionode *)calloc(1, sizeof(*node));
30731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	node->dev = iodev;
30831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	strcpy(node->name, iodev->info.name);
30931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	DL_APPEND(iodev->nodes, node);
31031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->active_node = node;
31131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	node->plugged = 1;
31231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	node->priority = 3;
31331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	gettimeofday(&node->plugged_time, NULL);
31431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
31531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	/* A2DP does output only */
31631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	err = cras_iodev_list_add_output(iodev);
31731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	if (err)
31831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		goto error;
31931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
32031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	return iodev;
32131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaoerror:
32231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	if (a2dpio) {
32331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		free_resources(a2dpio);
32431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		free(a2dpio);
32531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	}
32631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	return NULL;
32731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao}
32831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
32931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaovoid a2dp_iodev_destroy(struct cras_iodev *iodev)
33031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{
33131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	int rc;
33231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	struct a2dp_io *a2dpio = (struct a2dp_io *)iodev;
33331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
33431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	/* A2DP does output only */
33531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	rc = cras_iodev_list_rm_output(iodev);
33631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	if (rc != -EBUSY) {
33731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		free_resources(a2dpio);
33871aa1de70c395c3648ede3eec5838ac7c64646d5Chih-Chung Chang		cras_iodev_free_dsp(iodev);
33931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		free(a2dpio);
34031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	}
34131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao}
342