[cosmetics] update date in GPL header
[vuplus_xbmc] / xbmc / cores / omxplayer / OMXPlayerAudio.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://www.xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #if (defined HAVE_CONFIG_H) && (!defined WIN32)
22   #include "config.h"
23 #elif defined(_WIN32)
24 #include "system.h"
25 #endif
26
27 #include "OMXPlayerAudio.h"
28
29 #include <stdio.h>
30 #include <unistd.h>
31 #include <iomanip>
32
33 #include "linux/XMemUtils.h"
34 #include "utils/BitstreamStats.h"
35 #include "settings/GUISettings.h"
36 #include "settings/Settings.h"
37
38 #include "DVDDemuxers/DVDDemuxUtils.h"
39 #include "utils/MathUtils.h"
40 #include "settings/AdvancedSettings.h"
41 #include "settings/Settings.h"
42 #include "utils/TimeUtils.h"
43
44 #include "OMXPlayer.h"
45
46 #include <iostream>
47 #include <sstream>
48
49 class COMXMsgAudioCodecChange : public CDVDMsg
50 {
51 public:
52   COMXMsgAudioCodecChange(const CDVDStreamInfo &hints, COMXAudioCodecOMX* codec)
53     : CDVDMsg(GENERAL_STREAMCHANGE)
54     , m_codec(codec)
55     , m_hints(hints)
56   {}
57  ~COMXMsgAudioCodecChange()
58   {
59     delete m_codec;
60   }
61   COMXAudioCodecOMX   *m_codec;
62   CDVDStreamInfo      m_hints;
63 };
64
65 OMXPlayerAudio::OMXPlayerAudio(OMXClock *av_clock, CDVDMessageQueue& parent)
66 : CThread("COMXPlayerAudio")
67 , m_messageQueue("audio")
68 , m_messageParent(parent)
69 {
70   m_av_clock      = av_clock;
71   m_pAudioCodec   = NULL;
72   m_speed         = DVD_PLAYSPEED_NORMAL;
73   m_started       = false;
74   m_stalled       = false;
75   m_audioClock    = 0;
76   m_buffer_empty  = false;
77   m_nChannels     = 0;
78   m_DecoderOpen   = false;
79   m_freq          = CurrentHostFrequency();
80   m_send_eos      = false;
81   m_bad_state     = false;
82   m_hints_current.Clear();
83
84   m_av_clock->SetMasterClock(false);
85
86   m_messageQueue.SetMaxDataSize(3 * 1024 * 1024);
87   m_messageQueue.SetMaxTimeSize(8.0);
88 }
89
90
91 OMXPlayerAudio::~OMXPlayerAudio()
92 {
93   CloseStream(false);
94
95   m_DllBcmHost.Unload();
96 }
97
98 bool OMXPlayerAudio::OpenStream(CDVDStreamInfo &hints)
99 {
100   if(!m_DllBcmHost.Load())
101     return false;
102
103   m_bad_state = false;
104
105   COMXAudioCodecOMX *codec = new COMXAudioCodecOMX();
106
107   if(!codec || !codec->Open(hints))
108   {
109     CLog::Log(LOGERROR, "Unsupported audio codec");
110     delete codec; codec = NULL;
111     return false;
112   }
113
114   if(m_messageQueue.IsInited())
115     m_messageQueue.Put(new COMXMsgAudioCodecChange(hints, codec), 0);
116   else
117   {
118     OpenStream(hints, codec);
119     m_messageQueue.Init();
120     CLog::Log(LOGNOTICE, "Creating audio thread");
121     Create();
122   }
123
124   return true;
125 }
126
127 void OMXPlayerAudio::OpenStream(CDVDStreamInfo &hints, COMXAudioCodecOMX *codec)
128 {
129   SAFE_DELETE(m_pAudioCodec);
130
131   m_hints           = hints;
132   m_pAudioCodec     = codec;
133
134   if(m_hints.bitspersample == 0)
135     m_hints.bitspersample = 16;
136
137   m_speed           = DVD_PLAYSPEED_NORMAL;
138   m_audioClock      = 0;
139   m_error           = 0;
140   m_errorbuff       = 0;
141   m_errorcount      = 0;
142   m_integral        = 0;
143   m_skipdupcount    = 0;
144   m_prevskipped     = false;
145   m_syncclock       = true;
146   m_hw_decode       = false;
147   m_errortime       = CurrentHostCounter();
148   m_silence         = false;
149   m_started         = false;
150   m_flush           = false;
151   m_nChannels       = 0;
152   m_synctype        = SYNC_DISCON;
153   m_stalled         = m_messageQueue.GetPacketCount(CDVDMsg::DEMUXER_PACKET) == 0;
154   m_use_passthrough = (g_guiSettings.GetInt("audiooutput.mode") == AUDIO_HDMI) ? true : false ;
155   m_use_hw_decode   = g_advancedSettings.m_omxHWAudioDecode;
156   m_send_eos        = false;
157 }
158
159 bool OMXPlayerAudio::CloseStream(bool bWaitForBuffers)
160 {
161   // wait until buffers are empty
162   if (bWaitForBuffers && m_speed > 0) m_messageQueue.WaitUntilEmpty();
163
164   m_messageQueue.Abort();
165
166   if(IsRunning())
167     StopThread();
168
169   m_messageQueue.End();
170
171   if (m_pAudioCodec)
172   {
173     m_pAudioCodec->Dispose();
174     delete m_pAudioCodec;
175     m_pAudioCodec = NULL;
176   }
177
178   CloseDecoder();
179
180   m_speed         = DVD_PLAYSPEED_NORMAL;
181   m_started       = false;
182
183   return true;
184 }
185
186 void OMXPlayerAudio::OnStartup()
187 {
188 }
189
190 void OMXPlayerAudio::OnExit()
191 {
192   CLog::Log(LOGNOTICE, "thread end: OMXPlayerAudio::OnExit()");
193 }
194
195
196
197 void OMXPlayerAudio::HandleSyncError(double duration)
198 {
199   double clock = m_av_clock->GetClock();
200   double error = m_audioClock - clock;
201   int64_t now;
202
203   if( fabs(error) > DVD_MSEC_TO_TIME(100) || m_syncclock )
204   {
205     m_av_clock->Discontinuity(clock+error);
206     /*
207     if(m_speed == DVD_PLAYSPEED_NORMAL)
208     CLog::Log(LOGDEBUG, "OMXPlayerAudio:: Discontinuity - was:%f, should be:%f, error:%f\n", clock, clock+error, error);
209     */
210
211     m_errorbuff = 0;
212     m_errorcount = 0;
213     m_skipdupcount = 0;
214     m_error = 0;
215     m_syncclock = false;
216     m_errortime = m_av_clock->CurrentHostCounter();
217
218     return;
219   }
220
221   if (m_speed != DVD_PLAYSPEED_NORMAL)
222   {
223     m_errorbuff = 0;
224     m_errorcount = 0;
225     m_integral = 0;
226     m_skipdupcount = 0;
227     m_error = 0;
228     m_errortime = m_av_clock->CurrentHostCounter();
229     return;
230   }
231
232   //check if measured error for 1 second
233   now = m_av_clock->CurrentHostCounter();
234   if ((now - m_errortime) >= m_freq)
235   {
236     m_errortime = now;
237     m_error = m_errorbuff / m_errorcount;
238
239     m_errorbuff = 0;
240     m_errorcount = 0;
241
242     if (m_synctype == SYNC_DISCON)
243     {
244       double limit, error;
245
246       if (m_av_clock->GetRefreshRate(&limit) > 0)
247       {
248         //when the videoreferenceclock is running, the discontinuity limit is one vblank period
249         limit *= DVD_TIME_BASE;
250
251         //make error a multiple of limit, rounded towards zero,
252         //so it won't interfere with the sync methods in CXBMCRenderManager::WaitPresentTime
253         if (m_error > 0.0)
254           error = limit * floor(m_error / limit);
255         else
256           error = limit * ceil(m_error / limit);
257       }
258       else
259       {
260         limit = DVD_MSEC_TO_TIME(10);
261         error = m_error;
262       }
263
264       /*
265       limit = DVD_MSEC_TO_TIME(10);
266       error = m_error;
267       */
268
269       if (fabs(error) > limit - 0.001)
270       {
271         m_av_clock->Discontinuity(clock+error);
272         /*
273         if(m_speed == DVD_PLAYSPEED_NORMAL)
274           CLog::Log(LOGDEBUG, "COMXPlayerAudio:: Discontinuity - was:%f, should be:%f, error:%f", clock, clock+error, error);
275         */
276       }
277     }
278     /*
279     else if (m_synctype == SYNC_SKIPDUP && m_skipdupcount == 0 && fabs(m_error) > DVD_MSEC_TO_TIME(10))
280     if (m_skipdupcount == 0 && fabs(m_error) > DVD_MSEC_TO_TIME(10))
281     {
282       //check how many packets to skip/duplicate
283       m_skipdupcount = (int)(m_error / duration);
284       //if less than one frame off, see if it's more than two thirds of a frame, so we can get better in sync
285       if (m_skipdupcount == 0 && fabs(m_error) > duration / 3 * 2)
286         m_skipdupcount = (int)(m_error / (duration / 3 * 2));
287
288       if (m_skipdupcount > 0)
289         CLog::Log(LOGDEBUG, "OMXPlayerAudio:: Duplicating %i packet(s) of %.2f ms duration",
290                   m_skipdupcount, duration / DVD_TIME_BASE * 1000.0);
291       else if (m_skipdupcount < 0)
292         CLog::Log(LOGDEBUG, "OMXPlayerAudio:: Skipping %i packet(s) of %.2f ms duration ",
293                   m_skipdupcount * -1,  duration / DVD_TIME_BASE * 1000.0);
294     }
295     */
296   }
297 }
298
299 bool OMXPlayerAudio::CodecChange()
300 {
301   unsigned int old_bitrate = m_hints.bitrate;
302   unsigned int new_bitrate = m_hints_current.bitrate;
303
304   if(m_pAudioCodec)
305   {
306     m_hints.channels = m_pAudioCodec->GetChannels();
307     m_hints.samplerate = m_pAudioCodec->GetSampleRate();
308   }
309
310   /* only check bitrate changes on CODEC_ID_DTS, CODEC_ID_AC3, CODEC_ID_EAC3 */
311   if(m_hints.codec != CODEC_ID_DTS && m_hints.codec != CODEC_ID_AC3 && m_hints.codec != CODEC_ID_EAC3)
312     new_bitrate = old_bitrate = 0;
313     
314   if(m_hints_current.codec          != m_hints.codec ||
315      m_hints_current.channels       != m_hints.channels ||
316      m_hints_current.samplerate     != m_hints.samplerate ||
317      m_hints_current.bitspersample  != m_hints.bitspersample ||
318      old_bitrate                    != new_bitrate ||
319      !m_DecoderOpen)
320   {
321     m_hints_current = m_hints;
322     return true;
323   }
324
325   return false;
326 }
327
328 bool OMXPlayerAudio::Decode(DemuxPacket *pkt, bool bDropPacket)
329 {
330   if(!pkt || m_bad_state || !m_pAudioCodec)
331     return false;
332
333   if(pkt->dts != DVD_NOPTS_VALUE)
334     m_audioClock = pkt->dts;
335
336   const uint8_t *data_dec = pkt->pData;
337   int            data_len = pkt->iSize;
338
339   if(!OMX_IS_RAW(m_format.m_dataFormat))
340   {
341     while(!m_bStop && data_len > 0)
342     {
343       int len = m_pAudioCodec->Decode((BYTE *)data_dec, data_len);
344       if( (len < 0) || (len >  data_len) )
345       {
346         m_pAudioCodec->Reset();
347         break;
348       }
349
350       data_dec+= len;
351       data_len -= len;
352
353       uint8_t *decoded;
354       int decoded_size = m_pAudioCodec->GetData(&decoded);
355
356       if(decoded_size <=0)
357         continue;
358
359       int ret = 0;
360
361       m_audioStats.AddSampleBytes(decoded_size);
362
363       if(CodecChange())
364       {
365         m_DecoderOpen = OpenDecoder();
366         if(!m_DecoderOpen)
367           return false;
368       }
369
370       while(!m_bStop)
371       {
372         if(m_flush)
373         {
374           CSingleLock lock(m_flushLock);
375           m_flush = false;
376           lock.Leave();
377           break;
378         }
379
380         if(m_omxAudio.GetSpace() < (unsigned int)pkt->iSize)
381         {
382           Sleep(10);
383           continue;
384         }
385         
386         if(!bDropPacket)
387         {
388           // Zero out the frame data if we are supposed to silence the audio
389           if(m_silence)
390             memset(decoded, 0x0, decoded_size);
391
392           ret = m_omxAudio.AddPackets(decoded, decoded_size, m_audioClock, m_audioClock);
393
394           if(ret != decoded_size)
395           {
396             CLog::Log(LOGERROR, "error ret %d decoded_size %d\n", ret, decoded_size);
397           }
398         }
399
400         int n = (m_nChannels * m_hints.bitspersample * m_hints.samplerate)>>3;
401         if (n > 0)
402           m_audioClock += ((double)decoded_size * DVD_TIME_BASE) / n;
403
404         if(m_speed == DVD_PLAYSPEED_NORMAL)
405           HandleSyncError((((double)decoded_size * DVD_TIME_BASE) / n));
406         break;
407
408       }
409     }
410   }
411   else
412   {
413     if(CodecChange())
414     {
415       m_DecoderOpen = OpenDecoder();
416       if(!m_DecoderOpen)
417         return false;
418     }
419
420     while(!m_bStop)
421     {
422       if(m_flush)
423       {
424         CSingleLock lock(m_flushLock);
425         m_flush = false;
426         lock.Leave();
427         break;
428       }
429
430       if(m_omxAudio.GetSpace() < (unsigned int)pkt->iSize)
431       {
432         Sleep(10);
433         continue;
434       }
435         
436       if(!bDropPacket)
437       {
438         if(m_silence)
439           memset(pkt->pData, 0x0, pkt->iSize);
440
441         m_omxAudio.AddPackets(pkt->pData, pkt->iSize, m_audioClock, m_audioClock);
442       }
443
444       if(m_speed == DVD_PLAYSPEED_NORMAL)
445         HandleSyncError(0);
446
447       m_audioStats.AddSampleBytes(pkt->iSize);
448
449       break;
450     }
451   }
452
453   if(bDropPacket)
454     m_stalled = false;
455
456   if(m_omxAudio.GetCacheTime() < 0.1 /*&& min(99,m_messageQueue.GetLevel() + MathUtils::round_int(100.0/8.0*GetCacheTime())) > 10*/)
457   {
458     m_stalled = true;
459     if(!m_av_clock->OMXAudioBuffer() && m_av_clock->HasVideo() && m_speed == DVD_PLAYSPEED_NORMAL)
460     {
461       clock_gettime(CLOCK_REALTIME, &m_starttime);
462       m_av_clock->OMXAudioBufferStart();
463     }
464   }
465
466   // signal to our parent that we have initialized
467   if(m_started == false)
468   {
469     m_started = true;
470     m_messageParent.Put(new CDVDMsgInt(CDVDMsg::PLAYER_STARTED, DVDPLAYER_AUDIO));
471   }
472
473   return true;
474 }
475
476 void OMXPlayerAudio::Process()
477 {
478   m_audioStats.Start();
479
480   while(!m_bStop)
481   {
482     CDVDMsg* pMsg;
483     int priority = (m_speed == DVD_PLAYSPEED_PAUSE && m_started) ? 1 : 0;
484     int timeout = 1000;
485
486     MsgQueueReturnCode ret = m_messageQueue.Get(&pMsg, timeout, priority);
487
488     if (ret == MSGQ_TIMEOUT)
489     {
490       Sleep(10);
491       continue;
492     }
493
494     if (MSGQ_IS_ERROR(ret) || ret == MSGQ_ABORT)
495     {
496       Sleep(10);
497       continue;
498     }
499
500     if (pMsg->IsType(CDVDMsg::DEMUXER_PACKET))
501     {
502       DemuxPacket* pPacket = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacket();
503       bool bPacketDrop     = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacketDrop();
504
505       if(Decode(pPacket, m_speed > DVD_PLAYSPEED_NORMAL || m_speed < 0 || bPacketDrop))
506       {
507         if (m_stalled && (m_omxAudio.GetCacheTime() > (AUDIO_BUFFER_SECONDS * 0.75f)))
508         {
509           CLog::Log(LOGINFO, "COMXPlayerAudio - Switching to normal playback");
510           m_stalled = false;
511           if(m_av_clock->HasVideo() && m_av_clock->OMXAudioBuffer())
512             m_av_clock->OMXAudioBufferStop();
513         }
514       }
515       // hard unlock audio out buffering
516       clock_gettime(CLOCK_REALTIME, &m_endtime);
517       //int iLevel = min(99,m_messageQueue.GetLevel() + MathUtils::round_int(100.0/8.0*GetCacheTime()));
518       if(/*iLevel < 10 &&*/ m_stalled && (m_endtime.tv_sec - m_starttime.tv_sec) > 1)
519       {
520         m_stalled = false;
521         if(m_av_clock->HasVideo() && m_av_clock->OMXAudioBuffer())
522           m_av_clock->OMXAudioBufferStop();
523       }
524     }
525     else if (pMsg->IsType(CDVDMsg::GENERAL_SYNCHRONIZE))
526     {
527       if(((CDVDMsgGeneralSynchronize*)pMsg)->Wait( 100, SYNCSOURCE_AUDIO ))
528         CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::GENERAL_SYNCHRONIZE");
529       else
530         m_messageQueue.Put(pMsg->Acquire(), 1); /* push back as prio message, to process other prio messages */
531     }
532     else if (pMsg->IsType(CDVDMsg::GENERAL_RESYNC))
533     { //player asked us to set internal clock
534       CDVDMsgGeneralResync* pMsgGeneralResync = (CDVDMsgGeneralResync*)pMsg;
535
536       if (pMsgGeneralResync->m_timestamp != DVD_NOPTS_VALUE)
537         m_audioClock = pMsgGeneralResync->m_timestamp;
538
539       if (pMsgGeneralResync->m_clock)
540       {
541         CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::GENERAL_RESYNC(%f, 1)", m_audioClock);
542         m_av_clock->Discontinuity(m_audioClock);
543         //m_av_clock->OMXUpdateClock(m_audioClock);
544       }
545       else
546         CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::GENERAL_RESYNC(%f, 0)", m_audioClock);
547     }
548     else if (pMsg->IsType(CDVDMsg::GENERAL_RESET))
549     {
550       CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::GENERAL_RESET");
551       if (m_pAudioCodec)
552         m_pAudioCodec->Reset();
553       m_av_clock->Lock();
554       m_av_clock->OMXStop(false);
555       m_omxAudio.Flush();
556       m_av_clock->OMXReset(false);
557       m_av_clock->UnLock();
558       m_started = false;
559     }
560     else if (pMsg->IsType(CDVDMsg::GENERAL_FLUSH))
561     {
562       CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::GENERAL_FLUSH");
563       m_av_clock->Lock();
564       m_av_clock->OMXStop(false);
565       m_omxAudio.Flush();
566       m_av_clock->OMXReset(false);
567       m_av_clock->UnLock();
568       m_syncclock = true;
569       m_stalled   = true;
570       m_started   = false;
571
572       if (m_pAudioCodec)
573         m_pAudioCodec->Reset();
574     }
575     else if (pMsg->IsType(CDVDMsg::PLAYER_STARTED))
576     {
577       if(m_started)
578         m_messageParent.Put(new CDVDMsgInt(CDVDMsg::PLAYER_STARTED, DVDPLAYER_AUDIO));
579     }
580     else if (pMsg->IsType(CDVDMsg::GENERAL_EOF))
581     {
582       CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::GENERAL_EOF");
583       WaitCompletion();
584     }
585     else if (pMsg->IsType(CDVDMsg::GENERAL_DELAY))
586     {
587       if (m_speed != DVD_PLAYSPEED_PAUSE)
588       {
589         double timeout = static_cast<CDVDMsgDouble*>(pMsg)->m_value;
590
591         CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::GENERAL_DELAY(%f)", timeout);
592
593         timeout *= (double)DVD_PLAYSPEED_NORMAL / abs(m_speed);
594         timeout += m_av_clock->GetAbsoluteClock();
595
596         while(!m_bStop && m_av_clock->GetAbsoluteClock() < timeout)
597           Sleep(1);
598       }
599     }
600     else if (pMsg->IsType(CDVDMsg::PLAYER_SETSPEED))
601     {
602       CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::PLAYER_SETSPEED");
603       m_speed = static_cast<CDVDMsgInt*>(pMsg)->m_value;
604       if (m_speed != DVD_PLAYSPEED_NORMAL)
605       {
606         m_syncclock = true;
607       }
608     }
609     else if (pMsg->IsType(CDVDMsg::AUDIO_SILENCE))
610     {
611       m_silence = static_cast<CDVDMsgBool*>(pMsg)->m_value;
612       if (m_silence)
613         CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::AUDIO_SILENCE(%f, 1)", m_audioClock);
614       else
615         CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::AUDIO_SILENCE(%f, 0)", m_audioClock);
616     }
617     else if (pMsg->IsType(CDVDMsg::GENERAL_STREAMCHANGE))
618     {
619       COMXMsgAudioCodecChange* msg(static_cast<COMXMsgAudioCodecChange*>(pMsg));
620       OpenStream(msg->m_hints, msg->m_codec);
621       msg->m_codec = NULL;
622     }
623
624     pMsg->Release();
625   }
626 }
627
628 void OMXPlayerAudio::Flush()
629 {
630   CSingleLock lock(m_flushLock);
631   m_flush = true;
632   m_messageQueue.Flush();
633   m_messageQueue.Put( new CDVDMsg(CDVDMsg::GENERAL_FLUSH), 1);
634 }
635
636 void OMXPlayerAudio::WaitForBuffers()
637 {
638   // make sure there are no more packets available
639   m_messageQueue.WaitUntilEmpty();
640
641   // make sure almost all has been rendered
642   // leave 500ms to avound buffer underruns
643   double delay = GetCacheTime();
644   if(delay > 0.5)
645     Sleep((int)(1000 * (delay - 0.5)));
646 }
647
648 bool OMXPlayerAudio::Passthrough() const
649 {
650   return m_passthrough;
651 }
652
653 AEDataFormat OMXPlayerAudio::GetDataFormat(CDVDStreamInfo hints)
654 {
655   AEDataFormat dataFormat = AE_FMT_S16NE;
656   bool hdmi_passthrough_dts = false;
657   bool hdmi_passthrough_ac3 = false;
658
659   if (m_DllBcmHost.vc_tv_hdmi_audio_supported(EDID_AudioFormat_eAC3, 2, EDID_AudioSampleRate_e44KHz, EDID_AudioSampleSize_16bit ) == 0)
660     hdmi_passthrough_ac3 = true;
661   if (m_DllBcmHost.vc_tv_hdmi_audio_supported(EDID_AudioFormat_eDTS, 2, EDID_AudioSampleRate_e44KHz, EDID_AudioSampleSize_16bit ) == 0)
662     hdmi_passthrough_dts = true;
663   //printf("Audio support AC3=%d, DTS=%d\n", hdmi_passthrough_ac3, hdmi_passthrough_dts);
664
665   m_passthrough = false;
666   m_hw_decode   = false;
667
668   /* check our audio capabilties */
669
670   /* pathrought is overriding hw decode*/
671   if(AUDIO_IS_BITSTREAM(g_guiSettings.GetInt("audiooutput.mode")) && m_use_passthrough)
672   {
673     if(hints.codec == CODEC_ID_AC3 && g_guiSettings.GetBool("audiooutput.ac3passthrough") && hdmi_passthrough_ac3)
674     {
675       dataFormat = AE_FMT_AC3;
676       m_passthrough = true;
677     }
678     if(hints.codec == CODEC_ID_DTS && g_guiSettings.GetBool("audiooutput.dtspassthrough") && hdmi_passthrough_dts)
679     {
680       dataFormat = AE_FMT_DTS;
681       m_passthrough = true;
682     }
683   }
684
685   /* hw decode */
686   if(m_use_hw_decode && !m_passthrough)
687   {
688     if(hints.codec == CODEC_ID_AC3 && COMXAudio::CanHWDecode(m_hints.codec))
689     {
690       dataFormat = AE_FMT_AC3;
691       m_hw_decode = true;
692     }
693     if(hints.codec == CODEC_ID_DTS && COMXAudio::CanHWDecode(m_hints.codec))
694     {
695       dataFormat = AE_FMT_DTS;
696       m_hw_decode = true;
697     }
698   }
699
700   /* software path */
701   if(!m_passthrough && !m_hw_decode)
702   {
703     /* 6 channel have to be mapped to 8 for PCM */
704     if(m_nChannels > 4)
705       m_nChannels = 8;
706     dataFormat = AE_FMT_S16NE;
707   }
708
709   return dataFormat;
710 }
711
712 bool OMXPlayerAudio::OpenDecoder()
713 {
714   m_nChannels   = m_hints.channels;
715   m_passthrough = false;
716   m_hw_decode   = false;
717
718   bool bSendParent = false;
719
720   if(m_DecoderOpen)
721   {
722     WaitCompletion();
723     m_omxAudio.Deinitialize();
724     m_DecoderOpen = false;
725     bSendParent = true;
726   }
727
728   /* setup audi format for audio render */
729   m_format.m_sampleRate    = m_hints.samplerate;
730   m_format.m_channelLayout = m_pAudioCodec->GetChannelMap(); 
731   /* GetDataFormat is setting up evrything */
732   m_format.m_dataFormat = GetDataFormat(m_hints);
733
734   std::string device = "";
735   
736   if(g_guiSettings.GetInt("audiooutput.mode") == AUDIO_HDMI)
737     device = "hdmi";
738   else
739     device = "local";
740
741   m_av_clock->Lock();
742   m_av_clock->OMXStop(false);
743
744   bool bAudioRenderOpen = m_omxAudio.Initialize(m_format, device, m_av_clock, m_hints, m_passthrough, m_hw_decode);
745
746   m_codec_name = "";
747   m_bad_state  = !bAudioRenderOpen;
748   
749   if(!bAudioRenderOpen)
750   {
751     CLog::Log(LOGERROR, "OMXPlayerAudio : Error open audio output");
752     m_omxAudio.Deinitialize();
753   }
754   else
755   {
756     CLog::Log(LOGINFO, "Audio codec %s channels %d samplerate %d bitspersample %d\n",
757       m_codec_name.c_str(), m_nChannels, m_hints.samplerate, m_hints.bitspersample);
758   }
759
760   m_av_clock->OMXStateExecute(false);
761   m_av_clock->HasAudio(bAudioRenderOpen);
762   m_av_clock->OMXReset(false);
763   m_av_clock->UnLock();
764
765   m_started = false;
766
767   // TODO : Send FLUSH to parent, only if we had a valid open codec. 
768   // this is just a workaround to get the omx video decoder happy again
769   // This situation happens, for example where we have in the stream an audio codec change
770   if(bSendParent)
771     m_messageParent.Put(new CDVDMsg(CDVDMsg::GENERAL_FLUSH));
772
773   return bAudioRenderOpen;
774 }
775
776 void OMXPlayerAudio::CloseDecoder()
777 {
778   m_av_clock->Lock();
779   m_av_clock->OMXStop(false);
780   m_omxAudio.Deinitialize();
781   m_av_clock->HasAudio(false);
782   m_av_clock->OMXReset(false);
783   m_av_clock->UnLock();
784
785   m_DecoderOpen = false;
786 }
787
788 double OMXPlayerAudio::GetDelay()
789 {
790   return m_omxAudio.GetDelay();
791 }
792
793 double OMXPlayerAudio::GetCacheTime()
794 {
795   return m_omxAudio.GetCacheTime();
796 }
797
798 void OMXPlayerAudio::WaitCompletion()
799 {
800   if(!m_send_eos && !m_bad_state)
801     m_omxAudio.WaitCompletion();
802   m_send_eos = true;
803 }
804
805 void OMXPlayerAudio::RegisterAudioCallback(IAudioCallback *pCallback)
806 {
807   m_omxAudio.RegisterAudioCallback(pCallback);
808 }
809
810 void OMXPlayerAudio::UnRegisterAudioCallback()
811 {
812   m_omxAudio.UnRegisterAudioCallback();
813 }
814
815 void OMXPlayerAudio::SetCurrentVolume(float fVolume)
816 {
817   m_omxAudio.SetCurrentVolume(fVolume);
818 }
819
820 void OMXPlayerAudio::SetSpeed(int speed)
821 {
822   if(m_messageQueue.IsInited())
823     m_messageQueue.Put( new CDVDMsgInt(CDVDMsg::PLAYER_SETSPEED, speed), 1 );
824   else
825     m_speed = speed;
826 }
827
828 int OMXPlayerAudio::GetAudioBitrate()
829 {
830   return (int)m_audioStats.GetBitrate();
831 }
832
833 std::string OMXPlayerAudio::GetPlayerInfo()
834 {
835   std::ostringstream s;
836   s << "aq:"     << setw(2) << min(99,m_messageQueue.GetLevel() + MathUtils::round_int(100.0/8.0*GetCacheTime())) << "%";
837   s << ", Kb/s:" << fixed << setprecision(2) << (double)GetAudioBitrate() / 1024.0;
838
839   return s.str();
840 }