Windows: stream.start() fails with "Unanticipated host error -9999 / WdmSyncIoctl" because the audio executor thread never initializes COM
Maintainers usually reply within 6 days
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 62/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- python
- Domain
- audio-video-rtc, cli
Research direction
The fix belongs in AudioPlayer.__init__ in sendspin/audio.py, where _stream_executor is created without an initializer. Read how start, stop and close are submitted to that executor, then add a Windows-only COM initialization for its worker thread. Done means stream.start() on a WASAPI device no longer raises PaErrorCode -9999, which needs a Windows machine to confirm. The reconnect-loop note in the report is a separate issue and should not be bundled into this fix.
Written by the indexing model from the issue text.
Description
Environment
Windows 11, Python 3.12.10 (venv), sendspin 7.6.0 (installed from the 7.6.0 tag), aiosendspin 9.1.1, sounddevice 0.5.6
Output device: a Realtek "Speakers" endpoint, host API "Windows WASAPI", 48 kHz
Server: Music Assistant 2.10.6 (Sendspin provider)
What happens sendspin daemon --url ws://:8927/sendspin --audio-device 12 connects and pairs fine, but as soon as playback starts:
INFO:sendspin.audio:Stream STARTED: 3 chunks, 0.29 seconds buffered
ERROR:sendspin.audio:Stream operation start failed
sounddevice.PortAudioError: Error starting stream: Unanticipated host error [PaErrorCode -9999]:
'WdmSyncIoctl: DeviceIoControl GLE = 0x00000490 ...' [Windows WDM-KS error 0]
(The WDM-KS text is the generic "last host error", the device itself is a WASAPI one.) Nothing is heard.
Isolated reproduction (no Sendspin involved) Same device, RawOutputStream(samplerate=48000, channels=2, dtype="int24", blocksize=2048, latency="high"):
create + start + stop in the main thread: works
create in main thread, start() in another thread: fails with the error above
create and start() both inside a secondary thread: fails
same, but calling ctypes.windll.ole32.CoInitializeEx(None, 0) at the beginning of that thread: works
So PortAudio's WASAPI backend needs COM initialized on the thread that opens/starts the stream, and AudioPlayer._stream_executor (a 1-worker ThreadPoolExecutor) never does that; stream.start()/stop()/close() are all submitted to it.
Fix that works for me (sendspin/audio.py, AudioPlayer.init):
def _com_init() -> None:
if sys.platform == "win32":
import ctypes
ctypes.windll.ole32.CoInitializeEx(None, 0) # COINIT_MULTITHREADED
self._stream_executor = concurrent.futures.ThreadPoolExecutor(
max_workers=1, thread_name_prefix="sendspin-audio", initializer=_com_init
)
With this, a 3-beep test file played from Music Assistant through the Sendspin daemon comes out of the speakers correctly.
Happy to open a PR if you prefer.
Also noticed (minor): running two daemons with the same identity makes them kick each other in a tight reconnect loop (thousands of connect/disconnect lines per second). A backoff on "replaced by a new connection" would avoid log floods.
- Dominant language
- Python
- Stars
- 195
- Forks
- 39
- Avg merge
- 5d 13h
- Merged PRs (30d)
- 8
Getting set up
This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from Sendspin/sendspin-python-cli
-
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
Sendspin/sendspin-python-cli#280 · 1 comment · 1 reaction ·
Maintainers usually reply within 6 days
-
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
Sendspin/sendspin-python-cli#278 · 2 comments · 5 reactions ·
Maintainers usually reply within 6 days
-
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
Sendspin/sendspin-python-cli#257 ·
Maintainers usually reply within 6 days
-
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
Sendspin/sendspin-python-cli#256 ·
Maintainers usually reply within 6 days
-
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
Sendspin/sendspin-python-cli#113 · 10 comments ·
Maintainers usually reply within 6 days
All issues in Sendspin/sendspin-python-cli
Similar issues
-
feedback simulation workshop
Difficulty 2/5 1-3 hours Newbie friendliness 73/100
githubnext/gh-aw-workshop#4455 ·
Maintainers usually reply within 1 day
-
Triage 🩺
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
Maintainers usually reply within 1 day
-
[BUG] Container scenario crashes without expected_recovery_time, kube DNS example uses retry_waitOpenneeds-triage
Difficulty 2/5 1-3 hours Newbie friendliness 77/100
krkn-chaos/krkn#1627 · 1 comment ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
NousResearch/hermes-agent#136483 ·
Maintainers usually reply within 1 day
-
Difficulty 1/5 Under an hour Newbie friendliness 88/100
Maintainers usually reply within 1 day