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