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