Revision e21a6d08

b/py/maugis/scenic/application.py
1
#!/usr/bin/env python
2
# -*- coding: utf-8 -*-
3
# 
4
# Scenic
5
# Copyright (C) 2008 Société des arts technologiques (SAT)
6
# http://www.sat.qc.ca
7
# All rights reserved.
8
#
9
# This file is free software: you can redistribute it and/or modify
10
# it under the terms of the GNU General Public License as published by
11
# the Free Software Foundation, either version 2 of the License, or
12
# (at your option) any later version.
13
#
14
# Scenic is distributed in the hope that it will be useful,
15
# but WITHOUT ANY WARRANTY; without even the implied warranty of
16
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
# GNU General Public License for more details.
18
#
19
# You should have received a copy of the GNU General Public License
20
# along with Scenic. If not, see <http://www.gnu.org/licenses/>.
21

  
22
"""
23
Main application 
24
"""
25
import os
26
import gtk # for dialog responses. TODO: remove
27

  
28
from twisted.internet import defer
29
from twisted.internet import error
30
from twisted.internet import reactor
31

  
32
from scenic import communication
33
from scenic import saving
34
from scenic import process # just for constants
35
from scenic.streamer import StreamerManager
36
from scenic import dialogs
37
from scenic import ports
38
from scenic import gui
39
from scenic.gui import _ # gettext
40

  
41
class Config(saving.ConfigStateSaving):
42
    """
43
    Class attributes are default.
44
    """
45
    # Default values
46
    negotiation_port = 17446 # receiving TCP (SIC) messages on it.
47
    smtpserver = "smtp.sat.qc.ca"
48
    email_info = "scenic@sat.qc.ca"
49
    audio_source = "jackaudiosrc"
50
    audio_sink = "jackaudiosink"
51
    audio_codec = "raw"
52
    audio_channels = 8
53
    video_source = "v4l2src"
54
    video_device = "/dev/video0"
55
    video_sink = "xvimagesink"
56
    video_codec = "mpeg4"
57
    video_display = ":0.0"
58
    video_bitrate = "3000000"
59
    video_width = 640
60
    video_height = 480
61
    confirm_quit = False
62
    theme = "Darklooks"
63

  
64
    def __init__(self):
65
        config_file = 'scenic.cfg'
66
        if os.path.isfile('/etc/' + config_file):
67
            config_dir = '/etc'
68
        else:
69
            config_dir = os.environ['HOME'] + '/.scenic'
70
        config_file_path = os.path.join(config_dir, config_file)
71
        saving.ConfigStateSaving.__init__(self, config_file_path)
72

  
73
class Application(object):
74
    def __init__(self, kiosk_mode=False, fullscreen=False):
75
        self.config = Config()
76
        self.send_video_port = None
77
        self.recv_video_port = None
78
        self.send_audio_port = None
79
        self.recv_audio_port = None
80
        self.ports_allocator = ports.PortsAllocator()
81
        self.address_book = saving.AddressBook()
82
        self.streamer_manager = StreamerManager(self)
83
        self._has_session = False
84
        self.streamer_manager.state_changed_signal.connect(self.on_streamer_state_changed) # XXX
85
        print("Starting SIC server on port %s" % (self.config.negotiation_port)) 
86
        self.server = communication.Server(self, self.config.negotiation_port) # XXX
87
        self.client = None 
88
        self.got_bye = False 
89
        # starting the GUI:
90
        self.gui = gui.Gui(self, kiosk_mode=kiosk_mode, fullscreen=fullscreen)
91
        reactor.addSystemEventTrigger("before", "shutdown", self.before_shutdown)
92
        try:
93
            self.server.start_listening()
94
        except error.CannotListenError, e:
95
            print("Cannot start SIC server.")
96
            print(str(e))
97
            raise
98
    
99
    def before_shutdown(self):
100
        """
101
        Last things done before quitting.
102
        """
103
        print("The application is shutting down.")
104
        # TODO: stop streamers
105
        if self.client is not None:
106
            if not self.got_bye:
107
                self.send_bye()
108
                self.stop_streamers()
109
            self.disconnect_client()
110
        print('stopping server')
111
        self.server.close()
112
    # ------------------------- session occuring -------------
113
    def has_session(self):
114
        """
115
        @rettype: bool
116
        """
117
        return self._has_session
118
    # -------------------- streamer ports -----------------
119

  
120
    def allocate_ports(self):
121
        # TODO: start_session
122
        self.recv_video_port = self.ports_allocator.allocate()
123
        self.recv_audio_port = self.ports_allocator.allocate()
124

  
125
    def free_ports(self):
126
        # TODO: stop_session
127
        for port in [self.recv_video_port, self.recv_audio_port]:
128
            try:
129
                self.ports_allocator.free(port)
130
            except ports.PortsAllocatorError, e:
131
                print(e)
132

  
133
    def save_configuration(self):
134
        """
135
        Saves the configuration to a file.
136
        Reads the widget value prior to do it.
137
        """
138
        self.gui._gather_configuration() # need to get the value of the configuration widgets.
139
        self.config.save()
140
        self.address_book.save() # addressbook values are already stored.
141
    # --------------------------- network receives ------------
142
    def handle_invite(self, message, addr):
143
        self.got_bye = False
144
        send_to_port = message["please_send_to_port"]
145
        
146
        def _on_contact_request_dialog_response(response):
147
            """
148
            User is accetping or declining an offer.
149
            @param result: Answer to the dialog.
150
            """
151
            if response == gtk.RESPONSE_OK:
152
                if self.client is not None:
153
                    self.send_accept(message, addr)
154
                else:
155
                    print("Error: connection lost, so we could not accept.")# FIXME
156
            elif response == gtk.RESPONSE_CANCEL or gtk.RESPONSE_DELETE_EVENT:
157
                self.send_refuse_and_disconnect() 
158
            else:
159
                pass
160
            return True
161

  
162
        if self.streamer_manager.is_busy():
163
            print("Got invitation, but we are busy.")
164
            communication.connect_send_and_disconnect(addr, send_to_port, {'msg':'REFUSE', 'sid':0}) #FIXME: where do we get the port number from?
165
        else:
166
            self.client = communication.Client(self, send_to_port)
167
            self.client.connect(addr)
168
            # TODO: if a contact in the addressbook has this address, displays it!
169
            text = _("<b><big>%s is inviting you.</big></b>\n\nDo you accept the connection?" % addr)
170
            self.gui.show_invited_dialog(text, _on_contact_request_dialog_response)
171

  
172
    def handle_cancel(self):
173
        if self.client is not None:
174
            self.client.disconnect()
175
            self.client = None
176
        self.gui.invited_dialog.hide()
177
        dialogs.ErrorDialog.create("Remote peer cancelled invitation.", parent=self.gui.main_window)
178

  
179
    def handle_accept(self, message, addr):
180
        self.gui._unschedule_offerer_invite_timeout()
181
        # FIXME: this doesn't make sense here
182
        self.got_bye = False
183
        # TODO: Use session to contain settings and ports
184
        if self.client is not None:
185
            self.gui.hide_calling_dialog("accept")
186
            self.send_video_port = message["videoport"]
187
            self.send_audio_port = message["audioport"]
188
            if self.streamer_manager.is_busy():
189
                dialogs.ErrorDialog.create("A streaming session is already in progress.", parent=self.gui.main_window)
190
            else:
191
                print("Got ACCEPT. Starting streamers as initiator.")
192
                self.start_streamers(addr)
193
                self.send_ack()
194
        else:
195
            print("Error ! Connection lost.") # FIXME
196

  
197
    def handle_refuse(self):
198
        self.gui._unschedule_offerer_invite_timeout()
199
        self.free_ports()
200
        self.gui.hide_calling_dialog("refuse")
201

  
202
    def handle_ack(self, addr):
203
        print("Got ACK. Starting streamers as answerer.")
204
        self.start_streamers(addr)
205

  
206
    def handle_bye(self):
207
        self.got_bye = True
208
        self.stop_streamers()
209
        if self.client is not None:
210
            print('disconnecting client and sending BYE')
211
            self.client.send({"msg":"OK", "sid":0})
212
            self.disconnect_client()
213

  
214
    def handle_ok(self):
215
        print("received ok. Everything has an end.")
216
        print('disconnecting client')
217
        self.disconnect_client()
218

  
219
    def on_server_receive_command(self, message, addr):
220
        # XXX
221
        msg = message["msg"]
222
        print("Got %s from %s" % (msg, addr))
223
        
224
        if msg == "INVITE":
225
            self.handle_invite(message, addr)
226
        elif msg == "CANCEL":
227
            self.handle_cancel()
228
        elif msg == "ACCEPT":
229
            self.handle_accept(message, addr)
230
        elif msg == "REFUSE":
231
            self.handle_refuse()
232
        elif msg == "ACK":
233
            self.handle_ack(addr)
234
        elif msg == "BYE":
235
            self.handle_bye()
236
        elif msg == "OK":
237
            self.handle_ok()
238
        else:
239
            print ('WARNING: Unexpected message %s' % (msg))
240

  
241
    # -------------------------- actions on streamer manager --------
242

  
243
    def start_streamers(self, addr):
244
        self._has_session = True
245
        self.streamer_manager.start(addr, self.config)
246

  
247
    def stop_streamers(self):
248
        self.streamer_manager.stop()
249

  
250
    def on_streamers_stopped(self, addr):
251
        """
252
        We call this when all streamers are stopped.
253
        """
254
        print("on_streamers_stopped got called")
255
        self._has_session = False
256
        self.free_ports()
257

  
258
    # ---------------------- sending messages -----------
259
        
260
    def disconnect_client(self):
261
        """
262
        Disconnects the SIC sender.
263
        @rettype: L{Deferred}
264
        """
265
        def _cb(result, d1):
266
            self.client = None
267
            d1.callback(True)
268
        def _cl(d1):
269
            if self.client is not None:
270
                d2 = self.client.disconnect()
271
                d2.addCallback(_cb, d1)
272
            else:
273
                d1.callback(True)
274
        if self.client is not None:
275
            d = defer.Deferred()
276
            reactor.callLater(0, _cl, d)
277
            return d
278
        else: 
279
            return defer.succeed(True)
280

  
281
    def send_invite(self):
282
        self.allocate_ports()
283
        if self.streamer_manager.is_busy():
284
            dialogs.ErrorDialog.create("Impossible to invite a contact to start streaming. A streaming session is already in progress.", parent=self.gui.main_window)
285
        else:
286
            # UPDATE when initiating session
287
            self.gui._gather_configuration()
288
        msg = {
289
            "msg":"INVITE",
290
            "sid":0, 
291
            "videoport": self.recv_video_port,
292
            "audioport": self.recv_audio_port,
293
            "please_send_to_port": self.config.negotiation_port
294
            }
295
        port = self.config.negotiation_port
296
        ip = self.address_book.selected_contact["address"]
297

  
298
        def _on_connected(proto):
299
            self.gui._schedule_offerer_invite_timeout()
300
            self.client.send(msg)
301
            return proto
302
        def _on_error(reason):
303
            print ("error trying to connect to %s:%s : %s" % (ip, port, reason))
304
            self.gui.calling_dialog.hide()
305
            self.client = None
306
            return None
307
           
308
        print ("sending %s to %s:%s" % (msg, ip, port))
309
        self.client = communication.Client(self, port)
310
        deferred = self.client.connect(ip)
311
        deferred.addCallback(_on_connected).addErrback(_on_error)
312
        self.gui.calling_dialog.show()
313
        # window will be hidden when we receive ACCEPT or REFUSE
314
    
315
    def send_accept(self, message, addr):
316
        # UPDATE config once we accept the invitie
317
        self.gui._gather_configuration()
318
        self.allocate_ports()
319
        self.client.send({"msg":"ACCEPT", "videoport":self.recv_video_port, "audioport":self.recv_audio_port, "sid":0})
320
        # TODO: Use session to contain settings and ports
321
        self.send_video_port = message["videoport"]
322
        self.send_audio_port = message["audioport"]
323
        
324
    def send_ack(self):
325
        self.client.send({"msg":"ACK", "sid":0})
326

  
327
    def send_bye(self):
328
        """
329
        Sends BYE
330
        BYE stops the streaming on the remote host.
331
        """
332
        if self.client is not None:
333
            self.client.send({"msg":"BYE", "sid":0})
334
    
335
    def send_cancel_and_disconnect(self):
336
        """
337
        Sends CANCEL
338
        CANCEL cancels the invite on the remote host.
339
        """
340
        if self.client is not None:
341
            self.client.send({"msg":"CANCEL", "sid":0})
342
            self.client.disconnect()
343
            self.client = None
344
        else:
345
            print('Warning: Trying to send CANCEL even though client is None')
346
    
347
    def send_refuse_and_disconnect(self):
348
        """
349
        Sends REFUSE 
350
        REFUSE tells the offerer we can't have a session.
351
        """
352
        if self.client is not None:
353
            self.client.send({"msg":"REFUSE", "sid":0})
354
            self.client.disconnect()
355
            self.client = None
356
        else:
357
            print('Warning: Trying to send REFUSE even though client is None')
358

  
359
    # ------------------- streaming events handlers ----------------
360
    
361
    def on_streamer_state_changed(self, streamer, new_state):
362
        """
363
        Slot for scenic.streamer.StreamerManager.state_changed_signal
364
        """
365
        if new_state in [process.STATE_STOPPED]:
366
            if not self.got_bye:
367
                """ got_bye means our peer sent us a BYE, so we shouldn't send one back """
368
                print("Local StreamerManager stopped. Sending BYE")
369
                self.send_bye()
370
            
371
    def on_client_socket_error(self, client, err, msg):
372
        # XXX
373
        self.gui.hide_calling_dialog(msg)
374
        text = _("%s: %s") % (str(err), str(msg))
375
        self.gui.show_error_dialog(text)
b/py/maugis/scenic/gui.py
51 51
import webbrowser
52 52
import gettext
53 53

  
54
from twisted.internet import defer
55
from twisted.internet import error
56 54
from twisted.internet import reactor
57 55

  
58
from scenic import communication
59
from scenic import saving
60 56
from scenic import process # just for constants
61
from scenic.streamer import StreamerManager
62 57
from scenic import dialogs
63
from scenic import ports
64 58
from scenic import data
59

  
65 60
PACKAGE_DATA = os.path.dirname(data.__file__)
66 61

  
67 62
### MULTILINGUAL SUPPORT ###
......
71 66
gtk.glade.bindtextdomain(APP_NAME, os.path.join(PACKAGE_DATA, "locale"))
72 67
gtk.glade.textdomain(APP_NAME)
73 68

  
74
class Config(saving.ConfigStateSaving):
75
    """
76
    Class attributes are default.
77
    """
78
    # Default values
79
    negotiation_port = 17446 # receiving TCP (SIC) messages on it.
80
    smtpserver = "smtp.sat.qc.ca"
81
    email_info = "scenic@sat.qc.ca"
82
    audio_source = "jackaudiosrc"
83
    audio_sink = "jackaudiosink"
84
    audio_codec = "raw"
85
    audio_channels = 8
86
    video_source = "v4l2src"
87
    video_device = "/dev/video0"
88
    video_sink = "xvimagesink"
89
    video_codec = "mpeg4"
90
    video_display = ":0.0"
91
    video_bitrate = "3000000"
92
    video_width = 640
93
    video_height = 480
94
    confirm_quit = False
95
    theme = "Darklooks"
96

  
97
    def __init__(self):
98
        config_file = 'scenic.cfg'
99
        if os.path.isfile('/etc/' + config_file):
100
            config_dir = '/etc'
101
        else:
102
            config_dir = os.environ['HOME'] + '/.scenic'
103
        config_file_path = os.path.join(config_dir, config_file)
104
        saving.ConfigStateSaving.__init__(self, config_file_path)
105

  
106 69
def _get_combobox_value(widget):
107 70
    """
108 71
    Returns the current value of a GTK ComboBox widget.
......
157 120
Each peer decides what to receive from the other peer. Next, one peer can invite an other one to stream high-quality audio and video.
158 121
"""
159 122

  
160

  
161 123
class Gui(object):
162 124
    """
163 125
    Main application (arguably God) class
......
796 758
            self._offerer_invite_timeout = reactor.callLater(5, _cl_offerer_invite_timed_out)
797 759
        else:
798 760
            print("Warning: Already scheduled a timeout as we're already inviting a contact")
799

  
800
###########################################################
801

  
802
class Application(object):
803
    def __init__(self, kiosk_mode=False, fullscreen=False):
804
        self.config = Config()
805
        self.send_video_port = None
806
        self.recv_video_port = None
807
        self.send_audio_port = None
808
        self.recv_audio_port = None
809
        self.ports_allocator = ports.PortsAllocator()
810
        self.address_book = saving.AddressBook()
811
        self.streamer_manager = StreamerManager(self)
812
        self._has_session = False
813
        self.streamer_manager.state_changed_signal.connect(self.on_streamer_state_changed) # XXX
814
        print("Starting SIC server on port %s" % (self.config.negotiation_port)) 
815
        self.server = communication.Server(self, self.config.negotiation_port) # XXX
816
        self.client = None 
817
        self.got_bye = False 
818
        # starting the GUI:
819
        self.gui = Gui(self, kiosk_mode=kiosk_mode, fullscreen=fullscreen)
820
        reactor.addSystemEventTrigger("before", "shutdown", self.before_shutdown)
821
        try:
822
            self.server.start_listening()
823
        except error.CannotListenError, e:
824
            print("Cannot start SIC server.")
825
            print(str(e))
826
            raise
827
    
828
    def before_shutdown(self):
829
        """
830
        Last things done before quitting.
831
        """
832
        print("The application is shutting down.")
833
        # TODO: stop streamers
834
        if self.client is not None:
835
            if not self.got_bye:
836
                self.send_bye()
837
                self.stop_streamers()
838
            self.disconnect_client()
839
        print('stopping server')
840
        self.server.close()
841
    # ------------------------- session occuring -------------
842
    def has_session(self):
843
        """
844
        @rettype: bool
845
        """
846
        return self._has_session
847
    # -------------------- streamer ports -----------------
848

  
849
    def allocate_ports(self):
850
        # TODO: start_session
851
        self.recv_video_port = self.ports_allocator.allocate()
852
        self.recv_audio_port = self.ports_allocator.allocate()
853

  
854
    def free_ports(self):
855
        # TODO: stop_session
856
        for port in [self.recv_video_port, self.recv_audio_port]:
857
            try:
858
                self.ports_allocator.free(port)
859
            except ports.PortsAllocatorError, e:
860
                print(e)
861

  
862
    def save_configuration(self):
863
        """
864
        Saves the configuration to a file.
865
        Reads the widget value prior to do it.
866
        """
867
        self.gui._gather_configuration() # need to get the value of the configuration widgets.
868
        self.config.save()
869
        self.address_book.save() # addressbook values are already stored.
870
    # --------------------------- network receives ------------
871
    def handle_invite(self, message, addr):
872
        self.got_bye = False
873
        send_to_port = message["please_send_to_port"]
874
        
875
        def _on_contact_request_dialog_response(response):
876
            """
877
            User is accetping or declining an offer.
878
            @param result: Answer to the dialog.
879
            """
880
            if response == gtk.RESPONSE_OK:
881
                if self.client is not None:
882
                    self.send_accept(message, addr)
883
                else:
884
                    print("Error: connection lost, so we could not accept.")# FIXME
885
            elif response == gtk.RESPONSE_CANCEL or gtk.RESPONSE_DELETE_EVENT:
886
                self.send_refuse_and_disconnect() 
887
            else:
888
                pass
889
            return True
890

  
891
        if self.streamer_manager.is_busy():
892
            print("Got invitation, but we are busy.")
893
            communication.connect_send_and_disconnect(addr, send_to_port, {'msg':'REFUSE', 'sid':0}) #FIXME: where do we get the port number from?
894
        else:
895
            self.client = communication.Client(self, send_to_port)
896
            self.client.connect(addr)
897
            # TODO: if a contact in the addressbook has this address, displays it!
898
            text = _("<b><big>%s is inviting you.</big></b>\n\nDo you accept the connection?" % addr)
899
            self.gui.show_invited_dialog(text, _on_contact_request_dialog_response)
900

  
901
    def handle_cancel(self):
902
        if self.client is not None:
903
            self.client.disconnect()
904
            self.client = None
905
        self.gui.invited_dialog.hide()
906
        dialogs.ErrorDialog.create("Remote peer cancelled invitation.", parent=self.gui.main_window)
907

  
908
    def handle_accept(self, message, addr):
909
        self.gui._unschedule_offerer_invite_timeout()
910
        # FIXME: this doesn't make sense here
911
        self.got_bye = False
912
        # TODO: Use session to contain settings and ports
913
        if self.client is not None:
914
            self.gui.hide_calling_dialog("accept")
915
            self.send_video_port = message["videoport"]
916
            self.send_audio_port = message["audioport"]
917
            if self.streamer_manager.is_busy():
918
                dialogs.ErrorDialog.create("A streaming session is already in progress.", parent=self.gui.main_window)
919
            else:
920
                print("Got ACCEPT. Starting streamers as initiator.")
921
                self.start_streamers(addr)
922
                self.send_ack()
923
        else:
924
            print("Error ! Connection lost.") # FIXME
925

  
926
    def handle_refuse(self):
927
        self.gui._unschedule_offerer_invite_timeout()
928
        self.free_ports()
929
        self.gui.hide_calling_dialog("refuse")
930

  
931
    def handle_ack(self, addr):
932
        print("Got ACK. Starting streamers as answerer.")
933
        self.start_streamers(addr)
934

  
935
    def handle_bye(self):
936
        self.got_bye = True
937
        self.stop_streamers()
938
        if self.client is not None:
939
            print('disconnecting client and sending BYE')
940
            self.client.send({"msg":"OK", "sid":0})
941
            self.disconnect_client()
942

  
943
    def handle_ok(self):
944
        print("received ok. Everything has an end.")
945
        print('disconnecting client')
946
        self.disconnect_client()
947

  
948
    def on_server_receive_command(self, message, addr):
949
        # XXX
950
        msg = message["msg"]
951
        print("Got %s from %s" % (msg, addr))
952
        
953
        if msg == "INVITE":
954
            self.handle_invite(message, addr)
955
        elif msg == "CANCEL":
956
            self.handle_cancel()
957
        elif msg == "ACCEPT":
958
            self.handle_accept(message, addr)
959
        elif msg == "REFUSE":
960
            self.handle_refuse()
961
        elif msg == "ACK":
962
            self.handle_ack(addr)
963
        elif msg == "BYE":
964
            self.handle_bye()
965
        elif msg == "OK":
966
            self.handle_ok()
967
        else:
968
            print ('WARNING: Unexpected message %s' % (msg))
969

  
970
    # -------------------------- actions on streamer manager --------
971

  
972
    def start_streamers(self, addr):
973
        self._has_session = True
974
        self.streamer_manager.start(addr, self.config)
975

  
976
    def stop_streamers(self):
977
        self.streamer_manager.stop()
978

  
979
    def on_streamers_stopped(self, addr):
980
        """
981
        We call this when all streamers are stopped.
982
        """
983
        print("on_streamers_stopped got called")
984
        self._has_session = False
985
        self.free_ports()
986

  
987
    # ---------------------- sending messages -----------
988
        
989
    def disconnect_client(self):
990
        """
991
        Disconnects the SIC sender.
992
        @rettype: L{Deferred}
993
        """
994
        def _cb(result, d1):
995
            self.client = None
996
            d1.callback(True)
997
        def _cl(d1):
998
            if self.client is not None:
999
                d2 = self.client.disconnect()
1000
                d2.addCallback(_cb, d1)
1001
            else:
1002
                d1.callback(True)
1003
        if self.client is not None:
1004
            d = defer.Deferred()
1005
            reactor.callLater(0, _cl, d)
1006
            return d
1007
        else: 
1008
            return defer.succeed(True)
1009

  
1010
    def send_invite(self):
1011
        self.allocate_ports()
1012
        if self.streamer_manager.is_busy():
1013
            dialogs.ErrorDialog.create("Impossible to invite a contact to start streaming. A streaming session is already in progress.", parent=self.gui.main_window)
1014
        else:
1015
            # UPDATE when initiating session
1016
            self.gui._gather_configuration()
1017
        msg = {
1018
            "msg":"INVITE",
1019
            "sid":0, 
1020
            "videoport": self.recv_video_port,
1021
            "audioport": self.recv_audio_port,
1022
            "please_send_to_port": self.config.negotiation_port
1023
            }
1024
        port = self.config.negotiation_port
1025
        ip = self.address_book.selected_contact["address"]
1026

  
1027
        def _on_connected(proto):
1028
            self.gui._schedule_offerer_invite_timeout()
1029
            self.client.send(msg)
1030
            return proto
1031
        def _on_error(reason):
1032
            print ("error trying to connect to %s:%s : %s" % (ip, port, reason))
1033
            self.gui.calling_dialog.hide()
1034
            self.client = None
1035
            return None
1036
           
1037
        print ("sending %s to %s:%s" % (msg, ip, port))
1038
        self.client = communication.Client(self, port)
1039
        deferred = self.client.connect(ip)
1040
        deferred.addCallback(_on_connected).addErrback(_on_error)
1041
        self.gui.calling_dialog.show()
1042
        # window will be hidden when we receive ACCEPT or REFUSE
1043
    
1044
    def send_accept(self, message, addr):
1045
        # UPDATE config once we accept the invitie
1046
        self.gui._gather_configuration()
1047
        self.allocate_ports()
1048
        self.client.send({"msg":"ACCEPT", "videoport":self.recv_video_port, "audioport":self.recv_audio_port, "sid":0})
1049
        # TODO: Use session to contain settings and ports
1050
        self.send_video_port = message["videoport"]
1051
        self.send_audio_port = message["audioport"]
1052
        
1053
    def send_ack(self):
1054
        self.client.send({"msg":"ACK", "sid":0})
1055

  
1056
    def send_bye(self):
1057
        """
1058
        Sends BYE
1059
        BYE stops the streaming on the remote host.
1060
        """
1061
        if self.client is not None:
1062
            self.client.send({"msg":"BYE", "sid":0})
1063
    
1064
    def send_cancel_and_disconnect(self):
1065
        """
1066
        Sends CANCEL
1067
        CANCEL cancels the invite on the remote host.
1068
        """
1069
        if self.client is not None:
1070
            self.client.send({"msg":"CANCEL", "sid":0})
1071
            self.client.disconnect()
1072
            self.client = None
1073
        else:
1074
            print('Warning: Trying to send CANCEL even though client is None')
1075
    
1076
    def send_refuse_and_disconnect(self):
1077
        """
1078
        Sends REFUSE 
1079
        REFUSE tells the offerer we can't have a session.
1080
        """
1081
        if self.client is not None:
1082
            self.client.send({"msg":"REFUSE", "sid":0})
1083
            self.client.disconnect()
1084
            self.client = None
1085
        else:
1086
            print('Warning: Trying to send REFUSE even though client is None')
1087

  
1088
    # ------------------- streaming events handlers ----------------
1089
    
1090
    def on_streamer_state_changed(self, streamer, new_state):
1091
        """
1092
        Slot for scenic.streamer.StreamerManager.state_changed_signal
1093
        """
1094
        if new_state in [process.STATE_STOPPED]:
1095
            if not self.got_bye:
1096
                """ got_bye means our peer sent us a BYE, so we shouldn't send one back """
1097
                print("Local StreamerManager stopped. Sending BYE")
1098
                self.send_bye()
1099
            
1100
    def on_client_socket_error(self, client, err, msg):
1101
        # XXX
1102
        self.gui.hide_calling_dialog(msg)
1103
        text = _("%s: %s") % (str(err), str(msg))
1104
        self.gui.show_error_dialog(text)
b/py/maugis/scenic/runner.py
29 29
from twisted.internet import reactor
30 30
from twisted.internet import error
31 31
from twisted.python import log
32
from scenic import gui
32

  
33
from scenic import application
34
from scenic import version
33 35

  
34 36
def start_logging_to_stdout():
35 37
    log.startLogging(sys.stdout)
36 38

  
37 39
def run():
38 40
    # command line parsing
39
    parser = OptionParser(usage="%prog", version=str(gui.__version__))
41
    parser = OptionParser(usage="%prog", version=str(version.__version__))
40 42
    parser.add_option("-k", "--kiosk", action="store_true", help="Run in kiosk mode")
41 43
    parser.add_option("-f", "--fullscreen", action="store_true", help="Run in fullscreen mode")
42 44
    (options, args) = parser.parse_args()
43 45
    start_logging_to_stdout()
44 46
    try:
45
        app = gui.Application(kiosk_mode=options.kiosk, fullscreen=options.fullscreen)
47
        app = application.Application(kiosk_mode=options.kiosk, fullscreen=options.fullscreen)
46 48
    except error.CannotListenError, e:
47 49
        print("There must be an other Scenic running.")
48 50
        print(str(e))

Also available in: Unified diff