Add raw audio recorder
Add an alternative AudioRecorder to stream raw packets without encoding. PR #3757 <https://github.com/Genymobile/scrcpy/pull/3757>
This commit is contained in:
parent
dc228eaad0
commit
66b6c06443
3 changed files with 86 additions and 3 deletions
|
@ -4,7 +4,8 @@ import android.media.MediaFormat;
|
||||||
|
|
||||||
public enum AudioCodec implements Codec {
|
public enum AudioCodec implements Codec {
|
||||||
OPUS(0x6f_70_75_73, "opus", MediaFormat.MIMETYPE_AUDIO_OPUS),
|
OPUS(0x6f_70_75_73, "opus", MediaFormat.MIMETYPE_AUDIO_OPUS),
|
||||||
AAC(0x00_61_61_63, "aac", MediaFormat.MIMETYPE_AUDIO_AAC);
|
AAC(0x00_61_61_63, "aac", MediaFormat.MIMETYPE_AUDIO_AAC),
|
||||||
|
RAW(0x00_72_61_77, "raw", MediaFormat.MIMETYPE_AUDIO_RAW);
|
||||||
|
|
||||||
private final int id; // 4-byte ASCII representation of the name
|
private final int id; // 4-byte ASCII representation of the name
|
||||||
private final String name;
|
private final String name;
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
package com.genymobile.scrcpy;
|
||||||
|
|
||||||
|
import android.media.MediaCodec;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
public final class AudioRawRecorder implements AsyncProcessor {
|
||||||
|
|
||||||
|
private final Streamer streamer;
|
||||||
|
|
||||||
|
private Thread thread;
|
||||||
|
|
||||||
|
private static final int READ_MS = 5; // milliseconds
|
||||||
|
private static final int READ_SIZE = AudioCapture.millisToBytes(READ_MS);
|
||||||
|
|
||||||
|
public AudioRawRecorder(Streamer streamer) {
|
||||||
|
this.streamer = streamer;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void record() throws IOException, AudioCaptureForegroundException {
|
||||||
|
final ByteBuffer buffer = ByteBuffer.allocateDirect(READ_SIZE);
|
||||||
|
final MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
|
||||||
|
|
||||||
|
AudioCapture capture = new AudioCapture();
|
||||||
|
try {
|
||||||
|
capture.start();
|
||||||
|
|
||||||
|
streamer.writeHeader();
|
||||||
|
while (!Thread.currentThread().isInterrupted()) {
|
||||||
|
buffer.position(0);
|
||||||
|
int r = capture.read(buffer, READ_SIZE, bufferInfo);
|
||||||
|
if (r < 0) {
|
||||||
|
throw new IOException("Could not read audio: " + r);
|
||||||
|
}
|
||||||
|
buffer.limit(r);
|
||||||
|
|
||||||
|
streamer.writePacket(buffer, bufferInfo);
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
// Notify the client that the audio could not be captured
|
||||||
|
streamer.writeDisableStream(false);
|
||||||
|
throw e;
|
||||||
|
} finally {
|
||||||
|
capture.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start() {
|
||||||
|
thread = new Thread(() -> {
|
||||||
|
try {
|
||||||
|
record();
|
||||||
|
} catch (AudioCaptureForegroundException e) {
|
||||||
|
// Do not print stack trace, a user-friendly error-message has already been logged
|
||||||
|
} catch (IOException e) {
|
||||||
|
Ln.e("Audio recording error", e);
|
||||||
|
} finally {
|
||||||
|
Ln.d("Audio recorder stopped");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
thread.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop() {
|
||||||
|
if (thread != null) {
|
||||||
|
thread.interrupt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void join() throws InterruptedException {
|
||||||
|
if (thread != null) {
|
||||||
|
thread.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -107,9 +107,16 @@ public final class Server {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (audio) {
|
if (audio) {
|
||||||
Streamer audioStreamer = new Streamer(connection.getAudioFd(), options.getAudioCodec(), options.getSendCodecId(),
|
AudioCodec audioCodec = options.getAudioCodec();
|
||||||
|
Streamer audioStreamer = new Streamer(connection.getAudioFd(), audioCodec, options.getSendCodecId(),
|
||||||
options.getSendFrameMeta());
|
options.getSendFrameMeta());
|
||||||
AudioEncoder audioRecorder = new AudioEncoder(audioStreamer, options.getAudioBitRate(), options.getAudioCodecOptions(), options.getAudioEncoder());
|
AsyncProcessor audioRecorder;
|
||||||
|
if (audioCodec == AudioCodec.RAW) {
|
||||||
|
audioRecorder = new AudioRawRecorder(audioStreamer);
|
||||||
|
} else {
|
||||||
|
audioRecorder = new AudioEncoder(audioStreamer, options.getAudioBitRate(), options.getAudioCodecOptions(),
|
||||||
|
options.getAudioEncoder());
|
||||||
|
}
|
||||||
asyncProcessors.add(audioRecorder);
|
asyncProcessors.add(audioRecorder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue