{"record":{"id":"f0f1aa21bf9865f5","repo":"AlexxIT/go2rtc","slug":"av-server-not-ready","errorCode":null,"errorMessage":"av server not ready","messagePattern":"av server not ready","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/tutk/dtls/conn_dtls.go","lineNumber":332,"sourceCode":"\nfunc (c *DTLSConn) AVRecvFrameData() (*tutk.Packet, error) {\n\tselect {\n\tcase pkt, ok := <-c.frames.Recv():\n\t\tif !ok {\n\t\t\treturn nil, c.Error()\n\t\t}\n\t\treturn pkt, nil\n\tcase <-c.ctx.Done():\n\t\treturn nil, c.Error()\n\t}\n}\n\nfunc (c *DTLSConn) AVSendAudioData(codec byte, payload []byte, timestampUS uint32, sampleRate uint32, channels uint8) error {\n\tc.mu.Lock()\n\tconn := c.serverConn\n\tif conn == nil {\n\t\tc.mu.Unlock()\n\t\treturn fmt.Errorf(\"av server not ready\")\n\t}\n\n\tframe := c.msgAudioFrame(payload, timestampUS, codec, sampleRate, channels)\n\n\tc.mu.Unlock()\n\n\tn, err := conn.Write(frame)\n\tif c.verbose {\n\t\tif err != nil {\n\t\t\tfmt.Printf(\"[SERVER TX] DTLS Write ERROR: %v\\n\", err)\n\t\t} else {\n\t\t\tfmt.Printf(\"[SERVER TX] len=%d, data:\\n%s\", n, hexDump(frame))\n\t\t}\n\t}\n\treturn err\n}\n\nfunc (c *DTLSConn) Write(data []byte) error {","sourceCodeStart":314,"sourceCodeEnd":350,"githubUrl":"https://github.com/AlexxIT/go2rtc/blob/c245815e75e2a5fd60b4290f12bfc04e55a984d3/pkg/tutk/dtls/conn_dtls.go#L314-L350","documentation":"AVSendAudioData requires an established DTLS server connection (serverConn). If none exists when audio is sent, the library returns this sentinel-style error instead of writing. It means audio was requested before the server-side AV session was ready.","triggerScenarios":"Calling WriteAudio -> AVSendAudioData before StartIntercom/AVServStart has completed and assigned c.serverConn, or after the session failed and serverConn was never set / was torn down.","commonSituations":"Application starts streaming audio before the intercom handshake finishes; a prior handshake error left the session dead while the audio pump keeps running; race between session teardown and the audio writer loop.","solutions":["Only start the audio pump after StartIntercom returns successfully","Re-run the intercom/AV server setup before resuming audio sends","Check whether serverConn was invalidated by an earlier handshake failure and restart the session","Serialize session teardown and audio writing to avoid races"],"exampleFix":"// before\nerr := conn.WriteAudio(payload)\n// after\nif err := intercom.StartIntercom(ctx); err != nil {\n\treturn fmt.Errorf(\"cannot stream audio, session not established: %w\", err)\n}\nerr := conn.WriteAudio(payload)","handlingStrategy":"try-catch","validationCode":"if conn == nil || !conn.HasTwoWayStreaming() {\n\treturn fmt.Errorf(\"start intercom before writing audio\")\n}","typeGuard":"func audioReady(c *dtls.DTLSConn) bool {\n\treturn c != nil && c.HasTwoWayStreaming()\n}","tryCatchPattern":"if err := conn.WriteAudio(frame); err != nil {\n\tif err.Error() == \"av server not ready\" {\n\t\t// (re)establish session, then resume audio pump\n\t}\n}","preventionTips":["Gate the audio writer loop on successful StartIntercom completion","Stop the audio pump when the session tears down","Re-establish the session before resuming audio","Avoid racing teardown against audio writes"],"tags":["state","audio","intercom","lifecycle"],"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"}