Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions app/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,12 @@ if v4l2_support
src += [ 'src/v4l2_sink.c' ]
endif

libavdevice_dep = dependency('libavdevice', static: get_option('static'), required: false)
client_audio_support = get_option('client_audio') and libavdevice_dep.found()
if client_audio_support
src += [ 'src/client_audio.c' ]
endif

usb_support = get_option('usb')
if usb_support
src += [
Expand All @@ -129,8 +135,8 @@ dependencies = [
dependency('sdl3', version: '>= 3.2.0', static: static),
]

if v4l2_support
dependencies += dependency('libavdevice', static: static)
if v4l2_support or client_audio_support
dependencies += libavdevice_dep
endif

if usb_support
Expand Down Expand Up @@ -182,6 +188,9 @@ conf.set('SERVER_DEBUGGER', get_option('server_debugger'))
# enable V4L2 support (linux only)
conf.set('HAVE_V4L2', v4l2_support)

# enable client audio forwarding (requires libavdevice)
conf.set('HAVE_CLIENT_AUDIO', client_audio_support)

# enable HID over AOA support (linux only)
conf.set('HAVE_USB', usb_support)

Expand Down
48 changes: 47 additions & 1 deletion app/src/cli.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ enum {
OPT_SHORTCUT_MOD,
OPT_NO_KEY_REPEAT,
OPT_LEGACY_PASTE,
OPT_CLIENT_AUDIO_SOURCE,
OPT_VIDEO_ENCODER,
OPT_POWER_OFF_ON_CLOSE,
OPT_V4L2_SINK,
Expand Down Expand Up @@ -106,6 +107,7 @@ enum {
OPT_MIN_SIZE_ALIGNMENT,
OPT_NO_WINDOW_ASPECT_RATIO_LOCK,
OPT_KEEP_ACTIVE,
OPT_LIST_AUDIO_SOURCES,
};

struct sc_option {
Expand Down Expand Up @@ -384,6 +386,16 @@ static const struct sc_option options[] = {
.text = "Use TCP/IP device (if there is exactly one, like adb -e).\n"
"Also see -d (--select-usb).",
},
{
.longopt_id = OPT_CLIENT_AUDIO_SOURCE,
.longopt = "client-audio-source",
.argdesc = "source",
.text = "Inject audio into the device microphone from a device or file.\n"
"The source can be:\n"
" - A device name (e.g., \"Microphone\", \"default\")\n"
" - A file path prefixed with \"file://\" (e.g., \"file:///path/to/audio.mp3\")\n"
"Supported file formats: MP3, OGG, WAV, FLAC, etc.",
},
{
.shortopt = 'f',
.longopt = "fullscreen",
Expand Down Expand Up @@ -488,6 +500,11 @@ static const struct sc_option options[] = {
.longopt = "list-encoders",
.text = "List video and audio encoders available on the device.",
},
{
.longopt_id = OPT_LIST_AUDIO_SOURCES,
.longopt = "list-client-audio-sources",
.text = "List available audio input sources on the client computer.",
},
{
.shortopt = 'm',
.longopt = "max-size",
Expand Down Expand Up @@ -2547,6 +2564,14 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
case OPT_AUDIO_CODEC_OPTIONS:
opts->audio_codec_options = optarg;
break;
case OPT_CLIENT_AUDIO_SOURCE:
#ifdef HAVE_CLIENT_AUDIO
opts->client_audio_source = optarg;
break;
#else
LOGE("Client audio (--client-audio-source) is disabled in this build");
return false;
#endif
case OPT_VIDEO_ENCODER:
opts->video_encoder = optarg;
break;
Expand Down Expand Up @@ -2650,6 +2675,14 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
case OPT_LIST_APPS:
opts->list |= SC_OPTION_LIST_APPS;
break;
case OPT_LIST_AUDIO_SOURCES:
#ifdef HAVE_CLIENT_AUDIO
args->list_audio_sources = true;
break;
#else
LOGE("Client audio (--list-client-audio-sources) is disabled in this build");
return false;
#endif
case OPT_REQUIRE_AUDIO:
opts->require_audio = true;
break;
Expand Down Expand Up @@ -2833,7 +2866,11 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
opts->audio = false;
}

if (!opts->video && !opts->audio && !opts->control && !otg) {
bool has_client_audio = false;
#ifdef HAVE_CLIENT_AUDIO
has_client_audio = opts->client_audio_source != NULL;
#endif
if (!opts->video && !opts->audio && !opts->control && !otg && !has_client_audio) {
LOGE("No video, no audio, no control, no OTG: nothing to do");
return false;
}
Expand Down Expand Up @@ -2947,6 +2984,15 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
}
}

#ifdef HAVE_CLIENT_AUDIO
if (opts->client_audio_source &&
(opts->audio_source == SC_AUDIO_SOURCE_VOICE_CALL ||
opts->audio_source == SC_AUDIO_SOURCE_VOICE_CALL_UPLINK)) {
LOGE("--client-audio-source is incompatible with --audio-source=voice-call and --audio-source=voice-call-uplink");
return false;
}
#endif

if (otg) {
if (!opts->control) {
LOGE("--no-control is not allowed in OTG mode");
Expand Down
1 change: 1 addition & 0 deletions app/src/cli.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ struct scrcpy_cli_args {
struct scrcpy_options opts;
bool help;
bool version;
bool list_audio_sources;
enum sc_pause_on_exit pause_on_exit;
};

Expand Down
Loading