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
;
103 //==================================================================================================================================
107 CPortPinWaveRT::NewIrpTarget(
108 OUT
struct IIrpTarget
**OutTarget
,
111 IN POOL_TYPE PoolType
,
112 IN PDEVICE_OBJECT DeviceObject
,
114 IN KSOBJECT_CREATE
*CreateObject
)
117 return STATUS_UNSUCCESSFUL
;
122 CPortPinWaveRT::HandleKsProperty(
125 PKSPROPERTY Property
;
127 UNICODE_STRING GuidString
;
128 PIO_STACK_LOCATION IoStack
;
130 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
132 DPRINT("IPortPinWave_HandleKsProperty entered\n");
134 if (IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(KSPROPERTY
))
136 Irp
->IoStatus
.Information
= 0;
137 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
138 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
139 return STATUS_INVALID_PARAMETER
;
142 Property
= (PKSPROPERTY
)IoStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
144 if (IsEqualGUIDAligned(Property
->Set
, KSPROPSETID_Connection
))
146 if (Property
->Id
== KSPROPERTY_CONNECTION_STATE
)
148 PKSSTATE State
= (PKSSTATE
)Irp
->UserBuffer
;
150 if (IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(KSSTATE
))
152 Irp
->IoStatus
.Information
= sizeof(KSSTATE
);
153 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
154 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
155 return STATUS_BUFFER_TOO_SMALL
;
158 if (Property
->Flags
& KSPROPERTY_TYPE_SET
)
160 Status
= STATUS_UNSUCCESSFUL
;
161 Irp
->IoStatus
.Information
= 0;
165 Status
= m_Stream
->SetState(*State
);
167 DPRINT("Setting state %u %x\n", *State
, Status
);
168 if (NT_SUCCESS(Status
))
173 Irp
->IoStatus
.Status
= Status
;
174 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
177 else if (Property
->Flags
& KSPROPERTY_TYPE_GET
)
180 Irp
->IoStatus
.Information
= sizeof(KSSTATE
);
181 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
182 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
183 return STATUS_SUCCESS
;
186 else if (Property
->Id
== KSPROPERTY_CONNECTION_DATAFORMAT
)
188 PKSDATAFORMAT DataFormat
= (PKSDATAFORMAT
)Irp
->UserBuffer
;
189 if (Property
->Flags
& KSPROPERTY_TYPE_SET
)
191 PKSDATAFORMAT NewDataFormat
;
192 if (!RtlCompareMemory(DataFormat
, m_Format
, DataFormat
->FormatSize
))
194 Irp
->IoStatus
.Information
= DataFormat
->FormatSize
;
195 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
196 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
197 return STATUS_SUCCESS
;
200 NewDataFormat
= (PKSDATAFORMAT
)AllocateItem(NonPagedPool
, DataFormat
->FormatSize
, TAG_PORTCLASS
);
203 Irp
->IoStatus
.Information
= 0;
204 Irp
->IoStatus
.Status
= STATUS_NO_MEMORY
;
205 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
206 return STATUS_NO_MEMORY
;
208 RtlMoveMemory(NewDataFormat
, DataFormat
, DataFormat
->FormatSize
);
213 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL
);
214 ASSERT(NewDataFormat
->FormatSize
== sizeof(KSDATAFORMAT_WAVEFORMATEX
));
215 ASSERT(IsEqualGUIDAligned(&((PKSDATAFORMAT_WAVEFORMATEX
)NewDataFormat
)->DataFormat
.MajorFormat
, &KSDATAFORMAT_TYPE_AUDIO
));
216 ASSERT(IsEqualGUIDAligned(&((PKSDATAFORMAT_WAVEFORMATEX
)NewDataFormat
)->DataFormat
.SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
));
217 ASSERT(IsEqualGUIDAligned(&((PKSDATAFORMAT_WAVEFORMATEX
)NewDataFormat
)->DataFormat
.Specifier
, &KSDATAFORMAT_SPECIFIER_WAVEFORMATEX
));
219 ASSERT(m_State
== KSSTATE_STOP
);
221 DPRINT("NewDataFormat: Channels %u Bits %u Samples %u\n", ((PKSDATAFORMAT_WAVEFORMATEX
)NewDataFormat
)->WaveFormatEx
.nChannels
,
222 ((PKSDATAFORMAT_WAVEFORMATEX
)NewDataFormat
)->WaveFormatEx
.wBitsPerSample
,
223 ((PKSDATAFORMAT_WAVEFORMATEX
)NewDataFormat
)->WaveFormatEx
.nSamplesPerSec
);
225 Status
= m_Stream
->SetFormat(NewDataFormat
);
226 if (NT_SUCCESS(Status
))
229 FreeItem(m_Format
, TAG_PORTCLASS
);
231 m_Format
= NewDataFormat
;
232 Irp
->IoStatus
.Information
= DataFormat
->FormatSize
;
233 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
234 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
235 return STATUS_SUCCESS
;
238 DPRINT("Failed to set format\n");
239 Irp
->IoStatus
.Information
= 0;
240 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
241 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
242 return STATUS_UNSUCCESSFUL
;
244 else if (Property
->Flags
& KSPROPERTY_TYPE_GET
)
248 DPRINT("No format\n");
249 Irp
->IoStatus
.Information
= 0;
250 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
251 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
252 return STATUS_UNSUCCESSFUL
;
254 if (m_Format
->FormatSize
> IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
)
256 Irp
->IoStatus
.Information
= m_Format
->FormatSize
;
257 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
258 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
259 return STATUS_BUFFER_TOO_SMALL
;
262 RtlMoveMemory(DataFormat
, m_Format
, m_Format
->FormatSize
);
263 Irp
->IoStatus
.Information
= DataFormat
->FormatSize
;
264 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
265 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
266 return STATUS_SUCCESS
;
271 RtlStringFromGUID(Property
->Set
, &GuidString
);
272 DPRINT("Unhandeled property Set |%S| Id %u Flags %x\n", GuidString
.Buffer
, Property
->Id
, Property
->Flags
);
273 RtlFreeUnicodeString(&GuidString
);
275 Irp
->IoStatus
.Status
= STATUS_NOT_IMPLEMENTED
;
276 Irp
->IoStatus
.Information
= 0;
277 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
278 return STATUS_NOT_IMPLEMENTED
;
283 CPortPinWaveRT::HandleKsStream(
286 DPRINT("IPortPinWaveRT_HandleKsStream entered State %u Stream %p\n", m_State
, m_Stream
);
288 return STATUS_PENDING
;
293 CPortPinWaveRT::DeviceIoControl(
294 IN PDEVICE_OBJECT DeviceObject
,
297 PIO_STACK_LOCATION IoStack
;
299 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
302 if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_KS_PROPERTY
)
304 return HandleKsProperty(Irp
);
306 else if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_KS_ENABLE_EVENT
)
309 /// handle enable event
311 else if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_KS_DISABLE_EVENT
)
314 /// handle disable event
316 else if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_KS_RESET_STATE
)
319 /// handle reset state
321 else if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_KS_WRITE_STREAM
|| IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_KS_READ_STREAM
)
323 return HandleKsStream(Irp
);
327 return KsDefaultDeviceIoCompletion(DeviceObject
, Irp
);
332 Irp
->IoStatus
.Information
= 0;
333 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
334 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
336 return STATUS_UNSUCCESSFUL
;
341 CPortPinWaveRT::Read(
342 IN PDEVICE_OBJECT DeviceObject
,
345 return KsDispatchInvalidDeviceRequest(DeviceObject
, Irp
);
350 CPortPinWaveRT::Write(
351 IN PDEVICE_OBJECT DeviceObject
,
354 return KsDispatchInvalidDeviceRequest(DeviceObject
, Irp
);
359 CPortPinWaveRT::Flush(
360 IN PDEVICE_OBJECT DeviceObject
,
363 return KsDispatchInvalidDeviceRequest(DeviceObject
, Irp
);
369 IN PDEVICE_OBJECT DeviceObject
,
372 PMINIPORTWAVERTSTREAM Stream
;
374 ISubdevice
*ISubDevice
;
375 PSUBDEVICE_DESCRIPTOR Descriptor
;
376 CPortPinWaveRT
* This
;
377 PCLOSESTREAM_CONTEXT Ctx
= (PCLOSESTREAM_CONTEXT
)Context
;
379 This
= (CPortPinWaveRT
*)Ctx
->Pin
;
383 if (This
->m_State
!= KSSTATE_STOP
)
385 This
->m_Stream
->SetState(KSSTATE_STOP
);
386 KeStallExecutionProcessor(10);
390 Status
= This
->m_Port
->QueryInterface(IID_ISubdevice
, (PVOID
*)&ISubDevice
);
391 if (NT_SUCCESS(Status
))
393 Status
= ISubDevice
->GetDescriptor(&Descriptor
);
394 if (NT_SUCCESS(Status
))
396 Descriptor
->Factory
.Instances
[This
->m_ConnectDetails
->PinId
].CurrentPinInstanceCount
--;
398 ISubDevice
->Release();
403 FreeItem(This
->m_Format
, TAG_PORTCLASS
);
404 This
->m_Format
= NULL
;
407 if (This
->m_IrpQueue
)
409 This
->m_IrpQueue
->Release();
413 Ctx
->Irp
->IoStatus
.Information
= 0;
414 Ctx
->Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
415 IoCompleteRequest(Ctx
->Irp
, IO_NO_INCREMENT
);
417 // free the work item
418 IoFreeWorkItem(Ctx
->WorkItem
);
420 // free work item ctx
421 FreeItem(Ctx
, TAG_PORTCLASS
);
425 Stream
= This
->m_Stream
;
426 This
->m_Stream
= NULL
;
427 DPRINT("Closing stream at Irql %u\n", KeGetCurrentIrql());
434 CPortPinWaveRT::Close(
435 IN PDEVICE_OBJECT DeviceObject
,
438 PCLOSESTREAM_CONTEXT Ctx
;
442 Ctx
= (PCLOSESTREAM_CONTEXT
)AllocateItem(NonPagedPool
, sizeof(CLOSESTREAM_CONTEXT
), TAG_PORTCLASS
);
445 DPRINT("Failed to allocate stream context\n");
449 Ctx
->WorkItem
= IoAllocateWorkItem(DeviceObject
);
452 DPRINT("Failed to allocate work item\n");
459 IoMarkIrpPending(Irp
);
460 Irp
->IoStatus
.Information
= 0;
461 Irp
->IoStatus
.Status
= STATUS_PENDING
;
464 IoQueueWorkItem(Ctx
->WorkItem
, CloseStreamRoutine
, DelayedWorkQueue
, (PVOID
)Ctx
);
466 return STATUS_PENDING
;
469 Irp
->IoStatus
.Information
= 0;
470 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
471 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
473 return STATUS_SUCCESS
;
478 FreeItem(Ctx
, TAG_PORTCLASS
);
480 Irp
->IoStatus
.Information
= 0;
481 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
482 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
483 return STATUS_UNSUCCESSFUL
;
489 CPortPinWaveRT::QuerySecurity(
490 IN PDEVICE_OBJECT DeviceObject
,
493 return KsDispatchInvalidDeviceRequest(DeviceObject
, Irp
);
498 CPortPinWaveRT::SetSecurity(
499 IN PDEVICE_OBJECT DeviceObject
,
502 return KsDispatchInvalidDeviceRequest(DeviceObject
, Irp
);
507 CPortPinWaveRT::FastDeviceIoControl(
508 IN PFILE_OBJECT FileObject
,
510 IN PVOID InputBuffer
,
511 IN ULONG InputBufferLength
,
512 OUT PVOID OutputBuffer
,
513 IN ULONG OutputBufferLength
,
514 IN ULONG IoControlCode
,
515 OUT PIO_STATUS_BLOCK StatusBlock
,
516 IN PDEVICE_OBJECT DeviceObject
)
523 CPortPinWaveRT::FastRead(
524 IN PFILE_OBJECT FileObject
,
525 IN PLARGE_INTEGER FileOffset
,
530 OUT PIO_STATUS_BLOCK StatusBlock
,
531 IN PDEVICE_OBJECT DeviceObject
)
538 CPortPinWaveRT::FastWrite(
539 IN PFILE_OBJECT FileObject
,
540 IN PLARGE_INTEGER FileOffset
,
545 OUT PIO_STATUS_BLOCK StatusBlock
,
546 IN PDEVICE_OBJECT DeviceObject
)
553 CPortPinWaveRT::Init(
555 IN PPORTFILTERWAVERT Filter
,
556 IN KSPIN_CONNECT
* ConnectDetails
,
557 IN KSPIN_DESCRIPTOR
* KsPinDescriptor
,
558 IN PDEVICE_OBJECT DeviceObject
)
561 PKSDATAFORMAT DataFormat
;
563 KSRTAUDIO_HWLATENCY Latency
;
570 m_KsPinDescriptor
= KsPinDescriptor
;
571 m_ConnectDetails
= ConnectDetails
;
572 m_Miniport
= GetWaveRTMiniport(Port
);
574 DataFormat
= (PKSDATAFORMAT
)(ConnectDetails
+ 1);
576 DPRINT("CPortPinWaveRT::Init entered\n");
578 m_Format
= (PKSDATAFORMAT
)AllocateItem(NonPagedPool
, DataFormat
->FormatSize
, TAG_PORTCLASS
);
580 return STATUS_INSUFFICIENT_RESOURCES
;
582 RtlMoveMemory(m_Format
, DataFormat
, DataFormat
->FormatSize
);
584 Status
= NewIrpQueue(&m_IrpQueue
);
585 if (!NT_SUCCESS(Status
))
590 Status
= m_IrpQueue
->Init(ConnectDetails
, 0, 0);
591 if (!NT_SUCCESS(Status
))
596 Status
= NewPortWaveRTStream(&m_PortStream
);
597 if (!NT_SUCCESS(Status
))
602 if (KsPinDescriptor
->Communication
== KSPIN_COMMUNICATION_SINK
&& KsPinDescriptor
->DataFlow
== KSPIN_DATAFLOW_IN
)
606 else if (KsPinDescriptor
->Communication
== KSPIN_COMMUNICATION_SINK
&& KsPinDescriptor
->DataFlow
== KSPIN_DATAFLOW_OUT
)
612 DPRINT("Unexpected Communication %u DataFlow %u\n", KsPinDescriptor
->Communication
, KsPinDescriptor
->DataFlow
);
617 Status
= m_Miniport
->NewStream(&m_Stream
, m_PortStream
, ConnectDetails
->PinId
, Capture
, m_Format
);
618 DPRINT("CPortPinWaveRT::Init Status %x\n", Status
);
620 if (!NT_SUCCESS(Status
))
623 m_Stream
->GetHWLatency(&Latency
);
624 // delay of 10 milisec
625 m_Delay
= Int32x32To64(10, -10000);
627 Status
= m_Stream
->AllocateAudioBuffer(16384 * 11, &m_Mdl
, &m_CommonBufferSize
, &m_CommonBufferOffset
, &m_CacheType
);
628 if (!NT_SUCCESS(Status
))
630 DPRINT("AllocateAudioBuffer failed with %x\n", Status
);
634 m_CommonBuffer
= MmGetSystemAddressForMdlSafe(m_Mdl
, NormalPagePriority
);
635 if (!NT_SUCCESS(Status
))
637 DPRINT("Failed to get system address %x\n", Status
);
643 DPRINT("Setting state to acquire %x\n", m_Stream
->SetState(KSSTATE_ACQUIRE
));
644 DPRINT("Setting state to pause %x\n", m_Stream
->SetState(KSSTATE_PAUSE
));
645 m_State
= KSSTATE_PAUSE
;
646 return STATUS_SUCCESS
;
651 m_IrpQueue
->Release();
657 FreeItem(m_Format
, TAG_PORTCLASS
);
670 m_PortStream
->Release();
681 OUT IPortPinWaveRT
** OutPin
)
683 CPortPinWaveRT
* This
;
685 This
= new(NonPagedPool
, TAG_PORTCLASS
) CPortPinWaveRT(NULL
);
687 return STATUS_INSUFFICIENT_RESOURCES
;
692 *OutPin
= (PPORTPINWAVERT
)This
;
694 return STATUS_SUCCESS
;