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 <https://github.com/Genymobile/scrcpy/pull/3757>

Co-authored-by: Romain Vimont <rom@rom1v.com>
Signed-off-by: Romain Vimont <rom@rom1v.com>
This commit is contained in:
Simon Chan 2023-02-03 16:50:42 +01:00 committed by Romain Vimont
parent 3cf03e4a4b
commit e841241a8e
4 changed files with 69 additions and 4 deletions

View file

@ -391,6 +391,7 @@ sc_server_init(struct sc_server *server, const struct sc_server_params *params,
server->stopped = false; server->stopped = false;
server->video_socket = SC_SOCKET_NONE; server->video_socket = SC_SOCKET_NONE;
server->audio_socket = SC_SOCKET_NONE;
server->control_socket = SC_SOCKET_NONE; server->control_socket = SC_SOCKET_NONE;
sc_adb_tunnel_init(&server->tunnel); 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; const char *serial = server->serial;
assert(serial); assert(serial);
bool audio = server->params.audio;
bool control = server->params.control; bool control = server->params.control;
sc_socket video_socket = SC_SOCKET_NONE; sc_socket video_socket = SC_SOCKET_NONE;
sc_socket audio_socket = SC_SOCKET_NONE;
sc_socket control_socket = SC_SOCKET_NONE; sc_socket control_socket = SC_SOCKET_NONE;
if (!tunnel->forward) { if (!tunnel->forward) {
video_socket = net_accept_intr(&server->intr, tunnel->server_socket); 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; goto fail;
} }
if (audio) {
audio_socket =
net_accept_intr(&server->intr, tunnel->server_socket);
if (audio_socket == SC_SOCKET_NONE) {
goto fail;
}
}
if (control) { if (control) {
control_socket = control_socket =
net_accept_intr(&server->intr, tunnel->server_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; 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) { if (control) {
// we know that the device is listening, we don't need several // we know that the device is listening, we don't need several
// attempts // 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(video_socket != SC_SOCKET_NONE);
assert(!audio || audio_socket != SC_SOCKET_NONE);
assert(!control || control_socket != SC_SOCKET_NONE); assert(!control || control_socket != SC_SOCKET_NONE);
server->video_socket = video_socket; server->video_socket = video_socket;
server->audio_socket = audio_socket;
server->control_socket = control_socket; server->control_socket = control_socket;
return true; 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 (control_socket != SC_SOCKET_NONE) {
if (!net_close(control_socket)) { if (!net_close(control_socket)) {
LOGW("Could not close control socket"); LOGW("Could not close control socket");
@ -860,6 +891,11 @@ run_server(void *data) {
assert(server->video_socket != SC_SOCKET_NONE); assert(server->video_socket != SC_SOCKET_NONE);
net_interrupt(server->video_socket); 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) { if (server->control_socket != SC_SOCKET_NONE) {
// There is no control_socket if --no-control is set // There is no control_socket if --no-control is set
net_interrupt(server->control_socket); net_interrupt(server->control_socket);
@ -924,6 +960,9 @@ sc_server_destroy(struct sc_server *server) {
if (server->video_socket != SC_SOCKET_NONE) { if (server->video_socket != SC_SOCKET_NONE) {
net_close(server->video_socket); net_close(server->video_socket);
} }
if (server->audio_socket != SC_SOCKET_NONE) {
net_close(server->audio_socket);
}
if (server->control_socket != SC_SOCKET_NONE) { if (server->control_socket != SC_SOCKET_NONE) {
net_close(server->control_socket); net_close(server->control_socket);
} }

View file

@ -70,6 +70,7 @@ struct sc_server {
struct sc_adb_tunnel tunnel; struct sc_adb_tunnel tunnel;
sc_socket video_socket; sc_socket video_socket;
sc_socket audio_socket;
sc_socket control_socket; sc_socket control_socket;
const struct sc_server_callbacks *cbs; const struct sc_server_callbacks *cbs;

View file

@ -20,6 +20,9 @@ public final class DesktopConnection implements Closeable {
private final LocalSocket videoSocket; private final LocalSocket videoSocket;
private final FileDescriptor videoFd; private final FileDescriptor videoFd;
private final LocalSocket audioSocket;
private final FileDescriptor audioFd;
private final LocalSocket controlSocket; private final LocalSocket controlSocket;
private final InputStream controlInputStream; private final InputStream controlInputStream;
private final OutputStream controlOutputStream; private final OutputStream controlOutputStream;
@ -27,9 +30,10 @@ public final class DesktopConnection implements Closeable {
private final ControlMessageReader reader = new ControlMessageReader(); private final ControlMessageReader reader = new ControlMessageReader();
private final DeviceMessageWriter writer = new DeviceMessageWriter(); 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.videoSocket = videoSocket;
this.controlSocket = controlSocket; this.controlSocket = controlSocket;
this.audioSocket = audioSocket;
if (controlSocket != null) { if (controlSocket != null) {
controlInputStream = controlSocket.getInputStream(); controlInputStream = controlSocket.getInputStream();
controlOutputStream = controlSocket.getOutputStream(); controlOutputStream = controlSocket.getOutputStream();
@ -38,6 +42,7 @@ public final class DesktopConnection implements Closeable {
controlOutputStream = null; controlOutputStream = null;
} }
videoFd = videoSocket.getFileDescriptor(); videoFd = videoSocket.getFileDescriptor();
audioFd = audioSocket != null ? audioSocket.getFileDescriptor() : null;
} }
private static LocalSocket connect(String abstractName) throws IOException { 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); 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); String socketName = getSocketName(scid);
LocalSocket videoSocket = null; LocalSocket videoSocket = null;
LocalSocket audioSocket = null;
LocalSocket controlSocket = null; LocalSocket controlSocket = null;
try { try {
if (tunnelForward) { 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 // send one byte so the client may read() to detect a connection error
videoSocket.getOutputStream().write(0); videoSocket.getOutputStream().write(0);
} }
if (audio) {
audioSocket = localServerSocket.accept();
}
if (control) { if (control) {
controlSocket = localServerSocket.accept(); controlSocket = localServerSocket.accept();
} }
} }
} else { } else {
videoSocket = connect(socketName); videoSocket = connect(socketName);
if (audio) {
audioSocket = connect(socketName);
}
if (control) { if (control) {
controlSocket = connect(socketName); controlSocket = connect(socketName);
} }
@ -82,19 +94,27 @@ public final class DesktopConnection implements Closeable {
if (videoSocket != null) { if (videoSocket != null) {
videoSocket.close(); videoSocket.close();
} }
if (audioSocket != null) {
audioSocket.close();
}
if (controlSocket != null) { if (controlSocket != null) {
controlSocket.close(); controlSocket.close();
} }
throw e; throw e;
} }
return new DesktopConnection(videoSocket, controlSocket); return new DesktopConnection(videoSocket, audioSocket, controlSocket);
} }
public void close() throws IOException { public void close() throws IOException {
videoSocket.shutdownInput(); videoSocket.shutdownInput();
videoSocket.shutdownOutput(); videoSocket.shutdownOutput();
videoSocket.close(); videoSocket.close();
if (audioSocket != null) {
audioSocket.shutdownInput();
audioSocket.shutdownOutput();
audioSocket.close();
}
if (controlSocket != null) { if (controlSocket != null) {
controlSocket.shutdownInput(); controlSocket.shutdownInput();
controlSocket.shutdownOutput(); controlSocket.shutdownOutput();
@ -121,6 +141,10 @@ public final class DesktopConnection implements Closeable {
return videoFd; return videoFd;
} }
public FileDescriptor getAudioFd() {
return audioFd;
}
public ControlMessage receiveControlMessage() throws IOException { public ControlMessage receiveControlMessage() throws IOException {
ControlMessage msg = reader.next(); ControlMessage msg = reader.next();
while (msg == null) { while (msg == null) {

View file

@ -68,6 +68,7 @@ public final class Server {
int scid = options.getScid(); int scid = options.getScid();
boolean tunnelForward = options.isTunnelForward(); boolean tunnelForward = options.isTunnelForward();
boolean control = options.getControl(); boolean control = options.getControl();
boolean audio = options.getAudio();
boolean sendDummyByte = options.getSendDummyByte(); boolean sendDummyByte = options.getSendDummyByte();
Workarounds.prepareMainLooper(); Workarounds.prepareMainLooper();
@ -85,7 +86,7 @@ public final class Server {
Controller controller = null; 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(); VideoCodec codec = options.getCodec();
if (options.getSendDeviceMeta()) { if (options.getSendDeviceMeta()) {
Size videoSize = device.getScreenInfo().getVideoSize(); Size videoSize = device.getScreenInfo().getVideoSize();