- Timestamp:
- Dec 4, 2013 12:19:48 PM (11 years ago)
- Location:
- pjproject/branches/projects/pjsua2/pjsip-apps/src/pygui
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/branches/projects/pjsua2/pjsip-apps/src/pygui/account.py
r4675 r4677 69 69 70 70 def newChat(self, buddy): 71 chat = ch.Chat(self , buddy)71 chat = ch.Chat(self.app, self, buddy) 72 72 self.chatList.append(chat) 73 73 return chat … … 109 109 ci = c.getInfo() 110 110 msg = "Incoming call for account '%s'" % self.cfg.idUri 111 if msgbox.askquestion(msg, "Accept call from '%s'?" % (ci.remoteU RI), default=msgbox.YES) == u'yes':111 if msgbox.askquestion(msg, "Accept call from '%s'?" % (ci.remoteUri), default=msgbox.YES) == u'yes': 112 112 call_prm.statusCode = 200 113 113 c.answer(call_prm) 114 114 115 115 # create chat instance 116 bud = self.findBuddy(ci.remoteURI) 117 if not bud: return 116 bud = self.findBuddy(ci.remoteUri) 117 if not bud: 118 print "=== Incoming call from '%s': cannot find buddy" % ci.remoteUri 119 return 118 120 chat = self.findChat(bud) 119 if not chat: chat = self.newChat(bud, c) 120 121 if not chat: chat = self.newChat(bud) 122 123 chat.showWindow() 121 124 chat.registerCall(bud, c) 122 chat. showWindow()125 chat.updateCallState(c, ci) 123 126 else: 124 127 c.hangup(call_prm) … … 126 129 def onInstantMessage(self, prm): 127 130 bud = self.findBuddy(prm.fromUri) 128 if not bud: return 131 if not bud: 132 print "=== Incoming IM from '%s': cannot find buddy" % prm.fromUri 133 return 129 134 chat = self.findChat(bud) 130 135 if not chat: chat = self.newChat(bud) 131 136 137 chat.showWindow() 132 138 chat.addMessage(bud.cfg.uri, prm.msgBody) 133 chat.showWindow()134 139 135 140 def onInstantMessageStatus(self, prm): … … 145 150 def onTypingIndication(self, prm): 146 151 bud = self.findBuddy(prm.fromUri) 147 if not bud: return 152 if not bud: 153 print "=== Incoming typing indication from '%s': cannot find buddy" % prm.fromUri 154 return 148 155 chat = self.findChat(bud) 149 156 if not chat: return -
pjproject/branches/projects/pjsua2/pjsip-apps/src/pygui/application.py
r4675 r4677 58 58 59 59 # GUI variables 60 self.showLogWindow = tk.IntVar(value= 1)60 self.showLogWindow = tk.IntVar(value=0) 61 61 self.quitting = False 62 62 … … 378 378 if not chat: chat = acc.newChat(bud) 379 379 chat.showWindow() 380 chat.start Audio()380 chat.startCall() 381 381 elif label=='Send instant message': 382 382 chat = acc.findChat(bud) -
pjproject/branches/projects/pjsua2/pjsip-apps/src/pygui/call.py
r4671 r4677 51 51 self.chat.updateCallState(self, ci) 52 52 53 def onCallMediaState(self, prm): 54 ci = self.getInfo() 55 for mi in ci.media: 56 if mi.type == pj.PJMEDIA_TYPE_AUDIO and \ 57 (mi.status == pj.PJSUA_CALL_MEDIA_ACTIVE or \ 58 mi.status == pj.PJSUA_CALL_MEDIA_REMOTE_HOLD): 59 m = self.getMedia(mi.index) 60 print m 61 53 62 def onInstantMessage(self, prm): 54 63 # chat instance should have been initalized -
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() -
pjproject/branches/projects/pjsua2/pjsip-apps/src/pygui/chatgui.py
r4671 r4677 74 74 self.columnconfigure(1, weight=0) 75 75 76 self._text = tk.Text(self, font=("Arial", "10"))76 self._text = tk.Text(self, width=50, height=30, font=("Arial", "10")) 77 77 self._text.grid(row=0, column=0, sticky='nswe') 78 78 self._text.config(state=tk.DISABLED) … … 83 83 scrl.grid(row=0, column=1, sticky='nsw') 84 84 85 self._typingBox = tk.Text(self, height=1, font=("Arial", "10"))85 self._typingBox = tk.Text(self, width=50, height=1, font=("Arial", "10")) 86 86 self._typingBox.grid(row=1, columnspan=2, sticky='we', pady=0) 87 87 … … 112 112 113 113 class AudioObserver: 114 def onRetry(self, peer_uri): 115 pass 116 def onKick(self, peer_uri): 114 def onHangup(self, peer_uri): 117 115 pass 118 116 def onHold(self, peer_uri): 117 pass 118 def onUnhold(self, peer_uri): 119 119 pass 120 120 def onRxMute(self, peer_uri, is_muted): … … 135 135 self._rxMute = False 136 136 self._txMute = False 137 138 # internal state: 0:init - 1:established - 2:failure/rejected 3:normal cleared139 137 self._state = AudioState.NULL 140 138 … … 149 147 self._callFrame.pack_forget() 150 148 self._initFrame.pack(fill=tk.BOTH) 151 self._btnRetry.pack_forget()152 149 self._btnCancel.pack(side=tk.TOP) 153 150 self._lblInitState['text'] = 'Intializing..' … … 161 158 if state == AudioState.FAILED: 162 159 self._lblInitState['text'] = 'Failed' 163 self._btnRetry.pack()164 160 else: 165 161 self._lblInitState['text'] = 'Normal cleared' 166 162 self._btnCancel.pack_forget() 163 164 self._btnHold['text'] = 'Hold' 165 self._btnHold.config(state=tk.NORMAL) 167 166 168 167 # save last state 169 168 self._state = state 170 169 171 def _onRetry(self):172 self._btnRetry.pack_forget()173 self._state = 0174 # notify app175 self._observer.onRetry(self.peerUri)176 177 def _onKick(self):178 # notify app179 self._observer.onKick(self.peerUri)180 181 170 def _onHold(self): 182 # notify app 183 self._observer.onHold(self.peerUri) 171 self._btnHold.config(state=tk.DISABLED) 172 # notify app 173 if self._btnHold['text'] == 'Hold': 174 self._observer.onHold(self.peerUri) 175 self._btnHold['text'] = 'Unhold' 176 else: 177 self._observer.onUnhold(self.peerUri) 178 self._btnHold['text'] = 'Hold' 179 self._btnHold.config(state=tk.NORMAL) 184 180 185 181 def _onHangup(self): 186 182 # notify app 187 self._observer.on Kick(self.peerUri)183 self._observer.onHangup(self.peerUri) 188 184 189 185 def _onRxMute(self): … … 210 206 self._lblInitState.pack(side=tk.TOP, fill=tk.X, expand=1) 211 207 212 # Operation: retry, cancel/kick 213 self._btnRetry = ttk.Button(self._initFrame, text = 'Retry', command=self._onRetry) 214 self._btnRetry.pack(side=tk.TOP) 215 self._btnCancel = ttk.Button(self._initFrame, text = 'Cancel', command=self._onKick) 208 # Operation: cancel/kick 209 self._btnCancel = ttk.Button(self._initFrame, text = 'Cancel', command=self._onHangup) 216 210 self._btnCancel.pack(side=tk.TOP) 217 211 … … 383 377 aud_frm.updateState(state) 384 378 break 379 if state >= AudioState.DISCONNECTED and len(self._audioFrames) == 1: 380 self.enableAudio(False) 381 else: 382 self.enableAudio(True) 385 383 386 384 if __name__ == '__main__':
Note: See TracChangeset
for help on using the changeset viewer.