Skip to content

Commit 2a85a3b

Browse files
author
LisoUseInAIKyrios
authored
fix(YouTube Music - Spoof streaming data): Fix audio playback stuttering (#5839)
1 parent eee7220 commit 2a85a3b

File tree

12 files changed

+174
-82
lines changed

12 files changed

+174
-82
lines changed

extensions/music/build.gradle.kts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
dependencies {
2+
compileOnly(project(":extensions:shared:library"))
3+
compileOnly(project(":extensions:youtube:stub"))
4+
compileOnly(libs.annotation)
5+
}
6+
17
android {
28
defaultConfig {
39
minSdk = 26
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package app.revanced.extension.music.patches.spoof;
2+
3+
import static app.revanced.extension.shared.spoof.ClientType.ANDROID_VR_1_43_32;
4+
import static app.revanced.extension.shared.spoof.ClientType.ANDROID_VR_1_61_48;
5+
6+
import app.revanced.extension.shared.spoof.ClientType;
7+
import app.revanced.extension.shared.spoof.requests.StreamingDataRequest;
8+
9+
@SuppressWarnings("unused")
10+
public class SpoofVideoStreamsPatch {
11+
12+
/**
13+
* Injection point.
14+
*/
15+
public static void setClientOrderToUse() {
16+
ClientType[] availableClients = {
17+
ANDROID_VR_1_43_32,
18+
ANDROID_VR_1_61_48,
19+
};
20+
21+
StreamingDataRequest.setClientOrderToUse(availableClients, ANDROID_VR_1_43_32);
22+
}
23+
}

extensions/shared/library/src/main/java/app/revanced/extension/shared/settings/BaseSettings.java

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66
import static app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch.AudioStreamLanguageOverrideAvailability;
77
import static app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch.SpoofiOSAvailability;
88

9-
import app.revanced.extension.shared.Logger;
10-
import app.revanced.extension.shared.Utils;
119
import app.revanced.extension.shared.spoof.ClientType;
1210

1311
/**
@@ -36,18 +34,5 @@ public class BaseSettings {
3634
public static final BooleanSetting SPOOF_VIDEO_STREAMS_IOS_FORCE_AVC = new BooleanSetting("revanced_spoof_video_streams_ios_force_avc", FALSE, true,
3735
"revanced_spoof_video_streams_ios_force_avc_user_dialog_message", new SpoofiOSAvailability());
3836
// Client type must be last spoof setting due to cyclic references.
39-
public static final EnumSetting<ClientType> SPOOF_VIDEO_STREAMS_CLIENT_TYPE = new EnumSetting<>("revanced_spoof_video_streams_client_type", ClientType.ANDROID_VR_NO_AUTH, true, parent(SPOOF_VIDEO_STREAMS));
40-
41-
static {
42-
// Data migration fix for YT Music users updating from very old patches that always
43-
// stored default values in preference object, which requires manually updating
44-
// the setting if the default changes. Package name may not contain "youtube.music"
45-
// if the user has used change package name patch, but this will detect users
46-
// with default installations.
47-
if (!SPOOF_VIDEO_STREAMS_CLIENT_TYPE.isSetToDefault()
48-
&& Utils.getContext().getPackageName().contains("youtube.music")) {
49-
Logger.printInfo(() -> "Resetting spoof client from: " + SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get());
50-
SPOOF_VIDEO_STREAMS_CLIENT_TYPE.resetToDefault();
51-
}
52-
}
37+
public static final EnumSetting<ClientType> SPOOF_VIDEO_STREAMS_CLIENT_TYPE = new EnumSetting<>("revanced_spoof_video_streams_client_type", ClientType.ANDROID_VR_1_61_48, true, parent(SPOOF_VIDEO_STREAMS));
5338
}

extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/ClientType.java

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
public enum ClientType {
1414
// https://dumps.tadiphone.dev/dumps/oculus/eureka
15-
ANDROID_VR_NO_AUTH(
15+
ANDROID_VR_1_61_48(
1616
28,
1717
"ANDROID_VR",
1818
"com.google.android.apps.youtube.vr.oculus",
@@ -27,7 +27,7 @@ public enum ClientType {
2727
"1.61.48",
2828
false,
2929
false,
30-
"Android VR No auth"
30+
"Android VR 1.61"
3131
),
3232
// Chromecast with Google TV 4K.
3333
// https://dumps.tadiphone.dev/dumps/google/kirkwood
@@ -96,6 +96,26 @@ public enum ClientType {
9696
forceAVC()
9797
? "iOS TV Force AVC"
9898
: "iOS TV"
99+
),
100+
/**
101+
* Uses non adaptive bitrate, which fixes audio stuttering with YT Music.
102+
* Uses VP9 and not AV1.
103+
*/
104+
ANDROID_VR_1_43_32(
105+
ANDROID_VR_1_61_48.id,
106+
ANDROID_VR_1_61_48.clientName,
107+
ANDROID_VR_1_61_48.packageName,
108+
ANDROID_VR_1_61_48.deviceMake,
109+
ANDROID_VR_1_61_48.deviceModel,
110+
ANDROID_VR_1_61_48.osName,
111+
ANDROID_VR_1_61_48.osVersion,
112+
ANDROID_VR_1_61_48.androidSdkVersion,
113+
ANDROID_VR_1_61_48.buildId,
114+
"107.0.5284.2",
115+
"1.43.32",
116+
ANDROID_VR_1_61_48.requiresAuth,
117+
ANDROID_VR_1_61_48.useAuth,
118+
"Android VR 1.43"
99119
);
100120

101121
private static boolean forceAVC() {

extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/SpoofVideoStreamsPatch.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,8 +252,9 @@ public static String appendSpoofedClient(String videoFormat) {
252252
public static final class AudioStreamLanguageOverrideAvailability implements Setting.Availability {
253253
@Override
254254
public boolean isAvailable() {
255+
ClientType clientType = BaseSettings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get();
255256
return BaseSettings.SPOOF_VIDEO_STREAMS.get()
256-
&& BaseSettings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get() == ClientType.ANDROID_VR_NO_AUTH;
257+
&& (clientType == ClientType.ANDROID_VR_1_61_48 || clientType == ClientType.ANDROID_VR_1_43_32);
257258
}
258259
}
259260

extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/requests/PlayerRoutes.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ static String createInnertubeBody(ClientType clientType, String videoId) {
4242
// but if this is a fall over client it will set the language even though
4343
// the audio language is not selectable in the UI.
4444
ClientType userSelectedClient = BaseSettings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get();
45-
Locale streamLocale = userSelectedClient == ClientType.ANDROID_VR_NO_AUTH
45+
Locale streamLocale = (userSelectedClient == ClientType.ANDROID_VR_1_61_48
46+
|| userSelectedClient == ClientType.ANDROID_VR_1_43_32)
4647
? BaseSettings.SPOOF_VIDEO_STREAMS_LANGUAGE.get().getLocale()
4748
: Locale.getDefault();
4849

extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/requests/StreamingDataRequest.java

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,21 +35,22 @@
3535
*/
3636
public class StreamingDataRequest {
3737

38-
private static final ClientType[] CLIENT_ORDER_TO_USE;
38+
private static volatile ClientType[] clientOrderToUse = ClientType.values();
3939

40-
static {
41-
ClientType[] allClientTypes = ClientType.values();
42-
ClientType preferredClient = BaseSettings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get();
40+
public static void setClientOrderToUse(ClientType[] availableClients, ClientType preferredClient) {
41+
Objects.requireNonNull(availableClients);
4342

44-
CLIENT_ORDER_TO_USE = new ClientType[allClientTypes.length];
45-
CLIENT_ORDER_TO_USE[0] = preferredClient;
43+
clientOrderToUse = new ClientType[availableClients.length];
44+
clientOrderToUse[0] = preferredClient;
4645

4746
int i = 1;
48-
for (ClientType c : allClientTypes) {
47+
for (ClientType c : availableClients) {
4948
if (c != preferredClient) {
50-
CLIENT_ORDER_TO_USE[i++] = c;
49+
clientOrderToUse[i++] = c;
5150
}
5251
}
52+
53+
Logger.printDebug(() -> "Available spoof clients: " + Arrays.toString(clientOrderToUse));
5354
}
5455

5556
private static final String AUTHORIZATION_HEADER = "Authorization";
@@ -193,9 +194,9 @@ private static ByteBuffer fetch(String videoId, Map<String, String> playerHeader
193194

194195
// Retry with different client if empty response body is received.
195196
int i = 0;
196-
for (ClientType clientType : CLIENT_ORDER_TO_USE) {
197+
for (ClientType clientType : clientOrderToUse) {
197198
// Show an error if the last client type fails, or if debug is enabled then show for all attempts.
198-
final boolean showErrorToast = (++i == CLIENT_ORDER_TO_USE.length) || debugEnabled;
199+
final boolean showErrorToast = (++i == clientOrderToUse.length) || debugEnabled;
199200

200201
HttpURLConnection connection = send(clientType, videoId, playerHeaders, showErrorToast);
201202
if (connection != null) {
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package app.revanced.extension.youtube.patches.spoof;
2+
3+
import static app.revanced.extension.shared.spoof.ClientType.ANDROID_CREATOR;
4+
import static app.revanced.extension.shared.spoof.ClientType.ANDROID_UNPLUGGED;
5+
import static app.revanced.extension.shared.spoof.ClientType.ANDROID_VR_1_61_48;
6+
import static app.revanced.extension.shared.spoof.ClientType.IOS_UNPLUGGED;
7+
8+
import app.revanced.extension.shared.settings.BaseSettings;
9+
import app.revanced.extension.shared.spoof.ClientType;
10+
import app.revanced.extension.shared.spoof.requests.StreamingDataRequest;
11+
12+
@SuppressWarnings("unused")
13+
public class SpoofVideoStreamsPatch {
14+
15+
/**
16+
* Injection point.
17+
*/
18+
public static void setClientOrderToUse() {
19+
ClientType[] availableClients = {
20+
ANDROID_VR_1_61_48,
21+
ANDROID_UNPLUGGED,
22+
ANDROID_CREATOR,
23+
IOS_UNPLUGGED
24+
};
25+
26+
StreamingDataRequest.setClientOrderToUse(availableClients,
27+
BaseSettings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get());
28+
}
29+
}

extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/preference/SpoofStreamingDataSideEffectsPreference.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,8 @@ private void updateUI() {
8686
String summary = str(key + "_summary");
8787

8888
// Android VR supports AV1 but all other clients do not.
89-
if (clientType != ClientType.ANDROID_VR_NO_AUTH) {
89+
if (clientType != ClientType.ANDROID_VR_1_61_48
90+
&& clientType != ClientType.ANDROID_VR_1_43_32) {
9091
summary += '\n' + str("revanced_spoof_video_streams_about_no_av1");
9192
}
9293

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,20 @@
11
package app.revanced.patches.music.misc.spoof
22

3+
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
34
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
5+
import app.revanced.patches.music.misc.gms.musicActivityOnCreateFingerprint
46
import app.revanced.patches.music.playservice.is_7_33_or_greater
57
import app.revanced.patches.music.playservice.is_8_11_or_greater
68
import app.revanced.patches.music.playservice.is_8_15_or_greater
79
import app.revanced.patches.music.playservice.versionCheckPatch
810
import app.revanced.patches.shared.misc.spoof.spoofVideoStreamsPatch
911

12+
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/music/patches/spoof/SpoofVideoStreamsPatch;"
13+
1014
val spoofVideoStreamsPatch = spoofVideoStreamsPatch(
15+
fixMediaFetchHotConfigChanges = { true },
16+
fixMediaFetchHotConfigAlternativeChanges = { is_8_11_or_greater && !is_8_15_or_greater },
17+
fixParsePlaybackResponseFeatureFlag = { is_7_33_or_greater },
1118
block = {
1219
compatibleWith(
1320
"com.google.android.apps.youtube.music"(
@@ -17,7 +24,10 @@ val spoofVideoStreamsPatch = spoofVideoStreamsPatch(
1724

1825
dependsOn(sharedExtensionPatch, versionCheckPatch, userAgentClientSpoofPatch)
1926
},
20-
fixMediaFetchHotConfigChanges = { true },
21-
fixMediaFetchHotConfigAlternativeChanges = { is_8_11_or_greater && !is_8_15_or_greater },
22-
fixParsePlaybackResponseFeatureFlag = { is_7_33_or_greater }
27+
executeBlock = {
28+
musicActivityOnCreateFingerprint.method.addInstruction(
29+
1, // Must use 1 index so context is set by extension patch.
30+
"invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->setClientOrderToUse()V"
31+
)
32+
}
2333
)

0 commit comments

Comments
 (0)