Media (macOS): don't spawn child process

This commit is contained in:
Carter Li
2026-10-10 16:32:09 +08:00
parent 068d86ef13
commit 124f474f81
3 changed files with 51 additions and 101 deletions
+2 -99
View File
@@ -110,106 +110,9 @@ static const char* getMediaByMediaRemote(FFMediaResult* result, bool saveCover)
return error;
}
#if !FF_MODULE_DISABLE_MEDIA
// Called from the Perl helper process through `DynaLoader::dl_install_xsub`. That mechanism installs a
// plain C function as an XSUB, so Perl calls it with the `CV*` in the first parameter slot and no Perl
// argument ever reaches a parameter — a `bool saveCover` parameter read as a pointer and was always
// truthy. The flag has to travel in the environment instead; see `getMediaByAuthorizedProcess`.
[[gnu::visibility("default"), gnu::used]] int ffPrintMediaByMediaRemote(void) {
const char* saveCoverEnv = getenv("FF_MEDIA_REMOTE_SAVE_COVER");
bool saveCover = saveCoverEnv && saveCoverEnv[0] == '1';
FFMediaResult media = {
.status = ffStrbufCreate(),
.song = ffStrbufCreate(),
.artist = ffStrbufCreate(),
.album = ffStrbufCreate(),
.playerId = ffStrbufCreate(),
.player = ffStrbufCreate(),
.cover = ffStrbufCreate(),
};
if (getMediaByMediaRemote(&media, saveCover) != nullptr) {
return 1;
}
ffStrbufAppendC(&media.status, '\n');
ffStrbufAppend(&media.status, &media.song);
ffStrbufAppendC(&media.status, '\n');
ffStrbufAppend(&media.status, &media.artist);
ffStrbufAppendC(&media.status, '\n');
ffStrbufAppend(&media.status, &media.album);
ffStrbufAppendC(&media.status, '\n');
ffStrbufAppend(&media.status, &media.playerId);
ffStrbufAppendC(&media.status, '\n');
ffStrbufAppend(&media.status, &media.player);
ffStrbufAppendC(&media.status, '\n');
if (saveCover) {
ffStrbufAppend(&media.status, &media.cover);
}
ffStrbufAppendC(&media.status, '\n');
ffStrbufAppendUInt(&media.status, media.position);
ffStrbufAppendC(&media.status, '\n');
ffStrbufAppendUInt(&media.status, media.length);
write(STDOUT_FILENO, media.status.chars, media.status.length);
ffStrbufDestroy(&media.status);
ffStrbufDestroy(&media.song);
ffStrbufDestroy(&media.artist);
ffStrbufDestroy(&media.album);
ffStrbufDestroy(&media.playerId);
ffStrbufDestroy(&media.player);
ffStrbufDestroy(&media.cover);
return 0;
}
#endif
static const char* getMediaByAuthorizedProcess(FFMediaResult* result, bool saveCover) {
// #1737
// `DynaLoader::dl_install_xsub` hands the C function the `CV*` as its first parameter, so the flag
// cannot be passed as a Perl argument — `ffPrintMediaByMediaRemote` reads it from the environment,
// which the child process inherits.
FF_STRBUF_AUTO_DESTROY script = ffStrbufCreateF("$ENV{'FF_MEDIA_REMOTE_SAVE_COVER'}='%c';\
require DynaLoader;\
my $so = DynaLoader::dl_load_file('%s', 0);\
my $sym = DynaLoader::dl_find_symbol($so, 'ffPrintMediaByMediaRemote');\
DynaLoader::dl_install_xsub('fn', $sym, __FILE__);\
exit(fn())",
saveCover ? '1' : '0',
instance.state.platform.exePath.chars);
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
const char* error = ffProcessAppendStdOut(
&buffer,
(char* const[]) { "/usr/bin/perl", // Must be signed by Apple. Homebrew version doesn't work
"-e",
script.chars,
nil });
if (error) {
return error;
}
if (buffer.length == 0) {
return "No media found";
}
// status\ntitle\nartist\nalbum\nbundleName\nappName\ncoverPath\nelapsedTimeMS\ndurationMS
FFstrbuf* const strList[] = { &result->status, &result->song, &result->artist, &result->album, &result->playerId, &result->player, &result->cover };
char* line = nullptr;
size_t len = 0;
for (uint32_t i = 0; i < ARRAY_SIZE(strList) && ffStrbufGetline(&line, &len, &buffer); ++i) {
ffStrbufSetS(strList[i], line);
}
uint32_t* const numList[] = { &result->position, &result->length };
for (uint32_t i = 0; i < ARRAY_SIZE(numList) && ffStrbufGetline(&line, &len, &buffer); ++i) {
*numList[i] = (uint32_t) strtoul(line, nullptr, 10);
}
return nullptr;
}
void ffDetectMediaImpl(FFMediaResult* media, bool saveCover) {
const char* error;
if (@available(macOS 15.4, *)) {
error = getMediaByAuthorizedProcess(media, saveCover);
} else {
error = getMediaByMediaRemote(media, saveCover);
}
const char* error = getMediaByMediaRemote(media, saveCover);
if (error) {
ffStrbufAppendS(&media->error, error);
} else {