content: package com.genymobile.scrcpy;
  
  import java.io.IOException;
  import java.util.concurrent.ArrayBlockingQueue;
  import java.util.concurrent.BlockingQueue;
  
  public final class DeviceMessageSender {
  
      private final ControlChannel controlChannel;
  
      private Thread thread;
      private final BlockingQueue<DeviceMessage> queue = new ArrayBlockingQueue<>(16);
  
      public DeviceMessageSender(ControlChannel controlChannel) {
          this.controlChannel = controlChannel;
      }
  
      public void send(DeviceMessage msg) {
          if (!queue.offer(msg)) {
              Ln.w("Device message dropped: " + msg.getType());
          }
      }
  
      private void loop() throws IOException, InterruptedException {
          while (!Thread.currentThread().isInterrupted()) {
              DeviceMessage msg = queue.take();
              controlChannel.send(msg);
          }
      }
  
      public void start() {
          thread = new Thread(() -> {
              try {
                  loop();
              } catch (IOException | InterruptedException e) {
                  // this is expected on close
              } finally {
                  Ln.d("Device message sender stopped");
              }
          }, "control-send");
          thread.start();
      }
  
      public void stop() {
          if (thread != null) {
              thread.interrupt();
          }
      }
  
      public void join() throws InterruptedException {
          if (thread != null) {
              thread.join();
          }
      }
  }
  