Ignore:
Timestamp:
Dec 4, 2013 12:19:48 PM (10 years ago)
Author:
nanang
Message:

Re #1708: Implement adding participants, also various misc updates/fixes.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/branches/projects/pjsua2/pjsip-apps/src/pygui/chat.py

    r4671 r4677  
    3232         
    3333class 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 
    3536                self._acc = acc 
    3637                self._participantList = [] 
     
    5455                return the_call 
    5556                 
     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                 
    5672        def _sendTypingIndication(self, is_typing): 
    5773                type_ind_param = pj.SendTypingIndicationParam() 
     
    6076                        c = self._getCallFromBuddy(bud) 
    6177                        try: 
    62                                 if c: 
     78                                if c and c.connected: 
    6379                                        c.sendTypingIndication(type_ind_param) 
    6480                                else: 
     
    6783                                pass 
    6884 
     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 
    69104        def isPrivate(self): 
    70105                return len(self._participantList) <= 1 
    71106                 
    72         def isBuddyParticipant(self, bud, call_inst): 
     107        def isBuddyParticipant(self, bud): 
    73108                return bud in self._participantList 
    74109                 
     
    79114                try: 
    80115                        idx = self._participantList.index(bud) 
    81                         print "registering call...", idx, self._participantList 
    82116                        if len(self._callList) < idx+1: 
    83117                                self._callList.append(call_inst) 
    84118                        else: 
    85119                                self._callList[idx] = call_inst 
     120 
     121                        call_inst.chat = self 
     122                        call_inst.peerUri = bud.cfg.uri 
    86123                except: 
    87                         return None 
     124                        pass 
    88125                 
    89126        def showWindow(self): 
    90127                self._gui.bringToFront() 
    91128 
     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                 
    92135        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 
    93142                self._participantList.append(bud) 
    94143                if call_inst: 
     
    97146 
    98147                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): 
    104150                if bud in self._participantList: 
    105151                        idx = self._participantList.index(bud) 
     
    113159                        self._updateGui() 
    114160                else: 
    115                         # will this eventually destroy itself? 
     161                        # will remove entry from list eventually destroy this chat? 
    116162                        self._acc.chatList.remove(self) 
     163                         
     164                        # let's destroy GUI manually 
     165                        self._gui.destroy() 
     166                        #self.destroy() 
    117167                         
    118168        def addMessage(self, from_uri, msg): 
     
    120170                        msg = from_uri + ': ' + msg 
    121171                        self._gui.textAddMessage(msg) 
     172                        self._sendInstantMessage(msg, from_uri) 
    122173                else: 
    123174                        self._gui.textAddMessage(msg, False) 
     
    127178                 
    128179        def startCall(self): 
     180                self._gui.enableAudio() 
    129181                call_param = pj.CallOpParam() 
    130182                call_param.opt.audioCount = 1 
     
    146198                                c.makeCall(bud.cfg.uri, call_param) 
    147199                        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) 
    149203                         
    150204        def stopCall(self): 
     
    155209                del self._callList[:] 
    156210                 
    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: 
    159217                        self._gui.audioUpdateState(thecall.peerUri, gui.AudioState.CONNECTED) 
    160218                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                         
    162224                        # reset entry in the callList 
    163225                        try: 
     
    166228                        except: 
    167229                                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) 
    168237 
    169238                         
     
    172241        # Text 
    173242        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) 
    187244 
    188245        def onStartTyping(self): 
     
    193250                 
    194251        # 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 
    199258        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                 
    201270        def onRxMute(self, peer_uri, is_muted): 
    202271                pass 
     
    208277        # Chat room 
    209278        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                                 
    212286        def onStartAudio(self): 
    213287                self.startCall() 
     
    215289        def onStopAudio(self): 
    216290                self.stopCall() 
     291 
     292 
     293class 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.