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_shm.h"
18 #include "cras_types.h"
19 #include "buffer_share.h"
20 #include "cras_system_state.h"
21
22 /* Configure the shm area for the stream. */
setup_shm(struct cras_rstream * stream,struct cras_audio_shm * shm,struct rstream_shm_info * shm_info)23 static int setup_shm(struct cras_rstream *stream,
24 struct cras_audio_shm *shm,
25 struct rstream_shm_info *shm_info)
26 {
27 size_t used_size, samples_size, frame_bytes;
28 const struct cras_audio_format *fmt = &stream->format;
29
30 if (shm->area != NULL) /* already setup */
31 return -EEXIST;
32
33 frame_bytes = snd_pcm_format_physical_width(fmt->format) / 8 *
34 fmt->num_channels;
35 used_size = stream->buffer_frames * frame_bytes;
36 samples_size = used_size * CRAS_NUM_SHM_BUFFERS;
37 shm_info->length = sizeof(struct cras_audio_shm_area) + samples_size;
38
39 snprintf(shm_info->shm_name, sizeof(shm_info->shm_name),
40 "/cras-%d-stream-%08x", getpid(), stream->stream_id);
41
42 shm_info->shm_fd = cras_shm_open_rw(shm_info->shm_name, shm_info->length);
43 if (shm_info->shm_fd < 0)
44 return shm_info->shm_fd;
45
46 /* mmap shm. */
47 shm->area = mmap(NULL, shm_info->length,
48 PROT_READ | PROT_WRITE, MAP_SHARED,
49 shm_info->shm_fd, 0);
50 if (shm->area == (struct cras_audio_shm_area *)-1) {
51 close(shm_info->shm_fd);
52 return errno;
53 }
54
55 cras_shm_set_volume_scaler(shm, 1.0);
56 /* Set up config and copy to shared area. */
57 cras_shm_set_frame_bytes(shm, frame_bytes);
58 shm->config.frame_bytes = frame_bytes;
59 cras_shm_set_used_size(shm, used_size);
60 memcpy(&shm->area->config, &shm->config, sizeof(shm->config));
61 return 0;
62 }
63
64 /* Setup the shared memory area used for audio samples. */
setup_shm_area(struct cras_rstream * stream)65 static inline int setup_shm_area(struct cras_rstream *stream)
66 {
67 int rc;
68
69 rc = setup_shm(stream, &stream->shm,
70 &stream->shm_info);
71 if (rc)
72 return rc;
73 stream->audio_area =
74 cras_audio_area_create(stream->format.num_channels);
75 cras_audio_area_config_channels(stream->audio_area, &stream->format);
76
77 return 0;
78 }
79
buffer_meets_size_limit(size_t buffer_size,size_t rate)80 static inline int buffer_meets_size_limit(size_t buffer_size, size_t rate)
81 {
82 return buffer_size > (CRAS_MIN_BUFFER_TIME_IN_US * rate) / 1000000;
83 }
84
85 /* 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,struct cras_rclient * client,struct cras_rstream ** stream_out)86 static int verify_rstream_parameters(enum CRAS_STREAM_DIRECTION direction,
87 const struct cras_audio_format *format,
88 enum CRAS_STREAM_TYPE stream_type,
89 size_t buffer_frames,
90 size_t cb_threshold,
91 struct cras_rclient *client,
92 struct cras_rstream **stream_out)
93 {
94 if (!buffer_meets_size_limit(buffer_frames, format->frame_rate)) {
95 syslog(LOG_ERR, "rstream: invalid buffer_frames %zu\n",
96 buffer_frames);
97 return -EINVAL;
98 }
99 if (stream_out == NULL) {
100 syslog(LOG_ERR, "rstream: stream_out can't be NULL\n");
101 return -EINVAL;
102 }
103 if (format == NULL) {
104 syslog(LOG_ERR, "rstream: format can't be NULL\n");
105 return -EINVAL;
106 }
107 if ((format->format != SND_PCM_FORMAT_S16_LE) &&
108 (format->format != SND_PCM_FORMAT_S32_LE) &&
109 (format->format != SND_PCM_FORMAT_U8) &&
110 (format->format != SND_PCM_FORMAT_S24_LE)) {
111 syslog(LOG_ERR, "rstream: format %d not supported\n",
112 format->format);
113 return -EINVAL;
114 }
115 if (direction != CRAS_STREAM_OUTPUT && direction != CRAS_STREAM_INPUT) {
116 syslog(LOG_ERR, "rstream: Invalid direction.\n");
117 return -EINVAL;
118 }
119 if (stream_type < CRAS_STREAM_TYPE_DEFAULT ||
120 stream_type >= CRAS_STREAM_NUM_TYPES) {
121 syslog(LOG_ERR, "rstream: Invalid stream type.\n");
122 return -EINVAL;
123 }
124 if (!buffer_meets_size_limit(cb_threshold, format->frame_rate)) {
125 syslog(LOG_ERR, "rstream: cb_threshold too low\n");
126 return -EINVAL;
127 }
128 return 0;
129 }
130
131 /* Exported functions */
132
cras_rstream_create(struct cras_rstream_config * config,struct cras_rstream ** stream_out)133 int cras_rstream_create(struct cras_rstream_config *config,
134 struct cras_rstream **stream_out)
135 {
136 struct cras_rstream *stream;
137 int rc;
138
139 rc = verify_rstream_parameters(config->direction, config->format,
140 config->stream_type,
141 config->buffer_frames,
142 config->cb_threshold, config->client,
143 stream_out);
144 if (rc < 0)
145 return rc;
146
147 stream = calloc(1, sizeof(*stream));
148 if (stream == NULL)
149 return -ENOMEM;
150
151 stream->stream_id = config->stream_id;
152 stream->stream_type = config->stream_type;
153 stream->direction = config->direction;
154 stream->flags = config->flags;
155 stream->format = *config->format;
156 stream->buffer_frames = config->buffer_frames;
157 stream->cb_threshold = config->cb_threshold;
158 stream->client = config->client;
159 stream->shm.area = NULL;
160 stream->master_dev.dev_id = NO_DEVICE;
161 stream->master_dev.dev_ptr = NULL;
162 stream->is_pinned = (config->dev_idx != NO_DEVICE);
163 stream->pinned_dev_idx = config->dev_idx;
164 stream->fd = config->audio_fd;
165
166 rc = setup_shm_area(stream);
167 if (rc < 0) {
168 syslog(LOG_ERR, "failed to setup shm %d\n", rc);
169 free(stream);
170 return rc;
171 }
172
173 stream->buf_state = buffer_share_create(stream->buffer_frames);
174
175 syslog(LOG_DEBUG, "stream %x frames %zu, cb_thresh %zu",
176 config->stream_id, config->buffer_frames, config->cb_threshold);
177 *stream_out = stream;
178
179 cras_system_state_stream_added(stream->direction);
180
181 return 0;
182 }
183
cras_rstream_destroy(struct cras_rstream * stream)184 void cras_rstream_destroy(struct cras_rstream *stream)
185 {
186 cras_system_state_stream_removed(stream->direction);
187 close(stream->fd);
188 if (stream->shm.area != NULL) {
189 munmap(stream->shm.area, stream->shm_info.length);
190 cras_shm_close_unlink(stream->shm_info.shm_name,
191 stream->shm_info.shm_fd);
192 cras_audio_area_destroy(stream->audio_area);
193 }
194 buffer_share_destroy(stream->buf_state);
195 free(stream);
196 }
197
cras_rstream_record_fetch_interval(struct cras_rstream * rstream,const struct timespec * now)198 void cras_rstream_record_fetch_interval(struct cras_rstream *rstream,
199 const struct timespec *now)
200 {
201 struct timespec ts;
202
203 if (rstream->last_fetch_ts.tv_sec || rstream->last_fetch_ts.tv_nsec) {
204 subtract_timespecs(now, &rstream->last_fetch_ts, &ts);
205 if (timespec_after(&ts, &rstream->longest_fetch_interval))
206 rstream->longest_fetch_interval = ts;
207 }
208 }
209
init_audio_message(struct audio_message * msg,enum CRAS_AUDIO_MESSAGE_ID id,uint32_t frames)210 static void init_audio_message(struct audio_message *msg,
211 enum CRAS_AUDIO_MESSAGE_ID id,
212 uint32_t frames)
213 {
214 memset(msg, 0, sizeof(*msg));
215 msg->id = id;
216 msg->frames = frames;
217 }
218
cras_rstream_request_audio(struct cras_rstream * stream,const struct timespec * now)219 int cras_rstream_request_audio(struct cras_rstream *stream,
220 const struct timespec *now)
221 {
222 struct audio_message msg;
223 int rc;
224
225 /* Only request samples from output streams. */
226 if (stream->direction != CRAS_STREAM_OUTPUT)
227 return 0;
228
229 stream->last_fetch_ts = *now;
230
231 init_audio_message(&msg, AUDIO_MESSAGE_REQUEST_DATA,
232 stream->cb_threshold);
233 rc = write(stream->fd, &msg, sizeof(msg));
234 if (rc < 0)
235 return -errno;
236 return rc;
237 }
238
cras_rstream_audio_ready(struct cras_rstream * stream,size_t count)239 int cras_rstream_audio_ready(struct cras_rstream *stream, size_t count)
240 {
241 struct audio_message msg;
242 int rc;
243
244 cras_shm_buffer_write_complete(&stream->shm);
245
246 init_audio_message(&msg, AUDIO_MESSAGE_DATA_READY, count);
247 rc = write(stream->fd, &msg, sizeof(msg));
248 if (rc < 0)
249 return -errno;
250 return rc;
251 }
252
cras_rstream_get_audio_request_reply(const struct cras_rstream * stream)253 int cras_rstream_get_audio_request_reply(const struct cras_rstream *stream)
254 {
255 struct audio_message msg;
256 int rc;
257
258 rc = read(stream->fd, &msg, sizeof(msg));
259 if (rc < 0)
260 return -errno;
261 if (msg.error < 0)
262 return msg.error;
263 return 0;
264 }
265
cras_rstream_dev_attach(struct cras_rstream * rstream,unsigned int dev_id,void * dev_ptr)266 void cras_rstream_dev_attach(struct cras_rstream *rstream,
267 unsigned int dev_id,
268 void *dev_ptr)
269 {
270 if (buffer_share_add_id(rstream->buf_state, dev_id, dev_ptr) == 0)
271 rstream->num_attached_devs++;
272
273 /* TODO(hychao): Handle master device assignment for complicated
274 * routing case.
275 */
276 if (rstream->master_dev.dev_id == NO_DEVICE) {
277 rstream->master_dev.dev_id = dev_id;
278 rstream->master_dev.dev_ptr = dev_ptr;
279 }
280 }
281
cras_rstream_dev_detach(struct cras_rstream * rstream,unsigned int dev_id)282 void cras_rstream_dev_detach(struct cras_rstream *rstream, unsigned int dev_id)
283 {
284 if (buffer_share_rm_id(rstream->buf_state, dev_id) == 0)
285 rstream->num_attached_devs--;
286
287 if (rstream->master_dev.dev_id == dev_id) {
288 int i;
289 struct id_offset *o;
290
291 /* Choose the first device id as master. */
292 rstream->master_dev.dev_id = NO_DEVICE;
293 rstream->master_dev.dev_ptr = NULL;
294 for (i = 0; i < rstream->buf_state->id_sz; i++) {
295 o = &rstream->buf_state->wr_idx[i];
296 if (o->used) {
297 rstream->master_dev.dev_id = o->id;
298 rstream->master_dev.dev_ptr = o->data;
299 break;
300 }
301 }
302 }
303 }
304
cras_rstream_dev_offset_update(struct cras_rstream * rstream,unsigned int frames,unsigned int dev_id)305 void cras_rstream_dev_offset_update(struct cras_rstream *rstream,
306 unsigned int frames,
307 unsigned int dev_id)
308 {
309 buffer_share_offset_update(rstream->buf_state, dev_id, frames);
310 }
311
cras_rstream_update_input_write_pointer(struct cras_rstream * rstream)312 void cras_rstream_update_input_write_pointer(struct cras_rstream *rstream)
313 {
314 struct cras_audio_shm *shm = cras_rstream_input_shm(rstream);
315 unsigned int nwritten = buffer_share_get_new_write_point(
316 rstream->buf_state);
317
318 cras_shm_buffer_written(shm, nwritten);
319 }
320
cras_rstream_update_output_read_pointer(struct cras_rstream * rstream)321 void cras_rstream_update_output_read_pointer(struct cras_rstream *rstream)
322 {
323 struct cras_audio_shm *shm = cras_rstream_input_shm(rstream);
324 unsigned int nwritten = buffer_share_get_new_write_point(
325 rstream->buf_state);
326
327 cras_shm_buffer_read(shm, nwritten);
328 }
329
cras_rstream_dev_offset(const struct cras_rstream * rstream,unsigned int dev_id)330 unsigned int cras_rstream_dev_offset(const struct cras_rstream *rstream,
331 unsigned int dev_id)
332 {
333 return buffer_share_id_offset(rstream->buf_state, dev_id);
334 }
335
cras_rstream_update_queued_frames(struct cras_rstream * rstream)336 void cras_rstream_update_queued_frames(struct cras_rstream *rstream)
337 {
338 const struct cras_audio_shm *shm = cras_rstream_output_shm(rstream);
339 rstream->queued_frames = MIN(cras_shm_get_frames(shm),
340 rstream->buffer_frames);
341 }
342
cras_rstream_playable_frames(struct cras_rstream * rstream,unsigned int dev_id)343 unsigned int cras_rstream_playable_frames(struct cras_rstream *rstream,
344 unsigned int dev_id)
345 {
346 return rstream->queued_frames -
347 cras_rstream_dev_offset(rstream, dev_id);
348 }
349
cras_rstream_get_volume_scaler(struct cras_rstream * rstream)350 float cras_rstream_get_volume_scaler(struct cras_rstream *rstream)
351 {
352 const struct cras_audio_shm *shm = cras_rstream_output_shm(rstream);
353
354 return cras_shm_get_volume_scaler(shm);
355 }
356
cras_rstream_get_readable_frames(struct cras_rstream * rstream,unsigned int offset,size_t * frames)357 uint8_t *cras_rstream_get_readable_frames(struct cras_rstream *rstream,
358 unsigned int offset,
359 size_t *frames)
360 {
361 return cras_shm_get_readable_frames(&rstream->shm, offset, frames);
362 }
363
cras_rstream_get_mute(const struct cras_rstream * rstream)364 int cras_rstream_get_mute(const struct cras_rstream *rstream)
365 {
366 return cras_shm_get_mute(&rstream->shm);
367 }
368