scrcpy
scrcpy copied to clipboard
Audio not working on Vivo(Iqoo) Android 13 device
scrcpy 2.0 <https://github.com/Genymobile/scrcpy>
/usr/local/share/scrcpy/scrcpy-server: 1 file pushed. 4.8 MB/s (52867 bytes in 0.010s)
[server] INFO: Device: vivo I2202 (Android 13)
INFO: Renderer: opengl
INFO: OpenGL version: 3.1 Mesa 21.2.6
INFO: Trilinear filtering enabled
INFO: Initial texture: 1080x2400
WARN: Demuxer 'audio': stream explicitly disabled by the device
[server] ERROR: Exception on thread Thread[Thread-4,5,main]
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.content.Context.getOpPackageName()' on a null object reference
at android.media.VivoAudioRecordImpl.isSupportSubMixRecording(VivoAudioRecordImpl.java:133)
at android.media.AudioRecord.<init>(AudioRecord.java:493)
at android.media.AudioRecord.<init>(Unknown Source:0)
at android.media.AudioRecord$Builder.build(AudioRecord.java:999)
at com.genymobile.scrcpy.AudioCapture.createAudioRecord(AudioCapture.java:58)
at com.genymobile.scrcpy.AudioCapture.start(AudioCapture.java:90)
at com.genymobile.scrcpy.AudioEncoder.encode(AudioEncoder.java:183)
at com.genymobile.scrcpy.AudioEncoder.lambda$start$0$com-genymobile-scrcpy-AudioEncoder(AudioEncoder.java:120)
at com.genymobile.scrcpy.AudioEncoder$$ExternalSyntheticLambda0.run(Unknown Source:2)
at java.lang.Thread.run(Thread.java:1012)
Yes, unfortunately it doesn't work on some vivo devices: https://github.com/Genymobile/scrcpy/pull/3757#issuecomment-1454326127 https://github.com/Genymobile/scrcpy/issues/3791#issuecomment-1465214771
Following the discussion from #3791 (because here is the right place for this issue).
I asked to pull the following .jar:
adb pull /system/framework/framework.jar
adb pull /system/framework/vivo-framework.jar
adb pull /system/framework/vivo-media.jar
Here are the links you provided:
/system/framework/framework.jar/system/framework/vivo-framework.jar/system/framework/vivo-media.jar
And the list of available jarfiles in /system/framework:
adb shell ls /system/framework
QPerformance.jar
QXPerformance.jar
UxPerformance.jar
WfdCommon.jar
abx.jar
am.jar
android.hardware.wifi.supplicant-V1.0-java.jar
android.hardware.wifi.supplicant-V1.1-java.jar
android.hardware.wifi.supplicant-V1.2-java.jar
android.hardware.wifi.supplicant-V1.3-java.jar
android.hidl.base-V1.0-java.jar
android.hidl.manager-V1.0-java.jar
android.test.base.jar
android.test.mock.jar
android.test.runner.jar
appwidget.jar
arm
arm64
bmgr.jar
boot-QPerformance.vdex
boot-UxPerformance.vdex
boot-WfdCommon.vdex
boot-core-icu4j.vdex
boot-ext.vdex
boot-framework-adapter.vdex
boot-framework-graphics.vdex
boot-framework.vdex
boot-ims-common.vdex
boot-qcom.fmradio.vdex
boot-soc-framework.vdex
boot-tcmiface.vdex
boot-telephony-common.vdex
boot-telephony-ext.vdex
boot-vivo-framework.vdex
boot-vivo-media.vdex
boot-vivo-vgcclient.vdex
boot-voip-common.vdex
bu.jar
com.android.future.usb.accessory.jar
com.android.location.provider.jar
com.android.media.remotedisplay.jar
com.android.mediadrm.signer.jar
com.android.wm.shell.jar
com.novatek.framework.jar
content.jar
ext.jar
framework-adapter.jar
framework-graphics.jar
framework-res.apk
framework.jar
hid.jar
ims-common.jar
incident-helper-cmd.jar
javax.obex.jar
locksettings.jar
monkey.jar
oat
org.apache.http.legacy.jar
org.apache.http.legacy.jar.prof
qcom.fmradio.jar
requestsync.jar
services-adapter.jar
services.jar
services.jar.bprof
services.jar.prof
sm.jar
soc-framework.jar
soc-services.jar
svc.jar
tcmclient.jar
tcmiface.jar
telecom.jar
telephony-common.jar
telephony-ext.jar
uiautomator.jar
uinput.jar
vendor.qti.hardware.radio.qtiradio-V1-java.jar
vivo-framework.jar
vivo-media.jar
vivo-priv-telephony-common.jar
vivo-res.apk
vivo-services.jar
vivo-telephony-common-platform-ex.jar
vivo-telephony-common.jar
vivo-telephony-ext.jar
vivo-vgcclient.jar
voip-common.jar
vr.jar
wapicertstore.jar
wmshellapp.apk
The class VivoAudioRecordImpl is found in vivo-framework.jar. Here are the relevant parts:
public class VivoAudioRecordImpl implements IVivoAudioRecord {
// …
private Context mContext;
// …
public VivoAudioRecordImpl() {
Application currentApplication = ActivityThread.currentApplication();
this.mContext = currentApplication;
if (currentApplication != null) {
this.mAudioFeatures = new AudioFeatures(this.mContext, (String) null, (Object) null);
} else {
this.mAudioFeatures = null;
}
}
// …
public String isSupportSubMixRecording() {
AudioFeatures.TagParameters tp = new AudioFeatures.TagParameters("vivo_remote_support");
String mPackageName = this.mContext.getOpPackageName();
String PackSha256 = getSignInfo(this.mContext, mPackageName, SHA256);
tp.put(VivoPermissionManager.ACTION_KEY_PACKAGE, mPackageName);
tp.put("component", PackSha256);
tp.put(Calendar.CalendarAlertsColumns.STATE, VRequest.COMMAND_QUERY);
String ret = new AudioFeatures.TagParameters(this.mAudioFeatures.getAudioFeature(tp.toString(), this)).get(Calendar.CalendarAlertsColumns.STATE);
VLog.w(TAG, "isSupportSubMixRecording:" + ret + " PackSha256:" + PackSha256);
return ret;
}
// …
}
However, I did not find from where it is called. According to your stacktrace, it's from android.media.AudioRecord. This class is available in your framework.jar, but does not call isSupportSubMixRecording().
In any case, the obvious first attempt is to make the context initialized. This is what I did here. However, it was not suffient. So I don't know what to do.
isSupportSubMixRecording is being called from AudioRecord's constructor,
try {
AudioAttributes attributes3 = attributes2;
try {
int initResult = native_setup(new WeakReference(this), this.mAudioAttributes, sampleRate, this.mChannelMask, this.mChannelIndexMask, this.mAudioFormat, this.mNativeBufferSizeInBytes, session, attributionSourceState.getParcel(), 0L, maxSharedAudioHistoryMs);
if (initResult != 0) {
loge("Error code " + initResult + " when initializing native AudioRecord object.");
if (attributionSourceState != null) {
attributionSourceState.close();
return;
}
return;
}
if (attributionSourceState != null) {
attributionSourceState.close();
}
this.mSampleRate = sampleRate[0];
this.mSessionId = session[0];
IVivoAudioRecord iVivoAudioRecord = this.mVivoAudioRecord;
if (iVivoAudioRecord == null) {
i = 1;
} else {
String result = iVivoAudioRecord.isSupportSubMixRecording(); // <--- here
if (!"true".equals(result) || attributes3.getCapturePreset() != 8) {
i = 1;
} else {
i = 1;
this.mIsLiveApp = true;
this.mVivoAudioRecord.notifyGamecube(1);
this.mVivoAudioRecord.showNotificationStatus(true);
Log.d(TAG, "notifyGamecube start by " + this);
}
}
this.mState = i;
} catch (Throwable th2) {
th = th2;
if (attributionSourceState != null) {
try {
attributionSourceState.close();
} catch (Throwable th3) {
th.addSuppressed(th3);
}
}
throw th;
}
} catch (Throwable th4) {
th = th4;
}
But looking at isSupportSubMixRecording, maybe vivo only allows some apps to capture remote submix, Even if we have all methods on context, it might still not work.
The query request was sent to system_server, which should be in services.jar or vivo-services.jar
isSupportSubMixRecordingis being called fromAudioRecord's constructor,
I don't have this code in the AudioRecord.java from framework.jar. How did you decompile?
I'm using jadx https://github.com/skylot/jadx
Oh, I used jadx too, but an old version (v1.2.0). With the latest (v1.4.6), I get the same source as you :tada:
IVivoAudioRecord iVivoAudioRecord = this.mVivoAudioRecord;
if (iVivoAudioRecord == null) {
i = 1;
} else {
String result = iVivoAudioRecord.isSupportSubMixRecording();
Maybe we can force mVivoAudioRecord to be null :see_no_evil:
Let's try. @A-viral-dev please replace this binary in the v2.0 release, and run with scrcpy -Vdebug:
scrcpy-serverSHA-256: 682d39c1cbe24ae1279378b1c13b4d28106407ae5fa26db72613fdfeaec7f5e8
diff
diff --git a/server/src/main/java/com/genymobile/scrcpy/AudioCapture.java b/server/src/main/java/com/genymobile/scrcpy/AudioCapture.java
index 9228e3d71..ce0e09bde 100644
--- a/server/src/main/java/com/genymobile/scrcpy/AudioCapture.java
+++ b/server/src/main/java/com/genymobile/scrcpy/AudioCapture.java
@@ -55,7 +55,9 @@ public final class AudioCapture {
int minBufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE, CHANNEL_CONFIG, FORMAT);
// This buffer size does not impact latency
builder.setBufferSizeInBytes(8 * minBufferSize);
- return builder.build();
+ AudioRecord record = builder.build();
+ Workarounds.resetVivoAudioRecord(record);
+ return record;
}
private static void startWorkaroundAndroid11() {
diff --git a/server/src/main/java/com/genymobile/scrcpy/Workarounds.java b/server/src/main/java/com/genymobile/scrcpy/Workarounds.java
index 64cc12723..f4884c615 100644
--- a/server/src/main/java/com/genymobile/scrcpy/Workarounds.java
+++ b/server/src/main/java/com/genymobile/scrcpy/Workarounds.java
@@ -4,6 +4,7 @@ import android.annotation.SuppressLint;
import android.app.Application;
import android.content.ContextWrapper;
import android.content.pm.ApplicationInfo;
+import android.media.AudioRecord;
import android.os.Looper;
import java.lang.reflect.Constructor;
@@ -74,4 +75,15 @@ public final class Workarounds {
Ln.d("Could not fill app info: " + throwable.getMessage());
}
}
+
+ public static void resetVivoAudioRecord(AudioRecord record) {
+ try {
+ Field vivoAudioRecordField = AudioRecord.class.getDeclaredField("mVivoAudioRecord");
+ vivoAudioRecordField.setAccessible(true);
+ vivoAudioRecordField.set(record, null);
+ } catch (Throwable throwable) {
+ // this is a workaround, so failing is not an error
+ Ln.d("Could not reset vivo audio record: " + throwable.getMessage());
+ }
+ }
}
`aviralshivpuri@penguin:~$ scrcpy -Vdebug
scrcpy 2.0 <https://github.com/Genymobile/scrcpy>
DEBUG: ADB device found:
DEBUG: --> (tcpip) 192.168.29.216:5555 device I2202
DEBUG: Device serial: 192.168.29.216:5555
DEBUG: Using server: /usr/local/share/scrcpy/scrcpy-server
/usr/local/share/scrcpy/scrcpy-server: 1 file pushed. 1.4 MB/s (129307 bytes in 0.086s)
[server] INFO: Device: vivo I2202 (Android 13)
DEBUG: Server connected
DEBUG: Starting controller thread
DEBUG: Starting receiver thread
INFO: Renderer: opengl
INFO: OpenGL version: 3.1 Mesa 21.2.6
INFO: Trilinear filtering enabled
DEBUG: Using icon: /usr/local/share/icons/hicolor/256x256/apps/scrcpy.png
DEBUG: Demuxer 'video': starting thread
DEBUG: Demuxer 'audio': starting thread
[server] DEBUG: Using encoder: 'OMX.qcom.video.encoder.avc'
INFO: Initial texture: 1080x2400
[server] DEBUG: Using audio encoder: 'c2.android.opus.encoder'
WARN: Demuxer 'audio': stream explicitly disabled by the device
[server] DEBUG: Audio encoder stopped
[server] ERROR: Exception on thread Thread[Thread-4,5,main]
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.content.Context.getOpPackageName()' on a null object reference
at android.media.VivoAudioRecordImpl.isSupportSubMixRecording(VivoAudioRecordImpl.java:133)
at android.media.AudioRecord.<init>(AudioRecord.java:493)
at android.media.AudioRecord.<init>(Unknown Source:0)
at android.media.AudioRecord$Builder.build(AudioRecord.java:999)
at com.genymobile.scrcpy.AudioCapture.createAudioRecord(AudioCapture.java:58)
at com.genymobile.scrcpy.AudioCapture.start(AudioCapture.java:92)
at com.genymobile.scrcpy.AudioEncoder.encode(AudioEncoder.java:183)
at com.genymobile.scrcpy.AudioEncoder.lambda$start$0$com-genymobile-scrcpy-AudioEncoder(AudioEncoder.java:120)
at com.genymobile.scrcpy.AudioEncoder$$ExternalSyntheticLambda0.run(Unknown Source:2)
at java.lang.Thread.run(Thread.java:1012)`
Still no audio
The call is in the constructor, must get the instance before the call, doesn't seem to be possible.
Full decompiled source: https://gist.github.com/yume-chan/0e061cc819865d78d717b226513c27e9
Maybe invoke the AudioRecord(long nativeRecordInJavaObj) constructor by reflection (with 0) and do all initialization (native_setup) in Scrcpy?
The call is in the constructor
Oh, it was so far below that I thought it was in another method. :facepalm:
Please try this: scrcpy-server.zip
diff
diff --git a/server/build.gradle b/server/build.gradle
index ce234d10..644045af 100644
--- a/server/build.gradle
+++ b/server/build.gradle
@@ -20,6 +20,9 @@ android {
}
dependencies {
+ // https://mvnrepository.com/artifact/org.jooq/joor
+ implementation 'org.jooq:joor:0.9.14'
+
testImplementation 'junit:junit:4.13.2'
}
diff --git a/server/src/main/java/com/genymobile/scrcpy/AudioCapture.java b/server/src/main/java/com/genymobile/scrcpy/AudioCapture.java
index 6bb3ce23..eb65dedf 100644
--- a/server/src/main/java/com/genymobile/scrcpy/AudioCapture.java
+++ b/server/src/main/java/com/genymobile/scrcpy/AudioCapture.java
@@ -4,16 +4,23 @@ import com.genymobile.scrcpy.wrappers.ServiceManager;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
+import android.content.AttributionSource;
import android.content.ComponentName;
import android.content.Intent;
+import android.media.AudioAttributes;
import android.media.AudioFormat;
+import android.media.AudioManager;
import android.media.AudioRecord;
import android.media.AudioTimestamp;
import android.media.MediaCodec;
import android.media.MediaRecorder;
import android.os.Build;
+import android.os.Looper;
import android.os.SystemClock;
+import org.joor.Reflect;
+
+import java.lang.ref.WeakReference;
import java.nio.ByteBuffer;
public final class AudioCapture {
@@ -34,28 +41,65 @@ public final class AudioCapture {
return SAMPLE_RATE * CHANNELS * BYTES_PER_SAMPLE * millis / 1000;
}
- private static AudioFormat createAudioFormat() {
- AudioFormat.Builder builder = new AudioFormat.Builder();
- builder.setEncoding(FORMAT);
- builder.setSampleRate(SAMPLE_RATE);
- builder.setChannelMask(CHANNEL_CONFIG);
- return builder.build();
- }
-
@TargetApi(Build.VERSION_CODES.M)
- @SuppressLint({"WrongConstant", "MissingPermission"})
+ @SuppressLint({ "WrongConstant", "MissingPermission" })
private static AudioRecord createAudioRecord() {
- AudioRecord.Builder builder = new AudioRecord.Builder();
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
- // On older APIs, Workarounds.fillAppInfo() must be called beforehand
- builder.setContext(FakeContext.get());
+ try {
+ Reflect audioRecord = Reflect.onClass(AudioRecord.class).create(0L);
+
+ audioRecord.set("mRecordingState", AudioRecord.RECORDSTATE_STOPPED);
+
+ Looper looper = Looper.myLooper();
+ if (looper == null) {
+ looper = Looper.getMainLooper();
+ }
+ audioRecord.set("mInitializationLooper", looper);
+
+ audioRecord.set("mIsSubmixFullVolume", true);
+
+ AudioAttributes.Builder audioAttributesBuilder = new AudioAttributes.Builder();
+ Reflect.on(audioAttributesBuilder).call("setInternalCapturePreset",
+ MediaRecorder.AudioSource.REMOTE_SUBMIX);
+ AudioAttributes audioAttributes = audioAttributesBuilder.build();
+ audioRecord.set("mAudioAttributes", audioAttributes);
+
+ audioRecord.call("audioParamCheck", MediaRecorder.AudioSource.REMOTE_SUBMIX, SAMPLE_RATE, FORMAT);
+
+ audioRecord.set("mChannelMask", CHANNEL_CONFIG);
+ audioRecord.set("mChannelCount", CHANNELS);
+
+ int minBufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE, CHANNEL_CONFIG, FORMAT);
+ // This buffer size does not impact latency
+ audioRecord.call("audioBuffSizeCheck", 8 * minBufferSize);
+
+ int[] sampleRate = new int[] { 0 };
+ int[] session = new int[] { AudioManager.AUDIO_SESSION_ID_GENERATE };
+
+ AttributionSource attributionSource = FakeContext.get().getAttributionSource();
+ Reflect attributionSourceState = Reflect.on(attributionSource).call("asScopedParcelState");
+ try (AutoCloseable closeable = attributionSourceState.as(AutoCloseable.class)) {
+ int initResult = audioRecord
+ .call("native_setup", (Object) new WeakReference<AudioRecord>(audioRecord.get()),
+ (Object) audioAttributes, sampleRate, CHANNEL_CONFIG, 0, FORMAT,
+ audioRecord.get("mNativeBufferSizeInBytes"), session,
+ attributionSourceState.call("getParcel").get(), 0L, 0)
+ .get();
+ if (initResult != AudioRecord.SUCCESS) {
+ Ln.e("Error code " + initResult + " when initializing native AudioRecord object.");
+ return null;
+ }
+ }
+
+ audioRecord.set("mSampleRate", sampleRate[0]);
+ audioRecord.set("mSessionId", session[0]);
+
+ audioRecord.set("mState", AudioRecord.STATE_INITIALIZED);
+
+ return audioRecord.get();
+ } catch (Throwable e) {
+ Ln.e("createAudioRecord", e);
+ return null;
}
- builder.setAudioSource(MediaRecorder.AudioSource.REMOTE_SUBMIX);
- builder.setAudioFormat(createAudioFormat());
- int minBufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE, CHANNEL_CONFIG, FORMAT);
- // This buffer size does not impact latency
- builder.setBufferSizeInBytes(8 * minBufferSize);
- return builder.build();
}
private static void startWorkaroundAndroid11() {
D:\Download\scrcpy-win64-v2.0>scrcpy.exe scrcpy 2.0 https://github.com/Genymobile/scrcpy D:\Download\scrcpy-win64-v2.0\scrcpy-server: 1 file pushed, 0 skipped. 68.7 MB/s (62140 bytes in 0.001s) [server] INFO: Device: vivo V2118A (Android 12) INFO: Renderer: direct3d INFO: Initial texture: 1080x2408 [server] ERROR: Audio capture error java.io.IOException: Could not read audio: 0 at com.genymobile.scrcpy.AudioEncoder.inputThread(AudioEncoder.java:96) at com.genymobile.scrcpy.AudioEncoder.lambda$encode$1$com-genymobile-scrcpy-AudioEncoder(AudioEncoder.java:189) at com.genymobile.scrcpy.AudioEncoder$$ExternalSyntheticLambda1.run(Unknown Source:6) at java.lang.Thread.run(Thread.java:922)
met other issue exception in my vivo phone
That's with a newer build from dev branch. Ibdon't have any solution fornvivo phones.
great sound start to work
scrcpy 2.0 <https://github.com/Genymobile/scrcpy>
/usr/local/share/scrcpy/scrcpy-server: 1 file pushed, 0 skipped. 117.7 MB/s (62140 bytes in 0.001s)
[server] INFO: Device: vivo I2202 (Android 13)
INFO: Renderer: opengl
INFO: OpenGL version: 3.1 Mesa 21.2.6
INFO: Trilinear filtering enabled
INFO: Initial texture: 1080x2400
But
- ~~The captured video and the device performance become very slow and laggy when scrcpy is running.~~ Its my home wifi, its working fine on usb and other network.
- Another issue is that the sound from the device is only played on the computer and not on both devices. Maybe WAD.
great sound start to work
Nice. Now let @rom1v decide whether to use this as a fallback path.
the sound from the device is only played on the computer and not on both devices.
Yes this is expected. Remote submix is like a sound output (like a earphone), so all audio outputs are redirected to it.
@yume-chan Great :+1:
However, I'm a bit worried that it is a very specific/fragile code in the long run. On Android 11 it fails (because missing AttributeSource, but that's probably easy to fix). On Android 13 (non-vivo), it currently works though.
I think it should be used as a fallback, if the normal path fails, try this one instead.
It works on vanilla Android 12/13, but if another vendor also added some code to the constructor (that works with Scrcpy now), then the code will break them instead.
So no need to support Android 11, unless another vivo user with Android 11 reported an issue. Also little effort is required to maintain it, if it stopped working, I don't care, we can always declare the device as can't be supported.
OK, maybe. The code could may be moved in a new method Workarounds.createAudioRecord(), and with native reflection (not to add a joor dependency). I think it may be adapted for Android 11 too (just removing the AttributeSource stuff).
Please tell me if you want to work on a proper PR to implement it. Otherwise, I could do it later.
I can create a PR this weekend.
Please try this (only for testing whether vivo has an allowlist for capturing remote submix): scrcpy-server.zip
diff
It worked for me
Please try this: scrcpy-server.zip
diff
@yume-chan
还是不行啊大佬
E:\touping\scrcpy-win64-v2.0\scrcpy-server: 1 file pushed, 0 skipped. 59.5 MB/s (62140 bytes in 0.001s) [server] INFO: Device: vivo V2055A (Android 11) [server] ERROR: createAudioRecord java.lang.NoClassDefFoundError: Failed resolution of: Landroid/content/AttributionSource$Builder; at com.genymobile.scrcpy.FakeContext.getAttributionSource(FakeContext.java:37) at com.genymobile.scrcpy.AudioCapture.createAudioRecord(AudioCapture.java:78) at com.genymobile.scrcpy.AudioCapture.start(AudioCapture.java:134) at com.genymobile.scrcpy.AudioEncoder.encode(AudioEncoder.java:183) at com.genymobile.scrcpy.AudioEncoder.lambda$start$0$com-genymobile-scrcpy-AudioEncoder(AudioEncoder.java:120) at com.genymobile.scrcpy.AudioEncoder$$ExternalSyntheticLambda0.run(Unknown Source:2) at java.lang.Thread.run(Thread.java:923) Caused by: java.lang.ClassNotFoundException: android.content.AttributionSource$Builder ... 7 more INFO: Renderer: direct3d INFO: Initial texture: 1080x2400 WARN: Demuxer 'audio': stream explicitly disabled by the device [server] ERROR: Exception on thread Thread[Thread-4,5,main] java.lang.NullPointerException: Attempt to invoke virtual method 'void android.media.AudioRecord.startRecording()' on a null object reference at com.genymobile.scrcpy.AudioCapture.start(AudioCapture.java:135) at com.genymobile.scrcpy.AudioEncoder.encode(AudioEncoder.java:183) at com.genymobile.scrcpy.AudioEncoder.lambda$start$0$com-genymobile-scrcpy-AudioEncoder(AudioEncoder.java:120) at com.genymobile.scrcpy.AudioEncoder$$ExternalSyntheticLambda0.run(Unknown Source:2) at java.lang.Thread.run(Thread.java:923)
有解决办法吗
@zwjgi #3862
@zwjgi #3862
Sorry I'm a beginner, can you tell me how to use it or just give me a scrcpy-server file
iqoo android 12 here, what is the solution for non coder ??
vivo x80 audio no work
@631jike Please test this version: https://github.com/Genymobile/scrcpy/pull/3862#issuecomment-1561871804
(To Vivo device users)
The Vivo issue with audio is fixed on dev branch and it should work on the future scrcpy 2.1 release.
However, I'm afraid that a work-in-progress fix (#4015) for another device might break the fix for Vivo phones, so I need you to test the following version to make sure scrcpy 2.1 will still work on Vivo phones.
It basically contains the WIP fix branch and the following diff:
diff
diff --git a/server/src/main/java/com/genymobile/scrcpy/AudioCapture.java b/server/src/main/java/com/genymobile/scrcpy/AudioCapture.java
index 7b20cce4f..2e9f7d058 100644
--- a/server/src/main/java/com/genymobile/scrcpy/AudioCapture.java
+++ b/server/src/main/java/com/genymobile/scrcpy/AudioCapture.java
@@ -105,7 +105,9 @@ public final class AudioCapture {
private void startRecording() {
try {
recorder = createAudioRecord(audioSource);
+ Ln.i("==== native AudioRecord worked");
} catch (NullPointerException e) {
+ Ln.e("==== native AudioRecord failed", e);
// Creating an AudioRecord using an AudioRecord.Builder does not work on Vivo phones:
// - <https://github.com/Genymobile/scrcpy/issues/3805>
// - <https://github.com/Genymobile/scrcpy/pull/3862>
Here is a binary:
scrcpy-win64-issue3805.zipSHA-256: 3bee1433d5d82b454dcf5a88213ca0b387ebfafc9e7b474ffc5aa3df713b18c8
Please run it with your Vivo phone and post the whole console output.