- Timestamp:
- Dec 4, 2013 12:19:48 PM (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/branches/projects/pjsua2/pjsip-apps/src/pygui/chat.py
r4671 r4677 32 32 33 33 class Chat(gui.ChatObserver): 34 def __init__(self, acc, bud, call_inst=None): 34 def __init__(self, app, acc, bud, call_inst=None): 35 self._app = app 35 36 self._acc = acc 36 37 self._participantList = [] … … 54 55 return the_call 55 56 57 def _getBuddyFromUri(self, uri): 58 for bud in self._participantList: 59 if uri == bud.cfg.uri: 60 return bud 61 return None 62 63 def _getCallFromUri(self, uri, op = ''): 64 for idx, bud in enumerate(self._participantList): 65 if uri == bud.cfg.uri: 66 if idx < len(self._callList): 67 return self._callList[idx] 68 return None 69 print "=== %s cannot find buddy URI '%s'" % (op, uri) 70 return None 71 56 72 def _sendTypingIndication(self, is_typing): 57 73 type_ind_param = pj.SendTypingIndicationParam() … … 60 76 c = self._getCallFromBuddy(bud) 61 77 try: 62 if c :78 if c and c.connected: 63 79 c.sendTypingIndication(type_ind_param) 64 80 else: … … 67 83 pass 68 84 85 def _sendInstantMessage(self, msg, sender_uri=''): 86 send_im_param = pj.SendInstantMessageParam() 87 send_im_param.content = str(msg) 88 for bud in self._participantList: 89 # don't echo back to the original sender 90 if sender_uri and bud.cfg.uri == sender_uri: 91 continue 92 93 # send via call, if any, or buddy 94 c = self._getCallFromBuddy(bud) 95 try: 96 if c and c.connected: 97 c.sendInstantMessage(send_im_param) 98 else: 99 bud.sendInstantMessage(send_im_param) 100 except: 101 # error will be handled via Account::onInstantMessageStatus() 102 pass 103 69 104 def isPrivate(self): 70 105 return len(self._participantList) <= 1 71 106 72 def isBuddyParticipant(self, bud , call_inst):107 def isBuddyParticipant(self, bud): 73 108 return bud in self._participantList 74 109 … … 79 114 try: 80 115 idx = self._participantList.index(bud) 81 print "registering call...", idx, self._participantList82 116 if len(self._callList) < idx+1: 83 117 self._callList.append(call_inst) 84 118 else: 85 119 self._callList[idx] = call_inst 120 121 call_inst.chat = self 122 call_inst.peerUri = bud.cfg.uri 86 123 except: 87 return None124 pass 88 125 89 126 def showWindow(self): 90 127 self._gui.bringToFront() 91 128 129 # helper 130 def dumpParticipantList(self): 131 print "Number of participants: %d" % (len(self._participantList)) 132 for b in self._participantList: 133 print b.cfg.uri 134 92 135 def addParticipant(self, bud, call_inst=None): 136 # avoid duplication 137 if self.isBuddyParticipant(bud): return 138 for b in self._participantList: 139 if bud.cfg.uri == b.cfg.uri: return 140 141 # add it 93 142 self._participantList.append(bud) 94 143 if call_inst: … … 97 146 98 147 self._updateGui() 99 if not self.isPrivate(): 100 self.startCall() 101 self._gui.enableAudio() 102 103 def kickParticipant(bud): 148 149 def kickParticipant(self, bud): 104 150 if bud in self._participantList: 105 151 idx = self._participantList.index(bud) … … 113 159 self._updateGui() 114 160 else: 115 # will this eventually destroy itself?161 # will remove entry from list eventually destroy this chat? 116 162 self._acc.chatList.remove(self) 163 164 # let's destroy GUI manually 165 self._gui.destroy() 166 #self.destroy() 117 167 118 168 def addMessage(self, from_uri, msg): … … 120 170 msg = from_uri + ': ' + msg 121 171 self._gui.textAddMessage(msg) 172 self._sendInstantMessage(msg, from_uri) 122 173 else: 123 174 self._gui.textAddMessage(msg, False) … … 127 178 128 179 def startCall(self): 180 self._gui.enableAudio() 129 181 call_param = pj.CallOpParam() 130 182 call_param.opt.audioCount = 1 … … 146 198 c.makeCall(bud.cfg.uri, call_param) 147 199 except: 148 self._gui.audioUpdateState(bud.cfg.uri, gui.AudioState.FAILED) 200 #self._callList[idx] = None 201 #self._gui.audioUpdateState(bud.cfg.uri, gui.AudioState.FAILED) 202 self.kickParticipant(bud) 149 203 150 204 def stopCall(self): … … 155 209 del self._callList[:] 156 210 157 def updateCallState(self, thecall, info): 158 if info.state == pj.PJSIP_INV_STATE_CONFIRMED: 211 def updateCallState(self, thecall, info = None): 212 # info is optional here, just to avoid calling getInfo() twice (in the caller and here) 213 if not info: info = thecall.getInfo() 214 if info.state < pj.PJSIP_INV_STATE_CONFIRMED: 215 self._gui.audioUpdateState(thecall.peerUri, gui.AudioState.INITIALIZING) 216 elif info.state == pj.PJSIP_INV_STATE_CONFIRMED: 159 217 self._gui.audioUpdateState(thecall.peerUri, gui.AudioState.CONNECTED) 160 218 elif info.state == pj.PJSIP_INV_STATE_DISCONNECTED: 161 self._gui.audioUpdateState(thecall.peerUri, gui.AudioState.DISCONNECTED) 219 if info.lastStatusCode/100 != 2: 220 self._gui.audioUpdateState(thecall.peerUri, gui.AudioState.FAILED) 221 else: 222 self._gui.audioUpdateState(thecall.peerUri, gui.AudioState.DISCONNECTED) 223 162 224 # reset entry in the callList 163 225 try: … … 166 228 except: 167 229 pass 230 231 self.addMessage(None, "Call to '%s' disconnected: %s" % (thecall.peerUri, info.lastReason)) 232 233 # kick the disconnected participant, but the last (avoid zombie chat) 234 if not self.isPrivate(): 235 bud = self._getBuddyFromUri(thecall.peerUri) 236 if bud: self.kickParticipant(bud) 168 237 169 238 … … 172 241 # Text 173 242 def onSendMessage(self, msg): 174 send_im_param = pj.SendInstantMessageParam() 175 send_im_param.content = str(msg) 176 for bud in self._participantList: 177 # send via call, if any, or buddy 178 c = self._getCallFromBuddy(bud) 179 try: 180 if c: 181 c.sendInstantMessage(send_im_param) 182 else: 183 bud.sendInstantMessage(send_im_param) 184 except: 185 # error will be handled via Account::onInstantMessageStatus() 186 pass 243 self._sendInstantMessage(msg) 187 244 188 245 def onStartTyping(self): … … 193 250 194 251 # Audio 195 def onRetry(self, peer_uri): 196 pass 197 def onKick(self, peer_uri): 198 pass 252 def onHangup(self, peer_uri): 253 c = self._getCallFromUri(peer_uri, "onHangup()") 254 if not c: return 255 call_param = pj.CallOpParam() 256 c.hangup(call_param) 257 199 258 def onHold(self, peer_uri): 200 pass 259 c = self._getCallFromUri(peer_uri, "onHold()") 260 if not c: return 261 call_param = pj.CallOpParam() 262 c.setHold(call_param) 263 264 def onUnhold(self, peer_uri): 265 c = self._getCallFromUri(peer_uri, "onUnhold()") 266 if not c: return 267 call_param = pj.CallOpParam() 268 c.reinvite(call_param) 269 201 270 def onRxMute(self, peer_uri, is_muted): 202 271 pass … … 208 277 # Chat room 209 278 def onAddParticipant(self): 210 #self.addParticipant() 211 pass 279 buds = [] 280 dlg = AddParticipantDlg(None, self._app, buds) 281 if dlg.doModal(): 282 for bud in buds: 283 self.addParticipant(bud) 284 self.startCall() 285 212 286 def onStartAudio(self): 213 287 self.startCall() … … 215 289 def onStopAudio(self): 216 290 self.stopCall() 291 292 293 class AddParticipantDlg(tk.Toplevel): 294 """ 295 List of buddies 296 """ 297 def __init__(self, parent, app, bud_list): 298 tk.Toplevel.__init__(self, parent) 299 self.title('Add participants..') 300 self.transient(parent) 301 self.parent = parent 302 self._app = app 303 self.buddyList = bud_list 304 305 self.isOk = False 306 307 self.createWidgets() 308 309 def doModal(self): 310 if self.parent: 311 self.parent.wait_window(self) 312 else: 313 self.wait_window(self) 314 return self.isOk 315 316 def createWidgets(self): 317 # buddy list 318 list_frame = ttk.Frame(self) 319 list_frame.pack(side=tk.TOP, fill=tk.BOTH, expand=1, padx=20, pady=20) 320 #scrl = ttk.Scrollbar(self, orient=tk.VERTICAL, command=list_frame.yview) 321 #list_frame.config(yscrollcommand=scrl.set) 322 #scrl.pack(side=tk.RIGHT, fill=tk.Y) 323 324 # draw buddy list 325 self.buddies = [] 326 for acc in self._app.accList: 327 self.buddies.append((0, acc.cfg.idUri)) 328 for bud in acc.buddyList: 329 self.buddies.append((1, bud)) 330 331 self.bud_var = [] 332 for idx,(flag,bud) in enumerate(self.buddies): 333 self.bud_var.append(tk.IntVar()) 334 if flag==0: 335 s = ttk.Separator(list_frame, orient=tk.HORIZONTAL) 336 s.pack(fill=tk.X) 337 l = tk.Label(list_frame, anchor=tk.W, text="Account '%s':" % (bud)) 338 l.pack(fill=tk.X) 339 else: 340 c = tk.Checkbutton(list_frame, anchor=tk.W, text=bud.cfg.uri, variable=self.bud_var[idx]) 341 c.pack(fill=tk.X) 342 s = ttk.Separator(list_frame, orient=tk.HORIZONTAL) 343 s.pack(fill=tk.X) 344 345 # Ok/cancel buttons 346 tail_frame = ttk.Frame(self) 347 tail_frame.pack(side=tk.BOTTOM, fill=tk.BOTH, expand=1) 348 349 btnOk = ttk.Button(tail_frame, text='Ok', default=tk.ACTIVE, command=self.onOk) 350 btnOk.pack(side=tk.LEFT, padx=20, pady=10) 351 btnCancel = ttk.Button(tail_frame, text='Cancel', command=self.onCancel) 352 btnCancel.pack(side=tk.RIGHT, padx=20, pady=10) 353 354 def onOk(self): 355 self.buddyList[:] = [] 356 for idx,(flag,bud) in enumerate(self.buddies): 357 if not flag: continue 358 if self.bud_var[idx].get() and not (bud in self.buddyList): 359 self.buddyList.append(bud) 360 361 self.isOk = True 362 self.destroy() 363 364 def onCancel(self): 365 self.destroy()
Note: See TracChangeset
for help on using the changeset viewer.