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