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:
parent
5eed2c52c2
commit
7cf5cf5875
4 changed files with 58 additions and 2 deletions
46
server/src/main/java/com/genymobile/scrcpy/AudioCodec.java
Normal file
46
server/src/main/java/com/genymobile/scrcpy/AudioCodec.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ public interface Codec {
|
||||||
|
|
||||||
enum Type {
|
enum Type {
|
||||||
VIDEO,
|
VIDEO,
|
||||||
|
AUDIO,
|
||||||
}
|
}
|
||||||
|
|
||||||
Type getType();
|
Type getType();
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue