pipewire 1.3.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -9
- package/dist/bindings/context.d.ts +20 -0
- package/dist/bindings/context.d.ts.map +1 -0
- package/dist/bindings/context.js +12 -0
- package/dist/bindings/context.js.map +1 -0
- package/dist/bindings/core.d.ts +34 -0
- package/dist/bindings/core.d.ts.map +1 -0
- package/dist/bindings/core.js +36 -0
- package/dist/bindings/core.js.map +1 -0
- package/dist/bindings/dict.d.ts +3 -0
- package/dist/bindings/dict.d.ts.map +1 -0
- package/dist/bindings/dict.js +11 -0
- package/dist/bindings/dict.js.map +1 -0
- package/dist/bindings/hook.d.ts +3 -0
- package/dist/bindings/hook.d.ts.map +1 -0
- package/dist/bindings/hook.js +14 -0
- package/dist/bindings/hook.js.map +1 -0
- package/dist/bindings/index.d.ts +32 -0
- package/dist/bindings/index.d.ts.map +1 -0
- package/dist/bindings/index.js +16 -0
- package/dist/bindings/index.js.map +1 -0
- package/dist/bindings/list.d.ts +2 -0
- package/dist/bindings/list.d.ts.map +1 -0
- package/dist/bindings/list.js +7 -0
- package/dist/bindings/list.js.map +1 -0
- package/dist/bindings/loop.d.ts +33 -0
- package/dist/bindings/loop.d.ts.map +1 -0
- package/dist/bindings/loop.js +17 -0
- package/dist/bindings/loop.js.map +1 -0
- package/dist/bindings/main-loop.d.ts +47 -0
- package/dist/bindings/main-loop.d.ts.map +1 -0
- package/dist/bindings/main-loop.js +15 -0
- package/dist/bindings/main-loop.js.map +1 -0
- package/dist/bindings/node.d.ts +50 -0
- package/dist/bindings/node.d.ts.map +1 -0
- package/dist/bindings/node.js +81 -0
- package/dist/bindings/node.js.map +1 -0
- package/dist/bindings/param.d.ts +25 -0
- package/dist/bindings/param.d.ts.map +1 -0
- package/dist/bindings/param.js +33 -0
- package/dist/bindings/param.js.map +1 -0
- package/dist/bindings/pipewire.d.ts +19 -0
- package/dist/bindings/pipewire.d.ts.map +1 -0
- package/dist/bindings/pipewire.js +5 -0
- package/dist/bindings/pipewire.js.map +1 -0
- package/dist/bindings/pod.d.ts +2 -0
- package/dist/bindings/pod.d.ts.map +1 -0
- package/dist/bindings/pod.js +6 -0
- package/dist/bindings/pod.js.map +1 -0
- package/dist/bindings/properties.d.ts +2 -0
- package/dist/bindings/properties.d.ts.map +1 -0
- package/dist/bindings/properties.js +3 -0
- package/dist/bindings/properties.js.map +1 -0
- package/dist/bindings/props.d.ts +59 -0
- package/dist/bindings/props.d.ts.map +1 -0
- package/dist/bindings/props.js +59 -0
- package/dist/bindings/props.js.map +1 -0
- package/dist/bindings/proxy.d.ts +11 -0
- package/dist/bindings/proxy.d.ts.map +1 -0
- package/dist/bindings/proxy.js +5 -0
- package/dist/bindings/proxy.js.map +1 -0
- package/dist/bindings/registry.d.ts +20 -0
- package/dist/bindings/registry.d.ts.map +1 -0
- package/dist/bindings/registry.js +19 -0
- package/dist/bindings/registry.js.map +1 -0
- package/dist/bindings/thread-loop.d.ts +65 -0
- package/dist/bindings/thread-loop.d.ts.map +1 -0
- package/dist/bindings/thread-loop.js +18 -0
- package/dist/bindings/thread-loop.js.map +1 -0
- package/dist/index.d.ts +5 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -13
- package/dist/index.js.map +1 -1
- package/dist/loop.d.ts +27 -0
- package/dist/loop.d.ts.map +1 -1
- package/dist/loop.js +4 -0
- package/dist/loop.js.map +1 -1
- package/dist/node.d.ts +53 -39
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js +104 -69
- package/dist/node.js.map +1 -1
- package/dist/object.d.ts +18 -0
- package/dist/object.d.ts.map +1 -0
- package/dist/object.js +22 -0
- package/dist/object.js.map +1 -0
- package/dist/pipewire.d.ts +50 -15
- package/dist/pipewire.d.ts.map +1 -1
- package/dist/pipewire.js +94 -3
- package/dist/pipewire.js.map +1 -1
- package/dist/thread-loop.d.ts +65 -0
- package/dist/thread-loop.d.ts.map +1 -0
- package/dist/thread-loop.js +18 -0
- package/dist/thread-loop.js.map +1 -0
- package/examples/basic.ts +20 -0
- package/examples/{event-registry.ts → event-registry-async.ts} +13 -6
- package/examples/event-registry-sync.ts +60 -0
- package/examples/node-events.ts +34 -0
- package/package.json +1 -1
- package/src/{core.ts → bindings/core.ts} +8 -6
- package/src/bindings/index.ts +16 -0
- package/src/{loop.ts → bindings/loop.ts} +6 -0
- package/src/bindings/node.ts +92 -0
- package/src/bindings/param.ts +33 -0
- package/src/bindings/pipewire.ts +6 -0
- package/src/{registry.ts → bindings/registry.ts} +2 -0
- package/src/bindings/thread-loop.ts +23 -0
- package/src/index.ts +5 -13
- package/src/node.ts +167 -79
- package/src/object.ts +36 -0
- package/src/pipewire.ts +154 -3
- package/src/param.ts +0 -33
- /package/src/{context.ts → bindings/context.ts} +0 -0
- /package/src/{dict.ts → bindings/dict.ts} +0 -0
- /package/src/{hook.ts → bindings/hook.ts} +0 -0
- /package/src/{list.ts → bindings/list.ts} +0 -0
- /package/src/{main-loop.ts → bindings/main-loop.ts} +0 -0
- /package/src/{pod.ts → bindings/pod.ts} +0 -0
- /package/src/{properties.ts → bindings/properties.ts} +0 -0
- /package/src/{props.ts → bindings/props.ts} +0 -0
- /package/src/{proxy.ts → bindings/proxy.ts} +0 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import koffi from "koffi";
|
|
2
|
+
import { bindings as pw } from "../src/index.js";
|
|
3
|
+
|
|
4
|
+
(async () => {
|
|
5
|
+
pw.pipewire.pw_init(0, null);
|
|
6
|
+
|
|
7
|
+
const mainLoop = pw.main_loop.pw_main_loop_new(null);
|
|
8
|
+
const loop = pw.main_loop.pw_main_loop_get_loop(mainLoop);
|
|
9
|
+
const context = pw.context.pw_context_new(loop, null, 0);
|
|
10
|
+
const core = pw.core.pw_context_connect(context, null, 0);
|
|
11
|
+
const registry = pw.core.pw_core_get_registry(core, 3, 0);
|
|
12
|
+
|
|
13
|
+
const registry_event_global = (
|
|
14
|
+
data: unknown,
|
|
15
|
+
id: number,
|
|
16
|
+
permissions: number,
|
|
17
|
+
type: string,
|
|
18
|
+
version: number,
|
|
19
|
+
props: unknown
|
|
20
|
+
) => {
|
|
21
|
+
console.log(`New object: id: ${id} type: ${type} version: ${version}`);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const registry_event_global_remove = (data: unknown, id: number) => {
|
|
25
|
+
console.log(`Removed object: id: ${id}`);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const registry_listener = Buffer.alloc(koffi.sizeof(pw.hook.spa_hook));
|
|
29
|
+
const registry_events = Buffer.alloc(koffi.sizeof(pw.core.pw_registry_events));
|
|
30
|
+
const registry_event_global_register = koffi.register(
|
|
31
|
+
registry_event_global,
|
|
32
|
+
koffi.pointer(pw.core.pw_registry_events_global)
|
|
33
|
+
);
|
|
34
|
+
const registry_event_global_remove_register = koffi.register(
|
|
35
|
+
registry_event_global_remove,
|
|
36
|
+
koffi.pointer(pw.core.pw_registry_events_global_remove)
|
|
37
|
+
);
|
|
38
|
+
koffi.encode(registry_events, pw.core.pw_registry_events, {
|
|
39
|
+
version: 0,
|
|
40
|
+
global: registry_event_global_register,
|
|
41
|
+
global_remove: registry_event_global_remove_register
|
|
42
|
+
});
|
|
43
|
+
pw.registry.pw_registry_add_listener(registry, registry_listener, registry_events, null);
|
|
44
|
+
|
|
45
|
+
console.log("Starting PipeWire main loop...");
|
|
46
|
+
pw.loop.pw_loop_enter(loop);
|
|
47
|
+
const interval = setInterval(() => pw.loop.pw_loop_iterate(loop, 1), 10);
|
|
48
|
+
await new Promise((resolve) => process.on("SIGINT", resolve));
|
|
49
|
+
clearInterval(interval);
|
|
50
|
+
pw.loop.pw_loop_leave(loop);
|
|
51
|
+
|
|
52
|
+
pw.proxy.pw_proxy_destroy(registry);
|
|
53
|
+
koffi.unregister(registry_event_global_register);
|
|
54
|
+
koffi.unregister(registry_event_global_remove_register);
|
|
55
|
+
pw.core.pw_core_disconnect(core);
|
|
56
|
+
pw.context.pw_context_destroy(context);
|
|
57
|
+
pw.main_loop.pw_main_loop_destroy(mainLoop);
|
|
58
|
+
|
|
59
|
+
console.log("PipeWire main loop exited, cleanup done.");
|
|
60
|
+
})();
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Pipewire, PipewireNode } from "../src/index.js";
|
|
2
|
+
|
|
3
|
+
const pipewire = new Pipewire();
|
|
4
|
+
|
|
5
|
+
pipewire.on("objectAdded", (obj) => {
|
|
6
|
+
if (!(obj instanceof PipewireNode)) return;
|
|
7
|
+
console.log(`Node added: id: ${obj.id} name: ${obj.nodeName}`);
|
|
8
|
+
|
|
9
|
+
obj.on("nodeInfo", (info) => {
|
|
10
|
+
console.log(`Node info for id ${obj.id}: ${info.changes.join(", ")}`);
|
|
11
|
+
});
|
|
12
|
+
obj.on("rawNodeParam", () => {
|
|
13
|
+
console.log(`Node param for id ${obj.id}`);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
setImmediate(() => {
|
|
17
|
+
obj.attachListener();
|
|
18
|
+
obj.subscribeParams(Object.values(PipewireNode.spa_param_type).filter((v) => typeof v === "number"));
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
pipewire.on("objectRemoved", (obj) => {
|
|
23
|
+
if (!(obj instanceof PipewireNode)) return;
|
|
24
|
+
console.log(`Node removed: id: ${obj.id} name: ${obj.nodeName}`);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
console.log("Starting PipeWire main loop...");
|
|
28
|
+
pipewire.startLoop();
|
|
29
|
+
|
|
30
|
+
process.on("SIGINT", () => {
|
|
31
|
+
pipewire.stopLoop();
|
|
32
|
+
pipewire.deinit();
|
|
33
|
+
console.log("PipeWire main loop exited, cleanup done.");
|
|
34
|
+
});
|
package/package.json
CHANGED
|
@@ -4,19 +4,21 @@ import { pw_properties } from "./properties.js";
|
|
|
4
4
|
|
|
5
5
|
const pipewire = koffi.load("libpipewire-0.3.so.0");
|
|
6
6
|
|
|
7
|
+
export const PW_VERSION_REGISTRY = 3;
|
|
8
|
+
|
|
7
9
|
export const pw_core = koffi.opaque("pw_core");
|
|
8
10
|
export const pw_registry = koffi.opaque("pw_registry");
|
|
9
11
|
|
|
10
12
|
export const pw_context_connect = pipewire.func("pw_context_connect", koffi.pointer(pw_core), [
|
|
11
|
-
koffi.pointer(pw_context),
|
|
12
|
-
koffi.pointer(pw_properties),
|
|
13
|
-
"size_t"
|
|
13
|
+
koffi.pointer(pw_context), // context
|
|
14
|
+
koffi.pointer(pw_properties), // properties
|
|
15
|
+
"size_t" // user_data_size
|
|
14
16
|
]);
|
|
15
17
|
|
|
16
18
|
export const pw_core_get_registry = pipewire.func("pw_core_get_registry", koffi.pointer(pw_registry), [
|
|
17
|
-
koffi.pointer(pw_core),
|
|
18
|
-
"uint32_t",
|
|
19
|
-
"size_t"
|
|
19
|
+
koffi.pointer(pw_core), // core
|
|
20
|
+
"uint32_t", // version
|
|
21
|
+
"size_t" // user_data_size
|
|
20
22
|
]);
|
|
21
23
|
|
|
22
24
|
export const pw_registry_events_global = koffi.proto("void", [
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as context from "./context.js";
|
|
2
|
+
import * as core from "./core.js";
|
|
3
|
+
import * as dict from "./dict.js";
|
|
4
|
+
import * as hook from "./hook.js";
|
|
5
|
+
import * as loop from "./loop.js";
|
|
6
|
+
import * as main_loop from "./main-loop.js";
|
|
7
|
+
import * as node from "./node.js";
|
|
8
|
+
import * as param from "./param.js";
|
|
9
|
+
import * as pipewire from "./pipewire.js";
|
|
10
|
+
import * as pod from "./pod.js";
|
|
11
|
+
import * as props from "./props.js";
|
|
12
|
+
import * as proxy from "./proxy.js";
|
|
13
|
+
import * as registry from "./registry.js";
|
|
14
|
+
import * as thread_loop from "./thread-loop.js";
|
|
15
|
+
|
|
16
|
+
export default { context, core, dict, hook, loop, main_loop, node, param, pod, props, pipewire, proxy, registry, thread_loop };
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import koffi from "koffi";
|
|
2
2
|
|
|
3
|
+
const pipewire = koffi.load("libpipewire-0.3.so.0");
|
|
4
|
+
|
|
3
5
|
export const spa_system = koffi.opaque("spa_system");
|
|
4
6
|
export const spa_loop = koffi.opaque("spa_loop");
|
|
5
7
|
export const spa_loop_control = koffi.opaque("spa_loop_control");
|
|
@@ -13,3 +15,7 @@ export const pw_loop = koffi.struct("pw_loop", {
|
|
|
13
15
|
utils: koffi.pointer(spa_loop_utils),
|
|
14
16
|
name: "const char*"
|
|
15
17
|
});
|
|
18
|
+
|
|
19
|
+
export const pw_loop_enter = pipewire.func("pw_loop_enter", "void", [koffi.pointer(pw_loop)]);
|
|
20
|
+
export const pw_loop_iterate = pipewire.func("pw_loop_iterate", "int", [koffi.pointer(pw_loop), "int"]);
|
|
21
|
+
export const pw_loop_leave = pipewire.func("pw_loop_leave", "void", [koffi.pointer(pw_loop)]);
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import koffi from "koffi";
|
|
2
|
+
import { spa_hook } from "./hook.js";
|
|
3
|
+
import { spa_pod } from "./pod.js";
|
|
4
|
+
import { spa_dict } from "./dict.js";
|
|
5
|
+
import { spa_param_info } from "./param.js";
|
|
6
|
+
|
|
7
|
+
const pipewire = koffi.load("libpipewire-0.3.so.0");
|
|
8
|
+
|
|
9
|
+
export const PW_VERSION_NODE = 3;
|
|
10
|
+
export const PW_VERSION_NODE_EVENTS = 0;
|
|
11
|
+
|
|
12
|
+
export const PW_NODE_CHANGE_MASK = {
|
|
13
|
+
INPUT_PORTS: 1 << 0,
|
|
14
|
+
OUTPUT_PORTS: 1 << 1,
|
|
15
|
+
STATE: 1 << 2,
|
|
16
|
+
PROPS: 1 << 3,
|
|
17
|
+
PARAMS: 1 << 4
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export enum pw_node_state {
|
|
21
|
+
PW_NODE_STATE_ERROR = -1,
|
|
22
|
+
PW_NODE_STATE_CREATING = 0,
|
|
23
|
+
PW_NODE_STATE_SUSPENDED = 1,
|
|
24
|
+
PW_NODE_STATE_IDLE = 2,
|
|
25
|
+
PW_NODE_STATE_RUNNING = 3
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const pw_node = koffi.opaque("pw_node");
|
|
29
|
+
|
|
30
|
+
export const pw_node_state_enum = koffi.enumeration("pw_node_state", {
|
|
31
|
+
PW_NODE_STATE_ERROR: -1,
|
|
32
|
+
PW_NODE_STATE_CREATING: 0,
|
|
33
|
+
PW_NODE_STATE_SUSPENDED: 1,
|
|
34
|
+
PW_NODE_STATE_IDLE: 2,
|
|
35
|
+
PW_NODE_STATE_RUNNING: 3
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
export const pw_node_info = koffi.struct("pw_node_info", {
|
|
39
|
+
id: "uint32_t",
|
|
40
|
+
max_input_ports: "uint32_t",
|
|
41
|
+
max_output_ports: "uint32_t",
|
|
42
|
+
change_mask: "uint64_t",
|
|
43
|
+
n_input_ports: "uint32_t",
|
|
44
|
+
n_output_ports: "uint32_t",
|
|
45
|
+
state: pw_node_state_enum,
|
|
46
|
+
error: "const char*",
|
|
47
|
+
props: koffi.pointer(spa_dict),
|
|
48
|
+
params: koffi.pointer(spa_param_info),
|
|
49
|
+
n_params: "uint32_t"
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
export const pw_node_events_info = koffi.proto("void", [
|
|
53
|
+
"void*", // data
|
|
54
|
+
koffi.pointer(pw_node_info) // info
|
|
55
|
+
]);
|
|
56
|
+
|
|
57
|
+
export const pw_node_events_param = koffi.proto("void", [
|
|
58
|
+
"void*", // data
|
|
59
|
+
"int", // seq
|
|
60
|
+
"uint32_t", // id
|
|
61
|
+
"uint32_t", // index
|
|
62
|
+
"uint32_t", // next
|
|
63
|
+
koffi.pointer(spa_pod) // param
|
|
64
|
+
]);
|
|
65
|
+
|
|
66
|
+
export const pw_node_events = koffi.struct("pw_node_events", {
|
|
67
|
+
version: "uint32_t",
|
|
68
|
+
info: koffi.pointer(pw_node_events_info),
|
|
69
|
+
param: koffi.pointer(pw_node_events_param)
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
export const pw_node_add_listener = pipewire.func("pw_node_add_listener", "int", [
|
|
73
|
+
koffi.pointer(pw_node), // object
|
|
74
|
+
koffi.pointer(spa_hook), // listener
|
|
75
|
+
koffi.pointer(pw_node_events), // events
|
|
76
|
+
"void*" // data
|
|
77
|
+
]);
|
|
78
|
+
|
|
79
|
+
export const pw_node_enum_params = pipewire.func("pw_node_enum_params", "int", [
|
|
80
|
+
koffi.pointer(pw_node), // object
|
|
81
|
+
"int", // seq
|
|
82
|
+
"uint32_t", // id
|
|
83
|
+
"uint32_t", // start
|
|
84
|
+
"uint32_t", // num
|
|
85
|
+
koffi.pointer(spa_pod) // filter
|
|
86
|
+
]);
|
|
87
|
+
|
|
88
|
+
export const pw_node_subscribe_params = pipewire.func("pw_node_subscribe_params", "int", [
|
|
89
|
+
koffi.pointer(pw_node), // object
|
|
90
|
+
"uint32_t*", // ids
|
|
91
|
+
"uint32_t" // n_ids
|
|
92
|
+
]);
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import koffi from "koffi";
|
|
2
|
+
|
|
3
|
+
export const spa_param_info = koffi.struct("spa_param_info", {
|
|
4
|
+
id: "uint32_t",
|
|
5
|
+
flags: "uint32_t",
|
|
6
|
+
user: "uint32_t",
|
|
7
|
+
seq: "int32_t",
|
|
8
|
+
padding: koffi.array("uint32_t", 4)
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
export enum spa_param_type {
|
|
12
|
+
SPA_PARAM_Invalid,
|
|
13
|
+
SPA_PARAM_PropInfo,
|
|
14
|
+
SPA_PARAM_Props,
|
|
15
|
+
SPA_PARAM_EnumFormat,
|
|
16
|
+
SPA_PARAM_Format,
|
|
17
|
+
SPA_PARAM_Buffers,
|
|
18
|
+
SPA_PARAM_Meta,
|
|
19
|
+
SPA_PARAM_IO,
|
|
20
|
+
SPA_PARAM_EnumProfile,
|
|
21
|
+
SPA_PARAM_Profile,
|
|
22
|
+
SPA_PARAM_EnumPortConfig,
|
|
23
|
+
SPA_PARAM_PortConfig,
|
|
24
|
+
SPA_PARAM_EnumRoute,
|
|
25
|
+
SPA_PARAM_Route,
|
|
26
|
+
SPA_PARAM_Control,
|
|
27
|
+
SPA_PARAM_Latency,
|
|
28
|
+
SPA_PARAM_ProcessLatency,
|
|
29
|
+
SPA_PARAM_Tag,
|
|
30
|
+
SPA_PARAM_PeerEnumFormat,
|
|
31
|
+
SPA_PARAM_Capability,
|
|
32
|
+
SPA_PARAM_PeerCapability
|
|
33
|
+
}
|
|
@@ -4,6 +4,8 @@ import { spa_hook } from "./hook.js";
|
|
|
4
4
|
|
|
5
5
|
const pipewire = koffi.load("libpipewire-0.3.so.0");
|
|
6
6
|
|
|
7
|
+
export const PW_VERSION_REGISTRY_EVENTS = 0;
|
|
8
|
+
|
|
7
9
|
export const pw_registry_add_listener = pipewire.func("pw_registry_add_listener", "int", [
|
|
8
10
|
koffi.pointer(pw_registry), // registry
|
|
9
11
|
koffi.pointer(spa_hook), // listener
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import koffi from "koffi";
|
|
2
|
+
import { spa_dict } from "./dict.js";
|
|
3
|
+
import { pw_loop } from "./loop.js";
|
|
4
|
+
|
|
5
|
+
const pipewire = koffi.load("libpipewire-0.3.so.0");
|
|
6
|
+
|
|
7
|
+
export const pw_thread_loop = koffi.opaque("pw_thread_loop");
|
|
8
|
+
|
|
9
|
+
export const pw_thread_loop_new = pipewire.func("pw_thread_loop_new", koffi.pointer(pw_thread_loop), [
|
|
10
|
+
"const char*", // name
|
|
11
|
+
koffi.pointer(spa_dict) // props
|
|
12
|
+
]);
|
|
13
|
+
export const pw_thread_loop_destroy = pipewire.func("pw_thread_loop_destroy", "void", [koffi.pointer(pw_thread_loop)]);
|
|
14
|
+
|
|
15
|
+
export const pw_thread_loop_get_loop = pipewire.func("pw_thread_loop_get_loop", koffi.pointer(pw_loop), [
|
|
16
|
+
koffi.pointer(pw_thread_loop)
|
|
17
|
+
]);
|
|
18
|
+
|
|
19
|
+
export const pw_thread_loop_lock = pipewire.func("pw_thread_loop_lock", "void", [koffi.pointer(pw_thread_loop)]);
|
|
20
|
+
export const pw_thread_loop_unlock = pipewire.func("pw_thread_loop_unlock", "void", [koffi.pointer(pw_thread_loop)]);
|
|
21
|
+
|
|
22
|
+
export const pw_thread_loop_start = pipewire.func("pw_thread_loop_start", "int", [koffi.pointer(pw_thread_loop)]);
|
|
23
|
+
export const pw_thread_loop_stop = pipewire.func("pw_thread_loop_stop", "void", [koffi.pointer(pw_thread_loop)]);
|
package/src/index.ts
CHANGED
|
@@ -1,14 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import * as main_loop from "./main-loop.js";
|
|
6
|
-
import * as node from "./node.js";
|
|
7
|
-
import * as param from "./param.js";
|
|
8
|
-
import * as pipewire from "./pipewire.js";
|
|
9
|
-
import * as pod from "./pod.js";
|
|
10
|
-
import * as props from "./props.js";
|
|
11
|
-
import * as proxy from "./proxy.js";
|
|
12
|
-
import * as registry from "./registry.js";
|
|
1
|
+
import Pipewire from "./pipewire.js";
|
|
2
|
+
import PipewireObject from "./object.js";
|
|
3
|
+
import PipewireNode from "./node.js";
|
|
4
|
+
import bindings from "./bindings/index.js";
|
|
13
5
|
|
|
14
|
-
export {
|
|
6
|
+
export { Pipewire, PipewireObject, PipewireNode, bindings };
|
package/src/node.ts
CHANGED
|
@@ -1,81 +1,169 @@
|
|
|
1
1
|
import koffi from "koffi";
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
2
|
+
import type Pipewire from "./pipewire.js";
|
|
3
|
+
import type { pw_node_state } from "./bindings/node.js";
|
|
4
|
+
import type { spa_param_type } from "./bindings/param.js";
|
|
5
|
+
import PipewireObject from "./object.js";
|
|
6
|
+
import pw from "./bindings/index.js";
|
|
7
|
+
|
|
8
|
+
export default class PipewireNode extends PipewireObject {
|
|
9
|
+
static readonly pw_node_state = pw.node.pw_node_state_enum;
|
|
10
|
+
static readonly spa_param_type = pw.param.spa_param_type;
|
|
11
|
+
|
|
12
|
+
nodeName: string;
|
|
13
|
+
factoryId: number;
|
|
14
|
+
|
|
15
|
+
nodeProxy: unknown | null = null;
|
|
16
|
+
nodeListener: Buffer | null = null;
|
|
17
|
+
nodeEvents: Buffer | null = null;
|
|
18
|
+
nodeEventInfoRegister: bigint | null = null;
|
|
19
|
+
nodeEventParamRegister: bigint | null = null;
|
|
20
|
+
|
|
21
|
+
constructor(
|
|
22
|
+
pipewire: Pipewire,
|
|
23
|
+
id: number,
|
|
24
|
+
permissions: number,
|
|
25
|
+
type: string,
|
|
26
|
+
version: number,
|
|
27
|
+
props: { [key: string]: string }
|
|
28
|
+
) {
|
|
29
|
+
super(pipewire, id, permissions, type, version, props);
|
|
30
|
+
this.nodeName = props["node.name"]!;
|
|
31
|
+
this.factoryId = Number(props["factory.id"]);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
attachListener(): void {
|
|
35
|
+
if (this.removed) return;
|
|
36
|
+
if (this.nodeProxy) throw new Error(`Listener already attached to node ${this.id}`);
|
|
37
|
+
|
|
38
|
+
this.nodeProxy = pw.registry.pw_registry_bind(
|
|
39
|
+
this.pipewire.registry,
|
|
40
|
+
this.id,
|
|
41
|
+
this.type,
|
|
42
|
+
pw.node.PW_VERSION_NODE,
|
|
43
|
+
0
|
|
44
|
+
);
|
|
45
|
+
this.nodeListener = Buffer.alloc(koffi.sizeof(pw.hook.spa_hook));
|
|
46
|
+
this.nodeEvents = Buffer.alloc(koffi.sizeof(pw.node.pw_node_events));
|
|
47
|
+
this.nodeEventInfoRegister = koffi.register(
|
|
48
|
+
this.nodeEventInfo.bind(this),
|
|
49
|
+
koffi.pointer(pw.node.pw_node_events_info)
|
|
50
|
+
);
|
|
51
|
+
this.nodeEventParamRegister = koffi.register(
|
|
52
|
+
this.nodeEventParam.bind(this),
|
|
53
|
+
koffi.pointer(pw.node.pw_node_events_param)
|
|
54
|
+
);
|
|
55
|
+
koffi.encode(this.nodeEvents, pw.node.pw_node_events, {
|
|
56
|
+
version: pw.node.PW_VERSION_NODE_EVENTS,
|
|
57
|
+
info: this.nodeEventInfoRegister,
|
|
58
|
+
param: this.nodeEventParamRegister
|
|
59
|
+
});
|
|
60
|
+
pw.node.pw_node_add_listener(this.nodeProxy, this.nodeListener, this.nodeEvents, null);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
detachListener(): void {
|
|
64
|
+
if (!this.nodeProxy) throw new Error(`Listener not attached to node ${this.id}`);
|
|
65
|
+
|
|
66
|
+
if (!this.removed) pw.proxy.pw_proxy_destroy(this.nodeProxy);
|
|
67
|
+
koffi.unregister(this.nodeEventParamRegister!);
|
|
68
|
+
koffi.unregister(this.nodeEventInfoRegister!);
|
|
69
|
+
this.nodeEventInfoRegister = null;
|
|
70
|
+
this.nodeEventParamRegister = null;
|
|
71
|
+
this.nodeEvents = null;
|
|
72
|
+
this.nodeListener = null;
|
|
73
|
+
this.nodeProxy = null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
subscribeParams(params: spa_param_type[]) {
|
|
77
|
+
if (this.removed) return;
|
|
78
|
+
if (!this.nodeProxy) throw new Error(`Listener not attached to node ${this.id}`);
|
|
79
|
+
pw.node.pw_node_subscribe_params(this.nodeProxy, params, params.length);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
nodeEventInfo(_data: unknown, info: unknown): void {
|
|
83
|
+
this.emit("rawNodeInfo", info);
|
|
84
|
+
|
|
85
|
+
const nodeInfo = koffi.decode(info, pw.node.pw_node_info);
|
|
26
86
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
"
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
"
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
87
|
+
const changesMasks = Object.keys(pw.node.PW_NODE_CHANGE_MASK) as (keyof typeof pw.node.PW_NODE_CHANGE_MASK)[];
|
|
88
|
+
const changes = changesMasks.filter((key) => nodeInfo.change_mask & pw.node.PW_NODE_CHANGE_MASK[key]);
|
|
89
|
+
|
|
90
|
+
const props = koffi.decode(nodeInfo.props, pw.dict.spa_dict);
|
|
91
|
+
if (changes.includes("PROPS") !== !!props.items) throw new Error(`Node ${this.id} props change mismatch`);
|
|
92
|
+
|
|
93
|
+
const propsObj: { [key: string]: string } | null = changes.includes("PROPS") ? {} : null;
|
|
94
|
+
if (propsObj) {
|
|
95
|
+
const propsArray = koffi.decode(props.items, pw.dict.spa_dict_item, props.n_items);
|
|
96
|
+
for (const item of propsArray) propsObj[item.key] = item.value;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const paramsObj: spa_param_type[] = [];
|
|
100
|
+
if (nodeInfo.params) {
|
|
101
|
+
const params = koffi.decode(nodeInfo.params, pw.param.spa_param_info, nodeInfo.n_params);
|
|
102
|
+
for (const param of params) paramsObj.push(param.id as spa_param_type);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const nodeInfoObj: NodeInfo = {
|
|
106
|
+
id: nodeInfo.id,
|
|
107
|
+
maxInputPorts: nodeInfo.max_input_ports,
|
|
108
|
+
maxOutputPorts: nodeInfo.max_output_ports,
|
|
109
|
+
changes: changes,
|
|
110
|
+
inputPortsCount: nodeInfo.n_input_ports,
|
|
111
|
+
outputPortsCount: nodeInfo.n_output_ports,
|
|
112
|
+
state: nodeInfo.state as pw_node_state,
|
|
113
|
+
error: nodeInfo.error ? koffi.decode(nodeInfo.error, "string") : null,
|
|
114
|
+
props: propsObj,
|
|
115
|
+
params: paramsObj
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
this.emit("nodeInfo", nodeInfoObj);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
nodeEventParam(_data: unknown, info: unknown): void {
|
|
122
|
+
this.emit("rawNodeParam", info);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
on(event: "nodeInfo", listener: (info: NodeInfo) => void): this;
|
|
126
|
+
on(event: "rawNodeInfo", listener: (info: unknown) => void): this;
|
|
127
|
+
on(event: "rawNodeParam", listener: (info: unknown) => void): this;
|
|
128
|
+
on(event: string | symbol, listener: (...args: any[]) => void): this;
|
|
129
|
+
on(event: string | symbol, listener: (...args: any[]) => void): this {
|
|
130
|
+
return super.on(event, listener);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
once(event: "nodeInfo", listener: (info: NodeInfo) => void): this;
|
|
134
|
+
once(event: "rawNodeInfo", listener: (info: unknown) => void): this;
|
|
135
|
+
once(event: "rawNodeParam", listener: (info: unknown) => void): this;
|
|
136
|
+
once(event: string | symbol, listener: (...args: any[]) => void): this;
|
|
137
|
+
once(event: string | symbol, listener: (...args: any[]) => void): this {
|
|
138
|
+
return super.once(event, listener);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
off(event: "nodeInfo", listener: (info: NodeInfo) => void): this;
|
|
142
|
+
off(event: "rawNodeInfo", listener: (info: unknown) => void): this;
|
|
143
|
+
off(event: "rawNodeParam", listener: (info: unknown) => void): this;
|
|
144
|
+
off(event: string | symbol, listener: (...args: any[]) => void): this;
|
|
145
|
+
off(event: string | symbol, listener: (...args: any[]) => void): this {
|
|
146
|
+
return super.off(event, listener);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
emit(event: "nodeInfo", info: NodeInfo): boolean;
|
|
150
|
+
emit(event: "rawNodeInfo", info: unknown): boolean;
|
|
151
|
+
emit(event: "rawNodeParam", info: unknown): boolean;
|
|
152
|
+
emit(event: string | symbol, ...args: any[]): boolean;
|
|
153
|
+
emit(event: string | symbol, ...args: any[]): boolean {
|
|
154
|
+
return super.emit(event, ...args);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export type NodeInfo = {
|
|
159
|
+
id: number;
|
|
160
|
+
maxInputPorts: number;
|
|
161
|
+
maxOutputPorts: number;
|
|
162
|
+
changes: (keyof typeof pw.node.PW_NODE_CHANGE_MASK)[];
|
|
163
|
+
inputPortsCount: number;
|
|
164
|
+
outputPortsCount: number;
|
|
165
|
+
state: pw_node_state;
|
|
166
|
+
error: string | null;
|
|
167
|
+
props: { [key: string]: string } | null;
|
|
168
|
+
params: spa_param_type[];
|
|
169
|
+
};
|
package/src/object.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import EventEmitter from "node:events";
|
|
2
|
+
import type Pipewire from "./pipewire.js";
|
|
3
|
+
|
|
4
|
+
export default class PipewireObject extends EventEmitter {
|
|
5
|
+
pipewire: Pipewire;
|
|
6
|
+
removed: boolean = false;
|
|
7
|
+
|
|
8
|
+
id: number;
|
|
9
|
+
permissions: number;
|
|
10
|
+
type: string;
|
|
11
|
+
version: number;
|
|
12
|
+
props: { [key: string]: string };
|
|
13
|
+
|
|
14
|
+
objectSerial: number;
|
|
15
|
+
|
|
16
|
+
constructor(
|
|
17
|
+
pipewire: Pipewire,
|
|
18
|
+
id: number,
|
|
19
|
+
permissions: number,
|
|
20
|
+
type: string,
|
|
21
|
+
version: number,
|
|
22
|
+
props: { [key: string]: string }
|
|
23
|
+
) {
|
|
24
|
+
super();
|
|
25
|
+
|
|
26
|
+
this.pipewire = pipewire;
|
|
27
|
+
|
|
28
|
+
this.id = id;
|
|
29
|
+
this.permissions = permissions;
|
|
30
|
+
this.type = type;
|
|
31
|
+
this.version = version;
|
|
32
|
+
this.props = props;
|
|
33
|
+
|
|
34
|
+
this.objectSerial = Number(props["object.serial"]);
|
|
35
|
+
}
|
|
36
|
+
}
|