forked from timvideos/gst-switch
-
Notifications
You must be signed in to change notification settings - Fork 1
/
server.py
255 lines (227 loc) · 8.6 KB
/
server.py
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
243
244
245
246
247
248
249
250
251
252
253
254
255
import os
import signal
import subprocess
from errno import ENOENT
from exception import PathError, ServerProcessError
from time import sleep
__all__ = ["Server", ]
class Server(object):
"""Control all server related operations
:param path: Path where all executables gst-switch-srv, gst-launch-1.0, etc are located
:param video_port: The video port number - default = 3000
:param audio_port: The audio port number - default = 4000
:param control_port: The control port number - default = 5000
:param record_file: The record file format
:returns: nothing
"""
SLEEP_TIME = 0.5
def __init__(
self,
path,
video_port=3000,
audio_port=4000,
control_port=5000,
record_file='record.data'):
super(Server, self).__init__()
self.path = path
self.video_port = video_port
self.audio_port = audio_port
self.control_port = control_port
self.record_file = record_file
self.proc = None
self.pid = -1
@property
def path(self):
return self._path
@path.setter
def path(self, path):
"""Set path
:raises ValueError: Path cannot be left blank
"""
if not path:
raise ValueError("Path '{0}' cannot be blank".format(path))
else:
self._path = path
@property
def video_port(self):
return self._video_port
@video_port.setter
def video_port(self, video_port):
"""Set Video Port
:raises ValueError: Video Port cannot be left blank
:raises ValueError: Video Port must be in range 1 to 65535
:raises TypeError: Video Port must be a string or a number
"""
if not video_port:
raise ValueError("Video Port '{0}' cannot be blank"
.format(video_port))
else:
try:
i = int(video_port)
if i < 1 or i > 65535:
raise ValueError('Video Port must be in range 1 to 65535')
else:
self._video_port = video_port
except TypeError:
raise TypeError("Video Port must be a string or a number, "
"not '{0}'".format(type(video_port)))
@property
def audio_port(self):
return self._audio_port
@audio_port.setter
def audio_port(self, audio_port):
"""Set Audio Port
:raises ValueError: Audio Port cannot be left blank
:raises ValueError: Audio Port must be in range 1 to 65535
:raises TypeError: Audio Port must be a string or a number
"""
if not audio_port:
raise ValueError("Audio Port '{0}' cannot be blank"
.format(audio_port))
else:
try:
i = int(audio_port)
if i < 1 or i > 65535:
raise ValueError('Audio Port must be in range 1 to 65535')
else:
self._audio_port = audio_port
except TypeError:
raise TypeError("Audio Port must be a string or a number,"
" not '{0}'".format(type(audio_port)))
@property
def control_port(self):
return self._control_port
@control_port.setter
def control_port(self, control_port):
"""Set Control Port
:raises ValueError: Control Port cannot be left blank
:raises ValueError: Control Port must be in range 1 to 65535
:raises TypeError: Control Port must be a string or a number
"""
if not control_port:
raise ValueError("Control Port '{0}' cannot be blank"
.format(control_port))
else:
try:
i = int(control_port)
if i < 1 or i > 65535:
raise ValueError('Control Port must be in range 1 to 65535')
else:
self._control_port = control_port
except TypeError:
raise TypeError("Control Port must be a string or a number,"
" not '{0}'".format(type(control_port)))
@property
def record_file(self):
return self._record_file
@record_file.setter
def record_file(self, record_file):
"""Set Record File
:raises ValueError: Record File cannot be left blank
:raises ValueError: Record File cannot have forward slashes
"""
if not record_file:
raise ValueError("Record File '{0}' cannot be blank"
.format(record_file))
else:
rec = str(record_file)
if rec.find('/') < 0:
self._record_file = rec
else:
raise ValueError("Record File: '{0}' "
"cannot have forward slashes".format(rec))
def run(self, gst_option=''):
"""Launch the server process
:param: None
:gst-option: Any gstreamer option. Refer to http://www.linuxmanpages.com/man1/gst-launch-0.8.1.php#lbAF.
Multiple can be added separated by spaces
:returns: nothing
:raises IOError: Fail to open /dev/null (os.devnull)
:raises PathError: Unable to find gst-switch-srv at path specified
:raises ServerProcessError: Running gst-switch-srv gives a OS based error.
"""
self.gst_option_string = gst_option
print "Starting server"
self.proc = self._run_process()
if self.proc:
self.pid = self.proc.pid
# TODO: Sleep time may vary
sleep(self.SLEEP_TIME)
def _run_process(self):
"""Non-public method: Runs the gst-switch-srv process
"""
cmd = self.path
cmd += """gst-switch-srv \
{0} \
--video-input-port={1} \
--audio-input-port={2} \
--control-port={3} \
--record={4} """ .format(self.gst_option_string,
self.video_port,
self.audio_port,
self.control_port,
self.record_file)
cmd = " ".join(cmd.split())
proc = self._start_process(cmd)
return proc
def _start_process(self, cmd):
"""Non-public method: Start a process
:param cmd: The command which needs to be executed
:returns: process created
"""
print 'Creating process %s' % (cmd)
try:
with open(os.devnull, 'w') as tempf:
process = subprocess.Popen(
cmd.split(),
stdout=tempf,
stderr=tempf,
bufsize=-1,
shell=False)
print cmd
return process
except OSError as error:
if error.errno == ENOENT:
raise PathError("Cannot find gst-switch-srv at path:"
" '{0}'".format(self.path))
else:
raise ServerProcessError("Internal error "
"while launching process")
def terminate(self):
"""Terminate the server.
self.proc is made None on success
:param: None
:returns: True when success
:raises ServerProcessError: Process does not exist
:raises ServerProcessError: Cannot terminate process. Try killing it
"""
print 'Killing server'
proc = self.proc
if proc is None:
raise ServerProcessError('Server Process does not exist')
else:
try:
proc.terminate()
print 'Server Killed'
self.proc = None
return True
except OSError:
raise ServerProcessError("Cannot terminate server process. "
"Try killing it")
def kill(self):
"""Kill the server process by sending signal.SIGKILL
self.proc is made None on success
:param: None
:returns: True when success
:raises ServerProcessError: Process does not exist
:raises ServerProcessError: Cannot kill process
"""
if self.proc is None:
raise ServerProcessError('Server Process does not exist')
else:
try:
os.kill(self.pid, signal.SIGKILL)
self.proc = None
return True
except OSError:
raise ServerProcessError('Cannot kill process')