// WinMM waveform output over the native render-stream syscall ABI. #include #include #include #include #include #include typedef unsigned int MMRESULT; typedef void* HWAVEOUT; typedef unsigned int UINT; typedef uint32_t DWORD; typedef uintptr_t DWORD_PTR; typedef unsigned short WORD; typedef int BOOL; #define FALSE 0 #define TRUE 1 #define MMSYSERR_NOERROR 0u #define MMSYSERR_ERROR 1u #define MMSYSERR_BADDEVICEID 2u #define MMSYSERR_ALLOCATED 4u #define MMSYSERR_INVALHANDLE 5u #define MMSYSERR_NOMEM 7u #define MMSYSERR_NOTSUPPORTED 8u #define MMSYSERR_INVALFLAG 10u #define MMSYSERR_INVALPARAM 11u #define MMSYSERR_HANDLEBUSY 12u #define WAVERR_BADFORMAT 32u #define WAVERR_STILLPLAYING 33u #define WAVERR_UNPREPARED 34u #define WAVE_FORMAT_PCM 1u #define WAVE_MAPPER 0xFFFFFFFFu #define WAVE_FORMAT_QUERY 0x00000001u #define WAVE_ALLOWSYNC 0x00000002u #define WAVE_FORMAT_DIRECT 0x00000008u #define CALLBACK_TYPEMASK 0x00070000u #define CALLBACK_NULL 0x00000000u #define CALLBACK_WINDOW 0x00010000u #define CALLBACK_THREAD 0x00020000u #define CALLBACK_FUNCTION 0x00030000u #define CALLBACK_EVENT 0x00050000u #define WINMM_WAVE_OPEN_SUPPORTED_FLAGS \ (WAVE_FORMAT_QUERY | WAVE_ALLOWSYNC | WAVE_FORMAT_DIRECT | CALLBACK_TYPEMASK) #define WHDR_DONE 0x00000001u #define WHDR_PREPARED 0x00000002u #define WHDR_BEGINLOOP 0x00000004u #define WHDR_ENDLOOP 0x00000008u #define WHDR_INQUEUE 0x00000010u #define WOM_OPEN 0x03BBu #define WOM_CLOSE 0x03BCu #define WOM_DONE 0x03BDu #define TIME_MS 0x0001u #define TIME_SAMPLES 0x0002u #define TIME_BYTES 0x0004u #define WAVECAPS_VOLUME 0x0001u #define WAVECAPS_LRVOLUME 0x0002u #define WAVE_FORMAT_1M16 0x00000004u #define WAVE_FORMAT_1S16 0x00000008u #define WAVE_FORMAT_2M16 0x00000040u #define WAVE_FORMAT_2S16 0x00000080u #define WAVE_FORMAT_4M16 0x00000400u #define WAVE_FORMAT_4S16 0x00000800u #define WAVE_FORMAT_48M16 0x00004000u #define WAVE_FORMAT_48S16 0x00008000u #define WINMM_WAVEOUT_MAGIC 0x4F564157u #define WINMM_WAIT_MILLISECONDS 5000ull #define WINMM_WORKER_PRIORITY 1u #define WINMM_WRITE_CHUNK_FRAMES 1024u typedef struct WAVEFORMATEX { WORD wFormatTag; WORD nChannels; DWORD nSamplesPerSec; DWORD nAvgBytesPerSec; WORD nBlockAlign; WORD wBitsPerSample; WORD cbSize; } WAVEFORMATEX; typedef struct WAVEHDR { char* lpData; DWORD dwBufferLength; DWORD dwBytesRecorded; DWORD_PTR dwUser; DWORD dwFlags; DWORD dwLoops; struct WAVEHDR* lpNext; DWORD_PTR reserved; } WAVEHDR; typedef struct MMTIME { UINT wType; union { DWORD ms; DWORD sample; DWORD cb; DWORD ticks; } u; } MMTIME; typedef struct WAVEOUTCAPSA { WORD wMid; WORD wPid; DWORD vDriverVersion; char szPname[32]; DWORD dwFormats; WORD wChannels; WORD wReserved1; DWORD dwSupport; } WAVEOUTCAPSA; typedef struct WAVEOUTCAPSW { WORD wMid; WORD wPid; DWORD vDriverVersion; unsigned short szPname[32]; DWORD dwFormats; WORD wChannels; WORD wReserved1; DWORD dwSupport; } WAVEOUTCAPSW; typedef char WINMM_WAVEFORMATEX_SIZE[(sizeof(WAVEFORMATEX) == 20u) ? 1 : -1]; typedef char WINMM_WAVEHDR_SIZE[(sizeof(WAVEHDR) == 48u) ? 1 : -1]; typedef char WINMM_MMTIME_SIZE[(sizeof(MMTIME) == 8u) ? 1 : -1]; typedef char WINMM_WAVEOUTCAPSA_SIZE[(sizeof(WAVEOUTCAPSA) == 52u) ? 1 : -1]; typedef char WINMM_WAVEOUTCAPSW_SIZE[(sizeof(WAVEOUTCAPSW) == 84u) ? 1 : -1]; typedef void (__stdcall *WAVEOUTPROC)(HWAVEOUT waveOut, UINT message, DWORD_PTR instance, DWORD_PTR parameter1, DWORD_PTR parameter2); typedef enum WINMM_WAVE_COMMAND { WinmmWaveCommandNone = 0, WinmmWaveCommandPause, WinmmWaveCommandRestart, WinmmWaveCommandReset } WINMM_WAVE_COMMAND; typedef struct WINMM_WAVE_BUFFER { struct WINMM_WAVE_BUFFER* Next; WAVEHDR* Header; int16_t* Frames; uint32_t FrameCount; uint32_t SubmittedFrames; uint64_t PresentedTarget; uint8_t FullySubmitted; uint64_t Sequence; } WINMM_WAVE_BUFFER; typedef struct WINMM_WAVEOUT { struct WINMM_WAVEOUT* RegistryNext; uint32_t Magic; volatile long Lock; volatile long ApiUsers; uint32_t NativeStream; uint32_t WakeEvent; uint32_t CommandEvent; uint32_t ReadyEvent; uint32_t WorkerHandle; uint32_t WorkerTid; uint64_t EndpointId; WAVEFORMATEX SourceFormat; uintptr_t Callback; uintptr_t CallbackInstance; uint32_t CallbackMode; uint32_t DeviceId; uint32_t Volume; uint32_t Closing; uint32_t UserPaused; uint32_t AutoPaused; uint32_t Started; uint32_t TerminalError; WINMM_WAVE_COMMAND Command; MMRESULT CommandResult; WINMM_WAVE_BUFFER* QueueHead; WINMM_WAVE_BUFFER* QueueTail; WINMM_WAVE_BUFFER* SubmitNode; uint64_t NativeSubmitted; uint64_t KnownDiscontinuity; uint64_t HeadersQueued; uint64_t HeadersCompleted; uint64_t FramesQueued; } WINMM_WAVEOUT; static WINMM_WAVEOUT* gWaveOutRegistry; static volatile long gWaveOutRegistryLock; typedef struct WINMM_DEBUG_LINE { char Buffer[192]; size_t Length; } WINMM_DEBUG_LINE; // Appends text to one bounded WinMM diagnostic line. static void WinmmDebugText(WINMM_DEBUG_LINE* line, const char* text) { if (!line || !text) return; while (*text && line->Length + 1 < sizeof(line->Buffer)) line->Buffer[line->Length++] = *text++; } // Appends one unsigned decimal value to a WinMM diagnostic line. static void WinmmDebugU64(WINMM_DEBUG_LINE* line, uint64_t value) { char digits[24]; size_t count = 0; do { digits[count++] = (char)('0' + value % 10u); value /= 10u; } while (value && count < sizeof(digits)); while (count && line->Length + 1 < sizeof(line->Buffer)) line->Buffer[line->Length++] = digits[--count]; } // Appends one fixed-width hexadecimal value to a WinMM diagnostic line. static void WinmmDebugHex(WINMM_DEBUG_LINE* line, uint64_t value) { static const char digits[] = "0123456789ABCDEF"; WinmmDebugText(line, "0x"); int started = 0; for (int shift = 60; shift >= 0; shift -= 4) { uint8_t digit = (uint8_t)((value >> shift) & 0xFu); if (!started && digit == 0 && shift) continue; started = 1; if (line->Length + 1 < sizeof(line->Buffer)) line->Buffer[line->Length++] = digits[digit]; } } // Emits one complete WinMM diagnostic line through the native debug console. static void WinmmDebugCommit(WINMM_DEBUG_LINE* line) { if (!line) return; if (line->Length + 1 < sizeof(line->Buffer)) line->Buffer[line->Length++] = '\n'; line->Buffer[line->Length] = '\0'; SYS_PRINT_DEBUG_REQUEST request = { SysSvFromParts(line->Buffer, line->Length) }; (void)SysPrintDebug(&request); } // Logs one waveform-open request before validation changes its control flow. static void WinmmDebugOpenRequest(UINT deviceId, const WAVEFORMATEX* format, DWORD flags) { WINMM_DEBUG_LINE line = {0}; WinmmDebugText(&line, "WINMM: open request device="); WinmmDebugU64(&line, deviceId); WinmmDebugText(&line, " tag="); WinmmDebugU64(&line, format ? format->wFormatTag : 0); WinmmDebugText(&line, " rate="); WinmmDebugU64(&line, format ? format->nSamplesPerSec : 0); WinmmDebugText(&line, " channels="); WinmmDebugU64(&line, format ? format->nChannels : 0); WinmmDebugText(&line, " bits="); WinmmDebugU64(&line, format ? format->wBitsPerSample : 0); WinmmDebugText(&line, " align="); WinmmDebugU64(&line, format ? format->nBlockAlign : 0); WinmmDebugText(&line, " avg="); WinmmDebugU64(&line, format ? format->nAvgBytesPerSec : 0); WinmmDebugText(&line, " flags="); WinmmDebugHex(&line, flags); WinmmDebugCommit(&line); } // Logs one WinMM result with its handle and native stream identity. static void WinmmDebugResult(const char* operation, const WINMM_WAVEOUT* waveOut, uint64_t value) { WINMM_DEBUG_LINE line = {0}; WinmmDebugText(&line, "WINMM: "); WinmmDebugText(&line, operation); if (waveOut) { WinmmDebugText(&line, " handle="); WinmmDebugHex(&line, (uintptr_t)waveOut); WinmmDebugText(&line, " stream="); WinmmDebugU64(&line, waveOut->NativeStream); } WinmmDebugText(&line, " value="); WinmmDebugU64(&line, value); WinmmDebugCommit(&line); } // Acquires one short user-mode spin lock without entering the kernel. static void WinmmLock(volatile long* lock) { while (_InterlockedCompareExchange(lock, 1, 0) != 0) (void)SysYield(); } // Releases one short user-mode spin lock. static void WinmmUnlock(volatile long* lock) { _InterlockedExchange(lock, 0); } // Maps one native status to the closest waveform-open result. static MMRESULT WinmmMapNativeStatus(KSTATUS status) { if (status == NTLSTATUS_SUCCESS) return MMSYSERR_NOERROR; if (status == NTLSTATUS_NO_MEMORY) return MMSYSERR_NOMEM; if (status == NTLSTATUS_NOT_FOUND || status == NTLSTATUS_DEVICE_REMOVED) return MMSYSERR_BADDEVICEID; if (status == NTLSTATUS_NOT_SUPPORTED) return WAVERR_BADFORMAT; if (status == NTLSTATUS_INVALID_PARAMETER) return MMSYSERR_INVALPARAM; return MMSYSERR_ERROR; } // Returns whether one source rate is accepted by the native stream ABI. static int WinmmRateIsSupported(uint32_t sampleRate) { return sampleRate == 11025u || sampleRate == 22050u || sampleRate == 44100u || sampleRate == 48000u; } // Validates the narrow PCM surface implemented by this personality. static MMRESULT WinmmValidateFormat(const WAVEFORMATEX* format) { if (!format) return MMSYSERR_INVALPARAM; if (format->wFormatTag != WAVE_FORMAT_PCM || (format->nChannels != 1u && format->nChannels != 2u) || !WinmmRateIsSupported(format->nSamplesPerSec) || (format->wBitsPerSample != 16u && format->wBitsPerSample != 24u)) return WAVERR_BADFORMAT; uint32_t bytesPerSample = format->wBitsPerSample / 8u; uint32_t blockAlign = (uint32_t)format->nChannels * bytesPerSample; uint64_t averageBytes = (uint64_t)format->nSamplesPerSec * blockAlign; if (format->nBlockAlign != blockAlign || averageBytes > UINT32_MAX || format->nAvgBytesPerSec != (uint32_t)averageBytes) return WAVERR_BADFORMAT; return MMSYSERR_NOERROR; } // Enumerates available native endpoints into the caller's fixed snapshot. static MMRESULT WinmmEnumerateEndpoints(SYS_AUDIO_ENDPOINT_INFO* endpoints, uint32_t capacity, uint32_t* countOut) { SYS_AUDIO_ENUMERATE_ENDPOINTS_REQUEST request; memset(&request, 0, sizeof(request)); request.Size = sizeof(request); request.Endpoints = endpoints; request.Capacity = capacity; request.CountOut = countOut; return WinmmMapNativeStatus(SysAudioEnumerateEndpoints(&request)); } // Counts endpoints that are currently ready and available. static uint32_t WinmmAvailableEndpointCount(void) { SYS_AUDIO_ENDPOINT_INFO endpoints[SYS_AUDIO_MAX_ENDPOINTS]; uint32_t count = 0; if (WinmmEnumerateEndpoints(endpoints, SYS_AUDIO_MAX_ENDPOINTS, &count) != MMSYSERR_NOERROR) return 0; if (count > SYS_AUDIO_MAX_ENDPOINTS) count = SYS_AUDIO_MAX_ENDPOINTS; uint32_t available = 0; for (uint32_t index = 0; index < count; index++) { if (endpoints[index].State == SysAudioEndpointReady && (endpoints[index].Flags & SYS_AUDIO_ENDPOINT_FLAG_AVAILABLE)) available++; } return available; } // Resolves WAVE_MAPPER or one available-device index to a stable endpoint ID. static MMRESULT WinmmResolveEndpoint(uint32_t deviceId, uint64_t* endpointIdOut, uint32_t* resolvedDeviceIdOut) { SYS_AUDIO_ENDPOINT_INFO endpoints[SYS_AUDIO_MAX_ENDPOINTS]; uint32_t count = 0; MMRESULT result = WinmmEnumerateEndpoints(endpoints, SYS_AUDIO_MAX_ENDPOINTS, &count); if (result != MMSYSERR_NOERROR) return result; if (count > SYS_AUDIO_MAX_ENDPOINTS) count = SYS_AUDIO_MAX_ENDPOINTS; const SYS_AUDIO_ENDPOINT_INFO* fallback = NULL; uint32_t fallbackIndex = 0; uint32_t availableIndex = 0; for (uint32_t index = 0; index < count; index++) { const SYS_AUDIO_ENDPOINT_INFO* endpoint = &endpoints[index]; if (endpoint->State != SysAudioEndpointReady || (endpoint->Flags & SYS_AUDIO_ENDPOINT_FLAG_AVAILABLE) == 0) continue; if (!fallback) { fallback = endpoint; fallbackIndex = availableIndex; } if (deviceId == WAVE_MAPPER && (endpoint->Flags & SYS_AUDIO_ENDPOINT_FLAG_DEFAULT)) { *endpointIdOut = endpoint->EndpointId; *resolvedDeviceIdOut = availableIndex; return MMSYSERR_NOERROR; } if (deviceId != WAVE_MAPPER && availableIndex == deviceId) { *endpointIdOut = endpoint->EndpointId; *resolvedDeviceIdOut = availableIndex; return MMSYSERR_NOERROR; } availableIndex++; } if (deviceId == WAVE_MAPPER && fallback) { *endpointIdOut = fallback->EndpointId; *resolvedDeviceIdOut = fallbackIndex; return MMSYSERR_NOERROR; } return MMSYSERR_BADDEVICEID; } // Adds one live waveform handle to the process-local registry. static void WinmmRegisterWaveOut(WINMM_WAVEOUT* waveOut) { WinmmLock(&gWaveOutRegistryLock); waveOut->RegistryNext = gWaveOutRegistry; gWaveOutRegistry = waveOut; WinmmUnlock(&gWaveOutRegistryLock); } // References one registered waveform handle without dereferencing unknown pointers. static WINMM_WAVEOUT* WinmmReferenceWaveOut(HWAVEOUT handle) { WINMM_WAVEOUT* found = NULL; WinmmLock(&gWaveOutRegistryLock); for (WINMM_WAVEOUT* current = gWaveOutRegistry; current; current = current->RegistryNext) { if ((HWAVEOUT)current == handle && current->Magic == WINMM_WAVEOUT_MAGIC) { _InterlockedIncrement(¤t->ApiUsers); found = current; break; } } WinmmUnlock(&gWaveOutRegistryLock); return found; } // Releases one API-use reference acquired through the registry. static void WinmmReleaseWaveOut(WINMM_WAVEOUT* waveOut) { if (waveOut) _InterlockedDecrement(&waveOut->ApiUsers); } // Removes one waveform handle so no new API references can be acquired. static int WinmmRemoveWaveOut(WINMM_WAVEOUT* waveOut) { int removed = 0; WinmmLock(&gWaveOutRegistryLock); WINMM_WAVEOUT** link = &gWaveOutRegistry; while (*link) { if (*link == waveOut) { *link = waveOut->RegistryNext; waveOut->RegistryNext = NULL; removed = 1; break; } link = &(*link)->RegistryNext; } WinmmUnlock(&gWaveOutRegistryLock); return removed; } // Delivers one WinMM callback through a supported user-mode mechanism. static void WinmmNotify(WINMM_WAVEOUT* waveOut, uint32_t message, uintptr_t parameter1, uintptr_t parameter2) { if (waveOut->CallbackMode == CALLBACK_FUNCTION) { WAVEOUTPROC callback = (WAVEOUTPROC)waveOut->Callback; callback((HWAVEOUT)waveOut, message, waveOut->CallbackInstance, parameter1, parameter2); } else if (waveOut->CallbackMode == CALLBACK_EVENT) { (void)SysSignalEvent((uint32_t)waveOut->Callback); } } // Converts one packed PCM buffer into personality-owned native S16 frames. static MMRESULT WinmmCopyFrames(const WINMM_WAVEOUT* waveOut, const WAVEHDR* header, int16_t** framesOut, uint32_t* frameCountOut) { if (!header || !framesOut || !frameCountOut) return MMSYSERR_INVALPARAM; if (header->dwBufferLength && !header->lpData) return MMSYSERR_INVALPARAM; if (header->dwBufferLength % waveOut->SourceFormat.nBlockAlign) return WAVERR_BADFORMAT; uint32_t frameCount = header->dwBufferLength / waveOut->SourceFormat.nBlockAlign; size_t sampleCount = (size_t)frameCount * waveOut->SourceFormat.nChannels; if (frameCount && sampleCount > SIZE_MAX / sizeof(int16_t)) return MMSYSERR_NOMEM; int16_t* output = sampleCount ? (int16_t*)malloc(sampleCount * sizeof(int16_t)) : NULL; if (sampleCount && !output) return MMSYSERR_NOMEM; if (waveOut->SourceFormat.wBitsPerSample == 16u) { if (sampleCount) memcpy(output, header->lpData, sampleCount * sizeof(int16_t)); } else { const uint8_t* input = (const uint8_t*)header->lpData; for (size_t sampleIndex = 0; sampleIndex < sampleCount; sampleIndex++) { uint32_t packed = (uint32_t)input[sampleIndex * 3u] | ((uint32_t)input[sampleIndex * 3u + 1u] << 8u) | ((uint32_t)input[sampleIndex * 3u + 2u] << 16u); int32_t signedSample = (packed & 0x00800000u) ? (int32_t)(packed | 0xFF000000u) : (int32_t)packed; output[sampleIndex] = (int16_t)(signedSample / 256); } } *framesOut = output; *frameCountOut = frameCount; return MMSYSERR_NOERROR; } // Pops and completes every header whose source frames reached hardware presentation. static void WinmmCompletePresentedBuffers(WINMM_WAVEOUT* waveOut, uint64_t framesPresented) { while (true) { WinmmLock(&waveOut->Lock); WINMM_WAVE_BUFFER* buffer = waveOut->QueueHead; if (!buffer || !buffer->FullySubmitted || buffer->PresentedTarget > framesPresented) { WinmmUnlock(&waveOut->Lock); return; } waveOut->QueueHead = buffer->Next; if (!waveOut->QueueHead) waveOut->QueueTail = NULL; if (waveOut->SubmitNode == buffer) waveOut->SubmitNode = buffer->Next; buffer->Header->dwFlags &= ~WHDR_INQUEUE; buffer->Header->dwFlags |= WHDR_DONE; waveOut->HeadersCompleted++; WinmmUnlock(&waveOut->Lock); WinmmNotify(waveOut, WOM_DONE, (uintptr_t)buffer->Header, 0); free(buffer->Frames); free(buffer); } } // Detaches every queued buffer for reset or terminal failure completion. static WINMM_WAVE_BUFFER* WinmmDetachAllBuffers(WINMM_WAVEOUT* waveOut) { WinmmLock(&waveOut->Lock); WINMM_WAVE_BUFFER* buffers = waveOut->QueueHead; waveOut->QueueHead = NULL; waveOut->QueueTail = NULL; waveOut->SubmitNode = NULL; WinmmUnlock(&waveOut->Lock); return buffers; } // Completes and releases one detached buffer list in queue order. static void WinmmCompleteDetachedBuffers(WINMM_WAVEOUT* waveOut, WINMM_WAVE_BUFFER* buffers) { while (buffers) { WINMM_WAVE_BUFFER* next = buffers->Next; buffers->Header->dwFlags &= ~WHDR_INQUEUE; buffers->Header->dwFlags |= WHDR_DONE; waveOut->HeadersCompleted++; WinmmNotify(waveOut, WOM_DONE, (uintptr_t)buffers->Header, 0); free(buffers->Frames); free(buffers); buffers = next; } } // Queries one coherent native stream snapshot. static KSTATUS WinmmQueryNativeStream(WINMM_WAVEOUT* waveOut, SYS_AUDIO_STREAM_INFO* info) { memset(info, 0, sizeof(*info)); info->Size = sizeof(*info); return SysAudioQueryStream(waveOut->NativeStream, info); } // Updates the controlled discontinuity baseline after stop or reset. static void WinmmRefreshDiscontinuity(WINMM_WAVEOUT* waveOut) { SYS_AUDIO_STREAM_INFO info; if (WinmmQueryNativeStream(waveOut, &info) == NTLSTATUS_SUCCESS) waveOut->KnownDiscontinuity = info.DiscontinuityGeneration; } // Processes one synchronous control command on the worker thread. static void WinmmProcessCommand(WINMM_WAVEOUT* waveOut) { WinmmLock(&waveOut->Lock); WINMM_WAVE_COMMAND command = waveOut->Command; WinmmUnlock(&waveOut->Lock); if (command == WinmmWaveCommandNone) return; MMRESULT result = MMSYSERR_NOERROR; WINMM_WAVE_BUFFER* resetBuffers = NULL; if (command == WinmmWaveCommandPause) { if (!waveOut->UserPaused) { waveOut->UserPaused = 1; if (waveOut->Started && !waveOut->AutoPaused) { SYS_AUDIO_STREAM_INFO info; KSTATUS status = WinmmQueryNativeStream(waveOut, &info); if (status == NTLSTATUS_SUCCESS && info.State == SysAudioStreamRunning) status = SysAudioPause(waveOut->NativeStream); if (status != NTLSTATUS_SUCCESS) result = WinmmMapNativeStatus(status); } } } else if (command == WinmmWaveCommandRestart) { if (waveOut->UserPaused) { waveOut->UserPaused = 0; if (waveOut->Started && !waveOut->AutoPaused) { SYS_AUDIO_STREAM_INFO info; KSTATUS status = WinmmQueryNativeStream(waveOut, &info); if (status == NTLSTATUS_SUCCESS && info.State == SysAudioStreamPaused) status = SysAudioResume(waveOut->NativeStream); if (status != NTLSTATUS_SUCCESS) result = WinmmMapNativeStatus(status); } } } else if (command == WinmmWaveCommandReset) { (void)SysAudioStop(waveOut->NativeStream); KSTATUS status = SysAudioReset(waveOut->NativeStream); if (status != NTLSTATUS_SUCCESS) result = WinmmMapNativeStatus(status); else waveOut->TerminalError = 0; resetBuffers = WinmmDetachAllBuffers(waveOut); waveOut->NativeSubmitted = 0; waveOut->Started = 0; waveOut->UserPaused = 0; waveOut->AutoPaused = 0; WinmmRefreshDiscontinuity(waveOut); } if (resetBuffers) WinmmCompleteDetachedBuffers(waveOut, resetBuffers); WinmmLock(&waveOut->Lock); waveOut->CommandResult = result; waveOut->Command = WinmmWaveCommandNone; WinmmUnlock(&waveOut->Lock); (void)SysSignalEvent(waveOut->CommandEvent); } // Returns the next queued node that still has source frames to submit. static WINMM_WAVE_BUFFER* WinmmFindSubmitNode(WINMM_WAVEOUT* waveOut) { WinmmLock(&waveOut->Lock); WINMM_WAVE_BUFFER* buffer = waveOut->SubmitNode; while (buffer && buffer->FullySubmitted) buffer = buffer->Next; waveOut->SubmitNode = buffer; WinmmUnlock(&waveOut->Lock); return buffer; } // Feeds queued buffers into the native ring until it becomes full or empty. static KSTATUS WinmmFeedNativeStream(WINMM_WAVEOUT* waveOut, uint32_t* madeProgressOut) { *madeProgressOut = 0; while (true) { WINMM_WAVE_BUFFER* buffer = WinmmFindSubmitNode(waveOut); if (!buffer) return NTLSTATUS_SUCCESS; uint32_t remaining = buffer->FrameCount - buffer->SubmittedFrames; if (!remaining) { buffer->FullySubmitted = 1; buffer->PresentedTarget = waveOut->NativeSubmitted; continue; } uint32_t requestFrames = remaining < WINMM_WRITE_CHUNK_FRAMES ? remaining : WINMM_WRITE_CHUNK_FRAMES; uint32_t writtenFrames = 0; SYS_AUDIO_WRITE_REQUEST request; memset(&request, 0, sizeof(request)); request.Size = sizeof(request); request.StreamHandle = waveOut->NativeStream; request.FrameCount = requestFrames; request.Frames = buffer->Frames + (size_t)buffer->SubmittedFrames * waveOut->SourceFormat.nChannels; request.WrittenFramesOut = &writtenFrames; KSTATUS status = SysAudioWrite(&request); if (status == NTLSTATUS_WOULD_BLOCK) return status; if (status != NTLSTATUS_SUCCESS) return status; if (!writtenFrames) return NTLSTATUS_WOULD_BLOCK; buffer->SubmittedFrames += writtenFrames; waveOut->NativeSubmitted += writtenFrames; *madeProgressOut = 1; if (buffer->SubmittedFrames == buffer->FrameCount) { buffer->FullySubmitted = 1; buffer->PresentedTarget = waveOut->NativeSubmitted; } } } // Determines whether any queued buffer still needs native-ring submission. static int WinmmHasUnsubmittedBuffer(WINMM_WAVEOUT* waveOut) { return WinmmFindSubmitNode(waveOut) != NULL; } // Starts or resumes playback after a useful prefill is available. static KSTATUS WinmmEnsureStarted(WINMM_WAVEOUT* waveOut) { if (waveOut->UserPaused) return NTLSTATUS_SUCCESS; if (!waveOut->Started) { KSTATUS status = SysAudioStart(waveOut->NativeStream); if (status == NTLSTATUS_SUCCESS) { waveOut->Started = 1; waveOut->AutoPaused = 0; } return status; } if (waveOut->AutoPaused) { KSTATUS status = SysAudioResume(waveOut->NativeStream); if (status == NTLSTATUS_SUCCESS) waveOut->AutoPaused = 0; return status; } return NTLSTATUS_SUCCESS; } // Stops a completed empty stream without resetting its public position counters. static void WinmmStopEmptyStream(WINMM_WAVEOUT* waveOut) { if (!waveOut->Started) return; (void)SysAudioStop(waveOut->NativeStream); waveOut->Started = 0; waveOut->AutoPaused = 0; WinmmRefreshDiscontinuity(waveOut); } // Arms native progress conditions and waits for either stream progress or new work. static KSTATUS WinmmWaitForWork(WINMM_WAVEOUT* waveOut, const SYS_AUDIO_STREAM_INFO* info, int hasUnsubmitted) { SYS_AUDIO_ARM_WAIT_REQUEST arm; memset(&arm, 0, sizeof(arm)); arm.Size = sizeof(arm); arm.StreamHandle = waveOut->NativeStream; arm.Mask = SYS_AUDIO_WAIT_FAILED | SYS_AUDIO_WAIT_DISCONTINUITY; arm.DiscontinuityGeneration = waveOut->KnownDiscontinuity; if (hasUnsubmitted && !waveOut->UserPaused) { arm.Mask |= SYS_AUDIO_WAIT_WRITABLE; arm.WritableFrames = 1; } WinmmLock(&waveOut->Lock); WINMM_WAVE_BUFFER* head = waveOut->QueueHead; if (head && head->FullySubmitted) { arm.Mask |= SYS_AUDIO_WAIT_PRESENTED; arm.PresentedFrames = head->PresentedTarget; } WinmmUnlock(&waveOut->Lock); if (!hasUnsubmitted && waveOut->Started && info->FramesConsumed < waveOut->NativeSubmitted) { arm.Mask |= SYS_AUDIO_WAIT_CONSUMED; arm.ConsumedFrames = waveOut->NativeSubmitted; } KSTATUS status = SysAudioArmWait(&arm); if (status != NTLSTATUS_SUCCESS) return status; uint32_t handles[2] = { waveOut->WakeEvent, waveOut->NativeStream }; uint32_t selected = 0; SYS_WAIT_MANY_REQUEST wait; memset(&wait, 0, sizeof(wait)); wait.Size = sizeof(wait); wait.Handles = handles; wait.Count = 2; wait.SignaledIndexOut = &selected; wait.TimeoutMilliseconds = SYS_WAIT_TIMEOUT_INFINITE; return SysWaitMany(&wait); } // Retires a failed stream and returns all queued headers to the application. static void WinmmFailStream(WINMM_WAVEOUT* waveOut, MMRESULT error) { waveOut->TerminalError = error ? error : MMSYSERR_ERROR; WinmmDebugResult("stream failure", waveOut, waveOut->TerminalError); (void)SysAudioStop(waveOut->NativeStream); waveOut->Started = 0; waveOut->AutoPaused = 0; WINMM_WAVE_BUFFER* buffers = WinmmDetachAllBuffers(waveOut); WinmmCompleteDetachedBuffers(waveOut, buffers); } // Runs one waveform-output worker until close or process teardown. static void WinmmWaveWorker(uintptr_t argument) { WINMM_WAVEOUT* waveOut = (WINMM_WAVEOUT*)argument; waveOut->WorkerTid = SysGetCurrentTid(); WinmmNotify(waveOut, WOM_OPEN, 0, 0); (void)SysSignalEvent(waveOut->ReadyEvent); while (true) { WinmmProcessCommand(waveOut); if (waveOut->Closing) { WinmmStopEmptyStream(waveOut); WinmmNotify(waveOut, WOM_CLOSE, 0, 0); SysExitThread(0); } if (waveOut->TerminalError) { uint32_t handles[1] = { waveOut->WakeEvent }; uint32_t selected = 0; SYS_WAIT_MANY_REQUEST wait = { sizeof(wait), 0, handles, 1, &selected, SYS_WAIT_TIMEOUT_INFINITE }; (void)SysWaitMany(&wait); continue; } SYS_AUDIO_STREAM_INFO info; KSTATUS status = WinmmQueryNativeStream(waveOut, &info); if (status != NTLSTATUS_SUCCESS || info.State == SysAudioStreamFailed) { WinmmFailStream(waveOut, WinmmMapNativeStatus( status != NTLSTATUS_SUCCESS ? status : info.FailureStatus)); continue; } if (info.DiscontinuityGeneration != waveOut->KnownDiscontinuity) { // A native discontinuity is a timeline notification, not a stream // failure. The failed state remains the terminal error authority. waveOut->KnownDiscontinuity = info.DiscontinuityGeneration; WinmmDebugResult("stream discontinuity", waveOut, waveOut->KnownDiscontinuity); } WinmmCompletePresentedBuffers(waveOut, info.FramesPresented); WinmmLock(&waveOut->Lock); int queueEmpty = waveOut->QueueHead == NULL; WinmmUnlock(&waveOut->Lock); if (queueEmpty) { WinmmStopEmptyStream(waveOut); status = WinmmWaitForWork(waveOut, &info, 0); if (status != NTLSTATUS_SUCCESS) WinmmFailStream(waveOut, WinmmMapNativeStatus(status)); continue; } if (!waveOut->UserPaused) { uint32_t madeProgress = 0; status = WinmmFeedNativeStream(waveOut, &madeProgress); if (status != NTLSTATUS_SUCCESS && status != NTLSTATUS_WOULD_BLOCK) { WinmmFailStream(waveOut, WinmmMapNativeStatus(status)); continue; } if (waveOut->NativeSubmitted && (!waveOut->Started || waveOut->AutoPaused)) { status = WinmmEnsureStarted(waveOut); if (status != NTLSTATUS_SUCCESS) { WinmmFailStream(waveOut, WinmmMapNativeStatus(status)); continue; } } if (madeProgress) continue; } status = WinmmQueryNativeStream(waveOut, &info); if (status != NTLSTATUS_SUCCESS) { WinmmFailStream(waveOut, WinmmMapNativeStatus(status)); continue; } int hasUnsubmitted = WinmmHasUnsubmittedBuffer(waveOut); if (!hasUnsubmitted && waveOut->Started && !waveOut->UserPaused && !waveOut->AutoPaused && info.FramesConsumed >= waveOut->NativeSubmitted) { status = SysAudioPause(waveOut->NativeStream); if (status == NTLSTATUS_SUCCESS) waveOut->AutoPaused = 1; else { WinmmFailStream(waveOut, WinmmMapNativeStatus(status)); continue; } } status = WinmmWaitForWork(waveOut, &info, hasUnsubmitted); if (status != NTLSTATUS_SUCCESS) WinmmFailStream(waveOut, WinmmMapNativeStatus(status)); } } // Submits one synchronous worker command and waits for its completion. static MMRESULT WinmmSubmitCommand(WINMM_WAVEOUT* waveOut, WINMM_WAVE_COMMAND command) { if (waveOut->WorkerTid == SysGetCurrentTid()) return MMSYSERR_HANDLEBUSY; WinmmLock(&waveOut->Lock); if (waveOut->Command != WinmmWaveCommandNone) { WinmmUnlock(&waveOut->Lock); return MMSYSERR_ALLOCATED; } waveOut->Command = command; waveOut->CommandResult = MMSYSERR_ERROR; WinmmUnlock(&waveOut->Lock); (void)SysSignalEvent(waveOut->WakeEvent); KSTATUS status = SysWait(waveOut->CommandEvent, SYS_WAIT_FLAG_NONE); if (status != NTLSTATUS_SUCCESS) return WinmmMapNativeStatus(status); return waveOut->CommandResult; } // Returns the number of available logical waveform output devices. __declspec(dllexport) UINT waveOutGetNumDevs(void) { return WinmmAvailableEndpointCount(); } // Opens one waveform output handle or validates one format query. __declspec(dllexport) MMRESULT waveOutOpen(HWAVEOUT* handleOut, UINT deviceId, const WAVEFORMATEX* format, DWORD_PTR callback, DWORD_PTR callbackInstance, DWORD flags) { WinmmDebugOpenRequest(deviceId, format, flags); MMRESULT result = WinmmValidateFormat(format); if (result != MMSYSERR_NOERROR) { WinmmDebugResult("open rejected format", NULL, result); return result; } if (flags & ~WINMM_WAVE_OPEN_SUPPORTED_FLAGS) { WinmmDebugResult("open rejected flags", NULL, flags & ~WINMM_WAVE_OPEN_SUPPORTED_FLAGS); return MMSYSERR_INVALFLAG; } uint32_t callbackMode = flags & CALLBACK_TYPEMASK; if (callbackMode == CALLBACK_WINDOW || callbackMode == CALLBACK_THREAD) { WinmmDebugResult("open rejected callback", NULL, callbackMode); return MMSYSERR_NOTSUPPORTED; } if (callbackMode != CALLBACK_NULL && callbackMode != CALLBACK_FUNCTION && callbackMode != CALLBACK_EVENT) return MMSYSERR_INVALFLAG; if ((callbackMode == CALLBACK_FUNCTION || callbackMode == CALLBACK_EVENT) && !callback) return MMSYSERR_INVALPARAM; uint64_t endpointId = 0; uint32_t resolvedDeviceId = 0; result = WinmmResolveEndpoint(deviceId, &endpointId, &resolvedDeviceId); if (result != MMSYSERR_NOERROR) { WinmmDebugResult("open rejected endpoint", NULL, result); return result; } if (flags & WAVE_FORMAT_QUERY) { return MMSYSERR_NOERROR; } if (!handleOut) return MMSYSERR_INVALPARAM; *handleOut = NULL; WINMM_WAVEOUT* waveOut = (WINMM_WAVEOUT*)calloc(1, sizeof(*waveOut)); if (!waveOut) return MMSYSERR_NOMEM; waveOut->Magic = WINMM_WAVEOUT_MAGIC; waveOut->EndpointId = endpointId; waveOut->SourceFormat = *format; waveOut->Callback = callback; waveOut->CallbackInstance = callbackInstance; waveOut->CallbackMode = callbackMode; waveOut->DeviceId = resolvedDeviceId; waveOut->Volume = 0xFFFFFFFFu; SYS_AUDIO_OPEN_STREAM_REQUEST open; memset(&open, 0, sizeof(open)); open.Size = sizeof(open); open.EndpointId = endpointId; open.Format.SampleRate = format->nSamplesPerSec; open.Format.ChannelCount = format->nChannels; open.Format.SampleFormat = SysAudioSampleS16; open.StreamHandleOut = &waveOut->NativeStream; KSTATUS status = SysAudioOpenStream(&open); if (status != NTLSTATUS_SUCCESS) { result = WinmmMapNativeStatus(status); WinmmDebugResult("native stream open failed", waveOut, status); free(waveOut); return result; } status = SysCreateEvent(0, 0, &waveOut->WakeEvent); if (status == NTLSTATUS_SUCCESS) status = SysCreateEvent(0, 0, &waveOut->CommandEvent); if (status == NTLSTATUS_SUCCESS) status = SysCreateEvent(0, 0, &waveOut->ReadyEvent); if (status != NTLSTATUS_SUCCESS) { result = WinmmMapNativeStatus(status); WinmmDebugResult("event creation failed", waveOut, status); if (waveOut->ReadyEvent) (void)SysCloseHandle(waveOut->ReadyEvent); if (waveOut->CommandEvent) (void)SysCloseHandle(waveOut->CommandEvent); if (waveOut->WakeEvent) (void)SysCloseHandle(waveOut->WakeEvent); (void)SysCloseHandle(waveOut->NativeStream); free(waveOut); return result; } SYS_AUDIO_STREAM_INFO info; status = WinmmQueryNativeStream(waveOut, &info); if (status != NTLSTATUS_SUCCESS) { result = WinmmMapNativeStatus(status); (void)SysCloseHandle(waveOut->ReadyEvent); (void)SysCloseHandle(waveOut->CommandEvent); (void)SysCloseHandle(waveOut->WakeEvent); (void)SysCloseHandle(waveOut->NativeStream); free(waveOut); return result; } waveOut->KnownDiscontinuity = info.DiscontinuityGeneration; WinmmRegisterWaveOut(waveOut); SYS_CREATE_THREAD_REQUEST thread; memset(&thread, 0, sizeof(thread)); thread.Entry = (uintptr_t)WinmmWaveWorker; thread.Argument = (uintptr_t)waveOut; thread.Priority = WINMM_WORKER_PRIORITY; thread.ThreadHandleOut = &waveOut->WorkerHandle; thread.ThreadIdOut = &waveOut->WorkerTid; status = SysCreateThread(&thread); if (status != NTLSTATUS_SUCCESS) { (void)WinmmRemoveWaveOut(waveOut); result = WinmmMapNativeStatus(status); WinmmDebugResult("worker creation failed", waveOut, status); (void)SysCloseHandle(waveOut->ReadyEvent); (void)SysCloseHandle(waveOut->CommandEvent); (void)SysCloseHandle(waveOut->WakeEvent); (void)SysCloseHandle(waveOut->NativeStream); free(waveOut); return result; } status = SysWaitSingle(waveOut->ReadyEvent, SYS_WAIT_FLAG_NONE, WINMM_WAIT_MILLISECONDS); (void)SysCloseHandle(waveOut->ReadyEvent); waveOut->ReadyEvent = 0; if (status != NTLSTATUS_SUCCESS) { waveOut->Closing = 1; (void)SysSignalEvent(waveOut->WakeEvent); (void)SysWait(waveOut->WorkerHandle, SYS_WAIT_FLAG_NONE); (void)WinmmRemoveWaveOut(waveOut); (void)SysCloseHandle(waveOut->WorkerHandle); (void)SysCloseHandle(waveOut->CommandEvent); (void)SysCloseHandle(waveOut->WakeEvent); (void)SysCloseHandle(waveOut->NativeStream); free(waveOut); return WinmmMapNativeStatus(status); } *handleOut = (HWAVEOUT)waveOut; WINMM_DEBUG_LINE line = {0}; WinmmDebugText(&line, "WINMM: open success handle="); WinmmDebugHex(&line, (uintptr_t)waveOut); WinmmDebugText(&line, " endpoint="); WinmmDebugU64(&line, endpointId); WinmmDebugText(&line, " stream="); WinmmDebugU64(&line, waveOut->NativeStream); WinmmDebugText(&line, " worker="); WinmmDebugU64(&line, waveOut->WorkerTid); WinmmDebugCommit(&line); return MMSYSERR_NOERROR; } // Closes one idle waveform handle after its worker sends WOM_CLOSE. __declspec(dllexport) MMRESULT waveOutClose(HWAVEOUT handle) { WINMM_WAVEOUT* waveOut = WinmmReferenceWaveOut(handle); if (!waveOut) return MMSYSERR_INVALHANDLE; if (waveOut->WorkerTid == SysGetCurrentTid()) { WinmmReleaseWaveOut(waveOut); return MMSYSERR_HANDLEBUSY; } WinmmLock(&waveOut->Lock); int busy = waveOut->QueueHead != NULL || waveOut->Command != WinmmWaveCommandNone; WinmmUnlock(&waveOut->Lock); if (busy) { WinmmDebugResult("close still playing", waveOut, waveOut->HeadersQueued - waveOut->HeadersCompleted); WinmmReleaseWaveOut(waveOut); return WAVERR_STILLPLAYING; } if (!WinmmRemoveWaveOut(waveOut)) { WinmmReleaseWaveOut(waveOut); return MMSYSERR_INVALHANDLE; } waveOut->Closing = 1; (void)SysSignalEvent(waveOut->WakeEvent); KSTATUS status = SysWait(waveOut->WorkerHandle, SYS_WAIT_FLAG_NONE); while (waveOut->ApiUsers > 1) (void)SysYield(); waveOut->Magic = 0; (void)SysCloseHandle(waveOut->WorkerHandle); (void)SysCloseHandle(waveOut->CommandEvent); (void)SysCloseHandle(waveOut->WakeEvent); (void)SysCloseHandle(waveOut->NativeStream); WinmmReleaseWaveOut(waveOut); MMRESULT result = status == NTLSTATUS_SUCCESS ? MMSYSERR_NOERROR : WinmmMapNativeStatus(status); WinmmDebugResult("close complete", waveOut, result); free(waveOut); return result; } // Marks one caller-owned header ready for waveform submission. __declspec(dllexport) MMRESULT waveOutPrepareHeader(HWAVEOUT handle, WAVEHDR* header, UINT size) { WINMM_WAVEOUT* waveOut = WinmmReferenceWaveOut(handle); if (!waveOut) return MMSYSERR_INVALHANDLE; if (!header || size < sizeof(*header)) { WinmmReleaseWaveOut(waveOut); return MMSYSERR_INVALPARAM; } WinmmLock(&waveOut->Lock); if (header->dwFlags & WHDR_INQUEUE) { WinmmUnlock(&waveOut->Lock); WinmmReleaseWaveOut(waveOut); return WAVERR_STILLPLAYING; } if ((header->dwFlags & WHDR_PREPARED) && header->reserved != (DWORD_PTR)waveOut) { WinmmUnlock(&waveOut->Lock); WinmmReleaseWaveOut(waveOut); return MMSYSERR_ALLOCATED; } header->dwFlags &= ~WHDR_DONE; header->dwFlags |= WHDR_PREPARED; header->reserved = (DWORD_PTR)waveOut; WinmmUnlock(&waveOut->Lock); WinmmReleaseWaveOut(waveOut); return MMSYSERR_NOERROR; } // Releases preparation state after one header is no longer queued. __declspec(dllexport) MMRESULT waveOutUnprepareHeader(HWAVEOUT handle, WAVEHDR* header, UINT size) { WINMM_WAVEOUT* waveOut = WinmmReferenceWaveOut(handle); if (!waveOut) return MMSYSERR_INVALHANDLE; if (!header || size < sizeof(*header)) { WinmmReleaseWaveOut(waveOut); return MMSYSERR_INVALPARAM; } WinmmLock(&waveOut->Lock); if (header->dwFlags & WHDR_INQUEUE) { WinmmUnlock(&waveOut->Lock); WinmmReleaseWaveOut(waveOut); return WAVERR_STILLPLAYING; } if ((header->dwFlags & WHDR_PREPARED) == 0 || header->reserved != (DWORD_PTR)waveOut) { WinmmUnlock(&waveOut->Lock); WinmmReleaseWaveOut(waveOut); return MMSYSERR_INVALPARAM; } header->dwFlags &= ~WHDR_PREPARED; header->reserved = 0; WinmmUnlock(&waveOut->Lock); WinmmReleaseWaveOut(waveOut); return MMSYSERR_NOERROR; } // Copies one prepared buffer immediately and appends it to the user-mode queue. __declspec(dllexport) MMRESULT waveOutWrite(HWAVEOUT handle, WAVEHDR* header, UINT size) { WINMM_WAVEOUT* waveOut = WinmmReferenceWaveOut(handle); if (!waveOut) return MMSYSERR_INVALHANDLE; if (!header || size < sizeof(*header)) { WinmmReleaseWaveOut(waveOut); return MMSYSERR_INVALPARAM; } WinmmLock(&waveOut->Lock); if ((header->dwFlags & WHDR_PREPARED) == 0 || header->reserved != (DWORD_PTR)waveOut) { WinmmUnlock(&waveOut->Lock); WinmmReleaseWaveOut(waveOut); return WAVERR_UNPREPARED; } if (header->dwFlags & WHDR_INQUEUE) { WinmmUnlock(&waveOut->Lock); WinmmReleaseWaveOut(waveOut); return WAVERR_STILLPLAYING; } if ((header->dwFlags & (WHDR_BEGINLOOP | WHDR_ENDLOOP)) || header->dwLoops) { WinmmUnlock(&waveOut->Lock); WinmmReleaseWaveOut(waveOut); return MMSYSERR_NOTSUPPORTED; } if (waveOut->TerminalError) { MMRESULT error = waveOut->TerminalError; WinmmUnlock(&waveOut->Lock); WinmmReleaseWaveOut(waveOut); return error; } header->dwFlags &= ~WHDR_DONE; header->dwFlags |= WHDR_INQUEUE; WinmmUnlock(&waveOut->Lock); WINMM_WAVE_BUFFER* buffer = (WINMM_WAVE_BUFFER*)calloc(1, sizeof(*buffer)); if (!buffer) { WinmmLock(&waveOut->Lock); header->dwFlags &= ~WHDR_INQUEUE; WinmmUnlock(&waveOut->Lock); WinmmReleaseWaveOut(waveOut); return MMSYSERR_NOMEM; } MMRESULT result = WinmmCopyFrames(waveOut, header, &buffer->Frames, &buffer->FrameCount); if (result != MMSYSERR_NOERROR) { WinmmLock(&waveOut->Lock); header->dwFlags &= ~WHDR_INQUEUE; WinmmUnlock(&waveOut->Lock); free(buffer); WinmmReleaseWaveOut(waveOut); return result; } buffer->Header = header; if (!buffer->FrameCount) { buffer->FullySubmitted = 1; buffer->PresentedTarget = waveOut->NativeSubmitted; } WinmmLock(&waveOut->Lock); if (waveOut->Closing) { header->dwFlags &= ~WHDR_INQUEUE; WinmmUnlock(&waveOut->Lock); free(buffer->Frames); free(buffer); WinmmReleaseWaveOut(waveOut); return MMSYSERR_INVALHANDLE; } waveOut->HeadersQueued++; waveOut->FramesQueued += buffer->FrameCount; buffer->Sequence = waveOut->HeadersQueued; if (waveOut->QueueTail) waveOut->QueueTail->Next = buffer; else waveOut->QueueHead = buffer; waveOut->QueueTail = buffer; if (!waveOut->SubmitNode) waveOut->SubmitNode = buffer; WinmmUnlock(&waveOut->Lock); (void)SysSignalEvent(waveOut->WakeEvent); WinmmReleaseWaveOut(waveOut); return MMSYSERR_NOERROR; } // Pauses future source consumption while preserving queued headers. __declspec(dllexport) MMRESULT waveOutPause(HWAVEOUT handle) { WINMM_WAVEOUT* waveOut = WinmmReferenceWaveOut(handle); if (!waveOut) return MMSYSERR_INVALHANDLE; MMRESULT result = WinmmSubmitCommand(waveOut, WinmmWaveCommandPause); WinmmReleaseWaveOut(waveOut); return result; } // Resumes a user-paused waveform queue. __declspec(dllexport) MMRESULT waveOutRestart(HWAVEOUT handle) { WINMM_WAVEOUT* waveOut = WinmmReferenceWaveOut(handle); if (!waveOut) return MMSYSERR_INVALHANDLE; MMRESULT result = WinmmSubmitCommand(waveOut, WinmmWaveCommandRestart); WinmmReleaseWaveOut(waveOut); return result; } // Stops playback and returns every queued header as completed. __declspec(dllexport) MMRESULT waveOutReset(HWAVEOUT handle) { WINMM_WAVEOUT* waveOut = WinmmReferenceWaveOut(handle); if (!waveOut) return MMSYSERR_INVALHANDLE; MMRESULT result = WinmmSubmitCommand(waveOut, WinmmWaveCommandReset); WinmmReleaseWaveOut(waveOut); return result; } // Applies independent WinMM left and right volume values through native gain and pan. __declspec(dllexport) MMRESULT waveOutSetVolume(HWAVEOUT handle, DWORD volume) { WINMM_WAVEOUT* waveOut = WinmmReferenceWaveOut(handle); if (!waveOut) return MMSYSERR_INVALHANDLE; uint32_t left = volume & 0xFFFFu; uint32_t right = (volume >> 16u) & 0xFFFFu; uint32_t maximum = left > right ? left : right; uint32_t volumeQ16 = maximum ? (uint32_t)(((uint64_t)maximum * 65536u) / 65535u) : 0u; int32_t panQ16 = 0; if (left > right && left) panQ16 = -(int32_t)(((uint64_t)(left - right) * 65536u) / left); else if (right > left && right) panQ16 = (int32_t)(((uint64_t)(right - left) * 65536u) / right); SYS_AUDIO_SET_VOLUME_REQUEST request; memset(&request, 0, sizeof(request)); request.Size = sizeof(request); request.StreamHandle = waveOut->NativeStream; request.VolumeQ16 = volumeQ16; request.PanQ16 = panQ16; KSTATUS status = SysAudioSetVolume(&request); if (status == NTLSTATUS_SUCCESS) waveOut->Volume = volume; WinmmReleaseWaveOut(waveOut); return WinmmMapNativeStatus(status); } // Returns the last WinMM left and right volume value accepted for this handle. __declspec(dllexport) MMRESULT waveOutGetVolume(HWAVEOUT handle, DWORD* volumeOut) { WINMM_WAVEOUT* waveOut = WinmmReferenceWaveOut(handle); if (!waveOut) return MMSYSERR_INVALHANDLE; if (!volumeOut) { WinmmReleaseWaveOut(waveOut); return MMSYSERR_INVALPARAM; } *volumeOut = waveOut->Volume; WinmmReleaseWaveOut(waveOut); return MMSYSERR_NOERROR; } // Reports source-frame progress using the requested MMTIME unit. __declspec(dllexport) MMRESULT waveOutGetPosition(HWAVEOUT handle, MMTIME* timeOut, UINT size) { WINMM_WAVEOUT* waveOut = WinmmReferenceWaveOut(handle); if (!waveOut) return MMSYSERR_INVALHANDLE; if (!timeOut || size < sizeof(*timeOut)) { WinmmReleaseWaveOut(waveOut); return MMSYSERR_INVALPARAM; } SYS_AUDIO_STREAM_INFO info; KSTATUS status = WinmmQueryNativeStream(waveOut, &info); if (status != NTLSTATUS_SUCCESS) { WinmmReleaseWaveOut(waveOut); return WinmmMapNativeStatus(status); } uint64_t frames = info.FramesPresented; if (timeOut->wType == TIME_BYTES) { uint64_t bytes = frames * waveOut->SourceFormat.nBlockAlign; timeOut->u.cb = bytes > UINT32_MAX ? UINT32_MAX : (uint32_t)bytes; } else if (timeOut->wType == TIME_SAMPLES) { timeOut->u.sample = frames > UINT32_MAX ? UINT32_MAX : (uint32_t)frames; } else { uint64_t milliseconds = frames * 1000u / waveOut->SourceFormat.nSamplesPerSec; timeOut->wType = TIME_MS; timeOut->u.ms = milliseconds > UINT32_MAX ? UINT32_MAX : (uint32_t)milliseconds; } WinmmReleaseWaveOut(waveOut); return MMSYSERR_NOERROR; } // Returns the device index selected when the waveform handle was opened. __declspec(dllexport) MMRESULT waveOutGetID(HWAVEOUT handle, UINT* deviceIdOut) { WINMM_WAVEOUT* waveOut = WinmmReferenceWaveOut(handle); if (!waveOut) return MMSYSERR_INVALHANDLE; if (!deviceIdOut) { WinmmReleaseWaveOut(waveOut); return MMSYSERR_INVALPARAM; } *deviceIdOut = waveOut->DeviceId; WinmmReleaseWaveOut(waveOut); return MMSYSERR_NOERROR; } // Fills the minimal ANSI device capabilities supported by this personality. __declspec(dllexport) MMRESULT waveOutGetDevCapsA(UINT deviceId, WAVEOUTCAPSA* caps, UINT size) { uint64_t endpointId = 0; uint32_t resolvedDeviceId = 0; MMRESULT result = WinmmResolveEndpoint(deviceId, &endpointId, &resolvedDeviceId); if (result != MMSYSERR_NOERROR) { WinmmDebugResult("device caps rejected", NULL, result); return result; } (void)endpointId; (void)resolvedDeviceId; if (!caps || size < sizeof(*caps)) return MMSYSERR_INVALPARAM; memset(caps, 0, sizeof(*caps)); caps->vDriverVersion = 0x00010000u; memcpy(caps->szPname, "nt-lite analog output", sizeof("nt-lite analog output")); caps->dwFormats = WAVE_FORMAT_1M16 | WAVE_FORMAT_1S16 | WAVE_FORMAT_2M16 | WAVE_FORMAT_2S16 | WAVE_FORMAT_4M16 | WAVE_FORMAT_4S16 | WAVE_FORMAT_48M16 | WAVE_FORMAT_48S16; caps->wChannels = 2; caps->dwSupport = WAVECAPS_VOLUME | WAVECAPS_LRVOLUME; return MMSYSERR_NOERROR; } // Fills the minimal wide device capabilities supported by this personality. __declspec(dllexport) MMRESULT waveOutGetDevCapsW(UINT deviceId, WAVEOUTCAPSW* caps, UINT size) { if (!caps || size < sizeof(*caps)) return MMSYSERR_INVALPARAM; WAVEOUTCAPSA ansi; MMRESULT result = waveOutGetDevCapsA(deviceId, &ansi, sizeof(ansi)); if (result != MMSYSERR_NOERROR) return result; memset(caps, 0, sizeof(*caps)); caps->wMid = ansi.wMid; caps->wPid = ansi.wPid; caps->vDriverVersion = ansi.vDriverVersion; for (uint32_t index = 0; index < 32u && ansi.szPname[index]; index++) caps->szPname[index] = (unsigned short)(uint8_t)ansi.szPname[index]; caps->dwFormats = ansi.dwFormats; caps->wChannels = ansi.wChannels; caps->dwSupport = ansi.dwSupport; return MMSYSERR_NOERROR; } // Copies one fixed WinMM error description to an ANSI buffer. __declspec(dllexport) MMRESULT waveOutGetErrorTextA(MMRESULT error, char* text, UINT characters) { if (!text || !characters) return MMSYSERR_INVALPARAM; const char* message = "Unknown waveform output error"; switch (error) { case MMSYSERR_NOERROR: message = "No error"; break; case MMSYSERR_BADDEVICEID: message = "Bad waveform output device ID"; break; case MMSYSERR_INVALHANDLE: message = "Invalid waveform output handle"; break; case MMSYSERR_NOMEM: message = "Not enough memory"; break; case MMSYSERR_NOTSUPPORTED: message = "Operation not supported"; break; case MMSYSERR_INVALFLAG: message = "Invalid waveform output flags"; break; case MMSYSERR_INVALPARAM: message = "Invalid waveform output parameter"; break; case WAVERR_BADFORMAT: message = "Unsupported waveform format"; break; case WAVERR_STILLPLAYING: message = "Waveform buffer is still playing"; break; case WAVERR_UNPREPARED: message = "Waveform header is not prepared"; break; default: break; } uint32_t index = 0; while (index + 1u < characters && message[index]) { text[index] = message[index]; index++; } text[index] = '\0'; return MMSYSERR_NOERROR; } // Copies one fixed WinMM error description to a wide buffer. __declspec(dllexport) MMRESULT waveOutGetErrorTextW(MMRESULT error, unsigned short* text, UINT characters) { if (!text || !characters) return MMSYSERR_INVALPARAM; char ansi[96]; MMRESULT result = waveOutGetErrorTextA(error, ansi, sizeof(ansi)); if (result != MMSYSERR_NOERROR) return result; uint32_t index = 0; while (index + 1u < characters && ansi[index]) { text[index] = (unsigned short)(uint8_t)ansi[index]; index++; } text[index] = 0; return MMSYSERR_NOERROR; } // Rejects loop-breaking because looped headers are not part of this implementation. __declspec(dllexport) MMRESULT waveOutBreakLoop(HWAVEOUT handle) { WINMM_WAVEOUT* waveOut = WinmmReferenceWaveOut(handle); if (!waveOut) return MMSYSERR_INVALHANDLE; WinmmReleaseWaveOut(waveOut); return MMSYSERR_NOTSUPPORTED; } // Rejects driver-specific waveform messages instead of pretending they succeeded. __declspec(dllexport) MMRESULT waveOutMessage(HWAVEOUT handle, UINT message, DWORD_PTR parameter1, DWORD_PTR parameter2) { (void)message; (void)parameter1; (void)parameter2; WINMM_WAVEOUT* waveOut = WinmmReferenceWaveOut(handle); if (!waveOut) return MMSYSERR_INVALHANDLE; WinmmReleaseWaveOut(waveOut); return MMSYSERR_NOTSUPPORTED; }