b5e60aba by jrivera

Fix whitespace - tabs to spaces!

1 parent 2db4b64c
...@@ -87,378 +87,378 @@ const updateSegments = function(original, update, offset) { ...@@ -87,378 +87,378 @@ const updateSegments = function(original, update, offset) {
87 87
88 export default class PlaylistLoader extends Stream { 88 export default class PlaylistLoader extends Stream {
89 constructor(srcUrl, withCredentials) { 89 constructor(srcUrl, withCredentials) {
90 super(); 90 super();
91 let loader = this; 91 let loader = this;
92 let dispose; 92 let dispose;
93 let mediaUpdateTimeout; 93 let mediaUpdateTimeout;
94 let request; 94 let request;
95 let playlistRequestError; 95 let playlistRequestError;
96 let haveMetadata; 96 let haveMetadata;
97 97
98 // a flag that disables "expired time"-tracking this setting has 98 // a flag that disables "expired time"-tracking this setting has
99 // no effect when not playing a live stream 99 // no effect when not playing a live stream
100 this.trackExpiredTime_ = false; 100 this.trackExpiredTime_ = false;
101 101
102 if (!srcUrl) { 102 if (!srcUrl) {
103 throw new Error('A non-empty playlist URL is required'); 103 throw new Error('A non-empty playlist URL is required');
104 } 104 }
105 105
106 playlistRequestError = function(xhr, url, startingState) { 106 playlistRequestError = function(xhr, url, startingState) {
107 loader.setBandwidth(request || xhr); 107 loader.setBandwidth(request || xhr);
108 108
109 // any in-flight request is now finished 109 // any in-flight request is now finished
110 request = null; 110 request = null;
111 111
112 if (startingState) { 112 if (startingState) {
113 loader.state = startingState; 113 loader.state = startingState;
114 } 114 }
115 115
116 loader.error = { 116 loader.error = {
117 playlist: loader.master.playlists[url], 117 playlist: loader.master.playlists[url],
118 status: xhr.status, 118 status: xhr.status,
119 message: 'HLS playlist request error at URL: ' + url, 119 message: 'HLS playlist request error at URL: ' + url,
120 responseText: xhr.responseText, 120 responseText: xhr.responseText,
121 code: (xhr.status >= 500) ? 4 : 2 121 code: (xhr.status >= 500) ? 4 : 2
122 }; 122 };
123 loader.trigger('error'); 123 loader.trigger('error');
124 }; 124 };
125 125
126 // update the playlist loader's state in response to a new or 126 // update the playlist loader's state in response to a new or
127 // updated playlist. 127 // updated playlist.
128 128
129 haveMetadata = function(xhr, url) { 129 haveMetadata = function(xhr, url) {
130 let parser; 130 let parser;
131 let refreshDelay; 131 let refreshDelay;
132 let update; 132 let update;
133 133
134 loader.setBandwidth(request || xhr); 134 loader.setBandwidth(request || xhr);
135 135
136 // any in-flight request is now finished 136 // any in-flight request is now finished
137 request = null; 137 request = null;
138 loader.state = 'HAVE_METADATA'; 138 loader.state = 'HAVE_METADATA';
139 139
140 parser = new m3u8.Parser(); 140 parser = new m3u8.Parser();
141 parser.push(xhr.responseText); 141 parser.push(xhr.responseText);
142 parser.end(); 142 parser.end();
143 parser.manifest.uri = url; 143 parser.manifest.uri = url;
144 144
145 // merge this playlist into the master 145 // merge this playlist into the master
146 update = updateMaster(loader.master, parser.manifest); 146 update = updateMaster(loader.master, parser.manifest);
147 refreshDelay = (parser.manifest.targetDuration || 10) * 1000; 147 refreshDelay = (parser.manifest.targetDuration || 10) * 1000;
148 if (update) { 148 if (update) {
149 loader.master = update; 149 loader.master = update;
150 loader.updateMediaPlaylist_(parser.manifest); 150 loader.updateMediaPlaylist_(parser.manifest);
151 } else { 151 } else {
152 // if the playlist is unchanged since the last reload, 152 // if the playlist is unchanged since the last reload,
153 // try again after half the target duration 153 // try again after half the target duration
154 refreshDelay /= 2; 154 refreshDelay /= 2;
155 } 155 }
156 156
157 // refresh live playlists after a target duration passes 157 // refresh live playlists after a target duration passes
158 if (!loader.media().endList) { 158 if (!loader.media().endList) {
159 window.clearTimeout(mediaUpdateTimeout); 159 window.clearTimeout(mediaUpdateTimeout);
160 mediaUpdateTimeout = window.setTimeout(function() { 160 mediaUpdateTimeout = window.setTimeout(function() {
161 loader.trigger('mediaupdatetimeout'); 161 loader.trigger('mediaupdatetimeout');
162 }, refreshDelay); 162 }, refreshDelay);
163 } 163 }
164 164
165 loader.trigger('loadedplaylist'); 165 loader.trigger('loadedplaylist');
166 }; 166 };
167 167
168 // initialize the loader state 168 // initialize the loader state
169 loader.state = 'HAVE_NOTHING'; 169 loader.state = 'HAVE_NOTHING';
170 170
171 // track the time that has expired from the live window 171 // track the time that has expired from the live window
172 // this allows the seekable start range to be calculated even if 172 // this allows the seekable start range to be calculated even if
173 // all segments with timing information have expired 173 // all segments with timing information have expired
174 this.expired_ = 0; 174 this.expired_ = 0;
175 175
176 // capture the prototype dispose function 176 // capture the prototype dispose function
177 dispose = this.dispose; 177 dispose = this.dispose;
178 178
179 /** 179 /**
180 * Abort any outstanding work and clean up. 180 * Abort any outstanding work and clean up.
181 */ 181 */
182 loader.dispose = function() { 182 loader.dispose = function() {
183 if (request) { 183 if (request) {
184 request.onreadystatechange = null; 184 request.onreadystatechange = null;
185 request.abort(); 185 request.abort();
186 request = null; 186 request = null;
187 } 187 }
188 window.clearTimeout(mediaUpdateTimeout); 188 window.clearTimeout(mediaUpdateTimeout);
189 dispose.call(this); 189 dispose.call(this);
190 }; 190 };
191 191
192 /** 192 /**
193 * When called without any arguments, returns the currently 193 * When called without any arguments, returns the currently
194 * active media playlist. When called with a single argument, 194 * active media playlist. When called with a single argument,
195 * triggers the playlist loader to asynchronously switch to the 195 * triggers the playlist loader to asynchronously switch to the
196 * specified media playlist. Calling this method while the 196 * specified media playlist. Calling this method while the
197 * loader is in the HAVE_NOTHING causes an error to be emitted 197 * loader is in the HAVE_NOTHING causes an error to be emitted
198 * but otherwise has no effect. 198 * but otherwise has no effect.
199 * @param playlist (optional) {object} the parsed media playlist 199 * @param playlist (optional) {object} the parsed media playlist
200 * object to switch to 200 * object to switch to
201 */ 201 */
202 loader.media = function(playlist) { 202 loader.media = function(playlist) {
203 let startingState = loader.state; 203 let startingState = loader.state;
204 let mediaChange; 204 let mediaChange;
205 // getter 205 // getter
206 if (!playlist) { 206 if (!playlist) {
207 return loader.media_; 207 return loader.media_;
208 } 208 }
209 209
210 // setter 210 // setter
211 if (loader.state === 'HAVE_NOTHING') { 211 if (loader.state === 'HAVE_NOTHING') {
212 throw new Error('Cannot switch media playlist from ' + loader.state); 212 throw new Error('Cannot switch media playlist from ' + loader.state);
213 } 213 }
214 214
215 // find the playlist object if the target playlist has been 215 // find the playlist object if the target playlist has been
216 // specified by URI 216 // specified by URI
217 if (typeof playlist === 'string') { 217 if (typeof playlist === 'string') {
218 if (!loader.master.playlists[playlist]) { 218 if (!loader.master.playlists[playlist]) {
219 throw new Error('Unknown playlist URI: ' + playlist); 219 throw new Error('Unknown playlist URI: ' + playlist);
220 } 220 }
221 playlist = loader.master.playlists[playlist]; 221 playlist = loader.master.playlists[playlist];
222 } 222 }
223 223
224 mediaChange = !loader.media_ || playlist.uri !== loader.media_.uri; 224 mediaChange = !loader.media_ || playlist.uri !== loader.media_.uri;
225 225
226 // switch to fully loaded playlists immediately 226 // switch to fully loaded playlists immediately
227 if (loader.master.playlists[playlist.uri].endList) { 227 if (loader.master.playlists[playlist.uri].endList) {
228 // abort outstanding playlist requests 228 // abort outstanding playlist requests
229 if (request) { 229 if (request) {
230 request.onreadystatechange = null; 230 request.onreadystatechange = null;
231 request.abort(); 231 request.abort();
232 request = null; 232 request = null;
233 } 233 }
234 loader.state = 'HAVE_METADATA'; 234 loader.state = 'HAVE_METADATA';
235 loader.media_ = playlist; 235 loader.media_ = playlist;
236 236
237 // trigger media change if the active media has been updated 237 // trigger media change if the active media has been updated
238 if (mediaChange) { 238 if (mediaChange) {
239 loader.trigger('mediachange'); 239 loader.trigger('mediachange');
240 } 240 }
241 return; 241 return;
242 } 242 }
243 243
244 // switching to the active playlist is a no-op 244 // switching to the active playlist is a no-op
245 if (!mediaChange) { 245 if (!mediaChange) {
246 return; 246 return;
247 } 247 }
248 248
249 loader.state = 'SWITCHING_MEDIA'; 249 loader.state = 'SWITCHING_MEDIA';
250 250
251 // there is already an outstanding playlist request 251 // there is already an outstanding playlist request
252 if (request) { 252 if (request) {
253 if (resolveUrl(loader.master.uri, playlist.uri) === request.url) { 253 if (resolveUrl(loader.master.uri, playlist.uri) === request.url) {
254 // requesting to switch to the same playlist multiple times 254 // requesting to switch to the same playlist multiple times
255 // has no effect after the first 255 // has no effect after the first
256 return; 256 return;
257 } 257 }
258 request.onreadystatechange = null; 258 request.onreadystatechange = null;
259 request.abort(); 259 request.abort();
260 request = null; 260 request = null;
261 } 261 }
262 262
263 // request the new playlist 263 // request the new playlist
264 request = XhrModule({ 264 request = XhrModule({
265 uri: resolveUrl(loader.master.uri, playlist.uri), 265 uri: resolveUrl(loader.master.uri, playlist.uri),
266 withCredentials 266 withCredentials
267 }, function(error, request) { 267 }, function(error, request) {
268 if (error) { 268 if (error) {
269 return playlistRequestError(request, playlist.uri, startingState); 269 return playlistRequestError(request, playlist.uri, startingState);
270 } 270 }
271 271
272 haveMetadata(request, playlist.uri); 272 haveMetadata(request, playlist.uri);
273 273
274 // fire loadedmetadata the first time a media playlist is loaded 274 // fire loadedmetadata the first time a media playlist is loaded
275 if (startingState === 'HAVE_MASTER') { 275 if (startingState === 'HAVE_MASTER') {
276 loader.trigger('loadedmetadata'); 276 loader.trigger('loadedmetadata');
277 } else { 277 } else {
278 loader.trigger('mediachange'); 278 loader.trigger('mediachange');
279 } 279 }
280 }); 280 });
281 }; 281 };
282 282
283 loader.setBandwidth = function(xhr) { 283 loader.setBandwidth = function(xhr) {
284 loader.bandwidth = xhr.bandwidth; 284 loader.bandwidth = xhr.bandwidth;
285 }; 285 };
286 286
287 // In a live list, don't keep track of the expired time until 287 // In a live list, don't keep track of the expired time until
288 // HLS tells us that "first play" has commenced 288 // HLS tells us that "first play" has commenced
289 loader.on('firstplay', function() { 289 loader.on('firstplay', function() {
290 this.trackExpiredTime_ = true; 290 this.trackExpiredTime_ = true;
291 }); 291 });
292 292
293 // live playlist staleness timeout 293 // live playlist staleness timeout
294 loader.on('mediaupdatetimeout', function() { 294 loader.on('mediaupdatetimeout', function() {
295 if (loader.state !== 'HAVE_METADATA') { 295 if (loader.state !== 'HAVE_METADATA') {
296 // only refresh the media playlist if no other activity is going on 296 // only refresh the media playlist if no other activity is going on
297 return; 297 return;
298 } 298 }
299 299
300 loader.state = 'HAVE_CURRENT_METADATA'; 300 loader.state = 'HAVE_CURRENT_METADATA';
301 request = XhrModule({ 301 request = XhrModule({
302 uri: resolveUrl(loader.master.uri, loader.media().uri), 302 uri: resolveUrl(loader.master.uri, loader.media().uri),
303 withCredentials 303 withCredentials
304 }, function(error, request) { 304 }, function(error, request) {
305 if (error) { 305 if (error) {
306 return playlistRequestError(request, loader.media().uri); 306 return playlistRequestError(request, loader.media().uri);
307 } 307 }
308 haveMetadata(request, loader.media().uri); 308 haveMetadata(request, loader.media().uri);
309 }); 309 });
310 }); 310 });
311 311
312 // request the specified URL 312 // request the specified URL
313 request = XhrModule({ 313 request = XhrModule({
314 uri: srcUrl, 314 uri: srcUrl,
315 withCredentials 315 withCredentials
316 }, function(error, req) { 316 }, function(error, req) {
317 let parser; 317 let parser;
318 let i; 318 let i;
319 319
320 // clear the loader's request reference 320 // clear the loader's request reference
321 request = null; 321 request = null;
322 322
323 if (error) { 323 if (error) {
324 loader.error = { 324 loader.error = {
325 status: req.status, 325 status: req.status,
326 message: 'HLS playlist request error at URL: ' + srcUrl, 326 message: 'HLS playlist request error at URL: ' + srcUrl,
327 responseText: req.responseText, 327 responseText: req.responseText,
328 // MEDIA_ERR_NETWORK 328 // MEDIA_ERR_NETWORK
329 code: 2 329 code: 2
330 }; 330 };
331 return loader.trigger('error'); 331 return loader.trigger('error');
332 } 332 }
333 333
334 parser = new m3u8.Parser(); 334 parser = new m3u8.Parser();
335 parser.push(req.responseText); 335 parser.push(req.responseText);
336 parser.end(); 336 parser.end();
337 337
338 loader.state = 'HAVE_MASTER'; 338 loader.state = 'HAVE_MASTER';
339 339
340 parser.manifest.uri = srcUrl; 340 parser.manifest.uri = srcUrl;
341 341
342 // loaded a master playlist 342 // loaded a master playlist
343 if (parser.manifest.playlists) { 343 if (parser.manifest.playlists) {
344 loader.master = parser.manifest; 344 loader.master = parser.manifest;
345 345
346 // setup by-URI lookups 346 // setup by-URI lookups
347 i = loader.master.playlists.length; 347 i = loader.master.playlists.length;
348 while (i--) { 348 while (i--) {
349 loader.master.playlists[loader.master.playlists[i].uri] = loader.master.playlists[i]; 349 loader.master.playlists[loader.master.playlists[i].uri] = loader.master.playlists[i];
350 } 350 }
351 351
352 loader.trigger('loadedplaylist'); 352 loader.trigger('loadedplaylist');
353 if (!request) { 353 if (!request) {
354 // no media playlist was specifically selected so start 354 // no media playlist was specifically selected so start
355 // from the first listed one 355 // from the first listed one
356 loader.media(parser.manifest.playlists[0]); 356 loader.media(parser.manifest.playlists[0]);
357 } 357 }
358 return; 358 return;
359 } 359 }
360 360
361 // loaded a media playlist 361 // loaded a media playlist
362 // infer a master playlist if none was previously requested 362 // infer a master playlist if none was previously requested
363 loader.master = { 363 loader.master = {
364 uri: window.location.href, 364 uri: window.location.href,
365 playlists: [{ 365 playlists: [{
366 uri: srcUrl 366 uri: srcUrl
367 }] 367 }]
368 }; 368 };
369 loader.master.playlists[srcUrl] = loader.master.playlists[0]; 369 loader.master.playlists[srcUrl] = loader.master.playlists[0];
370 haveMetadata(req, srcUrl); 370 haveMetadata(req, srcUrl);
371 return loader.trigger('loadedmetadata'); 371 return loader.trigger('loadedmetadata');
372 }); 372 });
373 } 373 }
374 /** 374 /**
375 * Update the PlaylistLoader state to reflect the changes in an 375 * Update the PlaylistLoader state to reflect the changes in an
376 * update to the current media playlist. 376 * update to the current media playlist.
377 * @param update {object} the updated media playlist object 377 * @param update {object} the updated media playlist object
378 */ 378 */
379 updateMediaPlaylist_(update) { 379 updateMediaPlaylist_(update) {
380 let outdated; 380 let outdated;
381 let i; 381 let i;
382 let segment; 382 let segment;
383 383
384 outdated = this.media_; 384 outdated = this.media_;
385 this.media_ = this.master.playlists[update.uri]; 385 this.media_ = this.master.playlists[update.uri];
386 386
387 if (!outdated) { 387 if (!outdated) {
388 return; 388 return;
389 } 389 }
390 390
391 // don't track expired time until this flag is truthy 391 // don't track expired time until this flag is truthy
392 if (!this.trackExpiredTime_) { 392 if (!this.trackExpiredTime_) {
393 return; 393 return;
394 } 394 }
395 395
396 // if the update was the result of a rendition switch do not 396 // if the update was the result of a rendition switch do not
397 // attempt to calculate expired_ since media-sequences need not 397 // attempt to calculate expired_ since media-sequences need not
398 // correlate between renditions/variants 398 // correlate between renditions/variants
399 if (update.uri !== outdated.uri) { 399 if (update.uri !== outdated.uri) {
400 return; 400 return;
401 } 401 }
402 402
403 // try using precise timing from first segment of the updated 403 // try using precise timing from first segment of the updated
404 // playlist 404 // playlist
405 if (update.segments.length) { 405 if (update.segments.length) {
406 if (update.segments[0].start !== undefined) { 406 if (update.segments[0].start !== undefined) {
407 this.expired_ = update.segments[0].start; 407 this.expired_ = update.segments[0].start;
408 return; 408 return;
409 } else if (update.segments[0].end !== undefined) { 409 } else if (update.segments[0].end !== undefined) {
410 this.expired_ = update.segments[0].end - update.segments[0].duration; 410 this.expired_ = update.segments[0].end - update.segments[0].duration;
411 return; 411 return;
412 } 412 }
413 } 413 }
414 414
415 // calculate expired by walking the outdated playlist 415 // calculate expired by walking the outdated playlist
416 i = update.mediaSequence - outdated.mediaSequence - 1; 416 i = update.mediaSequence - outdated.mediaSequence - 1;
417 417
418 for (; i >= 0; i--) { 418 for (; i >= 0; i--) {
419 segment = outdated.segments[i]; 419 segment = outdated.segments[i];
420 420
421 if (!segment) { 421 if (!segment) {
422 // we missed information on this segment completely between 422 // we missed information on this segment completely between
423 // playlist updates so we'll have to take an educated guess 423 // playlist updates so we'll have to take an educated guess
424 // once we begin buffering again, any error we introduce can 424 // once we begin buffering again, any error we introduce can
425 // be corrected 425 // be corrected
426 this.expired_ += outdated.targetDuration || 10; 426 this.expired_ += outdated.targetDuration || 10;
427 continue; 427 continue;
428 } 428 }
429 429
430 if (segment.end !== undefined) { 430 if (segment.end !== undefined) {
431 this.expired_ = segment.end; 431 this.expired_ = segment.end;
432 return; 432 return;
433 } 433 }
434 if (segment.start !== undefined) { 434 if (segment.start !== undefined) {
435 this.expired_ = segment.start + segment.duration; 435 this.expired_ = segment.start + segment.duration;
436 return; 436 return;
437 } 437 }
438 this.expired_ += segment.duration; 438 this.expired_ += segment.duration;
439 } 439 }
440 } 440 }
441 441
442 /** 442 /**
443 * Determine the index of the segment that contains a specified 443 * Determine the index of the segment that contains a specified
444 * playback position in the current media playlist. Early versions 444 * playback position in the current media playlist. Early versions
445 * of the HLS specification require segment durations to be rounded 445 * of the HLS specification require segment durations to be rounded
446 * to the nearest integer which means it may not be possible to 446 * to the nearest integer which means it may not be possible to
447 * determine the correct segment for a playback position if that 447 * determine the correct segment for a playback position if that
448 * position is within .5 seconds of the segment duration. This 448 * position is within .5 seconds of the segment duration. This
449 * function will always return the lower of the two possible indices 449 * function will always return the lower of the two possible indices
450 * in those cases. 450 * in those cases.
451 * 451 *
452 * @param time {number} The number of seconds since the earliest 452 * @param time {number} The number of seconds since the earliest
453 * possible position to determine the containing segment for 453 * possible position to determine the containing segment for
454 * @returns {number} The number of the media segment that contains 454 * @returns {number} The number of the media segment that contains
455 * that time position. If the specified playback position is outside 455 * that time position. If the specified playback position is outside
456 * the time range of the current set of media segments, the return 456 * the time range of the current set of media segments, the return
457 * value will be clamped to the index of the segment containing the 457 * value will be clamped to the index of the segment containing the
458 * closest playback position that is currently available. 458 * closest playback position that is currently available.
459 */ 459 */
460 getMediaIndexForTime_(time) { 460 getMediaIndexForTime_(time) {
461 let i; 461 let i;
462 let segment; 462 let segment;
463 let originalTime = time; 463 let originalTime = time;
464 let numSegments = this.media_.segments.length; 464 let numSegments = this.media_.segments.length;
...@@ -468,99 +468,99 @@ export default class PlaylistLoader extends Stream { ...@@ -468,99 +468,99 @@ export default class PlaylistLoader extends Stream {
468 let knownStart; 468 let knownStart;
469 let knownEnd; 469 let knownEnd;
470 470
471 if (!this.media_) { 471 if (!this.media_) {
472 return 0; 472 return 0;
473 } 473 }
474 474
475 // when the requested position is earlier than the current set of 475 // when the requested position is earlier than the current set of
476 // segments, return the earliest segment index 476 // segments, return the earliest segment index
477 if (time < 0) { 477 if (time < 0) {
478 return 0; 478 return 0;
479 } 479 }
480 480
481 // find segments with known timing information that bound the 481 // find segments with known timing information that bound the
482 // target time 482 // target time
483 for (i = 0; i < numSegments; i++) { 483 for (i = 0; i < numSegments; i++) {
484 segment = this.media_.segments[i]; 484 segment = this.media_.segments[i];
485 if (segment.end) { 485 if (segment.end) {
486 if (segment.end > time) { 486 if (segment.end > time) {
487 knownEnd = segment.end; 487 knownEnd = segment.end;
488 endIndex = i; 488 endIndex = i;
489 break; 489 break;
490 } else { 490 } else {
491 knownStart = segment.end; 491 knownStart = segment.end;
492 startIndex = i + 1; 492 startIndex = i + 1;
493 } 493 }
494 } 494 }
495 } 495 }
496 496
497 // use the bounds we just found and playlist information to 497 // use the bounds we just found and playlist information to
498 // estimate the segment that contains the time we are looking for 498 // estimate the segment that contains the time we are looking for
499 if (startIndex !== undefined) { 499 if (startIndex !== undefined) {
500 // We have a known-start point that is before our desired time so 500 // We have a known-start point that is before our desired time so
501 // walk from that point forwards 501 // walk from that point forwards
502 time = time - knownStart; 502 time = time - knownStart;
503 for (i = startIndex; i < (endIndex || numSegments); i++) { 503 for (i = startIndex; i < (endIndex || numSegments); i++) {
504 segment = this.media_.segments[i]; 504 segment = this.media_.segments[i];
505 time -= segment.duration; 505 time -= segment.duration;
506 506
507 if (time < 0) { 507 if (time < 0) {
508 return i; 508 return i;
509 } 509 }
510 } 510 }
511 511
512 if (i >= endIndex) { 512 if (i >= endIndex) {
513 // We haven't found a segment but we did hit a known end point 513 // We haven't found a segment but we did hit a known end point
514 // so fallback to interpolating between the segment index 514 // so fallback to interpolating between the segment index
515 // based on the known span of the timeline we are dealing with 515 // based on the known span of the timeline we are dealing with
516 // and the number of segments inside that span 516 // and the number of segments inside that span
517 return startIndex + Math.floor( 517 return startIndex + Math.floor(
518 ((originalTime - knownStart) / (knownEnd - knownStart)) * 518 ((originalTime - knownStart) / (knownEnd - knownStart)) *
519 (endIndex - startIndex)); 519 (endIndex - startIndex));
520 } 520 }
521 521
522 // We _still_ haven't found a segment so load the last one 522 // We _still_ haven't found a segment so load the last one
523 return lastSegment; 523 return lastSegment;
524 } else if (endIndex !== undefined) { 524 } else if (endIndex !== undefined) {
525 // We _only_ have a known-end point that is after our desired time so 525 // We _only_ have a known-end point that is after our desired time so
526 // walk from that point backwards 526 // walk from that point backwards
527 time = knownEnd - time; 527 time = knownEnd - time;
528 for (i = endIndex; i >= 0; i--) { 528 for (i = endIndex; i >= 0; i--) {
529 segment = this.media_.segments[i]; 529 segment = this.media_.segments[i];
530 time -= segment.duration; 530 time -= segment.duration;
531 531
532 if (time < 0) { 532 if (time < 0) {
533 return i; 533 return i;
534 } 534 }
535 } 535 }
536 536
537 // We haven't found a segment so load the first one if time is zero 537 // We haven't found a segment so load the first one if time is zero
538 if (time === 0) { 538 if (time === 0) {
539 return 0; 539 return 0;
540 } else { 540 } else {
541 return -1; 541 return -1;
542 } 542 }
543 } else { 543 } else {
544 // We known nothing so walk from the front of the playlist, 544 // We known nothing so walk from the front of the playlist,
545 // subtracting durations until we find a segment that contains 545 // subtracting durations until we find a segment that contains
546 // time and return it 546 // time and return it
547 time = time - this.expired_; 547 time = time - this.expired_;
548 548
549 if (time < 0) { 549 if (time < 0) {
550 return -1; 550 return -1;
551 } 551 }
552 552
553 for (i = 0; i < numSegments; i++) { 553 for (i = 0; i < numSegments; i++) {
554 segment = this.media_.segments[i]; 554 segment = this.media_.segments[i];
555 time -= segment.duration; 555 time -= segment.duration;
556 if (time < 0) { 556 if (time < 0) {
557 return i; 557 return i;
558 } 558 }
559 } 559 }
560 // We are out of possible candidates so load the last one... 560 // We are out of possible candidates so load the last one...
561 // The last one is the least likely to overlap a buffer and therefore 561 // The last one is the least likely to overlap a buffer and therefore
562 // the one most likely to tell us something about the timeline 562 // the one most likely to tell us something about the timeline
563 return lastSegment; 563 return lastSegment;
564 } 564 }
565 } 565 }
566 } 566 }
......