# Dynamic Bandwidth Detection (BWCheck)

**URL:** <https://community.wowza.com/t/dynamic-bandwidth-detection-bwcheck/31>\
**Category:** Wowza Developer Dojo\
**Tags:** wowza-streaming-server-java-api\
**Created:** [March 15, 2007, 6:40am UTC](https://community.wowza.com/t/dynamic-bandwidth-detection-bwcheck/31 "2007-03-15T06:40:15Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/community.wowza.com/system/32/447_2.png) [@system](https://community.wowza.com/u/system)\
**Post date:** [March 15, 2007, 6:40am UTC](https://community.wowza.com/t/dynamic-bandwidth-detection-bwcheck/31/1 "2007-03-15T06:40:15Z")

</div>

[https://www.wowza.com/docs/how-to-test-server-to-client-bandwidth-for-rtmp-clients](https://www.wowza.com/docs/how-to-test-server-to-client-bandwidth-for-rtmp-clients)

---

<div class="post-metadata">

**Author:** ![Jake\_Hilton](https://avatars.discourse-cdn.com/v4/letter/j/9f8e36/32.png) [@Jake\_Hilton](https://community.wowza.com/u/Jake_Hilton)\
**Post date:** [April 6, 2010, 2:10pm UTC](https://community.wowza.com/t/dynamic-bandwidth-detection-bwcheck/31/2 "2010-04-06T14:10:53Z")

</div>

It seems the sample code is not up to date with the jar file… when using the jar the bw is reported to the client once… when using the code above compiled into a module… the bw call fires twice.

Also… one small suggestion… 🙂

When using the jar out of the box it might be nice to wrap the onConnect check in a try catch so that this error doesn’t occur if the second param isn’t passed:

invoke(onConnect): java.lang.ClassCastException: com.wowza.wms.amf.AMFDataObj cannot be cast to com.wowza.wms.amf.AMFDataItem: com.wowza.wms.amf.AMFDataList.getBoolean(null:-1)

Thanks!

Jake

---

<div class="post-metadata">

**Author:** ![Alan\_Halls](https://avatars.discourse-cdn.com/v4/letter/a/e9c0ed/32.png) [@Alan\_Halls](https://community.wowza.com/u/Alan_Halls)\
**Post date:** [June 9, 2010, 9:18pm UTC](https://community.wowza.com/t/dynamic-bandwidth-detection-bwcheck/31/3 "2010-06-09T21:18:50Z")

</div>

So I am a little new to the scene and confused 🙂 So I looked at the guide here, and also at [http://www.longtailvideo.com/support/tutorials/Bitrate-Switching](http://www.longtailvideo.com/support/tutorials/Bitrate-Switching) and am not sure if these go hand in hand, or if you choose one or the other.

As I understood it, Wowza accepted a single file in, and then would re-encode it on the fly for connections of lower bandwidth. I installed the .jar file, added the code into the Application.xml file and can see that it is calling the bwcheck module in the logs, but I have a few customers complaining that the stream is unable to keep up with their connection.

I am also not at all sure what the code below is… Do I need to change anything or is it the source code for the .jar in case I wanted to change some settings? A little more clarification on the original post would help out the newbies like me. Am supposed to make the changes that I made below changing the com.wowza to com.coursesaver?

When building the project in IDE, do I need the ModuleServerSide.java imported? I tried with and without and am getting the error posted in the photo: [http://www.coursesaver.com/personal/error.jpg](http://www.coursesaver.com/personal/error.jpg)

Sorry to have such a multi part post, I am just trying as much as I can and adding info along the way as I run into problems.

> ```auto
> package com.coursesaver.wms.plugin.bwcheck;
> import java.util.*;
> import com.coursesaver.util.*;
> import com.coursesaver.wms.amf.*;
> import com.coursesaver.wms.application.*;
> import com.coursesaver.wms.client.*;
> import com.coursesaver.wms.logging.*;
> import com.coursesaver.wms.module.*;
> import com.coursesaver.wms.request.*;
> /**
> * <p>New and improved bandwidth checker.</p>
> * @author Wowza Media Systems (Roger Littin)
> *
> */
> public class ModuleBWCheck2 extends ModuleBase
> {
> private int bwCheckPayloadSize = 1800;
> private int bwCheckMaxLoops = 6;
> private long bwCheckMaxTime = 1000;
> 	
> public void onAppStart(IApplicationInstance appInstance)
> {
> WMSProperties props = appInstance.getProperties();
> if (props != null)
> {
> this.bwCheckPayloadSize = props.getPropertyInt("bwCheckPayloadSize", bwCheckPayloadSize);
> this.bwCheckMaxLoops = props.getPropertyInt("bwCheckMaxLoops", bwCheckMaxLoops);
> this.bwCheckMaxTime = props.getPropertyLong("bwCheckMaxTime", bwCheckMaxTime);
> }
> 		
> getLogger().info("ModuleBWCheck2.onAppStart: bwCheckPayloadSize: "+this.bwCheckPayloadSize );
> getLogger().info("ModuleBWCheck2.onAppStart: bwCheckMaxLoops: "+this.bwCheckMaxLoops );
> getLogger().info("ModuleBWCheck2.onAppStart: bwCheckMaxTime: "+this.bwCheckMaxTime );
> }
> 	
> public void onConnect(IClient client, RequestFunction function, AMFDataList params)
> {
> boolean autoSenseBW = params.getBoolean(PARAM1);
> if (autoSenseBW)
> calculateClientBw(client);
> else
> client.call("onBWDone", null);
> }
> public void checkBandwidth(IClient client, RequestFunction function, AMFDataList params)
> {
> calculateClientBw(client);
> }
> private void calculateClientBw(IClient client)
> {
> final AMFDataArray payload = new AMFDataArray();
> for (int i = 0; i < bwCheckPayloadSize; i++)
> {
> payload.add(new AMFDataItem((double) Math.random()));
> }
> class ResultObj implements IModuleCallResult
> {
> IOPerformanceCounter totalStats;
> long bytesOutStart;
> double latency = 0;
> int cumLatency = 1;
> int count = 0;
> int sent = 0;
> double kbitDown = 0;
> double deltaDown = 0;
> double deltaTime = 0;
> long start = 0;
> List<Long> pakSent = new ArrayList<Long>();
> List<Long> pakRecv = new ArrayList<Long>();
> public ResultObj(IClient client)
> {
> totalStats = client.getTotalIOPerformanceCounter();
> }
> public void onResult(IClient client, RequestFunction function, AMFDataList params)
> {
> Long now = new Long(System.currentTimeMillis());
> pakRecv.add(now);
> if (count == 0)
> {
> latency = now - pakSent.get(0);
> latency = Math.min(latency, 800);
> //System.out.println("latency: " + latency);
> bytesOutStart = totalStats.getMessagesOutBytes();
> start = System.currentTimeMillis();
> }
> Long timePassed = (now - start);
> count++;
> if ((count >= 1 && count <= bwCheckMaxLoops) && (timePassed < bwCheckMaxTime))
> {
> pakSent.add(sent++, now);
> cumLatency++;
> client.call("onBWCheck", this, payload);
> }
> // Time elapsed now do the calcs
> else if (sent == count)
> {
> // see if we need to normalize latency
> if (latency >= 100)
> {
> // make sure satelite and modem is detected properly
> if (pakRecv.get(1) - pakRecv.get(0) > 1000)
> {
> latency = 100;
> }
> }
> // tidy up
> // and compute bandwidth
> deltaDown = (double) ((totalStats.getMessagesOutBytes() - bytesOutStart) * 8) / 1000; // bytes
> // to
> // kbits
> deltaTime = (double) ((now - start) - (latency * cumLatency)) / 1000;
> if (deltaTime <= 0)
> {
> deltaTime = (double) (now - start) / 1000;
> }
> kbitDown = Math.round(deltaDown / deltaTime); // kbits / sec
> WMSLoggerFactory.getLogger(null).info("onBWDone: " + this.kbitDown);
> client.call("onBWDone", null, this.kbitDown, this.deltaDown, this.deltaTime, this.latency);
> }
> }
> }
> class FirstResult implements IModuleCallResult
> {
> public void onResult(IClient client, RequestFunction function, AMFDataList params)
> {
> ResultObj res = new ResultObj(client);
> long now = System.currentTimeMillis();
> res.pakSent.add(res.sent++, now);
> client.call("onBWCheck", res, "");
> }
> }
> client.call("onBwCheck", new FirstResult(), payload); // First call to
> // client is
> // ignored.
> }
> public void onClientBWCheck(IClient client, RequestFunction function, AMFDataList params)
> {
> getLogger().info("onClientBWCheck");
> AMFDataObj statValues = new AMFDataObj();
> IOPerformanceCounter stats = client.getTotalIOPerformanceCounter();
> statValues.put("cOutBytes", new AMFDataItem(stats.getMessagesInBytes()));
> statValues.put("cInBytes", new AMFDataItem(stats.getMessagesOutBytes()));
> statValues.put("time", new AMFDataItem(params.getLong(PARAM1)));
> sendResult(client, params, statValues);
> }
> }
> 
> ```

---

<div class="post-metadata">

**Author:** ![Charlie\_Good](https://sea2.discourse-cdn.com/flex002/user_avatar/community.wowza.com/charlie_good/32/383_2.png) [@Charlie\_Good](https://community.wowza.com/u/Charlie_Good)\
**Post date:** [April 6, 2010, 2:40pm UTC](https://community.wowza.com/t/dynamic-bandwidth-detection-bwcheck/31/4 "2010-04-06T14:40:37Z")

</div>

I have udpated all of it with the latest, greatest code that I have.

Charlie

---

<div class="post-metadata">

**Author:** ![Richard\_Lanham](https://avatars.discourse-cdn.com/v4/letter/r/c68b51/32.png) [@Richard\_Lanham](https://community.wowza.com/u/Richard_Lanham)\
**Post date:** [April 6, 2010, 9:16pm UTC](https://community.wowza.com/t/dynamic-bandwidth-detection-bwcheck/31/5 "2010-04-06T21:16:34Z")

</div>

Jake,

I think twice is normal. Handle it like this example (adapted from JW Player):

```auto
/ **Receiving the bandwidth check result.** /
		public function onBWDone(... rest):void {
			if (rest.length > 0) {
				trace(rest[0]);
				//forward({bandwidth: rest[0]}, 'bandwidth');
			}
		};

```

Richard

---

<div class="post-metadata">

**Author:** ![Richard\_Lanham](https://avatars.discourse-cdn.com/v4/letter/r/c68b51/32.png) [@Richard\_Lanham](https://community.wowza.com/u/Richard_Lanham)\
**Post date:** [April 7, 2010, 12:02pm UTC](https://community.wowza.com/t/dynamic-bandwidth-detection-bwcheck/31/6 "2010-04-07T12:02:55Z")

</div>

No, this is not needed for that. The main thing you need is video versions that have properly aligned keyframe timecodes. Follow this tutorial:

[http://www.longtailvideo.com/support/tutorials/Bitrate-Switching](http://www.longtailvideo.com/support/tutorials/Bitrate-Switching)

Richard

---

<div class="post-metadata">

**Author:** ![Richard\_Lanham](https://avatars.discourse-cdn.com/v4/letter/r/c68b51/32.png) [@Richard\_Lanham](https://community.wowza.com/u/Richard_Lanham)\
**Post date:** [April 20, 2010, 9:21am UTC](https://community.wowza.com/t/dynamic-bandwidth-detection-bwcheck/31/7 "2010-04-20T09:21:56Z")

</div>

For most purposes “kbitDown” is the number you need. This is the measured bandwidth of server to the client. You don’t want to stream to this client with a higher bitrate stream that kbitDown. Ideally you would stream something less than that.

Richard

---

<div class="post-metadata">

**Author:** ![Richard\_Lanham](https://avatars.discourse-cdn.com/v4/letter/r/c68b51/32.png) [@Richard\_Lanham](https://community.wowza.com/u/Richard_Lanham)\
**Post date:** [April 20, 2010, 10:46am UTC](https://community.wowza.com/t/dynamic-bandwidth-detection-bwcheck/31/8 "2010-04-20T10:46:31Z")

</div>

“latency” is how long will it take to start playing

The speed at which it will play once it starts is indicated by kbitDown

Richard

---

<div class="post-metadata">

**Author:** ![Richard\_Lanham](https://avatars.discourse-cdn.com/v4/letter/r/c68b51/32.png) [@Richard\_Lanham](https://community.wowza.com/u/Richard_Lanham)\
**Post date:** [April 20, 2010, 1:14pm UTC](https://community.wowza.com/t/dynamic-bandwidth-detection-bwcheck/31/9 "2010-04-20T13:14:50Z")

</div>

There is a kbitDown number and latency number. One is not the other. Obviously this is about re-inventing a way to do Dynamic Streaming, because you said yesterday that you don’t think the QoS metrics built-in to Flash using the NetStream.info object are adequate. I really don’t agree with that premise. I suggest you backup and take a better look at NetStream.info object. Here is another Adobe article:

[http://www.adobe.com/devnet/flashmediaserver/articles/dynstream\_actionscript.html](http://www.adobe.com/devnet/flashmediaserver/articles/dynstream_actionscript.html)

Richard

---

<div class="post-metadata">

**Author:** ![Richard\_Lanham](https://avatars.discourse-cdn.com/v4/letter/r/c68b51/32.png) [@Richard\_Lanham](https://community.wowza.com/u/Richard_Lanham)\
**Post date:** [April 20, 2010, 4:10pm UTC](https://community.wowza.com/t/dynamic-bandwidth-detection-bwcheck/31/10 "2010-04-20T16:10:02Z")

</div>

```auto
You must have had someone else in mind when sending this message, Richard.

```

Oh, whoops, sorry about that. Please excuse me.

Yes, it is in seconds: kbs = kilobits per second. I think the forumula would be:

Latency + fileSize in kilobits / kbitdown

Richard

---

<div class="post-metadata">

**Author:** ![Richard\_Lanham](https://avatars.discourse-cdn.com/v4/letter/r/c68b51/32.png) [@Richard\_Lanham](https://community.wowza.com/u/Richard_Lanham)\
**Post date:** [April 20, 2010, 6:17pm UTC](https://community.wowza.com/t/dynamic-bandwidth-detection-bwcheck/31/11 "2010-04-20T18:17:43Z")

</div>

I think it is 1024.

Richard

---

<div class="post-metadata">

**Author:** ![Richard\_Lanham](https://avatars.discourse-cdn.com/v4/letter/r/c68b51/32.png) [@Richard\_Lanham](https://community.wowza.com/u/Richard_Lanham)\
**Post date:** [April 20, 2010, 6:38pm UTC](https://community.wowza.com/t/dynamic-bandwidth-detection-bwcheck/31/12 "2010-04-20T18:38:32Z")

</div>

But seems like video duration is all you really need. That could be different than your calculations, because Wowza throttles delivery to bitrate.

You can get duration in the metadata in the NetStream NetStatusEvent handler, or more directly by doing:

netconnection.call("getStreamLength, responderName,“example.flv”);

Richard

---

<div class="post-metadata">

**Author:** ![Richard\_Lanham](https://avatars.discourse-cdn.com/v4/letter/r/c68b51/32.png) [@Richard\_Lanham](https://community.wowza.com/u/Richard_Lanham)\
**Post date:** [May 2, 2010, 12:44pm UTC](https://community.wowza.com/t/dynamic-bandwidth-detection-bwcheck/31/13 "2010-05-02T12:44:55Z")

</div>

You could fake one, but the result set is returned all at once.

Richard

---

<div class="post-metadata">

**Author:** ![Richard\_Lanham](https://avatars.discourse-cdn.com/v4/letter/r/c68b51/32.png) [@Richard\_Lanham](https://community.wowza.com/u/Richard_Lanham)\
**Post date:** [May 2, 2010, 8:18pm UTC](https://community.wowza.com/t/dynamic-bandwidth-detection-bwcheck/31/14 "2010-05-02T20:18:43Z")

</div>

By result set, I mean the bandwidth numbers that are received by onBWDone. I don’t know how to do what you want exactly. I would just fake it, i.e, start up your display when bandwidth checking starts, increment the progress bar until the onBWDone function receives the result set, then have it go to 100% and disappear. The real purpose of a progress bar in this case is providing feedback to the user that something is happening. It doesn’t have to measure the progress accurately to do that.

Richard

---

<div class="post-metadata">

**Author:** ![Richard\_Lanham](https://avatars.discourse-cdn.com/v4/letter/r/c68b51/32.png) [@Richard\_Lanham](https://community.wowza.com/u/Richard_Lanham)\
**Post date:** [May 2, 2010, 8:40pm UTC](https://community.wowza.com/t/dynamic-bandwidth-detection-bwcheck/31/15 "2010-05-02T20:40:00Z")

</div>

Also, the “progress” is mostly on the server, so it’s not exactly available client-side the way you are thinking about it. But I suppose you could react to onBWcheck being triggered, and onBWdone gets called once prior to getting the final result. So the progress bar could key off that and increment in thirds. Something like that.

Richard

---

<div class="post-metadata">

**Author:** ![Richard\_Lanham](https://avatars.discourse-cdn.com/v4/letter/r/c68b51/32.png) [@Richard\_Lanham](https://community.wowza.com/u/Richard_Lanham)\
**Post date:** [May 18, 2010, 3:19am UTC](https://community.wowza.com/t/dynamic-bandwidth-detection-bwcheck/31/16 "2010-05-18T03:19:53Z")

</div>

Just setup BWCheck in your application following the guide in the top of this thread. You add a jar file to the Wowza lib folder, and add a Module to the Application.xml. Then the code that handles BWCheck in the player will work.

Richard

---

<div class="post-metadata">

**Author:** ![Richard\_Lanham](https://avatars.discourse-cdn.com/v4/letter/r/c68b51/32.png) [@Richard\_Lanham](https://community.wowza.com/u/Richard_Lanham)\
**Post date:** [May 30, 2010, 1:33pm UTC](https://community.wowza.com/t/dynamic-bandwidth-detection-bwcheck/31/17 "2010-05-30T13:33:02Z")

</div>

Install the Developer edition and the examples folder will be there.

[http://wowza.com/store.htm](http://wowza.com/store.htm)

Richard

---

<div class="post-metadata">

**Author:** ![Richard\_Lanham](https://avatars.discourse-cdn.com/v4/letter/r/c68b51/32.png) [@Richard\_Lanham](https://community.wowza.com/u/Richard_Lanham)\
**Post date:** [June 10, 2010, 1:55pm UTC](https://community.wowza.com/t/dynamic-bandwidth-detection-bwcheck/31/18 "2010-06-10T13:55:55Z")

</div>

There is a pre-built version of this module you can download from the first post in this thread, so you don’t need to build this code in the IDE.

JW Player’s dynamic streaming does use the BWCheck if it is present, and it is good idea to have it, it will work better. It does this at connection time only to decide which level to start with, then uses other methods (NetStream.info object/QoS metrics) during the streaming session to change levels.

> As I understood it, Wowza accepted a single file in, and then would re-encode it on the fly for connections of lower bandwidth

No, this does not happen. Wowza does no transcoding. You need multiple versions of a video or live stream to do this. (I’m curious what you read that gave you that understanding?)

Each version of video or live stream has to be keyframe and timecode aligned. FMLE is known to do this for live streams.

Richard

---

<div class="post-metadata">

**Author:** ![Richard\_Lanham](https://avatars.discourse-cdn.com/v4/letter/r/c68b51/32.png) [@Richard\_Lanham](https://community.wowza.com/u/Richard_Lanham)\
**Post date:** [June 10, 2010, 3:11pm UTC](https://community.wowza.com/t/dynamic-bandwidth-detection-bwcheck/31/19 "2010-06-10T15:11:17Z")

</div>

Yes, do follow the JW Player dynamic streaming tutorial. It’s a client-side solution. The only server-side aspect is the BWCheck module and the stream variations.

You can use remap a stream in an application module or use StreamNameAlias possibly to help with your use case:

Override play remap stream name

[https://www.wowza.com/forums/showthread.php?t=6876](https://www.wowza.com/forums/showthread.php?t=6876)

StreamNameAlias

[http://community.wowza.com/t/-/47](http://community.wowza.com/t/-/47)

We’ve been testing Expression encoder recently and it seems to be producing correctly aligned versions.

Richard

---

<div class="post-metadata">

**Author:** ![Richard\_Lanham](https://avatars.discourse-cdn.com/v4/letter/r/c68b51/32.png) [@Richard\_Lanham](https://community.wowza.com/u/Richard_Lanham)\
**Post date:** [June 14, 2010, 2:17am UTC](https://community.wowza.com/t/dynamic-bandwidth-detection-bwcheck/31/20 "2010-06-14T02:17:45Z")

</div>

The BWCheck works with Flowplayer. It works with that example and they have simpler version that just does the connection time BWCheck.

Richard

[Next page](https://community.wowza.com/t/dynamic-bandwidth-detection-bwcheck/31.md?page=2)
