dtmfbox (AB/CB/CT VoIP/ISDN/Analog)

bodega schrieb:
Die while-Schleife hatte ich mal eingebaut, damit voip_listen() noch ein bisschen laufen kann (um Meldungen abzuholen). Ich bin mir nicht sicher, ob das mal zum Workaround gedient hatte, da die Registrierung beim VoIP-Provider nicht immer aufgehoben wurde. Wenn das auf der FB Probleme macht, sollte man es rausnehmen. Ich müsste nur nochmal einen Blick auf die Registrierungssache werfen.

Die VoIP Deregistrierung sollte doch an dieser stelle gemacht werden:
Code:
    // Deinit VoIP
    voip_close();
und wenn sich diese funktion solange blockt bis alles deregistriert ist, dann sollte es doch passen. Musst nur schaun, dass hier nicht auch mehrere Threads am laufen sind (könnte ja sein, denn pjsip verwendet ja mehrere threads)

@gfuer:
ja, du hast reccht. ich hatte auch versucht ein global "int var=0;" hinzuzufügen und dann hat der gcc sich über multiple definitions beschwert. wenn man es hingegen mit uninitialisiert macht, dann schluckt er es. aber sauberer ist es auf jeden Fall mit der "extern ..." definition.

EDIT: @bodega
teste gerade die neuste version ausm trunk. dabei ist mir was aufgefallen. du hast die DDI script aufrufe eingebaut, die eigentlich sehr praktisch sind. nur bei mir, und wahrscheinlich wirklich nur bei mir wegen meiner komischen TK-Anlage, kommt er da am internen controller durcheinander. Ich wähle z.B. 00 danach leitet die Anlage 0 und 0 weiter, dann kommt der CAPI_CONNECT, nur was dann kommt, die DDI Aufrufe, die wiederholen dann die Nummer nochmal, da erscheint dann 0000 (siehe Log:)
Code:
 23:02:03.602  capi_events.c (IND, CTRL 3, PLCI: 771) - CAPI_CONNECT (Acc#: 00 ( 0), Target#: <mymsn>)
 23:02:03.603 script_funcs.c Run script: "/var/stick/dist/abscript.sh" "CONNECT"  "CAPI" "OUTGOING" "0" "-1" "<mymsn>" "00" "1" &
sh: /var/stick/dist/abscript.sh: not found
 23:02:03.651  capi_events.c (IND, CTRL 3, PLCI: 771) - DIALED (0) (3)
 23:02:03.652   capi_funcs.c DTMF RECEIVED: 0
 23:02:03.652 script_funcs.c Run script: "/var/stick/dist/abscript.sh" "DDI" "CA PI" "OUTGOING" "0" "-1" "<mymsn>" "0000" "1" "0" &
sh: /var/stick/dist/abscript.sh: not found
 23:02:03.690  capi_events.c (IND, CTRL 3, PLCI: 771) - DIALED (0) (3)
 23:02:03.691   capi_funcs.c DTMF RECEIVED: 0
 23:02:03.691 script_funcs.c Run script: "/var/stick/dist/abscript.sh" "DDI" "CA PI" "OUTGOING" "0" "-1" "<mymsn>" "0000" "1" "0" &
sh: /var/stick/dist/abscript.sh: not found
 23:02:03.760  capi_events.c (IND, CTRL 3, PLCI: 771) - CAPI_INFO (0xc000) - UNK NOWN INFO
 23:02:03.762  capi_events.c (IND, CTRL 3, PLCI: 771) - CAPI_INFO (0x800d) - SET UP ACK
 23:02:03.764  capi_events.c (IND, CTRL 3, PLCI: 771) - CAPI_INFO (0x001e) - PRO GRESS INDICATOR (0x02)
 23:02:03.766  capi_events.c (IND, CTRL 3, PLCI: 771) - CAPI_INFO (0xc000) - UNK NOWN INFO
 23:02:13.733  capi_events.c (IND, CTRL 3, PLCI: 771) - CAPI_DISCONNECT
 23:02:13.734   capi_funcs.c CAPI 0x3304 - Another application got that call
 [B]23:02:13.735 script_funcs.c Run script: "/var/stick/dist/abscript.sh" "DISCONNE CT" "CAPI" "OUTGOING" "0" "-1" "<mymsn>" "0000" "1" &[/B]
Wenn ich eine normale Nummer wähle: z.B. 12345678, dann folgen die Skriptaufrufe so:
Code:
 23:02:40.354 script_funcs.c Run script: "/var/stick/dist/abscript.sh" "CONNECT"  "CAPI" "OUTGOING" "0" "-1" "<mymsn>" "12" "1" &
 23:02:40.397 script_funcs.c Run script: "/var/stick/dist/abscript.sh" "DDI" "CA PI" "OUTGOING" "0" "-1" "<mymsn>" "[B]12[/B]12" "1" "1" &
 23:02:40.438 script_funcs.c Run script: "/var/stick/dist/abscript.sh" "DDI" "CA PI" "OUTGOING" "0" "-1" "<mymsn>" "1212" "1" "2" &
 
23:02:40.525 script_funcs.c Run script: "/var/stick/dist/abscript.sh" "DDI" "CA PI" "OUTGOING" "0" "-1" "<mymsn>" "1212345" "1" "3" &
23:02:40.578 script_funcs.c Run script: "/var/stick/dist/abscript.sh" "DDI" "CA PI" "OUTGOING" "0" "-1" "<mymsn>" "1212345" "1" "4" &
 23:02:40.624 script_funcs.c Run script: "/var/stick/dist/abscript.sh" "DDI" "CA PI" "OUTGOING" "0" "-1" "<mymsn>" "1212345" "1" "5" &

bisher kam alles via DIALED messages rein, jetzt wechselt die TK-Anlage auf DIALING messages (kleiner Puffer... ;-) ? )

 23:02:40.687 script_funcs.c Run script: "/var/stick/dist/abscript.sh" "DDI" "CA PI" "OUTGOING" "0" "-1" "<mymsn>" "12123456" "1" "6" &
 23:02:40.741 script_funcs.c Run script: "/var/stick/dist/abscript.sh" "DDI" "CA PI" "OUTGOING" "0" "-1" "<mymsn>" "121234567" "1" "7" &
23:02:40.798 script_funcs.c Run script: "/var/stick/dist/abscript.sh" "DDI" "CA PI" "OUTGOING" "0" "-1" "<mymsn>" "1212345678" "1" "8" &
[B]23:02:13.735 script_funcs.c Run script: "/var/stick/dist/abscript.sh" "DISCONNE CT" "CAPI" "OUTGOING" "0" "-1" "<mymsn>" "1212345678" "1" &[/B]
ist das ohne TK-Anlage genauso? Das stört halt bisschen, wenn ich im CONNECT skript-aufruf eine datei erzeuge tmp.00 und dann im DISCONNECT aufruf die datei tmp.0000 gelöscht werden soll ;-)
 
Zuletzt bearbeitet:
Also ohne TK-Anlage ist es nicht so. Ich habe jedoch festgestellt, das nach dem zweiten '#' die Nr. auch falsch übergeben wird (ist jedoch nicht so schlimm, wenn man nach dem zweiten '#' nichts weiter übergibt).
florixyz schrieb:
bisher kam alles via DIALED messages rein, jetzt wechselt die TK-Anlage auf DIALING messages (kleiner Puffer... ;-) ? )
Beim DIALING kommen die Zeichenfolgen einzeln an (wie DTMF). Beim DIALED kommen sie im Bündel. Dabei wird die Zielrufnummer auch immer länger.

Hier mal ein Log, wie bei mir die interne Wahl ausschaut:
Code:
 23:55:12.994  capi_events.c (IND, CTRL 3, PLCI: 4867) - CAPI_CONNECT (Acc#: unknown (0), Target#: xxxxxxx)
 23:55:12.994 script_funcs.c Run script: "/var/media/ftp/usb/dtmfbox/script/script_main.sh" "CONNECT" "CAPI" "OUTGOING" "0" "-1" "xxxxxxx" "unknown" "1" &
[B] 23:55:13.064  capi_events.c (IND, CTRL 3, PLCI: 4867) - CAPI_INFO (0x800d) - SETUP ACK
 23:55:13.065  capi_events.c (IND, CTRL 3, PLCI: 4867) - CAPI_INFO (0x001e) - PROGRESS INDICATOR (0x02)[/B]
 23:55:13.066  capi_events.c (IND, CTRL 3, PLCI: 4867) - CAPI_INFO (0xc000) - UNKNOWN INFO
 23:55:13.114  capi_events.c (IND, CTRL 3, PLCI: 4867) - CAPI_INFO (0x002c) - UNKNOWN INFO
 23:55:13.115  capi_events.c (IND, CTRL 3, PLCI: 4867) - DIALED (*) (6)
 23:55:13.116   capi_funcs.c DTMF RECEIVED: *
 23:55:13.116  capi_events.c (IND, CTRL 3, PLCI: 4867) - DIALED (#) (6)
 23:55:13.118   capi_funcs.c DTMF RECEIVED: #
 23:55:13.119 script_funcs.c Run script: "/var/media/ftp/usb/dtmfbox/script/script_main.sh" "DDI" "CAPI" "OUTGOING" "0" "-1" "xxxxxxx" "*#001#" "1" "*" &
 23:55:13.163  capi_events.c (IND, CTRL 3, PLCI: 4867) - DIALED (0) (6)
 23:55:13.164   capi_funcs.c DTMF RECEIVED: 0
 23:55:13.166  capi_events.c (IND, CTRL 3, PLCI: 4867) - DIALED (0) (6)
 23:55:13.166   capi_funcs.c DTMF RECEIVED: 0
 23:55:13.167  capi_events.c (IND, CTRL 3, PLCI: 4867) - DIALED (1) (6)
 23:55:13.168   capi_funcs.c DTMF RECEIVED: 1
 23:55:13.169  capi_events.c (IND, CTRL 3, PLCI: 4867) - DIALED (#) (6)
 23:55:13.170   capi_funcs.c DTMF RECEIVED: #
 23:55:13.173 script_funcs.c Run script: "/var/media/ftp/usb/dtmfbox/script/script_main.sh" "DDI" "CAPI" "OUTGOING" "0" "-1" "xxxxxxx" "*#001#" "1" "001" &
 23:55:13.315  capi_events.c (IND, CTRL 3, PLCI: 4867) - CAPI_INFO (0xc000) - UNKNOWN INFO
 23:55:13.384  capi_events.c (IND, CTRL 3, PLCI: 4867) - CAPI_INFO (0x8003) - PROGRESS
 23:55:13.385  capi_events.c (IND, CTRL 3, PLCI: 4867) - CAPI_INFO (0xc000) - UNKNOWN INFO
 23:55:13.438  capi_events.c (IND, CTRL 3, PLCI: 4867) - CAPI_INFO (0x8003) - PROGRESS
 23:55:13.439  capi_events.c (IND, CTRL 3, PLCI: 4867) - CAPI_INFO (0xc000) - UNKNOWN INFO
 23:55:14.051 script_funcs.c Queue: 6, Pending: 0
 23:55:14.055 script_funcs.c [0] - hook up!
 23:55:14.057    capi_ctrl.c (CNF, CTRL 3, PLCI: 4867) - CAPI_ALERT
 23:55:14.060  capi_events.c (IND, CTRL 3, PLCI: 4867) - CAPI_INFO (0x8001) - ALERTING
 23:55:14.062  capi_events.c (IND, CTRL 3, PLCI: 4867) - CAPI_INFO (0x001e) - PROGRESS INDICATOR (0x02)
 23:55:14.063  capi_events.c (IND, CTRL 3, PLCI: 4867) - CAPI_INFO (0xc000) - UNKNOWN INFO
 23:55:14.064  capi_events.c (IND, CTRL 3, PLCI: 4867) - CAPI_CONNECT_ACTIVE
 23:55:14.065 script_funcs.c Run script: "/var/media/ftp/usb/dtmfbox/script/script_main.sh" "CONFIRMED" "CAPI" "OUTGOING" "0" "-1" "xxxxxxx" "*#001#" "1" &
 23:55:14.144  capi_events.c (IND, CTRL 3, PLCI: 4867, NCCI: 70403) - CAPI_CONNECT_B3
 23:55:14.146  capi_events.c (IND, CTRL 3, PLCI: 4867, NCCI: 70403) - CAPI_CONNECT_B3_ACTIVE
 23:55:14.146   capi_funcs.c Enable DTMF for NCCI 70403
 23:55:14.147    capi_ctrl.c (CNF, CTRL 3, PLCI: 4867, NCCI: 70403) - CAPI_FACILITY
 23:55:14.353 script_funcs.c Queue: 7, Pending: 0
 23:55:14.353 script_funcs.c [0] - change scriptfile /var/media/ftp/usb/dtmfbox/script/script_admin.sh
 23:55:14.992 script_funcs.c Queue: 8, Pending: 0
 23:55:14.992 script_funcs.c [0] - playing /var/tmp/0-espeak.3089...
 23:55:14.993   filestream.c Filestream player created (/var/tmp/0-espeak.3089, 22050hz, 16bit, mono)
 23:55:18.148  capi_events.c (IND, CTRL 3, PLCI: 4867) - CAPI_INFO (0xc000) - UNKNOWN INFO
 23:55:18.148  capi_events.c (IND, CTRL 3, PLCI: 4867, NCCI: 70403) - CAPI_DISCONNECT_B3
 23:55:18.149 script_funcs.c Run script: "/var/media/ftp/usb/dtmfbox/script/script_admin.sh" "DISCONNECT" "CAPI" "OUTGOING" "0" "-1" "xxxxxxx" "*#001#" "1" &
 23:55:18.216   filestream.c Filestream player destroyed!
 23:55:18.325  capi_events.c (IND, CTRL 3, PLCI: 4867) - CAPI_DISCONNECT
cat: /var/media/ftp/usb/dtmfbox/tmp/current_script_0.tmp: No such file or directory

Was mir dabei spontan auffällt ist, dass SETUP ACK und PROGRESS INDICATOR erst später kommt (nach 00). Man müsste hier wahrscheinlich an die Funktion EV_CAPI_INFO() ran, damit der Wählstring erst nach dieser Message gespeichert wird.
 
Zuletzt bearbeitet:
Oje, in meinem Log kommen Setup ack, ja erst nachdem noch zwei dialed messages angekommen sind und der script mit ddi aufgerufen wurde .... jo, evtl. wie du gesagt hast in EV_CAPI_INFO() was ändern. eilt aber nicht so. wenn ich dafür bisschen zeit hab (bzw. wenn es mich mal zu sehr stört, dann schau ichs mir auch mal an).

bin grad dabei mir anzusehen wie die streams gemixt werden. passiert für capi ja in capi_streaming() (wo passiert es denn eigentlich für voip?). hab allerdings noch keine elegante lösung gefunden, wie man einen stream ausfaden könnte wenn ein anderer kommt, bzw. auch über skripte die lautstärke der einzelnen streams regeln könnte. man müsste dazu wissen welche teile vom wave_buffers zu welchem stream gehören. einfacher wäre es da wohl das in die pjmedia ports einzubauen, wenn man wirklich einen musik stream spielen will und darüber text mixen will. für alle anderen teile (wie töne, bridges) ist das mixen ja nicht so wichtig. denn so wie es im moment ist, einfach mittelwert, passt ja eigentlich. ausser, dass halt die umschaltung spontan erfolgt wenn ein stream dazu kommt (-> leichtes knacksen)

vllt. könnte man ich einen "mixer" media port implementieren, der als source ports die wave/stream player bekommt und als ausgabe port die daten ans capi oder voip übergibt? wären hierbei latenzen durch einen internen puffer schlimm? also so 1000-2000 sampels (evtl. auch einstellbar)?

EDIT: In capi_streaming() wird buf_cnt erhöht. wird irgendwo geprüft ob buf_cnt nicht zu groß geworden ist? d.h. größer als wave_buffers ? oder kann das gar nicht passieren? wenn doch, dann wäre das eine segfault quelle wenn viele streams gemixt werden...

EDIT2: Zum Resampling: Ich hab mal pjsip mit USE_SMALL_FILTER beim resampling compiliert und in der dtmfbox das auch geändert. ich finde die qualität von webradio und von der espeak ausgabe ist besser (vor allem bei zischlauten wie s und z). braucht allerdings ca. 10-15% mehr cpu und die dtmfbox wir ca. 50kb größer. denke das muss jeder user selber entscheiden wie er es haben will. ich wollt das nur mal anmerken, dass die qualität verbessert werden kann, wenn man es will.
 
Zuletzt bearbeitet:
florixyz schrieb:
passiert für capi ja in capi_streaming() (wo passiert es denn eigentlich für voip?).
CAPI und VoIP haben an der Stelle leider ihr eigenes Timing Device und ich musste etwas tricksen:

VoIP Verbindungen haben zwei Ports:
- einen Split-Channel Port (oCON.capi_port)
Für get_frame/put_frame in capi_streaming(). Ruft man pjmedia_getframe auf, empfängt man die Frames der VoIP-Verbindung - mit put_frame kann man an den VoIP-Port senden.

- einen Media-Port (oCON.media_port)
Dieser wird direkt mit einer anderen VoIP-Verbindung/Tone-Ports/Filestream-Ports/etc. verbunden (pjmedia_conf_connect_port). Das Streamen läuft dabei über den Masterport von PJSIP und das Mixen geht von allein.

Bei CAPI Verbindungen wird einfach der pcm_buffer zum Austausch verwendet :)

florixyz schrieb:
hab allerdings noch keine elegante lösung gefunden, wie man einen stream ausfaden könnte wenn ein anderer kommt, bzw. auch über skripte die lautstärke der einzelnen streams regeln könnte.
Das würde mich auch interessieren. Ein Normalisieren des Streams bei mehreren gemixten Waves wäre ja auch denkbar (wegen der Durchschnittsbildung).

florixyz schrieb:
vllt. könnte man ich einen "mixer" media port implementieren, der als source ports die wave/stream player bekommt und als ausgabe port die daten ans capi oder voip übergibt? wären hierbei latenzen durch einen internen puffer schlimm? also so 1000-2000 sampels (evtl. auch einstellbar)?

Das könnte man machen, um es noch einheitlicher zu bekommen. Aber wie oben bereits erwähnt, muss man VoIP und CAPI anders behandeln. Ein Port, der beide Verbindungen gleich behandelt, wäre schonmal ein Anfang.

EDIT:
Momentan schaue ich mir die Skriptsteuerung an. Ich habe eine Möglichkeit gefunden, das Skript zu "locken". Somit wird es nicht ständig neu augerufen. Sobald ein DTMF-Signal eintrifft, fährt das Programm fort. Damit wird es auf jedenfall etwas einfacher.

EDIT2:
zu der DDI-Sache:
ist das denn immer so, dass die ersten zwei Zeichen (egal was) wiederholt werden? Sonst reicht ja ein Parameter "ignore_ddi_numbers=2", oder sowas...

EDIT3:
florixyz schrieb:
In capi_streaming() wird buf_cnt erhöht. wird irgendwo geprüft ob buf_cnt nicht zu groß geworden ist? d.h. größer als wave_buffers ? oder kann das gar nicht passieren? wenn doch, dann wäre das eine segfault quelle wenn viele streams gemixt werden...
Das sollte nicht passieren. Ich habe es (hoffentlich) so groß deklariert wie die max. Anzahl der Verbindungen.
 
Zuletzt bearbeitet:
bodega schrieb:
Das könnte man machen, um es noch einheitlicher zu bekommen. Aber wie oben bereits erwähnt, muss man VoIP und CAPI anders behandeln. Ein Port, der beide Verbindungen gleich behandelt, wäre schonmal ein Anfang.
Und wenn man einfach mal einen player_port (der ja ein resampler port ist und mit einem filestream oder waveplayer verbunden ist) mit den daten des mixers füttert? das müsste dann doch für voip und capi gehen..?
dann würde mixen halt nur für streams gehen, die explizit über den mixer laufen (evtl. noch kommandozeilen-optionen, oder über ctrl. fifo den mixer mit echo "" > fifo steuern), aber ich fände das würde für den anfang reichen. dann könnte mein mixer.c mal eingebaut werden, erstmal ohne resampling, controlling über fifo und ein einziger port der die daten ausgibt, der statt dem filestream_player z.b. eingebunden wird wenn man als filename "_mixer_" oder so eingibt.
bodega schrieb:
zu der DDI-Sache:
ist das denn immer so, dass die ersten zwei Zeichen (egal was) wiederholt werden? Sonst reicht ja ein Parameter "ignore_ddi_numbers=2", oder sowas...
Ja, scheint bei meiner Anlage so zu sein. Weil die erst nachdem 2 zeichen gewählt wurden ihren externen s0 "abhebt" (und damit den internen der fbox), egal was und wie gewählt wird. somit würde der parameter reichen. wär ja eben nur wichtig, dass beim connect und disconnect immer die gleiche nummer übertragen wird.
bodega schrieb:
Das sollte nicht passieren. Ich habe es (hoffentlich) so groß deklariert wie die max. Anzahl der Verbindungen.

Ok, gut ;)
 
Es ist ja momentan so, das in dem Connection-Struct 10 filestreams vorhanden sind (file_play_port, play_port - also 10 waves/streams gleichzeitig pro Verbindung). Diese werden in der Funktion capi_streaming "manuell" gemixt aus unterschiedlichen Dateien/Pipes. Bei VoIP geht das Mixen ja von selbst (Die Callbacks werden autom. aufgerufen, anstelle von pjmedia_getframe).

Das wäre jetzt die Schicht, die der Mixer-Port auch benötigt, wenn ich dich richtig verstanden habe. Also die bereits auf 8000hz normalisierten Daten aus den unterschiedlichen Ports (play_port) zu einem Stream zusammenführen. Die Mixer-Callbacks könnten dann noch zusätlich Lautstärke, etc. beinflussen.

Jetzt wäre es natürlich auch schön, wenn dieser Mixer-Port noch weitere Ports aufnehmen könne (egal ob CAPI/VoIP/Tone-Port/Soundcard-Port/etc.). Damit könnte man sich die ganze Mix-Routine in capi_streaming sparen und das Faden würde auch bei VoIP-Verbindungen funktionieren (die per pjmedia_conf_port_connect verbunden sind).

capi_streaming müsste dann nur noch die Daten aus dem Mixer-Port abholen (ohne darauf zu achten, was für ein Port-Typ es ist) und seine eigenen Audio-Daten in einem Puffer abspeichern (damit diese vom Mixer-Port ausgelesen werden können).

Der Rest ginge dann von alleine und die Codemenge würde sich reduzieren, da nicht immer darauf geachtet werden muss, was für ein Port-Typ gerade behandelt wird (redundanter Code, vom Gefühl her).
Deswegen fände ich es gut, man könnte den Mixer-Port von Anfang an so gestalten, das er mit allen Porttypen umgehen kann:

Code:
[B]   Mixed     |      Resampled   |      RAW-Data[/B]
[B]------------------------------------------------------------------[/B]
[Mixer_Port] < [Resample_Port]  < [Filestream_Port] < [Wave-Datei]
             < [Resample_Port]  < [Filestream_Port] < [Fifo1]
             < [Resample_Port]  < [Filestream_Port] < [Fifo2]
             < [SplitComb_Port] < [RTP]     (VOIP)
             < [PCM_Buffer]     < [DATA_B3] (CAPI)

Beim Schreiben auf den Mixer-Port würde sich die Verbindung um die Füllung des eigenen Puffers kümmern.
 
Zuletzt bearbeitet:
Klingt gut. Ein zentraler Port von dem sowohl capi als auch voip lesen (get_frame) und alle anderen Quellen reinschreiben? Ich würde dann mal den Port implementieren. Wenn er fertig ist, dann wäre es hilfreich, wenn du ihn integrierst, weil du dich ja besser auskennst wo voip/capi reinschreibt/ließt ;-)

Die sache mit dem faden ist nur: welcher stream soll gefadet werden und welcher soll unverändert bleiben? Z.b. Hintergrundmusik sollte gefadet werden und sprache nicht. Vllt. als default immer den ersten Stream faden? Controlle über sh_actions, oder über zusätzlichen Control fifo, damit an der sh_actions sache nicht so viel geändert werden muss?
 
Damit der Mixer-Port geschrieben werden kann, müsste ich nur noch einen CAPI-Port erzeugen, dann hätte man schonmal alles "grob" gleichgezogen. Momentan wird dieser ja manuell befüllt (oCON.pcm_buffer). CAPI zu CAPI ist halt die einzige Stelle, die nicht über getframe/putframe arbeitet.
Wenn das drin ist, sollte der Mixer-Port zu realisieren sein.

Bzgl. des Fadens, kann man es ja so halten wie beim Verbindungsaufbau auch. Es wird eine ID zurückgeliefert:
Code:
PLAY_ID1=`dtmfbox 1 -playstreamthread /var/tmp/fifo1`
PLAY_ID2=`dtmfbox 1 -playstreamthread /var/tmp/fifo2`
dtmfbox 1 -stop play $PLAY_ID1   # stoppt fifo1
dtmfbox 1 -fadeout play $PLAY_ID2 # fadeout fifo2
dtmfbox 1 -setvolume $PLAY_ID2 1000 # volume fifo2
dtmfbox 1 -stop play # stoppt alles
dtmfbox 1 -list play  # alle Waves/Streams ausgeben der jew. Verbindung

Über Shared Memory geht der Befehlsaustausch am einfachsten (struct erweitern). Ein Control Fifo würde ich nicht einbauen.

EDIT:
So, gerade mal ein wenig rumexperimentiert und schon zwei Ports fertig. Das ist richtig genial mit den Ports.

Ich hab mir jetzt überlegt, alles in einzelne Dateien aufzuteilen und zwar so:
- port_capi.c
- port_voip.c
- port_soundcard.c
- port_filestream.c

Alle Objekte sind vom Typ 'pjmedia_port' und können gleich behandelt werden. 'port_mixer.c' kannst du ja schreiben, um ein Ganzes daraus zu machen :)
 
Zuletzt bearbeitet:
das klingt gut. ich bin dabei port_mixer.c zu schreiben.

via get_frame kann man die gemixten frames holen. via mixer_add_source kann man einen source port vom typ pjmedia_port hinzufügen (wenn es probleme wegen des typs gibt, könnte man auch nur den get_frame pointer übergeben). dann wird es noch "control" routinen geben. z.b. mixer_set_volume, mixer_fade, usw. (oder wars das schon? was braucht man denn noch für funktionen? effekte? pitch change, flanger... ? ;-) )

zu jedem source port kann der mixer auch eine unabhängige "playid" zuweisen. d.h. man könnte mixer_fade die playid übergeben (oder alternativ einfach die nummer des sourceports, also der reihenfolge nach, wie er hinzugefügt wurde. was ist besser?)

sobald ich was habe schicke ich es dir mal.
 
So.. hab auch gebastelt :) --> im SVN. Alle Ports sind jetzt als oCON.custom_port definiert. port_soundcard.c lasse ich mal außen vor, da müsste ich noch was ändern, damit es sich besser anhört. Alles andere ist soweit geblieben wie es war.

Den Tone-Port müsste ich auch noch umschreiben (port_tone.c)... morgen oder so... :rolleyes:
 
wie ist denn das mit der framesize? ist die überall konstant (clockrate *20 /1000) oder ist die bei den verschiedenen ports verschieden? wäre für den mixer wichtig, weil es dann schwerer wird den allgemeinen fall zu mixen, wenn die source ports unterschiedliche framesizes haben. und es ist auch wichtig was der mixer für eine ausgangs framesize haben soll.

EDIT: Eine Funktion set_volume wird es so direkt nicht geben, es wird alles über fade() geregelt , damit es nicht zum knacksen kommt.
Code:
static pj_status_t mixer_fade(pjmedia_port *port, int playid, int target_volume, int fadetime)
da gibt man target_volume an auf das in der zeit fadetime gefadet werden soll.

ich werde aber noch ein set_volume anbieten, das dann intern fade aufruft.
 
Zuletzt bearbeitet:
Die Frame-Size ist überall konstant (320 bytes/160 samples).

EDIT:
Mhh. eigentlich kann man den tone_port komplett unsichtbar machen. Wenn eine Verbindung gerade aufgebaut und noch kein Stream übertragen wird, überträgt man einfach einen Ton an den custom_port.

florixyz schrieb:
via get_frame kann man die gemixten frames holen. via mixer_add_source kann man einen source port vom typ pjmedia_port hinzufügen (wenn es probleme wegen des typs gibt, könnte man auch nur den get_frame pointer übergeben). dann wird es noch "control" routinen geben. z.b. mixer_set_volume, mixer_fade, usw.
Genauso stelle ich mir das vor :) - Typprobleme sollte es aber keine geben, da alle Ports vom Typ pjmedia_port sind. Die privaten Portdaten im pjmedia_port unterscheiden sich aber. Anhand des Port-Namens kann man diese dynamisch casten.

Ich überlege momentan noch, wie man das mit dem Filstream am besten lösen kann. Verbindungen (CAPI/VOIP/SCRD) sind alle unter dem selben Port zu erreichen (oCON.custom_port). Die Filestreams werden im Array mit fester Größe gespeichert (oCON.play_port[x]).

Sollte das so bleiben oder hättest du eine andere Idee?
 
Zuletzt bearbeitet:
bodega schrieb:
Sollte das so bleiben oder hättest du eine andere Idee?
Denke das passt erstmal so, könnte auch später noch geändert werden, wenn wir eine bessere Idee haben.

Eine Frage noch: Was passiert wenn sich ein port (z.B. ein file-play port) beendet, also das ende der datei erreicht, oder mit -stop play gestoppt wird. Wie bekommt der Mixer davon etwas mit? Wenn der betreffende port weiter existiert und erstmal nur Nullen zurückgibt, dann ist das ok (ausser dass es CPU verschwendung ist). Wenn er dann bald über mixer_remove_source gelöscht wird ist es perfekt. Verwenden die "downstream" ports allerdings callbacks oder ähnliches, dann muss ich das noch implementieren. Hab dazu allerdings nix gefunden.

Wird vermutlich noch bis zum Wochenende dauern bis der Mixer Port fertig ist, hab bis jetzt auch noch keine Möglichkeit ihn zu testen. Brauche dazu erstmal ein Framework, das z.B. ein paar player startet und den output mit einem recorder aufzeichnet. testen in der dtmfbox wäre auch eine möglichkeit, aber das könnte ein wenig ein hin und her werden, wär aber vllt. die schnellste möglichkeit, weil dazu nicht erst ein testprogramm geschrieben werden müsste.
 
florixyz schrieb:
Was passiert wenn sich ein port (z.B. ein file-play port) beendet, also das ende der datei erreicht, oder mit -stop play gestoppt wird. Wie bekommt der Mixer davon etwas mit?
Wenn der file_play port ein EOF bekommt, wird der EOF callback aufgerufen. Dieser sollte im Anschluss den Port freigeben.

florixyz schrieb:
Wird vermutlich noch bis zum Wochenende dauern bis der Mixer Port fertig ist, hab bis jetzt auch noch keine Möglichkeit ihn zu testen.
Das ist nicht schlimm, ich werde auch noch etwas brauchen.

Jetzt kommt nur etwas: port_capi.c kann in die Konferenzbrücke von PJSIP mitaufgenommen werden - bedeutet eigentlich soviel wie, das jeder CAPI-port mit jedem anderen Port über pjmedia_connect_port verbunden werden kann. Das Mixen geht also schon voll automatisch :)!! Das war eigentlich nicht geplant und ist mir während des Studierens von pjsip.org aufgefallen. Man muss dazu sagen, das es auch die größte Schwachstelle im Programm war, da für jeden Port ein Splitcomb und Reverse-Channel anlegt werden musste, nur um CAPI mit Daten zu füttern - das fällt nun weg.
Um die Lautstärke eines Ports zu beeinflussen, kann man nun auch mit pjmedia_conf_adjust_rx_level( ) und pjmedia_conf_adjust_tx_level( ) arbeiten....

Es ist wirklich viel angenehmer die Konferenzbrücke zu verwenden ... über Timing/Audio Stutter sollte ich mir keine Gedanken mehr machen müssen (hoffe ich :))...

EDIT:
SVN ist eingecheckt. capi_streaming() ist um Einiges geschrumpft und übersichtlicher. Die Funktion wird jetzt auch im eigenen Thread aufgerufen. pjmedia_port_get_frame() wird auf CUR_CON->custom_port durchgeführt (wo alle Audio-Daten zusammenfließen). Das Verbinden geschieht über pjmedia_conf_connect_port(). Echt cool... damit kann man alle andern Funktionen der Konferenz-Brücke verwenden.

Falls man doch irgendwie noch an die Frames ran muss, gibt es ja die Callbacks in den einzelnen Ports (und falls keiner existiert, überschreibt man einfach den getframe/putframe Callback des Ports).

btw: capi_port.c ist noch nicht ganz ausgereift. Beim Beenden der Verbindung werden die letzten Frames wiederholt - Kleinigkeit.. später ;) - PJSIP müsste man auch nochmal auschecken, da PRACK nun unterstützt wird ...
 
Zuletzt bearbeitet:
Das klingt schonmal alles sehr gut. Ich werds dann mal testen :)

Werde trotzdem meinen Mixer Port weiterentwickeln, da er (wenn er mal fertig ist) die einzelnen streams langsam oder schnell ein/aus faden kann, die streams auch verstärken kann, automatisch clipping control durchführen kann, damit nix übersteuert und eine talkover funktion bieten wird, d.h. man kann z.B. auch bei einem Telefongespräch Musik im Hintergrund laufen lassen, die dann sofort leiser gemacht wird, wenn jemand spricht ;) so ähnlich halt wie die ganzen Radiosender haben :)
Vllt. kann ja dann mal über ein #ifdef in die dtmfbox eingebaut werden. Würde auf jeden Fall eine Option bieten wollen, mit oder ohne mixer, da er wahrscheinlich mehr cpu resourcen verbraucht als die Konferenzbrücke von PJSIP.

EDIT: in port_tone.h ist ein Fehler. Die Definition für port_tone_generate_tones ist falsch. Die in port_tone.c ist richtig ;)
Hab die korrigierte datei in der update.tar.gz hochgeladen.
Mit da drin (in config.h) ist auch noch ein zusätzlicher define um das resample verhalten einzustellen (ob USE_LINEAR oder USE_SMALL_FILTER)

Noch eine Frage: Weisst du was mit den Pjsip pools passiert? jedesmal wenn ein player gestartet wird, wird speicher daruf alloziert, aber nichtmehr freigegeben. der pool selber wird dann erst beim beenden der dtmfbox freigegeben?? oder auch nach dem beenden eines players? sonst braucht die box mit der Zeit immer mehr speicher, je mehr player aktiv waren...
 

Anhänge

  • update.tar.gz
    8.9 KB · Aufrufe: 7
Zuletzt bearbeitet:
florixyz schrieb:
in port_tone.h ist ein Fehler. Die Definition für port_tone_generate_tones ist falsch. Die in port_tone.c ist richtig
Hab die korrigierte datei in der update.tar.gz hochgeladen
Ups, da hat wohl der gcc gemeckert.. - ich hatte es zu dem Zeitpunkt noch nicht für mips kompiliert gehabt - werde es übernehmen. Danke.

florixyz schrieb:
Weisst du was mit den Pjsip pools passiert? jedesmal wenn ein player gestartet wird, wird speicher daruf alloziert, aber nichtmehr freigegeben. der pool selber wird dann erst beim beenden der dtmfbox freigegeben?? oder auch nach dem beenden eines players?
Das sollte eigentlich nicht passieren. Ob es daran liegt, dass ich den filestream.c einfach so in port_filestream.c übernommen hatte? Die Poolsteuerung wollte ich hier noch abändern.
Eventuell passiert es, wenn was abgespielt wird und danach aufgelegt. Da habe ich die Befürchtung, dass der Pool nicht freigegeben wird. Wie kann ich das Nachstellen?

zum Pool:

Der Pool arbeitet "ähnlich" wie bei neueren Frameworks. Sobald dieser freigegeben wird, wird auch der reservierte Speicher freigegeben, der mit dem Pool alloziiert wurde. Super Sache, da man nicht jede einzelne Variable freigeben muss...

Die Player/Recorder bekommen alle ihren eigenen Pool. Sobald die Player nicht mehr abspielen, wird der Pool freigegeben. Ich müsste hier nur den Pool in die privaten Portdaten des Players packen (nicht unter dem CONNECTION Struct).

Dann werden auch noch Pools für die einzelnen Verbindungen vergeben (oCONS[x].pool). Bei neuer Verbindung, wird der alte Pool freigegeben.

oVOIP.pool ist ein globaler Pool, der bis zum Ende des Programms offen bleibt.
Nach Initialisierung des Programms, sollte hierauf nicht mehr alloziert werden.

EDIT:
ach so, einen habe ich noch Vergessen:
oCONS[x].pool_streamthread. Der wird auch mit jeder neuen Verbindung initialisiert, ist aber nur für capi_streaming zuständig.
 
Zuletzt bearbeitet:
okay, dann hab ich das mit den pools jetzt auch verstanden :) solange er nach ende einer Verbindung freigegeben wird, passt ja alles. Ich dachte nur es gibt nur einen einzigen play_pool, der erst beim beenden der dtmfbox freigegeben wird. Da hab ich dann wohl nicht genau genug gelesen.
 
Hallo, ich finde eure Diskussion hier echt interessant. Leider verstehe ich als Neuling auf diesem Gebiet nur Bahnhof.

Eigentlich bin ich auf der Suche nach einer auch für Einsteiger einfachen Möglichkeit, einen reinen VOIP-Callback mittels der Fritzbox zu realisieren. Bei der Suche bin ich auf diesen Beitrag gestoßen.

Im Einsatz habe ich eine Fritzbox 7170 mit der aktuellen offiziellen Firmware. Gibt es evtl. eine einfache Möglichkeit (z.B. mit dem Construction Kit) sich eine Firmware zusammenzubauen, in der die Callback-Funktion enthalten ist? Oder gibt es evtl. eine gepatchte aktuelle Firmware mir dieser Funktion? Leider konnte ich dazu nichts finden.

Über eine Antwort würde ich mich freuen...

LG Nice
 
@Nice: Du musst an der original Firmware gar nichts ändern. Du kannst die dtmfbox auf einem usb-stick installieren oder die standalone version verwenden. Es gibt in diesem Thread jede Menge Infos zur Dtmfbox, auch wie du sie installierst, ließ dich da mal ein bisschen rein. Vom ersten Beitrag aus findest du auch zu den einzelnen Versionen Infos, es gibt auch ein paar pdfs als doku.
Für Callback müsste es auch Skripte geben. Wenn nicht, dann musst du noch eine weile Warten, ich bin dabei mir selber ein kleines Skript für callback zu schreiben, wenn ich das mal habe, dann poste ich es hier auch.
 
Neues SVN ist eingecheckt. Der Thread um capi_streaming ist auf der FB nicht nötig und wenn man unter Windows die Thread-Priority auf 'Hoch' setzt, auch nicht mehr :)

Im 'mixer.c' gibt es nun einen getframe/putframe Callback. Alle Ports laufen hier zusammen und es können nachträglich Änderungen an den Frames vorgenommen werden.

Den Memory-Leak hatte ich gefunden. Bei reset_connection() wurde der falsche Pool zurückgesetzt. Vom Gefühl her, war da also was ...

Ein paar Änderungen sind noch nötig, aber die Struktur stimmt schonmal, um ein nachträgliches Mixen zu ermöglichen. Ob sich dadurch was am Laufzeitverhalten ändert, muss du mal testen.
 
Holen Sie sich 3CX - völlig kostenlos!
Verbinden Sie Ihr Team und Ihre Kunden Telefonie Livechat Videokonferenzen

Gehostet oder selbst-verwaltet. Für bis zu 10 Nutzer dauerhaft kostenlos. Keine Kreditkartendetails erforderlich. Ohne Risiko testen.

3CX
Für diese E-Mail-Adresse besteht bereits ein 3CX-Konto. Sie werden zum Kundenportal weitergeleitet, wo Sie sich anmelden oder Ihr Passwort zurücksetzen können, falls Sie dieses vergessen haben.