VirtualBox

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

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

SolaudiO: Fix for ubuntu guest desktop crashing on startup with audio enabled.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 22.2 KB
Line 
1/* $Id: solaudio.c 8345 2008-04-24 07:08:53Z vboxsync $ */
2/** @file
3 * VirtualBox Audio Driver - Solaris host.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22/*******************************************************************************
23* Header Files *
24*******************************************************************************/
25#include <unistd.h>
26#include <errno.h>
27#include <stropts.h>
28#include <fcntl.h>
29#include <sys/audio.h>
30#include <sys/stat.h>
31#include <sys/time.h>
32#include <sys/mixer.h>
33
34#define LOG_GROUP LOG_GROUP_DEV_AUDIO
35#define LOG_ENABLED
36#include <VBox/log.h>
37#include <iprt/env.h>
38
39#include "Builtins.h"
40#include "vl_vbox.h"
41#include "audio.h"
42#include <iprt/alloc.h>
43
44#define AUDIO_CAP "solaudio"
45#include "audio_int.h"
46
47/*******************************************************************************
48* Structures and Typedefs *
49*******************************************************************************/
50typedef struct solaudioVoiceOut
51{
52 HWVoiceOut Hw;
53 audio_info_t AudioInfo;
54 uint_t cBuffersPlayed;
55 void *pPCMBuf;
56} solaudioVoiceOut;
57
58typedef struct solaudioVoiceIn
59{
60 HWVoiceIn Hw;
61 audio_info_t AudioInfo;
62 void *pPCMBuf;
63} solaudioVoiceIn;
64
65
66/*******************************************************************************
67* Global Variables *
68*******************************************************************************/
69static struct
70{
71 int cbPlayBuffer;
72 int cbRecordBuffer;
73} conf =
74{
75 INIT_FIELD (cbPlayBuffer =) 4352,
76 INIT_FIELD (cbRecordBuffer = ) 8192
77};
78
79static int g_AudioDev = -1;
80static int g_RecordDev = -1;
81static int g_AudioCtl = -1;
82static char *g_pszAudioDev = NULL;
83static char *g_pszAudioCtl = NULL;
84
85typedef enum
86{
87 enmPlay = 6,
88 enmRecord = 9,
89 enmRecordPassive = 15
90} audio_dest_t;
91
92
93static int aud_to_solfmt (audfmt_e fmt)
94{
95 switch (fmt)
96 {
97 case AUD_FMT_S8:
98 case AUD_FMT_U8:
99 return AUDIO_PRECISION_8;
100
101 case AUD_FMT_S16:
102 case AUD_FMT_U16:
103 return AUDIO_PRECISION_16;
104
105 default:
106 LogRel(("solaudio: aud_to_solfmt: Bad audio format %d\n", fmt));
107 return AUDIO_PRECISION_8;
108 }
109}
110
111
112static int sol_to_audfmt (int fmt, int encoding)
113{
114 switch (fmt)
115 {
116 case AUDIO_PRECISION_8:
117 {
118 if (encoding == AUDIO_ENCODING_LINEAR8)
119 return AUD_FMT_U8;
120 else
121 return AUD_FMT_S8;
122 break;
123 }
124
125 case AUDIO_PRECISION_16:
126 {
127 if (encoding == AUDIO_ENCODING_LINEAR)
128 return AUD_FMT_S16;
129 else
130 return AUD_FMT_U16;
131 break;
132 }
133
134 default:
135 LogRel(("solaudio: sol_to_audfmt: Bad audio format %d\n", fmt));
136 return AUD_FMT_S8;
137 }
138}
139
140
141static char *solaudio_getdevice (void)
142{
143 /*
144 * This is for multiple audio devices where env. var determines current one,
145 * otherwise else we fallback to default.
146 */
147 const char *pszAudioDev = RTEnvGet("AUDIODEV");
148 if (pszAudioDev)
149 return RTStrDup(pszAudioDev);
150
151 return RTStrDup("/dev/audio");
152}
153
154
155static void solaudio_close_device (audio_dest_t dst)
156{
157 LogFlow(("solaudio: solaudio_close_device\n"));
158 switch (dst)
159 {
160 case enmPlay:
161 {
162 close(g_AudioDev);
163 g_AudioDev = -1;
164 break;
165 }
166
167 case enmRecord:
168 case enmRecordPassive:
169 {
170 close(g_RecordDev);
171 g_RecordDev = -1;
172 break;
173 }
174
175 default:
176 LogRel(("solaudio: cannot close. invalid audio destination %d.\n", dst));
177 }
178}
179
180
181static int solaudio_open_device (audio_dest_t dst)
182{
183 int rc = 0;
184
185 LogFlow(("solaudio: solaudio_open_device dest=%d\n", dst));
186
187 switch (dst)
188 {
189 case enmPlay:
190 {
191 LogFlow(("solaudio: open_device for enmPlay\n"));
192 g_AudioDev = open(g_pszAudioDev, O_WRONLY | O_NONBLOCK);
193 if (g_AudioDev < 0)
194 {
195 LogRel(("solaudio: failed to open device %s dst=%d\n", g_pszAudioDev, dst));
196 rc = -1;
197 }
198 break;
199 }
200
201 case enmRecord:
202 case enmRecordPassive:
203 {
204 LogFlow(("solaudio: open_device for enmRecord\n"));
205 g_RecordDev = open(g_pszAudioDev, (dst == enmRecord ? O_RDONLY : O_WRONLY) | O_NONBLOCK);
206 if (g_RecordDev < 0)
207 {
208 LogRel(("solaudio: failed to open device %s dst=%d\n", g_pszAudioDev, dst));
209 rc = -1;
210 }
211 break;
212 }
213
214 default:
215 LogRel(("solaudio: Invalid audio destination.\n"));
216 break;
217 }
218 return rc;
219}
220
221
222static int solaudio_setattrs(audio_dest_t dst, audio_info_t *info)
223{
224 audio_info_t AudioInfo;
225 audio_prinfo_t *pDstInfo;
226 audio_prinfo_t *pSrcInfo;
227
228 LogFlow(("solaudio: solaudio_setattrs dst=%d info=%p\n", dst, info));
229
230 if (!info)
231 return -1;
232
233 AUDIO_INITINFO(&AudioInfo);
234 if (ioctl(dst == enmPlay ? g_AudioDev : g_RecordDev, AUDIO_GETINFO, &AudioInfo) < 0)
235 {
236 LogRel(("solaudio: AUDIO_GETINFO failed\n"));
237 return -1;
238 }
239
240 if (dst == enmPlay)
241 {
242 pDstInfo = &AudioInfo.play;
243 pSrcInfo = &info->play;
244 }
245 else
246 {
247 pDstInfo = &AudioInfo.record;
248 pSrcInfo = &info->record;
249 }
250
251 pDstInfo->sample_rate = pSrcInfo->sample_rate;
252 pDstInfo->channels = pSrcInfo->channels;
253 pDstInfo->precision = pSrcInfo->precision;
254 pDstInfo->encoding = pSrcInfo->encoding;
255 pDstInfo->buffer_size = pSrcInfo->buffer_size;
256 pDstInfo->gain = AUDIO_MAX_GAIN;
257 pDstInfo->open = 0;
258
259 if (ioctl(dst == enmPlay ? g_AudioDev : g_RecordDev, AUDIO_SETINFO, &AudioInfo) < 0)
260 {
261 LogRel(("solaudio: AUDIO_SETINFO failed\n"));
262 return -1;
263 }
264 return 0;
265}
266
267
268static int solaudio_init_out (HWVoiceOut *hw, audsettings_t *as)
269{
270 solaudioVoiceOut *pSol = (solaudioVoiceOut *)hw;
271 audsettings_t ObtAudioInfo;
272
273 AUDIO_INITINFO(&pSol->AudioInfo);
274 pSol->AudioInfo.play.sample_rate = as->freq;
275 pSol->AudioInfo.play.channels = as->nchannels;
276 pSol->AudioInfo.play.precision = aud_to_solfmt(as->fmt);
277 pSol->AudioInfo.play.buffer_size = conf.cbPlayBuffer;
278
279 if (as->fmt == AUD_FMT_U8)
280 pSol->AudioInfo.play.encoding = AUDIO_ENCODING_LINEAR8;
281 else
282 pSol->AudioInfo.play.encoding = AUDIO_ENCODING_LINEAR;
283
284 /* Open device for playback. */
285 if (solaudio_open_device(enmPlay))
286 {
287 LogRel(("solaudio: solaudio_open failed\n"));
288 return -1;
289 }
290
291 /* Specify playback attributes to device. */
292 if (solaudio_setattrs(enmPlay, &pSol->AudioInfo))
293 {
294 LogRel(("solaudio: failed to set playback attributes.\n"));
295 return -1;
296 }
297
298 /* Copy obtained playback attributes. */
299 ObtAudioInfo.freq = pSol->AudioInfo.play.sample_rate;
300 ObtAudioInfo.nchannels = pSol->AudioInfo.play.channels;
301 ObtAudioInfo.fmt = sol_to_audfmt(pSol->AudioInfo.play.precision, pSol->AudioInfo.play.encoding);
302 ObtAudioInfo.endianness = as->endianness;
303
304 audio_pcm_init_info(&hw->info, &ObtAudioInfo);
305 pSol->cBuffersPlayed = 0;
306
307 hw->samples = pSol->AudioInfo.play.buffer_size >> hw->info.shift;
308 pSol->pPCMBuf = RTMemAllocZ(pSol->AudioInfo.play.buffer_size);
309 if (!pSol->pPCMBuf)
310 {
311 LogRel(("solaudio: failed to alloc %d %d bytes to pPCMBuf\n", hw->samples << hw->info.shift, hw->samples));
312 return -1;
313 }
314 LogFlow(("solaudio: init_out hw->samples=%d play.buffer_size=%d\n", hw->samples, pSol->AudioInfo.play.buffer_size));
315 return 0;
316}
317
318
319static void solaudio_fini_out (HWVoiceOut *hw)
320{
321 solaudioVoiceOut *sol = (solaudioVoiceOut *) hw;
322 LogFlow(("solaudio: fini_out\n"));
323
324 solaudio_close_device(enmPlay);
325 if (sol->pPCMBuf)
326 {
327 RTMemFree(sol->pPCMBuf);
328 sol->pPCMBuf = NULL;
329 }
330}
331
332
333static void solaudio_start_out (HWVoiceOut *hw)
334{
335 audio_info_t AudioInfo;
336 solaudioVoiceOut *pSol = (solaudioVoiceOut *)hw;
337 LogFlow(("solaudio: voice_enable\n"));
338
339 audio_pcm_info_clear_buf(&hw->info, pSol->pPCMBuf, hw->samples);
340
341 AUDIO_INITINFO(&AudioInfo);
342 ioctl(g_AudioDev, AUDIO_GETINFO, &AudioInfo);
343 AudioInfo.play.pause = 0;
344#if 0
345 AudioInfo.play.eof = 0;
346 AudioInfo.play.samples = 0;
347 pSol->cBuffersPlayed = 0;
348#endif
349 ioctl(g_AudioDev, AUDIO_SETINFO, &AudioInfo);
350}
351
352
353static void solaudio_stop_out (solaudioVoiceOut *sol)
354{
355 audio_info_t AudioInfo;
356 LogFlow(("solaudio: stop_out\n"));
357
358 if (ioctl(g_AudioCtl, I_SETSIG, 0) < 0)
359 {
360 Log(("solaudio: failed to stop signalling\n"));
361 return;
362 }
363
364 if (ioctl(g_AudioDev, I_FLUSH, FLUSHW) < 0)
365 {
366 LogRel(("solaudio: failed to drop unplayed buffers\n"));
367 return;
368 }
369
370 AUDIO_INITINFO(&AudioInfo);
371 AudioInfo.play.pause = 1;
372#if 0
373 AudioInfo.play.samples = 0;
374 AudioInfo.play.eof = 0;
375 AudioInfo.play.error = 0;
376 sol->cBuffersPlayed = 0;
377#endif
378 if (ioctl(g_AudioDev, AUDIO_SETINFO, &AudioInfo) < 0)
379 {
380 LogRel(("solaudio: AUDIO_SETINFO failed during stop_out.\n"));
381 return;
382 }
383}
384
385
386static int solaudio_availbuf (solaudioVoiceOut *sol)
387{
388 int cbPlayBuffer = 0;
389 if (ioctl(g_AudioDev, AUDIO_GETINFO, &sol->AudioInfo) < 0)
390 {
391 LogRel(("solaudio: AUDIO_GETINFO ioctl failed\n"));
392 return -1;
393 }
394
395 if (sol->cBuffersPlayed - sol->AudioInfo.play.eof <= 2)
396 cbPlayBuffer = conf.cbPlayBuffer;
397
398 /* Check for overflow */
399 if (sol->cBuffersPlayed > UINT_MAX - 4)
400 {
401 sol->cBuffersPlayed -= UINT_MAX - 4;
402 sol->AudioInfo.play.eof -= UINT_MAX - 4;
403 ioctl(g_AudioDev, AUDIO_SETINFO, &sol->AudioInfo);
404 }
405
406 LogFlow(("avail: eof=%d samples=%d bufplayed=%d avail=%d\n", sol->AudioInfo.play.eof, sol->AudioInfo.play.samples,
407 sol->cBuffersPlayed, cbPlayBuffer));
408 return cbPlayBuffer;
409}
410
411
412static int solaudio_run_out (HWVoiceOut *hw)
413{
414 solaudioVoiceOut *pSol = (solaudioVoiceOut *) hw;
415 int csLive, csDecr, csSamples, csToWrite, csAvail;
416 size_t cbAvail, cbToWrite, cbWritten;
417 uint8_t *pu8Dst;
418 st_sample_t *psSrc;
419
420 csLive = audio_pcm_hw_get_live_out(hw);
421 if (!csLive)
422 return 0;
423
424 cbAvail = solaudio_availbuf(pSol);
425 if (cbAvail <= 0)
426 return 0;
427
428 csAvail = cbAvail >> hw->info.shift; /* bytes => samples */
429 csDecr = audio_MIN(csLive, csAvail);
430 csSamples = csDecr;
431
432 while (csSamples)
433 {
434 /* split request at the end of our samples buffer */
435 csToWrite = audio_MIN(csSamples, hw->samples - hw->rpos);
436 cbToWrite = csToWrite << hw->info.shift;
437 psSrc = hw->mix_buf + hw->rpos;
438 pu8Dst = advance(pSol->pPCMBuf, hw->rpos << hw->info.shift);
439
440 hw->clip(pu8Dst, psSrc, csToWrite);
441
442 cbWritten = write(g_AudioDev, pu8Dst, cbToWrite);
443 if (cbWritten < 0)
444 break;
445
446 hw->rpos = (hw->rpos + csToWrite) % hw->samples;
447 csSamples -= csToWrite;
448 }
449
450 /* Increment eof marker for synchronous buffer processed */
451 write (g_AudioDev, NULL, 0);
452 pSol->cBuffersPlayed++;
453 return csDecr;
454}
455
456
457static int solaudio_ctl_out (HWVoiceOut *hw, int cmd, ...)
458{
459 solaudioVoiceOut *pSol = (solaudioVoiceOut *) hw;
460 switch (cmd)
461 {
462 case VOICE_ENABLE:
463 {
464 LogFlow(("solaudio: voice_enable\n"));
465 solaudio_start_out(hw);
466 break;
467 }
468
469 case VOICE_DISABLE:
470 {
471 LogFlow(("solaudio: voice_disable\n"));
472 solaudio_stop_out(pSol);
473 break;
474 }
475 }
476 return 0;
477}
478
479
480static int solaudio_write (SWVoiceOut *sw, void *buf, int len)
481{
482 return audio_pcm_sw_write (sw, buf, len);
483}
484
485
486static void *solaudio_audio_init (void)
487{
488 struct stat FileStat;
489
490 LogFlow(("solaudio_audio_init\n"));
491 if (!g_pszAudioDev)
492 {
493 g_pszAudioDev = solaudio_getdevice();
494 if (!g_pszAudioDev)
495 {
496 LogRel(("solaudio: solaudio_getdevice() failed to return a valid device.\n"));
497 return NULL;
498 }
499 }
500
501 if (stat(g_pszAudioDev, &FileStat) < 0)
502 {
503 LogRel(("solaudio: failed to stat %s\n", g_pszAudioDev));
504 return NULL;
505 }
506
507 if (!S_ISCHR(FileStat.st_mode))
508 {
509 LogRel(("solaudio: invalid mode for %s\n", g_pszAudioDev));
510 return NULL;
511 }
512
513 if (!g_pszAudioCtl)
514 RTStrAPrintf(&g_pszAudioCtl, "%sctl", g_pszAudioDev);
515
516 if (g_AudioCtl < 0)
517 {
518 g_AudioCtl = open(g_pszAudioCtl, O_RDWR | O_NONBLOCK);
519 if (g_AudioCtl < 0)
520 {
521 LogRel(("solaudio: failed to open device %s\n", g_pszAudioCtl));
522 return NULL;
523 }
524 }
525
526 return &conf;
527}
528
529
530static void solaudio_audio_fini (void *opaque)
531{
532 LogFlow(("solaudio_audio_fini\n"));
533 if (g_pszAudioDev)
534 {
535 RTStrFree(g_pszAudioDev);
536 g_pszAudioDev = NULL;
537 }
538 if (g_pszAudioCtl)
539 {
540 RTStrFree(g_pszAudioCtl);
541 g_pszAudioCtl = NULL;
542 }
543 close(g_AudioCtl);
544 g_AudioCtl = -1;
545
546 NOREF(opaque);
547}
548
549
550/* -=-=-=-=- Audio Input -=-=-=-=- */
551
552static void solaudio_pause_record(void)
553{
554 audio_info_t AudioInfo;
555 AUDIO_INITINFO(&AudioInfo);
556 if (ioctl(g_RecordDev, AUDIO_GETINFO, &AudioInfo) < 0)
557 {
558 LogRel(("solaudio: failed to get info. to pause recording.\n"));
559 return;
560 }
561
562 AudioInfo.record.pause = 1;
563 if (ioctl(g_RecordDev, AUDIO_SETINFO, &AudioInfo))
564 LogRel(("solaudio: failed to pause recording.\n"));
565}
566
567
568static void solaudio_resume_record(void)
569{
570 audio_info_t AudioInfo;
571 AUDIO_INITINFO(&AudioInfo);
572 if (ioctl(g_RecordDev, AUDIO_GETINFO, &AudioInfo) < 0)
573 {
574 LogRel(("solaudio: failed to get info. to resume recording.\n"));
575 return;
576 }
577
578 AudioInfo.record.pause = 0;
579 if (ioctl(g_RecordDev, AUDIO_SETINFO, &AudioInfo))
580 LogRel(("solaudio: failed to resume recording.\n"));
581}
582
583
584
585static void solaudio_stop_in (solaudioVoiceIn *sol)
586{
587 audio_info_t AudioInfo;
588 LogFlow(("solaudio: stop_in\n"));
589
590 if (ioctl(g_AudioCtl, I_SETSIG, 0) < 0)
591 {
592 Log(("solaudio: failed to stop signalling\n"));
593 return;
594 }
595
596 if (ioctl(g_RecordDev, I_FLUSH, FLUSHR) < 0)
597 {
598 LogRel(("solaudio: failed to drop record buffers\n"));
599 return;
600 }
601
602 AUDIO_INITINFO(&AudioInfo);
603 AudioInfo.record.samples = 0;
604 AudioInfo.record.pause = 1;
605 AudioInfo.record.eof = 0;
606 AudioInfo.record.error = 0;
607 if (ioctl(g_RecordDev, AUDIO_SETINFO, &AudioInfo) < 0)
608 {
609 LogRel(("solaudio: AUDIO_SETINFO failed during stop_in.\n"));
610 return;
611 }
612
613 solaudio_close_device(enmRecord);
614}
615
616
617static void solaudio_start_in (solaudioVoiceIn *sol)
618{
619 LogFlow(("solaudio: start_in\n"));
620 if (solaudio_open_device(enmRecord))
621 {
622 LogRel(("solaudio: failed to open for recording.\n"));
623 }
624
625 if (solaudio_setattrs(enmRecord, &sol->AudioInfo))
626 {
627 LogRel(("solaudio: solaudio_setattrs for recording failed.\n"));
628 return;
629 }
630 solaudio_resume_record();
631}
632
633
634static int solaudio_init_in (HWVoiceIn *hw, audsettings_t *as)
635{
636 solaudioVoiceIn *pSol = (solaudioVoiceIn *)hw;
637 audsettings_t ObtAudioInfo;
638
639 AUDIO_INITINFO(&pSol->AudioInfo);
640 pSol->AudioInfo.record.sample_rate = as->freq;
641 pSol->AudioInfo.record.channels = as->nchannels;
642 pSol->AudioInfo.record.precision = aud_to_solfmt(as->fmt);
643 pSol->AudioInfo.record.buffer_size = conf.cbRecordBuffer;
644
645 if (as->fmt == AUD_FMT_U8)
646 pSol->AudioInfo.record.encoding = AUDIO_ENCODING_LINEAR8;
647 else
648 pSol->AudioInfo.record.encoding = AUDIO_ENCODING_LINEAR;
649
650 /*
651 * Open device for recording in passive mode (O_WRONLY) as we do not
652 * want to start buffering audio immediately. This is what is recommended.
653 */
654 if (solaudio_open_device(enmRecordPassive))
655 {
656 LogRel(("solaudio: solaudio_open failed.\n"));
657 return -1;
658 }
659
660 /* Specify playback attributes to device. */
661 if (solaudio_setattrs(enmRecord, &pSol->AudioInfo))
662 {
663 LogRel(("solaudio: failed to set playback attributes.\n"));
664 return -1;
665 }
666
667 /* Copy obtained record attributes. */
668 ObtAudioInfo.freq = pSol->AudioInfo.record.sample_rate;
669 ObtAudioInfo.nchannels = pSol->AudioInfo.record.channels;
670 ObtAudioInfo.fmt = sol_to_audfmt(pSol->AudioInfo.record.precision, pSol->AudioInfo.record.encoding);
671 ObtAudioInfo.endianness = as->endianness;
672
673 audio_pcm_init_info(&hw->info, &ObtAudioInfo);
674
675 hw->samples = pSol->AudioInfo.record.buffer_size >> hw->info.shift;
676 pSol->pPCMBuf = RTMemAllocZ(pSol->AudioInfo.record.buffer_size);
677 if (!pSol->pPCMBuf)
678 {
679 LogRel(("solaudio: init_in: failed to alloc %d %d bytes to pPCMBuf\n", hw->samples << hw->info.shift, hw->samples));
680 return -1;
681 }
682 solaudio_close_device(enmRecordPassive);
683 LogFlow(("solaudio: init_in: hw->samples=%d record.buffer_size=%d rate=%d\n", hw->samples, pSol->AudioInfo.record.buffer_size,
684 pSol->AudioInfo.record.sample_rate));
685 return 0;
686}
687
688
689static void solaudio_fini_in (HWVoiceIn *hw)
690{
691 solaudioVoiceIn *sol = (solaudioVoiceIn *) hw;
692 LogFlow(("solaudio: fini_in done\n"));
693
694 if (sol->pPCMBuf)
695 {
696 RTMemFree(sol->pPCMBuf);
697 sol->pPCMBuf = NULL;
698 }
699}
700
701
702static int solaudio_run_in (HWVoiceIn *hw)
703{
704#if 0
705 solaudioVoiceIn *pSol = (solaudioVoiceIn *) hw;
706 int csDead, csDecr = 0, csSamples, csRead, csAvail;
707 size_t cbAvail, cbRead;
708 void *pu8Src;
709 st_sample_t *psDst;
710
711 csDead = hw->samples - audio_pcm_hw_get_live_in (hw);
712
713 if (!csDead)
714 return 0;
715
716 if (ioctl(g_AudioDev, I_NREAD, &cbAvail) < 0)
717 {
718 LogRel(("solaudio: I_NREAD failed\n"));
719 return 0;
720 }
721
722 if (!cbAvail)
723 return 0;
724
725 cbAvail = audio_MIN(cbAvail, conf.cbRecordBuffer);
726 pu8Src = pSol->pPCMBuf;
727 cbRead = read(g_AudioDev, pu8Src, cbAvail);
728 if (cbRead <= 0)
729 return 0;
730
731 csAvail = cbAvail >> hw->info.shift;
732 csDecr = audio_MIN (csDead, csAvail);
733 csSamples = csDecr;
734
735 while (csSamples)
736 {
737 /* split request at the end of our samples buffer */
738 psDst = hw->conv_buf + hw->wpos;
739 csRead = audio_MIN (csSamples, hw->samples - hw->wpos);
740 hw->conv (psDst, pu8Src, csRead, &pcm_in_volume);
741 hw->wpos = (hw->wpos + csRead) % hw->samples;
742 csSamples -= csRead;
743 pu8Src = (void *)((uint8_t*)pu8Src + (csRead << hw->info.shift));
744 }
745 return csDecr;
746#else
747 solaudioVoiceIn *sol = (solaudioVoiceIn *) hw;
748 int hwshift = hw->info.shift;
749 int i;
750 int live = audio_pcm_hw_get_live_in (hw);
751 int dead = hw->samples - live;
752 size_t read_samples = 0;
753 struct
754 {
755 int add;
756 int len;
757 } bufs[2];
758
759 bufs[0].add = hw->wpos;
760 bufs[0].len = 0;
761 bufs[1].add = 0;
762 bufs[1].len = 0;
763
764 if (!dead) {
765 return 0;
766 }
767
768 if (hw->wpos + dead > hw->samples)
769 {
770 bufs[0].len = (hw->samples - hw->wpos) << hwshift;
771 bufs[1].len = (dead - (hw->samples - hw->wpos)) << hwshift;
772 }
773 else
774 bufs[0].len = dead << hwshift;
775
776
777 for (i = 0; i < 2; ++i)
778 {
779 ssize_t nread;
780
781 if (bufs[i].len)
782 {
783 void *p = advance (sol->pPCMBuf, bufs[i].add << hwshift);
784 nread = read (g_RecordDev, p, bufs[i].len);
785
786 if (nread > 0)
787 {
788 read_samples += nread >> hwshift;
789 hw->conv (hw->conv_buf + bufs[i].add, p, nread >> hwshift,
790 &pcm_in_volume);
791 }
792
793 if (bufs[i].len - nread)
794 if (nread == -1)
795 break;
796 }
797 }
798
799 hw->wpos = (hw->wpos + read_samples) % hw->samples;
800 return read_samples;
801#endif
802}
803
804
805static int solaudio_read (SWVoiceIn *sw, void *buf, int size)
806{
807 return audio_pcm_sw_read (sw, buf, size);
808}
809
810
811static int solaudio_ctl_in (HWVoiceIn *hw, int cmd, ...)
812{
813 solaudioVoiceIn *pSol = (solaudioVoiceIn *) hw;
814 switch (cmd)
815 {
816 case VOICE_ENABLE:
817 {
818 LogRel(("solaudio: solaudio_ctl_in voice_enable\n"));
819 solaudio_start_in(pSol);
820 break;
821 }
822
823 case VOICE_DISABLE:
824 {
825 LogRel(("solaudio: solaudio_ctl_in voice_disable\n"));
826 solaudio_stop_in(pSol);
827 break;
828 }
829 }
830 return 0;
831}
832
833
834static struct audio_pcm_ops solaudio_pcm_ops =
835{
836 solaudio_init_out,
837 solaudio_fini_out,
838 solaudio_run_out,
839 solaudio_write,
840 solaudio_ctl_out,
841
842 NULL,
843 NULL,
844 NULL,
845 NULL,
846 NULL
847};
848
849
850static struct audio_option solaudio_options[] =
851{
852 {"PLAY_BUFFER_SIZE", AUD_OPT_INT, &conf.cbPlayBuffer,
853 "Size of the buffer in bytes", NULL, 0},
854#if 0
855 {"RECORD_BUFFER_SIZE", AUD_OPT_INT, &conf.cbRecordBuffer,
856 "Size of the record bufffer in bytes", NULL, 0},
857#endif
858 {NULL, 0, NULL, NULL, NULL, 0}
859};
860
861
862struct audio_driver solaudio_audio_driver =
863{
864 INIT_FIELD (name = ) "solaudio",
865 INIT_FIELD (descr = ) "SolarisAudio http://sun.com",
866 INIT_FIELD (options = ) solaudio_options,
867 INIT_FIELD (init = ) solaudio_audio_init,
868 INIT_FIELD (fini = ) solaudio_audio_fini,
869 INIT_FIELD (pcm_ops = ) &solaudio_pcm_ops,
870 INIT_FIELD (can_be_default = ) 1,
871 INIT_FIELD (max_voices_out = ) INT_MAX,
872 INIT_FIELD (max_voices_in = ) 0, /* Input not really supported. */
873 INIT_FIELD (voice_size_out = ) sizeof (solaudioVoiceOut),
874 INIT_FIELD (voice_size_in = ) 0
875};
876
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