void PAPlayer::UpdateCrossfadeTime(const CFileItem& file) { // we explicitly disable crossfading for audio cds if (file.IsCDDA()) m_upcomingCrossfadeMS = 0; else m_upcomingCrossfadeMS = m_defaultCrossfadeMS = CServiceBroker::GetSettings().GetInt(CSettings::SETTING_MUSICPLAYER_CROSSFADE) * 1000; if (m_upcomingCrossfadeMS) { if (!m_currentStream || (file.HasMusicInfoTag() && !CServiceBroker::GetSettings().GetBool(CSettings::SETTING_MUSICPLAYER_CROSSFADEALBUMTRACKS) && m_currentStream->m_fileItem.HasMusicInfoTag() && (m_currentStream->m_fileItem.GetMusicInfoTag()->GetAlbum() != "") && (m_currentStream->m_fileItem.GetMusicInfoTag()->GetAlbum() == file.GetMusicInfoTag()->GetAlbum()) && (m_currentStream->m_fileItem.GetMusicInfoTag()->GetDiscNumber() == file.GetMusicInfoTag()->GetDiscNumber()) && (m_currentStream->m_fileItem.GetMusicInfoTag()->GetTrackNumber() == file.GetMusicInfoTag()->GetTrackNumber() - 1))) { //do not crossfade when playing consecutive albumtracks m_upcomingCrossfadeMS = 0; } } }
void PAPlayer::UpdateCrossFadingTime(const CFileItem& file) { if ((m_crossFading = g_guiSettings.GetInt("musicplayer.crossfade"))) { if ( m_crossFading && ( file.IsCDDA() || file.IsLastFM() || ( file.HasMusicInfoTag() && !g_guiSettings.GetBool("musicplayer.crossfadealbumtracks") && (m_currentFile->GetMusicInfoTag()->GetAlbum() != "") && (m_currentFile->GetMusicInfoTag()->GetAlbum() == file.GetMusicInfoTag()->GetAlbum()) && (m_currentFile->GetMusicInfoTag()->GetDiscNumber() == file.GetMusicInfoTag()->GetDiscNumber()) && (m_currentFile->GetMusicInfoTag()->GetTrackNumber() == file.GetMusicInfoTag()->GetTrackNumber() - 1) ) || g_guiSettings.GetString("audiooutput.audiodevice").find("wasapi:") != CStdString::npos ) ) { m_crossFading = 0; } } }
bool PAPlayer::OpenFile(const CFileItem& file, const CPlayerOptions &options) { if (m_currentlyCrossFading) CloseFileInternal(false); //user seems to be in a hurry m_crossFading = g_guiSettings.GetInt("musicplayer.crossfade"); //WASAPI doesn't support multiple streams, no crossfading for cdda, cd-reading goes mad and no crossfading for last.fm doesn't like two connections if (file.IsCDDA() || file.IsLastFM() || g_guiSettings.GetString("audiooutput.audiodevice").find("wasapi:") != CStdString::npos) m_crossFading = 0; if (m_crossFading && IsPlaying()) { //do a short crossfade on trackskip //set to max 2 seconds for these prev/next transitions if (m_crossFading > 2) m_crossFading = 2; //queue for crossfading bool result = QueueNextFile(file, false); if (result) { //crossfading value may be update by QueueNextFile when nr of channels changed if (!m_crossFading) // swap to next track m_decoder[m_currentDecoder].SetStatus(STATUS_ENDED); else //force to fade to next track immediately m_forceFadeToNext = true; } return result; } // normal opening of file, nothing playing or crossfading not enabled // however no need to return to gui audio device CloseFileInternal(false); // always open the file using the current decoder m_currentDecoder = 0; if (!m_decoder[m_currentDecoder].Create(file, (__int64)(options.starttime * 1000), m_crossFading)) return false; m_iSpeed = 1; m_bPaused = false; m_bStopPlaying = false; m_bytesSentOut = 0; CLog::Log(LOGINFO, "PAPlayer: Playing %s", file.m_strPath.c_str()); m_timeOffset = (__int64)(options.starttime * 1000); unsigned int channel, sampleRate, bitsPerSample; m_decoder[m_currentDecoder].GetDataFormat(&channel, &sampleRate, &bitsPerSample); if (!CreateStream(m_currentStream, channel, sampleRate, bitsPerSample)) { m_decoder[m_currentDecoder].Destroy(); CLog::Log(LOGERROR, "PAPlayer::Unable to create audio stream"); } *m_currentFile = file; if (ThreadHandle() == NULL) Create(); m_startEvent.Set(); m_bIsPlaying = true; m_cachingNextFile = false; m_currentlyCrossFading = false; m_forceFadeToNext = false; m_bQueueFailed = false; m_decoder[m_currentDecoder].Start(); // start playback return true; }
bool PAPlayer::QueueNextFileEx(const CFileItem &file, bool fadeIn/* = true */, bool job /* = false */) { // 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; } 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; // 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); } // set m_upcomingCrossfadeMS depending on type of file and user settings 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; // 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; } 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; }