Use a streamer to send the audio stream

Send each encoded audio packet using a streamer.

PR #3757 <https://github.com/Genymobile/scrcpy/pull/3757>
This commit is contained in:
Romain Vimont 2023-02-09 21:37:16 +01:00
parent 5eed2c52c2
commit 7cf5cf5875
4 changed files with 58 additions and 2 deletions

View file

@ -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;
}
}

View file

@ -49,6 +49,8 @@ public final class AudioEncoder {
private static final int READ_MS = 5; // milliseconds private static final int READ_MS = 5; // milliseconds
private static final int READ_SIZE = SAMPLE_RATE * CHANNELS * BYTES_PER_SAMPLE * READ_MS / 1000; 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). // 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. // So many pending tasks would lead to an unacceptable delay anyway.
private final BlockingQueue<InputTask> inputTasks = new ArrayBlockingQueue<>(64); private final BlockingQueue<InputTask> inputTasks = new ArrayBlockingQueue<>(64);
@ -62,6 +64,10 @@ public final class AudioEncoder {
private boolean ended; private boolean ended;
public AudioEncoder(Streamer streamer) {
this.streamer = streamer;
}
private static AudioFormat createAudioFormat() { private static AudioFormat createAudioFormat() {
AudioFormat.Builder builder = new AudioFormat.Builder(); AudioFormat.Builder builder = new AudioFormat.Builder();
builder.setEncoding(FORMAT); builder.setEncoding(FORMAT);
@ -141,11 +147,13 @@ public final class AudioEncoder {
} }
private void outputThread(MediaCodec mediaCodec) throws IOException, InterruptedException { private void outputThread(MediaCodec mediaCodec) throws IOException, InterruptedException {
streamer.writeHeader();
while (!Thread.currentThread().isInterrupted()) { while (!Thread.currentThread().isInterrupted()) {
OutputTask task = outputTasks.take(); OutputTask task = outputTasks.take();
ByteBuffer buffer = mediaCodec.getOutputBuffer(task.index); ByteBuffer buffer = mediaCodec.getOutputBuffer(task.index);
try { try {
Ln.i("Audio packet [pts=" + task.bufferInfo.presentationTimeUs + "] " + buffer.remaining() + " bytes"); streamer.writePacket(buffer, task.bufferInfo);
} finally { } finally {
mediaCodec.releaseOutputBuffer(task.index, false); mediaCodec.releaseOutputBuffer(task.index, false);
} }

View file

@ -4,6 +4,7 @@ public interface Codec {
enum Type { enum Type {
VIDEO, VIDEO,
AUDIO,
} }
Type getType(); Type getType();

View file

@ -111,7 +111,8 @@ public final class Server {
} }
if (audio) { if (audio) {
audioEncoder = new AudioEncoder(); Streamer audioStreamer = new Streamer(connection.getAudioFd(), AudioCodec.OPUS, options.getSendCodecId(), options.getSendFrameMeta());
audioEncoder = new AudioEncoder(audioStreamer);
audioEncoder.start(); audioEncoder.start();
} }