[idd] audio: support 32-bit and common channel layouts

Advertise signed and floating-point 32-bit formats across mono,
stereo, quad, surround, 5.1, and 7.1 at every supported rate.

Carry sample encoding through the broker and LGMP protocol so integer
and floating-point streams remain distinct.

Expand packet, shared-memory, and ring capacity for eight-channel
32-bit audio.
This commit is contained in:
Geoffrey McRae
2026-09-05 07:39:32 +10:00
parent 5681dcdbe7
commit efc9952e74
13 changed files with 444 additions and 170 deletions

View File

@@ -420,6 +420,20 @@ static bool validFormat(const KVMFRAudioFormat * wire,
return false; return false;
break; break;
case KVMFR_AUDIO_SAMPLE_S32_LE:
format = LG_AUDIO_FMT_S32_LE;
bytesPerSample = 4;
if (wire->validBits != 32 || wire->containerBits != 32)
return false;
break;
case KVMFR_AUDIO_SAMPLE_F32_LE:
format = LG_AUDIO_FMT_F32_LE;
bytesPerSample = 4;
if (wire->validBits != 32 || wire->containerBits != 32)
return false;
break;
default: default:
return false; return false;
} }

View File

@@ -51,7 +51,7 @@ enum
#define KVMFR_AUDIO_MAX_CHANNELS 18U #define KVMFR_AUDIO_MAX_CHANNELS 18U
#define KVMFR_AUDIO_MAX_SAMPLE_RATE 192000U #define KVMFR_AUDIO_MAX_SAMPLE_RATE 192000U
#define KVMFR_AUDIO_MAX_FRAMES_PER_PACKET 2048U #define KVMFR_AUDIO_MAX_FRAMES_PER_PACKET 2048U
#define KVMFR_AUDIO_MAX_BYTES_PER_SAMPLE 3U #define KVMFR_AUDIO_MAX_BYTES_PER_SAMPLE 4U
#define KVMFR_AUDIO_STREAM_MAX_CHANNELS 8U #define KVMFR_AUDIO_STREAM_MAX_CHANNELS 8U
#define KVMFR_AUDIO_STREAM_SLOT_COUNT 16U #define KVMFR_AUDIO_STREAM_SLOT_COUNT 16U
#define KVMFR_AUDIO_OWNER_LEASE_MS 1000U #define KVMFR_AUDIO_OWNER_LEASE_MS 1000U
@@ -75,6 +75,9 @@ enum
KVMFR_AUDIO_SAMPLE_S16_LE = 1, KVMFR_AUDIO_SAMPLE_S16_LE = 1,
/* Signed little-endian samples packed into exactly three bytes. */ /* Signed little-endian samples packed into exactly three bytes. */
KVMFR_AUDIO_SAMPLE_S24_LE = 2, KVMFR_AUDIO_SAMPLE_S24_LE = 2,
KVMFR_AUDIO_SAMPLE_S32_LE = 3,
/* IEEE 754 little-endian floating-point samples. */
KVMFR_AUDIO_SAMPLE_F32_LE = 4,
}; };
typedef uint32_t KVMFRAudioSampleFormat; typedef uint32_t KVMFRAudioSampleFormat;
@@ -83,6 +86,8 @@ enum
{ {
KVMFR_AUDIO_SAMPLE_MASK_S16_LE = 1U << 0, KVMFR_AUDIO_SAMPLE_MASK_S16_LE = 1U << 0,
KVMFR_AUDIO_SAMPLE_MASK_S24_LE = 1U << 1, KVMFR_AUDIO_SAMPLE_MASK_S24_LE = 1U << 1,
KVMFR_AUDIO_SAMPLE_MASK_S32_LE = 1U << 2,
KVMFR_AUDIO_SAMPLE_MASK_F32_LE = 1U << 3,
}; };
typedef uint32_t KVMFRAudioSampleFormatFlags; typedef uint32_t KVMFRAudioSampleFormatFlags;

View File

@@ -778,11 +778,39 @@ namespace
_In_ const LGAudioBrokerFormat &format, _In_ const LGAudioBrokerFormat &format,
_Out_opt_ FormatFingerprint *fingerprint) _Out_opt_ FormatFingerprint *fingerprint)
{ {
if (format.reserved)
return false;
SampleFormat sampleFormat = SampleFormat::Unknown;
switch (format.sampleFormat)
{
case LGAUDIO_BROKER_SAMPLE_S16_LE:
if (format.containerBits != 16 || format.validBits != 16)
return false;
sampleFormat = SampleFormat::S16LE;
break;
case LGAUDIO_BROKER_SAMPLE_S24_LE:
if (format.containerBits != 24 || format.validBits != 24)
return false;
sampleFormat = SampleFormat::S24LE;
break;
case LGAUDIO_BROKER_SAMPLE_S32_LE:
if (format.containerBits != 32 || format.validBits != 32)
return false;
sampleFormat = SampleFormat::S32LE;
break;
case LGAUDIO_BROKER_SAMPLE_F32_LE:
if (format.containerBits != 32 || format.validBits != 32)
return false;
sampleFormat = SampleFormat::F32LE;
break;
default:
return false;
}
if (!format.sampleRate || if (!format.sampleRate ||
format.sampleRate > kMaximumSampleRate || format.sampleRate > kMaximumSampleRate ||
!format.channels || format.channels > 8 || !format.channels || format.channels > 8 ||
(format.containerBits != 16 && format.containerBits != 24) ||
format.validBits != format.containerBits ||
format.blockAlign != format.blockAlign !=
format.channels * (format.containerBits / 8)) format.channels * (format.containerBits / 8))
{ {
@@ -791,6 +819,7 @@ namespace
if (fingerprint) if (fingerprint)
{ {
fingerprint->sampleFormat = sampleFormat;
fingerprint->sampleRate = format.sampleRate; fingerprint->sampleRate = format.sampleRate;
fingerprint->channelMask = format.channelMask; fingerprint->channelMask = format.channelMask;
fingerprint->channels = format.channels; fingerprint->channels = format.channels;
@@ -805,12 +834,31 @@ namespace
_In_ const FormatFingerprint &source, _In_ const FormatFingerprint &source,
_Out_ LGAudioBrokerFormat *destination) _Out_ LGAudioBrokerFormat *destination)
{ {
switch (source.sampleFormat)
{
case SampleFormat::S16LE:
destination->sampleFormat = LGAUDIO_BROKER_SAMPLE_S16_LE;
break;
case SampleFormat::S24LE:
destination->sampleFormat = LGAUDIO_BROKER_SAMPLE_S24_LE;
break;
case SampleFormat::S32LE:
destination->sampleFormat = LGAUDIO_BROKER_SAMPLE_S32_LE;
break;
case SampleFormat::F32LE:
destination->sampleFormat = LGAUDIO_BROKER_SAMPLE_F32_LE;
break;
default:
destination->sampleFormat = 0;
break;
}
destination->sampleRate = source.sampleRate; destination->sampleRate = source.sampleRate;
destination->channelMask = source.channelMask; destination->channelMask = source.channelMask;
destination->channels = source.channels; destination->channels = source.channels;
destination->containerBits = source.containerBits; destination->containerBits = source.containerBits;
destination->validBits = source.validBits; destination->validBits = source.validBits;
destination->blockAlign = source.blockAlign; destination->blockAlign = source.blockAlign;
destination->reserved = 0;
} }
UINT32 GetBrokerStreamState(_In_ KSSTATE state) UINT32 GetBrokerStreamState(_In_ KSSTATE state)

View File

@@ -27,13 +27,19 @@ namespace LGAudio
constexpr USHORT kExtensibleExtraSize = static_cast<USHORT>( constexpr USHORT kExtensibleExtraSize = static_cast<USHORT>(
sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)); sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX));
bool IsAudioPcmWaveFormat(_In_ const KSDATAFORMAT * format) bool IsSupportedSubFormat(_In_ const GUID & subFormat)
{
return
IsEqualGUIDAligned(subFormat, KSDATAFORMAT_SUBTYPE_PCM) ||
IsEqualGUIDAligned(subFormat, KSDATAFORMAT_SUBTYPE_IEEE_FLOAT);
}
bool IsAudioWaveFormat(_In_ const KSDATAFORMAT * format)
{ {
return return
IsEqualGUIDAligned(format->MajorFormat, IsEqualGUIDAligned(format->MajorFormat,
KSDATAFORMAT_TYPE_AUDIO) && KSDATAFORMAT_TYPE_AUDIO) &&
IsEqualGUIDAligned(format->SubFormat, IsSupportedSubFormat(format->SubFormat) &&
KSDATAFORMAT_SUBTYPE_PCM) &&
IsEqualGUIDAligned(format->Specifier, IsEqualGUIDAligned(format->Specifier,
KSDATAFORMAT_SPECIFIER_WAVEFORMATEX); KSDATAFORMAT_SPECIFIER_WAVEFORMATEX);
} }
@@ -80,23 +86,6 @@ namespace LGAudio
} }
} }
void GetDataRangeList(
_In_ EndpointKind endpoint,
_Outptr_result_buffer_(*count) KSDATARANGE_AUDIO ** ranges,
_Out_ PULONG count)
{
if (endpoint == EndpointKind::Render)
{
*ranges = g_renderDataRanges;
*count = kRenderFormatCount;
}
else
{
*ranges = g_captureDataRanges;
*count = kCaptureFormatCount;
}
}
bool AudioRangeContainsFormat( bool AudioRangeContainsFormat(
_In_ const KSDATARANGE_AUDIO & range, _In_ const KSDATARANGE_AUDIO & range,
_In_ const KSDATAFORMAT_WAVEFORMATEXTENSIBLE & format) _In_ const KSDATAFORMAT_WAVEFORMATEXTENSIBLE & format)
@@ -104,6 +93,8 @@ namespace LGAudio
const WAVEFORMATEX & wave = format.WaveFormatExt.Format; const WAVEFORMATEX & wave = format.WaveFormatExt.Format;
return return
IsEqualGUIDAligned(range.DataRange.SubFormat,
format.DataFormat.SubFormat) &&
range.MaximumChannels == wave.nChannels && range.MaximumChannels == wave.nChannels &&
range.MinimumBitsPerSample <= wave.wBitsPerSample && range.MinimumBitsPerSample <= wave.wBitsPerSample &&
range.MaximumBitsPerSample >= wave.wBitsPerSample && range.MaximumBitsPerSample >= wave.wBitsPerSample &&
@@ -118,16 +109,48 @@ namespace LGAudio
const WAVEFORMATEX & wave = format.WaveFormatExt.Format; const WAVEFORMATEX & wave = format.WaveFormatExt.Format;
return return
IsEqualGUIDAligned(range.DataRange.SubFormat,
format.DataFormat.SubFormat) &&
range.MaximumChannels == wave.nChannels && range.MaximumChannels == wave.nChannels &&
range.MinimumBitsPerSample == wave.wBitsPerSample && range.MinimumBitsPerSample == wave.wBitsPerSample &&
range.MaximumBitsPerSample == wave.wBitsPerSample && range.MaximumBitsPerSample == wave.wBitsPerSample &&
range.MinimumSampleFrequency == wave.nSamplesPerSec && range.MinimumSampleFrequency == wave.nSamplesPerSec &&
range.MaximumSampleFrequency == wave.nSamplesPerSec; range.MaximumSampleFrequency == wave.nSamplesPerSec;
} }
SampleFormat GetSampleFormat(
_In_ const WAVEFORMATEXTENSIBLE & wave)
{
if (IsEqualGUIDAligned(wave.SubFormat,
KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))
{
return wave.Format.wBitsPerSample == 32 &&
wave.Samples.wValidBitsPerSample == 32 ?
SampleFormat::F32LE : SampleFormat::Unknown;
}
if (!IsEqualGUIDAligned(wave.SubFormat,
KSDATAFORMAT_SUBTYPE_PCM) ||
wave.Format.wBitsPerSample !=
wave.Samples.wValidBitsPerSample)
return SampleFormat::Unknown;
switch (wave.Format.wBitsPerSample)
{
case 16:
return SampleFormat::S16LE;
case 24:
return SampleFormat::S24LE;
case 32:
return SampleFormat::S32LE;
default:
return SampleFormat::Unknown;
}
}
} }
#define LG_AUDIO_FORMAT( \ #define LG_AUDIO_FORMAT( \
sampleRate_, channels_, containerBits_, validBits_, mask_) \ sampleRate_, channels_, bits_, mask_, subType_) \
{ \ { \
{ \ { \
sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE), \ sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE), \
@@ -135,7 +158,7 @@ namespace LGAudio
0, \ 0, \
0, \ 0, \
STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), \ STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), \
STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM), \ STATICGUIDOF(KSDATAFORMAT_SUBTYPE_##subType_), \
STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) \ STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) \
}, \ }, \
{ \ { \
@@ -143,28 +166,56 @@ namespace LGAudio
WAVE_FORMAT_EXTENSIBLE, \ WAVE_FORMAT_EXTENSIBLE, \
channels_, \ channels_, \
sampleRate_, \ sampleRate_, \
sampleRate_ * channels_ * (containerBits_ / 8), \ sampleRate_ * channels_ * (bits_ / 8), \
channels_ * (containerBits_ / 8), \ channels_ * (bits_ / 8), \
containerBits_, \ bits_, \
kExtensibleExtraSize \ kExtensibleExtraSize \
}, \ }, \
validBits_, \ bits_, \
mask_, \ mask_, \
STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM) \ STATICGUIDOF(KSDATAFORMAT_SUBTYPE_##subType_) \
} \ } \
} }
#define LG_RENDER_LAYOUTS(sampleRate_, bits_, subType_) \
LG_AUDIO_FORMAT(sampleRate_, 2, bits_, KSAUDIO_SPEAKER_STEREO, \
subType_), \
LG_AUDIO_FORMAT(sampleRate_, 1, bits_, KSAUDIO_SPEAKER_MONO, \
subType_), \
LG_AUDIO_FORMAT(sampleRate_, 4, bits_, KSAUDIO_SPEAKER_QUAD, \
subType_), \
LG_AUDIO_FORMAT(sampleRate_, 4, bits_, KSAUDIO_SPEAKER_SURROUND, \
subType_), \
LG_AUDIO_FORMAT(sampleRate_, 6, bits_, \
KSAUDIO_SPEAKER_5POINT1_SURROUND, subType_), \
LG_AUDIO_FORMAT(sampleRate_, 8, bits_, \
KSAUDIO_SPEAKER_7POINT1_SURROUND, subType_)
#define LG_CAPTURE_LAYOUTS(sampleRate_, bits_, subType_) \
LG_AUDIO_FORMAT(sampleRate_, 1, bits_, KSAUDIO_SPEAKER_MONO, \
subType_), \
LG_AUDIO_FORMAT(sampleRate_, 2, bits_, KSAUDIO_SPEAKER_STEREO, \
subType_), \
LG_AUDIO_FORMAT(sampleRate_, 4, bits_, KSAUDIO_SPEAKER_QUAD, \
subType_), \
LG_AUDIO_FORMAT(sampleRate_, 4, bits_, KSAUDIO_SPEAKER_SURROUND, \
subType_), \
LG_AUDIO_FORMAT(sampleRate_, 6, bits_, \
KSAUDIO_SPEAKER_5POINT1_SURROUND, subType_), \
LG_AUDIO_FORMAT(sampleRate_, 8, bits_, \
KSAUDIO_SPEAKER_7POINT1_SURROUND, subType_)
#define LG_RENDER_FORMATS(sampleRate_) \ #define LG_RENDER_FORMATS(sampleRate_) \
LG_AUDIO_FORMAT(sampleRate_, 2, 16, 16, KSAUDIO_SPEAKER_STEREO), \ LG_RENDER_LAYOUTS(sampleRate_, 16, PCM), \
LG_AUDIO_FORMAT(sampleRate_, 2, 24, 24, KSAUDIO_SPEAKER_STEREO), \ LG_RENDER_LAYOUTS(sampleRate_, 24, PCM), \
LG_AUDIO_FORMAT(sampleRate_, 6, 24, 24, \ LG_RENDER_LAYOUTS(sampleRate_, 32, PCM), \
KSAUDIO_SPEAKER_5POINT1_SURROUND), \ LG_RENDER_LAYOUTS(sampleRate_, 32, IEEE_FLOAT)
LG_AUDIO_FORMAT(sampleRate_, 8, 24, 24, \
KSAUDIO_SPEAKER_7POINT1_SURROUND)
#define LG_CAPTURE_FORMATS(sampleRate_) \ #define LG_CAPTURE_FORMATS(sampleRate_) \
LG_AUDIO_FORMAT(sampleRate_, 1, 16, 16, KSAUDIO_SPEAKER_MONO), \ LG_CAPTURE_LAYOUTS(sampleRate_, 16, PCM), \
LG_RENDER_FORMATS(sampleRate_) LG_CAPTURE_LAYOUTS(sampleRate_, 24, PCM), \
LG_CAPTURE_LAYOUTS(sampleRate_, 32, PCM), \
LG_CAPTURE_LAYOUTS(sampleRate_, 32, IEEE_FLOAT)
KSDATAFORMAT_WAVEFORMATEXTENSIBLE KSDATAFORMAT_WAVEFORMATEXTENSIBLE
g_renderFormats[kRenderFormatCount] = g_renderFormats[kRenderFormatCount] =
@@ -190,9 +241,11 @@ namespace LGAudio
#undef LG_CAPTURE_FORMATS #undef LG_CAPTURE_FORMATS
#undef LG_RENDER_FORMATS #undef LG_RENDER_FORMATS
#undef LG_CAPTURE_LAYOUTS
#undef LG_RENDER_LAYOUTS
#undef LG_AUDIO_FORMAT #undef LG_AUDIO_FORMAT
#define LG_AUDIO_RANGE(sampleRate_, channels_, containerBits_) \ #define LG_AUDIO_RANGE(sampleRate_, channels_, bits_, subType_) \
{ \ { \
{ \ { \
sizeof(KSDATARANGE_AUDIO), \ sizeof(KSDATARANGE_AUDIO), \
@@ -200,27 +253,43 @@ namespace LGAudio
0, \ 0, \
0, \ 0, \
STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), \ STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), \
STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM), \ STATICGUIDOF(KSDATAFORMAT_SUBTYPE_##subType_), \
STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) \ STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) \
}, \ }, \
channels_, \ channels_, \
containerBits_, \ bits_, \
containerBits_, \ bits_, \
sampleRate_, \ sampleRate_, \
sampleRate_ \ sampleRate_ \
} }
#define LG_RENDER_LAYOUT_RANGES(sampleRate_, bits_, subType_) \
LG_AUDIO_RANGE(sampleRate_, 2, bits_, subType_), \
LG_AUDIO_RANGE(sampleRate_, 1, bits_, subType_), \
LG_AUDIO_RANGE(sampleRate_, 4, bits_, subType_), \
LG_AUDIO_RANGE(sampleRate_, 6, bits_, subType_), \
LG_AUDIO_RANGE(sampleRate_, 8, bits_, subType_)
#define LG_CAPTURE_LAYOUT_RANGES(sampleRate_, bits_, subType_) \
LG_AUDIO_RANGE(sampleRate_, 1, bits_, subType_), \
LG_AUDIO_RANGE(sampleRate_, 2, bits_, subType_), \
LG_AUDIO_RANGE(sampleRate_, 4, bits_, subType_), \
LG_AUDIO_RANGE(sampleRate_, 6, bits_, subType_), \
LG_AUDIO_RANGE(sampleRate_, 8, bits_, subType_)
#define LG_RENDER_RANGES(sampleRate_) \ #define LG_RENDER_RANGES(sampleRate_) \
LG_AUDIO_RANGE(sampleRate_, 2, 16), \ LG_RENDER_LAYOUT_RANGES(sampleRate_, 16, PCM), \
LG_AUDIO_RANGE(sampleRate_, 2, 24), \ LG_RENDER_LAYOUT_RANGES(sampleRate_, 24, PCM), \
LG_AUDIO_RANGE(sampleRate_, 6, 24), \ LG_RENDER_LAYOUT_RANGES(sampleRate_, 32, PCM), \
LG_AUDIO_RANGE(sampleRate_, 8, 24) LG_RENDER_LAYOUT_RANGES(sampleRate_, 32, IEEE_FLOAT)
#define LG_CAPTURE_RANGES(sampleRate_) \ #define LG_CAPTURE_RANGES(sampleRate_) \
LG_AUDIO_RANGE(sampleRate_, 1, 16), \ LG_CAPTURE_LAYOUT_RANGES(sampleRate_, 16, PCM), \
LG_RENDER_RANGES(sampleRate_) LG_CAPTURE_LAYOUT_RANGES(sampleRate_, 24, PCM), \
LG_CAPTURE_LAYOUT_RANGES(sampleRate_, 32, PCM), \
LG_CAPTURE_LAYOUT_RANGES(sampleRate_, 32, IEEE_FLOAT)
KSDATARANGE_AUDIO g_renderDataRanges[kRenderFormatCount] = KSDATARANGE_AUDIO g_renderDataRanges[kRenderDataRangeCount] =
{ {
LG_RENDER_RANGES(48000), LG_RENDER_RANGES(48000),
LG_RENDER_RANGES(44100), LG_RENDER_RANGES(44100),
@@ -230,7 +299,7 @@ namespace LGAudio
LG_RENDER_RANGES(192000) LG_RENDER_RANGES(192000)
}; };
KSDATARANGE_AUDIO g_captureDataRanges[kCaptureFormatCount] = KSDATARANGE_AUDIO g_captureDataRanges[kCaptureDataRangeCount] =
{ {
LG_CAPTURE_RANGES(48000), LG_CAPTURE_RANGES(48000),
LG_CAPTURE_RANGES(44100), LG_CAPTURE_RANGES(44100),
@@ -242,43 +311,45 @@ namespace LGAudio
#undef LG_CAPTURE_RANGES #undef LG_CAPTURE_RANGES
#undef LG_RENDER_RANGES #undef LG_RENDER_RANGES
#undef LG_CAPTURE_LAYOUT_RANGES
#undef LG_RENDER_LAYOUT_RANGES
#undef LG_AUDIO_RANGE #undef LG_AUDIO_RANGE
#define LG_RENDER_RANGE_POINTERS(base_) \ #define LG_RANGE_POINTERS_5(ranges_, base_) \
(PKSDATARANGE)&g_renderDataRanges[(base_)], \ (PKSDATARANGE)&ranges_[(base_)], \
(PKSDATARANGE)&g_renderDataRanges[(base_) + 1], \ (PKSDATARANGE)&ranges_[(base_) + 1], \
(PKSDATARANGE)&g_renderDataRanges[(base_) + 2], \ (PKSDATARANGE)&ranges_[(base_) + 2], \
(PKSDATARANGE)&g_renderDataRanges[(base_) + 3] (PKSDATARANGE)&ranges_[(base_) + 3], \
(PKSDATARANGE)&ranges_[(base_) + 4]
#define LG_CAPTURE_RANGE_POINTERS(base_) \ #define LG_RANGE_POINTERS(ranges_, base_) \
(PKSDATARANGE)&g_captureDataRanges[(base_)], \ LG_RANGE_POINTERS_5(ranges_, base_), \
(PKSDATARANGE)&g_captureDataRanges[(base_) + 1], \ LG_RANGE_POINTERS_5(ranges_, (base_) + 5), \
(PKSDATARANGE)&g_captureDataRanges[(base_) + 2], \ LG_RANGE_POINTERS_5(ranges_, (base_) + 10), \
(PKSDATARANGE)&g_captureDataRanges[(base_) + 3], \ LG_RANGE_POINTERS_5(ranges_, (base_) + 15)
(PKSDATARANGE)&g_captureDataRanges[(base_) + 4]
PKSDATARANGE g_renderDataRangePointers[kRenderFormatCount] = PKSDATARANGE g_renderDataRangePointers[kRenderDataRangeCount] =
{ {
LG_RENDER_RANGE_POINTERS(0), LG_RANGE_POINTERS(g_renderDataRanges, 0),
LG_RENDER_RANGE_POINTERS(4), LG_RANGE_POINTERS(g_renderDataRanges, 20),
LG_RENDER_RANGE_POINTERS(8), LG_RANGE_POINTERS(g_renderDataRanges, 40),
LG_RENDER_RANGE_POINTERS(12), LG_RANGE_POINTERS(g_renderDataRanges, 60),
LG_RENDER_RANGE_POINTERS(16), LG_RANGE_POINTERS(g_renderDataRanges, 80),
LG_RENDER_RANGE_POINTERS(20) LG_RANGE_POINTERS(g_renderDataRanges, 100)
}; };
PKSDATARANGE g_captureDataRangePointers[kCaptureFormatCount] = PKSDATARANGE g_captureDataRangePointers[kCaptureDataRangeCount] =
{ {
LG_CAPTURE_RANGE_POINTERS(0), LG_RANGE_POINTERS(g_captureDataRanges, 0),
LG_CAPTURE_RANGE_POINTERS(5), LG_RANGE_POINTERS(g_captureDataRanges, 20),
LG_CAPTURE_RANGE_POINTERS(10), LG_RANGE_POINTERS(g_captureDataRanges, 40),
LG_CAPTURE_RANGE_POINTERS(15), LG_RANGE_POINTERS(g_captureDataRanges, 60),
LG_CAPTURE_RANGE_POINTERS(20), LG_RANGE_POINTERS(g_captureDataRanges, 80),
LG_CAPTURE_RANGE_POINTERS(25) LG_RANGE_POINTERS(g_captureDataRanges, 100)
}; };
#undef LG_CAPTURE_RANGE_POINTERS #undef LG_RANGE_POINTERS
#undef LG_RENDER_RANGE_POINTERS #undef LG_RANGE_POINTERS_5
_IRQL_requires_max_(DISPATCH_LEVEL) _IRQL_requires_max_(DISPATCH_LEVEL)
NTSTATUS ValidateFormat( NTSTATUS ValidateFormat(
@@ -292,7 +363,7 @@ namespace LGAudio
if (!dataFormat || if (!dataFormat ||
dataFormat->FormatSize < sizeof(KSDATAFORMAT_WAVEFORMATEX) || dataFormat->FormatSize < sizeof(KSDATAFORMAT_WAVEFORMATEX) ||
!IsAudioPcmWaveFormat(dataFormat)) !IsAudioWaveFormat(dataFormat))
return STATUS_NO_MATCH; return STATUS_NO_MATCH;
const WAVEFORMATEX * requested = const WAVEFORMATEX * requested =
@@ -307,18 +378,29 @@ namespace LGAudio
const KSDATAFORMAT_WAVEFORMATEXTENSIBLE & candidate = formats[i]; const KSDATAFORMAT_WAVEFORMATEXTENSIBLE & candidate = formats[i];
const WAVEFORMATEXTENSIBLE & candidateWave = candidate.WaveFormatExt; const WAVEFORMATEXTENSIBLE & candidateWave = candidate.WaveFormatExt;
if (!WaveFormatCoreMatches(candidateWave.Format, *requested)) if (!IsEqualGUIDAligned(candidate.DataFormat.SubFormat,
dataFormat->SubFormat) ||
!WaveFormatCoreMatches(candidateWave.Format, *requested))
continue; continue;
if (requested->wFormatTag == WAVE_FORMAT_PCM) if (requested->wFormatTag == WAVE_FORMAT_PCM)
{ {
// A stand-alone WAVEFORMATEX is unambiguous only for these legacy if (!IsEqualGUIDAligned(candidateWave.SubFormat,
// mono/stereo, 16-bit formats. KSDATAFORMAT_SUBTYPE_PCM) ||
if (candidateWave.Format.wBitsPerSample != 16 || candidateWave.Format.wBitsPerSample != 16 ||
candidateWave.Samples.wValidBitsPerSample != 16 || candidateWave.Samples.wValidBitsPerSample != 16 ||
candidateWave.Format.nChannels > 2) candidateWave.Format.nChannels > 2)
continue; continue;
} }
else if (requested->wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
{
if (!IsEqualGUIDAligned(candidateWave.SubFormat,
KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) ||
candidateWave.Format.wBitsPerSample != 32 ||
candidateWave.Samples.wValidBitsPerSample != 32 ||
candidateWave.Format.nChannels > 2)
continue;
}
else if (requested->wFormatTag == WAVE_FORMAT_EXTENSIBLE) else if (requested->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
{ {
if (dataFormat->FormatSize < if (dataFormat->FormatSize <
@@ -328,7 +410,9 @@ namespace LGAudio
const WAVEFORMATEXTENSIBLE * requestedExtensible = const WAVEFORMATEXTENSIBLE * requestedExtensible =
reinterpret_cast<const WAVEFORMATEXTENSIBLE *>(requested); reinterpret_cast<const WAVEFORMATEXTENSIBLE *>(requested);
if (!ExtensibleFormatMatches(candidateWave, *requestedExtensible)) if (!IsEqualGUIDAligned(dataFormat->SubFormat,
requestedExtensible->SubFormat) ||
!ExtensibleFormatMatches(candidateWave, *requestedExtensible))
continue; continue;
} }
else else
@@ -359,8 +443,8 @@ namespace LGAudio
if (clientDataRange->FormatSize < sizeof(KSDATARANGE_AUDIO) || if (clientDataRange->FormatSize < sizeof(KSDATARANGE_AUDIO) ||
driverDataRange->FormatSize < sizeof(KSDATARANGE_AUDIO) || driverDataRange->FormatSize < sizeof(KSDATARANGE_AUDIO) ||
!IsAudioPcmWaveFormat(clientDataRange) || !IsAudioWaveFormat(clientDataRange) ||
!IsAudioPcmWaveFormat(driverDataRange)) !IsAudioWaveFormat(driverDataRange))
return STATUS_NO_MATCH; return STATUS_NO_MATCH;
const KSDATARANGE_AUDIO & client = const KSDATARANGE_AUDIO & client =
@@ -369,20 +453,13 @@ namespace LGAudio
*reinterpret_cast<const KSDATARANGE_AUDIO *>(driverDataRange); *reinterpret_cast<const KSDATARANGE_AUDIO *>(driverDataRange);
KSDATAFORMAT_WAVEFORMATEXTENSIBLE * formats; KSDATAFORMAT_WAVEFORMATEXTENSIBLE * formats;
KSDATARANGE_AUDIO * ranges;
ULONG formatCount; ULONG formatCount;
ULONG rangeCount;
GetFormatList(endpoint, &formats, &formatCount); GetFormatList(endpoint, &formats, &formatCount);
GetDataRangeList(endpoint, &ranges, &rangeCount);
if (formatCount != rangeCount)
return STATUS_INTERNAL_ERROR;
const KSDATAFORMAT_WAVEFORMATEXTENSIBLE * selected = nullptr; const KSDATAFORMAT_WAVEFORMATEXTENSIBLE * selected = nullptr;
for (ULONG i = 0; i < formatCount; ++i) for (ULONG i = 0; i < formatCount; ++i)
{ {
if (!DataRangeIdentifiesFormat(driver, formats[i]) || if (!DataRangeIdentifiesFormat(driver, formats[i]) ||
!DataRangeIdentifiesFormat(ranges[i], formats[i]) ||
!AudioRangeContainsFormat(client, formats[i])) !AudioRangeContainsFormat(client, formats[i]))
continue; continue;
@@ -417,6 +494,7 @@ namespace LGAudio
return STATUS_INVALID_PARAMETER; return STATUS_INVALID_PARAMETER;
const WAVEFORMATEXTENSIBLE & wave = dataFormat->WaveFormatExt; const WAVEFORMATEXTENSIBLE & wave = dataFormat->WaveFormatExt;
const SampleFormat sampleFormat = GetSampleFormat(wave);
if (wave.Format.wFormatTag != WAVE_FORMAT_EXTENSIBLE || if (wave.Format.wFormatTag != WAVE_FORMAT_EXTENSIBLE ||
wave.Format.cbSize < kExtensibleExtraSize || wave.Format.cbSize < kExtensibleExtraSize ||
wave.Format.nChannels == 0 || wave.Format.nChannels == 0 ||
@@ -425,11 +503,13 @@ namespace LGAudio
wave.Samples.wValidBitsPerSample == 0 || wave.Samples.wValidBitsPerSample == 0 ||
wave.Samples.wValidBitsPerSample > wave.Samples.wValidBitsPerSample >
wave.Format.wBitsPerSample || wave.Format.wBitsPerSample ||
!IsAudioPcmWaveFormat(&dataFormat->DataFormat) || !IsAudioWaveFormat(&dataFormat->DataFormat) ||
!IsEqualGUIDAligned(wave.SubFormat, !IsEqualGUIDAligned(dataFormat->DataFormat.SubFormat,
KSDATAFORMAT_SUBTYPE_PCM)) wave.SubFormat) ||
sampleFormat == SampleFormat::Unknown)
return STATUS_INVALID_PARAMETER; return STATUS_INVALID_PARAMETER;
fingerprint->sampleFormat = sampleFormat;
fingerprint->sampleRate = wave.Format.nSamplesPerSec; fingerprint->sampleRate = wave.Format.nSamplesPerSec;
fingerprint->channelMask = wave.dwChannelMask; fingerprint->channelMask = wave.dwChannelMask;
fingerprint->channels = wave.Format.nChannels; fingerprint->channels = wave.Format.nChannels;
@@ -445,6 +525,7 @@ namespace LGAudio
_In_ const FormatFingerprint & right) _In_ const FormatFingerprint & right)
{ {
return return
left.sampleFormat == right.sampleFormat &&
left.sampleRate == right.sampleRate && left.sampleRate == right.sampleRate &&
left.channelMask == right.channelMask && left.channelMask == right.channelMask &&
left.channels == right.channels && left.channels == right.channels &&

View File

@@ -26,6 +26,15 @@
namespace LGAudio namespace LGAudio
{ {
enum class SampleFormat : ULONG
{
Unknown = 0,
S16LE = 1,
S24LE = 2,
S32LE = 3,
F32LE = 4
};
enum class EndpointKind : UCHAR enum class EndpointKind : UCHAR
{ {
Render, Render,
@@ -34,6 +43,7 @@ namespace LGAudio
struct FormatFingerprint struct FormatFingerprint
{ {
SampleFormat sampleFormat;
ULONG sampleRate; ULONG sampleRate;
ULONG channelMask; ULONG channelMask;
USHORT channels; USHORT channels;
@@ -44,15 +54,21 @@ namespace LGAudio
constexpr ULONG kSampleRate = 48000; constexpr ULONG kSampleRate = 48000;
constexpr ULONG kSampleRateCount = 6; constexpr ULONG kSampleRateCount = 6;
constexpr ULONG kRenderFormatsPerRate = 4; constexpr ULONG kRenderFormatsPerRate = 24;
constexpr ULONG kCaptureFormatsPerRate = 5; constexpr ULONG kCaptureFormatsPerRate = 24;
constexpr ULONG kRenderDataRangesPerRate = 20;
constexpr ULONG kCaptureDataRangesPerRate = 20;
constexpr ULONG kRenderFormatCount = constexpr ULONG kRenderFormatCount =
kSampleRateCount * kRenderFormatsPerRate; kSampleRateCount * kRenderFormatsPerRate;
constexpr ULONG kCaptureFormatCount = constexpr ULONG kCaptureFormatCount =
kSampleRateCount * kCaptureFormatsPerRate; kSampleRateCount * kCaptureFormatsPerRate;
constexpr ULONG kRenderDataRangeCount =
kSampleRateCount * kRenderDataRangesPerRate;
constexpr ULONG kCaptureDataRangeCount =
kSampleRateCount * kCaptureDataRangesPerRate;
constexpr ULONG kMaximumSampleRate = 192000; constexpr ULONG kMaximumSampleRate = 192000;
constexpr ULONG kMaximumBlockAlign = constexpr ULONG kMaximumBlockAlign =
8 * 3; 8 * 4;
constexpr ULONG kMaximumBytesPerSecond = constexpr ULONG kMaximumBytesPerSecond =
kMaximumSampleRate * kMaximumBlockAlign; kMaximumSampleRate * kMaximumBlockAlign;
@@ -61,11 +77,11 @@ namespace LGAudio
extern KSDATAFORMAT_WAVEFORMATEXTENSIBLE extern KSDATAFORMAT_WAVEFORMATEXTENSIBLE
g_captureFormats[kCaptureFormatCount]; g_captureFormats[kCaptureFormatCount];
extern KSDATARANGE_AUDIO g_renderDataRanges[kRenderFormatCount]; extern KSDATARANGE_AUDIO g_renderDataRanges[kRenderDataRangeCount];
extern KSDATARANGE_AUDIO g_captureDataRanges[kCaptureFormatCount]; extern KSDATARANGE_AUDIO g_captureDataRanges[kCaptureDataRangeCount];
extern PKSDATARANGE g_renderDataRangePointers[kRenderFormatCount]; extern PKSDATARANGE g_renderDataRangePointers[kRenderDataRangeCount];
extern PKSDATARANGE g_captureDataRangePointers[kCaptureFormatCount]; extern PKSDATARANGE g_captureDataRangePointers[kCaptureDataRangeCount];
/** /**
* Validate an instantiated WaveRT format against the endpoint's exact * Validate an instantiated WaveRT format against the endpoint's exact
@@ -106,6 +122,7 @@ namespace LGAudio
// The rest of the driver uses these as its shared, unqualified audio types. // The rest of the driver uses these as its shared, unqualified audio types.
using LGAudio::EndpointKind; using LGAudio::EndpointKind;
using LGAudio::FormatFingerprint; using LGAudio::FormatFingerprint;
using LGAudio::SampleFormat;
using LGAudio::EqualFormatFingerprint; using LGAudio::EqualFormatFingerprint;
using LGAudio::GetFormatFingerprint; using LGAudio::GetFormatFingerprint;
using LGAudio::SelectFormatIntersection; using LGAudio::SelectFormatIntersection;
@@ -117,9 +134,11 @@ using LGAudio::g_renderDataRangePointers;
using LGAudio::g_renderDataRanges; using LGAudio::g_renderDataRanges;
using LGAudio::g_renderFormats; using LGAudio::g_renderFormats;
using LGAudio::kCaptureFormatCount; using LGAudio::kCaptureFormatCount;
using LGAudio::kCaptureDataRangeCount;
using LGAudio::kMaximumBlockAlign; using LGAudio::kMaximumBlockAlign;
using LGAudio::kMaximumBytesPerSecond; using LGAudio::kMaximumBytesPerSecond;
using LGAudio::kMaximumSampleRate; using LGAudio::kMaximumSampleRate;
using LGAudio::kRenderFormatCount; using LGAudio::kRenderFormatCount;
using LGAudio::kRenderDataRangeCount;
using LGAudio::kSampleRate; using LGAudio::kSampleRate;
using LGAudio::kSampleRateCount; using LGAudio::kSampleRateCount;

View File

@@ -46,7 +46,7 @@ PCPIN_DESCRIPTOR g_RenderWavePins[] =
{ {
0, nullptr, 0, nullptr,
0, nullptr, 0, nullptr,
kRenderFormatCount, g_renderDataRangePointers, kRenderDataRangeCount, g_renderDataRangePointers,
KSPIN_DATAFLOW_IN, KSPIN_DATAFLOW_IN,
KSPIN_COMMUNICATION_SINK, KSPIN_COMMUNICATION_SINK,
&KSCATEGORY_AUDIO, &KSCATEGORY_AUDIO,
@@ -115,7 +115,7 @@ PCPIN_DESCRIPTOR g_CaptureWavePins[] =
{ {
0, nullptr, 0, nullptr,
0, nullptr, 0, nullptr,
kCaptureFormatCount, g_captureDataRangePointers, kCaptureDataRangeCount, g_captureDataRangePointers,
KSPIN_DATAFLOW_OUT, KSPIN_DATAFLOW_OUT,
KSPIN_COMMUNICATION_SINK, KSPIN_COMMUNICATION_SINK,
&KSCATEGORY_AUDIO, &KSCATEGORY_AUDIO,
@@ -284,8 +284,8 @@ NTSTATUS CMiniportWaveRT::NewStream(
if (InterlockedCompareExchange(&m_streamOpen, 1, 0) != 0) if (InterlockedCompareExchange(&m_streamOpen, 1, 0) != 0)
return STATUS_DEVICE_BUSY; return STATUS_DEVICE_BUSY;
CMiniportWaveRTStream *newStream = CWS *newStream =
new(NonPagedPoolNx, LGAUDIO_POOL_TAG) CMiniportWaveRTStream( new(NonPagedPoolNx, LGAUDIO_POOL_TAG) CWS(
this, m_adapter, portStream, m_kind); this, m_adapter, portStream, m_kind);
if (!newStream) if (!newStream)
{ {

View File

@@ -129,7 +129,7 @@ ULONGLONG FramesToQpcTicks(
} }
} }
CMiniportWaveRTStream::CMiniportWaveRTStream( CWS::CWS(
_In_ CMiniportWaveRT *miniport, _In_ CMiniportWaveRT *miniport,
_In_ CAudioAdapter *adapter, _In_ CAudioAdapter *adapter,
_In_ PPORTWAVERTSTREAM portStream, _In_ PPORTWAVERTSTREAM portStream,
@@ -177,7 +177,7 @@ CMiniportWaveRTStream::CMiniportWaveRTStream(
KeInitializeSpinLock(&m_positionLock); KeInitializeSpinLock(&m_positionLock);
} }
CMiniportWaveRTStream::~CMiniportWaveRTStream() CWS::~CWS()
{ {
SetState(KSSTATE_STOP); SetState(KSSTATE_STOP);
@@ -195,7 +195,7 @@ CMiniportWaveRTStream::~CMiniportWaveRTStream()
m_miniport->Release(); m_miniport->Release();
} }
NTSTATUS CMiniportWaveRTStream::Initialize( NTSTATUS CWS::Initialize(
_In_ const KSDATAFORMAT_WAVEFORMATEXTENSIBLE *format) _In_ const KSDATAFORMAT_WAVEFORMATEXTENSIBLE *format)
{ {
if (!format) if (!format)
@@ -221,7 +221,7 @@ NTSTATUS CMiniportWaveRTStream::Initialize(
return status; return status;
} }
NTSTATUS CMiniportWaveRTStream::QueryInterface( NTSTATUS CWS::QueryInterface(
_In_ REFIID interfaceId, _In_ REFIID interfaceId,
_COM_Outptr_ void **object) _COM_Outptr_ void **object)
{ {
@@ -254,12 +254,12 @@ NTSTATUS CMiniportWaveRTStream::QueryInterface(
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
ULONG CMiniportWaveRTStream::AddRef() ULONG CWS::AddRef()
{ {
return static_cast<ULONG>(InterlockedIncrement(&m_refCount)); return static_cast<ULONG>(InterlockedIncrement(&m_refCount));
} }
ULONG CMiniportWaveRTStream::Release() ULONG CWS::Release()
{ {
const LONG count = InterlockedDecrement(&m_refCount); const LONG count = InterlockedDecrement(&m_refCount);
if (!count) if (!count)
@@ -267,7 +267,7 @@ ULONG CMiniportWaveRTStream::Release()
return static_cast<ULONG>(count); return static_cast<ULONG>(count);
} }
NTSTATUS CMiniportWaveRTStream::SetFormat( NTSTATUS CWS::SetFormat(
_In_ PKSDATAFORMAT dataFormat) _In_ PKSDATAFORMAT dataFormat)
{ {
if (!dataFormat) if (!dataFormat)
@@ -301,7 +301,7 @@ NTSTATUS CMiniportWaveRTStream::SetFormat(
return status; return status;
} }
NTSTATUS CMiniportWaveRTStream::SetState(_In_ KSSTATE state) NTSTATUS CWS::SetState(_In_ KSSTATE state)
{ {
if (state < KSSTATE_STOP || state > KSSTATE_RUN) if (state < KSSTATE_STOP || state > KSSTATE_RUN)
return STATUS_INVALID_PARAMETER; return STATUS_INVALID_PARAMETER;
@@ -394,7 +394,7 @@ NTSTATUS CMiniportWaveRTStream::SetState(_In_ KSSTATE state)
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
NTSTATUS CMiniportWaveRTStream::GetPosition( NTSTATUS CWS::GetPosition(
_Out_ PKSAUDIO_POSITION position) _Out_ PKSAUDIO_POSITION position)
{ {
if (!position) if (!position)
@@ -418,7 +418,7 @@ NTSTATUS CMiniportWaveRTStream::GetPosition(
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
NTSTATUS CMiniportWaveRTStream::AllocateAudioBuffer( NTSTATUS CWS::AllocateAudioBuffer(
_In_ ULONG requestedSize, _In_ ULONG requestedSize,
_Out_ PMDL *audioBufferMdl, _Out_ PMDL *audioBufferMdl,
_Out_ ULONG *actualSize, _Out_ ULONG *actualSize,
@@ -429,7 +429,7 @@ NTSTATUS CMiniportWaveRTStream::AllocateAudioBuffer(
offsetFromFirstPage, cacheType); offsetFromFirstPage, cacheType);
} }
void CMiniportWaveRTStream::FreeAudioBuffer( void CWS::FreeAudioBuffer(
_In_opt_ PMDL audioBufferMdl, _In_opt_ PMDL audioBufferMdl,
_In_ ULONG bufferSize) _In_ ULONG bufferSize)
{ {
@@ -437,14 +437,14 @@ void CMiniportWaveRTStream::FreeAudioBuffer(
FreeBuffer(audioBufferMdl); FreeBuffer(audioBufferMdl);
} }
void CMiniportWaveRTStream::GetHWLatency( void CWS::GetHWLatency(
_Out_ PKSRTAUDIO_HWLATENCY latency) _Out_ PKSRTAUDIO_HWLATENCY latency)
{ {
if (latency) if (latency)
RtlZeroMemory(latency, sizeof(*latency)); RtlZeroMemory(latency, sizeof(*latency));
} }
NTSTATUS CMiniportWaveRTStream::GetPositionRegister( NTSTATUS CWS::GetPositionRegister(
_Out_ PKSRTAUDIO_HWREGISTER positionRegister) _Out_ PKSRTAUDIO_HWREGISTER positionRegister)
{ {
if (positionRegister) if (positionRegister)
@@ -452,7 +452,7 @@ NTSTATUS CMiniportWaveRTStream::GetPositionRegister(
return STATUS_NOT_IMPLEMENTED; return STATUS_NOT_IMPLEMENTED;
} }
NTSTATUS CMiniportWaveRTStream::GetClockRegister( NTSTATUS CWS::GetClockRegister(
_Out_ PKSRTAUDIO_HWREGISTER clockRegister) _Out_ PKSRTAUDIO_HWREGISTER clockRegister)
{ {
if (clockRegister) if (clockRegister)
@@ -460,7 +460,7 @@ NTSTATUS CMiniportWaveRTStream::GetClockRegister(
return STATUS_NOT_IMPLEMENTED; return STATUS_NOT_IMPLEMENTED;
} }
NTSTATUS CMiniportWaveRTStream::AllocateBufferWithNotification( NTSTATUS CWS::AllocateBufferWithNotification(
_In_ ULONG notificationCount, _In_ ULONG notificationCount,
_In_ ULONG requestedSize, _In_ ULONG requestedSize,
_Out_ PMDL *audioBufferMdl, _Out_ PMDL *audioBufferMdl,
@@ -475,7 +475,7 @@ NTSTATUS CMiniportWaveRTStream::AllocateBufferWithNotification(
actualSize, offsetFromFirstPage, cacheType); actualSize, offsetFromFirstPage, cacheType);
} }
void CMiniportWaveRTStream::FreeBufferWithNotification( void CWS::FreeBufferWithNotification(
_In_ PMDL audioBufferMdl, _In_ PMDL audioBufferMdl,
_In_ ULONG bufferSize) _In_ ULONG bufferSize)
{ {
@@ -483,7 +483,7 @@ void CMiniportWaveRTStream::FreeBufferWithNotification(
FreeBuffer(audioBufferMdl); FreeBuffer(audioBufferMdl);
} }
NTSTATUS CMiniportWaveRTStream::RegisterNotificationEvent( NTSTATUS CWS::RegisterNotificationEvent(
_In_ PKEVENT notificationEvent) _In_ PKEVENT notificationEvent)
{ {
if (!notificationEvent) if (!notificationEvent)
@@ -511,7 +511,7 @@ NTSTATUS CMiniportWaveRTStream::RegisterNotificationEvent(
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
NTSTATUS CMiniportWaveRTStream::UnregisterNotificationEvent( NTSTATUS CWS::UnregisterNotificationEvent(
_In_ PKEVENT notificationEvent) _In_ PKEVENT notificationEvent)
{ {
if (!notificationEvent) if (!notificationEvent)
@@ -535,7 +535,7 @@ NTSTATUS CMiniportWaveRTStream::UnregisterNotificationEvent(
return STATUS_NOT_FOUND; return STATUS_NOT_FOUND;
} }
NTSTATUS CMiniportWaveRTStream::GetReadPacket( NTSTATUS CWS::GetReadPacket(
_Out_ ULONG *packetNumber, _Out_ ULONG *packetNumber,
_Out_ DWORD *flags, _Out_ DWORD *flags,
_Out_ ULONG64 *performanceCounterValue, _Out_ ULONG64 *performanceCounterValue,
@@ -597,7 +597,7 @@ NTSTATUS CMiniportWaveRTStream::GetReadPacket(
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
NTSTATUS CMiniportWaveRTStream::SetWritePacket( NTSTATUS CWS::SetWritePacket(
_In_ ULONG packetNumber, _In_ ULONG packetNumber,
_In_ DWORD flags, _In_ DWORD flags,
_In_ ULONG eosPacketLength) _In_ ULONG eosPacketLength)
@@ -669,7 +669,7 @@ NTSTATUS CMiniportWaveRTStream::SetWritePacket(
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
NTSTATUS CMiniportWaveRTStream::GetOutputStreamPresentationPosition( NTSTATUS CWS::GetOutputStreamPresentationPosition(
_Out_ KSAUDIO_PRESENTATION_POSITION *position) _Out_ KSAUDIO_PRESENTATION_POSITION *position)
{ {
if (m_kind != EndpointKind::Render || !position) if (m_kind != EndpointKind::Render || !position)
@@ -710,7 +710,7 @@ NTSTATUS CMiniportWaveRTStream::GetOutputStreamPresentationPosition(
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
NTSTATUS CMiniportWaveRTStream::GetPacketCount( NTSTATUS CWS::GetPacketCount(
_Out_ ULONG *packetCount) _Out_ ULONG *packetCount)
{ {
if (m_kind != EndpointKind::Render || !packetCount) if (m_kind != EndpointKind::Render || !packetCount)
@@ -732,7 +732,7 @@ NTSTATUS CMiniportWaveRTStream::GetPacketCount(
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
NTSTATUS CMiniportWaveRTStream::AllocateBuffer( NTSTATUS CWS::AllocateBuffer(
_In_ ULONG notificationCount, _In_ ULONG notificationCount,
_In_ ULONG requestedSize, _In_ ULONG requestedSize,
_Out_ PMDL *audioBufferMdl, _Out_ PMDL *audioBufferMdl,
@@ -824,7 +824,7 @@ NTSTATUS CMiniportWaveRTStream::AllocateBuffer(
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
void CMiniportWaveRTStream::FreeBuffer(_In_opt_ PMDL audioBufferMdl) void CWS::FreeBuffer(_In_opt_ PMDL audioBufferMdl)
{ {
if (!audioBufferMdl) if (!audioBufferMdl)
return; return;
@@ -856,13 +856,13 @@ void CMiniportWaveRTStream::FreeBuffer(_In_opt_ PMDL audioBufferMdl)
m_portStream->FreePagesFromMdl(mdl); m_portStream->FreePagesFromMdl(mdl);
} }
void CMiniportWaveRTStream::StopTimer() void CWS::StopTimer()
{ {
if (m_timer) if (m_timer)
ExCancelTimer(m_timer, nullptr); ExCancelTimer(m_timer, nullptr);
} }
void CMiniportWaveRTStream::ArmTimerLocked() void CWS::ArmTimerLocked()
{ {
if (!m_timer || m_state != KSSTATE_RUN || !m_notificationCount || if (!m_timer || m_state != KSSTATE_RUN || !m_notificationCount ||
!m_packetSize || !m_clockFrequency || !m_qpcFrequency || !m_packetSize || !m_clockFrequency || !m_qpcFrequency ||
@@ -927,7 +927,7 @@ void CMiniportWaveRTStream::ArmTimerLocked()
ExSetTimer(m_timer, -static_cast<LONGLONG>(dueTime), 0, nullptr); ExSetTimer(m_timer, -static_cast<LONGLONG>(dueTime), 0, nullptr);
} }
void CMiniportWaveRTStream::AdvanceLocked( void CWS::AdvanceLocked(
_In_ const AudioClockSnapshot &clock) _In_ const AudioClockSnapshot &clock)
{ {
if (m_state != KSSTATE_RUN || !m_buffer || !m_bufferSize || if (m_state != KSSTATE_RUN || !m_buffer || !m_bufferSize ||
@@ -986,7 +986,7 @@ void CMiniportWaveRTStream::AdvanceLocked(
AdvanceEventPacketsLocked(clock); AdvanceEventPacketsLocked(clock);
} }
void CMiniportWaveRTStream::AdvanceEventPacketsLocked( void CWS::AdvanceEventPacketsLocked(
_In_ const AudioClockSnapshot &clock) _In_ const AudioClockSnapshot &clock)
{ {
if (!m_packetSize) if (!m_packetSize)
@@ -1080,7 +1080,7 @@ void CMiniportWaveRTStream::AdvanceEventPacketsLocked(
} }
} }
bool CMiniportWaveRTStream::RenderPacketCommittedLocked( bool CWS::RenderPacketCommittedLocked(
_In_ ULONGLONG position) const _In_ ULONGLONG position) const
{ {
if (m_kind != EndpointKind::Render || !m_notificationCount || if (m_kind != EndpointKind::Render || !m_notificationCount ||
@@ -1091,7 +1091,7 @@ bool CMiniportWaveRTStream::RenderPacketCommittedLocked(
return static_cast<LONG>(m_lastWritePacket - packet) >= 0; return static_cast<LONG>(m_lastWritePacket - packet) >= 0;
} }
void CMiniportWaveRTStream::PublishRenderFramesLocked() void CWS::PublishRenderFramesLocked()
{ {
if (m_kind != EndpointKind::Render || !m_notificationCount || if (m_kind != EndpointKind::Render || !m_notificationCount ||
!m_packetSize || !m_renderPublicationSliceBytes || !m_bufferSize) !m_packetSize || !m_renderPublicationSliceBytes || !m_bufferSize)
@@ -1133,7 +1133,7 @@ void CMiniportWaveRTStream::PublishRenderFramesLocked()
} }
} }
void CMiniportWaveRTStream::UpdatePresentationQpcLocked( void CWS::UpdatePresentationQpcLocked(
_In_ const AudioClockSnapshot &clock) _In_ const AudioClockSnapshot &clock)
{ {
const ULONG blockAlign = const ULONG blockAlign =
@@ -1161,7 +1161,7 @@ void CMiniportWaveRTStream::UpdatePresentationQpcLocked(
clock.QpcPosition - ticksSinceBoundary : 0; clock.QpcPosition - ticksSinceBoundary : 0;
} }
void CMiniportWaveRTStream::TransferFramesLocked( void CWS::TransferFramesLocked(
_In_ ULONGLONG bytes, _In_ ULONGLONG bytes,
_In_ bool transferRender) _In_ bool transferRender)
{ {
@@ -1233,19 +1233,19 @@ void CMiniportWaveRTStream::TransferFramesLocked(
} }
} }
void CMiniportWaveRTStream::SignalNotificationsLocked() void CWS::SignalNotificationsLocked()
{ {
for (ULONG i = 0; i < m_notificationEventCount; ++i) for (ULONG i = 0; i < m_notificationEventCount; ++i)
KeSetEvent(m_notificationEvents[i], IO_NO_INCREMENT, FALSE); KeSetEvent(m_notificationEvents[i], IO_NO_INCREMENT, FALSE);
} }
void CMiniportWaveRTStream::TimerCallback( void CWS::TimerCallback(
_In_ PEX_TIMER timer, _In_ PEX_TIMER timer,
_In_opt_ void *context) _In_opt_ void *context)
{ {
UNREFERENCED_PARAMETER(timer); UNREFERENCED_PARAMETER(timer);
auto *stream = static_cast<CMiniportWaveRTStream *>(context); auto *stream = static_cast<CWS *>(context);
if (!stream) if (!stream)
return; return;

View File

@@ -26,18 +26,18 @@
class CMiniportWaveRT; class CMiniportWaveRT;
class CMiniportWaveRTStream final : class CWS final :
public IMiniportWaveRTStreamNotification, public IMiniportWaveRTStreamNotification,
public IMiniportWaveRTInputStream, public IMiniportWaveRTInputStream,
public IMiniportWaveRTOutputStream public IMiniportWaveRTOutputStream
{ {
public: public:
CMiniportWaveRTStream( CWS(
_In_ CMiniportWaveRT *miniport, _In_ CMiniportWaveRT *miniport,
_In_ CAudioAdapter *adapter, _In_ CAudioAdapter *adapter,
_In_ PPORTWAVERTSTREAM portStream, _In_ PPORTWAVERTSTREAM portStream,
_In_ EndpointKind kind); _In_ EndpointKind kind);
~CMiniportWaveRTStream(); ~CWS();
NTSTATUS Initialize( NTSTATUS Initialize(
_In_ const KSDATAFORMAT_WAVEFORMATEXTENSIBLE *format); _In_ const KSDATAFORMAT_WAVEFORMATEXTENSIBLE *format);

View File

@@ -25,6 +25,8 @@ namespace LGAudio
namespace namespace
{ {
constexpr ULONG kRingPoolTag = 'rAGL'; constexpr ULONG kRingPoolTag = 'rAGL';
// LCM of every supported channel-count and sample-width block alignment.
constexpr ULONG kRingBufferAlignment = 288;
ULONG MinUlong(_In_ ULONG left, _In_ ULONG right) ULONG MinUlong(_In_ ULONG left, _In_ ULONG right)
{ {
@@ -56,8 +58,8 @@ namespace LGAudio
return STATUS_SUCCESS; return STATUS_SUCCESS;
constexpr ULONG capacity = constexpr ULONG capacity =
(kMaximumBytesPerSecond + kMaximumBlockAlign - 1) / (kMaximumBytesPerSecond + kRingBufferAlignment - 1) /
kMaximumBlockAlign * kMaximumBlockAlign; kRingBufferAlignment * kRingBufferAlignment;
#pragma warning(push) #pragma warning(push)
#pragma warning(disable:4996) // Required for pre-2004 Windows 10 releases. #pragma warning(disable:4996) // Required for pre-2004 Windows 10 releases.
@@ -110,7 +112,8 @@ namespace LGAudio
NTSTATUS CAudioRingBuffer::Configure( NTSTATUS CAudioRingBuffer::Configure(
_In_ const FormatFingerprint & format) _In_ const FormatFingerprint & format)
{ {
if (format.sampleRate == 0 || if (format.sampleFormat == SampleFormat::Unknown ||
format.sampleRate == 0 ||
format.channels == 0 || format.channels == 0 ||
format.containerBits == 0 || format.containerBits == 0 ||
(format.containerBits % 8) != 0 || (format.containerBits % 8) != 0 ||

View File

@@ -43,7 +43,7 @@ static const GUID LGAUDIO_BROKER_DEVICE_CLASS_GUID =
{ 0x98f877f1, 0x73d6, 0x4429, { 0x98f877f1, 0x73d6, 0x4429,
{ 0xb4, 0x90, 0x28, 0xc5, 0x30, 0xd2, 0x38, 0xcd } }; { 0xb4, 0x90, 0x28, 0xc5, 0x30, 0xd2, 0x38, 0xcd } };
static constexpr UINT32 LGAUDIO_BROKER_ABI_VERSION = 1U; static constexpr UINT32 LGAUDIO_BROKER_ABI_VERSION = 2U;
// The transfer limits in LGAudioBrokerCaps exclude the packet header. // The transfer limits in LGAudioBrokerCaps exclude the packet header.
static constexpr UINT32 LGAUDIO_BROKER_MAX_PAYLOAD_BYTES = 64U * 1024U; static constexpr UINT32 LGAUDIO_BROKER_MAX_PAYLOAD_BYTES = 64U * 1024U;
@@ -87,6 +87,14 @@ enum LGAudioBrokerPacketFlag : UINT32
LGAUDIO_BROKER_PACKET_DISCONTINUITY = 1U << 0 LGAUDIO_BROKER_PACKET_DISCONTINUITY = 1U << 0
}; };
enum LGAudioBrokerSampleFormat : UINT32
{
LGAUDIO_BROKER_SAMPLE_S16_LE = 1,
LGAUDIO_BROKER_SAMPLE_S24_LE = 2,
LGAUDIO_BROKER_SAMPLE_S32_LE = 3,
LGAUDIO_BROKER_SAMPLE_F32_LE = 4
};
static constexpr UINT32 IOCTL_LGAUDIO_BROKER_QUERY_CAPS = static constexpr UINT32 IOCTL_LGAUDIO_BROKER_QUERY_CAPS =
CTL_CODE(FILE_DEVICE_UNKNOWN, 0x900, METHOD_BUFFERED, CTL_CODE(FILE_DEVICE_UNKNOWN, 0x900, METHOD_BUFFERED,
FILE_READ_ACCESS | FILE_WRITE_ACCESS); FILE_READ_ACCESS | FILE_WRITE_ACCESS);
@@ -116,12 +124,14 @@ struct LGAudioBrokerHeader
struct LGAudioBrokerFormat struct LGAudioBrokerFormat
{ {
UINT32 sampleFormat;
UINT32 sampleRate; UINT32 sampleRate;
UINT32 channelMask; UINT32 channelMask;
UINT16 channels; UINT16 channels;
UINT16 containerBits; UINT16 containerBits;
UINT16 validBits; UINT16 validBits;
UINT16 blockAlign; UINT16 blockAlign;
UINT32 reserved;
}; };
struct LGAudioBrokerStreamState struct LGAudioBrokerStreamState
@@ -230,15 +240,15 @@ struct LGAudioBrokerClockControl
static_assert(sizeof(LGAudioBrokerHeader) == 8, static_assert(sizeof(LGAudioBrokerHeader) == 8,
"LGAudio broker header layout changed"); "LGAudio broker header layout changed");
static_assert(sizeof(LGAudioBrokerFormat) == 16, static_assert(sizeof(LGAudioBrokerFormat) == 24,
"LGAudio broker format layout changed"); "LGAudio broker format layout changed");
static_assert(sizeof(LGAudioBrokerStreamState) == 32, static_assert(sizeof(LGAudioBrokerStreamState) == 40,
"LGAudio broker stream-state layout changed"); "LGAudio broker stream-state layout changed");
static_assert(sizeof(LGAudioBrokerPacketHeader) == 80, static_assert(sizeof(LGAudioBrokerPacketHeader) == 88,
"LGAudio broker packet layout changed"); "LGAudio broker packet layout changed");
static_assert(sizeof(LGAudioBrokerCaps) == 64, static_assert(sizeof(LGAudioBrokerCaps) == 64,
"LGAudio broker capabilities layout changed"); "LGAudio broker capabilities layout changed");
static_assert(sizeof(LGAudioBrokerState) == 104, static_assert(sizeof(LGAudioBrokerState) == 120,
"LGAudio broker state layout changed"); "LGAudio broker state layout changed");
static_assert(sizeof(LGAudioBrokerBind) == 48, static_assert(sizeof(LGAudioBrokerBind) == 48,
"LGAudio broker binding layout changed"); "LGAudio broker binding layout changed");
@@ -247,5 +257,5 @@ static_assert(sizeof(LGAudioBrokerStats) == 160,
static_assert(sizeof(LGAudioBrokerClockControl) == 64, static_assert(sizeof(LGAudioBrokerClockControl) == 64,
"LGAudio broker clock-control layout changed"); "LGAudio broker clock-control layout changed");
static_assert(LGAUDIO_BROKER_MAX_PAYLOAD_BYTES >= static_assert(LGAUDIO_BROKER_MAX_PAYLOAD_BYTES >=
(192000U / 100U) * 8U * 3U, (192000U / 100U) * 8U * 4U,
"LGAudio broker payload cannot hold 10 ms at the maximum format"); "LGAudio broker payload cannot hold 10 ms at the maximum format");

View File

@@ -70,7 +70,8 @@ namespace
bool SameFormat(const AudioFormat& left, const AudioFormat& right) bool SameFormat(const AudioFormat& left, const AudioFormat& right)
{ {
return left.sampleRate == right.sampleRate && return left.sampleFormat == right.sampleFormat &&
left.sampleRate == right.sampleRate &&
left.channelMask == right.channelMask && left.channelMask == right.channelMask &&
left.channels == right.channels && left.channels == right.channels &&
left.containerBits == right.containerBits && left.containerBits == right.containerBits &&
@@ -78,6 +79,22 @@ namespace
left.blockAlign == right.blockAlign; left.blockAlign == right.blockAlign;
} }
bool ValidSampleFormat(const AudioFormat& format)
{
switch (format.sampleFormat)
{
case AudioSampleFormat::S16_LE:
return format.containerBits == 16 && format.validBits == 16;
case AudioSampleFormat::S24_LE:
return format.containerBits == 24 && format.validBits == 24;
case AudioSampleFormat::S32_LE:
case AudioSampleFormat::F32_LE:
return format.containerBits == 32 && format.validBits == 32;
default:
return false;
}
}
bool ValidFormat(const AudioFormat& format) bool ValidFormat(const AudioFormat& format)
{ {
return format.sampleRate && format.sampleRate <= 192000 && return format.sampleRate && format.sampleRate <= 192000 &&
@@ -85,15 +102,52 @@ namespace
format.channelMask && format.channelMask &&
!(format.channelMask & ~AUDIO_CHANNEL_POSITION_MASK) && !(format.channelMask & ~AUDIO_CHANNEL_POSITION_MASK) &&
PopCount(format.channelMask) == format.channels && PopCount(format.channelMask) == format.channels &&
(format.containerBits == 16 || format.containerBits == 24) && ValidSampleFormat(format) &&
format.validBits == format.containerBits &&
format.blockAlign == format.blockAlign ==
format.channels * (format.containerBits / 8); format.channels * (format.containerBits / 8);
} }
AudioSampleFormat BrokerSampleFormat(uint32_t source)
{
switch (source)
{
case LGAUDIO_BROKER_SAMPLE_S16_LE:
return AudioSampleFormat::S16_LE;
case LGAUDIO_BROKER_SAMPLE_S24_LE:
return AudioSampleFormat::S24_LE;
case LGAUDIO_BROKER_SAMPLE_S32_LE:
return AudioSampleFormat::S32_LE;
case LGAUDIO_BROKER_SAMPLE_F32_LE:
return AudioSampleFormat::F32_LE;
default:
return AudioSampleFormat::UNKNOWN;
}
}
uint32_t DeviceSampleFormat(AudioSampleFormat source)
{
switch (source)
{
case AudioSampleFormat::S16_LE:
return LGAUDIO_BROKER_SAMPLE_S16_LE;
case AudioSampleFormat::S24_LE:
return LGAUDIO_BROKER_SAMPLE_S24_LE;
case AudioSampleFormat::S32_LE:
return LGAUDIO_BROKER_SAMPLE_S32_LE;
case AudioSampleFormat::F32_LE:
return LGAUDIO_BROKER_SAMPLE_F32_LE;
default:
return 0;
}
}
AudioFormat BrokerFormat(const LGAudioBrokerFormat& source) AudioFormat BrokerFormat(const LGAudioBrokerFormat& source)
{ {
AudioFormat result; AudioFormat result;
if (source.reserved)
return result;
result.sampleFormat = BrokerSampleFormat(source.sampleFormat);
result.sampleRate = source.sampleRate; result.sampleRate = source.sampleRate;
result.channelMask = source.channelMask; result.channelMask = source.channelMask;
result.channels = source.channels; result.channels = source.channels;
@@ -106,6 +160,7 @@ namespace
LGAudioBrokerFormat DeviceFormat(const AudioFormat& source) LGAudioBrokerFormat DeviceFormat(const AudioFormat& source)
{ {
LGAudioBrokerFormat result = {}; LGAudioBrokerFormat result = {};
result.sampleFormat = DeviceSampleFormat(source.sampleFormat);
result.sampleRate = source.sampleRate; result.sampleRate = source.sampleRate;
result.channelMask = source.channelMask; result.channelMask = source.channelMask;
result.channels = source.channels; result.channels = source.channels;

View File

@@ -26,7 +26,7 @@
static constexpr uint32_t AUDIO_MAX_CHANNELS = 18; static constexpr uint32_t AUDIO_MAX_CHANNELS = 18;
static constexpr uint32_t AUDIO_STREAM_MAX_CHANNELS = 8; static constexpr uint32_t AUDIO_STREAM_MAX_CHANNELS = 8;
static constexpr uint32_t AUDIO_MAX_FRAMES_PER_PACKET = 2048; static constexpr uint32_t AUDIO_MAX_FRAMES_PER_PACKET = 2048;
static constexpr uint32_t AUDIO_MAX_BYTES_PER_SAMPLE = 3; static constexpr uint32_t AUDIO_MAX_BYTES_PER_SAMPLE = 4;
static constexpr uint32_t AUDIO_MAX_PCM_BYTES = static constexpr uint32_t AUDIO_MAX_PCM_BYTES =
AUDIO_MAX_FRAMES_PER_PACKET * AUDIO_STREAM_MAX_CHANNELS * AUDIO_MAX_FRAMES_PER_PACKET * AUDIO_STREAM_MAX_CHANNELS *
AUDIO_MAX_BYTES_PER_SAMPLE; AUDIO_MAX_BYTES_PER_SAMPLE;
@@ -54,6 +54,15 @@ enum AudioClockFlag : uint32_t
AUDIO_CLOCK_DISCONTINUITY = 1U << 2, AUDIO_CLOCK_DISCONTINUITY = 1U << 2,
}; };
enum class AudioSampleFormat : uint32_t
{
UNKNOWN = 0,
S16_LE = 1,
S24_LE = 2,
S32_LE = 3,
F32_LE = 4,
};
enum class AudioStreamState : uint32_t enum class AudioStreamState : uint32_t
{ {
UNAVAILABLE, UNAVAILABLE,
@@ -75,12 +84,13 @@ enum class AudioResult
struct AudioFormat struct AudioFormat
{ {
uint32_t sampleRate = 0; AudioSampleFormat sampleFormat = AudioSampleFormat::UNKNOWN;
uint32_t channelMask = 0; uint32_t sampleRate = 0;
uint16_t channels = 0; uint32_t channelMask = 0;
uint16_t containerBits = 0; uint16_t channels = 0;
uint16_t validBits = 0; uint16_t containerBits = 0;
uint16_t blockAlign = 0; uint16_t validBits = 0;
uint16_t blockAlign = 0;
}; };
struct AudioStreamStatus struct AudioStreamStatus

View File

@@ -50,6 +50,16 @@ namespace
"audio packet limits differ"); "audio packet limits differ");
static_assert(AUDIO_MAX_PCM_BYTES == KVMFR_AUDIO_PCM_BYTES, static_assert(AUDIO_MAX_PCM_BYTES == KVMFR_AUDIO_PCM_BYTES,
"audio PCM limits differ"); "audio PCM limits differ");
static_assert(
static_cast<uint32_t>(AudioSampleFormat::S16_LE) ==
KVMFR_AUDIO_SAMPLE_S16_LE &&
static_cast<uint32_t>(AudioSampleFormat::S24_LE) ==
KVMFR_AUDIO_SAMPLE_S24_LE &&
static_cast<uint32_t>(AudioSampleFormat::S32_LE) ==
KVMFR_AUDIO_SAMPLE_S32_LE &&
static_cast<uint32_t>(AudioSampleFormat::F32_LE) ==
KVMFR_AUDIO_SAMPLE_F32_LE,
"audio sample formats differ");
static_assert(static_cast<uint32_t>(AUDIO_CAP_PLAYBACK) == static_assert(static_cast<uint32_t>(AUDIO_CAP_PLAYBACK) ==
static_cast<uint32_t>(KVMFR_AUDIO_CAP_PLAYBACK) && static_cast<uint32_t>(KVMFR_AUDIO_CAP_PLAYBACK) &&
static_cast<uint32_t>(AUDIO_CAP_CAPTURE) == static_cast<uint32_t>(AUDIO_CAP_CAPTURE) ==
@@ -75,7 +85,7 @@ namespace
KVMFR_AUDIO_MESSAGE_CLOCK_VALID | KVMFR_AUDIO_MESSAGE_CLOCK_VALID |
KVMFR_AUDIO_MESSAGE_CLOCK_STABLE; KVMFR_AUDIO_MESSAGE_CLOCK_STABLE;
constexpr size_t AUDIO_SHARED_MEMORY_PREFLIGHT = constexpr size_t AUDIO_SHARED_MEMORY_PREFLIGHT =
2U * 1024U * 1024U; 3U * 1024U * 1024U;
bool ArmAudioPollTimer(HANDLE timer, uint32_t waitUs) bool ArmAudioPollTimer(HANDLE timer, uint32_t waitUs)
{ {
@@ -122,7 +132,8 @@ CLGMPAudioTransport::~CLGMPAudioTransport()
bool CLGMPAudioTransport::SameFormat( bool CLGMPAudioTransport::SameFormat(
const AudioFormat& left, const AudioFormat& right) const AudioFormat& left, const AudioFormat& right)
{ {
return left.sampleRate == right.sampleRate && return left.sampleFormat == right.sampleFormat &&
left.sampleRate == right.sampleRate &&
left.channelMask == right.channelMask && left.channelMask == right.channelMask &&
left.channels == right.channels && left.channels == right.channels &&
left.containerBits == right.containerBits && left.containerBits == right.containerBits &&
@@ -152,11 +163,29 @@ bool CLGMPAudioTransport::ValidFormat(const AudioFormat& format)
ChannelCount(format.channelMask) != format.channels) ChannelCount(format.channelMask) != format.channels)
return false; return false;
const bool s16 = format.containerBits == 16 && format.validBits == 16; bool validSampleFormat = false;
const bool s24 = format.containerBits == 24 && format.validBits == 24; switch (format.sampleFormat)
{
case AudioSampleFormat::S16_LE:
validSampleFormat =
format.containerBits == 16 && format.validBits == 16;
break;
case AudioSampleFormat::S24_LE:
validSampleFormat =
format.containerBits == 24 && format.validBits == 24;
break;
case AudioSampleFormat::S32_LE:
case AudioSampleFormat::F32_LE:
validSampleFormat =
format.containerBits == 32 && format.validBits == 32;
break;
default:
return false;
}
const uint16_t bytes = static_cast<uint16_t>( const uint16_t bytes = static_cast<uint16_t>(
format.channels * (format.containerBits / 8U)); format.channels * (format.containerBits / 8U));
return (s16 || s24) && format.blockAlign == bytes; return validSampleFormat && format.blockAlign == bytes;
} }
KVMFRAudioFormat CLGMPAudioTransport::WireFormat( KVMFRAudioFormat CLGMPAudioTransport::WireFormat(
@@ -165,8 +194,8 @@ KVMFRAudioFormat CLGMPAudioTransport::WireFormat(
KVMFRAudioFormat result = {}; KVMFRAudioFormat result = {};
result.version = KVMFR_AUDIO_FORMAT_VERSION; result.version = KVMFR_AUDIO_FORMAT_VERSION;
result.size = sizeof(result); result.size = sizeof(result);
result.sampleFormat = format.containerBits == 16 ? result.sampleFormat =
KVMFR_AUDIO_SAMPLE_S16_LE : KVMFR_AUDIO_SAMPLE_S24_LE; static_cast<uint32_t>(format.sampleFormat);
result.sampleRate = format.sampleRate; result.sampleRate = format.sampleRate;
result.channelMask = format.channelMask; result.channelMask = format.channelMask;
result.channelCount = format.channels; result.channelCount = format.channels;