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 <https://github.com/Genymobile/scrcpy/pull/3757>
This commit is contained in:
Romain Vimont 2023-02-23 21:27:11 +01:00
parent 9196dc1563
commit 50d56a9a2b
4 changed files with 32 additions and 8 deletions

View file

@ -195,6 +195,12 @@ run_demuxer(void *data) {
goto end; 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); enum AVCodecID codec_id = sc_demuxer_to_avcodec_id(raw_codec_id);
if (codec_id == AV_CODEC_ID_NONE) { if (codec_id == AV_CODEC_ID_NONE) {
LOGE("Demuxer '%s': stream disabled due to unsupported codec", LOGE("Demuxer '%s': stream disabled due to unsupported codec",

View file

@ -231,10 +231,19 @@ static void
sc_audio_demuxer_on_ended(struct sc_demuxer *demuxer, bool eos, sc_audio_demuxer_on_ended(struct sc_demuxer *demuxer, bool eos,
void *userdata) { void *userdata) {
(void) demuxer; (void) demuxer;
(void) eos;
(void) userdata; (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 static void

View file

@ -222,7 +222,7 @@ public final class AudioEncoder {
public void encode() throws IOException, ConfigurationException { public void encode() throws IOException, ConfigurationException {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
Ln.w("Audio disabled: it is not supported before Android 11"); Ln.w("Audio disabled: it is not supported before Android 11");
streamer.writeDisableStream(); streamer.writeDisableStream(false);
return; return;
} }
@ -279,9 +279,13 @@ public final class AudioEncoder {
outputThread.start(); outputThread.start();
waitEnded(); waitEnded();
} catch (ConfigurationException e) {
// Notify the error to make scrcpy exit
streamer.writeDisableStream(true);
throw e;
} catch (Throwable e) { } catch (Throwable e) {
// Notify the client that the audio could not be captured // Notify the client that the audio could not be captured
streamer.writeDisableStream(); streamer.writeDisableStream(false);
throw e; throw e;
} finally { } finally {
// Cleanup everything (either at the end or on error at any step of the initialization) // Cleanup everything (either at the end or on error at any step of the initialization)

View file

@ -40,10 +40,15 @@ public final class Streamer {
} }
} }
public void writeDisableStream() throws IOException { public void writeDisableStream(boolean error) throws IOException {
// Writing 0 (32-bit) as codec-id means that the device disables the stream (because it could not capture) // Writing a specific code as codec-id means that the device disables the stream
byte[] zeros = new byte[4]; // code 0: it explicitly disables the stream (because it could not capture audio), scrcpy should continue mirroring video only
IO.writeFully(fd, zeros, 0, zeros.length); // 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 { public void writePacket(ByteBuffer buffer, long pts, boolean config, boolean keyFrame) throws IOException {