-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathrtsdwavestream.cpp
More file actions
874 lines (733 loc) · 26.5 KB
/
rtsdwavestream.cpp
File metadata and controls
874 lines (733 loc) · 26.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
/*
Module Name:
rtsdwavestream.cpp
Abstract:
WaveCyclicStream-Miniport and IDmaChannel implementation. Does nothing HW related.
*/
#include "rtsdaudio.h"
#include "common.h"
#include "rtsdwave.h"
#include "rtsdwavestream.h"
#define DBGMESSAGE "[RTSD-Audio] rtsdwavestream.cpp: "
#define DBGPRINT(x) DbgPrint(DBGMESSAGE x)
/*PVOID myBuffer=NULL;
LONG myBufferSize=0;
LONG myBufferLocked=TRUE;
LONG myBufferWritePos=0;
LONG myBufferReadPos=0;
LONG myBufferReading=FALSE; //Determines wether there is a client that still reads data
//*/
//=============================================================================
CMiniportWaveCyclicStream::~CMiniportWaveCyclicStream(void)
/*
Routine Description:
Destructor for wavecyclicstream
Arguments:
Return Value:
NT status code.
*/
{
PAGED_CODE();
DPF_ENTER(("[CMiniportWaveCyclicStream::~CMiniportWaveCyclicStream]"));
if (NULL != m_pMiniport) {
if (m_fCapture)
m_pMiniport->m_fCaptureAllocated = FALSE;
else
m_pMiniport->m_fRenderAllocated = FALSE;
}
if (m_pTimer) {
KeCancelTimer(m_pTimer);
ExFreePool(m_pTimer);
}
if (m_pDpc)
ExFreePool( m_pDpc );
// Free the DMA buffer
FreeBuffer();
} // ~CMiniportWaveCyclicStream
//=============================================================================
NTSTATUS CMiniportWaveCyclicStream::Init(
IN PCMiniportWaveCyclic Miniport_,
IN ULONG Pin_,
IN BOOLEAN Capture_,
IN PKSDATAFORMAT DataFormat_
)
/*
Routine Description:
Initializes the stream object. Allocate a DMA buffer, timer and DPC
Arguments:
Miniport_ -
Pin_ -
Capture_ -
DataFormat -
DmaChannel_ -
Return Value:
NT status code.
*/
{
PAGED_CODE();
DPF_ENTER(("[CMiniportWaveCyclicStream::Init]"));
ASSERT(Miniport_);
ASSERT(DataFormat_);
m_pMiniport = Miniport_;
m_fCapture = FALSE;
m_fFormat16Bit = FALSE;
m_fFormatStereo = FALSE;
m_ksState = KSSTATE_STOP;
m_ulPin = (ULONG)-1;
m_pDpc = NULL;
m_pTimer = NULL;
m_fDmaActive = FALSE;
m_ulDmaPosition = 0;
m_pvDmaBuffer = NULL;
m_ulDmaBufferSize = 0;
m_ulDmaMovementRate = 0;
m_ullDmaTimeStamp = 0;
NTSTATUS ntStatus = STATUS_SUCCESS;
PWAVEFORMATEX pWfx;
pWfx = GetWaveFormatEx(DataFormat_);
if (!pWfx) {
DPF(D_TERSE, ("Invalid DataFormat param in NewStream"));
ntStatus = STATUS_INVALID_PARAMETER;
}
if (NT_SUCCESS(ntStatus)) {
m_ulPin = Pin_;
m_fCapture = Capture_;
m_fFormatStereo = (pWfx->nChannels == 2);
m_fFormat16Bit = (pWfx->wBitsPerSample == 16);
m_ksState = KSSTATE_STOP;
m_ulDmaPosition = 0;
m_fDmaActive = FALSE;
m_pDpc = NULL;
m_pTimer = NULL;
m_pvDmaBuffer = NULL;
}
// Allocate DMA buffer for this stream.
if (NT_SUCCESS(ntStatus)) {
ntStatus = AllocateBuffer(m_pMiniport->m_MaxDmaBufferSize, NULL);
}
// Set sample frequency. Note that m_SampleRateSync access should
// be syncronized.
if (NT_SUCCESS(ntStatus)) {
ntStatus = KeWaitForSingleObject(
&m_pMiniport->m_SampleRateSync,
Executive,
KernelMode,
FALSE,
NULL
);
if (NT_SUCCESS(ntStatus)) {
m_pMiniport->m_SamplingFrequency = pWfx->nSamplesPerSec;
KeReleaseMutex(&m_pMiniport->m_SampleRateSync, FALSE);
} else {
DPF(D_TERSE, ("[SamplingFrequency Sync failed: %08X]", ntStatus));
}
}
if (NT_SUCCESS(ntStatus)) {
ntStatus = SetFormat(DataFormat_);
}
if (NT_SUCCESS(ntStatus)) {
m_pDpc = (PRKDPC) ExAllocatePoolWithTag(
NonPagedPool,
sizeof(KDPC),
RTSDAUDIO_POOLTAG
);
if (!m_pDpc) {
DPF(D_TERSE, ("[Could not allocate memory for DPC]"));
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
}
if (NT_SUCCESS(ntStatus)) {
m_pTimer = (PKTIMER) ExAllocatePoolWithTag(
NonPagedPool,
sizeof(KTIMER),
RTSDAUDIO_POOLTAG
);
if (!m_pTimer) {
DPF(D_TERSE, ("[Could not allocate memory for Timer]"));
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
}
if (NT_SUCCESS(ntStatus)) {
KeInitializeDpc(m_pDpc, TimerNotify, m_pMiniport);
KeInitializeTimerEx(m_pTimer, NotificationTimer);
}
return ntStatus;
} // Init
//=============================================================================
STDMETHODIMP_(NTSTATUS) CMiniportWaveCyclicStream::NonDelegatingQueryInterface(
IN REFIID Interface,
OUT PVOID * Object
)
/*
Routine Description:
QueryInterface
Arguments:
Interface - GUID
Object - interface pointer to be returned
Return Value:
NT status code.
*/
{
PAGED_CODE();
ASSERT(Object);
if (IsEqualGUIDAligned(Interface, IID_IUnknown)) {
*Object = PVOID(PUNKNOWN(PMINIPORTWAVECYCLICSTREAM(this)));
} else if (IsEqualGUIDAligned(Interface, IID_IMiniportWaveCyclicStream)) {
*Object = PVOID(PMINIPORTWAVECYCLICSTREAM(this));
} else if (IsEqualGUIDAligned(Interface, IID_IDmaChannel)) {
*Object = PVOID(PDMACHANNEL(this));
} else {
*Object = NULL;
}
if (*Object) {
PUNKNOWN(*Object)->AddRef();
return STATUS_SUCCESS;
}
return STATUS_INVALID_PARAMETER;
} // NonDelegatingQueryInterface
#pragma code_seg()
//=============================================================================
STDMETHODIMP CMiniportWaveCyclicStream::GetPosition(
OUT PULONG Position
)
/*
Routine Description:
The GetPosition function gets the current position of the DMA read or write
pointer for the stream. Callers of GetPosition should run at
IRQL <= DISPATCH_LEVEL.
Arguments:
Position - Position of the DMA pointer
Return Value:
NT status code.
*/
{
if (m_fDmaActive) {
ULONGLONG CurrentTime = KeQueryInterruptTime();
ULONG TimeElapsedInMS = ( (ULONG) (CurrentTime - m_ullDmaTimeStamp) ) / 10000;
ULONG ByteDisplacement = (m_ulDmaMovementRate * TimeElapsedInMS) / 1000;
m_ulDmaPosition = (m_ulDmaPosition + ByteDisplacement) % m_ulDmaBufferSize;
*Position = m_ulDmaPosition;
m_ullDmaTimeStamp = CurrentTime;
} else {
*Position = m_ulDmaPosition;
}
return STATUS_SUCCESS;
} // GetPosition
//=============================================================================
STDMETHODIMP CMiniportWaveCyclicStream::NormalizePhysicalPosition(
IN OUT PLONGLONG PhysicalPosition
)
/*
Routine Description:
Given a physical position based on the actual number of bytes transferred,
NormalizePhysicalPosition converts the position to a time-based value of
100 nanosecond units. Callers of NormalizePhysicalPosition can run at any IRQL.
Arguments:
PhysicalPosition - On entry this variable contains the value to convert.
On return it contains the converted value
Return Value:
NT status code.
*/
{
*PhysicalPosition = ( _100NS_UNITS_PER_SECOND / ( 1 << ( m_fFormatStereo + m_fFormat16Bit ) ) * *PhysicalPosition ) / m_pMiniport->m_SamplingFrequency;
return STATUS_SUCCESS;
} // NormalizePhysicalPosition
#pragma code_seg("PAGE")
//=============================================================================
STDMETHODIMP_(NTSTATUS) CMiniportWaveCyclicStream::SetFormat(
IN PKSDATAFORMAT Format
)
/*
Routine Description:
The SetFormat function changes the format associated with a stream.
Callers of SetFormat should run at IRQL PASSIVE_LEVEL
Arguments:
Format - Pointer to a KSDATAFORMAT structure which indicates the new format
of the stream.
Return Value:
NT status code.
*/
{
PAGED_CODE();
ASSERT(Format);
DPF_ENTER(("[CMiniportWaveCyclicStream::SetFormat]"));
NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
PWAVEFORMATEX pWfx;
if (m_ksState != KSSTATE_RUN) {
//First validate the format
NTSTATUS ntValidFormat;
ntValidFormat = m_pMiniport->ValidateFormat(Format);
if (NT_SUCCESS(ntValidFormat)) {
pWfx = GetWaveFormatEx(Format);
if (pWfx) {
ntStatus = KeWaitForSingleObject(
&m_pMiniport->m_SampleRateSync,
Executive,
KernelMode,
FALSE,
NULL
);
if (NT_SUCCESS(ntStatus)) {
m_fFormatStereo = (pWfx->nChannels == 2);
m_fFormat16Bit = (pWfx->wBitsPerSample == 16);
m_pMiniport->m_SamplingFrequency = pWfx->nSamplesPerSec;
m_ulDmaMovementRate = pWfx->nAvgBytesPerSec;
DPF(D_TERSE, ("New Format: %d", pWfx->nSamplesPerSec));
}
KeReleaseMutex(&m_pMiniport->m_SampleRateSync, FALSE);
}
}
}
return ntStatus;
} // SetFormat
//=============================================================================
STDMETHODIMP_(ULONG) CMiniportWaveCyclicStream::SetNotificationFreq(
IN ULONG Interval,
OUT PULONG FramingSize
)
/*
Routine Description:
The SetNotificationFrequency function sets the frequency at which
notification interrupts are generated. Callers of SetNotificationFrequency
should run at IRQL PASSIVE_LEVEL.
Arguments:
Interval - Value indicating the interval between interrupts,
expressed in milliseconds
FramingSize - Pointer to a ULONG value where the number of bytes equivalent
to Interval milliseconds is returned
Return Value:
NT status code.
*/
{
PAGED_CODE();
ASSERT(FramingSize);
DPF_ENTER(("[CMiniportWaveCyclicStream::SetNotificationFreq]"));
m_pMiniport->m_NotificationInterval = Interval;
*FramingSize = ( 1 << ( m_fFormatStereo + m_fFormat16Bit ) ) * m_pMiniport->m_SamplingFrequency * Interval / 1000;
return m_pMiniport->m_NotificationInterval;
} // SetNotificationFreq
//=============================================================================
STDMETHODIMP CMiniportWaveCyclicStream::SetState(
IN KSSTATE NewState
)
/*
Routine Description:
The SetState function sets the new state of playback or recording for the
stream. SetState should run at IRQL PASSIVE_LEVEL
Arguments:
NewState - KSSTATE indicating the new state for the stream.
Return Value:
NT status code.
*/
{
PAGED_CODE();
DPF_ENTER(("[CMiniportWaveCyclicStream::SetState]"));
NTSTATUS ntStatus = STATUS_SUCCESS;
// The acquire state is not distinguishable from the stop state for our purposes.
if (NewState == KSSTATE_ACQUIRE) {
NewState = KSSTATE_STOP;
}
if (m_ksState != NewState) {
switch(NewState) {
case KSSTATE_PAUSE:
DPF(D_TERSE, ("KSSTATE_PAUSE"));
m_fDmaActive = FALSE;
break;
case KSSTATE_RUN:
DPF(D_TERSE, ("KSSTATE_RUN"));
LARGE_INTEGER delay;
// Set the timer for DPC.
m_ullDmaTimeStamp = KeQueryInterruptTime();
m_fDmaActive = TRUE;
delay.HighPart = 0;
delay.LowPart = m_pMiniport->m_NotificationInterval;
KeSetTimerEx(m_pTimer, delay, m_pMiniport->m_NotificationInterval, m_pDpc);
break;
case KSSTATE_STOP:
DPF(D_TERSE, ("KSSTATE_STOP"));
m_fDmaActive = FALSE;
m_ulDmaPosition = 0;
KeCancelTimer( m_pTimer );
break;
}
m_ksState = NewState;
}
return ntStatus;
} // SetState
#pragma code_seg()
//=============================================================================
STDMETHODIMP_(void) CMiniportWaveCyclicStream::Silence(
IN PVOID Buffer,
IN ULONG ByteCount
)
/*
Routine Description:
The Silence function is used to copy silence samplings to a certain location.
Callers of Silence can run at any IRQL
Arguments:
Buffer - Pointer to the buffer where the silence samplings should
be deposited.
ByteCount - Size of buffer indicating number of bytes to be deposited.
Return Value:
NT status code.
*/
{
RtlFillMemory(Buffer, ByteCount, m_fFormat16Bit ? 0 : 0x80);
} // Silence
#pragma code_seg("PAGE")
//=============================================================================
STDMETHODIMP_(NTSTATUS) CMiniportWaveCyclicStream::AllocateBuffer(
IN ULONG BufferSize,
IN PPHYSICAL_ADDRESS PhysicalAddressConstraint OPTIONAL
)
/*
Routine Description:
The AllocateBuffer function allocates a buffer associated with the DMA object.
The buffer is nonPaged.
Callers of AllocateBuffer should run at a passive IRQL.
Arguments:
BufferSize - Size in bytes of the buffer to be allocated.
PhysicalAddressConstraint - Optional constraint to place on the physical
address of the buffer. If supplied, only the bits
that are set in the constraint address may vary
from the beginning to the end of the buffer.
For example, if the desired buffer should not
cross a 64k boundary, the physical address
constraint 0x000000000000ffff should be specified
Return Value:
NT status code.
*/
{
DBGPRINT("[CMiniportWaveCyclicStream::AllocateBuffer]");
// Adjust this cap as needed...
ASSERT (BufferSize <= DMA_BUFFER_SIZE);
NTSTATUS ntStatus = STATUS_SUCCESS;
m_pvDmaBuffer = (PVOID) ExAllocatePoolWithTag(NonPagedPool, BufferSize, RTSDAUDIO_POOLTAG);
if (!m_pvDmaBuffer) {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
} else {
m_ulDmaBufferSize = BufferSize;
}
return ntStatus;
} // AllocateBuffer
#pragma code_seg()
//=============================================================================
STDMETHODIMP_(ULONG) CMiniportWaveCyclicStream::AllocatedBufferSize(void)
/*
Routine Description:
AllocatedBufferSize returns the size of the allocated buffer.
Callers of AllocatedBufferSize can run at any IRQL.
Arguments:
Return Value:
ULONG
*/
{
DBGPRINT("[CMiniportWaveCyclicStream::AllocatedBufferSize]");
return m_ulDmaBufferSize;
} // AllocatedBufferSize
//=============================================================================
STDMETHODIMP_(ULONG) CMiniportWaveCyclicStream::BufferSize(void)
/*
Routine Description:
BufferSize returns the size set by SetBufferSize or the allocated buffer size
if the buffer size has not been set. The DMA object does not actually use
this value internally. This value is maintained by the object to allow its
various clients to communicate the intended size of the buffer. This call
is often used to obtain the map size parameter to the Start member
function. Callers of BufferSize can run at any IRQL
Arguments:
Return Value:
ULONG
*/
{
return m_ulDmaBufferSize;
} // BufferSize
//=============================================================================
STDMETHODIMP_(void) CMiniportWaveCyclicStream::CopyFrom(
IN PVOID Destination,
IN PVOID Source,
IN ULONG ByteCount
)
/*
Routine Description:
The CopyFrom function copies sample data from the DMA buffer.
Callers of CopyFrom can run at any IRQL
Arguments:
Destination - Points to the destination buffer.
Source - Points to the source buffer.
ByteCount - Points to the source buffer.
Return Value:
void
*/
{
ULONG i=0;
ULONG FrameCount = ByteCount/2; //we guess 16-Bit sample rate
//DbgPrint(DBGMESSAGE "CopyFrom - ReadPos=%d",myBufferReadPos); DbgPrint(DBGMESSAGE "CopyFrom - WritePos=%d",myBufferWritePos);
if (!m_pMiniport->myBufferLocked) {
//DbgPrint(DBGMESSAGE "CopyFrom - ByteCount=%d", ByteCount);
InterlockedExchange(&m_pMiniport->myBufferLocked, TRUE);
ULONG umyBufferSize=(ULONG)m_pMiniport->myBufferSize;
ULONG availableDataCount = (umyBufferSize + m_pMiniport->myBufferWritePos) - m_pMiniport->myBufferReadPos;
if (availableDataCount >= umyBufferSize)
availableDataCount -= umyBufferSize;
if (availableDataCount < FrameCount) {
//if the caller wants to read more data than the buffer size is,
//we fill the rest with silence
//we write the silence at the beginning,
//because in the most cases we need to do this the caller begins to read - so we care
//for a continually stream of sound data
ULONG silenceCount = FrameCount - availableDataCount;
//DbgPrint(DBGMESSAGE "CopyFrom - need more data! NeedCount=%d", silenceCount);
for (i=0; i<=silenceCount ; i++) {
((PWORD)Destination)[i]=0;
}
}
//i=0;
while ((i < FrameCount) && //we have more data in the buffer than the caller would like to get
((m_pMiniport->myBufferWritePos != m_pMiniport->myBufferReadPos+1) && !((m_pMiniport->myBufferWritePos==0) && (m_pMiniport->myBufferReadPos==m_pMiniport->myBufferSize))) ) {
((PWORD)Destination)[i]=((PWORD)m_pMiniport->myBuffer)[m_pMiniport->myBufferReadPos];
i++;
m_pMiniport->myBufferReadPos++;
if (m_pMiniport->myBufferReadPos >= m_pMiniport->myBufferSize) //Loop the buffer
m_pMiniport->myBufferReadPos=0;
}
InterlockedExchange(&m_pMiniport->myBufferReading, TRUE); //now the caller reads from the buffer - so we can notify the CopyTo function
//DbgPrint(DBGMESSAGE "CopyFrom TRUE ByteCount=%d", ByteCount);
InterlockedExchange(&m_pMiniport->myBufferLocked, FALSE);
} else {
//in this case we can't obtain the data from buffer because it is locked
//the best we can do (to satisfy the caller) is to fill the whole buffer with silence
for (i=0; i < FrameCount ; i++) {
((PWORD)Destination)[i]=0;
}
DBGPRINT("CopyFrom FALSE");
}
} // CopyFrom
//=============================================================================
STDMETHODIMP_(void) CMiniportWaveCyclicStream::CopyTo(
IN PVOID Destination,
IN PVOID Source,
IN ULONG ByteCount
)
/*
Routine Description:
The CopyTo function copies sample data to the DMA buffer.
Callers of CopyTo can run at any IRQL.
Arguments:
Destination - Points to the destination buffer.
Source - Points to the source buffer
ByteCount - Number of bytes to be copied
Return Value:
void
*/
{
ULONG i=0;
ULONG FrameCount = ByteCount/2; //we guess 16-Bit sample rate
if (m_pMiniport->myBuffer==NULL) {
ULONG bufSize=64*1024; //size in bytes
DBGPRINT("Try to allocate buffer");
m_pMiniport->myBuffer = (PVOID) ExAllocatePoolWithTag(NonPagedPool, bufSize, RTSDAUDIO_POOLTAG);
if (!m_pMiniport->myBuffer) {
DBGPRINT("FAILED to allocate buffer");
} else {
DBGPRINT("Successfully allocated buffer");
m_pMiniport->myBufferSize = bufSize/2; //myBufferSize in frames
InterlockedExchange(&m_pMiniport->myBufferLocked, FALSE);
}
}
if (!m_pMiniport->myBufferLocked) {
//DbgPrint(DBGMESSAGE "Fill Buffer ByteCount=%d", ByteCount);
InterlockedExchange(&m_pMiniport->myBufferLocked, TRUE);
i=0;
while (i < FrameCount) {//while data is available
//test wether we arrived at the read-pos
//if (! ((myBufferWritePos+1 != myBufferReadPos) && !((myBufferReadPos==0) && (myBufferWritePos==myBufferSize)))) {
if ((m_pMiniport->myBufferWritePos+1==m_pMiniport->myBufferReadPos) || (m_pMiniport->myBufferReadPos==0 && m_pMiniport->myBufferWritePos==m_pMiniport->myBufferSize)){
//DbgPrint(DBGMESSAGE "CopyTo - there is no space for new data! NeedCount=%d", FrameCount-i);
if (m_pMiniport->myBufferReadPos==m_pMiniport->myBufferSize)
m_pMiniport->myBufferReadPos=0;
else
m_pMiniport->myBufferReadPos++;
//break; //we have to break - because there is no space for the rest data
}
((PWORD)m_pMiniport->myBuffer)[m_pMiniport->myBufferWritePos]=((PWORD)Source)[i];
i++;
m_pMiniport->myBufferWritePos++;
if (m_pMiniport->myBufferWritePos >= m_pMiniport->myBufferSize) //Loop the buffer
m_pMiniport->myBufferWritePos=0;
}
//DbgPrint(DBGMESSAGE "CopyTo - ReadPos=%d",myBufferReadPos); DbgPrint(DBGMESSAGE "CopyTo - WritePos=%d",myBufferWritePos);
InterlockedExchange(&m_pMiniport->myBufferLocked, FALSE);
//DbgPrint(DBGMESSAGE "(2) CopyTo - ReadPos=%d",myBufferReadPos); DbgPrint(DBGMESSAGE "(2) CopyTo - WritePos=%d",myBufferWritePos);
//DbgPrint(DBGMESSAGE "(2) CopyTo - Locked=%d",myBufferLocked);
}
} // CopyTo
//=============================================================================
#pragma code_seg("PAGE")
STDMETHODIMP_(void) CMiniportWaveCyclicStream::FreeBuffer(void)
/*
Routine Description:
The FreeBuffer function frees the buffer allocated by AllocateBuffer. Because
the buffer is automatically freed when the DMA object is deleted, this
function is not normally used. Callers of FreeBuffer should run at
IRQL PASSIVE_LEVEL.
Arguments:
Return Value:
void
*/
{
DBGPRINT("[CMiniportWaveCyclicStream::FreeBuffer]");
if ( m_pvDmaBuffer ) {
ExFreePool( m_pvDmaBuffer );
m_ulDmaBufferSize = 0;
m_pvDmaBuffer = NULL;
}
if (m_pMiniport->myBuffer) {
if (!m_pMiniport->myBufferLocked)
{
InterlockedExchange(&m_pMiniport->myBufferLocked, TRUE); //first lock the buffer, so nobody would try to read from myBuffer
ExFreePool(m_pMiniport->myBuffer);
m_pMiniport->myBufferSize = 0;
m_pMiniport->myBuffer = NULL;
}
}
} // FreeBuffer
#pragma code_seg()
//=============================================================================
STDMETHODIMP_(PADAPTER_OBJECT) CMiniportWaveCyclicStream::GetAdapterObject(void)
/*
Routine Description:
The GetAdapterObject function returns the DMA object's internal adapter
object. Callers of GetAdapterObject can run at any IRQL.
Arguments:
Return Value:
PADAPTER_OBJECT - The return value is the object's internal adapter object.
*/
{
DBGPRINT("[CMiniportWaveCyclicStream::GetAdapterObject]");
// MSVAD does not have need a physical DMA channel. Therefore it
// does not have physical DMA structure.
return NULL;
} // GetAdapterObject
//=============================================================================
STDMETHODIMP_(ULONG) CMiniportWaveCyclicStream::MaximumBufferSize(void)
/*
Routine Description:
Arguments:
Return Value:
NT status code.
*/
{
DBGPRINT("[CMiniportWaveCyclicStream::MaximumBufferSize]");
return m_pMiniport->m_MaxDmaBufferSize;
} // MaximumBufferSize
//=============================================================================
STDMETHODIMP_(PHYSICAL_ADDRESS) CMiniportWaveCyclicStream::PhysicalAddress(void)
/*
Routine Description:
MaximumBufferSize returns the size in bytes of the largest buffer this DMA
object is configured to support. Callers of MaximumBufferSize can run
at any IRQL
Arguments:
Return Value:
PHYSICAL_ADDRESS - The return value is the size in bytes of the largest
buffer this DMA object is configured to support.
*/
{
DBGPRINT("[CMiniportWaveCyclicStream::PhysicalAddress]");
PHYSICAL_ADDRESS pAddress;
pAddress.QuadPart = (LONGLONG) m_pvDmaBuffer;
return pAddress;
} // PhysicalAddress
//=============================================================================
STDMETHODIMP_(void) CMiniportWaveCyclicStream::SetBufferSize(
IN ULONG BufferSize
)
/*
Routine Description:
The SetBufferSize function sets the current buffer size. This value is set to
the allocated buffer size when AllocateBuffer is called. The DMA object does
not actually use this value internally. This value is maintained by the object
to allow its various clients to communicate the intended size of the buffer.
Callers of SetBufferSize can run at any IRQL.
Arguments:
BufferSize - Current size in bytes.
Return Value:
void
*/
{
DBGPRINT("[CMiniportWaveCyclicStream::SetBufferSize]");
if ( BufferSize <= m_ulDmaBufferSize ) {
m_ulDmaBufferSize = BufferSize;
} else {
DPF(D_ERROR, ("Tried to enlarge dma buffer size"));
}
} // SetBufferSize
//=============================================================================
STDMETHODIMP_(PVOID) CMiniportWaveCyclicStream::SystemAddress(void)
/*
Routine Description:
The SystemAddress function returns the virtual system address of the
allocated buffer. Callers of SystemAddress can run at any IRQL.
Arguments:
Return Value:
PVOID - The return value is the virtual system address of the
allocated buffer.
*/
{
return m_pvDmaBuffer;
} // SystemAddress
//=============================================================================
STDMETHODIMP_(ULONG) CMiniportWaveCyclicStream::TransferCount(void)
/*
Routine Description:
The TransferCount function returns the size in bytes of the buffer currently
being transferred by a slave DMA object. Callers of TransferCount can run
at any IRQL.
Arguments:
Return Value:
ULONG - The return value is the size in bytes of the buffer currently
being transferred.
*/
{
DBGPRINT("[CMiniportWaveCyclicStream::TransferCount]");
return m_ulDmaBufferSize;
}
//=============================================================================
/*long CMiniportWaveCyclicStream::zoh_process (PWORD source, PWORD destination, long input_frames, long output_frames, int channels)
{
KFLOATING_SAVE saveData;
NTSTATUS status;
status = KeSaveFloatingPointState(&saveData);
if(NT_SUCCESS(status)) {
long in_count, out_count, in_used, out_gen;
double src_ratio, input_index;
int ch;
in_count = input_frames * channels;
out_count = output_frames * channels;
in_used = out_gen = 0;
src_ratio = m_pMiniport->m_SamplingFrequency / 44100;
input_index = 0; // TODO: Unbekannt
in_used += channels * (long)(floor(input_index));
input_index -= floor(input_index);
// Main processing loop.
while (out_gen < out_count && in_used + channels * input_index <= in_count) {
for (ch = 0 ; ch < channels ; ch++) {
destination[out_gen] = source[in_used - channels + ch];
out_gen ++ ;
} ;
// Figure out the next index.
input_index += 1.0 / src_ratio ;
in_used += channels * (long)(floor(input_index)) ;
input_index -= floor(input_index) ;
} ;
if (in_used > in_count) {
input_index += in_used - in_count ;
in_used = in_count ;
} ;
KeRestoreFloatingPointState(&saveData);
return out_gen;
} else {
return 0;
}
}*/