{"record":{"id":"3469d18e5ac8165a","repo":"AlexxIT/go2rtc","slug":"multitrans-talkback-error-s","errorCode":null,"errorMessage":"multitrans: talkback error: %s","messagePattern":"multitrans: talkback error: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/multitrans/client.go","lineNumber":185,"sourceCode":"\tdata := fmt.Sprintf(\"MULTITRANS %s RTSP/1.0\\r\\nCSeq: 2\\r\\nSession: %s\\r\\nContent-Type: application/json\\r\\nContent-Length: %d\\r\\n\\r\\n%s\",\n\t\turi, session, len(payload), payload)\n\n\tif _, err := c.conn.Write([]byte(data)); err != nil {\n\t\treturn err\n\t}\n\n\tres, err := tcp.ReadResponse(c.rd)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif res.StatusCode != http.StatusOK {\n\t\treturn errors.New(\"multitrans: talkback failed: \" + res.Status)\n\t}\n\n\t// Python checks for \"error_code\":0 in body.\n\tif !bytes.Contains(res.Body, []byte(`\"error_code\":0`)) {\n\t\treturn fmt.Errorf(\"multitrans: talkback error: %s\", string(res.Body))\n\t}\n\n\treturn nil\n}\n\nfunc (c *Client) GetTrack(media *core.Media, codec *core.Codec) (*core.Receiver, error) {\n\treturn nil, core.ErrCantGetTrack\n}\n\nfunc (c *Client) Start() error {\n\t_ = c.closed.Wait()\n\treturn nil\n}\n\nfunc (c *Client) Stop() error {\n\tc.closed.Done(nil)\n\treturn c.Connection.Stop()\n}","sourceCodeStart":167,"sourceCodeEnd":203,"githubUrl":"https://github.com/AlexxIT/go2rtc/blob/c245815e75e2a5fd60b4290f12bfc04e55a984d3/pkg/multitrans/client.go#L167-L203","documentation":"openTalkChannel checks the Multitrans talkback HTTP response body for the literal \"error_code\":0 (mirroring the reference Python client). If the body lacks it, the whole response body is included in the error. The endpoint responded 200 OK but reported an application-level talkback failure.","triggerScenarios":"Opening a talkback (two-way audio) channel where the server returns a body with a non-zero error_code, a JSON shape like \"error_code\": 0 (with space, which the naive bytes.Contains misses), or an HTML error page instead of JSON.","commonSituations":"Camera rejects talkback because another client holds the audio channel; wrong credentials embedded in the talkback URL; device firmware returns pretty-printed JSON the string check misreads; talkback unsupported on the device model.","solutions":["Log/inspect string(res.Body) in the error to read the actual error_code and message.","Confirm the device supports talkback and no other session is using the audio channel.","Check the credentials/token used when constructing the talkback request URL.","Retry after closing other talkback sessions; some devices allow a single talkback client.","If the server uses spaced JSON, parse the body as JSON instead of the substring check (library-side fix)."],"exampleFix":"// before (client side retry loop slams an occupied channel)\nfor {\n    _ = client.StartTalkback(media)\n}\n// after\nif err := client.StartTalkback(media); err != nil {\n    log.Printf(\"talkback busy/failed: %v\", err)\n    time.Sleep(5 * time.Second)\n}","handlingStrategy":"try-catch","validationCode":"// check the device exposes a talkback endpoint before opening the channel\nif !device.Capabilities.Talkback { return errors.New(\"talkback unsupported\") }","typeGuard":null,"tryCatchPattern":"if err := openTalkback(media); err != nil {\n    if strings.Contains(err.Error(), \"talkback error\") {\n        log.Printf(\"talkback body: %v\", err) // includes raw response body\n        time.Sleep(backoff)\n        retry()\n    }\n}","preventionTips":["Serialize talkback sessions — one client at a time per camera","Verify device model supports two-way audio before wiring talkback","Read the embedded response body to distinguish busy vs auth errors","Add bounded retries with backoff for transient busy states"],"tags":["go","multitrans","talkback","api"],"backgroundTag":"api-error-response","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"}