Fri Jun 14 13:26:18 2019 UTC ()
seamonkey: This gets the newer get_position too.


(nia)
diff -r1.2 -r1.3 pkgsrc/www/seamonkey/files/cubeb_sun.c

cvs diff -r1.2 -r1.3 pkgsrc/www/seamonkey/files/cubeb_sun.c (switch to unified diff)

--- pkgsrc/www/seamonkey/files/cubeb_sun.c 2019/06/13 23:08:05 1.2
+++ pkgsrc/www/seamonkey/files/cubeb_sun.c 2019/06/14 13:26:18 1.3
@@ -1,754 +1,767 @@ @@ -1,754 +1,767 @@
1/* 1/*
2 * Copyright © 2019 Nia Alarie 2 * Copyright © 2019 Nia Alarie
3 * 3 *
4 * This program is made available under an ISC-style license. See the 4 * This program is made available under an ISC-style license. See the
5 * accompanying file LICENSE for details. 5 * accompanying file LICENSE for details.
6 */ 6 */
7#include <sys/audioio.h> 7#include <sys/audioio.h>
8#include <sys/ioctl.h> 8#include <sys/ioctl.h>
9#include <fcntl.h> 9#include <fcntl.h>
10#include <unistd.h> 10#include <unistd.h>
11#include <pthread.h> 11#include <pthread.h>
12#include <stdlib.h> 12#include <stdlib.h>
13#include <stdio.h> 13#include <stdio.h>
14#include <string.h> 14#include <string.h>
15#include <math.h> 15#include <math.h>
16#include "cubeb/cubeb.h" 16#include "cubeb/cubeb.h"
17#include "cubeb-internal.h" 17#include "cubeb-internal.h"
18 18
19#define CUBEB_OLD_API /* seamonkey and older firefox */ 19#define CUBEB_OLD_API /* seamonkey and older firefox */
20 20
21#define BYTES_TO_FRAMES(bytes, channels) \ 21#define BYTES_TO_FRAMES(bytes, channels) \
22 (bytes / (channels * sizeof(int16_t))) 22 (bytes / (channels * sizeof(int16_t)))
23 23
24#define FRAMES_TO_BYTES(frames, channels) \ 24#define FRAMES_TO_BYTES(frames, channels) \
25 (frames * (channels * sizeof(int16_t))) 25 (frames * (channels * sizeof(int16_t)))
26 26
27/* Default to 4 + 1 for the default device. */ 27/* Default to 4 + 1 for the default device. */
28#ifndef SUN_DEVICE_COUNT 28#ifndef SUN_DEVICE_COUNT
29#define SUN_DEVICE_COUNT (5) 29#define SUN_DEVICE_COUNT (5)
30#endif 30#endif
31 31
32/* Supported well by most hardware. */ 32/* Supported well by most hardware. */
33#ifndef SUN_PREFER_RATE 33#ifndef SUN_PREFER_RATE
34#define SUN_PREFER_RATE (48000) 34#define SUN_PREFER_RATE (48000)
35#endif 35#endif
36 36
37/* Standard acceptable minimum. */ 37/* Standard acceptable minimum. */
38#ifndef SUN_LATENCY_MS 38#ifndef SUN_LATENCY_MS
39#define SUN_LATENCY_MS (40) 39#define SUN_LATENCY_MS (40)
40#endif 40#endif
41 41
42#ifndef SUN_DEFAULT_DEVICE 42#ifndef SUN_DEFAULT_DEVICE
43#define SUN_DEFAULT_DEVICE "/dev/audio" 43#define SUN_DEFAULT_DEVICE "/dev/audio"
44#endif 44#endif
45 45
46#ifndef SUN_POLL_TIMEOUT 46#ifndef SUN_POLL_TIMEOUT
47#define SUN_POLL_TIMEOUT (1000) 47#define SUN_POLL_TIMEOUT (1000)
48#endif 48#endif
49 49
50#ifndef SUN_BUFFER_FRAMES 50#ifndef SUN_BUFFER_FRAMES
51#define SUN_BUFFER_FRAMES (32) 51#define SUN_BUFFER_FRAMES (32)
52#endif 52#endif
53 53
54/* 54/*
55 * Supported on NetBSD regardless of hardware. 55 * Supported on NetBSD regardless of hardware.
56 */ 56 */
57 57
58#ifndef SUN_MAX_CHANNELS 58#ifndef SUN_MAX_CHANNELS
59# ifdef __NetBSD__ 59# ifdef __NetBSD__
60# define SUN_MAX_CHANNELS (12) 60# define SUN_MAX_CHANNELS (12)
61# else 61# else
62# define SUN_MAX_CHANNELS (2) 62# define SUN_MAX_CHANNELS (2)
63# endif 63# endif
64#endif 64#endif
65 65
66#ifndef SUN_MIN_RATE 66#ifndef SUN_MIN_RATE
67#define SUN_MIN_RATE (1000) 67#define SUN_MIN_RATE (1000)
68#endif 68#endif
69 69
70#ifndef SUN_MAX_RATE 70#ifndef SUN_MAX_RATE
71#define SUN_MAX_RATE (192000) 71#define SUN_MAX_RATE (192000)
72#endif 72#endif
73 73
74static struct cubeb_ops const sun_ops; 74static struct cubeb_ops const sun_ops;
75 75
76struct cubeb { 76struct cubeb {
77 struct cubeb_ops const * ops; 77 struct cubeb_ops const * ops;
78}; 78};
79 79
80struct cubeb_stream { 80struct cubeb_stream {
81 struct cubeb * context; 81 struct cubeb * context;
82 void * user_ptr; 82 void * user_ptr;
83 pthread_t thread; 83 pthread_t thread;
84 pthread_mutex_t mutex; /* protects running, volume, frames_written */ 84 pthread_mutex_t mutex; /* protects running, volume, frames_written */
85 int floating; 85 int floating;
86 int running; 86 int running;
87 int play_fd; 87 int play_fd;
88 int record_fd; 88 int record_fd;
89 float volume; 89 float volume;
90 struct audio_info p_info; /* info for the play fd */ 90 struct audio_info p_info; /* info for the play fd */
91 struct audio_info r_info; /* info for the record fd */ 91 struct audio_info r_info; /* info for the record fd */
92 cubeb_data_callback data_cb; 92 cubeb_data_callback data_cb;
93 cubeb_state_callback state_cb; 93 cubeb_state_callback state_cb;
94 int16_t * play_buf; 94 int16_t * play_buf;
95 int16_t * record_buf; 95 int16_t * record_buf;
96 float * f_play_buf; 96 float * f_play_buf;
97 float * f_record_buf; 97 float * f_record_buf;
98 char input_name[32]; 98 char input_name[32];
99 char output_name[32]; 99 char output_name[32];
100 uint64_t frames_written; 100 uint64_t frames_written;
 101 uint64_t blocks_written;
101}; 102};
102 103
103int 104int
104sun_init(cubeb ** context, char const * context_name) 105sun_init(cubeb ** context, char const * context_name)
105{ 106{
106 cubeb * c; 107 cubeb * c;
107 108
108 (void)context_name; 109 (void)context_name;
109 if ((c = calloc(1, sizeof(cubeb))) == NULL) { 110 if ((c = calloc(1, sizeof(cubeb))) == NULL) {
110 return CUBEB_ERROR; 111 return CUBEB_ERROR;
111 } 112 }
112 c->ops = &sun_ops; 113 c->ops = &sun_ops;
113 *context = c; 114 *context = c;
114 return CUBEB_OK; 115 return CUBEB_OK;
115} 116}
116 117
117static void 118static void
118sun_destroy(cubeb * context) 119sun_destroy(cubeb * context)
119{ 120{
120 free(context); 121 free(context);
121} 122}
122 123
123static char const * 124static char const *
124sun_get_backend_id(cubeb * context) 125sun_get_backend_id(cubeb * context)
125{ 126{
126 return "sun"; 127 return "sun";
127} 128}
128 129
129static int 130static int
130sun_get_preferred_sample_rate(cubeb * context, uint32_t * rate) 131sun_get_preferred_sample_rate(cubeb * context, uint32_t * rate)
131{ 132{
132 (void)context; 133 (void)context;
133 134
134 *rate = SUN_PREFER_RATE; 135 *rate = SUN_PREFER_RATE;
135 return CUBEB_OK; 136 return CUBEB_OK;
136} 137}
137 138
138static int 139static int
139sun_get_max_channel_count(cubeb * context, uint32_t * max_channels) 140sun_get_max_channel_count(cubeb * context, uint32_t * max_channels)
140{ 141{
141 (void)context; 142 (void)context;
142 143
143 *max_channels = SUN_MAX_CHANNELS; 144 *max_channels = SUN_MAX_CHANNELS;
144 return CUBEB_OK; 145 return CUBEB_OK;
145} 146}
146 147
147static int 148static int
148sun_get_min_latency(cubeb * context, cubeb_stream_params params, 149sun_get_min_latency(cubeb * context, cubeb_stream_params params,
149 uint32_t * latency_frames) 150 uint32_t * latency_frames)
150{ 151{
151 (void)context; 152 (void)context;
152 153
153 *latency_frames = SUN_LATENCY_MS * params.rate / 1000; 154 *latency_frames = SUN_LATENCY_MS * params.rate / 1000;
154 return CUBEB_OK; 155 return CUBEB_OK;
155} 156}
156 157
157static int 158static int
158sun_get_hwinfo(const char * device, struct audio_info * format, 159sun_get_hwinfo(const char * device, struct audio_info * format,
159 int * props, struct audio_device * dev) 160 int * props, struct audio_device * dev)
160{ 161{
161 int fd = -1; 162 int fd = -1;
162 163
163 if ((fd = open(device, O_RDONLY)) == -1) { 164 if ((fd = open(device, O_RDONLY)) == -1) {
164 goto error; 165 goto error;
165 } 166 }
166#ifdef AUDIO_GETFORMAT 167#ifdef AUDIO_GETFORMAT
167 if (ioctl(fd, AUDIO_GETFORMAT, format) != 0) { 168 if (ioctl(fd, AUDIO_GETFORMAT, format) != 0) {
168 goto error; 169 goto error;
169 } 170 }
170#endif 171#endif
171#ifdef AUDIO_GETPROPS 172#ifdef AUDIO_GETPROPS
172 if (ioctl(fd, AUDIO_GETPROPS, props) != 0) { 173 if (ioctl(fd, AUDIO_GETPROPS, props) != 0) {
173 goto error; 174 goto error;
174 } 175 }
175#endif 176#endif
176 if (ioctl(fd, AUDIO_GETDEV, dev) != 0) { 177 if (ioctl(fd, AUDIO_GETDEV, dev) != 0) {
177 goto error; 178 goto error;
178 } 179 }
179 close(fd); 180 close(fd);
180 return CUBEB_OK; 181 return CUBEB_OK;
181error: 182error:
182 if (fd != -1) { 183 if (fd != -1) {
183 close(fd); 184 close(fd);
184 } 185 }
185 return CUBEB_ERROR; 186 return CUBEB_ERROR;
186} 187}
187 188
188/* 189/*
189 * XXX: PR kern/54264 190 * XXX: PR kern/54264
190 */ 191 */
191static int 192static int
192sun_prinfo_verify_sanity(struct audio_prinfo * prinfo) 193sun_prinfo_verify_sanity(struct audio_prinfo * prinfo)
193{ 194{
194 return prinfo->precision >= 8 && prinfo->precision <= 32 && 195 return prinfo->precision >= 8 && prinfo->precision <= 32 &&
195 prinfo->channels >= 1 && prinfo->channels < SUN_MAX_CHANNELS && 196 prinfo->channels >= 1 && prinfo->channels < SUN_MAX_CHANNELS &&
196 prinfo->sample_rate < SUN_MAX_RATE && prinfo->sample_rate > SUN_MIN_RATE; 197 prinfo->sample_rate < SUN_MAX_RATE && prinfo->sample_rate > SUN_MIN_RATE;
197} 198}
198 199
199#ifndef CUBEB_OLD_API 200#ifndef CUBEB_OLD_API
200static int 201static int
201sun_enumerate_devices(cubeb * context, cubeb_device_type type, 202sun_enumerate_devices(cubeb * context, cubeb_device_type type,
202 cubeb_device_collection * collection) 203 cubeb_device_collection * collection)
203{ 204{
204 unsigned i; 205 unsigned i;
205 cubeb_device_info device = {0}; 206 cubeb_device_info device = {0};
206 char dev[16] = SUN_DEFAULT_DEVICE; 207 char dev[16] = SUN_DEFAULT_DEVICE;
207 char dev_friendly[64]; 208 char dev_friendly[64];
208 struct audio_info hwfmt; 209 struct audio_info hwfmt;
209 struct audio_device hwname; 210 struct audio_device hwname;
210 struct audio_prinfo *prinfo = NULL; 211 struct audio_prinfo *prinfo = NULL;
211 int hwprops; 212 int hwprops;
212 213
213 collection->device = calloc(SUN_DEVICE_COUNT, sizeof(cubeb_device_info)); 214 collection->device = calloc(SUN_DEVICE_COUNT, sizeof(cubeb_device_info));
214 if (collection->device == NULL) { 215 if (collection->device == NULL) {
215 return CUBEB_ERROR; 216 return CUBEB_ERROR;
216 } 217 }
217 collection->count = 0; 218 collection->count = 0;
218 219
219 for (i = 0; i < SUN_DEVICE_COUNT; ++i) { 220 for (i = 0; i < SUN_DEVICE_COUNT; ++i) {
220 if (i > 0) { 221 if (i > 0) {
221 (void)snprintf(dev, sizeof(dev), "/dev/audio%u", i - 1); 222 (void)snprintf(dev, sizeof(dev), "/dev/audio%u", i - 1);
222 } 223 }
223 if (sun_get_hwinfo(dev, &hwfmt, &hwprops, &hwname) != CUBEB_OK) { 224 if (sun_get_hwinfo(dev, &hwfmt, &hwprops, &hwname) != CUBEB_OK) {
224 continue; 225 continue;
225 } 226 }
226#ifdef AUDIO_GETPROPS 227#ifdef AUDIO_GETPROPS
227 device.type = 0; 228 device.type = 0;
228 if ((hwprops & AUDIO_PROP_CAPTURE) != 0 && 229 if ((hwprops & AUDIO_PROP_CAPTURE) != 0 &&
229 sun_prinfo_verify_sanity(&hwfmt.record)) { 230 sun_prinfo_verify_sanity(&hwfmt.record)) {
230 /* the device supports recording, probably */ 231 /* the device supports recording, probably */
231 device.type |= CUBEB_DEVICE_TYPE_INPUT; 232 device.type |= CUBEB_DEVICE_TYPE_INPUT;
232 } 233 }
233 if ((hwprops & AUDIO_PROP_PLAYBACK) != 0 && 234 if ((hwprops & AUDIO_PROP_PLAYBACK) != 0 &&
234 sun_prinfo_verify_sanity(&hwfmt.play)) { 235 sun_prinfo_verify_sanity(&hwfmt.play)) {
235 /* the device supports playback, probably */ 236 /* the device supports playback, probably */
236 device.type |= CUBEB_DEVICE_TYPE_OUTPUT; 237 device.type |= CUBEB_DEVICE_TYPE_OUTPUT;
237 } 238 }
238 switch (device.type) { 239 switch (device.type) {
239 case 0: 240 case 0:
240 /* device doesn't do input or output, aliens probably involved */ 241 /* device doesn't do input or output, aliens probably involved */
241 continue; 242 continue;
242 case CUBEB_DEVICE_TYPE_INPUT: 243 case CUBEB_DEVICE_TYPE_INPUT:
243 if ((type & CUBEB_DEVICE_TYPE_INPUT) == 0) { 244 if ((type & CUBEB_DEVICE_TYPE_INPUT) == 0) {
244 /* this device is input only, not scanning for those, skip it */ 245 /* this device is input only, not scanning for those, skip it */
245 continue; 246 continue;
246 } 247 }
247 break; 248 break;
248 case CUBEB_DEVICE_TYPE_OUTPUT: 249 case CUBEB_DEVICE_TYPE_OUTPUT:
249 if ((type & CUBEB_DEVICE_TYPE_OUTPUT) == 0) { 250 if ((type & CUBEB_DEVICE_TYPE_OUTPUT) == 0) {
250 /* this device is output only, not scanning for those, skip it */ 251 /* this device is output only, not scanning for those, skip it */
251 continue; 252 continue;
252 } 253 }
253 break; 254 break;
254 } 255 }
255 if ((type & CUBEB_DEVICE_TYPE_INPUT) != 0) { 256 if ((type & CUBEB_DEVICE_TYPE_INPUT) != 0) {
256 prinfo = &hwfmt.record; 257 prinfo = &hwfmt.record;
257 } 258 }
258 if ((type & CUBEB_DEVICE_TYPE_OUTPUT) != 0) { 259 if ((type & CUBEB_DEVICE_TYPE_OUTPUT) != 0) {
259 prinfo = &hwfmt.play; 260 prinfo = &hwfmt.play;
260 } 261 }
261#endif 262#endif
262 if (i > 0) { 263 if (i > 0) {
263 (void)snprintf(dev_friendly, sizeof(dev_friendly), "%s %s %s (%d)", 264 (void)snprintf(dev_friendly, sizeof(dev_friendly), "%s %s %s (%d)",
264 hwname.name, hwname.version, hwname.config, i - 1); 265 hwname.name, hwname.version, hwname.config, i - 1);
265 } else { 266 } else {
266 (void)snprintf(dev_friendly, sizeof(dev_friendly), "%s %s %s (default)", 267 (void)snprintf(dev_friendly, sizeof(dev_friendly), "%s %s %s (default)",
267 hwname.name, hwname.version, hwname.config); 268 hwname.name, hwname.version, hwname.config);
268 } 269 }
269 device.devid = (void *)(uintptr_t)i; 270 device.devid = (void *)(uintptr_t)i;
270 device.device_id = strdup(dev); 271 device.device_id = strdup(dev);
271 device.friendly_name = strdup(dev_friendly); 272 device.friendly_name = strdup(dev_friendly);
272 device.group_id = strdup(dev); 273 device.group_id = strdup(dev);
273 device.vendor_name = strdup(hwname.name); 274 device.vendor_name = strdup(hwname.name);
274 device.type = type; 275 device.type = type;
275 device.state = CUBEB_DEVICE_STATE_ENABLED; 276 device.state = CUBEB_DEVICE_STATE_ENABLED;
276 device.preferred = (i == 0) ? CUBEB_DEVICE_PREF_ALL : CUBEB_DEVICE_PREF_NONE; 277 device.preferred = (i == 0) ? CUBEB_DEVICE_PREF_ALL : CUBEB_DEVICE_PREF_NONE;
277#ifdef AUDIO_GETFORMAT 278#ifdef AUDIO_GETFORMAT
278 device.max_channels = prinfo->channels; 279 device.max_channels = prinfo->channels;
279 device.default_rate = prinfo->sample_rate; 280 device.default_rate = prinfo->sample_rate;
280#else 281#else
281 device.max_channels = 2; 282 device.max_channels = 2;
282 device.default_rate = SUN_PREFER_RATE; 283 device.default_rate = SUN_PREFER_RATE;
283#endif 284#endif
284 device.default_format = CUBEB_DEVICE_FMT_S16NE; 285 device.default_format = CUBEB_DEVICE_FMT_S16NE;
285 device.format = CUBEB_DEVICE_FMT_S16NE; 286 device.format = CUBEB_DEVICE_FMT_S16NE;
286 device.min_rate = SUN_MIN_RATE; 287 device.min_rate = SUN_MIN_RATE;
287 device.max_rate = SUN_MAX_RATE; 288 device.max_rate = SUN_MAX_RATE;
288 device.latency_lo = SUN_LATENCY_MS * SUN_MIN_RATE / 1000; 289 device.latency_lo = SUN_LATENCY_MS * SUN_MIN_RATE / 1000;
289 device.latency_hi = SUN_LATENCY_MS * SUN_MAX_RATE / 1000; 290 device.latency_hi = SUN_LATENCY_MS * SUN_MAX_RATE / 1000;
290 collection->device[collection->count++] = device; 291 collection->device[collection->count++] = device;
291 } 292 }
292 return CUBEB_OK; 293 return CUBEB_OK;
293} 294}
294#endif 295#endif
295 296
296#ifndef CUBEB_OLD_API 297#ifndef CUBEB_OLD_API
297static int 298static int
298sun_device_collection_destroy(cubeb * context, 299sun_device_collection_destroy(cubeb * context,
299 cubeb_device_collection * collection) 300 cubeb_device_collection * collection)
300{ 301{
301 unsigned i; 302 unsigned i;
302 303
303 for (i = 0; i < collection->count; ++i) { 304 for (i = 0; i < collection->count; ++i) {
304 free((char *)collection->device[i].device_id); 305 free((char *)collection->device[i].device_id);
305 free((char *)collection->device[i].friendly_name); 306 free((char *)collection->device[i].friendly_name);
306 free((char *)collection->device[i].group_id); 307 free((char *)collection->device[i].group_id);
307 free((char *)collection->device[i].vendor_name); 308 free((char *)collection->device[i].vendor_name);
308 } 309 }
309 free(collection->device); 310 free(collection->device);
310 return CUBEB_OK; 311 return CUBEB_OK;
311} 312}
312#endif 313#endif
313 314
314static int 315static int
315sun_copy_params(int fd, cubeb_stream * stream, cubeb_stream_params * params, 316sun_copy_params(int fd, cubeb_stream * stream, cubeb_stream_params * params,
316 struct audio_info * info, struct audio_prinfo * prinfo) 317 struct audio_info * info, struct audio_prinfo * prinfo)
317{ 318{
318 prinfo->channels = params->channels; 319 prinfo->channels = params->channels;
319 prinfo->sample_rate = params->rate; 320 prinfo->sample_rate = params->rate;
320 prinfo->precision = 16; 321 prinfo->precision = 16;
321#ifdef AUDIO_ENCODING_SLINEAR_LE 322#ifdef AUDIO_ENCODING_SLINEAR_LE
322 switch (params->format) { 323 switch (params->format) {
323 case CUBEB_SAMPLE_S16LE: 324 case CUBEB_SAMPLE_S16LE:
324 prinfo->encoding = AUDIO_ENCODING_SLINEAR_LE; 325 prinfo->encoding = AUDIO_ENCODING_SLINEAR_LE;
325 break; 326 break;
326 case CUBEB_SAMPLE_S16BE: 327 case CUBEB_SAMPLE_S16BE:
327 prinfo->encoding = AUDIO_ENCODING_SLINEAR_BE; 328 prinfo->encoding = AUDIO_ENCODING_SLINEAR_BE;
328 break; 329 break;
329 case CUBEB_SAMPLE_FLOAT32NE: 330 case CUBEB_SAMPLE_FLOAT32NE:
330 stream->floating = 1; 331 stream->floating = 1;
331 prinfo->encoding = AUDIO_ENCODING_SLINEAR; 332 prinfo->encoding = AUDIO_ENCODING_SLINEAR;
332 break; 333 break;
333 default: 334 default:
334 LOG("Unsupported format"); 335 LOG("Unsupported format");
335 return CUBEB_ERROR_INVALID_FORMAT; 336 return CUBEB_ERROR_INVALID_FORMAT;
336 } 337 }
337#else 338#else
338 switch (params->format) { 339 switch (params->format) {
339 case CUBEB_SAMPLE_S16NE: 340 case CUBEB_SAMPLE_S16NE:
340 prinfo->encoding = AUDIO_ENCODING_LINEAR; 341 prinfo->encoding = AUDIO_ENCODING_LINEAR;
341 break; 342 break;
342 case CUBEB_SAMPLE_FLOAT32NE: 343 case CUBEB_SAMPLE_FLOAT32NE:
343 stream->floating = 1; 344 stream->floating = 1;
344 prinfo->encoding = AUDIO_ENCODING_LINEAR; 345 prinfo->encoding = AUDIO_ENCODING_LINEAR;
345 break; 346 break;
346 default: 347 default:
347 LOG("Unsupported format"); 348 LOG("Unsupported format");
348 return CUBEB_ERROR_INVALID_FORMAT; 349 return CUBEB_ERROR_INVALID_FORMAT;
349 } 350 }
350#endif 351#endif
351 if (ioctl(fd, AUDIO_SETINFO, info) == -1) { 352 if (ioctl(fd, AUDIO_SETINFO, info) == -1) {
352 return CUBEB_ERROR; 353 return CUBEB_ERROR;
353 } 354 }
354 if (ioctl(fd, AUDIO_GETINFO, info) == -1) { 355 if (ioctl(fd, AUDIO_GETINFO, info) == -1) {
355 return CUBEB_ERROR; 356 return CUBEB_ERROR;
356 } 357 }
357 return CUBEB_OK; 358 return CUBEB_OK;
358} 359}
359 360
360static int 361static int
361sun_stream_stop(cubeb_stream * s) 362sun_stream_stop(cubeb_stream * s)
362{ 363{
363 pthread_mutex_lock(&s->mutex); 364 pthread_mutex_lock(&s->mutex);
364 if (s->running) { 365 if (s->running) {
365 s->running = 0; 366 s->running = 0;
366 pthread_mutex_unlock(&s->mutex); 367 pthread_mutex_unlock(&s->mutex);
367 pthread_join(s->thread, NULL); 368 pthread_join(s->thread, NULL);
368 } else { 369 } else {
369 pthread_mutex_unlock(&s->mutex); 370 pthread_mutex_unlock(&s->mutex);
370 } 371 }
371 return CUBEB_OK; 372 return CUBEB_OK;
372} 373}
373 374
374static void 375static void
375sun_stream_destroy(cubeb_stream * s) 376sun_stream_destroy(cubeb_stream * s)
376{ 377{
377 pthread_mutex_destroy(&s->mutex); 378 pthread_mutex_destroy(&s->mutex);
378 sun_stream_stop(s); 379 sun_stream_stop(s);
379 if (s->play_fd != -1) { 380 if (s->play_fd != -1) {
380 close(s->play_fd); 381 close(s->play_fd);
381 } 382 }
382 if (s->record_fd != -1) { 383 if (s->record_fd != -1) {
383 close(s->record_fd); 384 close(s->record_fd);
384 } 385 }
385 free(s->f_play_buf); 386 free(s->f_play_buf);
386 free(s->f_record_buf); 387 free(s->f_record_buf);
387 free(s->play_buf); 388 free(s->play_buf);
388 free(s->record_buf); 389 free(s->record_buf);
389 free(s); 390 free(s);
390} 391}
391 392
392static void 393static void
393sun_float_to_linear(float * in, int16_t * out, 394sun_float_to_linear(float * in, int16_t * out,
394 unsigned channels, long frames, float vol) 395 unsigned channels, long frames, float vol)
395{ 396{
396 unsigned i, sample_count = frames * channels; 397 unsigned i, sample_count = frames * channels;
397 float multiplier = vol * 0x8000; 398 float multiplier = vol * 0x8000;
398 399
399 for (i = 0; i < sample_count; ++i) { 400 for (i = 0; i < sample_count; ++i) {
400 int32_t sample = lrintf(in[i] * multiplier); 401 int32_t sample = lrintf(in[i] * multiplier);
401 if (sample < -0x8000) { 402 if (sample < -0x8000) {
402 out[i] = -0x8000; 403 out[i] = -0x8000;
403 } else if (sample > 0x7fff) { 404 } else if (sample > 0x7fff) {
404 out[i] = 0x7fff; 405 out[i] = 0x7fff;
405 } else { 406 } else {
406 out[i] = sample; 407 out[i] = sample;
407 } 408 }
408 } 409 }
409} 410}
410 411
411static void 412static void
412sun_linear_to_float(int16_t * in, float * out, 413sun_linear_to_float(int16_t * in, float * out,
413 unsigned channels, long frames) 414 unsigned channels, long frames)
414{ 415{
415 unsigned i, sample_count = frames * channels; 416 unsigned i, sample_count = frames * channels;
416 417
417 for (i = 0; i < sample_count; ++i) { 418 for (i = 0; i < sample_count; ++i) {
418 out[i] = (1.0 / 0x8000) * in[i]; 419 out[i] = (1.0 / 0x8000) * in[i];
419 } 420 }
420} 421}
421 422
422static void 423static void
423sun_linear_set_vol(int16_t * buf, unsigned channels, long frames, float vol) 424sun_linear_set_vol(int16_t * buf, unsigned channels, long frames, float vol)
424{ 425{
425 unsigned i, sample_count = frames * channels; 426 unsigned i, sample_count = frames * channels;
426 int32_t multiplier = vol * 0x8000; 427 int32_t multiplier = vol * 0x8000;
427 428
428 for (i = 0; i < sample_count; ++i) { 429 for (i = 0; i < sample_count; ++i) {
429 buf[i] = (buf[i] * multiplier) >> 15; 430 buf[i] = (buf[i] * multiplier) >> 15;
430 } 431 }
431} 432}
432 433
433static void * 434static void *
434sun_io_routine(void * arg) 435sun_io_routine(void * arg)
435{ 436{
436 cubeb_stream *s = arg; 437 cubeb_stream *s = arg;
437 cubeb_state state = CUBEB_STATE_STARTED; 438 cubeb_state state = CUBEB_STATE_STARTED;
438 size_t to_read = 0; 439 size_t to_read = 0;
439 long to_write = 0; 440 long to_write = 0;
440 size_t write_ofs = 0; 441 size_t write_ofs = 0;
441 size_t read_ofs = 0; 442 size_t read_ofs = 0;
442 int drain = 0; 443 int drain = 0;
443 444
444 s->state_cb(s, s->user_ptr, CUBEB_STATE_STARTED); 445 s->state_cb(s, s->user_ptr, CUBEB_STATE_STARTED);
445 while (state != CUBEB_STATE_ERROR) { 446 while (state != CUBEB_STATE_ERROR) {
446 pthread_mutex_lock(&s->mutex); 447 pthread_mutex_lock(&s->mutex);
447 if (!s->running) { 448 if (!s->running) {
448 pthread_mutex_unlock(&s->mutex); 449 pthread_mutex_unlock(&s->mutex);
449 state = CUBEB_STATE_STOPPED; 450 state = CUBEB_STATE_STOPPED;
450 break; 451 break;
451 } 452 }
452 pthread_mutex_unlock(&s->mutex); 453 pthread_mutex_unlock(&s->mutex);
453 if (s->floating) { 454 if (s->floating) {
454 if (s->record_fd != -1) { 455 if (s->record_fd != -1) {
455 sun_linear_to_float(s->record_buf, s->f_record_buf, 456 sun_linear_to_float(s->record_buf, s->f_record_buf,
456 s->r_info.record.channels, SUN_BUFFER_FRAMES); 457 s->r_info.record.channels, SUN_BUFFER_FRAMES);
457 } 458 }
458 to_write = s->data_cb(s, s->user_ptr, 459 to_write = s->data_cb(s, s->user_ptr,
459 s->f_record_buf, s->f_play_buf, SUN_BUFFER_FRAMES); 460 s->f_record_buf, s->f_play_buf, SUN_BUFFER_FRAMES);
460 if (to_write == CUBEB_ERROR) { 461 if (to_write == CUBEB_ERROR) {
461 state = CUBEB_STATE_ERROR; 462 state = CUBEB_STATE_ERROR;
462 break; 463 break;
463 } 464 }
464 if (s->play_fd != -1) { 465 if (s->play_fd != -1) {
465 pthread_mutex_lock(&s->mutex); 466 pthread_mutex_lock(&s->mutex);
466 sun_float_to_linear(s->f_play_buf, s->play_buf, 467 sun_float_to_linear(s->f_play_buf, s->play_buf,
467 s->p_info.play.channels, to_write, s->volume); 468 s->p_info.play.channels, to_write, s->volume);
468 pthread_mutex_unlock(&s->mutex); 469 pthread_mutex_unlock(&s->mutex);
469 } 470 }
470 } else { 471 } else {
471 to_write = s->data_cb(s, s->user_ptr, 472 to_write = s->data_cb(s, s->user_ptr,
472 s->record_buf, s->play_buf, SUN_BUFFER_FRAMES); 473 s->record_buf, s->play_buf, SUN_BUFFER_FRAMES);
473 if (to_write == CUBEB_ERROR) { 474 if (to_write == CUBEB_ERROR) {
474 state = CUBEB_STATE_ERROR; 475 state = CUBEB_STATE_ERROR;
475 break; 476 break;
476 } 477 }
477 if (s->play_fd != -1) { 478 if (s->play_fd != -1) {
478 pthread_mutex_lock(&s->mutex); 479 pthread_mutex_lock(&s->mutex);
479 sun_linear_set_vol(s->play_buf, s->p_info.play.channels, to_write, s->volume); 480 sun_linear_set_vol(s->play_buf, s->p_info.play.channels, to_write, s->volume);
480 pthread_mutex_unlock(&s->mutex); 481 pthread_mutex_unlock(&s->mutex);
481 } 482 }
482 } 483 }
483 if (to_write < SUN_BUFFER_FRAMES) { 484 if (to_write < SUN_BUFFER_FRAMES) {
484 drain = 1; 485 drain = 1;
485 } 486 }
486 to_write = s->play_fd != -1 ? to_write : 0; 487 to_write = s->play_fd != -1 ? to_write : 0;
487 to_read = s->record_fd != -1 ? SUN_BUFFER_FRAMES : 0; 488 to_read = s->record_fd != -1 ? SUN_BUFFER_FRAMES : 0;
488 write_ofs = 0; 489 write_ofs = 0;
489 read_ofs = 0; 490 read_ofs = 0;
490 while (to_write > 0 || to_read > 0) { 491 while (to_write > 0 || to_read > 0) {
491 size_t bytes; 492 size_t bytes;
492 ssize_t n, frames; 493 ssize_t n, frames;
493 494
494 if (to_write > 0) { 495 if (to_write > 0) {
495 bytes = FRAMES_TO_BYTES(to_write, s->p_info.play.channels); 496 bytes = FRAMES_TO_BYTES(to_write, s->p_info.play.channels);
496 if ((n = write(s->play_fd, s->play_buf + write_ofs, bytes)) < 0) { 497 if ((n = write(s->play_fd, s->play_buf + write_ofs, bytes)) < 0) {
497 state = CUBEB_STATE_ERROR; 498 state = CUBEB_STATE_ERROR;
498 break; 499 break;
499 } 500 }
500 frames = BYTES_TO_FRAMES(n, s->p_info.play.channels); 501 frames = BYTES_TO_FRAMES(n, s->p_info.play.channels);
501 pthread_mutex_lock(&s->mutex); 502 pthread_mutex_lock(&s->mutex);
502 s->frames_written += frames; 503 s->frames_written += frames;
503 pthread_mutex_unlock(&s->mutex); 504 pthread_mutex_unlock(&s->mutex);
504 to_write -= frames; 505 to_write -= frames;
505 write_ofs += frames; 506 write_ofs += frames;
506 } 507 }
507 if (to_read > 0) { 508 if (to_read > 0) {
508 bytes = FRAMES_TO_BYTES(to_read, s->r_info.record.channels); 509 bytes = FRAMES_TO_BYTES(to_read, s->r_info.record.channels);
509 if ((n = read(s->record_fd, s->record_buf + read_ofs, bytes)) < 0) { 510 if ((n = read(s->record_fd, s->record_buf + read_ofs, bytes)) < 0) {
510 state = CUBEB_STATE_ERROR; 511 state = CUBEB_STATE_ERROR;
511 break; 512 break;
512 } 513 }
513 frames = BYTES_TO_FRAMES(n, s->r_info.record.channels); 514 frames = BYTES_TO_FRAMES(n, s->r_info.record.channels);
514 to_read -= frames; 515 to_read -= frames;
515 read_ofs += frames; 516 read_ofs += frames;
516 } 517 }
517 } 518 }
518 if (drain && state != CUBEB_STATE_ERROR) { 519 if (drain && state != CUBEB_STATE_ERROR) {
519 state = CUBEB_STATE_DRAINED; 520 state = CUBEB_STATE_DRAINED;
520 break; 521 break;
521 } 522 }
522 } 523 }
523 s->state_cb(s, s->user_ptr, state); 524 s->state_cb(s, s->user_ptr, state);
524 return NULL; 525 return NULL;
525} 526}
526 527
527static int 528static int
528sun_stream_init(cubeb * context, 529sun_stream_init(cubeb * context,
529 cubeb_stream ** stream, 530 cubeb_stream ** stream,
530 char const * stream_name, 531 char const * stream_name,
531 cubeb_devid input_device, 532 cubeb_devid input_device,
532 cubeb_stream_params * input_stream_params, 533 cubeb_stream_params * input_stream_params,
533 cubeb_devid output_device, 534 cubeb_devid output_device,
534 cubeb_stream_params * output_stream_params, 535 cubeb_stream_params * output_stream_params,
535 unsigned latency_frames, 536 unsigned latency_frames,
536 cubeb_data_callback data_callback, 537 cubeb_data_callback data_callback,
537 cubeb_state_callback state_callback, 538 cubeb_state_callback state_callback,
538 void * user_ptr) 539 void * user_ptr)
539{ 540{
540 int ret = CUBEB_OK; 541 int ret = CUBEB_OK;
541 cubeb_stream *s = NULL; 542 cubeb_stream *s = NULL;
542 543
543 (void)stream_name; 544 (void)stream_name;
544 (void)latency_frames; 545 (void)latency_frames;
545 if ((s = calloc(1, sizeof(cubeb_stream))) == NULL) { 546 if ((s = calloc(1, sizeof(cubeb_stream))) == NULL) {
546 ret = CUBEB_ERROR; 547 ret = CUBEB_ERROR;
547 goto error; 548 goto error;
548 } 549 }
549 s->record_fd = -1; 550 s->record_fd = -1;
550 s->play_fd = -1; 551 s->play_fd = -1;
551 if (input_device != 0) { 552 if (input_device != 0) {
552 snprintf(s->input_name, sizeof(s->input_name), 553 snprintf(s->input_name, sizeof(s->input_name),
553 "/dev/audio%zu", (uintptr_t)input_device - 1); 554 "/dev/audio%zu", (uintptr_t)input_device - 1);
554 } else { 555 } else {
555 snprintf(s->input_name, sizeof(s->input_name), "%s", SUN_DEFAULT_DEVICE); 556 snprintf(s->input_name, sizeof(s->input_name), "%s", SUN_DEFAULT_DEVICE);
556 } 557 }
557 if (output_device != 0) { 558 if (output_device != 0) {
558 snprintf(s->output_name, sizeof(s->output_name), 559 snprintf(s->output_name, sizeof(s->output_name),
559 "/dev/audio%zu", (uintptr_t)output_device - 1); 560 "/dev/audio%zu", (uintptr_t)output_device - 1);
560 } else { 561 } else {
561 snprintf(s->output_name, sizeof(s->output_name), "%s", SUN_DEFAULT_DEVICE); 562 snprintf(s->output_name, sizeof(s->output_name), "%s", SUN_DEFAULT_DEVICE);
562 } 563 }
563 if (input_stream_params != NULL) { 564 if (input_stream_params != NULL) {
564#ifndef CUBEB_OLD_API 565#ifndef CUBEB_OLD_API
565 if (input_stream_params->prefs & CUBEB_STREAM_PREF_LOOPBACK) { 566 if (input_stream_params->prefs & CUBEB_STREAM_PREF_LOOPBACK) {
566 LOG("Loopback not supported"); 567 LOG("Loopback not supported");
567 ret = CUBEB_ERROR_NOT_SUPPORTED; 568 ret = CUBEB_ERROR_NOT_SUPPORTED;
568 goto error; 569 goto error;
569 } 570 }
570#endif 571#endif
571 if (s->record_fd == -1) { 572 if (s->record_fd == -1) {
572 if ((s->record_fd = open(s->input_name, O_RDONLY)) == -1) { 573 if ((s->record_fd = open(s->input_name, O_RDONLY)) == -1) {
573 LOG("Audio device cannot be opened as read-only"); 574 LOG("Audio device cannot be opened as read-only");
574 ret = CUBEB_ERROR_DEVICE_UNAVAILABLE; 575 ret = CUBEB_ERROR_DEVICE_UNAVAILABLE;
575 goto error; 576 goto error;
576 } 577 }
577 } 578 }
578 AUDIO_INITINFO(&s->r_info); 579 AUDIO_INITINFO(&s->r_info);
579#ifdef AUMODE_RECORD 580#ifdef AUMODE_RECORD
580 s->r_info.mode = AUMODE_RECORD; 581 s->r_info.mode = AUMODE_RECORD;
581#endif 582#endif
582 if ((ret = sun_copy_params(s->record_fd, s, input_stream_params, 583 if ((ret = sun_copy_params(s->record_fd, s, input_stream_params,
583 &s->r_info, &s->r_info.record)) != CUBEB_OK) { 584 &s->r_info, &s->r_info.record)) != CUBEB_OK) {
584 LOG("Setting record params failed"); 585 LOG("Setting record params failed");
585 goto error; 586 goto error;
586 } 587 }
587 } 588 }
588 if (output_stream_params != NULL) { 589 if (output_stream_params != NULL) {
589#ifndef CUBEB_OLD_API 590#ifndef CUBEB_OLD_API
590 if (output_stream_params->prefs & CUBEB_STREAM_PREF_LOOPBACK) { 591 if (output_stream_params->prefs & CUBEB_STREAM_PREF_LOOPBACK) {
591 LOG("Loopback not supported"); 592 LOG("Loopback not supported");
592 ret = CUBEB_ERROR_NOT_SUPPORTED; 593 ret = CUBEB_ERROR_NOT_SUPPORTED;
593 goto error; 594 goto error;
594 } 595 }
595#endif 596#endif
596 if (s->play_fd == -1) { 597 if (s->play_fd == -1) {
597 if ((s->play_fd = open(s->output_name, O_WRONLY)) == -1) { 598 if ((s->play_fd = open(s->output_name, O_WRONLY)) == -1) {
598 LOG("Audio device cannot be opened as write-only"); 599 LOG("Audio device cannot be opened as write-only");
599 ret = CUBEB_ERROR_DEVICE_UNAVAILABLE; 600 ret = CUBEB_ERROR_DEVICE_UNAVAILABLE;
600 goto error; 601 goto error;
601 } 602 }
602 } 603 }
603 AUDIO_INITINFO(&s->p_info); 604 AUDIO_INITINFO(&s->p_info);
604#ifdef AUMODE_PLAY 605#ifdef AUMODE_PLAY
605 s->p_info.mode = AUMODE_PLAY; 606 s->p_info.mode = AUMODE_PLAY;
606#endif 607#endif
607 if ((ret = sun_copy_params(s->play_fd, s, output_stream_params, 608 if ((ret = sun_copy_params(s->play_fd, s, output_stream_params,
608 &s->p_info, &s->p_info.play)) != CUBEB_OK) { 609 &s->p_info, &s->p_info.play)) != CUBEB_OK) {
609 LOG("Setting play params failed"); 610 LOG("Setting play params failed");
610 goto error; 611 goto error;
611 } 612 }
612 } 613 }
613 s->context = context; 614 s->context = context;
614 s->volume = 1.0; 615 s->volume = 1.0;
615 s->state_cb = state_callback; 616 s->state_cb = state_callback;
616 s->data_cb = data_callback; 617 s->data_cb = data_callback;
617 s->user_ptr = user_ptr; 618 s->user_ptr = user_ptr;
618 if (pthread_mutex_init(&s->mutex, NULL) != 0) { 619 if (pthread_mutex_init(&s->mutex, NULL) != 0) {
619 LOG("Failed to create mutex"); 620 LOG("Failed to create mutex");
620 goto error; 621 goto error;
621 } 622 }
622 if (s->play_fd != -1 && (s->play_buf = calloc(SUN_BUFFER_FRAMES, 623 if (s->play_fd != -1 && (s->play_buf = calloc(SUN_BUFFER_FRAMES,
623 s->p_info.play.channels * sizeof(int16_t))) == NULL) { 624 s->p_info.play.channels * sizeof(int16_t))) == NULL) {
624 ret = CUBEB_ERROR; 625 ret = CUBEB_ERROR;
625 goto error; 626 goto error;
626 } 627 }
627 if (s->record_fd != -1 && (s->record_buf = calloc(SUN_BUFFER_FRAMES, 628 if (s->record_fd != -1 && (s->record_buf = calloc(SUN_BUFFER_FRAMES,
628 s->r_info.record.channels * sizeof(int16_t))) == NULL) { 629 s->r_info.record.channels * sizeof(int16_t))) == NULL) {
629 ret = CUBEB_ERROR; 630 ret = CUBEB_ERROR;
630 goto error; 631 goto error;
631 } 632 }
632 if (s->floating) { 633 if (s->floating) {
633 if (s->play_fd != -1 && (s->f_play_buf = calloc(SUN_BUFFER_FRAMES, 634 if (s->play_fd != -1 && (s->f_play_buf = calloc(SUN_BUFFER_FRAMES,
634 s->p_info.play.channels * sizeof(float))) == NULL) { 635 s->p_info.play.channels * sizeof(float))) == NULL) {
635 ret = CUBEB_ERROR; 636 ret = CUBEB_ERROR;
636 goto error; 637 goto error;
637 } 638 }
638 if (s->record_fd != -1 && (s->f_record_buf = calloc(SUN_BUFFER_FRAMES, 639 if (s->record_fd != -1 && (s->f_record_buf = calloc(SUN_BUFFER_FRAMES,
639 s->r_info.record.channels * sizeof(float))) == NULL) { 640 s->r_info.record.channels * sizeof(float))) == NULL) {
640 ret = CUBEB_ERROR; 641 ret = CUBEB_ERROR;
641 goto error; 642 goto error;
642 } 643 }
643 } 644 }
644 *stream = s; 645 *stream = s;
645 return CUBEB_OK; 646 return CUBEB_OK;
646error: 647error:
647 if (s != NULL) { 648 if (s != NULL) {
648 sun_stream_destroy(s); 649 sun_stream_destroy(s);
649 } 650 }
650 return ret; 651 return ret;
651} 652}
652 653
653static int 654static int
654sun_stream_start(cubeb_stream * s) 655sun_stream_start(cubeb_stream * s)
655{ 656{
656 s->running = 1; 657 s->running = 1;
657 if (pthread_create(&s->thread, NULL, sun_io_routine, s) != 0) { 658 if (pthread_create(&s->thread, NULL, sun_io_routine, s) != 0) {
658 LOG("Couldn't create thread"); 659 LOG("Couldn't create thread");
659 return CUBEB_ERROR; 660 return CUBEB_ERROR;
660 } 661 }
661 return CUBEB_OK; 662 return CUBEB_OK;
662} 663}
663 664
664static int 665static int
665sun_stream_get_position(cubeb_stream * s, uint64_t * position) 666sun_stream_get_position(cubeb_stream * s, uint64_t * position)
666{ 667{
 668#ifdef AUDIO_GETOOFFS
 669 struct audio_offset offset;
 670
 671 if (ioctl(s->play_fd, AUDIO_GETOOFFS, &offset) == -1) {
 672 return CUBEB_ERROR;
 673 }
 674 s->blocks_written += offset.deltablks;
 675 *position = BYTES_TO_FRAMES(s->blocks_written * s->p_info.blocksize,
 676 s->p_info.play.channels);
 677 return CUBEB_OK;
 678#else
667 pthread_mutex_lock(&s->mutex); 679 pthread_mutex_lock(&s->mutex);
668 *position = s->frames_written; 680 *position = s->frames_written;
669 pthread_mutex_unlock(&s->mutex); 681 pthread_mutex_unlock(&s->mutex);
670 return CUBEB_OK; 682 return CUBEB_OK;
 683#endif
671} 684}
672 685
673static int 686static int
674sun_stream_get_latency(cubeb_stream * stream, uint32_t * latency) 687sun_stream_get_latency(cubeb_stream * stream, uint32_t * latency)
675{ 688{
676#ifdef AUDIO_GETBUFINFO 689#ifdef AUDIO_GETBUFINFO
677 struct audio_info info; 690 struct audio_info info;
678 691
679 if (ioctl(stream->play_fd, AUDIO_GETBUFINFO, &info) == -1) { 692 if (ioctl(stream->play_fd, AUDIO_GETBUFINFO, &info) == -1) {
680 return CUBEB_ERROR; 693 return CUBEB_ERROR;
681 } 694 }
682 695
683 *latency = BYTES_TO_FRAMES(info.play.seek + info.blocksize, 696 *latency = BYTES_TO_FRAMES(info.play.seek + info.blocksize,
684 info.play.channels); 697 info.play.channels);
685 return CUBEB_OK; 698 return CUBEB_OK;
686#else 699#else
687 cubeb_stream_params params; 700 cubeb_stream_params params;
688 701
689 params.rate = stream->p_info.play.sample_rate; 702 params.rate = stream->p_info.play.sample_rate;
690 703
691 return sun_get_min_latency(NULL, params, latency); 704 return sun_get_min_latency(NULL, params, latency);
692#endif 705#endif
693} 706}
694 707
695static int 708static int
696sun_stream_set_volume(cubeb_stream * stream, float volume) 709sun_stream_set_volume(cubeb_stream * stream, float volume)
697{ 710{
698 pthread_mutex_lock(&stream->mutex); 711 pthread_mutex_lock(&stream->mutex);
699 stream->volume = volume; 712 stream->volume = volume;
700 pthread_mutex_unlock(&stream->mutex); 713 pthread_mutex_unlock(&stream->mutex);
701 return CUBEB_OK; 714 return CUBEB_OK;
702} 715}
703 716
704static int 717static int
705sun_get_current_device(cubeb_stream * stream, cubeb_device ** const device) 718sun_get_current_device(cubeb_stream * stream, cubeb_device ** const device)
706{ 719{
707 *device = calloc(1, sizeof(cubeb_device)); 720 *device = calloc(1, sizeof(cubeb_device));
708 if (*device == NULL) { 721 if (*device == NULL) {
709 return CUBEB_ERROR; 722 return CUBEB_ERROR;
710 } 723 }
711 (*device)->input_name = stream->record_fd != -1 ? 724 (*device)->input_name = stream->record_fd != -1 ?
712 strdup(stream->input_name) : NULL; 725 strdup(stream->input_name) : NULL;
713 (*device)->output_name = stream->play_fd != -1 ? 726 (*device)->output_name = stream->play_fd != -1 ?
714 strdup(stream->output_name) : NULL; 727 strdup(stream->output_name) : NULL;
715 return CUBEB_OK; 728 return CUBEB_OK;
716} 729}
717 730
718static int 731static int
719sun_stream_device_destroy(cubeb_stream * stream, cubeb_device * device) 732sun_stream_device_destroy(cubeb_stream * stream, cubeb_device * device)
720{ 733{
721 (void)stream; 734 (void)stream;
722 free(device->input_name); 735 free(device->input_name);
723 free(device->output_name); 736 free(device->output_name);
724 free(device); 737 free(device);
725 return CUBEB_OK; 738 return CUBEB_OK;
726} 739}
727 740
728static struct cubeb_ops const sun_ops = { 741static struct cubeb_ops const sun_ops = {
729 .init = sun_init, 742 .init = sun_init,
730 .get_backend_id = sun_get_backend_id, 743 .get_backend_id = sun_get_backend_id,
731 .get_max_channel_count = sun_get_max_channel_count, 744 .get_max_channel_count = sun_get_max_channel_count,
732 .get_min_latency = sun_get_min_latency, 745 .get_min_latency = sun_get_min_latency,
733 .get_preferred_sample_rate = sun_get_preferred_sample_rate, 746 .get_preferred_sample_rate = sun_get_preferred_sample_rate,
734#ifndef CUBEB_OLD_API 747#ifndef CUBEB_OLD_API
735 .enumerate_devices = sun_enumerate_devices, 748 .enumerate_devices = sun_enumerate_devices,
736 .device_collection_destroy = sun_device_collection_destroy, 749 .device_collection_destroy = sun_device_collection_destroy,
737#endif 750#endif
738 .destroy = sun_destroy, 751 .destroy = sun_destroy,
739 .stream_init = sun_stream_init, 752 .stream_init = sun_stream_init,
740 .stream_destroy = sun_stream_destroy, 753 .stream_destroy = sun_stream_destroy,
741 .stream_start = sun_stream_start, 754 .stream_start = sun_stream_start,
742 .stream_stop = sun_stream_stop, 755 .stream_stop = sun_stream_stop,
743#ifndef CUBEB_OLD_API 756#ifndef CUBEB_OLD_API
744 .stream_reset_default_device = NULL, 757 .stream_reset_default_device = NULL,
745#endif 758#endif
746 .stream_get_position = sun_stream_get_position, 759 .stream_get_position = sun_stream_get_position,
747 .stream_get_latency = sun_stream_get_latency, 760 .stream_get_latency = sun_stream_get_latency,
748 .stream_set_volume = sun_stream_set_volume, 761 .stream_set_volume = sun_stream_set_volume,
749 .stream_set_panning = NULL, 762 .stream_set_panning = NULL,
750 .stream_get_current_device = sun_get_current_device, 763 .stream_get_current_device = sun_get_current_device,
751 .stream_device_destroy = sun_stream_device_destroy, 764 .stream_device_destroy = sun_stream_device_destroy,
752 .stream_register_device_changed_callback = NULL, 765 .stream_register_device_changed_callback = NULL,
753 .register_device_collection_changed = NULL 766 .register_device_collection_changed = NULL
754}; 767};