Compare commits

..

No commits in common. "07e8456ce4d36ab289eb82b8a28c670080d32036" and "562b910aa0957711759ec48acc7cfd53538806de" have entirely different histories.

3 changed files with 99 additions and 108 deletions

View File

@ -1,10 +1,10 @@
;;; pipewire-zero.el --- pipewire-0 package definition -*- lexical-binding: t -*- ;;; pipewire-0-pkg.el --- pipewire-0 package definition -*- lexical-binding: t -*-
;; Copyright (C) 2022 Milan Zamazal <pdm@zamazal.org> ;; Copyright (C) 2022 Milan Zamazal <pdm@zamazal.org>
;; Author: Milan Zamazal <pdm@zamazal.org> ;; Author: Milan Zamazal <pdm@zamazal.org>
;; Version: 1 ;; Version: 1
;; Package-Requires: ((emacs "28.1")) ;; Package-Requires: ((emacs "25.1"))
;; Keywords: multimedia ;; Keywords: multimedia
;; URL: https://git.zamazal.org/pdm/pipewire-0 ;; URL: https://git.zamazal.org/pdm/pipewire-0
@ -23,6 +23,8 @@
;; You should have received a copy of the GNU General Public License ;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <http://www.gnu.org/licenses/>. ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
(require 'pipewire) (define-package "pipewire-zero" "1"
"Interface to PipeWire."
'((emacs "28.1")))
;;; pipewire-zero.el ends here ;;; pipewire-0-pkg.el ends here

View File

@ -57,8 +57,7 @@ PipeWire and VALUE is the corresponding value. VALUE is a number for
object ids, a string otherwise. object ids, a string otherwise.
A special entry with `type' symbol as its name contains the PipeWire A special entry with `type' symbol as its name contains the PipeWire
type of the objects, as a string (e.g. \"Device\", \"Node\", \"Port\", type of the objects, as a string (e.g. \"Device\", \"Node\", \"Port\",
\"Client\", ...). \"Client\", ...).")
CLASS is a PipeWire interface, see symbol `pw-accessor'.")
(cl-defgeneric pw-access-properties (class node-id) (cl-defgeneric pw-access-properties (class node-id)
"Return properties of the given node. "Return properties of the given node.
@ -74,9 +73,7 @@ property. VALUE can be:
avoid confusion with nil representing invalid or unavailable value). avoid confusion with nil representing invalid or unavailable value).
- A number for numeric values (ids, integers, floats). - A number for numeric values (ids, integers, floats).
- A string for string values. - A string for string values.
- A list of elements of any of these types for arrays and structs. - A list of elements of any of these types for arrays and structs.")
CLASS is a PipeWire interface, see symbol `pw-accessor'.")
(cl-defgeneric pw-access-set-properties (class node-id properties) (cl-defgeneric pw-access-set-properties (class node-id properties)
"Set PROPERTIES of the given node. "Set PROPERTIES of the given node.
@ -84,8 +81,7 @@ NODE-ID is a numeric PipeWire Node id (other kinds of PipeWire objects
are not supported in this method). are not supported in this method).
PROPERTIES is an association list in the same format as in PROPERTIES is an association list in the same format as in
`pw-access-properties'. It needn't contain all the properties, just `pw-access-properties'. It needn't contain all the properties, just
the properties to be changed. the properties to be changed.")
CLASS is a PipeWire interface, see symbol `pw-accessor'.")
(cl-defgeneric pw-access-current-profile (class device-id) (cl-defgeneric pw-access-current-profile (class device-id)
"Return current profile of the given device. "Return current profile of the given device.
@ -94,9 +90,7 @@ objects are not supported in this method).
The profile is an association list with elements of the form The profile is an association list with elements of the form
\(PROPERTY . VALUE), in the same format as properties in \(PROPERTY . VALUE), in the same format as properties in
`pw-access-properties'. `pw-access-properties'.")
CLASS is a PipeWire interface, see symbol `pw-accessor'.")
(cl-defgeneric pw-access-profiles (class device-id) (cl-defgeneric pw-access-profiles (class device-id)
"Return available profiles of the given device. "Return available profiles of the given device.
@ -104,32 +98,27 @@ DEVICE-ID is a numeric PipeWire Device id (other kinds of PipeWire
objects are not supported in this method). objects are not supported in this method).
Return a list of profiles, which are in the same format as in Return a list of profiles, which are in the same format as in
`pw-access-current-profile'. `pw-access-current-profile'.")
CLASS is a PipeWire interface, see symbol `pw-accessor'.")
(cl-defgeneric pw-access-set-profile (class device-id profile-index) (cl-defgeneric pw-access-set-profile (class device-id profile-index)
"Set the profile of the given device. "Set the profile of the given device.
DEVICE-ID is a numeric PipeWire Device id (other kinds of PipeWire DEVICE-ID is a numeric PipeWire Device id (other kinds of PipeWire
objects are not supported in this method). objects are not supported in this method).
PROFILE-INDEX is a numeric index of the profile to set, as returned PROFILE-INDEX is a numeric index of the profile to set, as returned
from PipeWire. from PipeWire.")
CLASS is a PipeWire interface, see symbol `pw-accessor'.")
(cl-defgeneric pw-access-defaults (class) (cl-defgeneric pw-access-defaults (class)
"Return default sinks and sources. "Return default sinks and sources.
An association lists is returned. Each list element is of the form An association lists is returned. Each list element is of the form
\(KEY . NAME) where KEY is a string identifying the given kind of \(KEY . NAME) where KEY is a string identifying the given kind of
default sink or source as reported by PipeWire and NAME is a string default sink or source as reported by PipeWire and NAME is a string
name of the node assigned to the default. name of the node assigned to the default.")
CLASS is a PipeWire interface, see symbol `pw-accessor'.")
(cl-defgeneric pw-access-set-default (class key node-name) (cl-defgeneric pw-access-set-default (class key node-name)
"Set default sink or source. "Set default sink or source.
KEY is a string identifying the given kind of default sink or source KEY is a string identifying the given kind of default sink or source
as reported in `pw-access-defaults' and NODE-NAME is a string name of as reported in `pw-access-defaults' and NODE-NAME is a string name of
the node that should be assigned to KEY. the node that should be assigned to KEY.")
CLASS is a PipeWire interface, see symbol `pw-accessor'.")
;; pw-cli interface ;; pw-cli interface

View File

@ -1,4 +1,4 @@
;;; pipewire.el --- PipeWire user interface -*- lexical-binding: t -*- ;;; pw-ui.el --- PipeWire user interface -*- lexical-binding: t -*-
;; Copyright (C) 2022 Milan Zamazal <pdm@zamazal.org> ;; Copyright (C) 2022 Milan Zamazal <pdm@zamazal.org>
@ -100,13 +100,13 @@ The indicator is displayed only on graphical terminals."
(defvar pipewire-buffer "*PipeWire*") (defvar pipewire-buffer "*PipeWire*")
(defvar pipewire-properties-buffer "*PipWire-properties*") (defvar pipewire-properties-buffer "*PipWire-properties*")
(defun pipewire--label (label) (defun pw-ui--label (label)
(propertize (concat label ":") 'face 'pipewire-label)) (propertize (concat label ":") 'face 'pipewire-label))
(defun pipewire--object-volume (object) (defun pw-ui--object-volume (object)
(propertize (pw-lib-volume object) 'face 'pipewire-volume)) (propertize (pw-lib-volume object) 'face 'pipewire-volume))
(defun pipewire--object-name (object) (defun pw-ui--object-name (object)
(let* ((type (pw-lib-object-type object)) (let* ((type (pw-lib-object-type object))
(description-properties (if (equal type "Client") (description-properties (if (equal type "Client")
'("application.name") '("application.name")
@ -118,10 +118,10 @@ The indicator is displayed only on graphical terminals."
description-properties)) description-properties))
""))) "")))
(defun pipewire--object-label (object default-ids) (defun pw-ui--object-label (object default-ids)
(let* ((id (pw-lib-object-id object)) (let* ((id (pw-lib-object-id object))
(type (pw-lib-object-type object)) (type (pw-lib-object-type object))
(text (format "%4s: %s" id (pipewire--object-name object))) (text (format "%4s: %s" id (pw-ui--object-name object)))
(profile (when (equal type "Device") (profile (when (equal type "Device")
(pw-lib-current-profile (pw-lib-object-id object)))) (pw-lib-current-profile (pw-lib-object-id object))))
(face (if (member id default-ids) 'pipewire-default-object 'default)) (face (if (member id default-ids) 'pipewire-default-object 'default))
@ -142,7 +142,7 @@ The indicator is displayed only on graphical terminals."
'face 'pipewire-volume)))))) 'face 'pipewire-volume))))))
label)))) label))))
(defun pipewire--insert-line (line object) (defun pw-ui--insert-line (line object)
(insert (propertize line 'pw-object-id (pw-lib-object-id object)) "\n")) (insert (propertize line 'pw-object-id (pw-lib-object-id object)) "\n"))
(defun pipewire-refresh (&optional _ignore-auto _noconfirm) (defun pipewire-refresh (&optional _ignore-auto _noconfirm)
@ -156,27 +156,27 @@ The indicator is displayed only on graphical terminals."
(default-ids (mapcar #'cdr (pw-lib-default-nodes))) (default-ids (mapcar #'cdr (pw-lib-default-nodes)))
(current-line (count-lines (point-min) (min (1+ (point)) (point-max))))) (current-line (count-lines (point-min) (min (1+ (point)) (point-max)))))
(erase-buffer) (erase-buffer)
(insert (pipewire--label "Devices") "\n") (insert (pw-ui--label "Devices") "\n")
(dolist (device (pw-lib-objects "Device")) (dolist (device (pw-lib-objects "Device"))
(pipewire--insert-line (pipewire--object-label device default-ids) device) (pw-ui--insert-line (pw-ui--object-label device default-ids) device)
(dolist (node (pw-lib-children (pw-lib-object-id device) "Node")) (dolist (node (pw-lib-children (pw-lib-object-id device) "Node"))
(pipewire--insert-line (concat " " (pipewire--object-label node default-ids)) node) (pw-ui--insert-line (concat " " (pw-ui--object-label node default-ids)) node)
(dolist (port (pw-lib-children (pw-lib-object-id node) "Port")) (dolist (port (pw-lib-children (pw-lib-object-id node) "Port"))
(pipewire--insert-line (concat " " (pipewire--object-label port default-ids)) port)))) (pw-ui--insert-line (concat " " (pw-ui--object-label port default-ids)) port))))
(insert (pipewire--label "Clients") "\n") (insert (pw-ui--label "Clients") "\n")
(dolist (client (pw-lib-objects "Client")) (dolist (client (pw-lib-objects "Client"))
(pipewire--insert-line (pipewire--object-label client default-ids) client)) (pw-ui--insert-line (pw-ui--object-label client default-ids) client))
(goto-char (point-min)) (goto-char (point-min))
(forward-line (1- current-line)))) (forward-line (1- current-line))))
(defun pipewire--current-object-id () (defun pw-ui--current-object-id ()
(get-text-property (point) 'pw-object-id)) (get-text-property (point) 'pw-object-id))
(defun pipewire--current-object (&optional use-default-p allowed-types) (defun pw-ui--current-object (&optional use-default-p allowed-types)
(let* ((id (pipewire--current-object-id)) (let* ((id (pw-ui--current-object-id))
(object (when id (pw-lib-get-object id)))) (object (when id (pw-lib-get-object id))))
(when (and object (when (and object
allowed-types (not (null allowed-types))
(not (member (pw-lib-object-type object) allowed-types))) (not (member (pw-lib-object-type object) allowed-types)))
(setq object nil)) (setq object nil))
(when (and use-default-p (not object)) (when (and use-default-p (not object))
@ -184,25 +184,25 @@ The indicator is displayed only on graphical terminals."
(pw-lib-default-audio-sink)))) (pw-lib-default-audio-sink))))
object)) object))
(defvar pipewire--osd-timer nil) (defvar pw-ui--osd-timer nil)
(defvar pipewire--osd-frame nil) (defvar pw-ui--osd-frame nil)
(defvar pipewire--osd-buffer nil) (defvar pw-ui--osd-buffer nil)
(defvar pipewire--osd-buffer-name "*pipewire-osd*") (defvar pw-ui--osd-buffer-name "*pipewire-osd*")
(defun pipewire--osd-display (string) (defun pw-ui--osd-display (string)
(when pipewire--osd-timer (when pw-ui--osd-timer
(cancel-timer pipewire--osd-timer)) (cancel-timer pw-ui--osd-timer))
(let ((frame-width (+ 2 (length string)))) (let ((frame-width (+ 2 (length string))))
(when (and pipewire--osd-frame (when (and pw-ui--osd-frame
(not (= frame-width (frame-width pipewire--osd-frame)))) (not (= frame-width (frame-width pw-ui--osd-frame))))
(delete-frame pipewire--osd-frame) (delete-frame pw-ui--osd-frame)
(setq pipewire--osd-frame nil)) (setq pw-ui--osd-frame nil))
(with-current-buffer (setq pipewire--osd-buffer (get-buffer-create pipewire--osd-buffer-name)) (with-current-buffer (setq pw-ui--osd-buffer (get-buffer-create pw-ui--osd-buffer-name))
(erase-buffer) (erase-buffer)
(insert " " string) (insert " " string)
(setq mode-line-format nil) (setq mode-line-format nil)
(unless pipewire--osd-frame (unless pw-ui--osd-frame
(setq pipewire--osd-frame (make-frame `((unsplittable . t) (setq pw-ui--osd-frame (make-frame `((unsplittable . t)
,@pipewire-osd-frame-parameters ,@pipewire-osd-frame-parameters
(minibuffer . nil) (minibuffer . nil)
(parent-frame . ,(selected-frame)) (parent-frame . ,(selected-frame))
@ -220,27 +220,27 @@ The indicator is displayed only on graphical terminals."
(tool-bar-lines . 0) (tool-bar-lines . 0)
(tab-bar-lines . 0) (tab-bar-lines . 0)
(cursor-type . nil))))))) (cursor-type . nil)))))))
(setq pipewire--osd-timer (setq pw-ui--osd-timer
(run-with-timer (run-with-timer
pipewire-osd-timeout nil pipewire-osd-timeout nil
(lambda () (lambda ()
(when pipewire--osd-frame (when pw-ui--osd-frame
(ignore-errors (delete-frame pipewire--osd-frame))) (ignore-errors (delete-frame pw-ui--osd-frame)))
(when pipewire--osd-buffer (when pw-ui--osd-buffer
(ignore-errors (kill-buffer pipewire--osd-buffer))) (ignore-errors (kill-buffer pw-ui--osd-buffer)))
(setq pipewire--osd-frame nil (setq pw-ui--osd-frame nil
pipewire--osd-timer nil pw-ui--osd-timer nil
pipewire--osd-buffer nil))))) pw-ui--osd-buffer nil)))))
(defmacro pipewire--osd (&rest body) (defmacro pw-ui--osd (&rest body)
(declare (debug (body)) (declare (debug (body))
(indent defun)) (indent defun))
(let (($string (gensym))) (let (($string (gensym)))
`(when (and window-system pipewire-osd-enable) `(when (and window-system pipewire-osd-enable)
(if-let ((,$string (progn ,@body))) (if-let ((,$string (progn ,@body)))
(pipewire--osd-display ,$string))))) (pw-ui--osd-display ,$string)))))
(defun pipewire--update (&optional message) (defun pw-ui--update (&optional message)
(if (get-buffer pipewire-buffer) (if (get-buffer pipewire-buffer)
(with-current-buffer pipewire-buffer (with-current-buffer pipewire-buffer
(pipewire-refresh)) (pipewire-refresh))
@ -248,9 +248,9 @@ The indicator is displayed only on graphical terminals."
(when message (when message
(message message))) (message message)))
(defun pipewire--osd-volume (object) (defun pw-ui--osd-volume (object)
(pipewire--osd (pw-ui--osd
(unless (eq (pipewire--current-object-id) (pw-lib-object-id object)) (unless (eq (pw-ui--current-object-id) (pw-lib-object-id object))
(let* ((object* (pw-lib-get-object (pw-lib-object-id object))) ; refreshed version (let* ((object* (pw-lib-get-object (pw-lib-object-id object))) ; refreshed version
(volume (pw-lib-volume object*)) (volume (pw-lib-volume object*))
(muted-p (pw-lib-muted-p object*)) (muted-p (pw-lib-muted-p object*))
@ -264,13 +264,13 @@ The indicator is displayed only on graphical terminals."
(propertize (make-string n-inactive mark) (propertize (make-string n-inactive mark)
'face `(:background ,pipewire-osd-volume-off-color))))))) 'face `(:background ,pipewire-osd-volume-off-color)))))))
(defun pipewire--update-muted (object muted-p) (defun pw-ui--update-muted (object muted-p)
(let* ((object-name (pipewire--object-name object)) (let* ((object-name (pw-ui--object-name object))
(parent-node (pw-lib-parent-node object)) (parent-node (pw-lib-parent-node object))
(node-info (if parent-node (node-info (if parent-node
(format " in %s" (pipewire--object-name parent-node)) (format " in %s" (pw-ui--object-name parent-node))
""))) "")))
(pipewire--update (format "%s%s %s" object-name node-info (if muted-p "muted" "unmuted"))))) (pw-ui--update (format "%s%s %s" object-name node-info (if muted-p "muted" "unmuted")))))
;;;###autoload ;;;###autoload
(defun pipewire-toggle-muted () (defun pipewire-toggle-muted ()
@ -278,10 +278,10 @@ The indicator is displayed only on graphical terminals."
If on a Node or Port in a PipeWire buffer, apply it on the given If on a Node or Port in a PipeWire buffer, apply it on the given
object. Otherwise apply it on the default audio sink." object. Otherwise apply it on the default audio sink."
(interactive) (interactive)
(let* ((object (pipewire--current-object t '("Node" "Port"))) (let* ((object (pw-ui--current-object t '("Node" "Port")))
(muted-p (pw-lib-toggle-mute object))) (muted-p (pw-lib-toggle-mute object)))
(pipewire--update-muted object muted-p) (pw-ui--update-muted object muted-p)
(pipewire--osd-volume object))) (pw-ui--osd-volume object)))
;;;###autoload ;;;###autoload
(defun pipewire-toggle-microphone () (defun pipewire-toggle-microphone ()
@ -289,7 +289,7 @@ object. Otherwise apply it on the default audio sink."
(interactive) (interactive)
(let* ((object (car (pw-lib-default-capture-ports))) (let* ((object (car (pw-lib-default-capture-ports)))
(muted-p (pw-lib-toggle-mute object))) (muted-p (pw-lib-toggle-mute object)))
(pipewire--update-muted object muted-p))) (pw-ui--update-muted object muted-p)))
;;;###autoload ;;;###autoload
(defun pipewire-set-volume (volume &optional object single-p) (defun pipewire-set-volume (volume &optional object single-p)
@ -303,13 +303,13 @@ corresponding object only."
(interactive "nVolume: ") (interactive "nVolume: ")
(setq volume (max 0 (min 100 volume))) (setq volume (max 0 (min 100 volume)))
(unless object (unless object
(setq object (pipewire--current-object t '("Node" "Port")))) (setq object (pw-ui--current-object t '("Node" "Port"))))
(pw-lib-set-volume volume object single-p) (pw-lib-set-volume volume object single-p)
(pipewire--update (format "Volume %s for %s" volume (pipewire--object-name object))) (pw-ui--update (format "Volume %s for %s" volume (pw-ui--object-name object)))
(pipewire--osd-volume object)) (pw-ui--osd-volume object))
(defun pipewire--change-volume (step &optional single-p) (defun pw-ui--change-volume (step &optional single-p)
(let* ((object (pipewire--current-object t '("Node" "Port"))) (let* ((object (pw-ui--current-object t '("Node" "Port")))
(volume (pw-lib-volume object)) (volume (pw-lib-volume object))
(new-volume (max 0 (min 100 (+ volume step))))) (new-volume (max 0 (min 100 (+ volume step)))))
(pipewire-set-volume new-volume object single-p))) (pipewire-set-volume new-volume object single-p)))
@ -322,7 +322,7 @@ If on a Node or Port in a PipeWire buffer, apply it on all the
channels of the given object, unless SINGLE-P is non-nil. channels of the given object, unless SINGLE-P is non-nil.
Otherwise apply it on the default audio sink." Otherwise apply it on the default audio sink."
(interactive) (interactive)
(pipewire--change-volume pipewire-volume-step single-p)) (pw-ui--change-volume pipewire-volume-step single-p))
;;;###autoload ;;;###autoload
(defun pipewire-increase-volume-single () (defun pipewire-increase-volume-single ()
@ -341,7 +341,7 @@ If on a Node or Port in a PipeWire buffer, apply it on all the
channels of the given object, unless SINGLE-P is non-nil. channels of the given object, unless SINGLE-P is non-nil.
Otherwise apply it on the default audio sink." Otherwise apply it on the default audio sink."
(interactive) (interactive)
(pipewire--change-volume (- pipewire-volume-step) single-p)) (pw-ui--change-volume (- pipewire-volume-step) single-p))
;;;###autoload ;;;###autoload
(defun pipewire-decrease-volume-single () (defun pipewire-decrease-volume-single ()
@ -359,37 +359,37 @@ If on a Node in a PipeWire buffer, apply it on the given object.
If on a Device, apply it on all its nodes. If on a Device, apply it on all its nodes.
Otherwise ask for the Node to set as the default Node." Otherwise ask for the Node to set as the default Node."
(interactive) (interactive)
(let ((object (or (pipewire--current-object nil '("Device" "Node")) (let ((object (or (pw-ui--current-object nil '("Device" "Node"))
(let* ((default-node-ids (mapcar #'cdr (pw-lib-default-nodes))) (let* ((default-node-ids (mapcar #'cdr (pw-lib-default-nodes)))
(nodes (cl-remove-if (nodes (cl-remove-if
(lambda (n) (member (pw-lib-object-id n) default-node-ids)) (lambda (n) (member (pw-lib-object-id n) default-node-ids))
(pw-lib-objects "Node"))) (pw-lib-objects "Node")))
(node-mapping (mapcar (lambda (n) (cons (pipewire--object-name n) (node-mapping (mapcar (lambda (n) (cons (pw-ui--object-name n)
(pw-lib-object-id n))) (pw-lib-object-id n)))
nodes)) nodes))
(node-name (completing-read "Default node: " node-mapping nil t))) (node-name (completing-read "Default node: " node-mapping nil t)))
(pw-lib-get-object (cdr (assoc node-name node-mapping))))))) (pw-lib-get-object (cdr (assoc node-name node-mapping)))))))
(pw-lib-set-default object nil) (pw-lib-set-default object nil)
(pw-lib-set-default object t) (pw-lib-set-default object t)
(pipewire--update))) (pw-ui--update)))
(defun pipewire-set-profile () (defun pipewire-set-profile ()
"Set profile of the device at the current point." "Set profile of the device at the current point."
(interactive) (interactive)
(if-let ((device (pipewire--current-object nil '("Device"))) (if-let ((device (pw-ui--current-object nil '("Device")))
(device-id (pw-lib-object-id device)) (device-id (pw-lib-object-id device))
(profiles (pw-lib-profiles device-id))) (profiles (pw-lib-profiles device-id)))
(progn (progn
(pw-lib-set-profile device-id (completing-read "Select profile: " profiles nil t)) (pw-lib-set-profile device-id (completing-read "Select profile: " profiles nil t))
;; Without this, ports of the device may not be displayed on the update: ;; Without this, ports of the device may not be displayed on the update:
(sit-for 0) (sit-for 0)
(pipewire--update)) (pw-ui--update))
(error "Nothing to set a profile for here"))) (error "Nothing to set a profile for here")))
(defun pipewire-properties () (defun pipewire-properties ()
"Display properties of the object at the current point." "Display properties of the object at the current point."
(interactive) (interactive)
(if-let ((object (pipewire--current-object))) (if-let ((object (pw-ui--current-object)))
(progn (progn
(pop-to-buffer pipewire-properties-buffer) (pop-to-buffer pipewire-properties-buffer)
(let ((inhibit-read-only t)) (let ((inhibit-read-only t))
@ -429,10 +429,10 @@ applied on some of them or the buffer:
(pipewire-refresh) (pipewire-refresh)
(pipewire-mode)) (pipewire-mode))
(provide 'pipewire) (provide 'pw-ui)
;; Local Variables: ;; Local Variables:
;; checkdoc-force-docstrings-flag: nil ;; checkdoc-force-docstrings-flag: nil
;; End: ;; End:
;;; pipewire.el ends here ;;; pw-ui.el ends here