Enabling Quality of Service for Online Video

This post is also available in: Russian

QoS для онлайн видео

To enhance the quality of video broadcast online, stream status statistics should be analyzed. To collect statistics, two classes can be used: NetStreamInfo and NetStreamMulticastInfo (for P2P connections).In this article, we will overview these classes and the ways to access them via the OSMF framework, which is all but intuitive. We will cover open source ActionScript 3 lib for sending statistics to Google Analytics with QoS metrics.

NetStreamInfo Class
The NetStreamInfo class gives access to Quality of Service (QOS) statistics. The data is fetched from the NetStream object and the audio, video and data streaming buffer used. The NetStreamInfo object is returned on accessing NetStream.info property, making a snapshot of the current QOS status and providing QOS statistics in terms of NetStreamInfo properties.

The NetStreamInfo class has the following statistical properties. They are all read-only and have the Number type:

  • audioBufferByteLength – the length of the NetStream audio buffer (in bytes).
  • audioBufferLength – the length of the NetStream audio buffer (in seconds).
  • audioByteCount – the total count of audio bytes enqueued, whether played back or cleaned data.
  • audioBytesPerSecond – the NetStream audio buffer fill rate (bytes per second).
  • audioLossRate – sets the level of audio loss for the NetStream session.
  • byteCount – the total count of bytes enqueued, whether played back or cleaned.
  • currentBytesPerSecond – the NetStream buffer fill rate (bytes per second).
  • dataBufferByteLength – the NetStream data buffer length (bytes).
  • dataBufferLength – the NetStream data buffer length (seconds).
  • dataByteCount – the total count of data message bytes enqueued, whether played back or cleaned.
  • dataBytesPerSecond – the NetStream data buffer fill rate (bytes per second).
  • droppedFrames – the number of video frames lost in the current NetStream playback session.
  • maxBytesPerSecond – the maximum NetStream buffer fill rate (bytes per second).
  • playbackBytesPerSecond – the stream playback rate (bytes per second).
  • SRTT – Smoothed Round Trip Time for the NetStream session, in milliseconds. This property is valid only for the RTMFP streams. For RTMP streams, it returns 0.
  • videoBufferByteLength – the NetStream video buffer length (bytes).
  • videoBufferLength – the NetStream data buffer length (seconds).
  • videoByteCount – the total count of video bytes enqueued, whether played back or cleaned.
  • videoBytesPerSecond – the NetStream video buffer fill rate (bytes per second).
  • videoLossRate – the percentage of video data loss through the NetStream object (percentage of lost messages in the total number of messages).

NetStreamMulticastInfo Class
NetStreamMulticastInfo class presents rich statistics on the quality of service (QoS), related to basic streaming using RTMFP peering and NetStream IP multicast. The NetStreamMulticastInfo object is returned by the NetStream.multicastInfo property.
The numeric properties are total amounts calculated from the start of multicast. Such properties include the number of media bytes sent or the number of media fragment messages received. The rate properties represent the current rate snapshot averaged over a few seconds. They specify the rate at which the local node receives the data.

NetStreamMulticastInfo class has the following statistical properties. They are all read-only and have the Number type:

  • bytesPushedFromPeers – the number of bytes of media content proactively pushed by peers and received by the local node.
  • bytesPushedToPeers – the number of media bytes proactively pushed by the local node to peers.
  • bytesReceivedFromIPMulticast – the number media bytes received by the local node from IP multicast.
  • bytesReceivedFromServer – the number of media bytes received by the local node from the server.
  • bytesRequestedByPeers – the number of media bytes sent by the local node to peers in response to their request of certain fragments.
  • bytesRequestedFromPeers – the number of media bytes that the local node requested and received from peers.
  • fragmentsPushedFromPeers – the number of media fragment messages proactively pushed from peers and received by the local node.
  • fragmentsPushedToPeers – the number of media fragment messages proactively pushed by the local node to peers.
  • fragmentsReceivedFromIPMulticast – the number of media fragment messages received by the local node from IP Multicast.
  • fragmentsReceivedFromServer – the number of media fragment messages received by the local node from the server.
  • fragmentsRequestedByPeers – the number of media fragment messages that the local node has sent to peers in response to their requests for specific fragments.
  • fragmentsRequestedFromPeers – the number of media fragment messages that the local node requested and received from peers.
  • receiveControlBytesPerSecond – the rate (bytes per second) at which the local node is receiving control overhead messages from peers.
  • receiveDataBytesPerSecond – the rate (bytes per second) at which the local node is receiving media data from peers, from the server, and IP Multicast.
  • receiveDataBytesPerSecondFromIPMulticast – the rate (bytes per second) at which the local node receives data from IP Multicast.
  • receiveDataBytesPerSecondFromServer – the rate (bytes per second) at which the local node receives media content from the server.
  • sendControlBytesPerSecond – the rate (bytes per second) at which the local node sends control overhead messages to peers and the server.
  • sendControlBytesPerSecondToServer – the rate (bytes per second) at which the local node sends control overhead messages to the server.
  • sendDataBytesPerSecond – the rate (bytes per second) at which the media content is sent by the local node to peers.

To directly access the NetStream class and its info and multicastInfo properties returning the instances of NetStreamInfo and NetStreamMulticastInfo classes respectively, from OSMF, you’ll need to override the createNetStream method of the org.osmf.net.NetLoader class, or of a class inherited from NetLoader. Also, you’ll need to introduce a get method for NetStream, returning the NetStream class when called by the parent class.

The below example shows access to the NetStream class and its info property using the OSMF framework and org.osmf.net.MulticastNetLoader.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// Create a custom loader class CustomMulticastNetLoader based on MulticastNetLoader
// and override the createNetStream method
package
{
import org.osmf.net.MulticastNetLoader;
import org.osmf.net.MulticastResource;
import org.osmf.media.URLResource;
import flash.net.NetStream;
import flash.net.NetConnection;
public class CustomMulticastNetLoader extends MulticastNetLoader
{
public function CustomMulticastNetLoader (factory: NetConnectionFactoryBase = null)
{
super (factory);
}
public function getNetStream (): NetStream {
return _netStream;
}
private var _netStream: NetStream;
override protected function createNetStream (connection: NetConnection, resource: URLResource): NetStream
{
var rs: MulticastResource = resource as MulticastResource;
_netStream = new NetStream (connection, rs.groupspec);
return _netStream;
}
}
}

Then create a test p2p player, using CustomMulticastNetLoader class as loader.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
package
{
import flash.display.Sprite;
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.net.NetStream;
import flash.net.NetStreamInfo;
import flash.net.NetStreamMulticastInfo;
import org.osmf.media.MediaPlayer;
import org.osmf.containers.MediaContainer;
import org.osmf.elements.VideoElement;
import org.osmf.net.MulticastResource;
import CustomMulticastNetLoader;
public class TestPlayer extends Sprite
{
public function TestPlayer ()
{
initPlayer ();
initMainTimer ();
}
private var loader: CustomMulticastNetLoader;
private function initPlayer (): void
{
var resource: MulticastResource = new MulticastResource ("your application URI", "your stream name");
resource.groupspec = "your descriptor";
resource.streamName = "your stream name";
loader = new CustomMulticastNetLoader ();
var videoElement = new VideoElement (resource, loader);
var mediaPlayer: MediaPlayer = new MediaPlayer ();
mediaPlayer.media = videoElement;
mediaPlayer.volume = 0.5;
var container: MediaContainer = new MediaContainer ();
container.width = 800;
container.height = 450;
container.addMediaElement (videoElement);
addChild (container);
}
private function initMainTimer (): void
{
var mainTimer: Timer = new Timer (1000, 0);
mainTimer.addEventListener (TimerEvent.TIMER, onMainTimerTickHandler);
mainTimer.start ();
}
private function onMainTimerTickHandler (evt: TimerEvent): void
{
var netStream: NetStream = loader.getNetStream ();
var netStreamInfo: NetStreamInfo = netStream.info;
var netStreamMulticastInfo: NetStreamMulticastInfo = netStream.multicastInfo;
/ / Display NetStreamInfo statistics
trace ("Video buffer length in byte:" + netStreamInfo.videoBufferByteLength);
trace ("Video buffer length in seconds:" + netStreamInfo.videoBufferLength);
trace ("Video byte / sec:" + netStreamInfo.videoBytesPerSecond);
trace ("Video loss rate:" + netStreamInfo.videoLossRate);
/ / Display NetStreamMulticastInfo statistics
trace ("Bytes pushed FROM peers:" + netStreamMulticastInfo.bytesPushedFromPeers);
trace ("Bytes pushed TO peers:" + netStreamMulticastInfo.bytesPushedToPeers);
trace ("Receive data bytes / second:" + netStreamMulticastInfo.receiveDataBytesPerSecond);
trace ("Send data bytes / second:" + netStreamMulticastInfo.sendDataBytesPerSecond);
}
}
}

After compiling a test player, the debug console every second outputs a statistical slice of the following parameters (metrics): videoBufferByteLength, videoBufferLength, videoBytesPerSecond, videoLossRate, as well as the parameters of the P2P: bytesPushedFromPeers, bytesPushedToPeers, receiveDataBytesPerSecond, sendDataBytesPerSecond.

This method of access to the NetStream class can be applied to all OSMF loader classes (HTTPStreamingNetLoader, RTMPDynamicStreamingNetLoader, DVRCastNetLoader and NetLoader).

TiViSta – this is our open source service to send statistics to Google Analytics, which could be really useful for automated QoS tracking, reporting and analysis.

Have a good QoS for all you visitors!

Leave a Reply