source: cmedia/trunk/Drv16/stream.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: 11.5 KB
Line 
1/* $Id: stream.cpp,v 1.5 2001/05/09 17:44:24 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>
27
28#include <include.h>
29#include <devhelp.h>
30
31#include "stream.hpp"
32#include "queue.hpp"
33#include "event.hpp"
34#include "strmbuff.hpp"
35#include "ioctl.h"
36
37#include <ossidc.h>
38
39#include <dbgos2.h>
40
41
42
43
44PQUEUEHEAD pStreamList; // List head for Streams. Initialized during DD initilialization.
45
46void STREAM::ReturnBuffer(void)
47{
48 SHD_REPORTINT shdri; // structure used to return buffers to SHD
49 PSTREAMBUFFER temp = (PSTREAMBUFFER)qhDone.PopHead();
50
51 if (temp)
52 {
53 shdri.ulFunction = SHD_REPORT_INT;
54
55 // if this is a write (playback) then set the streamtype and
56 // tell the stream handler that we played all of the buffer.
57 if (usStreamType & STREAM_WRITE) {
58 shdri.ulFlag = SHD_WRITE_COMPLETE;
59 shdri.ulStatus = temp->ulBuffsz;
60 }
61 // if this is a capture then tell the stream hamdler
62 // how much data we wrote to the buffer
63 else {
64 shdri.ulFlag = SHD_READ_COMPLETE;
65 shdri.ulStatus = temp->ulBuffpos;
66 }
67 shdri.hStream = hstream;
68 shdri.pBuffer = temp->pBuffptr;
69 shdri.ulStreamTime = GetCurrentTime();
70 pfnSHD(&shdri);
71 delete temp;
72 }
73}
74
75//
76// ReturnBuffers(void)
77// Return all buffers to MMPM.
78//
79void STREAM::ReturnBuffers(void)
80{
81 // move all buffers from the InProcess Queue to the Done Queue
82 while (qhInProcess.IsElements()) {
83 qhDone.PushOnTail(qhInProcess.PopHead());
84 }
85 // Return all the buffers on the Done Queue
86 while (qhDone.IsElements()) {
87#ifdef DEBUG
88 PSTREAMBUFFER ptemp = (PSTREAMBUFFER)qhDone.Head();
89 dprintf(("Return buffer %lx size %d", ptemp->pBuffptr, ptemp->ulBuffsz));
90#endif
91 ReturnBuffer();
92 }
93}
94//
95// ProcessEvents
96// called by the Process at interrupt time to see if there are
97// any events that have timed out
98//
99void STREAM::ProcessEvents(void)
100{
101//SvL: BUGFIX: check all events
102#if 1
103 if (qhEvent.IsElements()) {
104 PEVENT pnextevent = (PEVENT)qhEvent.Head();
105 ULONG time = GetCurrentTime();
106 while(pnextevent) {
107 ULONG eventtime = pnextevent->GetEventTime();
108 if (eventtime <= time)
109 pnextevent->Report(time);
110 pnextevent = (PEVENT)pnextevent->pNext;
111 }
112 }
113#else
114 if (qhEvent.IsElements()) {
115 PEVENT pnextevent = (PEVENT)qhEvent.Head();
116 ULONG time = GetCurrentTime();
117 ULONG eventtime = pnextevent->GetEventTime();
118 if (eventtime <= time)
119 pnextevent->Report(time);
120 }
121#endif
122}
123
124ULONG STREAM::EnableEvent(PDDCMDCONTROL pControl)
125{
126
127 // see if the event already exists on the event queue
128 // call FindEvent if we get back an address (event exists)
129 // call the UpdateEvent member function and get the event info updated.
130 // if Findevent returns NULL (no event on queue) then call the construct
131 // a new event and put it on the tail of the event queue. then call
132 // SetNextEvent to update the next event to time out....
133
134 PEVENT pevent = FindEvent(pControl->hEvent, &qhEvent);
135 if (pevent)
136 pevent->UpdateEvent(this,pControl->hEvent,(PCONTROL_PARM)pControl->pParm);
137 else {
138 pevent= new EVENT(this,pControl->hEvent,(PCONTROL_PARM)pControl->pParm);
139 }
140 if (!pevent)
141 return ERROR_TOO_MANY_EVENTS;
142
143 SetNextEvent();
144 return NO_ERROR;
145}
146
147ULONG STREAM::DisableEvent(PDDCMDCONTROL pControl)
148{
149 PEVENT pevent = FindEvent(pControl->hEvent, &qhEvent);
150 if (!pevent)
151 return ERROR_INVALID_EVENT;
152
153 // destroying an event may change things that get referenced in the ISR
154 // so we really need to cli/sti around the call to DestroyElement
155 cli();
156 qhEvent.DestroyElement((PQUEUEELEMENT)pevent);
157 if (qhEvent.Head() != qhEvent.Tail())
158 SetNextEvent();
159 sti();
160 return NO_ERROR;
161}
162
163ULONG STREAM::PauseStreamTime(void)
164{
165 fIncrementCounter = FALSE;
166 return NO_ERROR;
167}
168
169ULONG STREAM::ResumeStreamTime(void)
170{
171
172 fIncrementCounter = TRUE;
173 return NO_ERROR;
174}
175
176
177
178ULONG STREAM::Register(PDDCMDREGISTER p)
179{
180 hstream = p->hStream;
181 pfnSHD = (PFN_SHD) p->pSHDEntryPoint;
182
183 p->mmtimePerUnit = 0;
184 p->ulBytesPerUnit = 0;
185 p->ulNumBufs = 16;
186 p->ulBufSize = 512;
187 p->ulAddressType = ADDRESS_TYPE_VIRTUAL;
188
189 return 0;
190}
191
192
193void STREAM::DeRegister(void)
194{
195 hstream = 0;
196 pfnSHD = NULL;
197}
198
199
200#pragma off (unreferenced)
201virtual ULONG STREAM::Write(PSTREAMBUF pbuf, ULONG uLength, BOOL fLooping)
202#pragma on (unreferenced)
203{
204 qhInProcess.PushOnTail((PQUEUEELEMENT)new STREAMBUFFER(uLength, pbuf));
205 return 0;
206}
207
208/**@internal SetNextEvent
209 * @param None
210 * @return None
211 * @notes
212 * the function walks the event list and finds the next event to timeout.
213 * the event is moved to the head of the event queue.
214 *
215 */
216void STREAM::SetNextEvent(void)
217{
218
219 // if there are no events or only one event on the
220 // queue just return
221 if ((qhEvent.Head()) == (qhEvent.Tail()))
222 return;
223
224 PQUEUEELEMENT pele1 = qhEvent.Head();
225 PQUEUEELEMENT pele2 = NULL;
226 ULONG ulTimeToBeat = -1; // -1 equals 0xFFFFFFFF the maximum time
227
228 while (pele1) {
229 if (((PEVENT)pele1)->GetEventTime() <= ulTimeToBeat) {
230 pele2 = pele1;
231 ulTimeToBeat = ((PEVENT)pele1)->GetEventTime();
232 }
233 pele1 = pele1->pNext;
234 }
235 // pele2 should now contain the address of the next
236 // event to time out.. if it is not already on
237 // the head of the Event queue then put it there
238 if (pele2 != qhEvent.Head()) {
239 cli();
240 qhEvent.PopElement(pele2);
241 qhEvent.PushOnHead(pele2);
242 sti();
243 }
244}
245#define INVALID_HSTREAM ((HSTREAM) 0)
246#define INVALID_HFILE ((ULONG) 0)
247
248STREAM::STREAM(USHORT streamtype, USHORT filesysnum)
249{
250 // put this stream on the stream list
251 pStreamList->PushOnTail(this);
252
253 // get the pointer to the hardware object
254 pahw = GetHardwareDevice(streamtype);
255 usStreamType = streamtype;
256
257 hstream = INVALID_HSTREAM; // We're putting a stream into the stream list, but
258 usSysFileNum = filesysnum;
259
260 fIncrementCounter = TRUE;
261 ulCurrentTime = 0;
262 usStreamState = STREAM_STOPPED;
263
264 ulStreamId = 0;
265
266 volume = 100; // full
267 balance = 50; // middle
268 inputgain = 50; // moderate
269 inputsrc = MIX_RECSRC_LINE;
270}
271
272STREAM::~STREAM(void)
273{
274 if (usStreamState == STREAM_STREAMING)
275 pahw->Stop(this);
276 // detstoy all the STREAMBUFFERs and EVENTs that this STREAM
277 // may still have
278
279 while (qhInProcess.IsElements()) {
280 qhInProcess.DestroyElement(qhInProcess.Head());
281 } /* endwhile */
282
283 while (qhDone.IsElements()) {
284 qhDone.DestroyElement(qhDone.Head());
285 } /* endwhile */
286
287 while (qhEvent.IsElements()) {
288 qhEvent.DestroyElement(qhEvent.Head());
289 } /* endwhile */
290
291 pStreamList->PopElement(this);
292}
293
294void STREAM::SetLooping(BOOL /*fLooping*/)
295{
296 return;
297}
298
299BOOL STREAM::SetProperty(int type, ULONG value, ULONG /*reserved*/)
300{
301 switch(type) {
302 case PROPERTY_VOLUME:
303 if( volume != value ) {
304 volume = value; mixerchange = TRUE;
305 }
306 break;
307
308 case PROPERTY_BALANCE:
309 if( balance != value ) {
310 balance = value; mixerchange = TRUE;
311 }
312 break;
313
314 case PROPERTY_MASTERVOL:
315/* if( mastervol != value ) {
316 mastervol = value; mixerchange = TRUE;
317 return OSS16_SetMasterVol(this, mastervol);
318 }
319*/
320 SetMasterControl(value, (ULONG)-1);
321 break;
322
323 default:
324 return FALSE;
325 }
326
327 return TRUE;
328}
329
330ULONG STREAM::GetProperty(int type)
331{
332 switch(type) {
333 case PROPERTY_VOLUME:
334 return volume;
335
336 case PROPERTY_BALANCE:
337 return balance;
338
339 case PROPERTY_MASTERVOL:
340 return mastervol;
341/*
342 case PROPERTY_MASTERBAL:
343 return masterbal;
344
345 case PROPERTY_FREQUENCY:
346 case PROPERTY_LOOPING:
347 break;
348*/
349 }
350
351 return -1;
352}
353
354
355void STREAM::SetMasterControl(ULONG ulMasterVol, ULONG ulMasterBal)
356{
357 ULONG l, r;
358 USHORT ctChange = 0;
359
360 if( ulMasterVol != (ULONG)-1 && ulMasterVol != mastervol ) {
361 mastervol = ulMasterVol; ctChange++;
362 }
363
364 if( ulMasterBal != (ULONG)-1 && ulMasterBal != masterbal ) {
365 masterbal = ulMasterBal; ctChange++;
366 }
367
368 if( ctChange ) {
369 l = (GET_VOLUME_L(mastervol) * GET_VOLUME_L(masterbal)) / 100;
370 r = (GET_VOLUME_R(mastervol) * GET_VOLUME_R(masterbal)) / 100;
371
372 mixerchange |=
373 OSS16_SetGlobalVol(0, MIX_SETMASTERVOL, MAKE_VOLUME_LR(l, r));
374 }
375}
376
377
378ULONG STREAM::mastervol = MAKE_VOLUME_LR(100, 100);
379ULONG STREAM::masterbal = MAKE_VOLUME_LR(100, 100);
380BOOL STREAM::mixerchange = FALSE;
381
382
383
384
385PSTREAM FindActiveStream(USHORT StreamType)
386{
387 PSTREAM pStream = (PSTREAM) pStreamList->Head();
388
389 while (pStream)
390 if ((pStream->usStreamType == StreamType) &&
391 (pStream->usStreamState == STREAM_STREAMING))
392 return pStream;
393 else
394 pStream = (PSTREAM) pStream->pNext;
395
396 return NULL;
397}
398
399PSTREAM FindActiveStream(USHORT StreamType, ULONG StreamId)
400{
401 PSTREAM pStream = (PSTREAM) pStreamList->Head();
402
403 while (pStream)
404 if ((pStream->usStreamType == StreamType) &&
405 (pStream->usStreamState == STREAM_STREAMING) && (pStream->ulStreamId == StreamId))
406 return pStream;
407 else
408 pStream = (PSTREAM) pStream->pNext;
409
410 return NULL;
411}
412
413PSTREAM FindStream_fromFile(USHORT usSysFileNum)
414/* Map a system file handle to a Stream object.
415 * ### FUTURE: Make parm type a real type so we can use overloading,
416 * ### and change name/signature back to "FindStream( fileHandle )".
417 */
418{
419 PSTREAM pStream = (PSTREAM) pStreamList->Head();
420
421 while (pStream)
422 if (pStream->usSysFileNum == usSysFileNum)
423 return pStream;
424 else
425 pStream = (PSTREAM) pStream->pNext;
426
427 return NULL;
428}
429
430PSTREAM FindStream(HSTREAM hStream)
431/* Map a stream handle to a Stream object. */
432{
433 PSTREAM pStream = (PSTREAM) pStreamList->Head();
434
435 while (pStream)
436 if (pStream->hstream == hStream)
437 return pStream;
438 else
439 pStream = (PSTREAM) pStream->pNext;
440
441 return NULL;
442}
443
444// Rudi: enumerate stream list
445PSTREAM EnumStreams(PSTREAM pStream, USHORT StreamType)
446{
447 pStream = ( pStream ) ?
448 (PSTREAM) pStream->pNext : (PSTREAM) pStreamList->Head();
449
450 while( pStream )
451 if( StreamType == STREAM_ANY || StreamType == pStream->usStreamType )
452 return pStream;
453 else
454 pStream = (PSTREAM) pStream->pNext;
455
456 return NULL;
457}
458
Note: See TracBrowser for help on using the repository browser.