2 * Copyright (C) 2005-2008 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18 * http://www.gnu.org/copyleft/gpl.html
23 #include "CodecFactory.h"
24 #include "GUIInfoManager.h"
25 #include "Application.h"
27 #include "settings/AdvancedSettings.h"
28 #include "settings/GUISettings.h"
29 #include "settings/Settings.h"
30 #include "music/tags/MusicInfoTag.h"
31 #include "utils/TimeUtils.h"
32 #include "utils/log.h"
33 #include "utils/MathUtils.h"
35 #include "threads/SingleLock.h"
36 #include "cores/AudioEngine/AEFactory.h"
37 #include "cores/AudioEngine/Utils/AEUtil.h"
38 #include "cores/AudioEngine/Interfaces/AEStream.h"
40 #define TIME_TO_CACHE_NEXT_FILE 5000 /* 5 seconds before end of song, start caching the next song */
41 #define FAST_XFADE_TIME 80 /* 80 milliseconds */
42 #define MAX_SKIP_XFADE_TIME 2000 /* max 2 seconds crossfade on track skip */
44 CAEChannelInfo ICodec::GetChannelInfo()
46 return CAEUtil::GuessChLayout(m_Channels);
49 // PAP: Psycho-acoustic Audio Player
50 // Supporting all open audio codec standards.
51 // First one being nullsoft's nsv audio decoder format
53 PAPlayer::PAPlayer(IPlayerCallback& callback) :
56 m_signalSpeedChange (false),
61 m_defaultCrossfadeMS (0),
62 m_upcomingCrossfadeMS(0),
63 m_currentStream (NULL ),
64 m_audioCallback (NULL ),
65 m_FileItem (new CFileItem())
73 CloseAllStreams(false);
75 /* wait for the thread to terminate */
76 StopThread(true);//true - wait for end of thread
80 bool PAPlayer::HandlesType(const CStdString &type)
82 ICodec* codec = CodecFactory::CreateCodec(type);
83 if (codec && codec->CanInit())
92 void PAPlayer::SoftStart(bool wait/* = false */)
94 CSharedLock lock(m_streamsLock);
95 for(StreamList::iterator itt = m_streams.begin(); itt != m_streams.end(); ++itt)
97 StreamInfo* si = *itt;
98 if (si->m_fadeOutTriggered)
101 si->m_stream->FadeVolume(0.0f, 1.0f, FAST_XFADE_TIME);
102 si->m_stream->Resume();
107 /* wait for them to fade in */
109 Sleep(FAST_XFADE_TIME);
112 /* be sure they have faded in */
116 for(StreamList::iterator itt = m_streams.begin(); itt != m_streams.end(); ++itt)
118 StreamInfo* si = *itt;
119 if (si->m_stream->IsFading())
132 void PAPlayer::SoftStop(bool wait/* = false */, bool close/* = true */)
134 /* fade all the streams out fast for a nice soft stop */
135 CSharedLock lock(m_streamsLock);
136 for(StreamList::iterator itt = m_streams.begin(); itt != m_streams.end(); ++itt)
138 StreamInfo* si = *itt;
140 si->m_stream->FadeVolume(1.0f, 0.0f, FAST_XFADE_TIME);
144 si->m_prepareTriggered = true;
145 si->m_playNextTriggered = true;
146 si->m_fadeOutTriggered = true;
150 /* if we are going to wait for them to finish fading */
153 /* wait for them to fade out */
155 Sleep(FAST_XFADE_TIME);
158 /* be sure they have faded out */
162 for(StreamList::iterator itt = m_streams.begin(); itt != m_streams.end(); ++itt)
164 StreamInfo* si = *itt;
165 if (si->m_stream && si->m_stream->IsFading())
176 /* if we are not closing the streams, pause them */
179 for(StreamList::iterator itt = m_streams.begin(); itt != m_streams.end(); ++itt)
181 StreamInfo* si = *itt;
182 si->m_stream->Pause();
188 void PAPlayer::CloseAllStreams(bool fade/* = true */)
192 CExclusiveLock lock(m_streamsLock);
193 while(!m_streams.empty())
195 StreamInfo* si = m_streams.front();
196 m_streams.pop_front();
200 CAEFactory::FreeStream(si->m_stream);
204 si->m_decoder.Destroy();
208 while(!m_finishing.empty())
210 StreamInfo* si = m_finishing.front();
211 m_finishing.pop_front();
215 CAEFactory::FreeStream(si->m_stream);
219 si->m_decoder.Destroy();
222 m_currentStream = NULL;
226 SoftStop(false, true);
227 CExclusiveLock lock(m_streamsLock);
228 m_currentStream = NULL;
232 bool PAPlayer::OpenFile(const CFileItem& file, const CPlayerOptions &options)
234 m_defaultCrossfadeMS = g_guiSettings.GetInt("musicplayer.crossfade") * 1000;
236 if (m_streams.size() > 1 || !m_defaultCrossfadeMS)
241 if (!QueueNextFileEx(file, false))
244 CSharedLock lock(m_streamsLock);
245 if (m_streams.size() == 2)
247 //do a short crossfade on trackskip, set to max 2 seconds for these prev/next transitions
248 m_upcomingCrossfadeMS = std::min(m_defaultCrossfadeMS, (unsigned int)MAX_SKIP_XFADE_TIME);
250 //start transition to next track
251 StreamInfo* si = m_streams.front();
252 si->m_playNextAtFrame = si->m_framesSent; //start next track at current frame
253 si->m_prepareTriggered = true; //next track is ready to go
260 /* trigger playback start */
266 void PAPlayer::UpdateCrossfadeTime(const CFileItem& file)
268 m_upcomingCrossfadeMS = m_defaultCrossfadeMS = g_guiSettings.GetInt("musicplayer.crossfade") * 1000;
269 if (m_upcomingCrossfadeMS)
272 file.HasMusicInfoTag() && !g_guiSettings.GetBool("musicplayer.crossfadealbumtracks") &&
273 m_FileItem->HasMusicInfoTag() &&
274 (m_FileItem->GetMusicInfoTag()->GetAlbum() != "") &&
275 (m_FileItem->GetMusicInfoTag()->GetAlbum() == file.GetMusicInfoTag()->GetAlbum()) &&
276 (m_FileItem->GetMusicInfoTag()->GetDiscNumber() == file.GetMusicInfoTag()->GetDiscNumber()) &&
277 (m_FileItem->GetMusicInfoTag()->GetTrackNumber() == file.GetMusicInfoTag()->GetTrackNumber() - 1)
280 //do not crossfade when playing consecutive albumtracks
281 m_upcomingCrossfadeMS = 0;
286 bool PAPlayer::QueueNextFile(const CFileItem &file)
288 return QueueNextFileEx(file);
291 bool PAPlayer::QueueNextFileEx(const CFileItem &file, bool fadeIn/* = true */)
293 StreamInfo *si = new StreamInfo();
295 if (!si->m_decoder.Create(file, (file.m_lStartOffset * 1000) / 75))
297 CLog::Log(LOGWARNING, "PAPlayer::QueueNextFileEx - Failed to create the decoder");
300 m_callback.OnQueueNextItem();
304 /* decode until there is data-available */
305 si->m_decoder.Start();
306 while(si->m_decoder.GetDataSize() == 0)
308 int status = si->m_decoder.GetStatus();
309 if (status == STATUS_ENDED ||
310 status == STATUS_NO_FILE ||
311 si->m_decoder.ReadSamples(PACKET_SIZE) == RET_ERROR)
313 CLog::Log(LOGINFO, "PAPlayer::QueueNextFileEx - Error reading samples");
315 si->m_decoder.Destroy();
317 m_callback.OnQueueNextItem();
321 /* yield our time so that the main PAP thread doesnt stall */
325 UpdateCrossfadeTime(file);
327 /* init the streaminfo struct */
328 si->m_decoder.GetDataFormat(&si->m_channelInfo, &si->m_sampleRate, &si->m_encodedSampleRate, &si->m_dataFormat);
329 si->m_startOffset = file.m_lStartOffset * 1000 / 75;
330 si->m_endOffset = file.m_lEndOffset * 1000 / 75;
331 si->m_bytesPerSample = CAEUtil::DataFormatToBits(si->m_dataFormat) >> 3;
332 si->m_bytesPerFrame = si->m_bytesPerSample * si->m_channelInfo.Count();
333 si->m_started = false;
334 si->m_finishing = false;
335 si->m_framesSent = 0;
336 si->m_seekNextAtFrame = 0;
337 si->m_seekFrame = -1;
339 si->m_volume = (fadeIn && m_upcomingCrossfadeMS) ? 0.0f : 1.0f;
340 si->m_fadeOutTriggered = false;
341 si->m_isSlaved = false;
343 int64_t streamTotalTime = si->m_decoder.TotalTime();
345 streamTotalTime = si->m_endOffset - si->m_startOffset;
347 si->m_prepareNextAtFrame = 0;
348 if (streamTotalTime >= TIME_TO_CACHE_NEXT_FILE + m_defaultCrossfadeMS)
349 si->m_prepareNextAtFrame = (int)((streamTotalTime - TIME_TO_CACHE_NEXT_FILE - m_defaultCrossfadeMS) * si->m_sampleRate / 1000.0f);
351 si->m_prepareTriggered = false;
353 si->m_playNextAtFrame = 0;
354 si->m_playNextTriggered = false;
358 /* add the stream to the list */
359 CExclusiveLock lock(m_streamsLock);
360 m_streams.push_back(si);
361 //update the current stream to start playing the next track at the correct frame.
362 UpdateStreamInfoPlayNextAtFrame(m_currentStream, m_upcomingCrossfadeMS);
369 void PAPlayer::UpdateStreamInfoPlayNextAtFrame(StreamInfo *si, unsigned int crossFadingTime)
373 int64_t streamTotalTime = si->m_decoder.TotalTime();
375 streamTotalTime = si->m_endOffset - si->m_startOffset;
376 if (streamTotalTime < crossFadingTime)
377 si->m_playNextAtFrame = (int)((streamTotalTime / 2) * si->m_sampleRate / 1000.0f);
379 si->m_playNextAtFrame = (int)((streamTotalTime - crossFadingTime) * si->m_sampleRate / 1000.0f);
383 inline bool PAPlayer::PrepareStream(StreamInfo *si)
385 /* if we have a stream we are already prepared */
389 /* get a paused stream */
390 si->m_stream = CAEFactory::MakeStream(
393 si->m_encodedSampleRate,
400 CLog::Log(LOGDEBUG, "PAPlayer::PrepareStream - Failed to get IAEStream");
404 si->m_stream->SetVolume (si->m_volume);
405 si->m_stream->SetReplayGain(si->m_decoder.GetReplayGain());
407 /* if its not the first stream and crossfade is not enabled */
408 if (m_currentStream && m_currentStream != si && !m_upcomingCrossfadeMS)
410 /* slave the stream for gapless */
411 si->m_isSlaved = true;
412 m_currentStream->m_stream->RegisterSlave(si->m_stream);
415 /* fill the stream's buffer */
416 while(si->m_stream->IsBuffering())
418 int status = si->m_decoder.GetStatus();
419 if (status == STATUS_ENDED ||
420 status == STATUS_NO_FILE ||
421 si->m_decoder.ReadSamples(PACKET_SIZE) == RET_ERROR)
423 CLog::Log(LOGINFO, "PAPlayer::PrepareStream - Stream Finished");
430 /* yield our time so that the main PAP thread doesnt stall */
434 CLog::Log(LOGINFO, "PAPlayer::PrepareStream - Ready");
439 bool PAPlayer::CloseFile()
441 m_callback.OnPlayBackStopped();
445 void PAPlayer::Process()
447 if (!m_startEvent.WaitMSec(100))
449 CLog::Log(LOGDEBUG, "PAPlayer::Process - Failed to receive start event");
453 CLog::Log(LOGDEBUG, "PAPlayer::Process - Playback started");
454 while(m_isPlaying && !m_bStop)
456 /* this needs to happen outside of any locks to prevent deadlocks */
457 if (m_signalSpeedChange)
459 m_callback.OnPlayBackSpeedChanged(m_playbackSpeed);
460 m_signalSpeedChange = false;
463 double delay = 100.0;
464 double buffer = 100.0;
465 ProcessStreams(delay, buffer);
467 if (delay < buffer && delay > 0.75 * buffer)
468 CThread::Sleep(MathUtils::round_int((buffer - delay) * 1000.0));
472 inline void PAPlayer::ProcessStreams(double &delay, double &buffer)
474 CSharedLock sharedLock(m_streamsLock);
475 if (m_isFinished && m_streams.empty() && m_finishing.empty())
479 m_callback.OnPlayBackEnded();
483 /* destroy any drained streams */
484 for(StreamList::iterator itt = m_finishing.begin(); itt != m_finishing.end();)
486 StreamInfo* si = *itt;
487 if (si->m_stream->IsDrained())
489 itt = m_finishing.erase(itt);
490 CAEFactory::FreeStream(si->m_stream);
492 CLog::Log(LOGDEBUG, "PAPlayer::ProcessStreams - Stream Freed");
499 CExclusiveLock lock(m_streamsLock);
501 for(StreamList::iterator itt = m_streams.begin(); itt != m_streams.end(); ++itt)
503 StreamInfo* si = *itt;
504 if (!m_currentStream && !si->m_started)
505 m_currentStream = si;
506 /* if the stream is finishing */
507 if ((si->m_playNextTriggered && si->m_stream && !si->m_stream->IsFading()) || !ProcessStream(si, delay, buffer))
509 if (!si->m_prepareTriggered)
511 si->m_prepareTriggered = true;
512 m_callback.OnQueueNextItem();
515 /* remove the stream */
516 itt = m_streams.erase(itt);
517 /* if its the current stream */
518 if (si == m_currentStream)
520 /* if it was the last stream */
521 if (itt == m_streams.end())
523 /* if it didnt trigger the next queue item */
524 if (!si->m_prepareTriggered)
526 m_callback.OnQueueNextItem();
527 si->m_prepareTriggered = true;
529 m_currentStream = NULL;
533 m_currentStream = *itt;
537 /* unregister the audio callback */
538 si->m_stream->UnRegisterAudioCallback();
539 si->m_decoder.Destroy();
540 si->m_stream->Drain();
541 m_finishing.push_back(si);
548 /* is it time to prepare the next stream? */
549 if (si->m_prepareNextAtFrame > 0 && !si->m_prepareTriggered && si->m_framesSent >= si->m_prepareNextAtFrame)
551 si->m_prepareTriggered = true;
552 m_callback.OnQueueNextItem();
555 /* it is time to start playing the next stream? */
556 if (si->m_playNextAtFrame > 0 && !si->m_playNextTriggered && si->m_framesSent >= si->m_playNextAtFrame)
558 if (!si->m_prepareTriggered)
560 si->m_prepareTriggered = true;
561 m_callback.OnQueueNextItem();
566 if (m_upcomingCrossfadeMS)
568 si->m_stream->FadeVolume(1.0f, 0.0f, m_upcomingCrossfadeMS);
569 si->m_fadeOutTriggered = true;
571 m_currentStream = NULL;
573 /* unregister the audio callback */
574 si->m_stream->UnRegisterAudioCallback();
577 si->m_playNextTriggered = true;
582 inline bool PAPlayer::ProcessStream(StreamInfo *si, double &delay, double &buffer)
584 /* if playback needs to start on this stream, do it */
585 if (si == m_currentStream && !si->m_started)
587 si->m_started = true;
588 si->m_stream->RegisterAudioCallback(m_audioCallback);
590 si->m_stream->Resume();
591 si->m_stream->FadeVolume(0.0f, 1.0f, m_upcomingCrossfadeMS);
592 m_callback.OnPlayBackStarted();
595 /* if we have not started yet and the stream has been primed */
596 unsigned int space = si->m_stream->GetSpace();
597 if (!si->m_started && !space)
600 /* see if it is time yet to FF/RW or a direct seek */
601 if (!si->m_playNextTriggered && ((m_playbackSpeed != 1 && si->m_framesSent >= si->m_seekNextAtFrame) || si->m_seekFrame > -1))
603 int64_t time = (int64_t)0;
604 /* if its a direct seek */
605 if (si->m_seekFrame > -1)
607 time = (int64_t)((float)si->m_seekFrame / (float)si->m_sampleRate * 1000.0f);
608 si->m_framesSent = (int)(si->m_seekFrame - ((float)si->m_startOffset * (float)si->m_sampleRate) / 1000.0f);
609 si->m_seekFrame = -1;
614 si->m_framesSent += si->m_sampleRate * (m_playbackSpeed - 1);
615 si->m_seekNextAtFrame = si->m_framesSent + si->m_sampleRate / 2;
616 time = (int64_t)(((float)si->m_framesSent / (float)si->m_sampleRate * 1000.0f) + (float)si->m_startOffset);
619 /* if we are seeking back before the start of the track start normal playback */
620 if (time < si->m_startOffset || si->m_framesSent < 0)
622 time = si->m_startOffset;
623 si->m_framesSent = (int)(si->m_startOffset * si->m_sampleRate / 1000);
624 si->m_seekNextAtFrame = 0;
628 si->m_decoder.Seek(time);
631 int status = si->m_decoder.GetStatus();
632 if (status == STATUS_ENDED ||
633 status == STATUS_NO_FILE ||
634 si->m_decoder.ReadSamples(PACKET_SIZE) == RET_ERROR ||
635 ((si->m_endOffset) && (si->m_framesSent / si->m_sampleRate >= (si->m_endOffset - si->m_startOffset) / 1000)))
637 CLog::Log(LOGINFO, "PAPlayer::ProcessStream - Stream Finished");
644 /* update the delay time if we are running */
647 if (si->m_stream->IsBuffering())
650 delay = std::min(delay , si->m_stream->GetDelay());
651 buffer = std::min(buffer, si->m_stream->GetCacheTotal());
657 bool PAPlayer::QueueData(StreamInfo *si)
659 unsigned int space = si->m_stream->GetSpace();
660 unsigned int samples = std::min(si->m_decoder.GetDataSize(), space / si->m_bytesPerSample);
664 void* data = si->m_decoder.GetData(samples);
667 CLog::Log(LOGERROR, "PAPlayer::QueueData - Failed to get data from the decoder");
671 unsigned int added = si->m_stream->AddData(data, samples * si->m_bytesPerSample);
672 si->m_framesSent += added / si->m_bytesPerFrame;
677 void PAPlayer::OnExit()
682 void PAPlayer::RegisterAudioCallback(IAudioCallback* pCallback)
684 CSharedLock lock(m_streamsLock);
685 m_audioCallback = pCallback;
686 if (m_currentStream && m_currentStream->m_stream)
687 m_currentStream->m_stream->RegisterAudioCallback(pCallback);
690 void PAPlayer::UnRegisterAudioCallback()
692 CSharedLock lock(m_streamsLock);
693 /* only one stream should have the callback, but we do it to all just incase */
694 for(StreamList::iterator itt = m_streams.begin(); itt != m_streams.end(); ++itt)
695 if ((*itt)->m_stream)
696 (*itt)->m_stream->UnRegisterAudioCallback();
697 m_audioCallback = NULL;
700 void PAPlayer::OnNothingToQueueNotify()
705 bool PAPlayer::IsPlaying() const
710 bool PAPlayer::IsPaused() const
715 void PAPlayer::Pause()
725 SoftStop(true, false);
729 void PAPlayer::SetVolume(float volume)
734 void PAPlayer::SetDynamicRangeCompression(long drc)
739 void PAPlayer::ToFFRW(int iSpeed)
741 m_playbackSpeed = iSpeed;
742 m_signalSpeedChange = true;
745 int64_t PAPlayer::GetTime()
747 CSharedLock lock(m_streamsLock);
748 if (!m_currentStream)
751 double time = ((double)m_currentStream->m_framesSent / (double)m_currentStream->m_sampleRate);
752 if (m_currentStream->m_stream)
753 time -= m_currentStream->m_stream->GetDelay();
755 return (int64_t)(time * 1000.0);
758 int64_t PAPlayer::GetTotalTime64()
760 CSharedLock lock(m_streamsLock);
761 if (!m_currentStream)
764 int64_t total = m_currentStream->m_decoder.TotalTime();
765 if (m_currentStream->m_endOffset)
766 total = m_currentStream->m_endOffset;
767 total -= m_currentStream->m_startOffset;
771 int PAPlayer::GetTotalTime()
773 return (int)(GetTotalTime64() / 1000);
776 int PAPlayer::GetCacheLevel() const
778 CSharedLock lock(m_streamsLock);
779 if (!m_currentStream)
782 const ICodec* codec = m_currentStream->m_decoder.GetCodec();
784 return codec->GetCacheLevel();
788 int PAPlayer::GetChannels()
790 CSharedLock lock(m_streamsLock);
791 if (!m_currentStream)
794 return m_currentStream->m_channelInfo.Count();
797 int PAPlayer::GetBitsPerSample()
799 CSharedLock lock(m_streamsLock);
800 if (!m_currentStream)
803 return m_currentStream->m_bytesPerSample >> 3;
806 int PAPlayer::GetSampleRate()
808 CSharedLock lock(m_streamsLock);
809 if (!m_currentStream)
812 return m_currentStream->m_sampleRate;
815 CStdString PAPlayer::GetAudioCodecName()
817 CSharedLock lock(m_streamsLock);
818 if (!m_currentStream)
821 const ICodec* codec = m_currentStream->m_decoder.GetCodec();
823 return codec->m_CodecName;
827 int PAPlayer::GetAudioBitrate()
829 CSharedLock lock(m_streamsLock);
830 if (!m_currentStream)
833 const ICodec* codec = m_currentStream->m_decoder.GetCodec();
835 return codec->m_Bitrate;
839 bool PAPlayer::CanSeek()
841 CSharedLock lock(m_streamsLock);
842 if (!m_currentStream)
845 return m_currentStream->m_decoder.CanSeek();
848 void PAPlayer::Seek(bool bPlus, bool bLargeStep)
852 void PAPlayer::SeekTime(int64_t iTime /*=0*/)
854 if (!CanSeek()) return;
856 CSharedLock lock(m_streamsLock);
857 if (!m_currentStream)
860 int seekOffset = (int)(iTime - GetTime());
861 /*if (m_currentStream->m_startOffset)
862 iTime += m_currentStream->m_startOffset;*/
864 if (m_playbackSpeed != 1)
867 m_currentStream->m_seekFrame = (int)((float)m_currentStream->m_sampleRate * ((float)iTime + (float)m_currentStream->m_startOffset) / 1000.0f);
868 m_callback.OnPlayBackSeek((int)iTime, seekOffset);
871 void PAPlayer::SeekPercentage(float fPercent /*=0*/)
873 if (fPercent < 0.0f ) fPercent = 0.0f;
874 if (fPercent > 100.0f) fPercent = 100.0f;
875 SeekTime((int64_t)(fPercent * 0.01f * (float)GetTotalTime64()));
878 float PAPlayer::GetPercentage()
880 return GetTime() * 100.0f / GetTotalTime64();
883 bool PAPlayer::SkipNext()