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 DPRINT("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 DPRINT("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 DPRINT("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 DPRINT("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 DPRINT("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 DPRINT("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
);
418 Irp
->IoStatus
.Information
= 0;
419 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
420 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
422 return STATUS_UNSUCCESSFUL
;
427 CPortPinWaveRT::Read(
428 IN PDEVICE_OBJECT DeviceObject
,
431 return KsDispatchInvalidDeviceRequest(DeviceObject
, Irp
);
436 CPortPinWaveRT::Write(
437 IN PDEVICE_OBJECT DeviceObject
,
440 return KsDispatchInvalidDeviceRequest(DeviceObject
, Irp
);
445 CPortPinWaveRT::Flush(
446 IN PDEVICE_OBJECT DeviceObject
,
449 return KsDispatchInvalidDeviceRequest(DeviceObject
, Irp
);
455 IN PDEVICE_OBJECT DeviceObject
,
458 PMINIPORTWAVERTSTREAM Stream
;
460 ISubdevice
*ISubDevice
;
461 PSUBDEVICE_DESCRIPTOR Descriptor
;
462 CPortPinWaveRT
* This
;
463 PCLOSESTREAM_CONTEXT Ctx
= (PCLOSESTREAM_CONTEXT
)Context
;
465 This
= (CPortPinWaveRT
*)Ctx
->Pin
;
469 if (This
->m_State
!= KSSTATE_STOP
)
471 This
->m_Stream
->SetState(KSSTATE_STOP
);
472 KeStallExecutionProcessor(10);
476 Status
= This
->m_Port
->QueryInterface(IID_ISubdevice
, (PVOID
*)&ISubDevice
);
477 if (NT_SUCCESS(Status
))
479 Status
= ISubDevice
->GetDescriptor(&Descriptor
);
480 if (NT_SUCCESS(Status
))
482 Descriptor
->Factory
.Instances
[This
->m_ConnectDetails
->PinId
].CurrentPinInstanceCount
--;
484 ISubDevice
->Release();
489 ExFreePool(This
->m_Format
);
490 This
->m_Format
= NULL
;
493 if (This
->m_IrpQueue
)
495 This
->m_IrpQueue
->Release();
499 Ctx
->Irp
->IoStatus
.Information
= 0;
500 Ctx
->Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
501 IoCompleteRequest(Ctx
->Irp
, IO_NO_INCREMENT
);
503 // free the work item
504 IoFreeWorkItem(Ctx
->WorkItem
);
506 // free work item ctx
507 FreeItem(Ctx
, TAG_PORTCLASS
);
511 Stream
= This
->m_Stream
;
512 This
->m_Stream
= NULL
;
513 DPRINT("Closing stream at Irql %u\n", KeGetCurrentIrql());
520 CPortPinWaveRT::Close(
521 IN PDEVICE_OBJECT DeviceObject
,
524 PCLOSESTREAM_CONTEXT Ctx
;
528 Ctx
= (PCLOSESTREAM_CONTEXT
)AllocateItem(NonPagedPool
, sizeof(CLOSESTREAM_CONTEXT
), TAG_PORTCLASS
);
531 DPRINT("Failed to allocate stream context\n");
535 Ctx
->WorkItem
= IoAllocateWorkItem(DeviceObject
);
538 DPRINT("Failed to allocate work item\n");
545 IoMarkIrpPending(Irp
);
546 Irp
->IoStatus
.Information
= 0;
547 Irp
->IoStatus
.Status
= STATUS_PENDING
;
550 IoQueueWorkItem(Ctx
->WorkItem
, CloseStreamRoutine
, DelayedWorkQueue
, (PVOID
)Ctx
);
552 return STATUS_PENDING
;
555 Irp
->IoStatus
.Information
= 0;
556 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
557 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
559 return STATUS_SUCCESS
;
564 FreeItem(Ctx
, TAG_PORTCLASS
);
566 Irp
->IoStatus
.Information
= 0;
567 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
568 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
569 return STATUS_UNSUCCESSFUL
;
575 CPortPinWaveRT::QuerySecurity(
576 IN PDEVICE_OBJECT DeviceObject
,
579 return KsDispatchInvalidDeviceRequest(DeviceObject
, Irp
);
584 CPortPinWaveRT::SetSecurity(
585 IN PDEVICE_OBJECT DeviceObject
,
588 return KsDispatchInvalidDeviceRequest(DeviceObject
, Irp
);
593 CPortPinWaveRT::FastDeviceIoControl(
594 IN PFILE_OBJECT FileObject
,
596 IN PVOID InputBuffer
,
597 IN ULONG InputBufferLength
,
598 OUT PVOID OutputBuffer
,
599 IN ULONG OutputBufferLength
,
600 IN ULONG IoControlCode
,
601 OUT PIO_STATUS_BLOCK StatusBlock
,
602 IN PDEVICE_OBJECT DeviceObject
)
609 CPortPinWaveRT::FastRead(
610 IN PFILE_OBJECT FileObject
,
611 IN PLARGE_INTEGER FileOffset
,
616 OUT PIO_STATUS_BLOCK StatusBlock
,
617 IN PDEVICE_OBJECT DeviceObject
)
624 CPortPinWaveRT::FastWrite(
625 IN PFILE_OBJECT FileObject
,
626 IN PLARGE_INTEGER FileOffset
,
631 OUT PIO_STATUS_BLOCK StatusBlock
,
632 IN PDEVICE_OBJECT DeviceObject
)
639 CPortPinWaveRT::Init(
641 IN PPORTFILTERWAVERT Filter
,
642 IN KSPIN_CONNECT
* ConnectDetails
,
643 IN KSPIN_DESCRIPTOR
* KsPinDescriptor
,
644 IN PDEVICE_OBJECT DeviceObject
)
647 PKSDATAFORMAT DataFormat
;
649 KSRTAUDIO_HWLATENCY Latency
;
656 m_KsPinDescriptor
= KsPinDescriptor
;
657 m_ConnectDetails
= ConnectDetails
;
658 m_Miniport
= GetWaveRTMiniport(Port
);
660 DataFormat
= (PKSDATAFORMAT
)(ConnectDetails
+ 1);
662 DPRINT("CPortPinWaveRT::Init entered\n");
664 m_Format
= (PKSDATAFORMAT
)AllocateItem(NonPagedPool
, DataFormat
->FormatSize
, TAG_PORTCLASS
);
666 return STATUS_INSUFFICIENT_RESOURCES
;
668 RtlMoveMemory(m_Format
, DataFormat
, DataFormat
->FormatSize
);
670 Status
= NewIrpQueue(&m_IrpQueue
);
671 if (!NT_SUCCESS(Status
))
676 Status
= m_IrpQueue
->Init(ConnectDetails
, DataFormat
, DeviceObject
, 0, 0, NULL
);
677 if (!NT_SUCCESS(Status
))
682 Status
= NewPortWaveRTStream(&m_PortStream
);
683 if (!NT_SUCCESS(Status
))
688 if (KsPinDescriptor
->Communication
== KSPIN_COMMUNICATION_SINK
&& KsPinDescriptor
->DataFlow
== KSPIN_DATAFLOW_IN
)
692 else if (KsPinDescriptor
->Communication
== KSPIN_COMMUNICATION_SINK
&& KsPinDescriptor
->DataFlow
== KSPIN_DATAFLOW_OUT
)
698 DPRINT("Unexpected Communication %u DataFlow %u\n", KsPinDescriptor
->Communication
, KsPinDescriptor
->DataFlow
);
702 Status
= m_Miniport
->NewStream(&m_Stream
, m_PortStream
, ConnectDetails
->PinId
, Capture
, m_Format
);
703 DPRINT("CPortPinWaveRT::Init Status %x\n", Status
);
705 if (!NT_SUCCESS(Status
))
708 m_Stream
->GetHWLatency(&Latency
);
709 // delay of 10 milisec
710 m_Delay
= Int32x32To64(10, -10000);
712 Status
= m_Stream
->AllocateAudioBuffer(16384 * 11, &m_Mdl
, &m_CommonBufferSize
, &m_CommonBufferOffset
, &m_CacheType
);
713 if (!NT_SUCCESS(Status
))
715 DPRINT("AllocateAudioBuffer failed with %x\n", Status
);
719 m_CommonBuffer
= MmGetSystemAddressForMdlSafe(m_Mdl
, NormalPagePriority
);
720 if (!NT_SUCCESS(Status
))
722 DPRINT("Failed to get system address %x\n", Status
);
728 DPRINT("Setting state to acquire %x\n", m_Stream
->SetState(KSSTATE_ACQUIRE
));
729 DPRINT("Setting state to pause %x\n", m_Stream
->SetState(KSSTATE_PAUSE
));
730 m_State
= KSSTATE_PAUSE
;
731 return STATUS_SUCCESS
;
736 m_IrpQueue
->Release();
742 FreeItem(m_Format
, TAG_PORTCLASS
);
755 m_PortStream
->Release();
766 OUT IPortPinWaveRT
** OutPin
)
768 CPortPinWaveRT
* This
;
770 This
= new(NonPagedPool
, TAG_PORTCLASS
) CPortPinWaveRT(NULL
);
772 return STATUS_INSUFFICIENT_RESOURCES
;
777 *OutPin
= (PPORTPINWAVERT
)This
;
779 return STATUS_SUCCESS
;