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
17 class CPortPinWaveRT
: public IPortPinWaveRT
20 STDMETHODIMP
QueryInterface( REFIID InterfaceId
, PVOID
* Interface
);
22 STDMETHODIMP_(ULONG
) AddRef()
24 InterlockedIncrement(&m_Ref
);
27 STDMETHODIMP_(ULONG
) Release()
29 InterlockedDecrement(&m_Ref
);
39 CPortPinWaveRT(IUnknown
*OuterUnknown
){}
40 virtual ~CPortPinWaveRT(){}
45 IPortFilterWaveRT
* m_Filter
;
46 KSPIN_DESCRIPTOR
* m_KsPinDescriptor
;
47 PMINIPORTWAVERT m_Miniport
;
48 PMINIPORTWAVERTSTREAM m_Stream
;
49 PPORTWAVERTSTREAM m_PortStream
;
51 PKSDATAFORMAT m_Format
;
52 KSPIN_CONNECT
* m_ConnectDetails
;
55 ULONG m_CommonBufferSize
;
56 ULONG m_CommonBufferOffset
;
58 IIrpQueue
* m_IrpQueue
;
64 ULONG m_PostCompleted
;
68 MEMORY_CACHING_TYPE m_CacheType
;
73 NTSTATUS NTAPI
HandleKsProperty(IN PIRP Irp
);
74 NTSTATUS NTAPI
HandleKsStream(IN PIRP Irp
);
75 VOID NTAPI
SetStreamState(IN KSSTATE State
);
76 friend VOID NTAPI
SetStreamWorkerRoutine(IN PDEVICE_OBJECT DeviceObject
, IN PVOID Context
);
77 friend VOID NTAPI
CloseStreamRoutine(IN PDEVICE_OBJECT DeviceObject
, IN PVOID Context
);
85 PIO_WORKITEM WorkItem
;
87 }SETSTREAM_CONTEXT
, *PSETSTREAM_CONTEXT
;
90 //==================================================================================================================================
93 CPortPinWaveRT::QueryInterface(
97 DPRINT("IServiceSink_fnQueryInterface entered\n");
99 if (IsEqualGUIDAligned(refiid
, IID_IIrpTarget
) ||
100 IsEqualGUIDAligned(refiid
, IID_IUnknown
))
102 *Output
= PVOID(PUNKNOWN((IIrpTarget
*)this));
103 PUNKNOWN(*Output
)->AddRef();
104 return STATUS_SUCCESS
;
106 return STATUS_UNSUCCESSFUL
;
109 //==================================================================================================================================
113 CPortPinWaveRT::NewIrpTarget(
114 OUT
struct IIrpTarget
**OutTarget
,
117 IN POOL_TYPE PoolType
,
118 IN PDEVICE_OBJECT DeviceObject
,
120 IN KSOBJECT_CREATE
*CreateObject
)
123 return STATUS_UNSUCCESSFUL
;
128 CPortPinWaveRT::HandleKsProperty(
131 PKSPROPERTY Property
;
133 UNICODE_STRING GuidString
;
134 PIO_STACK_LOCATION IoStack
;
136 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
138 DPRINT("IPortPinWave_HandleKsProperty entered\n");
140 if (IoStack
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(KSPROPERTY
))
142 Irp
->IoStatus
.Information
= 0;
143 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
144 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
145 return STATUS_INVALID_PARAMETER
;
148 Property
= (PKSPROPERTY
)IoStack
->Parameters
.DeviceIoControl
.Type3InputBuffer
;
150 if (IsEqualGUIDAligned(Property
->Set
, KSPROPSETID_Connection
))
152 if (Property
->Id
== KSPROPERTY_CONNECTION_STATE
)
154 PKSSTATE State
= (PKSSTATE
)Irp
->UserBuffer
;
156 if (IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(KSSTATE
))
158 Irp
->IoStatus
.Information
= sizeof(KSSTATE
);
159 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
160 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
161 return STATUS_BUFFER_TOO_SMALL
;
164 if (Property
->Flags
& KSPROPERTY_TYPE_SET
)
166 Status
= STATUS_UNSUCCESSFUL
;
167 Irp
->IoStatus
.Information
= 0;
171 Status
= m_Stream
->SetState(*State
);
173 DPRINT("Setting state %u %x\n", *State
, Status
);
174 if (NT_SUCCESS(Status
))
179 Irp
->IoStatus
.Status
= Status
;
180 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
183 else if (Property
->Flags
& KSPROPERTY_TYPE_GET
)
186 Irp
->IoStatus
.Information
= sizeof(KSSTATE
);
187 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
188 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
189 return STATUS_SUCCESS
;
192 else if (Property
->Id
== KSPROPERTY_CONNECTION_DATAFORMAT
)
194 PKSDATAFORMAT DataFormat
= (PKSDATAFORMAT
)Irp
->UserBuffer
;
195 if (Property
->Flags
& KSPROPERTY_TYPE_SET
)
197 PKSDATAFORMAT NewDataFormat
;
198 if (!RtlCompareMemory(DataFormat
, m_Format
, DataFormat
->FormatSize
))
200 Irp
->IoStatus
.Information
= DataFormat
->FormatSize
;
201 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
202 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
203 return STATUS_SUCCESS
;
206 NewDataFormat
= (PKSDATAFORMAT
)AllocateItem(NonPagedPool
, DataFormat
->FormatSize
, TAG_PORTCLASS
);
209 Irp
->IoStatus
.Information
= 0;
210 Irp
->IoStatus
.Status
= STATUS_NO_MEMORY
;
211 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
212 return STATUS_NO_MEMORY
;
214 RtlMoveMemory(NewDataFormat
, DataFormat
, DataFormat
->FormatSize
);
219 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL
);
220 ASSERT(NewDataFormat
->FormatSize
== sizeof(KSDATAFORMAT_WAVEFORMATEX
));
221 ASSERT(IsEqualGUIDAligned(&((PKSDATAFORMAT_WAVEFORMATEX
)NewDataFormat
)->DataFormat
.MajorFormat
, &KSDATAFORMAT_TYPE_AUDIO
));
222 ASSERT(IsEqualGUIDAligned(&((PKSDATAFORMAT_WAVEFORMATEX
)NewDataFormat
)->DataFormat
.SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
));
223 ASSERT(IsEqualGUIDAligned(&((PKSDATAFORMAT_WAVEFORMATEX
)NewDataFormat
)->DataFormat
.Specifier
, &KSDATAFORMAT_SPECIFIER_WAVEFORMATEX
));
225 ASSERT(m_State
== KSSTATE_STOP
);
227 DPRINT("NewDataFormat: Channels %u Bits %u Samples %u\n", ((PKSDATAFORMAT_WAVEFORMATEX
)NewDataFormat
)->WaveFormatEx
.nChannels
,
228 ((PKSDATAFORMAT_WAVEFORMATEX
)NewDataFormat
)->WaveFormatEx
.wBitsPerSample
,
229 ((PKSDATAFORMAT_WAVEFORMATEX
)NewDataFormat
)->WaveFormatEx
.nSamplesPerSec
);
231 Status
= m_Stream
->SetFormat(NewDataFormat
);
232 if (NT_SUCCESS(Status
))
235 FreeItem(m_Format
, TAG_PORTCLASS
);
237 m_Format
= NewDataFormat
;
238 Irp
->IoStatus
.Information
= DataFormat
->FormatSize
;
239 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
240 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
241 return STATUS_SUCCESS
;
244 DPRINT("Failed to set format\n");
245 Irp
->IoStatus
.Information
= 0;
246 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
247 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
248 return STATUS_UNSUCCESSFUL
;
250 else if (Property
->Flags
& KSPROPERTY_TYPE_GET
)
254 DPRINT("No format\n");
255 Irp
->IoStatus
.Information
= 0;
256 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
257 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
258 return STATUS_UNSUCCESSFUL
;
260 if (m_Format
->FormatSize
> IoStack
->Parameters
.DeviceIoControl
.OutputBufferLength
)
262 Irp
->IoStatus
.Information
= m_Format
->FormatSize
;
263 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
264 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
265 return STATUS_BUFFER_TOO_SMALL
;
268 RtlMoveMemory(DataFormat
, m_Format
, m_Format
->FormatSize
);
269 Irp
->IoStatus
.Information
= DataFormat
->FormatSize
;
270 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
271 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
272 return STATUS_SUCCESS
;
277 RtlStringFromGUID(Property
->Set
, &GuidString
);
278 DPRINT("Unhandled property Set |%S| Id %u Flags %x\n", GuidString
.Buffer
, Property
->Id
, Property
->Flags
);
279 RtlFreeUnicodeString(&GuidString
);
281 Irp
->IoStatus
.Status
= STATUS_NOT_IMPLEMENTED
;
282 Irp
->IoStatus
.Information
= 0;
283 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
284 return STATUS_NOT_IMPLEMENTED
;
289 CPortPinWaveRT::HandleKsStream(
292 DPRINT("IPortPinWaveRT_HandleKsStream entered State %u Stream %p is UNIMPLEMENTED\n", m_State
, m_Stream
);
294 return STATUS_PENDING
;
299 CPortPinWaveRT::DeviceIoControl(
300 IN PDEVICE_OBJECT DeviceObject
,
303 PIO_STACK_LOCATION IoStack
;
305 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
308 if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_KS_PROPERTY
)
310 return HandleKsProperty(Irp
);
312 else if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_KS_ENABLE_EVENT
)
315 /// handle enable event
317 else if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_KS_DISABLE_EVENT
)
320 /// handle disable event
322 else if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_KS_RESET_STATE
)
325 /// handle reset state
327 else if (IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_KS_WRITE_STREAM
|| IoStack
->Parameters
.DeviceIoControl
.IoControlCode
== IOCTL_KS_READ_STREAM
)
329 return HandleKsStream(Irp
);
333 return KsDefaultDeviceIoCompletion(DeviceObject
, Irp
);
338 Irp
->IoStatus
.Information
= 0;
339 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
340 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
342 return STATUS_UNSUCCESSFUL
;
347 CPortPinWaveRT::Read(
348 IN PDEVICE_OBJECT DeviceObject
,
351 return KsDispatchInvalidDeviceRequest(DeviceObject
, Irp
);
356 CPortPinWaveRT::Write(
357 IN PDEVICE_OBJECT DeviceObject
,
360 return KsDispatchInvalidDeviceRequest(DeviceObject
, Irp
);
365 CPortPinWaveRT::Flush(
366 IN PDEVICE_OBJECT DeviceObject
,
369 return KsDispatchInvalidDeviceRequest(DeviceObject
, Irp
);
375 IN PDEVICE_OBJECT DeviceObject
,
378 PMINIPORTWAVERTSTREAM Stream
;
380 ISubdevice
*ISubDevice
;
381 PSUBDEVICE_DESCRIPTOR Descriptor
;
382 CPortPinWaveRT
* This
;
383 PCLOSESTREAM_CONTEXT Ctx
= (PCLOSESTREAM_CONTEXT
)Context
;
385 This
= (CPortPinWaveRT
*)Ctx
->Pin
;
389 if (This
->m_State
!= KSSTATE_STOP
)
391 This
->m_Stream
->SetState(KSSTATE_STOP
);
392 KeStallExecutionProcessor(10);
396 Status
= This
->m_Port
->QueryInterface(IID_ISubdevice
, (PVOID
*)&ISubDevice
);
397 if (NT_SUCCESS(Status
))
399 Status
= ISubDevice
->GetDescriptor(&Descriptor
);
400 if (NT_SUCCESS(Status
))
402 Descriptor
->Factory
.Instances
[This
->m_ConnectDetails
->PinId
].CurrentPinInstanceCount
--;
404 ISubDevice
->Release();
409 FreeItem(This
->m_Format
, TAG_PORTCLASS
);
410 This
->m_Format
= NULL
;
413 if (This
->m_IrpQueue
)
415 This
->m_IrpQueue
->Release();
419 Ctx
->Irp
->IoStatus
.Information
= 0;
420 Ctx
->Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
421 IoCompleteRequest(Ctx
->Irp
, IO_NO_INCREMENT
);
423 // free the work item
424 IoFreeWorkItem(Ctx
->WorkItem
);
426 // free work item ctx
427 FreeItem(Ctx
, TAG_PORTCLASS
);
431 Stream
= This
->m_Stream
;
432 This
->m_Stream
= NULL
;
433 DPRINT("Closing stream at Irql %u\n", KeGetCurrentIrql());
440 CPortPinWaveRT::Close(
441 IN PDEVICE_OBJECT DeviceObject
,
444 PCLOSESTREAM_CONTEXT Ctx
;
448 Ctx
= (PCLOSESTREAM_CONTEXT
)AllocateItem(NonPagedPool
, sizeof(CLOSESTREAM_CONTEXT
), TAG_PORTCLASS
);
451 DPRINT("Failed to allocate stream context\n");
455 Ctx
->WorkItem
= IoAllocateWorkItem(DeviceObject
);
458 DPRINT("Failed to allocate work item\n");
465 IoMarkIrpPending(Irp
);
466 Irp
->IoStatus
.Information
= 0;
467 Irp
->IoStatus
.Status
= STATUS_PENDING
;
470 IoQueueWorkItem(Ctx
->WorkItem
, CloseStreamRoutine
, DelayedWorkQueue
, (PVOID
)Ctx
);
472 return STATUS_PENDING
;
475 Irp
->IoStatus
.Information
= 0;
476 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
477 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
479 return STATUS_SUCCESS
;
484 FreeItem(Ctx
, TAG_PORTCLASS
);
486 Irp
->IoStatus
.Information
= 0;
487 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
488 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
489 return STATUS_UNSUCCESSFUL
;
495 CPortPinWaveRT::QuerySecurity(
496 IN PDEVICE_OBJECT DeviceObject
,
499 return KsDispatchInvalidDeviceRequest(DeviceObject
, Irp
);
504 CPortPinWaveRT::SetSecurity(
505 IN PDEVICE_OBJECT DeviceObject
,
508 return KsDispatchInvalidDeviceRequest(DeviceObject
, Irp
);
513 CPortPinWaveRT::FastDeviceIoControl(
514 IN PFILE_OBJECT FileObject
,
516 IN PVOID InputBuffer
,
517 IN ULONG InputBufferLength
,
518 OUT PVOID OutputBuffer
,
519 IN ULONG OutputBufferLength
,
520 IN ULONG IoControlCode
,
521 OUT PIO_STATUS_BLOCK StatusBlock
,
522 IN PDEVICE_OBJECT DeviceObject
)
529 CPortPinWaveRT::FastRead(
530 IN PFILE_OBJECT FileObject
,
531 IN PLARGE_INTEGER FileOffset
,
536 OUT PIO_STATUS_BLOCK StatusBlock
,
537 IN PDEVICE_OBJECT DeviceObject
)
544 CPortPinWaveRT::FastWrite(
545 IN PFILE_OBJECT FileObject
,
546 IN PLARGE_INTEGER FileOffset
,
551 OUT PIO_STATUS_BLOCK StatusBlock
,
552 IN PDEVICE_OBJECT DeviceObject
)
559 CPortPinWaveRT::Init(
561 IN PPORTFILTERWAVERT Filter
,
562 IN KSPIN_CONNECT
* ConnectDetails
,
563 IN KSPIN_DESCRIPTOR
* KsPinDescriptor
,
564 IN PDEVICE_OBJECT DeviceObject
)
567 PKSDATAFORMAT DataFormat
;
569 KSRTAUDIO_HWLATENCY Latency
;
576 m_KsPinDescriptor
= KsPinDescriptor
;
577 m_ConnectDetails
= ConnectDetails
;
578 m_Miniport
= GetWaveRTMiniport(Port
);
580 DataFormat
= (PKSDATAFORMAT
)(ConnectDetails
+ 1);
582 DPRINT("CPortPinWaveRT::Init entered\n");
584 m_Format
= (PKSDATAFORMAT
)AllocateItem(NonPagedPool
, DataFormat
->FormatSize
, TAG_PORTCLASS
);
586 return STATUS_INSUFFICIENT_RESOURCES
;
588 RtlMoveMemory(m_Format
, DataFormat
, DataFormat
->FormatSize
);
590 Status
= NewIrpQueue(&m_IrpQueue
);
591 if (!NT_SUCCESS(Status
))
596 Status
= m_IrpQueue
->Init(ConnectDetails
, KsPinDescriptor
, 0, 0, FALSE
);
597 if (!NT_SUCCESS(Status
))
602 Status
= NewPortWaveRTStream(&m_PortStream
);
603 if (!NT_SUCCESS(Status
))
608 if (KsPinDescriptor
->Communication
== KSPIN_COMMUNICATION_SINK
&& KsPinDescriptor
->DataFlow
== KSPIN_DATAFLOW_IN
)
612 else if (KsPinDescriptor
->Communication
== KSPIN_COMMUNICATION_SINK
&& KsPinDescriptor
->DataFlow
== KSPIN_DATAFLOW_OUT
)
618 DPRINT("Unexpected Communication %u DataFlow %u\n", KsPinDescriptor
->Communication
, KsPinDescriptor
->DataFlow
);
623 Status
= m_Miniport
->NewStream(&m_Stream
, m_PortStream
, ConnectDetails
->PinId
, Capture
, m_Format
);
624 DPRINT("CPortPinWaveRT::Init Status %x\n", Status
);
626 if (!NT_SUCCESS(Status
))
629 m_Stream
->GetHWLatency(&Latency
);
630 // delay of 10 millisec
631 m_Delay
= Int32x32To64(10, -10000);
633 Status
= m_Stream
->AllocateAudioBuffer(16384 * 11, &m_Mdl
, &m_CommonBufferSize
, &m_CommonBufferOffset
, &m_CacheType
);
634 if (!NT_SUCCESS(Status
))
636 DPRINT("AllocateAudioBuffer failed with %x\n", Status
);
640 m_CommonBuffer
= MmGetSystemAddressForMdlSafe(m_Mdl
, NormalPagePriority
);
643 DPRINT("Failed to get system address %x\n", Status
);
649 DPRINT("Setting state to acquire %x\n", m_Stream
->SetState(KSSTATE_ACQUIRE
));
650 DPRINT("Setting state to pause %x\n", m_Stream
->SetState(KSSTATE_PAUSE
));
651 m_State
= KSSTATE_PAUSE
;
652 return STATUS_SUCCESS
;
657 m_IrpQueue
->Release();
663 FreeItem(m_Format
, TAG_PORTCLASS
);
676 m_PortStream
->Release();
687 OUT IPortPinWaveRT
** OutPin
)
689 CPortPinWaveRT
* This
;
691 This
= new(NonPagedPool
, TAG_PORTCLASS
) CPortPinWaveRT(NULL
);
693 return STATUS_INSUFFICIENT_RESOURCES
;
698 *OutPin
= (PPORTPINWAVERT
)This
;
700 return STATUS_SUCCESS
;