VirtualBox

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

Last change on this file since 40754 was 35353, checked in by vboxsync, 13 years ago

Move the misc files the in src/VBox/Devices/ directory into a build/ subdirectory, changing their names to match the target module.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use