From 7cf5cf5875b217a5d2e141214d1dc344bdde4e73 Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Thu, 9 Feb 2023 21:37:16 +0100 Subject: [PATCH] Use a streamer to send the audio stream Send each encoded audio packet using a streamer. PR #3757 --- .../com/genymobile/scrcpy/AudioCodec.java | 46 +++++++++++++++++++ .../com/genymobile/scrcpy/AudioEncoder.java | 10 +++- .../java/com/genymobile/scrcpy/Codec.java | 1 + .../java/com/genymobile/scrcpy/Server.java | 3 +- 4 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 server/src/main/java/com/genymobile/scrcpy/AudioCodec.java diff --git a/server/src/main/java/com/genymobile/scrcpy/AudioCodec.java b/server/src/main/java/com/genymobile/scrcpy/AudioCodec.java new file mode 100644 index 00000000..4d9e3201 --- /dev/null +++ b/server/src/main/java/com/genymobile/scrcpy/AudioCodec.java @@ -0,0 +1,46 @@ +package com.genymobile.scrcpy; + +import android.media.MediaFormat; + +public enum AudioCodec implements Codec { + OPUS(0x6f_70_75_73, "opus", MediaFormat.MIMETYPE_AUDIO_OPUS); + + private final int id; // 4-byte ASCII representation of the name + private final String name; + private final String mimeType; + + AudioCodec(int id, String name, String mimeType) { + this.id = id; + this.name = name; + this.mimeType = mimeType; + } + + @Override + public Type getType() { + return Type.AUDIO; + } + + @Override + public int getId() { + return id; + } + + @Override + public String getName() { + return name; + } + + @Override + public String getMimeType() { + return mimeType; + } + + public static AudioCodec findByName(String name) { + for (AudioCodec codec : values()) { + if (codec.name.equals(name)) { + return codec; + } + } + return null; + } +} diff --git a/server/src/main/java/com/genymobile/scrcpy/AudioEncoder.java b/server/src/main/java/com/genymobile/scrcpy/AudioEncoder.java index 7b571126..74481f99 100644 --- a/server/src/main/java/com/genymobile/scrcpy/AudioEncoder.java +++ b/server/src/main/java/com/genymobile/scrcpy/AudioEncoder.java @@ -49,6 +49,8 @@ public final class AudioEncoder { private static final int READ_MS = 5; // milliseconds private static final int READ_SIZE = SAMPLE_RATE * CHANNELS * BYTES_PER_SAMPLE * READ_MS / 1000; + private final Streamer streamer; + // Capacity of 64 is in practice "infinite" (it is limited by the number of available MediaCodec buffers, typically 4). // So many pending tasks would lead to an unacceptable delay anyway. private final BlockingQueue inputTasks = new ArrayBlockingQueue<>(64); @@ -62,6 +64,10 @@ public final class AudioEncoder { private boolean ended; + public AudioEncoder(Streamer streamer) { + this.streamer = streamer; + } + private static AudioFormat createAudioFormat() { AudioFormat.Builder builder = new AudioFormat.Builder(); builder.setEncoding(FORMAT); @@ -141,11 +147,13 @@ public final class AudioEncoder { } private void outputThread(MediaCodec mediaCodec) throws IOException, InterruptedException { + streamer.writeHeader(); + while (!Thread.currentThread().isInterrupted()) { OutputTask task = outputTasks.take(); ByteBuffer buffer = mediaCodec.getOutputBuffer(task.index); try { - Ln.i("Audio packet [pts=" + task.bufferInfo.presentationTimeUs + "] " + buffer.remaining() + " bytes"); + streamer.writePacket(buffer, task.bufferInfo); } finally { mediaCodec.releaseOutputBuffer(task.index, false); } diff --git a/server/src/main/java/com/genymobile/scrcpy/Codec.java b/server/src/main/java/com/genymobile/scrcpy/Codec.java index 50e8acad..7e905af3 100644 --- a/server/src/main/java/com/genymobile/scrcpy/Codec.java +++ b/server/src/main/java/com/genymobile/scrcpy/Codec.java @@ -4,6 +4,7 @@ public interface Codec { enum Type { VIDEO, + AUDIO, } Type getType(); diff --git a/server/src/main/java/com/genymobile/scrcpy/Server.java b/server/src/main/java/com/genymobile/scrcpy/Server.java index c32e4612..eb0c1384 100644 --- a/server/src/main/java/com/genymobile/scrcpy/Server.java +++ b/server/src/main/java/com/genymobile/scrcpy/Server.java @@ -111,7 +111,8 @@ public final class Server { } if (audio) { - audioEncoder = new AudioEncoder(); + Streamer audioStreamer = new Streamer(connection.getAudioFd(), AudioCodec.OPUS, options.getSendCodecId(), options.getSendFrameMeta()); + audioEncoder = new AudioEncoder(audioStreamer); audioEncoder.start(); }