From 964be73fc5524920ffed83a43266d956c40f6c5f Mon Sep 17 00:00:00 2001 From: pablodz Date: Sun, 1 Jan 2023 21:48:34 +0000 Subject: [PATCH] PDOC-Automatic documentation Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- docs/html/pipewire_python.html | 6 +- docs/html/pipewire_python/_utils.html | 20 +- docs/html/pipewire_python/controller.html | 3452 ++++++++++----------- 3 files changed, 1738 insertions(+), 1740 deletions(-) diff --git a/docs/html/pipewire_python.html b/docs/html/pipewire_python.html index a782e91..f8ed22e 100644 --- a/docs/html/pipewire_python.html +++ b/docs/html/pipewire_python.html @@ -86,12 +86,12 @@

  • 🎵 APIs example https://fedoraproject.org/wiki/QA:Testcase_PipeWire_PipeWire_CLI
  • -

    Developed with ❤️ by Pablo Diaz & Anna Absi

    +

    Developed with ❤️ by Pablo Diaz

    Install via

    -
    pip3 install pipewire_python # or pip
    +
    pip3 install pipewire_python # or pip
     
    @@ -158,7 +158,7 @@

    Tutorial

    31- 🎵 Pipewire APIs https://www.linuxfromscratch.org/blfs/view/cvs/multimedia/pipewire.html 32- 🎵 APIs example https://fedoraproject.org/wiki/QA:Testcase_PipeWire_PipeWire_CLI 33 -34Developed with ❤️ by Pablo Diaz & Anna Absi +34Developed with ❤️ by Pablo Diaz 35 36 37## Install via diff --git a/docs/html/pipewire_python/_utils.html b/docs/html/pipewire_python/_utils.html index d028e85..bc184f4 100644 --- a/docs/html/pipewire_python/_utils.html +++ b/docs/html/pipewire_python/_utils.html @@ -74,7 +74,7 @@

    17 # Debug 18 verbose: bool = False, 19): - 20 """ + 20 """ 21 Print terminal output if are different to None and verbose activated 22 """ 23 @@ -89,7 +89,7 @@

    32 # Debug 33 verbose: bool = False, 34): - 35 """ + 35 """ 36 Converts shell output (str) to dictionary looking for 37 "default" and "--" values 38 """ @@ -110,7 +110,7 @@

    53 main_dict: Dict, 54 secondary_dict: Dict, 55): - 56 """ + 56 """ 57 Update values of one dictionary with values of another dictionary 58 based on keys 59 """ @@ -118,7 +118,7 @@

    61 62 63def _drop_keys_with_none_values(main_dict: dict): - 64 """ + 64 """ 65 Drop keys with None values to parse safe dictionary config 66 """ 67 return {k: v for k, v in main_dict.items() if v is not None} @@ -129,7 +129,7 @@

    72 # Debug 73 verbose: bool = False, 74): - 75 """ + 75 """ 76 Generate an array based on dictionary with keys and values 77 """ 78 array_command = [] @@ -148,7 +148,7 @@

    91 # Debug 92 verbose: bool = False, 93): - 94 """ + 94 """ 95 Execute command on terminal via subprocess 96 97 Args: @@ -191,7 +191,7 @@

    134 # Debug 135 verbose: bool = False, 136): -137 """[ASYNC] Function that execute terminal commands in asyncio way +137 """[ASYNC] Function that execute terminal commands in asyncio way 138 139 Args: 140 - command (str): command line to execute. Example: 'ls -l' @@ -223,7 +223,7 @@

    166 # Debug 167 verbose: bool = False, 168): -169 """ +169 """ 170 Function that transform long string of list targets 171 to a `dict` 172 """ @@ -261,7 +261,7 @@

    204 # Debug 205 verbose: bool = False, 206): -207 """ +207 """ 208 Function that transform long string of list interfaces 209 to a `dict` 210 """ @@ -336,7 +336,7 @@

    279 # Debug 280 verbose: bool = False, 281): -282 """ +282 """ 283 Function that filters a `dict` by type of interface 284 """ 285 diff --git a/docs/html/pipewire_python/controller.html b/docs/html/pipewire_python/controller.html index 403cf16..930460e 100644 --- a/docs/html/pipewire_python/controller.html +++ b/docs/html/pipewire_python/controller.html @@ -119,623 +119,621 @@

    16 _generate_dict_interfaces, 17 _generate_dict_list_targets, 18 _get_dict_from_stdout, - 19 _print_std, - 20 _update_dict_by_dict, - 21) - 22 - 23# Loading constants Constants.py - 24from ._constants import MESSAGES_ERROR, RECOMMENDED_FORMATS, RECOMMENDED_RATES - 25 - 26# [DEPRECATED] [FLAKE8] TO_AVOID_F401 PEP8 - 27# [DEPRECATED] https://stackoverflow.com/a/31079085/10491422 - 28# NOW USED IN DOCUMENTATION - 29# __all__ = [ - 30# # Classes and fucntions to doc - 31# 'Controller', - 32# # [DEPRECATED] Unused files pylint - 33# # "_print_std", - 34# # "_get_dict_from_stdout", - 35# # "_update_dict_by_dict", - 36# # "_drop_keys_with_none_values", - 37# # "_generate_command_by_dict", - 38# # "_execute_shell_command", - 39# ] - 40 - 41 - 42class Controller: - 43 """ - 44 Class that controls pipewire command line interface - 45 with shell commands, handling outputs, loading default - 46 configs and more. - 47 """ - 48 - 49 _pipewire_cli = { # Help - 50 "--help": "--help", # -h - 51 "--version": "--version", - 52 "--remote": None, # -r - 53 } - 54 - 55 _pipewire_modes = { # Modes - 56 "--playback": None, # -p - 57 "--record": None, # -r - 58 "--midi": None, # -m - 59 } - 60 - 61 _pipewire_list_targets = { # "--list-targets": None, - 62 "list_playback": None, - 63 "list_record": None, - 64 } - 65 - 66 _pipewire_configs = { # Configs - 67 "--media-type": None, # *default=Audio - 68 "--media-category": None, # *default=Playback - 69 "--media-role": None, # *default=Music - 70 "--target": None, # *default=auto - 71 "--latency": None, # *default=100ms (SOURCE FILE if not specified) - 72 "--rate": None, # *default=48000 - 73 "--channels": None, # [1,2] *default=2 - 74 "--channel-map": None, # ["stereo", "surround-51", "FL,FR"...] *default="FL,FR" - 75 "--format": None, # [u8|s8|s16|s32|f32|f64] *default=s16 - 76 "--volume": None, # [0.0,1.0] *default=1.000 - 77 "--quality": None, # -q # [0,15] *default=4 - 78 "--verbose": None, # -v - 79 } - 80 - 81 _kill_pipewire = { - 82 "all": ["kill", "$(pidof pw-cat)"], - 83 "playback": ["kill", "$(pidof pw-play)"], - 84 "record": ["kill", "$(pidof pw-record)"], - 85 } - 86 - 87 def __init__( - 88 self, - 89 # Debug - 90 verbose: bool = False, - 91 ): - 92 """This constructor load default configs from OS executing - 93 the following pipewire command - 94 - 95 ```bash - 96 #!/bin/bash - 97 # Get defaults from output of: - 98 pw-cat -h - 99 ``` -100 """ -101 # LOAD ALL DEFAULT PARAMETERS + 19) + 20 + 21# Loading constants Constants.py + 22from ._constants import MESSAGES_ERROR, RECOMMENDED_FORMATS, RECOMMENDED_RATES + 23 + 24# [DEPRECATED] [FLAKE8] TO_AVOID_F401 PEP8 + 25# [DEPRECATED] https://stackoverflow.com/a/31079085/10491422 + 26# NOW USED IN DOCUMENTATION + 27# __all__ = [ + 28# # Classes and fucntions to doc + 29# 'Controller', + 30# # [DEPRECATED] Unused files pylint + 31# # "_print_std", + 32# # "_get_dict_from_stdout", + 33# # "_update_dict_by_dict", + 34# # "_drop_keys_with_none_values", + 35# # "_generate_command_by_dict", + 36# # "_execute_shell_command", + 37# ] + 38 + 39 + 40class Controller: + 41 """ + 42 Class that controls pipewire command line interface + 43 with shell commands, handling outputs, loading default + 44 configs and more. + 45 """ + 46 + 47 _pipewire_cli = { # Help + 48 "--help": "--help", # -h + 49 "--version": "--version", + 50 "--remote": None, # -r + 51 } + 52 + 53 _pipewire_modes = { # Modes + 54 "--playback": None, # -p + 55 "--record": None, # -r + 56 "--midi": None, # -m + 57 } + 58 + 59 _pipewire_list_targets = { # "--list-targets": None, + 60 "list_playback": None, + 61 "list_record": None, + 62 } + 63 + 64 _pipewire_configs = { # Configs + 65 "--media-type": None, # *default=Audio + 66 "--media-category": None, # *default=Playback + 67 "--media-role": None, # *default=Music + 68 "--target": None, # *default=auto + 69 "--latency": None, # *default=100ms (SOURCE FILE if not specified) + 70 "--rate": None, # *default=48000 + 71 "--channels": None, # [1,2] *default=2 + 72 "--channel-map": None, # ["stereo", "surround-51", "FL,FR"...] *default="FL,FR" + 73 "--format": None, # [u8|s8|s16|s32|f32|f64] *default=s16 + 74 "--volume": None, # [0.0,1.0] *default=1.000 + 75 "--quality": None, # -q # [0,15] *default=4 + 76 "--verbose": None, # -v + 77 } + 78 + 79 _kill_pipewire = { + 80 "all": ["kill", "$(pidof pw-cat)"], + 81 "playback": ["kill", "$(pidof pw-play)"], + 82 "record": ["kill", "$(pidof pw-record)"], + 83 } + 84 + 85 def __init__( + 86 self, + 87 # Debug + 88 verbose: bool = False, + 89 ): + 90 """This constructor load default configs from OS executing + 91 the following pipewire command + 92 + 93 ```bash + 94 #!/bin/bash + 95 # Get defaults from output of: + 96 pw-cat -h + 97 ``` + 98 """ + 99 # LOAD ALL DEFAULT PARAMETERS +100 +101 mycommand = ["pw-cat", "-h"] 102 -103 mycommand = ["pw-cat", "-h"] -104 -105 # get default parameters with help -106 stdout, _ = _execute_shell_command(command=mycommand, verbose=verbose) # stderr -107 # convert stdout to dictionary -108 dict_default_values = _get_dict_from_stdout(stdout=str(stdout.decode()), verbose=verbose) -109 -110 if verbose: -111 print(self._pipewire_configs) -112 -113 # Save default system configs to our json -114 self._pipewire_configs.update( -115 ([(key, dict_default_values[key]) for key in dict_default_values]) -116 ) -117 -118 if verbose: -119 print(self._pipewire_configs) -120 -121 # Delete keys with None values -122 self._pipewire_configs = _drop_keys_with_none_values(self._pipewire_configs) -123 -124 if verbose: -125 print(self._pipewire_configs) -126 -127 # Load values of list targets -128 self.load_list_targets(mode="playback", verbose=verbose) -129 self.load_list_targets(mode="record", verbose=verbose) -130 -131 def _help_cli( -132 self, -133 # Debug -134 verbose: bool = True, -135 ): -136 """Get pipewire command line help""" +103 # get default parameters with help +104 stdout, _ = _execute_shell_command(command=mycommand, verbose=verbose) # stderr +105 # convert stdout to dictionary +106 dict_default_values = _get_dict_from_stdout(stdout=str(stdout.decode()), verbose=verbose) +107 +108 if verbose: +109 print(self._pipewire_configs) +110 +111 # Save default system configs to our json +112 self._pipewire_configs.update( +113 ([(key, dict_default_values[key]) for key in dict_default_values]) +114 ) +115 +116 if verbose: +117 print(self._pipewire_configs) +118 +119 # Delete keys with None values +120 self._pipewire_configs = _drop_keys_with_none_values(self._pipewire_configs) +121 +122 if verbose: +123 print(self._pipewire_configs) +124 +125 # Load values of list targets +126 self.load_list_targets(mode="playback", verbose=verbose) +127 self.load_list_targets(mode="record", verbose=verbose) +128 +129 def _help_cli( +130 self, +131 # Debug +132 verbose: bool = True, +133 ): +134 """Get pipewire command line help""" +135 +136 mycommand = ["pipewire", self._pipewire_cli["--help"]] 137 -138 mycommand = ["pipewire", self._pipewire_cli["--help"]] +138 stdout, _ = _execute_shell_command(command=mycommand, verbose=verbose) # stderr 139 -140 stdout, _ = _execute_shell_command(command=mycommand, verbose=verbose) # stderr +140 return stdout 141 -142 return stdout -143 -144 def get_version( -145 self, -146 # Debug -147 verbose: bool = False, -148 ): -149 """Get version of pipewire installed on OS by executing the following -150 code: -151 -152 ```bash -153 #!/bin/bash -154 pw-cli --version -155 ``` -156 -157 Args: -158 verbose (bool) : True enable debug logs. *default=False -159 -160 Returns: -161 - versions (list) : Versions of pipewire compiled -162 """ +142 def get_version( +143 self, +144 # Debug +145 verbose: bool = False, +146 ): +147 """Get version of pipewire installed on OS by executing the following +148 code: +149 +150 ```bash +151 #!/bin/bash +152 pw-cli --version +153 ``` +154 +155 Args: +156 verbose (bool) : True enable debug logs. *default=False +157 +158 Returns: +159 - versions (list) : Versions of pipewire compiled +160 """ +161 +162 mycommand = ["pw-cli", "--version"] 163 -164 mycommand = ["pw-cli", "--version"] -165 -166 if verbose: -167 print(f"[mycommand]{mycommand}") -168 -169 stdout, _ = _execute_shell_command(command=mycommand, timeout=-1, verbose=verbose) -170 versions = stdout.decode().split("\n")[1:] +164 if verbose: +165 print(f"[mycommand]{mycommand}") +166 +167 stdout, _ = _execute_shell_command(command=mycommand, timeout=-1, verbose=verbose) +168 versions = stdout.decode().split("\n")[1:] +169 +170 self._pipewire_cli["--version"] = versions 171 -172 self._pipewire_cli["--version"] = versions +172 return versions 173 -174 return versions -175 -176 def verbose( -177 self, -178 status: bool = True, -179 ): -180 """Get full log of pipewire stream status with the command `pw-cat` +174 def verbose( +175 self, +176 status: bool = True, +177 ): +178 """Get full log of pipewire stream status with the command `pw-cat` +179 +180 An example of pw-cli usage is the code below: 181 -182 An example of pw-cli usage is the code below: -183 -184 ```bash -185 #!/bin/bash -186 # For example -187 pw-cat --playback beers.wav --verbose -188 ``` +182 ```bash +183 #!/bin/bash +184 # For example +185 pw-cat --playback beers.wav --verbose +186 ``` +187 +188 that will generate an output like this: 189 -190 that will generate an output like this: -191 -192 ```bash -193 opened file "beers.wav" format 00010002 channels:2 rate:44100 -194 using default channel map: FL,FR -195 rate=44100 channels=2 fmt=s16 samplesize=2 stride=4 latency=4410 (0.100s) -196 connecting playback stream; target_id=4294967295 -197 stream state changed unconnected -> connecting -198 stream param change: id=2 -199 stream properties: -200 media.type = "Audio" -201 ... -202 now=0 rate=0/0 ticks=0 delay=0 queued=0 -203 remote 0 is named "pipewire-0" -204 core done -205 stream state changed connecting -> paused -206 stream param change: id=2 -207 ... -208 stream param change: id=15 -209 stream param change: id=15 -210 now=13465394419270 rate=1/48000 ticks=35840 delay=512 queued=0 -211 now=13466525228363 rate=1/48000 ticks=90112 delay=512 queued=0 -212 ... -213 stream drained -214 stream state changed streaming -> paused +190 ```bash +191 opened file "beers.wav" format 00010002 channels:2 rate:44100 +192 using default channel map: FL,FR +193 rate=44100 channels=2 fmt=s16 samplesize=2 stride=4 latency=4410 (0.100s) +194 connecting playback stream; target_id=4294967295 +195 stream state changed unconnected -> connecting +196 stream param change: id=2 +197 stream properties: +198 media.type = "Audio" +199 ... +200 now=0 rate=0/0 ticks=0 delay=0 queued=0 +201 remote 0 is named "pipewire-0" +202 core done +203 stream state changed connecting -> paused +204 stream param change: id=2 +205 ... +206 stream param change: id=15 +207 stream param change: id=15 +208 now=13465394419270 rate=1/48000 ticks=35840 delay=512 queued=0 +209 now=13466525228363 rate=1/48000 ticks=90112 delay=512 queued=0 +210 ... +211 stream drained +212 stream state changed streaming -> paused +213 stream param change: id=4 +214 stream state changed paused -> unconnected 215 stream param change: id=4 -216 stream state changed paused -> unconnected -217 stream param change: id=4 -218 ``` -219 """ -220 -221 if status: -222 self._pipewire_configs["--verbose"] = " " -223 else: -224 pass -225 -226 def get_config(self): -227 """Return config dictionary with default or setup variables, remember that -228 this object changes only on python-side. Is not updated on real time, -229 For real-time, please create and destroy the class. -230 -231 Args: -232 Nothing -233 -234 Returns: -235 - _pipewire_configs (`dict`) : dictionary with config values +216 ``` +217 """ +218 +219 if status: +220 self._pipewire_configs["--verbose"] = " " +221 else: +222 pass +223 +224 def get_config(self): +225 """Return config dictionary with default or setup variables, remember that +226 this object changes only on python-side. Is not updated on real time, +227 For real-time, please create and destroy the class. +228 +229 Args: +230 Nothing +231 +232 Returns: +233 - _pipewire_configs (`dict`) : dictionary with config values +234 +235 """ 236 -237 """ +237 return self._pipewire_configs 238 -239 return self._pipewire_configs -240 -241 def set_config( -242 self, -243 # configs -244 media_type=None, -245 media_category=None, -246 media_role=None, -247 target=None, -248 latency=None, -249 rate=None, -250 channels=None, -251 channels_map=None, -252 _format=None, -253 volume=None, -254 quality=None, -255 # Debug -256 verbose=False, -257 ): -258 """Method that get args as variables and set them -259 to the `json` parameter of the class `_pipewire_configs`, -260 then you can use in other method, such as `playback(...)` or -261 `record(...)`. This method verifies values to avoid wrong -262 settings. -263 -264 Args: -265 media_type : Set media type -266 media_category : Set media category -267 media_role : Set media role -268 target : Set node target -269 latency : Set node latency *example=100ms -270 rate : Set sample rate [8000,11025,16000,22050,44100,48000,88200,96000,176400,192000,352800,384000] -271 channels : Numbers of channels [1,2] -272 channels_map : ["stereo", "surround-51", "FL,FR", ...] -273 _format : ["u8", "s8", "s16", "s32", "f32", "f64"] -274 volume : Stream volume [0.000, 1.000] -275 quality : Resampler quality [0, 15] -276 verbose (`bool`): True enable debug logs. *default=False -277 -278 Returns: -279 - Nothing -280 -281 More: -282 Check all links listed at the beginning of this page -283 """ # 1 - media_type -284 if media_type: -285 self._pipewire_configs["--media-type"] = str(media_type) -286 elif media_type is None: -287 pass -288 else: -289 raise ValueError( -290 f"{MESSAGES_ERROR['ValueError']}[media_type='{media_type}'] EMPTY VALUE" -291 ) -292 # 2 - media_category -293 if media_category: -294 self._pipewire_configs["--media-category"] = str(media_category) -295 elif media_category is None: -296 pass -297 else: -298 raise ValueError( -299 f"{MESSAGES_ERROR['ValueError']}[media_category='{media_category}'] EMPTY VALUE" -300 ) -301 # 3 - media_role -302 if media_role: -303 self._pipewire_configs["--media-role"] = str(media_role) -304 elif media_role is None: -305 pass -306 else: -307 raise ValueError( -308 f"{MESSAGES_ERROR['ValueError']}[media_role='{media_role}'] EMPTY VALUE" -309 ) -310 # 4 - target -311 if target: -312 self._pipewire_configs["--target"] = str(target) -313 elif target is None: -314 pass -315 else: -316 raise ValueError(f"{MESSAGES_ERROR['ValueError']}[target='{target}'] EMPTY VALUE") -317 # 5 - latency -318 if latency: -319 if any(chr.isdigit() for chr in latency): # Contain numbers -320 self._pipewire_configs["--latency"] = str(latency) -321 else: -322 raise ValueError( -323 f"{MESSAGES_ERROR['ValueError']}[latency='{latency}'] NO NUMBER IN VARIABLE" -324 ) -325 elif latency is None: -326 pass -327 else: -328 raise ValueError(f"{MESSAGES_ERROR['ValueError']}[latency='{latency}'] EMPTY VALUE") -329 # 6 - rate -330 if rate: -331 if rate in RECOMMENDED_RATES: -332 self._pipewire_configs["--rate"] = str(rate) -333 else: -334 raise ValueError( -335 f"{MESSAGES_ERROR['ValueError']}[rate='{rate}']\ -336 VALUE NOT IN RECOMMENDED LIST \n{RECOMMENDED_RATES}" -337 ) -338 elif rate is None: -339 pass -340 else: -341 raise ValueError(f"{MESSAGES_ERROR['ValueError']}[rate='{rate}'] EMPTY VALUE") -342 # 7 - channels -343 if channels: -344 if channels in [1, 2]: # values -345 self._pipewire_configs["--channels"] = str(channels) -346 else: -347 raise ValueError( -348 f"{MESSAGES_ERROR['ValueError']}[channels='{channels}']\ -349 WRONG VALUE\n ONLY 1 or 2." -350 ) -351 elif channels is None: -352 pass -353 else: -354 raise ValueError(f"{MESSAGES_ERROR['ValueError']}[channels='{channels}'] EMPTY VALUE") -355 # 8 - channels-map -356 if channels_map: -357 self._pipewire_configs["--channels-map"] = str(channels_map) -358 elif channels_map is None: -359 pass -360 else: -361 raise ValueError( -362 f"{MESSAGES_ERROR['ValueError']}[channels_map='{channels_map}'] EMPTY VALUE" -363 ) -364 # 9 - format -365 if _format: -366 if _format in RECOMMENDED_FORMATS: -367 self._pipewire_configs["--format"] = str(_format) -368 else: -369 raise ValueError( -370 f"{MESSAGES_ERROR['ValueError']}[_format='{_format}']\ -371 VALUE NOT IN RECOMMENDED LIST \n{RECOMMENDED_FORMATS}" -372 ) -373 elif _format is None: -374 pass -375 else: -376 raise ValueError(f"{MESSAGES_ERROR['ValueError']}[_format='{_format}'] EMPTY VALUE") -377 # 10 - volume -378 if volume: -379 if 0.0 <= volume <= 1.0: -380 self._pipewire_configs["--volume"] = str(volume) -381 else: -382 raise ValueError( -383 f"{MESSAGES_ERROR['ValueError']}[volume='{volume}']\ -384 OUT OF RANGE \n [0.000, 1.000]" -385 ) -386 elif volume is None: -387 pass -388 else: -389 raise ValueError(f"{MESSAGES_ERROR['ValueError']}[volume='{volume}'] EMPTY VALUE") -390 # 11 - quality -391 if quality: -392 if 0 <= quality <= 15: -393 self._pipewire_configs["--quality"] = str(quality) -394 else: -395 raise ValueError( -396 f"{MESSAGES_ERROR['ValueError']}[quality='{quality}'] OUT OF RANGE \n [0, 15]" -397 ) -398 elif quality is None: -399 pass -400 else: -401 raise ValueError(f"{MESSAGES_ERROR['ValueError']}[volume='{volume}'] EMPTY VALUE") -402 -403 # 12 - verbose cli -404 if verbose: # True -405 self._pipewire_configs["--verbose"] = " " -406 else: -407 pass -408 -409 if verbose: -410 print(self._pipewire_configs) -411 -412 def load_list_targets( -413 self, -414 mode, # playback or record -415 # Debug, -416 verbose: bool = False, -417 ): -418 """Returns a list of targets to playback or record. Then you can use -419 the output to select a device to playback or record. -420 """ -421 -422 if mode == "playback": -423 mycommand = ["pw-cat", "--playback", "--list-targets"] -424 stdout, _ = _execute_shell_command(command=mycommand, timeout=-1, verbose=verbose) -425 self._pipewire_list_targets["list_playback"] = _generate_dict_list_targets( -426 longstring=stdout.decode(), verbose=verbose -427 ) -428 elif mode == "record": -429 mycommand = ["pw-cat", "--record", "--list-targets"] -430 stdout, _ = _execute_shell_command(command=mycommand, timeout=-1, verbose=verbose) -431 self._pipewire_list_targets["list_record"] = _generate_dict_list_targets( -432 longstring=stdout.decode(), verbose=verbose -433 ) -434 else: -435 raise AttributeError(MESSAGES_ERROR["ValueError"]) -436 -437 if verbose: -438 print(f"[mycommand]{mycommand}") -439 -440 def get_list_targets( -441 self, -442 # Debug, -443 verbose: bool = False, -444 ): -445 """Returns a list of targets to playback or record. Then you can use -446 the output to select a device to playback or record. -447 -448 Returns: -449 - `_pipewire_list_targets` -450 -451 Examples: -452 ```python -453 >>> Controller().get_list_targets() -454 { -455 "list_playback": { -456 "86": { -457 "description": "Starship/Matisse HD Audio Controller Pro", -458 "prior": "936" -459 }, -460 "_list_nodes": [ -461 "86" -462 ], -463 "_node_default": [ -464 "86" -465 ], -466 "_alsa_node": [ -467 "alsa_output.pci-0000_0a_00.4.pro-output-0" -468 ] -469 }, -470 "list_record": { -471 "86": { -472 "description": "Starship/Matisse HD Audio Controller Pro", -473 "prior": "936" -474 }, -475 "_list_nodes": [ -476 "86" -477 ], -478 "_node_default": [ -479 "86" -480 ], -481 "_alsa_node": [ -482 "alsa_output.pci-0000_0a_00.4.pro-output-0" -483 ] -484 } -485 } -486 ``` -487 """ -488 if verbose: -489 print(self._pipewire_list_targets) -490 return self._pipewire_list_targets -491 -492 def get_list_interfaces( -493 self, -494 filtered_by_type: str = True, -495 type_interfaces: str = "Client", -496 # Debug -497 verbose: bool = False, -498 ): -499 """Returns a list of applications currently using pipewire on Client. -500 An example of pw-cli usage is the code below: -501 -502 ```bash -503 #!/bin/bash -504 pw-cli ls Client -505 ``` -506 Args: -507 filtered_by_type : If False, returns all. If not, returns a fitered dict -508 type_interfaces : Set type of Interface ["Client","Link","Node","Factory","Module","Metadata","Endpoint","Session","Endpoint Stream","EndpointLink","Port"] -509 -510 Returns: -511 - dict_interfaces_filtered: dictionary with list of interfaces matching conditions -512 -513 Examples: -514 ```python -515 >>> Controller().get_list_interfaces() -516 -517 ``` -518 """ -519 mycommand = ["pw-cli", "info", "all"] -520 -521 # if verbose: -522 # print(f"[mycommand]{mycommand}") -523 -524 stdout, _ = _execute_shell_command(command=mycommand, timeout=-1, verbose=verbose) -525 dict_interfaces = _generate_dict_interfaces(longstring=stdout.decode(), verbose=verbose) -526 -527 if filtered_by_type: -528 dict_interfaces_filtered = _filter_by_type( -529 dict_interfaces=dict_interfaces, type_interfaces=type_interfaces -530 ) -531 else: -532 dict_interfaces_filtered = dict_interfaces +239 def set_config( +240 self, +241 # configs +242 media_type=None, +243 media_category=None, +244 media_role=None, +245 target=None, +246 latency=None, +247 rate=None, +248 channels=None, +249 channels_map=None, +250 _format=None, +251 volume=None, +252 quality=None, +253 # Debug +254 verbose=False, +255 ): +256 """Method that get args as variables and set them +257 to the `json` parameter of the class `_pipewire_configs`, +258 then you can use in other method, such as `playback(...)` or +259 `record(...)`. This method verifies values to avoid wrong +260 settings. +261 +262 Args: +263 media_type : Set media type +264 media_category : Set media category +265 media_role : Set media role +266 target : Set node target +267 latency : Set node latency *example=100ms +268 rate : Set sample rate [8000,11025,16000,22050,44100,48000,88200,96000,176400,192000,352800,384000] +269 channels : Numbers of channels [1,2] +270 channels_map : ["stereo", "surround-51", "FL,FR", ...] +271 _format : ["u8", "s8", "s16", "s32", "f32", "f64"] +272 volume : Stream volume [0.000, 1.000] +273 quality : Resampler quality [0, 15] +274 verbose (`bool`): True enable debug logs. *default=False +275 +276 Returns: +277 - Nothing +278 +279 More: +280 Check all links listed at the beginning of this page +281 """ # 1 - media_type +282 if media_type: +283 self._pipewire_configs["--media-type"] = str(media_type) +284 elif media_type is None: +285 pass +286 else: +287 raise ValueError( +288 f"{MESSAGES_ERROR['ValueError']}[media_type='{media_type}'] EMPTY VALUE" +289 ) +290 # 2 - media_category +291 if media_category: +292 self._pipewire_configs["--media-category"] = str(media_category) +293 elif media_category is None: +294 pass +295 else: +296 raise ValueError( +297 f"{MESSAGES_ERROR['ValueError']}[media_category='{media_category}'] EMPTY VALUE" +298 ) +299 # 3 - media_role +300 if media_role: +301 self._pipewire_configs["--media-role"] = str(media_role) +302 elif media_role is None: +303 pass +304 else: +305 raise ValueError( +306 f"{MESSAGES_ERROR['ValueError']}[media_role='{media_role}'] EMPTY VALUE" +307 ) +308 # 4 - target +309 if target: +310 self._pipewire_configs["--target"] = str(target) +311 elif target is None: +312 pass +313 else: +314 raise ValueError(f"{MESSAGES_ERROR['ValueError']}[target='{target}'] EMPTY VALUE") +315 # 5 - latency +316 if latency: +317 if any(chr.isdigit() for chr in latency): # Contain numbers +318 self._pipewire_configs["--latency"] = str(latency) +319 else: +320 raise ValueError( +321 f"{MESSAGES_ERROR['ValueError']}[latency='{latency}'] NO NUMBER IN VARIABLE" +322 ) +323 elif latency is None: +324 pass +325 else: +326 raise ValueError(f"{MESSAGES_ERROR['ValueError']}[latency='{latency}'] EMPTY VALUE") +327 # 6 - rate +328 if rate: +329 if rate in RECOMMENDED_RATES: +330 self._pipewire_configs["--rate"] = str(rate) +331 else: +332 raise ValueError( +333 f"{MESSAGES_ERROR['ValueError']}[rate='{rate}']\ +334 VALUE NOT IN RECOMMENDED LIST \n{RECOMMENDED_RATES}" +335 ) +336 elif rate is None: +337 pass +338 else: +339 raise ValueError(f"{MESSAGES_ERROR['ValueError']}[rate='{rate}'] EMPTY VALUE") +340 # 7 - channels +341 if channels: +342 if channels in [1, 2]: # values +343 self._pipewire_configs["--channels"] = str(channels) +344 else: +345 raise ValueError( +346 f"{MESSAGES_ERROR['ValueError']}[channels='{channels}']\ +347 WRONG VALUE\n ONLY 1 or 2." +348 ) +349 elif channels is None: +350 pass +351 else: +352 raise ValueError(f"{MESSAGES_ERROR['ValueError']}[channels='{channels}'] EMPTY VALUE") +353 # 8 - channels-map +354 if channels_map: +355 self._pipewire_configs["--channels-map"] = str(channels_map) +356 elif channels_map is None: +357 pass +358 else: +359 raise ValueError( +360 f"{MESSAGES_ERROR['ValueError']}[channels_map='{channels_map}'] EMPTY VALUE" +361 ) +362 # 9 - format +363 if _format: +364 if _format in RECOMMENDED_FORMATS: +365 self._pipewire_configs["--format"] = str(_format) +366 else: +367 raise ValueError( +368 f"{MESSAGES_ERROR['ValueError']}[_format='{_format}']\ +369 VALUE NOT IN RECOMMENDED LIST \n{RECOMMENDED_FORMATS}" +370 ) +371 elif _format is None: +372 pass +373 else: +374 raise ValueError(f"{MESSAGES_ERROR['ValueError']}[_format='{_format}'] EMPTY VALUE") +375 # 10 - volume +376 if volume: +377 if 0.0 <= volume <= 1.0: +378 self._pipewire_configs["--volume"] = str(volume) +379 else: +380 raise ValueError( +381 f"{MESSAGES_ERROR['ValueError']}[volume='{volume}']\ +382 OUT OF RANGE \n [0.000, 1.000]" +383 ) +384 elif volume is None: +385 pass +386 else: +387 raise ValueError(f"{MESSAGES_ERROR['ValueError']}[volume='{volume}'] EMPTY VALUE") +388 # 11 - quality +389 if quality: +390 if 0 <= quality <= 15: +391 self._pipewire_configs["--quality"] = str(quality) +392 else: +393 raise ValueError( +394 f"{MESSAGES_ERROR['ValueError']}[quality='{quality}'] OUT OF RANGE \n [0, 15]" +395 ) +396 elif quality is None: +397 pass +398 else: +399 raise ValueError(f"{MESSAGES_ERROR['ValueError']}[volume='{volume}'] EMPTY VALUE") +400 +401 # 12 - verbose cli +402 if verbose: # True +403 self._pipewire_configs["--verbose"] = " " +404 else: +405 pass +406 +407 if verbose: +408 print(self._pipewire_configs) +409 +410 def load_list_targets( +411 self, +412 mode, # playback or record +413 # Debug, +414 verbose: bool = False, +415 ): +416 """Returns a list of targets to playback or record. Then you can use +417 the output to select a device to playback or record. +418 """ +419 +420 if mode == "playback": +421 mycommand = ["pw-cat", "--playback", "--list-targets"] +422 stdout, _ = _execute_shell_command(command=mycommand, timeout=-1, verbose=verbose) +423 self._pipewire_list_targets["list_playback"] = _generate_dict_list_targets( +424 longstring=stdout.decode(), verbose=verbose +425 ) +426 elif mode == "record": +427 mycommand = ["pw-cat", "--record", "--list-targets"] +428 stdout, _ = _execute_shell_command(command=mycommand, timeout=-1, verbose=verbose) +429 self._pipewire_list_targets["list_record"] = _generate_dict_list_targets( +430 longstring=stdout.decode(), verbose=verbose +431 ) +432 else: +433 raise AttributeError(MESSAGES_ERROR["ValueError"]) +434 +435 if verbose: +436 print(f"[mycommand]{mycommand}") +437 +438 def get_list_targets( +439 self, +440 # Debug, +441 verbose: bool = False, +442 ): +443 """Returns a list of targets to playback or record. Then you can use +444 the output to select a device to playback or record. +445 +446 Returns: +447 - `_pipewire_list_targets` +448 +449 Examples: +450 ```python +451 >>> Controller().get_list_targets() +452 { +453 "list_playback": { +454 "86": { +455 "description": "Starship/Matisse HD Audio Controller Pro", +456 "prior": "936" +457 }, +458 "_list_nodes": [ +459 "86" +460 ], +461 "_node_default": [ +462 "86" +463 ], +464 "_alsa_node": [ +465 "alsa_output.pci-0000_0a_00.4.pro-output-0" +466 ] +467 }, +468 "list_record": { +469 "86": { +470 "description": "Starship/Matisse HD Audio Controller Pro", +471 "prior": "936" +472 }, +473 "_list_nodes": [ +474 "86" +475 ], +476 "_node_default": [ +477 "86" +478 ], +479 "_alsa_node": [ +480 "alsa_output.pci-0000_0a_00.4.pro-output-0" +481 ] +482 } +483 } +484 ``` +485 """ +486 if verbose: +487 print(self._pipewire_list_targets) +488 return self._pipewire_list_targets +489 +490 def get_list_interfaces( +491 self, +492 filtered_by_type: str = True, +493 type_interfaces: str = "Client", +494 # Debug +495 verbose: bool = False, +496 ): +497 """Returns a list of applications currently using pipewire on Client. +498 An example of pw-cli usage is the code below: +499 +500 ```bash +501 #!/bin/bash +502 pw-cli ls Client +503 ``` +504 Args: +505 filtered_by_type : If False, returns all. If not, returns a fitered dict +506 type_interfaces : Set type of Interface ["Client","Link","Node","Factory","Module","Metadata","Endpoint","Session","Endpoint Stream","EndpointLink","Port"] +507 +508 Returns: +509 - dict_interfaces_filtered: dictionary with list of interfaces matching conditions +510 +511 Examples: +512 ```python +513 >>> Controller().get_list_interfaces() +514 +515 ``` +516 """ +517 mycommand = ["pw-cli", "info", "all"] +518 +519 # if verbose: +520 # print(f"[mycommand]{mycommand}") +521 +522 stdout, _ = _execute_shell_command(command=mycommand, timeout=-1, verbose=verbose) +523 dict_interfaces = _generate_dict_interfaces(longstring=stdout.decode(), verbose=verbose) +524 +525 if filtered_by_type: +526 dict_interfaces_filtered = _filter_by_type( +527 dict_interfaces=dict_interfaces, type_interfaces=type_interfaces +528 ) +529 else: +530 dict_interfaces_filtered = dict_interfaces +531 +532 return dict_interfaces_filtered 533 -534 return dict_interfaces_filtered -535 -536 def playback( -537 self, -538 audio_filename: str = "myplayback.wav", -539 # Debug -540 verbose: bool = False, -541 ): -542 """Execute pipewire command to play an audio file with the following -543 command: -544 -545 ```bash -546 #!/bin/bash -547 pw-cat --playback {audio_filename} + {configs} -548 # configs are a concatenated params -549 ``` -550 -551 Args: -552 audio_filename (`str`): Path of the file to be played. *default='myplayback.wav' -553 verbose (`bool`): True enable debug logs. *default=False -554 -555 Returns: -556 - stdout (`str`): Shell response to the command in stdout format -557 - stderr (`str`): Shell response response to the command in stderr format -558 """ -559 warnings.warn("The name of the function may change on future releases", DeprecationWarning) -560 -561 mycommand = ["pw-cat", "--playback", audio_filename] + _generate_command_by_dict( -562 mydict=self._pipewire_configs, verbose=verbose -563 ) -564 -565 if verbose: -566 print(f"[mycommand]{mycommand}") -567 -568 stdout, stderr = _execute_shell_command(command=mycommand, timeout=-1, verbose=verbose) -569 return stdout, stderr -570 -571 def record( -572 self, -573 audio_filename: str = "myplayback.wav", -574 timeout_seconds=5, -575 # Debug -576 verbose: bool = False, -577 ): -578 """Execute pipewire command to record an audio file, with a timeout of 5 -579 seconds with the following code and exiting the shell when tiomeout is over. -580 -581 ```bash -582 #!/bin/bash -583 pw-cat --record {audio_filename} -584 # timeout is managed by python3 (when signal CTRL+C is sended) -585 ``` -586 -587 Args: -588 audio_filename (`str`): Path of the file to be played. *default='myplayback.wav' -589 verbose (`bool`): True enable debug logs. *default=False -590 -591 Returns: -592 - stdout (`str`): Shell response to the command in stdout format -593 - stderr (`str`): Shell response response to the command in stderr format -594 """ -595 warnings.warn("The name of the function may change on future releases", DeprecationWarning) -596 -597 mycommand = ["pw-cat", "--record", audio_filename] + _generate_command_by_dict( -598 mydict=self._pipewire_configs, verbose=verbose -599 ) -600 -601 if verbose: -602 print(f"[mycommand]{mycommand}") -603 -604 stdout, stderr = _execute_shell_command( -605 command=mycommand, timeout=timeout_seconds, verbose=verbose -606 ) -607 return stdout, stderr -608 -609 def clear_devices( -610 self, -611 mode: str = "all", # ['all','playback','record'] -612 # Debug -613 verbose: bool = False, -614 ): -615 """Function to stop process running under pipewire executed by -616 python controller and with default process name of `pw-cat`, `pw-play` or `pw-record`. -617 -618 Args: -619 mode (`str`) : string to kill process under `pw-cat`, `pw-play` or `pw-record`. -620 -621 Returns: -622 - stdoutdict (`dict`) : a dictionary with keys of `mode`. -623 -624 Example with pipewire: -625 pw-cat process -626 """ +534 def playback( +535 self, +536 audio_filename: str = "myplayback.wav", +537 # Debug +538 verbose: bool = False, +539 ): +540 """Execute pipewire command to play an audio file with the following +541 command: +542 +543 ```bash +544 #!/bin/bash +545 pw-cat --playback {audio_filename} + {configs} +546 # configs are a concatenated params +547 ``` +548 +549 Args: +550 audio_filename (`str`): Path of the file to be played. *default='myplayback.wav' +551 verbose (`bool`): True enable debug logs. *default=False +552 +553 Returns: +554 - stdout (`str`): Shell response to the command in stdout format +555 - stderr (`str`): Shell response response to the command in stderr format +556 """ +557 warnings.warn("The name of the function may change on future releases", DeprecationWarning) +558 +559 mycommand = ["pw-cat", "--playback", audio_filename] + _generate_command_by_dict( +560 mydict=self._pipewire_configs, verbose=verbose +561 ) +562 +563 if verbose: +564 print(f"[mycommand]{mycommand}") +565 +566 stdout, stderr = _execute_shell_command(command=mycommand, timeout=-1, verbose=verbose) +567 return stdout, stderr +568 +569 def record( +570 self, +571 audio_filename: str = "myplayback.wav", +572 timeout_seconds=5, +573 # Debug +574 verbose: bool = False, +575 ): +576 """Execute pipewire command to record an audio file, with a timeout of 5 +577 seconds with the following code and exiting the shell when tiomeout is over. +578 +579 ```bash +580 #!/bin/bash +581 pw-cat --record {audio_filename} +582 # timeout is managed by python3 (when signal CTRL+C is sended) +583 ``` +584 +585 Args: +586 audio_filename (`str`): Path of the file to be played. *default='myplayback.wav' +587 verbose (`bool`): True enable debug logs. *default=False +588 +589 Returns: +590 - stdout (`str`): Shell response to the command in stdout format +591 - stderr (`str`): Shell response response to the command in stderr format +592 """ +593 warnings.warn("The name of the function may change on future releases", DeprecationWarning) +594 +595 mycommand = ["pw-cat", "--record", audio_filename] + _generate_command_by_dict( +596 mydict=self._pipewire_configs, verbose=verbose +597 ) +598 +599 if verbose: +600 print(f"[mycommand]{mycommand}") +601 +602 stdout, stderr = _execute_shell_command( +603 command=mycommand, timeout=timeout_seconds, verbose=verbose +604 ) +605 return stdout, stderr +606 +607 def clear_devices( +608 self, +609 mode: str = "all", # ['all','playback','record'] +610 # Debug +611 verbose: bool = False, +612 ): +613 """Function to stop process running under pipewire executed by +614 python controller and with default process name of `pw-cat`, `pw-play` or `pw-record`. +615 +616 Args: +617 mode (`str`) : string to kill process under `pw-cat`, `pw-play` or `pw-record`. +618 +619 Returns: +620 - stdoutdict (`dict`) : a dictionary with keys of `mode`. +621 +622 Example with pipewire: +623 pw-cat process +624 """ +625 +626 mycommand = self._kill_pipewire[mode] 627 -628 mycommand = self._kill_pipewire[mode] -629 -630 if verbose: -631 print(f"[mycommands]{mycommand}") +628 if verbose: +629 print(f"[mycommands]{mycommand}") +630 +631 stdout, _ = _execute_shell_command(command=mycommand, verbose=verbose) 632 -633 stdout, _ = _execute_shell_command(command=mycommand, verbose=verbose) -634 -635 return {mode: stdout} +633 return {mode: stdout} @@ -751,600 +749,600 @@

    -
     43class Controller:
    - 44    """
    - 45    Class that controls pipewire command line interface
    - 46    with shell commands, handling outputs, loading default
    - 47    configs and more.
    - 48    """
    - 49
    - 50    _pipewire_cli = {  # Help
    - 51        "--help": "--help",  # -h
    - 52        "--version": "--version",
    - 53        "--remote": None,  # -r
    - 54    }
    - 55
    - 56    _pipewire_modes = {  # Modes
    - 57        "--playback": None,  # -p
    - 58        "--record": None,  # -r
    - 59        "--midi": None,  # -m
    - 60    }
    - 61
    - 62    _pipewire_list_targets = {  # "--list-targets": None,
    - 63        "list_playback": None,
    - 64        "list_record": None,
    - 65    }
    - 66
    - 67    _pipewire_configs = {  # Configs
    - 68        "--media-type": None,  # *default=Audio
    - 69        "--media-category": None,  # *default=Playback
    - 70        "--media-role": None,  # *default=Music
    - 71        "--target": None,  # *default=auto
    - 72        "--latency": None,  # *default=100ms (SOURCE FILE if not specified)
    - 73        "--rate": None,  # *default=48000
    - 74        "--channels": None,  # [1,2] *default=2
    - 75        "--channel-map": None,  # ["stereo", "surround-51", "FL,FR"...] *default="FL,FR"
    - 76        "--format": None,  # [u8|s8|s16|s32|f32|f64] *default=s16
    - 77        "--volume": None,  # [0.0,1.0] *default=1.000
    - 78        "--quality": None,  # -q # [0,15] *default=4
    - 79        "--verbose": None,  # -v
    - 80    }
    - 81
    - 82    _kill_pipewire = {
    - 83        "all": ["kill", "$(pidof pw-cat)"],
    - 84        "playback": ["kill", "$(pidof pw-play)"],
    - 85        "record": ["kill", "$(pidof pw-record)"],
    - 86    }
    - 87
    - 88    def __init__(
    - 89        self,
    - 90        # Debug
    - 91        verbose: bool = False,
    - 92    ):
    - 93        """This constructor load default configs from OS executing
    - 94        the following pipewire command
    - 95
    - 96        ```bash
    - 97        #!/bin/bash
    - 98        # Get defaults from output of:
    - 99        pw-cat -h
    -100        ```
    -101        """
    -102        # LOAD ALL DEFAULT PARAMETERS
    +            
     41class Controller:
    + 42    """
    + 43    Class that controls pipewire command line interface
    + 44    with shell commands, handling outputs, loading default
    + 45    configs and more.
    + 46    """
    + 47
    + 48    _pipewire_cli = {  # Help
    + 49        "--help": "--help",  # -h
    + 50        "--version": "--version",
    + 51        "--remote": None,  # -r
    + 52    }
    + 53
    + 54    _pipewire_modes = {  # Modes
    + 55        "--playback": None,  # -p
    + 56        "--record": None,  # -r
    + 57        "--midi": None,  # -m
    + 58    }
    + 59
    + 60    _pipewire_list_targets = {  # "--list-targets": None,
    + 61        "list_playback": None,
    + 62        "list_record": None,
    + 63    }
    + 64
    + 65    _pipewire_configs = {  # Configs
    + 66        "--media-type": None,  # *default=Audio
    + 67        "--media-category": None,  # *default=Playback
    + 68        "--media-role": None,  # *default=Music
    + 69        "--target": None,  # *default=auto
    + 70        "--latency": None,  # *default=100ms (SOURCE FILE if not specified)
    + 71        "--rate": None,  # *default=48000
    + 72        "--channels": None,  # [1,2] *default=2
    + 73        "--channel-map": None,  # ["stereo", "surround-51", "FL,FR"...] *default="FL,FR"
    + 74        "--format": None,  # [u8|s8|s16|s32|f32|f64] *default=s16
    + 75        "--volume": None,  # [0.0,1.0] *default=1.000
    + 76        "--quality": None,  # -q # [0,15] *default=4
    + 77        "--verbose": None,  # -v
    + 78    }
    + 79
    + 80    _kill_pipewire = {
    + 81        "all": ["kill", "$(pidof pw-cat)"],
    + 82        "playback": ["kill", "$(pidof pw-play)"],
    + 83        "record": ["kill", "$(pidof pw-record)"],
    + 84    }
    + 85
    + 86    def __init__(
    + 87        self,
    + 88        # Debug
    + 89        verbose: bool = False,
    + 90    ):
    + 91        """This constructor load default configs from OS executing
    + 92        the following pipewire command
    + 93
    + 94        ```bash
    + 95        #!/bin/bash
    + 96        # Get defaults from output of:
    + 97        pw-cat -h
    + 98        ```
    + 99        """
    +100        # LOAD ALL DEFAULT PARAMETERS
    +101
    +102        mycommand = ["pw-cat", "-h"]
     103
    -104        mycommand = ["pw-cat", "-h"]
    -105
    -106        # get default parameters with help
    -107        stdout, _ = _execute_shell_command(command=mycommand, verbose=verbose)  # stderr
    -108        # convert stdout to dictionary
    -109        dict_default_values = _get_dict_from_stdout(stdout=str(stdout.decode()), verbose=verbose)
    -110
    -111        if verbose:
    -112            print(self._pipewire_configs)
    -113
    -114        # Save default system configs to our json
    -115        self._pipewire_configs.update(
    -116            ([(key, dict_default_values[key]) for key in dict_default_values])
    -117        )
    -118
    -119        if verbose:
    -120            print(self._pipewire_configs)
    -121
    -122        # Delete keys with None values
    -123        self._pipewire_configs = _drop_keys_with_none_values(self._pipewire_configs)
    -124
    -125        if verbose:
    -126            print(self._pipewire_configs)
    -127
    -128        # Load values of list targets
    -129        self.load_list_targets(mode="playback", verbose=verbose)
    -130        self.load_list_targets(mode="record", verbose=verbose)
    -131
    -132    def _help_cli(
    -133        self,
    -134        # Debug
    -135        verbose: bool = True,
    -136    ):
    -137        """Get pipewire command line help"""
    +104        # get default parameters with help
    +105        stdout, _ = _execute_shell_command(command=mycommand, verbose=verbose)  # stderr
    +106        # convert stdout to dictionary
    +107        dict_default_values = _get_dict_from_stdout(stdout=str(stdout.decode()), verbose=verbose)
    +108
    +109        if verbose:
    +110            print(self._pipewire_configs)
    +111
    +112        # Save default system configs to our json
    +113        self._pipewire_configs.update(
    +114            ([(key, dict_default_values[key]) for key in dict_default_values])
    +115        )
    +116
    +117        if verbose:
    +118            print(self._pipewire_configs)
    +119
    +120        # Delete keys with None values
    +121        self._pipewire_configs = _drop_keys_with_none_values(self._pipewire_configs)
    +122
    +123        if verbose:
    +124            print(self._pipewire_configs)
    +125
    +126        # Load values of list targets
    +127        self.load_list_targets(mode="playback", verbose=verbose)
    +128        self.load_list_targets(mode="record", verbose=verbose)
    +129
    +130    def _help_cli(
    +131        self,
    +132        # Debug
    +133        verbose: bool = True,
    +134    ):
    +135        """Get pipewire command line help"""
    +136
    +137        mycommand = ["pipewire", self._pipewire_cli["--help"]]
     138
    -139        mycommand = ["pipewire", self._pipewire_cli["--help"]]
    +139        stdout, _ = _execute_shell_command(command=mycommand, verbose=verbose)  # stderr
     140
    -141        stdout, _ = _execute_shell_command(command=mycommand, verbose=verbose)  # stderr
    +141        return stdout
     142
    -143        return stdout
    -144
    -145    def get_version(
    -146        self,
    -147        # Debug
    -148        verbose: bool = False,
    -149    ):
    -150        """Get version of pipewire installed on OS by executing the following
    -151        code:
    -152
    -153        ```bash
    -154        #!/bin/bash
    -155        pw-cli --version
    -156        ```
    -157
    -158        Args:
    -159            verbose (bool) : True enable debug logs. *default=False
    -160
    -161        Returns:
    -162            - versions (list) : Versions of pipewire compiled
    -163        """
    +143    def get_version(
    +144        self,
    +145        # Debug
    +146        verbose: bool = False,
    +147    ):
    +148        """Get version of pipewire installed on OS by executing the following
    +149        code:
    +150
    +151        ```bash
    +152        #!/bin/bash
    +153        pw-cli --version
    +154        ```
    +155
    +156        Args:
    +157            verbose (bool) : True enable debug logs. *default=False
    +158
    +159        Returns:
    +160            - versions (list) : Versions of pipewire compiled
    +161        """
    +162
    +163        mycommand = ["pw-cli", "--version"]
     164
    -165        mycommand = ["pw-cli", "--version"]
    -166
    -167        if verbose:
    -168            print(f"[mycommand]{mycommand}")
    -169
    -170        stdout, _ = _execute_shell_command(command=mycommand, timeout=-1, verbose=verbose)
    -171        versions = stdout.decode().split("\n")[1:]
    +165        if verbose:
    +166            print(f"[mycommand]{mycommand}")
    +167
    +168        stdout, _ = _execute_shell_command(command=mycommand, timeout=-1, verbose=verbose)
    +169        versions = stdout.decode().split("\n")[1:]
    +170
    +171        self._pipewire_cli["--version"] = versions
     172
    -173        self._pipewire_cli["--version"] = versions
    +173        return versions
     174
    -175        return versions
    -176
    -177    def verbose(
    -178        self,
    -179        status: bool = True,
    -180    ):
    -181        """Get full log of pipewire stream status with the command `pw-cat`
    +175    def verbose(
    +176        self,
    +177        status: bool = True,
    +178    ):
    +179        """Get full log of pipewire stream status with the command `pw-cat`
    +180
    +181        An example of pw-cli usage is the code below:
     182
    -183        An example of pw-cli usage is the code below:
    -184
    -185        ```bash
    -186        #!/bin/bash
    -187        # For example
    -188        pw-cat --playback beers.wav --verbose
    -189        ```
    +183        ```bash
    +184        #!/bin/bash
    +185        # For example
    +186        pw-cat --playback beers.wav --verbose
    +187        ```
    +188
    +189        that will generate an output like this:
     190
    -191        that will generate an output like this:
    -192
    -193        ```bash
    -194        opened file "beers.wav" format 00010002 channels:2 rate:44100
    -195        using default channel map: FL,FR
    -196        rate=44100 channels=2 fmt=s16 samplesize=2 stride=4 latency=4410 (0.100s)
    -197        connecting playback stream; target_id=4294967295
    -198        stream state changed unconnected -> connecting
    -199        stream param change: id=2
    -200        stream properties:
    -201            media.type = "Audio"
    -202            ...
    -203        now=0 rate=0/0 ticks=0 delay=0 queued=0
    -204        remote 0 is named "pipewire-0"
    -205        core done
    -206        stream state changed connecting -> paused
    -207        stream param change: id=2
    -208        ...
    -209        stream param change: id=15
    -210        stream param change: id=15
    -211        now=13465394419270 rate=1/48000 ticks=35840 delay=512 queued=0
    -212        now=13466525228363 rate=1/48000 ticks=90112 delay=512 queued=0
    -213        ...
    -214        stream drained
    -215        stream state changed streaming -> paused
    +191        ```bash
    +192        opened file "beers.wav" format 00010002 channels:2 rate:44100
    +193        using default channel map: FL,FR
    +194        rate=44100 channels=2 fmt=s16 samplesize=2 stride=4 latency=4410 (0.100s)
    +195        connecting playback stream; target_id=4294967295
    +196        stream state changed unconnected -> connecting
    +197        stream param change: id=2
    +198        stream properties:
    +199            media.type = "Audio"
    +200            ...
    +201        now=0 rate=0/0 ticks=0 delay=0 queued=0
    +202        remote 0 is named "pipewire-0"
    +203        core done
    +204        stream state changed connecting -> paused
    +205        stream param change: id=2
    +206        ...
    +207        stream param change: id=15
    +208        stream param change: id=15
    +209        now=13465394419270 rate=1/48000 ticks=35840 delay=512 queued=0
    +210        now=13466525228363 rate=1/48000 ticks=90112 delay=512 queued=0
    +211        ...
    +212        stream drained
    +213        stream state changed streaming -> paused
    +214        stream param change: id=4
    +215        stream state changed paused -> unconnected
     216        stream param change: id=4
    -217        stream state changed paused -> unconnected
    -218        stream param change: id=4
    -219        ```
    -220        """
    -221
    -222        if status:
    -223            self._pipewire_configs["--verbose"] = "    "
    -224        else:
    -225            pass
    -226
    -227    def get_config(self):
    -228        """Return config dictionary with default or setup variables, remember that
    -229        this object changes only on python-side. Is not updated on real time,
    -230        For real-time, please create and destroy the class.
    -231
    -232        Args:
    -233            Nothing
    -234
    -235        Returns:
    -236            - _pipewire_configs (`dict`) : dictionary with config values
    +217        ```
    +218        """
    +219
    +220        if status:
    +221            self._pipewire_configs["--verbose"] = "    "
    +222        else:
    +223            pass
    +224
    +225    def get_config(self):
    +226        """Return config dictionary with default or setup variables, remember that
    +227        this object changes only on python-side. Is not updated on real time,
    +228        For real-time, please create and destroy the class.
    +229
    +230        Args:
    +231            Nothing
    +232
    +233        Returns:
    +234            - _pipewire_configs (`dict`) : dictionary with config values
    +235
    +236        """
     237
    -238        """
    +238        return self._pipewire_configs
     239
    -240        return self._pipewire_configs
    -241
    -242    def set_config(
    -243        self,
    -244        # configs
    -245        media_type=None,
    -246        media_category=None,
    -247        media_role=None,
    -248        target=None,
    -249        latency=None,
    -250        rate=None,
    -251        channels=None,
    -252        channels_map=None,
    -253        _format=None,
    -254        volume=None,
    -255        quality=None,
    -256        # Debug
    -257        verbose=False,
    -258    ):
    -259        """Method that get args as variables and set them
    -260        to the `json` parameter of the class `_pipewire_configs`,
    -261        then you can use in other method, such as `playback(...)` or
    -262        `record(...)`. This method verifies values to avoid wrong
    -263        settings.
    -264
    -265        Args:
    -266            media_type : Set media type
    -267            media_category : Set media category
    -268            media_role : Set media role
    -269            target : Set node target
    -270            latency : Set node latency *example=100ms
    -271            rate : Set sample rate [8000,11025,16000,22050,44100,48000,88200,96000,176400,192000,352800,384000]
    -272            channels : Numbers of channels [1,2]
    -273            channels_map : ["stereo", "surround-51", "FL,FR", ...]
    -274            _format : ["u8", "s8", "s16", "s32", "f32", "f64"]
    -275            volume : Stream volume [0.000, 1.000]
    -276            quality : Resampler quality [0, 15]
    -277            verbose (`bool`): True enable debug logs. *default=False
    -278
    -279        Returns:
    -280            - Nothing
    -281
    -282        More:
    -283            Check all links listed at the beginning of this page
    -284        """  # 1 - media_type
    -285        if media_type:
    -286            self._pipewire_configs["--media-type"] = str(media_type)
    -287        elif media_type is None:
    -288            pass
    -289        else:
    -290            raise ValueError(
    -291                f"{MESSAGES_ERROR['ValueError']}[media_type='{media_type}'] EMPTY VALUE"
    -292            )
    -293        # 2 - media_category
    -294        if media_category:
    -295            self._pipewire_configs["--media-category"] = str(media_category)
    -296        elif media_category is None:
    -297            pass
    -298        else:
    -299            raise ValueError(
    -300                f"{MESSAGES_ERROR['ValueError']}[media_category='{media_category}'] EMPTY VALUE"
    -301            )
    -302        # 3 - media_role
    -303        if media_role:
    -304            self._pipewire_configs["--media-role"] = str(media_role)
    -305        elif media_role is None:
    -306            pass
    -307        else:
    -308            raise ValueError(
    -309                f"{MESSAGES_ERROR['ValueError']}[media_role='{media_role}'] EMPTY VALUE"
    -310            )
    -311        # 4 - target
    -312        if target:
    -313            self._pipewire_configs["--target"] = str(target)
    -314        elif target is None:
    -315            pass
    -316        else:
    -317            raise ValueError(f"{MESSAGES_ERROR['ValueError']}[target='{target}'] EMPTY VALUE")
    -318        # 5 - latency
    -319        if latency:
    -320            if any(chr.isdigit() for chr in latency):  # Contain numbers
    -321                self._pipewire_configs["--latency"] = str(latency)
    -322            else:
    -323                raise ValueError(
    -324                    f"{MESSAGES_ERROR['ValueError']}[latency='{latency}'] NO NUMBER IN VARIABLE"
    -325                )
    -326        elif latency is None:
    -327            pass
    -328        else:
    -329            raise ValueError(f"{MESSAGES_ERROR['ValueError']}[latency='{latency}'] EMPTY VALUE")
    -330        # 6 - rate
    -331        if rate:
    -332            if rate in RECOMMENDED_RATES:
    -333                self._pipewire_configs["--rate"] = str(rate)
    -334            else:
    -335                raise ValueError(
    -336                    f"{MESSAGES_ERROR['ValueError']}[rate='{rate}']\
    -337                         VALUE NOT IN RECOMMENDED LIST \n{RECOMMENDED_RATES}"
    -338                )
    -339        elif rate is None:
    -340            pass
    -341        else:
    -342            raise ValueError(f"{MESSAGES_ERROR['ValueError']}[rate='{rate}'] EMPTY VALUE")
    -343        # 7 - channels
    -344        if channels:
    -345            if channels in [1, 2]:  # values
    -346                self._pipewire_configs["--channels"] = str(channels)
    -347            else:
    -348                raise ValueError(
    -349                    f"{MESSAGES_ERROR['ValueError']}[channels='{channels}']\
    -350                         WRONG VALUE\n ONLY 1 or 2."
    -351                )
    -352        elif channels is None:
    -353            pass
    -354        else:
    -355            raise ValueError(f"{MESSAGES_ERROR['ValueError']}[channels='{channels}'] EMPTY VALUE")
    -356        # 8 - channels-map
    -357        if channels_map:
    -358            self._pipewire_configs["--channels-map"] = str(channels_map)
    -359        elif channels_map is None:
    -360            pass
    -361        else:
    -362            raise ValueError(
    -363                f"{MESSAGES_ERROR['ValueError']}[channels_map='{channels_map}'] EMPTY VALUE"
    -364            )
    -365        # 9 - format
    -366        if _format:
    -367            if _format in RECOMMENDED_FORMATS:
    -368                self._pipewire_configs["--format"] = str(_format)
    -369            else:
    -370                raise ValueError(
    -371                    f"{MESSAGES_ERROR['ValueError']}[_format='{_format}']\
    -372                         VALUE NOT IN RECOMMENDED LIST \n{RECOMMENDED_FORMATS}"
    -373                )
    -374        elif _format is None:
    -375            pass
    -376        else:
    -377            raise ValueError(f"{MESSAGES_ERROR['ValueError']}[_format='{_format}'] EMPTY VALUE")
    -378        # 10 - volume
    -379        if volume:
    -380            if 0.0 <= volume <= 1.0:
    -381                self._pipewire_configs["--volume"] = str(volume)
    -382            else:
    -383                raise ValueError(
    -384                    f"{MESSAGES_ERROR['ValueError']}[volume='{volume}']\
    -385                         OUT OF RANGE \n [0.000, 1.000]"
    -386                )
    -387        elif volume is None:
    -388            pass
    -389        else:
    -390            raise ValueError(f"{MESSAGES_ERROR['ValueError']}[volume='{volume}'] EMPTY VALUE")
    -391        # 11 - quality
    -392        if quality:
    -393            if 0 <= quality <= 15:
    -394                self._pipewire_configs["--quality"] = str(quality)
    -395            else:
    -396                raise ValueError(
    -397                    f"{MESSAGES_ERROR['ValueError']}[quality='{quality}'] OUT OF RANGE \n [0, 15]"
    -398                )
    -399        elif quality is None:
    -400            pass
    -401        else:
    -402            raise ValueError(f"{MESSAGES_ERROR['ValueError']}[volume='{volume}'] EMPTY VALUE")
    -403
    -404        # 12 - verbose cli
    -405        if verbose:  # True
    -406            self._pipewire_configs["--verbose"] = "    "
    -407        else:
    -408            pass
    -409
    -410        if verbose:
    -411            print(self._pipewire_configs)
    -412
    -413    def load_list_targets(
    -414        self,
    -415        mode,  # playback or record
    -416        # Debug,
    -417        verbose: bool = False,
    -418    ):
    -419        """Returns a list of targets to playback or record. Then you can use
    -420        the output to select a device to playback or record.
    -421        """
    -422
    -423        if mode == "playback":
    -424            mycommand = ["pw-cat", "--playback", "--list-targets"]
    -425            stdout, _ = _execute_shell_command(command=mycommand, timeout=-1, verbose=verbose)
    -426            self._pipewire_list_targets["list_playback"] = _generate_dict_list_targets(
    -427                longstring=stdout.decode(), verbose=verbose
    -428            )
    -429        elif mode == "record":
    -430            mycommand = ["pw-cat", "--record", "--list-targets"]
    -431            stdout, _ = _execute_shell_command(command=mycommand, timeout=-1, verbose=verbose)
    -432            self._pipewire_list_targets["list_record"] = _generate_dict_list_targets(
    -433                longstring=stdout.decode(), verbose=verbose
    -434            )
    -435        else:
    -436            raise AttributeError(MESSAGES_ERROR["ValueError"])
    -437
    -438        if verbose:
    -439            print(f"[mycommand]{mycommand}")
    -440
    -441    def get_list_targets(
    -442        self,
    -443        # Debug,
    -444        verbose: bool = False,
    -445    ):
    -446        """Returns a list of targets to playback or record. Then you can use
    -447        the output to select a device to playback or record.
    -448
    -449        Returns:
    -450            - `_pipewire_list_targets`
    -451
    -452        Examples:
    -453        ```python
    -454        >>> Controller().get_list_targets()
    -455        {
    -456        "list_playback": {
    -457            "86": {
    -458            "description": "Starship/Matisse HD Audio Controller Pro",
    -459            "prior": "936"
    -460            },
    -461            "_list_nodes": [
    -462            "86"
    -463            ],
    -464            "_node_default": [
    -465            "86"
    -466            ],
    -467            "_alsa_node": [
    -468            "alsa_output.pci-0000_0a_00.4.pro-output-0"
    -469            ]
    -470        },
    -471        "list_record": {
    -472            "86": {
    -473            "description": "Starship/Matisse HD Audio Controller Pro",
    -474            "prior": "936"
    -475            },
    -476            "_list_nodes": [
    -477            "86"
    -478            ],
    -479            "_node_default": [
    -480            "86"
    -481            ],
    -482            "_alsa_node": [
    -483            "alsa_output.pci-0000_0a_00.4.pro-output-0"
    -484            ]
    -485        }
    -486        }
    -487        ```
    -488        """
    -489        if verbose:
    -490            print(self._pipewire_list_targets)
    -491        return self._pipewire_list_targets
    -492
    -493    def get_list_interfaces(
    -494        self,
    -495        filtered_by_type: str = True,
    -496        type_interfaces: str = "Client",
    -497        # Debug
    -498        verbose: bool = False,
    -499    ):
    -500        """Returns a list of applications currently using pipewire on Client.
    -501        An example of pw-cli usage is the code below:
    -502
    -503        ```bash
    -504        #!/bin/bash
    -505        pw-cli ls Client
    -506        ```
    -507        Args:
    -508            filtered_by_type : If False, returns all. If not, returns a fitered dict
    -509            type_interfaces : Set type of Interface ["Client","Link","Node","Factory","Module","Metadata","Endpoint","Session","Endpoint Stream","EndpointLink","Port"]
    -510
    -511        Returns:
    -512            - dict_interfaces_filtered: dictionary with list of interfaces matching conditions
    -513
    -514        Examples:
    -515        ```python
    -516        >>> Controller().get_list_interfaces()
    -517
    -518        ```
    -519        """
    -520        mycommand = ["pw-cli", "info", "all"]
    -521
    -522        # if verbose:
    -523        #     print(f"[mycommand]{mycommand}")
    -524
    -525        stdout, _ = _execute_shell_command(command=mycommand, timeout=-1, verbose=verbose)
    -526        dict_interfaces = _generate_dict_interfaces(longstring=stdout.decode(), verbose=verbose)
    -527
    -528        if filtered_by_type:
    -529            dict_interfaces_filtered = _filter_by_type(
    -530                dict_interfaces=dict_interfaces, type_interfaces=type_interfaces
    -531            )
    -532        else:
    -533            dict_interfaces_filtered = dict_interfaces
    +240    def set_config(
    +241        self,
    +242        # configs
    +243        media_type=None,
    +244        media_category=None,
    +245        media_role=None,
    +246        target=None,
    +247        latency=None,
    +248        rate=None,
    +249        channels=None,
    +250        channels_map=None,
    +251        _format=None,
    +252        volume=None,
    +253        quality=None,
    +254        # Debug
    +255        verbose=False,
    +256    ):
    +257        """Method that get args as variables and set them
    +258        to the `json` parameter of the class `_pipewire_configs`,
    +259        then you can use in other method, such as `playback(...)` or
    +260        `record(...)`. This method verifies values to avoid wrong
    +261        settings.
    +262
    +263        Args:
    +264            media_type : Set media type
    +265            media_category : Set media category
    +266            media_role : Set media role
    +267            target : Set node target
    +268            latency : Set node latency *example=100ms
    +269            rate : Set sample rate [8000,11025,16000,22050,44100,48000,88200,96000,176400,192000,352800,384000]
    +270            channels : Numbers of channels [1,2]
    +271            channels_map : ["stereo", "surround-51", "FL,FR", ...]
    +272            _format : ["u8", "s8", "s16", "s32", "f32", "f64"]
    +273            volume : Stream volume [0.000, 1.000]
    +274            quality : Resampler quality [0, 15]
    +275            verbose (`bool`): True enable debug logs. *default=False
    +276
    +277        Returns:
    +278            - Nothing
    +279
    +280        More:
    +281            Check all links listed at the beginning of this page
    +282        """  # 1 - media_type
    +283        if media_type:
    +284            self._pipewire_configs["--media-type"] = str(media_type)
    +285        elif media_type is None:
    +286            pass
    +287        else:
    +288            raise ValueError(
    +289                f"{MESSAGES_ERROR['ValueError']}[media_type='{media_type}'] EMPTY VALUE"
    +290            )
    +291        # 2 - media_category
    +292        if media_category:
    +293            self._pipewire_configs["--media-category"] = str(media_category)
    +294        elif media_category is None:
    +295            pass
    +296        else:
    +297            raise ValueError(
    +298                f"{MESSAGES_ERROR['ValueError']}[media_category='{media_category}'] EMPTY VALUE"
    +299            )
    +300        # 3 - media_role
    +301        if media_role:
    +302            self._pipewire_configs["--media-role"] = str(media_role)
    +303        elif media_role is None:
    +304            pass
    +305        else:
    +306            raise ValueError(
    +307                f"{MESSAGES_ERROR['ValueError']}[media_role='{media_role}'] EMPTY VALUE"
    +308            )
    +309        # 4 - target
    +310        if target:
    +311            self._pipewire_configs["--target"] = str(target)
    +312        elif target is None:
    +313            pass
    +314        else:
    +315            raise ValueError(f"{MESSAGES_ERROR['ValueError']}[target='{target}'] EMPTY VALUE")
    +316        # 5 - latency
    +317        if latency:
    +318            if any(chr.isdigit() for chr in latency):  # Contain numbers
    +319                self._pipewire_configs["--latency"] = str(latency)
    +320            else:
    +321                raise ValueError(
    +322                    f"{MESSAGES_ERROR['ValueError']}[latency='{latency}'] NO NUMBER IN VARIABLE"
    +323                )
    +324        elif latency is None:
    +325            pass
    +326        else:
    +327            raise ValueError(f"{MESSAGES_ERROR['ValueError']}[latency='{latency}'] EMPTY VALUE")
    +328        # 6 - rate
    +329        if rate:
    +330            if rate in RECOMMENDED_RATES:
    +331                self._pipewire_configs["--rate"] = str(rate)
    +332            else:
    +333                raise ValueError(
    +334                    f"{MESSAGES_ERROR['ValueError']}[rate='{rate}']\
    +335                         VALUE NOT IN RECOMMENDED LIST \n{RECOMMENDED_RATES}"
    +336                )
    +337        elif rate is None:
    +338            pass
    +339        else:
    +340            raise ValueError(f"{MESSAGES_ERROR['ValueError']}[rate='{rate}'] EMPTY VALUE")
    +341        # 7 - channels
    +342        if channels:
    +343            if channels in [1, 2]:  # values
    +344                self._pipewire_configs["--channels"] = str(channels)
    +345            else:
    +346                raise ValueError(
    +347                    f"{MESSAGES_ERROR['ValueError']}[channels='{channels}']\
    +348                         WRONG VALUE\n ONLY 1 or 2."
    +349                )
    +350        elif channels is None:
    +351            pass
    +352        else:
    +353            raise ValueError(f"{MESSAGES_ERROR['ValueError']}[channels='{channels}'] EMPTY VALUE")
    +354        # 8 - channels-map
    +355        if channels_map:
    +356            self._pipewire_configs["--channels-map"] = str(channels_map)
    +357        elif channels_map is None:
    +358            pass
    +359        else:
    +360            raise ValueError(
    +361                f"{MESSAGES_ERROR['ValueError']}[channels_map='{channels_map}'] EMPTY VALUE"
    +362            )
    +363        # 9 - format
    +364        if _format:
    +365            if _format in RECOMMENDED_FORMATS:
    +366                self._pipewire_configs["--format"] = str(_format)
    +367            else:
    +368                raise ValueError(
    +369                    f"{MESSAGES_ERROR['ValueError']}[_format='{_format}']\
    +370                         VALUE NOT IN RECOMMENDED LIST \n{RECOMMENDED_FORMATS}"
    +371                )
    +372        elif _format is None:
    +373            pass
    +374        else:
    +375            raise ValueError(f"{MESSAGES_ERROR['ValueError']}[_format='{_format}'] EMPTY VALUE")
    +376        # 10 - volume
    +377        if volume:
    +378            if 0.0 <= volume <= 1.0:
    +379                self._pipewire_configs["--volume"] = str(volume)
    +380            else:
    +381                raise ValueError(
    +382                    f"{MESSAGES_ERROR['ValueError']}[volume='{volume}']\
    +383                         OUT OF RANGE \n [0.000, 1.000]"
    +384                )
    +385        elif volume is None:
    +386            pass
    +387        else:
    +388            raise ValueError(f"{MESSAGES_ERROR['ValueError']}[volume='{volume}'] EMPTY VALUE")
    +389        # 11 - quality
    +390        if quality:
    +391            if 0 <= quality <= 15:
    +392                self._pipewire_configs["--quality"] = str(quality)
    +393            else:
    +394                raise ValueError(
    +395                    f"{MESSAGES_ERROR['ValueError']}[quality='{quality}'] OUT OF RANGE \n [0, 15]"
    +396                )
    +397        elif quality is None:
    +398            pass
    +399        else:
    +400            raise ValueError(f"{MESSAGES_ERROR['ValueError']}[volume='{volume}'] EMPTY VALUE")
    +401
    +402        # 12 - verbose cli
    +403        if verbose:  # True
    +404            self._pipewire_configs["--verbose"] = "    "
    +405        else:
    +406            pass
    +407
    +408        if verbose:
    +409            print(self._pipewire_configs)
    +410
    +411    def load_list_targets(
    +412        self,
    +413        mode,  # playback or record
    +414        # Debug,
    +415        verbose: bool = False,
    +416    ):
    +417        """Returns a list of targets to playback or record. Then you can use
    +418        the output to select a device to playback or record.
    +419        """
    +420
    +421        if mode == "playback":
    +422            mycommand = ["pw-cat", "--playback", "--list-targets"]
    +423            stdout, _ = _execute_shell_command(command=mycommand, timeout=-1, verbose=verbose)
    +424            self._pipewire_list_targets["list_playback"] = _generate_dict_list_targets(
    +425                longstring=stdout.decode(), verbose=verbose
    +426            )
    +427        elif mode == "record":
    +428            mycommand = ["pw-cat", "--record", "--list-targets"]
    +429            stdout, _ = _execute_shell_command(command=mycommand, timeout=-1, verbose=verbose)
    +430            self._pipewire_list_targets["list_record"] = _generate_dict_list_targets(
    +431                longstring=stdout.decode(), verbose=verbose
    +432            )
    +433        else:
    +434            raise AttributeError(MESSAGES_ERROR["ValueError"])
    +435
    +436        if verbose:
    +437            print(f"[mycommand]{mycommand}")
    +438
    +439    def get_list_targets(
    +440        self,
    +441        # Debug,
    +442        verbose: bool = False,
    +443    ):
    +444        """Returns a list of targets to playback or record. Then you can use
    +445        the output to select a device to playback or record.
    +446
    +447        Returns:
    +448            - `_pipewire_list_targets`
    +449
    +450        Examples:
    +451        ```python
    +452        >>> Controller().get_list_targets()
    +453        {
    +454        "list_playback": {
    +455            "86": {
    +456            "description": "Starship/Matisse HD Audio Controller Pro",
    +457            "prior": "936"
    +458            },
    +459            "_list_nodes": [
    +460            "86"
    +461            ],
    +462            "_node_default": [
    +463            "86"
    +464            ],
    +465            "_alsa_node": [
    +466            "alsa_output.pci-0000_0a_00.4.pro-output-0"
    +467            ]
    +468        },
    +469        "list_record": {
    +470            "86": {
    +471            "description": "Starship/Matisse HD Audio Controller Pro",
    +472            "prior": "936"
    +473            },
    +474            "_list_nodes": [
    +475            "86"
    +476            ],
    +477            "_node_default": [
    +478            "86"
    +479            ],
    +480            "_alsa_node": [
    +481            "alsa_output.pci-0000_0a_00.4.pro-output-0"
    +482            ]
    +483        }
    +484        }
    +485        ```
    +486        """
    +487        if verbose:
    +488            print(self._pipewire_list_targets)
    +489        return self._pipewire_list_targets
    +490
    +491    def get_list_interfaces(
    +492        self,
    +493        filtered_by_type: str = True,
    +494        type_interfaces: str = "Client",
    +495        # Debug
    +496        verbose: bool = False,
    +497    ):
    +498        """Returns a list of applications currently using pipewire on Client.
    +499        An example of pw-cli usage is the code below:
    +500
    +501        ```bash
    +502        #!/bin/bash
    +503        pw-cli ls Client
    +504        ```
    +505        Args:
    +506            filtered_by_type : If False, returns all. If not, returns a fitered dict
    +507            type_interfaces : Set type of Interface ["Client","Link","Node","Factory","Module","Metadata","Endpoint","Session","Endpoint Stream","EndpointLink","Port"]
    +508
    +509        Returns:
    +510            - dict_interfaces_filtered: dictionary with list of interfaces matching conditions
    +511
    +512        Examples:
    +513        ```python
    +514        >>> Controller().get_list_interfaces()
    +515
    +516        ```
    +517        """
    +518        mycommand = ["pw-cli", "info", "all"]
    +519
    +520        # if verbose:
    +521        #     print(f"[mycommand]{mycommand}")
    +522
    +523        stdout, _ = _execute_shell_command(command=mycommand, timeout=-1, verbose=verbose)
    +524        dict_interfaces = _generate_dict_interfaces(longstring=stdout.decode(), verbose=verbose)
    +525
    +526        if filtered_by_type:
    +527            dict_interfaces_filtered = _filter_by_type(
    +528                dict_interfaces=dict_interfaces, type_interfaces=type_interfaces
    +529            )
    +530        else:
    +531            dict_interfaces_filtered = dict_interfaces
    +532
    +533        return dict_interfaces_filtered
     534
    -535        return dict_interfaces_filtered
    -536
    -537    def playback(
    -538        self,
    -539        audio_filename: str = "myplayback.wav",
    -540        # Debug
    -541        verbose: bool = False,
    -542    ):
    -543        """Execute pipewire command to play an audio file with the following
    -544        command:
    -545
    -546        ```bash
    -547        #!/bin/bash
    -548        pw-cat --playback {audio_filename} + {configs}
    -549        # configs are a concatenated params
    -550        ```
    -551
    -552        Args:
    -553            audio_filename (`str`): Path of the file to be played. *default='myplayback.wav'
    -554            verbose (`bool`): True enable debug logs. *default=False
    -555
    -556        Returns:
    -557            - stdout (`str`): Shell response to the command in stdout format
    -558            - stderr (`str`): Shell response response to the command in stderr format
    -559        """
    -560        warnings.warn("The name of the function may change on future releases", DeprecationWarning)
    -561
    -562        mycommand = ["pw-cat", "--playback", audio_filename] + _generate_command_by_dict(
    -563            mydict=self._pipewire_configs, verbose=verbose
    -564        )
    -565
    -566        if verbose:
    -567            print(f"[mycommand]{mycommand}")
    -568
    -569        stdout, stderr = _execute_shell_command(command=mycommand, timeout=-1, verbose=verbose)
    -570        return stdout, stderr
    -571
    -572    def record(
    -573        self,
    -574        audio_filename: str = "myplayback.wav",
    -575        timeout_seconds=5,
    -576        # Debug
    -577        verbose: bool = False,
    -578    ):
    -579        """Execute pipewire command to record an audio file, with a timeout of 5
    -580        seconds with the following code and exiting the shell when tiomeout is over.
    -581
    -582        ```bash
    -583        #!/bin/bash
    -584        pw-cat --record {audio_filename}
    -585        # timeout is managed by python3 (when signal CTRL+C is sended)
    -586        ```
    -587
    -588        Args:
    -589            audio_filename (`str`): Path of the file to be played. *default='myplayback.wav'
    -590            verbose (`bool`): True enable debug logs. *default=False
    -591
    -592        Returns:
    -593            - stdout (`str`): Shell response to the command in stdout format
    -594            - stderr (`str`): Shell response response to the command in stderr format
    -595        """
    -596        warnings.warn("The name of the function may change on future releases", DeprecationWarning)
    -597
    -598        mycommand = ["pw-cat", "--record", audio_filename] + _generate_command_by_dict(
    -599            mydict=self._pipewire_configs, verbose=verbose
    -600        )
    -601
    -602        if verbose:
    -603            print(f"[mycommand]{mycommand}")
    -604
    -605        stdout, stderr = _execute_shell_command(
    -606            command=mycommand, timeout=timeout_seconds, verbose=verbose
    -607        )
    -608        return stdout, stderr
    -609
    -610    def clear_devices(
    -611        self,
    -612        mode: str = "all",  # ['all','playback','record']
    -613        # Debug
    -614        verbose: bool = False,
    -615    ):
    -616        """Function to stop process running under pipewire executed by
    -617        python controller and with default process name of `pw-cat`, `pw-play` or `pw-record`.
    -618
    -619        Args:
    -620            mode (`str`) : string to kill process under `pw-cat`, `pw-play` or `pw-record`.
    -621
    -622        Returns:
    -623            - stdoutdict (`dict`) : a dictionary with keys of `mode`.
    -624
    -625        Example with pipewire:
    -626            pw-cat process
    -627        """
    +535    def playback(
    +536        self,
    +537        audio_filename: str = "myplayback.wav",
    +538        # Debug
    +539        verbose: bool = False,
    +540    ):
    +541        """Execute pipewire command to play an audio file with the following
    +542        command:
    +543
    +544        ```bash
    +545        #!/bin/bash
    +546        pw-cat --playback {audio_filename} + {configs}
    +547        # configs are a concatenated params
    +548        ```
    +549
    +550        Args:
    +551            audio_filename (`str`): Path of the file to be played. *default='myplayback.wav'
    +552            verbose (`bool`): True enable debug logs. *default=False
    +553
    +554        Returns:
    +555            - stdout (`str`): Shell response to the command in stdout format
    +556            - stderr (`str`): Shell response response to the command in stderr format
    +557        """
    +558        warnings.warn("The name of the function may change on future releases", DeprecationWarning)
    +559
    +560        mycommand = ["pw-cat", "--playback", audio_filename] + _generate_command_by_dict(
    +561            mydict=self._pipewire_configs, verbose=verbose
    +562        )
    +563
    +564        if verbose:
    +565            print(f"[mycommand]{mycommand}")
    +566
    +567        stdout, stderr = _execute_shell_command(command=mycommand, timeout=-1, verbose=verbose)
    +568        return stdout, stderr
    +569
    +570    def record(
    +571        self,
    +572        audio_filename: str = "myplayback.wav",
    +573        timeout_seconds=5,
    +574        # Debug
    +575        verbose: bool = False,
    +576    ):
    +577        """Execute pipewire command to record an audio file, with a timeout of 5
    +578        seconds with the following code and exiting the shell when tiomeout is over.
    +579
    +580        ```bash
    +581        #!/bin/bash
    +582        pw-cat --record {audio_filename}
    +583        # timeout is managed by python3 (when signal CTRL+C is sended)
    +584        ```
    +585
    +586        Args:
    +587            audio_filename (`str`): Path of the file to be played. *default='myplayback.wav'
    +588            verbose (`bool`): True enable debug logs. *default=False
    +589
    +590        Returns:
    +591            - stdout (`str`): Shell response to the command in stdout format
    +592            - stderr (`str`): Shell response response to the command in stderr format
    +593        """
    +594        warnings.warn("The name of the function may change on future releases", DeprecationWarning)
    +595
    +596        mycommand = ["pw-cat", "--record", audio_filename] + _generate_command_by_dict(
    +597            mydict=self._pipewire_configs, verbose=verbose
    +598        )
    +599
    +600        if verbose:
    +601            print(f"[mycommand]{mycommand}")
    +602
    +603        stdout, stderr = _execute_shell_command(
    +604            command=mycommand, timeout=timeout_seconds, verbose=verbose
    +605        )
    +606        return stdout, stderr
    +607
    +608    def clear_devices(
    +609        self,
    +610        mode: str = "all",  # ['all','playback','record']
    +611        # Debug
    +612        verbose: bool = False,
    +613    ):
    +614        """Function to stop process running under pipewire executed by
    +615        python controller and with default process name of `pw-cat`, `pw-play` or `pw-record`.
    +616
    +617        Args:
    +618            mode (`str`) : string to kill process under `pw-cat`, `pw-play` or `pw-record`.
    +619
    +620        Returns:
    +621            - stdoutdict (`dict`) : a dictionary with keys of `mode`.
    +622
    +623        Example with pipewire:
    +624            pw-cat process
    +625        """
    +626
    +627        mycommand = self._kill_pipewire[mode]
     628
    -629        mycommand = self._kill_pipewire[mode]
    -630
    -631        if verbose:
    -632            print(f"[mycommands]{mycommand}")
    +629        if verbose:
    +630            print(f"[mycommands]{mycommand}")
    +631
    +632        stdout, _ = _execute_shell_command(command=mycommand, verbose=verbose)
     633
    -634        stdout, _ = _execute_shell_command(command=mycommand, verbose=verbose)
    -635
    -636        return {mode: stdout}
    +634        return {mode: stdout}
     
    @@ -1364,49 +1362,49 @@

    -
     88    def __init__(
    - 89        self,
    - 90        # Debug
    - 91        verbose: bool = False,
    - 92    ):
    - 93        """This constructor load default configs from OS executing
    - 94        the following pipewire command
    - 95
    - 96        ```bash
    - 97        #!/bin/bash
    - 98        # Get defaults from output of:
    - 99        pw-cat -h
    -100        ```
    -101        """
    -102        # LOAD ALL DEFAULT PARAMETERS
    +            
     86    def __init__(
    + 87        self,
    + 88        # Debug
    + 89        verbose: bool = False,
    + 90    ):
    + 91        """This constructor load default configs from OS executing
    + 92        the following pipewire command
    + 93
    + 94        ```bash
    + 95        #!/bin/bash
    + 96        # Get defaults from output of:
    + 97        pw-cat -h
    + 98        ```
    + 99        """
    +100        # LOAD ALL DEFAULT PARAMETERS
    +101
    +102        mycommand = ["pw-cat", "-h"]
     103
    -104        mycommand = ["pw-cat", "-h"]
    -105
    -106        # get default parameters with help
    -107        stdout, _ = _execute_shell_command(command=mycommand, verbose=verbose)  # stderr
    -108        # convert stdout to dictionary
    -109        dict_default_values = _get_dict_from_stdout(stdout=str(stdout.decode()), verbose=verbose)
    -110
    -111        if verbose:
    -112            print(self._pipewire_configs)
    -113
    -114        # Save default system configs to our json
    -115        self._pipewire_configs.update(
    -116            ([(key, dict_default_values[key]) for key in dict_default_values])
    -117        )
    -118
    -119        if verbose:
    -120            print(self._pipewire_configs)
    -121
    -122        # Delete keys with None values
    -123        self._pipewire_configs = _drop_keys_with_none_values(self._pipewire_configs)
    -124
    -125        if verbose:
    -126            print(self._pipewire_configs)
    -127
    -128        # Load values of list targets
    -129        self.load_list_targets(mode="playback", verbose=verbose)
    -130        self.load_list_targets(mode="record", verbose=verbose)
    +104        # get default parameters with help
    +105        stdout, _ = _execute_shell_command(command=mycommand, verbose=verbose)  # stderr
    +106        # convert stdout to dictionary
    +107        dict_default_values = _get_dict_from_stdout(stdout=str(stdout.decode()), verbose=verbose)
    +108
    +109        if verbose:
    +110            print(self._pipewire_configs)
    +111
    +112        # Save default system configs to our json
    +113        self._pipewire_configs.update(
    +114            ([(key, dict_default_values[key]) for key in dict_default_values])
    +115        )
    +116
    +117        if verbose:
    +118            print(self._pipewire_configs)
    +119
    +120        # Delete keys with None values
    +121        self._pipewire_configs = _drop_keys_with_none_values(self._pipewire_configs)
    +122
    +123        if verbose:
    +124            print(self._pipewire_configs)
    +125
    +126        # Load values of list targets
    +127        self.load_list_targets(mode="playback", verbose=verbose)
    +128        self.load_list_targets(mode="record", verbose=verbose)
     
    @@ -1416,7 +1414,7 @@

    #!/bin/bash
     # Get defaults from output of:
    -pw-cat -h
    +pw-cat -h
     

    @@ -1434,37 +1432,37 @@

    -
    145    def get_version(
    -146        self,
    -147        # Debug
    -148        verbose: bool = False,
    -149    ):
    -150        """Get version of pipewire installed on OS by executing the following
    -151        code:
    -152
    -153        ```bash
    -154        #!/bin/bash
    -155        pw-cli --version
    -156        ```
    -157
    -158        Args:
    -159            verbose (bool) : True enable debug logs. *default=False
    -160
    -161        Returns:
    -162            - versions (list) : Versions of pipewire compiled
    -163        """
    +            
    143    def get_version(
    +144        self,
    +145        # Debug
    +146        verbose: bool = False,
    +147    ):
    +148        """Get version of pipewire installed on OS by executing the following
    +149        code:
    +150
    +151        ```bash
    +152        #!/bin/bash
    +153        pw-cli --version
    +154        ```
    +155
    +156        Args:
    +157            verbose (bool) : True enable debug logs. *default=False
    +158
    +159        Returns:
    +160            - versions (list) : Versions of pipewire compiled
    +161        """
    +162
    +163        mycommand = ["pw-cli", "--version"]
     164
    -165        mycommand = ["pw-cli", "--version"]
    -166
    -167        if verbose:
    -168            print(f"[mycommand]{mycommand}")
    -169
    -170        stdout, _ = _execute_shell_command(command=mycommand, timeout=-1, verbose=verbose)
    -171        versions = stdout.decode().split("\n")[1:]
    +165        if verbose:
    +166            print(f"[mycommand]{mycommand}")
    +167
    +168        stdout, _ = _execute_shell_command(command=mycommand, timeout=-1, verbose=verbose)
    +169        versions = stdout.decode().split("\n")[1:]
    +170
    +171        self._pipewire_cli["--version"] = versions
     172
    -173        self._pipewire_cli["--version"] = versions
    -174
    -175        return versions
    +173        return versions
     
    @@ -1473,7 +1471,7 @@

    #!/bin/bash
    -pw-cli --version
    +pw-cli --version
     
    @@ -1505,55 +1503,55 @@

    Returns:
    -
    177    def verbose(
    -178        self,
    -179        status: bool = True,
    -180    ):
    -181        """Get full log of pipewire stream status with the command `pw-cat`
    +            
    175    def verbose(
    +176        self,
    +177        status: bool = True,
    +178    ):
    +179        """Get full log of pipewire stream status with the command `pw-cat`
    +180
    +181        An example of pw-cli usage is the code below:
     182
    -183        An example of pw-cli usage is the code below:
    -184
    -185        ```bash
    -186        #!/bin/bash
    -187        # For example
    -188        pw-cat --playback beers.wav --verbose
    -189        ```
    +183        ```bash
    +184        #!/bin/bash
    +185        # For example
    +186        pw-cat --playback beers.wav --verbose
    +187        ```
    +188
    +189        that will generate an output like this:
     190
    -191        that will generate an output like this:
    -192
    -193        ```bash
    -194        opened file "beers.wav" format 00010002 channels:2 rate:44100
    -195        using default channel map: FL,FR
    -196        rate=44100 channels=2 fmt=s16 samplesize=2 stride=4 latency=4410 (0.100s)
    -197        connecting playback stream; target_id=4294967295
    -198        stream state changed unconnected -> connecting
    -199        stream param change: id=2
    -200        stream properties:
    -201            media.type = "Audio"
    -202            ...
    -203        now=0 rate=0/0 ticks=0 delay=0 queued=0
    -204        remote 0 is named "pipewire-0"
    -205        core done
    -206        stream state changed connecting -> paused
    -207        stream param change: id=2
    -208        ...
    -209        stream param change: id=15
    -210        stream param change: id=15
    -211        now=13465394419270 rate=1/48000 ticks=35840 delay=512 queued=0
    -212        now=13466525228363 rate=1/48000 ticks=90112 delay=512 queued=0
    -213        ...
    -214        stream drained
    -215        stream state changed streaming -> paused
    +191        ```bash
    +192        opened file "beers.wav" format 00010002 channels:2 rate:44100
    +193        using default channel map: FL,FR
    +194        rate=44100 channels=2 fmt=s16 samplesize=2 stride=4 latency=4410 (0.100s)
    +195        connecting playback stream; target_id=4294967295
    +196        stream state changed unconnected -> connecting
    +197        stream param change: id=2
    +198        stream properties:
    +199            media.type = "Audio"
    +200            ...
    +201        now=0 rate=0/0 ticks=0 delay=0 queued=0
    +202        remote 0 is named "pipewire-0"
    +203        core done
    +204        stream state changed connecting -> paused
    +205        stream param change: id=2
    +206        ...
    +207        stream param change: id=15
    +208        stream param change: id=15
    +209        now=13465394419270 rate=1/48000 ticks=35840 delay=512 queued=0
    +210        now=13466525228363 rate=1/48000 ticks=90112 delay=512 queued=0
    +211        ...
    +212        stream drained
    +213        stream state changed streaming -> paused
    +214        stream param change: id=4
    +215        stream state changed paused -> unconnected
     216        stream param change: id=4
    -217        stream state changed paused -> unconnected
    -218        stream param change: id=4
    -219        ```
    -220        """
    -221
    -222        if status:
    -223            self._pipewire_configs["--verbose"] = "    "
    -224        else:
    -225            pass
    +217        ```
    +218        """
    +219
    +220        if status:
    +221            self._pipewire_configs["--verbose"] = "    "
    +222        else:
    +223            pass
     
    @@ -1564,38 +1562,38 @@
    Returns:
    #!/bin/bash
     # For example
    -pw-cat --playback beers.wav --verbose
    +pw-cat --playback beers.wav --verbose
     

    that will generate an output like this:

    -
    opened file "beers.wav" format 00010002 channels:2 rate:44100
    -using default channel map: FL,FR
    -rate=44100 channels=2 fmt=s16 samplesize=2 stride=4 latency=4410 (0.100s)
    -connecting playback stream; target_id=4294967295
    -stream state changed unconnected -> connecting
    -stream param change: id=2
    -stream properties:
    -    media.type = "Audio"
    -    ...
    -now=0 rate=0/0 ticks=0 delay=0 queued=0
    -remote 0 is named "pipewire-0"
    -core done
    -stream state changed connecting -> paused
    -stream param change: id=2
    +
    opened file "beers.wav" format 00010002 channels:2 rate:44100
    +using default channel map: FL,FR
    +rate=44100 channels=2 fmt=s16 samplesize=2 stride=4 latency=4410 (0.100s)
    +connecting playback stream; target_id=4294967295
    +stream state changed unconnected -> connecting
    +stream param change: id=2
    +stream properties:
    +    media.type = "Audio"
    +    ...
    +now=0 rate=0/0 ticks=0 delay=0 queued=0
    +remote 0 is named "pipewire-0"
    +core done
    +stream state changed connecting -> paused
    +stream param change: id=2
     ...
    -stream param change: id=15
    -stream param change: id=15
    -now=13465394419270 rate=1/48000 ticks=35840 delay=512 queued=0
    -now=13466525228363 rate=1/48000 ticks=90112 delay=512 queued=0
    +stream param change: id=15
    +stream param change: id=15
    +now=13465394419270 rate=1/48000 ticks=35840 delay=512 queued=0
    +now=13466525228363 rate=1/48000 ticks=90112 delay=512 queued=0
     ...
    -stream drained
    -stream state changed streaming -> paused
    -stream param change: id=4
    -stream state changed paused -> unconnected
    -stream param change: id=4
    +stream drained
    +stream state changed streaming -> paused
    +stream param change: id=4
    +stream state changed paused -> unconnected
    +stream param change: id=4
     
    @@ -1613,20 +1611,20 @@
    Returns:
    -
    227    def get_config(self):
    -228        """Return config dictionary with default or setup variables, remember that
    -229        this object changes only on python-side. Is not updated on real time,
    -230        For real-time, please create and destroy the class.
    -231
    -232        Args:
    -233            Nothing
    -234
    -235        Returns:
    -236            - _pipewire_configs (`dict`) : dictionary with config values
    +            
    225    def get_config(self):
    +226        """Return config dictionary with default or setup variables, remember that
    +227        this object changes only on python-side. Is not updated on real time,
    +228        For real-time, please create and destroy the class.
    +229
    +230        Args:
    +231            Nothing
    +232
    +233        Returns:
    +234            - _pipewire_configs (`dict`) : dictionary with config values
    +235
    +236        """
     237
    -238        """
    -239
    -240        return self._pipewire_configs
    +238        return self._pipewire_configs
     
    @@ -1662,176 +1660,176 @@
    Returns:
    -
    242    def set_config(
    -243        self,
    -244        # configs
    -245        media_type=None,
    -246        media_category=None,
    -247        media_role=None,
    -248        target=None,
    -249        latency=None,
    -250        rate=None,
    -251        channels=None,
    -252        channels_map=None,
    -253        _format=None,
    -254        volume=None,
    -255        quality=None,
    -256        # Debug
    -257        verbose=False,
    -258    ):
    -259        """Method that get args as variables and set them
    -260        to the `json` parameter of the class `_pipewire_configs`,
    -261        then you can use in other method, such as `playback(...)` or
    -262        `record(...)`. This method verifies values to avoid wrong
    -263        settings.
    -264
    -265        Args:
    -266            media_type : Set media type
    -267            media_category : Set media category
    -268            media_role : Set media role
    -269            target : Set node target
    -270            latency : Set node latency *example=100ms
    -271            rate : Set sample rate [8000,11025,16000,22050,44100,48000,88200,96000,176400,192000,352800,384000]
    -272            channels : Numbers of channels [1,2]
    -273            channels_map : ["stereo", "surround-51", "FL,FR", ...]
    -274            _format : ["u8", "s8", "s16", "s32", "f32", "f64"]
    -275            volume : Stream volume [0.000, 1.000]
    -276            quality : Resampler quality [0, 15]
    -277            verbose (`bool`): True enable debug logs. *default=False
    -278
    -279        Returns:
    -280            - Nothing
    -281
    -282        More:
    -283            Check all links listed at the beginning of this page
    -284        """  # 1 - media_type
    -285        if media_type:
    -286            self._pipewire_configs["--media-type"] = str(media_type)
    -287        elif media_type is None:
    -288            pass
    -289        else:
    -290            raise ValueError(
    -291                f"{MESSAGES_ERROR['ValueError']}[media_type='{media_type}'] EMPTY VALUE"
    -292            )
    -293        # 2 - media_category
    -294        if media_category:
    -295            self._pipewire_configs["--media-category"] = str(media_category)
    -296        elif media_category is None:
    -297            pass
    -298        else:
    -299            raise ValueError(
    -300                f"{MESSAGES_ERROR['ValueError']}[media_category='{media_category}'] EMPTY VALUE"
    -301            )
    -302        # 3 - media_role
    -303        if media_role:
    -304            self._pipewire_configs["--media-role"] = str(media_role)
    -305        elif media_role is None:
    -306            pass
    -307        else:
    -308            raise ValueError(
    -309                f"{MESSAGES_ERROR['ValueError']}[media_role='{media_role}'] EMPTY VALUE"
    -310            )
    -311        # 4 - target
    -312        if target:
    -313            self._pipewire_configs["--target"] = str(target)
    -314        elif target is None:
    -315            pass
    -316        else:
    -317            raise ValueError(f"{MESSAGES_ERROR['ValueError']}[target='{target}'] EMPTY VALUE")
    -318        # 5 - latency
    -319        if latency:
    -320            if any(chr.isdigit() for chr in latency):  # Contain numbers
    -321                self._pipewire_configs["--latency"] = str(latency)
    -322            else:
    -323                raise ValueError(
    -324                    f"{MESSAGES_ERROR['ValueError']}[latency='{latency}'] NO NUMBER IN VARIABLE"
    -325                )
    -326        elif latency is None:
    -327            pass
    -328        else:
    -329            raise ValueError(f"{MESSAGES_ERROR['ValueError']}[latency='{latency}'] EMPTY VALUE")
    -330        # 6 - rate
    -331        if rate:
    -332            if rate in RECOMMENDED_RATES:
    -333                self._pipewire_configs["--rate"] = str(rate)
    -334            else:
    -335                raise ValueError(
    -336                    f"{MESSAGES_ERROR['ValueError']}[rate='{rate}']\
    -337                         VALUE NOT IN RECOMMENDED LIST \n{RECOMMENDED_RATES}"
    -338                )
    -339        elif rate is None:
    -340            pass
    -341        else:
    -342            raise ValueError(f"{MESSAGES_ERROR['ValueError']}[rate='{rate}'] EMPTY VALUE")
    -343        # 7 - channels
    -344        if channels:
    -345            if channels in [1, 2]:  # values
    -346                self._pipewire_configs["--channels"] = str(channels)
    -347            else:
    -348                raise ValueError(
    -349                    f"{MESSAGES_ERROR['ValueError']}[channels='{channels}']\
    -350                         WRONG VALUE\n ONLY 1 or 2."
    -351                )
    -352        elif channels is None:
    -353            pass
    -354        else:
    -355            raise ValueError(f"{MESSAGES_ERROR['ValueError']}[channels='{channels}'] EMPTY VALUE")
    -356        # 8 - channels-map
    -357        if channels_map:
    -358            self._pipewire_configs["--channels-map"] = str(channels_map)
    -359        elif channels_map is None:
    -360            pass
    -361        else:
    -362            raise ValueError(
    -363                f"{MESSAGES_ERROR['ValueError']}[channels_map='{channels_map}'] EMPTY VALUE"
    -364            )
    -365        # 9 - format
    -366        if _format:
    -367            if _format in RECOMMENDED_FORMATS:
    -368                self._pipewire_configs["--format"] = str(_format)
    -369            else:
    -370                raise ValueError(
    -371                    f"{MESSAGES_ERROR['ValueError']}[_format='{_format}']\
    -372                         VALUE NOT IN RECOMMENDED LIST \n{RECOMMENDED_FORMATS}"
    -373                )
    -374        elif _format is None:
    -375            pass
    -376        else:
    -377            raise ValueError(f"{MESSAGES_ERROR['ValueError']}[_format='{_format}'] EMPTY VALUE")
    -378        # 10 - volume
    -379        if volume:
    -380            if 0.0 <= volume <= 1.0:
    -381                self._pipewire_configs["--volume"] = str(volume)
    -382            else:
    -383                raise ValueError(
    -384                    f"{MESSAGES_ERROR['ValueError']}[volume='{volume}']\
    -385                         OUT OF RANGE \n [0.000, 1.000]"
    -386                )
    -387        elif volume is None:
    -388            pass
    -389        else:
    -390            raise ValueError(f"{MESSAGES_ERROR['ValueError']}[volume='{volume}'] EMPTY VALUE")
    -391        # 11 - quality
    -392        if quality:
    -393            if 0 <= quality <= 15:
    -394                self._pipewire_configs["--quality"] = str(quality)
    -395            else:
    -396                raise ValueError(
    -397                    f"{MESSAGES_ERROR['ValueError']}[quality='{quality}'] OUT OF RANGE \n [0, 15]"
    -398                )
    -399        elif quality is None:
    -400            pass
    -401        else:
    -402            raise ValueError(f"{MESSAGES_ERROR['ValueError']}[volume='{volume}'] EMPTY VALUE")
    -403
    -404        # 12 - verbose cli
    -405        if verbose:  # True
    -406            self._pipewire_configs["--verbose"] = "    "
    -407        else:
    -408            pass
    -409
    -410        if verbose:
    -411            print(self._pipewire_configs)
    +            
    240    def set_config(
    +241        self,
    +242        # configs
    +243        media_type=None,
    +244        media_category=None,
    +245        media_role=None,
    +246        target=None,
    +247        latency=None,
    +248        rate=None,
    +249        channels=None,
    +250        channels_map=None,
    +251        _format=None,
    +252        volume=None,
    +253        quality=None,
    +254        # Debug
    +255        verbose=False,
    +256    ):
    +257        """Method that get args as variables and set them
    +258        to the `json` parameter of the class `_pipewire_configs`,
    +259        then you can use in other method, such as `playback(...)` or
    +260        `record(...)`. This method verifies values to avoid wrong
    +261        settings.
    +262
    +263        Args:
    +264            media_type : Set media type
    +265            media_category : Set media category
    +266            media_role : Set media role
    +267            target : Set node target
    +268            latency : Set node latency *example=100ms
    +269            rate : Set sample rate [8000,11025,16000,22050,44100,48000,88200,96000,176400,192000,352800,384000]
    +270            channels : Numbers of channels [1,2]
    +271            channels_map : ["stereo", "surround-51", "FL,FR", ...]
    +272            _format : ["u8", "s8", "s16", "s32", "f32", "f64"]
    +273            volume : Stream volume [0.000, 1.000]
    +274            quality : Resampler quality [0, 15]
    +275            verbose (`bool`): True enable debug logs. *default=False
    +276
    +277        Returns:
    +278            - Nothing
    +279
    +280        More:
    +281            Check all links listed at the beginning of this page
    +282        """  # 1 - media_type
    +283        if media_type:
    +284            self._pipewire_configs["--media-type"] = str(media_type)
    +285        elif media_type is None:
    +286            pass
    +287        else:
    +288            raise ValueError(
    +289                f"{MESSAGES_ERROR['ValueError']}[media_type='{media_type}'] EMPTY VALUE"
    +290            )
    +291        # 2 - media_category
    +292        if media_category:
    +293            self._pipewire_configs["--media-category"] = str(media_category)
    +294        elif media_category is None:
    +295            pass
    +296        else:
    +297            raise ValueError(
    +298                f"{MESSAGES_ERROR['ValueError']}[media_category='{media_category}'] EMPTY VALUE"
    +299            )
    +300        # 3 - media_role
    +301        if media_role:
    +302            self._pipewire_configs["--media-role"] = str(media_role)
    +303        elif media_role is None:
    +304            pass
    +305        else:
    +306            raise ValueError(
    +307                f"{MESSAGES_ERROR['ValueError']}[media_role='{media_role}'] EMPTY VALUE"
    +308            )
    +309        # 4 - target
    +310        if target:
    +311            self._pipewire_configs["--target"] = str(target)
    +312        elif target is None:
    +313            pass
    +314        else:
    +315            raise ValueError(f"{MESSAGES_ERROR['ValueError']}[target='{target}'] EMPTY VALUE")
    +316        # 5 - latency
    +317        if latency:
    +318            if any(chr.isdigit() for chr in latency):  # Contain numbers
    +319                self._pipewire_configs["--latency"] = str(latency)
    +320            else:
    +321                raise ValueError(
    +322                    f"{MESSAGES_ERROR['ValueError']}[latency='{latency}'] NO NUMBER IN VARIABLE"
    +323                )
    +324        elif latency is None:
    +325            pass
    +326        else:
    +327            raise ValueError(f"{MESSAGES_ERROR['ValueError']}[latency='{latency}'] EMPTY VALUE")
    +328        # 6 - rate
    +329        if rate:
    +330            if rate in RECOMMENDED_RATES:
    +331                self._pipewire_configs["--rate"] = str(rate)
    +332            else:
    +333                raise ValueError(
    +334                    f"{MESSAGES_ERROR['ValueError']}[rate='{rate}']\
    +335                         VALUE NOT IN RECOMMENDED LIST \n{RECOMMENDED_RATES}"
    +336                )
    +337        elif rate is None:
    +338            pass
    +339        else:
    +340            raise ValueError(f"{MESSAGES_ERROR['ValueError']}[rate='{rate}'] EMPTY VALUE")
    +341        # 7 - channels
    +342        if channels:
    +343            if channels in [1, 2]:  # values
    +344                self._pipewire_configs["--channels"] = str(channels)
    +345            else:
    +346                raise ValueError(
    +347                    f"{MESSAGES_ERROR['ValueError']}[channels='{channels}']\
    +348                         WRONG VALUE\n ONLY 1 or 2."
    +349                )
    +350        elif channels is None:
    +351            pass
    +352        else:
    +353            raise ValueError(f"{MESSAGES_ERROR['ValueError']}[channels='{channels}'] EMPTY VALUE")
    +354        # 8 - channels-map
    +355        if channels_map:
    +356            self._pipewire_configs["--channels-map"] = str(channels_map)
    +357        elif channels_map is None:
    +358            pass
    +359        else:
    +360            raise ValueError(
    +361                f"{MESSAGES_ERROR['ValueError']}[channels_map='{channels_map}'] EMPTY VALUE"
    +362            )
    +363        # 9 - format
    +364        if _format:
    +365            if _format in RECOMMENDED_FORMATS:
    +366                self._pipewire_configs["--format"] = str(_format)
    +367            else:
    +368                raise ValueError(
    +369                    f"{MESSAGES_ERROR['ValueError']}[_format='{_format}']\
    +370                         VALUE NOT IN RECOMMENDED LIST \n{RECOMMENDED_FORMATS}"
    +371                )
    +372        elif _format is None:
    +373            pass
    +374        else:
    +375            raise ValueError(f"{MESSAGES_ERROR['ValueError']}[_format='{_format}'] EMPTY VALUE")
    +376        # 10 - volume
    +377        if volume:
    +378            if 0.0 <= volume <= 1.0:
    +379                self._pipewire_configs["--volume"] = str(volume)
    +380            else:
    +381                raise ValueError(
    +382                    f"{MESSAGES_ERROR['ValueError']}[volume='{volume}']\
    +383                         OUT OF RANGE \n [0.000, 1.000]"
    +384                )
    +385        elif volume is None:
    +386            pass
    +387        else:
    +388            raise ValueError(f"{MESSAGES_ERROR['ValueError']}[volume='{volume}'] EMPTY VALUE")
    +389        # 11 - quality
    +390        if quality:
    +391            if 0 <= quality <= 15:
    +392                self._pipewire_configs["--quality"] = str(quality)
    +393            else:
    +394                raise ValueError(
    +395                    f"{MESSAGES_ERROR['ValueError']}[quality='{quality}'] OUT OF RANGE \n [0, 15]"
    +396                )
    +397        elif quality is None:
    +398            pass
    +399        else:
    +400            raise ValueError(f"{MESSAGES_ERROR['ValueError']}[volume='{volume}'] EMPTY VALUE")
    +401
    +402        # 12 - verbose cli
    +403        if verbose:  # True
    +404            self._pipewire_configs["--verbose"] = "    "
    +405        else:
    +406            pass
    +407
    +408        if verbose:
    +409            print(self._pipewire_configs)
     
    @@ -1886,33 +1884,33 @@
    More:
    -
    413    def load_list_targets(
    -414        self,
    -415        mode,  # playback or record
    -416        # Debug,
    -417        verbose: bool = False,
    -418    ):
    -419        """Returns a list of targets to playback or record. Then you can use
    -420        the output to select a device to playback or record.
    -421        """
    -422
    -423        if mode == "playback":
    -424            mycommand = ["pw-cat", "--playback", "--list-targets"]
    -425            stdout, _ = _execute_shell_command(command=mycommand, timeout=-1, verbose=verbose)
    -426            self._pipewire_list_targets["list_playback"] = _generate_dict_list_targets(
    -427                longstring=stdout.decode(), verbose=verbose
    -428            )
    -429        elif mode == "record":
    -430            mycommand = ["pw-cat", "--record", "--list-targets"]
    -431            stdout, _ = _execute_shell_command(command=mycommand, timeout=-1, verbose=verbose)
    -432            self._pipewire_list_targets["list_record"] = _generate_dict_list_targets(
    -433                longstring=stdout.decode(), verbose=verbose
    -434            )
    -435        else:
    -436            raise AttributeError(MESSAGES_ERROR["ValueError"])
    -437
    -438        if verbose:
    -439            print(f"[mycommand]{mycommand}")
    +            
    411    def load_list_targets(
    +412        self,
    +413        mode,  # playback or record
    +414        # Debug,
    +415        verbose: bool = False,
    +416    ):
    +417        """Returns a list of targets to playback or record. Then you can use
    +418        the output to select a device to playback or record.
    +419        """
    +420
    +421        if mode == "playback":
    +422            mycommand = ["pw-cat", "--playback", "--list-targets"]
    +423            stdout, _ = _execute_shell_command(command=mycommand, timeout=-1, verbose=verbose)
    +424            self._pipewire_list_targets["list_playback"] = _generate_dict_list_targets(
    +425                longstring=stdout.decode(), verbose=verbose
    +426            )
    +427        elif mode == "record":
    +428            mycommand = ["pw-cat", "--record", "--list-targets"]
    +429            stdout, _ = _execute_shell_command(command=mycommand, timeout=-1, verbose=verbose)
    +430            self._pipewire_list_targets["list_record"] = _generate_dict_list_targets(
    +431                longstring=stdout.decode(), verbose=verbose
    +432            )
    +433        else:
    +434            raise AttributeError(MESSAGES_ERROR["ValueError"])
    +435
    +436        if verbose:
    +437            print(f"[mycommand]{mycommand}")
     
    @@ -1933,57 +1931,57 @@
    More:
    -
    441    def get_list_targets(
    -442        self,
    -443        # Debug,
    -444        verbose: bool = False,
    -445    ):
    -446        """Returns a list of targets to playback or record. Then you can use
    -447        the output to select a device to playback or record.
    -448
    -449        Returns:
    -450            - `_pipewire_list_targets`
    -451
    -452        Examples:
    -453        ```python
    -454        >>> Controller().get_list_targets()
    -455        {
    -456        "list_playback": {
    -457            "86": {
    -458            "description": "Starship/Matisse HD Audio Controller Pro",
    -459            "prior": "936"
    -460            },
    -461            "_list_nodes": [
    -462            "86"
    -463            ],
    -464            "_node_default": [
    -465            "86"
    -466            ],
    -467            "_alsa_node": [
    -468            "alsa_output.pci-0000_0a_00.4.pro-output-0"
    -469            ]
    -470        },
    -471        "list_record": {
    -472            "86": {
    -473            "description": "Starship/Matisse HD Audio Controller Pro",
    -474            "prior": "936"
    -475            },
    -476            "_list_nodes": [
    -477            "86"
    -478            ],
    -479            "_node_default": [
    -480            "86"
    -481            ],
    -482            "_alsa_node": [
    -483            "alsa_output.pci-0000_0a_00.4.pro-output-0"
    -484            ]
    -485        }
    -486        }
    -487        ```
    -488        """
    -489        if verbose:
    -490            print(self._pipewire_list_targets)
    -491        return self._pipewire_list_targets
    +            
    439    def get_list_targets(
    +440        self,
    +441        # Debug,
    +442        verbose: bool = False,
    +443    ):
    +444        """Returns a list of targets to playback or record. Then you can use
    +445        the output to select a device to playback or record.
    +446
    +447        Returns:
    +448            - `_pipewire_list_targets`
    +449
    +450        Examples:
    +451        ```python
    +452        >>> Controller().get_list_targets()
    +453        {
    +454        "list_playback": {
    +455            "86": {
    +456            "description": "Starship/Matisse HD Audio Controller Pro",
    +457            "prior": "936"
    +458            },
    +459            "_list_nodes": [
    +460            "86"
    +461            ],
    +462            "_node_default": [
    +463            "86"
    +464            ],
    +465            "_alsa_node": [
    +466            "alsa_output.pci-0000_0a_00.4.pro-output-0"
    +467            ]
    +468        },
    +469        "list_record": {
    +470            "86": {
    +471            "description": "Starship/Matisse HD Audio Controller Pro",
    +472            "prior": "936"
    +473            },
    +474            "_list_nodes": [
    +475            "86"
    +476            ],
    +477            "_node_default": [
    +478            "86"
    +479            ],
    +480            "_alsa_node": [
    +481            "alsa_output.pci-0000_0a_00.4.pro-output-0"
    +482            ]
    +483        }
    +484        }
    +485        ```
    +486        """
    +487        if verbose:
    +488            print(self._pipewire_list_targets)
    +489        return self._pipewire_list_targets
     
    @@ -2051,49 +2049,49 @@
    Returns:
    -
    493    def get_list_interfaces(
    -494        self,
    -495        filtered_by_type: str = True,
    -496        type_interfaces: str = "Client",
    -497        # Debug
    -498        verbose: bool = False,
    -499    ):
    -500        """Returns a list of applications currently using pipewire on Client.
    -501        An example of pw-cli usage is the code below:
    -502
    -503        ```bash
    -504        #!/bin/bash
    -505        pw-cli ls Client
    -506        ```
    -507        Args:
    -508            filtered_by_type : If False, returns all. If not, returns a fitered dict
    -509            type_interfaces : Set type of Interface ["Client","Link","Node","Factory","Module","Metadata","Endpoint","Session","Endpoint Stream","EndpointLink","Port"]
    -510
    -511        Returns:
    -512            - dict_interfaces_filtered: dictionary with list of interfaces matching conditions
    -513
    -514        Examples:
    -515        ```python
    -516        >>> Controller().get_list_interfaces()
    -517
    -518        ```
    -519        """
    -520        mycommand = ["pw-cli", "info", "all"]
    -521
    -522        # if verbose:
    -523        #     print(f"[mycommand]{mycommand}")
    -524
    -525        stdout, _ = _execute_shell_command(command=mycommand, timeout=-1, verbose=verbose)
    -526        dict_interfaces = _generate_dict_interfaces(longstring=stdout.decode(), verbose=verbose)
    -527
    -528        if filtered_by_type:
    -529            dict_interfaces_filtered = _filter_by_type(
    -530                dict_interfaces=dict_interfaces, type_interfaces=type_interfaces
    -531            )
    -532        else:
    -533            dict_interfaces_filtered = dict_interfaces
    -534
    -535        return dict_interfaces_filtered
    +            
    491    def get_list_interfaces(
    +492        self,
    +493        filtered_by_type: str = True,
    +494        type_interfaces: str = "Client",
    +495        # Debug
    +496        verbose: bool = False,
    +497    ):
    +498        """Returns a list of applications currently using pipewire on Client.
    +499        An example of pw-cli usage is the code below:
    +500
    +501        ```bash
    +502        #!/bin/bash
    +503        pw-cli ls Client
    +504        ```
    +505        Args:
    +506            filtered_by_type : If False, returns all. If not, returns a fitered dict
    +507            type_interfaces : Set type of Interface ["Client","Link","Node","Factory","Module","Metadata","Endpoint","Session","Endpoint Stream","EndpointLink","Port"]
    +508
    +509        Returns:
    +510            - dict_interfaces_filtered: dictionary with list of interfaces matching conditions
    +511
    +512        Examples:
    +513        ```python
    +514        >>> Controller().get_list_interfaces()
    +515
    +516        ```
    +517        """
    +518        mycommand = ["pw-cli", "info", "all"]
    +519
    +520        # if verbose:
    +521        #     print(f"[mycommand]{mycommand}")
    +522
    +523        stdout, _ = _execute_shell_command(command=mycommand, timeout=-1, verbose=verbose)
    +524        dict_interfaces = _generate_dict_interfaces(longstring=stdout.decode(), verbose=verbose)
    +525
    +526        if filtered_by_type:
    +527            dict_interfaces_filtered = _filter_by_type(
    +528                dict_interfaces=dict_interfaces, type_interfaces=type_interfaces
    +529            )
    +530        else:
    +531            dict_interfaces_filtered = dict_interfaces
    +532
    +533        return dict_interfaces_filtered
     
    @@ -2102,7 +2100,7 @@
    Returns:
    #!/bin/bash
    -pw-cli ls Client
    +pw-cli ls Client
     
    @@ -2142,40 +2140,40 @@
    Returns:
    -
    537    def playback(
    -538        self,
    -539        audio_filename: str = "myplayback.wav",
    -540        # Debug
    -541        verbose: bool = False,
    -542    ):
    -543        """Execute pipewire command to play an audio file with the following
    -544        command:
    -545
    -546        ```bash
    -547        #!/bin/bash
    -548        pw-cat --playback {audio_filename} + {configs}
    -549        # configs are a concatenated params
    -550        ```
    -551
    -552        Args:
    -553            audio_filename (`str`): Path of the file to be played. *default='myplayback.wav'
    -554            verbose (`bool`): True enable debug logs. *default=False
    -555
    -556        Returns:
    -557            - stdout (`str`): Shell response to the command in stdout format
    -558            - stderr (`str`): Shell response response to the command in stderr format
    -559        """
    -560        warnings.warn("The name of the function may change on future releases", DeprecationWarning)
    -561
    -562        mycommand = ["pw-cat", "--playback", audio_filename] + _generate_command_by_dict(
    -563            mydict=self._pipewire_configs, verbose=verbose
    -564        )
    -565
    -566        if verbose:
    -567            print(f"[mycommand]{mycommand}")
    -568
    -569        stdout, stderr = _execute_shell_command(command=mycommand, timeout=-1, verbose=verbose)
    -570        return stdout, stderr
    +            
    535    def playback(
    +536        self,
    +537        audio_filename: str = "myplayback.wav",
    +538        # Debug
    +539        verbose: bool = False,
    +540    ):
    +541        """Execute pipewire command to play an audio file with the following
    +542        command:
    +543
    +544        ```bash
    +545        #!/bin/bash
    +546        pw-cat --playback {audio_filename} + {configs}
    +547        # configs are a concatenated params
    +548        ```
    +549
    +550        Args:
    +551            audio_filename (`str`): Path of the file to be played. *default='myplayback.wav'
    +552            verbose (`bool`): True enable debug logs. *default=False
    +553
    +554        Returns:
    +555            - stdout (`str`): Shell response to the command in stdout format
    +556            - stderr (`str`): Shell response response to the command in stderr format
    +557        """
    +558        warnings.warn("The name of the function may change on future releases", DeprecationWarning)
    +559
    +560        mycommand = ["pw-cat", "--playback", audio_filename] + _generate_command_by_dict(
    +561            mydict=self._pipewire_configs, verbose=verbose
    +562        )
    +563
    +564        if verbose:
    +565            print(f"[mycommand]{mycommand}")
    +566
    +567        stdout, stderr = _execute_shell_command(command=mycommand, timeout=-1, verbose=verbose)
    +568        return stdout, stderr
     
    @@ -2184,7 +2182,7 @@
    Returns:
    #!/bin/bash
    -pw-cat --playback {audio_filename} + {configs}
    +pw-cat --playback {audio_filename} + {configs}
     # configs are a concatenated params
     
    @@ -2219,43 +2217,43 @@
    Returns:
    -
    572    def record(
    -573        self,
    -574        audio_filename: str = "myplayback.wav",
    -575        timeout_seconds=5,
    -576        # Debug
    -577        verbose: bool = False,
    -578    ):
    -579        """Execute pipewire command to record an audio file, with a timeout of 5
    -580        seconds with the following code and exiting the shell when tiomeout is over.
    -581
    -582        ```bash
    -583        #!/bin/bash
    -584        pw-cat --record {audio_filename}
    -585        # timeout is managed by python3 (when signal CTRL+C is sended)
    -586        ```
    -587
    -588        Args:
    -589            audio_filename (`str`): Path of the file to be played. *default='myplayback.wav'
    -590            verbose (`bool`): True enable debug logs. *default=False
    -591
    -592        Returns:
    -593            - stdout (`str`): Shell response to the command in stdout format
    -594            - stderr (`str`): Shell response response to the command in stderr format
    -595        """
    -596        warnings.warn("The name of the function may change on future releases", DeprecationWarning)
    -597
    -598        mycommand = ["pw-cat", "--record", audio_filename] + _generate_command_by_dict(
    -599            mydict=self._pipewire_configs, verbose=verbose
    -600        )
    -601
    -602        if verbose:
    -603            print(f"[mycommand]{mycommand}")
    -604
    -605        stdout, stderr = _execute_shell_command(
    -606            command=mycommand, timeout=timeout_seconds, verbose=verbose
    -607        )
    -608        return stdout, stderr
    +            
    570    def record(
    +571        self,
    +572        audio_filename: str = "myplayback.wav",
    +573        timeout_seconds=5,
    +574        # Debug
    +575        verbose: bool = False,
    +576    ):
    +577        """Execute pipewire command to record an audio file, with a timeout of 5
    +578        seconds with the following code and exiting the shell when tiomeout is over.
    +579
    +580        ```bash
    +581        #!/bin/bash
    +582        pw-cat --record {audio_filename}
    +583        # timeout is managed by python3 (when signal CTRL+C is sended)
    +584        ```
    +585
    +586        Args:
    +587            audio_filename (`str`): Path of the file to be played. *default='myplayback.wav'
    +588            verbose (`bool`): True enable debug logs. *default=False
    +589
    +590        Returns:
    +591            - stdout (`str`): Shell response to the command in stdout format
    +592            - stderr (`str`): Shell response response to the command in stderr format
    +593        """
    +594        warnings.warn("The name of the function may change on future releases", DeprecationWarning)
    +595
    +596        mycommand = ["pw-cat", "--record", audio_filename] + _generate_command_by_dict(
    +597            mydict=self._pipewire_configs, verbose=verbose
    +598        )
    +599
    +600        if verbose:
    +601            print(f"[mycommand]{mycommand}")
    +602
    +603        stdout, stderr = _execute_shell_command(
    +604            command=mycommand, timeout=timeout_seconds, verbose=verbose
    +605        )
    +606        return stdout, stderr
     
    @@ -2264,7 +2262,7 @@
    Returns:
    #!/bin/bash
    -pw-cat --record {audio_filename}
    +pw-cat --record {audio_filename}
     # timeout is managed by python3 (when signal CTRL+C is sended)
     
    @@ -2299,33 +2297,33 @@
    Returns:
    -
    610    def clear_devices(
    -611        self,
    -612        mode: str = "all",  # ['all','playback','record']
    -613        # Debug
    -614        verbose: bool = False,
    -615    ):
    -616        """Function to stop process running under pipewire executed by
    -617        python controller and with default process name of `pw-cat`, `pw-play` or `pw-record`.
    -618
    -619        Args:
    -620            mode (`str`) : string to kill process under `pw-cat`, `pw-play` or `pw-record`.
    -621
    -622        Returns:
    -623            - stdoutdict (`dict`) : a dictionary with keys of `mode`.
    -624
    -625        Example with pipewire:
    -626            pw-cat process
    -627        """
    +            
    608    def clear_devices(
    +609        self,
    +610        mode: str = "all",  # ['all','playback','record']
    +611        # Debug
    +612        verbose: bool = False,
    +613    ):
    +614        """Function to stop process running under pipewire executed by
    +615        python controller and with default process name of `pw-cat`, `pw-play` or `pw-record`.
    +616
    +617        Args:
    +618            mode (`str`) : string to kill process under `pw-cat`, `pw-play` or `pw-record`.
    +619
    +620        Returns:
    +621            - stdoutdict (`dict`) : a dictionary with keys of `mode`.
    +622
    +623        Example with pipewire:
    +624            pw-cat process
    +625        """
    +626
    +627        mycommand = self._kill_pipewire[mode]
     628
    -629        mycommand = self._kill_pipewire[mode]
    -630
    -631        if verbose:
    -632            print(f"[mycommands]{mycommand}")
    +629        if verbose:
    +630            print(f"[mycommands]{mycommand}")
    +631
    +632        stdout, _ = _execute_shell_command(command=mycommand, verbose=verbose)
     633
    -634        stdout, _ = _execute_shell_command(command=mycommand, verbose=verbose)
    -635
    -636        return {mode: stdout}
    +634        return {mode: stdout}