mirror of
https://github.com/reactos/reactos.git
synced 2024-11-04 22:00:55 +00:00
543 lines
14 KiB
C
543 lines
14 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS Kernel Streaming
|
|
* FILE: lib/drivers/sound/mmixer/midi.c
|
|
* PURPOSE: Midi Support Functions
|
|
* PROGRAMMER: Johannes Anderwald
|
|
*/
|
|
|
|
#include "precomp.h"
|
|
|
|
#define YDEBUG
|
|
#include <debug.h>
|
|
|
|
MIXER_STATUS
|
|
MMixerGetPinDataFlowAndCommunication(
|
|
IN PMIXER_CONTEXT MixerContext,
|
|
IN HANDLE hDevice,
|
|
IN ULONG PinId,
|
|
OUT PKSPIN_DATAFLOW DataFlow,
|
|
OUT PKSPIN_COMMUNICATION Communication)
|
|
{
|
|
KSP_PIN Pin;
|
|
ULONG BytesReturned;
|
|
MIXER_STATUS Status;
|
|
|
|
/* setup request */
|
|
Pin.PinId = PinId;
|
|
Pin.Reserved = 0;
|
|
Pin.Property.Flags = KSPROPERTY_TYPE_GET;
|
|
Pin.Property.Id = KSPROPERTY_PIN_DATAFLOW;
|
|
Pin.Property.Set = KSPROPSETID_Pin;
|
|
|
|
/* get pin dataflow */
|
|
Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)DataFlow, sizeof(KSPIN_DATAFLOW), &BytesReturned);
|
|
if (Status != MM_STATUS_SUCCESS)
|
|
{
|
|
/* failed to retrieve dataflow */
|
|
return Status;
|
|
}
|
|
|
|
/* setup communication request */
|
|
Pin.Property.Id = KSPROPERTY_PIN_COMMUNICATION;
|
|
|
|
/* get pin communication */
|
|
Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)Communication, sizeof(KSPIN_COMMUNICATION), &BytesReturned);
|
|
|
|
return Status;
|
|
}
|
|
|
|
MIXER_STATUS
|
|
MMixerAddMidiPin(
|
|
IN PMIXER_CONTEXT MixerContext,
|
|
IN PMIXER_LIST MixerList,
|
|
IN ULONG DeviceId,
|
|
IN ULONG PinId,
|
|
IN ULONG bInput,
|
|
IN LPWSTR DeviceName)
|
|
{
|
|
LPMIDI_INFO MidiInfo;
|
|
|
|
/* allocate midi info */
|
|
MidiInfo = MixerContext->Alloc(sizeof(MIDI_INFO));
|
|
|
|
if (!MidiInfo)
|
|
{
|
|
/* no memory */
|
|
return MM_STATUS_NO_MEMORY;
|
|
}
|
|
|
|
/* initialize midi info */
|
|
MidiInfo->DeviceId = DeviceId;
|
|
MidiInfo->PinId = PinId;
|
|
|
|
/* sanity check */
|
|
ASSERT(!DeviceName || (wcslen(DeviceName) + 1 < MAXPNAMELEN));
|
|
|
|
/* copy device name */
|
|
if (bInput && DeviceName)
|
|
{
|
|
wcscpy(MidiInfo->u.InCaps.szPname, DeviceName);
|
|
}
|
|
else if (!bInput && DeviceName)
|
|
{
|
|
wcscpy(MidiInfo->u.OutCaps.szPname, DeviceName);
|
|
}
|
|
|
|
/* FIXME determine manufacturer / product id */
|
|
if (bInput)
|
|
{
|
|
MidiInfo->u.InCaps.dwSupport = 0;
|
|
MidiInfo->u.InCaps.wMid = MM_MICROSOFT;
|
|
MidiInfo->u.InCaps.wPid = MM_PID_UNMAPPED;
|
|
MidiInfo->u.InCaps.vDriverVersion = 1;
|
|
}
|
|
else
|
|
{
|
|
MidiInfo->u.OutCaps.dwSupport = 0;
|
|
MidiInfo->u.OutCaps.wMid = MM_MICROSOFT;
|
|
MidiInfo->u.OutCaps.wPid = MM_PID_UNMAPPED;
|
|
MidiInfo->u.OutCaps.vDriverVersion = 1;
|
|
}
|
|
|
|
if (bInput)
|
|
{
|
|
/* insert into list */
|
|
InsertTailList(&MixerList->MidiInList, &MidiInfo->Entry);
|
|
MixerList->MidiInListCount++;
|
|
}
|
|
else
|
|
{
|
|
/* insert into list */
|
|
InsertTailList(&MixerList->MidiOutList, &MidiInfo->Entry);
|
|
MixerList->MidiOutListCount++;
|
|
}
|
|
|
|
return MM_STATUS_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
MMixerCheckFilterPinMidiSupport(
|
|
IN PMIXER_CONTEXT MixerContext,
|
|
IN PMIXER_LIST MixerList,
|
|
IN LPMIXER_DATA MixerData,
|
|
IN ULONG PinId,
|
|
IN PKSMULTIPLE_ITEM MultipleItem,
|
|
IN LPWSTR szPname)
|
|
{
|
|
ULONG Index;
|
|
PKSDATARANGE DataRange;
|
|
KSPIN_COMMUNICATION Communication;
|
|
KSPIN_DATAFLOW DataFlow;
|
|
|
|
/* get first datarange */
|
|
DataRange = (PKSDATARANGE)(MultipleItem + 1);
|
|
|
|
/* alignment assert */
|
|
ASSERT(((ULONG_PTR)DataRange & 0x7) == 0);
|
|
|
|
/* iterate through all data ranges */
|
|
for(Index = 0; Index < MultipleItem->Count; Index++)
|
|
{
|
|
if (IsEqualGUIDAligned(&DataRange->MajorFormat, &KSDATAFORMAT_TYPE_MUSIC) &&
|
|
IsEqualGUIDAligned(&DataRange->SubFormat, &KSDATAFORMAT_SUBTYPE_MIDI) &&
|
|
IsEqualGUIDAligned(&DataRange->Specifier, &KSDATAFORMAT_SPECIFIER_NONE))
|
|
{
|
|
/* pin supports midi datarange */
|
|
if (MMixerGetPinDataFlowAndCommunication(MixerContext, MixerData->hDevice, PinId, &DataFlow, &Communication) == MM_STATUS_SUCCESS)
|
|
{
|
|
if (DataFlow == KSPIN_DATAFLOW_IN && Communication == KSPIN_COMMUNICATION_SINK)
|
|
{
|
|
MMixerAddMidiPin(MixerContext, MixerList, MixerData->DeviceId, PinId, FALSE, szPname);
|
|
}
|
|
else if (DataFlow == KSPIN_DATAFLOW_OUT && Communication == KSPIN_COMMUNICATION_SOURCE)
|
|
{
|
|
MMixerAddMidiPin(MixerContext, MixerList, MixerData->DeviceId, PinId, TRUE, szPname);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* move to next datarange */
|
|
DataRange = (PKSDATARANGE)((ULONG_PTR)DataRange + DataRange->FormatSize);
|
|
|
|
/* alignment assert */
|
|
ASSERT(((ULONG_PTR)DataRange & 0x7) == 0);
|
|
|
|
/* data ranges are 64-bit aligned */
|
|
DataRange = (PVOID)(((ULONG_PTR)DataRange + 0x7) & ~0x7);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
MMixerInitializeMidiForFilter(
|
|
IN PMIXER_CONTEXT MixerContext,
|
|
IN PMIXER_LIST MixerList,
|
|
IN LPMIXER_DATA MixerData,
|
|
IN PTOPOLOGY Topology)
|
|
{
|
|
ULONG PinCount, Index;
|
|
MIXER_STATUS Status;
|
|
PKSMULTIPLE_ITEM MultipleItem;
|
|
WCHAR szPname[MAXPNAMELEN];
|
|
|
|
/* get filter pin count */
|
|
MMixerGetTopologyPinCount(Topology, &PinCount);
|
|
|
|
/* get mixer name */
|
|
if (MMixerGetDeviceName(MixerContext, szPname, MixerData->hDeviceInterfaceKey) != MM_STATUS_SUCCESS)
|
|
{
|
|
/* clear name */
|
|
szPname[0] = 0;
|
|
}
|
|
|
|
/* iterate all pins and check for KSDATARANGE_MUSIC support */
|
|
for(Index = 0; Index < PinCount; Index++)
|
|
{
|
|
/* get audio pin data ranges */
|
|
Status = MMixerGetAudioPinDataRanges(MixerContext, MixerData->hDevice, Index, &MultipleItem);
|
|
|
|
/* check for success */
|
|
if (Status == MM_STATUS_SUCCESS)
|
|
{
|
|
/* check if there is support KSDATARANGE_MUSIC */
|
|
MMixerCheckFilterPinMidiSupport(MixerContext, MixerList, MixerData, Index, MultipleItem, szPname);
|
|
}
|
|
}
|
|
}
|
|
|
|
MIXER_STATUS
|
|
MMixerOpenMidiPin(
|
|
IN PMIXER_CONTEXT MixerContext,
|
|
IN PMIXER_LIST MixerList,
|
|
IN ULONG DeviceId,
|
|
IN ULONG PinId,
|
|
IN ACCESS_MASK DesiredAccess,
|
|
IN PIN_CREATE_CALLBACK CreateCallback,
|
|
IN PVOID Context,
|
|
OUT PHANDLE PinHandle)
|
|
{
|
|
PKSPIN_CONNECT PinConnect;
|
|
PKSDATAFORMAT DataFormat;
|
|
LPMIXER_DATA MixerData;
|
|
NTSTATUS Status;
|
|
MIXER_STATUS MixerStatus;
|
|
|
|
MixerData = MMixerGetDataByDeviceId(MixerList, DeviceId);
|
|
if (!MixerData)
|
|
return MM_STATUS_INVALID_PARAMETER;
|
|
|
|
/* allocate pin connect */
|
|
PinConnect = MMixerAllocatePinConnect(MixerContext, sizeof(KSDATAFORMAT));
|
|
if (!PinConnect)
|
|
{
|
|
/* no memory */
|
|
return MM_STATUS_NO_MEMORY;
|
|
}
|
|
|
|
/* initialize pin connect struct */
|
|
MMixerInitializePinConnect(PinConnect, PinId);
|
|
|
|
/* get offset to dataformat */
|
|
DataFormat = (PKSDATAFORMAT) (PinConnect + 1);
|
|
|
|
/* initialize data format */
|
|
RtlMoveMemory(&DataFormat->MajorFormat, &KSDATAFORMAT_TYPE_MUSIC, sizeof(GUID));
|
|
RtlMoveMemory(&DataFormat->SubFormat, &KSDATAFORMAT_SUBTYPE_MIDI, sizeof(GUID));
|
|
RtlMoveMemory(&DataFormat->Specifier, &KSDATAFORMAT_SPECIFIER_NONE, sizeof(GUID));
|
|
|
|
if (CreateCallback)
|
|
{
|
|
/* let the callback handle the creation */
|
|
MixerStatus = CreateCallback(Context, DeviceId, PinId, MixerData->hDevice, PinConnect, DesiredAccess, PinHandle);
|
|
}
|
|
else
|
|
{
|
|
/* now create the pin */
|
|
Status = KsCreatePin(MixerData->hDevice, PinConnect, DesiredAccess, PinHandle);
|
|
|
|
/* normalize status */
|
|
if (Status == STATUS_SUCCESS)
|
|
MixerStatus = MM_STATUS_SUCCESS;
|
|
else
|
|
MixerStatus = MM_STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
/* free create info */
|
|
MixerContext->Free(PinConnect);
|
|
|
|
/* done */
|
|
return MixerStatus;
|
|
}
|
|
|
|
MIXER_STATUS
|
|
MMixerGetMidiInfoByIndexAndType(
|
|
IN PMIXER_LIST MixerList,
|
|
IN ULONG DeviceIndex,
|
|
IN ULONG bMidiInputType,
|
|
OUT LPMIDI_INFO *OutMidiInfo)
|
|
{
|
|
ULONG Index = 0;
|
|
PLIST_ENTRY Entry, ListHead;
|
|
LPMIDI_INFO MidiInfo;
|
|
|
|
if (bMidiInputType)
|
|
ListHead = &MixerList->MidiInList;
|
|
else
|
|
ListHead = &MixerList->MidiOutList;
|
|
|
|
/* get first entry */
|
|
Entry = ListHead->Flink;
|
|
|
|
while(Entry != ListHead)
|
|
{
|
|
MidiInfo = (LPMIDI_INFO)CONTAINING_RECORD(Entry, MIDI_INFO, Entry);
|
|
|
|
if (Index == DeviceIndex)
|
|
{
|
|
*OutMidiInfo = MidiInfo;
|
|
return MM_STATUS_SUCCESS;
|
|
}
|
|
Index++;
|
|
Entry = Entry->Flink;
|
|
}
|
|
|
|
return MM_STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
MIXER_STATUS
|
|
MMixerMidiOutCapabilities(
|
|
IN PMIXER_CONTEXT MixerContext,
|
|
IN ULONG DeviceIndex,
|
|
OUT LPMIDIOUTCAPSW Caps)
|
|
{
|
|
PMIXER_LIST MixerList;
|
|
MIXER_STATUS Status;
|
|
LPMIDI_INFO MidiInfo;
|
|
|
|
/* 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 midi */
|
|
Status = MMixerGetMidiInfoByIndexAndType(MixerList, DeviceIndex, FALSE, &MidiInfo);
|
|
if (Status != MM_STATUS_SUCCESS)
|
|
{
|
|
/* failed to find midi info */
|
|
return MM_STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
/* copy capabilities */
|
|
MixerContext->Copy(Caps, &MidiInfo->u.OutCaps, sizeof(MIDIOUTCAPSW));
|
|
|
|
return MM_STATUS_SUCCESS;
|
|
}
|
|
|
|
MIXER_STATUS
|
|
MMixerMidiInCapabilities(
|
|
IN PMIXER_CONTEXT MixerContext,
|
|
IN ULONG DeviceIndex,
|
|
OUT LPMIDIINCAPSW Caps)
|
|
{
|
|
PMIXER_LIST MixerList;
|
|
MIXER_STATUS Status;
|
|
LPMIDI_INFO MidiInfo;
|
|
|
|
/* 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 midi */
|
|
Status = MMixerGetMidiInfoByIndexAndType(MixerList, DeviceIndex, TRUE, &MidiInfo);
|
|
if (Status != MM_STATUS_SUCCESS)
|
|
{
|
|
/* failed to find midi info */
|
|
return MM_STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
/* copy capabilities */
|
|
MixerContext->Copy(Caps, &MidiInfo->u.InCaps, sizeof(MIDIINCAPSW));
|
|
|
|
return MM_STATUS_SUCCESS;
|
|
}
|
|
|
|
MIXER_STATUS
|
|
MMixerGetMidiDevicePath(
|
|
IN PMIXER_CONTEXT MixerContext,
|
|
IN ULONG bMidiIn,
|
|
IN ULONG DeviceId,
|
|
OUT LPWSTR * DevicePath)
|
|
{
|
|
PMIXER_LIST MixerList;
|
|
LPMIXER_DATA MixerData;
|
|
LPMIDI_INFO MidiInfo;
|
|
SIZE_T Length;
|
|
MIXER_STATUS Status;
|
|
|
|
/* 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 midi */
|
|
Status = MMixerGetMidiInfoByIndexAndType(MixerList, DeviceId, bMidiIn, &MidiInfo);
|
|
if (Status != MM_STATUS_SUCCESS)
|
|
{
|
|
/* failed to find midi info */
|
|
return MM_STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
/* get associated device id */
|
|
MixerData = MMixerGetDataByDeviceId(MixerList, MidiInfo->DeviceId);
|
|
if (!MixerData)
|
|
return MM_STATUS_INVALID_PARAMETER;
|
|
|
|
/* calculate length */
|
|
Length = wcslen(MixerData->DeviceName)+1;
|
|
|
|
/* allocate destination buffer */
|
|
*DevicePath = MixerContext->Alloc(Length * sizeof(WCHAR));
|
|
|
|
if (!*DevicePath)
|
|
{
|
|
/* no memory */
|
|
return MM_STATUS_NO_MEMORY;
|
|
}
|
|
|
|
/* copy device path */
|
|
MixerContext->Copy(*DevicePath, MixerData->DeviceName, Length * sizeof(WCHAR));
|
|
|
|
/* done */
|
|
return MM_STATUS_SUCCESS;
|
|
}
|
|
|
|
MIXER_STATUS
|
|
MMixerSetMidiStatus(
|
|
IN PMIXER_CONTEXT MixerContext,
|
|
IN HANDLE PinHandle,
|
|
IN KSSTATE State)
|
|
{
|
|
KSPROPERTY Property;
|
|
ULONG Length;
|
|
|
|
/* setup property request */
|
|
Property.Set = KSPROPSETID_Connection;
|
|
Property.Id = KSPROPERTY_CONNECTION_STATE;
|
|
Property.Flags = KSPROPERTY_TYPE_SET;
|
|
|
|
return MixerContext->Control(PinHandle, IOCTL_KS_PROPERTY, &Property, sizeof(KSPROPERTY), &State, sizeof(KSSTATE), &Length);
|
|
}
|
|
|
|
MIXER_STATUS
|
|
MMixerOpenMidi(
|
|
IN PMIXER_CONTEXT MixerContext,
|
|
IN ULONG DeviceIndex,
|
|
IN ULONG bMidiIn,
|
|
IN PIN_CREATE_CALLBACK CreateCallback,
|
|
IN PVOID Context,
|
|
OUT PHANDLE PinHandle)
|
|
{
|
|
PMIXER_LIST MixerList;
|
|
MIXER_STATUS Status;
|
|
LPMIDI_INFO MidiInfo;
|
|
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;
|
|
|
|
/* find destination midi */
|
|
Status = MMixerGetMidiInfoByIndexAndType(MixerList, DeviceIndex, bMidiIn, &MidiInfo);
|
|
if (Status != MM_STATUS_SUCCESS)
|
|
{
|
|
/* failed to find midi info */
|
|
return MM_STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
/* get desired access */
|
|
if (bMidiIn)
|
|
{
|
|
DesiredAccess |= GENERIC_READ;
|
|
}
|
|
else
|
|
{
|
|
DesiredAccess |= GENERIC_WRITE;
|
|
}
|
|
|
|
/* now try open the pin */
|
|
return MMixerOpenMidiPin(MixerContext, MixerList, MidiInfo->DeviceId, MidiInfo->PinId, DesiredAccess, CreateCallback, Context, PinHandle);
|
|
}
|
|
|
|
ULONG
|
|
MMixerGetMidiInCount(
|
|
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 Status;
|
|
}
|
|
|
|
/* grab mixer list */
|
|
MixerList = (PMIXER_LIST)MixerContext->MixerContext;
|
|
|
|
return MixerList->MidiInListCount;
|
|
}
|
|
|
|
ULONG
|
|
MMixerGetMidiOutCount(
|
|
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 Status;
|
|
}
|
|
|
|
/* grab mixer list */
|
|
MixerList = (PMIXER_LIST)MixerContext->MixerContext;
|
|
|
|
return MixerList->MidiOutListCount;
|
|
}
|