• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright (c) 2013 The Chromium OS 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 <stdint.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <sys/socket.h>
10 #include <syslog.h>
11 
12 #include "audio_thread.h"
13 #include "byte_buffer.h"
14 #include "cras_iodev_list.h"
15 #include "cras_hfp_info.h"
16 #include "utlist.h"
17 
18 /* The max buffer size. Note that the actual used size must set to multiple
19  * of SCO packet size, and the packet size does not necessarily be equal to
20  * MTU.
21  */
22 #define MAX_HFP_BUF_SIZE_BYTES 16384
23 
24 /* rate(8kHz) * sample_size(2 bytes) * channels(1) */
25 #define HFP_BYTE_RATE 16000
26 
27 /* Structure to hold variables for a HFP connection. Since HFP supports
28  * bi-direction audio, two iodevs should share one hfp_info if they
29  * represent two directions of the same HFP headset
30  * Members:
31  *     fd - The file descriptor for SCO socket.
32  *     started - If the hfp_info has started to read/write SCO data.
33  *     mtu - The max transmit unit reported from BT adapter.
34  *     packet_size - The size of SCO packet to read/write preferred by
35  *         adapter, could be different than mtu.
36  *     capture_buf - The buffer to hold samples read from SCO socket.
37  *     playback_buf - The buffer to hold samples about to write to SCO socket.
38  *     idev - The input iodev using this hfp_info.
39  *     odev - The output iodev using this hfp_info.
40  *     packet_size_changed_cbs - The callbacks to trigger when SCO packet
41  *         size changed.
42  */
43 struct hfp_info {
44 	int fd;
45 	int started;
46 	unsigned int mtu;
47 	unsigned int packet_size;
48 	struct byte_buffer *capture_buf;
49 	struct byte_buffer *playback_buf;
50 
51 	struct cras_iodev *idev;
52 	struct cras_iodev *odev;
53 	struct hfp_packet_size_changed_callback *packet_size_changed_cbs;
54 };
55 
hfp_info_add_iodev(struct hfp_info * info,struct cras_iodev * dev)56 int hfp_info_add_iodev(struct hfp_info *info, struct cras_iodev *dev)
57 {
58 	if (dev->direction == CRAS_STREAM_OUTPUT) {
59 		if (info->odev)
60 			goto invalid;
61 		info->odev = dev;
62 
63 		buf_reset(info->playback_buf);
64 	} else if (dev->direction == CRAS_STREAM_INPUT) {
65 		if (info->idev)
66 			goto invalid;
67 		info->idev = dev;
68 
69 		buf_reset(info->capture_buf);
70 	}
71 
72 	return 0;
73 
74 invalid:
75 	return -EINVAL;
76 }
77 
hfp_info_rm_iodev(struct hfp_info * info,struct cras_iodev * dev)78 int hfp_info_rm_iodev(struct hfp_info *info, struct cras_iodev *dev)
79 {
80 	if (dev->direction == CRAS_STREAM_OUTPUT && info->odev == dev) {
81 		info->odev = NULL;
82 	} else if (dev->direction == CRAS_STREAM_INPUT && info->idev == dev){
83 		info->idev = NULL;
84 	} else
85 		return -EINVAL;
86 
87 	return 0;
88 }
89 
hfp_info_has_iodev(struct hfp_info * info)90 int hfp_info_has_iodev(struct hfp_info *info)
91 {
92 	return info->odev || info->idev;
93 }
94 
hfp_buf_acquire(struct hfp_info * info,struct cras_iodev * dev,uint8_t ** buf,unsigned * count)95 void hfp_buf_acquire(struct hfp_info *info, struct cras_iodev *dev,
96 		     uint8_t **buf, unsigned *count)
97 {
98 	size_t format_bytes;
99 	unsigned int buf_avail;
100 	format_bytes = cras_get_format_bytes(dev->format);
101 
102 	*count *= format_bytes;
103 
104 	if (dev->direction == CRAS_STREAM_OUTPUT)
105 		*buf = buf_write_pointer_size(info->playback_buf, &buf_avail);
106 	else
107 		*buf = buf_read_pointer_size(info->capture_buf, &buf_avail);
108 
109 	if (*count > buf_avail)
110 		*count = buf_avail;
111 	*count /= format_bytes;
112 }
113 
hfp_buf_size(struct hfp_info * info,struct cras_iodev * dev)114 int hfp_buf_size(struct hfp_info *info, struct cras_iodev *dev)
115 {
116 	return info->playback_buf->used_size / cras_get_format_bytes(dev->format);
117 }
118 
hfp_buf_release(struct hfp_info * info,struct cras_iodev * dev,unsigned written_frames)119 void hfp_buf_release(struct hfp_info *info, struct cras_iodev *dev,
120 		     unsigned written_frames)
121 {
122 	size_t format_bytes;
123 	format_bytes = cras_get_format_bytes(dev->format);
124 
125 	written_frames *= format_bytes;
126 
127 	if (dev->direction == CRAS_STREAM_OUTPUT)
128 		buf_increment_write(info->playback_buf, written_frames);
129 	else
130 		buf_increment_read(info->capture_buf, written_frames);
131 }
132 
hfp_buf_queued(struct hfp_info * info,const struct cras_iodev * dev)133 int hfp_buf_queued(struct hfp_info *info, const struct cras_iodev *dev)
134 {
135 	size_t format_bytes;
136 	format_bytes = cras_get_format_bytes(dev->format);
137 
138 	if (dev->direction == CRAS_STREAM_OUTPUT)
139 		return buf_queued_bytes(info->playback_buf) / format_bytes;
140 	else
141 		return buf_queued_bytes(info->capture_buf) / format_bytes;
142 }
143 
hfp_write(struct hfp_info * info)144 int hfp_write(struct hfp_info *info)
145 {
146 	int err = 0;
147 	unsigned to_send;
148 	uint8_t *samples;
149 
150 	/* Write something */
151 	samples = buf_read_pointer_size(info->playback_buf, &to_send);
152 	if (to_send < info->packet_size)
153 		return 0;
154 	to_send = info->packet_size;
155 
156 send_sample:
157 	err = send(info->fd, samples, to_send, 0);
158 	if (err < 0) {
159 		if (errno == EINTR)
160 			goto send_sample;
161 
162 		return err;
163 	}
164 
165 	if (err != (int)info->packet_size) {
166 		syslog(LOG_ERR,
167 		       "Partially write %d bytes for SCO packet size %u",
168 		       err, info->packet_size);
169 		return -1;
170 	}
171 
172 	buf_increment_read(info->playback_buf, to_send);
173 
174 	return err;
175 }
176 
177 
hfp_info_set_packet_size(struct hfp_info * info,unsigned int packet_size)178 static void hfp_info_set_packet_size(struct hfp_info *info,
179 				     unsigned int packet_size)
180 {
181 	struct hfp_packet_size_changed_callback *callback;
182 	unsigned int used_size =
183 		MAX_HFP_BUF_SIZE_BYTES / packet_size * packet_size;
184 	info->packet_size = packet_size;
185 	byte_buffer_set_used_size(info->playback_buf, used_size);
186 	byte_buffer_set_used_size(info->capture_buf, used_size);
187 
188 	DL_FOREACH(info->packet_size_changed_cbs, callback)
189 		callback->cb(callback->data);
190 }
191 
hfp_register_packet_size_changed_callback(struct hfp_info * info,void (* cb)(void * data),void * data)192 void hfp_register_packet_size_changed_callback(struct hfp_info *info,
193 					       void (*cb)(void *data),
194 					       void *data)
195 {
196 	struct hfp_packet_size_changed_callback *callback =
197 		(struct hfp_packet_size_changed_callback *)calloc(1,
198 			sizeof(struct hfp_packet_size_changed_callback));
199 	callback->data = data;
200 	callback->cb = cb;
201 	DL_APPEND(info->packet_size_changed_cbs, callback);
202 }
203 
hfp_unregister_packet_size_changed_callback(struct hfp_info * info,void * data)204 void hfp_unregister_packet_size_changed_callback(struct hfp_info *info,
205 						 void *data)
206 {
207 	struct hfp_packet_size_changed_callback *callback;
208 	DL_FOREACH(info->packet_size_changed_cbs, callback) {
209 		if (data == callback->data) {
210 			DL_DELETE(info->packet_size_changed_cbs, callback);
211 			free(callback);
212 		}
213 	}
214 }
215 
hfp_read(struct hfp_info * info)216 int hfp_read(struct hfp_info *info)
217 {
218 	int err = 0;
219 	unsigned to_read;
220 	uint8_t *capture_buf;
221 
222 	capture_buf = buf_write_pointer_size(info->capture_buf, &to_read);
223 
224 	if (to_read < info->packet_size)
225 		return 0;
226 	to_read = info->packet_size;
227 
228 recv_sample:
229 	err = recv(info->fd, capture_buf, to_read, 0);
230 	if (err < 0) {
231 		syslog(LOG_ERR, "Read error %s", strerror(errno));
232 		if (errno == EINTR)
233 			goto recv_sample;
234 
235 		return err;
236 	}
237 
238 	if (err != (int)info->packet_size) {
239 		/* Allow the SCO packet size be modified from the default MTU
240 		 * value to the size of SCO data we first read. This is for
241 		 * some adapters who prefers a different value than MTU for
242 		 * transmitting SCO packet.
243 		 */
244 		if (err && (info->packet_size == info->mtu)) {
245 			hfp_info_set_packet_size(info, err);
246 		} else {
247 			syslog(LOG_ERR, "Partially read %d bytes for %u size SCO packet",
248 			       err, info->packet_size);
249 			return -1;
250 		}
251 	}
252 
253 	buf_increment_write(info->capture_buf, err);
254 
255 	return err;
256 }
257 
258 /* Callback function to handle sample read and write.
259  * Note that we poll the SCO socket for read sample, since it reflects
260  * there is actual some sample to read while the socket always reports
261  * writable even when device buffer is full.
262  * The strategy is to synchronize read & write operations:
263  * 1. Read one chunk of MTU bytes of data.
264  * 2. When input device not attached, ignore the data just read.
265  * 3. When output device attached, write one chunk of MTU bytes of data.
266  */
hfp_info_callback(void * arg)267 static int hfp_info_callback(void *arg)
268 {
269 	struct hfp_info *info = (struct hfp_info *)arg;
270 	int err;
271 
272 	if (!info->started)
273 		goto read_write_error;
274 
275 	err = hfp_read(info);
276 	if (err < 0) {
277 		syslog(LOG_ERR, "Read error");
278 		goto read_write_error;
279 	}
280 
281 	/* Ignore the MTU bytes just read if input dev not in present */
282 	if (!info->idev)
283 		buf_increment_read(info->capture_buf, info->packet_size);
284 
285 	if (info->odev) {
286 		err = hfp_write(info);
287 		if (err < 0) {
288 			syslog(LOG_ERR, "Write error");
289 			goto read_write_error;
290 		}
291 	}
292 
293 	return 0;
294 
295 read_write_error:
296 	hfp_info_stop(info);
297 
298 	return 0;
299 }
300 
hfp_info_create()301 struct hfp_info *hfp_info_create()
302 {
303 	struct hfp_info *info;
304 	info = (struct hfp_info *)calloc(1, sizeof(*info));
305 	if (!info)
306 		goto error;
307 
308 	info->capture_buf = byte_buffer_create(MAX_HFP_BUF_SIZE_BYTES);
309 	if (!info->capture_buf)
310 		goto error;
311 
312 	info->playback_buf = byte_buffer_create(MAX_HFP_BUF_SIZE_BYTES);
313 	if (!info->playback_buf)
314 		goto error;
315 
316 	return info;
317 
318 error:
319 	if (info) {
320 		if (info->capture_buf)
321 			byte_buffer_destroy(info->capture_buf);
322 		if (info->playback_buf)
323 			byte_buffer_destroy(info->playback_buf);
324 		free(info);
325 	}
326 	return NULL;
327 }
328 
hfp_info_running(struct hfp_info * info)329 int hfp_info_running(struct hfp_info *info)
330 {
331 	return info->started;
332 }
333 
hfp_info_start(int fd,unsigned int mtu,struct hfp_info * info)334 int hfp_info_start(int fd, unsigned int mtu, struct hfp_info *info)
335 {
336 	info->fd = fd;
337 	info->mtu = mtu;
338 
339 	/* Make sure buffer size is multiple of packet size, which initially
340 	 * set to MTU. */
341 	hfp_info_set_packet_size(info, mtu);
342 	buf_reset(info->playback_buf);
343 	buf_reset(info->capture_buf);
344 
345 	audio_thread_add_callback(info->fd, hfp_info_callback, info);
346 
347 	info->started = 1;
348 
349 	return 0;
350 }
351 
hfp_info_stop(struct hfp_info * info)352 int hfp_info_stop(struct hfp_info *info)
353 {
354 	if (!info->started)
355 		return 0;
356 
357 	audio_thread_rm_callback_sync(
358 		cras_iodev_list_get_audio_thread(),
359 		info->fd);
360 
361 	close(info->fd);
362 	info->fd = 0;
363 	info->started = 0;
364 
365 	return 0;
366 }
367 
hfp_info_destroy(struct hfp_info * info)368 void hfp_info_destroy(struct hfp_info *info)
369 {
370 	if (info->capture_buf)
371 		byte_buffer_destroy(info->capture_buf);
372 
373 	if (info->playback_buf)
374 		byte_buffer_destroy(info->playback_buf);
375 
376 	free(info);
377 }
378