From 50d56a9a2bb75398c562e71b131de5c3ed43e95e Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Thu, 23 Feb 2023 21:27:11 +0100 Subject: [PATCH] Quit on audio configuration failure When audio capture fails on the device, scrcpy continues mirroring the video stream. This allows to enable audio by default only when supported. However, if an audio configuration occurs (for example the user explicitly selected an unknown audio encoder), this must be treated as an error and scrcpy must exit. PR #3757 --- app/src/demuxer.c | 6 ++++++ app/src/scrcpy.c | 13 +++++++++++-- .../java/com/genymobile/scrcpy/AudioEncoder.java | 8 ++++++-- .../main/java/com/genymobile/scrcpy/Streamer.java | 13 +++++++++---- 4 files changed, 32 insertions(+), 8 deletions(-) diff --git a/app/src/demuxer.c b/app/src/demuxer.c index 64bf30a3..d80a5dda 100644 --- a/app/src/demuxer.c +++ b/app/src/demuxer.c @@ -195,6 +195,12 @@ run_demuxer(void *data) { goto end; } + if (raw_codec_id == 1) { + LOGE("Demuxer '%s': stream configuration error on the device", + demuxer->name); + goto end; + } + enum AVCodecID codec_id = sc_demuxer_to_avcodec_id(raw_codec_id); if (codec_id == AV_CODEC_ID_NONE) { LOGE("Demuxer '%s': stream disabled due to unsupported codec", diff --git a/app/src/scrcpy.c b/app/src/scrcpy.c index 6d0fac9e..5739c3b2 100644 --- a/app/src/scrcpy.c +++ b/app/src/scrcpy.c @@ -231,10 +231,19 @@ static void sc_audio_demuxer_on_ended(struct sc_demuxer *demuxer, bool eos, void *userdata) { (void) demuxer; - (void) eos; (void) userdata; - // Contrary to the video demuxer, keep mirroring if only the audio fails + // Contrary to the video demuxer, keep mirroring if only the audio fails. + // 'eos' is true on end-of-stream, including when audio capture is not + // possible on the device (so that scrcpy continue to mirror video without + // failing). + // However, if an audio configuration failure occurs (for example the user + // explicitly selected an unknown audio encoder), 'eos' is false and scrcpy + // must exit. + + if (!eos) { + PUSH_EVENT(SC_EVENT_DEMUXER_ERROR); + } } static void diff --git a/server/src/main/java/com/genymobile/scrcpy/AudioEncoder.java b/server/src/main/java/com/genymobile/scrcpy/AudioEncoder.java index 540d8306..66950004 100644 --- a/server/src/main/java/com/genymobile/scrcpy/AudioEncoder.java +++ b/server/src/main/java/com/genymobile/scrcpy/AudioEncoder.java @@ -222,7 +222,7 @@ public final class AudioEncoder { public void encode() throws IOException, ConfigurationException { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { Ln.w("Audio disabled: it is not supported before Android 11"); - streamer.writeDisableStream(); + streamer.writeDisableStream(false); return; } @@ -279,9 +279,13 @@ public final class AudioEncoder { outputThread.start(); waitEnded(); + } catch (ConfigurationException e) { + // Notify the error to make scrcpy exit + streamer.writeDisableStream(true); + throw e; } catch (Throwable e) { // Notify the client that the audio could not be captured - streamer.writeDisableStream(); + streamer.writeDisableStream(false); throw e; } finally { // Cleanup everything (either at the end or on error at any step of the initialization) diff --git a/server/src/main/java/com/genymobile/scrcpy/Streamer.java b/server/src/main/java/com/genymobile/scrcpy/Streamer.java index 7cc065eb..9bfe7e91 100644 --- a/server/src/main/java/com/genymobile/scrcpy/Streamer.java +++ b/server/src/main/java/com/genymobile/scrcpy/Streamer.java @@ -40,10 +40,15 @@ public final class Streamer { } } - public void writeDisableStream() throws IOException { - // Writing 0 (32-bit) as codec-id means that the device disables the stream (because it could not capture) - byte[] zeros = new byte[4]; - IO.writeFully(fd, zeros, 0, zeros.length); + public void writeDisableStream(boolean error) throws IOException { + // Writing a specific code as codec-id means that the device disables the stream + // code 0: it explicitly disables the stream (because it could not capture audio), scrcpy should continue mirroring video only + // code 1: a configuration error occurred, scrcpy must be stopped + byte[] code = new byte[4]; + if (error) { + code[3] = 1; + } + IO.writeFully(fd, code, 0, code.length); } public void writePacket(ByteBuffer buffer, long pts, boolean config, boolean keyFrame) throws IOException {