2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: drivers/wdm/audio/backpln/portcls/pin_wavert.cpp
5 * PURPOSE: WaveRT IRP Audio Pin
6 * PROGRAMMER: Johannes Anderwald
11 class CPortPinWaveRT
: public IPortPinWaveRT
14 STDMETHODIMP
QueryInterface( REFIID InterfaceId
, PVOID
* Interface
);
16 STDMETHODIMP_(ULONG
) AddRef()
18 InterlockedIncrement(&m_Ref
);
21 STDMETHODIMP_(ULONG
) Release()
23 InterlockedDecrement(&m_Ref
);
33 CPortPinWaveRT(IUnknown
*OuterUnknown
){}
34 virtual ~CPortPinWaveRT(){}
39 IPortFilterWaveRT
* m_Filter
;
40 KSPIN_DESCRIPTOR
* m_KsPinDescriptor
;
41 PMINIPORTWAVERT m_Miniport
;
42 PMINIPORTWAVERTSTREAM m_Stream
;
43 PPORTWAVERTSTREAM m_PortStream
;
45 PKSDATAFORMAT m_Format
;
46 KSPIN_CONNECT
* m_ConnectDetails
;
49 ULONG m_CommonBufferSize
;
50 ULONG m_CommonBufferOffset
;
52 IIrpQueue
* m_IrpQueue
;
58 ULONG m_PostCompleted
;
62 MEMORY_CACHING_TYPE m_CacheType
;
67 NTSTATUS NTAPI
HandleKsProperty(IN PIRP Irp
);
68 NTSTATUS NTAPI
HandleKsStream(IN PIRP Irp
);
69 VOID NTAPI
SetStreamState(IN KSSTATE State
);
70 friend VOID NTAPI
SetStreamWorkerRoutine(IN PDEVICE_OBJECT DeviceObject
, IN PVOID Context
);
71 friend VOID NTAPI
CloseStreamRoutine(IN PDEVICE_OBJECT DeviceObject
, IN PVOID Context
);
79 PIO_WORKITEM WorkItem
;
81 }SETSTREAM_CONTEXT
, *PSETSTREAM_CONTEXT
;
84 //==================================================================================================================================
87 CPortPinWaveRT::QueryInterface(
91 DPRINT("IServiceSink_fnQueryInterface entered\n");
93 if (IsEqualGUIDAligned(refiid
, IID_IIrpTarget
) ||
94 IsEqualGUIDAligned(refiid
, IID_IUnknown
))
96 *Output
= PVOID(PUNKNOWN((IIrpTarget
*)this));
97 PUNKNOWN(*Output
)->AddRef();
98 return STATUS_SUCCESS
;
100 return STATUS_UNSUCCESSFUL
;
105 SetStreamWorkerRoutine(
106 IN PDEVICE_OBJECT DeviceObject
,
109 CPortPinWaveRT
* This
;
110 PSETSTREAM_CONTEXT Ctx
= (PSETSTREAM_CONTEXT
)Context
;
116 IoFreeWorkItem(Ctx
->WorkItem
);
117 FreeItem(Ctx
, TAG_PORTCLASS
);
119 // Has the audio stream resumed?
120 if (This
->m_IrpQueue
->NumMappings() && State
== KSSTATE_STOP
)
124 if (NT_SUCCESS(This
->m_Stream
->SetState(State
)))
126 // Set internal state to stop
127 This
->m_State
= State
;
129 if (This
->m_State
== KSSTATE_STOP
)
131 // reset start stream
132 This
->m_IrpQueue
->CancelBuffers(); //FIX function name
133 DPRINT1("Stopping PreCompleted %u PostCompleted %u\n", This
->m_PreCompleted
, This
->m_PostCompleted
);
136 if (This
->m_State
== KSSTATE_RUN
)
138 // start the notification timer
145 CPortPinWaveRT::SetStreamState(
148 PDEVICE_OBJECT DeviceObject
;
149 PIO_WORKITEM WorkItem
;
150 PSETSTREAM_CONTEXT Context
;
152 PC_ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL
);
154 // Has the audio stream resumed?
155 if (m_IrpQueue
->NumMappings() && State
== KSSTATE_STOP
)
158 // Has the audio state already been set?
159 if (m_State
== State
)
163 DeviceObject
= GetDeviceObjectFromPortWaveRT(m_Port
);
165 // allocate set state context
166 Context
= (PSETSTREAM_CONTEXT
)AllocateItem(NonPagedPool
, sizeof(SETSTREAM_CONTEXT
), TAG_PORTCLASS
);
171 // allocate work item
172 WorkItem
= IoAllocateWorkItem(DeviceObject
);
181 Context
->WorkItem
= WorkItem
;
182 Context
->State
= State
;
184 // queue the work item
185 IoQueueWorkItem(WorkItem
, SetStreamWorkerRoutine
, DelayedWorkQueue
, (PVOID
)Context
);
188 //==================================================================================================================================
192 CPortPinWaveRT::NewIrpTarget(
193 OUT
struct IIrpTarget
**OutTarget
,
196 IN POOL_TYPE PoolType
,
197 IN PDEVICE_OBJECT DeviceObject
,
199 IN KSOBJECT_CREATE
*CreateObject
)
202 return STATUS_UNSUCCESSFUL
;
207 CPortPinWaveRT::HandleKsProperty(
210 PKSPROPERTY Property
;
212 UNICODE_STRING GuidString
;
213 PIO_STACK_LOCATION IoStack
;
215 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
217 DPRINT("IPortPinWave_HandleKsProperty entered\n");
219 if (IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(KSPROPERTY
))
221 Irp
->IoStatus
.Information
= 0;
222 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
223 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
224 return STATUS_INVALID_PARAMETER
;
227 Property
= (PKSPROPERTY
)IoStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
229 if (IsEqualGUIDAligned(Property
->Set
, KSPROPSETID_Connection
))
231 if (Property
->Id
== KSPROPERTY_CONNECTION_STATE
)
233 PKSSTATE State
= (PKSSTATE
)Irp
->UserBuffer
;
235 if (IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(KSSTATE
))
237 Irp
->IoStatus
.Information
= sizeof(KSSTATE
);
238 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
239 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
240 return STATUS_BUFFER_TOO_SMALL
;
243 if (Property
->Flags
& KSPROPERTY_TYPE_SET
)
245 Status
= STATUS_UNSUCCESSFUL
;
246 Irp
->IoStatus
.Information
= 0;
250 Status
= m_Stream
->SetState(*State
);
252 DPRINT1("Setting state %u %x\n", *State
, Status
);
253 if (NT_SUCCESS(Status
))
258 Irp
->IoStatus
.Status
= Status
;
259 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
262 else if (Property
->Flags
& KSPROPERTY_TYPE_GET
)
265 Irp
->IoStatus
.Information
= sizeof(KSSTATE
);
266 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
267 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
268 return STATUS_SUCCESS
;
271 else if (Property
->Id
== KSPROPERTY_CONNECTION_DATAFORMAT
)
273 PKSDATAFORMAT DataFormat
= (PKSDATAFORMAT
)Irp
->UserBuffer
;
274 if (Property
->Flags
& KSPROPERTY_TYPE_SET
)
276 PKSDATAFORMAT NewDataFormat
;
277 if (!RtlCompareMemory(DataFormat
, m_Format
, DataFormat
->FormatSize
))
279 Irp
->IoStatus
.Information
= DataFormat
->FormatSize
;
280 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
281 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
282 return STATUS_SUCCESS
;
285 NewDataFormat
= (PKSDATAFORMAT
)AllocateItem(NonPagedPool
, DataFormat
->FormatSize
, TAG_PORTCLASS
);
288 Irp
->IoStatus
.Information
= 0;
289 Irp
->IoStatus
.Status
= STATUS_NO_MEMORY
;
290 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
291 return STATUS_NO_MEMORY
;
293 RtlMoveMemory(NewDataFormat
, DataFormat
, DataFormat
->FormatSize
);
298 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL
);
299 ASSERT(NewDataFormat
->FormatSize
== sizeof(KSDATAFORMAT_WAVEFORMATEX
));
300 ASSERT(IsEqualGUIDAligned(&((PKSDATAFORMAT_WAVEFORMATEX
)NewDataFormat
)->DataFormat
.MajorFormat
, &KSDATAFORMAT_TYPE_AUDIO
));
301 ASSERT(IsEqualGUIDAligned(&((PKSDATAFORMAT_WAVEFORMATEX
)NewDataFormat
)->DataFormat
.SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
));
302 ASSERT(IsEqualGUIDAligned(&((PKSDATAFORMAT_WAVEFORMATEX
)NewDataFormat
)->DataFormat
.Specifier
, &KSDATAFORMAT_SPECIFIER_WAVEFORMATEX
));
304 ASSERT(m_State
== KSSTATE_STOP
);
306 DPRINT1("NewDataFormat: Channels %u Bits %u Samples %u\n", ((PKSDATAFORMAT_WAVEFORMATEX
)NewDataFormat
)->WaveFormatEx
.nChannels
,
307 ((PKSDATAFORMAT_WAVEFORMATEX
)NewDataFormat
)->WaveFormatEx
.wBitsPerSample
,
308 ((PKSDATAFORMAT_WAVEFORMATEX
)NewDataFormat
)->WaveFormatEx
.nSamplesPerSec
);
310 Status
= m_Stream
->SetFormat(NewDataFormat
);
311 if (NT_SUCCESS(Status
))
314 ExFreePoolWithTag(m_Format
, TAG_PORTCLASS
);
316 m_IrpQueue
->UpdateFormat((PKSDATAFORMAT
)NewDataFormat
);
317 m_Format
= NewDataFormat
;
318 Irp
->IoStatus
.Information
= DataFormat
->FormatSize
;
319 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
320 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
321 return STATUS_SUCCESS
;
324 DPRINT1("Failed to set format\n");
325 Irp
->IoStatus
.Information
= 0;
326 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
327 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
328 return STATUS_UNSUCCESSFUL
;
330 else if (Property
->Flags
& KSPROPERTY_TYPE_GET
)
334 DPRINT1("No format\n");
335 Irp
->IoStatus
.Information
= 0;
336 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
337 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
338 return STATUS_UNSUCCESSFUL
;
340 if (m_Format
->FormatSize
> IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
)
342 Irp
->IoStatus
.Information
= m_Format
->FormatSize
;
343 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
344 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
345 return STATUS_BUFFER_TOO_SMALL
;
348 RtlMoveMemory(DataFormat
, m_Format
, m_Format
->FormatSize
);
349 Irp
->IoStatus
.Information
= DataFormat
->FormatSize
;
350 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
351 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
352 return STATUS_SUCCESS
;
357 RtlStringFromGUID(Property
->Set
, &GuidString
);
358 DPRINT1("Unhandeled property Set |%S| Id %u Flags %x\n", GuidString
.Buffer
, Property
->Id
, Property
->Flags
);
359 RtlFreeUnicodeString(&GuidString
);
361 Irp
->IoStatus
.Status
= STATUS_NOT_IMPLEMENTED
;
362 Irp
->IoStatus
.Information
= 0;
363 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
364 return STATUS_NOT_IMPLEMENTED
;
369 CPortPinWaveRT::HandleKsStream(
372 DPRINT("IPortPinWaveRT_HandleKsStream entered State %u Stream %p\n", m_State
, m_Stream
);
374 return STATUS_PENDING
;
379 CPortPinWaveRT::DeviceIoControl(
380 IN PDEVICE_OBJECT DeviceObject
,
383 PIO_STACK_LOCATION IoStack
;
385 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
388 if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_KS_PROPERTY
)
390 return HandleKsProperty(Irp
);
392 else if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_KS_ENABLE_EVENT
)
395 /// handle enable event
397 else if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_KS_DISABLE_EVENT
)
400 /// handle disable event
402 else if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_KS_RESET_STATE
)
405 /// handle reset state
407 else if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_KS_WRITE_STREAM
|| IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_KS_READ_STREAM
)
409 return HandleKsStream(Irp
);
413 return KsDefaultDeviceIoCompletion(DeviceObject
, Irp
);
419 Irp
->IoStatus
.Information
= 0;
420 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
421 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
423 return STATUS_UNSUCCESSFUL
;
428 CPortPinWaveRT::Read(
429 IN PDEVICE_OBJECT DeviceObject
,
432 return KsDispatchInvalidDeviceRequest(DeviceObject
, Irp
);
437 CPortPinWaveRT::Write(
438 IN PDEVICE_OBJECT DeviceObject
,
441 return KsDispatchInvalidDeviceRequest(DeviceObject
, Irp
);
446 CPortPinWaveRT::Flush(
447 IN PDEVICE_OBJECT DeviceObject
,
450 return KsDispatchInvalidDeviceRequest(DeviceObject
, Irp
);
456 IN PDEVICE_OBJECT DeviceObject
,
459 PMINIPORTWAVERTSTREAM Stream
;
461 ISubdevice
*ISubDevice
;
462 PSUBDEVICE_DESCRIPTOR Descriptor
;
463 CPortPinWaveRT
* This
;
464 PCLOSESTREAM_CONTEXT Ctx
= (PCLOSESTREAM_CONTEXT
)Context
;
466 This
= (CPortPinWaveRT
*)Ctx
->Pin
;
470 if (This
->m_State
!= KSSTATE_STOP
)
472 This
->m_Stream
->SetState(KSSTATE_STOP
);
473 KeStallExecutionProcessor(10);
477 Status
= This
->m_Port
->QueryInterface(IID_ISubdevice
, (PVOID
*)&ISubDevice
);
478 if (NT_SUCCESS(Status
))
480 Status
= ISubDevice
->GetDescriptor(&Descriptor
);
481 if (NT_SUCCESS(Status
))
483 Descriptor
->Factory
.Instances
[This
->m_ConnectDetails
->PinId
].CurrentPinInstanceCount
--;
485 ISubDevice
->Release();
490 ExFreePool(This
->m_Format
);
491 This
->m_Format
= NULL
;
494 if (This
->m_IrpQueue
)
496 This
->m_IrpQueue
->Release();
500 Ctx
->Irp
->IoStatus
.Information
= 0;
501 Ctx
->Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
502 IoCompleteRequest(Ctx
->Irp
, IO_NO_INCREMENT
);
504 // free the work item
505 IoFreeWorkItem(Ctx
->WorkItem
);
507 // free work item ctx
508 FreeItem(Ctx
, TAG_PORTCLASS
);
512 Stream
= This
->m_Stream
;
513 This
->m_Stream
= NULL
;
514 DPRINT1("Closing stream at Irql %u\n", KeGetCurrentIrql());
521 CPortPinWaveRT::Close(
522 IN PDEVICE_OBJECT DeviceObject
,
525 PCLOSESTREAM_CONTEXT Ctx
;
529 Ctx
= (PCLOSESTREAM_CONTEXT
)AllocateItem(NonPagedPool
, sizeof(CLOSESTREAM_CONTEXT
), TAG_PORTCLASS
);
532 DPRINT1("Failed to allocate stream context\n");
536 Ctx
->WorkItem
= IoAllocateWorkItem(DeviceObject
);
539 DPRINT1("Failed to allocate work item\n");
546 IoMarkIrpPending(Irp
);
547 Irp
->IoStatus
.Information
= 0;
548 Irp
->IoStatus
.Status
= STATUS_PENDING
;
551 IoQueueWorkItem(Ctx
->WorkItem
, CloseStreamRoutine
, DelayedWorkQueue
, (PVOID
)Ctx
);
553 return STATUS_PENDING
;
556 Irp
->IoStatus
.Information
= 0;
557 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
558 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
560 return STATUS_SUCCESS
;
565 FreeItem(Ctx
, TAG_PORTCLASS
);
567 Irp
->IoStatus
.Information
= 0;
568 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
569 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
570 return STATUS_UNSUCCESSFUL
;
576 CPortPinWaveRT::QuerySecurity(
577 IN PDEVICE_OBJECT DeviceObject
,
580 return KsDispatchInvalidDeviceRequest(DeviceObject
, Irp
);
585 CPortPinWaveRT::SetSecurity(
586 IN PDEVICE_OBJECT DeviceObject
,
589 return KsDispatchInvalidDeviceRequest(DeviceObject
, Irp
);
594 CPortPinWaveRT::FastDeviceIoControl(
595 IN PFILE_OBJECT FileObject
,
597 IN PVOID InputBuffer
,
598 IN ULONG InputBufferLength
,
599 OUT PVOID OutputBuffer
,
600 IN ULONG OutputBufferLength
,
601 IN ULONG IoControlCode
,
602 OUT PIO_STATUS_BLOCK StatusBlock
,
603 IN PDEVICE_OBJECT DeviceObject
)
610 CPortPinWaveRT::FastRead(
611 IN PFILE_OBJECT FileObject
,
612 IN PLARGE_INTEGER FileOffset
,
617 OUT PIO_STATUS_BLOCK StatusBlock
,
618 IN PDEVICE_OBJECT DeviceObject
)
625 CPortPinWaveRT::FastWrite(
626 IN PFILE_OBJECT FileObject
,
627 IN PLARGE_INTEGER FileOffset
,
632 OUT PIO_STATUS_BLOCK StatusBlock
,
633 IN PDEVICE_OBJECT DeviceObject
)
640 CPortPinWaveRT::Init(
642 IN PPORTFILTERWAVERT Filter
,
643 IN KSPIN_CONNECT
* ConnectDetails
,
644 IN KSPIN_DESCRIPTOR
* KsPinDescriptor
,
645 IN PDEVICE_OBJECT DeviceObject
)
648 PKSDATAFORMAT DataFormat
;
650 KSRTAUDIO_HWLATENCY Latency
;
657 m_KsPinDescriptor
= KsPinDescriptor
;
658 m_ConnectDetails
= ConnectDetails
;
659 m_Miniport
= GetWaveRTMiniport(Port
);
661 DataFormat
= (PKSDATAFORMAT
)(ConnectDetails
+ 1);
663 DPRINT("CPortPinWaveRT::Init entered\n");
665 m_Format
= (PKSDATAFORMAT
)AllocateItem(NonPagedPool
, DataFormat
->FormatSize
, TAG_PORTCLASS
);
667 return STATUS_INSUFFICIENT_RESOURCES
;
669 RtlMoveMemory(m_Format
, DataFormat
, DataFormat
->FormatSize
);
671 Status
= NewIrpQueue(&m_IrpQueue
);
672 if (!NT_SUCCESS(Status
))
677 Status
= m_IrpQueue
->Init(ConnectDetails
, DataFormat
, DeviceObject
, 0, 0, NULL
);
678 if (!NT_SUCCESS(Status
))
683 Status
= NewPortWaveRTStream(&m_PortStream
);
684 if (!NT_SUCCESS(Status
))
689 if (KsPinDescriptor
->Communication
== KSPIN_COMMUNICATION_SINK
&& KsPinDescriptor
->DataFlow
== KSPIN_DATAFLOW_IN
)
693 else if (KsPinDescriptor
->Communication
== KSPIN_COMMUNICATION_SINK
&& KsPinDescriptor
->DataFlow
== KSPIN_DATAFLOW_OUT
)
699 DPRINT1("Unexpected Communication %u DataFlow %u\n", KsPinDescriptor
->Communication
, KsPinDescriptor
->DataFlow
);
703 Status
= m_Miniport
->NewStream(&m_Stream
, m_PortStream
, ConnectDetails
->PinId
, Capture
, m_Format
);
704 DPRINT("CPortPinWaveRT::Init Status %x\n", Status
);
706 if (!NT_SUCCESS(Status
))
709 m_Stream
->GetHWLatency(&Latency
);
710 // delay of 10 milisec
711 m_Delay
= Int32x32To64(10, -10000);
713 Status
= m_Stream
->AllocateAudioBuffer(16384 * 11, &m_Mdl
, &m_CommonBufferSize
, &m_CommonBufferOffset
, &m_CacheType
);
714 if (!NT_SUCCESS(Status
))
716 DPRINT1("AllocateAudioBuffer failed with %x\n", Status
);
720 m_CommonBuffer
= MmGetSystemAddressForMdlSafe(m_Mdl
, NormalPagePriority
);
721 if (!NT_SUCCESS(Status
))
723 DPRINT1("Failed to get system address %x\n", Status
);
729 DPRINT1("Setting state to acquire %x\n", m_Stream
->SetState(KSSTATE_ACQUIRE
));
730 DPRINT1("Setting state to pause %x\n", m_Stream
->SetState(KSSTATE_PAUSE
));
731 m_State
= KSSTATE_PAUSE
;
732 return STATUS_SUCCESS
;
737 m_IrpQueue
->Release();
743 FreeItem(m_Format
, TAG_PORTCLASS
);
756 m_PortStream
->Release();
767 OUT IPortPinWaveRT
** OutPin
)
769 CPortPinWaveRT
* This
;
771 This
= new(NonPagedPool
, TAG_PORTCLASS
) CPortPinWaveRT(NULL
);
773 return STATUS_INSUFFICIENT_RESOURCES
;
778 *OutPin
= (PPORTPINWAVERT
)This
;
780 return STATUS_SUCCESS
;