{"action":"created","comment":{"url":"https://api.github.com/repos/jwplayer/hls.js/pulls/comments/91182965","pull_request_review_id":11692929,"id":91182965,"diff_hunk":"@@ -404,28 +404,38 @@ class StreamController extends EventHandler {\n     }\n     if (foundFrag) {\n       frag = foundFrag;\n-      start = foundFrag.start;\n+      const curSNIdx = frag.sn - levelDetails.startSN;\n+      const sameLevel = fragPrevious && frag.level === fragPrevious.level;\n       //logger.log('find SN matching with pos:' +  bufferEnd + ':' + frag.sn);\n-      if (fragPrevious && frag.level === fragPrevious.level && frag.sn === fragPrevious.sn) {\n-        if (frag.sn < levelDetails.endSN) {\n-          let deltaPTS = fragPrevious.deltaPTS,\n-          curSNIdx = frag.sn - levelDetails.startSN;\n-          // if there is a significant delta between audio and video, larger than max allowed hole,\n-          // and if previous remuxed fragment did not start with a keyframe. (fragPrevious.dropped)\n-          // let's try to load previous fragment again to get last keyframe\n-          // then we will reload again current fragment (that way we should be able to fill the buffer hole ...)\n-          if (deltaPTS && deltaPTS > config.maxBufferHole && fragPrevious.dropped && curSNIdx) {\n-            frag = fragments[curSNIdx-1];\n-            logger.warn(`SN just loaded, with large PTS gap between audio and video, maybe frag is not starting with a keyframe ? load previous one to try to overcome this`);\n-            // decrement previous frag load counter to avoid frag loop loading error when next fragment will get reloaded\n-            fragPrevious.loadCounter--;\n+       if (sameLevel && frag.sn === fragPrevious.sn) {\n+          if (frag.sn < levelDetails.endSN) {\n+            let deltaPTS = fragPrevious.deltaPTS;\n+            // if there is a significant delta between audio and video, larger than max allowed hole,\n+            // and if previous remuxed fragment did not start with a keyframe. (fragPrevious.dropped)\n+            // let's try to load previous fragment again to get last keyframe\n+            // then we will reload again current fragment (that way we should be able to fill the buffer hole ...)\n+            if (deltaPTS && deltaPTS > config.maxBufferHole && fragPrevious.dropped && curSNIdx) {\n+              frag = fragments[curSNIdx - 1];\n+              logger.warn(`SN just loaded, with large PTS gap between audio and video, maybe frag is not starting with a keyframe ? load previous one to try to overcome this`);\n+              // decrement previous frag load counter to avoid frag loop loading error when next fragment will get reloaded\n+              fragPrevious.loadCounter--;\n+            } else {\n+              frag = fragments[curSNIdx + 1];\n+              logger.log(`SN just loaded, load next one: ${frag.sn}`);\n+            }\n           } else {\n-            frag = fragments[curSNIdx+1];\n-            logger.log(`SN just loaded, load next one: ${frag.sn}`);\n+            frag = null;\n           }\n-        } else {\n-          frag = null;\n-        }\n+        } else if (frag.dropped && !sameLevel) {\n+         // If a fragment has dropped frames and it's in a different level/sequence, load the previous fragment to try and find the keyframe\n+         // Reset the dropped count now since it won't be reset until we parse the fragment again, which prevents infinite backtracking on the same segment\n+         logger.warn('Loaded fragment with dropped frames, backtracking 1 segment to find a keyframe');\n+         frag.dropped = 0;\n+         const prev = fragments[curSNIdx - 1];","path":"src/controller/stream-controller.js","position":50,"original_position":50,"commit_id":"9da472a23614b19f08a6f95326faee11076c6fc7","original_commit_id":"9da472a23614b19f08a6f95326faee11076c6fc7","user":{"login":"johnBartos","id":5042276,"avatar_url":"https://avatars.githubusercontent.com/u/5042276?v=3","gravatar_id":"","url":"https://api.github.com/users/johnBartos","html_url":"https://github.com/johnBartos","followers_url":"https://api.github.com/users/johnBartos/followers","following_url":"https://api.github.com/users/johnBartos/following{/other_user}","gists_url":"https://api.github.com/users/johnBartos/gists{/gist_id}","starred_url":"https://api.github.com/users/johnBartos/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/johnBartos/subscriptions","organizations_url":"https://api.github.com/users/johnBartos/orgs","repos_url":"https://api.github.com/users/johnBartos/repos","events_url":"https://api.github.com/users/johnBartos/events{/privacy}","received_events_url":"https://api.github.com/users/johnBartos/received_events","type":"User","site_admin":false},"body":"Thanks, good catch","created_at":"2016-12-06T22:06:10Z","updated_at":"2016-12-06T22:06:10Z","html_url":"https://github.com/jwplayer/hls.js/pull/32#discussion_r91182965","pull_request_url":"https://api.github.com/repos/jwplayer/hls.js/pulls/32","_links":{"self":{"href":"https://api.github.com/repos/jwplayer/hls.js/pulls/comments/91182965"},"html":{"href":"https://github.com/jwplayer/hls.js/pull/32#discussion_r91182965"},"pull_request":{"href":"https://api.github.com/repos/jwplayer/hls.js/pulls/32"}}},"pull_request":{"url":"https://api.github.com/repos/jwplayer/hls.js/pulls/32","id":96619611,"html_url":"https://github.com/jwplayer/hls.js/pull/32","diff_url":"https://github.com/jwplayer/hls.js/pull/32.diff","patch_url":"https://github.com/jwplayer/hls.js/pull/32.patch","issue_url":"https://api.github.com/repos/jwplayer/hls.js/issues/32","number":32,"state":"open","locked":false,"title":"[Comments Requested] Backtrack a segment when switching levels causes a gap","user":{"login":"johnBartos","id":5042276,"avatar_url":"https://avatars.githubusercontent.com/u/5042276?v=3","gravatar_id":"","url":"https://api.github.com/users/johnBartos","html_url":"https://github.com/johnBartos","followers_url":"https://api.github.com/users/johnBartos/followers","following_url":"https://api.github.com/users/johnBartos/following{/other_user}","gists_url":"https://api.github.com/users/johnBartos/gists{/gist_id}","starred_url":"https://api.github.com/users/johnBartos/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/johnBartos/subscriptions","organizations_url":"https://api.github.com/users/johnBartos/orgs","repos_url":"https://api.github.com/users/johnBartos/repos","events_url":"https://api.github.com/users/johnBartos/events{/privacy}","received_events_url":"https://api.github.com/users/johnBartos/received_events","type":"User","site_admin":false},"body":"- `https://content.jwplatform.com/manifests/3FL1BWlU.m3u8` (2 segments, second drops)\r\n- `https://content.jwplatform.com/manifests/THL4trVg.m3u8` (2 segments, second drops, audio drops)\r\n- `http://streambox.fr/playlists/issue_004_2/index.m3u8` (3+ segments, first few drop, error seeking back to dropped range, plays fine in vanilla 0.6.12)\r\n- `http://streambox.fr/playlists/issue_026/stream_multi.m3u8` (3+ segments, third drops, can seek back over range, (artifacts are \"normal\" in this stream), plays fine in vanilla 0.6.12)\r\n- `https://content.jwplatform.com/manifests/XrUBAnE2.m3u8` (3 segments)\r\n- `http://playertest.longtailvideo.com/adaptive/nih/playlist.m3u8` (3+ segments, 1 dropped frame on first segment, audio fragments arrive before video)\r\n\r\nThis seems to work well but I'd like feedback on the implementation/style. Also need additional test streams (3+ segments, backtracking in the middle, live).\r\n\r\nKnown Issues:\r\n- ~Selecting `nextLevel` the same level in the stream tester multiple times causes a `fragLoopLoadingError` but playback is OK~ fixed\r\n\r\n\r\nA good way to test for infinite loops is to mark every fragment as having dropped frames here:\r\nhttps://github.com/jwplayer/hls.js/blob/master/src/demux/tsdemuxer.js#L424\r\n\r\nJW7-3587","created_at":"2016-12-05T22:10:34Z","updated_at":"2016-12-06T22:06:10Z","closed_at":null,"merged_at":null,"merge_commit_sha":"77e9f8df12af2c170b3f4a74c4785975763af6ae","assignee":{"login":"robwalch","id":333258,"avatar_url":"https://avatars.githubusercontent.com/u/333258?v=3","gravatar_id":"","url":"https://api.github.com/users/robwalch","html_url":"https://github.com/robwalch","followers_url":"https://api.github.com/users/robwalch/followers","following_url":"https://api.github.com/users/robwalch/following{/other_user}","gists_url":"https://api.github.com/users/robwalch/gists{/gist_id}","starred_url":"https://api.github.com/users/robwalch/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/robwalch/subscriptions","organizations_url":"https://api.github.com/users/robwalch/orgs","repos_url":"https://api.github.com/users/robwalch/repos","events_url":"https://api.github.com/users/robwalch/events{/privacy}","received_events_url":"https://api.github.com/users/robwalch/received_events","type":"User","site_admin":false},"assignees":[{"login":"robwalch","id":333258,"avatar_url":"https://avatars.githubusercontent.com/u/333258?v=3","gravatar_id":"","url":"https://api.github.com/users/robwalch","html_url":"https://github.com/robwalch","followers_url":"https://api.github.com/users/robwalch/followers","following_url":"https://api.github.com/users/robwalch/following{/other_user}","gists_url":"https://api.github.com/users/robwalch/gists{/gist_id}","starred_url":"https://api.github.com/users/robwalch/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/robwalch/subscriptions","organizations_url":"https://api.github.com/users/robwalch/orgs","repos_url":"https://api.github.com/users/robwalch/repos","events_url":"https://api.github.com/users/robwalch/events{/privacy}","received_events_url":"https://api.github.com/users/robwalch/received_events","type":"User","site_admin":false},{"login":"egreaves","id":4603952,"avatar_url":"https://avatars.githubusercontent.com/u/4603952?v=3","gravatar_id":"","url":"https://api.github.com/users/egreaves","html_url":"https://github.com/egreaves","followers_url":"https://api.github.com/users/egreaves/followers","following_url":"https://api.github.com/users/egreaves/following{/other_user}","gists_url":"https://api.github.com/users/egreaves/gists{/gist_id}","starred_url":"https://api.github.com/users/egreaves/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/egreaves/subscriptions","organizations_url":"https://api.github.com/users/egreaves/orgs","repos_url":"https://api.github.com/users/egreaves/repos","events_url":"https://api.github.com/users/egreaves/events{/privacy}","received_events_url":"https://api.github.com/users/egreaves/received_events","type":"User","site_admin":false}],"milestone":null,"commits_url":"https://api.github.com/repos/jwplayer/hls.js/pulls/32/commits","review_comments_url":"https://api.github.com/repos/jwplayer/hls.js/pulls/32/comments","review_comment_url":"https://api.github.com/repos/jwplayer/hls.js/pulls/comments{/number}","comments_url":"https://api.github.com/repos/jwplayer/hls.js/issues/32/comments","statuses_url":"https://api.github.com/repos/jwplayer/hls.js/statuses/9da472a23614b19f08a6f95326faee11076c6fc7","head":{"label":"jwplayer:bugfix/abr-gaps","ref":"bugfix/abr-gaps","sha":"9da472a23614b19f08a6f95326faee11076c6fc7","user":{"login":"jwplayer","id":5090060,"avatar_url":"https://avatars.githubusercontent.com/u/5090060?v=3","gravatar_id":"","url":"https://api.github.com/users/jwplayer","html_url":"https://github.com/jwplayer","followers_url":"https://api.github.com/users/jwplayer/followers","following_url":"https://api.github.com/users/jwplayer/following{/other_user}","gists_url":"https://api.github.com/users/jwplayer/gists{/gist_id}","starred_url":"https://api.github.com/users/jwplayer/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jwplayer/subscriptions","organizations_url":"https://api.github.com/users/jwplayer/orgs","repos_url":"https://api.github.com/users/jwplayer/repos","events_url":"https://api.github.com/users/jwplayer/events{/privacy}","received_events_url":"https://api.github.com/users/jwplayer/received_events","type":"Organization","site_admin":false},"repo":{"id":71589822,"name":"hls.js","full_name":"jwplayer/hls.js","owner":{"login":"jwplayer","id":5090060,"avatar_url":"https://avatars.githubusercontent.com/u/5090060?v=3","gravatar_id":"","url":"https://api.github.com/users/jwplayer","html_url":"https://github.com/jwplayer","followers_url":"https://api.github.com/users/jwplayer/followers","following_url":"https://api.github.com/users/jwplayer/following{/other_user}","gists_url":"https://api.github.com/users/jwplayer/gists{/gist_id}","starred_url":"https://api.github.com/users/jwplayer/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jwplayer/subscriptions","organizations_url":"https://api.github.com/users/jwplayer/orgs","repos_url":"https://api.github.com/users/jwplayer/repos","events_url":"https://api.github.com/users/jwplayer/events{/privacy}","received_events_url":"https://api.github.com/users/jwplayer/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/jwplayer/hls.js","description":"MSE-based HLS client - http://dailymotion.github.io/hls.js/demo","fork":true,"url":"https://api.github.com/repos/jwplayer/hls.js","forks_url":"https://api.github.com/repos/jwplayer/hls.js/forks","keys_url":"https://api.github.com/repos/jwplayer/hls.js/keys{/key_id}","collaborators_url":"https://api.github.com/repos/jwplayer/hls.js/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/jwplayer/hls.js/teams","hooks_url":"https://api.github.com/repos/jwplayer/hls.js/hooks","issue_events_url":"https://api.github.com/repos/jwplayer/hls.js/issues/events{/number}","events_url":"https://api.github.com/repos/jwplayer/hls.js/events","assignees_url":"https://api.github.com/repos/jwplayer/hls.js/assignees{/user}","branches_url":"https://api.github.com/repos/jwplayer/hls.js/branches{/branch}","tags_url":"https://api.github.com/repos/jwplayer/hls.js/tags","blobs_url":"https://api.github.com/repos/jwplayer/hls.js/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/jwplayer/hls.js/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/jwplayer/hls.js/git/refs{/sha}","trees_url":"https://api.github.com/repos/jwplayer/hls.js/git/trees{/sha}","statuses_url":"https://api.github.com/repos/jwplayer/hls.js/statuses/{sha}","languages_url":"https://api.github.com/repos/jwplayer/hls.js/languages","stargazers_url":"https://api.github.com/repos/jwplayer/hls.js/stargazers","contributors_url":"https://api.github.com/repos/jwplayer/hls.js/contributors","subscribers_url":"https://api.github.com/repos/jwplayer/hls.js/subscribers","subscription_url":"https://api.github.com/repos/jwplayer/hls.js/subscription","commits_url":"https://api.github.com/repos/jwplayer/hls.js/commits{/sha}","git_commits_url":"https://api.github.com/repos/jwplayer/hls.js/git/commits{/sha}","comments_url":"https://api.github.com/repos/jwplayer/hls.js/comments{/number}","issue_comment_url":"https://api.github.com/repos/jwplayer/hls.js/issues/comments{/number}","contents_url":"https://api.github.com/repos/jwplayer/hls.js/contents/{+path}","compare_url":"https://api.github.com/repos/jwplayer/hls.js/compare/{base}...{head}","merges_url":"https://api.github.com/repos/jwplayer/hls.js/merges","archive_url":"https://api.github.com/repos/jwplayer/hls.js/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/jwplayer/hls.js/downloads","issues_url":"https://api.github.com/repos/jwplayer/hls.js/issues{/number}","pulls_url":"https://api.github.com/repos/jwplayer/hls.js/pulls{/number}","milestones_url":"https://api.github.com/repos/jwplayer/hls.js/milestones{/number}","notifications_url":"https://api.github.com/repos/jwplayer/hls.js/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/jwplayer/hls.js/labels{/name}","releases_url":"https://api.github.com/repos/jwplayer/hls.js/releases{/id}","deployments_url":"https://api.github.com/repos/jwplayer/hls.js/deployments","created_at":"2016-10-21T19:09:57Z","updated_at":"2016-11-21T09:19:33Z","pushed_at":"2016-12-06T19:35:23Z","git_url":"git://github.com/jwplayer/hls.js.git","ssh_url":"git@github.com:jwplayer/hls.js.git","clone_url":"https://github.com/jwplayer/hls.js.git","svn_url":"https://github.com/jwplayer/hls.js","homepage":"","size":17699,"stargazers_count":2,"watchers_count":2,"language":"JavaScript","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":3,"forks":0,"open_issues":3,"watchers":2,"default_branch":"master"}},"base":{"label":"jwplayer:master","ref":"master","sha":"ba4e36026331cfbcd2f90891999ae80e1c501377","user":{"login":"jwplayer","id":5090060,"avatar_url":"https://avatars.githubusercontent.com/u/5090060?v=3","gravatar_id":"","url":"https://api.github.com/users/jwplayer","html_url":"https://github.com/jwplayer","followers_url":"https://api.github.com/users/jwplayer/followers","following_url":"https://api.github.com/users/jwplayer/following{/other_user}","gists_url":"https://api.github.com/users/jwplayer/gists{/gist_id}","starred_url":"https://api.github.com/users/jwplayer/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jwplayer/subscriptions","organizations_url":"https://api.github.com/users/jwplayer/orgs","repos_url":"https://api.github.com/users/jwplayer/repos","events_url":"https://api.github.com/users/jwplayer/events{/privacy}","received_events_url":"https://api.github.com/users/jwplayer/received_events","type":"Organization","site_admin":false},"repo":{"id":71589822,"name":"hls.js","full_name":"jwplayer/hls.js","owner":{"login":"jwplayer","id":5090060,"avatar_url":"https://avatars.githubusercontent.com/u/5090060?v=3","gravatar_id":"","url":"https://api.github.com/users/jwplayer","html_url":"https://github.com/jwplayer","followers_url":"https://api.github.com/users/jwplayer/followers","following_url":"https://api.github.com/users/jwplayer/following{/other_user}","gists_url":"https://api.github.com/users/jwplayer/gists{/gist_id}","starred_url":"https://api.github.com/users/jwplayer/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jwplayer/subscriptions","organizations_url":"https://api.github.com/users/jwplayer/orgs","repos_url":"https://api.github.com/users/jwplayer/repos","events_url":"https://api.github.com/users/jwplayer/events{/privacy}","received_events_url":"https://api.github.com/users/jwplayer/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/jwplayer/hls.js","description":"MSE-based HLS client - http://dailymotion.github.io/hls.js/demo","fork":true,"url":"https://api.github.com/repos/jwplayer/hls.js","forks_url":"https://api.github.com/repos/jwplayer/hls.js/forks","keys_url":"https://api.github.com/repos/jwplayer/hls.js/keys{/key_id}","collaborators_url":"https://api.github.com/repos/jwplayer/hls.js/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/jwplayer/hls.js/teams","hooks_url":"https://api.github.com/repos/jwplayer/hls.js/hooks","issue_events_url":"https://api.github.com/repos/jwplayer/hls.js/issues/events{/number}","events_url":"https://api.github.com/repos/jwplayer/hls.js/events","assignees_url":"https://api.github.com/repos/jwplayer/hls.js/assignees{/user}","branches_url":"https://api.github.com/repos/jwplayer/hls.js/branches{/branch}","tags_url":"https://api.github.com/repos/jwplayer/hls.js/tags","blobs_url":"https://api.github.com/repos/jwplayer/hls.js/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/jwplayer/hls.js/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/jwplayer/hls.js/git/refs{/sha}","trees_url":"https://api.github.com/repos/jwplayer/hls.js/git/trees{/sha}","statuses_url":"https://api.github.com/repos/jwplayer/hls.js/statuses/{sha}","languages_url":"https://api.github.com/repos/jwplayer/hls.js/languages","stargazers_url":"https://api.github.com/repos/jwplayer/hls.js/stargazers","contributors_url":"https://api.github.com/repos/jwplayer/hls.js/contributors","subscribers_url":"https://api.github.com/repos/jwplayer/hls.js/subscribers","subscription_url":"https://api.github.com/repos/jwplayer/hls.js/subscription","commits_url":"https://api.github.com/repos/jwplayer/hls.js/commits{/sha}","git_commits_url":"https://api.github.com/repos/jwplayer/hls.js/git/commits{/sha}","comments_url":"https://api.github.com/repos/jwplayer/hls.js/comments{/number}","issue_comment_url":"https://api.github.com/repos/jwplayer/hls.js/issues/comments{/number}","contents_url":"https://api.github.com/repos/jwplayer/hls.js/contents/{+path}","compare_url":"https://api.github.com/repos/jwplayer/hls.js/compare/{base}...{head}","merges_url":"https://api.github.com/repos/jwplayer/hls.js/merges","archive_url":"https://api.github.com/repos/jwplayer/hls.js/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/jwplayer/hls.js/downloads","issues_url":"https://api.github.com/repos/jwplayer/hls.js/issues{/number}","pulls_url":"https://api.github.com/repos/jwplayer/hls.js/pulls{/number}","milestones_url":"https://api.github.com/repos/jwplayer/hls.js/milestones{/number}","notifications_url":"https://api.github.com/repos/jwplayer/hls.js/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/jwplayer/hls.js/labels{/name}","releases_url":"https://api.github.com/repos/jwplayer/hls.js/releases{/id}","deployments_url":"https://api.github.com/repos/jwplayer/hls.js/deployments","created_at":"2016-10-21T19:09:57Z","updated_at":"2016-11-21T09:19:33Z","pushed_at":"2016-12-06T19:35:23Z","git_url":"git://github.com/jwplayer/hls.js.git","ssh_url":"git@github.com:jwplayer/hls.js.git","clone_url":"https://github.com/jwplayer/hls.js.git","svn_url":"https://github.com/jwplayer/hls.js","homepage":"","size":17699,"stargazers_count":2,"watchers_count":2,"language":"JavaScript","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":3,"forks":0,"open_issues":3,"watchers":2,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/jwplayer/hls.js/pulls/32"},"html":{"href":"https://github.com/jwplayer/hls.js/pull/32"},"issue":{"href":"https://api.github.com/repos/jwplayer/hls.js/issues/32"},"comments":{"href":"https://api.github.com/repos/jwplayer/hls.js/issues/32/comments"},"review_comments":{"href":"https://api.github.com/repos/jwplayer/hls.js/pulls/32/comments"},"review_comment":{"href":"https://api.github.com/repos/jwplayer/hls.js/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/jwplayer/hls.js/pulls/32/commits"},"statuses":{"href":"https://api.github.com/repos/jwplayer/hls.js/statuses/9da472a23614b19f08a6f95326faee11076c6fc7"}}}}
{"actor":{"display_login":"johnBartos"}}