Seite 1 von 1

Suche PTT / Audio Ansatz

Verfasst: Donnerstag 20. Februar 2025, 20:57
von mmueller-87
Guten Abend an alle,

da ihr mir letztes mal so gut geholfen habt, muss ich euch noch eine Frage stellen. Ich bin immer noch ein Neuling in dem ganzen Gebiet. Ich suche eine Möglichkeit einer PTT (Push to talk) Steuerung. Ich benötige ein simples ausführbares Script, das bei einem Audioausgang eine COM Schnittstelle (Beispielweise: /dev/ttyUSB0) durchschaltet und zwar solange bis das Audiosignal (Ausgang) wieder abfällt. Ich habe mal versucht etwas zu basteln, aber dieses gebastelte funktioniert nur sporadisch, also mal weniger als mehr.

Kann mir einer helfen?

Code: Alles auswählen

import alsaaudio
import audioop
import serial
import time
import sys

com = '/dev/ttyUSB0'
dbm = 0
delay = 0
level = 100
dbr = 0
dbx = 0

rs232 = serial.Serial(str(com), baudrate = 38400, timeout = 3.0)

audio = alsaaudio.PCM(alsaaudio.PCM_CAPTURE, alsaaudio.PCM_NONBLOCK)
audio.setformat(alsaaudio.PCM_FORMAT_S16_LE)
audio.setperiodsize(160)
audio.setchannels(1)
audio.setrate(8000)

while True:
    try:
        len, data = audio.read()
        if audioop.avgpp(data, 1) > dbm:
            dbx = dbx + 2
            if dbx > delay:
                dbx = dbx - 1
                dbr = 0
                rs232.setDTR(1)
                rs232.setRTS(1)
            time.sleep(.025)
        else:
            dbr = dbr + 2
            if dbr >= level:
                dbr = dbr - 1
                dbx = 0
                rs232.setDTR(0)
                rs232.setRTS(0)
        time.sleep(.010)
    except Exception as e:
        print(e)

Re: Suche PTT / Audio Ansatz

Verfasst: Samstag 15. März 2025, 13:59
von __blackjack__
@mmueller-87: `sys` wird importiert, aber nirgends verwendet.

Es wäre sinnvoll Variablen und Konstanten für den Leser sichtbar zu machen. Konstanten werden per Konvention komplett gross geschrieben.

`com` ist bereits an eine Zeichenkette gebunden, da macht es keinen Sinn noch mal `str()` mit aufzurufen.

Da keine Daten über die serielle Schnittstelle gehen, macht ein `timeout`-Wert keinen Sinn.

Die ganzen Werte für das `PCM`-Objekt hätte man auch gleich beim erstellen des Objekts mitgeben können.

Eine Ausnahmebehandlung die *alle* Ausnahmen durch Ausgabe des Ausnahmeobjekts ohne den Traceback, und dann so weitermachen als wär nichts passiert ”behandelt”, ist selten eine sinnvolle Ausnahmebehandlung.

`len()` ist der Name einer eingebauten Funktion, den sollte man nicht für etwas anderes verwenden.

Der Code behandelt einen eventuellen Pufferüberlauf überhaupt nicht.

`avgpp()` wird mit falschen Argumenten aufgerufen. Die Audiodaten sind 16 Bit und werden dann dieser Funktion mit der Angabe sie wären 8 Bit übergeben. Das berechnet also nicht das richtige. Die Funktion an sich ist vielleicht auch fragwürdig. Um die Dokumentation zu zitieren: „No filtering is done, so the usefulness of this routine is questionable.“

Ausserdem ist die Kombination aus `PCM_NONBLOCK` und `sleep()` um dann doch irgendwie indirekt eine Puffergrösse zu haben auch komisch. Ebenso das ``+= 2`` und ``-= 1``. Da sollte erklärt werden warum das so gemacht wird. Und warum das okay ist das so zu machen, mit allen möglichen Randfällen. Die Puffergrösse und die `sleep()`-Zeiten hängen ja auch zusammen. Das sollte auch erklärt werden und auch nur eines von beidem angegeben werden, während das andere berechnet wird. Sonst kann man das ja gar nicht sicher ändern.

Bei `Serial` sollte man die veraltete API nicht mehr verwenden. Die beiden Leitungen sind mittlerweile Properties. Apropos veraltet: das `audioop`-Modul gibt es in den neuesten Python-Versionen nicht mehr.

Zwischenstand (ungetestet):

Code: Alles auswählen

#!/usr/bin/env python3
import audioop
import time
from contextlib import closing

import alsaaudio
import serial

SERIAL_PORT = "/dev/ttyUSB0"
MIN_DBM = 0
DELAY = 0
LEVEL = 100


def main():
    with serial.Serial(SERIAL_PORT, baudrate=38_400) as rs232:
        with closing(
            alsaaudio.PCM(
                alsaaudio.PCM_CAPTURE,
                alsaaudio.PCM_NONBLOCK,
                8000,
                1,
                alsaaudio.PCM_FORMAT_S16_LE,
                160,
            )
        ) as audio:
            dbr = 0
            dbx = 0
            while True:
                frame_count, data = audio.read()
                if frame_count > 0:
                    if audioop.avgpp(data, 2) > MIN_DBM:
                        dbx += 2
                        if dbx > DELAY:
                            dbx -= 1
                            dbr = 0
                            rs232.dtr = 1
                            rs232.rts = 1

                        time.sleep(0.025)
                    else:
                        dbr += 2
                        if dbr >= LEVEL:
                            dbr -= 1
                            dbx = 0
                            rs232.dtr = 0
                            rs232.rts = 0

                time.sleep(0.010)


if __name__ == "__main__":
    main()