From 3cad353823e19fbd21b44b3e6f6280ef9fe77431 Mon Sep 17 00:00:00 2001 From: Gerardo Rodriguez Date: Tue, 10 Nov 2026 06:20:12 +0000 Subject: [PATCH 1/4] msgconv/from-matrix: convert voice messages to ogg/opus --- pkg/connector/capabilities.go | 8 ++++++-- pkg/msgconv/from-matrix.go | 7 +++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/pkg/connector/capabilities.go b/pkg/connector/capabilities.go index b991893b..389c1fae 100644 --- a/pkg/connector/capabilities.go +++ b/pkg/connector/capabilities.go @@ -52,7 +52,7 @@ func (wa *WhatsAppConnector) GetCapabilities() *bridgev2.NetworkGeneralCapabilit } func (wa *WhatsAppConnector) GetBridgeInfoVersion() (info, caps int) { - return 1, 10 + return 1, 11 } const WAMaxFileSize = 2000 * 1024 * 1024 @@ -67,7 +67,7 @@ func supportedIfFFmpeg() event.CapabilitySupportLevel { } func capID() string { - base := "fi.mau.whatsapp.capabilities.2026_10_01" + base := "fi.mau.whatsapp.capabilities.2026_11_10" if ffmpeg.Supported() { return base + "+ffmpeg" } @@ -119,6 +119,10 @@ var whatsappCaps = &event.RoomFeatures{ MimeTypes: map[string]event.CapabilitySupportLevel{ "audio/ogg; codecs=opus": event.CapLevelFullySupported, "audio/ogg": event.CapLevelUnsupported, + "audio/mp4": supportedIfFFmpeg(), + "audio/aac": supportedIfFFmpeg(), + "audio/mpeg": supportedIfFFmpeg(), + "audio/webm": supportedIfFFmpeg(), }, Caption: event.CapLevelDropped, MaxSize: WAMaxFileSize, diff --git a/pkg/msgconv/from-matrix.go b/pkg/msgconv/from-matrix.go index ba2adc23..97047f3d 100644 --- a/pkg/msgconv/from-matrix.go +++ b/pkg/msgconv/from-matrix.go @@ -693,6 +693,13 @@ func (mc *MessageConverter) reuploadFileToWhatsApp( } mediaType = whatsmeow.MediaVideo case event.MsgAudio: + if content.MSC3245Voice != nil && mime != "audio/ogg; codecs=opus" && mime != "audio/ogg" && ffmpeg.Supported() { + data, err = ffmpeg.ConvertBytes(ctx, data, ".ogg", []string{}, []string{"-c:a", "libopus"}, mime) + if err != nil { + return nil, nil, mime, fmt.Errorf("%w (voice to ogg): %w", bridgev2.ErrMediaConvertFailed, err) + } + mime = "audio/ogg; codecs=opus" + } switch mime { case "audio/aac", "audio/mp4", "audio/amr", "audio/mpeg", "audio/ogg; codecs=opus": // Allowed From 97f2ee1d8309a81dd265b7231dd9dd86dec2ea5f Mon Sep 17 00:00:00 2001 From: Gerardo Rodriguez Date: Tue, 10 Nov 2026 06:23:21 +0000 Subject: [PATCH 2/4] msgconv/from-matrix: drop video streams when converting voice messages --- pkg/msgconv/from-matrix.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/msgconv/from-matrix.go b/pkg/msgconv/from-matrix.go index 97047f3d..03a761b4 100644 --- a/pkg/msgconv/from-matrix.go +++ b/pkg/msgconv/from-matrix.go @@ -694,7 +694,7 @@ func (mc *MessageConverter) reuploadFileToWhatsApp( mediaType = whatsmeow.MediaVideo case event.MsgAudio: if content.MSC3245Voice != nil && mime != "audio/ogg; codecs=opus" && mime != "audio/ogg" && ffmpeg.Supported() { - data, err = ffmpeg.ConvertBytes(ctx, data, ".ogg", []string{}, []string{"-c:a", "libopus"}, mime) + data, err = ffmpeg.ConvertBytes(ctx, data, ".ogg", []string{}, []string{"-vn", "-c:a", "libopus"}, mime) if err != nil { return nil, nil, mime, fmt.Errorf("%w (voice to ogg): %w", bridgev2.ErrMediaConvertFailed, err) } From bf68fcfe56fdde2e3f3236f96f5ec693f96a9131 Mon Sep 17 00:00:00 2001 From: Gerardo Rodriguez Date: Tue, 10 Nov 2026 18:43:37 +0000 Subject: [PATCH 3/4] msgconv/from-matrix: send natively supported voice formats as-is if conversion fails --- pkg/msgconv/from-matrix.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/pkg/msgconv/from-matrix.go b/pkg/msgconv/from-matrix.go index 03a761b4..26d8c066 100644 --- a/pkg/msgconv/from-matrix.go +++ b/pkg/msgconv/from-matrix.go @@ -694,11 +694,15 @@ func (mc *MessageConverter) reuploadFileToWhatsApp( mediaType = whatsmeow.MediaVideo case event.MsgAudio: if content.MSC3245Voice != nil && mime != "audio/ogg; codecs=opus" && mime != "audio/ogg" && ffmpeg.Supported() { - data, err = ffmpeg.ConvertBytes(ctx, data, ".ogg", []string{}, []string{"-vn", "-c:a", "libopus"}, mime) - if err != nil { + converted, err := ffmpeg.ConvertBytes(ctx, data, ".ogg", []string{}, []string{"-vn", "-c:a", "libopus"}, mime) + if err == nil { + data = converted + mime = "audio/ogg; codecs=opus" + } else if mime == "audio/aac" || mime == "audio/mp4" || mime == "audio/amr" || mime == "audio/mpeg" { + zerolog.Ctx(ctx).Warn().Err(err).Str("mime", mime).Msg("Failed to convert voice message to ogg, continuing with original file") + } else { return nil, nil, mime, fmt.Errorf("%w (voice to ogg): %w", bridgev2.ErrMediaConvertFailed, err) } - mime = "audio/ogg; codecs=opus" } switch mime { case "audio/aac", "audio/mp4", "audio/amr", "audio/mpeg", "audio/ogg; codecs=opus": From b0e566e863ae343e43528220e9e70e84d728577d Mon Sep 17 00:00:00 2001 From: Gerardo Rodriguez Date: Tue, 10 Nov 2026 18:58:20 +0000 Subject: [PATCH 4/4] msgconv/from-matrix: only convert voice formats WhatsApp doesn't accept --- pkg/connector/capabilities.go | 3 --- pkg/msgconv/from-matrix.go | 20 ++++++++------------ 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/pkg/connector/capabilities.go b/pkg/connector/capabilities.go index 389c1fae..36ec879f 100644 --- a/pkg/connector/capabilities.go +++ b/pkg/connector/capabilities.go @@ -119,9 +119,6 @@ var whatsappCaps = &event.RoomFeatures{ MimeTypes: map[string]event.CapabilitySupportLevel{ "audio/ogg; codecs=opus": event.CapLevelFullySupported, "audio/ogg": event.CapLevelUnsupported, - "audio/mp4": supportedIfFFmpeg(), - "audio/aac": supportedIfFFmpeg(), - "audio/mpeg": supportedIfFFmpeg(), "audio/webm": supportedIfFFmpeg(), }, Caption: event.CapLevelDropped, diff --git a/pkg/msgconv/from-matrix.go b/pkg/msgconv/from-matrix.go index 26d8c066..9a973984 100644 --- a/pkg/msgconv/from-matrix.go +++ b/pkg/msgconv/from-matrix.go @@ -693,17 +693,6 @@ func (mc *MessageConverter) reuploadFileToWhatsApp( } mediaType = whatsmeow.MediaVideo case event.MsgAudio: - if content.MSC3245Voice != nil && mime != "audio/ogg; codecs=opus" && mime != "audio/ogg" && ffmpeg.Supported() { - converted, err := ffmpeg.ConvertBytes(ctx, data, ".ogg", []string{}, []string{"-vn", "-c:a", "libopus"}, mime) - if err == nil { - data = converted - mime = "audio/ogg; codecs=opus" - } else if mime == "audio/aac" || mime == "audio/mp4" || mime == "audio/amr" || mime == "audio/mpeg" { - zerolog.Ctx(ctx).Warn().Err(err).Str("mime", mime).Msg("Failed to convert voice message to ogg, continuing with original file") - } else { - return nil, nil, mime, fmt.Errorf("%w (voice to ogg): %w", bridgev2.ErrMediaConvertFailed, err) - } - } switch mime { case "audio/aac", "audio/mp4", "audio/amr", "audio/mpeg", "audio/ogg; codecs=opus": // Allowed @@ -711,7 +700,14 @@ func (mc *MessageConverter) reuploadFileToWhatsApp( // Hopefully it's opus already mime = "audio/ogg; codecs=opus" default: - return nil, nil, mime, fmt.Errorf("%w %s in audio message", bridgev2.ErrUnsupportedMediaType, mime) + if content.MSC3245Voice == nil || !ffmpeg.Supported() { + return nil, nil, mime, fmt.Errorf("%w %s in audio message", bridgev2.ErrUnsupportedMediaType, mime) + } + data, err = ffmpeg.ConvertBytes(ctx, data, ".ogg", []string{}, []string{"-vn", "-c:a", "libopus"}, mime) + if err != nil { + return nil, nil, mime, fmt.Errorf("%w (voice to ogg): %w", bridgev2.ErrMediaConvertFailed, err) + } + mime = "audio/ogg; codecs=opus" } mediaType = whatsmeow.MediaAudio case event.MsgFile: