chenhg5/cc-connect · error

ffmpeg AMR conversion failed: %w (stderr: %s)

Error message

ffmpeg AMR conversion failed: %w (stderr: %s)

What it means

ConvertAudioToAMR shells out to ffmpeg; when cmd.Run() fails it wraps the error along with the captured stderr buffer. This signals that ffmpeg ran but the AMR conversion itself failed — the wrapper text differs per converter ("AMR conversion failed") so callers can tell which stage broke. The stderr content is ffmpeg's own error output and is the primary diagnostic.

Source

Thrown at core/speech.go:395

		"-c:a", "amr_nb",
		"-ar", "8000",   // 8kHz sample rate (AMR-NB standard)
		"-ac", "1",      // mono
		"-b:a", "12.2k", // 12.2 kbps bitrate (AMR-NB max)
		"-f", "amr",
		"-y",
		"pipe:1",
	}
	if srcFormat == "amr" || srcFormat == "silk" {
		args = append([]string{"-f", srcFormat}, args...)
	}
	cmd := exec.CommandContext(ctx, ffmpegPath, args...)
	cmd.Stdin = bytes.NewReader(audio)
	var stdout, stderr bytes.Buffer
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr

	if err := cmd.Run(); err != nil {
		return nil, fmt.Errorf("ffmpeg AMR conversion failed: %w (stderr: %s)", err, stderr.String())
	}
	return stdout.Bytes(), nil
}

// ConvertMP3ToOGG converts MP3 audio to OGG format using ffmpeg with stdin/stdout pipes.
// Optimized for voice: Opus codec, 16kHz mono, 32kbps, voip application.
func ConvertMP3ToOGG(ctx context.Context, mp3Data []byte) ([]byte, error) {
	ffmpegPath, err := exec.LookPath("ffmpeg")
	if err != nil {
		return nil, fmt.Errorf("ffmpeg not found in PATH: %w", err)
	}

	args := []string{
		"-i", "pipe:0",
		"-c:a", "libopus",
		"-ar", "16000",       // 16kHz sample rate for voice
		"-ac", "1",           // mono
		"-b:a", "32k",        // 32 kbps bitrate (voice quality)

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Check the stderr in the wrapped error for ffmpeg's exact failure (invalid data, unknown encoder, etc.).
  2. Install an ffmpeg build with AMR support (`ffmpeg -encoders | grep amr_nb`).
  3. Correct the srcFormat on the caller side so it matches the real input codec.
  4. If the error stems from context cancellation, increase the timeout; reject empty payloads before calling.

Example fix

// before
if err == nil && len(data) == 0 { /* conversion attempted with empty data */ }
amr, err := core.ConvertAudioToAMR(ctx, data, format)
// after
if len(data) == 0 {
    return fmt.Errorf("refusing to convert empty audio")
}
amr, err := core.ConvertAudioToAMR(ctx, data, format)
Defensive patterns

Strategy: try-catch

Validate before calling

if len(audio) == 0 || !bytes.HasPrefix(audio, []byte("#!AMR")) && format == "amr" {
    return fmt.Errorf("audio payload is not valid AMR")
}

Try / catch

amr, err := core.ConvertAudioToAMR(ctx, audio, srcFormat)
if err != nil {
    var exitErr *exec.ExitError
    if errors.As(err, &exitErr) {
        log.Error("AMR conversion failed", "stderr", extractStderr(err))
    }
    return fmt.Errorf("convert to AMR: %w", err)
}

Prevention

When it happens

Trigger: SendAudio (or a direct call) supplies bytes that cannot be decoded to AMR-NB: input already at a sample rate/codec ffmpeg refuses for amr_nb without resampling context, empty buffer, srcFormat mismatch (declared "silk" but actually mp3), missing amr_nb encoder in the ffmpeg build, or ctx cancellation terminating the process.

Common situations: Minimal ffmpeg builds without native AMR encoder; voice files from platforms that claim one codec but carry another; zero-byte uploads after a failed download; short conversion timeouts on slow hardware.

Related errors


AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06). Data as JSON: /api/errors/d7903e5ce6aa0322. Report an issue: GitHub.