Add support for device profiles
This is especially useful with Bluetooth devices.
This commit is contained in:
parent
1065d9d389
commit
2c421bb990
48
pw-access.el
48
pw-access.el
@ -73,6 +73,30 @@ PROPERTIES is an association list in the same format as in
|
||||
`pw-access-properties'. It needn't contain all the properties, just
|
||||
the properties to be changed.")
|
||||
|
||||
(cl-defgeneric pw-access-current-profile (class device-id)
|
||||
"Return current profile of the given device.
|
||||
DEVICE-ID is a numeric PipeWire Device id (other kinds of PipeWire
|
||||
objects are not supported in this method).
|
||||
|
||||
The profile is an association list with elements of the form
|
||||
(PROPERTY . VALUE), in the same format as properties in
|
||||
`pw-access-properties'.")
|
||||
|
||||
(cl-defgeneric pw-access-profiles (class device-id)
|
||||
"Return available profiles of the given device.
|
||||
DEVICE-ID is a numeric PipeWire Device id (other kinds of PipeWire
|
||||
objects are not supported in this method).
|
||||
|
||||
Return a list of profiles, which are in the same format as in
|
||||
`pw-access-current-profile'.")
|
||||
|
||||
(cl-defgeneric pw-access-set-profile (class device-id profile-index)
|
||||
"Set the profile of the given device.
|
||||
DEVICE-ID is a numeric PipeWire Device id (other kinds of PipeWire
|
||||
objects are not supported in this method).
|
||||
PROFILE-INDEX is a numeric index of the profile to set, as returned
|
||||
from PipeWire.")
|
||||
|
||||
(cl-defgeneric pw-access-defaults (class)
|
||||
"Return default sinks and sources.
|
||||
An association lists is returned. Each list element is of the form
|
||||
@ -183,11 +207,29 @@ Note this interface may not work with all PipeWire versions.")
|
||||
(defun pw-cli--format-property (property)
|
||||
(format "%s: %s" (car property) (pw-cli--format-property-value (cdr property))))
|
||||
|
||||
(let* ((formatted (mapconcat #'pw-cli--format-property properties ", "))
|
||||
(props (concat "{ " formatted " }")))
|
||||
(defun pw-cli--set-parameter (object-id parameter value)
|
||||
(let* ((formatted (mapconcat #'pw-cli--format-property value ", "))
|
||||
(param-value (concat "{ " formatted " }")))
|
||||
(call-process pw-cli-command nil pw-cli-command nil
|
||||
"set-param" (number-to-string node-id) "Props" props)))
|
||||
"set-param" (number-to-string object-id) parameter param-value)))
|
||||
|
||||
(cl-defmethod pw-access-set-properties ((_class pw-cli-accessor) node-id properties)
|
||||
(pw-cli--set-parameter node-id "Props" properties))
|
||||
|
||||
(cl-defmethod pw-access-current-profile ((_class pw-cli-accessor) device-id)
|
||||
(with-temp-buffer
|
||||
(pw-cli--command pw-cli-command `("enum-params" ,(number-to-string device-id) "Profile"))
|
||||
(pw-cli--parse-properties)))
|
||||
|
||||
(cl-defmethod pw-access-profiles ((_class pw-cli-accessor) device-id)
|
||||
(with-temp-buffer
|
||||
(pw-cli--command pw-cli-command `("enum-params" ,(number-to-string device-id) "EnumProfile"))
|
||||
(cl-loop for profile = (pw-cli--parse-properties) then (pw-cli--parse-properties)
|
||||
while profile
|
||||
collect profile)))
|
||||
|
||||
(cl-defmethod pw-access-set-profile ((_class pw-cli-accessor) device-id profile-index)
|
||||
(pw-cli--set-parameter device-id "Profile" `(("index" . ,profile-index) ("save" . "true"))))
|
||||
|
||||
(defun pw-cli--parse-metadata ()
|
||||
(let ((metadata '()))
|
||||
|
30
pw-lib.el
30
pw-lib.el
@ -81,6 +81,36 @@ If the given KEY doesn't exist in OBJECT, return DEFAULT."
|
||||
E.g. \"Device\", \"Node\", \"Port\", \"Client\", ..."
|
||||
(pw-lib-object-value object 'type))
|
||||
|
||||
(defun pw-lib--profile-name (profile)
|
||||
(cdr (or (assoc "description" profile)
|
||||
(assoc "name" profile))))
|
||||
|
||||
(defun pw-lib-current-profile (device-id)
|
||||
"Return the current profile name of the given device.
|
||||
DEVICE-ID is the numeric id of the device.
|
||||
The returned profile name is a string, or nil if it cannot be found."
|
||||
(pw-lib--profile-name (pw-access-current-profile pw-lib--accessor device-id)))
|
||||
|
||||
(defun pw-lib-profiles (device-id)
|
||||
"Return list of available profiles of the given device.
|
||||
DEVICE-ID is the numeric id of the device.
|
||||
A list of strings (possibly empty) is returned."
|
||||
(mapcar #'pw-lib--profile-name (pw-access-profiles pw-lib--accessor device-id)))
|
||||
|
||||
(defun pw-lib-set-profile (device-id profile)
|
||||
"Set the profile of the given device.
|
||||
DEVICE-ID is the numeric id of the device.
|
||||
PROFILE is a string name of the profile, it must be one of the values
|
||||
returned from `pw-lib-profiles'. "
|
||||
(let* ((all-profiles (pw-access-profiles pw-lib--accessor device-id))
|
||||
(properties (cl-find profile all-profiles :key #'pw-lib--profile-name :test #'equal)))
|
||||
(unless properties
|
||||
(error "Profile %s of device %s not found" profile device-id))
|
||||
(let ((index (cdr (assoc "index" properties))))
|
||||
(unless index
|
||||
(error "Index of %s profile of device %s not found" profile device-id))
|
||||
(pw-access-set-profile pw-lib--accessor device-id index))))
|
||||
|
||||
(defun pw-lib--node (object)
|
||||
(if (equal (pw-lib-object-type object) "Node")
|
||||
object
|
||||
|
18
pw-ui.el
18
pw-ui.el
@ -110,10 +110,14 @@ The indicator is displayed only on graphical terminals."
|
||||
(let* ((id (pw-lib-object-id object))
|
||||
(type (pw-lib-object-type object))
|
||||
(text (format "%4s: %s" id (pw-ui--object-name object)))
|
||||
(profile (when (equal type "Device")
|
||||
(pw-lib-current-profile (pw-lib-object-id object))))
|
||||
(face (if (member id default-ids) 'pipewire-default-object-face 'default))
|
||||
(media-class (pw-lib-object-value object "media.class")))
|
||||
(when media-class
|
||||
(setq text (format "%s (%s)" text media-class)))
|
||||
(when profile
|
||||
(setq text (format "%s: %s" text profile)))
|
||||
(let ((volume-p (member type '("Node" "Port"))))
|
||||
(when (and volume-p (pw-lib-muted-p object))
|
||||
(setq face `(:inherit (pipewire-muted-face ,face))))
|
||||
@ -337,10 +341,24 @@ Otherwise ask for the Node to set as the default Node."
|
||||
(pw-lib-set-default object t)
|
||||
(pw-ui--update)))
|
||||
|
||||
(defun pipewire-set-profile ()
|
||||
"Set profile of the device at the current point."
|
||||
(interactive)
|
||||
(if-let ((device (pw-ui--current-object nil '("Device")))
|
||||
(device-id (pw-lib-object-id device))
|
||||
(profiles (pw-lib-profiles device-id)))
|
||||
(progn
|
||||
(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:
|
||||
(sit-for 0)
|
||||
(pw-ui--update))
|
||||
(error "Nothing to set a profile for here")))
|
||||
|
||||
(defvar pipewire-mode-map
|
||||
(let ((map (make-sparse-keymap)))
|
||||
(define-key map "d" 'pipewire-set-default)
|
||||
(define-key map "m" 'pipewire-toggle-muted)
|
||||
(define-key map "p" 'pipewire-set-profile)
|
||||
(define-key map "v" 'pipewire-set-volume)
|
||||
(define-key map "=" 'pipewire-increase-volume)
|
||||
(define-key map "-" 'pipewire-decrease-volume)
|
||||
|
Loading…
Reference in New Issue
Block a user