mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-10 10:06:15 -08:00
fix(embedded-mpv): enable private Snap shared memory
This commit is contained in:
1 parent
cc18cae320
commit
08e92d4f27
5 files changed
+120
-11
No files matched your search
@@ -653,10 +653,20 @@ std::string libmpvClientApiVersion() {
|
||||
std::to_string(version & 0xffff);
|
||||
}
|
||||
|
||||
std::string runtimeProbeShmName() {
|
||||
#if defined(_WIN32)
|
||||
const uint64_t processId = (uint64_t)GetCurrentProcessId();
|
||||
#else
|
||||
const uint64_t processId = (uint64_t)getpid();
|
||||
#endif
|
||||
return "/impv-fc-runtime-probe-" + std::to_string(processId);
|
||||
}
|
||||
|
||||
/*
|
||||
* Bounded startup capability probe: initialize an idle libmpv client and
|
||||
* create the platform GL + mpv OpenGL render contexts. It deliberately does
|
||||
* not create an FBO/shm ring, open media, or enter either command loop.
|
||||
* create the platform GL + mpv OpenGL render contexts, then create, validate,
|
||||
* and destroy a minimal shared-memory ring. It deliberately does not create
|
||||
* an FBO, open media, or enter either command loop.
|
||||
*/
|
||||
int runRuntimeProbe() {
|
||||
mpv_handle* mpv = mpv_create();
|
||||
@@ -711,6 +721,31 @@ int runRuntimeProbe() {
|
||||
return runtimeProbeFailure("mpv-render-context-failed", renderError);
|
||||
}
|
||||
|
||||
frame_helper::ShmRing runtimeProbeRing;
|
||||
const std::string shmName = runtimeProbeShmName();
|
||||
if (!runtimeProbeRing.create(shmName, 16, 16, 1)) {
|
||||
runtimeProbeRing.destroy();
|
||||
mpv_render_context_free(renderContext);
|
||||
gl.destroy();
|
||||
mpv_terminate_destroy(mpv);
|
||||
return runtimeProbeFailure("shared-memory-create-failed");
|
||||
}
|
||||
const bool sharedMemoryInitialized =
|
||||
runtimeProbeRing.base != nullptr &&
|
||||
runtimeProbeRing.header != nullptr &&
|
||||
runtimeProbeRing.header->magic == FRAME_SHM_MAGIC &&
|
||||
runtimeProbeRing.header->version == FRAME_SHM_VERSION &&
|
||||
runtimeProbeRing.header->width == 16 &&
|
||||
runtimeProbeRing.header->height == 16 &&
|
||||
runtimeProbeRing.header->generation == 1;
|
||||
runtimeProbeRing.destroy();
|
||||
if (!sharedMemoryInitialized) {
|
||||
mpv_render_context_free(renderContext);
|
||||
gl.destroy();
|
||||
mpv_terminate_destroy(mpv);
|
||||
return runtimeProbeFailure("shared-memory-initialize-failed");
|
||||
}
|
||||
|
||||
const std::string libmpvVersion = libmpvClientApiVersion();
|
||||
mpv_render_context_free(renderContext);
|
||||
gl.destroy();
|
||||
|
||||
@@ -32,6 +32,16 @@ describe('Embedded MPV native source recording invariants', () => {
|
||||
),
|
||||
'utf8'
|
||||
);
|
||||
const electronBuilderConfig = JSON.parse(
|
||||
readFileSync(
|
||||
path.resolve(__dirname, '../../../../../electron-builder.json'),
|
||||
'utf8'
|
||||
)
|
||||
) as {
|
||||
snap?: {
|
||||
plugs?: unknown;
|
||||
};
|
||||
};
|
||||
const stageRuntimeSource = readFileSync(
|
||||
path.resolve(
|
||||
__dirname,
|
||||
@@ -778,12 +788,29 @@ describe('Embedded MPV native source recording invariants', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('runs the helper runtime probe without shared memory, media, or command loops', () => {
|
||||
it('keeps Electron Builder defaults and requests private Snap shared memory', () => {
|
||||
expect(electronBuilderConfig.snap?.plugs).toEqual([
|
||||
'default',
|
||||
{
|
||||
'shared-memory': {
|
||||
interface: 'shared-memory',
|
||||
private: true,
|
||||
},
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('runs the helper runtime probe through shared memory without media or command loops', () => {
|
||||
const runtimeProbe = sourceFunctionBody(
|
||||
frameHelperSource,
|
||||
'int runRuntimeProbe(',
|
||||
'runRuntimeProbe'
|
||||
);
|
||||
const runtimeProbeShmName = sourceFunctionBody(
|
||||
frameHelperSource,
|
||||
'std::string runtimeProbeShmName(',
|
||||
'runtimeProbeShmName'
|
||||
);
|
||||
const main = sourceFunctionBody(frameHelperSource, 'int main(', 'main');
|
||||
const runtimeProbeFailure = sourceFunctionBody(
|
||||
frameHelperSource,
|
||||
@@ -804,12 +831,30 @@ describe('Embedded MPV native source recording invariants', () => {
|
||||
expect(runtimeProbe).toContain('mpv_render_context_free(');
|
||||
expect(runtimeProbe).toContain('gl.destroy()');
|
||||
expect(runtimeProbe).toContain('mpv_terminate_destroy(mpv)');
|
||||
expect(runtimeProbe).toContain(
|
||||
'frame_helper::ShmRing runtimeProbeRing;'
|
||||
);
|
||||
expect(runtimeProbe).toContain(
|
||||
'const std::string shmName = runtimeProbeShmName();'
|
||||
);
|
||||
expect(runtimeProbe).toContain(
|
||||
'runtimeProbeRing.create(shmName, 16, 16, 1)'
|
||||
);
|
||||
expect(runtimeProbe).toContain(
|
||||
'runtimeProbeRing.header->magic == FRAME_SHM_MAGIC'
|
||||
);
|
||||
expect(runtimeProbe).toContain('runtimeProbeRing.destroy();');
|
||||
expect(runtimeProbe).toContain('"shared-memory-create-failed"');
|
||||
expect(runtimeProbe).toContain('"shared-memory-initialize-failed"');
|
||||
expect(runtimeProbeShmName).toContain('"/impv-fc-runtime-probe-"');
|
||||
expect(runtimeProbeShmName).toContain('getpid()');
|
||||
expect(runtimeProbeShmName).toContain('GetCurrentProcessId()');
|
||||
expect(runtimeProbeShmName).toContain('std::to_string(processId)');
|
||||
expect(runtimeProbe).toContain('.num("protocol", 1)');
|
||||
expect(runtimeProbe).toContain('.boolean("usable", true)');
|
||||
expect(runtimeProbe).toContain('.str("libmpv",');
|
||||
expect(runtimeProbe).toContain('.str("renderApi", gl.renderApiName())');
|
||||
expect(runtimeProbe).not.toContain('pipeline');
|
||||
expect(runtimeProbe).not.toContain('shm');
|
||||
expect(runtimeProbe).not.toContain('runStdinLoop');
|
||||
expect(runtimeProbe).not.toContain('runMpvEventLoop');
|
||||
expect(runtimeProbe).not.toContain('loadfile');
|
||||
|
||||
@@ -241,10 +241,22 @@ has succeeded. On Linux x64 that decision validates the profile manifest,
|
||||
regular-file/access modes, the complete declared bundled closure and hashes,
|
||||
then runs `iptvnator_mpv_helper --runtime-probe` with a three-second timeout.
|
||||
The probe loads dependencies through the normal ELF loader, initializes an
|
||||
idle libmpv client, and creates EGL/OpenGL plus mpv render contexts without
|
||||
opening media or shared memory. It must emit exactly one protocol-v1 JSON line
|
||||
and return zero. Bundled profiles prepend only their packaged `native/lib` to
|
||||
`LD_LIBRARY_PATH`; the system profile never injects a private loader path.
|
||||
idle libmpv client, creates EGL/OpenGL plus mpv render contexts, then
|
||||
creates, maps, validates, and destroys a minimal `16x16` shared-memory ring
|
||||
named `/impv-fc-runtime-probe-<pid>`. It never opens media or enters the media
|
||||
or command loops. Shared-memory creation/mapping and header-initialization
|
||||
failures emit the stable helper reasons `shared-memory-create-failed` and
|
||||
`shared-memory-initialize-failed`. The probe must emit exactly one protocol-v1
|
||||
JSON line and return zero. Bundled profiles prepend only their packaged
|
||||
`native/lib` to `LD_LIBRARY_PATH`; the system profile never injects a private
|
||||
loader path.
|
||||
|
||||
The strict Snap keeps Electron Builder's default plugs and adds an
|
||||
auto-connected private `shared-memory` plug. Private shared memory gives the
|
||||
app a confined, snap-specific POSIX shm namespace rather than global
|
||||
cross-snap access. Consequently the installed-Snap `--runtime-probe` validates
|
||||
the actual confinement and shm lifecycle required by frame-copy, not only the
|
||||
loader and graphics contexts.
|
||||
Packaged discovery is limited to packaged resource locations and never falls
|
||||
through to writable cwd/dist development paths. A disabled base experiment or
|
||||
any failed capability check keeps the renderer sandbox enabled and falls back
|
||||
|
||||
@@ -139,6 +139,15 @@
|
||||
"grade": "stable",
|
||||
"summary": "IPTV application for M3U playlists, Xtream Codes API, and Stalker portals",
|
||||
"executableArgs": ["--ozone-platform=x11"],
|
||||
"plugs": [
|
||||
"default",
|
||||
{
|
||||
"shared-memory": {
|
||||
"interface": "shared-memory",
|
||||
"private": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"environment": {
|
||||
"DISABLE_WAYLAND": "1"
|
||||
}
|
||||
|
||||
@@ -114,6 +114,10 @@ The DEB metadata requires `libmpv2` and is release-tested on Ubuntu 24.04
|
||||
(Noble). Ubuntu 22.04 (Jammy) only provides `libmpv1`; use the x64 AppImage on
|
||||
that distribution rather than relaxing the runtime contract.
|
||||
|
||||
The strict Snap retains Electron Builder's default plugs and adds an
|
||||
auto-connected private `shared-memory` plug. This supplies a snap-specific
|
||||
POSIX shm namespace without granting global cross-snap shared-memory access.
|
||||
|
||||
Profiles cannot share one Electron Builder pass because its targets reuse the
|
||||
same unpacked application directory. A missing or unsupported profile, or a
|
||||
target from another profile, fails packaging.
|
||||
@@ -147,9 +151,13 @@ iptvnator_mpv_helper --runtime-probe
|
||||
```
|
||||
|
||||
The bounded probe initializes idle libmpv plus EGL/OpenGL and mpv render
|
||||
contexts without media or shared memory. A timeout, loader failure, malformed
|
||||
protocol, missing file, hash mismatch, or unusable graphics path returns a
|
||||
stable reason and keeps the BrowserWindow sandbox enabled.
|
||||
contexts, then creates, maps, validates, and destroys a minimal `16x16`
|
||||
shared-memory ring named `/impv-fc-runtime-probe-<pid>`. It does not open media
|
||||
or enter media/command loops. A timeout, loader failure, malformed protocol,
|
||||
missing file, hash mismatch, unusable graphics path, or shm lifecycle failure
|
||||
returns a stable reason and keeps the BrowserWindow sandbox enabled. The
|
||||
installed-Snap probe therefore tests the private shared-memory confinement
|
||||
needed by playback rather than only loader and graphics startup.
|
||||
|
||||
## CI And Source Distribution
|
||||
|
||||
|
||||
Reference in new issue
Block a user