death / dbus

A D-BUS client library for Common Lisp
BSD 2-Clause "Simplified" License
45 stars 29 forks source link

Can't figure out how to make multiple consequtive calls that listen to Request.response signal #31

Open efim opened 3 months ago

efim commented 3 months ago

Hello!

I'm trying to write code that would start screen-sharing through "org.freedesktop.portal.ScreenCast"

as I understood the api - i need to make several calls, first Creating session and getting "session handle" and then configuring session by that handle, and finally Starting session.

Each of these methods are async, their immediate return value is "Request" object path on the bus, which will contain "Response" signal, to which I should subscribe

Reading existing examples I figured out how to register 'signal-handler' on the expected "Request" object path

(load (sb-ext:posix-getenv "ASDF"))
(asdf:load-system 'dbus)

(defpackage #:screencasting (:use #:cl))
(in-package #:screencasting)

;; https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.ScreenCast.html
(defconstant +screen-cast-interface+ "org.freedesktop.portal.ScreenCast")
(defconstant +request-interface+ "org.freedesktop.portal.Request")

(defun send-notification (bus message)
  (dbus:with-introspected-object (notification bus "/org/freedesktop/Notifications" "org.freedesktop.Notifications")
     (notification "org.freedesktop.Notifications" "Notify"
                        "Test" 0 "" "Test" (or message "This is a test; I repeat, this is a test.") '() '() -1)))
(defun call-screencast ()
  (handler-case
        (dbus:with-open-bus (bus (dbus:session-server-addresses))
          (let*
                ((requester-name (cl-ppcre:regex-replace "\\." (dbus:bus-name bus) "_" :start 1))
                 (request-name "yayay")
                 (resp-path (concatenate 'string "/org/freedesktop/portal/desktop/request/"
                                                 requester-name
                                                 "/"
                                                 request-name)))
             (dbus:define-dbus-object request-object
                (:path resp-path))

             (dbus:define-dbus-signal-handler (request-object response) ((id :uint32) (results (:ARRAY (:DICT-ENTRY :STRING :VARIANT)))) 
                (:interface +request-interface+)
                (format t "Got response  ~S with results ~S~%" id results)
                (send-notification bus "yayaya from the first response"))

             (format T "Will try to listen on ~A~%" resp-path)
             (format T "Bus connection name ~A~%" (dbus:bus-name bus))
             (dbus:add-match bus :type :signal
                                        :interface +request-interface+)
             (dbus:with-introspected-object (desktop bus "/org/freedesktop/portal/desktop" "org.freedesktop.portal.Desktop")
                (desktop +screen-cast-interface+ "CreateSession"
                            '(("handle_token" ((:string) "yayay"))
                              ("session_handle_token" ((:string) "hohoyyy")))))
             (dbus:publish-objects bus)))
     (end-of-file ()
      :disconnected-by-bus)))

And I do get the response data in the handler:

CL-USER> (in-package #:screencasting)
#<PACKAGE "SCREENCASTING">
SCREENCASTING> (call-screencast)
Will try to listen on /org/freedesktop/portal/desktop/request/1_105/yayay
Bus connection name :1.105
Got response  0 with results (("session_handle"
                               "/org/freedesktop/portal/desktop/session/1_105/hohoyyy"))
; Evaluation aborted on T

But when i call this function in REPL - the execution continues, i suppose the event-loop runs until I manually I kill it with C-c So how could I make multiple requests that listen on the Request.response signal? It seems that all such Requests should be declared before first invocation of "publish"

I've written code that declares all of the Requests\Response objects at the beginning:

(defun call-with-all-predefined ()
  (handler-case
        (dbus:with-open-bus (bus (dbus:session-server-addresses))
          (let*
                ((requester-name (cl-ppcre:regex-replace "\\." (dbus:bus-name bus) "_" :start 1))
                 (request-create-session-name "createSessionReq")
                 (resp-path (concatenate 'string "/org/freedesktop/portal/desktop/request/"
                                                 requester-name
                                                 "/"
                                                 request-create-session-name))
                 (request-select-sources "selectSourcesReq")
                 (select-sources-resp-path (concatenate 'string "/org/freedesktop/portal/desktop/request/"
                                                                     requester-name
                                                                     "/"
                                                                     request-select-sources))
                 (request-start "startReq")
                 (start-resp-path (concatenate 'string "/org/freedesktop/portal/desktop/request/"
                                                         requester-name
                                                         "/"
                                                         request-start))
                 (session-handle-hardcoded "yayay")
                 (session-handle-path (concatenate 'string "/org/freedesktop/portal/desktop/session/"
                                                              requester-name
                                                              "/"
                                                              session-handle-hardcoded)))
             (dbus:define-dbus-object request-object
                (:path resp-path))

             (dbus:define-dbus-signal-handler (request-object response) ((id :uint32) (results (:ARRAY (:DICT-ENTRY :STRING :VARIANT)))) 
                (:interface +request-interface+)
                (format t "Got response  ~S with results ~S~%" id results)
                (send-notification bus "yayaya from the first response")
                (format t "About sto send SelectSources with path ~S~%" session-handle-path)
                (force-output)
                (dbus:with-introspected-object (desktop bus "/org/freedesktop/portal/desktop" "org.freedesktop.portal.Desktop")
                  (desktop +screen-cast-interface+ "SelectSources"
                              session-handle-path ; hardcoded session-handle
                              `(("handle_token" ((:string) ,request-select-sources)))))
                (format t "Still first callback, after calling SelectSources~%")
                (force-output))

             (dbus:define-dbus-object select-sources-request-obj
                (:path select-sources-resp-path))

             (dbus:define-dbus-signal-handler (select-sources-request-obj response) ((id :uint32) (results (:ARRAY (:DICT-ENTRY :STRING :VARIANT))))
                (:interface +request-interface+)
                (format t ">> Got inside of SelectSources callback ~A ~A~%" id results)
                (dbus:with-introspected-object (desktop bus "/org/freedesktop/portal/desktop" "org.freedesktop.portal.Desktop")
                  (desktop +screen-cast-interface+ "Start"
                              session-handle-path
                              "parent-window"
                            `(("handle_token" ((:string) , request-start)))))
                (format t ">> Still inside SelectSources callback, after calling Start~%")
                (force-output))

             (dbus:define-dbus-object start-request-obj
                (:path start-resp-path))

             (dbus:define-dbus-signal-handler (start-request-obj response) ((id :uint32) (results (:ARRAY (:DICT-ENTRY :STRING :VARIANT))))
                (:interface +request-interface+)
                (format t ">> Got inside of Start callback ~A ~A~%" id results))

             (format T "Will try to listen on ~A~%" resp-path)
             (format T "Bus connection name ~A~%" (dbus:bus-name bus))
             (dbus:add-match bus :type :signal
                                        :interface +request-interface+)
             (dbus:with-introspected-object (desktop bus "/org/freedesktop/portal/desktop" "org.freedesktop.portal.Desktop")
                (desktop +screen-cast-interface+ "CreateSession"
                            `(("handle_token" ((:string) ,request-create-session-name))
                              ("session_handle_token" ((:string) ,session-handle-hardcoded)))))
             (dbus:publish-objects bus)))
     (end-of-file ()
      :disconnected-by-bus)))

and on wayland desktop I can see now output Node through qpwgraph and can open the video through gst-launch-1.0 pipewiresrc path=43 ! videoconvert ! autovideosink

But I can't shake off the feeling that this can't be only way, because if I'll need something like "interactive" control over things - I might now know how many requests I'd need

and maybe it's possible to "do a request" then close the bus connection programmaticaly?