void PAPlayer::SeekTime(int64_t iTime /*=0*/) { if (!CanSeek()) return; CSharedLock lock(m_streamsLock); if (!m_currentStream) return; int seekOffset = (int)(iTime - GetTimeInternal()); if (m_playbackSpeed != 1) ToFFRW(1); m_currentStream->m_seekFrame = (int)((float)m_currentStream->m_sampleRate * ((float)iTime + (float)m_currentStream->m_startOffset) / 1000.0f); m_callback.OnPlayBackSeek((int)iTime, seekOffset); }
bool PAPlayer::HandleFFwdRewd() { if (!m_IsFFwdRewding && m_iSpeed == 1) return true; // nothing to do if (m_IsFFwdRewding && m_iSpeed == 1) { // stop ffwd/rewd m_IsFFwdRewding = false; SetVolume(g_stSettings.m_nVolumeLevel); m_bytesSentOut = 0; FlushStreams(); return true; } // we're definitely fastforwarding or rewinding int snippet = m_BytesPerSecond / 2; if ( m_bytesSentOut >= snippet ) { // Calculate time to seek to if we do FF/RW __int64 time = GetTime(); // Is our offset inside the track range? if (time >= 0 && time <= m_decoder[m_currentDecoder].TotalTime()) { // just set next position to read m_IsFFwdRewding = true; time += m_currentFile->m_lStartOffset * 1000 / 75; m_clock.SetClock(m_decoder[m_currentDecoder].Seek(time)); FlushStreams(); SetVolume(g_stSettings.m_nVolumeLevel - VOLUME_FFWD_MUTE); // override xbmc mute } else if (time < 0) { // ...disable seeking and start the track again ToFFRW(1); time = m_currentFile->m_lStartOffset * 1000 / 75; m_clock.SetClock(m_decoder[m_currentDecoder].Seek(time)); FlushStreams(); SetVolume(g_stSettings.m_nVolumeLevel); // override xbmc mute } // is our next position greater then the end sector... else //if (time > m_codec->m_TotalTime) { // restore volume level so the next track isn't muted SetVolume(g_stSettings.m_nVolumeLevel); CLog::Log(LOGDEBUG, "PAP Player: End of track reached while seeking"); return false; } } return true; }
void CApplicationPlayer::SetPlaySpeed(int iSpeed, bool bApplicationMuted) { boost::shared_ptr<IPlayer> player = GetInternal(); if (!player) return; if (!IsPlayingAudio() && !IsPlayingVideo()) return ; if (m_iPlaySpeed == iSpeed) return ; if (!CanSeek()) return; if (IsPaused()) { if ( ((m_iPlaySpeed > 1) && (iSpeed > m_iPlaySpeed)) || ((m_iPlaySpeed < -1) && (iSpeed < m_iPlaySpeed)) ) { iSpeed = m_iPlaySpeed; // from pause to ff/rw, do previous ff/rw speed } Pause(); } m_iPlaySpeed = iSpeed; ToFFRW(m_iPlaySpeed); // if player has volume control, set it. if (ControlsVolume()) { if (m_iPlaySpeed == 1) { // restore volume player->SetVolume(g_application.GetVolume(false)); } else { // mute volume player->SetVolume(VOLUME_MINIMUM); } player->SetMute(bApplicationMuted); } }
inline bool PAPlayer::ProcessStream(StreamInfo *si, double &delay, double &buffer) { /* 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); m_callback.OnPlayBackStarted(); } /* 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_sampleRate * 1000.0f); si->m_framesSent = (int)(si->m_seekFrame - ((float)si->m_startOffset * (float)si->m_sampleRate) / 1000.0f); si->m_seekFrame = -1; m_playerGUIData.m_time = time; //update for GUI } /* if its FF/RW */ else { si->m_framesSent += si->m_sampleRate * (m_playbackSpeed - 1); si->m_seekNextAtFrame = si->m_framesSent + si->m_sampleRate / 2; time = (int64_t)(((float)si->m_framesSent / (float)si->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 = (int)(si->m_startOffset * si->m_sampleRate / 1000); si->m_seekNextAtFrame = 0; ToFFRW(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_sampleRate >= (si->m_endOffset - si->m_startOffset) / 1000))) { CLog::Log(LOGINFO, "PAPlayer::ProcessStream - Stream Finished"); return false; } if (!QueueData(si)) return false; /* update the delay time if we are running */ if (si->m_started) { if (si->m_stream->IsBuffering()) delay = 0.0; else delay = std::min(delay , si->m_stream->GetDelay()); buffer = std::min(buffer, si->m_stream->GetCacheTotal()); } return true; }
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); m_callback.OnPlayBackStarted(); } /* 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_sampleRate * 1000.0f); si->m_framesSent = (int)(si->m_seekFrame - ((float)si->m_startOffset * (float)si->m_sampleRate) / 1000.0f); si->m_seekFrame = -1; m_playerGUIData.m_time = time; //update for GUI si->m_seekNextAtFrame = 0; } /* if its FF/RW */ else { si->m_framesSent += si->m_sampleRate * (m_playbackSpeed - 1); si->m_seekNextAtFrame = si->m_framesSent + si->m_sampleRate / 2; time = (int64_t)(((float)si->m_framesSent / (float)si->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; ToFFRW(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_sampleRate >= (si->m_endOffset - si->m_startOffset) / 1000))) { if (si == m_currentStream && m_continueStream) { // update current stream with info of next track si->m_startOffset = m_FileItem->m_lStartOffset * 1000 / 75; if (m_FileItem->m_lEndOffset) si->m_endOffset = m_FileItem->m_lEndOffset * 1000 / 75; else si->m_endOffset = 0; si->m_framesSent = 0; 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_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); m_callback.OnPlayBackStarted(); m_continueStream = false; } 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 = (double)(si->m_stream->GetSpace() / si->m_bytesPerSample) / si->m_sampleRate; freeBufferTime = std::max(freeBufferTime , free_space); } } return true; }