[LINUX] PAPlayers flush wasn´t flushing the audiorenderer or the the pcmbuffer
[xbmc:xbmc-antiquated.git] / xbmc / cores / paplayer / paplayer_linux.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 "../../stdafx.h"
23 #include "paplayer.h"
24 #include "CodecFactory.h"
25 #include "../../utils/GUIInfoManager.h"
26 #include "AudioContext.h"
27 #include "../../FileSystem/FileShoutcast.h"
28 #include "../../Application.h"
29 #ifdef HAS_KARAOKE
30 #include "../../CdgParser.h"
31 #endif
32 #include "FileItem.h"
33 #include "Settings.h"
34 #include "MusicInfoTag.h"
35 #include "../AudioRenderers/AudioRendererFactory.h"
36
37 #ifdef _LINUX
38 #define XBMC_SAMPLE_RATE 44100
39 #else
40 #define XBMC_SAMPLE_RATE 48000
41 #endif
42
43 #define VOLUME_FFWD_MUTE 900 // 9dB
44
45 #define FADE_TIME 2 * 2048.0f / XBMC_SAMPLE_RATE.0f      // 2 packets
46
47 #define TIME_TO_CACHE_NEXT_FILE 5000L         // 5 seconds
48 #define TIME_TO_CROSS_FADE      10000L        // 10 seconds
49
50 extern XFILE::CFileShoutcast* m_pShoutCastRipper;
51
52 // PAP: Psycho-acoustic Audio Player
53 // Supporting all open  audio codec standards.
54 // First one being nullsoft's nsv audio decoder format
55
56 PAPlayer::PAPlayer(IPlayerCallback& callback) : IPlayer(callback)
57 {
58   m_bIsPlaying = false;
59   m_bPaused = false;
60   m_cachingNextFile = false;
61   m_currentlyCrossFading = false;
62   m_bQueueFailed = false;
63
64   m_currentDecoder = 0;
65
66   m_iSpeed = 1;
67   m_SeekTime=-1;
68   m_IsFFwdRewding = false;
69   m_timeOffset = 0;
70
71   m_pAudioDecoder[0] = NULL;
72   m_pAudioDecoder[1] = NULL;
73   m_pcmBuffer[0] = NULL;
74   m_pcmBuffer[1] = NULL;
75   m_bufferPos[0] = 0;
76   m_bufferPos[1] = 0;
77
78   m_currentStream = 0;
79   m_packet[0][0].packet = NULL;
80   m_packet[1][0].packet = NULL;
81
82   m_bytesSentOut = 0;
83
84   m_BytesPerSecond = 0;
85   m_SampleRate = 0;
86   m_Channels = 0;
87   m_BitsPerSample = 0;
88
89   m_resampleAudio = false;
90
91   m_visBufferLength = 0;
92   m_pCallback = NULL;
93
94   m_forceFadeToNext = false;
95   m_CacheLevel = 0;
96   m_LastCacheLevelCheck = 0;
97
98   m_currentFile = new CFileItem;
99   m_nextFile = new CFileItem;
100 }
101
102 PAPlayer::~PAPlayer()
103 {
104   CloseFileInternal(true);
105   delete m_currentFile;
106   delete m_nextFile;
107 }
108
109
110 void PAPlayer::OnExit()
111 {
112
113 }
114
115 bool PAPlayer::OpenFile(const CFileItem& file, const CPlayerOptions &options)
116 {
117   if (m_currentlyCrossFading) CloseFileInternal(false); //user seems to be in a hurry
118
119   m_crossFading = g_guiSettings.GetInt("musicplayer.crossfade");
120   //no crossfading for cdda, cd-reading goes mad and no crossfading for last.fm doesn't like two connections
121   if (file.IsCDDA() || file.IsLastFM() || file.IsShoutCast() ) m_crossFading = 0;
122   if (m_crossFading && IsPlaying())
123   {
124     //do a short crossfade on trackskip
125     //set to max 2 seconds for these prev/next transitions
126     if (m_crossFading > 2) m_crossFading = 2;
127     //queue for crossfading
128     bool result = QueueNextFile(file, false);
129     if (result)
130     {
131       //crossfading value may be update by QueueNextFile when nr of channels changed
132       if (!m_crossFading) // swap to next track
133         m_decoder[m_currentDecoder].SetStatus(STATUS_ENDED);
134       else //force to fade to next track immediately
135         m_forceFadeToNext = true;
136     }
137     return result;
138   }
139
140   // normal opening of file, nothing playing or crossfading not enabled
141   // however no need to return to gui audio device
142   CloseFileInternal(false);
143
144   // always open the file using the current decoder
145   m_currentDecoder = 0;
146
147   if (!m_decoder[m_currentDecoder].Create(file, (__int64)(options.starttime * 1000), m_crossFading))
148     return false;
149
150   m_iSpeed = 1;
151   m_bPaused = false;
152   m_bStopPlaying = false;
153   m_bytesSentOut = 0;
154
155   CLog::Log(LOGINFO, "PAPlayer: Playing %s", file.m_strPath.c_str());
156
157   m_timeOffset = (__int64)(options.starttime * 1000);
158
159   m_decoder[m_currentDecoder].GetDataFormat(&m_Channels, &m_SampleRate, &m_BitsPerSample);
160
161   if (!CreateStream(m_currentStream, m_Channels, m_SampleRate, m_BitsPerSample))
162   {
163     m_decoder[m_currentDecoder].Destroy();
164     CLog::Log(LOGERROR, "PAPlayer::Unable to create audio stream");
165   }
166
167   *m_currentFile = file;
168
169   if (ThreadHandle() == NULL)
170     Create();
171
172   m_startEvent.Set();
173
174   m_bIsPlaying = true;
175   m_cachingNextFile = false;
176   m_currentlyCrossFading = false;
177   m_forceFadeToNext = false;
178   m_bQueueFailed = false;
179
180   m_decoder[m_currentDecoder].Start();  // start playback
181
182   if (m_pAudioDecoder[m_currentStream])
183      m_pAudioDecoder[m_currentStream]->Pause();
184
185   if (m_pAudioDecoder[m_currentStream])
186      m_pAudioDecoder[m_currentStream]->Resume();
187
188   return true;
189 }
190
191 void PAPlayer::UpdateCrossFadingTime(const CFileItem& file)
192 {
193   if ((m_crossFading = g_guiSettings.GetInt("musicplayer.crossfade")))
194   {
195     if (
196       m_crossFading &&
197       (
198         file.IsCDDA() ||
199         file.IsLastFM() ||
200         (
201           file.HasMusicInfoTag() && !g_guiSettings.GetBool("musicplayer.crossfadealbumtracks") &&
202           (m_currentFile->GetMusicInfoTag()->GetAlbum() != "") &&
203           (m_currentFile->GetMusicInfoTag()->GetAlbum() == file.GetMusicInfoTag()->GetAlbum()) &&
204           (m_currentFile->GetMusicInfoTag()->GetDiscNumber() == file.GetMusicInfoTag()->GetDiscNumber()) &&
205           (m_currentFile->GetMusicInfoTag()->GetTrackNumber() == file.GetMusicInfoTag()->GetTrackNumber() - 1)
206         )
207       )
208     )
209     {
210       m_crossFading = 0;
211     }
212   }
213 }
214
215 void PAPlayer::OnNothingToQueueNotify()
216 {
217   //nothing to queue, stop playing
218   m_bQueueFailed = true;
219 }
220
221 bool PAPlayer::QueueNextFile(const CFileItem &file)
222 {
223   return QueueNextFile(file, true);
224 }
225
226 bool PAPlayer::QueueNextFile(const CFileItem &file, bool checkCrossFading)
227 {
228   if (IsPaused())
229     Pause();
230
231   if (file.m_strPath == m_currentFile->m_strPath &&
232       file.m_lStartOffset > 0 &&
233       file.m_lStartOffset == m_currentFile->m_lEndOffset)
234   { // continuing on a .cue sheet item - return true to say we'll handle the transistion
235     *m_nextFile = file;
236     return true;
237   }
238
239   // check if we can handle this file at all
240   int decoder = 1 - m_currentDecoder;
241   __int64 seekOffset = (file.m_lStartOffset * 1000) / 75;
242   if (!m_decoder[decoder].Create(file, seekOffset, m_crossFading))
243   {
244     m_bQueueFailed = true;
245     return false;
246   }
247
248   // ok, we're good to go on queuing this one up
249   CLog::Log(LOGINFO, "PAPlayer: Queuing next file %s", file.m_strPath.c_str());
250
251   m_bQueueFailed = false;
252   if (checkCrossFading)
253   {
254     UpdateCrossFadingTime(file);
255   }
256
257   unsigned int channels, samplerate, bitspersample;
258   m_decoder[decoder].GetDataFormat(&channels, &samplerate, &bitspersample);
259
260   // check the number of channels isn't changing (else we can't do crossfading)
261   if (m_crossFading && m_decoder[m_currentDecoder].GetChannels() == channels)
262   { // crossfading - need to create a new stream
263     if (!CreateStream(1 - m_currentStream, channels, samplerate, bitspersample))
264     {
265       m_decoder[decoder].Destroy();
266       CLog::Log(LOGERROR, "PAPlayer::Unable to create audio stream");
267     }
268   }
269   else
270   { // no crossfading if nr of channels is not the same
271     m_crossFading = 0;
272   }
273
274   *m_nextFile = file;
275
276   return true;
277 }
278
279
280
281 bool PAPlayer::CloseFileInternal(bool bAudioDevice /*= true*/)
282 {
283   if (IsPaused())
284     Pause();
285
286   m_bStopPlaying = true;
287   m_bStop = true;
288
289   m_visBufferLength = 0;
290   StopThread();
291
292   // kill both our streams if we need to
293   for (int i = 0; i < 2; i++)
294   {
295     m_decoder[i].Destroy();
296     FreeStream(i);
297   }
298
299   m_currentFile->Reset();
300   m_nextFile->Reset();
301
302   if(bAudioDevice)
303     g_audioContext.SetActiveDevice(CAudioContext::DEFAULT_DEVICE);
304
305   return true;
306 }
307
308 void PAPlayer::FreeStream(int stream)
309 {
310   if (m_pAudioDecoder[stream])
311   {
312     DrainStream(stream);
313
314     delete m_pAudioDecoder[stream];
315     free(m_pcmBuffer[stream]);
316   }
317   m_pAudioDecoder[stream] = 0;
318
319   if (m_packet[stream][0].packet)
320     free(m_packet[stream][0].packet);
321
322   for (int i = 0; i < PACKET_COUNT; i++)
323   {
324     m_packet[stream][i].packet = NULL;
325   }
326
327   m_resampler[stream].DeInitialize();
328 }
329
330 void PAPlayer::DrainStream(int stream)
331 {
332   DWORD silence = m_pAudioDecoder[stream]->GetChunkLen() - m_bufferPos[stream] % m_pAudioDecoder[stream]->GetChunkLen(); 
333
334         if(silence > 0 && m_bufferPos[stream] > 0) 
335   { 
336     CLog::Log(LOGDEBUG, "PAPlayer: Drain - adding %d bytes of silence, real pcmdata size: %d, chunk size: %d", silence, m_bufferPos[stream], m_pAudioDecoder[stream]->GetChunkLen()); 
337     memset(m_pcmBuffer[stream] + m_bufferPos[stream], 0, silence); 
338     m_bufferPos[stream] += silence; 
339   }
340
341   if(m_pAudioDecoder[stream]->AddPackets(m_pcmBuffer[stream], m_bufferPos[stream]) != m_bufferPos[stream]) 
342     CLog::Log(LOGERROR, "PAPlayer: Drain - failed to play the final %d bytes", m_bufferPos[stream]); 
343  
344   m_bufferPos[stream] = 0; 
345
346   m_pAudioDecoder[stream]->WaitCompletion();
347 }
348
349 bool PAPlayer::CreateStream(int num, int channels, int samplerate, int bitspersample, CStdString codec)
350 {
351   FreeStream(num);
352
353   if (channels <= 2 && g_advancedSettings.m_musicResample)
354     m_SampleRateOutput = g_advancedSettings.m_musicResample;
355   else
356     m_SampleRateOutput = samplerate;
357
358   m_BitsPerSampleOutput = 16;
359
360   m_BytesPerSecond = (m_BitsPerSampleOutput / 8)*m_SampleRateOutput*channels;
361
362   /* Open the device */
363   m_pAudioDecoder[num] = CAudioRendererFactory::Create(m_pCallback, channels, m_SampleRateOutput, m_BitsPerSampleOutput, false, codec.c_str(), true, false);
364
365   if (!m_pAudioDecoder[num]) return false;
366
367   m_pcmBuffer[num] = (unsigned char*)malloc((m_pAudioDecoder[num]->GetChunkLen() + PACKET_SIZE));
368   m_bufferPos[num] = 0;
369
370   m_packet[num][0].packet = (BYTE*)malloc(PACKET_SIZE * PACKET_COUNT);
371   for (int i = 1; i < PACKET_COUNT ; i++)
372     m_packet[num][i].packet = m_packet[num][i - 1].packet + PACKET_SIZE;
373
374   // create our resampler  // upsample to XBMC_SAMPLE_RATE, only do this for sources with 1 or 2 channels
375   m_resampler[num].InitConverter(samplerate, bitspersample, channels, m_SampleRateOutput, m_BitsPerSampleOutput, PACKET_SIZE);
376
377   // set initial volume
378   SetStreamVolume(num, g_stSettings.m_nVolumeLevel);
379
380   // TODO: How do we best handle the callback, given that our samplerate etc. may be
381   // changing at this point?
382
383   // fire off our init to our callback
384   if (m_pCallback)
385     m_pCallback->OnInitialize(channels, m_SampleRateOutput, m_BitsPerSampleOutput);
386
387   return true;
388 }
389
390 void PAPlayer::Pause()
391 {
392   CLog::Log(LOGDEBUG,"PAPlayer: pause m_bplaying: %d", m_bIsPlaying);
393   if (!m_bIsPlaying || !m_pAudioDecoder)
394   return ;
395
396   m_bPaused = !m_bPaused;
397
398   if (m_bPaused)
399   {
400   // pause both streams if we're crossfading
401     if (m_pAudioDecoder[m_currentStream])
402       m_pAudioDecoder[m_currentStream]->Resume();
403
404     if (m_currentlyCrossFading && m_pAudioDecoder[1 - m_currentStream])
405       m_pAudioDecoder[1 - m_currentStream]->Resume();
406
407   CLog::Log(LOGDEBUG, "PAPlayer: Playback paused");
408   }
409   else
410   {
411     if (m_pAudioDecoder[m_currentStream])
412       m_pAudioDecoder[m_currentStream]->Pause();
413
414     if (m_currentlyCrossFading && m_pAudioDecoder[1 - m_currentStream])
415       m_pAudioDecoder[1 - m_currentStream]->Pause();
416
417
418     FlushStreams();
419
420     CLog::Log(LOGDEBUG, "PAPlayer: Playback resumed");
421   }
422 }
423
424 void PAPlayer::SetVolume(long nVolume)
425 {
426   m_pAudioDecoder[m_currentStream]->SetCurrentVolume(nVolume);
427 }
428
429 void PAPlayer::SetDynamicRangeCompression(long drc)
430 {
431   // TODO: Add volume amplification
432   CLog::Log(LOGDEBUG,"PAPlayer::SetDynamicRangeCompression - drc: %lu", drc);
433 }
434
435 void PAPlayer::Process()
436 {
437   CLog::Log(LOGDEBUG, "PAPlayer: Thread started");
438   if (m_startEvent.WaitMSec(100))
439   {
440     m_startEvent.Reset();
441
442     m_callback.OnPlayBackStarted();
443
444     do
445     {
446       if (!m_bPaused)
447       {
448         if (!ProcessPAP())
449           break;
450       }
451       else
452       {
453         Sleep(100);
454       }
455     }
456     while (!m_bStopPlaying && m_bIsPlaying && !m_bStop);
457
458     CLog::Log(LOGINFO, "PAPlayer: End of playback reached");
459     m_bIsPlaying = false;
460     if (!m_bStopPlaying && !m_bStop)
461       m_callback.OnPlayBackEnded();
462     else
463       m_callback.OnPlayBackStopped();
464   }
465   CLog::Log(LOGDEBUG, "PAPlayer: Thread end");
466 }
467
468 void PAPlayer::ToFFRW(int iSpeed)
469 {
470   m_iSpeed = iSpeed;
471 }
472
473 void PAPlayer::UpdateCacheLevel()
474 {
475   //check cachelevel every .5 seconds
476   if (m_LastCacheLevelCheck + 500 < GetTickCount())
477   {
478     ICodec* codec = m_decoder[m_currentDecoder].GetCodec();
479     if (codec)
480     {
481       m_CacheLevel = codec->GetCacheLevel();
482       m_LastCacheLevelCheck = GetTickCount();
483       //CLog::Log(LOGDEBUG,"Cachelevel: %i%%", m_CacheLevel);
484     }
485   }
486 }
487
488 bool PAPlayer::ProcessPAP()
489 {
490   /*
491    * Here's what we should be doing in each player loop:
492    *
493    * 1.  Run DoWork() on our audio device to actually output audio.
494    *
495    * 2.  Pass our current buffer to the audio device to see if it wants anything,
496    *     and if so, reduce our buffer size accordingly.
497    *
498    * 3.  Check whether we have space in our buffer for more data, and if so,
499    *     read some more in.
500    *
501    * 4.  Check for end of file and return false if we reach it.
502    *
503    * 5.  Perform any seeking and ffwd/rewding as necessary.
504    *
505    * 6.  If we don't do anything in 2...5, we can take a breather and break out for sleeping.
506    */
507   while (true)
508   {
509     if (m_bStop) return false;
510
511     // Check for .cue sheet item end
512     if (m_currentFile->m_lEndOffset && GetTime() >= GetTotalTime64())
513     {
514       CLog::Log(LOGINFO, "PAPlayer: Passed end of track in a .cue sheet item");
515       m_decoder[m_currentDecoder].SetStatus(STATUS_ENDED);
516     }
517
518     // check whether we need to send off our callbacks etc.
519     int status = m_decoder[m_currentDecoder].GetStatus();
520     if (status == STATUS_NO_FILE)
521       return false;
522
523     UpdateCacheLevel();
524
525     // check whether we should queue the next file up
526     if ((GetTotalTime64() > 0) && GetTotalTime64() - GetTime() < TIME_TO_CACHE_NEXT_FILE + m_crossFading * 1000L && !m_cachingNextFile)
527     { // request the next file from our application
528       m_callback.OnQueueNextItem();
529       m_cachingNextFile = true;
530     }
531
532     if (m_crossFading && m_decoder[0].GetChannels() == m_decoder[1].GetChannels())
533     {
534       if (((GetTotalTime64() - GetTime() < m_crossFading * 1000L) || (m_forceFadeToNext)) && !m_currentlyCrossFading)
535       { // request the next file from our application
536         if (m_decoder[1 - m_currentDecoder].GetStatus() == STATUS_QUEUED && m_pAudioDecoder[1 - m_currentStream])
537         {
538           m_currentlyCrossFading = true;
539           if (m_forceFadeToNext)
540           {
541             m_forceFadeToNext = false;
542             m_crossFadeLength = m_crossFading * 1000L;
543           }
544           else
545           {
546             m_crossFadeLength = GetTotalTime64() - GetTime();
547           }
548           m_currentDecoder = 1 - m_currentDecoder;
549           m_decoder[m_currentDecoder].Start();
550           m_currentStream = 1 - m_currentStream;
551           CLog::Log(LOGDEBUG, "Starting Crossfade - resuming stream %i", m_currentStream);
552
553           m_pAudioDecoder[m_currentStream]->Resume();
554
555           m_callback.OnPlayBackStarted();
556           m_timeOffset = m_nextFile->m_lStartOffset * 1000 / 75;
557           m_bytesSentOut = 0;
558           *m_currentFile = *m_nextFile;
559           m_nextFile->Reset();
560           m_cachingNextFile = false;
561         }
562       }
563     }
564
565     // Check for EOF and queue the next track if applicable
566     if (m_decoder[m_currentDecoder].GetStatus() == STATUS_ENDED)
567     { // time to swap tracks
568       if (m_nextFile->m_strPath != m_currentFile->m_strPath ||
569           !m_nextFile->m_lStartOffset ||
570           m_nextFile->m_lStartOffset != m_currentFile->m_lEndOffset)
571       { // don't have a .cue sheet item
572         int nextstatus = m_decoder[1 - m_currentDecoder].GetStatus();
573         if (nextstatus == STATUS_QUEUED || nextstatus == STATUS_QUEUING || nextstatus == STATUS_PLAYING)
574         { // swap streams
575           CLog::Log(LOGDEBUG, "PAPlayer: Swapping tracks %i to %i", m_currentDecoder, 1-m_currentDecoder);
576           if (!m_crossFading || m_decoder[0].GetChannels() != m_decoder[1].GetChannels())
577           { // playing gapless (we use only the 1 output stream in this case)
578             int prefixAmount = m_decoder[m_currentDecoder].GetDataSize();
579             CLog::Log(LOGDEBUG, "PAPlayer::Prefixing %i samples of old data to new track for gapless playback", prefixAmount);
580             m_decoder[1 - m_currentDecoder].PrefixData(m_decoder[m_currentDecoder].GetData(prefixAmount), prefixAmount);
581             // check if we need to change the resampler (due to format change)
582             unsigned int channels, samplerate, bitspersample;
583             m_decoder[m_currentDecoder].GetDataFormat(&channels, &samplerate, &bitspersample);
584             unsigned int channels2, samplerate2, bitspersample2;
585             m_decoder[1 - m_currentDecoder].GetDataFormat(&channels2, &samplerate2, &bitspersample2);
586             // change of channels - reinitialize our speaker configuration
587             if (channels != channels2 || (g_advancedSettings.m_musicResample == 0 && (samplerate != samplerate2 || bitspersample != bitspersample2)))
588             {
589               CLog::Log(LOGINFO, "PAPlayer: Stream properties have changed, restarting stream");
590               FreeStream(m_currentStream);
591               if (!CreateStream(m_currentStream, channels2, samplerate2, bitspersample2))
592               {
593                 CLog::Log(LOGERROR, "PAPlayer: Error creating stream!");
594                 return false;
595               }
596               m_pAudioDecoder[m_currentStream]->Resume();
597             }
598             else if (samplerate != samplerate2 || bitspersample != bitspersample2)
599             {
600               CLog::Log(LOGINFO, "PAPlayer: Restarting resampler due to a change in data format");
601               m_resampler[m_currentStream].DeInitialize();
602               if (!m_resampler[m_currentStream].InitConverter(samplerate2, bitspersample2, channels2, g_advancedSettings.m_musicResample, 16, PACKET_SIZE))
603               {
604                 CLog::Log(LOGERROR, "PAPlayer: Error initializing resampler!");
605                 return false;
606               }
607             }
608             CLog::Log(LOGINFO, "PAPlayer: Starting new track");
609
610             m_decoder[m_currentDecoder].Destroy();
611             m_decoder[1 - m_currentDecoder].Start();
612             m_callback.OnPlayBackStarted();
613             m_timeOffset = m_nextFile->m_lStartOffset * 1000 / 75;
614             m_bytesSentOut = 0;
615             *m_currentFile = *m_nextFile;
616             m_nextFile->Reset();
617             m_cachingNextFile = false;
618             m_currentDecoder = 1 - m_currentDecoder;
619           }
620           else
621           { // cross fading - shouldn't ever get here - if we do, return false
622             if (!m_currentlyCrossFading)
623             {
624               CLog::Log(LOGERROR, "End of file Reached before crossfading kicked in!");
625               return false;
626             }
627             else
628             {
629               CLog::Log(LOGINFO, "End of file reached before crossfading finished!");
630               return false;
631             }
632           }
633         }
634         else
635         {
636           if (GetTotalTime64() <= 0 && !m_bQueueFailed)
637           { //we did not know the duration so didn't queue the next song, try queueing it now
638             if (!m_cachingNextFile)
639             {// request the next file from our application
640               m_callback.OnQueueNextItem();
641               m_cachingNextFile = true;
642             }
643           }
644           else
645           {
646             // no track queued - return and get another one once we are finished
647             // with the current stream
648             WaitForStream();
649             return false;
650           }
651         }
652       }
653       else
654       {
655         // set the next track playing (.cue sheet)
656         m_decoder[m_currentDecoder].SetStatus(STATUS_PLAYING);
657         m_callback.OnPlayBackStarted();
658         m_timeOffset = m_nextFile->m_lStartOffset * 1000 / 75;
659         m_bytesSentOut = 0;
660         *m_currentFile = *m_nextFile;
661         m_nextFile->Reset();
662         m_cachingNextFile = false;
663       }
664     }
665
666     // handle seeking and ffwd/rewding.
667     HandleSeeking();
668     if (!HandleFFwdRewd())
669     {
670       // need to skip to the next track - let's see if we already have another one
671       m_decoder[m_currentDecoder].SetStatus(STATUS_ENDED);
672       continue; // loop around to start the next track
673     }
674
675     if (!m_bPaused) {
676
677     // Let our decoding stream(s) do their thing
678     int retVal = m_decoder[m_currentDecoder].ReadSamples(PACKET_SIZE);
679     if (retVal == RET_ERROR)
680     {
681       m_decoder[m_currentDecoder].Destroy();
682       return false;
683     }
684
685     int retVal2 = m_decoder[1 - m_currentDecoder].ReadSamples(PACKET_SIZE);
686     if (retVal2 == RET_ERROR)
687     {
688       m_decoder[1 - m_currentDecoder].Destroy();
689     }
690
691     // if we're cross-fading, then we do this for both streams, otherwise
692     // we do it just for the one stream.
693     if (m_currentlyCrossFading)
694     {
695       if (GetTime() >= m_crossFadeLength)  // finished
696       {
697         CLog::Log(LOGDEBUG, "Finished Crossfading");
698         m_currentlyCrossFading = false;
699         SetStreamVolume(m_currentStream, g_stSettings.m_nVolumeLevel);
700         FreeStream(1 - m_currentStream);
701         m_decoder[1 - m_currentDecoder].Destroy();
702       }
703       else
704       {
705         float fraction = (float)(m_crossFadeLength - GetTime()) / (float)m_crossFadeLength - 0.5f;
706         // make sure we can take valid logs.
707         if (fraction > 0.499f) fraction = 0.499f;
708         if (fraction < -0.499f) fraction = -0.499f;
709         float volumeCurrent = 2000.0f * log10(0.5f - fraction);
710         float volumeNext = 2000.0f * log10(0.5f + fraction);
711         SetStreamVolume(m_currentStream, g_stSettings.m_nVolumeLevel + (int)volumeCurrent);
712         SetStreamVolume(1 - m_currentStream, g_stSettings.m_nVolumeLevel + (int)volumeNext);
713         if (AddPacketsToStream(1 - m_currentStream, m_decoder[1 - m_currentDecoder]))
714           retVal2 = RET_SUCCESS;
715       }
716     }
717
718        // add packets as necessary
719        if (AddPacketsToStream(m_currentStream, m_decoder[m_currentDecoder]))
720          retVal = RET_SUCCESS;
721
722        if (retVal == RET_SLEEP && retVal2 == RET_SLEEP)
723          Sleep(1);
724     }
725     else
726         Sleep(100);
727   }
728   return true;
729 }
730
731 void PAPlayer::ResetTime()
732 {
733   m_bytesSentOut = 0;
734 }
735
736 __int64 PAPlayer::GetTime()
737 {
738   __int64  timeplus = m_BytesPerSecond ? (__int64)(((float) m_bytesSentOut / (float)m_BytesPerSecond ) * 1000.0) : 0;
739   return m_timeOffset + timeplus - m_currentFile->m_lStartOffset * 1000 / 75;
740 }
741
742 __int64 PAPlayer::GetTotalTime64()
743 {
744   __int64 total = m_decoder[m_currentDecoder].TotalTime();
745   if (m_currentFile->m_lEndOffset)
746     total = m_currentFile->m_lEndOffset * 1000 / 75;
747   if (m_currentFile->m_lStartOffset)
748     total -= m_currentFile->m_lStartOffset * 1000 / 75;
749   return total;
750 }
751
752 int PAPlayer::GetTotalTime()
753 {
754   return (int)(GetTotalTime64()/1000);
755 }
756
757 int PAPlayer::GetCacheLevel() const
758 {
759   const ICodec* codec = m_decoder[m_currentDecoder].GetCodec();
760   if (codec)
761     return codec->GetCacheLevel();
762
763   return -1;
764 }
765
766 int PAPlayer::GetChannels()
767 {
768   ICodec* codec = m_decoder[m_currentDecoder].GetCodec();
769   if (codec)
770     return codec->m_Channels;
771   return 0;
772 }
773
774 int PAPlayer::GetBitsPerSample()
775 {
776   ICodec* codec = m_decoder[m_currentDecoder].GetCodec();
777   if (codec)
778     return codec->m_BitsPerSample;
779   return 0;
780 }
781
782 int PAPlayer::GetSampleRate()
783 {
784   ICodec* codec = m_decoder[m_currentDecoder].GetCodec();
785   if (codec)
786     return (int)((codec->m_SampleRate / 1000) + 0.5);
787   return 0;
788 }
789
790 CStdString PAPlayer::GetCodecName()
791 {
792   ICodec* codec = m_decoder[m_currentDecoder].GetCodec();
793   if (codec)
794     return codec->m_CodecName;
795   return "";
796 }
797
798 int PAPlayer::GetAudioBitrate()
799 {
800   ICodec* codec = m_decoder[m_currentDecoder].GetCodec();
801   if (codec)
802     return (int)((codec->m_Bitrate / 1000) + 0.5); // in kbits/s, rounded to the nearest int
803   return 0;
804 }
805
806 bool PAPlayer::CanSeek()
807 {
808   return ((m_decoder[m_currentDecoder].TotalTime() > 0) && m_decoder[m_currentDecoder].CanSeek());
809 }
810
811 void PAPlayer::Seek(bool bPlus, bool bLargeStep)
812 {
813   __int64 seek;
814   if (g_advancedSettings.m_musicUseTimeSeeking && GetTotalTime() > 2*g_advancedSettings.m_musicTimeSeekForwardBig)
815   {
816     if (bLargeStep)
817       seek = bPlus ? g_advancedSettings.m_musicTimeSeekForwardBig : g_advancedSettings.m_musicTimeSeekBackwardBig;
818     else
819       seek = bPlus ? g_advancedSettings.m_musicTimeSeekForward : g_advancedSettings.m_musicTimeSeekBackward;
820     seek *= 1000;
821     seek += GetTime();
822   }
823   else
824   {
825     float percent;
826     if (bLargeStep)
827       percent = bPlus ? g_advancedSettings.m_musicPercentSeekForwardBig : g_advancedSettings.m_musicPercentSeekBackwardBig;
828     else
829       percent = bPlus ? g_advancedSettings.m_musicPercentSeekForward : g_advancedSettings.m_musicPercentSeekBackward;
830     seek = (__int64)(GetTotalTime64()*(GetPercentage()+percent)/100);
831   }
832
833   SeekTime(seek);
834 }
835
836 void PAPlayer::SeekTime(__int64 iTime /*=0*/)
837 {
838   if (!CanSeek()) return;
839   if (m_currentFile->m_lStartOffset)
840     iTime += m_currentFile->m_lStartOffset * 1000 / 75;
841   m_SeekTime = iTime;
842   CLog::Log(LOGDEBUG, "PAPlayer::Seeking to time %f", 0.001f * m_SeekTime);
843 }
844
845 void PAPlayer::SeekPercentage(float fPercent /*=0*/)
846 {
847   if (fPercent < 0.0f) fPercent = 0.0f;
848   if (fPercent > 100.0f) fPercent = 100.0f;
849   SeekTime((__int64)(fPercent * 0.01f * (float)GetTotalTime64()));
850 }
851
852 float PAPlayer::GetPercentage()
853 {
854   float percent = (float)GetTime() * 100.0f / GetTotalTime64();
855   return percent;
856 }
857
858 void PAPlayer::HandleSeeking()
859 {
860   if (m_SeekTime != -1)
861   {
862     DWORD time = timeGetTime();
863     m_timeOffset = m_decoder[m_currentDecoder].Seek(m_SeekTime);
864     CLog::Log(LOGDEBUG, "Seek to time %f took %u ms",
865               0.001f * m_SeekTime, timeGetTime() - time);
866     FlushStreams();
867     m_bytesSentOut = 0;
868     m_SeekTime = -1;
869   }
870   g_infoManager.m_performingSeek = false;
871 }
872
873 void PAPlayer::FlushStreams()
874 {
875   for (int stream = 0; stream < 2; stream++)
876   {
877     if (m_pAudioDecoder[stream] && m_packet[stream])
878     {
879       m_pAudioDecoder[stream]->Resume();
880       m_bufferPos[stream] = 0;
881     }
882   }
883 }
884
885 bool PAPlayer::HandleFFwdRewd()
886 {
887   if (!m_IsFFwdRewding && m_iSpeed == 1)
888     return true;  // nothing to do
889   if (m_IsFFwdRewding && m_iSpeed == 1)
890   { // stop ffwd/rewd
891     m_IsFFwdRewding = false;
892     SetVolume(g_stSettings.m_nVolumeLevel);
893     m_bytesSentOut = 0;
894     FlushStreams();
895     return true;
896   }
897   // we're definitely fastforwarding or rewinding
898   int snippet = m_BytesPerSecond / 2;
899   if ( m_bytesSentOut >= snippet )
900   {
901     // Calculate offset to seek if we do FF/RW
902     __int64 time = GetTime();
903     if (m_IsFFwdRewding) snippet = (int)m_bytesSentOut;
904     time += (__int64)((double)snippet * (m_iSpeed - 1.0) / m_BytesPerSecond * 1000.0);
905
906     // Is our offset inside the track range?
907     if (time >= 0 && time <= m_decoder[m_currentDecoder].TotalTime())
908     { // just set next position to read
909       m_IsFFwdRewding = true;
910       time += m_currentFile->m_lStartOffset * 1000 / 75;
911       m_timeOffset = m_decoder[m_currentDecoder].Seek(time);
912       m_bytesSentOut = 0;
913       FlushStreams();
914       SetVolume(g_stSettings.m_nVolumeLevel - VOLUME_FFWD_MUTE); // override xbmc mute
915     }
916     else if (time < 0)
917     { // ...disable seeking and start the track again
918       time = m_currentFile->m_lStartOffset * 1000 / 75;
919       m_timeOffset = m_decoder[m_currentDecoder].Seek(time);
920       m_bytesSentOut = 0;
921       FlushStreams();
922       m_iSpeed = 1;
923       SetVolume(g_stSettings.m_nVolumeLevel); // override xbmc mute
924     } // is our next position greater then the end sector...
925     else //if (time > m_codec->m_TotalTime)
926     {
927       // restore volume level so the next track isn't muted
928       SetVolume(g_stSettings.m_nVolumeLevel);
929       CLog::Log(LOGDEBUG, "PAPlayer: End of track reached while seeking");
930       return false;
931     }
932   }
933   return true;
934 }
935
936 void PAPlayer::SetStreamVolume(int stream, long nVolume)
937 {
938   m_pAudioDecoder[stream]->SetCurrentVolume(nVolume);
939 }
940
941 bool PAPlayer::AddPacketsToStream(int stream, CAudioDecoder &dec)
942 {
943   if (!m_pAudioDecoder[stream] || dec.GetStatus() == STATUS_NO_FILE)
944     return false;
945
946   bool ret = false;
947
948   if (m_resampler[stream].GetData(m_packet[stream][0].packet))
949   {
950     // got some data from our resampler - construct audio packet
951     m_packet[stream][0].length = PACKET_SIZE;
952     m_packet[stream][0].stream = stream;
953
954     unsigned char *pcmPtr = m_packet[stream][0].packet;
955     int len = m_packet[stream][0].length;
956     StreamCallback(&m_packet[stream][0]);
957
958     memcpy(m_pcmBuffer[stream]+m_bufferPos[stream], pcmPtr, len);
959     m_bufferPos[stream] += len;
960
961     while (m_bufferPos[stream] >= m_pAudioDecoder[stream]->GetChunkLen())
962     {
963       while(m_pAudioDecoder[stream]->GetChunkLen() > m_pAudioDecoder[stream]->GetSpace()) // Wait until we can send the chunk
964         usleep(1);
965
966       int rtn = m_pAudioDecoder[stream]->AddPackets(m_pcmBuffer[stream], m_bufferPos[stream]);
967       m_bufferPos[stream] -= rtn;
968       memcpy(m_pcmBuffer[stream], m_pcmBuffer[stream] + rtn, m_bufferPos[stream]);
969     }
970
971     // something done
972     ret = true;
973   }
974   else
975   { // resampler wants more data - let's feed it
976     int amount = m_resampler[stream].GetInputSamples();
977     if (amount > 0 && amount <= (int)dec.GetDataSize())
978     {
979       // needs some data - let's feed it
980       m_resampler[stream].PutFloatData((float *)dec.GetData(amount), amount);
981       ret = true;
982     }
983   }
984
985   return ret;
986 }
987
988 bool PAPlayer::FindFreePacket( int stream, DWORD* pdwPacket )
989 {
990   return true;
991 }
992
993 void PAPlayer::RegisterAudioCallback(IAudioCallback *pCallback)
994 {
995   m_pCallback = pCallback;
996   if (m_pCallback)
997     m_pCallback->OnInitialize(m_Channels, m_SampleRateOutput, m_BitsPerSampleOutput);
998 }
999
1000 void PAPlayer::UnRegisterAudioCallback()
1001 {
1002   m_pCallback = NULL;
1003 }
1004
1005 void PAPlayer::DoAudioWork()
1006 {
1007   if (m_pCallback && m_visBufferLength)
1008   {
1009     m_pCallback->OnAudioData((BYTE*)m_visBuffer, m_visBufferLength);
1010     m_visBufferLength = 0;
1011   }
1012 }
1013
1014 void PAPlayer::StreamCallback( LPVOID pPacketContext )
1015 {
1016   AudioPacket *pkt = (AudioPacket *)pPacketContext;
1017
1018
1019   // only process from the current stream (if we're crossfading for instance)
1020   if (pkt->stream != m_currentStream)
1021     return;
1022
1023   m_bytesSentOut += pkt->length;
1024
1025   if (m_pCallback)
1026   { // copy into our visualisation buffer.
1027     // can't use a memcpy() here due to the context (will crash otherwise)
1028     memcpy((short*)m_visBuffer, pkt->packet, pkt->length);
1029     m_visBufferLength = pkt->length;
1030   }
1031 }
1032
1033 void CALLBACK StaticStreamCallback( VOID* pStreamContext, VOID* pPacketContext, DWORD dwStatus )
1034 {
1035   PAPlayer* pPlayer = (PAPlayer*)pStreamContext;
1036   pPlayer->StreamCallback(pPacketContext);
1037 }
1038
1039 bool PAPlayer::HandlesType(const CStdString &type)
1040 {
1041   ICodec* codec=CodecFactory::CreateCodec(type);
1042
1043   if (codec && codec->CanInit())
1044   {
1045     delete codec;
1046     return true;
1047   }
1048   if (codec)
1049     delete codec;
1050
1051   return false;
1052 }
1053
1054 // Skip to next track/item inside the current media (if supported).
1055 bool PAPlayer::SkipNext()
1056 {
1057   if (m_decoder[m_currentDecoder].GetCodec() && m_decoder[m_currentDecoder].GetCodec()->SkipNext())
1058   {
1059     return true;
1060   }
1061   return false;
1062 }
1063
1064 bool PAPlayer::CanRecord()
1065 {
1066   if (!m_pShoutCastRipper) return false;
1067   return m_pShoutCastRipper->CanRecord();
1068 }
1069
1070 bool PAPlayer::IsRecording()
1071 {
1072   if (!m_pShoutCastRipper) return false;
1073   return m_pShoutCastRipper->IsRecording();
1074 }
1075
1076 bool PAPlayer::Record(bool bOnOff)
1077 {
1078   if (!m_pShoutCastRipper) return false;
1079   if (bOnOff && IsRecording()) return true;
1080   if (bOnOff == false && IsRecording() == false) return true;
1081   if (bOnOff)
1082     return m_pShoutCastRipper->Record();
1083
1084   m_pShoutCastRipper->StopRecording();
1085   return true;
1086 }
1087
1088 void PAPlayer::WaitForStream()
1089 {
1090   // should we wait for our other stream as well?
1091   // currently we don't.
1092   if (!m_pAudioDecoder[m_currentStream])
1093   {
1094     m_pAudioDecoder[m_currentStream]->WaitCompletion();
1095   }
1096 }