From 2d8f0daeefb51bc983761abc12f324124fc76dbb Mon Sep 17 00:00:00 2001 From: Stefan Sayer Date: Thu, 29 Dec 2022 10:14:04 +0100 Subject: [PATCH] MT#55831 confpin: simple pin conference app confpin: simple pin conference app Change-Id: I730df6aca1b68bc0ffa311ec9b6adb412b9135f8 --- apps/confpin/confpin.conf | 39 +++ apps/confpin/lib/confpin.dsm | 237 ++++++++++++++++++ apps/confpin/lib/sw_audio.dsm | 50 ++++ apps/confpin/lib/sw_audio_api.dsm | 66 +++++ apps/confpin/prompts/Makefile | 22 ++ apps/confpin/prompts/conference_first.txt | 1 + apps/confpin/prompts/conference_greeting.txt | 1 + apps/confpin/prompts/conference_join.txt | 1 + apps/confpin/prompts/conference_joined.txt | 1 + apps/confpin/prompts/conference_leave.txt | 1 + apps/confpin/prompts/conference_music.txt | 1 + apps/confpin/prompts/conference_pin_wrong.txt | 1 + apps/confpin/prompts/goodbye.txt | 1 + apps/confpin/tools/clear_file | 14 ++ apps/confpin/tools/fetch_file | 14 ++ apps/confpin/tools/push_file | 14 ++ 16 files changed, 464 insertions(+) create mode 100644 apps/confpin/confpin.conf create mode 100644 apps/confpin/lib/confpin.dsm create mode 100644 apps/confpin/lib/sw_audio.dsm create mode 100644 apps/confpin/lib/sw_audio_api.dsm create mode 100644 apps/confpin/prompts/Makefile create mode 100644 apps/confpin/prompts/conference_first.txt create mode 100644 apps/confpin/prompts/conference_greeting.txt create mode 100644 apps/confpin/prompts/conference_join.txt create mode 100644 apps/confpin/prompts/conference_joined.txt create mode 100644 apps/confpin/prompts/conference_leave.txt create mode 100644 apps/confpin/prompts/conference_music.txt create mode 100644 apps/confpin/prompts/conference_pin_wrong.txt create mode 100644 apps/confpin/prompts/goodbye.txt create mode 100644 apps/confpin/tools/clear_file create mode 100644 apps/confpin/tools/fetch_file create mode 100644 apps/confpin/tools/push_file diff --git a/apps/confpin/confpin.conf b/apps/confpin/confpin.conf new file mode 100644 index 00000000..2af4d141 --- /dev/null +++ b/apps/confpin/confpin.conf @@ -0,0 +1,39 @@ +# configuration for confpin app + + +# audio cache configuration +# audio_cache - same as cache_dir in audio_cache.conf +#audio_cache=/tmp +#audio_cache=/home/stefan/frafos/customers/sipwise/pbx/new_repo/sipwise_modules/callqueues/prompts +audio_cache=../apps/confpin/cache/ +# MySQL database connection for downloading audio prompts +db_url=mysql://root:frafos@127.0.0.1/provisioning + +# default sound set if non provisioned with app-param +sound_set_id=1 + +digit_collection_timeout=10 + +###### digits - to be put into DB +#digits_right=yes or no +# single digits before 10s - for e.g. German: no, for eg. English: yes +digits_right=yes +# directory with digits - e.g. cache directory +# the language (lng app param) will be added at the end, e.g. +# digits_dir=../apps/callingcard/prompts/es/ +digits_dir=../../sipwise_modules/callqueues/prompts/ + +####### +# it's best to leave those below as-is +#diag_path=/usr/lib/sems/dsm/confpin +#mod_path=/usr/lib/sems/dsm/ + +# in-tree testing: +diag_path=../apps/confpin/lib +mod_path=../apps/dsm/mods/lib/ + +load_diags=confpin,sw_audio_api +register_apps=confpin +run_invite_event=yes +set_param_variables=yes +run_system_dsms=sw_audio_api diff --git a/apps/confpin/lib/confpin.dsm b/apps/confpin/lib/confpin.dsm new file mode 100644 index 00000000..2f4f6de8 --- /dev/null +++ b/apps/confpin/lib/confpin.dsm @@ -0,0 +1,237 @@ +#[% TAGS [- -] %] +--- +-- This DSM app +-- * asks caller to enter pin for conference room +-- * puts caller in conference room identified by roompin +-- +-- Parameters (P-App-Param): +-- confpin - dsm app +-- roompin - pin from db for particular subscriber +-- room - conference room consists subscriber and roompin +-- sound_set_id - sound set to use +-- +-- Example: P-App-Param: confpin;roompin="pin_from_db";room="$fU"_"pin_from_db";sound_set_id=3 +-- + +import(mod_conference); +import(mod_dlg); +import(mod_utils); +import(mod_groups); + +#include "sw_audio.dsm" + +function stopCall() { + stop(true); +}; + +function refuseWith500() { + set(connect_session=0); + dlg.reply(500, "Server Internal Error"); + stop(false); +}; + +function enterConference() { + set($audio_id="conference_joined"); + swMixInFile(); + info(">> entering conference in room '$room'"); + conference.setPlayoutType(adaptive); + conference.join($room); + set($joined=true); + groups.postEvent($room, joined); + groups.join($room); + groups.getSize($roomsize=$room); + if test($roomsize==1) { + set($audio_id="conference_first"); + swMixInFile(); + set($audio_id="conference_music"); + set($sw_audio_loop="true"); + swMixInFile(); + clear($sw_audio_loop); + set($lonely_user=true); + } + info("entered conference, $roomsize people in here<<"); +}; +initial state START; + +transition "DB exception" START - exception / { + error("Error in initializing :"); + refuseWith500(); +} -> END; + +transition "check for sound_set_id provisioning" START - invite; test($sound_set_id=="") / { + error("Error in provisioning: no sound_set_id application parameter set"); + refuseWith500(); +} -> END; + +transition "Fetching File exception" START - exception; test(#type=="result") / { + error("error in DB query for fetching audio file:"); + logAll(1); + stop(true); +} -> END; + +transition "call starts" START - invite / { + -- process session establishment in DSM app + set(connect_session=0); + dlg.acceptInvite(); + connectMedia(); + + -- connect to DB + mysql.connect(); + + if test($roompin=="") + { + info(pin is empty); + set($autoEnter=1); + repost(); + } + else + { + info(">> start_pin_entry"); + set($tryAgain=0); + set($pin=""); + + -- rfc4240 + if test($room=="") { + info("room is empty"); + dlg.reply(404,"Not found"); + } else { + set($audio_id="conference_greeting"); + swPlayFile(); + } + info("start_pin_entry <<"); + } +} -> COLLECT_PIN; + +-------------------------------------------------------- +state COLLECT_PIN; +transition "prompt ends, start collection timer" COLLECT_PIN - noAudio / setTimer(1, $config.digit_collection_timeout) -> COLLECT_PIN; + +transition "roompin empty, enter conference" COLLECT_PIN - test($autoEnter==1) / { + info(">> empty_pin"); + enterConference(); +} -> CONFERENCE; + +transition "timer, short pin, too many tries" COLLECT_PIN - timer(#id==1); test(len($pin)<3); test($pin_tries==$config.pin_max_retries) / { + stopCall(); +} -> END; +transition "timer, short pin, too many tries" COLLECT_PIN - timer(#id==1); test(len($pin)<3); test($pin_tries>$config.pin_max_retries) / { + stopCall(); +} -> END; +transition "hash entered, short pin, too many tries" COLLECT_PIN - key(#key==11); test(len($pin)<3); test($pin_tries>$config.pin_max_retries) / { + stopCall(); +} -> END; +transition "hash entered, short pin, too many tries" COLLECT_PIN - key(#key==11); test(len($pin)<3); test($pin_tries==$config.pin_max_retries) / { + stopCall(); +} -> END; + +transition "collect pin timer hit, short pin" COLLECT_PIN - timer(#id==1); test(len($pin)<3) / { + set($audio_id="conference_pin_wrong"); + swPlayFile(); + inc($pin_tries); +} -> COLLECT_PIN; + +transition "hash entered, short pin" COLLECT_PIN - key(#key==11); test(len($pin)<3) / { + set($audio_id="conference_pin_wrong"); + swPlayFile(); + inc($pin_tries); +} -> COLLECT_PIN; + +transition "number entered" COLLECT_PIN - key(#key<10) / { + -- stop prompt + closePlaylist(false); + append($pin, #key); + info("USER ENTERED key '#key'"); + setTimer(1, $config.digit_collection_timeout); +} -> COLLECT_PIN; + +transition "collect pin timer hit" COLLECT_PIN - timer(#id==1) -> TESTPINRESULT; +transition "hash entered, finished pin" COLLECT_PIN - key(#key==11) / removeTimer(1) -> TESTPINRESULT; + +-------------------------------------------------------- +state TESTPINRESULT +enter { + info("Key #key pressed, tryAgain is $tryAgain"); + repost(); +}; + +transition "incorrect_retry" TESTPINRESULT - test($pin!=$roompin); test($tryAgain<3) / { + info(">> incorrect_retry, pin '$pin', tryAgain '$tryAgain'"); + inc($tryAgain); + set($pin=""); + set($audio_id="conference_pin_wrong"); + swPlayFile(); + info("incorrect_retry <<"); +} -> COLLECT_PIN; + +transition "incorrect_no_retry" TESTPINRESULT - test($pin!=$roompin); test($tryAgain==3) / { + info(">> incorrect_no_retry, tryAgain '$tryAgain'"); + set($audio_id="goodbye"); + swPlayFile(); + info("incorrect_no_retry <<"); +} -> PLAY_FIN; + +-------------------------------------------------------- +state PLAY_FIN; +transition "bye_after_fin" PLAY_FIN - noAudio / stopCall() -> END; + +-------------------------------------------------------- + +transition "correct_pin" TESTPINRESULT - test($pin==$roompin) / { + info(">> correct_pin"); + enterConference(); +} -> CONFERENCE; + +state CONFERENCE; + +transition "got leave event" CONFERENCE - event(#leave==true) / { + logParams(); + set($audio_id="conference_leave"); + swMixInFile(); +} -> CONFERENCE; + +transition "got join event" CONFERENCE - event(#joined==true) / { + logParams(); + if test($lonely_user==true) { + conference.flushMixInList(); + } + set($audio_id="conference_join"); + swMixInFile(); +} -> CONFERENCE; + +transition "kick_event" CONFERENCE - eventTest(#action==kick) / { + info(">> kick_event"); + closePlaylist(); + conference.leave(); + set($leave=true); + groups.leaveAll(); + groups.postEvent($room, leave); + stop(true); + info("kick_event <<"); +} -> END; + +# is this the same as kick? +transition "leave_event" CONFERENCE - eventTest(#action==leave) / { + info(">> leave_event"); + closePlaylist(); + conference.leave(); + set($leave=true); + groups.leaveAll(); + groups.postEvent($room, leave); + stop(true); + info("leave_event <<"); +} -> END; + +transition "leave_conference" CONFERENCE - hangup / { + info(">> leave_conference"); + closePlaylist(); + conference.leave(); + set($leave=true); + groups.leaveAll(); + groups.postEvent($room, leave); + stop(false); + info("leave_conference <<"); +} -> END; + +transition "bye_recvd" (START,COLLECT_PIN,PLAY_FIN,TESTPINRESULT) - hangup / stop(false) -> END; + +state END; diff --git a/apps/confpin/lib/sw_audio.dsm b/apps/confpin/lib/sw_audio.dsm new file mode 100644 index 00000000..322266bf --- /dev/null +++ b/apps/confpin/lib/sw_audio.dsm @@ -0,0 +1,50 @@ +-- sw_audio +-- +-- The playFile() function plays a file with ID $audio_id from the $config.audio_cache directory. +-- $sound_set_id is used as subdirectory under $config.audio_cache. +-- If it doesn't exist, it is tried to be fetched from the MySQL DB, using the $audio_id. +-- If that fails, an exception with type playFile is thrown +-- +-- swMixInFile() mixes the file in to a mixInList setup by the conference module. it uses +-- the $has_mixin variable to record that state, and setup the mixin if it's not there. +-- +-- set($sw_audio_loop="true") makes the file to be looped + +import(mod_sys); +import(mod_mysql); +import(mod_conference); + +function swPlayFile() { + sets($__file_cache_path="$(config.audio_cache)/$(sound_set_id)/"); + sets($__file_path="$(__file_cache_path)$(audio_id).wav"); + + if sys.file_not_exists($__file_path) { + if sys.file_not_exists($__file_cache_path) { + sys.mkdir($__file_cache_path); + } + -- connect to DB + if not mysql.connected() { + mysql.connect(); + throwOnError(); + } + + mysql.getFileFromDB('SELECT data FROM provisioning.voip_sound_files vsf, provisioning.voip_sound_handles vsh WHERE vsh.name="$audio_id" AND vsf.set_id=$sound_set_id AND vsh.id=vsf.handle_id',$__file_path); + throwOnError(); + } + if test($mix_file==true) { + conference.playMixInList($__file_path, $sw_audio_loop); + } else { + playFile($__file_path, $sw_audio_loop); + } + clear($__file_path); + clear($__file_cache_path); +}; + +function swMixInFile() { + set($mix_file=true); + if test($has_mixin!=true) { + conference.setupMixIn(0.5, 0); + set($has_mixin=true); + } + swPlayFile(); +}; \ No newline at end of file diff --git a/apps/confpin/lib/sw_audio_api.dsm b/apps/confpin/lib/sw_audio_api.dsm new file mode 100644 index 00000000..aba8d255 --- /dev/null +++ b/apps/confpin/lib/sw_audio_api.dsm @@ -0,0 +1,66 @@ +-- sw_audio_api +-- +-- this SystemDSM implements API functions to handle the prompt cache +-- + +import(mod_sys); +import(mod_mysql); + +initial state SW_AUDIO_START; + +transition "server startup" SW_AUDIO_START - startup / { + log(2, "sw_audio cache handler started"); + registerEventQueue("sw_audio"); + mysql.connect(); + logAll(3); +} -> SW_AUDIO_WAIT_EVENT; + +state SW_AUDIO_WAIT_EVENT; + +transition "exception in server startup" (SW_AUDIO_START,SW_AUDIO_WAIT_EVENT) - exception / { + logAll(1); +} -> SW_AUDIO_WAIT_EVENT; + +transition "server shutdown" SW_AUDIO_WAIT_EVENT - system(#type=="ServerShutdown") / { + log(2, "sw_audio cache handler stopping"); + unregisterEventQueue("sw_audio"); + stop(false); +} -> SW_AUDIO_END; + +transition "clear File" SW_AUDIO_WAIT_EVENT - event(#cmd=="clearFile") / { + log(3, "sw_audio cache handler: clearFile"); + logParams(3); + sets($__file_path="$(config.audio_cache)/#(sound_set_id)/#(audio_id).wav"); + sys.unlink($__file_path); + clear($__file_path); +} -> SW_AUDIO_WAIT_EVENT; + +transition "fetch File" SW_AUDIO_WAIT_EVENT - event(#cmd=="fetchFile") / { + log(3, "sw_audio cache handler: fetchFile"); + logParams(3); + sets($__file_path="$(config.audio_cache)/#(sound_set_id)/#(audio_id).wav"); + mysql.getFileFromDB(SELECT data FROM provisioning.audio_files WHERE id="#audio_id",$__file_path); + clear($__file_path); +} -> SW_AUDIO_WAIT_EVENT; + +transition "push File" SW_AUDIO_WAIT_EVENT - event(#cmd=="pushFile") / { + log(3, "sw_audio cache handler: pushFile"); + log(3, "WARNING! for debug purposes only"); + logParams(3); + sets($__file_path="$(config.audio_cache)/#(sound_set_id)/#(audio_id).wav"); + mysql.connect(); + mysql.query(SELECT id as vsh_id FROM provisioning.voip_sound_handles where name="#audio_id"); + logAll(3); + if test($db.rows==0) { + mysql.execute(INSERT INTO provisioning.voip_sound_handles (name) VALUES ("#audio_id")); + set($vsh_id=$db.insert_id); + } else { + mysql.getResult(0); + }; + log(3, $vsh_id); + mysql.putFileToDB('INSERT INTO provisioning.voip_sound_files (handle_id,set_id,data) VALUES ($vsh_id,#sound_set_id, "__FILE__")', $__file_path); + logAll(3); + clear($__file_path); +} -> SW_AUDIO_WAIT_EVENT; + +state SW_AUDIO_END; \ No newline at end of file diff --git a/apps/confpin/prompts/Makefile b/apps/confpin/prompts/Makefile new file mode 100644 index 00000000..25028e88 --- /dev/null +++ b/apps/confpin/prompts/Makefile @@ -0,0 +1,22 @@ +SRCS=$(wildcard *.txt) +WAVS=$(SRCS:.txt=.wav) +DBS=$(SRCS:.txt=.dbs) + +all: $(WAVS) + +db_upload: $(DBS) + +%.wav : %.txt Makefile + flite -f $< -o $(basename $@)_16k.wav +## text2wave $< -o $(basename $@)_16k.wav + sox $(basename $@)_16k.wav -r 8000 $@ + rm $(basename $@)_16k.wav + +%.dbs: %.wav Makefile + mkdir -p ../cache/1 + cp $(basename $@).wav ../cache/1 + ../tools/push_file $(basename $@) 1 + touch $(basename $@).dbs + +clean: + rm -f *.dbs *.wav \ No newline at end of file diff --git a/apps/confpin/prompts/conference_first.txt b/apps/confpin/prompts/conference_first.txt new file mode 100644 index 00000000..15892167 --- /dev/null +++ b/apps/confpin/prompts/conference_first.txt @@ -0,0 +1 @@ +you are the first participant in the conference. diff --git a/apps/confpin/prompts/conference_greeting.txt b/apps/confpin/prompts/conference_greeting.txt new file mode 100644 index 00000000..ac5cadcf --- /dev/null +++ b/apps/confpin/prompts/conference_greeting.txt @@ -0,0 +1 @@ +welcome to the conference, please enter your pin number diff --git a/apps/confpin/prompts/conference_join.txt b/apps/confpin/prompts/conference_join.txt new file mode 100644 index 00000000..58e771ad --- /dev/null +++ b/apps/confpin/prompts/conference_join.txt @@ -0,0 +1 @@ +someone joined the conference diff --git a/apps/confpin/prompts/conference_joined.txt b/apps/confpin/prompts/conference_joined.txt new file mode 100644 index 00000000..29a4febb --- /dev/null +++ b/apps/confpin/prompts/conference_joined.txt @@ -0,0 +1 @@ +you joined the conference diff --git a/apps/confpin/prompts/conference_leave.txt b/apps/confpin/prompts/conference_leave.txt new file mode 100644 index 00000000..2a5a8814 --- /dev/null +++ b/apps/confpin/prompts/conference_leave.txt @@ -0,0 +1 @@ +someone left the conference diff --git a/apps/confpin/prompts/conference_music.txt b/apps/confpin/prompts/conference_music.txt new file mode 100644 index 00000000..d075594f --- /dev/null +++ b/apps/confpin/prompts/conference_music.txt @@ -0,0 +1 @@ +bum bada bum bum bamm, bamm bada bamm bamm bamm, hum di dum di dum dum dumm diff --git a/apps/confpin/prompts/conference_pin_wrong.txt b/apps/confpin/prompts/conference_pin_wrong.txt new file mode 100644 index 00000000..16a203a9 --- /dev/null +++ b/apps/confpin/prompts/conference_pin_wrong.txt @@ -0,0 +1 @@ +sorry, that pin is wrong. please try again diff --git a/apps/confpin/prompts/goodbye.txt b/apps/confpin/prompts/goodbye.txt new file mode 100644 index 00000000..024d23dc --- /dev/null +++ b/apps/confpin/prompts/goodbye.txt @@ -0,0 +1 @@ +good bye diff --git a/apps/confpin/tools/clear_file b/apps/confpin/tools/clear_file new file mode 100644 index 00000000..a3bf1069 --- /dev/null +++ b/apps/confpin/tools/clear_file @@ -0,0 +1,14 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +import sys +from xmlrpclib import * + +if len(sys.argv) != 3: + print "usage: %s " % sys.argv[0] + sys.exit(1) + +s = ServerProxy('http://localhost:8090') +print "Active calls: %d" % s.calls() +#p ={ 'name' : sys.argv[1], 'path' : sys.argv[2] } +#print s.di('sbc','loadProfile',p) +print s.di('dsm', 'postDSMEvent', 'sw_audio', [['cmd', 'clearFile'],['audio_id', sys.argv[1]],['sound_set_id', sys.argv[2]]]) \ No newline at end of file diff --git a/apps/confpin/tools/fetch_file b/apps/confpin/tools/fetch_file new file mode 100644 index 00000000..bb54ae68 --- /dev/null +++ b/apps/confpin/tools/fetch_file @@ -0,0 +1,14 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +import sys +from xmlrpclib import * + +if len(sys.argv) != 3: + print "usage: %s " % sys.argv[0] + sys.exit(1) + +s = ServerProxy('http://localhost:8090') +print "Active calls: %d" % s.calls() +#p ={ 'name' : sys.argv[1], 'path' : sys.argv[2] } +#print s.di('sbc','loadProfile',p) +print s.di('dsm', 'postDSMEvent', 'sw_audio', [['cmd', 'fetchFile'],['audio_id', sys.argv[1]],['sound_set_id', sys.argv[2]]]) \ No newline at end of file diff --git a/apps/confpin/tools/push_file b/apps/confpin/tools/push_file new file mode 100644 index 00000000..d949d992 --- /dev/null +++ b/apps/confpin/tools/push_file @@ -0,0 +1,14 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +import sys +from xmlrpclib import * + +if len(sys.argv) != 3: + print "usage: %s " % sys.argv[0] + sys.exit(1) + +s = ServerProxy('http://localhost:8090') +print "Active calls: %d" % s.calls() +#p ={ 'name' : sys.argv[1], 'path' : sys.argv[2] } +#print s.di('sbc','loadProfile',p) +print s.di('dsm','postDSMEvent', 'sw_audio', [['cmd', 'pushFile'],['audio_id', sys.argv[1]],['sound_set_id', sys.argv[2]]])