VirtualBox

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

Last change on this file since 22638 was 21602, checked in by vboxsync, 15 years ago

Audio/Solaris: don't define LOG_ENABLED unconditionally.

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