cras_a2dp_iodev.c revision 639a342fcc14cf262e11612220079aff45f40ad5
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" 1331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao#include "cras_iodev.h" 1431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao#include "cras_iodev_list.h" 1531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao#include "cras_util.h" 16f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao#include "rtp.h" 1731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao#include "utlist.h" 1831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 1938cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao#define PCM_BUF_MAX_SIZE_BYTES 1024 2031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 2131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostruct a2dp_io { 2231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao struct cras_iodev base; 236f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao struct a2dp_info a2dp; 2431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao struct cras_bt_transport *transport; 2531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 2638cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao uint8_t pcm_buf[PCM_BUF_MAX_SIZE_BYTES]; 2738cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao int pcm_buf_offset; 2838cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao int pcm_buf_size; 2931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao int pcm_buf_used; 30f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao 31f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao int bt_queued_frames; 32f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao struct timespec bt_queued_fr_last_update; 3331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao}; 3431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 3531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostatic int update_supported_formats(struct cras_iodev *iodev) 3631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{ 3731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao struct a2dp_io *a2dpio = (struct a2dp_io *)iodev; 3831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao size_t rate = 0; 3931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao size_t channel; 4031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao a2dp_sbc_t a2dp; 4131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 4231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao cras_bt_transport_configuration(a2dpio->transport, &a2dp, 4331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao sizeof(a2dp)); 4431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 4531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao iodev->format->format = SND_PCM_FORMAT_S16_LE; 4631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao channel = (a2dp.channel_mode == SBC_CHANNEL_MODE_MONO) ? 1 : 2; 4731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 4831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao if (a2dp.frequency & SBC_SAMPLING_FREQ_48000) 4931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao rate = 48000; 5031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao else if (a2dp.frequency & SBC_SAMPLING_FREQ_44100) 5131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao rate = 44100; 5231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao else if (a2dp.frequency & SBC_SAMPLING_FREQ_32000) 5331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao rate = 32000; 5431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao else if (a2dp.frequency & SBC_SAMPLING_FREQ_16000) 5531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao rate = 16000; 5631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 57639a342fcc14cf262e11612220079aff45f40ad5Dylan Reid free(iodev->supported_rates); 5831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao iodev->supported_rates = (size_t *)malloc(2 * sizeof(rate)); 5931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao iodev->supported_rates[0] = rate; 6031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao iodev->supported_rates[1] = 0; 6131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 62639a342fcc14cf262e11612220079aff45f40ad5Dylan Reid free(iodev->supported_channel_counts); 6331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao iodev->supported_channel_counts = (size_t *)malloc(2 * sizeof(channel)); 6431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao iodev->supported_channel_counts[0] = channel; 6531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao iodev->supported_channel_counts[1] = 0; 6631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 6731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao return 0; 6831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao} 6931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 70f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao/* Calculates the amount of consumed frames since given time. 71f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao */ 72f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chaostatic unsigned long frames_since(struct timespec ts, size_t rate) 73f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao{ 74f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao struct timespec te, diff; 75f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao 76f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao clock_gettime(CLOCK_MONOTONIC, &te); 77f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao subtract_timespecs(&te, &ts, &diff); 78f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao return diff.tv_sec * rate + diff.tv_nsec / (1000000000L / rate); 79f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao} 80f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao 81f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao/* Maintains a virtual buffer for transmitted frames, assume this buffer is 82f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao * consumed at the same frame rate at bluetooth device side. 83f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao * Args: 84f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao * iodev: The a2dp iodev to estimate the queued frames for. 85f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao * fr: The amount of frames just transmitted. 86f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao */ 87f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chaostatic int get_bt_queued_frames(const struct cras_iodev *iodev, int fr) 88f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao{ 89f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao unsigned long consumed; 90f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao struct a2dp_io *a2dpio = (struct a2dp_io *)iodev; 91f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao 92f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao /* Calculate consumed frames since last update time, also update 93f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao * the last update time. 94f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao */ 95f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao consumed = frames_since(a2dpio->bt_queued_fr_last_update, 96f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao iodev->format->frame_rate); 97f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao clock_gettime(CLOCK_MONOTONIC, &a2dpio->bt_queued_fr_last_update); 98f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao 99f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao if (a2dpio->bt_queued_frames > consumed) 100f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao a2dpio->bt_queued_frames -= consumed; 101f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao else 102f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao a2dpio->bt_queued_frames = 0; 103f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao 104f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao a2dpio->bt_queued_frames += fr; 105f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao 106f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao return a2dpio->bt_queued_frames; 107f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao} 108f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao 10931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostatic int frames_queued(const struct cras_iodev *iodev) 11031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{ 111f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao size_t format_bytes; 112f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao int frames; 113f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao struct a2dp_io *a2dpio = (struct a2dp_io *)iodev; 114f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao 115f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao format_bytes = cras_get_format_bytes(iodev->format); 116f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao 117f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao frames = a2dpio->pcm_buf_used / format_bytes 118f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao + a2dp_queued_frames(&a2dpio->a2dp) 119f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao + get_bt_queued_frames(iodev, 0); 120f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao 121f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao return frames; 12231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao} 12331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 124f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao 12531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostatic int open_dev(struct cras_iodev *iodev) 12631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{ 127f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao int err = 0, block_size; 128f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao size_t format_bytes; 12931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao struct a2dp_io *a2dpio = (struct a2dp_io *)iodev; 13031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 13131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao err = cras_bt_transport_acquire(a2dpio->transport); 13231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao if (err < 0) { 13331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao syslog(LOG_ERR, "transport_acquire failed"); 13431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao return err; 13531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao } 13631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 13731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao /* Assert format is set before opening device. */ 13831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao if (iodev->format == NULL) 13931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao return -EINVAL; 14031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao iodev->format->format = SND_PCM_FORMAT_S16_LE; 141f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao format_bytes = cras_get_format_bytes(iodev->format); 14231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 143f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao /* Back calculate the max size of a2dp block before encode. */ 144f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao block_size = a2dp_block_size( 145f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao &a2dpio->a2dp, 146f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao cras_bt_transport_write_mtu(a2dpio->transport) - 147f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao sizeof(struct rtp_header) - 148f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao sizeof(struct rtp_payload)); 149f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao 150f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao /* Assert pcm_buf_size be multiple of codesize */ 151f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao a2dpio->pcm_buf_size = PCM_BUF_MAX_SIZE_BYTES 152f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao / a2dp_codesize(&a2dpio->a2dp) 153f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao * a2dp_codesize(&a2dpio->a2dp); 154f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao iodev->buffer_size = (a2dpio->pcm_buf_size + block_size) / format_bytes; 15531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao if (iodev->used_size > iodev->buffer_size) 15631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao iodev->used_size = iodev->buffer_size; 157f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao 158f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao syslog(LOG_DEBUG, "a2dp iodev buf size %lu, used size %lu", 159f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao iodev->buffer_size, iodev->used_size); 160f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao 16131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao return 0; 16231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao} 16331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 16431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostatic int close_dev(struct cras_iodev *iodev) 16531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{ 16631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao int err; 16731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao struct a2dp_io *a2dpio = (struct a2dp_io *)iodev; 16831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 16931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao if (!a2dpio->transport) 17031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao return 0; 17131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 17231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao err = cras_bt_transport_release(a2dpio->transport); 17331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao if (err < 0) 17431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao syslog(LOG_ERR, "transport_release failed"); 17531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 1766f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao a2dp_drain(&a2dpio->a2dp); 17731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao a2dpio->pcm_buf_used = 0; 17831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao cras_iodev_free_format(iodev); 17931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao return 0; 18031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao} 18131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 18231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostatic int is_open(const struct cras_iodev *iodev) 18331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{ 18431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao struct a2dp_io *a2dpio = (struct a2dp_io *)iodev; 18531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao return cras_bt_transport_fd(a2dpio->transport) > 0; 18631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao} 18731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 18831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostatic int dev_running(const struct cras_iodev *iodev) 18931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{ 19031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao // TODO(hychao): Track if a2dp iodev is actually playing. 19131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao return is_open(iodev); 19231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao} 19331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 19431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostatic int delay_frames(const struct cras_iodev *iodev) 19531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{ 196f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao return frames_queued(iodev); 19731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao} 19831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 19931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostatic int get_buffer(struct cras_iodev *iodev, uint8_t **dst, unsigned *frames) 20031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{ 20131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao size_t format_bytes; 20231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao struct a2dp_io *a2dpio; 20331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao a2dpio = (struct a2dp_io *)iodev; 20431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 20531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao format_bytes = cras_get_format_bytes(iodev->format); 20631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 20731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao if (iodev->direction == CRAS_STREAM_OUTPUT) { 20838cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao *dst = a2dpio->pcm_buf + a2dpio->pcm_buf_offset 20938cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao + a2dpio->pcm_buf_used; 21038cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao *frames = (a2dpio->pcm_buf_size - a2dpio->pcm_buf_offset - 21138cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao a2dpio->pcm_buf_used) / format_bytes; 21231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao } 21331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao return 0; 21431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao} 21531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 21631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostatic int put_buffer(struct cras_iodev *iodev, unsigned nwritten) 21731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{ 21831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao size_t format_bytes; 21938cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao int written = 0; 22038cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao int processed; 22131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao struct a2dp_io *a2dpio = (struct a2dp_io *)iodev; 222f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao 22331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao format_bytes = cras_get_format_bytes(iodev->format); 22431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 22538cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao if (a2dpio->pcm_buf_used + a2dpio->pcm_buf_offset + 22638cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao nwritten * format_bytes > a2dpio->pcm_buf_size) 22731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao return -1; 22831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao a2dpio->pcm_buf_used += nwritten * format_bytes; 2296f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao 23038cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao processed = a2dp_write(a2dpio->pcm_buf + a2dpio->pcm_buf_offset, 23138cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao a2dpio->pcm_buf_used, 23238cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao &a2dpio->a2dp, 23338cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao format_bytes, 23438cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao cras_bt_transport_fd(a2dpio->transport), 23538cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao cras_bt_transport_write_mtu(a2dpio->transport), 23638cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao &written); 23738cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao 23838cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao if (a2dpio->pcm_buf_used == processed) { 23938cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao a2dpio->pcm_buf_offset = 0; 24038cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao a2dpio->pcm_buf_used = 0; 24138cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao } else { 24238cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao a2dpio->pcm_buf_offset += processed; 24338cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao a2dpio->pcm_buf_used -= processed; 24438cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao } 24538cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao 246f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao if (written == -EAGAIN) { 247f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao syslog(LOG_ERR, "a2dp_write error"); 248f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao return 0; 249f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao } 25038cc0db5a86cfc6145df903e87e866d6221407ffHsin-Yu Chao 251f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao get_bt_queued_frames(iodev, 252f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao a2dp_block_size(&a2dpio->a2dp, written) 253f3df2ca6f9d8180969c00ec48f37b717069c8811Hsin-Yu Chao / format_bytes); 25431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao return 0; 25531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao} 25631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 25731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaovoid free_resources(struct a2dp_io *a2dpio) 25831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{ 25931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao free(a2dpio->base.supported_channel_counts); 26031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao free(a2dpio->base.supported_rates); 2616f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao destroy_a2dp(&a2dpio->a2dp); 26231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao} 26331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 26431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaostruct cras_iodev *a2dp_iodev_create(struct cras_bt_transport *transport) 26531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{ 26631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao int err; 26731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao struct a2dp_io *a2dpio; 26831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao struct cras_iodev *iodev; 26931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao struct cras_ionode *node; 2701cbde1fb3f2aad5494f33d49dacaeafebc753ac2Hsin-Yu Chao a2dp_sbc_t a2dp; 27131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 27231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao a2dpio = (struct a2dp_io *)calloc(1, sizeof(*a2dpio)); 27331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao if (!a2dpio) 27431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao goto error; 27531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 2761cbde1fb3f2aad5494f33d49dacaeafebc753ac2Hsin-Yu Chao a2dpio->transport = transport; 2771cbde1fb3f2aad5494f33d49dacaeafebc753ac2Hsin-Yu Chao cras_bt_transport_configuration(a2dpio->transport, &a2dp, 2781cbde1fb3f2aad5494f33d49dacaeafebc753ac2Hsin-Yu Chao sizeof(a2dp)); 2796f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao err = init_a2dp(&a2dpio->a2dp, &a2dp); 2806f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao if (err) { 2816f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao syslog(LOG_ERR, "Fail to init a2dp"); 2826f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao goto error; 2836f71f72193bbda4d9468b579a9a3a156fe61ecdbHsin-Yu Chao } 2841cbde1fb3f2aad5494f33d49dacaeafebc753ac2Hsin-Yu Chao 28531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao iodev = &a2dpio->base; 28631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 28731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao /* A2DP only does output now */ 28831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao iodev->direction = CRAS_STREAM_OUTPUT; 28931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 29031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao snprintf(iodev->info.name, sizeof(iodev->info.name), "%s", 29131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao cras_bt_transport_object_path(a2dpio->transport)); 29231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 29331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao iodev->info.name[ARRAY_SIZE(iodev->info.name) - 1] = '\0'; 29431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 29531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao iodev->open_dev = open_dev; 29631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao iodev->is_open = is_open; /* Needed by thread_add_stream */ 29731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao iodev->frames_queued = frames_queued; 29831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao iodev->dev_running = dev_running; 29931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao iodev->delay_frames = delay_frames; 30031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao iodev->get_buffer = get_buffer; 30131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao iodev->put_buffer = put_buffer; 30231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao iodev->close_dev = close_dev; 30331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao iodev->update_supported_formats = update_supported_formats; 30431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 30531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao /* Create a dummy ionode */ 30631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao node = (struct cras_ionode *)calloc(1, sizeof(*node)); 30731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao node->dev = iodev; 30831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao strcpy(node->name, iodev->info.name); 30931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao DL_APPEND(iodev->nodes, node); 31031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao iodev->active_node = node; 31131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao node->plugged = 1; 31231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao node->priority = 3; 31331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao gettimeofday(&node->plugged_time, NULL); 31431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 31531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao /* A2DP does output only */ 31631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao err = cras_iodev_list_add_output(iodev); 31731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao if (err) 31831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao goto error; 31931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 32031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao return iodev; 32131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaoerror: 32231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao if (a2dpio) { 32331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao free_resources(a2dpio); 32431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao free(a2dpio); 32531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao } 32631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao return NULL; 32731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao} 32831635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 32931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chaovoid a2dp_iodev_destroy(struct cras_iodev *iodev) 33031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao{ 33131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao int rc; 33231635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao struct a2dp_io *a2dpio = (struct a2dp_io *)iodev; 33331635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao 33431635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao /* A2DP does output only */ 33531635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao rc = cras_iodev_list_rm_output(iodev); 33631635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao if (rc != -EBUSY) { 33731635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao free_resources(a2dpio); 33871aa1de70c395c3648ede3eec5838ac7c64646d5Chih-Chung Chang cras_iodev_free_dsp(iodev); 33931635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao free(a2dpio); 34031635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao } 34131635aee19f32c75657411865c4d3a4abec9dc56Hsin-Yu Chao} 342