2021년 9월 5일 일요일

scrcpy (안드로이드 단말을 PC에 연결해서 화면 보기, 스크린 미러링) #2 소스 분석


계속해서 scrcpy의 소스 구조를 탐험하였다.

지난번에 확인한것은 adb 명령으로 jar파일을 넣고 해당 jar파일을 실행시키는것까지 확인하였다.

다음으로 궁금한것은 화면을 어떤 방식으로 전달하고 있는가이다.


pc 용 프로그램에서는

scrcpy() 함수를 호출하고, 해당 함수가 끝나면 종료되는 구조


이전 글에서 설명한 부분이 server_start()함수이며, jar 파일 전송과 실행을 adb로 담당하게되고

    if (!server_start(&s->server, &params)) {

        goto end;

    }

SDL은 PC에서 화면을 출력하기 위한 라이브러리이다.

    if (!sdl_init_and_configure(options->display, options->render_driver,

                                options->disable_screensaver)) {

        goto end;

    }

아래 부분이 이번에 다루게될 부분으로 통신이 어떻게 된건지 해부해볼 부분이다.

    if (!server_connect_to(&s->server, device_name, &frame_size)) {

        goto end;

    }

함수에서 server->video_socket 부분을 따라가면 되는데, 그 외에도 제어를 위해서 server->control_socket 도 있긴합니다.

일단 video_socket 부분만 확인하면 아래와 같은 코드들이 보입니다.

server->video_socket = net_accept(server->server_socket);

server->video_socket =

            connect_to_server(server->local_port, attempts, delay);


enable_tunnel_any_port


기본적인 통신은 소켓을 이용하여 통신을 하게 되는데, 

PC쪽에 서버 소켓을 만들지 , android 쪽에 만들지에 대한 부분이 차이가 나서 코드가 복잡하게 되어있다.


이 내용은 안드로이 단말에 올라가는 jar 파일 소스를 보면 좀 더 명확해진다.

https://github.com/Genymobile/scrcpy/blob/master/server/src/main/java/com/genymobile/scrcpy/DesktopConnection.java


    public static DesktopConnection open(Device device, boolean tunnelForward) throws IOException {
        LocalSocket videoSocket;
        LocalSocket controlSocket;
        if (tunnelForward) {
            LocalServerSocket localServerSocket = new LocalServerSocket(SOCKET_NAME);
            try {
                videoSocket = localServerSocket.accept();
                // send one byte so the client may read() to detect a connection error
                videoSocket.getOutputStream().write(0);
                try {
                    controlSocket = localServerSocket.accept();
                } catch (IOException | RuntimeException e) {
                    videoSocket.close();
                    throw e;
                }
            } finally {
                localServerSocket.close();
            }
        } else {
            videoSocket = connect(SOCKET_NAME);
            try {
                controlSocket = connect(SOCKET_NAME);
            } catch (IOException | RuntimeException e) {
                videoSocket.close();
                throw e;
            }
        }

        DesktopConnection connection = new DesktopConnection(videoSocket, controlSocket);
        Size videoSize = device.getScreenInfo().getVideoSize();
        connection.send(Device.getDeviceName(), videoSize.getWidth(), videoSize.getHeight());
        return connection;
    }


코드는 이부분이고 tunnelForward 에 따라 자체적으로 localserver socket 으로 만들지 아니면 접속할지 코드가 나뉘어져 있다.


오늘은 통신이 연결된 구조에 대해 알아보았습니다.

한줄 요약 : 로컬 소켓 통신(TCP/IP)을 하도록 구성되어있음



댓글 없음:

댓글 쓰기