Package pyjamas :: Package media :: Module Media
[hide private]
[frames] | no frames]

Source Code for Module pyjamas.media.Media

  1  """ 
  2  * Copyright 2009 Mark Renouf 
  3  * 
  4  * Licensed under the Apache License, Version 2.0 (the "License") you may not 
  5  * use this file except in compliance with the License. You may obtain a copy of 
  6  * the License at 
  7  * 
  8  * http:#www.apache.org/licenses/LICENSE-2.0 
  9  * 
 10  * Unless required by applicable law or agreed to in writing, software 
 11  * distributed under the License is distributed on an "AS IS" BASIS, WITHDIR 
 12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 
 13  * License for the specific language governing permissions and limitations under 
 14  * the License. 
 15  """ 
 16   
 17   
 18  from pyjamas.ui import Event 
 19  from pyjamas import DOM 
 20  from pyjamas.ui.Widget import Widget 
 21   
22 -def mediaEventGetTypeInt(eventType):
23 JS(""" 24 window['console']['log']('mediaEventGetTypeInt: ' + eventType) 25 switch (eventType) { 26 case "abort": return 0x00001; 27 case "canplay": return 0x00002; 28 case "canplaythrough": return 0x00004; 29 case "durationchange": return 0x00008; 30 case "emptied": return 0x00010; 31 case "ended": return 0x00020; 32 case "error": return 0x00040; 33 case "loadstart": return 0x00080; 34 case "loadeddata": return 0x00100; 35 case "loadedmetadata": return 0x00200; 36 case "pause": return 0x00400; 37 case "play": return 0x00800; 38 case "playing": return 0x01000; 39 case "progress": return 0x02000; 40 case "ratechange": return 0x04000; 41 case "seeked": return 0x08000; 42 case "seeking": return 0x10000; 43 case "stalled": return 0x20000; 44 case "suspend": return 0x40000; 45 case "timeupdate": return 0x80000; 46 case "volumechange": return 0x100000; 47 case "waiting": return 0x200000; 48 default: 49 window['console']['debug']("Unknown media eventType: " + eventType) 50 return 0; 51 } 52 """)
53
54 -class Media(Widget):
55 """ 56 HasAbortHandlers, 57 HasCanPlayHandlers, HasCanPlayThroughHandlers, HasDurationChangeHandlers, 58 HasEmptiedHandlers, 59 HasEndedHandlers, HasErrorHandlers, HasLoadStartHandlers, 60 HasLoadedDataHandlers, HasLoadedMetadataHandlers, HasPauseHandlers, 61 HasPlayHandlers, HasPlayingHandlers, HasProgressHandlers, 62 HasRateChangeHandlers, HasSeekedHandlers, HasSeekingHandlers, 63 HasStalledHandlers, HasSuspendHandlers, HasTimeUpdateHandlers, 64 HasVolumeChangeHandlers, HasWaitingHandlers, HasAllMouseHandlers, 65 HasClickHandlers""" 66
67 - def __init__(self, **kwargs):
68 self.mediaEventsToSink = 0 69 self.mediaEventsInitialized = False 70 71 Widget.__init__(self, **kwargs)
72
73 - def setSrc(self, src):
74 DOM.setAttribute(self.getElement(), 'src', src)
75
76 - def addSrc(self, src):
77 s = DOM.createElement("source") 78 DOM.setAttribute(s, 'src', src) 79 DOM.appendChild(self.getElement(), s)
80
81 - def getSrc(self):
82 return DOM.getAttribute(self.getElement(), 'src')
83
84 - def getError(self):
85 " return (this.error == null) ? 0 : this.error; " 86 return self.getElement().error or 0
87
88 - def getCurrentSrc(self):
89 return self.getElement().currentSrc
90
91 - def getCurrentTime(self):
92 return self.getElement().currentTime
93
94 - def setCurrentTime(self, time):
95 self.getElement().currentTime = time
96
97 - def getStartTime(self):
98 return self.getElement().startTime
99
100 - def getDuration(self):
101 return self.getElement().duration
102
103 - def isPaused(self):
104 return self.getElement().paused
105
106 - def getDefaultPlaybackRate(self):
107 return self.getElement().defaultPlaybackRate
108
109 - def setDefaultPlaybackRate(self, rate):
110 self.getElement().defaultPlaybackRate = rate
111
112 - def getPlaybackRate(self):
113 return self.getElement().playbackRate
114
115 - def setPlaybackRate(self, rate):
116 self.getElement().playbackRate = rate
117
118 - def getPlayed(self):
119 return self.getElement().played
120
121 - def getSeekable(self):
122 return self.getElement().seekable
123
124 - def hasEnded(self):
125 return self.getElement().ended
126
127 - def isLoop(self):
128 return bool(self.getElement().loop)
129
130 - def getVolume(self):
131 return self.getElement().volume
132
133 - def setVolume(self, volume):
134 self.getElement().volume = volume
135
136 - def getReadyState(self):
137 return self.getElement().readyState
138 139 140 """* 141 * If set, this informs the browser that the media element is likely to be 142 * played and that it should begin buffering the content immediately. 143 * <p> 144 * This setting has no effect if {@linkplain #setAutoplay(boolean) autoplay} 145 * is set. Per the current HTML5 spec, the browser is not required to support 146 * this feature. 147 * 148 * @param autobuffer Whether to begin buffering content immediately 149 """
150 - def setAutobuffer(self, autobuffer):
151 self.getElement().autobuffer = autobuffer
152 153 154 """* 155 * Whether to automatically begin playback of the media resource as soon as 156 * it's possible to do so without stopping. 157 * 158 * @param autoplay Whether the content should begin playing immediately 159 """
160 - def setAutoplay(self, autoplay):
161 self.getElement().autoplay = autoplay
162 163 164 """* 165 * Whether the media element is to seek back to the start of the media 166 * resource upon reaching the end. 167 * 168 * @param loop whether the media element should loop 169 """
170 - def setLoop(self, loop):
171 self.getElement().loop = loop
172 173 174 """* 175 * Whether the browser should expose a user interface to the user. This user 176 * interface should include features to begin playback, pause playback, seek 177 * to an arbitrary position in the content (if the content supports arbitrary 178 * seeking), change the volume, and show the media content in manners more 179 * suitable to the user (e.g. full-screen video or in an independent resizable 180 * window). Other controls may also be made available. 181 * 182 * @param controls Whether the browser should show playback controls 183 """
184 - def setControls(self, controls):
185 DOM.setBooleanAttribute(self.getElement(), "controls", controls)
186
187 - def hasControls(self):
188 DOM.getBooleanAttribute(self.getElement(), "controls")
189
190 - def isMuted(self):
191 return self.getElement().muted
192
193 - def play(self):
194 self.getElement().play()
195
196 - def load(self):
197 self.getElement().load()
198
199 - def pause(self):
200 self.getElement().pause()
201
202 - def canPlayType(self, etype):
203 self.getElement().canPlayType(etype)
204
205 - def setMute(self, muted):
206 self.getElement().setMute(muted)
207 208 209 """* 210 * Adds a handler to be called when the user agent stops fetching the media data before it is 211 * completely downloaded, but not due to an error. 212 """ 213
214 - def addAbortHandler(self, handler):
215 return self.addMediaEventHandler(handler, AbortEvent.getType())
216 217 218 """* 219 * Adds a handler to be called when the user agent can resume playback of the media data, but 220 * estimates that if playback were to be started now, the media resource could 221 * not be rendered at the current playback rate up to its end without having 222 * to stop for further buffering of content. 223 * 224 * @param handler the {@link CanPlayHandler} to be called 225 """ 226
227 - def addCanPlayHandler(self, handler):
228 return self.addMediaEventHandler(handler, CanPlayEvent.getType())
229 230 231 """* 232 * Adds a handler to be called when the user agent estimates that if playback were to be started 233 * now, the media resource could be rendered at the current playback rate all 234 * the way to its end without having to stop for further buffering. 235 * 236 * @param handler the {@link CanPlayThroughHandler} to be called 237 """ 238
239 - def addCanPlayThroughHandler(self, handler):
240 return self.addMediaEventHandler(handler, CanPlayThroughEvent.getType())
241 242 243
244 - def addDurationChangeHandle(self, handler):
245 return self.addMediaEventHandler(handler, DurationChangeEvent.getType())
246 247 248 """* 249 * Adds a handler to be called when the duration attribute has just been updated. 250 * 251 * @param handler the {@link DurationChangeHandler} to be called 252 """ 253
254 - def addEmptiedHandler(self, handler):
255 return self.addMediaEventHandler(handler, EmptiedEvent.getType())
256 257 258 """* 259 * Adds a handler to be called when a media element whose networkState was previously not in the 260 * NETWORK_EMPTY state has just switched to that state (either because of a 261 * fatal error during load that's about to be reported, or because the load() 262 * method was invoked while the resource selection algorithm was already 263 * running, in which case it is fired synchronously during the load() method 264 * call). 265 * 266 * @param handler the {@link EmptiedHandler} to be called 267 """ 268
269 - def addEndedHandler(self, handler):
270 return self.addMediaEventHandler(handler, EndedEvent.getType())
271 272 273 """* 274 * Adds a handler to be called when playback has stopped because the end of the media resource was 275 * reached. 276 * 277 * @param handler the {@link EndedHandler} to be called 278 """ 279
280 - def addErrorHandler(self, handler):
281 return self.addMediaEventHandler(handler, ErrorEvent.getType())
282 283 284 """* 285 * Adds a handler to be called when the user agent begins looking for media data, as part of the 286 * resource selection algorithm. 287 * 288 * @param handler the {@link LoadStartHandler} to be called 289 """ 290
291 - def addLoadStartHandler(self, handler):
292 return self.addMediaEventHandler(handler, LoadStartEvent.getType())
293 294 295 """* 296 * Adds a handler to be called when the user agent can render the media data at the current 297 * playback position for the first time. 298 * 299 * @param handler the {@link LoadedDataHandler} to be called 300 """ 301
302 - def addLoadedDataHandler(self, handler):
303 return self.addMediaEventHandler(handler, LoadedDataEvent.getType())
304 305 306 """* 307 * Adds a handler to be called when the user agent has just determined the duration and dimensions 308 * of the media resource. 309 * 310 * @param handler the {@link LoadedMetadataHandler} to be called 311 """ 312
313 - def addLoadedMetadataHandler(self, handler):
314 return self.addMediaEventHandler(handler, LoadedMetadataEvent.getType())
315 316 317 """* 318 * Adds a handler to be called when playback has been paused. Fired after the pause method has 319 * returned. 320 * 321 * @param handler the {@link PauseHandler} to be called 322 """ 323
324 - def addPauseHandler(self, handler):
325 return self.addMediaEventHandler(handler, PauseEvent.getType())
326 327 328 """* 329 * Adds a handler to be called when playback has begun. Fired after the play() method has returned. 330 * 331 * @param handler the {@link PlayHandler} to be called 332 """ 333
334 - def addPlayHandler(self, handler):
335 return self.addMediaEventHandler(handler, PlayEvent.getType())
336 337 338 """* 339 * Adds a handler to be called when playback has started. 340 * 341 * @param handler the {@link PlayingHandler} to be called 342 """ 343
344 - def addPlayingHandler(self, handler):
345 return self.addMediaEventHandler(handler, PlayingEvent.getType())
346 347 348 """* 349 * Adds a handler to be called when the user agent is fetching media data. 350 * 351 * @param handler the {@link ProgressHandler} to be called 352 """ 353
354 - def addProgressHandler(self, handler):
355 return self.addMediaEventHandler(handler, ProgressEvent.getType())
356 357 358 """* 359 * Adds a handler to be called when either the defaultPlaybackRate or the playbackRate attribute 360 * has just been updated. 361 * 362 * @param handler the {@link RateChangeHandler} to be called 363 """ 364
365 - def addRateChangeHandler(self, handler):
366 return self.addMediaEventHandler(handler, RateChangeEvent.getType())
367 368 369 """* 370 * Adds a handler to be called when a seek operation has completed. 371 * 372 * @param handler the {@link SeekedHandler} to be called 373 """ 374
375 - def addSeekedHandler(self, handler):
376 return self.addMediaEventHandler(handler, SeekedEvent.getType())
377 378 379 """* 380 * Adds a handler to be called when the user agent is seeking to a time position in the stream. 381 * 382 * @param handler the {@link SeekingHandler} to be called 383 """ 384
385 - def addSeekingHandler(self, handler):
386 return self.addMediaEventHandler(handler, SeekingEvent.getType())
387 388 389 """* 390 * Adds a handler to be called when the user agent is trying to fetch media data, but data is 391 * unexpectedly not forthcoming. 392 * 393 * @param handler the {@link StalledHandler} to be called 394 """ 395
396 - def addStalledHandler(self, handler):
397 return self.addMediaEventHandler(handler, StalledEvent.getType())
398 399 400 """* 401 * Adds a handler to be called when the user agent is intentionally not currently fetching media 402 * data, but does not have the entire media resource downloaded. 403 * 404 * @param handler the {@link SuspendHandler} to be called 405 """ 406
407 - def addSuspendHandler(self, handler):
408 return self.addMediaEventHandler(handler, SuspendEvent.getType())
409 410 411 """* 412 * Adds a handler to be called when the current playback position changed as part of normal 413 * playback or in an especially interesting way, for example discontinuously. 414 * 415 * @param handler the {@link TimeUpdateHandler} to be called 416 """ 417
418 - def addTimeUpdateHandler(self, handler):
419 return self.addMediaEventHandler(handler, TimeUpdateEvent.getType())
420 421 422 """* 423 * Adds a handler to be called when either the volume attribute or the muted attribute has changed. 424 * Fired after the relevant attribute's setter has returned. 425 * 426 * @param handler the {@link VolumeChangeHandler} to be called 427 """ 428
429 - def addVolumeChangeHandler(self, handler):
430 return self.addMediaEventHandler(handler, VolumeChangeEvent.getType())
431 432 433 """* 434 * Adds a handler to be called when playback has stopped because the next frame is not available, 435 * but the user agent expects that frame to become available in due course. 436 * 437 * @param handler the {@link WaitingHandler} to be called 438 """ 439
440 - def addWaitingHandler(self, handler):
441 return self.addMediaEventHandler(handler, WaitingEvent.getType())
442 443
444 - def addMediaEventHandler(self, handler, etype):
445 assert handler is not None, "handler must not be None" 446 assert etype is not None, "type must not be None" 447 self.maybeInitMediaEvents() 448 self.sinkMediaEvents(mediaEventGetTypeInt(etype.getName())) 449 return addHandler(handler, etype)
450 451 452
453 - def sinkMediaEvents(self, eventBitsToAdd):
454 if self.isOrWasAttached(): 455 self.nativeSinkMediaEvents(self.getElement(), eventBitsToAdd) 456 else: 457 self.mediaEventsToSink |= eventBitsToAdd
458 459 460 461 """* 462 * doAttachChildren is called immediately after sinkEvents is called in 463 * Widget. This opportunity is taken to lazily attach event handlers to the 464 * element. 465 """
466 - def doAttachChildren(self):
467 bitsToAdd = self.mediaEventsToSink 468 self.mediaEventsToSink = -1 469 if bitsToAdd > 0: 470 self.nativeSinkMediaEvents(self.getElement(), bitsToAdd)
471 472
473 - def nativeSinkMediaEvents(self, elem, bits):
474 # chMask = (elem.__mediaEventBits or 0) ^ bits 475 # elem.__mediaEventBits = bits; 476 # if not chMask: 477 # return 478 # 479 # if (chMask & 0x00001) and (bits & 0x00001): 480 # elem.addEventListener('abort', mediaDispatchEvent, false) 481 # else: 482 # elem.removeEventListener('abort', mediaDispatchEvent, false) 483 # if (chMask & 0x00002) and (bits & 0x00002): 484 # elem.addEventListener('canplay', mediaDispatchEvent, false) 485 # else: 486 # elem.removeEventListener('canplay', mediaDispatchEvent, false) 487 # if (chMask & 0x00004) and (bits & 0x00004): 488 # elem.addEventListener('canplaythrough', mediaDispatchEvent, false) 489 # else: 490 # elem.removeEventListener('canplaythrough', mediaDispatchEvent, false) 491 # if (chMask & 0x00008) and (bits & 0x00008): 492 # elem.addEventListener('durationchange', mediaDispatchEvent, false) 493 # else: 494 # elem.removeEventListener('durationchange', mediaDispatchEvent, false) 495 # if (chMask & 0x00010) and (bits & 0x00010): 496 # elem.addEventListener('emptied', mediaDispatchEvent, false) 497 # else: 498 # elem.removeEventListener('emptied', mediaDispatchEvent, false) 499 # if (chMask & 0x00020) and (bits & 0x00020): 500 # elem.addEventListener('ended', mediaDispatchEvent, false) 501 # else: 502 # elem.removeEventListener('ended', mediaDispatchEvent, false) 503 # if (chMask & 0x00040) and (bits & 0x00040): 504 # elem.addEventListener('error', mediaDispatchEvent, false) 505 # else: 506 # elem.removeEventListener('error', mediaDispatchEvent, false) 507 # if (chMask & 0x00080) and (bits & 0x00080): 508 # elem.addEventListener('loadstart', mediaDispatchEvent, false) 509 # else: 510 # elem.removeEventListener('loadstart', mediaDispatchEvent, false) 511 # if (chMask & 0x00100) and (bits & 0x00100): 512 # elem.addEventListener('loadeddata', mediaDispatchEvent, false) 513 # else: 514 # elem.removeEventListener('loadeddata', mediaDispatchEvent, false) 515 # if (chMask & 0x00200) and (bits & 0x00200): 516 # elem.addEventListener('loadedmetadata', mediaDispatchEvent, false) 517 # else: 518 # elem.removeEventListener('loadedmetadata', mediaDispatchEvent, false) 519 # if (chMask & 0x00400) and (bits & 0x00400): 520 # elem.addEventListener('pause', mediaDispatchEvent, false) 521 # else: 522 # elem.removeEventListener('pause', mediaDispatchEvent, false) 523 # if (chMask & 0x00800) and (bits & 0x00800): 524 # elem.addEventListener('play', mediaDispatchEvent, false) 525 # else: 526 # elem.removeEventListener('play', mediaDispatchEvent, false) 527 # if (chMask & 0x01000) and (bits & 0x01000): 528 # elem.addEventListener('playing', mediaDispatchEvent, false) 529 # else: 530 # elem.removeEventListener('playing', mediaDispatchEvent, false) 531 # if (chMask & 0x02000) and (bits & 0x02000): 532 # elem.addEventListener('progress', mediaDispatchEvent, false) 533 # else: 534 # elem.removeEventListener('progress', mediaDispatchEvent, false) 535 # if (chMask & 0x04000) and (bits & 0x04000): 536 # elem.addEventListener('ratechange', mediaDispatchEvent, false) 537 # else: 538 # elem.removeEventListener('ratechange', mediaDispatchEvent, false) 539 # if (chMask & 0x08000) and (bits & 0x08000): 540 # elem.addEventListener('seeked', mediaDispatchEvent, false) 541 # else: 542 # elem.removeEventListener('seeked', mediaDispatchEvent, false) 543 # if (chMask & 0x10000) and (bits & 0x10000): 544 # elem.addEventListener('seeking', mediaDispatchEvent, false) 545 # else: 546 # elem.removeEventListener('seeking', mediaDispatchEvent, false) 547 # if (chMask & 0x20000) and (bits & 0x20000): 548 # elem.addEventListener('stalled', mediaDispatchEvent, false) 549 # else: 550 # elem.removeEventListener('stalled', mediaDispatchEvent, false) 551 # if (chMask & 0x40000) and (bits & 0x40000): 552 # elem.addEventListener('suspend', mediaDispatchEvent, false) 553 # else: 554 # elem.removeEventListener('suspend', mediaDispatchEvent, false) 555 # if (chMask & 0x80000) and (bits & 0x80000): 556 # elem.addEventListener('timeupdate', mediaDispatchEvent, false) 557 # else: 558 # elem.removeEventListener('timeupdate', mediaDispatchEvent, false) 559 # if (chMask & 0x100000) and (bits & 0x100000): 560 # elem.addEventListener('volumechange', mediaDispatchEvent, false) 561 # else: 562 # elem.removeEventListener('volumechange', mediaDispatchEvent, false) 563 # if (chMask & 0x200000) and (bits & 0x200000): 564 # elem.addEventListener('waiting', mediaDispatchEvent, false) 565 # else: 566 # elem.removeEventListener('waiting', mediaDispatchEvent, false) 567 return
568
569 - def addMouseDownHandler(self, handler):
570 return addDomHandler(handler, MouseDownEvent.getType())
571 572 573
574 - def addMouseUpHandler(self, handler):
575 return addDomHandler(handler, MouseUpEvent.getType())
576 577 578
579 - def addMouseOutHandler(self, handler):
580 return addDomHandler(handler, MouseOutEvent.getType())
581 582 583
584 - def addMouseOverHandler(self, handler):
585 return addDomHandler(handler, MouseOverEvent.getType())
586 587 588
589 - def addMouseMoveHandler(self, handler):
590 return addDomHandler(handler, MouseMoveEvent.getType())
591 592 593
594 - def addMouseWheelHandler(self, handler):
595 return addDomHandler(handler, MouseWheelEvent.getType())
596 597 598
599 - def addClickHandler(self, handler):
600 return addDomHandler(handler, ClickEvent.getType())
601 602
603 - def maybeInitMediaEvents(self):
604 if not mediaEventsInitialized: 605 initMediaEvents() 606 mediaEventsInitialized = True
607 608 609 610 """* 611 * Warning: W3C/Standards version 612 """
613 - def initMediaEvents(self):
614 JS(""" 615 mediaDispatchEvent = function(evt) { 616 var curElem = evt['target']; 617 var listener = curElem['__listener']; 618 if (listener) { 619 @{{self['dispatchMediaEvent']}}(evt, listener) 620 } 621 } 622 """)
623 624 625 """* 626 * Dispatches an event to the listener. This bypasses the main GWT event 627 * handling system because it's not possible to access from external packages. 628 * <p> 629 * Due to this event catpure and event preview will not work properly for 630 * media-specific events (existing GWT handled events are not affected). Also, 631 * since the sinkEvents system is not extensible media events can only be 632 * listened for directly on the Media object generating them ie. they will not 633 * be received or handled by any containing elements because these objects 634 * won't know how to set the correct event listeners. 635 * 636 * @param evt 637 * @param listener 638 """
639 - def dispatchMediaEvent(self, evt, listener):
640 # Pass the event to the listener. 641 listener.onBrowserEvent(evt)
642