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>
7e5c801e32174b718f7e36ba07d67753af71f2e76Dylan Reid#include <sys/ioctl.h>
82c1e4a94b93ea1ca23ae1ab177a80ad769a7c18aDylan Reid#include <sys/param.h>
9e5c801e32174b718f7e36ba07d67753af71f2e76Dylan Reid#include <linux/sockios.h>
1031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao#include <sys/socket.h>
1131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao#include <syslog.h>
12f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao#include <time.h>
1331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
1477fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid#include "audio_thread.h"
15c9452136e619b69333dc3bd5fb87e5168793c9c0Dylan Reid#include "audio_thread_log.h"
163d316d343d4e80012d2c7d6c5e7e183533e8d7d5Dylan Reid#include "byte_buffer.h"
175528e7442cd3b86037fa84e45ca42cf10b126bdfHsin-Yu Chao#include "cras_iodev_list.h"
185c890457a82d673cd0ab619d6b506a1fbea630ebHsin-Yu Chao#include "cras_a2dp_endpoint.h"
191cbde1fb3f2aad5494f33d49dacaeafebc753ac2Hsin-Yu Chao#include "cras_a2dp_info.h"
2031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao#include "cras_a2dp_iodev.h"
21cc32f2cfb655c1c2a39a1db448415583f8ecc2d0Hsin-Yu Chao#include "cras_audio_area.h"
22dd2f666a53a1090744819bf38cd672b4548aca22Hsin-Yu Chao#include "cras_bt_device.h"
2331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao#include "cras_iodev.h"
2431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao#include "cras_util.h"
2585137d0c83307ebbfa890e8a64446de5957fbbbcChinyue Chen#include "sfh.h"
26f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao#include "rtp.h"
2731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao#include "utlist.h"
2831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
29433639d2a30c4a7e5cee97518426c7a3d2196dd4Dylan Reid#define PCM_BUF_MAX_SIZE_FRAMES (4096*4)
3077fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid#define PCM_BUF_MAX_SIZE_BYTES (PCM_BUF_MAX_SIZE_FRAMES * 4)
3131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
327e32d4dde1a7e935dc0e56d15dcca45c8c1e30f7Hsin-Yu Chao/* Child of cras_iodev to handle bluetooth A2DP streaming.
337e32d4dde1a7e935dc0e56d15dcca45c8c1e30f7Hsin-Yu Chao * Members:
347e32d4dde1a7e935dc0e56d15dcca45c8c1e30f7Hsin-Yu Chao *    base - The cras_iodev structure "base class"
357e32d4dde1a7e935dc0e56d15dcca45c8c1e30f7Hsin-Yu Chao *    a2dp - The codec and encoded state of a2dp_io.
367e32d4dde1a7e935dc0e56d15dcca45c8c1e30f7Hsin-Yu Chao *    transport - The transport object for bluez media API.
377e32d4dde1a7e935dc0e56d15dcca45c8c1e30f7Hsin-Yu Chao *    sock_depth_frames - Socket depth in frames of the a2dp socket.
387e32d4dde1a7e935dc0e56d15dcca45c8c1e30f7Hsin-Yu Chao *    pcm_buf - Buffer to hold pcm samples before encode.
391037abe53d0bb703539faa80268bcbe0a06f7278Hsin-Yu Chao *    destroyed - Flag to note if this a2dp_io is about to destroy.
407e32d4dde1a7e935dc0e56d15dcca45c8c1e30f7Hsin-Yu Chao *    pre_fill_complete - Flag to note if socket pre-fill is completed.
417e32d4dde1a7e935dc0e56d15dcca45c8c1e30f7Hsin-Yu Chao *    bt_written_frames - Accumulated frames written to a2dp socket. Used
427e32d4dde1a7e935dc0e56d15dcca45c8c1e30f7Hsin-Yu Chao *        together with the device open timestamp to estimate how many virtual
437e32d4dde1a7e935dc0e56d15dcca45c8c1e30f7Hsin-Yu Chao *        buffer is queued there.
447e32d4dde1a7e935dc0e56d15dcca45c8c1e30f7Hsin-Yu Chao *    dev_open_time - The last time a2dp_ios is opened.
457e32d4dde1a7e935dc0e56d15dcca45c8c1e30f7Hsin-Yu Chao */
4631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostruct a2dp_io {
4731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	struct cras_iodev base;
486f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao	struct a2dp_info a2dp;
4931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	struct cras_bt_transport *transport;
50c1cd9fc1dfc9e00240ad28571fbae2adea36c628Hsin-Yu Chao	unsigned sock_depth_frames;
513d316d343d4e80012d2c7d6c5e7e183533e8d7d5Dylan Reid	struct byte_buffer *pcm_buf;
521037abe53d0bb703539faa80268bcbe0a06f7278Hsin-Yu Chao	int destroyed;
5395bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid	int pre_fill_complete;
549f02b64519595d12ec2346ea699c9507b01437c9Hsin-Yu Chao	uint64_t bt_written_frames;
559f02b64519595d12ec2346ea699c9507b01437c9Hsin-Yu Chao	struct timespec dev_open_time;
5631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao};
5731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
5877fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reidstatic int flush_data(void *arg);
5977fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid
6031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostatic int update_supported_formats(struct cras_iodev *iodev)
6131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{
6231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	struct a2dp_io *a2dpio = (struct a2dp_io *)iodev;
6331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	size_t rate = 0;
6431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	size_t channel;
6531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	a2dp_sbc_t a2dp;
6631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
6731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	cras_bt_transport_configuration(a2dpio->transport, &a2dp,
6831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao					sizeof(a2dp));
6931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
7031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->format->format = SND_PCM_FORMAT_S16_LE;
7131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	channel = (a2dp.channel_mode == SBC_CHANNEL_MODE_MONO) ? 1 : 2;
7231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
7331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	if (a2dp.frequency & SBC_SAMPLING_FREQ_48000)
7431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		rate = 48000;
7531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	else if (a2dp.frequency & SBC_SAMPLING_FREQ_44100)
7631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		rate = 44100;
7731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	else if (a2dp.frequency & SBC_SAMPLING_FREQ_32000)
7831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		rate = 32000;
7931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	else if (a2dp.frequency & SBC_SAMPLING_FREQ_16000)
8031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		rate = 16000;
8131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
82639a342fcc14cf262e11612220079aff45f40ad5Dylan Reid	free(iodev->supported_rates);
8331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->supported_rates = (size_t *)malloc(2 * sizeof(rate));
8431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->supported_rates[0] = rate;
8531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->supported_rates[1] = 0;
8631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
87639a342fcc14cf262e11612220079aff45f40ad5Dylan Reid	free(iodev->supported_channel_counts);
8831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->supported_channel_counts = (size_t *)malloc(2 * sizeof(channel));
8931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->supported_channel_counts[0] = channel;
9031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->supported_channel_counts[1] = 0;
9131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
92a485ac04bdfc71e374a3a5d2fbcf4699999a2939Dylan Reid	free(iodev->supported_formats);
93a485ac04bdfc71e374a3a5d2fbcf4699999a2939Dylan Reid	iodev->supported_formats =
94a485ac04bdfc71e374a3a5d2fbcf4699999a2939Dylan Reid		(snd_pcm_format_t *)malloc(2 * sizeof(snd_pcm_format_t));
95a485ac04bdfc71e374a3a5d2fbcf4699999a2939Dylan Reid	iodev->supported_formats[0] = SND_PCM_FORMAT_S16_LE;
96a485ac04bdfc71e374a3a5d2fbcf4699999a2939Dylan Reid	iodev->supported_formats[1] = 0;
97a485ac04bdfc71e374a3a5d2fbcf4699999a2939Dylan Reid
9831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	return 0;
9931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao}
10031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
1019f02b64519595d12ec2346ea699c9507b01437c9Hsin-Yu Chao/* Calculates the number of virtual buffer in frames. Assuming all written
1029f02b64519595d12ec2346ea699c9507b01437c9Hsin-Yu Chao * buffer is consumed in a constant frame rate at bluetooth device side.
103f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao * Args:
104f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao *    iodev: The a2dp iodev to estimate the queued frames for.
105f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao *    fr: The amount of frames just transmitted.
106f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao */
1079f02b64519595d12ec2346ea699c9507b01437c9Hsin-Yu Chaostatic int bt_queued_frames(const struct cras_iodev *iodev, int fr)
108f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao{
1099f02b64519595d12ec2346ea699c9507b01437c9Hsin-Yu Chao	uint64_t consumed;
110f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	struct a2dp_io *a2dpio = (struct a2dp_io *)iodev;
111f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao
1129f02b64519595d12ec2346ea699c9507b01437c9Hsin-Yu Chao	/* Calculate consumed frames since device has opened */
1139f02b64519595d12ec2346ea699c9507b01437c9Hsin-Yu Chao	a2dpio->bt_written_frames += fr;
1146fa2060737ffe7bd0364cce87bd60861222a174fChinyue Chen	consumed = cras_frames_since_time(&a2dpio->dev_open_time,
1156fa2060737ffe7bd0364cce87bd60861222a174fChinyue Chen					  iodev->format->frame_rate);
116f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao
1179f02b64519595d12ec2346ea699c9507b01437c9Hsin-Yu Chao	if (a2dpio->bt_written_frames > consumed)
1189f02b64519595d12ec2346ea699c9507b01437c9Hsin-Yu Chao		return a2dpio->bt_written_frames - consumed;
119f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	else
1209f02b64519595d12ec2346ea699c9507b01437c9Hsin-Yu Chao		return 0;
121f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao}
122f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao
1233d316d343d4e80012d2c7d6c5e7e183533e8d7d5Dylan Reid
124fa4cd9766aec6eae544b1078ed835687c4e74617John Muirstatic int frames_queued(const struct cras_iodev *iodev,
125fa4cd9766aec6eae544b1078ed835687c4e74617John Muir			 struct timespec *tstamp)
12631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{
127f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	struct a2dp_io *a2dpio = (struct a2dp_io *)iodev;
12870c72e44ad8a2a7d8fb51cd668f36d6d8021e422Hsin-Yu Chao	int estimate_queued_frames = bt_queued_frames(iodev, 0);
12970c72e44ad8a2a7d8fb51cd668f36d6d8021e422Hsin-Yu Chao	int local_queued_frames =
13070c72e44ad8a2a7d8fb51cd668f36d6d8021e422Hsin-Yu Chao			a2dp_queued_frames(&a2dpio->a2dp) +
13170c72e44ad8a2a7d8fb51cd668f36d6d8021e422Hsin-Yu Chao			buf_queued_bytes(a2dpio->pcm_buf) /
13270c72e44ad8a2a7d8fb51cd668f36d6d8021e422Hsin-Yu Chao				cras_get_format_bytes(iodev->format);
133fa4cd9766aec6eae544b1078ed835687c4e74617John Muir	clock_gettime(CLOCK_MONOTONIC_RAW, tstamp);
13470c72e44ad8a2a7d8fb51cd668f36d6d8021e422Hsin-Yu Chao	return MIN(iodev->buffer_size,
13570c72e44ad8a2a7d8fb51cd668f36d6d8021e422Hsin-Yu Chao		   MAX(estimate_queued_frames, local_queued_frames));
13631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao}
13731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
1382e14c232763ac89fd9d2fa5e9b3fdcf6581b2db8Chinyue Chenstatic int open_dev(struct cras_iodev *iodev)
13931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{
14031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	struct a2dp_io *a2dpio = (struct a2dp_io *)iodev;
141e5c801e32174b718f7e36ba07d67753af71f2e76Dylan Reid	int sock_depth;
142e5c801e32174b718f7e36ba07d67753af71f2e76Dylan Reid	int err;
14331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
14431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	err = cras_bt_transport_acquire(a2dpio->transport);
14531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	if (err < 0) {
14631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		syslog(LOG_ERR, "transport_acquire failed");
14731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		return err;
14831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	}
14931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
150d6ba8e31ac15c1e5c5403aa790597857e3380da8Hsin-Yu Chao	/* Apply the node's volume after transport is acquired. Doing this
151d6ba8e31ac15c1e5c5403aa790597857e3380da8Hsin-Yu Chao	 * is necessary because the volume can not sync to hardware until
152d6ba8e31ac15c1e5c5403aa790597857e3380da8Hsin-Yu Chao	 * it is opened. */
153d6ba8e31ac15c1e5c5403aa790597857e3380da8Hsin-Yu Chao	iodev->set_volume(iodev);
154d6ba8e31ac15c1e5c5403aa790597857e3380da8Hsin-Yu Chao
15531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	/* Assert format is set before opening device. */
15631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	if (iodev->format == NULL)
15731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		return -EINVAL;
15831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->format->format = SND_PCM_FORMAT_S16_LE;
1599690a3281b7167e5a38368fd8db39375bea8a1f8Hsin-Yu Chao	cras_iodev_init_audio_area(iodev, iodev->format->num_channels);
16031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
1613d316d343d4e80012d2c7d6c5e7e183533e8d7d5Dylan Reid	a2dpio->pcm_buf = byte_buffer_create(PCM_BUF_MAX_SIZE_BYTES);
1623d316d343d4e80012d2c7d6c5e7e183533e8d7d5Dylan Reid	if (!a2dpio->pcm_buf)
1633d316d343d4e80012d2c7d6c5e7e183533e8d7d5Dylan Reid		return -ENOMEM;
1643d316d343d4e80012d2c7d6c5e7e183533e8d7d5Dylan Reid
16577fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid	iodev->buffer_size = PCM_BUF_MAX_SIZE_FRAMES;
166c1cd9fc1dfc9e00240ad28571fbae2adea36c628Hsin-Yu Chao
167c1cd9fc1dfc9e00240ad28571fbae2adea36c628Hsin-Yu Chao	/* Set up the socket to hold two MTUs full of data before returning
168c1cd9fc1dfc9e00240ad28571fbae2adea36c628Hsin-Yu Chao	 * EAGAIN.  This will allow the write to be throttled when a reasonable
169c1cd9fc1dfc9e00240ad28571fbae2adea36c628Hsin-Yu Chao	 * amount of data is queued. */
170c1cd9fc1dfc9e00240ad28571fbae2adea36c628Hsin-Yu Chao	sock_depth = 2 * cras_bt_transport_write_mtu(a2dpio->transport);
171c1cd9fc1dfc9e00240ad28571fbae2adea36c628Hsin-Yu Chao	setsockopt(cras_bt_transport_fd(a2dpio->transport),
172c1cd9fc1dfc9e00240ad28571fbae2adea36c628Hsin-Yu Chao		   SOL_SOCKET, SO_SNDBUF, &sock_depth, sizeof(sock_depth));
173c1cd9fc1dfc9e00240ad28571fbae2adea36c628Hsin-Yu Chao
174c1cd9fc1dfc9e00240ad28571fbae2adea36c628Hsin-Yu Chao	a2dpio->sock_depth_frames =
175c1cd9fc1dfc9e00240ad28571fbae2adea36c628Hsin-Yu Chao		a2dp_block_size(&a2dpio->a2dp,
176c1cd9fc1dfc9e00240ad28571fbae2adea36c628Hsin-Yu Chao				cras_bt_transport_write_mtu(a2dpio->transport))
177c1cd9fc1dfc9e00240ad28571fbae2adea36c628Hsin-Yu Chao			/ cras_get_format_bytes(iodev->format) * 2;
178c1cd9fc1dfc9e00240ad28571fbae2adea36c628Hsin-Yu Chao	iodev->min_buffer_level = a2dpio->sock_depth_frames;
179c1cd9fc1dfc9e00240ad28571fbae2adea36c628Hsin-Yu Chao
18095bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid	a2dpio->pre_fill_complete = 0;
181f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao
1829f02b64519595d12ec2346ea699c9507b01437c9Hsin-Yu Chao	/* Initialize variables for bt_queued_frames() */
1839f02b64519595d12ec2346ea699c9507b01437c9Hsin-Yu Chao	a2dpio->bt_written_frames = 0;
184cd23b811ccefce5cd01335c3a2c98a443bc14024Dylan Reid	clock_gettime(CLOCK_MONOTONIC_RAW, &a2dpio->dev_open_time);
1859f02b64519595d12ec2346ea699c9507b01437c9Hsin-Yu Chao
18677fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid	audio_thread_add_write_callback(cras_bt_transport_fd(a2dpio->transport),
18777fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid					flush_data, iodev);
18877fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid	audio_thread_enable_callback(cras_bt_transport_fd(a2dpio->transport),
18977fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid				     0);
19031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	return 0;
19131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao}
19231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
19331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostatic int close_dev(struct cras_iodev *iodev)
19431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{
19531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	int err;
19631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	struct a2dp_io *a2dpio = (struct a2dp_io *)iodev;
1972232117de7c9542713986c95235bb088d0fa6c40Hsin-Yu Chao	struct cras_bt_device *device;
19831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
19931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	if (!a2dpio->transport)
20031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		return 0;
20131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
2025528e7442cd3b86037fa84e45ca42cf10b126bdfHsin-Yu Chao	/* Remove audio thread callback and sync before releasing
2035528e7442cd3b86037fa84e45ca42cf10b126bdfHsin-Yu Chao	 * the transport. */
2045528e7442cd3b86037fa84e45ca42cf10b126bdfHsin-Yu Chao	audio_thread_rm_callback_sync(
2055528e7442cd3b86037fa84e45ca42cf10b126bdfHsin-Yu Chao			cras_iodev_list_get_audio_thread(),
2065528e7442cd3b86037fa84e45ca42cf10b126bdfHsin-Yu Chao			cras_bt_transport_fd(a2dpio->transport));
20777fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid
2081037abe53d0bb703539faa80268bcbe0a06f7278Hsin-Yu Chao	err = cras_bt_transport_release(a2dpio->transport,
2091037abe53d0bb703539faa80268bcbe0a06f7278Hsin-Yu Chao					!a2dpio->destroyed);
21031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	if (err < 0)
21131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		syslog(LOG_ERR, "transport_release failed");
21231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
2132232117de7c9542713986c95235bb088d0fa6c40Hsin-Yu Chao	device = cras_bt_transport_device(a2dpio->transport);
2142232117de7c9542713986c95235bb088d0fa6c40Hsin-Yu Chao	if (device)
2152232117de7c9542713986c95235bb088d0fa6c40Hsin-Yu Chao		cras_bt_device_cancel_suspend(device);
2166f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao	a2dp_drain(&a2dpio->a2dp);
2173d316d343d4e80012d2c7d6c5e7e183533e8d7d5Dylan Reid	byte_buffer_destroy(a2dpio->pcm_buf);
21831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	cras_iodev_free_format(iodev);
2199690a3281b7167e5a38368fd8db39375bea8a1f8Hsin-Yu Chao	cras_iodev_free_audio_area(iodev);
22031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	return 0;
22131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao}
22231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
22395bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reidstatic int pre_fill_socket(struct a2dp_io *a2dpio)
22495bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid{
22595bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid	static const uint16_t zero_buffer[1024 * 2];
22695bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid	int processed;
22795bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid	int written = 0;
22895bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid
22995bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid	while (1) {
23095bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid		processed = a2dp_encode(
23195bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid				&a2dpio->a2dp,
23295bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid				zero_buffer,
23395bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid				sizeof(zero_buffer),
23495bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid				cras_get_format_bytes(a2dpio->base.format),
23595bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid				cras_bt_transport_write_mtu(a2dpio->transport));
23695bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid		if (processed < 0)
23795bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid			return processed;
23895bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid		if (processed == 0)
23995bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid			break;
24095bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid
24195bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid		written = a2dp_write(
24295bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid				&a2dpio->a2dp,
24395bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid				cras_bt_transport_fd(a2dpio->transport),
24495bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid				cras_bt_transport_write_mtu(a2dpio->transport));
24595bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid		/* Full when EAGAIN is returned. */
24695bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid		if (written == -EAGAIN)
24795bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid			break;
24895bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid		else if (written < 0)
24995bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid			return written;
25095bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid		else if (written == 0)
25195bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid			break;
25295bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid	};
25395bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid
254d313f15b63753cb0324fd424ed6d2b9cac71b098Hsin-Yu Chao	a2dp_drain(&a2dpio->a2dp);
25595bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid	return 0;
25695bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid}
25795bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid
258cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao/* Flushes queued buffer, including pcm and a2dp buffer.
25985cc54d7c2bf9a24abbc5518297bf5aacd91c47bHsin-Yu Chao * Returns:
26085cc54d7c2bf9a24abbc5518297bf5aacd91c47bHsin-Yu Chao *    0 when the flush succeeded, -1 when error occurred.
261cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao */
26277fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reidstatic int flush_data(void *arg)
263cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao{
2645c890457a82d673cd0ab619d6b506a1fbea630ebHsin-Yu Chao	struct cras_iodev *iodev = (struct cras_iodev *)arg;
265cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao	int processed;
266cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao	size_t format_bytes;
267cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao	int written = 0;
26840ec4b17c945adab7667121f50eedc57448c4effHsin-Yu Chao	int queued_frames;
269cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao	struct a2dp_io *a2dpio;
2702232117de7c9542713986c95235bb088d0fa6c40Hsin-Yu Chao	struct cras_bt_device *device;
271cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao
272cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao	a2dpio = (struct a2dp_io *)iodev;
273cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao	format_bytes = cras_get_format_bytes(iodev->format);
2742232117de7c9542713986c95235bb088d0fa6c40Hsin-Yu Chao	device = cras_bt_transport_device(a2dpio->transport);
2752232117de7c9542713986c95235bb088d0fa6c40Hsin-Yu Chao
2762232117de7c9542713986c95235bb088d0fa6c40Hsin-Yu Chao	/* If bt device has been destroyed, this a2dp iodev will soon be
2772232117de7c9542713986c95235bb088d0fa6c40Hsin-Yu Chao	 * destroyed as well. */
2782232117de7c9542713986c95235bb088d0fa6c40Hsin-Yu Chao	if (device == NULL)
2792232117de7c9542713986c95235bb088d0fa6c40Hsin-Yu Chao		return -EINVAL;
280cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao
28177fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reidencode_more:
28201d37ad909523378f12ecf939419829134aec32fDylan Reid	while (buf_queued_bytes(a2dpio->pcm_buf)) {
28327089cd9e476fff3c1d82622f17a23a80da0fd51Dylan Reid		processed = a2dp_encode(
28427089cd9e476fff3c1d82622f17a23a80da0fd51Dylan Reid				&a2dpio->a2dp,
28501d37ad909523378f12ecf939419829134aec32fDylan Reid				buf_read_pointer(a2dpio->pcm_buf),
28601d37ad909523378f12ecf939419829134aec32fDylan Reid				buf_readable_bytes(a2dpio->pcm_buf),
28701d37ad909523378f12ecf939419829134aec32fDylan Reid				format_bytes,
28827089cd9e476fff3c1d82622f17a23a80da0fd51Dylan Reid				cras_bt_transport_write_mtu(a2dpio->transport));
289192f5007487e47d4b1e3ba9d2df95d11fcd01d4eVadim Kharchenko		ATLOG(atlog, AUDIO_THREAD_A2DP_ENCODE,
290c9452136e619b69333dc3bd5fb87e5168793c9c0Dylan Reid					    processed,
291c9452136e619b69333dc3bd5fb87e5168793c9c0Dylan Reid					    buf_queued_bytes(a2dpio->pcm_buf),
292c9452136e619b69333dc3bd5fb87e5168793c9c0Dylan Reid					    buf_readable_bytes(a2dpio->pcm_buf)
293c9452136e619b69333dc3bd5fb87e5168793c9c0Dylan Reid					    );
29477fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid		if (processed == -ENOSPC || processed == 0)
29527089cd9e476fff3c1d82622f17a23a80da0fd51Dylan Reid			break;
29677fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid		if (processed < 0)
29777fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid			return 0;
29801d37ad909523378f12ecf939419829134aec32fDylan Reid
29977fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid		buf_increment_read(a2dpio->pcm_buf, processed);
300cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao	}
30185cc54d7c2bf9a24abbc5518297bf5aacd91c47bHsin-Yu Chao
30277fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid	written = a2dp_write(&a2dpio->a2dp,
30377fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid			     cras_bt_transport_fd(a2dpio->transport),
30477fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid			     cras_bt_transport_write_mtu(a2dpio->transport));
305192f5007487e47d4b1e3ba9d2df95d11fcd01d4eVadim Kharchenko	ATLOG(atlog, AUDIO_THREAD_A2DP_WRITE,
306c9452136e619b69333dc3bd5fb87e5168793c9c0Dylan Reid				    written,
307c9452136e619b69333dc3bd5fb87e5168793c9c0Dylan Reid				    a2dp_queued_frames(&a2dpio->a2dp), 0);
30877fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid	if (written == -EAGAIN) {
3095c890457a82d673cd0ab619d6b506a1fbea630ebHsin-Yu Chao		/* If EAGAIN error lasts longer than 5 seconds, suspend the
3105c890457a82d673cd0ab619d6b506a1fbea630ebHsin-Yu Chao		 * a2dp connection. */
3112232117de7c9542713986c95235bb088d0fa6c40Hsin-Yu Chao		cras_bt_device_schedule_suspend(device, 5000);
31277fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid		audio_thread_enable_callback(
31377fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid				cras_bt_transport_fd(a2dpio->transport), 1);
31477fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid		return 0;
31577fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid	} else if (written < 0) {
3165c890457a82d673cd0ab619d6b506a1fbea630ebHsin-Yu Chao		/* Suspend a2dp immediately when receives error other than
3175c890457a82d673cd0ab619d6b506a1fbea630ebHsin-Yu Chao		 * EAGAIN. */
3182232117de7c9542713986c95235bb088d0fa6c40Hsin-Yu Chao		cras_bt_device_cancel_suspend(device);
3192232117de7c9542713986c95235bb088d0fa6c40Hsin-Yu Chao		cras_bt_device_schedule_suspend(device, 0);
3205c890457a82d673cd0ab619d6b506a1fbea630ebHsin-Yu Chao		return written;
32177fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid	}
32277fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid
323b94ca5c623b0e4f4661ddaf007f1189e117780e7Hsin-Yu Chao	/* Data succcessfully written to a2dp socket, cancel any scheduled
324b94ca5c623b0e4f4661ddaf007f1189e117780e7Hsin-Yu Chao	 * suspend timer. */
3252232117de7c9542713986c95235bb088d0fa6c40Hsin-Yu Chao	cras_bt_device_cancel_suspend(device);
326b94ca5c623b0e4f4661ddaf007f1189e117780e7Hsin-Yu Chao
327b94ca5c623b0e4f4661ddaf007f1189e117780e7Hsin-Yu Chao	/* If it looks okay to write more and we do have queued data, try
32840ec4b17c945adab7667121f50eedc57448c4effHsin-Yu Chao	 * encode more. But avoid the case when PCM buffer level is too close
32940ec4b17c945adab7667121f50eedc57448c4effHsin-Yu Chao	 * to min_buffer_level so that another A2DP write could causes underrun.
33040ec4b17c945adab7667121f50eedc57448c4effHsin-Yu Chao	 */
33140ec4b17c945adab7667121f50eedc57448c4effHsin-Yu Chao	queued_frames = buf_queued_bytes(a2dpio->pcm_buf) / format_bytes;
33240ec4b17c945adab7667121f50eedc57448c4effHsin-Yu Chao	if (written && (iodev->min_buffer_level + written < queued_frames))
33377fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid		goto encode_more;
33477fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid
33577fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid	/* everything written. */
33677fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid	audio_thread_enable_callback(
33777fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid			cras_bt_transport_fd(a2dpio->transport), 0);
33877fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid
3395c890457a82d673cd0ab619d6b506a1fbea630ebHsin-Yu Chao	return 0;
340cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao}
341cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao
34231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostatic int delay_frames(const struct cras_iodev *iodev)
34331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{
34477fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid	const struct a2dp_io *a2dpio = (struct a2dp_io *)iodev;
345fa4cd9766aec6eae544b1078ed835687c4e74617John Muir	struct timespec tstamp;
34677fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid
347e5c801e32174b718f7e36ba07d67753af71f2e76Dylan Reid	/* The number of frames in the pcm buffer plus two mtu packets */
348fa4cd9766aec6eae544b1078ed835687c4e74617John Muir	return frames_queued(iodev, &tstamp) + a2dpio->sock_depth_frames;
34931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao}
35031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
351cc32f2cfb655c1c2a39a1db448415583f8ecc2d0Hsin-Yu Chaostatic int get_buffer(struct cras_iodev *iodev,
352cc32f2cfb655c1c2a39a1db448415583f8ecc2d0Hsin-Yu Chao		      struct cras_audio_area **area,
353cc32f2cfb655c1c2a39a1db448415583f8ecc2d0Hsin-Yu Chao		      unsigned *frames)
35431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{
35531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	size_t format_bytes;
35631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	struct a2dp_io *a2dpio;
35715e137c3cc39fafffc303b5612de7a4de7a27982Hsin-Yu Chao
35831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	a2dpio = (struct a2dp_io *)iodev;
35931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
36031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	format_bytes = cras_get_format_bytes(iodev->format);
36131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
362cc32f2cfb655c1c2a39a1db448415583f8ecc2d0Hsin-Yu Chao	if (iodev->direction != CRAS_STREAM_OUTPUT)
363cc32f2cfb655c1c2a39a1db448415583f8ecc2d0Hsin-Yu Chao		return 0;
364cc32f2cfb655c1c2a39a1db448415583f8ecc2d0Hsin-Yu Chao
3653d316d343d4e80012d2c7d6c5e7e183533e8d7d5Dylan Reid	*frames = MIN(*frames, buf_writable_bytes(a2dpio->pcm_buf) /
3663d316d343d4e80012d2c7d6c5e7e183533e8d7d5Dylan Reid					format_bytes);
367cc32f2cfb655c1c2a39a1db448415583f8ecc2d0Hsin-Yu Chao	iodev->area->frames = *frames;
368cc32f2cfb655c1c2a39a1db448415583f8ecc2d0Hsin-Yu Chao	cras_audio_area_config_buf_pointers(
369cc32f2cfb655c1c2a39a1db448415583f8ecc2d0Hsin-Yu Chao			iodev->area, iodev->format,
3703d316d343d4e80012d2c7d6c5e7e183533e8d7d5Dylan Reid			buf_write_pointer(a2dpio->pcm_buf));
371cc32f2cfb655c1c2a39a1db448415583f8ecc2d0Hsin-Yu Chao	*area = iodev->area;
37231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	return 0;
37331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao}
37431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
37531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostatic int put_buffer(struct cras_iodev *iodev, unsigned nwritten)
37631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{
37795bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid	size_t written_bytes;
37831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	size_t format_bytes;
37931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	struct a2dp_io *a2dpio = (struct a2dp_io *)iodev;
380f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao
38131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	format_bytes = cras_get_format_bytes(iodev->format);
38295bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid	written_bytes = nwritten * format_bytes;
38331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
38495bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid	if (written_bytes > buf_writable_bytes(a2dpio->pcm_buf))
3853d316d343d4e80012d2c7d6c5e7e183533e8d7d5Dylan Reid		return -EINVAL;
3863d316d343d4e80012d2c7d6c5e7e183533e8d7d5Dylan Reid
38795bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid	buf_increment_write(a2dpio->pcm_buf, written_bytes);
38895bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid
38995bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid	bt_queued_frames(iodev, nwritten);
39095bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid
39195bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid	/* Until the minimum number of frames have been queued, don't send
39295bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid	 * anything. */
39395bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid	if (!a2dpio->pre_fill_complete) {
39495bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid		pre_fill_socket(a2dpio);
39595bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid		a2dpio->pre_fill_complete = 1;
39695bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid		/* Start measuring frames_consumed from now. */
397cd23b811ccefce5cd01335c3a2c98a443bc14024Dylan Reid		clock_gettime(CLOCK_MONOTONIC_RAW, &a2dpio->dev_open_time);
39895bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid	}
3996f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao
4002509f106abb44aa2f0dca35a28c47cce8459da5dHsin-Yu Chao	return flush_data(iodev);
40131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao}
40231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
4033f787ac37a53be6b3a065ee5d1a47427fae78100Hsin-Yu Chaostatic int flush_buffer(struct cras_iodev *iodev)
4043f787ac37a53be6b3a065ee5d1a47427fae78100Hsin-Yu Chao{
4053f787ac37a53be6b3a065ee5d1a47427fae78100Hsin-Yu Chao	return 0;
4063f787ac37a53be6b3a065ee5d1a47427fae78100Hsin-Yu Chao}
4073f787ac37a53be6b3a065ee5d1a47427fae78100Hsin-Yu Chao
408d6ba8e31ac15c1e5c5403aa790597857e3380da8Hsin-Yu Chaostatic void set_volume(struct cras_iodev *iodev)
409d6ba8e31ac15c1e5c5403aa790597857e3380da8Hsin-Yu Chao{
410d6ba8e31ac15c1e5c5403aa790597857e3380da8Hsin-Yu Chao	size_t volume;
411d6ba8e31ac15c1e5c5403aa790597857e3380da8Hsin-Yu Chao	struct a2dp_io *a2dpio = (struct a2dp_io *)iodev;
412d6ba8e31ac15c1e5c5403aa790597857e3380da8Hsin-Yu Chao	struct cras_bt_device *device =
413d6ba8e31ac15c1e5c5403aa790597857e3380da8Hsin-Yu Chao			cras_bt_transport_device(a2dpio->transport);
414d6ba8e31ac15c1e5c5403aa790597857e3380da8Hsin-Yu Chao
415d6ba8e31ac15c1e5c5403aa790597857e3380da8Hsin-Yu Chao	if (!cras_bt_device_get_use_hardware_volume(device))
416d6ba8e31ac15c1e5c5403aa790597857e3380da8Hsin-Yu Chao		return;
417d6ba8e31ac15c1e5c5403aa790597857e3380da8Hsin-Yu Chao
418d6ba8e31ac15c1e5c5403aa790597857e3380da8Hsin-Yu Chao	volume = iodev->active_node->volume * 127 / 100;
419d6ba8e31ac15c1e5c5403aa790597857e3380da8Hsin-Yu Chao
420d6ba8e31ac15c1e5c5403aa790597857e3380da8Hsin-Yu Chao	if (a2dpio->transport)
421d6ba8e31ac15c1e5c5403aa790597857e3380da8Hsin-Yu Chao		cras_bt_transport_set_volume(a2dpio->transport, volume);
422d6ba8e31ac15c1e5c5403aa790597857e3380da8Hsin-Yu Chao}
423d6ba8e31ac15c1e5c5403aa790597857e3380da8Hsin-Yu Chao
4240def72b968591065f56e88d67e5c83234184811bHsin-Yu Chaostatic void update_active_node(struct cras_iodev *iodev, unsigned node_idx,
4250def72b968591065f56e88d67e5c83234184811bHsin-Yu Chao			       unsigned dev_enabled)
4260b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao{
4270b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao}
4280b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao
42931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaovoid free_resources(struct a2dp_io *a2dpio)
43031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{
4310b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao	struct cras_ionode *node;
4320b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao
4330b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao	node = a2dpio->base.active_node;
4340b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao	if (node) {
4350b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao		cras_iodev_rm_node(&a2dpio->base, node);
4360b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao		free(node);
4370b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao	}
43831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	free(a2dpio->base.supported_channel_counts);
43931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	free(a2dpio->base.supported_rates);
4406f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao	destroy_a2dp(&a2dpio->a2dp);
44131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao}
44231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
4435c890457a82d673cd0ab619d6b506a1fbea630ebHsin-Yu Chaostruct cras_iodev *a2dp_iodev_create(struct cras_bt_transport *transport)
44431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{
44531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	int err;
44631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	struct a2dp_io *a2dpio;
44731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	struct cras_iodev *iodev;
44831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	struct cras_ionode *node;
4491cbde1fb3f2aad5494f33d49dacaeafebc753ac2Hsin-Yu Chao	a2dp_sbc_t a2dp;
450dd2f666a53a1090744819bf38cd672b4548aca22Hsin-Yu Chao	struct cras_bt_device *device;
45108a60dcbe8a2c2f20146bab0b281c1de85bc68ccHsin-Yu Chao	const char *name;
45231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
45331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	a2dpio = (struct a2dp_io *)calloc(1, sizeof(*a2dpio));
45431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	if (!a2dpio)
45531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		goto error;
45631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
4571cbde1fb3f2aad5494f33d49dacaeafebc753ac2Hsin-Yu Chao	a2dpio->transport = transport;
4581cbde1fb3f2aad5494f33d49dacaeafebc753ac2Hsin-Yu Chao	cras_bt_transport_configuration(a2dpio->transport, &a2dp,
4591cbde1fb3f2aad5494f33d49dacaeafebc753ac2Hsin-Yu Chao					sizeof(a2dp));
4606f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao	err = init_a2dp(&a2dpio->a2dp, &a2dp);
4616f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao	if (err) {
4626f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao		syslog(LOG_ERR, "Fail to init a2dp");
4636f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao		goto error;
4646f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao	}
4651cbde1fb3f2aad5494f33d49dacaeafebc753ac2Hsin-Yu Chao
46631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev = &a2dpio->base;
46731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
46831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	/* A2DP only does output now */
46931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->direction = CRAS_STREAM_OUTPUT;
47031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
471dd2f666a53a1090744819bf38cd672b4548aca22Hsin-Yu Chao	/* Set iodev's name by bluetooth device's readable name, if
472dd2f666a53a1090744819bf38cd672b4548aca22Hsin-Yu Chao	 * the readable name is not available, use address instead.
473dd2f666a53a1090744819bf38cd672b4548aca22Hsin-Yu Chao	 */
474dd2f666a53a1090744819bf38cd672b4548aca22Hsin-Yu Chao	device = cras_bt_transport_device(transport);
47508a60dcbe8a2c2f20146bab0b281c1de85bc68ccHsin-Yu Chao	name = cras_bt_device_name(device);
47608a60dcbe8a2c2f20146bab0b281c1de85bc68ccHsin-Yu Chao	if (!name)
47708a60dcbe8a2c2f20146bab0b281c1de85bc68ccHsin-Yu Chao		name = cras_bt_transport_object_path(a2dpio->transport);
47831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
47908a60dcbe8a2c2f20146bab0b281c1de85bc68ccHsin-Yu Chao	snprintf(iodev->info.name, sizeof(iodev->info.name), "%s", name);
48031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->info.name[ARRAY_SIZE(iodev->info.name) - 1] = '\0';
48185137d0c83307ebbfa890e8a64446de5957fbbbcChinyue Chen	iodev->info.stable_id = SuperFastHash(
482538e024653d4052dbadddcde55da44c0395c3a42Hsin-Yu Chao			cras_bt_device_object_path(device),
483538e024653d4052dbadddcde55da44c0395c3a42Hsin-Yu Chao			strlen(cras_bt_device_object_path(device)),
484538e024653d4052dbadddcde55da44c0395c3a42Hsin-Yu Chao			strlen(cras_bt_device_object_path(device)));
485c84eb15a0fbd4a6b336d11438836b644fefc2679Moja Hsu	iodev->info.stable_id_new = iodev->info.stable_id;
48631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
4872e14c232763ac89fd9d2fa5e9b3fdcf6581b2db8Chinyue Chen	iodev->open_dev = open_dev;
48831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->frames_queued = frames_queued;
48931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->delay_frames = delay_frames;
49031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->get_buffer = get_buffer;
49131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->put_buffer = put_buffer;
4923f787ac37a53be6b3a065ee5d1a47427fae78100Hsin-Yu Chao	iodev->flush_buffer = flush_buffer;
49331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->close_dev = close_dev;
49431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->update_supported_formats = update_supported_formats;
4950b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao	iodev->update_active_node = update_active_node;
496d6ba8e31ac15c1e5c5403aa790597857e3380da8Hsin-Yu Chao	iodev->set_volume = set_volume;
49731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
49831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	/* Create a dummy ionode */
49931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	node = (struct cras_ionode *)calloc(1, sizeof(*node));
50031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	node->dev = iodev;
50131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	strcpy(node->name, iodev->info.name);
50231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	node->plugged = 1;
5030b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao	node->type = CRAS_NODE_TYPE_BLUETOOTH;
504b7fb7aad1bb54683361c3beda234e01bcf455becDylan Reid	node->volume = 100;
50531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	gettimeofday(&node->plugged_time, NULL);
50631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
50731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	/* A2DP does output only */
508ddecc26b70fc359d2100c2e3e742c464b6c38226Hsin-Yu Chao	cras_bt_device_append_iodev(device, iodev,
509ddecc26b70fc359d2100c2e3e742c464b6c38226Hsin-Yu Chao			cras_bt_transport_profile(a2dpio->transport));
5100b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao	cras_iodev_add_node(iodev, node);
5110b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao	cras_iodev_set_active_node(iodev, node);
5120b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao
51331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	return iodev;
51431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaoerror:
51531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	if (a2dpio) {
51631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		free_resources(a2dpio);
51731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		free(a2dpio);
51831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	}
51931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	return NULL;
52031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao}
52131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
52231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaovoid a2dp_iodev_destroy(struct cras_iodev *iodev)
52331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{
52431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	struct a2dp_io *a2dpio = (struct a2dp_io *)iodev;
525ddecc26b70fc359d2100c2e3e742c464b6c38226Hsin-Yu Chao	struct cras_bt_device *device;
526ddecc26b70fc359d2100c2e3e742c464b6c38226Hsin-Yu Chao
5271037abe53d0bb703539faa80268bcbe0a06f7278Hsin-Yu Chao	a2dpio->destroyed = 1;
528ddecc26b70fc359d2100c2e3e742c464b6c38226Hsin-Yu Chao	device = cras_bt_transport_device(a2dpio->transport);
52931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
53031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	/* A2DP does output only */
531ddecc26b70fc359d2100c2e3e742c464b6c38226Hsin-Yu Chao	cras_bt_device_rm_iodev(device, iodev);
5320fc4865c82dd7a07d978c598ec7f2d108a8a3279Hsin-Yu Chao
5330fc4865c82dd7a07d978c598ec7f2d108a8a3279Hsin-Yu Chao	/* Free resources when device successfully removed. */
5340fc4865c82dd7a07d978c598ec7f2d108a8a3279Hsin-Yu Chao	free_resources(a2dpio);
535a854651b825010352a05f55e720e29bdca6fb1baDylan Reid	cras_iodev_free_resources(iodev);
5360fc4865c82dd7a07d978c598ec7f2d108a8a3279Hsin-Yu Chao	free(a2dpio);
53731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao}
538