Suche PTT / Audio Ansatz

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
mmueller-87
User
Beiträge: 12
Registriert: Sonntag 11. Juni 2023, 07:25

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)
Benutzeravatar
__blackjack__
User
Beiträge: 14005
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@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()
“The best book on programming for the layman is »Alice in Wonderland«; but that's because it's the best book on anything for the layman.” — Alan J. Perlis
Antworten