Skip to content

Commit 50734c9

Browse files
committed
improve support for mac/apple
1 parent 0c0610e commit 50734c9

File tree

6 files changed

+82
-16
lines changed

6 files changed

+82
-16
lines changed

app/meson.build

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ src = [
2525
'src/keyboard_sdk.c',
2626
'src/mouse_capture.c',
2727
'src/mouse_sdk.c',
28-
'src/client_audio.c',
2928
'src/opengl.c',
3029
'src/options.c',
3130
'src/packet_merger.c',
@@ -97,6 +96,12 @@ if v4l2_support
9796
src += [ 'src/v4l2_sink.c' ]
9897
endif
9998

99+
libavdevice_dep = dependency('libavdevice', static: get_option('static'), required: false)
100+
client_audio_support = get_option('client_audio') and libavdevice_dep.found()
101+
if client_audio_support
102+
src += [ 'src/client_audio.c' ]
103+
endif
104+
100105
usb_support = get_option('usb')
101106
if usb_support
102107
src += [
@@ -122,8 +127,8 @@ dependencies = [
122127
dependency('sdl3', version: '>= 3.2.0', static: static),
123128
]
124129

125-
if v4l2_support
126-
dependencies += dependency('libavdevice', static: static)
130+
if v4l2_support or client_audio_support
131+
dependencies += libavdevice_dep
127132
endif
128133

129134
if usb_support
@@ -175,6 +180,9 @@ conf.set('SERVER_DEBUGGER', get_option('server_debugger'))
175180
# enable V4L2 support (linux only)
176181
conf.set('HAVE_V4L2', v4l2_support)
177182

183+
# enable client audio forwarding (requires libavdevice)
184+
conf.set('HAVE_CLIENT_AUDIO', client_audio_support)
185+
178186
# enable HID over AOA support (linux only)
179187
conf.set('HAVE_USB', usb_support)
180188

app/src/cli.c

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2650,8 +2650,13 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
26502650
"use --video-encoder or --audio-encoder.");
26512651
return false;
26522652
case OPT_CLIENT_AUDIO_SOURCE:
2653+
#ifdef HAVE_CLIENT_AUDIO
26532654
opts->client_audio_source = optarg;
26542655
break;
2656+
#else
2657+
LOGE("Client audio (--client-audio-source) is disabled in this build");
2658+
return false;
2659+
#endif
26552660
case OPT_VIDEO_ENCODER:
26562661
opts->video_encoder = optarg;
26572662
break;
@@ -2771,8 +2776,13 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
27712776
opts->list |= SC_OPTION_LIST_APPS;
27722777
break;
27732778
case OPT_LIST_AUDIO_SOURCES:
2779+
#ifdef HAVE_CLIENT_AUDIO
27742780
args->list_audio_sources = true;
27752781
break;
2782+
#else
2783+
LOGE("Client audio (--list-client-audio-sources) is disabled in this build");
2784+
return false;
2785+
#endif
27762786
case OPT_REQUIRE_AUDIO:
27772787
opts->require_audio = true;
27782788
break;
@@ -2944,8 +2954,12 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
29442954
opts->audio = false;
29452955
}
29462956

2947-
if (!opts->video && !opts->audio && !opts->control && !otg && !opts->client_audio_source) {
2948-
LOGE("No video, no audio, no control, no OTG, no client audio: nothing to do");
2957+
bool has_client_audio = false;
2958+
#ifdef HAVE_CLIENT_AUDIO
2959+
has_client_audio = opts->client_audio_source != NULL;
2960+
#endif
2961+
if (!opts->video && !opts->audio && !opts->control && !otg && !has_client_audio) {
2962+
LOGE("No video, no audio, no control, no OTG: nothing to do");
29492963
return false;
29502964
}
29512965

@@ -3065,12 +3079,14 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
30653079
}
30663080
}
30673081

3082+
#ifdef HAVE_CLIENT_AUDIO
30683083
if (opts->client_audio_source &&
30693084
(opts->audio_source == SC_AUDIO_SOURCE_VOICE_CALL ||
30703085
opts->audio_source == SC_AUDIO_SOURCE_VOICE_CALL_UPLINK)) {
30713086
LOGE("--client-audio-source is incompatible with --audio-source=voice-call and --audio-source=voice-call-uplink");
30723087
return false;
30733088
}
3089+
#endif
30743090

30753091
if (otg) {
30763092
if (!opts->control) {

app/src/client_audio.c

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,30 @@ sc_microphone_list_audio_sources(void) {
5454
LOGI("Audio input format: %s (%s)",
5555
input_format->name,
5656
input_format->long_name ? input_format->long_name : "no description");
57+
58+
#ifdef __APPLE__
59+
LOGI("Listing devices via avfoundation (see output above/below):");
60+
61+
AVDictionary *options = NULL;
62+
av_dict_set(&options, "list_devices", "true", 0);
63+
64+
AVFormatContext *fmt_ctx = NULL;
65+
avformat_open_input(&fmt_ctx, "", input_format, &options);
66+
67+
av_dict_free(&options);
68+
if (fmt_ctx) {
69+
avformat_close_input(&fmt_ctx);
70+
}
71+
72+
LOGI("How to use:");
73+
LOGI(" Use the audio device index with --client-audio-source");
74+
LOGI(" Format: \":AUDIO_INDEX\" (e.g., \":0\" for first audio device)");
75+
LOGI("Examples:");
76+
LOGI(" scrcpy --client-audio-source :0");
77+
LOGI(" scrcpy --client-audio-source file:///path/to/audio.mp3");
78+
return;
79+
#endif
80+
5781
LOGI("Available audio sources:");
5882

5983
AVDeviceInfoList *device_list = NULL;
@@ -66,9 +90,6 @@ sc_microphone_list_audio_sources(void) {
6690
#ifdef _WIN32
6791
LOGI(" - \"audio=DEVICE_NAME\" (for dshow)");
6892
LOGI(" - Try running 'ffmpeg -list_devices true -f dshow -i dummy' to see available devices");
69-
#elif defined(__APPLE__)
70-
LOGI(" - \":0\" (default microphone)");
71-
LOGI(" - Try running 'ffmpeg -f avfoundation -list_devices true -i \"\"' to see available devices");
7293
#else
7394
LOGI(" - \"default\" (default ALSA device)");
7495
LOGI(" - \"hw:0,0\" (hardware device)");
@@ -93,13 +114,10 @@ sc_microphone_list_audio_sources(void) {
93114
avdevice_free_list_devices(&device_list);
94115

95116
LOGI("How to use:");
96-
LOGI(" Use the device name exactly as shown above with --client-audio-source");
117+
LOGI(" Pass the device names shown above as --client-audio-source <device>");
97118
LOGI("Common microphone devices:");
98119
#ifdef _WIN32
99120
LOGI(" - \"audio=DEVICE_NAME\" (use the exact name from the list)");
100-
#elif defined(__APPLE__)
101-
LOGI(" - \":0\" or \":1\" (device indices for macOS)");
102-
LOGI(" - \"default\" (default microphone)");
103121
#else
104122
LOGI(" - \"default\" (usually your default microphone)");
105123
LOGI(" - \"hw:CARD,DEV\" devices are hardware devices");
@@ -289,8 +307,15 @@ sc_microphone_run(void *data) {
289307
}
290308

291309
if (read_ret < 0) {
292-
// For device input, any error means we should stop
310+
// EAGAIN means no data available yet, retry
311+
if (read_ret == AVERROR(EAGAIN)) {
312+
av_usleep(1000);
313+
continue;
314+
}
293315
if (!is_file) {
316+
char errbuf[128];
317+
av_strerror(read_ret, errbuf, sizeof(errbuf));
318+
LOGD("av_read_frame error: %d (%s)", read_ret, errbuf);
294319
break;
295320
}
296321
continue;

app/src/main.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
#include <stdbool.h>
44
#include <stdio.h>
5-
#ifdef HAVE_V4L2
5+
#ifdef HAVE_CLIENT_AUDIO
66
# include <libavdevice/avdevice.h>
77
#endif
88
#include <SDL3/SDL.h>
@@ -17,7 +17,9 @@
1717
#include "util/net.h"
1818
#include "util/thread.h"
1919
#include "version.h"
20-
#include "client_audio.h"
20+
#ifdef HAVE_CLIENT_AUDIO
21+
# include "client_audio.h"
22+
#endif
2123

2224
#ifdef _WIN32
2325
#include <windows.h>
@@ -73,6 +75,7 @@ main_scrcpy(int argc, char *argv[]) {
7375
av_register_all();
7476
#endif
7577

78+
#ifdef HAVE_CLIENT_AUDIO
7679
//needed for capturing microphone and listing audio sources
7780
avdevice_register_all();
7881

@@ -81,6 +84,7 @@ main_scrcpy(int argc, char *argv[]) {
8184
ret = SCRCPY_EXIT_SUCCESS;
8285
goto end;
8386
}
87+
#endif
8488

8589
// The current thread is the main thread
8690
SC_MAIN_THREAD_ID = sc_thread_get_id();

app/src/scrcpy.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@
2626
#include "recorder.h"
2727
#include "screen.h"
2828
#include "server.h"
29-
#include "client_audio.h"
29+
#ifdef HAVE_CLIENT_AUDIO
30+
# include "client_audio.h"
31+
#endif
3032
#include "uhid/gamepad_uhid.h"
3133
#include "uhid/keyboard_uhid.h"
3234
#include "uhid/mouse_uhid.h"
@@ -62,8 +64,10 @@ struct scrcpy {
6264
#endif
6365
struct sc_controller controller;
6466
struct sc_file_pusher file_pusher;
67+
#ifdef HAVE_CLIENT_AUDIO
6568
struct sc_microphone_params microphone_params;
6669
sc_thread microphone_thread;
70+
#endif
6771
#ifdef HAVE_USB
6872
struct sc_usb usb;
6973
struct sc_aoa aoa;
@@ -451,7 +455,11 @@ scrcpy(struct scrcpy_options *options) {
451455
.display_ime_policy = options->display_ime_policy,
452456
.video = options->video,
453457
.audio = options->audio,
458+
#ifdef HAVE_CLIENT_AUDIO
454459
.client_audio = options->client_audio_source != NULL,
460+
#else
461+
.client_audio = false,
462+
#endif
455463
.audio_dup = options->audio_dup,
456464
.show_touches = options->show_touches,
457465
.stay_awake = options->stay_awake,
@@ -892,6 +900,7 @@ scrcpy(struct scrcpy_options *options) {
892900
audio_demuxer_started = true;
893901
}
894902

903+
#ifdef HAVE_CLIENT_AUDIO
895904
bool microphone_started = false;
896905
if (options->client_audio_source) {
897906
s->microphone_params.socket = s->server.client_mic_socket;
@@ -903,6 +912,7 @@ scrcpy(struct scrcpy_options *options) {
903912
}
904913
microphone_started = true;
905914
}
915+
#endif
906916

907917
// If the device screen is to be turned off, send the control message after
908918
// everything is set up
@@ -1032,9 +1042,11 @@ scrcpy(struct scrcpy_options *options) {
10321042
sc_demuxer_join(&s->audio_demuxer);
10331043
}
10341044

1045+
#ifdef HAVE_CLIENT_AUDIO
10351046
if (microphone_started) {
10361047
sc_thread_join(&s->microphone_thread, NULL);
10371048
}
1049+
#endif
10381050

10391051
#ifdef HAVE_V4L2
10401052
if (v4l2_sink_initialized) {

meson_options.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ option('static', type: 'boolean', value: false, description: 'Use static depende
66
option('server_debugger', type: 'boolean', value: false, description: 'Run a server debugger and wait for a client to be attached')
77
option('v4l2', type: 'boolean', value: true, description: 'Enable V4L2 feature when supported')
88
option('usb', type: 'boolean', value: true, description: 'Enable HID/OTG features when supported')
9+
option('client_audio', type: 'boolean', value: true, description: 'Enable client audio forwarding (requires libavdevice)')

0 commit comments

Comments
 (0)