Customizing HTTP Dynamic Streaming
From osmf.adobe
For most players, simply enabling OSMF's default Dynamic Streaming is sufficient. For some players, customizing the HTTP Dynamic Streaming (HDS) adaptive bitrate algorithm may be desired, but note that this is an advanced task.
Below is a representation of the customizable areas of the adaptive bitrate algorithm.
The rest of this article describes the various levels of customization, in order of complexity, starting with simple parameter customization and ending with the complete replacement of the adaptive bitrate algorithm.
Contents |
Basic customization
In order to customize the HDS algorithm, you must first write your own NetLoader for HDS. To do this, you can extend the org.osmf.net.httpstreaming.HTTPStreamingNetLoader class and override the createSwitchManager() method.
The CustomHTTPStreamingNetLoader class would look like this:
public class CustomHTTPStreamingNetLoader extends HTTPStreamingNetLoader
{
public function CustomHTTPStreamingNetLoader()
{
super();
}
override protected function createNetStreamSwitchManager(connection:NetConnection, netStream:NetStream, dsResource:DynamicStreamingResource):NetStreamSwitchManagerBase
{
// TODO
// Create the switch manager here
}
}
Note that you can change the behavior of the HDS algorithm significantly without implementing new metrics, rules, or a new Switch Manager. You can decide to not use a certain rule or to use multiple instances of a rule, each with different sets of parameters. To do this, in createNetStreamSwitchManager(), simply instantiate the rules and the Switch Manager with different parameters. You can override either the function or the values of the protected constants.
Here is the content of the createNetStreamSwitchManager() method of HTTPStreamingNetLoader:
// Create a QoSInfoHistory, to hold a history of QoSInfo provided by the NetStream var netStreamQoSInfoHistory:QoSInfoHistory = createNetStreamQoSInfoHistory(netStream); // Create a MetricFactory, to be used by the metric repository for instantiating metrics var metricFactory:MetricFactory = createMetricFactory(netStreamQoSInfoHistory); // Create the MetricRepository, which caches metrics var metricRepository:MetricRepository = new MetricRepository(metricFactory); // Create the normal rule var normalRules:Vector.<RuleBase> = new Vector.<RuleBase>(); var normalRuleWeights:Vector.<Number> = new Vector.<Number>(); normalRules.push ( new BufferBandwidthRule ( metricRepository , BANDWIDTH_BUFFER_RULE_WEIGHTS , BANDWIDTH_BUFFER_RULE_BUFFER_FRAGMENTS_THRESHOLD ) ); normalRuleWeights.push(1); // Create the emergency rules var emergencyRules:Vector.<RuleBase> = new Vector.<RuleBase>(); emergencyRules.push(new DroppedFPSRule(metricRepository)); emergencyRules.push ( new EmptyBufferRule ( metricRepository , EMPTY_BUFFER_RULE_SCALE_DOWN_FACTOR ) ); emergencyRules.push ( new AfterUpSwitchBufferBandwidthRule ( metricRepository , AFTER_UP_SWITCH_BANDWIDTH_BUFFER_RULE_BUFFER_FRAGMENTS_THRESHOLD , AFTER_UP_SWITCH_BANDWIDTH_BUFFER_RULE_MIN_RATIO ) ); // Create a NetStreamSwitcher to handle the low-level details of NetStream // stream switching var nsSwitcher:NetStreamSwitcher = new NetStreamSwitcher(netStream, dsResource); // Finally, return an instance of the DefaultSwitchManager, passing it // the objects instantiated above return new DefaultHTTPStreamingSwitchManager ( netStream , nsSwitcher , metricRepository , emergencyRules , true , normalRules , normalRuleWeights );
Note that the createNetStreamSwitchManager function uses a couple of additional protected functions:
/**
* Creates a QoSInfoHistory to be used in Adaptive Bitrate switching
* by the metrics. Subclasses may override.
*/
protected function createNetStreamQoSInfoHistory(netStream:NetStream):QoSInfoHistory
{
return new QoSInfoHistory(netStream, QOS_MAX_HISTORY_LENGTH);
}
/**
* Creates a MetricFactory to be used in Adaptive Bitrate switching for
* instantiating metrics. Subclasses may override.
*/
protected function createMetricFactory(netStreamQoSInfoHistory:QoSInfoHistory):MetricFactory
{
return new DefaultMetricFactory(netStreamQoSInfoHistory);
}
The constants used in the above code are also protected and can be overridden by subclasses.
Your code should look similar to the one above. You need to make sure you:
- Instantiate a QoSInfoHistory object. Use a suitable length for your algorithm. Either use the existing createQoSInfoHistory function or override it.
- Instantiate a MetricFactory object. You can use the DefaultMetricFactory or a custom one (sections below describe how to implement new metrics and metric factories). Either use the existing createMetricFactory function or override it.
- Instantiate a MetricRepository object. Keep this unchanged; there shouldn't be any need for you to create a custom metric repository.
- Instantiate the emergency rules and put them in a vector.
- Instantiate the normal rules and put them in a vector. If you plan to use the DefaultHTTPStreamingSwitchManager, then you should also create a vector with their weights (configuring how important they are in the algorithm). The default algorithm uses only one rule - BufferBandwidthRule.
- Instantiate a NetStreamSwitcher object. Keep this unchanged; there shouldn't be any need for you to create a custom NetStream switcher.
- Instantiate a RuleSwitchManagerBase object. You can use DefaultHTTPStreamingSwitchManager or your own custom Switch Manager (as described in sections below).
Important: If you want to be able to use a MediaFactory object to generate media elements, you must create your own media factory that knows about your custom NetLoader. The easiest way to do this is to extend org.osmf.media.DefaultMediaFactory, like this:
/**
* CustomMediaFactory is extending the DefaultMediaFactory by changing the HDS loader.
*/
public class CustomMediaFactory extends DefaultMediaFactory
{
public function CustomMediaFactory()
{
super();
// Add the custom item (it will replace the existing one)
var customHTTPStreamingNetLoader:CustomHTTPStreamingNetLoader = new CustomHTTPStreamingNetLoader();
addItem
( new MediaFactoryItem
( "org.osmf.elements.video.httpstreaming"
, customHTTPStreamingNetLoader.canHandleResource
, function():MediaElement
{
return new VideoElement(null, customHTTPStreamingNetLoader);
}
)
);
}
}
Customizing the Metrics
This section describes how you can customize the metrics of the existing types (defined in org.osmf.net.metrics.MetricType). You may want to do this if you want to leave the rules and the Switch Manager unchanged, but change the way the metrics are computed.
The default metrics
The following metrics are implemented in the framework:
- ActualBitrateMetric - Computes the actual bitrate of the quality level currently being downloaded. It is computed on a configurable number of fragments (minimum one).
- AvailableQualityLevelsMetric - Lists all quality levels for the content that are specified in the F4M file.
- BandwidthMetric - Computes the bandwidth available to the client (Bytes/second). The bandwidth can be calculated on at least on fragment, by dividing the size of the fragment (bytes) by the download duration (seconds). The metric is computed on a configurable number of fragments by performing a weighted average of the bandwidths resulted from each fragment.
- BufferFragmentsMetric - Computes the number of whole fragments in the buffer.
- BufferLengthMetric - Computes the length of the buffer (in seconds).
- BufferOccupationRatioMetric - Computes the ratio of occupation of the buffer (buffer length divided by the buffer time).
- CurrentStatusMetric - Provides the indices of the quality levels: currently playing (currentIndex) and currently downloading (actualIndex).
- DroppedFPSMetric - Computes the number of dropped frames per second, over a configurable amount of time.
- FPSMetric - Provides the FPS characteristic to the asset.
- FragmentCountMetric - Provides the number of fragments in the QoSInfoHistory.
- RecentSwitchMetric - Provides the difference in the indices of the last downloaded fragment's quality level and the previously downloaded fragment's quality level. For example:
- If the last fragment was an up-switch from level 2 to level 4, this metric returns 2.
- If the last fragment was a down switch from level 5 to level 1, this metric returns -4.
- If there was no switch (the last two fragments are from the same quality level), this metric returns 0.
- EmptyBufferMetric - Specifies whether there was an empty buffer event (the buffer ran dry) in the last QoS update interval. It is based on the QoSInfo emptyBufferOccurred, which is set by the NetStream on the QoSInfo if the buffer ran dry at any time before dispatching it, but after dispatching the previous QoSInfo.
Implementing a Metric, part 1
When implementing a custom metric, you have two options: to extend an existing metric or to extend the MetricBase class. In either case you must conserve the metric's type and constructor parameters.
Let's assume you want to create a new bandwidth metric from scratch. The existing bandwidth metric has the following constructor definition:
/** * Constructor. * * @param qosInfoHistory The QoSInfoHistory to be used for computing the metric * @param weights The weights of the fragments (first values are the weights of the most recent fragments) */ public function BandwidthMetric(qosInfoHistory:QoSInfoHistory, weights:Vector.<Number>)
Given the need to conserve that definition, here's what a custom bandwidth metric would look like:
package com.example.net.metrics
{
import org.osmf.net.metrics.MetricBase;
import org.osmf.net.metrics.MetricType;
import org.osmf.net.metrics.MetricValue;
import org.osmf.net.qos.QoSInfo;
import org.osmf.net.qos.QoSInfoHistory;
/**
* My custom bandwidth metric.
* Measurement unit: bytes / second
*/
public class CustomBandwidthMetric extends MetricBase
{
/**
* Constructor
*/
public function CustomBandwidthMetric(qosInfoHistory:QoSInfoHistory, weights:Vector.<Number>)
{
super(qosInfoHistory, MetricType.BANDWIDTH);
// Perform some validations of the weights parameter
// [..]
}
/**
* Computes the value of the bandwidth (in bytes/second)
*/
override protected function getValueForced():MetricValue
{
// Perform custom computations on the qosInfoHistory
// [...]
// If it was possible to compute the metric
if (metricComputedSuccessfully)
{
return new MetricValue(computedBandwidth, true);
}
else
{
return new MetricValue(undefined, false);
}
}
}
}
As shown, you must always do two things in the constructor:
Call the MetricBase constructor with the qosInfoHistory and the metric type parameters. There is no need to perform any validations on qosInfoHistory, as this is performed in the MetricBase constructor.
Then, overridde getValueForced(). This is where you implement the computation of the metric. Note that here you must return a MetricValue object. The first parameter of MetricValue is the value of the metric (which can be of any type). The second represents the validity of the metric. If the metric cannot be computed, the method should return a MetricValue object that has undefined as a value and false as a validity.
There is no need to handle the caching of the value in your implementation. It is done in MetricBase.
Finally, in order for your custom metric to be used, you must create a custom metric factory. This is described in the following section, "Implementing a Metric, part 2".
Implementing a Metric, part 2
The following example shows how to create a metric factory to use your CustomBandwidthMetric instead of the default BandwidthMetric.
package com.example.net.metrics
{
import org.osmf.net.metrics.DefaultMetricFactory;
import org.osmf.net.metrics.MetricBase;
import org.osmf.net.metrics.MetricFactoryItem;
import org.osmf.net.metrics.MetricType;
import org.osmf.net.qos.QoSInfoHistory;
/**
* Custom metric factory that replaces the MetricFactoryItem handling
* the bandwidth metric type with a custom implementation
*/
public class CustomMetricFactory extends DefaultMetricFactory
{
/**
* Constructor.
*/
public function CustomMetricFactory(qosInfoHistory:QoSInfoHistory)
{
super(qosInfoHistory);
// Adding this item will replace the existing one
addItem
( new MetricFactoryItem
( MetricType.BANDWIDTH
, function(qosInfoHistory:QoSInfoHistory, weights:Vector.<Number>):MetricBase
{
return new CustomBandwidthMetric(qosInfoHistory, weights);
}
)
);
}
}
}
Customizing the rules
This level of customization allows you to add or replace existing rules in the algorithm. No changes to the Switch Manager are required.
The default HDS algorithm uses two types of rules:
- Normal rules: These can recommend both lower and higher values than the current actual bitrate (currently downloading bitrate):
- Bandwidth rule
- BufferBandwidth rule
- Emergency rules. These recommend an ideal bitrate, but only in emergency situations, and the bitrate is always lower than the current actual bitrate:
- DroppedFPS rule
- EmptyBuffer rule
- AfterUpSwitchBufferBandwidth rule
Note: The purpose of the last two rules (EmptyBufferRule & AfterUpSwitchBufferBandwidthRule) is to protect against false metrics caused by caching.
Bandwidth Rule
The bandwidth rule has the purpose of recommending the ideal bitrate to be played in regard to the bandwidth conditions.
Configuration: weights: the Vector of the weights to be passed to the BandwidthMetric. For example, to compute the bandwidth on the latest 3 fragments, with the weight of the most recent one being 0.5, the weight of the previous one 0.3 and the oldest (third) fragment's weight 0.2, one would set the weights Vector to new <Number>[0.5, 0.3, 0.2].
Recommended bitrate: The value of the Bandwidth metric computed with the specified weights.
Confidence: The confidence is 1 when at least maxFragments where available for computation. Otherwise, it is computed by dividing the sum of the weights of the available fragments to the total sum of weights. For example, let's take the weights in the above example ([0.5, 0.3, 0.2]). Let's assume that only two fragments are available for bandwidth computation. This means that the confidence will be (0.5 + 0.3) / (0.5 + 0.3 + 0.2) = 0.8. While in this example the sum of the given weights was 1, this is not mandatory. The same formula applies for any values.
Note: This rule is included in the framework, but it is not used in the default algorithm. Instead, its extension (BufferBandwidth Rule) is used.
Default values: In the default switching manager the weights are 7 and 3, using 2 fragments with a higher weight on the last fragment.
BufferBandwidth Rule
This rule extends the Bandwidth rule with the purpose of limiting the recommendations to lower bitrates if the buffer is bigger than a threshold.
Configuration: weights: same meaning as BandwidthRule's weights. bufferFragmentsThreshold: The number of fragments in the buffer above which no lower bitrates are recomended. For example, assume the bandwidth has a value of 3000 kbps and the actual bitrate is 5000 kbps. If the number of fragments in the buffer is below the threshold, the rule will recommend 3000 kbps; otherwise, it will recommend 5000 kbps.
Recommended bitrate: The same as the Bandwidth rule, except for the case when both the following conditions apply:
- the number of fragments in the buffer is greater or equal than bufferFragmentsThreshold
- the bitrate recommended by the bandwidth rule is lower than the current actual bitrate
In this case, the current actual bitrate is recommended (or the declared bitrate, if the actual bitrate metric is not available).
Confidence: Same as the Bandwidth rule.
Default values: In the default switching manager the weights are 7 and 3, using 2 fragments with a higher weight on the last fragment. The fragment threshold is set to 2.
DroppedFPS Rule
This is an emergency rule meant to suggest lower bitrates if the current one is being played poorly (dropped frames).
Configuration: desiredSampleLength: The desired length of the content (in seconds) on which to compute the dropped FPS metric. maximumDroppedFPSRatio: The maximum acceptable ratio of dropped FPS (droppedFPS / FPS).
Recommended bitrate: The current actual bitrate is scaled down to the value that would theoretically cause no dropped frames.
Confidence: If the dropped frames per second ratio (droppedFPS / FPS) is higher than maximumDroppedFPSRatio, then the confidence is 1. Otherwise, the confidence computed according to the formula: droppedFPS / (FPS * maximumDroppedFPSRatio).
Default values: In the default switching manager the desiredSampleLength is 10 seconds and the maximumDroppedFPSRatio is set to 0.1, allowing small variations around the original FPS.
EmptyBuffer Rule
This is an emergency rule meant to suggest a lower bitrate if a buffering event occurred since the last RUN_ALGORITHM event. This rule is introduced because a buffering event represents a significant reason to force a lower quality level. Such events can occur in most use-cases, but in a network with cached content the chances are higher. This happens because the in such a network, various fragments from various quality levels are cached and are therefore downloaded at very high speed. It is likely to reach a cached quality level that plays well until a fragment is requested which is not cached. If the current quality level is high and the bandwidth is not so great, it will take a long time to download this new fragment. This might cause the playback to stop due to buffering, if the entire buffer is consumed during the download of this fragment. This rule will prevent the algorithm from sticking with this quality level, as it might have done, deciding it was only a negative spike. This rule has good applicability in this scenario.
Note: This rule is based on empty buffer events caused by poor playback. The initial buffering and the buffering caused by seeking will not be considered.
Configuration: scaleDownFactor: The factor to be applied to the current actual bitrate. Takes values between 0 and 1.
Recommended bitrate: The current actual bitrate is scaled down with the scaleDownFactor. The formula is: recommendedBitrate = currentBitrate * scaleDownFactor
Confidence: The confidence is 1, if an empty buffer occurred. Otherwise, the confidence is 0.
Default values: in the default switch manager, scaleDownFactor is 0.4.
AfterUpSwitchBandwidthBuffer Rule
This is an emergency rule meant to limit the effects of an erratic switch decision, caused by metrics influenced by cached content. Its purpose is to force a down switch immediately if the bitrate we have just switched to is not sustainable. This rule kicks in only after the first fragment of a new and higher quality level is downloaded.
The rule uses the RecentSwitchMetric to identify whether an up-switch occurred (the last downloaded fragment is from a higher quality level than the previous one).
An example use-case which this rule addresses is when the 400kbps quality level is playing and downloads very quickly, because it's cached. This causes the algorithm to estimate the bandwidth at a very high value (e.g. 10000 kbps), even if it's not the real bandwidth (e.g. 600kbps). The switch manager decides to switch to a higher quality level (e.g. 1200 kbps). This quality level is not cached and is well above our real bandwidth. It is not sustainable and we need to switch down immediately.
Configuration: minBandwidthToBitrateRatio: The minimum acceptable bandwidth / bitrate ratio. The bandwidth here refers to the apparent bandwidth computed on the last downloaded fragment. It is a value >= 0. We don't recommend setting this ratio to 1, as we don't want to dismiss a higher quality level simply because its first fragment downloaded during a negative bandwidth spike. bufferFragmentsThreshold: The number of fragments in the buffer above which no lower bitrates are recomended (just like at the BandwidthBuffer rule).
Recommended bitrate: The value of the bandwidth, as computed on the last fragment.
Confidence: 1, if the last fragment downloaded was from a higher quality level and the bandwidth is unsustainable (bandwidth / bitrate < bitrateToBandwidthRatio) and the buffer is below the bufferFragmentsThreshold. 0, otherwise.
Default values: in the default switch manager, minBandwidthToBitrateRatio is 0.5 and bufferFragmentsThreshold is 2.
Implementing new rules
The procedure for implementing normal rules and emergency rules is the same. (For information on disabling the emergency rules, see the "Customizing the Switch Manager" section below.)
As with the metrics, to implement a rule, you must either extend an existing rule or extend the RuleBase object. Whether you create a rule to replace an existing rule or create entirely new rules, there is no distinction in the procedure.
You decide whether you want your rule to use existing metrics or add new ones. To add new metrics, you follow the same procedure described above for replacing existing metrics, with the difference being that you need to be careful to avoid using the same metric type for two metrics. You can, of course, extend the MetricFactory directly (instead of DefaultMetricFactory), which contains no default items. You then can add only the ones you intend to use.
Here is an example of a custom rule:
package com.example.net.rules
{
import org.osmf.net.metrics.MetricBase;
import org.osmf.net.metrics.MetricRepository;
import org.osmf.net.metrics.MetricType;
import org.osmf.net.metrics.MetricValue;
import org.osmf.net.qos.QualityLevel;
public class CustomRule extends RuleBase
{
/**
* Constructor.
*
* @param metricRepository The metric repository from which to retrieve the necessary metrics
* @param someParameter Some parameter
* @param someOtherParameter Some other parameter
*/
public function CustomRule
( metricRepository:MetricRepository
, someParameter:SomeType = SOME_DEFAULT_VALUE
, someOtherParameter:SomeOtherType = SOME_OTHER_DEFAULT_VALUE
)
{
super(metricRepository);
// Validate the parameters
// [...]
}
override public function getRecommendation():Recommendation
{
// Obtain the needed metrics (if we don't already have them)
if (someMetric == null)
{
var someMetric:MetricBase = metricRepository.getMetric(SOME_METRIC_TYPE);
}
// [...]
// Compute the recommendation of the rule (the bitrate and the confidence) and return it
if (confidence == 0)
{
// It is customary to recommend a bitrate of 0 when the confidence is 0
// However, this can be any valid Number (except Number.NaN)
bitrate = 0;
}
return new Recommendation(CUSTOM_RULE_TYPE, bitrate, confidence);
}
}
}
After you've implemented your rules, you instantiate them in the createNetStreamSwitchManager() method in your custom NetLoader and pass them to DefaultSwitchManager.
Customizing the Switch Manager
The Switch Manager determines when a bitrate change is made and to what quality. This is the final level of customization.
The default Switch Manager
DefaultHTTPStreamingSwitchManager is OSMF's default implementation of RuleSwitchManagerBase for HTTP Dynamic Streaming. In other words, it is the default HDS Switch Manager. The job of the Switch Manager is to gather the recommendations from all the normal rules and create a weighted average representing the ideal bitrate to be played.
Note that DefaultHTTPStreamingSwitchManager doesn't concern itself with the emergency rules, as RuleSwitchManagerBase controls when these are called. RuleSwitchManagerBase identifies the minimum bitrate indicated by the confident emergency rules and calls the getNewEmergencyIndex() method. If there is no emergency, the getNewIndex() method is called.
The Switch Manager denies switches to unreliable quality levels by keeping a record of its prior decisions. Whenever the Switch Manager makes a switch decision -- whether or not the decision results in a change of bitrate -- it stores the decision in the history. It also notes whether this was an emergency switch or not.
The history for a given quality level is stored for a defined maximum number of records (maxReliabilityRecordSize). The history for a quality level is not considered a valid source of data if its length has not yet reached a minimum size (minReliabilityRecordSize). However, a quality level can be considered unreliable even if the reliability record size is above minReliabilityRecordSize, if an emergency down-switch has occurred from that quality level.
A quality level can have a reliability ranging from 0 (totally unreliable) to 1 (completely reliable) or it may have no reliability due to lack of data. The DefaultSwitchManager does not avoid quality levels about which it has no relevant data. This means that the Switch Manager may switch either (a) to reliable quality levels or (b) to quality levels which don't have a determined reliability.
When computing reliability, the Switch Manager only considers the decisions it made in auto-switch mode. This means that manual switches to various quality levels are not used in the computation. In computing the reliability of a given quality level, the Switch Manager uses these factors:
- downSwitchesFrom = The number of times the Switch Manager has decided to switch down from the specific quality level.
- switchesFrom = The number of times the Switch Manager had decided to switch anywhere from the specific quality level. Important: Even decisions to remain on the same quality level are counted here.
- historyLength = The length of the reliability record.
Additionally, a quality level's reliability is 0 if at least one emergency down-switch exists in the record.
Therefore, a quality level is considered reliable if any of the following statements are true:
- The reliability is greater than the configurable threshold minReliability.
- The reliability is not available, due to lack of data.
In addition to the reliability constraints used by the Switch Manager, there are also two switch constraints that operate. These help to limit the size of the jumps when switching and to ensure that the Switch Manager only switches to a bitrate that is both reliable and within the switch limits:
- maxUpSwitchLimit: The maximum difference between the indices of the old and new quality level when switching up; defaults to 1.
- maxDownSwitchLimit: The maximum difference between the indices of the old and new quality level when switching down; defaults to 2. The maxDownSwitchLimit constraint does not apply to switches caused by emergency rules. This ensures that the algorithm does not get too aggressive / jumpy. Set their values to -1 (negative one) to disable these constraints.
Implementing a custom Switch Manager
This is the most advanced level of HDS customization. You can write your own custom switch manager by extending RuleSwitchManagerBase or DefaultHTTPStreamingSwitchManager.
A custom Switch Manager must only override two methods: getNewIndex() and getNewEmergencyIndex(). There is no need to handle the emergency rules themselves in the custom Switch Manager. RuleSwitchManagerBase() identifies the minimum bitrate indicated by the confident emergency rules and calls the getNewEmergencyIndex() method. If there is no emergency, it calls getNewIndex().
Below is an example:
package com.example.net
{
import org.osmf.net.NetStreamSwitcher;
import org.osmf.net.SwitchManagerBase;
import org.osmf.net.metrics.MetricRepository;
import org.osmf.net.rules.RuleBase;
public class CustomSwitchManager extends RuleSwitchManagerBase
{
/**
* Constructor.
*
* @param notifier The EventDispatcher which dispatches the HTTPStreamingEvent.RUN_ALGORITHM events
* @param switcher The NetStreamSwitcher to use for switching
* @param metricRepository The repository responsible with providing metrics
* @param emergencyRules Array of rules to be used in the algorithm.
* An emergency rule can only recommend lower bitrates than the current one.
* @param someCustomParam Some custom param
* @param autoSwitch Flag deciding whether autoSwitch should be enabled
* @param someOtherCustomParam Some other custom param
*/
public function CustomSwitchManager
( notifier:EventDispatcher
, switcher:NetStreamSwitcher
, metricRepository:MetricRepository
, emergencyRules:Vector.<RuleBase>
, autoSwitch:Boolean = true
, someCustomParam:SomeType
, someOtherCustomParam:SomeOtherType = SOME_DEFAULT_VALUE
)
{
super(netStream, switcher, metricRepository, emergencyRules, autoSwitch);
// Perform some validations of the custom parameters
// [..]
}
override public function getNewIndex():uint
{
// Interogate the rules, access the needed metrics and compute a new index to be played
// [...]
// Perform some other actions (e.g. remember the decision for future reference)
// [...]
return index;
}
override public function getNewEmergencyIndex(maxBitrate:Number):uint
{
// Compute the next index to be played, considering that the
// emergency rules recommended a maximum bitrate given as a parameter
// [...]
// Perform some other actions (e.g. remember the decision for future reference)
// [...]
return index;
}
}
}
See also:
- Buffering for details on setting buffer sizes for dynamic streams.
- Dynamic Stream Switching engineering specification. Please note that an engineering design specification is a snapshot in time and is not guaranteed to contain the most current information.
