mirror of
git://f0xx.org/android_cast
synced 2026-07-29 08:19:00 +03:00
playing with Opus/Speex
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
Reference in New Issue
Block a user