Skip to content

[BUG]: WinMM input cannot release queued buffers after device removal, retaining a MIDI Services connection #1157

Description

@darmolian

Summary

After an in-use MIDI input is physically disconnected, the WinMM client cannot complete its normal reset/close sequence. midiInReset and midiInStop return MMSYSERR_NODRIVER, while midiInClose repeatedly returns MIDIERR_STILLPLAYING. The client can open the reconnected endpoint and receive MIDI normally, but MIDI Services retains the old connection until the process exits.

MIDIERR_STILLPLAYING is expected while buffers remain queued. The issue is that the documented way to return those buffers, midiInReset, is rejected after the port has been invalidated, leaving the client without a successful cleanup path.

This reproduces with both a vendor-specific MIDI driver and Microsoft's class-compliant USB MIDI driver. It was also independently observed in Cubase 15.

AI Generated Content: This report and the public-source analysis were prepared with OpenAI Codex. I personally performed the hardware power-cycle tests and confirmed the application behavior described below.

Personal observation that led to this report

I became curious about why the connection instances reported for a WinMM session kept accumulating after a MIDI controller was powered off and back on. The controller reconnected and worked normally, but the session count increased instead of returning to one. We captured the session before and after a controlled power cycle, repeated the test with a second class-compliant USB-MIDI keyboard, and compared the behavior with Cubase 15. That testing is what led me to report the cleanup behavior.

Environment

  • Windows 11 Pro 25H2, build 26200.9168
  • midisrv.exe: 10.0.26100.7705
  • wdmaud2.drv: 10.0.26100.7705
  • Custom JUCE 9.0.0 application using WinMM MIDI input
  • Devices tested:
    • Native Instruments Komplete Kontrol S88 mk2 using Native Instruments driver 5.0.0.57 (nikksm2midi.inf)
    • Class-compliant USB-MIDI device, VID 0F54, PID 0101, using Microsoft usbmidi2.inf 10.0.26100.9168

The official MIDI Diagnostics Tool is not installed on this machine. Session data was captured directly from the MIDI Services session tracker before and after each cycle; the relevant count was 1 before removal, 2 after successful reconnection, and remained 2 in a delayed snapshot.

Steps and observed results

  1. Open a MIDI input through WinMM and start it. The MIDI Services session reports one instance for the endpoint.
  2. Power the controller off and wait for its endpoint to disappear.
  3. Power it back on and allow the application to reopen the returned endpoint.
  4. Inspect the WinMM results while releasing the old handle:
midiInReset: 6 (MMSYSERR_NODRIVER)
midiInStop:  6 (MMSYSERR_NODRIVER)
midiInClose: 65 (MIDIERR_STILLPLAYING), unchanged across five attempts
  1. The replacement midiInOpen and midiInStart both return success. MIDI from the reconnected keyboard reaches the loaded instrument and produces sound.
  2. The MIDI Services session now reports two instances for the same endpoint. The count remains two in a delayed snapshot.
  3. In the S88 test, exiting the client process removed the entire session, including the retained instance.

The same sequence and 1 -> 2 retained instance count reproduced with both devices listed above.

Independent application comparison

With Cubase 15 at its Hub and no project open, the S88 endpoint began with one instance. One S88 power cycle increased the same input endpoint to two instances. Several related S88/NI endpoints increased further, then stabilized. Exiting Cubase removed its entire session and all accumulated instances.

This comparison does not establish which close operations Cubase attempted, but it shows that retained instances after the same hot-plug event are not specific to the custom application.

Expected behavior

After surprise removal, WinMM should provide a cleanup path that returns queued input buffers and permits the obsolete handle and MIDI Services connection to close. Reopening the returned endpoint should leave only the replacement connection in the session.

Current public-source observation

Inspected at public main commit 3f16275e4ca10a084fc010a6b7c9a18c5976a504:

  • Device removal marks an open WinMM port invalidated: MidiSrvPorts.cpp.
  • Once invalidated, every input operation except MIDM_CLOSE returns MMSYSERR_NODRIVER, including MIDM_STOP and MIDM_RESET: MidiSrvPorts.cpp.
  • CMidiPort::Reset is the local operation that completes and removes queued input buffers, while CMidiPort::Close returns MIDIERR_STILLPLAYING if those buffers remain: MidiSrvPort.cpp.
  • Higher-level close and transport shutdown occur only after the port's close check succeeds: MidiSrvPorts.cpp.
  • Service-side device removal invalidates the device pipe but does not destroy its client connections: MidiClientManager.cpp.

This appears to leave a cleanup dead-end when an invalidated input has queued MIDIHDR buffers: reset is rejected because the device is gone, while close is rejected because reset could not return the buffers. Allowing local stop/reset cleanup for an invalidated port, or returning its queued buffers during removal, may resolve the cycle.

The public source was inspected but not built or substituted for the installed Windows components. Unpublished Microsoft source may differ from both the public revision and the installed binaries.

Related issues

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions