{"record":{"id":"ca36e279c4ff79bd","repo":"tonhowtf/omniget","slug":"edge-tts-nao-devolveu-audio-o-servico-pode-ter-mudado-o","errorCode":null,"errorMessage":"Edge TTS nao devolveu audio (o servico pode ter mudado o token; tente de novo mais tarde)","messagePattern":"Edge TTS nao devolveu audio \\(o servico pode ter mudado o token; tente de novo mais tarde\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-tauri/omniget-core/src/core/tools/edge_tts.rs","lineNumber":317,"sourceCode":"                    continue;\n                }\n                let header_len = u16::from_be_bytes([b[0], b[1]]) as usize;\n                if b.len() < header_len + 2 {\n                    continue;\n                }\n                let header = String::from_utf8_lossy(&b[2..2 + header_len]);\n                if header.contains(\"Path:audio\") {\n                    audio.extend_from_slice(&b[2 + header_len..]);\n                    got_audio = true;\n                }\n            }\n            Message::Close(_) => break,\n            _ => {}\n        }\n    }\n    let _ = ws.close(None).await;\n    if !got_audio {\n        return Err(anyhow!(\"Edge TTS nao devolveu audio (o servico pode ter mudado o token; tente de novo mais tarde)\"));\n    }\n    Ok(ChunkOut { audio, words })\n}\n\n/// Agrupa palavras em legendas curtas (até 8 palavras, corta em pausas).\npub fn words_to_cues(words: &[WordBoundary]) -> Vec<Cue> {\n    let mut cues = Vec::new();\n    let mut buf: Vec<&WordBoundary> = Vec::new();\n    let flush = |buf: &mut Vec<&WordBoundary>, cues: &mut Vec<Cue>| {\n        if buf.is_empty() {\n            return;\n        }\n        let start = buf[0].start_ms;\n        let last = buf[buf.len() - 1];\n        let end = last.start_ms + last.duration_ms.max(200);\n        let text = buf\n            .iter()\n            .map(|w| w.text.as_str())","sourceCodeStart":299,"sourceCodeEnd":335,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/omniget-core/src/core/tools/edge_tts.rs#L299-L335","documentation":"After streaming the TTS request over the WebSocket, synth_chunk expects at least one audio message. If the socket closed (or all messages were parsed) without any audio payload, this error fires, hinting that Microsoft may have changed its DRM token so the service silently returns nothing.","triggerScenarios":"Calling synthesize() when the Edge TTS service accepts the WebSocket but never sends audio: expired/invalid Sec-MS-GEC token, Microsoft service-side contract change, or the request being silently rejected (e.g. bad voice id causing immediate close).","commonSituations":"Microsoft rotating the DRM token algorithm after a browser update; using an outdated library whose token generator is stale; requesting an invalid/deprecated voice name; service-side outage returning empty streams.","solutions":["Retry later — the message itself suggests the token/service may be temporarily mismatched","Update the edge-tts library to a version with a current Sec-MS-GEC token generator","Verify the requested voice id exists (see list_voices)","Log raw WebSocket messages to confirm whether the server sends an error frame instead of audio"],"exampleFix":"// before\nlet out = edge_tts::synthesize(&opts, &path, progress).await?;\n// after\nlet out = edge_tts::synthesize(&opts, &path, progress).await\n    .map_err(|e| if e.to_string().contains(\"nao devolveu audio\") {\n        anyhow!(\"TTS upstream empty; check library version / retry later: {e}\")\n    } else { e })?;","handlingStrategy":"retry","validationCode":"// verify the voice exists first so the service isn't silently rejecting the request\nlet voices = edge_tts::list_voices().await?;\nif !voices.iter().any(|v| v.short_name == opts.voice) { return Err(anyhow!(\"voz desconhecida\")); }","typeGuard":null,"tryCatchPattern":"match edge_tts::synthesize(&opts, &path, progress).await {\n    Ok(r) => r,\n    Err(e) if e.to_string().contains(\"nao devolveu audio\") => {\n        tokio::time::sleep(Duration::from_secs(5)).await;\n        edge_tts::synthesize(&opts, &path, progress).await\n    }\n    Err(e) => Err(e),\n}","preventionTips":["Pin/update the edge-tts library so the DRM token generator stays current","Retry before failing the whole job — this is often transient","Validate voice ids against list_voices before synthesis"],"tags":["edge-tts","websocket","empty-response","upstream"],"backgroundTag":"empty-response-body","analyzedSha":"8600b91f4246848bac346874daa9e61c1fc5677a","analyzedAt":"2026-09-12T14:29:19.317Z","contentChangedAt":"2026-09-12T14:29:19.317Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}