Merge pull request #1129 from jmarshallnz/remove_smb_auth_details_in_add_source
[vuplus_xbmc] / xbmc / cores / paplayer / PAPlayer.cpp
1 /*
2  *      Copyright (C) 2005-2008 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, write to
17  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18  *  http://www.gnu.org/copyleft/gpl.html
19  *
20  */
21
22 #include "PAPlayer.h"
23 #include "CodecFactory.h"
24 #include "GUIInfoManager.h"
25 #include "Application.h"
26 #include "FileItem.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"
34
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"
39
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 */
43
44 CAEChannelInfo ICodec::GetChannelInfo()
45 {
46   return CAEUtil::GuessChLayout(m_Channels);
47 }
48
49 // PAP: Psycho-acoustic Audio Player
50 // Supporting all open  audio codec standards.
51 // First one being nullsoft's nsv audio decoder format
52
53 PAPlayer::PAPlayer(IPlayerCallback& callback) :
54   IPlayer              (callback),
55   CThread              ("PAPlayer"),
56   m_signalSpeedChange  (false),
57   m_playbackSpeed      (1    ),
58   m_isPlaying          (false),
59   m_isPaused           (false),
60   m_isFinished         (false),
61   m_defaultCrossfadeMS (0),
62   m_upcomingCrossfadeMS(0),
63   m_currentStream      (NULL ),
64   m_audioCallback      (NULL ),
65   m_FileItem           (new CFileItem())
66 {
67 }
68
69 PAPlayer::~PAPlayer()
70 {
71   if (!m_isPaused)
72     SoftStop(true, true);
73   CloseAllStreams(false);  
74
75   /* wait for the thread to terminate */
76   StopThread(true);//true - wait for end of thread
77   delete m_FileItem;
78 }
79
80 bool PAPlayer::HandlesType(const CStdString &type)
81 {
82   ICodec* codec = CodecFactory::CreateCodec(type);
83   if (codec && codec->CanInit())
84   {
85     delete codec;
86     return true;
87   }
88
89   return false;
90 }
91
92 void PAPlayer::SoftStart(bool wait/* = false */)
93 {
94   CSharedLock lock(m_streamsLock);
95   for(StreamList::iterator itt = m_streams.begin(); itt != m_streams.end(); ++itt)
96   {
97     StreamInfo* si = *itt;
98     if (si->m_fadeOutTriggered)
99       continue;
100
101     si->m_stream->FadeVolume(0.0f, 1.0f, FAST_XFADE_TIME);
102     si->m_stream->Resume();
103   }
104   
105   if (wait)
106   {
107     /* wait for them to fade in */
108     lock.Leave();
109     Sleep(FAST_XFADE_TIME);
110     lock.Enter();
111
112     /* be sure they have faded in */
113     while(wait)
114     {
115       wait = false;
116       for(StreamList::iterator itt = m_streams.begin(); itt != m_streams.end(); ++itt)
117       {
118         StreamInfo* si = *itt;
119         if (si->m_stream->IsFading())
120         {
121           lock.Leave();   
122           wait = true;
123           Sleep(1);
124           lock.Enter();
125           break;
126         }
127       }
128     }
129   }
130 }
131
132 void PAPlayer::SoftStop(bool wait/* = false */, bool close/* = true */)
133 {
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)
137   {
138     StreamInfo* si = *itt;
139     if (si->m_stream)
140       si->m_stream->FadeVolume(1.0f, 0.0f, FAST_XFADE_TIME);
141
142     if (close)
143     {
144       si->m_prepareTriggered  = true;
145       si->m_playNextTriggered = true;
146       si->m_fadeOutTriggered  = true;
147     }
148   }
149
150   /* if we are going to wait for them to finish fading */
151   if(wait)
152   {
153     /* wait for them to fade out */
154     lock.Leave();
155     Sleep(FAST_XFADE_TIME);
156     lock.Enter();
157
158     /* be sure they have faded out */
159     while(wait)
160     {
161       wait = false;
162       for(StreamList::iterator itt = m_streams.begin(); itt != m_streams.end(); ++itt)
163       {
164         StreamInfo* si = *itt;
165         if (si->m_stream && si->m_stream->IsFading())
166         {
167           lock.Leave();   
168           wait = true;
169           Sleep(1);
170           lock.Enter();
171           break;
172         }
173       }
174     }
175
176     /* if we are not closing the streams, pause them */
177     if (!close)
178     {
179       for(StreamList::iterator itt = m_streams.begin(); itt != m_streams.end(); ++itt)
180       {
181         StreamInfo* si = *itt;
182         si->m_stream->Pause();
183       }
184     }
185   }
186 }
187
188 void PAPlayer::CloseAllStreams(bool fade/* = true */)
189 {
190   if (!fade) 
191   {
192     CExclusiveLock lock(m_streamsLock);    
193     while(!m_streams.empty())
194     {
195       StreamInfo* si = m_streams.front();
196       m_streams.pop_front();
197       
198       if (si->m_stream)
199       {
200         CAEFactory::FreeStream(si->m_stream);
201         si->m_stream = NULL;
202       }
203
204       si->m_decoder.Destroy();
205       delete si;
206     }
207
208     while(!m_finishing.empty())
209     {
210       StreamInfo* si = m_finishing.front();
211       m_finishing.pop_front();
212
213       if (si->m_stream)
214       {
215         CAEFactory::FreeStream(si->m_stream);
216         si->m_stream = NULL;
217       }
218
219       si->m_decoder.Destroy();
220       delete si;
221     }
222     m_currentStream = NULL;
223   }
224   else
225   {
226     SoftStop(false, true);
227     CExclusiveLock lock(m_streamsLock);
228     m_currentStream = NULL;
229   }  
230 }
231
232 bool PAPlayer::OpenFile(const CFileItem& file, const CPlayerOptions &options)
233 {
234   m_defaultCrossfadeMS = g_guiSettings.GetInt("musicplayer.crossfade") * 1000;
235
236   if (m_streams.size() > 1 || !m_defaultCrossfadeMS)
237   {
238     CloseAllStreams();
239   }
240
241   if (!QueueNextFileEx(file, false))
242     return false;
243
244   CSharedLock lock(m_streamsLock);
245   if (m_streams.size() == 2)
246   {
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);
249
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
254   }
255   lock.Leave();
256
257   if (!IsRunning())
258     Create();
259
260   /* trigger playback start */
261   m_isPlaying = true;
262   m_startEvent.Set();
263   return true;
264 }
265
266 void PAPlayer::UpdateCrossfadeTime(const CFileItem& file)
267 {
268   m_upcomingCrossfadeMS = m_defaultCrossfadeMS = g_guiSettings.GetInt("musicplayer.crossfade") * 1000;
269   if (m_upcomingCrossfadeMS)
270   {
271     if (
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)
278     )
279     {
280       //do not crossfade when playing consecutive albumtracks
281       m_upcomingCrossfadeMS = 0;
282     }
283   }
284 }
285
286 bool PAPlayer::QueueNextFile(const CFileItem &file)
287 {
288   return QueueNextFileEx(file);
289 }
290
291 bool PAPlayer::QueueNextFileEx(const CFileItem &file, bool fadeIn/* = true */)
292 {
293   StreamInfo *si = new StreamInfo();
294
295   if (!si->m_decoder.Create(file, (file.m_lStartOffset * 1000) / 75))
296   {
297     CLog::Log(LOGWARNING, "PAPlayer::QueueNextFileEx - Failed to create the decoder");
298
299     delete si;
300     m_callback.OnQueueNextItem();
301     return false;
302   }
303
304   /* decode until there is data-available */
305   si->m_decoder.Start();
306   while(si->m_decoder.GetDataSize() == 0)
307   {
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)
312     {
313       CLog::Log(LOGINFO, "PAPlayer::QueueNextFileEx - Error reading samples");
314
315       si->m_decoder.Destroy();
316       delete si;
317       m_callback.OnQueueNextItem();
318       return false;
319     }
320
321     /* yield our time so that the main PAP thread doesnt stall */
322     CThread::Sleep(1);
323   }
324
325   UpdateCrossfadeTime(file);
326
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;
338   si->m_stream             = NULL;
339   si->m_volume             = (fadeIn && m_upcomingCrossfadeMS) ? 0.0f : 1.0f;
340   si->m_fadeOutTriggered   = false;
341   si->m_isSlaved           = false;
342
343   int64_t streamTotalTime = si->m_decoder.TotalTime();
344   if (si->m_endOffset)
345     streamTotalTime = si->m_endOffset - si->m_startOffset;
346   
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);
350
351   si->m_prepareTriggered = false;
352
353   si->m_playNextAtFrame = 0;
354   si->m_playNextTriggered = false;
355
356   PrepareStream(si);
357
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);
363
364   *m_FileItem = file;
365
366   return true;
367 }
368
369 void PAPlayer::UpdateStreamInfoPlayNextAtFrame(StreamInfo *si, unsigned int crossFadingTime)
370 {
371   if (si)
372   {
373     int64_t streamTotalTime = si->m_decoder.TotalTime();
374     if (si->m_endOffset)
375       streamTotalTime = si->m_endOffset - si->m_startOffset;
376     if (streamTotalTime < crossFadingTime)
377       si->m_playNextAtFrame = (int)((streamTotalTime / 2) * si->m_sampleRate / 1000.0f);
378     else
379       si->m_playNextAtFrame = (int)((streamTotalTime - crossFadingTime) * si->m_sampleRate / 1000.0f);
380   }
381 }
382
383 inline bool PAPlayer::PrepareStream(StreamInfo *si)
384 {
385   /* if we have a stream we are already prepared */
386   if (si->m_stream)
387     return true;
388
389   /* get a paused stream */
390   si->m_stream = CAEFactory::MakeStream(
391     si->m_dataFormat,
392     si->m_sampleRate,
393     si->m_encodedSampleRate,
394     si->m_channelInfo,
395     AESTREAM_PAUSED
396   );
397
398   if (!si->m_stream)
399   {
400     CLog::Log(LOGDEBUG, "PAPlayer::PrepareStream - Failed to get IAEStream");
401     return false;
402   }
403
404   si->m_stream->SetVolume    (si->m_volume);
405   si->m_stream->SetReplayGain(si->m_decoder.GetReplayGain());
406
407   /* if its not the first stream and crossfade is not enabled */
408   if (m_currentStream && m_currentStream != si && !m_upcomingCrossfadeMS)
409   {
410     /* slave the stream for gapless */
411     si->m_isSlaved = true;
412     m_currentStream->m_stream->RegisterSlave(si->m_stream);
413   }
414
415   /* fill the stream's buffer */
416   while(si->m_stream->IsBuffering())
417   {
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)
422     {
423       CLog::Log(LOGINFO, "PAPlayer::PrepareStream - Stream Finished");
424       break;
425     }
426
427     if (!QueueData(si))
428       break;
429
430     /* yield our time so that the main PAP thread doesnt stall */
431     CThread::Sleep(1);
432   }
433
434   CLog::Log(LOGINFO, "PAPlayer::PrepareStream - Ready");
435
436   return true;
437 }
438
439 bool PAPlayer::CloseFile()
440 {
441   m_callback.OnPlayBackStopped();
442   return true;
443 }
444
445 void PAPlayer::Process()
446 {
447   if (!m_startEvent.WaitMSec(100))
448   {
449     CLog::Log(LOGDEBUG, "PAPlayer::Process - Failed to receive start event");
450     return;
451   }
452
453   CLog::Log(LOGDEBUG, "PAPlayer::Process - Playback started");  
454   while(m_isPlaying && !m_bStop)
455   {
456     /* this needs to happen outside of any locks to prevent deadlocks */
457     if (m_signalSpeedChange)
458     {
459       m_callback.OnPlayBackSpeedChanged(m_playbackSpeed);
460       m_signalSpeedChange = false;
461     }
462
463     double delay  = 100.0;
464     double buffer = 100.0;
465     ProcessStreams(delay, buffer);
466
467     if (delay < buffer && delay > 0.75 * buffer)
468       CThread::Sleep(MathUtils::round_int((buffer - delay) * 1000.0));
469   }
470 }
471
472 inline void PAPlayer::ProcessStreams(double &delay, double &buffer)
473 {
474   CSharedLock sharedLock(m_streamsLock);
475   if (m_isFinished && m_streams.empty() && m_finishing.empty())
476   {
477     m_isPlaying = false;
478     delay       = 0;
479     m_callback.OnPlayBackEnded();
480     return;
481   }
482
483   /* destroy any drained streams */
484   for(StreamList::iterator itt = m_finishing.begin(); itt != m_finishing.end();)
485   {
486     StreamInfo* si = *itt;
487     if (si->m_stream->IsDrained())
488     {      
489       itt = m_finishing.erase(itt);
490       CAEFactory::FreeStream(si->m_stream);
491       delete si;
492       CLog::Log(LOGDEBUG, "PAPlayer::ProcessStreams - Stream Freed");
493     }
494     else
495       ++itt;
496   }
497
498   sharedLock.Leave();
499   CExclusiveLock lock(m_streamsLock);
500
501   for(StreamList::iterator itt = m_streams.begin(); itt != m_streams.end(); ++itt)
502   {
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))
508     {
509       if (!si->m_prepareTriggered)
510       {
511         si->m_prepareTriggered = true;
512         m_callback.OnQueueNextItem();
513       }
514
515       /* remove the stream */
516       itt = m_streams.erase(itt);
517       /* if its the current stream */
518       if (si == m_currentStream)
519       {
520         /* if it was the last stream */
521         if (itt == m_streams.end())
522         {
523           /* if it didnt trigger the next queue item */
524           if (!si->m_prepareTriggered)
525           {
526             m_callback.OnQueueNextItem();
527             si->m_prepareTriggered = true;
528           }
529           m_currentStream = NULL;
530         }
531         else
532         {
533           m_currentStream = *itt;
534         }
535       }
536
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);
542       return;
543     }
544
545     if (!si->m_started)
546       continue;
547
548     /* is it time to prepare the next stream? */
549     if (si->m_prepareNextAtFrame > 0 && !si->m_prepareTriggered && si->m_framesSent >= si->m_prepareNextAtFrame)
550     {
551       si->m_prepareTriggered = true;
552       m_callback.OnQueueNextItem();
553     }
554
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)
557     {
558       if (!si->m_prepareTriggered)
559       {
560         si->m_prepareTriggered = true;
561         m_callback.OnQueueNextItem();
562       }
563
564       if (!m_isFinished)
565       {
566         if (m_upcomingCrossfadeMS)
567         {
568           si->m_stream->FadeVolume(1.0f, 0.0f, m_upcomingCrossfadeMS);
569           si->m_fadeOutTriggered = true;
570         }
571         m_currentStream = NULL;
572
573         /* unregister the audio callback */
574         si->m_stream->UnRegisterAudioCallback();
575       }
576
577       si->m_playNextTriggered = true;      
578     }
579   }
580 }
581
582 inline bool PAPlayer::ProcessStream(StreamInfo *si, double &delay, double &buffer)
583 {
584   /* if playback needs to start on this stream, do it */
585   if (si == m_currentStream && !si->m_started)
586   {
587     si->m_started = true;
588     si->m_stream->RegisterAudioCallback(m_audioCallback);
589     if (!si->m_isSlaved)
590       si->m_stream->Resume();
591     si->m_stream->FadeVolume(0.0f, 1.0f, m_upcomingCrossfadeMS);
592     m_callback.OnPlayBackStarted();
593   }
594
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)
598     return true;
599
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))
602   {
603     int64_t time = (int64_t)0;
604     /* if its a direct seek */
605     if (si->m_seekFrame > -1)
606     {
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;
610     }
611     /* if its FF/RW */
612     else
613     {
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);
617     }
618
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)
621     {
622       time = si->m_startOffset;
623       si->m_framesSent      = (int)(si->m_startOffset * si->m_sampleRate / 1000);
624       si->m_seekNextAtFrame = 0;
625       ToFFRW(1);
626     }
627
628     si->m_decoder.Seek(time);
629   }
630
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)))
636   {
637     CLog::Log(LOGINFO, "PAPlayer::ProcessStream - Stream Finished");
638     return false;
639   }
640
641   if (!QueueData(si))
642     return false;
643
644   /* update the delay time if we are running */
645   if (si->m_started)
646   {
647     if (si->m_stream->IsBuffering())
648       delay = 0.0;
649     else
650       delay = std::min(delay , si->m_stream->GetDelay());
651     buffer = std::min(buffer, si->m_stream->GetCacheTotal());
652   }
653
654   return true;
655 }
656
657 bool PAPlayer::QueueData(StreamInfo *si)
658 {
659   unsigned int space   = si->m_stream->GetSpace();
660   unsigned int samples = std::min(si->m_decoder.GetDataSize(), space / si->m_bytesPerSample);
661   if (!samples)
662     return true;
663
664   void* data = si->m_decoder.GetData(samples);
665   if (!data)
666   {
667     CLog::Log(LOGERROR, "PAPlayer::QueueData - Failed to get data from the decoder");
668     return false;
669   }
670
671   unsigned int added = si->m_stream->AddData(data, samples * si->m_bytesPerSample);
672   si->m_framesSent += added / si->m_bytesPerFrame;
673
674   return true;
675 }
676
677 void PAPlayer::OnExit()
678 {
679
680 }
681
682 void PAPlayer::RegisterAudioCallback(IAudioCallback* pCallback)
683 {
684   CSharedLock lock(m_streamsLock);
685   m_audioCallback = pCallback;
686   if (m_currentStream && m_currentStream->m_stream)
687     m_currentStream->m_stream->RegisterAudioCallback(pCallback);
688 }
689
690 void PAPlayer::UnRegisterAudioCallback()
691 {
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;
698 }
699
700 void PAPlayer::OnNothingToQueueNotify()
701 {
702   m_isFinished = true;
703 }
704
705 bool PAPlayer::IsPlaying() const
706 {
707   return m_isPlaying;
708 }
709
710 bool PAPlayer::IsPaused() const
711 {
712   return m_isPaused;
713 }
714
715 void PAPlayer::Pause()
716 {
717   if (m_isPaused)
718   {
719     m_isPaused = false;
720     SoftStart();
721   }
722   else
723   {
724     m_isPaused = true;    
725     SoftStop(true, false);
726   }
727 }
728
729 void PAPlayer::SetVolume(float volume)
730 {
731
732 }
733
734 void PAPlayer::SetDynamicRangeCompression(long drc)
735 {
736
737 }
738
739 void PAPlayer::ToFFRW(int iSpeed)
740 {
741   m_playbackSpeed     = iSpeed;
742   m_signalSpeedChange = true;
743 }
744
745 int64_t PAPlayer::GetTime()
746 {
747   CSharedLock lock(m_streamsLock);
748   if (!m_currentStream)
749     return 0;
750
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();
754
755   return (int64_t)(time * 1000.0);
756 }
757
758 int64_t PAPlayer::GetTotalTime64()
759 {
760   CSharedLock lock(m_streamsLock);
761   if (!m_currentStream)
762     return 0;
763
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;
768   return total;
769 }
770
771 int PAPlayer::GetTotalTime()
772 {
773   return (int)(GetTotalTime64() / 1000);
774 }
775
776 int PAPlayer::GetCacheLevel() const
777 {
778   CSharedLock lock(m_streamsLock);
779   if (!m_currentStream)
780     return -1;
781
782   const ICodec* codec = m_currentStream->m_decoder.GetCodec();
783   if (codec)
784     return codec->GetCacheLevel();
785   return -1;
786 }
787
788 int PAPlayer::GetChannels()
789 {
790   CSharedLock lock(m_streamsLock);
791   if (!m_currentStream)
792     return 0;
793
794   return m_currentStream->m_channelInfo.Count();
795 }
796
797 int PAPlayer::GetBitsPerSample()
798 {
799   CSharedLock lock(m_streamsLock);
800   if (!m_currentStream)
801     return 0;
802
803   return m_currentStream->m_bytesPerSample >> 3;
804 }
805
806 int PAPlayer::GetSampleRate()
807 {
808   CSharedLock lock(m_streamsLock);
809   if (!m_currentStream)
810     return 0;
811
812   return m_currentStream->m_sampleRate;
813 }
814
815 CStdString PAPlayer::GetAudioCodecName()
816 {
817   CSharedLock lock(m_streamsLock);
818   if (!m_currentStream)
819     return "";
820
821   const ICodec* codec = m_currentStream->m_decoder.GetCodec();
822   if (codec)
823     return codec->m_CodecName;
824   return "";
825 }
826
827 int PAPlayer::GetAudioBitrate()
828 {
829   CSharedLock lock(m_streamsLock);
830   if (!m_currentStream)
831     return 0;
832
833   const ICodec* codec = m_currentStream->m_decoder.GetCodec();
834   if (codec)
835     return codec->m_Bitrate;
836   return 0;
837 }
838
839 bool PAPlayer::CanSeek()
840 {
841   CSharedLock lock(m_streamsLock);
842   if (!m_currentStream)
843     return false;
844
845   return m_currentStream->m_decoder.CanSeek();
846 }
847
848 void PAPlayer::Seek(bool bPlus, bool bLargeStep)
849 {
850 }
851
852 void PAPlayer::SeekTime(int64_t iTime /*=0*/)
853 {
854   if (!CanSeek()) return;
855
856   CSharedLock lock(m_streamsLock);
857   if (!m_currentStream)
858     return;
859
860   int seekOffset = (int)(iTime - GetTime());
861   /*if (m_currentStream->m_startOffset)
862     iTime += m_currentStream->m_startOffset;*/
863
864   if (m_playbackSpeed != 1)
865     ToFFRW(1);
866
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);
869 }
870
871 void PAPlayer::SeekPercentage(float fPercent /*=0*/)
872 {
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()));
876 }
877
878 float PAPlayer::GetPercentage()
879 {
880   return GetTime() * 100.0f / GetTotalTime64();
881 }
882
883 bool PAPlayer::SkipNext()
884 {
885   return false;
886 }