AlexxIT/go2rtc · error
speaker wait failed
Error message
speaker wait failed: %w
What it means
SendSpeaker publishes a speaker protocol message and then blocks on speakerWaiter.Wait(), which is completed by onMqttSpeaker when the camera responds. This error wraps any error the waiter was completed with — i.e. the camera replied with a non-zero resCode (delivered via error 316) or the wait timed out / was cancelled by the waiter implementation. It's the user-facing signal that the speaker command failed at the device level.
Solutions
- Unwrap the error to see the underlying cause (resCode value vs timeout) and handle each distinctly
- Increase/verify the waiter timeout to accommodate camera wake-up latency
- Ensure the camera is awake (call WakeUp first) and subscribed to response topics
- Check the speaker request payload parameters against what the device model supports
Example fix
// before
err := client.SendSpeaker(sdp, res, streamType, hevc)
// after
err := client.SendSpeaker(sdp, res, streamType, hevc)
if err != nil && strings.Contains(err.Error(), "speaker wait failed") {
if strings.Contains(err.Error(), "resCode") { return err }
// timeout path: retry once after waking the device
_ = client.WakeUp(deviceID)
err = client.SendSpeaker(sdp, res, streamType, hevc)
} Defensive patterns
Strategy: try-catch
Validate before calling
// ensure device is awake before speaker commands
if !deviceAwake { if err := client.WakeUp(deviceID); err != nil { return err } } Try / catch
err := client.SendSpeaker(...)
if err != nil {
if strings.Contains(err.Error(), "resCode") { return fmt.Errorf("device rejected: %v", err) }
// else treat as timeout: retry once
} Prevention
- Set waiter timeouts longer than camera wake-up latency
- Serialize speaker commands with a mutex
- Wake the device explicitly before SendSpeaker
When it happens
Trigger: Calling SendSpeaker when the camera responds with resCode != 0, or the waiter times out because no speaker response arrives (camera offline, wrong dps payload rejected), or the wait context is cancelled.
Common situations: Camera busy or in low-power sleep and not answering within the wait window, unsupported audio parameters in the speaker request, or MQTT responses arriving on a topic the client isn't subscribed to.
Understand the failure class
Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.
Related errors
- speaker failed with resCode
- openIoTHubConfigResponse.Msg
- failed to publish wake-up message
- failed to subscribe to lowPower topic
- mqtt client is closed, send mqtt message fail
AI-assisted analysis of AlexxIT/go2rtc@c245815e75 (2026-09-07).
Data as JSON: /api/errors/c9d9e3dfe8287c5d.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/tuya/mqtt.go:263
}
return c.sendMqttMessage("resolution", 312, "", ResolutionFrame{
Mode: "webrtc",
Value: resolution, // 0: HD, 1: SD
})
}
func (c *TuyaMqttClient) SendSpeaker(speaker int) error {
if err := c.sendMqttMessage("speaker", 312, "", SpeakerFrame{
Mode: "webrtc",
Value: speaker, // 0: off, 1: on
}); err != nil {
return err
}
// Wait for camera response
if err := c.speakerWaiter.Wait(); err != nil {
return fmt.Errorf("speaker wait failed: %w", err)
}
return nil
}
func (c *TuyaMqttClient) SendDisconnect() error {
return c.sendMqttMessage("disconnect", 302, "", DisconnectFrame{
Mode: "webrtc",
})
}
func (c *TuyaMqttClient) onConnect(client mqtt.Client) {
if token := client.Subscribe(c.subscribeTopic, 1, c.onMessage); token.Wait() && token.Error() != nil {
c.waiter.Done(token.Error())
return
}
c.waiter.Done(nil)View on GitHub (pinned to c245815e75)