Genymobile / scrcpy

Display and control your Android device
Apache License 2.0
110.43k stars 10.58k forks source link

Audio not working on Vivo(Iqoo) Android 13 device #3805

Closed A-viral-dev closed 1 year ago

A-viral-dev commented 1 year ago
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)
rom1v commented 1 year ago

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

rom1v commented 1 year ago

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:

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.

yume-chan commented 1 year ago

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

rom1v commented 1 year ago

isSupportSubMixRecording is being called from AudioRecord's constructor,

I don't have this code in the AudioRecord.java from framework.jar. How did you decompile?

yume-chan commented 1 year ago

I'm using jadx https://github.com/skylot/jadx

rom1v commented 1 year ago

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:

rom1v commented 1 year ago
                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:

rom1v commented 1 year ago

Let's try. @A-viral-dev please replace this binary in the v2.0 release, and run with scrcpy -Vdebug:

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 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()); + } + } } ```
A-viral-dev commented 1 year ago
`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)`
A-viral-dev commented 1 year ago

Still no audio

yume-chan commented 1 year ago

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?

rom1v commented 1 year ago

The call is in the constructor

Oh, it was so far below that I thought it was in another method. :facepalm:

yume-chan commented 1 year ago

Please try this: scrcpy-server.zip

diff ```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.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() { ```
Ryan2009 commented 1 year ago

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

rom1v commented 1 year ago

That's with a newer build from dev branch. Ibdon't have any solution fornvivo phones.

A-viral-dev commented 1 year ago

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

  1. 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.
  2. Another issue is that the sound from the device is only played on the computer and not on both devices. Maybe WAD.
yume-chan commented 1 year ago

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.

rom1v commented 1 year ago

@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.

yume-chan commented 1 year ago

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.

rom1v commented 1 year ago

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.

yume-chan commented 1 year ago

I can create a PR this weekend.

mziyadrahmani commented 1 year ago

Please try this (only for testing whether vivo has an allowlist for capturing remote submix): scrcpy-server.zip

diff

It worked for me

zwjgi commented 1 year ago

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)

有解决办法吗

rom1v commented 1 year ago

@zwjgi #3862

zwjgi commented 1 year ago

@zwjgi #3862

Sorry I'm a beginner, can you tell me how to use it or just give me a scrcpy-server file

ugly-fat-pig-yt commented 1 year ago

iqoo android 12 here, what is the solution for non coder ??

Dancying commented 1 year ago

Please try this: scrcpy-server.zip

diff

it works for me (iqoo 9, android 13)

631jike commented 1 year ago

vivo x80 audio no work

rom1v commented 1 year ago

@631jike Please test this version: https://github.com/Genymobile/scrcpy/pull/3862#issuecomment-1561871804

rom1v commented 1 year ago

(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 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: // - // - ```

Here is a binary:

Please run it with your Vivo phone and post the whole console output.

Helaer commented 1 year ago

@rom1v

C:\Users\mr.song\Downloads\scrcpy-win64-issue3805\scrcpy-win64-v2.0-95-g9bff8ccad>scrcpy -Vdebug
scrcpy 2.0 <https://github.com/Genymobile/scrcpy>
DEBUG: ADB device found:
DEBUG:     -->   (usb)       3468348101003D0            device  V2157A
DEBUG: Device serial: 3468348101003D0
DEBUG: Using server (portable): C:\Users\mr.song\Downloads\scrcpy-win64-issue3805\scrcpy-win64-v2.0-95-g9bff8ccad\scrcpy-server
C:\Users\mr.song\Downloads\scrcpy-win64-issue3805\scrcpy-w... file pushed, 0 skipped. 34.7 MB/s (57051 bytes in 0.002s)
[server] INFO: Device: [vivo] vivo V2157A (Android 13)
DEBUG: Server connected
DEBUG: Starting controller thread
DEBUG: Starting receiver thread
[server] DEBUG: Using video encoder: 'OMX.qcom.video.encoder.avc'
[server] DEBUG: Using audio encoder: 'c2.android.opus.encoder'
INFO: Renderer: direct3d
DEBUG: Trilinear filtering disable[server] DEBUG: Audio encoder stopped
d (not an OpenGL renderer
DEBUG: Using icon (portable): C:\Users\mr.song\Downloads\scrcpy-win64-issue3805\scrcpy-win64-v2.0-95-g9bff8ccad\icon.pngDEBUG: Demuxer 'video': starting thread
DEBUG: Demuxer 'audi[server] ERROR: Exception on thread Thread[audio-encoder,5,main]
o': starting thread
WARN: Demuxer 'java.lang.AssertionError: java.lang.reflect.InvocationTargetExceptiona
u       at com.genymobile.scrcpy.wrappers.ActivityThread.<clinit>(ActivityThread.java:17)d
i       at com.genymobile.scrcpy.wrappers.ActivityThread.getActivityThreadClass(ActivityThread.java:30)o
'       at com.genymobile.scrcpy.FakeContext.retrieveSystemContext(FakeContext.java:23):
        at com.genymobile.scrcpy.FakeContext.<init>(FakeContext.java:39)s
t       at com.genymobile.scrcpy.FakeContext.<clinit>(FakeContext.java:19)r
e       at com.genymobile.scrcpy.FakeContext.get(FakeContext.java:35)am exp
l       at com.genymobile.scrcpy.AudioCapture.createAudioRecord(AudioCapture.java:57)i
c       at com.genymobile.scrcpy.AudioCapture.startRecording(AudioCapture.java:107)i
t       at com.genymobile.scrcpy.AudioCapture.start(AudioCapture.java:128)l
y       at com.genymobile.scrcpy.AudioEncoder.encode(AudioEncoder.java:193)
d       at com.genymobile.scrcpy.AudioEncoder.lambda$start$0$com-genymobile-scrcpy-AudioEncoder(AudioEncoder.java:124)i
s       at com.genymobile.scrcpy.AudioEncoder$$ExternalSyntheticLambda0.run(Unknown Source:4)a
b       at java.lang.Thread.run(Thread.java:1015)l
eCaused by: java.lang.reflect.InvocationTargetExceptiond
        at java.lang.reflect.Constructor.newInstance0(Native Method)b
y       at java.lang.reflect.Constructor.newInstance(Constructor.java:343)
t       at com.genymobile.scrcpy.wrappers.ActivityThread.<clinit>(ActivityThread.java:15)h
e       ... 12 more
deCaused by: java.lang.RuntimeException: Can't create handler inside thread Thread[audio-encoder,5,main] that has not called Looper.prepare()v
i       at android.os.Handler.<init>(Handler.java:227)c
e       at android.os.Handler.<init>(Handler.java:129)

I       at android.app.ActivityThread$H.<init>(ActivityThread.java:2262)N
F       at android.app.ActivityThread.<init>(ActivityThread.java:420)O
:       ... 15 more
Texture: 1080x2400
rom1v commented 1 year ago

@Helaer Thank you very much, that helped a lot.

Could you please try this new version: https://github.com/Genymobile/scrcpy/issues/4015#issuecomment-1596192278 and confirm that audio still works on Vivo phones?

Helaer commented 1 year ago

@Helaer Thank you very much, that helped a lot.

Could you please try this new version: #4015 (comment) and confirm that audio still works on Vivo phones?

@rom1v It works fine.

C:\Users\mr.song\Downloads\scrcpy-win64-issue4015\scrcpy-win64-v2.0-93-g86e5c90ed>scrcpy -Vdebug scrcpy 2.0 https://github.com/Genymobile/scrcpy DEBUG: ADB device found: DEBUG: --> (usb) 3468348101003D0 device V2157A DEBUG: Device serial: 3468348101003D0 DEBUG: Using server (portable): C:\Users\mr.song\Downloads\scrcpy-win64-issue4015\scrcpy-win64-v2.0-93-g86e5c90ed\scrcpy-server C:\Users\mr.song\Downloads\scrcpy-win64-issue4015\scrcpy-w... file pushed, 0 skipped. 37.2 MB/s (56923 bytes in 0.001s) [server] INFO: Device: [vivo] vivo V2157A (Android 13) [server] DEBUG: Using video encoder: 'OMX.qcom.video.encoder.avc' [server] DEBUG: Using audio encoder: 'c2.android.opus.encoder' DEBUG: Server connected DEBUG: Starting controller thread DEBUG: Starting receiver thread INFO: Renderer: direct3d DEBUG: Trilinear filtering disabled (not an OpenGL renderer DEBUG: Using icon (portable): C:\Users\mr.song\Downloads\scrcpy-win64-issue4015\scrcpy-win64-v2.0-93-g86e5c90ed\icon.png DEBUG: Demuxer 'video': starting thread DEBUG: Demuxer 'audio': starting thread INFO: Texture: 1080x2400 DEBUG: [Audio] Buffering threshold exceeded, skipping 240 samples DEBUG: [Audio] Buffering threshold exceeded, skipping 960 samples DEBUG: [Audio] Buffering threshold exceeded, skipping 480 samples DEBUG: [Audio] Buffering threshold exceeded, skipping 960 samples DEBUG: [Audio] Buffering threshold exceeded, skipping 960 samples DEBUG: [Audio] Buffering threshold exceeded, skipping 960 samples DEBUG: [Audio] Buffering threshold exceeded, skipping 480 samples

rom1v commented 1 year ago

@Helaer Unfortunately, the version above did not work for Honor devices, so here is a new one which is confirmed to work on Honor devices: https://github.com/Genymobile/scrcpy/issues/4015#issuecomment-1597148925

Could you please confirm that it also works for Vivo devices?

Helaer commented 1 year ago

不幸的是,上面的版本不适用于荣耀设备,所以这里有一个确认适用于荣耀设备的新版本:#4015(评论)

您能否确认它也适用于Vivo设备?

@rom1v It works fine.

C:\Users\mr.song\Downloads\scrcpy-win64-honor_6\scrcpy-win64-v2.0-94-g9f9b852ae>scrcpy -Vdebug scrcpy 2.0 https://github.com/Genymobile/scrcpy DEBUG: ADB device found: DEBUG: --> (usb) 3468348101003D0 device V2157A DEBUG: Device serial: 3468348101003D0 DEBUG: Using server (portable): C:\Users\mr.song\Downloads\scrcpy-win64-honor_6\scrcpy-win64-v2.0-94-g9f9b852ae\scrcpy-server C:\Users\mr.song\Downloads\scrcpy-win64-honor_6\scrcpy-win...file pushed, 0 skipped. 125.7 MB/s (56935 bytes in 0.000s) [server] INFO: Device: [vivo] vivo V2157A (Android 13) DEBUG: Server connected DEBUG: Starting controller thread DEBUG: Starting receiver thread [server] DEBUG: Using audio encoder: 'c2.android.opus.encoder' [server] DEBUG: Using video encoder: 'OMX.qcom.video.encoder.avc' INFO: Renderer: direct3d DEBUG: Trilinear filtering disabled (not an OpenGL renderer DEBUG: Using icon (portable): C:\Users\mr.song\Downloads\scrcpy-win64-honor_6\scrcpy-win64-v2.0-94-g9f9b852ae\icon.png DEBUG: Demuxer 'video': starting thread DEBUG: Demuxer 'audio': starting thread INFO: Texture: 1080x2400 DEBUG: [Audio] Buffering threshold exceeded, skipping 240 samples DEBUG: [Audio] Buffering threshold exceeded, skipping 480 samples DEBUG: [Audio] Buffer underflow, inserting silence: 87 samples DEBUG: [Audio] Buffer underflow, inserting silence: 240 samples DEBUG: [Audio] Buffer underflow, inserting silence: 240 samples

rom1v commented 2 months ago

@Helaer In reference to https://github.com/Genymobile/scrcpy/issues/3805#issuecomment-1596148031, could you please test https://github.com/Genymobile/scrcpy/pull/5154?

Helaer commented 2 months ago

@Helaer In reference to #3805 (comment), could you please test #5154?

@rom1v The audio works fine on my vivo device.

rom1v commented 2 months ago

Oh, great 🎉 Thank you for the test :+1: