scrcpy.c 5.2 KB
Newer Older
R
Romain Vimont 已提交
1
#include "scrcpy.h"
R
Romain Vimont 已提交
2

R
Romain Vimont 已提交
3 4
#include <stdio.h>
#include <string.h>
R
Romain Vimont 已提交
5 6
#include <unistd.h>
#include <libavformat/avformat.h>
R
Romain Vimont 已提交
7
#include <sys/time.h>
R
Romain Vimont 已提交
8 9
#include <SDL2/SDL.h>

R
Romain Vimont 已提交
10 11
#include "command.h"
#include "common.h"
R
Romain Vimont 已提交
12
#include "controller.h"
R
Romain Vimont 已提交
13
#include "decoder.h"
14
#include "device.h"
R
Romain Vimont 已提交
15 16
#include "events.h"
#include "frames.h"
R
Romain Vimont 已提交
17
#include "fpscounter.h"
18
#include "inputmanager.h"
R
Romain Vimont 已提交
19
#include "log.h"
R
Romain Vimont 已提交
20
#include "lockutil.h"
21
#include "net.h"
22
#include "screen.h"
R
Romain Vimont 已提交
23
#include "server.h"
R
Romain Vimont 已提交
24
#include "tinyxpm.h"
R
Romain Vimont 已提交
25

26
static struct server server = SERVER_INITIALIZER;
27
static struct screen screen = SCREEN_INITIALIZER;
R
Romain Vimont 已提交
28 29 30 31
static struct frames frames;
static struct decoder decoder;
static struct controller controller;

32 33
static struct input_manager input_manager = {
    .controller = &controller,
34
    .frames = &frames,
35 36 37
    .screen = &screen,
};

R
Romain Vimont 已提交
38
static void event_loop(void) {
R
Romain Vimont 已提交
39 40 41
    SDL_Event event;
    while (SDL_WaitEvent(&event)) {
        switch (event.type) {
R
Romain Vimont 已提交
42
            case EVENT_DECODER_STOPPED:
R
Romain Vimont 已提交
43
                LOGD("Video decoder stopped");
R
Romain Vimont 已提交
44
                return;
R
Romain Vimont 已提交
45
            case SDL_QUIT:
R
Romain Vimont 已提交
46
                LOGD("User requested to quit");
R
Romain Vimont 已提交
47
                return;
R
Romain Vimont 已提交
48
            case EVENT_NEW_FRAME:
R
Romain Vimont 已提交
49 50 51 52 53
                if (!screen.has_frame) {
                    screen.has_frame = SDL_TRUE;
                    // this is the very first frame, show the window
                    screen_show_window(&screen);
                }
R
Romain Vimont 已提交
54
                if (!screen_update_frame(&screen, &frames)) {
R
Romain Vimont 已提交
55 56 57 58 59 60 61
                    return;
                }
                break;
            case SDL_WINDOWEVENT:
                switch (event.window.event) {
                case SDL_WINDOWEVENT_EXPOSED:
                case SDL_WINDOWEVENT_SIZE_CHANGED:
62
                    screen_render(&screen);
R
Romain Vimont 已提交
63 64 65 66
                    break;
                }
                break;
            case SDL_TEXTINPUT: {
67
                input_manager_process_text_input(&input_manager, &event.text);
R
Romain Vimont 已提交
68
                break;
R
Romain Vimont 已提交
69
            }
R
Romain Vimont 已提交
70 71
            case SDL_KEYDOWN:
            case SDL_KEYUP:
72
                input_manager_process_key(&input_manager, &event.key);
R
Romain Vimont 已提交
73 74
                break;
            case SDL_MOUSEMOTION:
75
                input_manager_process_mouse_motion(&input_manager, &event.motion);
R
Romain Vimont 已提交
76 77
                break;
            case SDL_MOUSEWHEEL: {
78
                input_manager_process_mouse_wheel(&input_manager, &event.wheel);
R
Romain Vimont 已提交
79 80 81 82
                break;
            }
            case SDL_MOUSEBUTTONDOWN:
            case SDL_MOUSEBUTTONUP: {
83
                input_manager_process_mouse_button(&input_manager, &event.button);
R
Romain Vimont 已提交
84 85 86 87 88 89
                break;
            }
        }
    }
}

R
Romain Vimont 已提交
90
SDL_bool scrcpy(const char *serial, Uint16 local_port, Uint16 max_size, Uint32 bit_rate) {
91
    if (!server_start(&server, serial, local_port, max_size, bit_rate)) {
R
Romain Vimont 已提交
92 93 94
        return SDL_FALSE;
    }

95 96
    SDL_bool ret = SDL_TRUE;

R
Romain Vimont 已提交
97 98 99 100 101
    if (!sdl_init_and_configure()) {
        ret = SDL_FALSE;
        goto finally_destroy_server;
    }

102 103 104 105
    // SDL initialization replace the signal handler for SIGTERM, so Ctrl+C is
    // managed by the event loop. This blocking call blocks the event loop, so
    // timeout the connection not to block indefinitely in case of SIGTERM.
#define SERVER_CONNECT_TIMEOUT_MS 2000
106 107
    socket_t device_socket = server_connect_to(&server, serial, SERVER_CONNECT_TIMEOUT_MS);
    if (device_socket == INVALID_SOCKET) {
108
        server_stop(&server, serial);
109 110
        ret = SDL_FALSE;
        goto finally_destroy_server;
R
Romain Vimont 已提交
111 112 113
    }

    char device_name[DEVICE_NAME_FIELD_LENGTH];
114
    struct size frame_size;
R
Romain Vimont 已提交
115 116 117 118

    // screenrecord does not send frames when the screen content does not change
    // therefore, we transmit the screen size before the video stream, to be able
    // to init the window immediately
119
    if (!device_read_info(device_socket, device_name, &frame_size)) {
120
        server_stop(&server, serial);
121 122
        ret = SDL_FALSE;
        goto finally_destroy_server;
R
Romain Vimont 已提交
123 124 125
    }

    if (!frames_init(&frames)) {
126
        server_stop(&server, serial);
127 128
        ret = SDL_FALSE;
        goto finally_destroy_server;
R
Romain Vimont 已提交
129 130
    }

R
Romain Vimont 已提交
131
    decoder_init(&decoder, &frames, device_socket);
R
Romain Vimont 已提交
132 133 134 135 136

    // now we consumed the header values, the socket receives the video stream
    // start the decoder
    if (!decoder_start(&decoder)) {
        ret = SDL_FALSE;
137
        server_stop(&server, serial);
138
        goto finally_destroy_frames;
R
Romain Vimont 已提交
139 140 141 142
    }

    if (!controller_init(&controller, device_socket)) {
        ret = SDL_FALSE;
143
        goto finally_stop_decoder;
R
Romain Vimont 已提交
144 145 146 147
    }

    if (!controller_start(&controller)) {
        ret = SDL_FALSE;
148
        goto finally_destroy_controller;
R
Romain Vimont 已提交
149 150
    }

151
    if (!screen_init_rendering(&screen, device_name, frame_size)) {
R
Romain Vimont 已提交
152
        ret = SDL_FALSE;
153
        goto finally_stop_and_join_controller;
R
Romain Vimont 已提交
154
    }
R
Romain Vimont 已提交
155 156 157

    event_loop();

R
Romain Vimont 已提交
158
    LOGD("quit...");
159 160
    screen_destroy(&screen);
finally_stop_and_join_controller:
R
Romain Vimont 已提交
161 162
    controller_stop(&controller);
    controller_join(&controller);
163
finally_destroy_controller:
R
Romain Vimont 已提交
164
    controller_destroy(&controller);
165
finally_stop_decoder:
166
    decoder_stop(&decoder);
167
    // stop the server before decoder_join() to wake up the decoder
168
    server_stop(&server, serial);
R
Romain Vimont 已提交
169
    decoder_join(&decoder);
170
finally_destroy_frames:
R
Romain Vimont 已提交
171
    frames_destroy(&frames);
172 173
finally_destroy_server:
    server_destroy(&server);
R
Romain Vimont 已提交
174

R
Romain Vimont 已提交
175
    return ret;
R
Romain Vimont 已提交
176
}