@@ -5,10 +5,8 @@ function sepiaFW_build_ui_cards_embed(){
55 //TODO: add MediaPlayer
66 /*
77 - Controls: start, pause/stop, resume, next, previous
8- - State functions: getState, isOnHold
9- - Broadcast state change (start, pause, hold, resume, ?)
10- - Make sure only one is active
118 - Implement async. callback with msgId and timeout
9+ - Get media info and use SepiaFW.audio.setPlayerTitle('', '') + setMediaSessionState (SepiaFW.audio)
1210 */
1311 var playerWidgets = {
1412 default : "<assist_server>/widgets/mp-default.html" ,
@@ -24,14 +22,19 @@ function sepiaFW_build_ui_cards_embed(){
2422 function getNewMediaPlayerId ( ) {
2523 mediaPlayerLastId ++ ;
2624 var overflow = false ;
27- if ( mediaPlayerLastId >= 20 ) {
25+ if ( mediaPlayerLastId > 5 ) {
2826 mediaPlayerLastId = 1 ;
2927 overflow = true ;
3028 }
3129 var newId = ( "sepia-embedded-player-" + mediaPlayerLastId ) ;
3230 if ( overflow ) {
33- //TODO: remove old players
34- //activeMediaPlayers ...
31+ //remove old players
32+ var oldMp = activeMediaPlayers [ newId ] ;
33+ if ( oldMp && oldMp . exists ( ) ) {
34+ oldMp . release ( ) ;
35+ $ ( oldMp . cardItem ) . remove ( ) ;
36+ }
37+ //console.error("RELEASED and REMOVED", newId, activeMediaPlayers[newId]); //DEBUG
3538 }
3639 return newId ;
3740 }
@@ -84,25 +87,32 @@ function sepiaFW_build_ui_cards_embed(){
8487 }
8588 }
8689 //Register new audio fade (stop/start) handler
87- function registerMediaPlayerFadeInOutListener ( mediaPlayer ) {
90+ function registerMediaPlayerFadeInOutListener ( ) {
8891 //NOTE: will always overwrite old ones if existing (same ID for every player, we control only last one)
8992 SepiaFW . audio . registerNewFadeListener ( {
9093 id : "embedded-media-player" ,
9194 isOnHold : function ( ) {
92- return mediaPlayer . isOnHold ( ) ;
95+ var mp = Embed . getActiveMediaPlayer ( ) ;
96+ if ( mp && mp . isOnHold ( ) ) {
97+ return true ;
98+ } else {
99+ return false ;
100+ }
93101 } ,
94102 onFadeOutRequest : function ( force ) {
95103 //check if player is playing
96- if ( mediaPlayer . isPlaying ( ) && ! mediaPlayer . isWaitingForPause ( ) ) {
97- mediaPlayer . fadeOut ( ) ;
104+ var mp = Embed . getActiveMediaPlayer ( ) ;
105+ if ( mp && mp . isPlaying ( ) && ! mp . isWaitingForPause ( ) ) {
106+ mp . fadeOut ( ) ;
98107 return true ;
99108 } else {
100109 return false ;
101110 }
102111 } ,
103112 onFadeInRequest : function ( ) {
104- if ( mediaPlayer . isOnHold ( ) && mediaPlayer . isPaused ( ) ) {
105- mediaPlayer . fadeIn ( ) ;
113+ var mp = Embed . getActiveMediaPlayer ( ) ;
114+ if ( mp && mp . isOnHold ( ) && mp . isPaused ( ) ) {
115+ mp . fadeIn ( ) ;
106116 return true ;
107117 } else {
108118 return false ;
@@ -113,7 +123,24 @@ function sepiaFW_build_ui_cards_embed(){
113123
114124 //Get active media player
115125 Embed . getActiveMediaPlayer = function ( ) {
116- return lastActiveMediaPlayer ;
126+ if ( lastActiveMediaPlayer && lastActiveMediaPlayer . exists ( ) ) {
127+ return lastActiveMediaPlayer ;
128+ } else {
129+ return ;
130+ }
131+ }
132+ //Stop all media players
133+ Embed . stopAllMediaPlayers = function ( except ) {
134+ var triedToStopAtLeastOne = false ;
135+ Object . values ( activeMediaPlayers ) . forEach ( function ( mp ) {
136+ if ( ! except || mp != except ) {
137+ if ( mp . isPlaying ( ) || mp . isWaitingForPlay ( ) ) {
138+ mp . pause ( ) ;
139+ triedToStopAtLeastOne = true ;
140+ }
141+ }
142+ } ) ;
143+ return triedToStopAtLeastOne ;
117144 }
118145
119146 //MediaPlayer interface
@@ -128,13 +155,19 @@ function sepiaFW_build_ui_cards_embed(){
128155 //events: onready
129156
130157 var thisPlayer = this ;
131- console . error ( "TEST" , "embedWebPlayer ", options ) ; //DEBUG
158+ // console.error("Embedded MediaPlayer ", options); //DEBUG
132159
133160 //ID
134161 var playerId = getNewMediaPlayerId ( ) ;
162+ var lastMessageId = 0 ;
135163 thisPlayer . getId = function ( ) {
136164 return playerId ;
137165 }
166+ function getMessageId ( ) {
167+ lastMessageId ++ ;
168+ if ( lastMessageId > 10000 ) lastMessageId = 1 ;
169+ return ( playerId + "-" + lastMessageId ) ;
170+ }
138171
139172 //Widget URL
140173 var widgetUrl = ( options . widgetUrl || playerWidgets [ options . widget ] ) . trim ( ) ;
@@ -147,26 +180,61 @@ function sepiaFW_build_ui_cards_embed(){
147180 //URL parameters (so we have the data during loading)
148181 widgetUrl = SepiaFW . tools . setParameterInURL ( widgetUrl , "skinStyle" , SepiaFW . ui . getSkinStyle ( ) ) ;
149182 widgetUrl = SepiaFW . tools . setParameterInURL ( widgetUrl , "skinId" , SepiaFW . ui . getSkin ( ) ) ;
183+ //add more: language, isMobile, env, ...?
150184
151- console . error ( "URL" , widgetUrl , "isTrusted" , widgetIsTrusted ) ; //DEBUG
185+ console . error ( "Media Player URL" , widgetUrl , "isTrusted" , widgetIsTrusted ) ; //DEBUG
152186
153187 //Create card (DOM element)
154188 var mpObj = createMediaPlayerDomElement ( playerId , widgetUrl , widgetIsTrusted , function ( ) {
155189 //on-load
156- console . error ( "on-load" , playerId ) ; //DEBUG
190+ // console.error("on-load", playerId); //DEBUG
157191 } ) ;
158192 thisPlayer . iframe = mpObj . iframe ;
193+ thisPlayer . cardItem = mpObj . card ;
194+ thisPlayer . exists = function ( ) {
195+ var ex = thisPlayer . cardItem && document . body . contains ( thisPlayer . cardItem ) ;
196+ if ( ! ex && state != 11 ) {
197+ thisPlayer . release ( ) ;
198+ }
199+ return ex ;
200+ }
159201 options . parentElement . appendChild ( mpObj . card ) ;
202+
203+ //Card move and delete actions
204+ mpObj . card . sepiaCardOnBeforeMove = function ( ) {
205+ console . error ( "MOVE EVENT" , playerId ) ; //DEBUG
206+ //TODO: rescue state - anything else? (note: onready is a one-time event now)
207+ }
208+ mpObj . card . sepiaCardOnBeforeRemove = function ( ) {
209+ //TODO: currently called nowhere
210+ console . error ( "REMOVE EVENT" , playerId ) ; //DEBUG
211+ thisPlayer . release ( ) ;
212+ }
160213
161214 //SEPIA postMessage interface
162215 function sendEvent ( ev ) {
216+ if ( state && state == 11 ) {
217+ //player is already released
218+ SepiaFW . debug . info ( "Embedded MediaPlayer - Blocked 'sendEvent' because player was already released." ) ;
219+ return ;
220+ }
163221 thisPlayer . iframe . contentWindow . postMessage ( {
164222 type : "sepia-embedded-player-event" ,
223+ msgId : getMessageId ( ) ,
165224 ev : ev
166225 } , "*" ) ;
167226 }
168227 thisPlayer . eventHandler = function ( ev ) {
169- console . error ( "ev" , playerId , ev ) ; //DEBUG
228+ //player still exists? (is this even possible?)
229+ if ( ! thisPlayer . exists ( ) ) {
230+ SepiaFW . debug . error ( "Embedded MediaPlayer - Player received event but was removed or released!" ) ;
231+ return ;
232+ }
233+ if ( state && state == 11 ) {
234+ //player is already released
235+ SepiaFW . debug . info ( "Embedded MediaPlayer - Blocked 'sendEvent' because player was already released." ) ;
236+ return ;
237+ }
170238 if ( ev . state != undefined ) {
171239 stateHandler ( ev ) ;
172240 }
@@ -187,28 +255,40 @@ function sepiaFW_build_ui_cards_embed(){
187255 thisPlayer . iframe . style . height = data . size . height ;
188256 }
189257 setTimeout ( function ( ) { $ ( mpObj . overlay ) . hide ( ) ; } , 500 ) ;
190- //callback
191- if ( options . onready ) options . onready ( ) ;
258+ //callback (only once)
259+ if ( options . onready ) {
260+ options . onready ( ) ;
261+ options . onready = undefined ;
262+ }
192263
193264 } else if ( ev . state == 2 ) {
194265 //on-play
195266 state = ev . state ;
196267 SepiaFW . audio . broadcastAudioEvent ( "embedded-media-player" , "start" ) ;
268+ lastActiveMediaPlayer = thisPlayer ; //TODO: use?
269+ SepiaFW . debug . info ( "Embedded MediaPlayer - Last active player switched to: " + playerId ) ;
270+ //Embed.stopAllMediaPlayers(thisPlayer) //this should be handled globally for ALL media
271+
197272 } else if ( ev . state == 3 ) {
198273 //on-pause
199274 state = ev . state ;
200275 SepiaFW . audio . broadcastAudioEvent ( "embedded-media-player" , "pause" ) ;
276+
201277 } else if ( ev . state == 10 ) {
202278 //on-error
279+ var lastWasError = ( state == 10 ) ;
203280 state = ev . state ;
204- //TODO: check "code" and "name" - broadcast error? - reset states? - make sure all is off?
205281 //ev.code-ev.name: 1-UnknownEvent, 2-NoMediaMatch, 3-PlayerErrorNotAllowed, 4-PlayerError (any), ... tbd
206- if ( ev . name == "NoMediaMatch" ) {
207- SepiaFW . client . controls . sendMediaPlayerErrorFollowUpMessage ( "notFound" , undefined , undefined ) ;
208- } else if ( ev . name == "PlayerErrorNotAllowed" ) {
209- SepiaFW . client . controls . sendMediaPlayerErrorFollowUpMessage ( "notPossible" , undefined , undefined ) ;
282+ if ( lastWasError ) {
283+ SepiaFW . ui . showInfo ( "Media-Player error: " + ( ev . name || ev . message || "?" ) ) ;
210284 } else {
211- SepiaFW . client . controls . sendMediaPlayerErrorFollowUpMessage ( "error" , undefined , undefined ) ;
285+ if ( ev . name == "NoMediaMatch" ) {
286+ SepiaFW . client . controls . sendMediaPlayerErrorFollowUpMessage ( "notFound" , undefined , undefined ) ;
287+ } else if ( ev . name == "PlayerErrorNotAllowed" ) {
288+ SepiaFW . client . controls . sendMediaPlayerErrorFollowUpMessage ( "notPossible" , undefined , undefined ) ;
289+ } else {
290+ SepiaFW . client . controls . sendMediaPlayerErrorFollowUpMessage ( "error" , undefined , undefined ) ;
291+ }
212292 }
213293 SepiaFW . debug . error ( "Embedded MediaPlayer - Error:" , ev . name , ev . message , ev . code ) ;
214294 SepiaFW . audio . broadcastAudioEvent ( "embedded-media-player" , "error" ) ;
@@ -223,41 +303,38 @@ function sepiaFW_build_ui_cards_embed(){
223303
224304 //state getters
225305 thisPlayer . isReady = function ( ) {
226- return ( state >= 1 && state < 10 ) ;
306+ return ( thisPlayer . exists ( ) && state >= 1 && state < 10 ) ;
227307 }
228308 thisPlayer . isPlaying = function ( ) {
229- //lastActiveMediaPlayer = thisPlayer; //TODO: use?
230- return state == 2 ;
309+ return ( thisPlayer . exists ( ) && state == 2 ) ;
231310 }
232311 thisPlayer . isPaused = function ( ) {
233- return state == 3 ;
312+ return ( thisPlayer . exists ( ) && state == 3 ) ;
234313 }
235314 thisPlayer . isWaitingForPlay = function ( ) {
236- return isWaitingForPlay ;
315+ return ( thisPlayer . exists ( ) && isWaitingForPlay ) ;
237316 }
238317 thisPlayer . isWaitingForPause = function ( ) {
239- return isWaitingForPause ;
318+ return ( thisPlayer . exists ( ) && isWaitingForPause ) ;
240319 }
241320 thisPlayer . isOnHold = function ( ) {
242- //TODO: implement
243- return isOnHold ;
321+ //TODO: implemented correct?
322+ return ( thisPlayer . exists ( ) && isOnHold ) ;
244323 }
245324 thisPlayer . isActive = function ( ) {
246- return ( state == 2 || isOnHold ) ; //include 'isOnHold'? (atm we don't check this for internal player)
325+ return ( thisPlayer . exists ( ) && ( state == 2 || isOnHold ) ) ;
326+ //include 'isOnHold'? (atm we don't check this for internal player)
247327 }
248328
249- //TODO: SepiaFW.audio.setPlayerTitle('', '') + setMediaSessionState (SepiaFW.audio)
250- //TODO: move to my-view handler (avoid additional onready event due to iframe reload etc.)
251- //TODO: prevent multiple error messages
252-
253- //Controls - TODO: implement
329+ //Controls - TODO: implement callbacks?! more?
254330 thisPlayer . play = function ( doneCallback , errorCallback ) {
255331 sendEvent ( { controls : "play" } ) ;
256332 isWaitingForPlay = true ;
257333 }
258334 thisPlayer . pause = function ( doneCallback , errorCallback ) {
259335 sendEvent ( { controls : "pause" } ) ;
260336 isWaitingForPause = true ;
337+ isOnHold = false ;
261338 }
262339 thisPlayer . fadeOut = function ( doneCallback , errorCallback ) {
263340 sendEvent ( { controls : "fadeOut" } ) ;
@@ -307,14 +384,21 @@ function sepiaFW_build_ui_cards_embed(){
307384
308385 //stop, release resources and remove handle
309386 thisPlayer . release = function ( doneCallback , errorCallback ) {
310- //TODO: implement
311- // - stop, remove from active players, remove from DOM?
387+ // - remove from active players, block incoming events
312388 state = 11 ;
389+ if ( lastActiveMediaPlayer == thisPlayer ) lastActiveMediaPlayer = undefined ;
390+ delete activeMediaPlayers [ playerId ] ;
391+ SepiaFW . debug . info ( "Embedded MediaPlayer - Released player with id: " + playerId ) ;
313392 }
314393
315- //add audio-interface events
394+ //add audio-interface events (make sure its set)
316395 registerMediaPlayerFadeInOutListener ( thisPlayer ) ;
317396
397+ //make sure last active player is stopped
398+ if ( lastActiveMediaPlayer && ( lastActiveMediaPlayer . isPlaying ( ) || lastActiveMediaPlayer . isWaitingForPlay ( ) ) ) {
399+ lastActiveMediaPlayer . pause ( ) ;
400+ }
401+
318402 //store in list
319403 activeMediaPlayers [ playerId ] = thisPlayer ;
320404 lastActiveMediaPlayer = thisPlayer ;
0 commit comments