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
cras_a2dp_get_capabilities(struct cras_bt_endpoint * endpoint,void * capabilities,int * len)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
cras_a2dp_select_configuration(struct cras_bt_endpoint * endpoint,void * capabilities,int len,void * configuration)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
cras_a2dp_set_configuration(struct cras_bt_endpoint * endpoint,struct cras_bt_transport * transport)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
cras_a2dp_suspend(struct cras_bt_endpoint * endpoint,struct cras_bt_transport * transport)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
a2dp_transport_state_changed(struct cras_bt_endpoint * endpoint,struct cras_bt_transport * transport)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
cras_a2dp_endpoint_create(DBusConnection * conn)179 int cras_a2dp_endpoint_create(DBusConnection *conn)
180 {
181 return cras_bt_endpoint_add(conn, &cras_a2dp_endpoint);
182 }
183
cras_a2dp_start(struct cras_bt_device * device)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
cras_a2dp_connected_device()206 struct cras_bt_device *cras_a2dp_connected_device()
207 {
208 return connected_a2dp.device;
209 }
210
cras_a2dp_suspend_connected_device(struct cras_bt_device * device)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