Home | History | Annotate | Download | only in server
      1 /* Copyright (c) 2013 The Chromium Authors. All rights reserved.
      2  * Use of this source code is governed by a BSD-style license that can be
      3  * found in the LICENSE file.
      4  */
      5 
      6 #include <errno.h>
      7 #include <stdint.h>
      8 #include <syslog.h>
      9 
     10 #include "a2dp-codecs.h"
     11 #include "cras_a2dp_endpoint.h"
     12 #include "cras_a2dp_iodev.h"
     13 #include "cras_iodev.h"
     14 #include "cras_bt_constants.h"
     15 #include "cras_bt_endpoint.h"
     16 #include "cras_system_state.h"
     17 #include "cras_util.h"
     18 
     19 #define A2DP_SOURCE_ENDPOINT_PATH "/org/chromium/Cras/Bluetooth/A2DPSource"
     20 #define A2DP_SINK_ENDPOINT_PATH   "/org/chromium/Cras/Bluetooth/A2DPSink"
     21 
     22 
     23 /* Pointers for the only connected a2dp device. */
     24 static struct a2dp {
     25 	struct cras_iodev *iodev;
     26 	struct cras_bt_device *device;
     27 } connected_a2dp;
     28 
     29 static int cras_a2dp_get_capabilities(struct cras_bt_endpoint *endpoint,
     30 				      void *capabilities, int *len)
     31 {
     32 	a2dp_sbc_t *sbc_caps = capabilities;
     33 
     34 	if (*len < sizeof(*sbc_caps))
     35 		return -ENOSPC;
     36 
     37 	*len = sizeof(*sbc_caps);
     38 
     39 	/* Return all capabilities. */
     40 	sbc_caps->channel_mode = SBC_CHANNEL_MODE_MONO |
     41 			SBC_CHANNEL_MODE_DUAL_CHANNEL |
     42 			SBC_CHANNEL_MODE_STEREO |
     43 			SBC_CHANNEL_MODE_JOINT_STEREO;
     44 	sbc_caps->frequency = SBC_SAMPLING_FREQ_16000 |
     45 			SBC_SAMPLING_FREQ_32000 |
     46 			SBC_SAMPLING_FREQ_44100 |
     47 			SBC_SAMPLING_FREQ_48000;
     48 	sbc_caps->allocation_method = SBC_ALLOCATION_SNR |
     49 			SBC_ALLOCATION_LOUDNESS;
     50 	sbc_caps->subbands = SBC_SUBBANDS_4 | SBC_SUBBANDS_8;
     51 	sbc_caps->block_length = SBC_BLOCK_LENGTH_4 |
     52 			SBC_BLOCK_LENGTH_8 |
     53 			SBC_BLOCK_LENGTH_12 |
     54 			SBC_BLOCK_LENGTH_16;
     55 	sbc_caps->min_bitpool = MIN_BITPOOL;
     56 	sbc_caps->max_bitpool = MAX_BITPOOL;
     57 
     58 	return 0;
     59 }
     60 
     61 static int cras_a2dp_select_configuration(struct cras_bt_endpoint *endpoint,
     62 					  void *capabilities, int len,
     63 					  void *configuration)
     64 {
     65 	a2dp_sbc_t *sbc_caps = capabilities;
     66 	a2dp_sbc_t *sbc_config = configuration;
     67 
     68 	/* Pick the highest configuration. */
     69 	if (sbc_caps->channel_mode & SBC_CHANNEL_MODE_JOINT_STEREO) {
     70 		sbc_config->channel_mode = SBC_CHANNEL_MODE_JOINT_STEREO;
     71 	} else if (sbc_caps->channel_mode & SBC_CHANNEL_MODE_STEREO) {
     72 		sbc_config->channel_mode = SBC_CHANNEL_MODE_STEREO;
     73 	} else if (sbc_caps->channel_mode & SBC_CHANNEL_MODE_DUAL_CHANNEL) {
     74 		sbc_config->channel_mode = SBC_CHANNEL_MODE_DUAL_CHANNEL;
     75 	} else if (sbc_caps->channel_mode & SBC_CHANNEL_MODE_MONO) {
     76 		sbc_config->channel_mode = SBC_CHANNEL_MODE_MONO;
     77 	} else {
     78 		syslog(LOG_WARNING, "No supported channel modes.");
     79 		return -ENOSYS;
     80 	}
     81 
     82 	if (sbc_caps->frequency & SBC_SAMPLING_FREQ_48000) {
     83 		sbc_config->frequency = SBC_SAMPLING_FREQ_48000;
     84 	} else if (sbc_caps->frequency & SBC_SAMPLING_FREQ_44100) {
     85 		sbc_config->frequency = SBC_SAMPLING_FREQ_44100;
     86 	} else if (sbc_caps->frequency & SBC_SAMPLING_FREQ_32000) {
     87 		sbc_config->frequency = SBC_SAMPLING_FREQ_32000;
     88 	} else if (sbc_caps->frequency & SBC_SAMPLING_FREQ_16000) {
     89 		sbc_config->frequency = SBC_SAMPLING_FREQ_16000;
     90 	} else {
     91 		syslog(LOG_WARNING, "No supported sampling frequencies.");
     92 		return -ENOSYS;
     93 	}
     94 
     95 	if (sbc_caps->allocation_method & SBC_ALLOCATION_LOUDNESS) {
     96 		sbc_config->allocation_method = SBC_ALLOCATION_LOUDNESS;
     97 	} else if (sbc_caps->allocation_method & SBC_ALLOCATION_SNR) {
     98 		sbc_config->allocation_method = SBC_ALLOCATION_SNR;
     99 	} else {
    100 		syslog(LOG_WARNING, "No supported allocation method.");
    101 		return -ENOSYS;
    102 	}
    103 
    104 	if (sbc_caps->subbands & SBC_SUBBANDS_8) {
    105 		sbc_config->subbands = SBC_SUBBANDS_8;
    106 	} else if (sbc_caps->subbands & SBC_SUBBANDS_4) {
    107 		sbc_config->subbands = SBC_SUBBANDS_4;
    108 	} else {
    109 		syslog(LOG_WARNING, "No supported subbands.");
    110 		return -ENOSYS;
    111 	}
    112 
    113 	if (sbc_caps->block_length & SBC_BLOCK_LENGTH_16) {
    114 		sbc_config->block_length = SBC_BLOCK_LENGTH_16;
    115 	} else if (sbc_caps->block_length & SBC_BLOCK_LENGTH_12) {
    116 		sbc_config->block_length = SBC_BLOCK_LENGTH_12;
    117 	} else if (sbc_caps->block_length & SBC_BLOCK_LENGTH_8) {
    118 		sbc_config->block_length = SBC_BLOCK_LENGTH_8;
    119 	} else if (sbc_caps->block_length & SBC_BLOCK_LENGTH_4) {
    120 		sbc_config->block_length = SBC_BLOCK_LENGTH_4;
    121 	} else {
    122 		syslog(LOG_WARNING, "No supported block length.");
    123 		return -ENOSYS;
    124 	}
    125 
    126 	sbc_config->min_bitpool = (sbc_caps->min_bitpool > MIN_BITPOOL
    127 				   ? sbc_caps->min_bitpool : MIN_BITPOOL);
    128 	sbc_config->max_bitpool = (sbc_caps->max_bitpool < MAX_BITPOOL
    129 				   ? sbc_caps->max_bitpool : MAX_BITPOOL);
    130 
    131 	return 0;
    132 }
    133 
    134 static void cras_a2dp_set_configuration(struct cras_bt_endpoint *endpoint,
    135 			    struct cras_bt_transport *transport)
    136 {
    137 	struct cras_bt_device *device;
    138 
    139 	device = cras_bt_transport_device(transport);
    140 	cras_bt_device_a2dp_configured(device);
    141 }
    142 
    143 static void cras_a2dp_suspend(struct cras_bt_endpoint *endpoint,
    144 			      struct cras_bt_transport *transport)
    145 {
    146 	struct cras_bt_device *device = cras_bt_transport_device(transport);
    147 	cras_a2dp_suspend_connected_device(device);
    148 }
    149 
    150 static void a2dp_transport_state_changed(struct cras_bt_endpoint *endpoint,
    151 					 struct cras_bt_transport *transport)
    152 {
    153 	if (connected_a2dp.iodev && transport) {
    154 		/* When pending message is received in bluez, try to aquire
    155 		 * the transport. */
    156 		if (cras_bt_transport_fd(transport) != -1 &&
    157 		    cras_bt_transport_state(transport) ==
    158 				CRAS_BT_TRANSPORT_STATE_PENDING)
    159 			cras_bt_transport_try_acquire(transport);
    160 	}
    161 }
    162 
    163 static struct cras_bt_endpoint cras_a2dp_endpoint = {
    164 	/* BlueZ connects the device A2DP Sink to our A2DP Source endpoint,
    165 	 * and the device A2DP Source to our A2DP Sink. It's best if you don't
    166 	 * think about it too hard.
    167 	 */
    168 	.object_path = A2DP_SOURCE_ENDPOINT_PATH,
    169 	.uuid = A2DP_SOURCE_UUID,
    170 	.codec = A2DP_CODEC_SBC,
    171 
    172 	.get_capabilities = cras_a2dp_get_capabilities,
    173 	.select_configuration = cras_a2dp_select_configuration,
    174 	.set_configuration = cras_a2dp_set_configuration,
    175 	.suspend = cras_a2dp_suspend,
    176 	.transport_state_changed = a2dp_transport_state_changed
    177 };
    178 
    179 int cras_a2dp_endpoint_create(DBusConnection *conn)
    180 {
    181 	return cras_bt_endpoint_add(conn, &cras_a2dp_endpoint);
    182 }
    183 
    184 void cras_a2dp_start(struct cras_bt_device *device)
    185 {
    186 	struct cras_bt_transport *transport = cras_a2dp_endpoint.transport;
    187 
    188 	if (!transport || device != cras_bt_transport_device(transport)) {
    189 		syslog(LOG_ERR, "Device and active transport not match.");
    190 		return;
    191 	}
    192 
    193 	if (connected_a2dp.iodev) {
    194 		syslog(LOG_WARNING,
    195 		       "Replacing existing endpoint configuration");
    196 		a2dp_iodev_destroy(connected_a2dp.iodev);
    197 	}
    198 
    199 	connected_a2dp.iodev = a2dp_iodev_create(transport);
    200 	connected_a2dp.device = cras_bt_transport_device(transport);
    201 
    202 	if (!connected_a2dp.iodev)
    203 		syslog(LOG_WARNING, "Failed to create a2dp iodev");
    204 }
    205 
    206 struct cras_bt_device *cras_a2dp_connected_device()
    207 {
    208 	return connected_a2dp.device;
    209 }
    210 
    211 void cras_a2dp_suspend_connected_device(struct cras_bt_device *device)
    212 {
    213 	if (connected_a2dp.device != device)
    214 		return;
    215 
    216 	if (connected_a2dp.iodev) {
    217 		syslog(LOG_INFO, "Destroying iodev for A2DP device");
    218 		a2dp_iodev_destroy(connected_a2dp.iodev);
    219 		connected_a2dp.iodev = NULL;
    220 		connected_a2dp.device = NULL;
    221 	}
    222 }
    223