//============================================================================= 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) { // MSVAD does not validate the format. pWfx = GetWaveFormatEx(Format); if (pWfx) { ntStatus = KeWaitForSingleObject(&m_pMiniport->m_SampleRateSync, Executive, KernelMode, FALSE, NULL); if (STATUS_SUCCESS == ntStatus) { m_usBlockAlign = pWfx->nBlockAlign; m_fFormat16Bit = (pWfx->wBitsPerSample == 16); m_pMiniport->m_SamplingFrequency = pWfx->nSamplesPerSec; m_ulDmaMovementRate = pWfx->nAvgBytesPerSec; DPF(D_TERSE, ("New Format - SpS: %d - BpS: %d - aBypS: %d - C: %d", pWfx->nSamplesPerSec, pWfx->wBitsPerSample, pWfx->nAvgBytesPerSec, pWfx->nChannels)); } KeReleaseMutex(&m_pMiniport->m_SampleRateSync, FALSE); } } return ntStatus; } // SetFormat
NTSTATUS CMiniportWaveRTStream::Init ( _In_ PCMiniportWaveRT Miniport_, _In_ PPORTWAVERTSTREAM PortStream_, _In_ ULONG Pin_, _In_ BOOLEAN Capture_, _In_ PKSDATAFORMAT DataFormat_, _In_ GUID SignalProcessingMode ) /*++ Routine Description: Initializes the stream object. Arguments: Miniport_ - Pin_ - Capture_ - DataFormat - SignalProcessingMode - The driver uses the signalProcessingMode to configure driver and/or hardware specific signal processing to be applied to this new stream. Return Value: NT status code. --*/ { PAGED_CODE(); PWAVEFORMATEX pWfEx = NULL; NTSTATUS ntStatus = STATUS_SUCCESS; m_pMiniport = NULL; m_ulPin = 0; m_bUnregisterStream = FALSE; m_bCapture = FALSE; m_ulDmaBufferSize = 0; m_pDmaBuffer = NULL; m_KsState = KSSTATE_STOP; m_pTimer = NULL; m_pDpc = NULL; m_ullPlayPosition = 0; m_ullWritePosition = 0; m_ullDmaTimeStamp = 0; m_hnsElapsedTimeCarryForward = 0; m_ulDmaMovementRate = 0; m_bLfxEnabled = FALSE; m_pbMuted = NULL; m_plVolumeLevel = NULL; m_plPeakMeter = NULL; m_pWfExt = NULL; m_ullLinearPosition = 0; m_ulContentId = 0; m_ulCurrentWritePosition = 0; m_IsCurrentWritePositionUpdated = 0; #ifdef SYSVAD_BTH_BYPASS m_ScoOpen = FALSE; #endif // SYSVAD_BTH_BYPASS m_pPortStream = PortStream_; InitializeListHead(&m_NotificationList); m_ulNotificationIntervalMs = 0; m_pNotificationDpc = (PRKDPC)ExAllocatePoolWithTag( NonPagedPoolNx, sizeof(KDPC), MINWAVERTSTREAM_POOLTAG); if (!m_pNotificationDpc) { return STATUS_INSUFFICIENT_RESOURCES; } m_pNotificationTimer = (PKTIMER)ExAllocatePoolWithTag( NonPagedPoolNx, sizeof(KTIMER), MINWAVERTSTREAM_POOLTAG); if (!m_pNotificationTimer) { return STATUS_INSUFFICIENT_RESOURCES; } KeInitializeDpc(m_pNotificationDpc, TimerNotifyRT, this); KeInitializeTimerEx(m_pNotificationTimer, NotificationTimer); pWfEx = GetWaveFormatEx(DataFormat_); if (NULL == pWfEx) { return STATUS_UNSUCCESSFUL; } m_pMiniport = reinterpret_cast<CMiniportWaveRT*>(Miniport_); if (m_pMiniport == NULL) { return STATUS_INVALID_PARAMETER; } m_pMiniport->AddRef(); if (!NT_SUCCESS(ntStatus)) { return ntStatus; } m_ulPin = Pin_; m_bCapture = Capture_; m_ulDmaMovementRate = pWfEx->nAvgBytesPerSec; m_pDpc = (PRKDPC)ExAllocatePoolWithTag(NonPagedPoolNx, sizeof(KDPC), MINWAVERTSTREAM_POOLTAG); if (!m_pDpc) { return STATUS_INSUFFICIENT_RESOURCES; } m_pWfExt = (PWAVEFORMATEXTENSIBLE)ExAllocatePoolWithTag(NonPagedPoolNx, sizeof(WAVEFORMATEX) + pWfEx->cbSize, MINWAVERTSTREAM_POOLTAG); if (m_pWfExt == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } RtlCopyMemory(m_pWfExt, pWfEx, sizeof(WAVEFORMATEX) + pWfEx->cbSize); m_pbMuted = (PBOOL)ExAllocatePoolWithTag(NonPagedPoolNx, m_pWfExt->Format.nChannels * sizeof(BOOL), MINWAVERTSTREAM_POOLTAG); if (m_pbMuted == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } RtlZeroMemory(m_pbMuted, m_pWfExt->Format.nChannels * sizeof(BOOL)); m_plVolumeLevel = (PLONG)ExAllocatePoolWithTag(NonPagedPoolNx, m_pWfExt->Format.nChannels * sizeof(LONG), MINWAVERTSTREAM_POOLTAG); if (m_plVolumeLevel == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } RtlZeroMemory(m_plVolumeLevel, m_pWfExt->Format.nChannels * sizeof(LONG)); m_plPeakMeter = (PLONG)ExAllocatePoolWithTag(NonPagedPoolNx, m_pWfExt->Format.nChannels * sizeof(LONG), MINWAVERTSTREAM_POOLTAG); if (m_plPeakMeter == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } RtlZeroMemory(m_plPeakMeter, m_pWfExt->Format.nChannels * sizeof(LONG)); if (m_bCapture) { DWORD toneFrequency = 0; if (!m_pMiniport->IsRenderDevice()) { // // Init sine wave generator. To exercise the SignalProcessingMode parameter // this sample driver selects the frequency based on the parameter. // toneFrequency = IsEqualGUID(SignalProcessingMode, AUDIO_SIGNALPROCESSINGMODE_RAW) ? 1000 : 2000; } else { // // Loopbacks pins use a different frequency for test validation. // ASSERT(Pin_ == m_pMiniport->GetLoopbackPinId()); toneFrequency = 3000; // 3 kHz } ntStatus = m_ToneGenerator.Init(toneFrequency, m_pWfExt); if (!NT_SUCCESS(ntStatus)) { return ntStatus; } } else if (!g_DoNotCreateDataFiles) { // // Create an output file for the render data. // DPF(D_TERSE, ("SaveData %p", &m_SaveData)); ntStatus = m_SaveData.SetDataFormat(DataFormat_); if (NT_SUCCESS(ntStatus)) { ntStatus = m_SaveData.Initialize(m_pMiniport->IsOffloadSupported() ? (Pin_ == m_pMiniport->GetOffloadPinId()) : FALSE); } if (!NT_SUCCESS(ntStatus)) { return ntStatus; } } // // Register this stream. // ntStatus = m_pMiniport->StreamCreated(m_ulPin, this); if (NT_SUCCESS(ntStatus)) { m_bUnregisterStream = TRUE; } return ntStatus; } // Init
//============================================================================= NTSTATUS CMiniportWaveCyclic::ValidateFormat ( IN ULONG nPin, IN PKSDATAFORMAT pDataFormat ) /*++ Routine Description: Validates that the given dataformat is valid. This overwrites BaseWave's ValidateFormat and includes checks for AC3 format. Arguments: pDataFormat - The dataformat for validation. Return Value: NT status code. --*/ { PAGED_CODE(); DPF_ENTER(("[CMiniportWaveCyclic::ValidateFormat]")); NTSTATUS ntStatus = STATUS_INVALID_PARAMETER; PWAVEFORMATEX pwfx; pwfx = GetWaveFormatEx(pDataFormat); if (pwfx) { if (IS_VALID_WAVEFORMATEX_GUID(&pDataFormat->SubFormat)) { USHORT wfxID = EXTRACT_WAVEFORMATEX_ID(&pDataFormat->SubFormat); if ((wfxID == WAVE_FORMAT_PCM) || ((wfxID == WAVE_FORMAT_DOLBY_AC3_SPDIF) && ((nPin == KSPIN_WAVE_SPDIF_CAPTURE_HOST) || (nPin == KSPIN_WAVE_SPDIF_RENDER_HOST)))) { if ( (pDataFormat->FormatSize == sizeof(KSDATAFORMAT_WAVEFORMATEX)) && (pwfx->cbSize == 0) && (pwfx->nChannels <= MAX_CHANNELS ) && (pwfx->wBitsPerSample >= MIN_BITS_PER_SAMPLE)&& (pwfx->wBitsPerSample <= MAX_BITS_PER_SAMPLE)&& (pwfx->nSamplesPerSec >= MIN_SAMPLE_RATE) && (pwfx->nSamplesPerSec <= MAX_SAMPLE_RATE) ) { ntStatus = STATUS_SUCCESS; } else { DPF(D_TERSE, ("Invalid format")); } } else { DPF(D_TERSE, ("Invalid format tag")); } } else { DPF(D_TERSE, ("Invalid pDataFormat->SubFormat!") ); } } return ntStatus; } // ValidateFormat
//============================================================================= 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(); ASSERT(Miniport_); ASSERT(DataFormat_); 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_pMiniport = Miniport_; m_ulPin = Pin_; m_fCapture = Capture_; m_usBlockAlign = pWfx->nBlockAlign; m_fFormat16Bit = (pWfx->wBitsPerSample == 16); m_ksState = KSSTATE_STOP; m_ulDmaPosition = 0; m_ullElapsedTimeCarryForward = 0; m_ulByteDisplacementCarryForward = 0; m_fDmaActive = FALSE; m_pDpc = NULL; m_pTimer = NULL; m_pvDmaBuffer = NULL; // If this is not the capture stream, create the output file. if (!m_fCapture) { if (NT_SUCCESS(ntStatus)) { ntStatus = m_SaveData.Initialize(); } } } // 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 (STATUS_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), MSVAD_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), MSVAD_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