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