-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathcommunity_menu.py
More file actions
242 lines (205 loc) · 11.1 KB
/
community_menu.py
File metadata and controls
242 lines (205 loc) · 11.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
#import the necessary stuff here
import urllib
from datetime import datetime, timedelta
from time import mktime
import feedparser
from rootio.config import *
from rootio.content.models import CommunityContent
from sqlalchemy import create_engine, desc
from sqlalchemy.orm import sessionmaker
import re
import os
from time import sleep
from datetime import datetime, timedelta
class CommunityMenu:
def __init__(self, radio_station):
#Load GWs for ths station
#register listeners for incoming calls on those extensions, basically parked.
self.__category_id = None
self.__num_days = None
self.__recorded_file = None
self.__post_recording_option = None
self.__call = None
self.__radio_station = radio_station
self.__gateway = None
self.__accumulated_dtmf = None
self.__last_speak_time = None
self.__is_speaking = False
self.__is_playing_audio = False
self.__db = self.__get_db_connection()
self.__menu = self.__get_community_menu() #is a 1:1 mapping between the two tables
self.__start_listener()
def __get_db_connection(self):
engine = create_engine(DefaultConfig.SQLALCHEMY_DATABASE_URI)
return sessionmaker(bind=engine)()
def __start_listener(self):
self.__gateway = self.__get_gateway_used()
if self.__gateway != None:
self.__radio_station.call_handler.register_for_incoming_calls(self, True)
self.__radio_station.call_handler.register_for_call_hangup(self, str(self.__gateway))
self.__radio_station.call_handler.register_for_media_playback_stop(self, str(self.__gateway))
self.__radio_station.call_handler.register_for_media_playback_start(self, str(self.__gateway))
def __get_community_menu(self):
if len(self.__radio_station.station.community_menu) > 0:
return self.__radio_station.station.community_menu[0]
else:
return None
def __get_gateway_used(self): #this retrieves the extension that listens for calls for ads and announcements
gws = []
for gw in self.__radio_station.station.incoming_gateways:
gws.append(gw.number_bottom)
gws.sort()
if len(gws) > 0:
return gws[0]
else:
return None
def __finalize(self):
#hangup, clean variables, deregister for DTMF
try:
self.__radio_station.call_handler.hangup(self.__call['Channel-Call-UUID'])
except:
pass
self.__radio_station.call_handler.deregister_for_incoming_dtmf(str(self.__gateway))
#self.__radio_station.call_handler.deregister_for_incoming_calls(self)
#self.__radio_station.call_handler.deregister_for_call_hangup(str(self.__gateway))
#self.__radio_station.call_handler.deregister_for_media_playback_stop(str(self.__gateway))
#self.__radio_station.call_handler.deregister_for_media_playback_start(str(self.__gateway))
#self.__category_id = None
self.__num_days = None
self.__recorded_file = None
self.__post_recording_option = None
self.__call = None
self.__accumulated_dtmf = None
self.__last_speak_time = None
self.__is_speaking = False
self.__is_playing_audio = False
def notify_incoming_call(self, call_json):
self.__call = call_json
self.__radio_station.call_handler.bridge_incoming_call(call_json['Channel-Call-UUID'], "12")
self.__start(self.__call['Channel-Call-UUID'])
def notify_incoming_dtmf(self, event_json):
if self.__accumulated_dtmf == None:
self.__accumulated_dtmf = event_json["DTMF-Digit"]
else:
self.__accumulated_dtmf = self.__accumulated_dtmf + event_json["DTMF-Digit"]
def notify_speak_stop(self, event_json):
self.__last_speak_time = datetime.now()
self.__is_speaking = False
def notify_speak_start(self, event_json):
self.__is_speaking = True
def notify_media_play_stop(self, event_json):
self.__is_playing_audio = False
def notify_media_play_start(self, event_json):
self.__is_playing_audio = True
def notify_call_hangup(self, event_json):
self.__finalize()
'''
This plays an audio prompt and then gets the digits entered.
Will wait for a maximum of timeout_secs to return the entered DTMF digits
'''
def __play_and_get_max_dtmf(self, call_uuid, audio_prompt, max_int, timeout_secs, num_attempts):
attempts = 0
while attempts < num_attempts:
self.__play(call_uuid, audio_prompt)
self.__radio_station.call_handler.register_for_incoming_dtmf(self, self.__gateway)
sleep(timeout_secs)
#self.__radio_station.call_handler.deregister_for_incoming_dtmf(self.__gateway)
if self.__accumulated_dtmf != None and int(self.__accumulated_dtmf) <= max_int:
dtmf = self.__accumulated_dtmf
self.__accumulated_dtmf = None
return dtmf
attempts = attempts + 1
self.__accumulated_dtmf = None
return None
def __play_and_get_specific_dtmf(self, call_uuid, audio_prompt, allowed_digits, timeout_secs, num_attempts):
attempts = 0
while attempts < num_attempts:
self.__play(call_uuid, audio_prompt)
self.__radio_station.call_handler.register_for_incoming_dtmf(self, str(self.__gateway))
start_time = datetime.now()
while datetime.now() < start_time +timedelta(0, timeout_secs) and self.__accumulated_dtmf == None:
pass #wait
#self.__radio_station.call_handler.deregister_for_incoming_dtmf(str(self.__gateway))
if self.__accumulated_dtmf != None and self.__accumulated_dtmf in allowed_digits:
dtmf = self.__accumulated_dtmf
self.__accumulated_dtmf = None
return dtmf
attempts = attempts + 1
self.__accumulated_dtmf = None
return None
def __play(self, call_uuid, audio_file):
self.__radio_station.call_handler.play(call_uuid, audio_file)
self.__is_playing_audio = True #Not safe - Audio might throw an error
self.__wait_on_audio()
def __record_audio_file(self, call_uuid, audio_path):
self.__radio_station.call_handler.record_call(call_uuid, audio_path)
def __stop_record_audio_file(self, call_uuid, audio_path):
self.__radio_station.call_handler.stop_record_call(call_uuid, audio_path)
def __save_message(self, filename, originator, date_recorded, duration, message_type, valid_until, station):
cm = CommunityContent()
cm.date_created = date_recorded
cm.originator = originator
cm.duration = duration
cm.type_code = message_type
cm.valid_until = valid_until
cm.message = filename
cm.station = station
db_session = self.__db.object_session(cm)
db_session._model_changes = {}
db_session.add(cm)
db_session.commit()
def __wait_on_audio(self): #commands issued after play of audio are executed while FS is playing audio...
while self.__is_playing_audio:
pass
def __start(self, call_uuid): #called by the call handler upon receiving a call on the extension for which this is registered
self.__radio_station.call_handler.register_for_media_playback_stop(self, str(self.__gateway))
self.__radio_station.call_handler.register_for_media_playback_start(self, str(self.__gateway))
self.__play(call_uuid, os.path.join(DefaultConfig.CONTENT_DIR, self.__menu.welcome_message))
#get the category of the message being left
self.__category_id = self.__play_and_get_specific_dtmf(call_uuid, os.path.join(DefaultConfig.CONTENT_DIR, self.__menu.message_type_prompt), ["1","2","3"], 15, 3)
if self.__category_id == None:
self.__finalize()
return
#get the number of days for which valid
self.__num_days = self.__play_and_get_max_dtmf(call_uuid, os.path.join(DefaultConfig.CONTENT_DIR, self.__menu.days_prompt), 14, 15, 3)
if self.__num_days == None:
self.__finalize()
return
#instruct the person to record their message
self.__play(call_uuid, os.path.join(DefaultConfig.CONTENT_DIR, self.__menu.record_prompt))
filename = "{0}_{1}_recording.wav".format(self.__call['Caller-ANI'], datetime.strftime(datetime.now(), "%Y%M%d%H%M%S"))
audio_path = os.path.join(DefaultConfig.CONTENT_DIR, "community-content", str(self.__radio_station.station.id), self.__category_id, filename)
self.__record_audio_file(call_uuid, audio_path)
self.__radio_station.call_handler.register_for_speak_stop(self, str(self.__gateway))
self.__radio_station.call_handler.register_for_speak_start(self, str(self.__gateway))
self.__radio_station.call_handler.register_for_incoming_dtmf(self, str(self.__gateway))
self.__recording_start_time = datetime.now()
self.__is_speaking = True
self.__last_speak_time = datetime.now()
while (self.__is_speaking and self.__last_speak_time + timedelta(0, 30) > datetime.now()) and not (self.__accumulated_dtmf != None and "#" in self.__accumulated_dtmf): #duration of 30 sec, # key or silence of 5 seconds will result in end of recording
pass
self.__accumulated_dtmf = None
self.__stop_record_audio_file(call_uuid, audio_path)
self.__radio_station.call_handler.deregister_for_speak_stop(str(self.__gateway))
self.__radio_station.call_handler.deregister_for_speak_start(str(self.__gateway))
self.__radio_station.call_handler.deregister_for_incoming_dtmf(str(self.__gateway))
self.__recording_stop_time = datetime.now()
#Ask what to do with the recording
ctr = 0
is_finalized = False
while ctr < 3 and not is_finalized:
self.__post_recording_option = self.__play_and_get_specific_dtmf(call_uuid, os.path.join(DefaultConfig.CONTENT_DIR, self.__menu.finalization_prompt), ["1","2","3"], 15, 3)
if self.__post_recording_option == None:
self.__finalize()
elif self.__post_recording_option == "1": #Listen to the recording
self.__play(call_uuid, audio_path)
elif self.__post_recording_option == "2": #save the reording
self.__save_message(filename, self.__call['Caller-ANI'], datetime.now(), (self.__recording_stop_time - self.__recording_start_time).seconds, int(self.__category_id), datetime.now() + timedelta(int(self.__num_days), 0), self.__radio_station.station)
is_finalized = True
elif self.__post_recording_option == "3": #Discard
is_finalized = True #Just do not save the recording to the DB
ctr = ctr +1
#play that last thank you, goodbye message
self.__play(call_uuid, os.path.join(DefaultConfig.CONTENT_DIR, self.__menu.goodbye_message))
#clean up, hangup
self.__finalize()