• 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 <pthread.h>
7 #include <sys/param.h>
8 #include <syslog.h>
9 
10 #include "cras_audio_area.h"
11 #include "cras_config.h"
12 #include "cras_iodev.h"
13 #include "cras_iodev_list.h"
14 #include "cras_rstream.h"
15 #include "cras_types.h"
16 #include "utlist.h"
17 
18 #define EMPTY_BUFFER_SIZE (16 * 1024)
19 #define EMPTY_FRAME_SIZE 4
20 #define EMPTY_FRAMES (EMPTY_BUFFER_SIZE / EMPTY_FRAME_SIZE)
21 
22 static size_t empty_supported_rates[] = { 44100, 48000, 0 };
23 
24 static size_t empty_supported_channel_counts[] = { 1, 2, 0 };
25 
26 static snd_pcm_format_t empty_supported_formats[] = {
27 	SND_PCM_FORMAT_S16_LE, SND_PCM_FORMAT_S24_LE, SND_PCM_FORMAT_S32_LE,
28 	SND_PCM_FORMAT_S24_3LE, 0
29 };
30 
31 struct empty_iodev {
32 	struct cras_iodev base;
33 	uint8_t *audio_buffer;
34 	uint64_t read_frames, written_frames;
35 	struct timespec dev_start_time;
36 };
37 
38 /*
39  * Current level of the audio buffer.  This is made up based on what has been
40  * read/written and how long it has been since the start. Simulates audio
41  * hardware running at the given sample rate.
42  */
current_level(const struct cras_iodev * iodev)43 static unsigned int current_level(const struct cras_iodev *iodev)
44 {
45 	struct empty_iodev *empty_iodev = (struct empty_iodev *)iodev;
46 	uint64_t frames_since_start, nframes;
47 
48 	if (iodev->active_node->type == CRAS_NODE_TYPE_HOTWORD)
49 		return 0;
50 
51 	frames_since_start = cras_frames_since_time(
52 		&empty_iodev->dev_start_time, iodev->format->frame_rate);
53 
54 	if (iodev->direction == CRAS_STREAM_INPUT) {
55 		nframes = frames_since_start - empty_iodev->read_frames;
56 		return MIN(nframes, EMPTY_FRAMES);
57 	}
58 
59 	/* output */
60 	if (empty_iodev->written_frames <= frames_since_start)
61 		return 0;
62 	return empty_iodev->written_frames - frames_since_start;
63 }
64 
65 /*
66  * iodev callbacks.
67  */
68 
frames_queued(const struct cras_iodev * iodev,struct timespec * tstamp)69 static int frames_queued(const struct cras_iodev *iodev,
70 			 struct timespec *tstamp)
71 {
72 	clock_gettime(CLOCK_MONOTONIC_RAW, tstamp);
73 	return current_level(iodev);
74 }
75 
delay_frames(const struct cras_iodev * iodev)76 static int delay_frames(const struct cras_iodev *iodev)
77 {
78 	return 0;
79 }
80 
close_dev(struct cras_iodev * iodev)81 static int close_dev(struct cras_iodev *iodev)
82 {
83 	struct empty_iodev *empty_iodev = (struct empty_iodev *)iodev;
84 
85 	free(empty_iodev->audio_buffer);
86 	empty_iodev->audio_buffer = NULL;
87 	cras_iodev_free_audio_area(iodev);
88 	return 0;
89 }
90 
configure_dev(struct cras_iodev * iodev)91 static int configure_dev(struct cras_iodev *iodev)
92 {
93 	struct empty_iodev *empty_iodev = (struct empty_iodev *)iodev;
94 
95 	if (iodev->format == NULL)
96 		return -EINVAL;
97 
98 	cras_iodev_init_audio_area(iodev, iodev->format->num_channels);
99 	empty_iodev->audio_buffer = calloc(1, EMPTY_BUFFER_SIZE);
100 	empty_iodev->read_frames = 0;
101 	empty_iodev->written_frames = 0;
102 
103 	clock_gettime(CLOCK_MONOTONIC_RAW, &empty_iodev->dev_start_time);
104 
105 	return 0;
106 }
107 
get_buffer(struct cras_iodev * iodev,struct cras_audio_area ** area,unsigned * frames)108 static int get_buffer(struct cras_iodev *iodev, struct cras_audio_area **area,
109 		      unsigned *frames)
110 {
111 	struct empty_iodev *empty_iodev = (struct empty_iodev *)iodev;
112 	unsigned int avail, current;
113 
114 	if (iodev->direction == CRAS_STREAM_OUTPUT) {
115 		avail = EMPTY_FRAMES - current_level(iodev);
116 		*frames = MIN(*frames, avail);
117 	} else {
118 		current = current_level(iodev);
119 		*frames = MIN(*frames, current);
120 	}
121 
122 	iodev->area->frames = *frames;
123 	cras_audio_area_config_buf_pointers(iodev->area, iodev->format,
124 					    empty_iodev->audio_buffer);
125 	*area = iodev->area;
126 	return 0;
127 }
128 
129 /*
130  * Returns -EPIPE if there are not enough frames or spaces in device buffer.
131  * It matches other alsa-based devices.
132  */
put_buffer(struct cras_iodev * iodev,unsigned frames)133 static int put_buffer(struct cras_iodev *iodev, unsigned frames)
134 {
135 	struct empty_iodev *empty_iodev = (struct empty_iodev *)iodev;
136 
137 	if (iodev->direction == CRAS_STREAM_INPUT) {
138 		if (current_level(iodev) < frames)
139 			return -EPIPE;
140 		empty_iodev->read_frames += frames;
141 	} else {
142 		if (EMPTY_FRAMES - current_level(iodev) < frames)
143 			return -EPIPE;
144 		empty_iodev->written_frames += frames;
145 	}
146 	return 0;
147 }
148 
flush_buffer(struct cras_iodev * iodev)149 static int flush_buffer(struct cras_iodev *iodev)
150 {
151 	struct empty_iodev *empty_iodev = (struct empty_iodev *)iodev;
152 
153 	if (iodev->direction == CRAS_STREAM_INPUT)
154 		empty_iodev->read_frames = 0;
155 	else
156 		empty_iodev->written_frames = 0;
157 
158 	clock_gettime(CLOCK_MONOTONIC_RAW, &empty_iodev->dev_start_time);
159 	return 0;
160 }
161 
update_active_node(struct cras_iodev * iodev,unsigned node_idx,unsigned dev_enabled)162 static void update_active_node(struct cras_iodev *iodev, unsigned node_idx,
163 			       unsigned dev_enabled)
164 {
165 }
166 
167 /*
168  * Exported Interface.
169  */
170 
empty_iodev_create(enum CRAS_STREAM_DIRECTION direction,enum CRAS_NODE_TYPE node_type)171 struct cras_iodev *empty_iodev_create(enum CRAS_STREAM_DIRECTION direction,
172 				      enum CRAS_NODE_TYPE node_type)
173 {
174 	struct empty_iodev *empty_iodev;
175 	struct cras_iodev *iodev;
176 	struct cras_ionode *node;
177 
178 	if (direction != CRAS_STREAM_INPUT && direction != CRAS_STREAM_OUTPUT)
179 		return NULL;
180 
181 	empty_iodev = calloc(1, sizeof(*empty_iodev));
182 	if (empty_iodev == NULL)
183 		return NULL;
184 	iodev = &empty_iodev->base;
185 	iodev->direction = direction;
186 
187 	iodev->supported_rates = empty_supported_rates;
188 	iodev->supported_channel_counts = empty_supported_channel_counts;
189 	iodev->supported_formats = empty_supported_formats;
190 	iodev->buffer_size = EMPTY_FRAMES;
191 
192 	iodev->configure_dev = configure_dev;
193 	iodev->close_dev = close_dev;
194 	iodev->frames_queued = frames_queued;
195 	iodev->delay_frames = delay_frames;
196 	iodev->get_buffer = get_buffer;
197 	iodev->put_buffer = put_buffer;
198 	iodev->flush_buffer = flush_buffer;
199 	iodev->update_active_node = update_active_node;
200 	iodev->no_stream = cras_iodev_default_no_stream_playback;
201 
202 	/* Create a dummy ionode */
203 	node = (struct cras_ionode *)calloc(1, sizeof(*node));
204 	node->dev = iodev;
205 	node->type = node_type;
206 	node->volume = 100;
207 	strcpy(node->name, "(default)");
208 	cras_iodev_add_node(iodev, node);
209 	cras_iodev_set_active_node(iodev, node);
210 
211 	/* Finally add it to the appropriate iodev list. */
212 	if (direction == CRAS_STREAM_INPUT) {
213 		if (node->type == CRAS_NODE_TYPE_HOTWORD) {
214 			snprintf(iodev->info.name, ARRAY_SIZE(iodev->info.name),
215 				 "Silent hotword device.");
216 			iodev->info.name[ARRAY_SIZE(iodev->info.name) - 1] =
217 				'\0';
218 			iodev->info.idx = SILENT_HOTWORD_DEVICE;
219 		} else {
220 			snprintf(iodev->info.name, ARRAY_SIZE(iodev->info.name),
221 				 "Silent record device.");
222 			iodev->info.name[ARRAY_SIZE(iodev->info.name) - 1] =
223 				'\0';
224 			iodev->info.idx = SILENT_RECORD_DEVICE;
225 		}
226 	} else {
227 		snprintf(iodev->info.name, ARRAY_SIZE(iodev->info.name),
228 			 "Silent playback device.");
229 		iodev->info.name[ARRAY_SIZE(iodev->info.name) - 1] = '\0';
230 		iodev->info.idx = SILENT_PLAYBACK_DEVICE;
231 	}
232 
233 	return iodev;
234 }
235 
empty_iodev_destroy(struct cras_iodev * iodev)236 void empty_iodev_destroy(struct cras_iodev *iodev)
237 {
238 	struct empty_iodev *empty_iodev = (struct empty_iodev *)iodev;
239 
240 	if (iodev->direction == CRAS_STREAM_INPUT)
241 		cras_iodev_list_rm_input(iodev);
242 	else
243 		cras_iodev_list_rm_output(iodev);
244 	free(iodev->active_node);
245 	cras_iodev_free_resources(iodev);
246 	free(empty_iodev);
247 }
248