[release] version bump to 13.0 beta1
[vuplus_xbmc] / xbmc / cores / paplayer / PAPlayer.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://xbmc.org
4  *
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)
8  *  any later version.
9  *
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.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "PAPlayer.h"
22 #include "CodecFactory.h"
23 #include "FileItem.h"
24 #include "settings/AdvancedSettings.h"
25 #include "settings/Settings.h"
26 #include "music/tags/MusicInfoTag.h"
27 #include "utils/TimeUtils.h"
28 #include "utils/log.h"
29 #include "utils/MathUtils.h"
30 #include "utils/JobManager.h"
31
32 #include "threads/SingleLock.h"
33 #include "cores/AudioEngine/AEFactory.h"
34 #include "cores/AudioEngine/Utils/AEUtil.h"
35 #include "cores/AudioEngine/Interfaces/AEStream.h"
36
37 #define TIME_TO_CACHE_NEXT_FILE 5000 /* 5 seconds before end of song, start caching the next song */
38 #define FAST_XFADE_TIME           80 /* 80 milliseconds */
39 #define MAX_SKIP_XFADE_TIME     2000 /* max 2 seconds crossfade on track skip */
40
41 CAEChannelInfo ICodec::GetChannelInfo()
42 {
43   return CAEUtil::GuessChLayout(m_Channels);
44 }
45
46 class CQueueNextFileJob : public CJob
47 {
48   CFileItem m_item;
49   PAPlayer &m_player;
50
51 public:
52                 CQueueNextFileJob(const CFileItem& item, PAPlayer &player)
53                   : m_item(item), m_player(player) {}
54   virtual       ~CQueueNextFileJob() {}
55   virtual bool  DoWork()
56   {
57     return m_player.QueueNextFileEx(m_item, true, true);
58   }
59 };
60
61 // PAP: Psycho-acoustic Audio Player
62 // Supporting all open  audio codec standards.
63 // First one being nullsoft's nsv audio decoder format
64
65 PAPlayer::PAPlayer(IPlayerCallback& callback) :
66   IPlayer              (callback),
67   CThread              ("PAPlayer"),
68   m_signalSpeedChange  (false),
69   m_playbackSpeed      (1    ),
70   m_isPlaying          (false),
71   m_isPaused           (false),
72   m_isFinished         (false),
73   m_defaultCrossfadeMS (0),
74   m_upcomingCrossfadeMS(0),
75   m_currentStream      (NULL ),
76   m_audioCallback      (NULL ),
77   m_FileItem           (new CFileItem()),
78   m_jobCounter         (0),
79   m_continueStream     (false)
80 {
81   memset(&m_playerGUIData, 0, sizeof(m_playerGUIData));
82 }
83
84 PAPlayer::~PAPlayer()
85 {
86   CloseFile();
87   delete m_FileItem;
88 }
89
90 bool PAPlayer::HandlesType(const CStdString &type)
91 {
92   ICodec* codec = CodecFactory::CreateCodec(type);
93   if (codec && codec->CanInit())
94   {
95     delete codec;
96     return true;
97   }
98
99   return false;
100 }
101
102 void PAPlayer::SoftStart(bool wait/* = false */)
103 {
104   CSharedLock lock(m_streamsLock);
105   for(StreamList::iterator itt = m_streams.begin(); itt != m_streams.end(); ++itt)
106   {
107     StreamInfo* si = *itt;
108     if (si->m_fadeOutTriggered)
109       continue;
110
111     si->m_stream->Resume();
112     si->m_stream->FadeVolume(0.0f, 1.0f, FAST_XFADE_TIME);
113   }
114   
115   if (wait)
116   {
117     /* wait for them to fade in */
118     lock.Leave();
119     Sleep(FAST_XFADE_TIME);
120     lock.Enter();
121
122     /* be sure they have faded in */
123     while(wait)
124     {
125       wait = false;
126       for(StreamList::iterator itt = m_streams.begin(); itt != m_streams.end(); ++itt)
127       {
128         StreamInfo* si = *itt;
129         if (si->m_stream->IsFading())
130         {
131           lock.Leave();
132           wait = true;
133           Sleep(1);
134           lock.Enter();
135           break;
136         }
137       }
138     }
139   }
140 }
141
142 void PAPlayer::SoftStop(bool wait/* = false */, bool close/* = true */)
143 {
144   /* fade all the streams out fast for a nice soft stop */
145   CSharedLock lock(m_streamsLock);
146   for(StreamList::iterator itt = m_streams.begin(); itt != m_streams.end(); ++itt)
147   {
148     StreamInfo* si = *itt;
149     if (si->m_stream)
150       si->m_stream->FadeVolume(1.0f, 0.0f, FAST_XFADE_TIME);
151
152     if (close)
153     {
154       si->m_prepareTriggered  = true;
155       si->m_playNextTriggered = true;
156       si->m_fadeOutTriggered  = true;
157     }
158   }
159
160   /* if we are going to wait for them to finish fading */
161   if(wait)
162   {
163     /* wait for them to fade out */
164     lock.Leave();
165     Sleep(FAST_XFADE_TIME);
166     lock.Enter();
167
168     /* be sure they have faded out */
169     while(wait && !CAEFactory::IsSuspended())
170     {
171       wait = false;
172       for(StreamList::iterator itt = m_streams.begin(); itt != m_streams.end(); ++itt)
173       {
174         StreamInfo* si = *itt;
175         if (si->m_stream && si->m_stream->IsFading())
176         {
177           lock.Leave();
178           wait = true;
179           Sleep(1);
180           lock.Enter();
181           break;
182         }
183       }
184     }
185
186     /* if we are not closing the streams, pause them */
187     if (!close)
188     {
189       for(StreamList::iterator itt = m_streams.begin(); itt != m_streams.end(); ++itt)
190       {
191         StreamInfo* si = *itt;
192         si->m_stream->Pause();
193       }
194     }
195   }
196 }
197
198 void PAPlayer::CloseAllStreams(bool fade/* = true */)
199 {
200   if (!fade) 
201   {
202     CExclusiveLock lock(m_streamsLock);
203     while(!m_streams.empty())
204     {
205       StreamInfo* si = m_streams.front();
206       m_streams.pop_front();
207       
208       if (si->m_stream)
209       {
210         CAEFactory::FreeStream(si->m_stream);
211         si->m_stream = NULL;
212       }
213
214       si->m_decoder.Destroy();
215       delete si;
216     }
217
218     while(!m_finishing.empty())
219     {
220       StreamInfo* si = m_finishing.front();
221       m_finishing.pop_front();
222
223       if (si->m_stream)
224       {
225         CAEFactory::FreeStream(si->m_stream);
226         si->m_stream = NULL;
227       }
228
229       si->m_decoder.Destroy();
230       delete si;
231     }
232     m_currentStream = NULL;
233   }
234   else
235   {
236     SoftStop(false, true);
237     CExclusiveLock lock(m_streamsLock);
238     m_currentStream = NULL;
239   }  
240 }
241
242 bool PAPlayer::OpenFile(const CFileItem& file, const CPlayerOptions &options)
243 {
244   m_defaultCrossfadeMS = CSettings::Get().GetInt("musicplayer.crossfade") * 1000;
245
246   if (m_streams.size() > 1 || !m_defaultCrossfadeMS || m_isPaused)
247   {
248     CloseAllStreams(!m_isPaused);
249     StopThread();
250     m_isPaused = false; // Make sure to reset the pause state
251   }
252
253   if (!QueueNextFileEx(file, false))
254     return false;
255
256   CSharedLock lock(m_streamsLock);
257   if (m_streams.size() == 2)
258   {
259     //do a short crossfade on trackskip, set to max 2 seconds for these prev/next transitions
260     m_upcomingCrossfadeMS = std::min(m_defaultCrossfadeMS, (unsigned int)MAX_SKIP_XFADE_TIME);
261
262     //start transition to next track
263     StreamInfo* si = m_streams.front();
264     si->m_playNextAtFrame  = si->m_framesSent; //start next track at current frame
265     si->m_prepareTriggered = true; //next track is ready to go
266   }
267   lock.Leave();
268
269   if (!IsRunning())
270     Create();
271
272   /* trigger playback start */
273   m_isPlaying = true;
274   m_startEvent.Set();
275   return true;
276 }
277
278 void PAPlayer::UpdateCrossfadeTime(const CFileItem& file)
279 {
280   // we explicitely disable crossfading for audio cds
281   if(file.IsCDDA())
282    m_upcomingCrossfadeMS = 0;
283   else
284     m_upcomingCrossfadeMS = m_defaultCrossfadeMS = CSettings::Get().GetInt("musicplayer.crossfade") * 1000;
285   if (m_upcomingCrossfadeMS)
286   {
287     if (m_streams.size() == 0 ||
288          (
289             file.HasMusicInfoTag() && !CSettings::Get().GetBool("musicplayer.crossfadealbumtracks") &&
290             m_FileItem->HasMusicInfoTag() &&
291             (m_FileItem->GetMusicInfoTag()->GetAlbum() != "") &&
292             (m_FileItem->GetMusicInfoTag()->GetAlbum() == file.GetMusicInfoTag()->GetAlbum()) &&
293             (m_FileItem->GetMusicInfoTag()->GetDiscNumber() == file.GetMusicInfoTag()->GetDiscNumber()) &&
294             (m_FileItem->GetMusicInfoTag()->GetTrackNumber() == file.GetMusicInfoTag()->GetTrackNumber() - 1)
295          )
296        )
297     {
298       //do not crossfade when playing consecutive albumtracks
299       m_upcomingCrossfadeMS = 0;
300     }
301   }
302 }
303
304 bool PAPlayer::QueueNextFile(const CFileItem &file)
305 {
306   {
307     CExclusiveLock lock(m_streamsLock);
308     m_jobCounter++;
309   }
310   CJobManager::GetInstance().AddJob(new CQueueNextFileJob(file, *this), this, CJob::PRIORITY_NORMAL);
311   return true;
312 }
313
314 bool PAPlayer::QueueNextFileEx(const CFileItem &file, bool fadeIn/* = true */, bool job /* = false */)
315 {
316   StreamInfo *si = new StreamInfo();
317
318   // check if we advance a track of a CUE sheet
319   // if this is the case we don't need to open a new stream
320   std::string newURL = file.GetMusicInfoTag() ? file.GetMusicInfoTag()->GetURL() : file.GetPath();
321   std::string oldURL = m_FileItem->GetMusicInfoTag() ? m_FileItem->GetMusicInfoTag()->GetURL() : m_FileItem->GetPath();
322   if (newURL.compare(oldURL) == 0 &&
323       file.m_lStartOffset &&
324       file.m_lStartOffset == m_FileItem->m_lEndOffset &&
325       m_currentStream && m_currentStream->m_prepareTriggered)
326   {
327     m_continueStream = true;
328     m_upcomingCrossfadeMS = 0;
329     *m_FileItem = file;
330     return true;
331   }
332   else
333   {
334     m_continueStream = false;
335   }
336
337   if (!si->m_decoder.Create(file, (file.m_lStartOffset * 1000) / 75))
338   {
339     CLog::Log(LOGWARNING, "PAPlayer::QueueNextFileEx - Failed to create the decoder");
340
341     delete si;
342     // advance playlist
343     if (job)
344       m_callback.OnPlayBackStarted();
345     m_callback.OnQueueNextItem();
346     return false;
347   }
348
349   /* decode until there is data-available */
350   si->m_decoder.Start();
351   while(si->m_decoder.GetDataSize() == 0)
352   {
353     int status = si->m_decoder.GetStatus();
354     if (status == STATUS_ENDED   ||
355         status == STATUS_NO_FILE ||
356         si->m_decoder.ReadSamples(PACKET_SIZE) == RET_ERROR)
357     {
358       CLog::Log(LOGINFO, "PAPlayer::QueueNextFileEx - Error reading samples");
359
360       si->m_decoder.Destroy();
361       delete si;
362       // advance playlist
363       if (job)
364         m_callback.OnPlayBackStarted();
365       m_callback.OnQueueNextItem();
366       return false;
367     }
368
369     /* yield our time so that the main PAP thread doesnt stall */
370     CThread::Sleep(1);
371   }
372
373   /* init the streaminfo struct */
374   si->m_decoder.GetDataFormat(&si->m_channelInfo, &si->m_sampleRate, &si->m_encodedSampleRate, &si->m_dataFormat);
375   si->m_startOffset        = file.m_lStartOffset * 1000 / 75;
376   si->m_endOffset          = file.m_lEndOffset   * 1000 / 75;
377   si->m_bytesPerSample     = CAEUtil::DataFormatToBits(si->m_dataFormat) >> 3;
378   si->m_bytesPerFrame      = si->m_bytesPerSample * si->m_channelInfo.Count();
379   si->m_started            = false;
380   si->m_finishing          = false;
381   si->m_framesSent         = 0;
382   si->m_seekNextAtFrame    = 0;
383   si->m_seekFrame          = -1;
384   si->m_stream             = NULL;
385   si->m_volume             = (fadeIn && m_upcomingCrossfadeMS) ? 0.0f : 1.0f;
386   si->m_fadeOutTriggered   = false;
387   si->m_isSlaved           = false;
388
389   int64_t streamTotalTime = si->m_decoder.TotalTime();
390   if (si->m_endOffset)
391     streamTotalTime = si->m_endOffset - si->m_startOffset;
392   
393   si->m_prepareNextAtFrame = 0;
394   // cd drives don't really like it to be crossfaded or prepared
395   if(!file.IsCDDA())
396   {
397     if (streamTotalTime >= TIME_TO_CACHE_NEXT_FILE + m_defaultCrossfadeMS)
398       si->m_prepareNextAtFrame = (int)((streamTotalTime - TIME_TO_CACHE_NEXT_FILE - m_defaultCrossfadeMS) * si->m_sampleRate / 1000.0f);
399   }
400
401   if (m_currentStream && (AE_IS_RAW(m_currentStream->m_dataFormat) || AE_IS_RAW(si->m_dataFormat)))
402   {
403     m_currentStream->m_prepareTriggered = false;
404     m_currentStream->m_waitOnDrain = true;
405     m_currentStream->m_prepareNextAtFrame = 0;
406     si->m_decoder.Destroy();
407     delete si;
408     return false;
409   }
410
411   UpdateCrossfadeTime(file);
412
413   si->m_prepareTriggered = false;
414   si->m_playNextAtFrame = 0;
415   si->m_playNextTriggered = false;
416   si->m_waitOnDrain = false;
417
418   if (!PrepareStream(si))
419   {
420     CLog::Log(LOGINFO, "PAPlayer::QueueNextFileEx - Error preparing stream");
421     
422     si->m_decoder.Destroy();
423     delete si;
424     // advance playlist
425     if (job)
426       m_callback.OnPlayBackStarted();
427     m_callback.OnQueueNextItem();
428     return false;
429   }
430
431   /* add the stream to the list */
432   CExclusiveLock lock(m_streamsLock);
433   m_streams.push_back(si);
434   //update the current stream to start playing the next track at the correct frame.
435   UpdateStreamInfoPlayNextAtFrame(m_currentStream, m_upcomingCrossfadeMS);
436
437   *m_FileItem = file;
438
439   return true;
440 }
441
442 void PAPlayer::UpdateStreamInfoPlayNextAtFrame(StreamInfo *si, unsigned int crossFadingTime)
443 {
444   if (si)
445   {
446     int64_t streamTotalTime = si->m_decoder.TotalTime();
447     if (si->m_endOffset)
448       streamTotalTime = si->m_endOffset - si->m_startOffset;
449     if (streamTotalTime < crossFadingTime)
450       si->m_playNextAtFrame = (int)((streamTotalTime / 2) * si->m_sampleRate / 1000.0f);
451     else
452       si->m_playNextAtFrame = (int)((streamTotalTime - crossFadingTime) * si->m_sampleRate / 1000.0f);
453   }
454 }
455
456 inline bool PAPlayer::PrepareStream(StreamInfo *si)
457 {
458   /* if we have a stream we are already prepared */
459   if (si->m_stream)
460     return true;
461
462   /* get a paused stream */
463   si->m_stream = CAEFactory::MakeStream(
464     si->m_dataFormat,
465     si->m_sampleRate,
466     si->m_encodedSampleRate,
467     si->m_channelInfo,
468     AESTREAM_PAUSED
469   );
470
471   if (!si->m_stream)
472   {
473     CLog::Log(LOGDEBUG, "PAPlayer::PrepareStream - Failed to get IAEStream");
474     return false;
475   }
476
477   si->m_stream->SetVolume    (si->m_volume);
478   si->m_stream->SetReplayGain(si->m_decoder.GetReplayGain());
479
480   /* if its not the first stream and crossfade is not enabled */
481   if (m_currentStream && m_currentStream != si && !m_upcomingCrossfadeMS)
482   {
483     /* slave the stream for gapless */
484     si->m_isSlaved = true;
485     m_currentStream->m_stream->RegisterSlave(si->m_stream);
486   }
487
488   /* fill the stream's buffer */
489   while(si->m_stream->IsBuffering())
490   {
491     int status = si->m_decoder.GetStatus();
492     if (status == STATUS_ENDED   ||
493         status == STATUS_NO_FILE ||
494         si->m_decoder.ReadSamples(PACKET_SIZE) == RET_ERROR)
495     {
496       CLog::Log(LOGINFO, "PAPlayer::PrepareStream - Stream Finished");
497       break;
498     }
499
500     if (!QueueData(si))
501       break;
502
503     /* yield our time so that the main PAP thread doesnt stall */
504     CThread::Sleep(1);
505   }
506
507   CLog::Log(LOGINFO, "PAPlayer::PrepareStream - Ready");
508
509   return true;
510 }
511
512 bool PAPlayer::CloseFile(bool reopen)
513 {
514   if (reopen)
515     CAEFactory::KeepConfiguration(3000);
516
517   if (!m_isPaused)
518     SoftStop(true, true);
519   CloseAllStreams(false);
520
521   /* wait for the thread to terminate */
522   StopThread(true);//true - wait for end of thread
523   return true;
524 }
525
526 void PAPlayer::Process()
527 {
528   if (!m_startEvent.WaitMSec(100))
529   {
530     CLog::Log(LOGDEBUG, "PAPlayer::Process - Failed to receive start event");
531     return;
532   }
533
534   CLog::Log(LOGDEBUG, "PAPlayer::Process - Playback started");  
535   while(m_isPlaying && !m_bStop)
536   {
537     /* this needs to happen outside of any locks to prevent deadlocks */
538     if (m_signalSpeedChange)
539     {
540       m_callback.OnPlayBackSpeedChanged(m_playbackSpeed);
541       m_signalSpeedChange = false;
542     }
543
544     double freeBufferTime = 0.0;
545     ProcessStreams(freeBufferTime);
546
547     // if none of our streams wants at least 10ms of data, we sleep
548     if (freeBufferTime < 0.01)
549     {
550       CThread::Sleep(10);
551     }
552
553     GetTimeInternal(); //update for GUI
554   }
555
556   // wait for any pending jobs to complete
557   {
558     CSharedLock lock(m_streamsLock);
559     while (m_jobCounter > 0)
560     {
561       lock.Leave();
562       m_jobEvent.WaitMSec(100);
563       lock.Enter();
564     }
565   }
566
567   if(m_isFinished && !m_bStop)
568     m_callback.OnPlayBackEnded();
569   else
570     m_callback.OnPlayBackStopped();
571 }
572
573 inline void PAPlayer::ProcessStreams(double &freeBufferTime)
574 {
575   CSharedLock sharedLock(m_streamsLock);
576   if (m_isFinished && m_streams.empty() && m_finishing.empty())
577   {
578     m_isPlaying = false;
579     freeBufferTime = 1.0;
580     return;
581   }
582
583   /* destroy any drained streams */
584   for(StreamList::iterator itt = m_finishing.begin(); itt != m_finishing.end();)
585   {
586     StreamInfo* si = *itt;
587     if (si->m_stream->IsDrained())
588     {      
589       itt = m_finishing.erase(itt);
590       CAEFactory::FreeStream(si->m_stream);
591       delete si;
592       CLog::Log(LOGDEBUG, "PAPlayer::ProcessStreams - Stream Freed");
593     }
594     else
595       ++itt;
596   }
597
598   sharedLock.Leave();
599   CExclusiveLock lock(m_streamsLock);
600
601   for(StreamList::iterator itt = m_streams.begin(); itt != m_streams.end(); ++itt)
602   {
603     StreamInfo* si = *itt;
604     if (!m_currentStream && !si->m_started)
605     {
606       m_currentStream = si;
607       UpdateGUIData(si); //update for GUI
608     }
609     /* if the stream is finishing */
610     if ((si->m_playNextTriggered && si->m_stream && !si->m_stream->IsFading()) || !ProcessStream(si, freeBufferTime))
611     {
612       if (!si->m_prepareTriggered)
613       {
614         if (si->m_waitOnDrain)
615         {
616           si->m_stream->Drain(true);
617           si->m_waitOnDrain = false;
618         }
619         si->m_prepareTriggered = true;
620         m_callback.OnQueueNextItem();
621       }
622
623       /* remove the stream */
624       itt = m_streams.erase(itt);
625       /* if its the current stream */
626       if (si == m_currentStream)
627       {
628         /* if it was the last stream */
629         if (itt == m_streams.end())
630         {
631           /* if it didnt trigger the next queue item */
632           if (!si->m_prepareTriggered)
633           {
634             if (si->m_waitOnDrain)
635             {
636               si->m_stream->Drain(true);
637               si->m_waitOnDrain = false;
638             }
639             m_callback.OnQueueNextItem();
640             si->m_prepareTriggered = true;
641           }
642           m_currentStream = NULL;
643         }
644         else
645         {
646           m_currentStream = *itt;
647           UpdateGUIData(*itt); //update for GUI
648         }
649       }
650
651       /* unregister the audio callback */
652       si->m_stream->UnRegisterAudioCallback();
653       si->m_decoder.Destroy();      
654       si->m_stream->Drain(false);
655       m_finishing.push_back(si);
656       return;
657     }
658
659     if (!si->m_started)
660       continue;
661
662     /* is it time to prepare the next stream? */
663     if (si->m_prepareNextAtFrame > 0 && !si->m_prepareTriggered && si->m_framesSent >= si->m_prepareNextAtFrame)
664     {
665       si->m_prepareTriggered = true;
666       m_callback.OnQueueNextItem();
667     }
668
669     /* it is time to start playing the next stream? */
670     if (si->m_playNextAtFrame > 0 && !si->m_playNextTriggered && !m_continueStream && si->m_framesSent >= si->m_playNextAtFrame)
671     {
672       if (!si->m_prepareTriggered)
673       {
674         si->m_prepareTriggered = true;
675         m_callback.OnQueueNextItem();
676       }
677
678       if (!m_isFinished)
679       {
680         if (m_upcomingCrossfadeMS)
681         {
682           si->m_stream->FadeVolume(1.0f, 0.0f, m_upcomingCrossfadeMS);
683           si->m_fadeOutTriggered = true;
684         }
685         m_currentStream = NULL;
686
687         /* unregister the audio callback */
688         si->m_stream->UnRegisterAudioCallback();
689       }
690
691       si->m_playNextTriggered = true;
692     }
693   }
694 }
695
696 inline bool PAPlayer::ProcessStream(StreamInfo *si, double &freeBufferTime)
697 {
698   /* if playback needs to start on this stream, do it */
699   if (si == m_currentStream && !si->m_started)
700   {
701     si->m_started = true;
702     si->m_stream->RegisterAudioCallback(m_audioCallback);
703     if (!si->m_isSlaved)
704       si->m_stream->Resume();
705     si->m_stream->FadeVolume(0.0f, 1.0f, m_upcomingCrossfadeMS);
706     m_callback.OnPlayBackStarted();
707   }
708
709   /* if we have not started yet and the stream has been primed */
710   unsigned int space = si->m_stream->GetSpace();
711   if (!si->m_started && !space)
712     return true;
713
714   /* see if it is time yet to FF/RW or a direct seek */
715   if (!si->m_playNextTriggered && ((m_playbackSpeed != 1 && si->m_framesSent >= si->m_seekNextAtFrame) || si->m_seekFrame > -1))
716   {
717     int64_t time = (int64_t)0;
718     /* if its a direct seek */
719     if (si->m_seekFrame > -1)
720     {
721       time = (int64_t)((float)si->m_seekFrame / (float)si->m_sampleRate * 1000.0f);
722       si->m_framesSent = (int)(si->m_seekFrame - ((float)si->m_startOffset * (float)si->m_sampleRate) / 1000.0f);
723       si->m_seekFrame  = -1;
724       m_playerGUIData.m_time = time; //update for GUI
725       si->m_seekNextAtFrame = 0;
726     }
727     /* if its FF/RW */
728     else
729     {
730       si->m_framesSent      += si->m_sampleRate * (m_playbackSpeed  - 1);
731       si->m_seekNextAtFrame  = si->m_framesSent + si->m_sampleRate / 2;
732       time = (int64_t)(((float)si->m_framesSent / (float)si->m_sampleRate * 1000.0f) + (float)si->m_startOffset);
733     }
734
735     /* if we are seeking back before the start of the track start normal playback */
736     if (time < si->m_startOffset || si->m_framesSent < 0)
737     {
738       time = si->m_startOffset;
739       si->m_framesSent      = 0;
740       si->m_seekNextAtFrame = 0;
741       ToFFRW(1);
742     }
743
744     si->m_decoder.Seek(time);
745   }
746
747   int status = si->m_decoder.GetStatus();
748   if (status == STATUS_ENDED   ||
749       status == STATUS_NO_FILE ||
750       si->m_decoder.ReadSamples(PACKET_SIZE) == RET_ERROR ||
751       ((si->m_endOffset) && (si->m_framesSent / si->m_sampleRate >= (si->m_endOffset - si->m_startOffset) / 1000)))
752   {
753     if (si == m_currentStream && m_continueStream)
754     {
755       // update current stream with info of next track
756       si->m_startOffset = m_FileItem->m_lStartOffset * 1000 / 75;
757       if (m_FileItem->m_lEndOffset)
758         si->m_endOffset = m_FileItem->m_lEndOffset * 1000 / 75;
759       else
760         si->m_endOffset = 0;
761       si->m_framesSent = 0;
762
763       int64_t streamTotalTime = si->m_decoder.TotalTime() - si->m_startOffset;
764       if (si->m_endOffset)
765         streamTotalTime = si->m_endOffset - si->m_startOffset;
766
767       // calculate time when to prepare next stream
768       si->m_prepareNextAtFrame = 0;
769       if (streamTotalTime >= TIME_TO_CACHE_NEXT_FILE + m_defaultCrossfadeMS)
770         si->m_prepareNextAtFrame = (int)((streamTotalTime - TIME_TO_CACHE_NEXT_FILE - m_defaultCrossfadeMS) * si->m_sampleRate / 1000.0f);
771
772       si->m_prepareTriggered = false;
773       si->m_playNextAtFrame = 0;
774       si->m_playNextTriggered = false;
775       si->m_seekNextAtFrame = 0;
776
777       //update the current stream to start playing the next track at the correct frame.
778       UpdateStreamInfoPlayNextAtFrame(m_currentStream, m_upcomingCrossfadeMS);
779
780       UpdateGUIData(si);
781       m_callback.OnPlayBackStarted();
782       m_continueStream = false;
783     }
784     else
785     {
786       CLog::Log(LOGINFO, "PAPlayer::ProcessStream - Stream Finished");
787       return false;
788     }
789   }
790
791   if (!QueueData(si))
792     return false;
793
794   /* update free buffer time if we are running */
795   if (si->m_started)
796   {
797     if (si->m_stream->IsBuffering())
798       freeBufferTime = 1.0;
799     else
800     {
801       double free_space = (double)(si->m_stream->GetSpace() / si->m_bytesPerSample) / si->m_sampleRate;
802       freeBufferTime = std::max(freeBufferTime , free_space);
803     }
804   }
805
806   return true;
807 }
808
809 bool PAPlayer::QueueData(StreamInfo *si)
810 {
811   unsigned int space   = si->m_stream->GetSpace();
812   unsigned int samples = std::min(si->m_decoder.GetDataSize(), space / si->m_bytesPerSample);
813   if (!samples)
814     return true;
815
816   void* data = si->m_decoder.GetData(samples);
817   if (!data)
818   {
819     CLog::Log(LOGERROR, "PAPlayer::QueueData - Failed to get data from the decoder");
820     return false;
821   }
822
823   unsigned int added = si->m_stream->AddData(data, samples * si->m_bytesPerSample);
824   si->m_framesSent += added / si->m_bytesPerFrame;
825
826   const ICodec* codec = si->m_decoder.GetCodec();
827   m_playerGUIData.m_cacheLevel = codec ? codec->GetCacheLevel() : 0; //update for GUI
828
829   return true;
830 }
831
832 void PAPlayer::OnExit()
833 {
834
835 }
836
837 void PAPlayer::RegisterAudioCallback(IAudioCallback* pCallback)
838 {
839   CSharedLock lock(m_streamsLock);
840   m_audioCallback = pCallback;
841   if (m_currentStream && m_currentStream->m_stream)
842     m_currentStream->m_stream->RegisterAudioCallback(pCallback);
843 }
844
845 void PAPlayer::UnRegisterAudioCallback()
846 {
847   CSharedLock lock(m_streamsLock);
848   /* only one stream should have the callback, but we do it to all just incase */
849   for(StreamList::iterator itt = m_streams.begin(); itt != m_streams.end(); ++itt)
850     if ((*itt)->m_stream)
851       (*itt)->m_stream->UnRegisterAudioCallback();
852   m_audioCallback = NULL;
853 }
854
855 void PAPlayer::OnNothingToQueueNotify()
856 {
857   m_isFinished = true;
858 }
859
860 bool PAPlayer::IsPlaying() const
861 {
862   return m_isPlaying;
863 }
864
865 bool PAPlayer::IsPaused() const
866 {
867   return m_isPaused;
868 }
869
870 void PAPlayer::Pause()
871 {
872   if (m_isPaused)
873   {
874     m_isPaused = false;
875     SoftStart();
876     m_callback.OnPlayBackResumed();
877   }
878   else
879   {
880     m_isPaused = true;    
881     SoftStop(true, false);
882     m_callback.OnPlayBackPaused();
883   }
884 }
885
886 void PAPlayer::SetVolume(float volume)
887 {
888
889 }
890
891 void PAPlayer::SetDynamicRangeCompression(long drc)
892 {
893
894 }
895
896 void PAPlayer::ToFFRW(int iSpeed)
897 {
898   m_playbackSpeed     = iSpeed;
899   m_signalSpeedChange = true;
900 }
901
902 int64_t PAPlayer::GetTimeInternal()
903 {
904   CSharedLock lock(m_streamsLock);
905   if (!m_currentStream)
906     return 0;
907
908   double time = ((double)m_currentStream->m_framesSent / (double)m_currentStream->m_sampleRate);
909   if (m_currentStream->m_stream)
910     time -= m_currentStream->m_stream->GetDelay();
911   time = time * 1000.0;
912
913   m_playerGUIData.m_time = (int64_t)time; //update for GUI
914
915   return (int64_t)time;
916 }
917
918 int64_t PAPlayer::GetTime()
919 {
920   return m_playerGUIData.m_time;
921 }
922
923 int64_t PAPlayer::GetTotalTime64()
924 {
925   CSharedLock lock(m_streamsLock);
926   if (!m_currentStream)
927     return 0;
928
929   int64_t total = m_currentStream->m_decoder.TotalTime();
930   if (m_currentStream->m_endOffset)
931     total = m_currentStream->m_endOffset;
932   total -= m_currentStream->m_startOffset;
933   return total;
934 }
935
936 int64_t PAPlayer::GetTotalTime()
937 {
938   return m_playerGUIData.m_totalTime;
939 }
940
941 int PAPlayer::GetCacheLevel() const
942 {
943   return m_playerGUIData.m_cacheLevel;
944 }
945
946 void PAPlayer::GetAudioStreamInfo(int index, SPlayerAudioStreamInfo &info)
947 {
948   info.bitrate = m_playerGUIData.m_audioBitrate;
949   info.channels = m_playerGUIData.m_channelCount;
950   info.audioCodecName = m_playerGUIData.m_codec;
951   info.samplerate = m_playerGUIData.m_sampleRate;
952   info.bitspersample = m_playerGUIData.m_bitsPerSample;
953 }
954
955 bool PAPlayer::CanSeek()
956 {
957   return m_playerGUIData.m_canSeek;
958 }
959
960 void PAPlayer::Seek(bool bPlus, bool bLargeStep, bool bChapterOverride)
961 {
962   if (!CanSeek()) return;
963
964   __int64 seek;
965   if (g_advancedSettings.m_musicUseTimeSeeking && GetTotalTime() > 2 * g_advancedSettings.m_musicTimeSeekForwardBig)
966   {
967     if (bLargeStep)
968       seek = bPlus ? g_advancedSettings.m_musicTimeSeekForwardBig : g_advancedSettings.m_musicTimeSeekBackwardBig;
969     else
970       seek = bPlus ? g_advancedSettings.m_musicTimeSeekForward : g_advancedSettings.m_musicTimeSeekBackward;
971     seek *= 1000;
972     seek += GetTime();
973   }
974   else
975   {
976     float percent;
977     if (bLargeStep)
978       percent = bPlus ? (float)g_advancedSettings.m_musicPercentSeekForwardBig : (float)g_advancedSettings.m_musicPercentSeekBackwardBig;
979     else
980       percent = bPlus ? (float)g_advancedSettings.m_musicPercentSeekForward : (float)g_advancedSettings.m_musicPercentSeekBackward;
981     seek = (__int64)(GetTotalTime64() * (GetPercentage() + percent) / 100);
982   }
983
984   SeekTime(seek);
985 }
986
987 void PAPlayer::SeekTime(int64_t iTime /*=0*/)
988 {
989   if (!CanSeek()) return;
990
991   CSharedLock lock(m_streamsLock);
992   if (!m_currentStream)
993     return;
994
995   int seekOffset = (int)(iTime - GetTimeInternal());
996
997   if (m_playbackSpeed != 1)
998     ToFFRW(1);
999
1000   m_currentStream->m_seekFrame = (int)((float)m_currentStream->m_sampleRate * ((float)iTime + (float)m_currentStream->m_startOffset) / 1000.0f);
1001   m_callback.OnPlayBackSeek((int)iTime, seekOffset);
1002 }
1003
1004 void PAPlayer::SeekPercentage(float fPercent /*=0*/)
1005 {
1006   if (fPercent < 0.0f  ) fPercent = 0.0f;
1007   if (fPercent > 100.0f) fPercent = 100.0f;
1008   SeekTime((int64_t)(fPercent * 0.01f * (float)GetTotalTime64()));
1009 }
1010
1011 float PAPlayer::GetPercentage()
1012 {
1013   if (m_playerGUIData.m_totalTime > 0)
1014     return m_playerGUIData.m_time * 100.0f / m_playerGUIData.m_totalTime;
1015
1016   return 0.0f;
1017 }
1018
1019 bool PAPlayer::SkipNext()
1020 {
1021   return false;
1022 }
1023
1024 void PAPlayer::UpdateGUIData(StreamInfo *si)
1025 {
1026   /* Store data need by external threads in member
1027    * structure to prevent locking conflicts when
1028    * data required by GUI and main application
1029    */
1030   CSharedLock lock(m_streamsLock);
1031
1032   m_playerGUIData.m_sampleRate    = si->m_sampleRate;
1033   m_playerGUIData.m_bitsPerSample = si->m_bytesPerSample << 3;
1034   m_playerGUIData.m_channelCount  = si->m_channelInfo.Count();
1035   m_playerGUIData.m_canSeek       = si->m_decoder.CanSeek();
1036
1037   const ICodec* codec = si->m_decoder.GetCodec();
1038
1039   m_playerGUIData.m_audioBitrate = codec ? codec->m_Bitrate : 0;
1040   strncpy(m_playerGUIData.m_codec,codec ? codec->m_CodecName : "",20);
1041   m_playerGUIData.m_cacheLevel   = codec ? codec->GetCacheLevel() : 0;
1042
1043   int64_t total = si->m_decoder.TotalTime();
1044   if (si->m_endOffset)
1045     total = m_currentStream->m_endOffset;
1046   total -= m_currentStream->m_startOffset;
1047   m_playerGUIData.m_totalTime = total;
1048 }
1049
1050 void PAPlayer::OnJobComplete(unsigned int jobID, bool success, CJob *job)
1051 {
1052   CExclusiveLock lock(m_streamsLock);
1053   m_jobCounter--;
1054   m_jobEvent.Set();
1055 }