1 | /* $Id: stream.cpp 166 2001-03-22 18:13:01Z 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>
|
---|
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 <ossidc.h>
|
---|
36 |
|
---|
37 | PQUEUEHEAD pStreamList; // List head for Streams. Initialized during DD initilialization.
|
---|
38 |
|
---|
39 | void STREAM::ReturnBuffer(void)
|
---|
40 | {
|
---|
41 | SHD_REPORTINT shdri; // structure used to return buffers to SHD
|
---|
42 | PSTREAMBUFFER temp = (PSTREAMBUFFER)qhDone.PopHead();
|
---|
43 |
|
---|
44 | if (temp)
|
---|
45 | {
|
---|
46 | shdri.ulFunction = SHD_REPORT_INT;
|
---|
47 |
|
---|
48 | // if this is a write (playback) then set the streamtype and
|
---|
49 | // tell the stream handler that we played all of the buffer.
|
---|
50 | if (ulStreamType & STREAM_WRITE) {
|
---|
51 | shdri.ulFlag = SHD_WRITE_COMPLETE;
|
---|
52 | shdri.ulStatus = temp->ulBuffsz;
|
---|
53 | }
|
---|
54 | // if this is a capture then tell the stream hamdler
|
---|
55 | // how much data we wrote to the buffer
|
---|
56 | else {
|
---|
57 | shdri.ulFlag = SHD_READ_COMPLETE;
|
---|
58 | shdri.ulStatus = temp->ulBuffpos;
|
---|
59 | }
|
---|
60 | shdri.hStream = hstream;
|
---|
61 | shdri.pBuffer = temp->pBuffptr;
|
---|
62 | shdri.ulStreamTime = GetCurrentTime();
|
---|
63 | pfnSHD(&shdri);
|
---|
64 | delete temp;
|
---|
65 | }
|
---|
66 | }
|
---|
67 |
|
---|
68 | //
|
---|
69 | // ReturnBuffers(void)
|
---|
70 | // Return all buffers to MMPM.
|
---|
71 | //
|
---|
72 | void STREAM::ReturnBuffers(void)
|
---|
73 | {
|
---|
74 | // move all buffers from the InProcess Queue to the Done Queue
|
---|
75 | while (qhInProcess.IsElements()) {
|
---|
76 | qhDone.PushOnTail(qhInProcess.PopHead());
|
---|
77 | }
|
---|
78 | // Return all the buffers on the Done Queue
|
---|
79 | while (qhDone.IsElements()) {
|
---|
80 | ReturnBuffer();
|
---|
81 | }
|
---|
82 | }
|
---|
83 | //
|
---|
84 | // ProcessEvents
|
---|
85 | // called by the Process at interrupt time to see if there are
|
---|
86 | // any events that have timed out
|
---|
87 | //
|
---|
88 | void STREAM::ProcessEvents(void)
|
---|
89 | {
|
---|
90 | //SvL: BUGFIX: check all events
|
---|
91 | #if 1
|
---|
92 | if (qhEvent.IsElements()) {
|
---|
93 | PEVENT pnextevent = (PEVENT)qhEvent.Head();
|
---|
94 | ULONG time = GetCurrentTime();
|
---|
95 | while(pnextevent) {
|
---|
96 | ULONG eventtime = pnextevent->GetEventTime();
|
---|
97 | if (eventtime <= time)
|
---|
98 | pnextevent->Report(time);
|
---|
99 | pnextevent = (PEVENT)pnextevent->pNext;
|
---|
100 | }
|
---|
101 | }
|
---|
102 | #else
|
---|
103 | if (qhEvent.IsElements()) {
|
---|
104 | PEVENT pnextevent = (PEVENT)qhEvent.Head();
|
---|
105 | ULONG time = GetCurrentTime();
|
---|
106 | ULONG eventtime = pnextevent->GetEventTime();
|
---|
107 | if (eventtime <= time)
|
---|
108 | pnextevent->Report(time);
|
---|
109 | }
|
---|
110 | #endif
|
---|
111 | }
|
---|
112 |
|
---|
113 | ULONG STREAM::EnableEvent(PDDCMDCONTROL pControl)
|
---|
114 | {
|
---|
115 |
|
---|
116 | // see if the event already exists on the event queue
|
---|
117 | // call FindEvent if we get back an address (event exists)
|
---|
118 | // call the UpdateEvent member function and get the event info updated.
|
---|
119 | // if Findevent returns NULL (no event on queue) then call the construct
|
---|
120 | // a new event and put it on the tail of the event queue. then call
|
---|
121 | // SetNextEvent to update the next event to time out....
|
---|
122 |
|
---|
123 | PEVENT pevent = FindEvent(pControl->hEvent, &qhEvent);
|
---|
124 | if (pevent)
|
---|
125 | pevent->UpdateEvent(this,pControl->hEvent,(PCONTROL_PARM)pControl->pParm);
|
---|
126 | else {
|
---|
127 | pevent= new EVENT(this,pControl->hEvent,(PCONTROL_PARM)pControl->pParm);
|
---|
128 | }
|
---|
129 | if (!pevent)
|
---|
130 | return ERROR_TOO_MANY_EVENTS;
|
---|
131 |
|
---|
132 | SetNextEvent();
|
---|
133 | return NO_ERROR;
|
---|
134 | }
|
---|
135 |
|
---|
136 | ULONG STREAM::DisableEvent(PDDCMDCONTROL pControl)
|
---|
137 | {
|
---|
138 | PEVENT pevent = FindEvent(pControl->hEvent, &qhEvent);
|
---|
139 | if (!pevent)
|
---|
140 | return ERROR_INVALID_EVENT;
|
---|
141 |
|
---|
142 | // destroying an event may change things that get referenced in the ISR
|
---|
143 | // so we really need to cli/sti around the call to DestroyElement
|
---|
144 | cli();
|
---|
145 | qhEvent.DestroyElement((PQUEUEELEMENT)pevent);
|
---|
146 | if (qhEvent.Head() != qhEvent.Tail())
|
---|
147 | SetNextEvent();
|
---|
148 | sti();
|
---|
149 | return NO_ERROR;
|
---|
150 | }
|
---|
151 |
|
---|
152 | ULONG STREAM::PauseStreamTime(void)
|
---|
153 | {
|
---|
154 | fIncrementCounter = FALSE;
|
---|
155 | return NO_ERROR;
|
---|
156 | }
|
---|
157 |
|
---|
158 | ULONG STREAM::ResumeStreamTime(void)
|
---|
159 | {
|
---|
160 |
|
---|
161 | fIncrementCounter = TRUE;
|
---|
162 | return NO_ERROR;
|
---|
163 | }
|
---|
164 |
|
---|
165 |
|
---|
166 |
|
---|
167 | ULONG STREAM::Register(PDDCMDREGISTER p)
|
---|
168 | {
|
---|
169 | hstream = p->hStream;
|
---|
170 | pfnSHD = (PFN_SHD) p->pSHDEntryPoint;
|
---|
171 | p->ulAddressType = ADDRESS_TYPE_LINEAR;
|
---|
172 | p->mmtimePerUnit = 0;
|
---|
173 | p->ulBytesPerUnit = 0;
|
---|
174 | p->ulNumBufs = 0x00000010;
|
---|
175 | if (ulStreamType & 0xFFFFFF60) // if this is a midi stream
|
---|
176 | p->ulBufSize = 0x00000200;
|
---|
177 | else
|
---|
178 | p->ulBufSize = 0x00004000;
|
---|
179 | return 0;
|
---|
180 | }
|
---|
181 |
|
---|
182 |
|
---|
183 | void STREAM::DeRegister(void)
|
---|
184 | {
|
---|
185 | hstream = 0;
|
---|
186 | pfnSHD = NULL;
|
---|
187 | }
|
---|
188 |
|
---|
189 |
|
---|
190 | virtual ULONG STREAM::Write(PSTREAMBUF pbuf, ULONG uLength)
|
---|
191 | {
|
---|
192 | qhInProcess.PushOnTail((PQUEUEELEMENT)new STREAMBUFFER(uLength, pbuf));
|
---|
193 | return 0;
|
---|
194 | }
|
---|
195 |
|
---|
196 | /**@internal SetNextEvent
|
---|
197 | * @param None
|
---|
198 | * @return None
|
---|
199 | * @notes
|
---|
200 | * the function walks the event list and finds the next event to timeout.
|
---|
201 | * the event is moved to the head of the event queue.
|
---|
202 | *
|
---|
203 | */
|
---|
204 | void STREAM::SetNextEvent(void)
|
---|
205 | {
|
---|
206 |
|
---|
207 | // if there are no events or only one event on the
|
---|
208 | // queue just return
|
---|
209 | if ((qhEvent.Head()) == (qhEvent.Tail()))
|
---|
210 | return;
|
---|
211 |
|
---|
212 | PQUEUEELEMENT pele1 = qhEvent.Head();
|
---|
213 | PQUEUEELEMENT pele2 = NULL;
|
---|
214 | ULONG ulTimeToBeat = -1; // -1 equals 0xFFFFFFFF the maximum time
|
---|
215 |
|
---|
216 | while (pele1) {
|
---|
217 | if (((PEVENT)pele1)->GetEventTime() <= ulTimeToBeat) {
|
---|
218 | pele2 = pele1;
|
---|
219 | ulTimeToBeat = ((PEVENT)pele1)->GetEventTime();
|
---|
220 | }
|
---|
221 | pele1 = pele1->pNext;
|
---|
222 | }
|
---|
223 | // pele2 should now contain the address of the next
|
---|
224 | // event to time out.. if it is not already on
|
---|
225 | // the head of the Event queue then put it there
|
---|
226 | if (pele2 != qhEvent.Head()) {
|
---|
227 | cli();
|
---|
228 | qhEvent.PopElement(pele2);
|
---|
229 | qhEvent.PushOnHead(pele2);
|
---|
230 | sti();
|
---|
231 | }
|
---|
232 | }
|
---|
233 | #define INVALID_HSTREAM ((HSTREAM) 0)
|
---|
234 | #define INVALID_HFILE ((ULONG) 0)
|
---|
235 |
|
---|
236 | STREAM::STREAM(ULONG streamtype, USHORT filesysnum)
|
---|
237 | {
|
---|
238 | // put this stream on the stream list
|
---|
239 | pStreamList->PushOnTail(this);
|
---|
240 |
|
---|
241 | // get the pointer to the hardware object
|
---|
242 | pahw = GetHardwareDevice(streamtype);
|
---|
243 | ulStreamType = streamtype;
|
---|
244 |
|
---|
245 | hstream = INVALID_HSTREAM; // We're putting a stream into the stream list, but
|
---|
246 | ulSysFileNum = filesysnum;
|
---|
247 |
|
---|
248 | fIncrementCounter = TRUE;
|
---|
249 | ulCurrentTime = 0;
|
---|
250 | ulStreamState = STREAM_STOPPED;
|
---|
251 |
|
---|
252 | ulStreamId = 0;
|
---|
253 |
|
---|
254 | balance = 50; //middle
|
---|
255 | volume = 80;
|
---|
256 | inputgain = 50;
|
---|
257 | inputsrc = MIX_RECSRC_LINE;
|
---|
258 | }
|
---|
259 |
|
---|
260 | STREAM::~STREAM(void)
|
---|
261 | {
|
---|
262 | if (ulStreamState == STREAM_STREAMING)
|
---|
263 | pahw->Stop(this);
|
---|
264 | // detstoy all the STREAMBUFFERs and EVENTs that this STREAM
|
---|
265 | // may still have
|
---|
266 |
|
---|
267 | while (qhInProcess.IsElements()) {
|
---|
268 | qhInProcess.DestroyElement(qhInProcess.Head());
|
---|
269 | } /* endwhile */
|
---|
270 |
|
---|
271 | while (qhDone.IsElements()) {
|
---|
272 | qhDone.DestroyElement(qhDone.Head());
|
---|
273 | } /* endwhile */
|
---|
274 |
|
---|
275 | while (qhEvent.IsElements()) {
|
---|
276 | qhEvent.DestroyElement(qhEvent.Head());
|
---|
277 | } /* endwhile */
|
---|
278 |
|
---|
279 | pStreamList->PopElement(this);
|
---|
280 | }
|
---|
281 |
|
---|
282 | void STREAM::SetInputSrc(int src) { inputsrc = src; }
|
---|
283 | void STREAM::SetInputGain(ULONG gain) { inputgain = gain; }
|
---|
284 | void STREAM::SetVolume(ULONG volume) { this->volume = volume; }
|
---|
285 | void STREAM::SetBalance(ULONG balance) { this->balance = balance; }
|
---|
286 |
|
---|
287 | BOOL STREAM::SetMasterVol(ULONG volume)
|
---|
288 | {
|
---|
289 | if(mastervol != volume) {
|
---|
290 | mastervol = volume;
|
---|
291 | return OSS16_SetMasterVol(this, volume);
|
---|
292 | }
|
---|
293 | return TRUE;
|
---|
294 | }
|
---|
295 | ULONG STREAM::mastervol = MAKE_VOLUME_LR(100, 100);
|
---|
296 |
|
---|
297 | PSTREAM FindActiveStream(ULONG StreamType)
|
---|
298 | {
|
---|
299 | PSTREAM pStream = (PSTREAM) pStreamList->Head();
|
---|
300 |
|
---|
301 | while (pStream)
|
---|
302 | if ((pStream->ulStreamType == StreamType) &&
|
---|
303 | (pStream->ulStreamState == STREAM_STREAMING))
|
---|
304 | return pStream;
|
---|
305 | else
|
---|
306 | pStream = (PSTREAM) pStream->pNext;
|
---|
307 |
|
---|
308 | return NULL;
|
---|
309 | }
|
---|
310 |
|
---|
311 | PSTREAM FindActiveStream(ULONG StreamType, ULONG StreamId)
|
---|
312 | {
|
---|
313 | PSTREAM pStream = (PSTREAM) pStreamList->Head();
|
---|
314 |
|
---|
315 | while (pStream)
|
---|
316 | if ((pStream->ulStreamType == StreamType) &&
|
---|
317 | (pStream->ulStreamState == STREAM_STREAMING) && (pStream->ulStreamId == StreamId))
|
---|
318 | return pStream;
|
---|
319 | else
|
---|
320 | pStream = (PSTREAM) pStream->pNext;
|
---|
321 |
|
---|
322 | return NULL;
|
---|
323 | }
|
---|
324 |
|
---|
325 | PSTREAM FindStream_fromFile(ULONG ulSysFileNum)
|
---|
326 | /* Map a system file handle to a Stream object.
|
---|
327 | * ### FUTURE: Make parm type a real type so we can use overloading,
|
---|
328 | * ### and change name/signature back to "FindStream( fileHandle )".
|
---|
329 | */
|
---|
330 | {
|
---|
331 | PSTREAM pStream = (PSTREAM) pStreamList->Head();
|
---|
332 |
|
---|
333 | while (pStream)
|
---|
334 | if (pStream->ulSysFileNum == ulSysFileNum)
|
---|
335 | return pStream;
|
---|
336 | else
|
---|
337 | pStream = (PSTREAM) pStream->pNext;
|
---|
338 |
|
---|
339 | return NULL;
|
---|
340 | }
|
---|
341 |
|
---|
342 | PSTREAM FindStream(HSTREAM hStream)
|
---|
343 | /* Map a stream handle to a Stream object. */
|
---|
344 | {
|
---|
345 | PSTREAM pStream = (PSTREAM) pStreamList->Head();
|
---|
346 |
|
---|
347 | while (pStream)
|
---|
348 | if (pStream->hstream == hStream)
|
---|
349 | return pStream;
|
---|
350 | else
|
---|
351 | pStream = (PSTREAM) pStream->pNext;
|
---|
352 |
|
---|
353 | return NULL;
|
---|
354 | }
|
---|