cras_a2dp_iodev.c revision 192f5007487e47d4b1e3ba9d2df95d11fcd01d4e
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"
171cbde1fb3f2aad5494f33d49dacaeafebc753ac2Hsin-Yu Chao#include "cras_a2dp_info.h"
1831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao#include "cras_a2dp_iodev.h"
19cc32f2cfb655c1c2a39a1db448415583f8ecc2d0Hsin-Yu Chao#include "cras_audio_area.h"
20dd2f666a53a1090744819bf38cd672b4548aca22Hsin-Yu Chao#include "cras_bt_device.h"
2131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao#include "cras_iodev.h"
2231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao#include "cras_util.h"
2385137d0c83307ebbfa890e8a64446de5957fbbbcChinyue Chen#include "sfh.h"
24f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao#include "rtp.h"
2531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao#include "utlist.h"
2631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
27433639d2a30c4a7e5cee97518426c7a3d2196dd4Dylan Reid#define PCM_BUF_MAX_SIZE_FRAMES (4096*4)
2877fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid#define PCM_BUF_MAX_SIZE_BYTES (PCM_BUF_MAX_SIZE_FRAMES * 4)
2931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
3031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostruct a2dp_io {
3131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	struct cras_iodev base;
326f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao	struct a2dp_info a2dp;
3331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	struct cras_bt_transport *transport;
3497d900eef92b8c5db6e98072bb7bfe7899edc79bHsin-Yu Chao	a2dp_force_suspend_cb force_suspend_cb;
35c1cd9fc1dfc9e00240ad28571fbae2adea36c628Hsin-Yu Chao	unsigned sock_depth_frames;
3631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
373d316d343d4e80012d2c7d6c5e7e183533e8d7d5Dylan Reid	/* To hold the pcm samples. */
383d316d343d4e80012d2c7d6c5e7e183533e8d7d5Dylan Reid	struct byte_buffer *pcm_buf;
393d316d343d4e80012d2c7d6c5e7e183533e8d7d5Dylan Reid
4095bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid	/* Has the socket been filled once. */
4195bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid	int pre_fill_complete;
42f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao
439f02b64519595d12ec2346ea699c9507b01437c9Hsin-Yu Chao	/* Accumulated frames written to a2dp socket. Will need this info
449f02b64519595d12ec2346ea699c9507b01437c9Hsin-Yu Chao	 * together with the device open time stamp to get how many virtual
459f02b64519595d12ec2346ea699c9507b01437c9Hsin-Yu Chao	 * buffer is queued there.
469f02b64519595d12ec2346ea699c9507b01437c9Hsin-Yu Chao	 */
479f02b64519595d12ec2346ea699c9507b01437c9Hsin-Yu Chao	uint64_t bt_written_frames;
489f02b64519595d12ec2346ea699c9507b01437c9Hsin-Yu Chao	struct timespec dev_open_time;
4931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao};
5031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
5177fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reidstatic int flush_data(void *arg);
5277fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid
5331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostatic int update_supported_formats(struct cras_iodev *iodev)
5431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{
5531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	struct a2dp_io *a2dpio = (struct a2dp_io *)iodev;
5631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	size_t rate = 0;
5731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	size_t channel;
5831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	a2dp_sbc_t a2dp;
5931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
6031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	cras_bt_transport_configuration(a2dpio->transport, &a2dp,
6131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao					sizeof(a2dp));
6231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
6331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->format->format = SND_PCM_FORMAT_S16_LE;
6431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	channel = (a2dp.channel_mode == SBC_CHANNEL_MODE_MONO) ? 1 : 2;
6531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
6631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	if (a2dp.frequency & SBC_SAMPLING_FREQ_48000)
6731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		rate = 48000;
6831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	else if (a2dp.frequency & SBC_SAMPLING_FREQ_44100)
6931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		rate = 44100;
7031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	else if (a2dp.frequency & SBC_SAMPLING_FREQ_32000)
7131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		rate = 32000;
7231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	else if (a2dp.frequency & SBC_SAMPLING_FREQ_16000)
7331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		rate = 16000;
7431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
75639a342fcc14cf262e11612220079aff45f40ad5Dylan Reid	free(iodev->supported_rates);
7631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->supported_rates = (size_t *)malloc(2 * sizeof(rate));
7731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->supported_rates[0] = rate;
7831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->supported_rates[1] = 0;
7931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
80639a342fcc14cf262e11612220079aff45f40ad5Dylan Reid	free(iodev->supported_channel_counts);
8131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->supported_channel_counts = (size_t *)malloc(2 * sizeof(channel));
8231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->supported_channel_counts[0] = channel;
8331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->supported_channel_counts[1] = 0;
8431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
85a485ac04bdfc71e374a3a5d2fbcf4699999a2939Dylan Reid	free(iodev->supported_formats);
86a485ac04bdfc71e374a3a5d2fbcf4699999a2939Dylan Reid	iodev->supported_formats =
87a485ac04bdfc71e374a3a5d2fbcf4699999a2939Dylan Reid		(snd_pcm_format_t *)malloc(2 * sizeof(snd_pcm_format_t));
88a485ac04bdfc71e374a3a5d2fbcf4699999a2939Dylan Reid	iodev->supported_formats[0] = SND_PCM_FORMAT_S16_LE;
89a485ac04bdfc71e374a3a5d2fbcf4699999a2939Dylan Reid	iodev->supported_formats[1] = 0;
90a485ac04bdfc71e374a3a5d2fbcf4699999a2939Dylan Reid
9131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	return 0;
9231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao}
9331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
949f02b64519595d12ec2346ea699c9507b01437c9Hsin-Yu Chao/* Calculates the number of virtual buffer in frames. Assuming all written
959f02b64519595d12ec2346ea699c9507b01437c9Hsin-Yu Chao * buffer is consumed in a constant frame rate at bluetooth device side.
96f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao * Args:
97f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao *    iodev: The a2dp iodev to estimate the queued frames for.
98f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao *    fr: The amount of frames just transmitted.
99f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao */
1009f02b64519595d12ec2346ea699c9507b01437c9Hsin-Yu Chaostatic int bt_queued_frames(const struct cras_iodev *iodev, int fr)
101f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao{
1029f02b64519595d12ec2346ea699c9507b01437c9Hsin-Yu Chao	uint64_t consumed;
103f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	struct a2dp_io *a2dpio = (struct a2dp_io *)iodev;
104f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao
1059f02b64519595d12ec2346ea699c9507b01437c9Hsin-Yu Chao	/* Calculate consumed frames since device has opened */
1069f02b64519595d12ec2346ea699c9507b01437c9Hsin-Yu Chao	a2dpio->bt_written_frames += fr;
1076fa2060737ffe7bd0364cce87bd60861222a174fChinyue Chen	consumed = cras_frames_since_time(&a2dpio->dev_open_time,
1086fa2060737ffe7bd0364cce87bd60861222a174fChinyue Chen					  iodev->format->frame_rate);
109f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao
1109f02b64519595d12ec2346ea699c9507b01437c9Hsin-Yu Chao	if (a2dpio->bt_written_frames > consumed)
1119f02b64519595d12ec2346ea699c9507b01437c9Hsin-Yu Chao		return a2dpio->bt_written_frames - consumed;
112f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	else
1139f02b64519595d12ec2346ea699c9507b01437c9Hsin-Yu Chao		return 0;
114f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao}
115f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao
1163d316d343d4e80012d2c7d6c5e7e183533e8d7d5Dylan Reid
11731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostatic int frames_queued(const struct cras_iodev *iodev)
11831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{
119f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao	struct a2dp_io *a2dpio = (struct a2dp_io *)iodev;
12070c72e44ad8a2a7d8fb51cd668f36d6d8021e422Hsin-Yu Chao	int estimate_queued_frames = bt_queued_frames(iodev, 0);
12170c72e44ad8a2a7d8fb51cd668f36d6d8021e422Hsin-Yu Chao	int local_queued_frames =
12270c72e44ad8a2a7d8fb51cd668f36d6d8021e422Hsin-Yu Chao			a2dp_queued_frames(&a2dpio->a2dp) +
12370c72e44ad8a2a7d8fb51cd668f36d6d8021e422Hsin-Yu Chao			buf_queued_bytes(a2dpio->pcm_buf) /
12470c72e44ad8a2a7d8fb51cd668f36d6d8021e422Hsin-Yu Chao				cras_get_format_bytes(iodev->format);
12570c72e44ad8a2a7d8fb51cd668f36d6d8021e422Hsin-Yu Chao
12670c72e44ad8a2a7d8fb51cd668f36d6d8021e422Hsin-Yu Chao	return MIN(iodev->buffer_size,
12770c72e44ad8a2a7d8fb51cd668f36d6d8021e422Hsin-Yu Chao		   MAX(estimate_queued_frames, local_queued_frames));
12831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao}
12931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
13031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostatic int open_dev(struct cras_iodev *iodev)
13131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{
13231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	struct a2dp_io *a2dpio = (struct a2dp_io *)iodev;
133e5c801e32174b718f7e36ba07d67753af71f2e76Dylan Reid	int sock_depth;
134e5c801e32174b718f7e36ba07d67753af71f2e76Dylan Reid	int err;
13531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
13631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	err = cras_bt_transport_acquire(a2dpio->transport);
13731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	if (err < 0) {
13831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		syslog(LOG_ERR, "transport_acquire failed");
13931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		return err;
14031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	}
14131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
14231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	/* Assert format is set before opening device. */
14331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	if (iodev->format == NULL)
14431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		return -EINVAL;
14531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->format->format = SND_PCM_FORMAT_S16_LE;
1469690a3281b7167e5a38368fd8db39375bea8a1f8Hsin-Yu Chao	cras_iodev_init_audio_area(iodev, iodev->format->num_channels);
14731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
1483d316d343d4e80012d2c7d6c5e7e183533e8d7d5Dylan Reid	a2dpio->pcm_buf = byte_buffer_create(PCM_BUF_MAX_SIZE_BYTES);
1493d316d343d4e80012d2c7d6c5e7e183533e8d7d5Dylan Reid	if (!a2dpio->pcm_buf)
1503d316d343d4e80012d2c7d6c5e7e183533e8d7d5Dylan Reid		return -ENOMEM;
1513d316d343d4e80012d2c7d6c5e7e183533e8d7d5Dylan Reid
15277fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid	iodev->buffer_size = PCM_BUF_MAX_SIZE_FRAMES;
153c1cd9fc1dfc9e00240ad28571fbae2adea36c628Hsin-Yu Chao
154c1cd9fc1dfc9e00240ad28571fbae2adea36c628Hsin-Yu Chao	/* Set up the socket to hold two MTUs full of data before returning
155c1cd9fc1dfc9e00240ad28571fbae2adea36c628Hsin-Yu Chao	 * EAGAIN.  This will allow the write to be throttled when a reasonable
156c1cd9fc1dfc9e00240ad28571fbae2adea36c628Hsin-Yu Chao	 * amount of data is queued. */
157c1cd9fc1dfc9e00240ad28571fbae2adea36c628Hsin-Yu Chao	sock_depth = 2 * cras_bt_transport_write_mtu(a2dpio->transport);
158c1cd9fc1dfc9e00240ad28571fbae2adea36c628Hsin-Yu Chao	setsockopt(cras_bt_transport_fd(a2dpio->transport),
159c1cd9fc1dfc9e00240ad28571fbae2adea36c628Hsin-Yu Chao		   SOL_SOCKET, SO_SNDBUF, &sock_depth, sizeof(sock_depth));
160c1cd9fc1dfc9e00240ad28571fbae2adea36c628Hsin-Yu Chao
161c1cd9fc1dfc9e00240ad28571fbae2adea36c628Hsin-Yu Chao	a2dpio->sock_depth_frames =
162c1cd9fc1dfc9e00240ad28571fbae2adea36c628Hsin-Yu Chao		a2dp_block_size(&a2dpio->a2dp,
163c1cd9fc1dfc9e00240ad28571fbae2adea36c628Hsin-Yu Chao				cras_bt_transport_write_mtu(a2dpio->transport))
164c1cd9fc1dfc9e00240ad28571fbae2adea36c628Hsin-Yu Chao			/ cras_get_format_bytes(iodev->format) * 2;
165c1cd9fc1dfc9e00240ad28571fbae2adea36c628Hsin-Yu Chao	iodev->min_buffer_level = a2dpio->sock_depth_frames;
166c1cd9fc1dfc9e00240ad28571fbae2adea36c628Hsin-Yu Chao
16795bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid	a2dpio->pre_fill_complete = 0;
168f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao
1699f02b64519595d12ec2346ea699c9507b01437c9Hsin-Yu Chao	/* Initialize variables for bt_queued_frames() */
1709f02b64519595d12ec2346ea699c9507b01437c9Hsin-Yu Chao	a2dpio->bt_written_frames = 0;
171cd23b811ccefce5cd01335c3a2c98a443bc14024Dylan Reid	clock_gettime(CLOCK_MONOTONIC_RAW, &a2dpio->dev_open_time);
1729f02b64519595d12ec2346ea699c9507b01437c9Hsin-Yu Chao
17377fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid	audio_thread_add_write_callback(cras_bt_transport_fd(a2dpio->transport),
17477fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid					flush_data, iodev);
17577fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid	audio_thread_enable_callback(cras_bt_transport_fd(a2dpio->transport),
17677fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid				     0);
17731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	return 0;
17831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao}
17931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
18031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostatic int close_dev(struct cras_iodev *iodev)
18131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{
18231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	int err;
18331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	struct a2dp_io *a2dpio = (struct a2dp_io *)iodev;
18431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
18531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	if (!a2dpio->transport)
18631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		return 0;
18731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
18877fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid	audio_thread_rm_callback(cras_bt_transport_fd(a2dpio->transport));
18977fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid
19031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	err = cras_bt_transport_release(a2dpio->transport);
19131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	if (err < 0)
19231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		syslog(LOG_ERR, "transport_release failed");
19331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
1946f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao	a2dp_drain(&a2dpio->a2dp);
1953d316d343d4e80012d2c7d6c5e7e183533e8d7d5Dylan Reid	byte_buffer_destroy(a2dpio->pcm_buf);
19631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	cras_iodev_free_format(iodev);
1979690a3281b7167e5a38368fd8db39375bea8a1f8Hsin-Yu Chao	cras_iodev_free_audio_area(iodev);
19831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	return 0;
19931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao}
20031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
20131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostatic int is_open(const struct cras_iodev *iodev)
20231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{
20331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	struct a2dp_io *a2dpio = (struct a2dp_io *)iodev;
20431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	return cras_bt_transport_fd(a2dpio->transport) > 0;
20531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao}
20631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
20795bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reidstatic int pre_fill_socket(struct a2dp_io *a2dpio)
20895bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid{
20995bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid	static const uint16_t zero_buffer[1024 * 2];
21095bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid	int processed;
21195bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid	int written = 0;
21295bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid
21395bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid	while (1) {
21495bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid		processed = a2dp_encode(
21595bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid				&a2dpio->a2dp,
21695bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid				zero_buffer,
21795bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid				sizeof(zero_buffer),
21895bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid				cras_get_format_bytes(a2dpio->base.format),
21995bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid				cras_bt_transport_write_mtu(a2dpio->transport));
22095bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid		if (processed < 0)
22195bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid			return processed;
22295bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid		if (processed == 0)
22395bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid			break;
22495bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid
22595bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid		written = a2dp_write(
22695bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid				&a2dpio->a2dp,
22795bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid				cras_bt_transport_fd(a2dpio->transport),
22895bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid				cras_bt_transport_write_mtu(a2dpio->transport));
22995bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid		/* Full when EAGAIN is returned. */
23095bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid		if (written == -EAGAIN)
23195bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid			break;
23295bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid		else if (written < 0)
23395bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid			return written;
23495bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid		else if (written == 0)
23595bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid			break;
23695bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid	};
23795bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid
238d313f15b63753cb0324fd424ed6d2b9cac71b098Hsin-Yu Chao	a2dp_drain(&a2dpio->a2dp);
23995bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid	return 0;
24095bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid}
24195bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid
242cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao/* Flushes queued buffer, including pcm and a2dp buffer.
24385cc54d7c2bf9a24abbc5518297bf5aacd91c47bHsin-Yu Chao * Returns:
24485cc54d7c2bf9a24abbc5518297bf5aacd91c47bHsin-Yu Chao *    0 when the flush succeeded, -1 when error occurred.
245cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao */
24677fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reidstatic int flush_data(void *arg)
247cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao{
24877fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid	const struct cras_iodev *iodev = (const struct cras_iodev *)arg;
249cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao	int processed;
250cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao	size_t format_bytes;
2512509f106abb44aa2f0dca35a28c47cce8459da5dHsin-Yu Chao	int err = 0;
252cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao	int written = 0;
253cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao	struct a2dp_io *a2dpio;
254cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao
255cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao	a2dpio = (struct a2dp_io *)iodev;
256cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao	format_bytes = cras_get_format_bytes(iodev->format);
257cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao
25877fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reidencode_more:
25901d37ad909523378f12ecf939419829134aec32fDylan Reid	while (buf_queued_bytes(a2dpio->pcm_buf)) {
26027089cd9e476fff3c1d82622f17a23a80da0fd51Dylan Reid		processed = a2dp_encode(
26127089cd9e476fff3c1d82622f17a23a80da0fd51Dylan Reid				&a2dpio->a2dp,
26201d37ad909523378f12ecf939419829134aec32fDylan Reid				buf_read_pointer(a2dpio->pcm_buf),
26301d37ad909523378f12ecf939419829134aec32fDylan Reid				buf_readable_bytes(a2dpio->pcm_buf),
26401d37ad909523378f12ecf939419829134aec32fDylan Reid				format_bytes,
26527089cd9e476fff3c1d82622f17a23a80da0fd51Dylan Reid				cras_bt_transport_write_mtu(a2dpio->transport));
266192f5007487e47d4b1e3ba9d2df95d11fcd01d4eVadim Kharchenko		ATLOG(atlog, AUDIO_THREAD_A2DP_ENCODE,
267c9452136e619b69333dc3bd5fb87e5168793c9c0Dylan Reid					    processed,
268c9452136e619b69333dc3bd5fb87e5168793c9c0Dylan Reid					    buf_queued_bytes(a2dpio->pcm_buf),
269c9452136e619b69333dc3bd5fb87e5168793c9c0Dylan Reid					    buf_readable_bytes(a2dpio->pcm_buf)
270c9452136e619b69333dc3bd5fb87e5168793c9c0Dylan Reid					    );
27177fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid		if (processed == -ENOSPC || processed == 0)
27227089cd9e476fff3c1d82622f17a23a80da0fd51Dylan Reid			break;
27377fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid		if (processed < 0)
27477fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid			return 0;
27501d37ad909523378f12ecf939419829134aec32fDylan Reid
27677fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid		buf_increment_read(a2dpio->pcm_buf, processed);
277cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao	}
27885cc54d7c2bf9a24abbc5518297bf5aacd91c47bHsin-Yu Chao
27977fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid	written = a2dp_write(&a2dpio->a2dp,
28077fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid			     cras_bt_transport_fd(a2dpio->transport),
28177fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid			     cras_bt_transport_write_mtu(a2dpio->transport));
282192f5007487e47d4b1e3ba9d2df95d11fcd01d4eVadim Kharchenko	ATLOG(atlog, AUDIO_THREAD_A2DP_WRITE,
283c9452136e619b69333dc3bd5fb87e5168793c9c0Dylan Reid				    written,
284c9452136e619b69333dc3bd5fb87e5168793c9c0Dylan Reid				    a2dp_queued_frames(&a2dpio->a2dp), 0);
28577fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid	if (written == -EAGAIN) {
28677fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid		audio_thread_enable_callback(
28777fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid				cras_bt_transport_fd(a2dpio->transport), 1);
28877fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid		return 0;
28977fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid	} else if (written < 0) {
29077fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid		if (a2dpio->force_suspend_cb)
29177fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid			a2dpio->force_suspend_cb(&a2dpio->base);
2922509f106abb44aa2f0dca35a28c47cce8459da5dHsin-Yu Chao		err = written;
29377fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid		goto write_done;
29477fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid	} else if (written == 0) {
29577fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid		goto write_done;
29677fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid	}
29777fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid
29877fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid	if (buf_queued_bytes(a2dpio->pcm_buf))
29977fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid		goto encode_more;
30077fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid
30177fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reidwrite_done:
30277fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid	/* everything written. */
30377fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid	audio_thread_enable_callback(
30477fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid			cras_bt_transport_fd(a2dpio->transport), 0);
30577fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid
3062509f106abb44aa2f0dca35a28c47cce8459da5dHsin-Yu Chao	return err;
307cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao}
308cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao
30931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostatic int dev_running(const struct cras_iodev *iodev)
31031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{
31177fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid	return is_open(iodev);
31231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao}
31331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
31431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostatic int delay_frames(const struct cras_iodev *iodev)
31531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{
31677fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid	const struct a2dp_io *a2dpio = (struct a2dp_io *)iodev;
31777fb304248eb69a39c0d087b2a6ab91d49d5d498Dylan Reid
318e5c801e32174b718f7e36ba07d67753af71f2e76Dylan Reid	/* The number of frames in the pcm buffer plus two mtu packets */
319c1cd9fc1dfc9e00240ad28571fbae2adea36c628Hsin-Yu Chao	return frames_queued(iodev) + a2dpio->sock_depth_frames;
32031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao}
32131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
322cc32f2cfb655c1c2a39a1db448415583f8ecc2d0Hsin-Yu Chaostatic int get_buffer(struct cras_iodev *iodev,
323cc32f2cfb655c1c2a39a1db448415583f8ecc2d0Hsin-Yu Chao		      struct cras_audio_area **area,
324cc32f2cfb655c1c2a39a1db448415583f8ecc2d0Hsin-Yu Chao		      unsigned *frames)
32531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{
32631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	size_t format_bytes;
32731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	struct a2dp_io *a2dpio;
32815e137c3cc39fafffc303b5612de7a4de7a27982Hsin-Yu Chao
32931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	a2dpio = (struct a2dp_io *)iodev;
33031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
33131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	format_bytes = cras_get_format_bytes(iodev->format);
33231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
333cc32f2cfb655c1c2a39a1db448415583f8ecc2d0Hsin-Yu Chao	if (iodev->direction != CRAS_STREAM_OUTPUT)
334cc32f2cfb655c1c2a39a1db448415583f8ecc2d0Hsin-Yu Chao		return 0;
335cc32f2cfb655c1c2a39a1db448415583f8ecc2d0Hsin-Yu Chao
3363d316d343d4e80012d2c7d6c5e7e183533e8d7d5Dylan Reid	*frames = MIN(*frames, buf_writable_bytes(a2dpio->pcm_buf) /
3373d316d343d4e80012d2c7d6c5e7e183533e8d7d5Dylan Reid					format_bytes);
338cc32f2cfb655c1c2a39a1db448415583f8ecc2d0Hsin-Yu Chao	iodev->area->frames = *frames;
339cc32f2cfb655c1c2a39a1db448415583f8ecc2d0Hsin-Yu Chao	cras_audio_area_config_buf_pointers(
340cc32f2cfb655c1c2a39a1db448415583f8ecc2d0Hsin-Yu Chao			iodev->area, iodev->format,
3413d316d343d4e80012d2c7d6c5e7e183533e8d7d5Dylan Reid			buf_write_pointer(a2dpio->pcm_buf));
342cc32f2cfb655c1c2a39a1db448415583f8ecc2d0Hsin-Yu Chao	*area = iodev->area;
34331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	return 0;
34431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao}
34531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
34631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostatic int put_buffer(struct cras_iodev *iodev, unsigned nwritten)
34731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{
34895bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid	size_t written_bytes;
34931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	size_t format_bytes;
35031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	struct a2dp_io *a2dpio = (struct a2dp_io *)iodev;
351f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao
35231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	format_bytes = cras_get_format_bytes(iodev->format);
35395bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid	written_bytes = nwritten * format_bytes;
35431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
35595bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid	if (written_bytes > buf_writable_bytes(a2dpio->pcm_buf))
3563d316d343d4e80012d2c7d6c5e7e183533e8d7d5Dylan Reid		return -EINVAL;
3573d316d343d4e80012d2c7d6c5e7e183533e8d7d5Dylan Reid
35895bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid	buf_increment_write(a2dpio->pcm_buf, written_bytes);
35995bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid
36095bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid	bt_queued_frames(iodev, nwritten);
36195bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid
36295bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid	/* Until the minimum number of frames have been queued, don't send
36395bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid	 * anything. */
36495bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid	if (!a2dpio->pre_fill_complete) {
36595bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid		pre_fill_socket(a2dpio);
36695bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid		a2dpio->pre_fill_complete = 1;
36795bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid		/* Start measuring frames_consumed from now. */
368cd23b811ccefce5cd01335c3a2c98a443bc14024Dylan Reid		clock_gettime(CLOCK_MONOTONIC_RAW, &a2dpio->dev_open_time);
36995bb35a0c39e45ff54983eedd61eb4c07d4ffad7Dylan Reid	}
3706f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao
3712509f106abb44aa2f0dca35a28c47cce8459da5dHsin-Yu Chao	return flush_data(iodev);
37231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao}
37331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
3743f787ac37a53be6b3a065ee5d1a47427fae78100Hsin-Yu Chaostatic int flush_buffer(struct cras_iodev *iodev)
3753f787ac37a53be6b3a065ee5d1a47427fae78100Hsin-Yu Chao{
3763f787ac37a53be6b3a065ee5d1a47427fae78100Hsin-Yu Chao	return 0;
3773f787ac37a53be6b3a065ee5d1a47427fae78100Hsin-Yu Chao}
3783f787ac37a53be6b3a065ee5d1a47427fae78100Hsin-Yu Chao
379bb28140f38fdf6627ec26696c943dfa4f9188450Hsin-Yu Chaostatic void update_active_node(struct cras_iodev *iodev, unsigned node_idx)
3800b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao{
3810b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao}
3820b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao
38331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaovoid free_resources(struct a2dp_io *a2dpio)
38431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{
3850b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao	struct cras_ionode *node;
3860b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao
3870b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao	node = a2dpio->base.active_node;
3880b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao	if (node) {
3890b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao		cras_iodev_rm_node(&a2dpio->base, node);
3900b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao		free(node);
3910b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao	}
39231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	free(a2dpio->base.supported_channel_counts);
39331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	free(a2dpio->base.supported_rates);
3946f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao	destroy_a2dp(&a2dpio->a2dp);
39531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao}
39631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
39797d900eef92b8c5db6e98072bb7bfe7899edc79bHsin-Yu Chaostruct cras_iodev *a2dp_iodev_create(struct cras_bt_transport *transport,
39897d900eef92b8c5db6e98072bb7bfe7899edc79bHsin-Yu Chao				     a2dp_force_suspend_cb force_suspend_cb)
39931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{
40031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	int err;
40131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	struct a2dp_io *a2dpio;
40231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	struct cras_iodev *iodev;
40331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	struct cras_ionode *node;
4041cbde1fb3f2aad5494f33d49dacaeafebc753ac2Hsin-Yu Chao	a2dp_sbc_t a2dp;
405dd2f666a53a1090744819bf38cd672b4548aca22Hsin-Yu Chao	struct cras_bt_device *device;
40608a60dcbe8a2c2f20146bab0b281c1de85bc68ccHsin-Yu Chao	const char *name;
40731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
40831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	a2dpio = (struct a2dp_io *)calloc(1, sizeof(*a2dpio));
40931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	if (!a2dpio)
41031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		goto error;
41131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
4121cbde1fb3f2aad5494f33d49dacaeafebc753ac2Hsin-Yu Chao	a2dpio->transport = transport;
4131cbde1fb3f2aad5494f33d49dacaeafebc753ac2Hsin-Yu Chao	cras_bt_transport_configuration(a2dpio->transport, &a2dp,
4141cbde1fb3f2aad5494f33d49dacaeafebc753ac2Hsin-Yu Chao					sizeof(a2dp));
4156f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao	err = init_a2dp(&a2dpio->a2dp, &a2dp);
4166f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao	if (err) {
4176f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao		syslog(LOG_ERR, "Fail to init a2dp");
4186f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao		goto error;
4196f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao	}
42097d900eef92b8c5db6e98072bb7bfe7899edc79bHsin-Yu Chao	a2dpio->force_suspend_cb = force_suspend_cb;
4211cbde1fb3f2aad5494f33d49dacaeafebc753ac2Hsin-Yu Chao
42231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev = &a2dpio->base;
42331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
42431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	/* A2DP only does output now */
42531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->direction = CRAS_STREAM_OUTPUT;
42631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
427dd2f666a53a1090744819bf38cd672b4548aca22Hsin-Yu Chao	/* Set iodev's name by bluetooth device's readable name, if
428dd2f666a53a1090744819bf38cd672b4548aca22Hsin-Yu Chao	 * the readable name is not available, use address instead.
429dd2f666a53a1090744819bf38cd672b4548aca22Hsin-Yu Chao	 */
430dd2f666a53a1090744819bf38cd672b4548aca22Hsin-Yu Chao	device = cras_bt_transport_device(transport);
43108a60dcbe8a2c2f20146bab0b281c1de85bc68ccHsin-Yu Chao	name = cras_bt_device_name(device);
43208a60dcbe8a2c2f20146bab0b281c1de85bc68ccHsin-Yu Chao	if (!name)
43308a60dcbe8a2c2f20146bab0b281c1de85bc68ccHsin-Yu Chao		name = cras_bt_transport_object_path(a2dpio->transport);
43431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
43508a60dcbe8a2c2f20146bab0b281c1de85bc68ccHsin-Yu Chao	snprintf(iodev->info.name, sizeof(iodev->info.name), "%s", name);
43631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->info.name[ARRAY_SIZE(iodev->info.name) - 1] = '\0';
43785137d0c83307ebbfa890e8a64446de5957fbbbcChinyue Chen	iodev->info.stable_id = SuperFastHash(
438538e024653d4052dbadddcde55da44c0395c3a42Hsin-Yu Chao			cras_bt_device_object_path(device),
439538e024653d4052dbadddcde55da44c0395c3a42Hsin-Yu Chao			strlen(cras_bt_device_object_path(device)),
440538e024653d4052dbadddcde55da44c0395c3a42Hsin-Yu Chao			strlen(cras_bt_device_object_path(device)));
44131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
44231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->open_dev = open_dev;
44331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->is_open = is_open; /* Needed by thread_add_stream */
44431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->frames_queued = frames_queued;
44531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->dev_running = dev_running;
44631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->delay_frames = delay_frames;
44731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->get_buffer = get_buffer;
44831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->put_buffer = put_buffer;
4493f787ac37a53be6b3a065ee5d1a47427fae78100Hsin-Yu Chao	iodev->flush_buffer = flush_buffer;
45031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->close_dev = close_dev;
45131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	iodev->update_supported_formats = update_supported_formats;
4520b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao	iodev->update_active_node = update_active_node;
453a7892d9129d4cdb25dbd099aa2f5295bd53120dfHsin-Yu Chao	iodev->software_volume_needed = 1;
45431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
45531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	/* Create a dummy ionode */
45631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	node = (struct cras_ionode *)calloc(1, sizeof(*node));
45731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	node->dev = iodev;
45831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	strcpy(node->name, iodev->info.name);
45931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	node->plugged = 1;
4600b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao	node->type = CRAS_NODE_TYPE_BLUETOOTH;
461b7fb7aad1bb54683361c3beda234e01bcf455becDylan Reid	node->volume = 100;
46231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	gettimeofday(&node->plugged_time, NULL);
46331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
46431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	/* A2DP does output only */
465ddecc26b70fc359d2100c2e3e742c464b6c38226Hsin-Yu Chao	cras_bt_device_append_iodev(device, iodev,
466ddecc26b70fc359d2100c2e3e742c464b6c38226Hsin-Yu Chao			cras_bt_transport_profile(a2dpio->transport));
4670b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao	cras_iodev_add_node(iodev, node);
4680b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao	cras_iodev_set_active_node(iodev, node);
4690b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao
47031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	return iodev;
47131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaoerror:
47231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	if (a2dpio) {
47331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		free_resources(a2dpio);
47431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao		free(a2dpio);
47531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	}
47631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	return NULL;
47731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao}
47831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
47931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaovoid a2dp_iodev_destroy(struct cras_iodev *iodev)
48031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{
48131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	struct a2dp_io *a2dpio = (struct a2dp_io *)iodev;
482ddecc26b70fc359d2100c2e3e742c464b6c38226Hsin-Yu Chao	struct cras_bt_device *device;
483ddecc26b70fc359d2100c2e3e742c464b6c38226Hsin-Yu Chao
484ddecc26b70fc359d2100c2e3e742c464b6c38226Hsin-Yu Chao	device = cras_bt_transport_device(a2dpio->transport);
48531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao
48631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao	/* A2DP does output only */
487ddecc26b70fc359d2100c2e3e742c464b6c38226Hsin-Yu Chao	cras_bt_device_rm_iodev(device, iodev);
4880fc4865c82dd7a07d978c598ec7f2d108a8a3279Hsin-Yu Chao
4890fc4865c82dd7a07d978c598ec7f2d108a8a3279Hsin-Yu Chao	/* Free resources when device successfully removed. */
4900fc4865c82dd7a07d978c598ec7f2d108a8a3279Hsin-Yu Chao	free_resources(a2dpio);
491a854651b825010352a05f55e720e29bdca6fb1baDylan Reid	cras_iodev_free_resources(iodev);
4920fc4865c82dd7a07d978c598ec7f2d108a8a3279Hsin-Yu Chao	free(a2dpio);
49331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao}
494