diff --git a/src/main/kotlin/app/revanced/patches/spotify/audio/bytecode/patch/DisableCaptureRestrictionBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/spotify/audio/bytecode/patch/DisableCaptureRestrictionBytecodePatch.kt index 5cf39625d..88aae6a28 100644 --- a/src/main/kotlin/app/revanced/patches/spotify/audio/bytecode/patch/DisableCaptureRestrictionBytecodePatch.kt +++ b/src/main/kotlin/app/revanced/patches/spotify/audio/bytecode/patch/DisableCaptureRestrictionBytecodePatch.kt @@ -8,46 +8,79 @@ import app.revanced.patcher.extensions.instruction import app.revanced.patcher.extensions.replaceInstruction import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultError import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import app.revanced.patches.spotify.audio.annotation.DisableCaptureRestrictionCompatibility import app.revanced.patches.spotify.audio.fingerprints.DisableCaptureRestrictionAudioDriverFingerprint import app.revanced.patches.spotify.audio.resource.patch.DisableCaptureRestrictionResourcePatch -import org.jf.dexlib2.iface.instruction.Instruction +import org.jf.dexlib2.Opcode +import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction import org.jf.dexlib2.iface.instruction.OneRegisterInstruction +import org.jf.dexlib2.iface.instruction.ReferenceInstruction +import org.jf.dexlib2.iface.reference.MethodReference @Patch @Name("disable-capture-restriction") @DependsOn([DisableCaptureRestrictionResourcePatch::class]) @Description("Allows capturing Spotify's audio output while screen sharing or screen recording.") @DisableCaptureRestrictionCompatibility -@Version("0.0.1") +@Version("0.0.2") class DisableCaptureRestrictionBytecodePatch : BytecodePatch( listOf( DisableCaptureRestrictionAudioDriverFingerprint ) ) { - private fun MutableMethod.replaceConstant4Instruction(index: Int, instruction: Instruction, with: Int) { - val register = (instruction as OneRegisterInstruction).registerA - this.replaceInstruction( - index, "const/4 v$register, $with" - ) - } - override fun execute(context: BytecodeContext): PatchResult { val method = DisableCaptureRestrictionAudioDriverFingerprint.result!!.mutableMethod - // Replace constant that contains the capture policy parameter for AudioAttributesBuilder.setAllowedCapturePolicy() - val instruction = method.instruction(CONST_INSTRUCTION_POSITION) - method.replaceConstant4Instruction(CONST_INSTRUCTION_POSITION, instruction, ALLOW_CAPTURE_BY_ALL) + var invokePosition: Int? = null + var invokeParamRegister: Int? = null - return PatchResultSuccess() + // Find INVOKE_VIRTUAL opcode with call to AudioAttributesBuilder.setAllowedCapturePolicy(I) + for ((index, instruction) in method.implementation!!.instructions.withIndex()) { + if(instruction.opcode != Opcode.INVOKE_VIRTUAL) + continue + + val methodName = ((instruction as ReferenceInstruction).reference as MethodReference).name + if (methodName != "setAllowedCapturePolicy") + continue + + // Store register of the integer parameter for setAllowedCapturePolicy + invokeParamRegister = (instruction as FiveRegisterInstruction).registerD + invokePosition = index + } + + if(invokePosition == null || invokeParamRegister == null) + return PatchResultError("Cannot find setAllowedCapturePolicy method call") + + // Walk back to the const/4 instruction that sets the parameter register + var matchFound = false + for (index in invokePosition downTo 0) { + val instruction = method.instruction(index) + if(instruction.opcode != Opcode.CONST_4) + continue + + val register = (instruction as OneRegisterInstruction).registerA + if(register != invokeParamRegister) + continue + + // Replace parameter value + method.replaceInstruction( + index, "const/4 v$register, $ALLOW_CAPTURE_BY_ALL" + ) + matchFound = true + break + } + + return if (matchFound) + PatchResultSuccess() + else + PatchResultError("Const instruction not found") } private companion object { - const val CONST_INSTRUCTION_POSITION = 2 const val ALLOW_CAPTURE_BY_ALL = 0x01 } } \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/spotify/audio/fingerprints/DisableCaptureRestrictionAudioDriverFingerprint.kt b/src/main/kotlin/app/revanced/patches/spotify/audio/fingerprints/DisableCaptureRestrictionAudioDriverFingerprint.kt index d4c0788e9..cf500b862 100644 --- a/src/main/kotlin/app/revanced/patches/spotify/audio/fingerprints/DisableCaptureRestrictionAudioDriverFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/spotify/audio/fingerprints/DisableCaptureRestrictionAudioDriverFingerprint.kt @@ -9,7 +9,7 @@ import app.revanced.patches.spotify.audio.annotation.DisableCaptureRestrictionCo @Name("disable-capture-restriction-audio-driver-fingerprint") @DisableCaptureRestrictionCompatibility -@Version("0.0.1") +@Version("0.0.2") object DisableCaptureRestrictionAudioDriverFingerprint : MethodFingerprint( customFingerprint = { methodDef -> methodDef.definingClass == "Lcom/spotify/playback/playbacknative/AudioDriver;" && methodDef.name == "constructAudioAttributes" diff --git a/src/main/kotlin/app/revanced/patches/spotify/audio/resource/patch/DisableCaptureRestrictionResourcePatch.kt b/src/main/kotlin/app/revanced/patches/spotify/audio/resource/patch/DisableCaptureRestrictionResourcePatch.kt index 9274c6815..5088cce81 100644 --- a/src/main/kotlin/app/revanced/patches/spotify/audio/resource/patch/DisableCaptureRestrictionResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/spotify/audio/resource/patch/DisableCaptureRestrictionResourcePatch.kt @@ -13,7 +13,7 @@ import org.w3c.dom.Element @Name("disable-capture-restriction-resource-patch") @Description("Sets allowAudioPlaybackCapture in manifest to true.") @DisableCaptureRestrictionCompatibility -@Version("0.0.1") +@Version("0.0.2") class DisableCaptureRestrictionResourcePatch : ResourcePatch { override fun execute(context: ResourceContext): PatchResult { // create an xml editor instance