1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 import gettext
19 import re
20
21 from flumotion.admin.assistant.configurationwriter import ConfigurationWriter
22 from flumotion.admin.assistant.models import Muxer, AudioProducer, \
23 VideoProducer, AudioEncoder, VideoEncoder
24
25 _ = gettext.gettext
26 __version__ = "$Rev$"
27
28
30 """I am used to link components together and generate XML for them.
31 To use me, add some components by some of the methods and then call
32 my getXML() method to get the xml configuration.
33 """
34
36 self._existingComponentNames = []
37 self._flowComponents = []
38 self._atmosphereComponents = []
39 self._muxers = {}
40 self._flowName = None
41 self._audioProducer = None
42 self._videoProducer = None
43 self._audioEncoder = None
44 self._videoEncoder = None
45 self._videoOverlay = None
46 self._useCCLicense = False
47 self._muxerType = None
48 self._muxerWorker = None
49 self._confXml = None
50
51
52
54 """Sets the name of the flow we're saving.
55 @param flowName:
56 @type flowName: string
57 """
58 self._flowName = flowName
59
61 """Attach a audio producer for this flow
62 @param audioProducer: audio producer
63 @type audioProducer: L{AudioProducer} subclass or None
64 """
65 if (audioProducer is not None and
66 not isinstance(audioProducer, AudioProducer)):
67 raise TypeError(
68 "audioProducer must be a AudioProducer subclass, not %r" % (
69 audioProducer, ))
70 self._audioProducer = audioProducer
71
73 """Attach a video producer for this flow
74 @param videoProducer: video producer
75 @type videoProducer: L{VideoProducer} subclass or None
76 """
77 if (videoProducer is not None and
78 not isinstance(videoProducer, VideoProducer)):
79 raise TypeError(
80 "videoProducer must be a VideoProducer subclass, not %r" % (
81 videoProducer, ))
82 self._videoProducer = videoProducer
83
85 if not self._videoProducer:
86 raise ValueError(
87 "You can't add a video overlay component without "
88 "first setting a video producer")
89 self._videoOverlay = videoOverlay
90
92 """Attach a audio encoder for this flow
93 @param audioEncoder: audio encoder
94 @type audioEncoder: L{AudioEncoder} subclass or None
95 """
96 if (audioEncoder is not None and
97 not isinstance(audioEncoder, AudioEncoder)):
98 raise TypeError(
99 "audioEncoder must be a AudioEncoder subclass, not %r" % (
100 audioEncoder, ))
101 self._audioEncoder = audioEncoder
102
104 """Attach a video encoder for this flow
105 @param videoEncoder: video encoder
106 @type videoEncoder: L{VideoEncoder} subclass or None
107 """
108 if (videoEncoder is not None and
109 not isinstance(videoEncoder, VideoEncoder)):
110 raise TypeError(
111 "videoEncoder must be a VideoEncoder subclass, not %r" % (
112 videoEncoder, ))
113 self._videoEncoder = videoEncoder
114
115 - def setMuxer(self, muxerType, muxerWorker):
116 """Adds the necessary state to be able to create a muxer
117 for this flow.
118 @param muxerType:
119 @type muxerType: string
120 @param muxerWorker: name of the worker
121 @type muxerWorker: string
122 """
123 self._muxerType = muxerType
124 self._muxerWorker = muxerWorker
125
127 """Adds an existing muxer to the flow. This way it will be reused and
128 the saver won't create a new one. Used when adding a new streamer.
129 @param muxerType: type of the muxer, one of audio/video/audio-video
130 @type muxerType: str
131 @param muxer: a muxer model
132 @type muxer: L{Muxer}
133 """
134 self._muxers[muxerType] = muxer
135
137 """Add a server consumer. Currently limited a to http-server
138 server consumers
139 @param server: server consumer
140 @type server:
141 @param consumerType: the type of the consumer, one of
142 audio/video/audio-video
143 @type consumerType: string
144 """
145 server.name = 'http-server-%s' % (consumerType, )
146 self._atmosphereComponents.append(server)
147
149 """Add a porter
150 @param porter: porter
151 @type porter:
152 @param consumerType: the type of the consumer, one of
153 audio/video/audio-video
154 @type consumerType: string
155 """
156 porter.name = 'porter-%s' % (consumerType, )
157 self._atmosphereComponents.append(porter)
158
160 """Add a consumer
161 @param consumer: consumer
162 @type consumer:
163 @param consumerType: the type of the consumer, one of
164 audio/video/audio-video
165 @type consumerType: string
166 """
167
168 consumer.name = consumer.prefix + '-' + consumerType
169
170 self._getMuxer(consumerType).link(consumer)
171 self._flowComponents.append(consumer)
172
174 """Sets if we should use a Creative Common license on
175 the created flow. This will overlay an image if we do
176 video streaming.
177 @param useCCLicense: if we should use a CC license
178 @type useCCLicense: bool
179 """
180 self._useCCLicense = useCCLicense
181
202
204 self._confXml = open(xmlFile, 'r').read()
205
207 """Tells the saver about the existing components available, so
208 we can resolve naming conflicts before fetching the configuration xml
209 @param componentNames: existing component names
210 @type componentNames: list of strings
211 """
212 self._existingComponentNames = componentNames
213
215 """Gets the flow components of the save instance
216 @returns: the flow components
217 @rtype: list of components
218 """
219 return self._flowComponents
220
222 """Gets the atmosphere components of the save instance
223 @returns: the atmosphere components
224 @rtype: list of components
225 """
226 return self._atmosphereComponents
227
228
229
231 return self._atmosphereComponents + self._flowComponents
232
234 if name in self._muxers:
235 muxer = self._muxers[name]
236 else:
237 muxer = Muxer()
238 muxer.name = 'muxer-' + name
239 muxer.componentType = self._muxerType
240 muxer.worker = self._muxerWorker
241 self._muxers[name] = muxer
242 return muxer
243
249
251 if not self._audioProducer:
252 return
253
254 if not self._audioProducer.name:
255 self._audioProducer.name = 'producer-audio'
256
257 self._flowComponents.append(self._audioProducer)
258
259 if self._audioEncoder is None:
260 raise ValueError("You need to set an audio encoder")
261
262 self._audioEncoder.name = 'encoder-audio'
263 self._flowComponents.append(self._audioEncoder)
264
265 self._audioProducer.link(self._audioEncoder)
266
268 if not self._videoProducer:
269 return
270
271 if not self._videoProducer.name:
272 self._videoProducer.name = 'producer-video'
273
274 self._flowComponents.append(self._videoProducer)
275
276 if self._videoEncoder is None:
277 raise ValueError("You need to set a video encoder")
278
279 self._videoEncoder.name = 'encoder-video'
280 self._flowComponents.append(self._videoEncoder)
281
282 self._videoProducer.link(self._videoEncoder)
283
285 if not self._videoOverlay:
286 return
287
288 self._videoProducer.unlink(self._videoEncoder)
289
290 self._videoProducer.link(self._videoOverlay)
291 self._videoOverlay.link(self._videoEncoder)
292 self._flowComponents.append(self._videoOverlay)
293
294 self._videoOverlay.name = 'overlay-video'
295
296 if not self._videoOverlay.show_logo:
297 return
298
299
300 self._videoOverlay.properties.fluendo_logo = True
301 if self._muxerType == 'ogg-muxer':
302 self._videoOverlay.properties.xiph_logo = True
303
304 if self._useCCLicense:
305 self._videoOverlay.properties.cc_logo = True
306
308
309
310
311 video = self._videoProducer
312 audio = self._audioProducer
313 if (video is not None and
314 audio is not None and
315 video == audio):
316 self._flowComponents.remove(self._audioProducer)
317 if not audio.exists:
318 self._audioProducer.name = 'producer-audio-video'
319 if not video.exists:
320 self._videoProducer.name = 'producer-audio-video'
321 self._audioProducer = self._videoProducer
322
324 for muxerName, components in [('audio', [self._audioEncoder]),
325 ('video', [self._videoEncoder]),
326 ('audio-video', [self._audioEncoder,
327 self._videoEncoder])]:
328 muxer = self._getMuxer(muxerName)
329 if muxer.feeders:
330 self._flowComponents.append(muxer)
331 for component in components:
332 component and component.link(muxer)
333
337
349
351
352
353
354 pattern = re.compile('(\d*$)')
355 match = pattern.search(suggestedName)
356 trailingDigit = match.group()
357
358
359
360
361 if trailingDigit:
362 digit = int(trailingDigit) + 1
363 suggestedName = suggestedName[:-len(trailingDigit)]
364
365
366
367 else:
368 digit = 2
369 return suggestedName + str(digit)
370
380