/*****************************************************
*
* Copyright 2010 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) 2010 Adobe Systems
* Incorporated. All Rights Reserved.
*
*****************************************************/
package org.osmf.net.dvr
{
import flash.events.Event;
import flash.net.NetConnection;
import flash.net.Responder;
import flash.utils.Dictionary;
import org.osmf.events.MediaError;
import org.osmf.events.MediaErrorCodes;
import org.osmf.events.NetConnectionFactoryEvent;
import org.osmf.media.URLResource;
import org.osmf.net.NetConnectionFactory;
import org.osmf.net.NetConnectionFactoryBase;
import org.osmf.net.NetStreamUtils;
import org.osmf.net.StreamingURLResource;
[ExcludeClass]
/**
* @private
*/
public class DVRCastNetConnectionFactory extends NetConnectionFactoryBase
{
/**
* Constructor.
**/
public function DVRCastNetConnectionFactory(factory:NetConnectionFactoryBase = null)
{
subscribedStreams = new Dictionary();
innerFactory = factory || new NetConnectionFactory();
innerFactory.addEventListener
( NetConnectionFactoryEvent.CREATION_COMPLETE
, onCreationComplete
);
innerFactory.addEventListener
( NetConnectionFactoryEvent.CREATION_ERROR
, onCreationError
);
super();
}
/**
* @private
**/
override public function create(resource:URLResource):void
{
innerFactory.create(resource);
}
/**
* @private
**/
override public function closeNetConnection(netConnection:NetConnection):void
{
var streamName:String = subscribedStreams[netConnection];
if (streamName != null)
{
netConnection.call
( DVRCastConstants.RPC_UNSUBSCRIBE
, null
, streamName
);
delete subscribedStreams[netConnection];
}
innerFactory.closeNetConnection(netConnection);
}
// Internals
//
private function onCreationComplete(event:NetConnectionFactoryEvent):void
{
var urlResource:URLResource = event.resource as URLResource;
var netConnection:NetConnection = event.netConnection;
var streamName:String;
// Capture this event, whithold it from the outside world until
// we have succeeded subscribing to the DVRCast stream:
event.stopImmediatePropagation();
var streamingResource:StreamingURLResource = urlResource as StreamingURLResource;
var urlIncludesFMSApplicationInstance:Boolean
= streamingResource
? streamingResource.urlIncludesFMSApplicationInstance
: false;
streamName = NetStreamUtils.getStreamNameFromURL(urlResource.url, urlIncludesFMSApplicationInstance);
var responder:Responder
= new TestableResponder
( onStreamSubscriptionResult
, onServerCallError
);
event.netConnection.call(DVRCastConstants.RPC_SUBSCRIBE, responder, streamName);
function onStreamSubscriptionResult(result:Object):void
{
var streamInfoRetriever:DVRCastStreamInfoRetriever
= new DVRCastStreamInfoRetriever
( netConnection
, streamName
);
streamInfoRetriever.addEventListener(Event.COMPLETE, onStreamInfoRetrieverComplete);
streamInfoRetriever.retrieve();
}
function onStreamInfoRetrieverComplete(event:Event):void
{
var streamInfoRetriever:DVRCastStreamInfoRetriever = event.target as DVRCastStreamInfoRetriever;
if (streamInfoRetriever.streamInfo != null)
{
// Remove the completion listener:
removeEventListener(NetConnectionFactoryEvent.CREATION_COMPLETE, onCreationComplete);
if (streamInfoRetriever.streamInfo.offline == true)
{
// The content is offline, signal this as a media error:
dispatchEvent
( new NetConnectionFactoryEvent
( NetConnectionFactoryEvent.CREATION_ERROR
, false
, false
, netConnection
, urlResource
, new MediaError(MediaErrorCodes.DVRCAST_CONTENT_OFFLINE)
)
);
// Unsubscribe:
netConnection.call(DVRCastConstants.RPC_UNSUBSCRIBE, null, streamName);
netConnection = null;
}
else
{
// Instantiate a new recording info object:
var recordingInfo:DVRCastRecordingInfo = new DVRCastRecordingInfo();
recordingInfo.startDuration = streamInfoRetriever.streamInfo.currentLength;
recordingInfo.startOffset = calculateOffset(streamInfoRetriever.streamInfo);
recordingInfo.startTime = new Date();
// Add the stream info and recording info to the resource as metadata:
streamingResource.addMetadataValue(DVRCastConstants.STREAM_INFO_KEY, streamInfoRetriever.streamInfo);
streamingResource.addMetadataValue(DVRCastConstants.RECORDING_INFO_KEY, recordingInfo);
// Store the subscribed stream with the connection instance:
subscribedStreams[netConnection] = streamName;
// Now that we're done, signal completion, so the VideoElement will
// continue its loading process:
dispatchEvent
( new NetConnectionFactoryEvent
( NetConnectionFactoryEvent.CREATION_COMPLETE
, false
, false
, netConnection
, urlResource
)
);
}
}
else
{
onServerCallError(streamInfoRetriever.error);
}
}
function onServerCallError(error:Object):void
{
dispatchEvent
( new NetConnectionFactoryEvent
( NetConnectionFactoryEvent.CREATION_ERROR
, false
, false
, netConnection
, urlResource
, new MediaError(MediaErrorCodes.DVRCAST_SUBSCRIBE_FAILED, error ? error.message : "")
)
);
}
}
private function onCreationError(event:NetConnectionFactoryEvent):void
{
dispatchEvent(event.clone());
}
private function calculateOffset(streamInfo:DVRCastStreamInfo):Number
{
return DVRUtils.calculateOffset(streamInfo.beginOffset, streamInfo.endOffset, streamInfo.currentLength);
}
private var innerFactory:NetConnectionFactoryBase;
private var subscribedStreams:Dictionary;
}
}