mirror of
https://github.com/reactos/reactos.git
synced 2025-05-18 16:51:18 +00:00
[MMIXER]
- Add support for enumerating wave in/out devices. Based on the wdmaud driver code svn path=/trunk/; revision=44664
This commit is contained in:
parent
20608aeb5a
commit
f45bd7617a
7 changed files with 676 additions and 2 deletions
|
@ -827,6 +827,7 @@ MMixerInitializeFilter(
|
|||
ULONG BytesReturned;
|
||||
KSP_PIN Pin;
|
||||
LPWSTR Buffer = NULL;
|
||||
ULONG PinId;
|
||||
|
||||
// allocate a mixer info struct
|
||||
MixerInfo = (LPMIXER_INFO) MixerContext->Alloc(sizeof(MIXER_INFO));
|
||||
|
@ -864,10 +865,15 @@ MMixerInitializeFilter(
|
|||
// now get the target pins of the ADC / DAC node
|
||||
Status = MMixerGetTargetPins(MixerContext, NodeTypes, NodeConnections, NodeIndex, !bInputMixer, Pins, PinCount);
|
||||
|
||||
// find a target pin with a name
|
||||
PinId = PinCount +1;
|
||||
for(Index = 0; Index < PinCount; Index++)
|
||||
{
|
||||
if (Pins[Index])
|
||||
{
|
||||
// store index of pin
|
||||
PinId = Index;
|
||||
|
||||
/* retrieve pin name */
|
||||
Pin.PinId = Index;
|
||||
Pin.Reserved = 0;
|
||||
|
@ -900,6 +906,12 @@ MMixerInitializeFilter(
|
|||
}
|
||||
}
|
||||
|
||||
if (PinId < PinCount)
|
||||
{
|
||||
// create an wave info struct
|
||||
MMixerInitializeWaveInfo(MixerContext, MixerList, MixerData, MixerInfo->MixCaps.szPname, bInputMixer, PinId);
|
||||
}
|
||||
|
||||
Status = MMixerCreateDestinationLine(MixerContext, MixerInfo, bInputMixer, Buffer);
|
||||
|
||||
if (Buffer)
|
||||
|
|
|
@ -251,3 +251,27 @@ MMixerSetGetControlDetails(
|
|||
DPRINT("Status %x bSet %u NodeId %u Value %d PropertyId %u\n", Status, bSet, NodeId, Value, PropertyId);
|
||||
return Status;
|
||||
}
|
||||
|
||||
ULONG
|
||||
MMixerGetPinInstanceCount(
|
||||
PMIXER_CONTEXT MixerContext,
|
||||
HANDLE hFilter,
|
||||
ULONG PinId)
|
||||
{
|
||||
KSP_PIN PinRequest;
|
||||
KSPIN_CINSTANCES PinInstances;
|
||||
ULONG BytesReturned;
|
||||
MIXER_STATUS Status;
|
||||
|
||||
/* query the instance count */
|
||||
PinRequest.Reserved = 0;
|
||||
PinRequest.PinId = PinId;
|
||||
PinRequest.Property.Set = KSPROPSETID_Pin;
|
||||
PinRequest.Property.Flags = KSPROPERTY_TYPE_GET;
|
||||
PinRequest.Property.Id = KSPROPERTY_PIN_CINSTANCES;
|
||||
|
||||
Status = MixerContext->Control(hFilter, IOCTL_KS_PROPERTY, (PVOID)&PinRequest, sizeof(KSP_PIN), (PVOID)&PinInstances, sizeof(KSPIN_CINSTANCES), &BytesReturned);
|
||||
ASSERT(Status == MM_STATUS_SUCCESS);
|
||||
return PinInstances.CurrentCount;
|
||||
}
|
||||
|
||||
|
|
|
@ -215,7 +215,7 @@ MMixerGetLineControls(
|
|||
IN PMIXER_CONTEXT MixerContext,
|
||||
IN HANDLE MixerHandle,
|
||||
IN ULONG Flags,
|
||||
OUT LPMIXERLINECONTROLS MixerLineControls)
|
||||
OUT LPMIXERLINECONTROLSW MixerLineControls)
|
||||
{
|
||||
LPMIXER_INFO MixerInfo;
|
||||
LPMIXERLINE_EXT MixerLineSrc;
|
||||
|
@ -440,8 +440,13 @@ MMixerInitialize(
|
|||
//initialize mixer list
|
||||
MixerList->MixerListCount = 0;
|
||||
MixerList->MixerDataCount = 0;
|
||||
MixerList->WaveInListCount = 0;
|
||||
MixerList->WaveOutListCount = 0;
|
||||
InitializeListHead(&MixerList->MixerList);
|
||||
InitializeListHead(&MixerList->MixerData);
|
||||
InitializeListHead(&MixerList->WaveInList);
|
||||
InitializeListHead(&MixerList->WaveOutList);
|
||||
|
||||
|
||||
// store mixer list
|
||||
MixerContext->MixerContext = (PVOID)MixerList;
|
||||
|
|
|
@ -95,6 +95,15 @@ ULONG
|
|||
MMixerGetCount(
|
||||
IN PMIXER_CONTEXT MixerContext);
|
||||
|
||||
ULONG
|
||||
MMixerGetWaveInCount(
|
||||
IN PMIXER_CONTEXT MixerContext);
|
||||
|
||||
ULONG
|
||||
MMixerGetWaveOutCount(
|
||||
IN PMIXER_CONTEXT MixerContext);
|
||||
|
||||
|
||||
MIXER_STATUS
|
||||
MMixerGetCapabilities(
|
||||
IN PMIXER_CONTEXT MixerContext,
|
||||
|
@ -121,7 +130,7 @@ MMixerGetLineControls(
|
|||
IN PMIXER_CONTEXT MixerContext,
|
||||
IN HANDLE MixerHandle,
|
||||
IN ULONG Flags,
|
||||
OUT LPMIXERLINECONTROLS MixerLineControls);
|
||||
OUT LPMIXERLINECONTROLSW MixerLineControls);
|
||||
|
||||
MIXER_STATUS
|
||||
MMixerSetControlDetails(
|
||||
|
@ -137,4 +146,24 @@ MMixerGetControlDetails(
|
|||
IN ULONG Flags,
|
||||
OUT LPMIXERCONTROLDETAILS MixerControlDetails);
|
||||
|
||||
MIXER_STATUS
|
||||
MMixerWaveOutCapabilities(
|
||||
IN PMIXER_CONTEXT MixerContext,
|
||||
IN ULONG DeviceIndex,
|
||||
OUT LPWAVEOUTCAPSW Caps);
|
||||
|
||||
MIXER_STATUS
|
||||
MMixerWaveInCapabilities(
|
||||
IN PMIXER_CONTEXT MixerContext,
|
||||
IN ULONG DeviceIndex,
|
||||
OUT LPWAVEINCAPSW Caps);
|
||||
|
||||
MIXER_STATUS
|
||||
MMixerOpenWave(
|
||||
IN PMIXER_CONTEXT MixerContext,
|
||||
IN ULONG DeviceIndex,
|
||||
IN ULONG bWaveIn,
|
||||
IN LPWAVEFORMATEX WaveFormat,
|
||||
OUT PHANDLE PinHandle);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,4 +7,5 @@
|
|||
<file>filter.c</file>
|
||||
<file>mixer.c</file>
|
||||
<file>sup.c</file>
|
||||
<file>wave.c</file>
|
||||
</module>
|
||||
|
|
|
@ -64,12 +64,28 @@ typedef struct
|
|||
LPWSTR DeviceName;
|
||||
}MIXER_DATA, *LPMIXER_DATA;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
LIST_ENTRY Entry;
|
||||
ULONG DeviceId;
|
||||
ULONG PinId;
|
||||
union
|
||||
{
|
||||
WAVEOUTCAPSW OutCaps;
|
||||
WAVEINCAPSW InCaps;
|
||||
}u;
|
||||
}WAVE_INFO, *LPWAVE_INFO;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ULONG MixerListCount;
|
||||
LIST_ENTRY MixerList;
|
||||
ULONG MixerDataCount;
|
||||
LIST_ENTRY MixerData;
|
||||
ULONG WaveInListCount;
|
||||
LIST_ENTRY WaveInList;
|
||||
ULONG WaveOutListCount;
|
||||
LIST_ENTRY WaveOutList;
|
||||
}MIXER_LIST, *PMIXER_LIST;
|
||||
|
||||
#define DESTINATION_LINE 0xFFFF0000
|
||||
|
@ -243,4 +259,13 @@ MMixerGetDeviceName(
|
|||
IN LPMIXER_INFO MixerInfo,
|
||||
IN HANDLE hKey);
|
||||
|
||||
MIXER_STATUS
|
||||
MMixerInitializeWaveInfo(
|
||||
IN PMIXER_CONTEXT MixerContext,
|
||||
IN PMIXER_LIST MixerList,
|
||||
IN LPMIXER_DATA MixerData,
|
||||
IN LPWSTR DeviceName,
|
||||
IN ULONG bWaveIn,
|
||||
IN ULONG PinId);
|
||||
|
||||
#endif
|
||||
|
|
578
reactos/lib/drivers/sound/mmixer/wave.c
Normal file
578
reactos/lib/drivers/sound/mmixer/wave.c
Normal file
|
@ -0,0 +1,578 @@
|
|||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Kernel Streaming
|
||||
* FILE: lib/drivers/sound/mmixer/mmixer.c
|
||||
* PURPOSE: Mixer Handling Functions
|
||||
* PROGRAMMER: Johannes Anderwald
|
||||
*/
|
||||
|
||||
#include "priv.h"
|
||||
|
||||
const GUID KSDATAFORMAT_SPECIFIER_WAVEFORMATEX = {0x05589f81L, 0xc356, 0x11ce, {0xbf, 0x01, 0x00, 0xaa, 0x00, 0x55, 0x59, 0x5a}};
|
||||
const GUID KSDATAFORMAT_SUBTYPE_PCM = {0x00000001L, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
|
||||
const GUID KSDATAFORMAT_TYPE_AUDIO = {0x73647561L, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
|
||||
const GUID KSINTERFACESETID_Standard = {0x1A8766A0L, 0x62CE, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
|
||||
const GUID KSMEDIUMSETID_Standard = {0x4747B320L, 0x62CE, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ULONG SampleRate;
|
||||
ULONG Bit8Mono;
|
||||
ULONG Bit8Stereo;
|
||||
ULONG Bit16Mono;
|
||||
ULONG Bit16Stereo;
|
||||
}AUDIO_RANGE;
|
||||
|
||||
#define AUDIO_TEST_RANGE (5)
|
||||
|
||||
static AUDIO_RANGE TestRange[AUDIO_TEST_RANGE] =
|
||||
{
|
||||
{
|
||||
11025,
|
||||
WAVE_FORMAT_1M08,
|
||||
WAVE_FORMAT_1S08,
|
||||
WAVE_FORMAT_1M16,
|
||||
WAVE_FORMAT_1S16
|
||||
},
|
||||
{
|
||||
22050,
|
||||
WAVE_FORMAT_2M08,
|
||||
WAVE_FORMAT_2S08,
|
||||
WAVE_FORMAT_2M16,
|
||||
WAVE_FORMAT_2S16
|
||||
},
|
||||
{
|
||||
44100,
|
||||
WAVE_FORMAT_4M08,
|
||||
WAVE_FORMAT_4S08,
|
||||
WAVE_FORMAT_4M16,
|
||||
WAVE_FORMAT_4S16
|
||||
},
|
||||
{
|
||||
48000,
|
||||
WAVE_FORMAT_48M08,
|
||||
WAVE_FORMAT_48S08,
|
||||
WAVE_FORMAT_48M16,
|
||||
WAVE_FORMAT_48S16
|
||||
},
|
||||
{
|
||||
96000,
|
||||
WAVE_FORMAT_96M08,
|
||||
WAVE_FORMAT_96S08,
|
||||
WAVE_FORMAT_96M16,
|
||||
WAVE_FORMAT_96S16
|
||||
}
|
||||
};
|
||||
|
||||
PKSPIN_CONNECT
|
||||
MMixerAllocatePinConnect(
|
||||
IN PMIXER_CONTEXT MixerContext,
|
||||
ULONG DataFormatSize)
|
||||
{
|
||||
return MixerContext->Alloc(sizeof(KSPIN_CONNECT) + DataFormatSize);
|
||||
}
|
||||
|
||||
MIXER_STATUS
|
||||
MMixerGetWaveInfoByIndexAndType(
|
||||
IN PMIXER_LIST MixerList,
|
||||
IN ULONG DeviceIndex,
|
||||
IN ULONG bWaveInType,
|
||||
OUT LPWAVE_INFO *OutWaveInfo)
|
||||
{
|
||||
ULONG Index = 0;
|
||||
PLIST_ENTRY Entry, ListHead;
|
||||
LPWAVE_INFO WaveInfo;
|
||||
|
||||
if (bWaveInType)
|
||||
ListHead = &MixerList->WaveInList;
|
||||
else
|
||||
ListHead = &MixerList->WaveOutList;
|
||||
|
||||
/* get first entry */
|
||||
Entry = ListHead->Flink;
|
||||
|
||||
while(Entry != ListHead)
|
||||
{
|
||||
WaveInfo = (LPWAVE_INFO)CONTAINING_RECORD(Entry, WAVE_INFO, Entry);
|
||||
|
||||
if (Index == DeviceIndex)
|
||||
{
|
||||
*OutWaveInfo = WaveInfo;
|
||||
return MM_STATUS_SUCCESS;
|
||||
}
|
||||
Index++;
|
||||
Entry = Entry->Flink;
|
||||
}
|
||||
|
||||
return MM_STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
|
||||
VOID
|
||||
MMixerInitializePinConnect(
|
||||
IN OUT PKSPIN_CONNECT PinConnect,
|
||||
IN ULONG PinId)
|
||||
{
|
||||
PinConnect->Interface.Set = KSINTERFACESETID_Standard;
|
||||
PinConnect->Interface.Id = KSINTERFACE_STANDARD_STREAMING;
|
||||
PinConnect->Interface.Flags = 0;
|
||||
PinConnect->Medium.Set = KSMEDIUMSETID_Standard;
|
||||
PinConnect->Medium.Id = KSMEDIUM_TYPE_ANYINSTANCE;
|
||||
PinConnect->Medium.Flags = 0;
|
||||
PinConnect->PinToHandle = NULL;
|
||||
PinConnect->PinId = PinId;
|
||||
PinConnect->Priority.PriorityClass = KSPRIORITY_NORMAL;
|
||||
PinConnect->Priority.PrioritySubClass = 1;
|
||||
}
|
||||
|
||||
VOID
|
||||
MMixerInitializeDataFormat(
|
||||
IN PKSDATAFORMAT_WAVEFORMATEX DataFormat,
|
||||
LPWAVEFORMATEX WaveFormatEx)
|
||||
{
|
||||
|
||||
DataFormat->WaveFormatEx.wFormatTag = WaveFormatEx->wFormatTag;
|
||||
DataFormat->WaveFormatEx.nChannels = WaveFormatEx->nChannels;
|
||||
DataFormat->WaveFormatEx.nSamplesPerSec = WaveFormatEx->nSamplesPerSec;
|
||||
DataFormat->WaveFormatEx.nBlockAlign = WaveFormatEx->nBlockAlign;
|
||||
DataFormat->WaveFormatEx.nAvgBytesPerSec = WaveFormatEx->nAvgBytesPerSec;
|
||||
DataFormat->WaveFormatEx.wBitsPerSample = WaveFormatEx->wBitsPerSample;
|
||||
DataFormat->WaveFormatEx.cbSize = 0;
|
||||
DataFormat->DataFormat.FormatSize = sizeof(KSDATAFORMAT) + sizeof(WAVEFORMATEX);
|
||||
DataFormat->DataFormat.Flags = 0;
|
||||
DataFormat->DataFormat.Reserved = 0;
|
||||
DataFormat->DataFormat.MajorFormat = KSDATAFORMAT_TYPE_AUDIO;
|
||||
|
||||
DataFormat->DataFormat.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
|
||||
DataFormat->DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX;
|
||||
DataFormat->DataFormat.SampleSize = 4;
|
||||
}
|
||||
|
||||
|
||||
MIXER_STATUS
|
||||
MMixerGetAudioPinDataRanges(
|
||||
IN PMIXER_CONTEXT MixerContext,
|
||||
IN HANDLE hDevice,
|
||||
IN ULONG PinId,
|
||||
IN OUT PKSMULTIPLE_ITEM * OutMultipleItem)
|
||||
{
|
||||
KSP_PIN PinProperty;
|
||||
ULONG BytesReturned = 0;
|
||||
MIXER_STATUS Status;
|
||||
PKSMULTIPLE_ITEM MultipleItem;
|
||||
|
||||
/* retrieve size of data ranges buffer */
|
||||
PinProperty.Reserved = 0;
|
||||
PinProperty.PinId = PinId;
|
||||
PinProperty.Property.Set = KSPROPSETID_Pin;
|
||||
PinProperty.Property.Id = KSPROPERTY_PIN_DATARANGES;
|
||||
PinProperty.Property.Flags = KSPROPERTY_TYPE_GET;
|
||||
|
||||
Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&PinProperty, sizeof(KSP_PIN), (PVOID)NULL, 0, &BytesReturned);
|
||||
if (Status != MM_STATUS_MORE_ENTRIES)
|
||||
{
|
||||
return Status;
|
||||
}
|
||||
|
||||
MultipleItem = MixerContext->Alloc(BytesReturned);
|
||||
if (!MultipleItem)
|
||||
{
|
||||
/* not enough memory */
|
||||
return MM_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&PinProperty, sizeof(KSP_PIN), (PVOID)MultipleItem, BytesReturned, &BytesReturned);
|
||||
if (Status != MM_STATUS_SUCCESS)
|
||||
{
|
||||
/* failed */
|
||||
MixerContext->Free(MultipleItem);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* save result */
|
||||
*OutMultipleItem = MultipleItem;
|
||||
return Status;
|
||||
}
|
||||
|
||||
MIXER_STATUS
|
||||
MMixerFindAudioDataRange(
|
||||
PKSMULTIPLE_ITEM MultipleItem,
|
||||
PKSDATARANGE_AUDIO * OutDataRangeAudio)
|
||||
{
|
||||
ULONG Index;
|
||||
PKSDATARANGE_AUDIO DataRangeAudio;
|
||||
PKSDATARANGE DataRange;
|
||||
|
||||
DataRange = (PKSDATARANGE) (MultipleItem + 1);
|
||||
for(Index = 0; Index < MultipleItem->Count; Index++)
|
||||
{
|
||||
if (DataRange->FormatSize == sizeof(KSDATARANGE_AUDIO))
|
||||
{
|
||||
DataRangeAudio = (PKSDATARANGE_AUDIO)DataRange;
|
||||
if (IsEqualGUIDAligned(&DataRangeAudio->DataRange.MajorFormat, &KSDATAFORMAT_TYPE_AUDIO) &&
|
||||
IsEqualGUIDAligned(&DataRangeAudio->DataRange.SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) &&
|
||||
IsEqualGUIDAligned(&DataRangeAudio->DataRange.Specifier, &KSDATAFORMAT_SPECIFIER_WAVEFORMATEX))
|
||||
{
|
||||
DPRINT("Min Sample %u Max Sample %u Min Bits %u Max Bits %u Max Channel %u\n", DataRangeAudio->MinimumSampleFrequency, DataRangeAudio->MaximumSampleFrequency,
|
||||
DataRangeAudio->MinimumBitsPerSample, DataRangeAudio->MaximumBitsPerSample, DataRangeAudio->MaximumChannels);
|
||||
*OutDataRangeAudio = DataRangeAudio;
|
||||
return MM_STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
DataRange = (PKSDATARANGE)((ULONG_PTR)DataRange + DataRange->FormatSize);
|
||||
}
|
||||
return MM_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
MIXER_STATUS
|
||||
MMixerOpenWavePin(
|
||||
IN PMIXER_CONTEXT MixerContext,
|
||||
IN PMIXER_LIST MixerList,
|
||||
IN ULONG DeviceId,
|
||||
IN ULONG PinId,
|
||||
IN LPWAVEFORMATEX WaveFormatEx,
|
||||
IN ACCESS_MASK DesiredAccess,
|
||||
OUT PHANDLE PinHandle)
|
||||
{
|
||||
PKSPIN_CONNECT PinConnect;
|
||||
PKSDATAFORMAT_WAVEFORMATEX DataFormat;
|
||||
LPMIXER_DATA MixerData;
|
||||
NTSTATUS Status;
|
||||
|
||||
MixerData = MMixerGetDataByDeviceId(MixerList, DeviceId);
|
||||
if (!MixerData)
|
||||
return MM_STATUS_INVALID_PARAMETER;
|
||||
|
||||
/* allocate pin connect */
|
||||
PinConnect = MMixerAllocatePinConnect(MixerContext, sizeof(KSDATAFORMAT_WAVEFORMATEX));
|
||||
if (!PinConnect)
|
||||
{
|
||||
/* no memory */
|
||||
return MM_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
/* initialize pin connect struct */
|
||||
MMixerInitializePinConnect(PinConnect, PinId);
|
||||
|
||||
/* get offset to dataformat */
|
||||
DataFormat = (PKSDATAFORMAT_WAVEFORMATEX) (PinConnect + 1);
|
||||
/* initialize with requested wave format */
|
||||
MMixerInitializeDataFormat(DataFormat, WaveFormatEx);
|
||||
|
||||
/* now create the pin */
|
||||
Status = KsCreatePin(MixerData->hDevice, PinConnect, DesiredAccess, PinHandle);
|
||||
|
||||
/* free create info */
|
||||
MixerContext->Free(PinConnect);
|
||||
|
||||
if (Status == STATUS_SUCCESS)
|
||||
return MM_STATUS_SUCCESS;
|
||||
else
|
||||
return MM_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
VOID
|
||||
MMixerCheckFormat(
|
||||
IN PKSDATARANGE_AUDIO DataRangeAudio,
|
||||
IN LPWAVE_INFO WaveInfo,
|
||||
IN ULONG bInput)
|
||||
{
|
||||
ULONG Index, SampleFrequency;
|
||||
ULONG Result = 0;
|
||||
|
||||
for(Index = 0; Index < AUDIO_TEST_RANGE; Index++)
|
||||
{
|
||||
SampleFrequency = TestRange[Index].SampleRate;
|
||||
|
||||
if (DataRangeAudio->MinimumSampleFrequency <= SampleFrequency && DataRangeAudio->MaximumSampleFrequency >= SampleFrequency)
|
||||
{
|
||||
/* the audio adapter supports the sample frequency */
|
||||
if (DataRangeAudio->MinimumBitsPerSample <= 8 && DataRangeAudio->MaximumBitsPerSample >= 8)
|
||||
{
|
||||
Result |= TestRange[Index].Bit8Mono;
|
||||
|
||||
if (DataRangeAudio->MaximumChannels > 1)
|
||||
{
|
||||
/* check if pin supports the sample rate in 8-Bit Stereo */
|
||||
Result |= TestRange[Index].Bit8Stereo;
|
||||
}
|
||||
}
|
||||
|
||||
if (DataRangeAudio->MinimumBitsPerSample <= 16 && DataRangeAudio->MaximumBitsPerSample >= 16)
|
||||
{
|
||||
/* check if pin supports the sample rate in 16-Bit Mono */
|
||||
Result |= TestRange[Index].Bit16Mono;
|
||||
|
||||
|
||||
if (DataRangeAudio->MaximumChannels > 1)
|
||||
{
|
||||
/* check if pin supports the sample rate in 16-Bit Stereo */
|
||||
Result |= TestRange[Index].Bit16Stereo;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (bInput)
|
||||
WaveInfo->u.InCaps.dwFormats = Result;
|
||||
else
|
||||
WaveInfo->u.OutCaps.dwFormats = Result;
|
||||
|
||||
DPRINT("Format %lx bInput %u\n", Result, bInput);
|
||||
}
|
||||
|
||||
MIXER_STATUS
|
||||
MMixerInitializeWaveInfo(
|
||||
IN PMIXER_CONTEXT MixerContext,
|
||||
IN PMIXER_LIST MixerList,
|
||||
IN LPMIXER_DATA MixerData,
|
||||
IN LPWSTR DeviceName,
|
||||
IN ULONG bWaveIn,
|
||||
IN ULONG PinId)
|
||||
{
|
||||
MIXER_STATUS Status;
|
||||
PKSMULTIPLE_ITEM MultipleItem;
|
||||
PKSDATARANGE_AUDIO DataRangeAudio;
|
||||
LPWAVE_INFO WaveInfo;
|
||||
|
||||
WaveInfo = (LPWAVE_INFO)MixerContext->Alloc(sizeof(WAVE_INFO));
|
||||
if (!WaveInfo)
|
||||
return MM_STATUS_NO_MEMORY;
|
||||
|
||||
/* initialize wave info */
|
||||
WaveInfo->DeviceId = MixerData->DeviceId;
|
||||
WaveInfo->PinId = PinId;
|
||||
|
||||
/* FIXME determine manufacturer / product id */
|
||||
if (bWaveIn)
|
||||
{
|
||||
WaveInfo->u.InCaps.wMid = MM_MICROSOFT;
|
||||
WaveInfo->u.InCaps.wPid = MM_PID_UNMAPPED;
|
||||
WaveInfo->u.InCaps.vDriverVersion = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
WaveInfo->u.OutCaps.wMid = MM_MICROSOFT;
|
||||
WaveInfo->u.OutCaps.wPid = MM_PID_UNMAPPED;
|
||||
WaveInfo->u.OutCaps.vDriverVersion = 1;
|
||||
}
|
||||
|
||||
/* get audio pin data ranges */
|
||||
Status = MMixerGetAudioPinDataRanges(MixerContext, MixerData->hDevice, PinId, &MultipleItem);
|
||||
if (Status != MM_STATUS_SUCCESS)
|
||||
{
|
||||
/* failed to get audio pin data ranges */
|
||||
MixerContext->Free(WaveInfo);
|
||||
return MM_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
/* find an KSDATARANGE_AUDIO range */
|
||||
Status = MMixerFindAudioDataRange(MultipleItem, &DataRangeAudio);
|
||||
if (Status != MM_STATUS_SUCCESS)
|
||||
{
|
||||
/* failed to find audio pin data range */
|
||||
MixerContext->Free(MultipleItem);
|
||||
MixerContext->Free(WaveInfo);
|
||||
return MM_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
/* store channel count */
|
||||
if (bWaveIn)
|
||||
{
|
||||
WaveInfo->u.InCaps.wChannels = DataRangeAudio->MaximumChannels;
|
||||
}
|
||||
else
|
||||
{
|
||||
WaveInfo->u.OutCaps.wChannels = DataRangeAudio->MaximumChannels;
|
||||
}
|
||||
|
||||
/* get all supported formats */
|
||||
MMixerCheckFormat(DataRangeAudio, WaveInfo, bWaveIn);
|
||||
|
||||
/* free dataranges buffer */
|
||||
MixerContext->Free(MultipleItem);
|
||||
|
||||
|
||||
if (bWaveIn)
|
||||
{
|
||||
InsertTailList(&MixerList->WaveInList, &WaveInfo->Entry);
|
||||
MixerList->WaveInListCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
InsertTailList(&MixerList->WaveOutList, &WaveInfo->Entry);
|
||||
MixerList->WaveOutListCount++;
|
||||
}
|
||||
|
||||
return MM_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
MIXER_STATUS
|
||||
MMixerOpenWave(
|
||||
IN PMIXER_CONTEXT MixerContext,
|
||||
IN ULONG DeviceIndex,
|
||||
IN ULONG bWaveIn,
|
||||
IN LPWAVEFORMATEX WaveFormat,
|
||||
OUT PHANDLE PinHandle)
|
||||
{
|
||||
PMIXER_LIST MixerList;
|
||||
MIXER_STATUS Status;
|
||||
LPWAVE_INFO WaveInfo;
|
||||
ACCESS_MASK DesiredAccess = 0;
|
||||
|
||||
// verify mixer context
|
||||
Status = MMixerVerifyContext(MixerContext);
|
||||
|
||||
if (Status != MM_STATUS_SUCCESS)
|
||||
{
|
||||
// invalid context passed
|
||||
return Status;
|
||||
}
|
||||
|
||||
// grab mixer list
|
||||
MixerList = (PMIXER_LIST)MixerContext->MixerContext;
|
||||
|
||||
if (WaveFormat->wFormatTag != WAVE_FORMAT_PCM)
|
||||
{
|
||||
// not implemented
|
||||
return MM_STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/* find destination wave */
|
||||
Status = MMixerGetWaveInfoByIndexAndType(MixerList, DeviceIndex, bWaveIn, &WaveInfo);
|
||||
if (Status != MM_STATUS_SUCCESS)
|
||||
{
|
||||
/* failed to find wave info */
|
||||
return MM_STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
/* get desired access */
|
||||
if (bWaveIn)
|
||||
{
|
||||
DesiredAccess |= GENERIC_READ;
|
||||
}
|
||||
else
|
||||
{
|
||||
DesiredAccess |= GENERIC_WRITE;
|
||||
}
|
||||
|
||||
/* now try open the pin */
|
||||
return MMixerOpenWavePin(MixerContext, MixerList, WaveInfo->DeviceId, WaveInfo->PinId, WaveFormat, DesiredAccess, PinHandle);
|
||||
}
|
||||
|
||||
MIXER_STATUS
|
||||
MMixerWaveInCapabilities(
|
||||
IN PMIXER_CONTEXT MixerContext,
|
||||
IN ULONG DeviceIndex,
|
||||
OUT LPWAVEINCAPSW Caps)
|
||||
{
|
||||
PMIXER_LIST MixerList;
|
||||
MIXER_STATUS Status;
|
||||
LPWAVE_INFO WaveInfo;
|
||||
|
||||
// verify mixer context
|
||||
Status = MMixerVerifyContext(MixerContext);
|
||||
|
||||
if (Status != MM_STATUS_SUCCESS)
|
||||
{
|
||||
// invalid context passed
|
||||
return Status;
|
||||
}
|
||||
|
||||
// grab mixer list
|
||||
MixerList = (PMIXER_LIST)MixerContext->MixerContext;
|
||||
|
||||
/* find destination wave */
|
||||
Status = MMixerGetWaveInfoByIndexAndType(MixerList, DeviceIndex, TRUE, &WaveInfo);
|
||||
if (Status != MM_STATUS_SUCCESS)
|
||||
{
|
||||
/* failed to find wave info */
|
||||
return MM_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
//copy capabilities
|
||||
MixerContext->Copy(Caps, &WaveInfo->u.InCaps, sizeof(WAVEINCAPSW));
|
||||
|
||||
return MM_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
MIXER_STATUS
|
||||
MMixerWaveOutCapabilities(
|
||||
IN PMIXER_CONTEXT MixerContext,
|
||||
IN ULONG DeviceIndex,
|
||||
OUT LPWAVEOUTCAPSW Caps)
|
||||
{
|
||||
PMIXER_LIST MixerList;
|
||||
MIXER_STATUS Status;
|
||||
LPWAVE_INFO WaveInfo;
|
||||
|
||||
// verify mixer context
|
||||
Status = MMixerVerifyContext(MixerContext);
|
||||
|
||||
if (Status != MM_STATUS_SUCCESS)
|
||||
{
|
||||
// invalid context passed
|
||||
return Status;
|
||||
}
|
||||
|
||||
// grab mixer list
|
||||
MixerList = (PMIXER_LIST)MixerContext->MixerContext;
|
||||
|
||||
/* find destination wave */
|
||||
Status = MMixerGetWaveInfoByIndexAndType(MixerList, DeviceIndex, FALSE, &WaveInfo);
|
||||
if (Status != MM_STATUS_SUCCESS)
|
||||
{
|
||||
/* failed to find wave info */
|
||||
return MM_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
//copy capabilities
|
||||
MixerContext->Copy(Caps, &WaveInfo->u.OutCaps, sizeof(WAVEOUTCAPSW));
|
||||
|
||||
return MM_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ULONG
|
||||
MMixerGetWaveInCount(
|
||||
IN PMIXER_CONTEXT MixerContext)
|
||||
{
|
||||
PMIXER_LIST MixerList;
|
||||
MIXER_STATUS Status;
|
||||
|
||||
// verify mixer context
|
||||
Status = MMixerVerifyContext(MixerContext);
|
||||
|
||||
if (Status != MM_STATUS_SUCCESS)
|
||||
{
|
||||
// invalid context passed
|
||||
return 0;
|
||||
}
|
||||
|
||||
// grab mixer list
|
||||
MixerList = (PMIXER_LIST)MixerContext->MixerContext;
|
||||
|
||||
return MixerList->WaveInListCount;
|
||||
}
|
||||
|
||||
ULONG
|
||||
MMixerGetWaveOutCount(
|
||||
IN PMIXER_CONTEXT MixerContext)
|
||||
{
|
||||
PMIXER_LIST MixerList;
|
||||
MIXER_STATUS Status;
|
||||
|
||||
// verify mixer context
|
||||
Status = MMixerVerifyContext(MixerContext);
|
||||
|
||||
if (Status != MM_STATUS_SUCCESS)
|
||||
{
|
||||
// invalid context passed
|
||||
return 0;
|
||||
}
|
||||
|
||||
// grab mixer list
|
||||
MixerList = (PMIXER_LIST)MixerContext->MixerContext;
|
||||
|
||||
return MixerList->WaveOutListCount;
|
||||
}
|
Loading…
Reference in a new issue