/*****************************************************
*
* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved.
*
*****************************************************
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
* License for the specific language governing rights and limitations
* under the License.
*
*
* The Initial Developer of the Original Code is Adobe Systems Incorporated.
* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems
* Incorporated. All Rights Reserved.
*
*****************************************************/
package org.osmf.elements.compositeClasses
{
import __AS3__.vec.Vector;
import org.osmf.events.SeekEvent;
import org.osmf.media.MediaElement;
import org.osmf.traits.MediaTraitBase;
import org.osmf.traits.MediaTraitType;
import org.osmf.traits.PlayState;
import org.osmf.traits.PlayTrait;
import org.osmf.traits.SeekTrait;
import org.osmf.traits.TimeTrait;
/**
* Implementation of SeekTrait which can be a composite media trait.
*
* This is the parallel case in which all child media elements seek together.
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion OSMF 1.0
*/
internal class ParallelSeekTrait extends CompositeSeekTrait
{
public function ParallelSeekTrait(traitAggregator:TraitAggregator, owner:MediaElement)
{
super(traitAggregator, CompositionMode.PARALLEL, owner);
this.owner = owner;
}
// Overrides
//
/**
* @private
*/
override protected function doSeek(seekOp:CompositeSeekOperationInfo):void
{
inSeek = true;
// How to seek has been done by a call to the canSeekTo method. For parallel
// seekable trait, it needs to instruct each child to seek.
var parallelSeek:ParallelSeekOperationInfo = seekOp as ParallelSeekOperationInfo;
var childSeekOperations:Vector.<ChildSeekOperation> = parallelSeek.childSeekOperations;
for (var i:int = 0; i < childSeekOperations.length; i++)
{
doChildSeek(childSeekOperations[i] as ChildSeekOperation);
}
inSeek = false;
}
private function doChildSeek(childSeekOperation:ChildSeekOperation):void
{
var childSeekTrait:SeekTrait = childSeekOperation.child.getTrait(MediaTraitType.SEEK) as SeekTrait;
childSeekTrait.addEventListener(SeekEvent.SEEKING_CHANGE, onChildSeekingChange);
childSeekTrait.seek(childSeekOperation.time);
function onChildSeekingChange(event:SeekEvent):void
{
if (event.seeking == false)
{
childSeekTrait.removeEventListener(SeekEvent.SEEKING_CHANGE, onChildSeekingChange);
// When the seek completes, make sure the child is playing if the
// composite element is playing. But if a child has reached its
// duration, then there's no need to play it.
var childPlayTrait:PlayTrait = childSeekOperation.child.getTrait(MediaTraitType.PLAY) as PlayTrait;
var childTimeTrait:TimeTrait = childSeekOperation.child.getTrait(MediaTraitType.TIME) as TimeTrait;
var parentPlayTrait:PlayTrait = owner.getTrait(MediaTraitType.PLAY) as PlayTrait;
if ( childPlayTrait != null
&& parentPlayTrait != null
&& ( childTimeTrait == null
|| childTimeTrait.currentTime != childTimeTrait.duration
)
)
{
if (parentPlayTrait.playState == PlayState.PLAYING)
{
childPlayTrait.play();
}
else if (parentPlayTrait.playState == PlayState.PAUSED && childPlayTrait.canPause)
{
childPlayTrait.pause();
}
}
}
}
}
/**
* @private
*/
override protected function prepareSeekOperationInfo(time:Number):CompositeSeekOperationInfo
{
var seekToOp:ParallelSeekOperationInfo = new ParallelSeekOperationInfo();
for (var i:int = 0; i < traitAggregator.numChildren; i++)
{
var childSeekTrait:SeekTrait = traitAggregator.getChildAt(i).getTrait(MediaTraitType.SEEK) as SeekTrait;
var childTimeTrait:TimeTrait = traitAggregator.getChildAt(i).getTrait(MediaTraitType.TIME) as TimeTrait;
if (childTimeTrait == null || isNaN(childTimeTrait.duration))
{
// If the child has no TimeTrait (such as an image element) or the duration is undefined, ignore it.
continue;
}
if (childSeekTrait == null)
{
// This is the condition where TimeTrait is not null and duration is well defined while
// the SeekTrait is absent, so we cannot seek.
seekToOp.canSeekTo = false;
break;
}
var seekTime:Number = Math.min(time, childTimeTrait.duration);
seekToOp.canSeekTo = childSeekTrait.canSeekTo(seekTime);
if (seekToOp.canSeekTo)
{
var childSeekOp:ChildSeekOperation = new ChildSeekOperation
( traitAggregator.getChildAt(i)
, seekTime
);
seekToOp.childSeekOperations.push(childSeekOp);
}
else
{
break;
}
}
// If no seek operations were prepared, then we can't actually seek.
if (seekToOp.childSeekOperations.length == 0)
{
seekToOp.canSeekTo = false;
}
return seekToOp;
}
/**
* @private
*/
override protected function checkSeeking():Boolean
{
// The parallel seek trait is in the seeking state if at least one
// of the children is in the seeking state.
var seekingState:Boolean = false;
traitAggregator.forEachChildTrait
(
function(mediaTrait:MediaTraitBase):void
{
seekingState ||= SeekTrait(mediaTrait).seeking;
}
, MediaTraitType.SEEK
);
return seekingState;
}
/**
* @private
*/
override protected function onSeekingChanged(event:SeekEvent):void
{
if (event.seeking && !inSeek)
{
// In this case, the child seek causes its siblings (in
// parallel) to seek.
seek(event.time);
}
else if (event.seeking == false && checkSeeking() == false)
{
// The child is exiting the seeking state, so we just
// update the composite seeking state.
setSeeking(false, event.time);
}
}
private var inSeek:Boolean = false;
private var owner:MediaElement;
}
}