Add values for delivered segment bitrate
When a segment begins arriving, record its bitrate. Add a second y-axis to the timeline and plot segment bitrates on it.
Showing
1 changed file
with
56 additions
and
18 deletions
... | @@ -84,7 +84,11 @@ | ... | @@ -84,7 +84,11 @@ |
84 | 84 | ||
85 | // run the simulation | 85 | // run the simulation |
86 | runSimulation = function(options, done) { | 86 | runSimulation = function(options, done) { |
87 | var results = [], | 87 | var results = { |
88 | bandwidth: [], | ||
89 | playlists: [], | ||
90 | options: options | ||
91 | }, | ||
88 | bandwidths = options.bandwidths, | 92 | bandwidths = options.bandwidths, |
89 | fixture = document.getElementById('fixture'), | 93 | fixture = document.getElementById('fixture'), |
90 | 94 | ||
... | @@ -101,7 +105,6 @@ | ... | @@ -101,7 +105,6 @@ |
101 | player.dispose(); | 105 | player.dispose(); |
102 | }; | 106 | }; |
103 | 107 | ||
104 | |||
105 | // mock out the environment | 108 | // mock out the environment |
106 | clock = sinon.useFakeTimers(); | 109 | clock = sinon.useFakeTimers(); |
107 | fakeXhr = sinon.useFakeXMLHttpRequest(); | 110 | fakeXhr = sinon.useFakeXMLHttpRequest(); |
... | @@ -159,7 +162,7 @@ | ... | @@ -159,7 +162,7 @@ |
159 | while (bandwidths[i + 1] && bandwidths[i + 1].time <= t) { | 162 | while (bandwidths[i + 1] && bandwidths[i + 1].time <= t) { |
160 | i++; | 163 | i++; |
161 | } | 164 | } |
162 | results.push({ | 165 | results.bandwidth.push({ |
163 | time: t, | 166 | time: t, |
164 | bandwidth: bandwidths[i].bandwidth | 167 | bandwidth: bandwidths[i].bandwidth |
165 | }); | 168 | }); |
... | @@ -168,11 +171,10 @@ | ... | @@ -168,11 +171,10 @@ |
168 | requests = requests.reduce(function(remaining, request) { | 171 | requests = requests.reduce(function(remaining, request) { |
169 | var arrival = request.startTime + propagationDelay, | 172 | var arrival = request.startTime + propagationDelay, |
170 | delivered = Math.max(0, bandwidths[i].bandwidth * (t - arrival)), | 173 | delivered = Math.max(0, bandwidths[i].bandwidth * (t - arrival)), |
171 | playlist = /playlist-\d+$/.test(request.url), | ||
172 | segmentSize = +request.url.match(/(\d+)-\d+$/)[1] * segmentDuration; | 174 | segmentSize = +request.url.match(/(\d+)-\d+$/)[1] * segmentDuration; |
173 | 175 | ||
174 | // playlist responses | 176 | // playlist responses |
175 | if (playlist) { | 177 | if (/playlist-\d+$/.test(request.url)) { |
176 | // playlist responses have no trasmission time | 178 | // playlist responses have no trasmission time |
177 | if (t === arrival) { | 179 | if (t === arrival) { |
178 | request.respond(200, null, playlistResponse(+requests[0].url.match(/\d+$/))); | 180 | request.respond(200, null, playlistResponse(+requests[0].url.match(/\d+$/))); |
... | @@ -194,6 +196,11 @@ | ... | @@ -194,6 +196,11 @@ |
194 | } else { | 196 | } else { |
195 | if (t === arrival) { | 197 | if (t === arrival) { |
196 | // segment response headers arrive after the propogation delay | 198 | // segment response headers arrive after the propogation delay |
199 | |||
200 | results.playlists.push({ | ||
201 | time: t, | ||
202 | bitrate: +request.url.match(/(\d+)-\d+$/)[1] | ||
203 | }); | ||
197 | request.setResponseHeaders({ | 204 | request.setResponseHeaders({ |
198 | 'Content-Type': 'video/mp2t' | 205 | 'Content-Type': 'video/mp2t' |
199 | }); | 206 | }); |
... | @@ -244,39 +251,43 @@ | ... | @@ -244,39 +251,43 @@ |
244 | .append('g') | 251 | .append('g') |
245 | .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); | 252 | .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); |
246 | 253 | ||
247 | displayTimeline = function(error, bandwidth) { | 254 | displayTimeline = function(error, data) { |
248 | var x = d3.scale.linear().range([0, width]), | 255 | var x = d3.scale.linear().range([0, width]), |
249 | y = d3.scale.linear().range([height, 0]), | 256 | y0 = d3.scale.linear().range([height, 0]), |
257 | y1 = d3.scale.ordinal().rangeRoundBands([height, 0], 0.1), | ||
250 | 258 | ||
251 | xAxis = d3.svg.axis().scale(x).orient('bottom'), | 259 | timeAxis = d3.svg.axis().scale(x).orient('bottom'), |
252 | yAxis = d3.svg.axis().scale(y).orient('left'), | 260 | bandwidthAxis = d3.svg.axis().scale(y0).orient('left'), |
261 | segmentBitrateAxis = d3.svg.axis().scale(y1).orient('right'), | ||
253 | 262 | ||
254 | line = d3.svg.line() | 263 | bandwidthLine = d3.svg.line() |
255 | .interpolate('basis') | 264 | .interpolate('basis') |
256 | .x(function(data) { | 265 | .x(function(data) { |
257 | return x(data.time); | 266 | return x(data.time); |
258 | }) | 267 | }) |
259 | .y(function(data) { | 268 | .y(function(data) { |
260 | return y(data.bandwidth); | 269 | return y0(data.bandwidth); |
261 | }); | 270 | }); |
262 | 271 | ||
263 | x.domain(d3.extent(bandwidth, function(data) { | 272 | x.domain(d3.extent(data.bandwidth, function(data) { |
264 | return data.time; | 273 | return data.time; |
265 | })); | 274 | })); |
266 | y.domain([0, d3.max(bandwidth, function(data) { | 275 | y0.domain([0, d3.max(data.bandwidth, function(data) { |
267 | return data.bandwidth; | 276 | return data.bandwidth; |
268 | })]); | 277 | })]); |
278 | y1.domain(data.options.playlists); | ||
269 | 279 | ||
270 | // draw the new timeline | 280 | // time axis |
271 | svg.selectAll('.axis').remove(); | 281 | svg.selectAll('.axis').remove(); |
272 | svg.append('g') | 282 | svg.append('g') |
273 | .attr('class', 'x axis') | 283 | .attr('class', 'x axis') |
274 | .attr('transform', 'translate(0,' + height + ')') | 284 | .attr('transform', 'translate(0,' + height + ')') |
275 | .call(xAxis); | 285 | .call(timeAxis); |
276 | 286 | ||
287 | // bandwidth axis | ||
277 | svg.append('g') | 288 | svg.append('g') |
278 | .attr('class', 'y axis') | 289 | .attr('class', 'y axis') |
279 | .call(yAxis) | 290 | .call(bandwidthAxis) |
280 | .append('text') | 291 | .append('text') |
281 | .attr('transform', 'rotate(-90)') | 292 | .attr('transform', 'rotate(-90)') |
282 | .attr('y', 6) | 293 | .attr('y', 6) |
... | @@ -284,11 +295,38 @@ | ... | @@ -284,11 +295,38 @@ |
284 | .style('text-anchor', 'end') | 295 | .style('text-anchor', 'end') |
285 | .text('Bandwidth (b/s)'); | 296 | .text('Bandwidth (b/s)'); |
286 | 297 | ||
298 | // segment bitrate axis | ||
299 | svg.append('g') | ||
300 | .attr('class', 'y axis') | ||
301 | .attr('transform', 'translate(' + width + ', 0)') | ||
302 | .call(segmentBitrateAxis) | ||
303 | .append('text') | ||
304 | .attr('transform', 'rotate(-90)') | ||
305 | .attr('y', 6) | ||
306 | .attr('dy', '-.71em') | ||
307 | .style('text-anchor', 'end') | ||
308 | .text('Bitrate (b/s)'); | ||
309 | |||
310 | // bandwidth line | ||
287 | svg.selectAll('.bandwidth').remove(); | 311 | svg.selectAll('.bandwidth').remove(); |
288 | svg.append('path') | 312 | svg.append('path') |
289 | .datum(bandwidth) | 313 | .datum(data.bandwidth) |
290 | .attr('class', 'line bandwidth') | 314 | .attr('class', 'line bandwidth') |
291 | .attr('d', line); | 315 | .attr('d', bandwidthLine); |
316 | |||
317 | // segment bitrate dots | ||
318 | svg.selectAll('.segment-bitrate').remove(); | ||
319 | svg.selectAll('.segment-bitrate') | ||
320 | .data(data.playlists) | ||
321 | .enter().append('circle') | ||
322 | .attr('class', 'dot segment-bitrate') | ||
323 | .attr('r', 3.5) | ||
324 | .attr('cx', function(playlist) { | ||
325 | return x(playlist.time); | ||
326 | }) | ||
327 | .attr('cy', function(playlist) { | ||
328 | return y1(playlist.bitrate) + (y1.rangeBand() / 2); | ||
329 | }); | ||
292 | }; | 330 | }; |
293 | })(); | 331 | })(); |
294 | 332 | ... | ... |
-
Please register or sign in to post a comment