{"record":{"id":"873ef3686487aab5","repo":"AlexxIT/go2rtc","slug":"speaker-channel-not-connected","errorCode":null,"errorMessage":"speaker channel not connected","messagePattern":"speaker channel not connected","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/wyze/client.go","lineNumber":242,"sourceCode":"\nfunc (c *Client) StopIntercom() error {\n\tif c.conn == nil || !c.conn.IsBackchannelReady() {\n\t\treturn nil\n\t}\n\n\tk10010 := c.buildK10010(MediaTypeReturnAudio, false)\n\tc.conn.WriteIOCtrl(k10010)\n\n\treturn c.conn.AVServStop()\n}\n\nfunc (c *Client) ReadPacket() (*tutk.Packet, error) {\n\treturn c.conn.AVRecvFrameData()\n}\n\nfunc (c *Client) WriteAudio(codec byte, payload []byte, timestamp uint32, sampleRate uint32, channels uint8) error {\n\tif !c.conn.IsBackchannelReady() {\n\t\treturn fmt.Errorf(\"speaker channel not connected\")\n\t}\n\n\tif c.verbose {\n\t\tfmt.Printf(\"[Wyze] WriteAudio: codec=0x%02x, payload=%d bytes, rate=%d, ch=%d\\n\", codec, len(payload), sampleRate, channels)\n\t}\n\n\treturn c.conn.AVSendAudioData(codec, payload, timestamp, sampleRate, channels)\n}\n\nfunc (c *Client) SetDeadline(t time.Time) error {\n\tif c.conn != nil {\n\t\treturn c.conn.SetDeadline(t)\n\t}\n\treturn nil\n}\n\nfunc (c *Client) Protocol() string {\n\treturn \"wyze/dtls\"","sourceCodeStart":224,"sourceCodeEnd":260,"githubUrl":"https://github.com/AlexxIT/go2rtc/blob/c245815e75e2a5fd60b4290f12bfc04e55a984d3/pkg/wyze/client.go#L224-L260","documentation":"WriteAudio sends encoded audio frames over the backchannel (speaker) channel. Before writing it checks conn.IsBackchannelReady(); if the intercom channel was never enabled (StartIntercom not called or not yet acknowledged), the write is refused with this error.","triggerScenarios":"Calling WriteAudio without a prior successful StartIntercom; StartIntercom still in flight (backchannel not yet ready); backchannel dropped after a reconnect or camera-side channel close.","commonSituations":"Pushing microphone frames into WriteAudio as soon as a track is added, before the camera acknowledged the control-channel response; session reconnect cleared backchannel readiness; Opus/AAC frames queued during connection setup.","solutions":["Call StartIntercom and wait until conn.IsBackchannelReady() (or intercom-ready signal) before writing audio.","Gate the audio-send loop with a ready flag/condition variable instead of calling WriteAudio unconditionally.","After any reconnect, re-run StartIntercom to re-enable the speaker channel.","Buffer or drop outgoing frames while the backchannel is not ready instead of erroring per-frame."],"exampleFix":"// before\nclient.WriteAudio(codec, payload, ts, 16000, 1)\n\n// after\nif client.IsBackchannelReady() {\n    if err := client.WriteAudio(codec, payload, ts, 16000, 1); err != nil {\n        log.Printf(\"write audio: %v\", err)\n    }\n}","handlingStrategy":"type-guard","validationCode":"if !client.IsBackchannelReady() {\n    return fmt.Errorf(\"backchannel not ready; call StartIntercom first\")\n}","typeGuard":"func canWriteAudio(c *wyze.Client) bool { return c != nil && c.IsBackchannelReady() }","tryCatchPattern":"if err := client.WriteAudio(codec, payload, ts, rate, ch); err != nil {\n    if strings.Contains(err.Error(), \"speaker channel not connected\") {\n        // drop frame or re-enable intercom\n        return errBackchannelDown\n    }\n    return err\n}","preventionTips":["Gate the audio write loop on IsBackchannelReady","Call StartIntercom at session setup and after every reconnect","Queue frames until the backchannel signals ready instead of failing"],"tags":["go","iot","audio","state-machine"],"backgroundTag":"invalid-state-transition","analyzedSha":"c245815e75e2a5fd60b4290f12bfc04e55a984d3","analyzedAt":"2026-09-07T11:47:02.965Z","contentChangedAt":"2026-09-07T11:47:02.965Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}