Skip to content

Commit 9d10730

Browse files
committed
Try forward client microphone without encoding
1 parent f2538e4 commit 9d10730

File tree

12 files changed

+355
-7
lines changed

12 files changed

+355
-7
lines changed

app/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ src = [
2525
'src/keyboard_sdk.c',
2626
'src/mouse_capture.c',
2727
'src/mouse_sdk.c',
28+
'src/microphone.c',
2829
'src/opengl.c',
2930
'src/options.c',
3031
'src/packet_merger.c',

app/src/main.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "util/net.h"
1717
#include "util/thread.h"
1818
#include "version.h"
19+
#include "microphone.h"
1920

2021
#ifdef _WIN32
2122
#include <windows.h>
@@ -73,11 +74,16 @@ main_scrcpy(int argc, char *argv[]) {
7374
av_register_all();
7475
#endif
7576

77+
/*
7678
#ifdef HAVE_V4L2
7779
if (args.opts.v4l2_device) {
7880
avdevice_register_all();
7981
}
8082
#endif
83+
*/
84+
85+
//NEED TO DO THIS for microphone
86+
avdevice_register_all();
8187

8288
if (!net_init()) {
8389
ret = SCRCPY_EXIT_FAILURE;

app/src/microphone.c

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
#include "microphone.h"
2+
#include <libavcodec/avcodec.h>
3+
#include <libavdevice/avdevice.h>
4+
#include <libavformat/avformat.h>
5+
#include <stdio.h>
6+
#include "util/log.h"
7+
#include "util/net.h"
8+
9+
int read_mic(void *data) {
10+
sc_socket mic_socket = *(sc_socket*)data;
11+
const char *input_format_name = "alsa";
12+
const char *device_name = "default";
13+
14+
AVInputFormat *input_format = av_find_input_format(input_format_name);
15+
if (!input_format) {
16+
fprintf(stderr, "Could not find ALSA input format\n");
17+
return 1;
18+
}
19+
20+
AVFormatContext *fmt_ctx = NULL;
21+
if (avformat_open_input(&fmt_ctx, device_name, input_format, NULL) < 0) {
22+
fprintf(stderr, "Could not open ALSA device '%s'\n", device_name);
23+
return 1;
24+
}
25+
26+
if (avformat_find_stream_info(fmt_ctx, NULL) < 0) {
27+
fprintf(stderr, "Could not read stream info\n");
28+
avformat_close_input(&fmt_ctx);
29+
return 1;
30+
}
31+
32+
// ALSA has only one audio stream
33+
int audio_stream_index = 0;
34+
AVCodecParameters *codecpar = fmt_ctx->streams[audio_stream_index]->codecpar;
35+
AVCodec *codec = avcodec_find_decoder(codecpar->codec_id);
36+
if (!codec) {
37+
fprintf(stderr, "Codec not found\n");
38+
avformat_close_input(&fmt_ctx);
39+
return 1;
40+
}
41+
42+
AVCodecContext *codec_ctx = avcodec_alloc_context3(codec);
43+
avcodec_parameters_to_context(codec_ctx, codecpar);
44+
if (avcodec_open2(codec_ctx, codec, NULL) < 0) {
45+
fprintf(stderr, "Could not open codec\n");
46+
avcodec_free_context(&codec_ctx);
47+
avformat_close_input(&fmt_ctx);
48+
return 1;
49+
}
50+
LOGD("sample_fmt = %d\n", codec_ctx->sample_fmt);
51+
LOGD("sample rate = %d\n", codec_ctx->sample_rate);
52+
53+
AVPacket pkt;
54+
AVFrame *frame = av_frame_alloc();
55+
printf("Recording audio (Ctrl+C to stop)...\n");
56+
57+
while (av_read_frame(fmt_ctx, &pkt) >= 0) {
58+
// ALSA always gives audio packets, so skip the stream_index check
59+
if (avcodec_send_packet(codec_ctx, &pkt) >= 0) {
60+
while (avcodec_receive_frame(codec_ctx, frame) >= 0) {
61+
int bytes_per_sample = av_get_bytes_per_sample(codec_ctx->sample_fmt);
62+
int data_size = frame->nb_samples * frame->ch_layout.nb_channels * bytes_per_sample;
63+
64+
net_send_all(mic_socket, frame->data[0], data_size);
65+
}
66+
}
67+
av_packet_unref(&pkt);
68+
}
69+
70+
av_frame_free(&frame);
71+
avcodec_free_context(&codec_ctx);
72+
avformat_close_input(&fmt_ctx);
73+
return 0;
74+
}

app/src/microphone.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#include "util/net.h"
2+
int read_mic(void *);

app/src/options.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ const struct scrcpy_options scrcpy_options_default = {
101101
.power_on = true,
102102
.video = true,
103103
.audio = true,
104+
.microphone = true,
104105
.require_audio = false,
105106
.kill_adb_on_close = false,
106107
.camera_high_speed = false,

app/src/options.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,7 @@ struct scrcpy_options {
311311
bool power_on;
312312
bool video;
313313
bool audio;
314+
bool microphone;
314315
bool require_audio;
315316
bool kill_adb_on_close;
316317
bool camera_high_speed;

app/src/scrcpy.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "recorder.h"
2727
#include "screen.h"
2828
#include "server.h"
29+
#include "microphone.h"
2930
#include "uhid/gamepad_uhid.h"
3031
#include "uhid/keyboard_uhid.h"
3132
#include "uhid/mouse_uhid.h"
@@ -450,6 +451,7 @@ scrcpy(struct scrcpy_options *options) {
450451
.display_ime_policy = options->display_ime_policy,
451452
.video = options->video,
452453
.audio = options->audio,
454+
.microphone = options->microphone,
453455
.audio_dup = options->audio_dup,
454456
.show_touches = options->show_touches,
455457
.stay_awake = options->stay_awake,
@@ -887,6 +889,14 @@ scrcpy(struct scrcpy_options *options) {
887889
audio_demuxer_started = true;
888890
}
889891

892+
if (options->microphone) {
893+
sc_thread mic_thread;
894+
bool ok = sc_thread_create(&mic_thread, read_mic, "scrcpy-mic", &s->server.mic_socket);
895+
if (!ok) {
896+
goto end;
897+
}
898+
}
899+
890900
// If the device screen is to be turned off, send the control message after
891901
// everything is set up
892902
if (options->control && options->turn_screen_off) {

app/src/server.c

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "util/env.h"
1212
#include "util/file.h"
1313
#include "util/log.h"
14+
#include "util/net.h"
1415
#include "util/net_intr.h"
1516
#include "util/process.h"
1617
#include "util/str.h"
@@ -555,6 +556,7 @@ sc_server_init(struct sc_server *server, const struct sc_server_params *params,
555556
server->video_socket = SC_SOCKET_NONE;
556557
server->audio_socket = SC_SOCKET_NONE;
557558
server->control_socket = SC_SOCKET_NONE;
559+
server->mic_socket = SC_SOCKET_NONE;
558560

559561
sc_adb_tunnel_init(&server->tunnel);
560562

@@ -597,10 +599,12 @@ sc_server_connect_to(struct sc_server *server, struct sc_server_info *info) {
597599
bool video = server->params.video;
598600
bool audio = server->params.audio;
599601
bool control = server->params.control;
602+
bool microphone = server->params.microphone;
600603

601604
sc_socket video_socket = SC_SOCKET_NONE;
602605
sc_socket audio_socket = SC_SOCKET_NONE;
603606
sc_socket control_socket = SC_SOCKET_NONE;
607+
sc_socket mic_socket = SC_SOCKET_NONE;
604608
if (!tunnel->forward) {
605609
if (video) {
606610
video_socket =
@@ -625,6 +629,14 @@ sc_server_connect_to(struct sc_server *server, struct sc_server_info *info) {
625629
goto fail;
626630
}
627631
}
632+
633+
if (microphone) {
634+
mic_socket =
635+
net_accept_intr(&server->intr, tunnel->server_socket);
636+
if (mic_socket == SC_SOCKET_NONE) {
637+
goto fail;
638+
}
639+
}
628640
} else {
629641
uint32_t tunnel_host = server->params.tunnel_host;
630642
if (!tunnel_host) {
@@ -681,14 +693,19 @@ sc_server_connect_to(struct sc_server *server, struct sc_server_info *info) {
681693
}
682694
}
683695

696+
// Disable Nagle's algorithm for the control socket
697+
// (it only impacts the sending side, so it is useless to set it
698+
// for the other sockets)
684699
if (control_socket != SC_SOCKET_NONE) {
685-
// Disable Nagle's algorithm for the control socket
686-
// (it only impacts the sending side, so it is useless to set it
687-
// for the other sockets)
688700
bool ok = net_set_tcp_nodelay(control_socket, true);
689701
(void) ok; // error already logged
690702
}
691703

704+
if (mic_socket != SC_SOCKET_NONE) {
705+
bool ok = net_set_tcp_nodelay(mic_socket, true);
706+
(void) ok; // error already logged
707+
}
708+
692709
// we don't need the adb tunnel anymore
693710
sc_adb_tunnel_close(tunnel, &server->intr, serial,
694711
server->device_socket_name);
@@ -706,10 +723,12 @@ sc_server_connect_to(struct sc_server *server, struct sc_server_info *info) {
706723
assert(!video || video_socket != SC_SOCKET_NONE);
707724
assert(!audio || audio_socket != SC_SOCKET_NONE);
708725
assert(!control || control_socket != SC_SOCKET_NONE);
726+
assert(!microphone || mic_socket != SC_SOCKET_NONE);
709727

710728
server->video_socket = video_socket;
711729
server->audio_socket = audio_socket;
712730
server->control_socket = control_socket;
731+
server->mic_socket = mic_socket;
713732

714733
return true;
715734

@@ -732,6 +751,12 @@ sc_server_connect_to(struct sc_server *server, struct sc_server_info *info) {
732751
}
733752
}
734753

754+
if (mic_socket != SC_SOCKET_NONE) {
755+
if (!net_close(mic_socket)) {
756+
LOGW("Could not close microphone socket");
757+
}
758+
}
759+
735760
if (tunnel->enabled) {
736761
// Always leave this function with tunnel disabled
737762
sc_adb_tunnel_close(tunnel, &server->intr, serial,
@@ -1121,6 +1146,11 @@ run_server(void *data) {
11211146
net_interrupt(server->control_socket);
11221147
}
11231148

1149+
if (server->mic_socket != SC_SOCKET_NONE) {
1150+
// There is no control_socket if --no-microphone is set
1151+
net_interrupt(server->mic_socket);
1152+
}
1153+
11241154
// Give some delay for the server to terminate properly
11251155
#define WATCHDOG_DELAY SC_TICK_FROM_SEC(1)
11261156
sc_tick deadline = sc_tick_now() + WATCHDOG_DELAY;
@@ -1189,6 +1219,9 @@ sc_server_destroy(struct sc_server *server) {
11891219
if (server->control_socket != SC_SOCKET_NONE) {
11901220
net_close(server->control_socket);
11911221
}
1222+
if (server->mic_socket != SC_SOCKET_NONE) {
1223+
net_close(server->mic_socket);
1224+
}
11921225

11931226
free(server->serial);
11941227
free(server->device_socket_name);

app/src/server.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ struct sc_server_params {
5353
enum sc_display_ime_policy display_ime_policy;
5454
bool video;
5555
bool audio;
56+
bool microphone;
5657
bool audio_dup;
5758
bool show_touches;
5859
bool stay_awake;
@@ -91,6 +92,7 @@ struct sc_server {
9192

9293
sc_socket video_socket;
9394
sc_socket audio_socket;
95+
sc_socket mic_socket;
9496
sc_socket control_socket;
9597

9698
const struct sc_server_callbacks *cbs;

server/src/main/java/com/genymobile/scrcpy/Options.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ public class Options {
2626
private int scid = -1; // 31-bit non-negative value, or -1
2727
private boolean video = true;
2828
private boolean audio = true;
29+
private boolean microphone = true;
2930
private int maxSize;
3031
private VideoCodec videoCodec = VideoCodec.H264;
3132
private AudioCodec audioCodec = AudioCodec.OPUS;
@@ -96,6 +97,10 @@ public boolean getAudio() {
9697
return audio;
9798
}
9899

100+
public boolean getMicrophone() {
101+
return microphone;
102+
}
103+
99104
public int getMaxSize() {
100105
return maxSize;
101106
}
@@ -327,6 +332,9 @@ public static Options parse(String... args) {
327332
case "audio":
328333
options.audio = Boolean.parseBoolean(value);
329334
break;
335+
case "microphone":
336+
options.microphone = Boolean.parseBoolean(value);
337+
break;
330338
case "video_codec":
331339
VideoCodec videoCodec = VideoCodec.findByName(value);
332340
if (videoCodec == null) {

0 commit comments

Comments
 (0)