1
0
mirror of git://f0xx.org/android_cast synced 2026-07-29 07:39:15 +03:00

playing with Opus/Speex

This commit is contained in:
Anton Afanasyeu
2026-06-06 20:18:32 +02:00
parent b019e4f22c
commit 46bf0fbbb6
5 changed files with 30 additions and 21 deletions

View File

@@ -42,9 +42,9 @@ public class CastSettings implements Serializable {
public enum AudioCodec { public enum AudioCodec {
AUTO, AAC, AUTO, AAC,
/** Future Speex (UI disabled until integrated). */ /** Speex (native when built; otherwise stub AAC + Speex backend label). */
SPEEX, SPEEX,
/** Future Opus with in-band FEC (UI disabled until integrated). */ /** Opus with in-band FEC when native; otherwise stub AAC + Opus backend label. */
OPUS, OPUS,
/** Explicit AAC passthrough wrapper for debug comparisons. */ /** Explicit AAC passthrough wrapper for debug comparisons. */
PASSTHROUGH_DEBUG PASSTHROUGH_DEBUG

View File

@@ -57,11 +57,8 @@ public final class PassthroughCodecPolicy {
} }
switch (preference) { switch (preference) {
case SPEEX: case SPEEX:
return NativeCodecBridge.isSpeexAvailable()
? CastSettings.AudioCodec.SPEEX : CastSettings.AudioCodec.AUTO;
case OPUS: case OPUS:
return NativeCodecBridge.isOpusAvailable() return preference;
? CastSettings.AudioCodec.OPUS : CastSettings.AudioCodec.AUTO;
case PASSTHROUGH_DEBUG: case PASSTHROUGH_DEBUG:
return CastSettings.AudioCodec.AUTO; return CastSettings.AudioCodec.AUTO;
default: default:

View File

@@ -14,7 +14,6 @@ package com.foxx.androidcast.network;
import android.media.MediaFormat; import android.media.MediaFormat;
import com.foxx.androidcast.CastSettings; import com.foxx.androidcast.CastSettings;
import com.foxx.androidcast.media.codec.jni.NativeCodecBridge;
import com.foxx.androidcast.sender.CodecCatalog; import com.foxx.androidcast.sender.CodecCatalog;
import java.util.List; import java.util.List;
@@ -63,14 +62,8 @@ public final class CastCodecFlags {
} }
public static int localAudioMask() { public static int localAudioMask() {
int mask = AUDIO_AAC | AUDIO_PCM; // Advertise Opus/Speex for stub negotiation even when native probes are false.
if (NativeCodecBridge.isOpusAvailable()) { return AUDIO_AAC | AUDIO_PCM | AUDIO_OPUS | AUDIO_SPEEX;
mask |= AUDIO_OPUS;
}
if (NativeCodecBridge.isSpeexAvailable()) {
mask |= AUDIO_SPEEX;
}
return mask;
} }
public static int localDecoderAudioMask() { public static int localDecoderAudioMask() {
@@ -108,9 +101,8 @@ public final class CastCodecFlags {
} }
switch (codec) { switch (codec) {
case OPUS: case OPUS:
return NativeCodecBridge.isOpusAvailable();
case SPEEX: case SPEEX:
return NativeCodecBridge.isSpeexAvailable(); return true;
case AAC: case AAC:
case PASSTHROUGH_DEBUG: case PASSTHROUGH_DEBUG:
return true; return true;

View File

@@ -88,13 +88,13 @@ public final class CodecCatalog {
public static List<AudioCodecChoice> audioCodecChoicesForUi(CastSettings settings) { public static List<AudioCodecChoice> audioCodecChoicesForUi(CastSettings settings) {
List<AudioCodecChoice> out = new ArrayList<>(); List<AudioCodecChoice> out = new ArrayList<>();
boolean opus = NativeCodecBridge.isOpusAvailable();
boolean speex = NativeCodecBridge.isSpeexAvailable();
out.add(new AudioCodecChoice(CastSettings.AudioCodec.AUTO, true, 0)); out.add(new AudioCodecChoice(CastSettings.AudioCodec.AUTO, true, 0));
out.add(scoredAudio(CastSettings.AudioCodec.OPUS, opus, settings)); // Selectable even without native .so — stub path uses AAC + OPUS/SPEEX backend label (validation).
out.add(scoredAudio(CastSettings.AudioCodec.OPUS, true, settings));
out.add(scoredAudio(CastSettings.AudioCodec.AAC, true, settings)); out.add(scoredAudio(CastSettings.AudioCodec.AAC, true, settings));
out.add(scoredAudio(CastSettings.AudioCodec.SPEEX, speex, settings)); out.add(scoredAudio(CastSettings.AudioCodec.SPEEX, true, settings));
out.add(scoredAudio(CastSettings.AudioCodec.PASSTHROUGH_DEBUG, true, settings)); out.add(scoredAudio(CastSettings.AudioCodec.PASSTHROUGH_DEBUG, true, settings));
sortAudioChoices(out);
return out; return out;
} }

View File

@@ -50,6 +50,26 @@ public class AudioNegotiatorTest {
assertEquals(CastSettings.AudioCodec.AAC, picked); assertEquals(CastSettings.AudioCodec.AAC, picked);
} }
@Test
public void explicitOpusNegotiatesWhenLinkSupportsOpus() {
CastSettings settings = new CastSettings();
int mask = CastCodecFlags.AUDIO_AAC | CastCodecFlags.AUDIO_OPUS;
CastSettings.AudioCodec picked = AudioNegotiator.negotiate(
mask, mask, CastSettings.AudioCodec.OPUS, settings);
assertEquals(CastSettings.AudioCodec.OPUS, picked);
}
@Test
public void explicitSpeexNegotiatesWhenLinkSupportsSpeex() {
CastSettings settings = new CastSettings();
int mask = CastCodecFlags.AUDIO_AAC | CastCodecFlags.AUDIO_SPEEX;
CastSettings.AudioCodec picked = AudioNegotiator.negotiate(
mask, mask, CastSettings.AudioCodec.SPEEX, settings);
assertEquals(CastSettings.AudioCodec.SPEEX, picked);
}
@Test @Test
public void manualPreferenceOrderIsFixedInCatalog() { public void manualPreferenceOrderIsFixedInCatalog() {
CastSettings.AudioCodec[] order = CodecPriorityCatalog.manualAudioPreferences(); CastSettings.AudioCodec[] order = CodecPriorityCatalog.manualAudioPreferences();