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