VirtualBox

source: vbox/trunk/src/VBox/Devices/Audio/solaudio.c@ 7333

Last change on this file since 7333 was 7333, checked in by vboxsync, 17 years ago

solaudio: some fixes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 11.6 KB
Line 
1/* $Id: solaudio.c 7333 2008-03-06 16:29:34Z vboxsync $ */
2/** @file
3 * VirtualBox Audio Driver - Solaris host.
4 */
5
6/*
7 * Copyright (C) 2006-2007 innotek GmbH
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/*******************************************************************************
19* Header Files *
20*******************************************************************************/
21#include <unistd.h>
22#include <errno.h>
23#include <stropts.h>
24#include <fcntl.h>
25#include <sys/audio.h>
26#include <sys/fcntl.h>
27#include <sys/stat.h>
28#include <sys/time.h>
29
30#define LOG_GROUP LOG_GROUP_DEV_AUDIO
31#include <VBox/log.h>
32
33#include "Builtins.h"
34#include "vl_vbox.h"
35#include "audio.h"
36#include <iprt/alloc.h>
37
38#define AUDIO_CAP "solaudio"
39#include "audio_int.h"
40
41
42/*******************************************************************************
43* Structures and Typedefs *
44*******************************************************************************/
45typedef struct solaudioVoiceOut {
46 HWVoiceOut hw;
47 int AudioDev;
48 int AudioCtl;
49 int cBuffersPlayed;
50 void *pPCMBuf;
51} solaudioVoiceOut;
52
53
54/*******************************************************************************
55* Global Variables *
56*******************************************************************************/
57struct
58{
59 int buffer_size;
60 int nbuffers;
61} conf =
62{
63 INIT_FIELD (buffer_size =) 8192,
64 INIT_FIELD (nbuffers =) 4,
65};
66
67
68static void GCC_FMT_ATTR (2, 3) solaudio_logerr (int err, const char *fmt, ...)
69{
70 va_list ap;
71
72 va_start (ap, fmt);
73 AUD_vlog (AUDIO_CAP, fmt, ap);
74 va_end (ap);
75
76 AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err));
77}
78
79
80static int aud_to_solfmt (audfmt_e fmt)
81{
82 switch (fmt)
83 {
84 case AUD_FMT_S8:
85 case AUD_FMT_U8:
86 return AUDIO_PRECISION_8;
87
88 case AUD_FMT_S16:
89 case AUD_FMT_U16:
90 return AUDIO_PRECISION_16;
91
92 default:
93 solaudio_logerr (-1, "Bad audio format %d\n", fmt);
94 return AUDIO_PRECISION_8;
95 }
96}
97
98
99static int sol_to_audfmt (int fmt, int encoding)
100{
101 switch (fmt)
102 {
103 case AUDIO_PRECISION_8:
104 {
105 if (encoding == AUDIO_ENCODING_LINEAR8)
106 return AUD_FMT_U8;
107 else
108 return AUD_FMT_S8;
109 break;
110 }
111
112 case AUDIO_PRECISION_16:
113 return AUD_FMT_U16;
114
115 default:
116 solaudio_logerr (-1, "Bad audio format %d\n", fmt);
117 return AUD_FMT_S8;
118 }
119}
120
121
122static int solaudio_open (int in, audio_info_t *info, int *pfd, int *pctl_fd)
123{
124 int fd;
125 int ctl_fd;
126 struct stat st;
127 const char *deviceName = "/dev/audio";
128 const char *ctlDeviceName = "/dev/audioctl";
129 audio_info_t audInfo;
130
131 /* @todo Use AUDIO_GETDEV instead of hardcoding /dev/audio */
132 if (stat(deviceName, &st) < 0)
133 {
134 LogRel(("solaudio: failed to stat %s\n", deviceName));
135 return -1;
136 }
137
138 if (!S_ISCHR(st.st_mode))
139 {
140 LogRel(("solaudio: invalid mode for %s\n", deviceName));
141 return -1;
142 }
143
144 fd = open(deviceName, O_WRONLY | O_NONBLOCK);
145 if (fd < 0)
146 {
147 LogRel(("solaudio: failed to open %s\n", deviceName));
148 return -1;
149 }
150
151 ctl_fd = open(ctlDeviceName, O_WRONLY | O_NONBLOCK);
152 if (ctl_fd < 0)
153 {
154 LogRel(("solaudio: failed to open %s\n", ctlDeviceName));
155 close(fd);
156 return -1;
157 }
158
159 AUDIO_INITINFO(&audInfo);
160 if (ioctl(fd, AUDIO_GETINFO, &audInfo) < 0)
161 {
162 LogRel(("solaudio: AUDIO_GETINFO failed\n"));
163 close(fd);
164 return -1;
165 }
166 audInfo.play.sample_rate = info->play.sample_rate;
167 audInfo.play.channels = info->play.channels;
168 audInfo.play.precision = info->play.precision;
169 audInfo.play.encoding = info->play.encoding;
170 audInfo.play.buffer_size = info->play.buffer_size;
171 audInfo.play.gain = AUDIO_MID_GAIN;
172 if (ioctl(fd, AUDIO_SETINFO, &audInfo) < 0)
173 {
174 LogRel(("solaudio: AUDIO_SETINFO failed\n"));
175 close(fd);
176 return -1;
177 }
178 LogFlow(("solaudio: system buffer_size=%d\n", audInfo.play.buffer_size));
179 *pfd = fd;
180 *pctl_fd = ctl_fd;
181 return 0;
182}
183
184
185static int solaudio_init_out (HWVoiceOut *hw, audsettings_t *as)
186{
187 solaudioVoiceOut *sol = (solaudioVoiceOut *) hw;
188 audio_info_t audioInfo;
189 audsettings_t obt_as;
190 int fd = -1;
191 int ctl_fd = -1;
192
193 AUDIO_INITINFO(&audioInfo);
194 audioInfo.play.sample_rate = as->freq;
195 audioInfo.play.channels = as->nchannels;
196 audioInfo.play.precision = aud_to_solfmt(as->fmt);
197 audioInfo.play.buffer_size = conf.buffer_size;
198 if (as->fmt == AUD_FMT_U8)
199 audioInfo.play.encoding = AUDIO_ENCODING_LINEAR8;
200 else
201 audioInfo.play.encoding = AUDIO_ENCODING_LINEAR;
202
203 if (solaudio_open(0, &audioInfo, &fd, &ctl_fd))
204 {
205 LogRel(("solaudio: solaudio_open failed\n"));
206 return -1;
207 }
208
209 sol->AudioDev = fd;
210 sol->AudioCtl = ctl_fd;
211 obt_as.freq = audioInfo.play.sample_rate;
212 obt_as.nchannels = audioInfo.play.channels;
213 obt_as.fmt = sol_to_audfmt(audioInfo.play.precision, audioInfo.play.encoding);
214 obt_as.endianness = as->endianness;
215
216 audio_pcm_init_info (&hw->info, &obt_as);
217 sol->cBuffersPlayed = audioInfo.play.eof;
218
219 hw->samples = audioInfo.play.buffer_size >> hw->info.shift;
220 sol->pPCMBuf = RTMemAllocZ(audioInfo.play.buffer_size);
221 if (!sol->pPCMBuf)
222 {
223 LogRel(("solaudio: failed to alloc %d %d bytes to pPCMBuf\n", hw->samples << hw->info.shift, hw->samples));
224 return -1;
225 }
226 LogFlow(("solaudio: hw->samples=%d play.buffer_size=%d\n", hw->samples, audioInfo.play.buffer_size));
227 return 0;
228}
229
230
231static void solaudio_stop (solaudioVoiceOut *solvw)
232{
233 LogFlow(("solaudio: stop\n"));
234 if (solvw->AudioDev < 0 || solvw->AudioCtl < 0)
235 {
236 Log(("solaudio: invalid file descriptors\n"));
237 return;
238 }
239
240 if (ioctl(solvw->AudioCtl, I_SETSIG, 0) < 0)
241 {
242 LogRel(("solaudio: failed to stop signalling\n"));
243 return;
244 }
245
246 if (ioctl(solvw->AudioDev, I_FLUSH, FLUSHW) < 0)
247 {
248 Log(("solaudio: failed to drop unplayed buffers\n"));
249 return;
250 }
251
252 close(solvw->AudioDev);
253 solvw->AudioDev = -1;
254 close(solvw->AudioCtl);
255 solvw->AudioCtl = -1;
256 solvw->cBuffersPlayed = 0;
257 if (solvw->pPCMBuf)
258 {
259 RTMemFree(solvw->pPCMBuf);
260 solvw->pPCMBuf = NULL;
261 }
262}
263
264
265static void solaudio_fini_out (HWVoiceOut *hw)
266{
267 solaudioVoiceOut *sol = (solaudioVoiceOut *) hw;
268 solaudio_stop (sol);
269 LogFlow(("solaudio: fini_out done\n"));
270}
271
272
273static int solaudio_availbuf (solaudioVoiceOut *solvw)
274{
275 audio_info_t audioInfo;
276 int buffers = 0;
277
278 AUDIO_INITINFO(&audioInfo);
279 if (ioctl(solvw->AudioDev, AUDIO_GETINFO, &audioInfo) < 0)
280 {
281 Log(("solaudio: AUDIO_GETINFO ioctl failed\n"));
282 return -1;
283 }
284
285 buffers = audioInfo.play.buffer_size * (2 + audioInfo.play.eof - solvw->cBuffersPlayed);
286
287 LogFlow(("avail: eof=%d samples=%d bufsize=%d bufplayed=%d avail=%d\n", audioInfo.play.eof, audioInfo.play.samples,
288 audioInfo.play.buffer_size, solvw->cBuffersPlayed, buffers));
289 return buffers;
290}
291
292static void solaudio_yield (solaudioVoiceOut *pSol)
293{
294 audio_info_t AudioInfo;
295 timespec_t WaitTimeSpec;
296 if (ioctl (pSol->AudioDev, AUDIO_GETINFO, &AudioInfo) < 0)
297 return;
298
299 WaitTimeSpec.tv_sec = 0;
300 WaitTimeSpec.tv_nsec = 10000000;
301
302 while (AudioInfo.play.eof < pSol->cBuffersPlayed - 2)
303 {
304 nanosleep(&WaitTimeSpec, NULL);
305 if (ioctl(pSol->AudioDev, AUDIO_GETINFO, &AudioInfo) < 0)
306 break;
307 }
308}
309
310
311static int solaudio_run_out (HWVoiceOut *hw)
312{
313 solaudioVoiceOut *pSol = (solaudioVoiceOut *) hw;
314 int csLive, csDecr, csSamples, csToWrite, csAvail;
315 size_t cbAvail, cbToWrite, cbWritten;
316 uint8_t *pu8Dst;
317 st_sample_t *psSrc;
318
319 csLive = audio_pcm_hw_get_live_out (hw);
320 if (!csLive)
321 return 0;
322
323 for (;;)
324 {
325 cbAvail = solaudio_availbuf (pSol);
326 if (cbAvail > 0)
327 break;
328 solaudio_yield(pSol);
329 }
330
331 csAvail = cbAvail >> hw->info.shift; /* bytes => samples */
332 csDecr = audio_MIN (csLive, csAvail);
333 csSamples = csDecr;
334
335 while (csSamples)
336 {
337 /* split request at the end of our samples buffer */
338 csToWrite = audio_MIN (csSamples, hw->samples - hw->rpos);
339 cbToWrite = csToWrite << hw->info.shift;
340 psSrc = hw->mix_buf + hw->rpos;
341 pu8Dst = advance (pSol->pPCMBuf, hw->rpos << hw->info.shift);
342
343 hw->clip (pu8Dst, psSrc, csToWrite);
344
345 cbWritten = write (pSol->AudioDev, pu8Dst, cbToWrite);
346 if (cbWritten < 0)
347 break;
348
349 hw->rpos = (hw->rpos + csToWrite) % hw->samples;
350 csSamples -= csToWrite;
351 }
352 /* Increment eof marker for synchronous buffer processed */
353 write (pSol->AudioDev, NULL, 0);
354 pSol->cBuffersPlayed++;
355 return csDecr;
356}
357
358
359static int solaudio_ctl_out (HWVoiceOut *hw, int cmd, ...)
360{
361 solaudioVoiceOut *sol = (solaudioVoiceOut *) hw;
362 switch (cmd)
363 {
364 case VOICE_ENABLE:
365 {
366 /* reset the eof marker and samples markers */
367 audio_info_t audioInfo;
368 AUDIO_INITINFO(&audioInfo);
369 ioctl(sol->AudioDev, AUDIO_GETINFO, &audioInfo);
370 audioInfo.play.eof = 0;
371 audioInfo.play.samples = 0;
372 ioctl(sol->AudioDev, AUDIO_SETINFO, &audioInfo);
373
374 sol->cBuffersPlayed = 0;
375 audio_pcm_info_clear_buf (&hw->info, sol->pPCMBuf, hw->samples);
376 LogFlow(("solaudio: voice_enable\n"));
377 break;
378 }
379
380 case VOICE_DISABLE:
381 {
382 LogFlow(("solaudio: voice_disable\n"));
383 solaudio_stop(sol);
384 break;
385 }
386 }
387 return 0;
388}
389
390
391static int solaudio_write (SWVoiceOut *sw, void *buf, int len)
392{
393 return audio_pcm_sw_write (sw, buf, len);
394}
395
396
397static void *solaudio_audio_init (void)
398{
399 return &conf;
400}
401
402
403static void solaudio_audio_fini (void *opaque)
404{
405 (void) opaque;
406}
407
408
409static struct audio_pcm_ops solaudio_pcm_ops = {
410 solaudio_init_out,
411 solaudio_fini_out,
412 solaudio_run_out,
413 solaudio_write,
414 solaudio_ctl_out,
415
416 NULL,
417 NULL,
418 NULL,
419 NULL,
420 NULL
421};
422
423static struct audio_option solaudio_options[] = {
424 {"BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_size,
425 "Size of the buffer in frames", NULL, 0},
426 {"BUFFER_COUNT", AUD_OPT_INT, &conf.nbuffers,
427 "Number of buffers", NULL, 0},
428 {NULL, 0, NULL, NULL, NULL, 0}
429};
430
431struct audio_driver solaudio_audio_driver = {
432 INIT_FIELD (name = ) "solaudio",
433 INIT_FIELD (descr = ) "SolarisAudio http://sun.com",
434 INIT_FIELD (options = ) solaudio_options,
435 INIT_FIELD (init = ) solaudio_audio_init,
436 INIT_FIELD (fini = ) solaudio_audio_fini,
437 INIT_FIELD (pcm_ops = ) &solaudio_pcm_ops,
438 INIT_FIELD (can_be_default = ) 1,
439 INIT_FIELD (max_voices_out = ) 1,
440 INIT_FIELD (max_voices_in = ) 0,
441 INIT_FIELD (voice_size_out = ) sizeof (solaudioVoiceOut),
442 INIT_FIELD (voice_size_in = ) 0
443};
444
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette