133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh/* 233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh * 333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh * BlueZ - Bluetooth protocol stack for Linux 433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh * 533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh * Copyright (C) 2006-2007 Nokia Corporation 633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org> 733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh * 833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh * 933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh * This library is free software; you can redistribute it and/or 1033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh * modify it under the terms of the GNU Lesser General Public 1133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh * License as published by the Free Software Foundation; either 1233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh * version 2.1 of the License, or (at your option) any later version. 1333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh * 1433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh * This library is distributed in the hope that it will be useful, 1533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh * but WITHOUT ANY WARRANTY; without even the implied warranty of 1633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh * Lesser General Public License for more details. 1833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh * 1933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh * You should have received a copy of the GNU Lesser General Public 2033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh * License along with this library; if not, write to the Free Software 2133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 2233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh * 2333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh */ 2433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 2533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#ifdef HAVE_CONFIG_H 2633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#include <config.h> 2733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#endif 2833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 2933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#include <stdint.h> 3033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#include <sys/socket.h> 3133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#include <sys/un.h> 3233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#include <signal.h> 3333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#include <limits.h> 3433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#include <fcntl.h> 3533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#include <unistd.h> 3633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#include <pthread.h> 3733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 3833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#include <netinet/in.h> 3933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#include <sys/poll.h> 4033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#include <sys/prctl.h> 4133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 4282c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly#include <bluetooth/bluetooth.h> 4382c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly#include <bluetooth/l2cap.h> 4482c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly 4533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#include "ipc.h" 4633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#include "sbc.h" 4733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#include "rtp.h" 4833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#include "liba2dp.h" 4933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 5033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#define LOG_NDEBUG 0 5133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#define LOG_TAG "A2DP" 5233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#include <utils/Log.h> 5333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 5433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#define ENABLE_DEBUG 5533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh/* #define ENABLE_VERBOSE */ 5633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh/* #define ENABLE_TIMING */ 5733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 5833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#define BUFFER_SIZE 2048 5933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 6033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#ifdef ENABLE_DEBUG 61ae2da65e52e1720eb385135ea35552d5b5e4d9d1Steve Block#define DBG ALOGD 6233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#else 6333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#define DBG(fmt, arg...) 6433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#endif 6533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 6633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#ifdef ENABLE_VERBOSE 67999d00b91f78f2fe1aa0648aab49bc857bdec8f6Steve Block#define VDBG ALOGV 6833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#else 6933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#define VDBG(fmt, arg...) 7033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#endif 7133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 7233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#ifndef MIN 7333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh# define MIN(x, y) ((x) < (y) ? (x) : (y)) 7433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#endif 7533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 7633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#ifndef MAX 7733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh# define MAX(x, y) ((x) > (y) ? (x) : (y)) 7833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#endif 7933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 8033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#define MAX_BITPOOL 64 8133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#define MIN_BITPOOL 2 8233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 836934b76075fabbd7a1f542b3000b250f4a589492Steve Block#define ERR ALOGE 8433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 8533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh/* Number of packets to buffer in the stream socket */ 8633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#define PACKET_BUFFER_COUNT 10 8733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 8833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh/* timeout in milliseconds to prevent poll() from hanging indefinitely */ 8933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#define POLL_TIMEOUT 1000 9033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 9114de1515561ce4627260bef13ec5677550e674c1Nick Pelly/* milliseconds of unsucessfull a2dp packets before we stop trying to catch up 9214de1515561ce4627260bef13ec5677550e674c1Nick Pelly * on write()'s and fall-back to metered writes */ 9314de1515561ce4627260bef13ec5677550e674c1Nick Pelly#define CATCH_UP_TIMEOUT 200 9414de1515561ce4627260bef13ec5677550e674c1Nick Pelly 9533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh/* timeout in milliseconds for a2dp_write */ 96722318b1247152c6ee282195f56efea4b0595e3cIan Kent#define WRITE_TIMEOUT 1000 9733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 985abd6d6344fa6d196ab172f724e4b7e1a755689eEric Laurent/* timeout in seconds for command socket recv() */ 99927aeb48a23a21c95f57ee990779fd529539873eEric Laurent#define RECV_TIMEOUT 5 1005abd6d6344fa6d196ab172f724e4b7e1a755689eEric Laurent 10133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 10233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganeshtypedef enum { 10333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh A2DP_STATE_NONE = 0, 10433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh A2DP_STATE_INITIALIZED, 10533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh A2DP_STATE_CONFIGURING, 10633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh A2DP_STATE_CONFIGURED, 10733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh A2DP_STATE_STARTING, 10833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh A2DP_STATE_STARTED, 10933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh A2DP_STATE_STOPPING, 11033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh} a2dp_state_t; 11133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 11233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganeshtypedef enum { 11333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh A2DP_CMD_NONE = 0, 11467bf8f93bc209d3d8873d41662796ecec0d6524cJaikumar Ganesh A2DP_CMD_INIT, 11533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh A2DP_CMD_CONFIGURE, 11633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh A2DP_CMD_START, 11733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh A2DP_CMD_STOP, 11833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh A2DP_CMD_QUIT, 11933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh} a2dp_command_t; 12033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 12133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganeshstruct bluetooth_data { 122c4e47c15ae8fe36673e7cdd7ee3caaffddb5071eNick Pelly unsigned int link_mtu; /* MTU for transport channel */ 12333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh struct pollfd stream; /* Audio stream filedescriptor */ 12433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh struct pollfd server; /* Audio daemon filedescriptor */ 12533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh a2dp_state_t state; /* Current A2DP state */ 12633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh a2dp_command_t command; /* Current command for a2dp_thread */ 12733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh pthread_t thread; 12833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh pthread_mutex_t mutex; 1295bac662a139181195fae0a6292bdc6c12ba6f463Ian Kent int started; 1305bac662a139181195fae0a6292bdc6c12ba6f463Ian Kent pthread_cond_t thread_start; 13133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh pthread_cond_t thread_wait; 13233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh pthread_cond_t client_wait; 13333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 13433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh sbc_capabilities_t sbc_capabilities; 13533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh sbc_t sbc; /* Codec data */ 13633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh int frame_duration; /* length of an SBC frame in microseconds */ 13733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh int codesize; /* SBC codesize */ 13833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh int samples; /* Number of encoded samples */ 13933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh uint8_t buffer[BUFFER_SIZE]; /* Codec transfer buffer */ 14033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh int count; /* Codec transfer buffer counter */ 14133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 14233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh int nsamples; /* Cumulative number of codec samples */ 14333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh uint16_t seq_num; /* Cumulative packet sequence */ 14433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh int frame_count; /* Current frames in buffer*/ 14533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 14633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh char address[20]; 14733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh int rate; 14833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh int channels; 14933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 15033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh /* used for pacing our writes to the output socket */ 15133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh uint64_t next_write; 15233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh}; 15333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 15433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganeshstatic uint64_t get_microseconds() 15533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh{ 156e92f5a8ea09b2550c855964da37ceea5db372f5dNick Pelly struct timespec now; 157e92f5a8ea09b2550c855964da37ceea5db372f5dNick Pelly clock_gettime(CLOCK_MONOTONIC, &now); 158e92f5a8ea09b2550c855964da37ceea5db372f5dNick Pelly return (now.tv_sec * 1000000UL + now.tv_nsec / 1000UL); 15933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh} 16033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 16133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#ifdef ENABLE_TIMING 16233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganeshstatic void print_time(const char* message, uint64_t then, uint64_t now) 16333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh{ 16433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh DBG("%s: %lld us", message, now - then); 16533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh} 16633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#endif 16733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 16833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganeshstatic int audioservice_send(struct bluetooth_data *data, const bt_audio_msg_header_t *msg); 16933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganeshstatic int audioservice_expect(struct bluetooth_data *data, bt_audio_msg_header_t *outmsg, 17033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh int expected_type); 17133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganeshstatic int bluetooth_a2dp_hw_params(struct bluetooth_data *data); 17233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganeshstatic void set_state(struct bluetooth_data *data, a2dp_state_t state); 17333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 17433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 17533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganeshstatic void bluetooth_close(struct bluetooth_data *data) 17633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh{ 17733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh DBG("bluetooth_close"); 17833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh if (data->server.fd >= 0) { 17933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh bt_audio_service_close(data->server.fd); 18033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->server.fd = -1; 18133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh } 18233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 18333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh if (data->stream.fd >= 0) { 18433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh close(data->stream.fd); 18533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->stream.fd = -1; 18633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh } 18733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 18833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->state = A2DP_STATE_NONE; 18933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh} 19033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 19182c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pellystatic int l2cap_set_flushable(int fd, int flushable) 19282c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly{ 19382c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly int flags; 19482c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly socklen_t len; 19582c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly 19682c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly len = sizeof(flags); 19782c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly if (getsockopt(fd, SOL_BLUETOOTH, BT_FLUSHABLE, &flags, &len) < 0) 19882c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly return -errno; 19982c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly 20082c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly if (flushable) { 20182c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly if (flags == BT_FLUSHABLE_ON) 20282c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly return 0; 20382c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly flags = BT_FLUSHABLE_ON; 20482c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly } else { 20582c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly if (flags == BT_FLUSHABLE_OFF) 20682c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly return 0; 20782c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly flags = BT_FLUSHABLE_OFF; 20882c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly } 20982c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly 21082c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly if (setsockopt(fd, SOL_BLUETOOTH, L2CAP_LM, &flags, sizeof(flags)) < 0) 21182c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly return -errno; 21282c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly 21382c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly return 0; 21482c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly} 21582c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly 21633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganeshstatic int bluetooth_start(struct bluetooth_data *data) 21733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh{ 21833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh char c = 'w'; 21933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh char buf[BT_SUGGESTED_BUFFER_SIZE]; 22033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh struct bt_start_stream_req *start_req = (void*) buf; 22133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh struct bt_start_stream_rsp *start_rsp = (void*) buf; 22233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh struct bt_new_stream_ind *streamfd_ind = (void*) buf; 22333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh int opt_name, err, bytes; 22433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 22533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh DBG("bluetooth_start"); 22633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->state = A2DP_STATE_STARTING; 22733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh /* send start */ 22833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh memset(start_req, 0, BT_SUGGESTED_BUFFER_SIZE); 22974c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh start_req->h.type = BT_REQUEST; 23074c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh start_req->h.name = BT_START_STREAM; 23174c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh start_req->h.length = sizeof(*start_req); 23233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 23333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 23433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh err = audioservice_send(data, &start_req->h); 23533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh if (err < 0) 23633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh goto error; 23733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 23833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh start_rsp->h.length = sizeof(*start_rsp); 23933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh err = audioservice_expect(data, &start_rsp->h, BT_START_STREAM); 24033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh if (err < 0) 24133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh goto error; 24233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 24374c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh streamfd_ind->h.length = sizeof(*streamfd_ind); 24433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh err = audioservice_expect(data, &streamfd_ind->h, BT_NEW_STREAM); 24533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh if (err < 0) 24633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh goto error; 24733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 24833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->stream.fd = bt_audio_service_get_data_fd(data->server.fd); 24933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh if (data->stream.fd < 0) { 25033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh ERR("bt_audio_service_get_data_fd failed, errno: %d", errno); 25133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh err = -errno; 25233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh goto error; 25333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh } 25482c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly l2cap_set_flushable(data->stream.fd, 1); 25533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->stream.events = POLLOUT; 25633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 25733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh /* set our socket buffer to the size of PACKET_BUFFER_COUNT packets */ 25833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh bytes = data->link_mtu * PACKET_BUFFER_COUNT; 25933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh setsockopt(data->stream.fd, SOL_SOCKET, SO_SNDBUF, &bytes, 26033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh sizeof(bytes)); 26133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 26233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->count = sizeof(struct rtp_header) + sizeof(struct rtp_payload); 26333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->frame_count = 0; 26433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->samples = 0; 26533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->nsamples = 0; 26633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->seq_num = 0; 26733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->frame_count = 0; 26833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->next_write = 0; 26933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 27033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh set_state(data, A2DP_STATE_STARTED); 27133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh return 0; 27233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 27333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesherror: 274927aeb48a23a21c95f57ee990779fd529539873eEric Laurent /* close bluetooth connection to force reinit and reconfiguration */ 275007af38ddeb22f02663a2d879634642b61457634Mathias Jeppsson if (data->state == A2DP_STATE_STARTING) { 276927aeb48a23a21c95f57ee990779fd529539873eEric Laurent bluetooth_close(data); 277007af38ddeb22f02663a2d879634642b61457634Mathias Jeppsson /* notify client that thread is ready for next command */ 278007af38ddeb22f02663a2d879634642b61457634Mathias Jeppsson pthread_cond_signal(&data->client_wait); 279007af38ddeb22f02663a2d879634642b61457634Mathias Jeppsson } 28033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh return err; 28133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh} 28233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 28333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganeshstatic int bluetooth_stop(struct bluetooth_data *data) 28433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh{ 28533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh char buf[BT_SUGGESTED_BUFFER_SIZE]; 28633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh struct bt_stop_stream_req *stop_req = (void*) buf; 28733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh struct bt_stop_stream_rsp *stop_rsp = (void*) buf; 28833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh int err; 28933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 29033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh DBG("bluetooth_stop"); 29133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 29233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->state = A2DP_STATE_STOPPING; 29382c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly l2cap_set_flushable(data->stream.fd, 0); 29433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh if (data->stream.fd >= 0) { 29533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh close(data->stream.fd); 29633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->stream.fd = -1; 29733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh } 29833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 29933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh /* send stop request */ 30033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh memset(stop_req, 0, BT_SUGGESTED_BUFFER_SIZE); 30174c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh stop_req->h.type = BT_REQUEST; 30274c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh stop_req->h.name = BT_STOP_STREAM; 30374c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh stop_req->h.length = sizeof(*stop_req); 30433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 30533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh err = audioservice_send(data, &stop_req->h); 30633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh if (err < 0) 30733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh goto error; 30833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 30933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh stop_rsp->h.length = sizeof(*stop_rsp); 31033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh err = audioservice_expect(data, &stop_rsp->h, BT_STOP_STREAM); 31133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh if (err < 0) 31233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh goto error; 31333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 31433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesherror: 31533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh if (data->state == A2DP_STATE_STOPPING) 31633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh set_state(data, A2DP_STATE_CONFIGURED); 31733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh return err; 31833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh} 31933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 32033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganeshstatic uint8_t default_bitpool(uint8_t freq, uint8_t mode) 32133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh{ 32233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh switch (freq) { 32333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh case BT_SBC_SAMPLING_FREQ_16000: 32433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh case BT_SBC_SAMPLING_FREQ_32000: 32533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh return 53; 32633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh case BT_SBC_SAMPLING_FREQ_44100: 32733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh switch (mode) { 32833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh case BT_A2DP_CHANNEL_MODE_MONO: 32933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh case BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL: 33033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh return 31; 33133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh case BT_A2DP_CHANNEL_MODE_STEREO: 33233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh case BT_A2DP_CHANNEL_MODE_JOINT_STEREO: 33333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh return 53; 33433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh default: 33533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh ERR("Invalid channel mode %u", mode); 33633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh return 53; 33733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh } 33833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh case BT_SBC_SAMPLING_FREQ_48000: 33933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh switch (mode) { 34033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh case BT_A2DP_CHANNEL_MODE_MONO: 34133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh case BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL: 34233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh return 29; 34333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh case BT_A2DP_CHANNEL_MODE_STEREO: 34433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh case BT_A2DP_CHANNEL_MODE_JOINT_STEREO: 34533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh return 51; 34633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh default: 34733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh ERR("Invalid channel mode %u", mode); 34833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh return 51; 34933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh } 35033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh default: 35133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh ERR("Invalid sampling freq %u", freq); 35233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh return 53; 35333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh } 35433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh} 35533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 35633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganeshstatic int bluetooth_a2dp_init(struct bluetooth_data *data) 35733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh{ 35833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh sbc_capabilities_t *cap = &data->sbc_capabilities; 35933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh unsigned int max_bitpool, min_bitpool; 36033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh int dir; 36133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 36233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh switch (data->rate) { 36333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh case 48000: 36433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh cap->frequency = BT_SBC_SAMPLING_FREQ_48000; 36533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh break; 36633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh case 44100: 36733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh cap->frequency = BT_SBC_SAMPLING_FREQ_44100; 36833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh break; 36933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh case 32000: 37033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh cap->frequency = BT_SBC_SAMPLING_FREQ_32000; 37133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh break; 37233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh case 16000: 37333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh cap->frequency = BT_SBC_SAMPLING_FREQ_16000; 37433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh break; 37533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh default: 37633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh ERR("Rate %d not supported", data->rate); 37733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh return -1; 37833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh } 37933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 38033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh if (data->channels == 2) { 38133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh if (cap->channel_mode & BT_A2DP_CHANNEL_MODE_JOINT_STEREO) 38233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh cap->channel_mode = BT_A2DP_CHANNEL_MODE_JOINT_STEREO; 38333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh else if (cap->channel_mode & BT_A2DP_CHANNEL_MODE_STEREO) 38433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh cap->channel_mode = BT_A2DP_CHANNEL_MODE_STEREO; 38533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh else if (cap->channel_mode & BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL) 38633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh cap->channel_mode = BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL; 38733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh } else { 38833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh if (cap->channel_mode & BT_A2DP_CHANNEL_MODE_MONO) 38933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh cap->channel_mode = BT_A2DP_CHANNEL_MODE_MONO; 39033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh } 39133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 39233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh if (!cap->channel_mode) { 39333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh ERR("No supported channel modes"); 39433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh return -1; 39533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh } 39633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 39733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh if (cap->block_length & BT_A2DP_BLOCK_LENGTH_16) 39833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh cap->block_length = BT_A2DP_BLOCK_LENGTH_16; 39933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh else if (cap->block_length & BT_A2DP_BLOCK_LENGTH_12) 40033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh cap->block_length = BT_A2DP_BLOCK_LENGTH_12; 40133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh else if (cap->block_length & BT_A2DP_BLOCK_LENGTH_8) 40233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh cap->block_length = BT_A2DP_BLOCK_LENGTH_8; 40333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh else if (cap->block_length & BT_A2DP_BLOCK_LENGTH_4) 40433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh cap->block_length = BT_A2DP_BLOCK_LENGTH_4; 40533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh else { 40633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh ERR("No supported block lengths"); 40733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh return -1; 40833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh } 40933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 41033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh if (cap->subbands & BT_A2DP_SUBBANDS_8) 41133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh cap->subbands = BT_A2DP_SUBBANDS_8; 41233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh else if (cap->subbands & BT_A2DP_SUBBANDS_4) 41333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh cap->subbands = BT_A2DP_SUBBANDS_4; 41433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh else { 41533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh ERR("No supported subbands"); 41633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh return -1; 41733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh } 41833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 41933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh if (cap->allocation_method & BT_A2DP_ALLOCATION_LOUDNESS) 42033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh cap->allocation_method = BT_A2DP_ALLOCATION_LOUDNESS; 42133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh else if (cap->allocation_method & BT_A2DP_ALLOCATION_SNR) 42233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh cap->allocation_method = BT_A2DP_ALLOCATION_SNR; 42333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 42433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh min_bitpool = MAX(MIN_BITPOOL, cap->min_bitpool); 42533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh max_bitpool = MIN(default_bitpool(cap->frequency, 42633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh cap->channel_mode), 42733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh cap->max_bitpool); 42833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 42933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh cap->min_bitpool = min_bitpool; 43033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh cap->max_bitpool = max_bitpool; 43133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 43233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh return 0; 43333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh} 43433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 43533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganeshstatic void bluetooth_a2dp_setup(struct bluetooth_data *data) 43633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh{ 43733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh sbc_capabilities_t active_capabilities = data->sbc_capabilities; 43833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 43933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh sbc_reinit(&data->sbc, 0); 44033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 44133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh if (active_capabilities.frequency & BT_SBC_SAMPLING_FREQ_16000) 44233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->sbc.frequency = SBC_FREQ_16000; 44333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 44433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh if (active_capabilities.frequency & BT_SBC_SAMPLING_FREQ_32000) 44533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->sbc.frequency = SBC_FREQ_32000; 44633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 44733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh if (active_capabilities.frequency & BT_SBC_SAMPLING_FREQ_44100) 44833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->sbc.frequency = SBC_FREQ_44100; 44933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 45033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh if (active_capabilities.frequency & BT_SBC_SAMPLING_FREQ_48000) 45133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->sbc.frequency = SBC_FREQ_48000; 45233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 45333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh if (active_capabilities.channel_mode & BT_A2DP_CHANNEL_MODE_MONO) 45433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->sbc.mode = SBC_MODE_MONO; 45533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 45633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh if (active_capabilities.channel_mode & BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL) 45733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->sbc.mode = SBC_MODE_DUAL_CHANNEL; 45833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 45933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh if (active_capabilities.channel_mode & BT_A2DP_CHANNEL_MODE_STEREO) 46033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->sbc.mode = SBC_MODE_STEREO; 46133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 46233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh if (active_capabilities.channel_mode & BT_A2DP_CHANNEL_MODE_JOINT_STEREO) 46333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->sbc.mode = SBC_MODE_JOINT_STEREO; 46433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 46533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->sbc.allocation = active_capabilities.allocation_method 46633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh == BT_A2DP_ALLOCATION_SNR ? SBC_AM_SNR 46733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh : SBC_AM_LOUDNESS; 46833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 46933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh switch (active_capabilities.subbands) { 47033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh case BT_A2DP_SUBBANDS_4: 47133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->sbc.subbands = SBC_SB_4; 47233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh break; 47333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh case BT_A2DP_SUBBANDS_8: 47433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->sbc.subbands = SBC_SB_8; 47533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh break; 47633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh } 47733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 47833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh switch (active_capabilities.block_length) { 47933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh case BT_A2DP_BLOCK_LENGTH_4: 48033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->sbc.blocks = SBC_BLK_4; 48133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh break; 48233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh case BT_A2DP_BLOCK_LENGTH_8: 48333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->sbc.blocks = SBC_BLK_8; 48433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh break; 48533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh case BT_A2DP_BLOCK_LENGTH_12: 48633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->sbc.blocks = SBC_BLK_12; 48733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh break; 48833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh case BT_A2DP_BLOCK_LENGTH_16: 48933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->sbc.blocks = SBC_BLK_16; 49033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh break; 49133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh } 49233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 49333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->sbc.bitpool = active_capabilities.max_bitpool; 49433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->codesize = sbc_get_codesize(&data->sbc); 49533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->frame_duration = sbc_get_frame_duration(&data->sbc); 49633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh DBG("frame_duration: %d us", data->frame_duration); 49733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh} 49833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 49933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganeshstatic int bluetooth_a2dp_hw_params(struct bluetooth_data *data) 50033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh{ 50133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh char buf[BT_SUGGESTED_BUFFER_SIZE]; 50233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh struct bt_open_req *open_req = (void *) buf; 50333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh struct bt_open_rsp *open_rsp = (void *) buf; 50433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh struct bt_set_configuration_req *setconf_req = (void*) buf; 50533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh struct bt_set_configuration_rsp *setconf_rsp = (void*) buf; 50633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh int err; 50733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 50874c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh memset(open_req, 0, BT_SUGGESTED_BUFFER_SIZE); 50933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh open_req->h.type = BT_REQUEST; 51033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh open_req->h.name = BT_OPEN; 51133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh open_req->h.length = sizeof(*open_req); 51233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh strncpy(open_req->destination, data->address, 18); 51374c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh open_req->seid = data->sbc_capabilities.capability.seid; 51433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh open_req->lock = BT_WRITE_LOCK; 51533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 51674c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh err = audioservice_send(data, &open_req->h); 51774c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh if (err < 0) 51874c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh return err; 51933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 52074c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh open_rsp->h.length = sizeof(*open_rsp); 52174c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh err = audioservice_expect(data, &open_rsp->h, BT_OPEN); 52274c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh if (err < 0) 52374c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh return err; 52433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 52574c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh err = bluetooth_a2dp_init(data); 52674c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh if (err < 0) 52774c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh return err; 52833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 52933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 53033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh memset(setconf_req, 0, BT_SUGGESTED_BUFFER_SIZE); 53133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh setconf_req->h.type = BT_REQUEST; 53233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh setconf_req->h.name = BT_SET_CONFIGURATION; 53374c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh setconf_req->h.length = sizeof(*setconf_req); 53474c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh memcpy(&setconf_req->codec, &data->sbc_capabilities, 53574c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh sizeof(data->sbc_capabilities)); 53633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 53733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh setconf_req->codec.transport = BT_CAPABILITIES_TRANSPORT_A2DP; 53833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh setconf_req->codec.length = sizeof(data->sbc_capabilities); 53933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh setconf_req->h.length += setconf_req->codec.length - sizeof(setconf_req->codec); 54033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 54133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh DBG("bluetooth_a2dp_hw_params sending configuration:\n"); 54233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh switch (data->sbc_capabilities.channel_mode) { 54333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh case BT_A2DP_CHANNEL_MODE_MONO: 54433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh DBG("\tchannel_mode: MONO\n"); 54533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh break; 54633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh case BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL: 54733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh DBG("\tchannel_mode: DUAL CHANNEL\n"); 54833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh break; 54933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh case BT_A2DP_CHANNEL_MODE_STEREO: 55033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh DBG("\tchannel_mode: STEREO\n"); 55133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh break; 55233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh case BT_A2DP_CHANNEL_MODE_JOINT_STEREO: 55333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh DBG("\tchannel_mode: JOINT STEREO\n"); 55433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh break; 55533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh default: 55633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh DBG("\tchannel_mode: UNKNOWN (%d)\n", 55733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->sbc_capabilities.channel_mode); 55833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh } 55933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh switch (data->sbc_capabilities.frequency) { 56033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh case BT_SBC_SAMPLING_FREQ_16000: 56133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh DBG("\tfrequency: 16000\n"); 56233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh break; 56333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh case BT_SBC_SAMPLING_FREQ_32000: 56433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh DBG("\tfrequency: 32000\n"); 56533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh break; 56633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh case BT_SBC_SAMPLING_FREQ_44100: 56733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh DBG("\tfrequency: 44100\n"); 56833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh break; 56933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh case BT_SBC_SAMPLING_FREQ_48000: 57033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh DBG("\tfrequency: 48000\n"); 57133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh break; 57233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh default: 57333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh DBG("\tfrequency: UNKNOWN (%d)\n", 57433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->sbc_capabilities.frequency); 57533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh } 57633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh switch (data->sbc_capabilities.allocation_method) { 57733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh case BT_A2DP_ALLOCATION_SNR: 57833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh DBG("\tallocation_method: SNR\n"); 57933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh break; 58033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh case BT_A2DP_ALLOCATION_LOUDNESS: 58133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh DBG("\tallocation_method: LOUDNESS\n"); 58233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh break; 58333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh default: 58433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh DBG("\tallocation_method: UNKNOWN (%d)\n", 58533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->sbc_capabilities.allocation_method); 58633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh } 58733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh switch (data->sbc_capabilities.subbands) { 58833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh case BT_A2DP_SUBBANDS_4: 58933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh DBG("\tsubbands: 4\n"); 59033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh break; 59133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh case BT_A2DP_SUBBANDS_8: 59233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh DBG("\tsubbands: 8\n"); 59333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh break; 59433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh default: 59533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh DBG("\tsubbands: UNKNOWN (%d)\n", 59633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->sbc_capabilities.subbands); 59733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh } 59833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh switch (data->sbc_capabilities.block_length) { 59933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh case BT_A2DP_BLOCK_LENGTH_4: 60033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh DBG("\tblock_length: 4\n"); 60133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh break; 60233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh case BT_A2DP_BLOCK_LENGTH_8: 60333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh DBG("\tblock_length: 8\n"); 60433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh break; 60533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh case BT_A2DP_BLOCK_LENGTH_12: 60633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh DBG("\tblock_length: 12\n"); 60733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh break; 60833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh case BT_A2DP_BLOCK_LENGTH_16: 60933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh DBG("\tblock_length: 16\n"); 61033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh break; 61133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh default: 61233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh DBG("\tblock_length: UNKNOWN (%d)\n", 61333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->sbc_capabilities.block_length); 61433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh } 61533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh DBG("\tmin_bitpool: %d\n", data->sbc_capabilities.min_bitpool); 61633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh DBG("\tmax_bitpool: %d\n", data->sbc_capabilities.max_bitpool); 61733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 61833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh err = audioservice_send(data, &setconf_req->h); 61933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh if (err < 0) 62033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh return err; 62133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 62233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh err = audioservice_expect(data, &setconf_rsp->h, BT_SET_CONFIGURATION); 62333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh if (err < 0) 62433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh return err; 62533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 62633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->link_mtu = setconf_rsp->link_mtu; 62733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh DBG("MTU: %d", data->link_mtu); 62833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 62933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh /* Setup SBC encoder now we agree on parameters */ 63033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh bluetooth_a2dp_setup(data); 63133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 63233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh DBG("\tallocation=%u\n\tsubbands=%u\n\tblocks=%u\n\tbitpool=%u\n", 63333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->sbc.allocation, data->sbc.subbands, data->sbc.blocks, 63433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->sbc.bitpool); 63533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 63633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh return 0; 63733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh} 63833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 63933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganeshstatic int avdtp_write(struct bluetooth_data *data) 64033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh{ 64133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh int ret = 0; 64233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh struct rtp_header *header; 64333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh struct rtp_payload *payload; 64433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 64533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh uint64_t now; 64633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh long duration = data->frame_duration * data->frame_count; 64733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#ifdef ENABLE_TIMING 64833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh uint64_t begin, end, begin2, end2; 64933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh begin = get_microseconds(); 65033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#endif 65133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 65233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh header = (struct rtp_header *)data->buffer; 65333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh payload = (struct rtp_payload *)(data->buffer + sizeof(*header)); 65433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 65533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh memset(data->buffer, 0, sizeof(*header) + sizeof(*payload)); 65633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 65733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh payload->frame_count = data->frame_count; 65833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh header->v = 2; 65933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh header->pt = 1; 66033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh header->sequence_number = htons(data->seq_num); 66133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh header->timestamp = htonl(data->nsamples); 66233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh header->ssrc = htonl(1); 66333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 66433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->stream.revents = 0; 66533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#ifdef ENABLE_TIMING 66633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh begin2 = get_microseconds(); 66733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#endif 66833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh ret = poll(&data->stream, 1, POLL_TIMEOUT); 66933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#ifdef ENABLE_TIMING 67033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh end2 = get_microseconds(); 67133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh print_time("poll", begin2, end2); 67233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#endif 67333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh if (ret == 1 && data->stream.revents == POLLOUT) { 67433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh long ahead = 0; 67533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh now = get_microseconds(); 67633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 67733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh if (data->next_write) { 67833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh ahead = data->next_write - now; 67933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#ifdef ENABLE_TIMING 68033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh DBG("duration: %ld, ahead: %ld", duration, ahead); 68133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#endif 68233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh if (ahead > 0) { 68333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh /* too fast, need to throttle */ 68433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh usleep(ahead); 68533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh } 68633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh } else { 68733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->next_write = now; 68833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh } 68914de1515561ce4627260bef13ec5677550e674c1Nick Pelly if (ahead <= -CATCH_UP_TIMEOUT * 1000) { 69014de1515561ce4627260bef13ec5677550e674c1Nick Pelly /* fallen too far behind, don't try to catch up */ 69114de1515561ce4627260bef13ec5677550e674c1Nick Pelly VDBG("ahead < %d, reseting next_write timestamp", -CATCH_UP_TIMEOUT * 1000); 69214de1515561ce4627260bef13ec5677550e674c1Nick Pelly data->next_write = 0; 69314de1515561ce4627260bef13ec5677550e674c1Nick Pelly } else { 69414de1515561ce4627260bef13ec5677550e674c1Nick Pelly data->next_write += duration; 69514de1515561ce4627260bef13ec5677550e674c1Nick Pelly } 69633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 69733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#ifdef ENABLE_TIMING 69833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh begin2 = get_microseconds(); 69933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#endif 70033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh ret = send(data->stream.fd, data->buffer, data->count, MSG_NOSIGNAL); 70133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#ifdef ENABLE_TIMING 70233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh end2 = get_microseconds(); 70333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh print_time("send", begin2, end2); 70433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#endif 70533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh if (ret < 0) { 70633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh /* can happen during normal remote disconnect */ 70733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh VDBG("send() failed: %d (errno %s)", ret, strerror(errno)); 70833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh } 70933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh if (ret == -EPIPE) { 71033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh bluetooth_close(data); 71133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh } 71233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh } else { 71333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh /* can happen during normal remote disconnect */ 71433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh VDBG("poll() failed: %d (revents = %d, errno %s)", 71533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh ret, data->stream.revents, strerror(errno)); 71614de1515561ce4627260bef13ec5677550e674c1Nick Pelly data->next_write = 0; 71733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh } 71833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 71933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh /* Reset buffer of data to send */ 72033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->count = sizeof(struct rtp_header) + sizeof(struct rtp_payload); 72133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->frame_count = 0; 72233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->samples = 0; 72333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->seq_num++; 72433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 72533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#ifdef ENABLE_TIMING 72633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh end = get_microseconds(); 72733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh print_time("avdtp_write", begin, end); 72833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#endif 72933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh return 0; /* always return success */ 73033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh} 73133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 73233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganeshstatic int audioservice_send(struct bluetooth_data *data, 73333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh const bt_audio_msg_header_t *msg) 73433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh{ 73533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh int err; 73633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh uint16_t length; 73733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 73874c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh length = msg->length ? msg->length : BT_SUGGESTED_BUFFER_SIZE; 73933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 740927aeb48a23a21c95f57ee990779fd529539873eEric Laurent VDBG("sending %s", bt_audio_strtype(msg->type)); 74133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh if (send(data->server.fd, msg, length, 74233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh MSG_NOSIGNAL) > 0) 74333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh err = 0; 74433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh else { 74533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh err = -errno; 74633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh ERR("Error sending data to audio service: %s(%d)", 74733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh strerror(errno), errno); 74833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh if (err == -EPIPE) 74933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh bluetooth_close(data); 75033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh } 75133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 75233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh return err; 75333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh} 75433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 75533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganeshstatic int audioservice_recv(struct bluetooth_data *data, 75633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh bt_audio_msg_header_t *inmsg) 75733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh{ 75833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh int err, ret; 75933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh const char *type, *name; 76074c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh uint16_t length; 76133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 762104ccdd9639814000c5a817b3e22bee4a1c89598Jaikumar Ganesh length = inmsg->length ? inmsg->length : BT_SUGGESTED_BUFFER_SIZE; 76333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 76433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh ret = recv(data->server.fd, inmsg, length, 0); 76574c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh if (ret < 0) { 76674c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh err = -errno; 76774c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh ERR("Error receiving IPC data from bluetoothd: %s (%d)", 76874c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh strerror(errno), errno); 76933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh if (err == -EPIPE) 77033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh bluetooth_close(data); 77174c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh } else if ((size_t) ret < sizeof(bt_audio_msg_header_t)) { 77274c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh ERR("Too short (%d bytes) IPC packet from bluetoothd", ret); 77374c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh err = -EINVAL; 774104ccdd9639814000c5a817b3e22bee4a1c89598Jaikumar Ganesh } else if (inmsg->type == BT_ERROR) { 775104ccdd9639814000c5a817b3e22bee4a1c89598Jaikumar Ganesh bt_audio_error_t *error = (bt_audio_error_t *)inmsg; 776104ccdd9639814000c5a817b3e22bee4a1c89598Jaikumar Ganesh ret = recv(data->server.fd, &error->posix_errno, 777104ccdd9639814000c5a817b3e22bee4a1c89598Jaikumar Ganesh sizeof(error->posix_errno), 0); 778104ccdd9639814000c5a817b3e22bee4a1c89598Jaikumar Ganesh if (ret < 0) { 779104ccdd9639814000c5a817b3e22bee4a1c89598Jaikumar Ganesh err = -errno; 780104ccdd9639814000c5a817b3e22bee4a1c89598Jaikumar Ganesh ERR("Error receiving error code for BT_ERROR: %s (%d)", 781104ccdd9639814000c5a817b3e22bee4a1c89598Jaikumar Ganesh strerror(errno), errno); 782104ccdd9639814000c5a817b3e22bee4a1c89598Jaikumar Ganesh if (err == -EPIPE) 783104ccdd9639814000c5a817b3e22bee4a1c89598Jaikumar Ganesh bluetooth_close(data); 784104ccdd9639814000c5a817b3e22bee4a1c89598Jaikumar Ganesh } else { 785104ccdd9639814000c5a817b3e22bee4a1c89598Jaikumar Ganesh ERR("%s failed : %s(%d)", 786104ccdd9639814000c5a817b3e22bee4a1c89598Jaikumar Ganesh bt_audio_strname(error->h.name), 787104ccdd9639814000c5a817b3e22bee4a1c89598Jaikumar Ganesh strerror(error->posix_errno), 788104ccdd9639814000c5a817b3e22bee4a1c89598Jaikumar Ganesh error->posix_errno); 789104ccdd9639814000c5a817b3e22bee4a1c89598Jaikumar Ganesh err = -error->posix_errno; 790104ccdd9639814000c5a817b3e22bee4a1c89598Jaikumar Ganesh } 79174c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh } else { 79274c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh type = bt_audio_strtype(inmsg->type); 79374c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh name = bt_audio_strname(inmsg->name); 79474c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh if (type && name) { 79574c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh DBG("Received %s - %s", type, name); 79674c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh err = 0; 79774c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh } else { 79874c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh err = -EINVAL; 79974c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh ERR("Bogus message type %d - name %d" 80074c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh " received from audio service", 80174c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh inmsg->type, inmsg->name); 80274c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh } 80374c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh 80474c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh } 80533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh return err; 80633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh} 80733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 80833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganeshstatic int audioservice_expect(struct bluetooth_data *data, 80933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh bt_audio_msg_header_t *rsp_hdr, int expected_name) 81033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh{ 81174c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh int err = audioservice_recv(data, rsp_hdr); 81274c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh 81374c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh if (err != 0) 81474c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh return err; 81574c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh 81674c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh if (rsp_hdr->name != expected_name) { 81774c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh err = -EINVAL; 81874c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh ERR("Bogus message %s received while %s was expected", 81974c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh bt_audio_strname(rsp_hdr->name), 82074c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh bt_audio_strname(expected_name)); 82174c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh } 82274c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh return err; 82333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 82433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh} 82533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 82633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganeshstatic int bluetooth_init(struct bluetooth_data *data) 82733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh{ 82833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh int sk, err; 829927aeb48a23a21c95f57ee990779fd529539873eEric Laurent struct timeval tv = {.tv_sec = RECV_TIMEOUT}; 83033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 83133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh DBG("bluetooth_init"); 83233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 83333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh sk = bt_audio_service_open(); 834927aeb48a23a21c95f57ee990779fd529539873eEric Laurent if (sk < 0) { 83533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh ERR("bt_audio_service_open failed\n"); 83633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh return -errno; 83733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh } 83833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 839927aeb48a23a21c95f57ee990779fd529539873eEric Laurent err = setsockopt(sk, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); 840927aeb48a23a21c95f57ee990779fd529539873eEric Laurent if (err < 0) { 841927aeb48a23a21c95f57ee990779fd529539873eEric Laurent ERR("bluetooth_init setsockopt(SO_RCVTIMEO) failed %d", err); 842927aeb48a23a21c95f57ee990779fd529539873eEric Laurent return err; 843927aeb48a23a21c95f57ee990779fd529539873eEric Laurent } 8445abd6d6344fa6d196ab172f724e4b7e1a755689eEric Laurent 84533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->server.fd = sk; 84633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->server.events = POLLIN; 84733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->state = A2DP_STATE_INITIALIZED; 84833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 84933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh return 0; 85033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh} 85133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 85233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganeshstatic int bluetooth_parse_capabilities(struct bluetooth_data *data, 85374c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh struct bt_get_capabilities_rsp *rsp) 85433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh{ 85574c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh int bytes_left = rsp->h.length - sizeof(*rsp); 85674c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh codec_capabilities_t *codec = (void *) rsp->data; 85733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 85874c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh if (codec->transport != BT_CAPABILITIES_TRANSPORT_A2DP) 859927aeb48a23a21c95f57ee990779fd529539873eEric Laurent return -EINVAL; 86033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 86174c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh while (bytes_left > 0) { 86274c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh if ((codec->type == BT_A2DP_SBC_SINK) && 863927aeb48a23a21c95f57ee990779fd529539873eEric Laurent !(codec->lock & BT_WRITE_LOCK)) 86474c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh break; 86533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 866927aeb48a23a21c95f57ee990779fd529539873eEric Laurent if (codec->length == 0) { 867927aeb48a23a21c95f57ee990779fd529539873eEric Laurent ERR("bluetooth_parse_capabilities() invalid codec capabilities length"); 868927aeb48a23a21c95f57ee990779fd529539873eEric Laurent return -EINVAL; 869927aeb48a23a21c95f57ee990779fd529539873eEric Laurent } 87074c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh bytes_left -= codec->length; 871927aeb48a23a21c95f57ee990779fd529539873eEric Laurent codec = (codec_capabilities_t *)((char *)codec + codec->length); 87274c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh } 87333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 87474c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh if (bytes_left <= 0 || 87574c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh codec->length != sizeof(data->sbc_capabilities)) 87674c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh return -EINVAL; 87733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 87874c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh memcpy(&data->sbc_capabilities, codec, codec->length); 87974c3402b5b785402f2632398bca971719f5aa1a5Jaikumar Ganesh return 0; 88033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh} 88133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 88233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 88333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganeshstatic int bluetooth_configure(struct bluetooth_data *data) 88433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh{ 88533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh char buf[BT_SUGGESTED_BUFFER_SIZE]; 88633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh struct bt_get_capabilities_req *getcaps_req = (void*) buf; 88733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh struct bt_get_capabilities_rsp *getcaps_rsp = (void*) buf; 88833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh int err; 88933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 89033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh DBG("bluetooth_configure"); 89133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 89233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->state = A2DP_STATE_CONFIGURING; 89333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh memset(getcaps_req, 0, BT_SUGGESTED_BUFFER_SIZE); 89433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh getcaps_req->h.type = BT_REQUEST; 89533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh getcaps_req->h.name = BT_GET_CAPABILITIES; 89633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 89733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh getcaps_req->flags = 0; 89833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh getcaps_req->flags |= BT_FLAG_AUTOCONNECT; 89933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh strncpy(getcaps_req->destination, data->address, 18); 90033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh getcaps_req->transport = BT_CAPABILITIES_TRANSPORT_A2DP; 90133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh getcaps_req->h.length = sizeof(*getcaps_req); 90233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 90333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh err = audioservice_send(data, &getcaps_req->h); 90433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh if (err < 0) { 90533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh ERR("audioservice_send failed for BT_GETCAPABILITIES_REQ\n"); 90633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh goto error; 90733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh } 90833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 90933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh getcaps_rsp->h.length = 0; 91033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh err = audioservice_expect(data, &getcaps_rsp->h, BT_GET_CAPABILITIES); 91133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh if (err < 0) { 91233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh ERR("audioservice_expect failed for BT_GETCAPABILITIES_RSP\n"); 91333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh goto error; 91433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh } 91533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 916927aeb48a23a21c95f57ee990779fd529539873eEric Laurent err = bluetooth_parse_capabilities(data, getcaps_rsp); 917927aeb48a23a21c95f57ee990779fd529539873eEric Laurent if (err < 0) { 918927aeb48a23a21c95f57ee990779fd529539873eEric Laurent ERR("bluetooth_parse_capabilities failed err: %d", err); 919927aeb48a23a21c95f57ee990779fd529539873eEric Laurent goto error; 920927aeb48a23a21c95f57ee990779fd529539873eEric Laurent } 921927aeb48a23a21c95f57ee990779fd529539873eEric Laurent 92233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh err = bluetooth_a2dp_hw_params(data); 92333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh if (err < 0) { 92433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh ERR("bluetooth_a2dp_hw_params failed err: %d", err); 92533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh goto error; 92633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh } 92733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 928927aeb48a23a21c95f57ee990779fd529539873eEric Laurent 92933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh set_state(data, A2DP_STATE_CONFIGURED); 93033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh return 0; 93133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 93233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesherror: 933927aeb48a23a21c95f57ee990779fd529539873eEric Laurent 934007af38ddeb22f02663a2d879634642b61457634Mathias Jeppsson if (data->state == A2DP_STATE_CONFIGURING) { 935927aeb48a23a21c95f57ee990779fd529539873eEric Laurent bluetooth_close(data); 936007af38ddeb22f02663a2d879634642b61457634Mathias Jeppsson /* notify client that thread is ready for next command */ 937007af38ddeb22f02663a2d879634642b61457634Mathias Jeppsson pthread_cond_signal(&data->client_wait); 938007af38ddeb22f02663a2d879634642b61457634Mathias Jeppsson } 93933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh return err; 94033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh} 94133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 94233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganeshstatic void set_state(struct bluetooth_data *data, a2dp_state_t state) 94333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh{ 94433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->state = state; 94533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh pthread_cond_signal(&data->client_wait); 94633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh} 94733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 94871d71d08545fdc8f923119dea69f4c274ca60b71Ian Kentstatic void __set_command(struct bluetooth_data *data, a2dp_command_t command) 94933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh{ 95033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh VDBG("set_command %d\n", command); 95133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->command = command; 95233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh pthread_cond_signal(&data->thread_wait); 95371d71d08545fdc8f923119dea69f4c274ca60b71Ian Kent return; 95471d71d08545fdc8f923119dea69f4c274ca60b71Ian Kent} 95571d71d08545fdc8f923119dea69f4c274ca60b71Ian Kent 95671d71d08545fdc8f923119dea69f4c274ca60b71Ian Kentstatic void set_command(struct bluetooth_data *data, a2dp_command_t command) 95771d71d08545fdc8f923119dea69f4c274ca60b71Ian Kent{ 95871d71d08545fdc8f923119dea69f4c274ca60b71Ian Kent pthread_mutex_lock(&data->mutex); 95971d71d08545fdc8f923119dea69f4c274ca60b71Ian Kent __set_command(data, command); 96033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh pthread_mutex_unlock(&data->mutex); 96133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh} 96233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 9639ad46087066dbeda8def8ba0fbda32b4ea7074baMike Lockwood/* timeout is in milliseconds */ 96433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganeshstatic int wait_for_start(struct bluetooth_data *data, int timeout) 96533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh{ 96633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh a2dp_state_t state = data->state; 9679ad46087066dbeda8def8ba0fbda32b4ea7074baMike Lockwood struct timeval tv; 96833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh struct timespec ts; 96933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh int err = 0; 97033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 9719ad46087066dbeda8def8ba0fbda32b4ea7074baMike Lockwood#ifdef ENABLE_TIMING 9729ad46087066dbeda8def8ba0fbda32b4ea7074baMike Lockwood uint64_t begin, end; 97333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh begin = get_microseconds(); 9749ad46087066dbeda8def8ba0fbda32b4ea7074baMike Lockwood#endif 9759ad46087066dbeda8def8ba0fbda32b4ea7074baMike Lockwood 9769ad46087066dbeda8def8ba0fbda32b4ea7074baMike Lockwood gettimeofday(&tv, (struct timezone *) NULL); 9779ad46087066dbeda8def8ba0fbda32b4ea7074baMike Lockwood ts.tv_sec = tv.tv_sec + (timeout / 1000); 9789ad46087066dbeda8def8ba0fbda32b4ea7074baMike Lockwood ts.tv_nsec = (tv.tv_usec + (timeout % 1000) * 1000L ) * 1000L; 97933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 98071d71d08545fdc8f923119dea69f4c274ca60b71Ian Kent pthread_mutex_lock(&data->mutex); 981b259b11bf5ac5259069d1144cd049e213352ed74Ian Kent while (state != A2DP_STATE_STARTED) { 98233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh if (state == A2DP_STATE_NONE) 9835abd6d6344fa6d196ab172f724e4b7e1a755689eEric Laurent __set_command(data, A2DP_CMD_INIT); 98433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh else if (state == A2DP_STATE_INITIALIZED) 98571d71d08545fdc8f923119dea69f4c274ca60b71Ian Kent __set_command(data, A2DP_CMD_CONFIGURE); 98671d71d08545fdc8f923119dea69f4c274ca60b71Ian Kent else if (state == A2DP_STATE_CONFIGURED) { 98771d71d08545fdc8f923119dea69f4c274ca60b71Ian Kent __set_command(data, A2DP_CMD_START); 98871d71d08545fdc8f923119dea69f4c274ca60b71Ian Kent } 989b259b11bf5ac5259069d1144cd049e213352ed74Ian Kentagain: 990b259b11bf5ac5259069d1144cd049e213352ed74Ian Kent err = pthread_cond_timedwait(&data->client_wait, &data->mutex, &ts); 991b259b11bf5ac5259069d1144cd049e213352ed74Ian Kent if (err) { 992b259b11bf5ac5259069d1144cd049e213352ed74Ian Kent /* don't timeout if we're done */ 993b259b11bf5ac5259069d1144cd049e213352ed74Ian Kent if (data->state == A2DP_STATE_STARTED) { 994b259b11bf5ac5259069d1144cd049e213352ed74Ian Kent err = 0; 995b259b11bf5ac5259069d1144cd049e213352ed74Ian Kent break; 996b259b11bf5ac5259069d1144cd049e213352ed74Ian Kent } 997b259b11bf5ac5259069d1144cd049e213352ed74Ian Kent if (err == ETIMEDOUT) 998b259b11bf5ac5259069d1144cd049e213352ed74Ian Kent break; 999b259b11bf5ac5259069d1144cd049e213352ed74Ian Kent goto again; 1000b259b11bf5ac5259069d1144cd049e213352ed74Ian Kent } 1001b259b11bf5ac5259069d1144cd049e213352ed74Ian Kent 1002b259b11bf5ac5259069d1144cd049e213352ed74Ian Kent if (state == data->state) 1003b259b11bf5ac5259069d1144cd049e213352ed74Ian Kent goto again; 100433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 100533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh state = data->state; 100671d71d08545fdc8f923119dea69f4c274ca60b71Ian Kent 100771d71d08545fdc8f923119dea69f4c274ca60b71Ian Kent if (state == A2DP_STATE_NONE) { 100871d71d08545fdc8f923119dea69f4c274ca60b71Ian Kent err = ENODEV; 100971d71d08545fdc8f923119dea69f4c274ca60b71Ian Kent break; 101071d71d08545fdc8f923119dea69f4c274ca60b71Ian Kent } 101133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh } 101271d71d08545fdc8f923119dea69f4c274ca60b71Ian Kent pthread_mutex_unlock(&data->mutex); 101333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 101433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#ifdef ENABLE_TIMING 101533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh end = get_microseconds(); 101633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh print_time("wait_for_start", begin, end); 101733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#endif 101833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 101933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh /* pthread_cond_timedwait returns positive errors */ 102033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh return -err; 102133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh} 102233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 1023be89a6e822dcb07e368a10fce392f2d19cc55d68Ian Kentstatic void a2dp_free(struct bluetooth_data *data) 1024be89a6e822dcb07e368a10fce392f2d19cc55d68Ian Kent{ 1025be89a6e822dcb07e368a10fce392f2d19cc55d68Ian Kent pthread_cond_destroy(&data->client_wait); 1026be89a6e822dcb07e368a10fce392f2d19cc55d68Ian Kent pthread_cond_destroy(&data->thread_wait); 1027be89a6e822dcb07e368a10fce392f2d19cc55d68Ian Kent pthread_cond_destroy(&data->thread_start); 1028be89a6e822dcb07e368a10fce392f2d19cc55d68Ian Kent pthread_mutex_destroy(&data->mutex); 1029be89a6e822dcb07e368a10fce392f2d19cc55d68Ian Kent free(data); 1030be89a6e822dcb07e368a10fce392f2d19cc55d68Ian Kent return; 1031be89a6e822dcb07e368a10fce392f2d19cc55d68Ian Kent} 1032be89a6e822dcb07e368a10fce392f2d19cc55d68Ian Kent 103333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganeshstatic void* a2dp_thread(void *d) 103433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh{ 103533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh struct bluetooth_data* data = (struct bluetooth_data*)d; 10366782d7bd225048e49ff485d06d8da5be8472fcf3Ian Kent a2dp_command_t command = A2DP_CMD_NONE; 1037927aeb48a23a21c95f57ee990779fd529539873eEric Laurent int err = 0; 103833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 103933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh DBG("a2dp_thread started"); 1040c4e47c15ae8fe36673e7cdd7ee3caaffddb5071eNick Pelly prctl(PR_SET_NAME, (int)"a2dp_thread", 0, 0, 0); 104133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 1042281c324f0ba38b0720884b53d465b1420fac616aIan Kent pthread_mutex_lock(&data->mutex); 1043281c324f0ba38b0720884b53d465b1420fac616aIan Kent 1044281c324f0ba38b0720884b53d465b1420fac616aIan Kent data->started = 1; 1045281c324f0ba38b0720884b53d465b1420fac616aIan Kent pthread_cond_signal(&data->thread_start); 1046281c324f0ba38b0720884b53d465b1420fac616aIan Kent 104733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh while (1) 104833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh { 10496782d7bd225048e49ff485d06d8da5be8472fcf3Ian Kent while (1) { 10506782d7bd225048e49ff485d06d8da5be8472fcf3Ian Kent pthread_cond_wait(&data->thread_wait, &data->mutex); 105133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 10526782d7bd225048e49ff485d06d8da5be8472fcf3Ian Kent /* Initialization needed */ 10536782d7bd225048e49ff485d06d8da5be8472fcf3Ian Kent if (data->state == A2DP_STATE_NONE && 1054927aeb48a23a21c95f57ee990779fd529539873eEric Laurent data->command != A2DP_CMD_QUIT) { 1055927aeb48a23a21c95f57ee990779fd529539873eEric Laurent err = bluetooth_init(data); 10566782d7bd225048e49ff485d06d8da5be8472fcf3Ian Kent } 10576782d7bd225048e49ff485d06d8da5be8472fcf3Ian Kent 10586782d7bd225048e49ff485d06d8da5be8472fcf3Ian Kent /* New state command signaled */ 10596782d7bd225048e49ff485d06d8da5be8472fcf3Ian Kent if (command != data->command) { 10606782d7bd225048e49ff485d06d8da5be8472fcf3Ian Kent command = data->command; 10616782d7bd225048e49ff485d06d8da5be8472fcf3Ian Kent break; 10626782d7bd225048e49ff485d06d8da5be8472fcf3Ian Kent } 10636782d7bd225048e49ff485d06d8da5be8472fcf3Ian Kent } 106433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 106533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh switch (command) { 106633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh case A2DP_CMD_CONFIGURE: 106733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh if (data->state != A2DP_STATE_INITIALIZED) 106833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh break; 1069927aeb48a23a21c95f57ee990779fd529539873eEric Laurent err = bluetooth_configure(data); 107033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh break; 107133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 107233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh case A2DP_CMD_START: 107333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh if (data->state != A2DP_STATE_CONFIGURED) 107433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh break; 1075927aeb48a23a21c95f57ee990779fd529539873eEric Laurent err = bluetooth_start(data); 107633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh break; 107733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 107833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh case A2DP_CMD_STOP: 107933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh if (data->state != A2DP_STATE_STARTED) 108033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh break; 1081927aeb48a23a21c95f57ee990779fd529539873eEric Laurent err = bluetooth_stop(data); 108233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh break; 108333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 108433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh case A2DP_CMD_QUIT: 108533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh bluetooth_close(data); 108633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh sbc_finish(&data->sbc); 1087be89a6e822dcb07e368a10fce392f2d19cc55d68Ian Kent a2dp_free(data); 108833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh goto done; 108933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 1090533b9f6e793e4c7aa09e7127077d8e9a2d388504Nick Pelly case A2DP_CMD_INIT: 1091533b9f6e793e4c7aa09e7127077d8e9a2d388504Nick Pelly /* already called bluetooth_init() */ 109233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh default: 109333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh break; 109433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh } 1095927aeb48a23a21c95f57ee990779fd529539873eEric Laurent // reset last command in case of error to allow 1096927aeb48a23a21c95f57ee990779fd529539873eEric Laurent // re-execution of the same command 1097927aeb48a23a21c95f57ee990779fd529539873eEric Laurent if (err < 0) { 1098927aeb48a23a21c95f57ee990779fd529539873eEric Laurent command = A2DP_CMD_NONE; 1099927aeb48a23a21c95f57ee990779fd529539873eEric Laurent } 110033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh } 110133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 110233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganeshdone: 1103281c324f0ba38b0720884b53d465b1420fac616aIan Kent pthread_mutex_unlock(&data->mutex); 110433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh DBG("a2dp_thread finished"); 110533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh return NULL; 110633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh} 110733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 110833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganeshint a2dp_init(int rate, int channels, a2dpData* dataPtr) 110933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh{ 111033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh struct bluetooth_data* data; 111133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh pthread_attr_t attr; 111233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh int err; 111333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 111433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh DBG("a2dp_init rate: %d channels: %d", rate, channels); 111533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh *dataPtr = NULL; 111633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data = malloc(sizeof(struct bluetooth_data)); 111733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh if (!data) 111833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh return -1; 111933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 112033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh memset(data, 0, sizeof(struct bluetooth_data)); 112133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->server.fd = -1; 112233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->stream.fd = -1; 112333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->state = A2DP_STATE_NONE; 11246782d7bd225048e49ff485d06d8da5be8472fcf3Ian Kent data->command = A2DP_CMD_NONE; 112533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 112633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh strncpy(data->address, "00:00:00:00:00:00", 18); 112733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->rate = rate; 112833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->channels = channels; 112933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 113033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh sbc_init(&data->sbc, 0); 113133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 113233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh pthread_mutex_init(&data->mutex, NULL); 11335bac662a139181195fae0a6292bdc6c12ba6f463Ian Kent pthread_cond_init(&data->thread_start, NULL); 113433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh pthread_cond_init(&data->thread_wait, NULL); 113533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh pthread_cond_init(&data->client_wait, NULL); 113633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 11375bac662a139181195fae0a6292bdc6c12ba6f463Ian Kent pthread_mutex_lock(&data->mutex); 11385bac662a139181195fae0a6292bdc6c12ba6f463Ian Kent data->started = 0; 11395bac662a139181195fae0a6292bdc6c12ba6f463Ian Kent 114033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh pthread_attr_init(&attr); 114133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 11425bac662a139181195fae0a6292bdc6c12ba6f463Ian Kent 11435bac662a139181195fae0a6292bdc6c12ba6f463Ian Kent err = pthread_create(&data->thread, &attr, a2dp_thread, data); 11445bac662a139181195fae0a6292bdc6c12ba6f463Ian Kent if (err) { 11455bac662a139181195fae0a6292bdc6c12ba6f463Ian Kent /* If the thread create fails we must not wait */ 11465bac662a139181195fae0a6292bdc6c12ba6f463Ian Kent pthread_mutex_unlock(&data->mutex); 11475bac662a139181195fae0a6292bdc6c12ba6f463Ian Kent err = -err; 11485bac662a139181195fae0a6292bdc6c12ba6f463Ian Kent goto error; 11495bac662a139181195fae0a6292bdc6c12ba6f463Ian Kent } 11505bac662a139181195fae0a6292bdc6c12ba6f463Ian Kent 1151281c324f0ba38b0720884b53d465b1420fac616aIan Kent /* Make sure the state machine is ready and waiting */ 11525bac662a139181195fae0a6292bdc6c12ba6f463Ian Kent while (!data->started) { 11535bac662a139181195fae0a6292bdc6c12ba6f463Ian Kent pthread_cond_wait(&data->thread_start, &data->mutex); 11545bac662a139181195fae0a6292bdc6c12ba6f463Ian Kent } 11555bac662a139181195fae0a6292bdc6c12ba6f463Ian Kent 1156281c324f0ba38b0720884b53d465b1420fac616aIan Kent /* Poke the state machine to get it going */ 1157281c324f0ba38b0720884b53d465b1420fac616aIan Kent pthread_cond_signal(&data->thread_wait); 1158281c324f0ba38b0720884b53d465b1420fac616aIan Kent 11595bac662a139181195fae0a6292bdc6c12ba6f463Ian Kent pthread_mutex_unlock(&data->mutex); 11603da4d6ad9402b574ee4dc7923f1d27b1fa2302a0Ian Kent pthread_attr_destroy(&attr); 116133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 116233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh *dataPtr = data; 116333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh return 0; 116433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesherror: 116533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh bluetooth_close(data); 11665bac662a139181195fae0a6292bdc6c12ba6f463Ian Kent sbc_finish(&data->sbc); 11673da4d6ad9402b574ee4dc7923f1d27b1fa2302a0Ian Kent pthread_attr_destroy(&attr); 1168be89a6e822dcb07e368a10fce392f2d19cc55d68Ian Kent a2dp_free(data); 116933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 117033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh return err; 117133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh} 117233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 117333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganeshvoid a2dp_set_sink(a2dpData d, const char* address) 117433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh{ 117533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh struct bluetooth_data* data = (struct bluetooth_data*)d; 117633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh if (strncmp(data->address, address, 18)) { 117733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh strncpy(data->address, address, 18); 117867bf8f93bc209d3d8873d41662796ecec0d6524cJaikumar Ganesh set_command(data, A2DP_CMD_INIT); 117933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh } 118033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh} 118133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 118233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganeshint a2dp_write(a2dpData d, const void* buffer, int count) 118333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh{ 118433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh struct bluetooth_data* data = (struct bluetooth_data*)d; 118533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh uint8_t* src = (uint8_t *)buffer; 118633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh int codesize; 118733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh int err, ret = 0; 118833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh long frames_left = count; 1189c4e47c15ae8fe36673e7cdd7ee3caaffddb5071eNick Pelly int encoded; 1190c4e47c15ae8fe36673e7cdd7ee3caaffddb5071eNick Pelly unsigned int written; 119133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh const char *buff; 119233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh int did_configure = 0; 119333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#ifdef ENABLE_TIMING 119433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh uint64_t begin, end; 119533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh DBG("********** a2dp_write **********"); 119633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh begin = get_microseconds(); 119733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#endif 119833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 119933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh err = wait_for_start(data, WRITE_TIMEOUT); 120033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh if (err < 0) 120133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh return err; 120233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 120333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh codesize = data->codesize; 120433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 120533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh while (frames_left >= codesize) { 120633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh /* Enough data to encode (sbc wants 512 byte blocks) */ 120733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh encoded = sbc_encode(&(data->sbc), src, codesize, 120833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->buffer + data->count, 120933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh sizeof(data->buffer) - data->count, 121033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh &written); 121133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh if (encoded <= 0) { 121233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh ERR("Encoding error %d", encoded); 121333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh goto done; 121433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh } 121533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh VDBG("sbc_encode returned %d, codesize: %d, written: %d\n", 121633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh encoded, codesize, written); 121733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 121833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh src += encoded; 121933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->count += written; 122033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->frame_count++; 122133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->samples += encoded; 122233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->nsamples += encoded; 122333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 122433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh /* No space left for another frame then send */ 12259d60b87413f23ef48d3cb24bb44f51745c02a332Yu Kang Ku if ((data->count + written >= data->link_mtu) || 12269d60b87413f23ef48d3cb24bb44f51745c02a332Yu Kang Ku (data->count + written >= BUFFER_SIZE)) { 122733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh VDBG("sending packet %d, count %d, link_mtu %u", 122833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->seq_num, data->count, 122933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh data->link_mtu); 123033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh err = avdtp_write(data); 123133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh if (err < 0) 123233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh return err; 123333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh } 123433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 123533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh ret += encoded; 123633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh frames_left -= encoded; 123733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh } 123833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 123933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh if (frames_left > 0) 124033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh ERR("%ld bytes left at end of a2dp_write\n", frames_left); 124133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 124233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganeshdone: 124333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#ifdef ENABLE_TIMING 124433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh end = get_microseconds(); 124533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh print_time("a2dp_write total", begin, end); 124633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh#endif 124733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh return ret; 124833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh} 124933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 125033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganeshint a2dp_stop(a2dpData d) 125133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh{ 125233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh struct bluetooth_data* data = (struct bluetooth_data*)d; 125333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh DBG("a2dp_stop\n"); 125433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh if (!data) 125533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh return 0; 125633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 125733e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh set_command(data, A2DP_CMD_STOP); 125833e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh return 0; 125933e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh} 126033e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh 126133e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganeshvoid a2dp_cleanup(a2dpData d) 126233e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh{ 126333e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh struct bluetooth_data* data = (struct bluetooth_data*)d; 126433e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh DBG("a2dp_cleanup\n"); 126533e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh set_command(data, A2DP_CMD_QUIT); 126633e9fec43232e0341dba27786ec207c0d366b8b2Jaikumar Ganesh} 1267