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: 7777 $"
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
54
55
57 """Sets the name of the flow we're saving.
58 @param flowName:
59 @type flowName: string
60 """
61 self._flowName = flowName
62
64 """Attach a audio producer for this flow
65 @param audioProducer: audio producer
66 @type audioProducer: L{AudioProducer} subclass or None
67 """
68 if (audioProducer is not None and
69 not isinstance(audioProducer, AudioProducer)):
70 raise TypeError(
71 "audioProducer must be a AudioProducer subclass, not %r" % (
72 audioProducer, ))
73 self._audioProducer = audioProducer
74
76 """Attach a video producer for this flow
77 @param videoProducer: video producer
78 @type videoProducer: L{VideoProducer} subclass or None
79 """
80 if (videoProducer is not None and
81 not isinstance(videoProducer, VideoProducer)):
82 raise TypeError(
83 "videoProducer must be a VideoProducer subclass, not %r" % (
84 videoProducer, ))
85 self._videoProducer = videoProducer
86
88 if not self._videoProducer:
89 raise ValueError(
90 "You can't add a video overlay component without "
91 "first setting a video producer")
92 self._videoOverlay = videoOverlay
93
95 """Attach a audio encoder for this flow
96 @param audioEncoder: audio encoder
97 @type audioEncoder: L{AudioEncoder} subclass or None
98 """
99 if (audioEncoder is not None and
100 not isinstance(audioEncoder, AudioEncoder)):
101 raise TypeError(
102 "audioEncoder must be a AudioEncoder subclass, not %r" % (
103 audioEncoder, ))
104 self._audioEncoder = audioEncoder
105
107 """Attach a video encoder for this flow
108 @param videoEncoder: video encoder
109 @type videoEncoder: L{VideoEncoder} subclass or None
110 """
111 if (videoEncoder is not None and
112 not isinstance(videoEncoder, VideoEncoder)):
113 raise TypeError(
114 "videoEncoder must be a VideoEncoder subclass, not %r" % (
115 videoEncoder, ))
116 self._videoEncoder = videoEncoder
117
118 - def setMuxer(self, muxerType, muxerWorker):
119 """Adds the necessary state to be able to create a muxer
120 for this flow.
121 @param muxerType:
122 @type muxerType: string
123 @param muxerWorker: name of the worker
124 @type muxerWorker: string
125 """
126 self._muxerType = muxerType
127 self._muxerWorker = muxerWorker
128
130 """Add a server consumer. Currently limited a to http-server
131 server consumers
132 @param server: server consumer
133 @type server:
134 @param consumerType: the type of the consumer, one of
135 audio/video/audio-video
136 @type consumerType: string
137 """
138 server.name = 'http-server-%s' % (consumerType, )
139 self._atmosphereComponents.append(server)
140
142 """Add a porter
143 @param porter: porter
144 @type porter:
145 @param consumerType: the type of the consumer, one of
146 audio/video/audio-video
147 @type consumerType: string
148 """
149 porter.name = 'porter-%s' % (consumerType, )
150 self._atmosphereComponents.append(porter)
151
153 """Add a consumer
154 @param consumer: consumer
155 @type consumer:
156 @param consumerType: the type of the consumer, one of
157 audio/video/audio-video
158 @type consumerType: string
159 """
160 if consumer.componentType == 'http-streamer':
161 prefix = 'http'
162 elif consumer.componentType == 'disk-consumer':
163 prefix = 'disk'
164 elif consumer.componentType == 'shout2-consumer':
165 prefix = 'shout2'
166 else:
167 raise AssertionError("unknown component: %s" % (
168 consumer.componentType))
169
170
171 consumer.name = prefix + '-' + consumerType
172
173 self._getMuxer(consumerType).link(consumer)
174 self._flowComponents.append(consumer)
175
177 """Sets if we should use a Creative Common license on
178 the created flow. This will overlay an image if we do
179 video streaming.
180 @param useCCLicense: if we should use a CC license
181 @type useCCLicense: bool
182 """
183 self._useCCLicense = useCCLicense
184
202
204 """Tells the saver about the existing components available, so
205 we can resolve naming conflicts before fetching the configuration xml
206 @param componentNames: existing component names
207 @type componentNames: list of strings
208 """
209 self._existingComponentNames = componentNames
210
212 """Gets the flow components of the save instance
213 @returns: the flow components
214 @rtype: list of components
215 """
216 return self._flowComponents
217
219 """Gets the atmosphere components of the save instance
220 @returns: the atmosphere components
221 @rtype: list of components
222 """
223 return self._atmosphereComponents
224
225
226
228 return self._atmosphereComponents + self._flowComponents
229
231 if name in self._muxers:
232 muxer = self._muxers[name]
233 else:
234 muxer = Muxer()
235 muxer.name = 'muxer-' + name
236 muxer.componentType = self._muxerType
237 muxer.worker = self._muxerWorker
238 self._muxers[name] = muxer
239 return muxer
240
246
248 if not self._audioProducer:
249 return
250
251 if not self._audioProducer.name:
252 self._audioProducer.name = 'producer-audio'
253
254 self._flowComponents.append(self._audioProducer)
255
256 if self._audioEncoder is None:
257 raise ValueError("You need to set an audio encoder")
258
259 self._audioEncoder.name = 'encoder-audio'
260 self._flowComponents.append(self._audioEncoder)
261
262 self._audioProducer.link(self._audioEncoder)
263
265 if not self._videoProducer:
266 return
267
268 if not self._videoProducer.name:
269 self._videoProducer.name = 'producer-video'
270
271 self._flowComponents.append(self._videoProducer)
272
273 if self._videoEncoder is None:
274 raise ValueError("You need to set a video encoder")
275
276 self._videoEncoder.name = 'encoder-video'
277 self._flowComponents.append(self._videoEncoder)
278
279 self._videoProducer.link(self._videoEncoder)
280
282 if not self._videoOverlay:
283 return
284
285 self._videoProducer.unlink(self._videoEncoder)
286
287 self._videoProducer.link(self._videoOverlay)
288 self._videoOverlay.link(self._videoEncoder)
289 self._flowComponents.append(self._videoOverlay)
290
291 self._videoOverlay.name = 'overlay-video'
292
293 if not self._videoOverlay.show_logo:
294 return
295
296
297 self._videoOverlay.properties.fluendo_logo = True
298 if self._muxerType == 'ogg-muxer':
299 self._videoOverlay.properties.xiph_logo = True
300
301 if self._useCCLicense:
302 self._videoOverlay.properties.cc_logo = True
303
320
322 for muxerName, components in [('audio', [self._audioEncoder]),
323 ('video', [self._videoEncoder]),
324 ('audio-video', [self._audioEncoder,
325 self._videoEncoder])]:
326 muxer = self._getMuxer(muxerName)
327 if muxer.feeders:
328 self._flowComponents.append(muxer)
329 for component in components:
330 component.link(muxer)
331
335
347
349
350
351
352 pattern = re.compile('(\d*$)')
353 match = pattern.search(suggestedName)
354 trailingDigit = match.group()
355
356
357
358
359 if trailingDigit:
360 digit = int(trailingDigit) + 1
361 suggestedName = suggestedName[:-len(trailingDigit)]
362
363
364
365 else:
366 digit = 2
367 return suggestedName + str(digit)
368
378