From e841241a8ea135772a339687b9e7c45779c7864c Mon Sep 17 00:00:00 2001 From: Simon Chan <1330321+yume-chan@users.noreply.github.com> Date: Fri, 3 Feb 2023 16:50:42 +0100 Subject: [PATCH] Add a new socket for audio stream When audio is enabled, open a new socket to send the audio stream from the device to the client. PR #3757 Co-authored-by: Romain Vimont Signed-off-by: Romain Vimont --- app/src/server.c | 39 +++++++++++++++++++ app/src/server.h | 1 + .../genymobile/scrcpy/DesktopConnection.java | 30 ++++++++++++-- .../java/com/genymobile/scrcpy/Server.java | 3 +- 4 files changed, 69 insertions(+), 4 deletions(-) diff --git a/app/src/server.c b/app/src/server.c index 0ff0d3c8..88e3421f 100644 --- a/app/src/server.c +++ b/app/src/server.c @@ -391,6 +391,7 @@ sc_server_init(struct sc_server *server, const struct sc_server_params *params, server->stopped = false; server->video_socket = SC_SOCKET_NONE; + server->audio_socket = SC_SOCKET_NONE; server->control_socket = SC_SOCKET_NONE; sc_adb_tunnel_init(&server->tunnel); @@ -434,9 +435,11 @@ sc_server_connect_to(struct sc_server *server, struct sc_server_info *info) { const char *serial = server->serial; assert(serial); + bool audio = server->params.audio; bool control = server->params.control; sc_socket video_socket = SC_SOCKET_NONE; + sc_socket audio_socket = SC_SOCKET_NONE; sc_socket control_socket = SC_SOCKET_NONE; if (!tunnel->forward) { video_socket = net_accept_intr(&server->intr, tunnel->server_socket); @@ -444,6 +447,14 @@ sc_server_connect_to(struct sc_server *server, struct sc_server_info *info) { goto fail; } + if (audio) { + audio_socket = + net_accept_intr(&server->intr, tunnel->server_socket); + if (audio_socket == SC_SOCKET_NONE) { + goto fail; + } + } + if (control) { control_socket = net_accept_intr(&server->intr, tunnel->server_socket); @@ -470,6 +481,18 @@ sc_server_connect_to(struct sc_server *server, struct sc_server_info *info) { goto fail; } + if (audio) { + audio_socket = net_socket(); + if (audio_socket == SC_SOCKET_NONE) { + goto fail; + } + bool ok = net_connect_intr(&server->intr, audio_socket, tunnel_host, + tunnel_port); + if (!ok) { + goto fail; + } + } + if (control) { // we know that the device is listening, we don't need several // attempts @@ -496,9 +519,11 @@ sc_server_connect_to(struct sc_server *server, struct sc_server_info *info) { } assert(video_socket != SC_SOCKET_NONE); + assert(!audio || audio_socket != SC_SOCKET_NONE); assert(!control || control_socket != SC_SOCKET_NONE); server->video_socket = video_socket; + server->audio_socket = audio_socket; server->control_socket = control_socket; return true; @@ -510,6 +535,12 @@ fail: } } + if (audio_socket != SC_SOCKET_NONE) { + if (!net_close(audio_socket)) { + LOGW("Could not close audio socket"); + } + } + if (control_socket != SC_SOCKET_NONE) { if (!net_close(control_socket)) { LOGW("Could not close control socket"); @@ -860,6 +891,11 @@ run_server(void *data) { assert(server->video_socket != SC_SOCKET_NONE); net_interrupt(server->video_socket); + if (server->audio_socket != SC_SOCKET_NONE) { + // There is no audio_socket if --no-audio is set + net_interrupt(server->audio_socket); + } + if (server->control_socket != SC_SOCKET_NONE) { // There is no control_socket if --no-control is set net_interrupt(server->control_socket); @@ -924,6 +960,9 @@ sc_server_destroy(struct sc_server *server) { if (server->video_socket != SC_SOCKET_NONE) { net_close(server->video_socket); } + if (server->audio_socket != SC_SOCKET_NONE) { + net_close(server->audio_socket); + } if (server->control_socket != SC_SOCKET_NONE) { net_close(server->control_socket); } diff --git a/app/src/server.h b/app/src/server.h index 95e24b41..3005ebd2 100644 --- a/app/src/server.h +++ b/app/src/server.h @@ -70,6 +70,7 @@ struct sc_server { struct sc_adb_tunnel tunnel; sc_socket video_socket; + sc_socket audio_socket; sc_socket control_socket; const struct sc_server_callbacks *cbs; diff --git a/server/src/main/java/com/genymobile/scrcpy/DesktopConnection.java b/server/src/main/java/com/genymobile/scrcpy/DesktopConnection.java index 3cb36a09..3e743621 100644 --- a/server/src/main/java/com/genymobile/scrcpy/DesktopConnection.java +++ b/server/src/main/java/com/genymobile/scrcpy/DesktopConnection.java @@ -20,6 +20,9 @@ public final class DesktopConnection implements Closeable { private final LocalSocket videoSocket; private final FileDescriptor videoFd; + private final LocalSocket audioSocket; + private final FileDescriptor audioFd; + private final LocalSocket controlSocket; private final InputStream controlInputStream; private final OutputStream controlOutputStream; @@ -27,9 +30,10 @@ public final class DesktopConnection implements Closeable { private final ControlMessageReader reader = new ControlMessageReader(); private final DeviceMessageWriter writer = new DeviceMessageWriter(); - private DesktopConnection(LocalSocket videoSocket, LocalSocket controlSocket) throws IOException { + private DesktopConnection(LocalSocket videoSocket, LocalSocket audioSocket, LocalSocket controlSocket) throws IOException { this.videoSocket = videoSocket; this.controlSocket = controlSocket; + this.audioSocket = audioSocket; if (controlSocket != null) { controlInputStream = controlSocket.getInputStream(); controlOutputStream = controlSocket.getOutputStream(); @@ -38,6 +42,7 @@ public final class DesktopConnection implements Closeable { controlOutputStream = null; } videoFd = videoSocket.getFileDescriptor(); + audioFd = audioSocket != null ? audioSocket.getFileDescriptor() : null; } private static LocalSocket connect(String abstractName) throws IOException { @@ -55,10 +60,11 @@ public final class DesktopConnection implements Closeable { return SOCKET_NAME_PREFIX + String.format("_%08x", scid); } - public static DesktopConnection open(int scid, boolean tunnelForward, boolean control, boolean sendDummyByte) throws IOException { + public static DesktopConnection open(int scid, boolean tunnelForward, boolean audio, boolean control, boolean sendDummyByte) throws IOException { String socketName = getSocketName(scid); LocalSocket videoSocket = null; + LocalSocket audioSocket = null; LocalSocket controlSocket = null; try { if (tunnelForward) { @@ -68,12 +74,18 @@ public final class DesktopConnection implements Closeable { // send one byte so the client may read() to detect a connection error videoSocket.getOutputStream().write(0); } + if (audio) { + audioSocket = localServerSocket.accept(); + } if (control) { controlSocket = localServerSocket.accept(); } } } else { videoSocket = connect(socketName); + if (audio) { + audioSocket = connect(socketName); + } if (control) { controlSocket = connect(socketName); } @@ -82,19 +94,27 @@ public final class DesktopConnection implements Closeable { if (videoSocket != null) { videoSocket.close(); } + if (audioSocket != null) { + audioSocket.close(); + } if (controlSocket != null) { controlSocket.close(); } throw e; } - return new DesktopConnection(videoSocket, controlSocket); + return new DesktopConnection(videoSocket, audioSocket, controlSocket); } public void close() throws IOException { videoSocket.shutdownInput(); videoSocket.shutdownOutput(); videoSocket.close(); + if (audioSocket != null) { + audioSocket.shutdownInput(); + audioSocket.shutdownOutput(); + audioSocket.close(); + } if (controlSocket != null) { controlSocket.shutdownInput(); controlSocket.shutdownOutput(); @@ -121,6 +141,10 @@ public final class DesktopConnection implements Closeable { return videoFd; } + public FileDescriptor getAudioFd() { + return audioFd; + } + public ControlMessage receiveControlMessage() throws IOException { ControlMessage msg = reader.next(); while (msg == null) { diff --git a/server/src/main/java/com/genymobile/scrcpy/Server.java b/server/src/main/java/com/genymobile/scrcpy/Server.java index 2aeeb79e..55b38c6d 100644 --- a/server/src/main/java/com/genymobile/scrcpy/Server.java +++ b/server/src/main/java/com/genymobile/scrcpy/Server.java @@ -68,6 +68,7 @@ public final class Server { int scid = options.getScid(); boolean tunnelForward = options.isTunnelForward(); boolean control = options.getControl(); + boolean audio = options.getAudio(); boolean sendDummyByte = options.getSendDummyByte(); Workarounds.prepareMainLooper(); @@ -85,7 +86,7 @@ public final class Server { Controller controller = null; - try (DesktopConnection connection = DesktopConnection.open(scid, tunnelForward, control, sendDummyByte)) { + try (DesktopConnection connection = DesktopConnection.open(scid, tunnelForward, audio, control, sendDummyByte)) { VideoCodec codec = options.getCodec(); if (options.getSendDeviceMeta()) { Size videoSize = device.getScreenInfo().getVideoSize();