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