Skip to content

Commit 3acc093

Browse files
committed
checkpoint 4
1 parent efadca6 commit 3acc093

2 files changed

Lines changed: 50 additions & 43 deletions

File tree

src/server/gstreamer/captureProvider.ts

Lines changed: 45 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -97,47 +97,39 @@ export class LinuxWaylandPortalCaptureProvider implements CaptureProvider {
9797
private async waitForPortalResponse(requestPath: string): Promise<any> {
9898
logger.info(`Request path = ${requestPath}`)
9999

100-
const requestObj = await this.dbusConnection.getProxyObject(
101-
"org.freedesktop.portal.Desktop",
102-
requestPath,
103-
)
104-
105-
logger.info(
106-
`Interfaces = ${Object.keys(requestObj.nodes ?? {}).join(", ")}`,
107-
)
108-
109-
logger.info(
110-
JSON.stringify(
111-
requestObj.interfaces.map((i: any) => i.$name),
112-
null,
113-
2,
114-
),
115-
)
116-
117-
const requestIface = requestObj.getInterface(
118-
"org.freedesktop.portal.Request",
119-
)
120100
return Promise.race([
121101
new Promise((resolve, reject) => {
122-
requestIface.on("Response", (responseCode: number, results: any) => {
123-
if (responseCode === 0) {
124-
resolve(results)
125-
} else if (responseCode === 1) {
102+
const handler = (msg: any) => {
103+
if (msg.path !== requestPath) return
104+
if (msg.interface !== "org.freedesktop.portal.Request") return
105+
if (msg.member !== "Response") return
106+
107+
this.dbusConnection.removeListener("message", handler)
108+
109+
const [responseCode, results] = msg.body
110+
if (responseCode === 0) resolve(results)
111+
else if (responseCode === 1)
126112
reject(new Error("User cancelled the Wayland screen cast prompt"))
127-
} else {
113+
else
128114
reject(
129115
new Error(
130116
`Portal request failed with response code: ${responseCode}`,
131117
),
132118
)
133-
}
134-
})
119+
}
120+
this.dbusConnection.on("message", handler)
135121
}),
136122
new Promise((_, reject) =>
137-
setTimeout(() => reject(new Error("Portal request timeout")), 10000),
123+
setTimeout(() => reject(new Error("Portal request timeout")), 30000),
138124
),
139125
])
140126
}
127+
private getDbusId(): string {
128+
// dbus-next exposes the unique name as e.g. ":1.88"
129+
const uniqueName: string = this.dbusConnection.name ?? ""
130+
// ":1.88" -> "1_88"
131+
return uniqueName.replace(":", "").replace(/\./g, "_")
132+
}
141133

142134
private async negotiateScreenCastPortal(): Promise<void> {
143135
const portalDest = "org.freedesktop.portal.Desktop"
@@ -149,6 +141,9 @@ export class LinuxWaylandPortalCaptureProvider implements CaptureProvider {
149141
logger.info("Portal Step 2 - Get ScreenRequest")
150142
// 1. Create Session
151143
const token = generateToken().replaceAll("-", "_")
144+
const sessionResponsePromise = this.waitForPortalResponse(
145+
`/org/freedesktop/portal/desktop/request/${this.getDbusId()}/rein_create_req_${token}`,
146+
)
152147
const sessionRequestPath = await screenCast.CreateSession({
153148
// Use this.dbusModule.Variant instead of this.dbusConnection.Variant
154149
session_handle_token: new this.dbusModule.Variant(
@@ -162,7 +157,7 @@ export class LinuxWaylandPortalCaptureProvider implements CaptureProvider {
162157
})
163158
logger.info("Portal Step 2 - Get ScreenCast Results")
164159
logger.info(`CreateSession returned: ${JSON.stringify(sessionRequestPath)}`)
165-
const sessionResults = await this.waitForPortalResponse(sessionRequestPath)
160+
const sessionResults = await sessionResponsePromise
166161
logger.info(`CreateSession response: ${JSON.stringify(sessionResults)}`)
167162
this.sessionPath = sessionResults["session_handle"].value
168163

@@ -173,18 +168,27 @@ export class LinuxWaylandPortalCaptureProvider implements CaptureProvider {
173168
}
174169

175170
// 2. Select Sources
176-
const selectRequestPath = await screenCast.SelectSources(this.sessionPath, {
171+
const selectToken = "rein_select_req"
172+
const selectResponsePromise = this.waitForPortalResponse(
173+
`/org/freedesktop/portal/desktop/request/${this.getDbusId()}/${selectToken}`,
174+
)
175+
await screenCast.SelectSources(this.sessionPath, {
177176
multiple: new this.dbusModule.Variant("b", false),
178177
types: new this.dbusModule.Variant("u", 1),
179-
handle_token: new this.dbusModule.Variant("s", "rein_select_req"),
178+
handle_token: new this.dbusModule.Variant("s", selectToken),
180179
})
181-
await this.waitForPortalResponse(selectRequestPath)
180+
await selectResponsePromise
182181

183182
// 3. Start Session
184-
const startRequestPath = await screenCast.Start(this.sessionPath, {
185-
handle_token: new this.dbusModule.Variant("s", "rein_start_req"),
183+
const startToken = "rein_start_req"
184+
const startResponsePromise = this.waitForPortalResponse(
185+
`/org/freedesktop/portal/desktop/request/${this.getDbusId()}/${startToken}`,
186+
)
187+
await screenCast.Start(this.sessionPath, "", {
188+
// <-- "" is the parent window handle
189+
handle_token: new this.dbusModule.Variant("s", startToken),
186190
})
187-
const startResults = await this.waitForPortalResponse(startRequestPath)
191+
const startResults = await startResponsePromise
188192

189193
const streamsVariant = startResults["streams"]
190194
if (
@@ -196,21 +200,21 @@ export class LinuxWaylandPortalCaptureProvider implements CaptureProvider {
196200
logger.info(
197201
`Successfully negotiated Wayland Portal. Target PipeWire Node: ${this.pipewireNodeId}`,
198202
)
203+
logger.info(
204+
`Streams payload: ${JSON.stringify(streamsVariant.value, null, 2)}`,
205+
)
206+
//await new Promise(() => {})
199207
} else {
200208
throw new Error("No screen cast streams returned by the Wayland portal.")
201209
}
202210

203211
// 4. OpenPipeWireRemote
204-
await screenCast.OpenPipeWireRemote(this.sessionPath, {})
212+
//await screenCast.OpenPipeWireRemote(this.sessionPath, {})
205213
}
206214

207215
public async getGStreamerSource(): Promise<string[]> {
208216
if (this.pipewireNodeId !== null && this.pipewireNodeId > 0) {
209-
return [
210-
"pipewiresrc",
211-
`target-object=${this.pipewireNodeId}`,
212-
"do-timestamp=true",
213-
]
217+
return ["pipewiresrc", `path=${this.pipewireNodeId}`, "do-timestamp=true"]
214218
}
215219

216220
throw new Error("PipeWire node ID was not successfully extracted.")

src/server/gstreamer/gstManager.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,11 @@ export class GstManager extends EventEmitter {
9393
try {
9494
this.provider = CaptureProviderFactory.create()
9595
await this.provider.initialize()
96-
96+
logger.warn("Exited out")
9797
const sourceBlocks = await this.provider.getGStreamerSource()
9898
const pipelineArgs = this.buildPipelineArgs(sourceBlocks, token, whipPort)
99-
99+
logger.info(`Source blocks: ${JSON.stringify(sourceBlocks)}`)
100+
logger.info(`Pipeline args: ${pipelineArgs.join(" ")}`)
100101
this.executePipeline(pipelineArgs, whipPort, token)
101102
} catch (error) {
102103
logger.error(
@@ -112,6 +113,7 @@ export class GstManager extends EventEmitter {
112113
whipPort: number,
113114
token: string,
114115
): void {
116+
logger.info("Starting Pipeline")
115117
const spawnedEnv = { ...process.env }
116118
if (!spawnedEnv.DISPLAY) spawnedEnv.DISPLAY = ":0"
117119
if (!spawnedEnv.XAUTHORITY) {
@@ -147,6 +149,7 @@ export class GstManager extends EventEmitter {
147149

148150
this.process.stderr?.on("data", (data: Buffer) => {
149151
const logStr = data.toString()
152+
logger.info(`GStreamer raw stderr [${this.sessionId}]: ${logStr.trim()}`)
150153
if (
151154
logStr.includes("ERROR") &&
152155
logStr.includes("pipeline doesn't want to preroll")

0 commit comments

Comments
 (0)