From 39079b38030135c1f25b466b887b3e584e84e3b1 Mon Sep 17 00:00:00 2001 From: Pablo Date: Sun, 15 May 2022 18:29:09 -0500 Subject: [PATCH 1/8] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 0412e02..79aaf26 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ JOIN OUR TELEGRAM SUPPORT: [![Telegram](https://img.shields.io/badge/Telegram-2CA5E0?style=for-the-badge&logo=telegram&logoColor=white)](https://t.me/pipewire_python) ## **ONLY AUDIO BY NOW [PR & FR WELCOME]** +## **STREAMING NOT SUPPORTED BY NOW**
From 0f70f12f4278e85c7c9a072285be6648f7d4c49a Mon Sep 17 00:00:00 2001 From: Pablo Date: Sun, 15 May 2022 18:29:26 -0500 Subject: [PATCH 2/8] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 79aaf26..b4bc5f0 100644 --- a/README.md +++ b/README.md @@ -14,8 +14,8 @@ JOIN OUR TELEGRAM SUPPORT: [![Telegram](https://img.shields.io/badge/Telegram-2CA5E0?style=for-the-badge&logo=telegram&logoColor=white)](https://t.me/pipewire_python) -## **ONLY AUDIO BY NOW [PR & FR WELCOME]** -## **STREAMING NOT SUPPORTED BY NOW** +**ONLY AUDIO BY NOW [PR & FR WELCOME]** +**STREAMING NOT SUPPORTED BY NOW**
From 563a4ea551c245c750c3f8e932f02252f4607033 Mon Sep 17 00:00:00 2001 From: Pablo Date: Sun, 15 May 2022 18:29:35 -0500 Subject: [PATCH 3/8] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b4bc5f0..f72925b 100644 --- a/README.md +++ b/README.md @@ -14,8 +14,8 @@ JOIN OUR TELEGRAM SUPPORT: [![Telegram](https://img.shields.io/badge/Telegram-2CA5E0?style=for-the-badge&logo=telegram&logoColor=white)](https://t.me/pipewire_python) -**ONLY AUDIO BY NOW [PR & FR WELCOME]** -**STREAMING NOT SUPPORTED BY NOW** +- **ONLY AUDIO BY NOW [PR & FR WELCOME]** +- **STREAMING NOT SUPPORTED BY NOW**
From a6832918857f9a310973a26ef214b0ff81ad63b1 Mon Sep 17 00:00:00 2001 From: pablodz Date: Sun, 15 May 2022 23:30:00 +0000 Subject: [PATCH 4/8] PDOC-Automatic documentation Signed-off-by: github-actions[bot] --- docs/html/pipewire_python.html | 177 +- docs/html/pipewire_python/_constants.html | 67 +- docs/html/pipewire_python/_utils.html | 609 ++-- docs/html/pipewire_python/controller.html | 3776 ++++++++++----------- 4 files changed, 2304 insertions(+), 2325 deletions(-) diff --git a/docs/html/pipewire_python.html b/docs/html/pipewire_python.html index 0dbc753..c914835 100644 --- a/docs/html/pipewire_python.html +++ b/docs/html/pipewire_python.html @@ -3,14 +3,14 @@ - + pipewire_python API documentation - - + +
-
+
Edit on GitHub

pipewire_python

@@ -113,89 +113,90 @@

Tutorial

-
- View Source -
"""
-## Description
+                        
+
+                        
+
+                        
 1"""
+ 2## Description
+ 3
+ 4[PIPEWIRE](https://pipewire.org/) provides a low-latency, graph based processing engine
+ 5on top of audio and video devices that can be used to
+ 6support the use cases currently handled by both pulseaudio
+ 7and JACK. PipeWire was designed with a powerful security model
+ 8that makes interacting with audio and video devices from 
+ 9containerized applications easy, with supporting Flatpak
+10applications being the primary goal. Alongside Wayland and
+11Flatpak we expect PipeWire to provide a core building block 
+12for the future of Linux application development.
+13
+14[pipewire_python](https://pypi.org/project/pipewire_python/) 
+15controlls `pipewire` via terminal, creating shell commands and executing them as required.
+16
+17🎹 There are two ways to manage the python package:
+18
+191. NO_ASYNC: this way works as expected with delay time between 
+20`pipewire_python` and the rest of your code.
+21
+222. ASYNC: [⚠️Not yet implemented] this way works delegating the task to record or to play
+23a song file in background. Works with threads.
+24
+253. MULTIPROCESS: [⚠️Not yet implemented] Works with processes.
+26
+27
+28📄 More information about `pipewire` and it's API's:
+29
+30- 🎵 Asyncio https://docs.python.org/3/library/asyncio-subprocess.html
+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 
+35
+36
+37##  Install via
+38```bash
+39
+40pip3 install pipewire_python # or pip
+41```
+42
+43## Tutorial
+44
+45
+46```python
+47from pipewire_python.controller import Controller
+48
+49# PLAYBACK: normal way
+50audio_controller = Controller()
+51audio_controller.set_config(rate=384000,
+52                            channels=2,
+53                            _format='f64',
+54                            volume=0.98,
+55                            quality=4,
+56                            # Debug
+57                            verbose=True)
+58audio_controller.playback(audio_filename='docs/beers.wav')
+59
+60# RECORD: normal way
+61audio_controller = Controller(verbose=True)
+62audio_controller.record(audio_filename='docs/5sec_record.wav',
+63                        timeout_seconds=5,
+64                        # Debug
+65                        verbose=True)
+66
+67```
+68"""
+69
+70__version__ = "0.1.1"
+71
+72import sys
+73
+74if sys.platform == "linux":
+75    # from pipewire_python.controller import *
+76    pass
+77else:
+78    raise NotImplementedError("By now, Pipewire only runs on linux.")
+
-[PIPEWIRE](https://pipewire.org/) provides a low-latency, graph based processing engine -on top of audio and video devices that can be used to -support the use cases currently handled by both pulseaudio -and JACK. PipeWire was designed with a powerful security model -that makes interacting with audio and video devices from -containerized applications easy, with supporting Flatpak -applications being the primary goal. Alongside Wayland and -Flatpak we expect PipeWire to provide a core building block -for the future of Linux application development. - -[pipewire_python](https://pypi.org/project/pipewire_python/) -controlls `pipewire` via terminal, creating shell commands and executing them as required. - -🎹 There are two ways to manage the python package: - -1. NO_ASYNC: this way works as expected with delay time between -`pipewire_python` and the rest of your code. - -2. ASYNC: [⚠️Not yet implemented] this way works delegating the task to record or to play -a song file in background. Works with threads. - -3. MULTIPROCESS: [⚠️Not yet implemented] Works with processes. - - -📄 More information about `pipewire` and it's API's: - -- 🎵 Asyncio https://docs.python.org/3/library/asyncio-subprocess.html -- 🎵 Pipewire APIs https://www.linuxfromscratch.org/blfs/view/cvs/multimedia/pipewire.html -- 🎵 APIs example https://fedoraproject.org/wiki/QA:Testcase_PipeWire_PipeWire_CLI - -Developed with ❤️ by Pablo Diaz & Anna Absi - - -## Install via -```bash - -pip3 install pipewire_python # or pip -``` - -## Tutorial - - -```python -from pipewire_python.controller import Controller - -# PLAYBACK: normal way -audio_controller = Controller() -audio_controller.set_config(rate=384000, - channels=2, - _format='f64', - volume=0.98, - quality=4, - # Debug - verbose=True) -audio_controller.playback(audio_filename='docs/beers.wav') - -# RECORD: normal way -audio_controller = Controller(verbose=True) -audio_controller.record(audio_filename='docs/5sec_record.wav', - timeout_seconds=5, - # Debug - verbose=True) - -``` -""" - -__version__ = "0.1.1" - -import sys - -if sys.platform == "linux": - # from pipewire_python.controller import * - pass -else: - raise NotImplementedError("By now, Pipewire only runs on linux.") -
- -
diff --git a/docs/html/pipewire_python/_constants.html b/docs/html/pipewire_python/_constants.html index ced6fed..ff00bc2 100644 --- a/docs/html/pipewire_python/_constants.html +++ b/docs/html/pipewire_python/_constants.html @@ -3,14 +3,14 @@ - + pipewire_python._constants API documentation - - + +
-
+
Edit on GitHub

pipewire_python._constants

@@ -47,37 +47,38 @@

to see something here in documentation html version.

-
- View Source -
"""
-Here we store constant values, don't expect
-to see something here in documentation html version.
-"""
+                        
 
-MESSAGES_ERROR = {
-    "NotImplementedError": "This function is not yet implemented",
-    "ValueError": "The value entered is wrong",
-}
+                        
 
-RECOMMENDED_RATES = [
-    8000,
-    11025,
-    16000,
-    22050,
-    44100,
-    48000,
-    88200,
-    96000,
-    176400,
-    192000,
-    352800,
-    384000,
-]
+                        
 1"""
+ 2Here we store constant values, don't expect
+ 3to see something here in documentation html version.
+ 4"""
+ 5
+ 6MESSAGES_ERROR = {
+ 7    "NotImplementedError": "This function is not yet implemented",
+ 8    "ValueError": "The value entered is wrong",
+ 9}
+10
+11RECOMMENDED_RATES = [
+12    8000,
+13    11025,
+14    16000,
+15    22050,
+16    44100,
+17    48000,
+18    88200,
+19    96000,
+20    176400,
+21    192000,
+22    352800,
+23    384000,
+24]
+25
+26RECOMMENDED_FORMATS = ["u8", "s8", "s16", "s32", "f32", "f64"]
+
-RECOMMENDED_FORMATS = ["u8", "s8", "s16", "s32", "f32", "f64"] -
- -

diff --git a/docs/html/pipewire_python/_utils.html b/docs/html/pipewire_python/_utils.html index 144e24c..428dd64 100644 --- a/docs/html/pipewire_python/_utils.html +++ b/docs/html/pipewire_python/_utils.html @@ -3,14 +3,14 @@ - + pipewire_python._utils API documentation - - + +
-
+
Edit on GitHub

pipewire_python._utils

@@ -51,306 +51,307 @@

to see something here in documentation html version.

-
- View Source -
"""
-Here we store internal functions, don't expect
-to see something here in documentation html version.
-"""
-import asyncio
-import re
-import subprocess
-from typing import Dict, List
+                        
+
+                        
+
+                        
  1"""
+  2Here we store internal functions, don't expect
+  3to see something here in documentation html version.
+  4"""
+  5import asyncio
+  6import re
+  7import subprocess
+  8from typing import Dict, List
+  9
+ 10# Loading constants Constants.py
+ 11from ._constants import MESSAGES_ERROR
+ 12
+ 13
+ 14def _print_std(
+ 15    stdout: bytes,
+ 16    stderr: bytes,
+ 17    # Debug
+ 18    verbose: bool = False,
+ 19):
+ 20    """
+ 21    Print terminal output if are different to None and verbose activated
+ 22    """
+ 23
+ 24    if stdout is not None and verbose:
+ 25        print(f"[_print_std][stdout][type={type(stdout)}]\n{stdout.decode()}")
+ 26    if stderr is not None and verbose:
+ 27        print(f"[_print_std][stderr][type={type(stderr)}]\n{stderr.decode()}")
+ 28
+ 29
+ 30def _get_dict_from_stdout(
+ 31    stdout: str,
+ 32    # Debug
+ 33    verbose: bool = False,
+ 34):
+ 35    """
+ 36    Converts shell output (str) to dictionary looking for
+ 37    "default" and "--" values
+ 38    """
+ 39
+ 40    rows = stdout.split("\n")
+ 41    config_dict = {}
+ 42    for row in rows:
+ 43        if "default" in row:
+ 44            key = "--" + row.split("--")[1].split(" ")[0]
+ 45            value = row.split("default ")[1].replace(")", "")
+ 46            config_dict[key] = value
+ 47    if verbose:
+ 48        print(config_dict)
+ 49    return config_dict
+ 50
+ 51
+ 52def _update_dict_by_dict(
+ 53    main_dict: Dict,
+ 54    secondary_dict: Dict,
+ 55):
+ 56    """
+ 57    Update values of one dictionary with values of another dictionary
+ 58    based on keys
+ 59    """
+ 60    return main_dict.update(([(key, secondary_dict[key]) for key in secondary_dict.keys()]))
+ 61
+ 62
+ 63def _drop_keys_with_none_values(main_dict: dict):
+ 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}
+ 68
+ 69
+ 70def _generate_command_by_dict(
+ 71    mydict: Dict,
+ 72    # Debug
+ 73    verbose: bool = False,
+ 74):
+ 75    """
+ 76    Generate an array based on dictionary with keys and values
+ 77    """
+ 78    array_command = []
+ 79    # append to a list
+ 80    for key, value in mydict.items():
+ 81        array_command.extend([key, value])
+ 82    if verbose:
+ 83        print(array_command)
+ 84    # return values
+ 85    return array_command
+ 86
+ 87
+ 88def _execute_shell_command(
+ 89    command: List[str],
+ 90    timeout: int = -1,  # *default= no limit
+ 91    # Debug
+ 92    verbose: bool = False,
+ 93):
+ 94    """
+ 95    Execute command on terminal via subprocess
+ 96
+ 97    Args:
+ 98        - command (str): command line to execute. Example: 'ls -l'
+ 99        - timeout (int): (seconds) time to end the terminal process
+100        - verbose (bool): print variables for debug purposes
+101    Return:
+102        - stdout (str): terminal response to the command
+103        - stderr (str): terminal response to the command
+104    """
+105    # Create subprocess
+106    # NO-RESOURCE-ALLOCATING
+107    # terminal_subprocess = subprocess.Popen(
+108    #     command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT  # Example ['ls ','l']
+109    # )
+110
+111    with subprocess.Popen(
+112        command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT  # Example ['ls ','l']
+113    ) as terminal_subprocess:
+114        # Execute command depending or not in timeout
+115        try:
+116            if timeout == -1:
+117                stdout, stderr = terminal_subprocess.communicate()
+118            else:
+119                stdout, stderr = terminal_subprocess.communicate(timeout=timeout)
+120        except subprocess.TimeoutExpired:  # When script finish in time
+121            terminal_subprocess.kill()
+122            stdout, stderr = terminal_subprocess.communicate()
+123
+124        # Print terminal output
+125        _print_std(stdout, stderr, verbose=verbose)
+126
+127        # Return terminal output
+128        return stdout, stderr
+129
+130
+131async def _execute_shell_command_async(
+132    command,
+133    timeout: int = -1,
+134    # Debug
+135    verbose: bool = False,
+136):
+137    """[ASYNC] Function that execute terminal commands in asyncio way
+138
+139    Args:
+140        - command (str): command line to execute. Example: 'ls -l'
+141    Return:
+142        - stdout (str): terminal response to the command.
+143        - stderr (str): terminal response to the command.
+144    """
+145    if timeout == -1:
+146        # No timeout
+147        terminal_process_async = await asyncio.create_subprocess_shell(
+148            command, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE
+149        )
+150        stdout, stderr = await terminal_process_async.communicate()
+151        print(
+152            f"[_execute_shell_command_async]\
+153                [{command!r} exited with\
+154                {terminal_process_async.returncode}]"
+155        )
+156        _print_std(stdout, stderr, verbose=verbose)
+157
+158    else:
+159        raise NotImplementedError(MESSAGES_ERROR["NotImplementedError"])
+160
+161    return stdout, stderr
+162
+163
+164def _generate_dict_list_targets(
+165    longstring: str,  # string output of shell
+166    # Debug
+167    verbose: bool = False,
+168):
+169    """
+170    Function that transform long string of list targets
+171    to a `dict`
+172    """
+173
+174    regex_id = r"(\d.*):"
+175    regex_desc = r'description="([^"]*)"'
+176    regex_prio = r"prio=(-?\d.*)"
+177    regex_default_node = r"[*]\t(\d\d)"
+178    regex_alsa_node = r"(alsa_[a-zA-Z].*)"
+179
+180    results_regex_id = re.findall(regex_id, longstring)
+181    results_regex_desc = re.findall(regex_desc, longstring)
+182    results_regex_prio = re.findall(regex_prio, longstring)
+183    results_regex_default_node = re.findall(regex_default_node, longstring)
+184    results_regex_alsa_mode = re.findall(regex_alsa_node, longstring)
+185
+186    mydict = {}
+187    for idx, _ in enumerate(results_regex_id):
+188        mydict[results_regex_id[idx]] = {
+189            "description": results_regex_desc[idx],
+190            "prior": results_regex_prio[idx],
+191        }
+192    mydict["_list_nodes"] = results_regex_id
+193    mydict["_node_default"] = results_regex_default_node
+194    mydict["_alsa_node"] = results_regex_alsa_mode
+195
+196    if verbose:
+197        print(mydict)
+198
+199    return mydict
+200
+201
+202def _generate_dict_interfaces(
+203    longstring: str,  # string output of shell
+204    # Debug
+205    verbose: bool = False,
+206):
+207    """
+208    Function that transform long string of list interfaces
+209    to a `dict`
+210    """
+211
+212    mydict = {}
+213    text_in_lines = longstring.split("\n")
+214    first_level = "X"
+215
+216    for line in text_in_lines:
+217        try:
+218            is_interface = True
+219            if "id: " in line:
+220                # when interface starts
+221                regex_id = r"\tid: ([0-9]*)"
+222                results_regex_id = re.findall(regex_id, line)
+223                is_interface = False
+224
+225            if is_interface:
+226                if "*" in line[:1]:
+227                    # delete * on each line at the beginning
+228                    line = line[1:]
+229                if "\t\t" in line:
+230                    # third level data
+231                    data = line.replace("\t\t", "")
+232                    data = data.split(" = ")
+233                    third_level = str(data[0])
+234                    data_to_place = " ".join(data[1:]).replace('"', "")
+235
+236                    if "properties" not in mydict[first_level]:
+237                        mydict[first_level]["properties"] = {}
+238                    if third_level not in mydict[first_level]["properties"]:
+239                        mydict[first_level]["properties"][third_level] = {}
+240                    mydict[first_level]["properties"][third_level] = data_to_place
+241
+242                elif "\t  " in line:
+243                    # second level data: params
+244
+245                    data = line.replace("\t  ", "").split(" ")
+246                    third_level = str(data[0])
+247                    if type(mydict[first_level]["params"]) != dict:
+248                        mydict[first_level]["params"] = {}
+249                    mydict[first_level]["params"][third_level] = {
+250                        "spa": data[1],
+251                        "permissions": data[2],
+252                    }
+253
+254                elif "\t" in line:
+255                    # first level data
+256                    data = line.replace("\t", "")
+257                    data = data.split(": ")
+258                    first_level = str(results_regex_id[0])
+259                    second_level = str(data[0])
+260                    data_to_place = " ".join(data[1:]).replace('"', "")
+261
+262                    # to_dict
+263                    if first_level not in mydict:
+264                        mydict[str(first_level)] = {}
+265
+266                    mydict[first_level][second_level] = data_to_place
+267        except Exception as e:
+268            print(e)
+269
+270    if verbose:
+271        print(mydict)
+272
+273    return mydict
+274
+275
+276def _filter_by_type(
+277    dict_interfaces: dict,  # interfaecs dict
+278    type_interfaces: str,  # string with type
+279    # Debug
+280    verbose: bool = False,
+281):
+282    """
+283    Function that filters a `dict` by type of interface
+284    """
+285
+286    dict_filtered = {}
+287    for key in dict_interfaces:
+288        # Filter
+289        if type_interfaces in dict_interfaces[key]["type"]:
+290            dict_filtered[key] = dict_interfaces[key]
+291
+292    if verbose:
+293        print(dict_filtered)
+294
+295    return dict_filtered
+
-# Loading constants Constants.py -from ._constants import MESSAGES_ERROR - - -def _print_std( - stdout: bytes, - stderr: bytes, - # Debug - verbose: bool = False, -): - """ - Print terminal output if are different to None and verbose activated - """ - - if stdout is not None and verbose: - print(f"[_print_std][stdout][type={type(stdout)}]\n{stdout.decode()}") - if stderr is not None and verbose: - print(f"[_print_std][stderr][type={type(stderr)}]\n{stderr.decode()}") - - -def _get_dict_from_stdout( - stdout: str, - # Debug - verbose: bool = False, -): - """ - Converts shell output (str) to dictionary looking for - "default" and "--" values - """ - - rows = stdout.split("\n") - config_dict = {} - for row in rows: - if "default" in row: - key = "--" + row.split("--")[1].split(" ")[0] - value = row.split("default ")[1].replace(")", "") - config_dict[key] = value - if verbose: - print(config_dict) - return config_dict - - -def _update_dict_by_dict( - main_dict: Dict, - secondary_dict: Dict, -): - """ - Update values of one dictionary with values of another dictionary - based on keys - """ - return main_dict.update(([(key, secondary_dict[key]) for key in secondary_dict.keys()])) - - -def _drop_keys_with_none_values(main_dict: dict): - """ - Drop keys with None values to parse safe dictionary config - """ - return {k: v for k, v in main_dict.items() if v is not None} - - -def _generate_command_by_dict( - mydict: Dict, - # Debug - verbose: bool = False, -): - """ - Generate an array based on dictionary with keys and values - """ - array_command = [] - # append to a list - for key, value in mydict.items(): - array_command.extend([key, value]) - if verbose: - print(array_command) - # return values - return array_command - - -def _execute_shell_command( - command: List[str], - timeout: int = -1, # *default= no limit - # Debug - verbose: bool = False, -): - """ - Execute command on terminal via subprocess - - Args: - - command (str): command line to execute. Example: 'ls -l' - - timeout (int): (seconds) time to end the terminal process - - verbose (bool): print variables for debug purposes - Return: - - stdout (str): terminal response to the command - - stderr (str): terminal response to the command - """ - # Create subprocess - # NO-RESOURCE-ALLOCATING - # terminal_subprocess = subprocess.Popen( - # command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT # Example ['ls ','l'] - # ) - - with subprocess.Popen( - command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT # Example ['ls ','l'] - ) as terminal_subprocess: - # Execute command depending or not in timeout - try: - if timeout == -1: - stdout, stderr = terminal_subprocess.communicate() - else: - stdout, stderr = terminal_subprocess.communicate(timeout=timeout) - except subprocess.TimeoutExpired: # When script finish in time - terminal_subprocess.kill() - stdout, stderr = terminal_subprocess.communicate() - - # Print terminal output - _print_std(stdout, stderr, verbose=verbose) - - # Return terminal output - return stdout, stderr - - -async def _execute_shell_command_async( - command, - timeout: int = -1, - # Debug - verbose: bool = False, -): - """[ASYNC] Function that execute terminal commands in asyncio way - - Args: - - command (str): command line to execute. Example: 'ls -l' - Return: - - stdout (str): terminal response to the command. - - stderr (str): terminal response to the command. - """ - if timeout == -1: - # No timeout - terminal_process_async = await asyncio.create_subprocess_shell( - command, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE - ) - stdout, stderr = await terminal_process_async.communicate() - print( - f"[_execute_shell_command_async]\ - [{command!r} exited with\ - {terminal_process_async.returncode}]" - ) - _print_std(stdout, stderr, verbose=verbose) - - else: - raise NotImplementedError(MESSAGES_ERROR["NotImplementedError"]) - - return stdout, stderr - - -def _generate_dict_list_targets( - longstring: str, # string output of shell - # Debug - verbose: bool = False, -): - """ - Function that transform long string of list targets - to a `dict` - """ - - regex_id = r"(\d.*):" - regex_desc = r'description="([^"]*)"' - regex_prio = r"prio=(-?\d.*)" - regex_default_node = r"[*]\t(\d\d)" - regex_alsa_node = r"(alsa_[a-zA-Z].*)" - - results_regex_id = re.findall(regex_id, longstring) - results_regex_desc = re.findall(regex_desc, longstring) - results_regex_prio = re.findall(regex_prio, longstring) - results_regex_default_node = re.findall(regex_default_node, longstring) - results_regex_alsa_mode = re.findall(regex_alsa_node, longstring) - - mydict = {} - for idx, _ in enumerate(results_regex_id): - mydict[results_regex_id[idx]] = { - "description": results_regex_desc[idx], - "prior": results_regex_prio[idx], - } - mydict["_list_nodes"] = results_regex_id - mydict["_node_default"] = results_regex_default_node - mydict["_alsa_node"] = results_regex_alsa_mode - - if verbose: - print(mydict) - - return mydict - - -def _generate_dict_interfaces( - longstring: str, # string output of shell - # Debug - verbose: bool = False, -): - """ - Function that transform long string of list interfaces - to a `dict` - """ - - mydict = {} - text_in_lines = longstring.split("\n") - first_level = "X" - - for line in text_in_lines: - try: - is_interface = True - if "id: " in line: - # when interface starts - regex_id = r"\tid: ([0-9]*)" - results_regex_id = re.findall(regex_id, line) - is_interface = False - - if is_interface: - if "*" in line[:1]: - # delete * on each line at the beginning - line = line[1:] - if "\t\t" in line: - # third level data - data = line.replace("\t\t", "") - data = data.split(" = ") - third_level = str(data[0]) - data_to_place = " ".join(data[1:]).replace('"', "") - - if "properties" not in mydict[first_level]: - mydict[first_level]["properties"] = {} - if third_level not in mydict[first_level]["properties"]: - mydict[first_level]["properties"][third_level] = {} - mydict[first_level]["properties"][third_level] = data_to_place - - elif "\t " in line: - # second level data: params - - data = line.replace("\t ", "").split(" ") - third_level = str(data[0]) - if type(mydict[first_level]["params"]) != dict: - mydict[first_level]["params"] = {} - mydict[first_level]["params"][third_level] = { - "spa": data[1], - "permissions": data[2], - } - - elif "\t" in line: - # first level data - data = line.replace("\t", "") - data = data.split(": ") - first_level = str(results_regex_id[0]) - second_level = str(data[0]) - data_to_place = " ".join(data[1:]).replace('"', "") - - # to_dict - if first_level not in mydict: - mydict[str(first_level)] = {} - - mydict[first_level][second_level] = data_to_place - except Exception as e: - print(e) - - if verbose: - print(mydict) - - return mydict - - -def _filter_by_type( - dict_interfaces: dict, # interfaecs dict - type_interfaces: str, # string with type - # Debug - verbose: bool = False, -): - """ - Function that filters a `dict` by type of interface - """ - - dict_filtered = {} - for key in dict_interfaces: - # Filter - if type_interfaces in dict_interfaces[key]["type"]: - dict_filtered[key] = dict_interfaces[key] - - if verbose: - print(dict_filtered) - - return dict_filtered -
- -

diff --git a/docs/html/pipewire_python/controller.html b/docs/html/pipewire_python/controller.html index 34106e7..0cefe47 100644 --- a/docs/html/pipewire_python/controller.html +++ b/docs/html/pipewire_python/controller.html @@ -3,14 +3,14 @@ - + pipewire_python.controller API documentation - - + +
-
+
Edit on GitHub

pipewire_python.controller

@@ -97,1256 +97,1256 @@

controller.py.

-
- View Source -
"""
-## Documentation
-
-In the next pages you'll see documentation of each python component
-`controller.py`.
-"""
-
-import warnings
-
-# Loading internal functions
-from ._utils import (
-    _drop_keys_with_none_values,
-    _execute_shell_command,
-    _filter_by_type,
-    _generate_command_by_dict,
-    _generate_dict_interfaces,
-    _generate_dict_list_targets,
-    _get_dict_from_stdout,
-    _print_std,
-    _update_dict_by_dict,
-)
-
-# Loading constants Constants.py
-from ._constants import MESSAGES_ERROR, RECOMMENDED_FORMATS, RECOMMENDED_RATES
-
-# [DEPRECATED] [FLAKE8] TO_AVOID_F401 PEP8
-# [DEPRECATED] https://stackoverflow.com/a/31079085/10491422
-# NOW USED IN DOCUMENTATION
-# __all__ = [
-#     # Classes and fucntions to doc
-#     'Controller',
-#     # [DEPRECATED] Unused files pylint
-#     # "_print_std",
-#     # "_get_dict_from_stdout",
-#     # "_update_dict_by_dict",
-#     # "_drop_keys_with_none_values",
-#     # "_generate_command_by_dict",
-#     # "_execute_shell_command",
-# ]
-
-
-class Controller:
-    """
-    Class that controls pipewire command line interface
-    with shell commands, handling outputs, loading default
-    configs and more.
-    """
-
-    _pipewire_cli = {  # Help
-        "--help": "--help",  # -h
-        "--version": "--version",
-        "--remote": None,  # -r
-    }
-
-    _pipewire_modes = {  # Modes
-        "--playback": None,  # -p
-        "--record": None,  # -r
-        "--midi": None,  # -m
-    }
-
-    _pipewire_list_targets = {  # "--list-targets": None,
-        "list_playback": None,
-        "list_record": None,
-    }
-
-    _pipewire_configs = {  # Configs
-        "--media-type": None,  # *default=Audio
-        "--media-category": None,  # *default=Playback
-        "--media-role": None,  # *default=Music
-        "--target": None,  # *default=auto
-        "--latency": None,  # *default=100ms (SOURCE FILE if not specified)
-        "--rate": None,  # *default=48000
-        "--channels": None,  # [1,2] *default=2
-        "--channel-map": None,  # ["stereo", "surround-51", "FL,FR"...] *default="FL,FR"
-        "--format": None,  # [u8|s8|s16|s32|f32|f64] *default=s16
-        "--volume": None,  # [0.0,1.0] *default=1.000
-        "--quality": None,  # -q # [0,15] *default=4
-        "--verbose": None,  # -v
-    }
-
-    _kill_pipewire = {
-        "all": ["kill", "$(pidof pw-cat)"],
-        "playback": ["kill", "$(pidof pw-play)"],
-        "record": ["kill", "$(pidof pw-record)"],
-    }
-
-    def __init__(
-        self,
-        # Debug
-        verbose: bool = False,
-    ):
-        """This constructor load default configs from OS executing
-        the following pipewire command
-
-        ```bash
-        #!/bin/bash
-        # Get defaults from output of:
-        pw-cat -h
-        ```
-        """
-        # LOAD ALL DEFAULT PARAMETERS
-
-        mycommand = ["pw-cat", "-h"]
-
-        # get default parameters with help
-        stdout, _ = _execute_shell_command(command=mycommand, verbose=verbose)  # stderr
-        # convert stdout to dictionary
-        dict_default_values = _get_dict_from_stdout(stdout=str(stdout.decode()), verbose=verbose)
-
-        if verbose:
-            print(self._pipewire_configs)
-
-        # Save default system configs to our json
-        self._pipewire_configs.update(
-            ([(key, dict_default_values[key]) for key in dict_default_values])
-        )
-
-        if verbose:
-            print(self._pipewire_configs)
-
-        # Delete keys with None values
-        self._pipewire_configs = _drop_keys_with_none_values(self._pipewire_configs)
-
-        if verbose:
-            print(self._pipewire_configs)
-
-        # Load values of list targets
-        self.load_list_targets(mode="playback", verbose=verbose)
-        self.load_list_targets(mode="record", verbose=verbose)
-
-    def _help_cli(
-        self,
-        # Debug
-        verbose: bool = True,
-    ):
-        """Get pipewire command line help"""
-
-        mycommand = ["pipewire", self._pipewire_cli["--help"]]
-
-        stdout, _ = _execute_shell_command(command=mycommand, verbose=verbose)  # stderr
-
-        return stdout
-
-    def get_version(
-        self,
-        # Debug
-        verbose: bool = False,
-    ):
-        """Get version of pipewire installed on OS by executing the following
-        code:
-
-        ```bash
-        #!/bin/bash
-        pw-cli --version
-        ```
-
-        Args:
-            verbose (bool) : True enable debug logs. *default=False
-
-        Returns:
-            - versions (list) : Versions of pipewire compiled
-        """
-
-        mycommand = ["pw-cli", "--version"]
-
-        if verbose:
-            print(f"[mycommand]{mycommand}")
-
-        stdout, _ = _execute_shell_command(command=mycommand, timeout=-1, verbose=verbose)
-        versions = stdout.decode().split("\n")[1:]
-
-        self._pipewire_cli["--version"] = versions
-
-        return versions
-
-    def verbose(
-        self,
-        status: bool = True,
-    ):
-        """Get full log of pipewire stream status with the command `pw-cat`
-
-        An example of pw-cli usage is the code below:
-
-        ```bash
-        #!/bin/bash
-        # For example
-        pw-cat --playback beers.wav --verbose
-        ```
-
-        that will generate an output like this:
-
-        ```bash
-        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 drained
-        stream state changed streaming -> paused
-        stream param change: id=4
-        stream state changed paused -> unconnected
-        stream param change: id=4
-        ```
-        """
-
-        if status:
-            self._pipewire_configs["--verbose"] = "    "
-        else:
-            pass
-
-    def get_config(self):
-        """Return config dictionary with default or setup variables, remember that
-        this object changes only on python-side. Is not updated on real time,
-        For real-time, please create and destroy the class.
-
-        Args:
-            Nothing
-
-        Returns:
-            - _pipewire_configs (`dict`) : dictionary with config values
-
-        """
-
-        return self._pipewire_configs
-
-    def set_config(
-        self,
-        # configs
-        media_type=None,
-        media_category=None,
-        media_role=None,
-        target=None,
-        latency=None,
-        rate=None,
-        channels=None,
-        channels_map=None,
-        _format=None,
-        volume=None,
-        quality=None,
-        # Debug
-        verbose=False,
-    ):
-        """Method that get args as variables and set them
-        to the `json` parameter of the class `_pipewire_configs`,
-        then you can use in other method, such as `playback(...)` or
-        `record(...)`. This method verifies values to avoid wrong
-        settings.
-
-        Args:
-            media_type : Set media type
-            media_category : Set media category
-            media_role : Set media role
-            target : Set node target
-            latency : Set node latency *example=100ms
-            rate : Set sample rate [8000,11025,16000,22050,44100,48000,88200,96000,176400,192000,352800,384000]
-            channels : Numbers of channels [1,2]
-            channels_map : ["stereo", "surround-51", "FL,FR", ...]
-            _format : ["u8", "s8", "s16", "s32", "f32", "f64"]
-            volume : Stream volume [0.000, 1.000]
-            quality : Resampler quality [0, 15]
-            verbose (`bool`): True enable debug logs. *default=False
-
-        Returns:
-            - Nothing
-
-        More:
-            Check all links listed at the beginning of this page
-        """  # 1 - media_type
-        if media_type:
-            self._pipewire_configs["--media-type"] = str(media_type)
-        elif media_type is None:
-            pass
-        else:
-            raise ValueError(
-                f"{MESSAGES_ERROR['ValueError']}[media_type='{media_type}'] EMPTY VALUE"
-            )
-        # 2 - media_category
-        if media_category:
-            self._pipewire_configs["--media-category"] = str(media_category)
-        elif media_category is None:
-            pass
-        else:
-            raise ValueError(
-                f"{MESSAGES_ERROR['ValueError']}[media_category='{media_category}'] EMPTY VALUE"
-            )
-        # 3 - media_role
-        if media_role:
-            self._pipewire_configs["--media-role"] = str(media_role)
-        elif media_role is None:
-            pass
-        else:
-            raise ValueError(
-                f"{MESSAGES_ERROR['ValueError']}[media_role='{media_role}'] EMPTY VALUE"
-            )
-        # 4 - target
-        if target:
-            self._pipewire_configs["--target"] = str(target)
-        elif target is None:
-            pass
-        else:
-            raise ValueError(f"{MESSAGES_ERROR['ValueError']}[target='{target}'] EMPTY VALUE")
-        # 5 - latency
-        if latency:
-            if any(chr.isdigit() for chr in latency):  # Contain numbers
-                self._pipewire_configs["--latency"] = str(latency)
-            else:
-                raise ValueError(
-                    f"{MESSAGES_ERROR['ValueError']}[latency='{latency}'] NO NUMBER IN VARIABLE"
-                )
-        elif latency is None:
-            pass
-        else:
-            raise ValueError(f"{MESSAGES_ERROR['ValueError']}[latency='{latency}'] EMPTY VALUE")
-        # 6 - rate
-        if rate:
-            if rate in RECOMMENDED_RATES:
-                self._pipewire_configs["--rate"] = str(rate)
-            else:
-                raise ValueError(
-                    f"{MESSAGES_ERROR['ValueError']}[rate='{rate}']\
-                         VALUE NOT IN RECOMMENDED LIST \n{RECOMMENDED_RATES}"
-                )
-        elif rate is None:
-            pass
-        else:
-            raise ValueError(f"{MESSAGES_ERROR['ValueError']}[rate='{rate}'] EMPTY VALUE")
-        # 7 - channels
-        if channels:
-            if channels in [1, 2]:  # values
-                self._pipewire_configs["--channels"] = str(channels)
-            else:
-                raise ValueError(
-                    f"{MESSAGES_ERROR['ValueError']}[channels='{channels}']\
-                         WRONG VALUE\n ONLY 1 or 2."
-                )
-        elif channels is None:
-            pass
-        else:
-            raise ValueError(f"{MESSAGES_ERROR['ValueError']}[channels='{channels}'] EMPTY VALUE")
-        # 8 - channels-map
-        if channels_map:
-            self._pipewire_configs["--channels-map"] = str(channels_map)
-        elif channels_map is None:
-            pass
-        else:
-            raise ValueError(
-                f"{MESSAGES_ERROR['ValueError']}[channels_map='{channels_map}'] EMPTY VALUE"
-            )
-        # 9 - format
-        if _format:
-            if _format in RECOMMENDED_FORMATS:
-                self._pipewire_configs["--format"] = str(_format)
-            else:
-                raise ValueError(
-                    f"{MESSAGES_ERROR['ValueError']}[_format='{_format}']\
-                         VALUE NOT IN RECOMMENDED LIST \n{RECOMMENDED_FORMATS}"
-                )
-        elif _format is None:
-            pass
-        else:
-            raise ValueError(f"{MESSAGES_ERROR['ValueError']}[_format='{_format}'] EMPTY VALUE")
-        # 10 - volume
-        if volume:
-            if 0.0 <= volume <= 1.0:
-                self._pipewire_configs["--volume"] = str(volume)
-            else:
-                raise ValueError(
-                    f"{MESSAGES_ERROR['ValueError']}[volume='{volume}']\
-                         OUT OF RANGE \n [0.000, 1.000]"
-                )
-        elif volume is None:
-            pass
-        else:
-            raise ValueError(f"{MESSAGES_ERROR['ValueError']}[volume='{volume}'] EMPTY VALUE")
-        # 11 - quality
-        if quality:
-            if 0 <= quality <= 15:
-                self._pipewire_configs["--quality"] = str(quality)
-            else:
-                raise ValueError(
-                    f"{MESSAGES_ERROR['ValueError']}[quality='{quality}'] OUT OF RANGE \n [0, 15]"
-                )
-        elif quality is None:
-            pass
-        else:
-            raise ValueError(f"{MESSAGES_ERROR['ValueError']}[volume='{volume}'] EMPTY VALUE")
-
-        # 12 - verbose cli
-        if verbose:  # True
-            self._pipewire_configs["--verbose"] = "    "
-        else:
-            pass
-
-        if verbose:
-            print(self._pipewire_configs)
-
-    def load_list_targets(
-        self,
-        mode,  # playback or record
-        # Debug,
-        verbose: bool = False,
-    ):
-        """Returns a list of targets to playback or record. Then you can use
-        the output to select a device to playback or record.
-        """
-
-        if mode == "playback":
-            mycommand = ["pw-cat", "--playback", "--list-targets"]
-            stdout, _ = _execute_shell_command(command=mycommand, timeout=-1, verbose=verbose)
-            self._pipewire_list_targets["list_playback"] = _generate_dict_list_targets(
-                longstring=stdout.decode(), verbose=verbose
-            )
-        elif mode == "record":
-            mycommand = ["pw-cat", "--record", "--list-targets"]
-            stdout, _ = _execute_shell_command(command=mycommand, timeout=-1, verbose=verbose)
-            self._pipewire_list_targets["list_record"] = _generate_dict_list_targets(
-                longstring=stdout.decode(), verbose=verbose
-            )
-        else:
-            raise AttributeError(MESSAGES_ERROR["ValueError"])
-
-        if verbose:
-            print(f"[mycommand]{mycommand}")
-
-    def get_list_targets(
-        self,
-        # Debug,
-        verbose: bool = False,
-    ):
-        """Returns a list of targets to playback or record. Then you can use
-        the output to select a device to playback or record.
-
-        Returns:
-            - `_pipewire_list_targets`
-
-        Examples:
-        ```python
-        >>> Controller().get_list_targets()
-        {
-        "list_playback": {
-            "86": {
-            "description": "Starship/Matisse HD Audio Controller Pro",
-            "prior": "936"
-            },
-            "_list_nodes": [
-            "86"
-            ],
-            "_node_default": [
-            "86"
-            ],
-            "_alsa_node": [
-            "alsa_output.pci-0000_0a_00.4.pro-output-0"
-            ]
-        },
-        "list_record": {
-            "86": {
-            "description": "Starship/Matisse HD Audio Controller Pro",
-            "prior": "936"
-            },
-            "_list_nodes": [
-            "86"
-            ],
-            "_node_default": [
-            "86"
-            ],
-            "_alsa_node": [
-            "alsa_output.pci-0000_0a_00.4.pro-output-0"
-            ]
-        }
-        }
-        ```
-        """
-        if verbose:
-            print(self._pipewire_list_targets)
-        return self._pipewire_list_targets
-
-    def get_list_interfaces(
-        self,
-        filtered_by_type: str = True,
-        type_interfaces: str = "Client",
-        # Debug
-        verbose: bool = False,
-    ):
-        """Returns a list of applications currently using pipewire on Client.
-        An example of pw-cli usage is the code below:
-
-        ```bash
-        #!/bin/bash
-        pw-cli ls Client
-        ```
-        Args:
-            filtered_by_type : If False, returns all. If not, returns a fitered dict
-            type_interfaces : Set type of Interface ["Client","Link","Node","Factory","Module","Metadata","Endpoint","Session","Endpoint Stream","EndpointLink","Port"]
-
-        Returns:
-            - dict_interfaces_filtered: dictionary with list of interfaces matching conditions
-
-        Examples:
-        ```python
-        >>> Controller().get_list_interfaces()
-
-        ```
-        """
-        mycommand = ["pw-cli", "info", "all"]
-
-        # if verbose:
-        #     print(f"[mycommand]{mycommand}")
-
-        stdout, _ = _execute_shell_command(command=mycommand, timeout=-1, verbose=verbose)
-        dict_interfaces = _generate_dict_interfaces(longstring=stdout.decode(), verbose=verbose)
-
-        if filtered_by_type:
-            dict_interfaces_filtered = _filter_by_type(
-                dict_interfaces=dict_interfaces, type_interfaces=type_interfaces
-            )
-        else:
-            dict_interfaces_filtered = dict_interfaces
-
-        return dict_interfaces_filtered
-
-    def playback(
-        self,
-        audio_filename: str = "myplayback.wav",
-        # Debug
-        verbose: bool = False,
-    ):
-        """Execute pipewire command to play an audio file with the following
-        command:
-
-        ```bash
-        #!/bin/bash
-        pw-cat --playback {audio_filename} + {configs}
-        # configs are a concatenated params
-        ```
-
-        Args:
-            audio_filename (`str`): Path of the file to be played. *default='myplayback.wav'
-            verbose (`bool`): True enable debug logs. *default=False
-
-        Returns:
-            - stdout (`str`): Shell response to the command in stdout format
-            - stderr (`str`): Shell response response to the command in stderr format
-        """
-        warnings.warn("The name of the function may change on future releases", DeprecationWarning)
-
-        mycommand = ["pw-cat", "--playback", audio_filename] + _generate_command_by_dict(
-            mydict=self._pipewire_configs, verbose=verbose
-        )
-
-        if verbose:
-            print(f"[mycommand]{mycommand}")
-
-        stdout, stderr = _execute_shell_command(command=mycommand, timeout=-1, verbose=verbose)
-        return stdout, stderr
-
-    def record(
-        self,
-        audio_filename: str = "myplayback.wav",
-        timeout_seconds=5,
-        # Debug
-        verbose: bool = False,
-    ):
-        """Execute pipewire command to record an audio file, with a timeout of 5
-        seconds with the following code and exiting the shell when tiomeout is over.
-
-        ```bash
-        #!/bin/bash
-        pw-cat --record {audio_filename}
-        # timeout is managed by python3 (when signal CTRL+C is sended)
-        ```
-
-        Args:
-            audio_filename (`str`): Path of the file to be played. *default='myplayback.wav'
-            verbose (`bool`): True enable debug logs. *default=False
-
-        Returns:
-            - stdout (`str`): Shell response to the command in stdout format
-            - stderr (`str`): Shell response response to the command in stderr format
-        """
-        warnings.warn("The name of the function may change on future releases", DeprecationWarning)
-
-        mycommand = ["pw-cat", "--record", audio_filename] + _generate_command_by_dict(
-            mydict=self._pipewire_configs, verbose=verbose
-        )
-
-        if verbose:
-            print(f"[mycommand]{mycommand}")
-
-        stdout, stderr = _execute_shell_command(
-            command=mycommand, timeout=timeout_seconds, verbose=verbose
-        )
-        return stdout, stderr
-
-    def clear_devices(
-        self,
-        mode: str = "all",  # ['all','playback','record']
-        # Debug
-        verbose: bool = False,
-    ):
-        """Function to stop process running under pipewire executed by
-        python controller and with default process name of `pw-cat`, `pw-play` or `pw-record`.
-
-        Args:
-            mode (`str`) : string to kill process under `pw-cat`, `pw-play` or `pw-record`.
-
-        Returns:
-            - stdoutdict (`dict`) : a dictionary with keys of `mode`.
-
-        Example with pipewire:
-            pw-cat process
-        """
-
-        mycommand = self._kill_pipewire[mode]
-
-        if verbose:
-            print(f"[mycommands]{mycommand}")
-
-        stdout, _ = _execute_shell_command(command=mycommand, verbose=verbose)
-
-        return {mode: stdout}
-
- -
+ + + + +
  1"""
+  2## Documentation
+  3
+  4In the next pages you'll see documentation of each python component
+  5`controller.py`.
+  6"""
+  7
+  8import warnings
+  9
+ 10# Loading internal functions
+ 11from ._utils import (
+ 12    _drop_keys_with_none_values,
+ 13    _execute_shell_command,
+ 14    _filter_by_type,
+ 15    _generate_command_by_dict,
+ 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
+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"""
+137
+138        mycommand = ["pipewire", self._pipewire_cli["--help"]]
+139
+140        stdout, _ = _execute_shell_command(command=mycommand, verbose=verbose)  # stderr
+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        """
+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:]
+171
+172        self._pipewire_cli["--version"] = 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`
+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        ```
+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
+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
+236
+237        """
+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
+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        """
+627
+628        mycommand = self._kill_pipewire[mode]
+629
+630        if verbose:
+631            print(f"[mycommands]{mycommand}")
+632
+633        stdout, _ = _execute_shell_command(command=mycommand, verbose=verbose)
+634
+635        return {mode: stdout}
+
+

-
- #   + +
+ + class + Controller: + + - - class - Controller:
+ +
 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
+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"""
+138
+139        mycommand = ["pipewire", self._pipewire_cli["--help"]]
+140
+141        stdout, _ = _execute_shell_command(command=mycommand, verbose=verbose)  # stderr
+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        """
+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:]
+172
+173        self._pipewire_cli["--version"] = 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`
+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        ```
+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
+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
+237
+238        """
+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
+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        """
+628
+629        mycommand = self._kill_pipewire[mode]
+630
+631        if verbose:
+632            print(f"[mycommands]{mycommand}")
+633
+634        stdout, _ = _execute_shell_command(command=mycommand, verbose=verbose)
+635
+636        return {mode: stdout}
+
-
- View Source -
class Controller:
-    """
-    Class that controls pipewire command line interface
-    with shell commands, handling outputs, loading default
-    configs and more.
-    """
-
-    _pipewire_cli = {  # Help
-        "--help": "--help",  # -h
-        "--version": "--version",
-        "--remote": None,  # -r
-    }
-
-    _pipewire_modes = {  # Modes
-        "--playback": None,  # -p
-        "--record": None,  # -r
-        "--midi": None,  # -m
-    }
-
-    _pipewire_list_targets = {  # "--list-targets": None,
-        "list_playback": None,
-        "list_record": None,
-    }
-
-    _pipewire_configs = {  # Configs
-        "--media-type": None,  # *default=Audio
-        "--media-category": None,  # *default=Playback
-        "--media-role": None,  # *default=Music
-        "--target": None,  # *default=auto
-        "--latency": None,  # *default=100ms (SOURCE FILE if not specified)
-        "--rate": None,  # *default=48000
-        "--channels": None,  # [1,2] *default=2
-        "--channel-map": None,  # ["stereo", "surround-51", "FL,FR"...] *default="FL,FR"
-        "--format": None,  # [u8|s8|s16|s32|f32|f64] *default=s16
-        "--volume": None,  # [0.0,1.0] *default=1.000
-        "--quality": None,  # -q # [0,15] *default=4
-        "--verbose": None,  # -v
-    }
-
-    _kill_pipewire = {
-        "all": ["kill", "$(pidof pw-cat)"],
-        "playback": ["kill", "$(pidof pw-play)"],
-        "record": ["kill", "$(pidof pw-record)"],
-    }
-
-    def __init__(
-        self,
-        # Debug
-        verbose: bool = False,
-    ):
-        """This constructor load default configs from OS executing
-        the following pipewire command
-
-        ```bash
-        #!/bin/bash
-        # Get defaults from output of:
-        pw-cat -h
-        ```
-        """
-        # LOAD ALL DEFAULT PARAMETERS
-
-        mycommand = ["pw-cat", "-h"]
-
-        # get default parameters with help
-        stdout, _ = _execute_shell_command(command=mycommand, verbose=verbose)  # stderr
-        # convert stdout to dictionary
-        dict_default_values = _get_dict_from_stdout(stdout=str(stdout.decode()), verbose=verbose)
-
-        if verbose:
-            print(self._pipewire_configs)
-
-        # Save default system configs to our json
-        self._pipewire_configs.update(
-            ([(key, dict_default_values[key]) for key in dict_default_values])
-        )
-
-        if verbose:
-            print(self._pipewire_configs)
-
-        # Delete keys with None values
-        self._pipewire_configs = _drop_keys_with_none_values(self._pipewire_configs)
-
-        if verbose:
-            print(self._pipewire_configs)
-
-        # Load values of list targets
-        self.load_list_targets(mode="playback", verbose=verbose)
-        self.load_list_targets(mode="record", verbose=verbose)
-
-    def _help_cli(
-        self,
-        # Debug
-        verbose: bool = True,
-    ):
-        """Get pipewire command line help"""
-
-        mycommand = ["pipewire", self._pipewire_cli["--help"]]
-
-        stdout, _ = _execute_shell_command(command=mycommand, verbose=verbose)  # stderr
-
-        return stdout
-
-    def get_version(
-        self,
-        # Debug
-        verbose: bool = False,
-    ):
-        """Get version of pipewire installed on OS by executing the following
-        code:
-
-        ```bash
-        #!/bin/bash
-        pw-cli --version
-        ```
-
-        Args:
-            verbose (bool) : True enable debug logs. *default=False
-
-        Returns:
-            - versions (list) : Versions of pipewire compiled
-        """
-
-        mycommand = ["pw-cli", "--version"]
-
-        if verbose:
-            print(f"[mycommand]{mycommand}")
-
-        stdout, _ = _execute_shell_command(command=mycommand, timeout=-1, verbose=verbose)
-        versions = stdout.decode().split("\n")[1:]
-
-        self._pipewire_cli["--version"] = versions
-
-        return versions
-
-    def verbose(
-        self,
-        status: bool = True,
-    ):
-        """Get full log of pipewire stream status with the command `pw-cat`
-
-        An example of pw-cli usage is the code below:
-
-        ```bash
-        #!/bin/bash
-        # For example
-        pw-cat --playback beers.wav --verbose
-        ```
-
-        that will generate an output like this:
-
-        ```bash
-        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 drained
-        stream state changed streaming -> paused
-        stream param change: id=4
-        stream state changed paused -> unconnected
-        stream param change: id=4
-        ```
-        """
-
-        if status:
-            self._pipewire_configs["--verbose"] = "    "
-        else:
-            pass
-
-    def get_config(self):
-        """Return config dictionary with default or setup variables, remember that
-        this object changes only on python-side. Is not updated on real time,
-        For real-time, please create and destroy the class.
-
-        Args:
-            Nothing
-
-        Returns:
-            - _pipewire_configs (`dict`) : dictionary with config values
-
-        """
-
-        return self._pipewire_configs
-
-    def set_config(
-        self,
-        # configs
-        media_type=None,
-        media_category=None,
-        media_role=None,
-        target=None,
-        latency=None,
-        rate=None,
-        channels=None,
-        channels_map=None,
-        _format=None,
-        volume=None,
-        quality=None,
-        # Debug
-        verbose=False,
-    ):
-        """Method that get args as variables and set them
-        to the `json` parameter of the class `_pipewire_configs`,
-        then you can use in other method, such as `playback(...)` or
-        `record(...)`. This method verifies values to avoid wrong
-        settings.
-
-        Args:
-            media_type : Set media type
-            media_category : Set media category
-            media_role : Set media role
-            target : Set node target
-            latency : Set node latency *example=100ms
-            rate : Set sample rate [8000,11025,16000,22050,44100,48000,88200,96000,176400,192000,352800,384000]
-            channels : Numbers of channels [1,2]
-            channels_map : ["stereo", "surround-51", "FL,FR", ...]
-            _format : ["u8", "s8", "s16", "s32", "f32", "f64"]
-            volume : Stream volume [0.000, 1.000]
-            quality : Resampler quality [0, 15]
-            verbose (`bool`): True enable debug logs. *default=False
-
-        Returns:
-            - Nothing
-
-        More:
-            Check all links listed at the beginning of this page
-        """  # 1 - media_type
-        if media_type:
-            self._pipewire_configs["--media-type"] = str(media_type)
-        elif media_type is None:
-            pass
-        else:
-            raise ValueError(
-                f"{MESSAGES_ERROR['ValueError']}[media_type='{media_type}'] EMPTY VALUE"
-            )
-        # 2 - media_category
-        if media_category:
-            self._pipewire_configs["--media-category"] = str(media_category)
-        elif media_category is None:
-            pass
-        else:
-            raise ValueError(
-                f"{MESSAGES_ERROR['ValueError']}[media_category='{media_category}'] EMPTY VALUE"
-            )
-        # 3 - media_role
-        if media_role:
-            self._pipewire_configs["--media-role"] = str(media_role)
-        elif media_role is None:
-            pass
-        else:
-            raise ValueError(
-                f"{MESSAGES_ERROR['ValueError']}[media_role='{media_role}'] EMPTY VALUE"
-            )
-        # 4 - target
-        if target:
-            self._pipewire_configs["--target"] = str(target)
-        elif target is None:
-            pass
-        else:
-            raise ValueError(f"{MESSAGES_ERROR['ValueError']}[target='{target}'] EMPTY VALUE")
-        # 5 - latency
-        if latency:
-            if any(chr.isdigit() for chr in latency):  # Contain numbers
-                self._pipewire_configs["--latency"] = str(latency)
-            else:
-                raise ValueError(
-                    f"{MESSAGES_ERROR['ValueError']}[latency='{latency}'] NO NUMBER IN VARIABLE"
-                )
-        elif latency is None:
-            pass
-        else:
-            raise ValueError(f"{MESSAGES_ERROR['ValueError']}[latency='{latency}'] EMPTY VALUE")
-        # 6 - rate
-        if rate:
-            if rate in RECOMMENDED_RATES:
-                self._pipewire_configs["--rate"] = str(rate)
-            else:
-                raise ValueError(
-                    f"{MESSAGES_ERROR['ValueError']}[rate='{rate}']\
-                         VALUE NOT IN RECOMMENDED LIST \n{RECOMMENDED_RATES}"
-                )
-        elif rate is None:
-            pass
-        else:
-            raise ValueError(f"{MESSAGES_ERROR['ValueError']}[rate='{rate}'] EMPTY VALUE")
-        # 7 - channels
-        if channels:
-            if channels in [1, 2]:  # values
-                self._pipewire_configs["--channels"] = str(channels)
-            else:
-                raise ValueError(
-                    f"{MESSAGES_ERROR['ValueError']}[channels='{channels}']\
-                         WRONG VALUE\n ONLY 1 or 2."
-                )
-        elif channels is None:
-            pass
-        else:
-            raise ValueError(f"{MESSAGES_ERROR['ValueError']}[channels='{channels}'] EMPTY VALUE")
-        # 8 - channels-map
-        if channels_map:
-            self._pipewire_configs["--channels-map"] = str(channels_map)
-        elif channels_map is None:
-            pass
-        else:
-            raise ValueError(
-                f"{MESSAGES_ERROR['ValueError']}[channels_map='{channels_map}'] EMPTY VALUE"
-            )
-        # 9 - format
-        if _format:
-            if _format in RECOMMENDED_FORMATS:
-                self._pipewire_configs["--format"] = str(_format)
-            else:
-                raise ValueError(
-                    f"{MESSAGES_ERROR['ValueError']}[_format='{_format}']\
-                         VALUE NOT IN RECOMMENDED LIST \n{RECOMMENDED_FORMATS}"
-                )
-        elif _format is None:
-            pass
-        else:
-            raise ValueError(f"{MESSAGES_ERROR['ValueError']}[_format='{_format}'] EMPTY VALUE")
-        # 10 - volume
-        if volume:
-            if 0.0 <= volume <= 1.0:
-                self._pipewire_configs["--volume"] = str(volume)
-            else:
-                raise ValueError(
-                    f"{MESSAGES_ERROR['ValueError']}[volume='{volume}']\
-                         OUT OF RANGE \n [0.000, 1.000]"
-                )
-        elif volume is None:
-            pass
-        else:
-            raise ValueError(f"{MESSAGES_ERROR['ValueError']}[volume='{volume}'] EMPTY VALUE")
-        # 11 - quality
-        if quality:
-            if 0 <= quality <= 15:
-                self._pipewire_configs["--quality"] = str(quality)
-            else:
-                raise ValueError(
-                    f"{MESSAGES_ERROR['ValueError']}[quality='{quality}'] OUT OF RANGE \n [0, 15]"
-                )
-        elif quality is None:
-            pass
-        else:
-            raise ValueError(f"{MESSAGES_ERROR['ValueError']}[volume='{volume}'] EMPTY VALUE")
-
-        # 12 - verbose cli
-        if verbose:  # True
-            self._pipewire_configs["--verbose"] = "    "
-        else:
-            pass
-
-        if verbose:
-            print(self._pipewire_configs)
-
-    def load_list_targets(
-        self,
-        mode,  # playback or record
-        # Debug,
-        verbose: bool = False,
-    ):
-        """Returns a list of targets to playback or record. Then you can use
-        the output to select a device to playback or record.
-        """
-
-        if mode == "playback":
-            mycommand = ["pw-cat", "--playback", "--list-targets"]
-            stdout, _ = _execute_shell_command(command=mycommand, timeout=-1, verbose=verbose)
-            self._pipewire_list_targets["list_playback"] = _generate_dict_list_targets(
-                longstring=stdout.decode(), verbose=verbose
-            )
-        elif mode == "record":
-            mycommand = ["pw-cat", "--record", "--list-targets"]
-            stdout, _ = _execute_shell_command(command=mycommand, timeout=-1, verbose=verbose)
-            self._pipewire_list_targets["list_record"] = _generate_dict_list_targets(
-                longstring=stdout.decode(), verbose=verbose
-            )
-        else:
-            raise AttributeError(MESSAGES_ERROR["ValueError"])
-
-        if verbose:
-            print(f"[mycommand]{mycommand}")
-
-    def get_list_targets(
-        self,
-        # Debug,
-        verbose: bool = False,
-    ):
-        """Returns a list of targets to playback or record. Then you can use
-        the output to select a device to playback or record.
-
-        Returns:
-            - `_pipewire_list_targets`
-
-        Examples:
-        ```python
-        >>> Controller().get_list_targets()
-        {
-        "list_playback": {
-            "86": {
-            "description": "Starship/Matisse HD Audio Controller Pro",
-            "prior": "936"
-            },
-            "_list_nodes": [
-            "86"
-            ],
-            "_node_default": [
-            "86"
-            ],
-            "_alsa_node": [
-            "alsa_output.pci-0000_0a_00.4.pro-output-0"
-            ]
-        },
-        "list_record": {
-            "86": {
-            "description": "Starship/Matisse HD Audio Controller Pro",
-            "prior": "936"
-            },
-            "_list_nodes": [
-            "86"
-            ],
-            "_node_default": [
-            "86"
-            ],
-            "_alsa_node": [
-            "alsa_output.pci-0000_0a_00.4.pro-output-0"
-            ]
-        }
-        }
-        ```
-        """
-        if verbose:
-            print(self._pipewire_list_targets)
-        return self._pipewire_list_targets
-
-    def get_list_interfaces(
-        self,
-        filtered_by_type: str = True,
-        type_interfaces: str = "Client",
-        # Debug
-        verbose: bool = False,
-    ):
-        """Returns a list of applications currently using pipewire on Client.
-        An example of pw-cli usage is the code below:
-
-        ```bash
-        #!/bin/bash
-        pw-cli ls Client
-        ```
-        Args:
-            filtered_by_type : If False, returns all. If not, returns a fitered dict
-            type_interfaces : Set type of Interface ["Client","Link","Node","Factory","Module","Metadata","Endpoint","Session","Endpoint Stream","EndpointLink","Port"]
-
-        Returns:
-            - dict_interfaces_filtered: dictionary with list of interfaces matching conditions
-
-        Examples:
-        ```python
-        >>> Controller().get_list_interfaces()
-
-        ```
-        """
-        mycommand = ["pw-cli", "info", "all"]
-
-        # if verbose:
-        #     print(f"[mycommand]{mycommand}")
-
-        stdout, _ = _execute_shell_command(command=mycommand, timeout=-1, verbose=verbose)
-        dict_interfaces = _generate_dict_interfaces(longstring=stdout.decode(), verbose=verbose)
-
-        if filtered_by_type:
-            dict_interfaces_filtered = _filter_by_type(
-                dict_interfaces=dict_interfaces, type_interfaces=type_interfaces
-            )
-        else:
-            dict_interfaces_filtered = dict_interfaces
-
-        return dict_interfaces_filtered
-
-    def playback(
-        self,
-        audio_filename: str = "myplayback.wav",
-        # Debug
-        verbose: bool = False,
-    ):
-        """Execute pipewire command to play an audio file with the following
-        command:
-
-        ```bash
-        #!/bin/bash
-        pw-cat --playback {audio_filename} + {configs}
-        # configs are a concatenated params
-        ```
-
-        Args:
-            audio_filename (`str`): Path of the file to be played. *default='myplayback.wav'
-            verbose (`bool`): True enable debug logs. *default=False
-
-        Returns:
-            - stdout (`str`): Shell response to the command in stdout format
-            - stderr (`str`): Shell response response to the command in stderr format
-        """
-        warnings.warn("The name of the function may change on future releases", DeprecationWarning)
-
-        mycommand = ["pw-cat", "--playback", audio_filename] + _generate_command_by_dict(
-            mydict=self._pipewire_configs, verbose=verbose
-        )
-
-        if verbose:
-            print(f"[mycommand]{mycommand}")
-
-        stdout, stderr = _execute_shell_command(command=mycommand, timeout=-1, verbose=verbose)
-        return stdout, stderr
-
-    def record(
-        self,
-        audio_filename: str = "myplayback.wav",
-        timeout_seconds=5,
-        # Debug
-        verbose: bool = False,
-    ):
-        """Execute pipewire command to record an audio file, with a timeout of 5
-        seconds with the following code and exiting the shell when tiomeout is over.
-
-        ```bash
-        #!/bin/bash
-        pw-cat --record {audio_filename}
-        # timeout is managed by python3 (when signal CTRL+C is sended)
-        ```
-
-        Args:
-            audio_filename (`str`): Path of the file to be played. *default='myplayback.wav'
-            verbose (`bool`): True enable debug logs. *default=False
-
-        Returns:
-            - stdout (`str`): Shell response to the command in stdout format
-            - stderr (`str`): Shell response response to the command in stderr format
-        """
-        warnings.warn("The name of the function may change on future releases", DeprecationWarning)
-
-        mycommand = ["pw-cat", "--record", audio_filename] + _generate_command_by_dict(
-            mydict=self._pipewire_configs, verbose=verbose
-        )
-
-        if verbose:
-            print(f"[mycommand]{mycommand}")
-
-        stdout, stderr = _execute_shell_command(
-            command=mycommand, timeout=timeout_seconds, verbose=verbose
-        )
-        return stdout, stderr
-
-    def clear_devices(
-        self,
-        mode: str = "all",  # ['all','playback','record']
-        # Debug
-        verbose: bool = False,
-    ):
-        """Function to stop process running under pipewire executed by
-        python controller and with default process name of `pw-cat`, `pw-play` or `pw-record`.
-
-        Args:
-            mode (`str`) : string to kill process under `pw-cat`, `pw-play` or `pw-record`.
-
-        Returns:
-            - stdoutdict (`dict`) : a dictionary with keys of `mode`.
-
-        Example with pipewire:
-            pw-cat process
-        """
-
-        mycommand = self._kill_pipewire[mode]
-
-        if verbose:
-            print(f"[mycommands]{mycommand}")
-
-        stdout, _ = _execute_shell_command(command=mycommand, verbose=verbose)
-
-        return {mode: stdout}
-
- -

Class that controls pipewire command line interface with shell commands, handling outputs, loading default @@ -1355,60 +1355,60 @@

-
#   - - - Controller(verbose: bool = False) -
- -
- View Source -
    def __init__(
-        self,
-        # Debug
-        verbose: bool = False,
-    ):
-        """This constructor load default configs from OS executing
-        the following pipewire command
-
-        ```bash
-        #!/bin/bash
-        # Get defaults from output of:
-        pw-cat -h
-        ```
-        """
-        # LOAD ALL DEFAULT PARAMETERS
-
-        mycommand = ["pw-cat", "-h"]
-
-        # get default parameters with help
-        stdout, _ = _execute_shell_command(command=mycommand, verbose=verbose)  # stderr
-        # convert stdout to dictionary
-        dict_default_values = _get_dict_from_stdout(stdout=str(stdout.decode()), verbose=verbose)
-
-        if verbose:
-            print(self._pipewire_configs)
-
-        # Save default system configs to our json
-        self._pipewire_configs.update(
-            ([(key, dict_default_values[key]) for key in dict_default_values])
-        )
-
-        if verbose:
-            print(self._pipewire_configs)
-
-        # Delete keys with None values
-        self._pipewire_configs = _drop_keys_with_none_values(self._pipewire_configs)
+                                        
+
+ + Controller(verbose: bool = False) - if verbose: - print(self._pipewire_configs) + - # Load values of list targets - self.load_list_targets(mode="playback", verbose=verbose) - self.load_list_targets(mode="record", verbose=verbose) -
+
+ +
 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
+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)
+
-

This constructor load default configs from OS executing the following pipewire command

@@ -1422,49 +1422,49 @@

-
#   - - - def - get_version(self, verbose: bool = False): -
- -
- View Source -
    def get_version(
-        self,
-        # Debug
-        verbose: bool = False,
-    ):
-        """Get version of pipewire installed on OS by executing the following
-        code:
-
-        ```bash
-        #!/bin/bash
-        pw-cli --version
-        ```
-
-        Args:
-            verbose (bool) : True enable debug logs. *default=False
+                                        
+
+ + def + get_version(self, verbose: bool = False) - Returns: - - versions (list) : Versions of pipewire compiled - """ + - mycommand = ["pw-cli", "--version"] - - if verbose: - print(f"[mycommand]{mycommand}") - - stdout, _ = _execute_shell_command(command=mycommand, timeout=-1, verbose=verbose) - versions = stdout.decode().split("\n")[1:] - - self._pipewire_cli["--version"] = versions - - return versions -
+
+ +
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        """
+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:]
+172
+173        self._pipewire_cli["--version"] = versions
+174
+175        return versions
+
-

Get version of pipewire installed on OS by executing the following code:

@@ -1491,67 +1491,67 @@
Returns
-
#   + +
+ + def + verbose(self, status: bool = True) + + - - def - verbose(self, status: bool = True):
+ +
177    def verbose(
+178        self,
+179        status: bool = True,
+180    ):
+181        """Get full log of pipewire stream status with the command `pw-cat`
+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        ```
+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
+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
+
-
- View Source -
    def verbose(
-        self,
-        status: bool = True,
-    ):
-        """Get full log of pipewire stream status with the command `pw-cat`
-
-        An example of pw-cli usage is the code below:
-
-        ```bash
-        #!/bin/bash
-        # For example
-        pw-cat --playback beers.wav --verbose
-        ```
-
-        that will generate an output like this:
-
-        ```bash
-        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 drained
-        stream state changed streaming -> paused
-        stream param change: id=4
-        stream state changed paused -> unconnected
-        stream param change: id=4
-        ```
-        """
-
-        if status:
-            self._pipewire_configs["--verbose"] = "    "
-        else:
-            pass
-
- -

Get full log of pipewire stream status with the command pw-cat

@@ -1595,32 +1595,32 @@
Returns
-
#   + +
+ + def + get_config(self) - - def - get_config(self): -
- -
- View Source -
    def get_config(self):
-        """Return config dictionary with default or setup variables, remember that
-        this object changes only on python-side. Is not updated on real time,
-        For real-time, please create and destroy the class.
-
-        Args:
-            Nothing
+                
 
-        Returns:
-            - _pipewire_configs (`dict`) : dictionary with config values
-
-        """
-
-        return self._pipewire_configs
-
+
+ +
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
+237
+238        """
+239
+240        return self._pipewire_configs
+
-

Return config dictionary with default or setup variables, remember that this object changes only on python-side. Is not updated on real time, @@ -1644,202 +1644,188 @@

Returns
-
#   - - - def - set_config( - self, - media_type=None, - media_category=None, - media_role=None, - target=None, - latency=None, - rate=None, - channels=None, - channels_map=None, - _format=None, - volume=None, - quality=None, - verbose=False -): + +
+ + def + set_config( self, media_type=None, media_category=None, media_role=None, target=None, latency=None, rate=None, channels=None, channels_map=None, _format=None, volume=None, quality=None, verbose=False) + + +
+ +
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)
+
-
- View Source -
    def set_config(
-        self,
-        # configs
-        media_type=None,
-        media_category=None,
-        media_role=None,
-        target=None,
-        latency=None,
-        rate=None,
-        channels=None,
-        channels_map=None,
-        _format=None,
-        volume=None,
-        quality=None,
-        # Debug
-        verbose=False,
-    ):
-        """Method that get args as variables and set them
-        to the `json` parameter of the class `_pipewire_configs`,
-        then you can use in other method, such as `playback(...)` or
-        `record(...)`. This method verifies values to avoid wrong
-        settings.
-
-        Args:
-            media_type : Set media type
-            media_category : Set media category
-            media_role : Set media role
-            target : Set node target
-            latency : Set node latency *example=100ms
-            rate : Set sample rate [8000,11025,16000,22050,44100,48000,88200,96000,176400,192000,352800,384000]
-            channels : Numbers of channels [1,2]
-            channels_map : ["stereo", "surround-51", "FL,FR", ...]
-            _format : ["u8", "s8", "s16", "s32", "f32", "f64"]
-            volume : Stream volume [0.000, 1.000]
-            quality : Resampler quality [0, 15]
-            verbose (`bool`): True enable debug logs. *default=False
-
-        Returns:
-            - Nothing
-
-        More:
-            Check all links listed at the beginning of this page
-        """  # 1 - media_type
-        if media_type:
-            self._pipewire_configs["--media-type"] = str(media_type)
-        elif media_type is None:
-            pass
-        else:
-            raise ValueError(
-                f"{MESSAGES_ERROR['ValueError']}[media_type='{media_type}'] EMPTY VALUE"
-            )
-        # 2 - media_category
-        if media_category:
-            self._pipewire_configs["--media-category"] = str(media_category)
-        elif media_category is None:
-            pass
-        else:
-            raise ValueError(
-                f"{MESSAGES_ERROR['ValueError']}[media_category='{media_category}'] EMPTY VALUE"
-            )
-        # 3 - media_role
-        if media_role:
-            self._pipewire_configs["--media-role"] = str(media_role)
-        elif media_role is None:
-            pass
-        else:
-            raise ValueError(
-                f"{MESSAGES_ERROR['ValueError']}[media_role='{media_role}'] EMPTY VALUE"
-            )
-        # 4 - target
-        if target:
-            self._pipewire_configs["--target"] = str(target)
-        elif target is None:
-            pass
-        else:
-            raise ValueError(f"{MESSAGES_ERROR['ValueError']}[target='{target}'] EMPTY VALUE")
-        # 5 - latency
-        if latency:
-            if any(chr.isdigit() for chr in latency):  # Contain numbers
-                self._pipewire_configs["--latency"] = str(latency)
-            else:
-                raise ValueError(
-                    f"{MESSAGES_ERROR['ValueError']}[latency='{latency}'] NO NUMBER IN VARIABLE"
-                )
-        elif latency is None:
-            pass
-        else:
-            raise ValueError(f"{MESSAGES_ERROR['ValueError']}[latency='{latency}'] EMPTY VALUE")
-        # 6 - rate
-        if rate:
-            if rate in RECOMMENDED_RATES:
-                self._pipewire_configs["--rate"] = str(rate)
-            else:
-                raise ValueError(
-                    f"{MESSAGES_ERROR['ValueError']}[rate='{rate}']\
-                         VALUE NOT IN RECOMMENDED LIST \n{RECOMMENDED_RATES}"
-                )
-        elif rate is None:
-            pass
-        else:
-            raise ValueError(f"{MESSAGES_ERROR['ValueError']}[rate='{rate}'] EMPTY VALUE")
-        # 7 - channels
-        if channels:
-            if channels in [1, 2]:  # values
-                self._pipewire_configs["--channels"] = str(channels)
-            else:
-                raise ValueError(
-                    f"{MESSAGES_ERROR['ValueError']}[channels='{channels}']\
-                         WRONG VALUE\n ONLY 1 or 2."
-                )
-        elif channels is None:
-            pass
-        else:
-            raise ValueError(f"{MESSAGES_ERROR['ValueError']}[channels='{channels}'] EMPTY VALUE")
-        # 8 - channels-map
-        if channels_map:
-            self._pipewire_configs["--channels-map"] = str(channels_map)
-        elif channels_map is None:
-            pass
-        else:
-            raise ValueError(
-                f"{MESSAGES_ERROR['ValueError']}[channels_map='{channels_map}'] EMPTY VALUE"
-            )
-        # 9 - format
-        if _format:
-            if _format in RECOMMENDED_FORMATS:
-                self._pipewire_configs["--format"] = str(_format)
-            else:
-                raise ValueError(
-                    f"{MESSAGES_ERROR['ValueError']}[_format='{_format}']\
-                         VALUE NOT IN RECOMMENDED LIST \n{RECOMMENDED_FORMATS}"
-                )
-        elif _format is None:
-            pass
-        else:
-            raise ValueError(f"{MESSAGES_ERROR['ValueError']}[_format='{_format}'] EMPTY VALUE")
-        # 10 - volume
-        if volume:
-            if 0.0 <= volume <= 1.0:
-                self._pipewire_configs["--volume"] = str(volume)
-            else:
-                raise ValueError(
-                    f"{MESSAGES_ERROR['ValueError']}[volume='{volume}']\
-                         OUT OF RANGE \n [0.000, 1.000]"
-                )
-        elif volume is None:
-            pass
-        else:
-            raise ValueError(f"{MESSAGES_ERROR['ValueError']}[volume='{volume}'] EMPTY VALUE")
-        # 11 - quality
-        if quality:
-            if 0 <= quality <= 15:
-                self._pipewire_configs["--quality"] = str(quality)
-            else:
-                raise ValueError(
-                    f"{MESSAGES_ERROR['ValueError']}[quality='{quality}'] OUT OF RANGE \n [0, 15]"
-                )
-        elif quality is None:
-            pass
-        else:
-            raise ValueError(f"{MESSAGES_ERROR['ValueError']}[volume='{volume}'] EMPTY VALUE")
-
-        # 12 - verbose cli
-        if verbose:  # True
-            self._pipewire_configs["--verbose"] = "    "
-        else:
-            pass
-
-        if verbose:
-            print(self._pipewire_configs)
-
- -

Method that get args as variables and set them to the json parameter of the class _pipewire_configs, @@ -1882,45 +1868,45 @@

More
-
#   + +
+ + def + load_list_targets(self, mode, verbose: bool = False) + + - - def - load_list_targets(self, mode, verbose: bool = False):
+ +
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}")
+
-
- View Source -
    def load_list_targets(
-        self,
-        mode,  # playback or record
-        # Debug,
-        verbose: bool = False,
-    ):
-        """Returns a list of targets to playback or record. Then you can use
-        the output to select a device to playback or record.
-        """
-
-        if mode == "playback":
-            mycommand = ["pw-cat", "--playback", "--list-targets"]
-            stdout, _ = _execute_shell_command(command=mycommand, timeout=-1, verbose=verbose)
-            self._pipewire_list_targets["list_playback"] = _generate_dict_list_targets(
-                longstring=stdout.decode(), verbose=verbose
-            )
-        elif mode == "record":
-            mycommand = ["pw-cat", "--record", "--list-targets"]
-            stdout, _ = _execute_shell_command(command=mycommand, timeout=-1, verbose=verbose)
-            self._pipewire_list_targets["list_record"] = _generate_dict_list_targets(
-                longstring=stdout.decode(), verbose=verbose
-            )
-        else:
-            raise AttributeError(MESSAGES_ERROR["ValueError"])
-
-        if verbose:
-            print(f"[mycommand]{mycommand}")
-
- -

Returns a list of targets to playback or record. Then you can use the output to select a device to playback or record.

@@ -1929,69 +1915,69 @@
More
-
#   + +
+ + def + get_list_targets(self, verbose: bool = False) + + - - def - get_list_targets(self, verbose: bool = False):
+ +
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
+
-
- View Source -
    def get_list_targets(
-        self,
-        # Debug,
-        verbose: bool = False,
-    ):
-        """Returns a list of targets to playback or record. Then you can use
-        the output to select a device to playback or record.
-
-        Returns:
-            - `_pipewire_list_targets`
-
-        Examples:
-        ```python
-        >>> Controller().get_list_targets()
-        {
-        "list_playback": {
-            "86": {
-            "description": "Starship/Matisse HD Audio Controller Pro",
-            "prior": "936"
-            },
-            "_list_nodes": [
-            "86"
-            ],
-            "_node_default": [
-            "86"
-            ],
-            "_alsa_node": [
-            "alsa_output.pci-0000_0a_00.4.pro-output-0"
-            ]
-        },
-        "list_record": {
-            "86": {
-            "description": "Starship/Matisse HD Audio Controller Pro",
-            "prior": "936"
-            },
-            "_list_nodes": [
-            "86"
-            ],
-            "_node_default": [
-            "86"
-            ],
-            "_alsa_node": [
-            "alsa_output.pci-0000_0a_00.4.pro-output-0"
-            ]
-        }
-        }
-        ```
-        """
-        if verbose:
-            print(self._pipewire_list_targets)
-        return self._pipewire_list_targets
-
- -

Returns a list of targets to playback or record. Then you can use the output to select a device to playback or record.

@@ -2045,66 +2031,61 @@
Returns
-
#   - - - def - get_list_interfaces( - self, - filtered_by_type: str = True, - type_interfaces: str = 'Client', - verbose: bool = False -): + +
+ + def + get_list_interfaces( self, filtered_by_type: str = True, type_interfaces: str = 'Client', verbose: bool = False) + + +
+ +
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
+
-
- View Source -
    def get_list_interfaces(
-        self,
-        filtered_by_type: str = True,
-        type_interfaces: str = "Client",
-        # Debug
-        verbose: bool = False,
-    ):
-        """Returns a list of applications currently using pipewire on Client.
-        An example of pw-cli usage is the code below:
-
-        ```bash
-        #!/bin/bash
-        pw-cli ls Client
-        ```
-        Args:
-            filtered_by_type : If False, returns all. If not, returns a fitered dict
-            type_interfaces : Set type of Interface ["Client","Link","Node","Factory","Module","Metadata","Endpoint","Session","Endpoint Stream","EndpointLink","Port"]
-
-        Returns:
-            - dict_interfaces_filtered: dictionary with list of interfaces matching conditions
-
-        Examples:
-        ```python
-        >>> Controller().get_list_interfaces()
-
-        ```
-        """
-        mycommand = ["pw-cli", "info", "all"]
-
-        # if verbose:
-        #     print(f"[mycommand]{mycommand}")
-
-        stdout, _ = _execute_shell_command(command=mycommand, timeout=-1, verbose=verbose)
-        dict_interfaces = _generate_dict_interfaces(longstring=stdout.decode(), verbose=verbose)
-
-        if filtered_by_type:
-            dict_interfaces_filtered = _filter_by_type(
-                dict_interfaces=dict_interfaces, type_interfaces=type_interfaces
-            )
-        else:
-            dict_interfaces_filtered = dict_interfaces
-
-        return dict_interfaces_filtered
-
- -

Returns a list of applications currently using pipewire on Client. An example of pw-cli usage is the code below:

@@ -2137,52 +2118,52 @@
Returns
-
#   + +
+ + def + playback(self, audio_filename: str = 'myplayback.wav', verbose: bool = False) + + - - def - playback(self, audio_filename: str = 'myplayback.wav', verbose: bool = False):
+ +
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
+
-
- View Source -
    def playback(
-        self,
-        audio_filename: str = "myplayback.wav",
-        # Debug
-        verbose: bool = False,
-    ):
-        """Execute pipewire command to play an audio file with the following
-        command:
-
-        ```bash
-        #!/bin/bash
-        pw-cat --playback {audio_filename} + {configs}
-        # configs are a concatenated params
-        ```
-
-        Args:
-            audio_filename (`str`): Path of the file to be played. *default='myplayback.wav'
-            verbose (`bool`): True enable debug logs. *default=False
-
-        Returns:
-            - stdout (`str`): Shell response to the command in stdout format
-            - stderr (`str`): Shell response response to the command in stderr format
-        """
-        warnings.warn("The name of the function may change on future releases", DeprecationWarning)
-
-        mycommand = ["pw-cat", "--playback", audio_filename] + _generate_command_by_dict(
-            mydict=self._pipewire_configs, verbose=verbose
-        )
-
-        if verbose:
-            print(f"[mycommand]{mycommand}")
-
-        stdout, stderr = _execute_shell_command(command=mycommand, timeout=-1, verbose=verbose)
-        return stdout, stderr
-
- -

Execute pipewire command to play an audio file with the following command:

@@ -2212,60 +2193,55 @@
Returns
-
#   - - - def - record( - self, - audio_filename: str = 'myplayback.wav', - timeout_seconds=5, - verbose: bool = False -): + +
+ + def + record( self, audio_filename: str = 'myplayback.wav', timeout_seconds=5, verbose: bool = False) + + +
+ +
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
+
-
- View Source -
    def record(
-        self,
-        audio_filename: str = "myplayback.wav",
-        timeout_seconds=5,
-        # Debug
-        verbose: bool = False,
-    ):
-        """Execute pipewire command to record an audio file, with a timeout of 5
-        seconds with the following code and exiting the shell when tiomeout is over.
-
-        ```bash
-        #!/bin/bash
-        pw-cat --record {audio_filename}
-        # timeout is managed by python3 (when signal CTRL+C is sended)
-        ```
-
-        Args:
-            audio_filename (`str`): Path of the file to be played. *default='myplayback.wav'
-            verbose (`bool`): True enable debug logs. *default=False
-
-        Returns:
-            - stdout (`str`): Shell response to the command in stdout format
-            - stderr (`str`): Shell response response to the command in stderr format
-        """
-        warnings.warn("The name of the function may change on future releases", DeprecationWarning)
-
-        mycommand = ["pw-cat", "--record", audio_filename] + _generate_command_by_dict(
-            mydict=self._pipewire_configs, verbose=verbose
-        )
-
-        if verbose:
-            print(f"[mycommand]{mycommand}")
-
-        stdout, stderr = _execute_shell_command(
-            command=mycommand, timeout=timeout_seconds, verbose=verbose
-        )
-        return stdout, stderr
-
- -

Execute pipewire command to record an audio file, with a timeout of 5 seconds with the following code and exiting the shell when tiomeout is over.

@@ -2295,45 +2271,45 @@
Returns
-
#   - - - def - clear_devices(self, mode: str = 'all', verbose: bool = False): -
- -
- View Source -
    def clear_devices(
-        self,
-        mode: str = "all",  # ['all','playback','record']
-        # Debug
-        verbose: bool = False,
-    ):
-        """Function to stop process running under pipewire executed by
-        python controller and with default process name of `pw-cat`, `pw-play` or `pw-record`.
+                                        
+
+ + def + clear_devices(self, mode: str = 'all', verbose: bool = False) - Args: - mode (`str`) : string to kill process under `pw-cat`, `pw-play` or `pw-record`. + - Returns: - - stdoutdict (`dict`) : a dictionary with keys of `mode`. - - Example with pipewire: - pw-cat process - """ - - mycommand = self._kill_pipewire[mode] - - if verbose: - print(f"[mycommands]{mycommand}") - - stdout, _ = _execute_shell_command(command=mycommand, verbose=verbose) - - return {mode: stdout} -
+
+ +
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        """
+628
+629        mycommand = self._kill_pipewire[mode]
+630
+631        if verbose:
+632            print(f"[mycommands]{mycommand}")
+633
+634        stdout, _ = _execute_shell_command(command=mycommand, verbose=verbose)
+635
+636        return {mode: stdout}
+
-

Function to stop process running under pipewire executed by python controller and with default process name of pw-cat, pw-play or pw-record.

From bc326bb8b85cacc27de1c958d6d674f5a2dc0848 Mon Sep 17 00:00:00 2001 From: Pablo Date: Tue, 6 Dec 2022 00:06:00 -0500 Subject: [PATCH 5/8] fix --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 824e865..9d94958 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "flit_core.buildapi" [tool.flit.metadata] module = "pipewire_python" -author = "Pablo Diaz & Anna Absi" +author = "Pablo Diaz" home-page = "https://github.com/pablodz/pipewire_python" requires-python = ">=3.7" description-file = "README.md" From b11a3d2b782babfffd5b2cfdbffdf9e193972793 Mon Sep 17 00:00:00 2001 From: pablodz Date: Tue, 6 Dec 2022 05:06:29 +0000 Subject: [PATCH 6/8] PDOC-Automatic documentation Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- docs/html/pipewire_python.html | 40 ++++--- docs/html/pipewire_python/_constants.html | 22 ++-- docs/html/pipewire_python/_utils.html | 18 ++-- docs/html/pipewire_python/controller.html | 126 +++++++++++++--------- 4 files changed, 126 insertions(+), 80 deletions(-) diff --git a/docs/html/pipewire_python.html b/docs/html/pipewire_python.html index c914835..a782e91 100644 --- a/docs/html/pipewire_python.html +++ b/docs/html/pipewire_python.html @@ -3,14 +3,14 @@ - + pipewire_python API documentation - +
- + - +
 1"""
  2## Description
@@ -300,9 +308,13 @@ 

Tutorial

} let heading; - switch (result.doc.type) { + switch (result.doc.kind) { case "function": - heading = `${doc.funcdef} ${doc.fullname}${doc.signature}:`; + if (doc.fullname.endsWith(".__init__")) { + heading = `${doc.fullname.replace(/\.__init__$/, "")}${doc.signature}`; + } else { + heading = `${doc.funcdef} ${doc.fullname}${doc.signature}`; + } break; case "class": heading = `class ${doc.fullname}`; @@ -323,7 +335,7 @@

Tutorial

} html += `
- ${heading} + ${heading}
${doc.doc}
`; diff --git a/docs/html/pipewire_python/_constants.html b/docs/html/pipewire_python/_constants.html index ff00bc2..7537c39 100644 --- a/docs/html/pipewire_python/_constants.html +++ b/docs/html/pipewire_python/_constants.html @@ -3,14 +3,14 @@ - + pipewire_python._constants API documentation - +
- + - +
 1"""
  2Here we store constant values, don't expect
@@ -182,9 +186,13 @@ 

} let heading; - switch (result.doc.type) { + switch (result.doc.kind) { case "function": - heading = `${doc.funcdef} ${doc.fullname}${doc.signature}:`; + if (doc.fullname.endsWith(".__init__")) { + heading = `${doc.fullname.replace(/\.__init__$/, "")}${doc.signature}`; + } else { + heading = `${doc.funcdef} ${doc.fullname}${doc.signature}`; + } break; case "class": heading = `class ${doc.fullname}`; @@ -205,7 +213,7 @@

} html += `
- ${heading} + ${heading}
${doc.doc}
`; diff --git a/docs/html/pipewire_python/_utils.html b/docs/html/pipewire_python/_utils.html index 428dd64..d028e85 100644 --- a/docs/html/pipewire_python/_utils.html +++ b/docs/html/pipewire_python/_utils.html @@ -3,14 +3,14 @@ - + pipewire_python._utils API documentation - +

- + - +
  1"""
   2Here we store internal functions, don't expect
@@ -455,9 +455,13 @@ 

} let heading; - switch (result.doc.type) { + switch (result.doc.kind) { case "function": - heading = `${doc.funcdef} ${doc.fullname}${doc.signature}:`; + if (doc.fullname.endsWith(".__init__")) { + heading = `${doc.fullname.replace(/\.__init__$/, "")}${doc.signature}`; + } else { + heading = `${doc.funcdef} ${doc.fullname}${doc.signature}`; + } break; case "class": heading = `class ${doc.fullname}`; @@ -478,7 +482,7 @@

} html += `
- ${heading} + ${heading}
${doc.doc}
`; diff --git a/docs/html/pipewire_python/controller.html b/docs/html/pipewire_python/controller.html index 0cefe47..403cf16 100644 --- a/docs/html/pipewire_python/controller.html +++ b/docs/html/pipewire_python/controller.html @@ -3,14 +3,14 @@ - + pipewire_python.controller API documentation - +

- + - +
  1"""
   2## Documentation
@@ -1413,10 +1413,12 @@ 

This constructor load default configs from OS executing the following pipewire command

-
#!/bin/bash
+
+
#!/bin/bash
 # Get defaults from output of:
 pw-cat -h
-
+
+
@@ -1426,7 +1428,7 @@

def - get_version(self, verbose: bool = False) + get_version(self, verbose: bool = False): @@ -1469,17 +1471,19 @@

Get version of pipewire installed on OS by executing the following code:

-
#!/bin/bash
+
+
#!/bin/bash
 pw-cli --version
-
+
+
-
Args
+
Arguments:
  • verbose (bool) : True enable debug logs. *default=False
-
Returns
+
Returns:
    @@ -1495,7 +1499,7 @@
    Returns
    def - verbose(self, status: bool = True) + verbose(self, status: bool = True): @@ -1557,14 +1561,17 @@
    Returns

    An example of pw-cli usage is the code below:

    -
    #!/bin/bash
    +
    +
    #!/bin/bash
     # For example
     pw-cat --playback beers.wav --verbose
    -
    +
    +

    that will generate an output like this:

    -
    opened file "beers.wav" format 00010002 channels:2 rate:44100
    +
    +
    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
    @@ -1589,7 +1596,8 @@ 
    Returns
    stream param change: id=4 stream state changed paused -> unconnected stream param change: id=4 -
    +
    +
    @@ -1599,7 +1607,7 @@
    Returns
    def - get_config(self) + get_config(self): @@ -1626,13 +1634,13 @@
    Returns
    this object changes only on python-side. Is not updated on real time, For real-time, please create and destroy the class.

    -
    Args
    +
    Arguments:
    • Nothing
    -
    Returns
    +
    Returns:
      @@ -1648,7 +1656,7 @@
      Returns
      def - set_config( self, media_type=None, media_category=None, media_role=None, target=None, latency=None, rate=None, channels=None, channels_map=None, _format=None, volume=None, quality=None, verbose=False) + set_config( self, media_type=None, media_category=None, media_role=None, target=None, latency=None, rate=None, channels=None, channels_map=None, _format=None, volume=None, quality=None, verbose=False): @@ -1833,7 +1841,7 @@
      Returns
      record(...). This method verifies values to avoid wrong settings.

      -
      Args
      +
      Arguments:
      • media_type : Set media type
      • @@ -1850,7 +1858,7 @@
        Args
      • verbose (bool): True enable debug logs. *default=False
      -
      Returns
      +
      Returns:
        @@ -1858,7 +1866,7 @@
        Returns
      -
      More
      +
      More:

      Check all links listed at the beginning of this page

      @@ -1872,7 +1880,7 @@
      More
      def - load_list_targets(self, mode, verbose: bool = False) + load_list_targets(self, mode, verbose: bool = False): @@ -1919,7 +1927,7 @@
      More
      def - get_list_targets(self, verbose: bool = False) + get_list_targets(self, verbose: bool = False): @@ -1982,7 +1990,7 @@
      More

      Returns a list of targets to playback or record. Then you can use the output to select a device to playback or record.

      -
      Returns
      +
      Returns:
        @@ -1992,7 +2000,8 @@
        Returns

        Examples:

        -
        >>> Controller().get_list_targets()
        +
        +
        >>> Controller().get_list_targets()
         {
         "list_playback": {
             "86": {
        @@ -2025,7 +2034,8 @@ 
        Returns
        ] } } -
        +
        +
      @@ -2035,7 +2045,7 @@
      Returns
      def - get_list_interfaces( self, filtered_by_type: str = True, type_interfaces: str = 'Client', verbose: bool = False) + get_list_interfaces( self, filtered_by_type: str = True, type_interfaces: str = 'Client', verbose: bool = False): @@ -2090,18 +2100,20 @@
      Returns

      Returns a list of applications currently using pipewire on Client. An example of pw-cli usage is the code below:

      -
      #!/bin/bash
      +
      +
      #!/bin/bash
       pw-cli ls Client
      -
      +
      +
      -
      Args
      +
      Arguments:
      • filtered_by_type : If False, returns all. If not, returns a fitered dict
      • type_interfaces : Set type of Interface ["Client","Link","Node","Factory","Module","Metadata","Endpoint","Session","Endpoint Stream","EndpointLink","Port"]
      -
      Returns
      +
      Returns:
        @@ -2111,8 +2123,10 @@
        Returns

        Examples:

        -
        >>> Controller().get_list_interfaces()
        -
        +
        +
        >>> Controller().get_list_interfaces()
        +
        +
      @@ -2122,7 +2136,7 @@
      Returns
      def - playback(self, audio_filename: str = 'myplayback.wav', verbose: bool = False) + playback(self, audio_filename: str = 'myplayback.wav', verbose: bool = False): @@ -2168,19 +2182,21 @@
      Returns

      Execute pipewire command to play an audio file with the following command:

      -
      #!/bin/bash
      +
      +
      #!/bin/bash
       pw-cat --playback {audio_filename} + {configs}
       # configs are a concatenated params
      -
      +
      +
      -
      Args
      +
      Arguments:
      • audio_filename (str): Path of the file to be played. *default='myplayback.wav'
      • verbose (bool): True enable debug logs. *default=False
      -
      Returns
      +
      Returns:
        @@ -2197,7 +2213,7 @@
        Returns
        def - record( self, audio_filename: str = 'myplayback.wav', timeout_seconds=5, verbose: bool = False) + record( self, audio_filename: str = 'myplayback.wav', timeout_seconds=5, verbose: bool = False): @@ -2246,19 +2262,21 @@
        Returns

        Execute pipewire command to record an audio file, with a timeout of 5 seconds with the following code and exiting the shell when tiomeout is over.

        -
        #!/bin/bash
        +
        +
        #!/bin/bash
         pw-cat --record {audio_filename}
         # timeout is managed by python3 (when signal CTRL+C is sended)
        -
        +
        +
        -
        Args
        +
        Arguments:
        • audio_filename (str): Path of the file to be played. *default='myplayback.wav'
        • verbose (bool): True enable debug logs. *default=False
        -
        Returns
        +
        Returns:
          @@ -2275,7 +2293,7 @@
          Returns
          def - clear_devices(self, mode: str = 'all', verbose: bool = False) + clear_devices(self, mode: str = 'all', verbose: bool = False): @@ -2314,13 +2332,13 @@
          Returns

          Function to stop process running under pipewire executed by python controller and with default process name of pw-cat, pw-play or pw-record.

          -
          Args
          +
          Arguments:
          • mode (str) : string to kill process under pw-cat, pw-play or pw-record.
          -
          Returns
          +
          Returns:
            @@ -2328,7 +2346,7 @@
            Returns
          -
          Example with pipewire
          +
          Example with pipewire:

          pw-cat process

          @@ -2439,9 +2457,13 @@
          Example with pipewire
          } let heading; - switch (result.doc.type) { + switch (result.doc.kind) { case "function": - heading = `${doc.funcdef} ${doc.fullname}${doc.signature}:`; + if (doc.fullname.endsWith(".__init__")) { + heading = `${doc.fullname.replace(/\.__init__$/, "")}${doc.signature}`; + } else { + heading = `${doc.funcdef} ${doc.fullname}${doc.signature}`; + } break; case "class": heading = `class ${doc.fullname}`; @@ -2462,7 +2484,7 @@
          Example with pipewire
          } html += `
          - ${heading} + ${heading}
          ${doc.doc}
          `; From 6258d1a35db1bb12a051879df980df1bc3f860a2 Mon Sep 17 00:00:00 2001 From: Pablo Diaz Date: Sun, 1 Jan 2023 17:48:11 -0400 Subject: [PATCH 7/8] Feature: suport py3.10 & py3.11 --- .github/workflows/build.yml | 2 ++ LICENSE | 2 +- pipewire_python/__init__.py | 2 +- pipewire_python/controller.py | 2 -- pyproject.toml | 2 ++ tox.ini | 8 +++++++- 6 files changed, 13 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f16520c..7ab2173 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,6 +15,8 @@ jobs: - 3.7 - 3.8 - 3.9 + - 3.10 + - 3.11 # env: # PYTHON_FOR_COVERAGE: "3.9" steps: diff --git a/LICENSE b/LICENSE index 120f108..33e6146 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2021 Pablo Diaz & Anna Absi +Copyright (c) 2022 Pablo Diaz Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/pipewire_python/__init__.py b/pipewire_python/__init__.py index a942384..99dbcb0 100644 --- a/pipewire_python/__init__.py +++ b/pipewire_python/__init__.py @@ -31,7 +31,7 @@ - 🎵 Pipewire APIs https://www.linuxfromscratch.org/blfs/view/cvs/multimedia/pipewire.html - 🎵 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 diff --git a/pipewire_python/controller.py b/pipewire_python/controller.py index 5ea246c..ee6818f 100644 --- a/pipewire_python/controller.py +++ b/pipewire_python/controller.py @@ -16,8 +16,6 @@ _generate_dict_interfaces, _generate_dict_list_targets, _get_dict_from_stdout, - _print_std, - _update_dict_by_dict, ) # Loading constants Constants.py diff --git a/pyproject.toml b/pyproject.toml index 9d94958..54e17bf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,6 +17,8 @@ classifiers = [ "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", ] diff --git a/tox.ini b/tox.ini index 50831d9..10668aa 100644 --- a/tox.ini +++ b/tox.ini @@ -3,7 +3,11 @@ # CONFIGS https://medium.com/analytics-vidhya/essential-developer-tools-for-improving-your-python-code-71616254134b [tox] envlist = - py39 # python 3.9 + py37 + py38 + py39 + py310 + py311 isolated_build = true [gh-actions] @@ -11,6 +15,8 @@ python = 3.7: py37 3.8: py38 3.9: py39 + 3.10: py310 + 3.11: py311 [testenv] description= run the tests with pytest under {basepython} From 964be73fc5524920ffed83a43266d956c40f6c5f Mon Sep 17 00:00:00 2001 From: pablodz Date: Sun, 1 Jan 2023 21:48:34 +0000 Subject: [PATCH 8/8] 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}