• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright (c) 2012 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 <fcntl.h>
7 #include <stdint.h>
8 #include <sys/mman.h>
9 #include <sys/types.h>
10 #include <syslog.h>
11 
12 #include "cras_audio_area.h"
13 #include "cras_config.h"
14 #include "cras_messages.h"
15 #include "cras_rclient.h"
16 #include "cras_rstream.h"
17 #include "cras_server_metrics.h"
18 #include "cras_shm.h"
19 #include "cras_types.h"
20 #include "buffer_share.h"
21 #include "cras_system_state.h"
22 
cras_rstream_config_init(struct cras_rclient * client,cras_stream_id_t stream_id,enum CRAS_STREAM_TYPE stream_type,enum CRAS_CLIENT_TYPE client_type,enum CRAS_STREAM_DIRECTION direction,uint32_t dev_idx,uint32_t flags,uint32_t effects,const struct cras_audio_format * format,size_t buffer_frames,size_t cb_threshold,int * audio_fd,int * client_shm_fd,size_t client_shm_size,struct cras_rstream_config * stream_config)23 void cras_rstream_config_init(
24 	struct cras_rclient *client, cras_stream_id_t stream_id,
25 	enum CRAS_STREAM_TYPE stream_type, enum CRAS_CLIENT_TYPE client_type,
26 	enum CRAS_STREAM_DIRECTION direction, uint32_t dev_idx, uint32_t flags,
27 	uint32_t effects, const struct cras_audio_format *format,
28 	size_t buffer_frames, size_t cb_threshold, int *audio_fd,
29 	int *client_shm_fd, size_t client_shm_size,
30 	struct cras_rstream_config *stream_config)
31 {
32 	stream_config->stream_id = stream_id;
33 	stream_config->stream_type = stream_type;
34 	stream_config->client_type = client_type;
35 	stream_config->direction = direction;
36 	stream_config->dev_idx = dev_idx;
37 	stream_config->flags = flags;
38 	stream_config->effects = effects;
39 	stream_config->format = format;
40 	stream_config->buffer_frames = buffer_frames;
41 	stream_config->cb_threshold = cb_threshold;
42 	stream_config->audio_fd = *audio_fd;
43 	*audio_fd = -1;
44 	stream_config->client_shm_fd = *client_shm_fd;
45 	*client_shm_fd = -1;
46 	stream_config->client_shm_size = client_shm_size;
47 	stream_config->client = client;
48 }
49 
cras_rstream_config_init_with_message(struct cras_rclient * client,const struct cras_connect_message * msg,int * aud_fd,int * client_shm_fd,const struct cras_audio_format * remote_fmt,struct cras_rstream_config * stream_config)50 void cras_rstream_config_init_with_message(
51 	struct cras_rclient *client, const struct cras_connect_message *msg,
52 	int *aud_fd, int *client_shm_fd,
53 	const struct cras_audio_format *remote_fmt,
54 	struct cras_rstream_config *stream_config)
55 {
56 	cras_rstream_config_init(client, msg->stream_id, msg->stream_type,
57 				 msg->client_type, msg->direction, msg->dev_idx,
58 				 msg->flags, msg->effects, remote_fmt,
59 				 msg->buffer_frames, msg->cb_threshold, aud_fd,
60 				 client_shm_fd, msg->client_shm_size,
61 				 stream_config);
62 }
63 
cras_rstream_config_cleanup(struct cras_rstream_config * stream_config)64 void cras_rstream_config_cleanup(struct cras_rstream_config *stream_config)
65 {
66 	if (stream_config->audio_fd >= 0)
67 		close(stream_config->audio_fd);
68 	if (stream_config->client_shm_fd >= 0)
69 		close(stream_config->client_shm_fd);
70 }
71 
72 /* Setup the shared memory area used for audio samples. client_shm_fd must be
73  * closed after calling this function.
74  */
setup_shm_area(struct cras_rstream * stream,int client_shm_fd,size_t client_shm_size)75 static inline int setup_shm_area(struct cras_rstream *stream, int client_shm_fd,
76 				 size_t client_shm_size)
77 {
78 	const struct cras_audio_format *fmt = &stream->format;
79 	char header_name[NAME_MAX];
80 	char samples_name[NAME_MAX];
81 	struct cras_shm_info header_info, samples_info;
82 	uint32_t frame_bytes, used_size;
83 	int rc;
84 
85 	if (stream->shm) {
86 		/* already setup */
87 		return -EEXIST;
88 	}
89 
90 	snprintf(header_name, sizeof(header_name),
91 		 "/cras-%d-stream-%08x-header", getpid(), stream->stream_id);
92 
93 	rc = cras_shm_info_init(header_name, cras_shm_header_size(),
94 				&header_info);
95 	if (rc)
96 		return rc;
97 
98 	frame_bytes = snd_pcm_format_physical_width(fmt->format) / 8 *
99 		      fmt->num_channels;
100 	used_size = stream->buffer_frames * frame_bytes;
101 
102 	if (client_shm_fd >= 0 && client_shm_size > 0) {
103 		rc = cras_shm_info_init_with_fd(client_shm_fd, client_shm_size,
104 						&samples_info);
105 	} else {
106 		snprintf(samples_name, sizeof(samples_name),
107 			 "/cras-%d-stream-%08x-samples", getpid(),
108 			 stream->stream_id);
109 		rc = cras_shm_info_init(
110 			samples_name,
111 			cras_shm_calculate_samples_size(used_size),
112 			&samples_info);
113 	}
114 	if (rc) {
115 		cras_shm_info_cleanup(&header_info);
116 		return rc;
117 	}
118 
119 	int samples_prot = 0;
120 	if (stream->direction == CRAS_STREAM_OUTPUT)
121 		samples_prot = PROT_READ;
122 	else
123 		samples_prot = PROT_WRITE;
124 
125 	rc = cras_audio_shm_create(&header_info, &samples_info, samples_prot,
126 				   &stream->shm);
127 	if (rc)
128 		return rc;
129 
130 	cras_shm_set_frame_bytes(stream->shm, frame_bytes);
131 	cras_shm_set_used_size(stream->shm, used_size);
132 
133 	stream->audio_area =
134 		cras_audio_area_create(stream->format.num_channels);
135 	cras_audio_area_config_channels(stream->audio_area, &stream->format);
136 
137 	return 0;
138 }
139 
buffer_meets_size_limit(size_t buffer_size,size_t rate)140 static inline int buffer_meets_size_limit(size_t buffer_size, size_t rate)
141 {
142 	return buffer_size > (CRAS_MIN_BUFFER_TIME_IN_US * rate) / 1000000;
143 }
144 
145 /* Verifies that the given stream parameters are valid. */
verify_rstream_parameters(enum CRAS_STREAM_DIRECTION direction,const struct cras_audio_format * format,enum CRAS_STREAM_TYPE stream_type,size_t buffer_frames,size_t cb_threshold,int client_shm_fd,size_t client_shm_size,struct cras_rclient * client,struct cras_rstream ** stream_out)146 static int verify_rstream_parameters(enum CRAS_STREAM_DIRECTION direction,
147 				     const struct cras_audio_format *format,
148 				     enum CRAS_STREAM_TYPE stream_type,
149 				     size_t buffer_frames, size_t cb_threshold,
150 				     int client_shm_fd, size_t client_shm_size,
151 				     struct cras_rclient *client,
152 				     struct cras_rstream **stream_out)
153 {
154 	if (!buffer_meets_size_limit(buffer_frames, format->frame_rate)) {
155 		syslog(LOG_ERR, "rstream: invalid buffer_frames %zu\n",
156 		       buffer_frames);
157 		return -EINVAL;
158 	}
159 	if (stream_out == NULL) {
160 		syslog(LOG_ERR, "rstream: stream_out can't be NULL\n");
161 		return -EINVAL;
162 	}
163 	if (format == NULL) {
164 		syslog(LOG_ERR, "rstream: format can't be NULL\n");
165 		return -EINVAL;
166 	}
167 	if ((format->format != SND_PCM_FORMAT_S16_LE) &&
168 	    (format->format != SND_PCM_FORMAT_S32_LE) &&
169 	    (format->format != SND_PCM_FORMAT_U8) &&
170 	    (format->format != SND_PCM_FORMAT_S24_LE)) {
171 		syslog(LOG_ERR, "rstream: format %d not supported\n",
172 		       format->format);
173 		return -EINVAL;
174 	}
175 	if (direction != CRAS_STREAM_OUTPUT && direction != CRAS_STREAM_INPUT) {
176 		syslog(LOG_ERR, "rstream: Invalid direction.\n");
177 		return -EINVAL;
178 	}
179 	if (stream_type < CRAS_STREAM_TYPE_DEFAULT ||
180 	    stream_type >= CRAS_STREAM_NUM_TYPES) {
181 		syslog(LOG_ERR, "rstream: Invalid stream type.\n");
182 		return -EINVAL;
183 	}
184 	if (!buffer_meets_size_limit(cb_threshold, format->frame_rate)) {
185 		syslog(LOG_ERR, "rstream: cb_threshold too low\n");
186 		return -EINVAL;
187 	}
188 	if ((client_shm_size > 0 && client_shm_fd < 0) ||
189 	    (client_shm_size == 0 && client_shm_fd >= 0)) {
190 		syslog(LOG_ERR, "rstream: invalid client-provided shm info\n");
191 		return -EINVAL;
192 	}
193 	return 0;
194 }
195 
196 /*
197  * Setting pending reply is only needed inside this module.
198  */
set_pending_reply(struct cras_rstream * stream)199 static void set_pending_reply(struct cras_rstream *stream)
200 {
201 	cras_shm_set_callback_pending(stream->shm, 1);
202 }
203 
204 /*
205  * Clearing pending reply is only needed inside this module.
206  */
clear_pending_reply(struct cras_rstream * stream)207 static void clear_pending_reply(struct cras_rstream *stream)
208 {
209 	cras_shm_set_callback_pending(stream->shm, 0);
210 }
211 
212 /*
213  * Reads one response of audio request from client.
214  * Args:
215  *   stream[in]: A pointer to cras_rstream.
216  *   msg[out]: A pointer to audio_message to hold the message.
217  * Returns:
218  *   Number of bytes read from the socket.
219  *   A negative error code if read fails or the message from client
220  *   has errors.
221  */
get_audio_request_reply(const struct cras_rstream * stream,struct audio_message * msg)222 static int get_audio_request_reply(const struct cras_rstream *stream,
223 				   struct audio_message *msg)
224 {
225 	int rc;
226 
227 	rc = read(stream->fd, msg, sizeof(*msg));
228 	if (rc < 0)
229 		return -errno;
230 	if (rc == 0)
231 		return rc;
232 	if (msg->error < 0)
233 		return msg->error;
234 	return rc;
235 }
236 
237 /*
238  * Reads and handles one audio message from client.
239  * Returns:
240  *   Number of bytes read from the socket.
241  *   A negative error code if read fails or the message from client
242  *   has errors.
243  */
read_and_handle_client_message(struct cras_rstream * stream)244 static int read_and_handle_client_message(struct cras_rstream *stream)
245 {
246 	struct audio_message msg;
247 	int rc;
248 
249 	rc = get_audio_request_reply(stream, &msg);
250 	if (rc <= 0) {
251 		syslog(LOG_ERR, "Got error from client: rc: %d", rc);
252 		clear_pending_reply(stream);
253 		return rc;
254 	}
255 
256 	/*
257 	 * Got client reply that data in the input stream is captured.
258 	 */
259 	if (stream->direction == CRAS_STREAM_INPUT &&
260 	    msg.id == AUDIO_MESSAGE_DATA_CAPTURED) {
261 		clear_pending_reply(stream);
262 	}
263 
264 	/*
265 	 * Got client reply that data for output stream is ready in shm.
266 	 */
267 	if (stream->direction == CRAS_STREAM_OUTPUT &&
268 	    msg.id == AUDIO_MESSAGE_DATA_READY) {
269 		clear_pending_reply(stream);
270 	}
271 
272 	return rc;
273 }
274 
275 /* Exported functions */
276 
cras_rstream_create(struct cras_rstream_config * config,struct cras_rstream ** stream_out)277 int cras_rstream_create(struct cras_rstream_config *config,
278 			struct cras_rstream **stream_out)
279 {
280 	struct cras_rstream *stream;
281 	int rc;
282 
283 	rc = verify_rstream_parameters(
284 		config->direction, config->format, config->stream_type,
285 		config->buffer_frames, config->cb_threshold,
286 		config->client_shm_fd, config->client_shm_size, config->client,
287 		stream_out);
288 	if (rc < 0)
289 		return rc;
290 
291 	stream = calloc(1, sizeof(*stream));
292 	if (stream == NULL)
293 		return -ENOMEM;
294 
295 	stream->stream_id = config->stream_id;
296 	stream->stream_type = config->stream_type;
297 	stream->client_type = config->client_type;
298 	stream->direction = config->direction;
299 	stream->flags = config->flags;
300 	stream->format = *config->format;
301 	stream->buffer_frames = config->buffer_frames;
302 	stream->cb_threshold = config->cb_threshold;
303 	stream->client = config->client;
304 	stream->shm = NULL;
305 	stream->master_dev.dev_id = NO_DEVICE;
306 	stream->master_dev.dev_ptr = NULL;
307 	stream->num_missed_cb = 0;
308 	stream->is_pinned = (config->dev_idx != NO_DEVICE);
309 	stream->pinned_dev_idx = config->dev_idx;
310 
311 	rc = setup_shm_area(stream, config->client_shm_fd,
312 			    config->client_shm_size);
313 	if (rc < 0) {
314 		syslog(LOG_ERR, "failed to setup shm %d\n", rc);
315 		free(stream);
316 		return rc;
317 	}
318 
319 	stream->fd = config->audio_fd;
320 	config->audio_fd = -1;
321 	stream->buf_state = buffer_share_create(stream->buffer_frames);
322 	stream->apm_list =
323 		(stream->direction == CRAS_STREAM_INPUT) ?
324 			cras_apm_list_create(stream, config->effects) :
325 			NULL;
326 
327 	syslog(LOG_DEBUG, "stream %x frames %zu, cb_thresh %zu",
328 	       config->stream_id, config->buffer_frames, config->cb_threshold);
329 	*stream_out = stream;
330 
331 	cras_system_state_stream_added(stream->direction);
332 
333 	clock_gettime(CLOCK_MONOTONIC_RAW, &stream->start_ts);
334 
335 	return 0;
336 }
337 
cras_rstream_destroy(struct cras_rstream * stream)338 void cras_rstream_destroy(struct cras_rstream *stream)
339 {
340 	cras_server_metrics_missed_cb_frequency(stream);
341 	cras_system_state_stream_removed(stream->direction);
342 	close(stream->fd);
343 	cras_audio_shm_destroy(stream->shm);
344 	cras_audio_area_destroy(stream->audio_area);
345 	buffer_share_destroy(stream->buf_state);
346 	if (stream->apm_list)
347 		cras_apm_list_destroy(stream->apm_list);
348 	free(stream);
349 }
350 
cras_rstream_get_effects(const struct cras_rstream * stream)351 unsigned int cras_rstream_get_effects(const struct cras_rstream *stream)
352 {
353 	return stream->apm_list ? cras_apm_list_get_effects(stream->apm_list) :
354 				  0;
355 }
356 
357 struct cras_audio_format *
cras_rstream_post_processing_format(const struct cras_rstream * stream,void * dev_ptr)358 cras_rstream_post_processing_format(const struct cras_rstream *stream,
359 				    void *dev_ptr)
360 {
361 	struct cras_apm *apm;
362 
363 	if (NULL == stream->apm_list)
364 		return NULL;
365 
366 	apm = cras_apm_list_get(stream->apm_list, dev_ptr);
367 	if (NULL == apm)
368 		return NULL;
369 	return cras_apm_list_get_format(apm);
370 }
371 
cras_rstream_record_fetch_interval(struct cras_rstream * rstream,const struct timespec * now)372 void cras_rstream_record_fetch_interval(struct cras_rstream *rstream,
373 					const struct timespec *now)
374 {
375 	struct timespec ts;
376 
377 	if (rstream->last_fetch_ts.tv_sec || rstream->last_fetch_ts.tv_nsec) {
378 		subtract_timespecs(now, &rstream->last_fetch_ts, &ts);
379 		if (timespec_after(&ts, &rstream->longest_fetch_interval))
380 			rstream->longest_fetch_interval = ts;
381 	}
382 }
383 
init_audio_message(struct audio_message * msg,enum CRAS_AUDIO_MESSAGE_ID id,uint32_t frames)384 static void init_audio_message(struct audio_message *msg,
385 			       enum CRAS_AUDIO_MESSAGE_ID id, uint32_t frames)
386 {
387 	memset(msg, 0, sizeof(*msg));
388 	msg->id = id;
389 	msg->frames = frames;
390 }
391 
cras_rstream_request_audio(struct cras_rstream * stream,const struct timespec * now)392 int cras_rstream_request_audio(struct cras_rstream *stream,
393 			       const struct timespec *now)
394 {
395 	struct audio_message msg;
396 	int rc;
397 
398 	/* Only request samples from output streams. */
399 	if (stream->direction != CRAS_STREAM_OUTPUT)
400 		return 0;
401 
402 	stream->last_fetch_ts = *now;
403 
404 	init_audio_message(&msg, AUDIO_MESSAGE_REQUEST_DATA,
405 			   stream->cb_threshold);
406 	rc = write(stream->fd, &msg, sizeof(msg));
407 	if (rc < 0)
408 		return -errno;
409 
410 	set_pending_reply(stream);
411 
412 	return rc;
413 }
414 
cras_rstream_audio_ready(struct cras_rstream * stream,size_t count)415 int cras_rstream_audio_ready(struct cras_rstream *stream, size_t count)
416 {
417 	struct audio_message msg;
418 	int rc;
419 
420 	cras_shm_buffer_write_complete(stream->shm);
421 
422 	/* Mark shm as used. */
423 	if (stream_is_server_only(stream)) {
424 		cras_shm_buffer_read_current(stream->shm, count);
425 		return 0;
426 	}
427 
428 	init_audio_message(&msg, AUDIO_MESSAGE_DATA_READY, count);
429 	rc = write(stream->fd, &msg, sizeof(msg));
430 	if (rc < 0)
431 		return -errno;
432 
433 	set_pending_reply(stream);
434 
435 	return rc;
436 }
437 
cras_rstream_dev_attach(struct cras_rstream * rstream,unsigned int dev_id,void * dev_ptr)438 void cras_rstream_dev_attach(struct cras_rstream *rstream, unsigned int dev_id,
439 			     void *dev_ptr)
440 {
441 	if (buffer_share_add_id(rstream->buf_state, dev_id, dev_ptr) == 0)
442 		rstream->num_attached_devs++;
443 
444 	/* TODO(hychao): Handle master device assignment for complicated
445 	 * routing case.
446 	 */
447 	if (rstream->master_dev.dev_id == NO_DEVICE) {
448 		rstream->master_dev.dev_id = dev_id;
449 		rstream->master_dev.dev_ptr = dev_ptr;
450 	}
451 }
452 
cras_rstream_dev_detach(struct cras_rstream * rstream,unsigned int dev_id)453 void cras_rstream_dev_detach(struct cras_rstream *rstream, unsigned int dev_id)
454 {
455 	if (buffer_share_rm_id(rstream->buf_state, dev_id) == 0)
456 		rstream->num_attached_devs--;
457 
458 	if (rstream->master_dev.dev_id == dev_id) {
459 		int i;
460 		struct id_offset *o;
461 
462 		/* Choose the first device id as master. */
463 		rstream->master_dev.dev_id = NO_DEVICE;
464 		rstream->master_dev.dev_ptr = NULL;
465 		for (i = 0; i < rstream->buf_state->id_sz; i++) {
466 			o = &rstream->buf_state->wr_idx[i];
467 			if (o->used) {
468 				rstream->master_dev.dev_id = o->id;
469 				rstream->master_dev.dev_ptr = o->data;
470 				break;
471 			}
472 		}
473 	}
474 }
475 
cras_rstream_dev_offset_update(struct cras_rstream * rstream,unsigned int frames,unsigned int dev_id)476 void cras_rstream_dev_offset_update(struct cras_rstream *rstream,
477 				    unsigned int frames, unsigned int dev_id)
478 {
479 	buffer_share_offset_update(rstream->buf_state, dev_id, frames);
480 }
481 
cras_rstream_update_input_write_pointer(struct cras_rstream * rstream)482 void cras_rstream_update_input_write_pointer(struct cras_rstream *rstream)
483 {
484 	unsigned int nwritten =
485 		buffer_share_get_new_write_point(rstream->buf_state);
486 
487 	cras_shm_buffer_written(rstream->shm, nwritten);
488 }
489 
cras_rstream_update_output_read_pointer(struct cras_rstream * rstream)490 void cras_rstream_update_output_read_pointer(struct cras_rstream *rstream)
491 {
492 	unsigned int nwritten =
493 		buffer_share_get_new_write_point(rstream->buf_state);
494 
495 	cras_shm_buffer_read(rstream->shm, nwritten);
496 }
497 
cras_rstream_dev_offset(const struct cras_rstream * rstream,unsigned int dev_id)498 unsigned int cras_rstream_dev_offset(const struct cras_rstream *rstream,
499 				     unsigned int dev_id)
500 {
501 	return buffer_share_id_offset(rstream->buf_state, dev_id);
502 }
503 
cras_rstream_update_queued_frames(struct cras_rstream * rstream)504 void cras_rstream_update_queued_frames(struct cras_rstream *rstream)
505 {
506 	rstream->queued_frames =
507 		MIN(cras_shm_get_frames(rstream->shm), rstream->buffer_frames);
508 }
509 
cras_rstream_playable_frames(struct cras_rstream * rstream,unsigned int dev_id)510 unsigned int cras_rstream_playable_frames(struct cras_rstream *rstream,
511 					  unsigned int dev_id)
512 {
513 	return rstream->queued_frames -
514 	       cras_rstream_dev_offset(rstream, dev_id);
515 }
516 
cras_rstream_get_volume_scaler(struct cras_rstream * rstream)517 float cras_rstream_get_volume_scaler(struct cras_rstream *rstream)
518 {
519 	return cras_shm_get_volume_scaler(rstream->shm);
520 }
521 
cras_rstream_get_readable_frames(struct cras_rstream * rstream,unsigned int offset,size_t * frames)522 uint8_t *cras_rstream_get_readable_frames(struct cras_rstream *rstream,
523 					  unsigned int offset, size_t *frames)
524 {
525 	return cras_shm_get_readable_frames(rstream->shm, offset, frames);
526 }
527 
cras_rstream_get_mute(const struct cras_rstream * rstream)528 int cras_rstream_get_mute(const struct cras_rstream *rstream)
529 {
530 	return cras_shm_get_mute(rstream->shm);
531 }
532 
cras_rstream_is_pending_reply(const struct cras_rstream * stream)533 int cras_rstream_is_pending_reply(const struct cras_rstream *stream)
534 {
535 	return cras_shm_callback_pending(stream->shm);
536 }
537 
cras_rstream_flush_old_audio_messages(struct cras_rstream * stream)538 int cras_rstream_flush_old_audio_messages(struct cras_rstream *stream)
539 {
540 	struct pollfd pollfd;
541 	int err;
542 
543 	if (!stream->fd)
544 		return 0;
545 
546 	if (stream_is_server_only(stream))
547 		return 0;
548 
549 	pollfd.fd = stream->fd;
550 	pollfd.events = POLLIN;
551 
552 	do {
553 		err = poll(&pollfd, 1, 0);
554 		if (pollfd.revents & POLLIN) {
555 			err = read_and_handle_client_message(stream);
556 		}
557 	} while (err > 0);
558 
559 	return 0;
560 }
561