В модуле midi _ pin реализованы все функции, которые обеспечивают работу с музыкальным пином на уровне ядра. В работе с музыкальным пином используются запросы на установку состояния пина и отправление пакетов с музыкальными данными.
NTSTATUS PinInit()
В этой функции происходит инициализация полей заголовка IRP-пакета и MIDI-данных, которые используются во время отправления музыкальных команд в пин. Далее в функциях PinMidiNoteOn и PinMidiNoteOff используется инициализированный заголовок.
Инициализация заголовка IRP-пакета происходит следующим образом:
typedef __declspec(align(16)) struct _MIDI_DATA
{KSMUSICFORMAT InstrumentFormat; // include <ksmedia.h>
union
{UCHAR InstrumentByte[4];
UCHAR NoteOffByte[4];};
KSMUSICFORMAT NoteFormat;
UCHAR NoteOnByte[4];
} MIDI_DATA, * PMIDI_DATA;
MIDI_DATA PinMidiData;
KSSTREAM_HEADER PinWriteHeader; // include <ks.h>
RtlZeroMemory(&PinWriteHeader, sizeof(PinWriteHeader));
// 12 байт
PinMidiData.InstrumentFormat.TimeDeltaMs = 0;
PinMidiData.InstrumentFormat.ByteCount = 3;
PinMidiData.InstrumentByte[0] = 0x00;
PinMidiData.InstrumentByte[1] = 0x00;
PinMidiData.InstrumentByte[2] = 0x00;
PinMidiData.InstrumentByte[3] = 0x00;
// ещё 12 байт
PinMidiData.NoteFormat.TimeDeltaMs = 0;
PinMidiData.NoteFormat.ByteCount = 3;
PinMidiData.NoteOnByte[0] = 0x00;
PinMidiData.NoteOnByte[1] = 0x00;
PinMidiData.NoteOnByte[2] = 0x00;
PinMidiData.NoteOnByte[3] = 0x00;
PinWriteHeader.Size = sizeof(PinWriteHeader);
PinWriteHeader.TypeSpecificFlags = 0;
PinWriteHeader.PresentationTime.Time = 0;
PinWriteHeader.PresentationTime.Numerator = 1;
PinWriteHeader.PresentationTime.Denominator = 1;
PinWriteHeader.Duration = 0;
PinWriteHeader.FrameExtent = 24; // всего 24 байта
PinWriteHeader.DataUsed = 24; // всего 24 байта
PinWriteHeader.Data = &PinMidiData;
NTSTATUS PinOpenStream(IN HANDLE UserPin)
Когда через запрос IOCTL_SHARE_PIN драйвер получает объект открытого пина, то необходимо вызвать эту функцию. В ней происходит вызов функции ObReferenceObjectByHandle для того, чтобы получить указатель на объект пина в режиме ядра и увеличить число ссылок на объект. Это делается для того, чтобы объект пина не был удалён из таблицы объектов ОС после заверешения работы пользовательского приложения, в котором был создан объект пина. Также здесь происходит установка флага, что пин открыт для драйвера.
UserPin – HANDLE того пина, который содержится в буфере IRP-пакета.
NTSTATUS PinIsOpenedStream()
Возвращает STATUS_SUCCESS если пин открыт.
NTSTATUS PinFree()
Здесь происходит вызов функции ObDereferenceObject, которая уменьшает число ссылок на объект пина.
NTSTATUS PinSetState(IN KSSTATE State)
Устанавливает состояние пина в State (KSSTATE_RUN, KSSTATE_PAUSE или KSSTATE_STOP). Перед тем, как воспроизводить ноты, необходимо установить состояние пина в KSSTATE_RUN. Функция работает только при IRQL = PASSIVE_LEVEL.
NTSTATUS PinWriteData(IN KSSTREAM_HEADER * Pheader)
Отправляет заголовок в открытый пин посредством IOCTL_KS_WRITE_STREAM.
Функция работает только при IRQL = PASSIVE_LEVEL.
NTSTATUS PinMidiNoteOn(IN UCHAR Channel,
IN UCHAR Instrument, IN UCHAR Note)
Если пин открыт, то отправляет команду на воспроизведение ноты Note с использованием инструмента Instrument в канале Channel.
Модификация инициализированного заголовка:
PinMidiData.InstrumentByte[0] = 0xC0 | Channel;
PinMidiData.InstrumentByte[1] = Instrument;
PinMidiData.NoteOnByte[0] = 0x90 | Channel;
PinMidiData.NoteOnByte[1] = Note;
PinMidiData.NoteOnByte[2] = 0x7F;
// 24 байта отправляем, т.к. в одном
PinWriteHeader.FrameExtent = 24; // пакете 2 команды: устанавливаем
PinWriteHeader.DataUsed = 24; // инструмент и отправляем ноту
PinWriteData(&PinWriteHeader);
Функция работает только при IRQL = PASSIVE_LEVEL.
NTSTATUS PinMidiNoteOff(IN UCHAR Channel, IN UCHAR Note)
Выключает ноту Note в канале Channel.
Модификация инициализированного заголовка:
PinMidiData.NoteOffByte[0] = 0x80 | Channel;
PinMidiData.NoteOffByte[1] = Note;
PinWriteHeader.FrameExtent = 12; // 12 байт шлём, т.к. в одном пакете
PinWriteHeader.DataUsed = 12; // 1 команда: выключаем ноту
PinWriteData(&PinWriteHeader);
Функция работает только при IRQL = PASSIVE_LEVEL.
Дата: 2019-12-22, просмотров: 266.