source: cmedia/trunk/Drv16/wavestrm.cpp@ 354

Last change on this file since 354 was 354, checked in by stevenhl, 17 years ago

Import untested baseline cmedia sources, work products and binaries
Binaries and work products should be deleted from repository.
once new builds are verified to work.

File size: 21.2 KB
Line 
1/* $Id: wavestrm.cpp,v 1.9 2001/04/30 21:07:59 sandervl Exp $ */
2
3/* SCCSID = %W% %E% */
4/****************************************************************************
5 * *
6 * Copyright (c) IBM Corporation 1994 - 1997. *
7 * *
8 * The following IBM OS/2 source code is provided to you solely for the *
9 * the purpose of assisting you in your development of OS/2 device drivers. *
10 * You may use this code in accordance with the IBM License Agreement *
11 * provided in the IBM Device Driver Source Kit for OS/2. *
12 * *
13 ****************************************************************************/
14/**@internal %W%
15 * @notes
16 * @version %I%
17 * @context Unless otherwise noted, all interfaces are Ring-0, 16-bit,
18 * <stack context>.
19 * @history
20 *
21 */
22#define INCL_NOPMAPI
23#define INCL_DOSERRORS // for ERROR_INVALID_FUNCTION
24#include <os2.h>
25#include <os2me.h>
26#include <audio.h> // for #define MIDI
27#include <include.h>
28
29#include "wavestrm.hpp"
30#include "audiohw.hpp"
31#include "waudio.hpp"
32#include "memutil.h"
33#include <ossidc.h>
34#include <dbgos2.h>
35#include "ioctl.h"
36
37#ifndef min
38#define min(a,b) (a>b) ? b : a
39#endif
40
41#include <DevHelp.h>
42#include "trace.h"
43
44
45//
46// _vRealignBuffer
47// called just after a wave stream pause on a playback.
48// Gets the end position of the stream when paused and a pointer to a
49// STREAMBUFFER. Basicly this function looks at the streambuffer and if
50// there is any unplayed data in it it adjusts the bufpos counter.
51// the donepos counter is ALWAYS set to zero. It will return 0 if all
52// the data has been played and 1 if there is still some data left.
53//
54USHORT WAVESTREAM::_vRealignBuffer(ULONG FAR *bytesinc, PSTREAMBUFFER pbuffer)
55{
56 // if none of the data in this stream buffer has been consumed
57 if (!*bytesinc) {
58 pbuffer->ulDonepos = 0;
59 pbuffer->ulBuffpos = 0;
60 return 1;
61 }
62
63 pbuffer->ulDonepos += *bytesinc;
64 pbuffer->ulBuffpos = pbuffer->ulDonepos;
65 *bytesinc = 0;
66 if(pbuffer->ulDonepos >= pbuffer->ulBuffsz) {
67 //calc position in next buffer
68 *bytesinc = pbuffer->ulDonepos - pbuffer->ulBuffsz;
69 return 0; //all of the buffer has been consumed
70 }
71 return 1;
72}
73//
74// _vRealignPausedBuffers(void)
75// when a stream is paused we need to "realign" the data in the audio buffer
76// with reality. On playback, not all the data in the audio buffer has been
77// consumed. Likewise on a capture, not all the good data in the audio buffer
78// has been copied out. After receiving the DDCMDCONTROL Pause we will call
79// this function to line the MMPM buffers back up.
80// there are 2 cases here: first one is the case of a capture stream.
81// for a capture stream we simply read any data that is still in the audio
82// buffer into a MMPM buffer.
83// for a playback stream things are not so straight forward.
84// first check the STREAMBUFFER on pHead to see if any of it's data is in the
85// audio buffer and not consumed, if yes back up the ulBuffpos in the
86// STREAMBUFFER. Next check any STREAMBUFFERS on pdone starting with the last
87// one. (the one on the tail of the queue) If necessary back up the ulBuffpos
88// and put the STREAMBUFFER on the Head queue.
89//
90void WAVESTREAM::_vRealignPausedBuffers(ULONG endpos)
91{
92 PSTREAMBUFFER ptempbuff;
93
94 switch (usStreamType & STREAM_WRITE) {
95 case STREAM_READ:
96 //SvL: Don't get the lastest recording data as a read command
97 // would now restart recording (as it's stopped)
98 // Just return what we've got or push the buffer on the inprocess queue
99 ptempbuff = (PSTREAMBUFFER)qhDone.Head();
100 if(ptempbuff) {
101 if(ptempbuff->ulBuffpos) {//if we recorded anything into this buffer, then return it now
102 ReturnBuffer();
103 return;
104 }
105 ptempbuff->ulBuffpos = 0;
106 ptempbuff->ulDonepos = 0;
107 qhInProcess.PushOnHead(qhDone.PopHead());
108 }
109 break;
110
111 case STREAM_WRITE:
112 {
113 PQUEUEHEAD pTempHead = new QUEUEHEAD;
114 ULONG bytesinc;
115 USHORT usRC;
116
117 bytesinc = endpos - _ulBytesProcessed;
118 bytesinc &= 0xFFFFFFFC; //keep it on a dword boundary
119
120 // if there are bufferes on the done queue, pop them off the head and
121 // push them on the head of qhTempHead. This will reorder them so
122 // that the more recently used ones will be in the front of the queue.
123 // Pass them all to _vRealignBuffer. If the rc from _vRealignBuffer is
124 // 0 then there is no unprocessed data in the buffer (it is ready to
125 // be returned) so put it on the Tail of the done queue.
126 // If the rc is 1 then put it on the head of the InProcess queue.
127
128 while (qhDone.IsElements()) {
129 pTempHead->PushOnTail(qhDone.PopHead());
130 } /* endwhile */
131
132 while (qhInProcess.IsElements()) {
133 pTempHead->PushOnTail(qhInProcess.PopHead());
134 } /* endwhile */
135
136 while(pTempHead->IsElements()) {
137 usRC = _vRealignBuffer(&bytesinc, (PSTREAMBUFFER)pTempHead->Head());
138 if (usRC) {
139 qhInProcess.PushOnTail(pTempHead->PopHead());
140 }
141 else {
142 qhDone.PushOnTail(pTempHead->PopHead());
143 }
144 } /* endwhile */
145 if(qhDone.IsElements())
146 ReturnBuffer();
147
148 delete pTempHead; // free the memory this ain't no Java here !!
149 break;
150 }
151 default:
152 break;
153 } /* endswitch */
154}
155//
156// get ready to start streaming
157// this requires the following:
158// call Initbuffer in the audiobuffer object
159// if this is a write stream call _vFillAudioBuf
160//
161#pragma off (unreferenced)
162void WAVESTREAM::AddBuffers(BOOL fFirst)
163#pragma on (unreferenced)
164{
165 ULONG space, byteswritten;
166
167 if (usStreamType & STREAM_WRITE) {
168 if(!qhInProcess.Head() && !qhDone.Head()) {
169 //underrun: stop playback
170 dprintf(("underrun: stop playback"));
171 pahw->Stop(this);
172 fUnderrun = TRUE;
173 return;
174 }
175 space = OSS16_StreamGetSpace(this);
176 while(space) {
177 byteswritten = AddBuffer(space);
178 if( byteswritten == (ULONG)-1 ) break;
179 space -= byteswritten;
180 }
181 }
182}
183
184//
185// write one buffer to the audio buffer
186// the caller of this function MUST make sure it ok to write the audio buffer..
187// _AudioBufWrite will not check if there is room in the audio buffer of if
188// there are buffers on pHead... BEWARE
189//
190ULONG WAVESTREAM::AddBuffer(ULONG space)
191{
192 PSTREAMBUFFER pTemp = (PSTREAMBUFFER)qhDone.Tail();
193 ULONG pdataBuf;
194 ULONG Buff_left, byteswritten;
195
196 if(!pTemp || pTemp->ulBuffpos >= (pTemp->ulBuffsz & 0xFFFFFFFC)) {
197 pTemp = (PSTREAMBUFFER)qhInProcess.Head();
198 }
199 if(!pTemp) {
200 dprintf4(("AddBuffer: pTemp == NULL"));
201 return (ULONG)-1;
202 }
203
204 // get the buffer pointer and amount of data remaining
205 pdataBuf = (ULONG)pTemp->pBuffptr + pTemp->ulBuffpos;
206 Buff_left = pTemp->ulBuffsz - pTemp->ulBuffpos;
207
208 if( Buff_left ) {
209
210 // write the audio buffer
211 Buff_left = min(Buff_left, space);
212 byteswritten = OSS16_StreamAddBuffer(this, pdataBuf, Buff_left);
213
214 if(byteswritten == 0) {
215 return (ULONG)-1; //no more room
216 }
217
218 // update the buffer pos counter
219 pTemp->ulBuffpos += byteswritten;
220 }
221 else byteswritten = 0;
222
223// if(pTemp != qhDone.Tail()) {
224 if(pTemp == qhInProcess.Head()) {
225 qhDone.PushOnTail(qhInProcess.PopHead());
226 }
227 dprintf4(("AddBuffer %lx size %d, bytes written %d", pdataBuf, (USHORT)Buff_left, (USHORT)byteswritten));
228
229/*
230 dprintf(("AddBuffer2 %lx, buffsz: %ld, buffpos: %ld free %d, written %d,",
231 pTemp->pBuffptr, pTemp->ulBuffsz, pTemp->ulBuffpos, (USHORT)Buff_left, (USHORT)byteswritten));
232*/
233 return byteswritten;
234}
235
236// Read data from the audio Buffer.
237// Called at interrupt time to get the good data from the audiobuffer object.
238//
239BOOL WAVESTREAM::_vReadAudioBuf(void)
240{
241 PSTREAMBUFFER pTemp = (PSTREAMBUFFER)qhInProcess.Head();
242 ULONG pdataBuf;
243 ULONG Buff_left, bytesread;
244
245 if(!pTemp) return FALSE;
246
247 // get the buffer pointer and amount of data remaining
248 pdataBuf = (ULONG)pTemp->pBuffptr + pTemp->ulBuffpos;
249 Buff_left = pTemp->ulBuffsz - pTemp->ulBuffpos;
250
251 // write the audio buffer
252 bytesread = OSS16_StreamAddBuffer(this, pdataBuf, Buff_left);
253 if(bytesread == 0) {
254 return FALSE; //no more data
255 }
256
257 dprintf4(("_vReadAudioBuf %lx size %d, bytes read %d", pdataBuf, Buff_left, bytesread));
258
259 // update the buffer pos counter
260 pTemp->ulBuffpos += bytesread;
261 _ulBytesProcessed += bytesread;
262
263 if(pTemp->ulBuffpos == pTemp->ulBuffsz) {
264 qhDone.PushOnTail(qhInProcess.PopHead());
265 ReturnBuffer();
266 dprintf4(("_vReadAudioBuf return buffer %lx size %ld, bytes read %ld",
267 (ULONG)pTemp->pBuffptr, pTemp->ulBuffsz, bytesread));
268 }
269
270 return TRUE;
271}
272// called by the irq function in the hardware object when we get an interrupt
273// first call _vUpdateProcessed() to update the dma amd audio buffer related
274// stuff. Next if we have buffers on the primary queue try to read/write them
275// to the audiobuffer. Look at the buffers on the done queue and see if they
276// can be returned and finally process any events pending.
277void WAVESTREAM::Process(void)
278{
279 PSTREAMBUFFER ptemp;
280 ULONG ulCurBytesProcessed = 0;
281 ULONG bytesinc;
282
283 switch (usStreamType & STREAM_WRITE) {
284 case STREAM_WRITE:
285 {
286 OSS16_StreamGetPos(this, &ulCurBytesProcessed);
287 if(ulCurBytesProcessed == 0) {
288 //shouldn't happen
289 DebugInt3();
290 return;
291 }
292 bytesinc = ulCurBytesProcessed - _ulBytesProcessed;
293 dprintf4(("Process: %lx %x", ulCurBytesProcessed, (USHORT)bytesinc));
294
295//DevSysTrace(240, 200, sizeof(bytesinc), &bytesinc);
296//dprintf(("Process: %lx %x", ulCurBytesProcessed, (USHORT)bytesinc));
297
298 if(ulCurBytesProcessed < _ulBytesProcessed) {
299 dprintf(("WARNING: Process: Current pos %ld incr %d",
300 ulCurBytesProcessed, (USHORT)bytesinc));
301 }
302 _ulBytesProcessed = ulCurBytesProcessed;
303
304
305 while(bytesinc) {
306 if(qhDone.IsElements()) { // if there are buffers that have been
307 // completly written to the audio buffer
308 // check the first one on the done queue
309 // if it's data has been consumed by
310 // the hardware return it
311 ptemp = (PSTREAMBUFFER)qhDone.Head();
312 ptemp->ulDonepos += bytesinc;
313
314//dprintf(("ptemp->ulDonepos: %ld, ptemp->ulBuffsz: %ld", (ULONG)ptemp->ulDonepos, (ULONG)ptemp->ulBuffsz));
315
316 bytesinc = 0;
317 if(ptemp->ulDonepos >= ptemp->ulBuffsz) {
318 //calc position in next buffer
319
320 bytesinc = ptemp->ulDonepos - ptemp->ulBuffsz;
321// dprintf(("Process: Return buffer %lx size %d", ptemp->pBuffptr, ptemp->ulBuffsz));
322
323 ReturnBuffer();
324 }
325 }
326 else
327 break; //shouldn't happen
328 }
329
330/*
331 //Get rid of empty buffers
332 ptemp = (PSTREAMBUFFER)qhInProcess.Head();
333 if(ptemp && (ptemp->ulBuffsz == 0 || ptemp->pBuffptr == NULL)) {
334 dprintf(("Returning 0 size buffer immediately(%lx, %d)", ptemp->pBuffptr, ptemp->ulBuffsz));
335//Rudi: ReturnBuffer works on qhDone !
336 qhDone.PushOnHead(qhInProcess.PopHead());
337 ReturnBuffer();
338 }
339*/
340/*
341dprintf(("qhInProcess.head: %x, qhInProcess.tail: %x, qhDone.head: %x, qhDone.tail: %x",
342 qhInProcess.Head(), qhInProcess.Tail(), qhDone.Head(), qhDone.Tail()));
343*/
344 AddBuffers(FALSE);
345 break;
346 }
347 case STREAM_READ:
348 while(_vReadAudioBuf());
349 break;
350 default:
351 break;
352 } /* endswitch */
353
354 ProcessEvents();
355}
356
357#pragma off (unreferenced)
358ULONG WAVESTREAM::Write(PSTREAMBUF pbuf, ULONG uLength, BOOL fLooping)
359#pragma on (unreferenced)
360{
361 PSTREAMBUFFER pStreamBuf = new STREAMBUFFER(uLength, pbuf);
362
363 return Write(pStreamBuf);
364}
365
366ULONG WAVESTREAM::Write(PSTREAMBUFFER pStreamBuf)
367{
368 cli2();
369 qhInProcess.PushOnTail((PQUEUEELEMENT)pStreamBuf);
370 popf();
371
372// dprintf2(("WAVESTREAM::Write: Push on tail %lx %ld", ((PSTREAMBUFFER)qhInProcess.Tail())->pBuffptr, ((PSTREAMBUFFER)qhInProcess.Tail())->ulBuffsz));
373
374 if(fUnderrun) {
375 fUnderrun = FALSE;
376 OSS16_StreamReset(this);
377 AddBuffers(TRUE);
378
379 if( !fStreamVolIOCTL90 &&
380 usStreamType == STREAM_WAVE_PLAY ) OSS16_SetWaveOutVol(this, volume);
381 }
382 return 0;
383}
384
385ULONG WAVESTREAM::Read(PSTREAMBUF pbuf, unsigned uLength)
386{
387 PQUEUEELEMENT pQElem = (PQUEUEELEMENT)new STREAMBUFFER(uLength, pbuf);
388
389 cli2();
390 qhInProcess.PushOnTail(pQElem);
391 popf();
392
393 dprintf2(("WAVESTREAM::Read: Push on tail %lx %d",
394 ((PSTREAMBUFFER)qhInProcess.Head())->pBuffptr, ((PSTREAMBUFFER)qhInProcess.Head())->ulBuffsz));
395 return 0;
396}
397
398// WAVESTREAM::GetCurrentTime(void)
399// get current time will calculate the stream time in milliseconds based on
400// NOW.... the open mpeg folks this is the greatest thing since my last
401// pay raise!!
402// but then again you know what those ring 3 programmers are like....
403// the algorythum goes like this....
404// bytes consumed / consume rate = seconds
405// Note before calling BufferUpdate check to see if the stream is running.
406// if it is not then call with flags of 0. This will prevent the audio buffer
407// trying to get the latest consumption info from the hardware object. (dma or
408// or pci as the case may be) Asking a hardware object that is not running for
409// status information is just not a good idea.....
410//
411
412ULONG WAVESTREAM::GetCurrentTime()
413{
414 ULONG Seconds, MilliSeconds, Overflow, Processed;
415
416 if (usStreamState == STREAM_STREAMING) // if the stream is active
417 {
418 if (usStreamType & STREAM_WRITE) {
419 OSS16_StreamGetPos(this, &Processed);
420 }
421 else Processed = _ulBytesProcessed;
422 }
423 else Processed = _ulBytesProcessed;
424
425 // if we haven't processed anything then just return
426 // _ulTimeBase
427 if(Processed == 0)
428 return(_ulTimeBase);
429
430 Seconds = Processed / _configinfo.ulPCMConsumeRate;
431 Overflow = Processed - (Seconds * _configinfo.ulPCMConsumeRate);
432 MilliSeconds = ((Overflow * 1000) + (_configinfo.ulPCMConsumeRate / 2)) / _configinfo.ulPCMConsumeRate;
433 MilliSeconds += (Seconds * 1000);
434 return(MilliSeconds + _ulTimeBase);
435}
436
437ULONG WAVESTREAM::GetCurrentPos(void)
438{
439 ULONG Processed;
440
441 if (usStreamState == STREAM_STREAMING) // if the stream is active
442 {
443 if (usStreamType & STREAM_WRITE) {
444 OSS16_StreamGetPos(this, &Processed);
445 }
446 else Processed = _ulBytesProcessed;
447 }
448 else Processed = _ulBytesProcessed;
449
450 return Processed;
451}
452
453ULONG WAVESTREAM::GetCurrentWritePos(void)
454{
455 ULONG writepos = 0;
456
457 cli2();
458
459 PSTREAMBUFFER pTemp = (PSTREAMBUFFER)qhDone.Tail();
460
461 if(!pTemp) {
462 pTemp = (PSTREAMBUFFER)qhInProcess.Head();
463 }
464 if(pTemp) {
465 writepos = pTemp->ulBuffpos;
466 }
467
468 popf();
469
470 return writepos;
471}
472
473//
474// SetCurrentTime
475// MMPM will send in the "starting stream time" as they see it.
476// "our stream time" will always start at 0, so we save "their" time and
477// add it to the elapsed time we calculate when we need to return time.
478//
479void WAVESTREAM::SetCurrentTime(ULONG time)
480{
481 _ulTimeBase = time;
482}
483
484//
485//
486ULONG WAVESTREAM::StartStream(void)
487{
488 PSTREAMBUFFER pTemp = (PSTREAMBUFFER)qhInProcess.Head();
489
490
491 // configure the wave device
492 ((PWAVEAUDIO)pahw)->ConfigDev(this, &_configinfo);
493
494// Rudi: reduce interrupt rate
495#if 0
496 if(usStreamType == STREAM_WAVE_PLAY) {
497 fragsize = _configinfo.ulPCMConsumeRate/64; //start with 64 irqs/sec
498 }
499 else fragsize = _configinfo.ulPCMConsumeRate/32; //start with 32 irqs/sec (no need for more)
500
501#else
502 fragsize = _configinfo.ulPCMConsumeRate/32;
503
504#endif
505
506 //if the buffer is smaller than our predefined fragmentsize (*2), then correct it
507 //I assume here that buffers sizes don't radically change (except the last one)
508 //while playing a stream. If they do get a lot smaller, then we'll run into problems.
509 //There's nothing we can do about it as the fragment size can't be changed
510 //while the stream is playing.
511 if(pTemp->ulBuffsz/2 < fragsize) {
512 fragsize = pTemp->ulBuffsz/2;
513 if(fragsize < _configinfo.ulPCMConsumeRate/256)
514 {//lower limit; don't accept extremely small buffers
515 fragsize = _configinfo.ulPCMConsumeRate/256;
516 }
517 }
518
519
520 OSS16_StreamSetFragment(this, fragsize);
521 dprintf(("WAVESTREAM::StartStream: Fragment size %d", (USHORT)fragsize));
522 _ulBytesProcessed = 0;
523 fUnderrun = FALSE;
524
525 usStreamState = STREAM_STREAMING;
526 //Adding the first buffer also starts playback
527 if(usStreamType == STREAM_WAVE_PLAY) {
528 AddBuffers(TRUE);
529 }
530 else {
531 if(!fRecSrcIOCTL90)
532 OSS16_SetVolume(this, MIX_SETINPUTSRC, inputsrc);
533 if(!fRecGainIOCTL90)
534 OSS16_SetVolume(this, MIX_SETINPUTGAIN, inputgain);
535 OSS16_StartStream(this);
536 }
537
538 //Must set volume after adding buffers (voices inside sblive driver might not
539 //be allocated otherwise (first start) )
540 if( !fStreamVolIOCTL90 &&
541 usStreamType == STREAM_WAVE_PLAY ) OSS16_SetWaveOutVol(this, volume);
542
543 dprintf(("WAVESTREAM::StartStream %lx", ulStreamId));
544 return NO_ERROR;
545
546}
547
548ULONG WAVESTREAM::StopStream(PCONTROL_PARM pControl)
549{
550 if(usStreamState == STREAM_STOPPED) {
551 dprintf(("WAVESTREAM::StopStream %lx (already stopped)", ulStreamId));
552 fUnderrun = FALSE;
553 pControl->ulTime = GetCurrentTime();
554 return NO_ERROR;
555 }
556 pahw->Stop(this);
557
558 //Reset cleans up waveout instance
559 OSS16_StreamReset(this);
560
561 usStreamState = STREAM_STOPPED;
562 fUnderrun = FALSE;
563 dprintf(("WAVESTREAM::StopStream %lx", ulStreamId));
564 ReturnBuffers();
565
566 pControl->ulTime = _ulTimeBase = GetCurrentTime();
567
568dprintf(("STOP qhInProcess.head: %x, qhInProcess.tail: %x, qhDone.head: %x, qhDone.tail: %x",
569 qhInProcess.Head(), qhInProcess.Tail(), qhDone.Head(), qhDone.Tail()));
570
571 return NO_ERROR;
572
573}
574
575ULONG WAVESTREAM::PauseStream(PCONTROL_PARM pControl)
576{
577 ULONG endpos;
578
579 if (usStreamState == STREAM_PAUSED) // is the stream paused?
580 return ERROR_INVALID_SEQUENCE;
581
582 OSS16_StreamGetPos(this, &endpos);
583
584 pahw->Stop(this);
585
586 //Reset cleans up waveout instance
587 OSS16_StreamReset(this);
588
589 usStreamState = STREAM_PAUSED;
590 fUnderrun = FALSE;
591
592 dprintf(("WAVESTREAM::PauseStream %lx", ulStreamId));
593 _vRealignPausedBuffers(endpos);
594
595 _ulBytesProcessed = endpos;
596 pControl->ulTime = _ulTimeBase = GetCurrentTime();
597 return NO_ERROR;
598
599}
600
601ULONG WAVESTREAM::ResumeStream(void)
602{
603 if (usStreamState == STREAM_STREAMING) // is the stream paused?
604 return ERROR_INVALID_SEQUENCE;
605
606 // configure the wave device
607 ((PWAVEAUDIO)pahw)->ConfigDev(this, &_configinfo);
608
609 // Rudi: restore fragment size
610 OSS16_StreamSetFragment(this, fragsize);
611
612 if( !fStreamVolIOCTL90 &&
613 usStreamType == STREAM_WAVE_PLAY ) OSS16_SetWaveOutVol(this, volume);
614
615 dprintf(("WAVESTREAM::ResumeStream %lx", ulStreamId));
616 _ulBytesProcessed = 0;
617 fUnderrun = FALSE;
618
619 usStreamState = STREAM_STREAMING;
620 //Adding the first buffer also starts playback
621 AddBuffers(TRUE);
622 return NO_ERROR;
623
624}
625
626
627BOOL WAVESTREAM::SetProperty(int type, ULONG value, ULONG reserved)
628{
629 switch(type) {
630 case PROPERTY_VOLUME:
631 if( volume != value ) {
632 volume = value; mixerchange = TRUE;
633 }
634
635 if( usStreamState == STREAM_STREAMING &&
636 usStreamType == STREAM_WAVE_PLAY &&
637 !fStreamVolIOCTL90 ) OSS16_SetWaveOutVol(this, volume);
638
639 return TRUE;
640
641 case PROPERTY_INPUTSRC:
642 if( inputsrc != value ) {
643 inputsrc = value; mixerchange = TRUE;
644 }
645 return TRUE;
646
647 case PROPERTY_INPUTGAIN:
648 if( inputgain != value ) {
649 inputgain = value; mixerchange = TRUE;
650 }
651 return TRUE;
652 }
653
654 return STREAM::SetProperty(type, value, reserved);
655}
656
657ULONG WAVESTREAM::GetProperty(int type)
658{
659 switch(type) {
660 case PROPERTY_FREQUENCY:
661 return _configinfo.ulSampleRate;
662
663 case PROPERTY_INPUTSRC:
664 return inputsrc;
665
666 case PROPERTY_INPUTGAIN:
667 return inputgain;
668 }
669
670 return STREAM::GetProperty(type);
671}
672
673WAVESTREAM::WAVESTREAM(USHORT streamtype, LPMCI_AUDIO_INIT pinit, USHORT filesysnum):
674 STREAM(streamtype, filesysnum)
675{
676 _configinfo.ulSampleRate = (ULONG)pinit->lSRate;
677 _configinfo.usBitsPerSample = (USHORT)pinit->lBitsPerSRate;
678 _configinfo.usNumChannels = (USHORT)pinit->sChannels;
679 _configinfo.usDataType = (USHORT)pinit->sMode;
680 _ulBytesProcessed = 0;
681 _ulTimeBase = 0;
682
683 fUnderrun = FALSE;
684
685 pinit->ulFlags |= FIXED; // Fixed length data
686
687// Rudi
688// if (pinit->lBitsPerSRate == 8)
689 if (pinit->lBitsPerSRate == 16)
690 pinit->ulFlags |= TWOS_COMPLEMENT; // 2's complement data
691
692// Rudi: set stereo volume
693 volume = MAKE_VOLUME_LR(100, 100);
694
695 hProcessHook = 0;
696 DevHelp_AllocateCtxHook((NPFN)ProcessHookStub, &hProcessHook);
697
698 ulStreamId = OSS16_OpenStream(this);
699 dprintf(("WAVESTREAM ctor %lx: rate %d bps %d numchan %d type %x",
700 ulStreamId, (USHORT)_configinfo.ulSampleRate,
701 _configinfo.usBitsPerSample, _configinfo.usNumChannels,
702 _configinfo.usDataType));
703}
704
705
706WAVESTREAM::~WAVESTREAM()
707{
708 dprintf(("WAVESTREAM dtor %lx", ulStreamId));
709
710 if( ulStreamId ) OSS16_CloseStream(this);
711
712 if( hProcessHook ) DevHelp_FreeCtxHook(hProcessHook);
713}
714
715
716void WAVESTREAM::ArmProcessHook(void)
717{
718 DevHelp_ArmCtxHook((ULONG)this, hProcessHook);
719}
720
721
722ULONG WAVESTREAM::Register(PDDCMDREGISTER p)
723{
724 ULONG ulResult = STREAM::Register(p);
725
726 p->ulBufSize = 16384;
727 p->ulAddressType = ADDRESS_TYPE_LINEAR;
728
729 return ulResult;
730}
731
732
Note: See TracBrowser for help on using the repository browser.