diff --git a/gearslip/src/main/java/app/seb3thehacker/gearslip/audio/AacEncoder.kt b/gearslip/src/main/java/app/seb3thehacker/gearslip/audio/AacEncoder.kt index f80ae92..27869d8 100644 --- a/gearslip/src/main/java/app/seb3thehacker/gearslip/audio/AacEncoder.kt +++ b/gearslip/src/main/java/app/seb3thehacker/gearslip/audio/AacEncoder.kt @@ -87,8 +87,17 @@ internal class AacEncoder(private val sampleRate: Int, private val channels: Int runCatching { codec.release() } } - private companion object { - const val INPUT_WAIT_US = 10_000L - val FREQUENCIES = listOf(96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350) + companion object { + private const val INPUT_WAIT_US = 10_000L + private val FREQUENCIES = listOf(96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350) + + /** The two-byte AudioSpecificConfig for AAC-LC: object type 2, rate index, channel count. */ + fun audioSpecificConfig(sampleRate: Int, channels: Int): ByteArray { + val freq = FREQUENCIES.indexOf(sampleRate).let { if (it < 0) 3 else it } + return byteArrayOf( + ((2 shl 3) or (freq shr 1)).toByte(), + (((freq and 1) shl 7) or (channels shl 3)).toByte(), + ) + } } } diff --git a/gearslip/src/main/java/app/seb3thehacker/gearslip/audio/AudioLink.kt b/gearslip/src/main/java/app/seb3thehacker/gearslip/audio/AudioLink.kt index 51f73fc..0513ddb 100644 --- a/gearslip/src/main/java/app/seb3thehacker/gearslip/audio/AudioLink.kt +++ b/gearslip/src/main/java/app/seb3thehacker/gearslip/audio/AudioLink.kt @@ -251,6 +251,12 @@ class AudioLink( MSG_START, Protobuf.varintField(1, sessionId.toLong()) + Protobuf.varintField(2, configIndex.toLong()), ) + // Raw AAC-LC has no header of its own: the car needs the codec config before the first frame. + if (service.codecType == ServiceDiscovery.CODEC_AAC_LC) { + val asc = AacEncoder.audioSpecificConfig(sampleRate, channels) + sendOnChannel(MSG_CODEC_CONFIG, asc) + GearslipLog.hex("$tag: -> CodecConfig (AudioSpecificConfig)", asc) + } inFlight = 0 lastAckAt = System.currentTimeMillis() if (aacSink && aac == null) { @@ -364,6 +370,7 @@ class AudioLink( const val MSG_FOCUS_RESPONSE = 19 private const val MSG_CHANNEL_OPEN_RESPONSE = 8 private const val MSG_DATA = 0 + private const val MSG_CODEC_CONFIG = 1 private const val MSG_SETUP = 32768 private const val MSG_START = 32769 private const val MSG_STOP = 32770