Skip to content

Commit

Permalink
hook up device events
Browse files Browse the repository at this point in the history
  • Loading branch information
Gottox committed Oct 4, 2024
1 parent c586646 commit 38b9970
Show file tree
Hide file tree
Showing 13 changed files with 427 additions and 17 deletions.
10 changes: 10 additions & 0 deletions app/src/control_msg.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ enum sc_control_msg_type {
SC_CONTROL_MSG_TYPE_UHID_INPUT,
SC_CONTROL_MSG_TYPE_UHID_DESTROY,
SC_CONTROL_MSG_TYPE_OPEN_HARD_KEYBOARD_SETTINGS,
SC_CONTROL_MSG_TYPE_MEDIA_STATE,
SC_CONTROL_MSG_TYPE_MEDIA_SEEK,
};

enum sc_screen_power_mode {
Expand Down Expand Up @@ -110,6 +112,14 @@ struct sc_control_msg {
struct {
uint16_t id;
} uhid_destroy;
struct {
uint16_t player_id;
uint64_t position;
} media_seek;
struct {
uint16_t player_id;
uint8_t state;
} media_state;
};
};

Expand Down
64 changes: 48 additions & 16 deletions app/src/device_msg.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,20 @@
#include "util/binary.h"
#include "util/log.h"

static int read_message(uint8_t **target, const uint8_t *src, const uint16_t size) {
uint8_t *data = malloc(size + 1);
if (!data) {
LOG_OOM();
return -1;
}
if (size) {
data[size] = '\0';
memcpy(data, src, size);
}
*target = data;
return 0;
}

ssize_t
sc_device_msg_deserialize(const uint8_t *buf, size_t len,
struct sc_device_msg *msg) {
Expand All @@ -25,17 +39,10 @@ sc_device_msg_deserialize(const uint8_t *buf, size_t len,
if (clipboard_len > len - 5) {
return 0; // no complete message
}
char *text = malloc(clipboard_len + 1);
if (!text) {
LOG_OOM();
if (read_message((uint8_t **)&msg->clipboard.text, &buf[5], clipboard_len) == -1) {
return -1;
}
if (clipboard_len) {
memcpy(text, &buf[5], clipboard_len);
}
text[clipboard_len] = '\0';

msg->clipboard.text = text;
return 5 + clipboard_len;
}
case DEVICE_MSG_TYPE_ACK_CLIPBOARD: {
Expand All @@ -56,21 +63,43 @@ sc_device_msg_deserialize(const uint8_t *buf, size_t len,
if (size < len - 5) {
return 0; // not available
}
uint8_t *data = malloc(size);
if (!data) {
LOG_OOM();

msg->uhid_output.id = id;
msg->uhid_output.size = size;
if (read_message(&msg->uhid_output.data, &buf[5], size) == -1) {
return -1;
}
if (size) {
memcpy(data, &buf[5], size);

return 5 + size;
case DEVICE_MSG_TYPE_MEDIA_UPDATE: {
if (len < 5) {
// at least id + size
return 0; // not available
}
uint16_t id = sc_read16be(&buf[1]);
size_t size = sc_read16be(&buf[3]);
if (size < len - 5) {
return 0; // not available
}

msg->uhid_output.id = id;
msg->uhid_output.size = size;
msg->uhid_output.data = data;
msg->media_update.id = id;
msg->media_update.size = size;
if (read_message(&msg->media_update.data, &buf[5], size) == -1) {
return -1;
}

return 5 + size;
}
case DEVICE_MSG_TYPE_MEDIA_REMOVE: {
if (len < 3) {
// at least id
return 0; // not available
}
uint16_t id = sc_read16be(&buf[1]);
msg->media_remove.id = id;
return 3;
}
}
default:
LOGW("Unknown device message type: %d", (int) msg->type);
return -1; // error, we cannot recover
Expand All @@ -86,6 +115,9 @@ sc_device_msg_destroy(struct sc_device_msg *msg) {
case DEVICE_MSG_TYPE_UHID_OUTPUT:
free(msg->uhid_output.data);
break;
case DEVICE_MSG_TYPE_MEDIA_UPDATE:
free(msg->media_update.data);
break;
default:
// nothing to do
break;
Expand Down
10 changes: 10 additions & 0 deletions app/src/device_msg.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ enum sc_device_msg_type {
DEVICE_MSG_TYPE_CLIPBOARD,
DEVICE_MSG_TYPE_ACK_CLIPBOARD,
DEVICE_MSG_TYPE_UHID_OUTPUT,
DEVICE_MSG_TYPE_MEDIA_UPDATE,
DEVICE_MSG_TYPE_MEDIA_REMOVE,
};

struct sc_device_msg {
Expand All @@ -31,6 +33,14 @@ struct sc_device_msg {
uint16_t size;
uint8_t *data; // owned, to be freed by free()
} uhid_output;
struct {
uint16_t id;
uint16_t size;
uint8_t *data; // owned, to be freed by free()
} media_update;
struct {
uint16_t id;
} media_remove;
};
};

Expand Down
22 changes: 22 additions & 0 deletions app/src/receiver.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,22 @@ task_uhid_output(void *userdata) {
free(data);
}

static void
dump_media_update(const struct sc_device_msg* msg) {
uint8_t msg_type = 0;
uint8_t *msg_ptr = NULL;
for (int i = 0; i < msg->media_update.size; i++) {
if (msg_ptr == NULL) {
msg_type = msg->media_update.data[i];
msg_ptr = &msg->media_update.data[i + 1];
} else if (msg->media_update.data[i] == 0) {
LOGI("Media update: %i, %s", (int)msg_type, msg_ptr);
msg_ptr = NULL;
msg_type = 0;
}
}
}

static void
process_msg(struct sc_receiver *receiver, struct sc_device_msg *msg) {
switch (msg->type) {
Expand Down Expand Up @@ -150,6 +166,12 @@ process_msg(struct sc_receiver *receiver, struct sc_device_msg *msg) {
return;
}

break;
case DEVICE_MSG_TYPE_MEDIA_UPDATE:
dump_media_update(msg);
break;
case DEVICE_MSG_TYPE_MEDIA_REMOVE:
LOGI("Media remove: %i", msg->media_remove.id);
break;
}
}
Expand Down
5 changes: 5 additions & 0 deletions server/src/main/java/com/genymobile/scrcpy/Options.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public class Options {
private int scid = -1; // 31-bit non-negative value, or -1
private boolean video = true;
private boolean audio = true;
private boolean mediaControl = true;
private int maxSize;
private VideoCodec videoCodec = VideoCodec.H264;
private AudioCodec audioCodec = AudioCodec.OPUS;
Expand Down Expand Up @@ -81,6 +82,10 @@ public boolean getAudio() {
return audio;
}

public boolean getMediaControls() {
return mediaControl;
}

public int getMaxSize() {
return maxSize;
}
Expand Down
41 changes: 41 additions & 0 deletions server/src/main/java/com/genymobile/scrcpy/Server.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@
import com.genymobile.scrcpy.video.SurfaceCapture;
import com.genymobile.scrcpy.video.SurfaceEncoder;
import com.genymobile.scrcpy.video.VideoSource;
import com.genymobile.scrcpy.wrappers.MediaManager;

import android.media.MediaMetadata;
import android.media.session.PlaybackState;
import android.os.BatteryManager;
import android.os.Build;

Expand Down Expand Up @@ -139,6 +142,7 @@ private static void scrcpy(Options options) throws IOException, ConfigurationExc
boolean control = options.getControl();
boolean video = options.getVideo();
boolean audio = options.getAudio();
boolean media = options.getMediaControls();
boolean sendDummyByte = options.getSendDummyByte();
boolean camera = video && options.getVideoSource() == VideoSource.CAMERA;

Expand All @@ -162,6 +166,40 @@ private static void scrcpy(Options options) throws IOException, ConfigurationExc
controller.getSender().send(msg);
});
asyncProcessors.add(controller);

if (media) {
MediaManager mediaManager = MediaManager.create();

mediaManager.setMediaChangeListener(new MediaManager.MediaChange() {
@Override
public void onMetadataChange(int id, MediaMetadata metadata) {
Ln.i("onMetadataChange " + id);
byte[] data = MediaManager.mediaMetadataSerialize(metadata);
DeviceMessage msg = DeviceMessage.createMediaUpdate(id, data);
controller.getSender().send(msg);
}

@Override
public void onPlaybackStateChange(int id, PlaybackState playbackState) {
Ln.i("onPlaybackStateChange " + id);
int state = MediaManager.create().playbackStateSerialize(playbackState);
if(state < 0) {
return;
}
DeviceMessage msg = DeviceMessage.createMediaState(id, state);
controller.getSender().send(msg);
}

@Override
public void onRemove(int id) {
Ln.i("onRemove " + id);
DeviceMessage msg = DeviceMessage.createMediaRemove(id);
controller.getSender().send(msg);
}
});

mediaManager.start();
}
}

if (audio) {
Expand Down Expand Up @@ -200,6 +238,9 @@ private static void scrcpy(Options options) throws IOException, ConfigurationExc
asyncProcessors.add(surfaceEncoder);
}




Completion completion = new Completion(asyncProcessors.size());
for (AsyncProcessor asyncProcessor : asyncProcessors) {
asyncProcessor.start((fatalError) -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ public final class ControlMessage {
public static final int TYPE_UHID_INPUT = 13;
public static final int TYPE_UHID_DESTROY = 14;
public static final int TYPE_OPEN_HARD_KEYBOARD_SETTINGS = 15;
public static final int TYPE_MEDIA_STATE = 16;
public static final int TYPE_MEDIA_SEEK = 17;

public static final long SEQUENCE_INVALID = 0;

Expand All @@ -48,6 +50,9 @@ public final class ControlMessage {
private long sequence;
private int id;
private byte[] data;
private int mediaState;
private long mediaSeek;


private ControlMessage() {
}
Expand Down Expand Up @@ -155,6 +160,22 @@ public static ControlMessage createUhidDestroy(int id) {
return msg;
}

public static ControlMessage createMediaState(int receiverId, byte state) {
ControlMessage msg = new ControlMessage();
msg.type = TYPE_MEDIA_STATE;
msg.id = receiverId;
msg.mediaState = state;
return msg;
}

public static ControlMessage createMediaSeek(int receiverId, long position) {
ControlMessage msg = new ControlMessage();
msg.type = TYPE_MEDIA_STATE;
msg.id = receiverId;
msg.mediaSeek = position;
return msg;
}

public int getType() {
return type;
}
Expand Down Expand Up @@ -226,4 +247,12 @@ public int getId() {
public byte[] getData() {
return data;
}

public long getMediaSeek() {
return mediaSeek;
}

public int getMediaState() {
return mediaState;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,27 @@ public ControlMessage read() throws IOException {
return parseUhidInput();
case ControlMessage.TYPE_UHID_DESTROY:
return parseUhidDestroy();
case ControlMessage.TYPE_MEDIA_STATE:
return parseMediaPlayStateRequest();
case ControlMessage.TYPE_MEDIA_SEEK:
return parseMediaSeekRequest();
default:
throw new ControlProtocolException("Unknown event type: " + type);
}
}

private ControlMessage parseMediaSeekRequest() throws IOException {
int receiverId = dis.readUnsignedShort();
long position = dis.readLong();
return ControlMessage.createMediaSeek(receiverId, position);
}

private ControlMessage parseMediaPlayStateRequest() throws IOException {
int receiverId = dis.readUnsignedShort();
byte state = dis.readByte();
return ControlMessage.createMediaState(receiverId, state);
}

private ControlMessage parseInjectKeycode() throws IOException {
int action = dis.readUnsignedByte();
int keycode = dis.readInt();
Expand Down
14 changes: 14 additions & 0 deletions server/src/main/java/com/genymobile/scrcpy/control/Controller.java
Original file line number Diff line number Diff line change
Expand Up @@ -221,13 +221,27 @@ private boolean handleEvent() throws IOException {
case ControlMessage.TYPE_OPEN_HARD_KEYBOARD_SETTINGS:
openHardKeyboardSettings();
break;
case ControlMessage.TYPE_MEDIA_STATE:
mediaUpdateState(msg.getId(), msg.getMediaState());
break;
case ControlMessage.TYPE_MEDIA_SEEK:
mediaSeek(msg.getId(), msg.getMediaSeek());
break;
default:
// do nothing
}

return true;
}

private void mediaUpdateState(int id, int mediaState) {
// TODO
}

private void mediaSeek(int id, long mediaSeek) {
// TODO
}

private boolean injectKeycode(int action, int keycode, int repeat, int metaState) {
if (keepPowerModeOff && action == KeyEvent.ACTION_UP && (keycode == KeyEvent.KEYCODE_POWER || keycode == KeyEvent.KEYCODE_WAKEUP)) {
schedulePowerModeOff();
Expand Down
Loading

0 comments on commit 38b9970

Please sign in to comment.