Beispiel #1
0
bool PAPlayer::QueueNextFileEx(const CFileItem &file, bool fadeIn/* = true */)
{
  StreamInfo *si = new StreamInfo();

  if (!si->m_decoder.Create(file, (file.m_lStartOffset * 1000) / 75))
  {
    CLog::Log(LOGWARNING, "PAPlayer::QueueNextFileEx - Failed to create the decoder");

    delete si;
    m_callback.OnQueueNextItem();
    return false;
  }

  /* decode until there is data-available */
  si->m_decoder.Start();
  while(si->m_decoder.GetDataSize() == 0)
  {
    int status = si->m_decoder.GetStatus();
    if (status == STATUS_ENDED   ||
        status == STATUS_NO_FILE ||
        si->m_decoder.ReadSamples(PACKET_SIZE) == RET_ERROR)
    {
      CLog::Log(LOGINFO, "PAPlayer::QueueNextFileEx - Error reading samples");

      si->m_decoder.Destroy();
      delete si;
      m_callback.OnQueueNextItem();
      return false;
    }

    /* yield our time so that the main PAP thread doesnt stall */
    CThread::Sleep(1);
  }

  UpdateCrossfadeTime(file);

  /* init the streaminfo struct */
  si->m_decoder.GetDataFormat(&si->m_channelInfo, &si->m_sampleRate, &si->m_encodedSampleRate, &si->m_dataFormat);
  si->m_startOffset        = file.m_lStartOffset * 1000 / 75;
  si->m_endOffset          = file.m_lEndOffset   * 1000 / 75;
  si->m_bytesPerSample     = CAEUtil::DataFormatToBits(si->m_dataFormat) >> 3;
  si->m_bytesPerFrame      = si->m_bytesPerSample * si->m_channelInfo.Count();
  si->m_started            = false;
  si->m_finishing          = false;
  si->m_framesSent         = 0;
  si->m_seekNextAtFrame    = 0;
  si->m_seekFrame          = -1;
  si->m_stream             = NULL;
  si->m_volume             = (fadeIn && m_upcomingCrossfadeMS) ? 0.0f : 1.0f;
  si->m_fadeOutTriggered   = false;
  si->m_isSlaved           = false;

  int64_t streamTotalTime = si->m_decoder.TotalTime();
  if (si->m_endOffset)
    streamTotalTime = si->m_endOffset - si->m_startOffset;
  
  si->m_prepareNextAtFrame = 0;
  if (streamTotalTime >= TIME_TO_CACHE_NEXT_FILE + m_defaultCrossfadeMS)
    si->m_prepareNextAtFrame = (int)((streamTotalTime - TIME_TO_CACHE_NEXT_FILE - m_defaultCrossfadeMS) * si->m_sampleRate / 1000.0f);

  si->m_prepareTriggered = false;

  si->m_playNextAtFrame = 0;
  si->m_playNextTriggered = false;

  if (!PrepareStream(si))
  {
    CLog::Log(LOGINFO, "PAPlayer::QueueNextFileEx - Error preparing stream");
    
    si->m_decoder.Destroy();
    delete si;
    m_callback.OnQueueNextItem();
    return false;
  }

  /* add the stream to the list */
  CExclusiveLock lock(m_streamsLock);
  m_streams.push_back(si);
  //update the current stream to start playing the next track at the correct frame.
  UpdateStreamInfoPlayNextAtFrame(m_currentStream, m_upcomingCrossfadeMS);

  *m_FileItem = file;

  return true;
}
Beispiel #2
0
bool PAPlayer::QueueNextFileEx(const CFileItem &file, bool fadeIn)
{
  if (m_currentStream)
  {
    // check if we advance a track of a CUE sheet
    // if this is the case we don't need to open a new stream
    std::string newURL = file.GetDynURL().GetFileName();
    std::string oldURL = m_currentStream->m_fileItem.GetDynURL().GetFileName();
    if (newURL.compare(oldURL) == 0 &&
        file.m_lStartOffset &&
        file.m_lStartOffset == m_currentStream->m_fileItem.m_lEndOffset &&
        m_currentStream && m_currentStream->m_prepareTriggered)
    {
      m_currentStream->m_nextFileItem.reset(new CFileItem(file));
      m_upcomingCrossfadeMS = 0;
      return true;
    }
    m_currentStream->m_nextFileItem.reset();
  }

  StreamInfo *si = new StreamInfo();
  si->m_fileItem = file;
  if (!si->m_decoder.Create(file, si->m_fileItem.m_lStartOffset))
  {
    CLog::Log(LOGWARNING, "PAPlayer::QueueNextFileEx - Failed to create the decoder");

    // advance playlist
    AdvancePlaylistOnError(si->m_fileItem);
    m_callback.OnQueueNextItem();

    delete si;
    return false;
  }

  /* decode until there is data-available */
  si->m_decoder.Start();
  while (si->m_decoder.GetDataSize(true) == 0)
  {
    int status = si->m_decoder.GetStatus();
    if (status == STATUS_ENDED   ||
        status == STATUS_NO_FILE ||
        si->m_decoder.ReadSamples(PACKET_SIZE) == RET_ERROR)
    {
      CLog::Log(LOGINFO, "PAPlayer::QueueNextFileEx - Error reading samples");

      si->m_decoder.Destroy();
      // advance playlist
      AdvancePlaylistOnError(si->m_fileItem);
      m_callback.OnQueueNextItem();
      delete si;
      return false;
    }

    /* yield our time so that the main PAP thread doesnt stall */
    CThread::Sleep(1);
  }

  // set m_upcomingCrossfadeMS depending on type of file and user settings
  UpdateCrossfadeTime(si->m_fileItem);

  /* init the streaminfo struct */
  si->m_audioFormat = si->m_decoder.GetFormat();
  si->m_startOffset = file.m_lStartOffset;
  si->m_endOffset = file.m_lEndOffset;
  si->m_bytesPerSample = CAEUtil::DataFormatToBits(si->m_audioFormat.m_dataFormat) >> 3;
  si->m_bytesPerFrame = si->m_bytesPerSample * si->m_audioFormat.m_channelLayout.Count();
  si->m_started = false;
  si->m_finishing = false;
  si->m_framesSent = 0;
  si->m_seekNextAtFrame = 0;
  si->m_seekFrame = -1;
  si->m_stream = NULL;
  si->m_volume = (fadeIn && m_upcomingCrossfadeMS) ? 0.0f : 1.0f;
  si->m_fadeOutTriggered = false;
  si->m_isSlaved = false;

  si->m_decoderTotal = si->m_decoder.TotalTime();
  int64_t streamTotalTime = si->m_decoderTotal;
  if (si->m_endOffset)
    streamTotalTime = si->m_endOffset - si->m_startOffset;

  si->m_prepareNextAtFrame = 0;
  // cd drives don't really like it to be crossfaded or prepared
  if(!file.IsCDDA())
  {
    if (streamTotalTime >= TIME_TO_CACHE_NEXT_FILE + m_defaultCrossfadeMS)
      si->m_prepareNextAtFrame = (int)((streamTotalTime - TIME_TO_CACHE_NEXT_FILE - m_defaultCrossfadeMS) * si->m_audioFormat.m_sampleRate / 1000.0f);
  }

  if (m_currentStream && ((m_currentStream->m_audioFormat.m_dataFormat == AE_FMT_RAW) || (si->m_audioFormat.m_dataFormat == AE_FMT_RAW)))
  {
    m_currentStream->m_prepareTriggered = false;
    m_currentStream->m_waitOnDrain = true;
    m_currentStream->m_prepareNextAtFrame = 0;
    si->m_decoder.Destroy();
    delete si;
    return false;
  }

  si->m_prepareTriggered = false;
  si->m_playNextAtFrame = 0;
  si->m_playNextTriggered = false;
  si->m_waitOnDrain = false;

  if (!PrepareStream(si))
  {
    CLog::Log(LOGINFO, "PAPlayer::QueueNextFileEx - Error preparing stream");

    si->m_decoder.Destroy();
    // advance playlist
    AdvancePlaylistOnError(si->m_fileItem);
    m_callback.OnQueueNextItem();
    delete si;
    return false;
  }

  /* add the stream to the list */
  CSingleLock lock(m_streamsLock);
  m_streams.push_back(si);
  //update the current stream to start playing the next track at the correct frame.
  UpdateStreamInfoPlayNextAtFrame(m_currentStream, m_upcomingCrossfadeMS);

  return true;
}
Beispiel #3
0
inline bool PAPlayer::ProcessStream(StreamInfo *si, double &freeBufferTime)
{
  /* if playback needs to start on this stream, do it */
  if (si == m_currentStream && !si->m_started)
  {
    si->m_started = true;
    si->m_stream->RegisterAudioCallback(m_audioCallback);
    if (!si->m_isSlaved)
      si->m_stream->Resume();
    si->m_stream->FadeVolume(0.0f, 1.0f, m_upcomingCrossfadeMS);
    if (m_signalStarted)
      m_callback.OnPlayBackStarted(si->m_fileItem);
    m_signalStarted = true;
    m_callback.OnAVStarted(si->m_fileItem);
  }

  /* if we have not started yet and the stream has been primed */
  unsigned int space = si->m_stream->GetSpace();
  if (!si->m_started && !space)
    return true;

  /* see if it is time yet to FF/RW or a direct seek */
  if (!si->m_playNextTriggered && ((m_playbackSpeed != 1 && si->m_framesSent >= si->m_seekNextAtFrame) || si->m_seekFrame > -1))
  {
    int64_t time = (int64_t)0;
    /* if its a direct seek */
    if (si->m_seekFrame > -1)
    {
      time = (int64_t)((float)si->m_seekFrame / (float)si->m_audioFormat.m_sampleRate * 1000.0f);
      si->m_framesSent = (int)(si->m_seekFrame - ((float)si->m_startOffset * (float)si->m_audioFormat.m_sampleRate) / 1000.0f);
      si->m_seekFrame  = -1;
      m_playerGUIData.m_time = time; //update for GUI
      si->m_seekNextAtFrame = 0;
      CDataCacheCore::GetInstance().SetPlayTimes(0, time, 0, m_playerGUIData.m_totalTime);
    }
    /* if its FF/RW */
    else
    {
      si->m_framesSent      += si->m_audioFormat.m_sampleRate * (m_playbackSpeed  - 1);
      si->m_seekNextAtFrame  = si->m_framesSent + si->m_audioFormat.m_sampleRate / 2;
      time = (int64_t)(((float)si->m_framesSent / (float)si->m_audioFormat.m_sampleRate * 1000.0f) + (float)si->m_startOffset);
    }

    /* if we are seeking back before the start of the track start normal playback */
    if (time < si->m_startOffset || si->m_framesSent < 0)
    {
      time = si->m_startOffset;
      si->m_framesSent      = 0;
      si->m_seekNextAtFrame = 0;
      SetSpeed(1);
    }

    si->m_decoder.Seek(time);
  }

  int status = si->m_decoder.GetStatus();
  if (status == STATUS_ENDED   ||
      status == STATUS_NO_FILE ||
      si->m_decoder.ReadSamples(PACKET_SIZE) == RET_ERROR ||
      ((si->m_endOffset) && (si->m_framesSent / si->m_audioFormat.m_sampleRate >= (si->m_endOffset - si->m_startOffset) / 1000)))
  {
    if (si == m_currentStream && si->m_nextFileItem)
    {
      CloseFileCB(*si);

      // update current stream with info of next track
      si->m_startOffset = si->m_nextFileItem->m_lStartOffset;
      if (si->m_nextFileItem->m_lEndOffset)
        si->m_endOffset = si->m_nextFileItem->m_lEndOffset;
      else
        si->m_endOffset = 0;
      si->m_framesSent = 0;

      si->m_fileItem = *si->m_nextFileItem;
      si->m_nextFileItem.reset();

      int64_t streamTotalTime = si->m_decoder.TotalTime() - si->m_startOffset;
      if (si->m_endOffset)
        streamTotalTime = si->m_endOffset - si->m_startOffset;

      // calculate time when to prepare next stream
      si->m_prepareNextAtFrame = 0;
      if (streamTotalTime >= TIME_TO_CACHE_NEXT_FILE + m_defaultCrossfadeMS)
        si->m_prepareNextAtFrame = (int)((streamTotalTime - TIME_TO_CACHE_NEXT_FILE - m_defaultCrossfadeMS) * si->m_audioFormat.m_sampleRate / 1000.0f);

      si->m_prepareTriggered = false;
      si->m_playNextAtFrame = 0;
      si->m_playNextTriggered = false;
      si->m_seekNextAtFrame = 0;

      //update the current stream to start playing the next track at the correct frame.
      UpdateStreamInfoPlayNextAtFrame(m_currentStream, m_upcomingCrossfadeMS);

      UpdateGUIData(si);
      if (m_signalStarted)
        m_callback.OnPlayBackStarted(si->m_fileItem);
      m_signalStarted = true;
      m_callback.OnAVStarted(si->m_fileItem);
    }
    else
    {
      CLog::Log(LOGINFO, "PAPlayer::ProcessStream - Stream Finished");
      return false;
    }
  }

  if (!QueueData(si))
    return false;

  /* update free buffer time if we are running */
  if (si->m_started)
  {
    if (si->m_stream->IsBuffering())
      freeBufferTime = 1.0;
    else
    {
      double free_space;
      if (si->m_audioFormat.m_dataFormat != AE_FMT_RAW)
        free_space = (double)(si->m_stream->GetSpace() / si->m_bytesPerSample) / si->m_audioFormat.m_sampleRate;
      else
        free_space = (double) si->m_stream->GetSpace() * si->m_audioFormat.m_streamInfo.GetDuration() / 1000;

      freeBufferTime = std::max(freeBufferTime , free_space);
    }
  }

  return true;
}
Beispiel #4
0
bool PAPlayer::QueueNextFileEx(const CFileItem &file, bool fadeIn/* = true */, bool job /* = false */)
{
  StreamInfo *si = new StreamInfo();

  // check if we advance a track of a CUE sheet
  // if this is the case we don't need to open a new stream
  std::string newURL = file.GetMusicInfoTag() ? file.GetMusicInfoTag()->GetURL() : file.GetPath();
  std::string oldURL = m_FileItem->GetMusicInfoTag() ? m_FileItem->GetMusicInfoTag()->GetURL() : m_FileItem->GetPath();
  if (newURL.compare(oldURL) == 0 &&
      file.m_lStartOffset &&
      file.m_lStartOffset == m_FileItem->m_lEndOffset &&
      m_currentStream && m_currentStream->m_prepareTriggered)
  {
    m_continueStream = true;
    m_upcomingCrossfadeMS = 0;
    *m_FileItem = file;
    return true;
  }
  else
  {
    m_continueStream = false;
  }

  if (!si->m_decoder.Create(file, (file.m_lStartOffset * 1000) / 75))
  {
    CLog::Log(LOGWARNING, "PAPlayer::QueueNextFileEx - Failed to create the decoder");

    delete si;
    // advance playlist
    if (job)
      m_callback.OnPlayBackStarted();
    m_callback.OnQueueNextItem();
    return false;
  }

  /* decode until there is data-available */
  si->m_decoder.Start();
  while(si->m_decoder.GetDataSize() == 0)
  {
    int status = si->m_decoder.GetStatus();
    if (status == STATUS_ENDED   ||
        status == STATUS_NO_FILE ||
        si->m_decoder.ReadSamples(PACKET_SIZE) == RET_ERROR)
    {
      CLog::Log(LOGINFO, "PAPlayer::QueueNextFileEx - Error reading samples");

      si->m_decoder.Destroy();
      delete si;
      // advance playlist
      if (job)
        m_callback.OnPlayBackStarted();
      m_callback.OnQueueNextItem();
      return false;
    }

    /* yield our time so that the main PAP thread doesnt stall */
    CThread::Sleep(1);
  }

  /* init the streaminfo struct */
  si->m_decoder.GetDataFormat(&si->m_channelInfo, &si->m_sampleRate, &si->m_encodedSampleRate, &si->m_dataFormat);
  si->m_startOffset        = file.m_lStartOffset * 1000 / 75;
  si->m_endOffset          = file.m_lEndOffset   * 1000 / 75;
  si->m_bytesPerSample     = CAEUtil::DataFormatToBits(si->m_dataFormat) >> 3;
  si->m_bytesPerFrame      = si->m_bytesPerSample * si->m_channelInfo.Count();
  si->m_started            = false;
  si->m_finishing          = false;
  si->m_framesSent         = 0;
  si->m_seekNextAtFrame    = 0;
  si->m_seekFrame          = -1;
  si->m_stream             = NULL;
  si->m_volume             = (fadeIn && m_upcomingCrossfadeMS) ? 0.0f : 1.0f;
  si->m_fadeOutTriggered   = false;
  si->m_isSlaved           = false;

  int64_t streamTotalTime = si->m_decoder.TotalTime();
  if (si->m_endOffset)
    streamTotalTime = si->m_endOffset - si->m_startOffset;
  
  si->m_prepareNextAtFrame = 0;
  // cd drives don't really like it to be crossfaded or prepared
  if(!file.IsCDDA())
  {
    if (streamTotalTime >= TIME_TO_CACHE_NEXT_FILE + m_defaultCrossfadeMS)
      si->m_prepareNextAtFrame = (int)((streamTotalTime - TIME_TO_CACHE_NEXT_FILE - m_defaultCrossfadeMS) * si->m_sampleRate / 1000.0f);
  }

  if (m_currentStream && (AE_IS_RAW(m_currentStream->m_dataFormat) || AE_IS_RAW(si->m_dataFormat)))
  {
    m_currentStream->m_prepareTriggered = false;
    m_currentStream->m_waitOnDrain = true;
    m_currentStream->m_prepareNextAtFrame = 0;
    si->m_decoder.Destroy();
    delete si;
    return false;
  }

  UpdateCrossfadeTime(file);

  si->m_prepareTriggered = false;
  si->m_playNextAtFrame = 0;
  si->m_playNextTriggered = false;
  si->m_waitOnDrain = false;

  if (!PrepareStream(si))
  {
    CLog::Log(LOGINFO, "PAPlayer::QueueNextFileEx - Error preparing stream");
    
    si->m_decoder.Destroy();
    delete si;
    // advance playlist
    if (job)
      m_callback.OnPlayBackStarted();
    m_callback.OnQueueNextItem();
    return false;
  }

  /* add the stream to the list */
  CExclusiveLock lock(m_streamsLock);
  m_streams.push_back(si);
  //update the current stream to start playing the next track at the correct frame.
  UpdateStreamInfoPlayNextAtFrame(m_currentStream, m_upcomingCrossfadeMS);

  *m_FileItem = file;

  return true;
}