title: How to fix "If playback doesn't begin shortly, try restarting your device" using Youtube iFrame API on iPad?
body: <p>I've created a little YouTube streaming script which randomly plays YouTube music videos or from a queue. It's worked fine for months up until this week in which it doesn't seem to want to load the videos when using an iPad/iPhone. I get the following error instead:</p>
  
  <blockquote>
    <p>If playback doesn't begin shortly, try restarting your device</p>
  </blockquote>
  
  <p><strong>What I've tried:</strong></p>
  
  <p>I've tried Safari, Chrome, Firefox and Opera and they all error. I've tried clearing website data/cache, restarting the device, fulling restarting the device. Nothing works. The weird thing is, it works absolutely fine on a Windows desktop which leads me to believe it's not an error in the code, but something that has either changed with the API or with Safari. My code has not been edited recently either which could have caused it to stop working.</p>
  
  <p>I've tried debugging it using jsconsole.com, nothing suspicious pops up. In some cases, the player will load, the title of the video will display and so will the image, but after about 30 seconds, the error above displays along with the loading spinner.</p>
  
  <p>I'm aware that playVideo(); doesn't work (autoplay) on iOS devices. This is fine, and again, the script has worked previously, i've only had to press play on the <strong>first</strong> video. But now, it seems like iOS is trying to auto-play the video. So, I've also tested by removing the playVideo() calls, problem still persists.</p>
  
  <p>Tested on iPad 2, iPad mini and iPhone 4 (all with the latest iOS available on the device and all worked previously). </p>
  
  <p>I'm at a loss and trying to get this fixed before the weekend for a house party :) So I'd appreciate any help or hints as to what might be causing the failure on iOS.</p>
  
  <p><strong>Here is the javascript code:</strong></p>
  
  <pre><code>// 2. This code loads the IFrame Player API code asynchronously.
  var tag = document.createElement('script');
  
  tag.src = "https://www.youtube.com/iframe_api";
  var firstScriptTag = document.getElementsByTagName('script')[0];
  firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
  
  // 3. This function creates an &lt;iframe&gt; (and YouTube player)
  //    after the API code downloads.
  var player;
  function onYouTubeIframeAPIReady() {
      player = new YT.Player('player', {
          height: '390',
          width: '640',
          events: {
              'onReady': onPlayerReady,
              'onStateChange': onPlayerStateChange
          }
      });
  }
  
  // 4. The API will call this function when the video player is ready.
  function onPlayerReady(event) {
      check_queue_timer = setTimeout(check_queue(),3000);
  }
  
  // 5. The API calls this function when the player's state changes.
  //    The function indicates that when playing a video (state=1),
  //    the player should play for six seconds and then stop.
  var done = false;
  function onPlayerStateChange(event) {
      if (event.data === 0) {
          // TRACK AS DONE, REFRESH QUEUE AND GET NEXT SONG
          // POST TO WRITE TO FILE
          $.ajax({
              type: 'POST',
              url: site_url+'ajax_next_track',
              dataType: 'json',
              data: 'queue_id='+$('#queue_id').val(),
              cache: false,
              success:
              function(data){
  
                  if(data.status == 'success'){
                      $("#queue_table").empty();
                      if(data.queue.length == 0){
                          check_queue_timer = setTimeout(check_queue(),3000);
                      }
                      $.each(data.queue, function(i, item) {
                          if(i == 0){
                              event.target.loadVideoById(item.video_id);
                              event.target.playVideo();
                              $('#queue_id').val(item.queue_id);
                          }
                          $('#queue_table').append('&lt;tr&gt;&lt;td&gt;'+item.title+'&lt;/td&gt;&lt;/tr&gt;');
                      });
                  }
                  else{
                      console(data.message);
                  }
              },
              error:
              function( jqXHR, textStatus, errorThrown ){
                  $('#error_msg').html('Something broke.').fadeIn();
              }
  
          });
      }
  }
  function stopVideo() {
      player.stopVideo();
  }
  
  function check_queue(){
      $.ajax({
          type: 'POST',
          url: site_url+'ajax_next_track',
          dataType: 'json',
          data: 'no_delete=1',
          cache: false,
          success:
          function(data){
  
              if(data.status == 'success'){
                  $("#queue_table").empty();
                  if(data.queue.length == 0){
                      clearTimeout(check_queue_timer);
                      check_queue_timer = setTimeout(check_queue(),3000);
                  }
                  $.each(data.queue, function(i, item) {
                      if(i == 0){
                          player.loadVideoById(item.video_id);
                          player.playVideo();
                          $('#queue_id').val(item.queue_id);
                          clearTimeout(check_queue_timer);
                      }
                      $('#queue_table').append('&lt;tr&gt;&lt;td&gt;'+item.title+'&lt;/td&gt;&lt;/tr&gt;');
                  });
              }
              else{
                  console(data.message);
              }
          },
          error:
          function( jqXHR, textStatus, errorThrown ){
              $('#error_msg').html('Something broke.').fadeIn();
          }
  
      });
  }
  </code></pre>
  
  <p><strong>UPDATE 1 (25TH NOV 2015)</strong></p>
  
  <p>I've decided to start from scratch and work with the example code on <a href="https://developers.google.com/youtube/iframe_api_reference">https://developers.google.com/youtube/iframe_api_reference</a> . It seems that loadVideoById() is no longer working on iPads. It was before. If I don't include the loadVideoById() or playVideo() it works. Ideally, i'd like it to work with loadVideoById().</p>