cras_a2dp_iodev.c revision dd2f666a53a1090744819bf38cd672b4548aca22
131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved. 231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao * Use of this source code is governed by a BSD-style license that can be 331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao * found in the LICENSE file. 431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao */ 531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao#include <stdint.h> 731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao#include <sys/socket.h> 831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao#include <syslog.h> 9f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao#include <time.h> 1031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 111cbde1fb3f2aad5494f33d49dacaeafebc753ac2Hsin-Yu Chao#include "cras_a2dp_info.h" 1231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao#include "cras_a2dp_iodev.h" 13dd2f666a53a1090744819bf38cd672b4548aca22Hsin-Yu Chao#include "cras_bt_device.h" 1431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao#include "cras_iodev.h" 1531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao#include "cras_iodev_list.h" 1631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao#include "cras_util.h" 17f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao#include "rtp.h" 1831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao#include "utlist.h" 1931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 2038cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao#define PCM_BUF_MAX_SIZE_BYTES 1024 2131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 2231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostruct a2dp_io { 2331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao struct cras_iodev base; 246f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao struct a2dp_info a2dp; 2531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao struct cras_bt_transport *transport; 2631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 2738cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao uint8_t pcm_buf[PCM_BUF_MAX_SIZE_BYTES]; 2838cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao int pcm_buf_offset; 2938cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao int pcm_buf_size; 3031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao int pcm_buf_used; 31f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao 32f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao int bt_queued_frames; 33f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao struct timespec bt_queued_fr_last_update; 3431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao}; 3531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 3631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostatic int update_supported_formats(struct cras_iodev *iodev) 3731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{ 3831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao struct a2dp_io *a2dpio = (struct a2dp_io *)iodev; 3931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao size_t rate = 0; 4031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao size_t channel; 4131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao a2dp_sbc_t a2dp; 4231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 4331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao cras_bt_transport_configuration(a2dpio->transport, &a2dp, 4431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao sizeof(a2dp)); 4531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 4631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao iodev->format->format = SND_PCM_FORMAT_S16_LE; 4731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao channel = (a2dp.channel_mode == SBC_CHANNEL_MODE_MONO) ? 1 : 2; 4831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 4931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao if (a2dp.frequency & SBC_SAMPLING_FREQ_48000) 5031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao rate = 48000; 5131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao else if (a2dp.frequency & SBC_SAMPLING_FREQ_44100) 5231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao rate = 44100; 5331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao else if (a2dp.frequency & SBC_SAMPLING_FREQ_32000) 5431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao rate = 32000; 5531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao else if (a2dp.frequency & SBC_SAMPLING_FREQ_16000) 5631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao rate = 16000; 5731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 58639a342fcc14cf262e11612220079aff45f40ad5Dylan Reid free(iodev->supported_rates); 5931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao iodev->supported_rates = (size_t *)malloc(2 * sizeof(rate)); 6031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao iodev->supported_rates[0] = rate; 6131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao iodev->supported_rates[1] = 0; 6231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 63639a342fcc14cf262e11612220079aff45f40ad5Dylan Reid free(iodev->supported_channel_counts); 6431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao iodev->supported_channel_counts = (size_t *)malloc(2 * sizeof(channel)); 6531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao iodev->supported_channel_counts[0] = channel; 6631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao iodev->supported_channel_counts[1] = 0; 6731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 6831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao return 0; 6931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao} 7031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 71f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao/* Calculates the amount of consumed frames since given time. 72f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao */ 73f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chaostatic unsigned long frames_since(struct timespec ts, size_t rate) 74f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao{ 75f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao struct timespec te, diff; 76f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao 77f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao clock_gettime(CLOCK_MONOTONIC, &te); 78f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao subtract_timespecs(&te, &ts, &diff); 79f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao return diff.tv_sec * rate + diff.tv_nsec / (1000000000L / rate); 80f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao} 81f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao 82f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao/* Maintains a virtual buffer for transmitted frames, assume this buffer is 83f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao * consumed at the same frame rate at bluetooth device side. 84f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao * Args: 85f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao * iodev: The a2dp iodev to estimate the queued frames for. 86f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao * fr: The amount of frames just transmitted. 87f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao */ 88f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chaostatic int get_bt_queued_frames(const struct cras_iodev *iodev, int fr) 89f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao{ 90f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao unsigned long consumed; 91f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao struct a2dp_io *a2dpio = (struct a2dp_io *)iodev; 92f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao 93f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao /* Calculate consumed frames since last update time, also update 94f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao * the last update time. 95f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao */ 96f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao consumed = frames_since(a2dpio->bt_queued_fr_last_update, 97f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao iodev->format->frame_rate); 98f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao clock_gettime(CLOCK_MONOTONIC, &a2dpio->bt_queued_fr_last_update); 99f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao 100f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao if (a2dpio->bt_queued_frames > consumed) 101f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao a2dpio->bt_queued_frames -= consumed; 102f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao else 103f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao a2dpio->bt_queued_frames = 0; 104f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao 105f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao a2dpio->bt_queued_frames += fr; 106f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao 107f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao return a2dpio->bt_queued_frames; 108f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao} 109f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao 11031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostatic int frames_queued(const struct cras_iodev *iodev) 11131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{ 112f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao size_t format_bytes; 113f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao int frames; 114f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao struct a2dp_io *a2dpio = (struct a2dp_io *)iodev; 115f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao 116f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao format_bytes = cras_get_format_bytes(iodev->format); 117f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao 118f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao frames = a2dpio->pcm_buf_used / format_bytes 119f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao + a2dp_queued_frames(&a2dpio->a2dp) 120f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao + get_bt_queued_frames(iodev, 0); 121f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao 122f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao return frames; 12331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao} 12431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 125f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao 12631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostatic int open_dev(struct cras_iodev *iodev) 12731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{ 128f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao int err = 0, block_size; 129f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao size_t format_bytes; 13031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao struct a2dp_io *a2dpio = (struct a2dp_io *)iodev; 13131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 13231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao err = cras_bt_transport_acquire(a2dpio->transport); 13331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao if (err < 0) { 13431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao syslog(LOG_ERR, "transport_acquire failed"); 13531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao return err; 13631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao } 13731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 13831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao /* Assert format is set before opening device. */ 13931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao if (iodev->format == NULL) 14031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao return -EINVAL; 14131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao iodev->format->format = SND_PCM_FORMAT_S16_LE; 142f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao format_bytes = cras_get_format_bytes(iodev->format); 14331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 144f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao /* Back calculate the max size of a2dp block before encode. */ 145f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao block_size = a2dp_block_size( 146f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao &a2dpio->a2dp, 147f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao cras_bt_transport_write_mtu(a2dpio->transport) - 148f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao sizeof(struct rtp_header) - 149f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao sizeof(struct rtp_payload)); 150f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao 151f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao /* Assert pcm_buf_size be multiple of codesize */ 152f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao a2dpio->pcm_buf_size = PCM_BUF_MAX_SIZE_BYTES 153f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao / a2dp_codesize(&a2dpio->a2dp) 154f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao * a2dp_codesize(&a2dpio->a2dp); 155f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao iodev->buffer_size = (a2dpio->pcm_buf_size + block_size) / format_bytes; 15631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao if (iodev->used_size > iodev->buffer_size) 15731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao iodev->used_size = iodev->buffer_size; 158f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao 159f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao syslog(LOG_DEBUG, "a2dp iodev buf size %lu, used size %lu", 160f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao iodev->buffer_size, iodev->used_size); 161f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao 16231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao return 0; 16331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao} 16431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 16531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostatic int close_dev(struct cras_iodev *iodev) 16631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{ 16731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao int err; 16831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao struct a2dp_io *a2dpio = (struct a2dp_io *)iodev; 16931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 17031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao if (!a2dpio->transport) 17131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao return 0; 17231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 17331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao err = cras_bt_transport_release(a2dpio->transport); 17431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao if (err < 0) 17531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao syslog(LOG_ERR, "transport_release failed"); 17631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 1776f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao a2dp_drain(&a2dpio->a2dp); 17831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao a2dpio->pcm_buf_used = 0; 17931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao cras_iodev_free_format(iodev); 18031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao return 0; 18131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao} 18231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 18331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostatic int is_open(const struct cras_iodev *iodev) 18431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{ 18531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao struct a2dp_io *a2dpio = (struct a2dp_io *)iodev; 18631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao return cras_bt_transport_fd(a2dpio->transport) > 0; 18731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao} 18831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 189cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao/* Flushes queued buffer, including pcm and a2dp buffer. 190cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao */ 191cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chaostatic void flush_data(const struct cras_iodev *iodev) 192cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao{ 193cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao int processed; 194cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao size_t format_bytes; 195cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao int written = 0; 196cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao struct a2dp_io *a2dpio; 197cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao 198cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao a2dpio = (struct a2dp_io *)iodev; 199cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao format_bytes = cras_get_format_bytes(iodev->format); 200cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao 201cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao processed = a2dp_write(a2dpio->pcm_buf + a2dpio->pcm_buf_offset, 202cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao a2dpio->pcm_buf_used, 203cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao &a2dpio->a2dp, 204cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao format_bytes, 205cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao cras_bt_transport_fd(a2dpio->transport), 206cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao cras_bt_transport_write_mtu(a2dpio->transport), 207cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao &written); 208cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao 209cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao if (a2dpio->pcm_buf_used == processed) { 210cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao a2dpio->pcm_buf_offset = 0; 211cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao a2dpio->pcm_buf_used = 0; 212cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao } else { 213cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao a2dpio->pcm_buf_offset += processed; 214cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao a2dpio->pcm_buf_used -= processed; 215cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao } 216cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao 217cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao if (written == -EAGAIN) { 218cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao syslog(LOG_ERR, "a2dp_write error"); 219cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao return; 220cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao } 221cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao get_bt_queued_frames(iodev, 222cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao a2dp_block_size(&a2dpio->a2dp, written) 223cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao / format_bytes); 224cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao} 225cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao 22631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostatic int dev_running(const struct cras_iodev *iodev) 22731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{ 228cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao // Flush queued buffer when dev is open. 229cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao if (is_open(iodev)) 230cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao flush_data(iodev); 231cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao return 0; 23231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao} 23331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 23431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostatic int delay_frames(const struct cras_iodev *iodev) 23531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{ 236f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao return frames_queued(iodev); 23731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao} 23831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 23931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostatic int get_buffer(struct cras_iodev *iodev, uint8_t **dst, unsigned *frames) 24031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{ 24131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao size_t format_bytes; 24231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao struct a2dp_io *a2dpio; 24331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao a2dpio = (struct a2dp_io *)iodev; 24431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 24531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao format_bytes = cras_get_format_bytes(iodev->format); 24631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 24731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao if (iodev->direction == CRAS_STREAM_OUTPUT) { 24838cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao *dst = a2dpio->pcm_buf + a2dpio->pcm_buf_offset 24938cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao + a2dpio->pcm_buf_used; 25038cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao *frames = (a2dpio->pcm_buf_size - a2dpio->pcm_buf_offset - 25138cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao a2dpio->pcm_buf_used) / format_bytes; 25231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao } 25331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao return 0; 25431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao} 25531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 25631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostatic int put_buffer(struct cras_iodev *iodev, unsigned nwritten) 25731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{ 25831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao size_t format_bytes; 25931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao struct a2dp_io *a2dpio = (struct a2dp_io *)iodev; 260f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao 26131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao format_bytes = cras_get_format_bytes(iodev->format); 26231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 26338cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao if (a2dpio->pcm_buf_used + a2dpio->pcm_buf_offset + 26438cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao nwritten * format_bytes > a2dpio->pcm_buf_size) 26531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao return -1; 26631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao a2dpio->pcm_buf_used += nwritten * format_bytes; 2676f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao 268cc6d9b913cf7e16db85d55d2adf90e4077ffab76Hsin-Yu Chao flush_data(iodev); 26931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao return 0; 27031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao} 27131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 2720b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chaostatic void update_active_node(struct cras_iodev *iodev) 2730b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao{ 2740b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao} 2750b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao 27631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaovoid free_resources(struct a2dp_io *a2dpio) 27731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{ 2780b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao struct cras_ionode *node; 2790b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao 2800b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao node = a2dpio->base.active_node; 2810b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao if (node) { 2820b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao cras_iodev_rm_node(&a2dpio->base, node); 2830b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao free(node); 2840b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao } 28531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao free(a2dpio->base.supported_channel_counts); 28631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao free(a2dpio->base.supported_rates); 2876f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao destroy_a2dp(&a2dpio->a2dp); 28831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao} 28931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 29031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostruct cras_iodev *a2dp_iodev_create(struct cras_bt_transport *transport) 29131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{ 29231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao int err; 29331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao struct a2dp_io *a2dpio; 29431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao struct cras_iodev *iodev; 29531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao struct cras_ionode *node; 2961cbde1fb3f2aad5494f33d49dacaeafebc753ac2Hsin-Yu Chao a2dp_sbc_t a2dp; 297dd2f666a53a1090744819bf38cd672b4548aca22Hsin-Yu Chao struct cras_bt_device *device; 29831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 29931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao a2dpio = (struct a2dp_io *)calloc(1, sizeof(*a2dpio)); 30031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao if (!a2dpio) 30131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao goto error; 30231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 3031cbde1fb3f2aad5494f33d49dacaeafebc753ac2Hsin-Yu Chao a2dpio->transport = transport; 3041cbde1fb3f2aad5494f33d49dacaeafebc753ac2Hsin-Yu Chao cras_bt_transport_configuration(a2dpio->transport, &a2dp, 3051cbde1fb3f2aad5494f33d49dacaeafebc753ac2Hsin-Yu Chao sizeof(a2dp)); 3066f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao err = init_a2dp(&a2dpio->a2dp, &a2dp); 3076f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao if (err) { 3086f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao syslog(LOG_ERR, "Fail to init a2dp"); 3096f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao goto error; 3106f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao } 3111cbde1fb3f2aad5494f33d49dacaeafebc753ac2Hsin-Yu Chao 31231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao iodev = &a2dpio->base; 31331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 31431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao /* A2DP only does output now */ 31531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao iodev->direction = CRAS_STREAM_OUTPUT; 31631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 317dd2f666a53a1090744819bf38cd672b4548aca22Hsin-Yu Chao /* Set iodev's name by bluetooth device's readable name, if 318dd2f666a53a1090744819bf38cd672b4548aca22Hsin-Yu Chao * the readable name is not available, use address instead. 319dd2f666a53a1090744819bf38cd672b4548aca22Hsin-Yu Chao */ 320dd2f666a53a1090744819bf38cd672b4548aca22Hsin-Yu Chao device = cras_bt_transport_device(transport); 321dd2f666a53a1090744819bf38cd672b4548aca22Hsin-Yu Chao if (device) 322dd2f666a53a1090744819bf38cd672b4548aca22Hsin-Yu Chao snprintf(iodev->info.name, sizeof(iodev->info.name), "%s", 323dd2f666a53a1090744819bf38cd672b4548aca22Hsin-Yu Chao cras_bt_device_name(device)); 324dd2f666a53a1090744819bf38cd672b4548aca22Hsin-Yu Chao else 325dd2f666a53a1090744819bf38cd672b4548aca22Hsin-Yu Chao snprintf(iodev->info.name, sizeof(iodev->info.name), "%s", 326dd2f666a53a1090744819bf38cd672b4548aca22Hsin-Yu Chao cras_bt_transport_object_path(a2dpio->transport)); 32731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 32831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao iodev->info.name[ARRAY_SIZE(iodev->info.name) - 1] = '\0'; 32931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 33031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao iodev->open_dev = open_dev; 33131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao iodev->is_open = is_open; /* Needed by thread_add_stream */ 33231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao iodev->frames_queued = frames_queued; 33331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao iodev->dev_running = dev_running; 33431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao iodev->delay_frames = delay_frames; 33531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao iodev->get_buffer = get_buffer; 33631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao iodev->put_buffer = put_buffer; 33731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao iodev->close_dev = close_dev; 33831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao iodev->update_supported_formats = update_supported_formats; 3390b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao iodev->update_active_node = update_active_node; 340a7892d9129d4cdb25dbd099aa2f5295bd53120dfHsin-Yu Chao iodev->software_volume_needed = 1; 34131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 34231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao /* Create a dummy ionode */ 34331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao node = (struct cras_ionode *)calloc(1, sizeof(*node)); 34431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao node->dev = iodev; 34531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao strcpy(node->name, iodev->info.name); 34631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao node->plugged = 1; 34731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao node->priority = 3; 3480b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao node->type = CRAS_NODE_TYPE_BLUETOOTH; 349b7fb7aad1bb54683361c3beda234e01bcf455becDylan Reid node->volume = 100; 35031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao gettimeofday(&node->plugged_time, NULL); 35131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 35231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao /* A2DP does output only */ 35331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao err = cras_iodev_list_add_output(iodev); 35431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao if (err) 35531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao goto error; 35631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 3570b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao cras_iodev_add_node(iodev, node); 3580b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao cras_iodev_set_active_node(iodev, node); 3590b48706599ecf6372671a544ab6e3e85f5c81657Hsin-Yu Chao 36031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao return iodev; 36131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaoerror: 36231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao if (a2dpio) { 36331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao free_resources(a2dpio); 36431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao free(a2dpio); 36531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao } 36631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao return NULL; 36731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao} 36831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 36931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaovoid a2dp_iodev_destroy(struct cras_iodev *iodev) 37031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{ 37131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao int rc; 37231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao struct a2dp_io *a2dpio = (struct a2dp_io *)iodev; 37331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 37431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao /* A2DP does output only */ 37531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao rc = cras_iodev_list_rm_output(iodev); 3760fc4865c82dd7a07d978c598ec7f2d108a8a3279Hsin-Yu Chao if (rc == -EBUSY) { 3770fc4865c82dd7a07d978c598ec7f2d108a8a3279Hsin-Yu Chao syslog(LOG_ERR, "Failed to remove iodev %s", iodev->info.name); 3780fc4865c82dd7a07d978c598ec7f2d108a8a3279Hsin-Yu Chao return; 37931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao } 3800fc4865c82dd7a07d978c598ec7f2d108a8a3279Hsin-Yu Chao 3810fc4865c82dd7a07d978c598ec7f2d108a8a3279Hsin-Yu Chao /* Free resources when device successfully removed. */ 3820fc4865c82dd7a07d978c598ec7f2d108a8a3279Hsin-Yu Chao free_resources(a2dpio); 3830fc4865c82dd7a07d978c598ec7f2d108a8a3279Hsin-Yu Chao cras_iodev_free_dsp(iodev); 3840fc4865c82dd7a07d978c598ec7f2d108a8a3279Hsin-Yu Chao free(a2dpio); 38531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao} 386