c6ba9c6225a31915154890a9e1183acb1c678ef1
[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 TARGET_WINDOWS)
22   #include "config.h"
23 #elif defined(TARGET_WINDOWS)
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
36 #include "DVDDemuxers/DVDDemuxUtils.h"
37 #include "cores/AudioEngine/Utils/AEUtil.h"
38 #include "utils/MathUtils.h"
39 #include "settings/AdvancedSettings.h"
40 #include "settings/Settings.h"
41 #include "utils/TimeUtils.h"
42
43 #include "OMXPlayer.h"
44
45 #include <iostream>
46 #include <sstream>
47
48 class COMXMsgAudioCodecChange : public CDVDMsg
49 {
50 public:
51   COMXMsgAudioCodecChange(const CDVDStreamInfo &hints, COMXAudioCodecOMX* codec)
52     : CDVDMsg(GENERAL_STREAMCHANGE)
53     , m_codec(codec)
54     , m_hints(hints)
55   {}
56  ~COMXMsgAudioCodecChange()
57   {
58     delete m_codec;
59   }
60   COMXAudioCodecOMX   *m_codec;
61   CDVDStreamInfo      m_hints;
62 };
63
64 OMXPlayerAudio::OMXPlayerAudio(OMXClock *av_clock, CDVDMessageQueue& parent)
65 : CThread("OMXPlayerAudio")
66 , m_messageQueue("audio")
67 , m_messageParent(parent)
68 {
69   m_av_clock      = av_clock;
70   m_pAudioCodec   = NULL;
71   m_speed         = DVD_PLAYSPEED_NORMAL;
72   m_started       = false;
73   m_stalled       = false;
74   m_audioClock    = 0;
75   m_buffer_empty  = false;
76   m_nChannels     = 0;
77   m_DecoderOpen   = false;
78   m_bad_state     = false;
79   m_hints_current.Clear();
80
81   m_messageQueue.SetMaxDataSize(3 * 1024 * 1024);
82   m_messageQueue.SetMaxTimeSize(8.0);
83   m_use_passthrough = false;
84   m_passthrough = false;
85   m_use_hw_decode = false;
86   m_hw_decode = false;
87   m_silence = false;
88   m_flush = false;  
89 }
90
91
92 OMXPlayerAudio::~OMXPlayerAudio()
93 {
94   CloseStream(false);
95
96   m_DllBcmHost.Unload();
97 }
98
99 bool OMXPlayerAudio::OpenStream(CDVDStreamInfo &hints)
100 {
101   if(!m_DllBcmHost.Load())
102     return false;
103
104   m_bad_state = false;
105
106   COMXAudioCodecOMX *codec = new COMXAudioCodecOMX();
107
108   if(!codec || !codec->Open(hints))
109   {
110     CLog::Log(LOGERROR, "Unsupported audio codec");
111     delete codec; codec = NULL;
112     return false;
113   }
114
115   if(m_messageQueue.IsInited())
116     m_messageQueue.Put(new COMXMsgAudioCodecChange(hints, codec), 0);
117   else
118   {
119     OpenStream(hints, codec);
120     m_messageQueue.Init();
121     CLog::Log(LOGNOTICE, "Creating audio thread");
122     Create();
123   }
124
125   return true;
126 }
127
128 void OMXPlayerAudio::OpenStream(CDVDStreamInfo &hints, COMXAudioCodecOMX *codec)
129 {
130   SAFE_DELETE(m_pAudioCodec);
131
132   m_hints           = hints;
133   m_pAudioCodec     = codec;
134
135   if(m_hints.bitspersample == 0)
136     m_hints.bitspersample = 16;
137
138   m_speed           = DVD_PLAYSPEED_NORMAL;
139   m_audioClock      = 0;
140   m_hw_decode       = false;
141   m_silence         = false;
142   m_started         = false;
143   m_flush           = false;
144   m_nChannels       = 0;
145   m_stalled         = m_messageQueue.GetPacketCount(CDVDMsg::DEMUXER_PACKET) == 0;
146   m_use_passthrough = (CSettings::Get().GetInt("audiooutput.mode") == AUDIO_HDMI) ? true : false ;
147   m_use_hw_decode   = g_advancedSettings.m_omxHWAudioDecode;
148 }
149
150 bool OMXPlayerAudio::CloseStream(bool bWaitForBuffers)
151 {
152   // wait until buffers are empty
153   if (bWaitForBuffers && m_speed > 0) m_messageQueue.WaitUntilEmpty();
154
155   m_messageQueue.Abort();
156
157   if(IsRunning())
158     StopThread();
159
160   m_messageQueue.End();
161
162   if (m_pAudioCodec)
163   {
164     m_pAudioCodec->Dispose();
165     delete m_pAudioCodec;
166     m_pAudioCodec = NULL;
167   }
168
169   CloseDecoder();
170
171   m_speed         = DVD_PLAYSPEED_NORMAL;
172   m_started       = false;
173
174   return true;
175 }
176
177 void OMXPlayerAudio::OnStartup()
178 {
179 }
180
181 void OMXPlayerAudio::OnExit()
182 {
183   CLog::Log(LOGNOTICE, "thread end: OMXPlayerAudio::OnExit()");
184 }
185
186 bool OMXPlayerAudio::CodecChange()
187 {
188   unsigned int old_bitrate = m_hints.bitrate;
189   unsigned int new_bitrate = m_hints_current.bitrate;
190
191   if(m_pAudioCodec)
192   {
193     m_hints.channels = m_pAudioCodec->GetChannels();
194     m_hints.samplerate = m_pAudioCodec->GetSampleRate();
195   }
196
197   /* only check bitrate changes on CODEC_ID_DTS, CODEC_ID_AC3, CODEC_ID_EAC3 */
198   if(m_hints.codec != CODEC_ID_DTS && m_hints.codec != CODEC_ID_AC3 && m_hints.codec != CODEC_ID_EAC3)
199     new_bitrate = old_bitrate = 0;
200     
201   if(m_hints_current.codec          != m_hints.codec ||
202      m_hints_current.channels       != m_hints.channels ||
203      m_hints_current.samplerate     != m_hints.samplerate ||
204      m_hints_current.bitspersample  != m_hints.bitspersample ||
205      old_bitrate                    != new_bitrate ||
206      !m_DecoderOpen)
207   {
208     m_hints_current = m_hints;
209     return true;
210   }
211
212   return false;
213 }
214
215 bool OMXPlayerAudio::Decode(DemuxPacket *pkt, bool bDropPacket)
216 {
217   if(!pkt || m_bad_state || !m_pAudioCodec)
218     return false;
219
220   if(pkt->dts != DVD_NOPTS_VALUE)
221     m_audioClock = pkt->dts;
222
223   const uint8_t *data_dec = pkt->pData;
224   int            data_len = pkt->iSize;
225
226   if(!OMX_IS_RAW(m_format.m_dataFormat))
227   {
228     while(!m_bStop && data_len > 0)
229     {
230       int len = m_pAudioCodec->Decode((BYTE *)data_dec, data_len);
231       if( (len < 0) || (len >  data_len) )
232       {
233         m_pAudioCodec->Reset();
234         break;
235       }
236
237       data_dec+= len;
238       data_len -= len;
239
240       uint8_t *decoded;
241       int decoded_size = m_pAudioCodec->GetData(&decoded);
242
243       if(decoded_size <=0)
244         continue;
245
246       int ret = 0;
247
248       m_audioStats.AddSampleBytes(decoded_size);
249
250       if(CodecChange())
251       {
252         m_DecoderOpen = OpenDecoder();
253         if(!m_DecoderOpen)
254           return false;
255       }
256
257       while(!m_bStop)
258       {
259         // discard if flushing as clocks may be stopped and we'll never submit it
260         if(m_flush)
261           break;
262
263         if(m_omxAudio.GetSpace() < (unsigned int)decoded_size)
264         {
265           Sleep(10);
266           continue;
267         }
268         
269         if(!bDropPacket)
270         {
271           // Zero out the frame data if we are supposed to silence the audio
272           if(m_silence)
273             memset(decoded, 0x0, decoded_size);
274
275           ret = m_omxAudio.AddPackets(decoded, decoded_size, m_audioClock, m_audioClock);
276
277           if(ret != decoded_size)
278           {
279             CLog::Log(LOGERROR, "error ret %d decoded_size %d\n", ret, decoded_size);
280           }
281         }
282
283         int n = (m_nChannels * m_hints.bitspersample * m_hints.samplerate)>>3;
284         if (n > 0)
285           m_audioClock += ((double)decoded_size * DVD_TIME_BASE) / n;
286         break;
287
288       }
289     }
290   }
291   else
292   {
293     if(CodecChange())
294     {
295       m_DecoderOpen = OpenDecoder();
296       if(!m_DecoderOpen)
297         return false;
298     }
299
300     while(!m_bStop)
301     {
302       if(m_flush)
303         break;
304
305       if(m_omxAudio.GetSpace() < (unsigned int)pkt->iSize)
306       {
307         Sleep(10);
308         continue;
309       }
310         
311       if(!bDropPacket)
312       {
313         if(m_silence)
314           memset(pkt->pData, 0x0, pkt->iSize);
315
316         m_omxAudio.AddPackets(pkt->pData, pkt->iSize, m_audioClock, m_audioClock);
317       }
318
319       m_audioStats.AddSampleBytes(pkt->iSize);
320
321       break;
322     }
323   }
324
325   if(bDropPacket)
326     m_stalled = false;
327
328   if(m_omxAudio.GetCacheTime() < 0.1 /*&& min(99,m_messageQueue.GetLevel() + MathUtils::round_int(100.0/8.0*GetCacheTime())) > 10*/)
329   {
330     m_stalled = true;
331     if(!m_av_clock->OMXAudioBuffer() && m_av_clock->HasVideo() && m_speed == DVD_PLAYSPEED_NORMAL)
332     {
333       clock_gettime(CLOCK_REALTIME, &m_starttime);
334       m_av_clock->OMXAudioBufferStart();
335     }
336   }
337
338   // signal to our parent that we have initialized
339   if(m_started == false)
340   {
341     m_started = true;
342     m_messageParent.Put(new CDVDMsgInt(CDVDMsg::PLAYER_STARTED, DVDPLAYER_AUDIO));
343   }
344
345   return true;
346 }
347
348 void OMXPlayerAudio::Process()
349 {
350   m_audioStats.Start();
351
352   while(!m_bStop)
353   {
354     CDVDMsg* pMsg;
355     int priority = (m_speed == DVD_PLAYSPEED_PAUSE && m_started) ? 1 : 0;
356     int timeout = 1000;
357
358     MsgQueueReturnCode ret = m_messageQueue.Get(&pMsg, timeout, priority);
359
360     if (ret == MSGQ_TIMEOUT)
361     {
362       Sleep(10);
363       continue;
364     }
365
366     if (MSGQ_IS_ERROR(ret) || ret == MSGQ_ABORT)
367     {
368       Sleep(10);
369       continue;
370     }
371
372     if (pMsg->IsType(CDVDMsg::DEMUXER_PACKET))
373     {
374       DemuxPacket* pPacket = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacket();
375       bool bPacketDrop     = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacketDrop();
376
377       #ifdef _DEBUG
378       CLog::Log(LOGINFO, "Audio: dts:%.0f pts:%.0f size:%d (s:%d f:%d d:%d l:%d) s:%d %d/%d late:%d,%d", pPacket->dts, pPacket->pts,
379            (int)pPacket->iSize, m_started, m_flush, bPacketDrop, m_stalled, m_speed, 0, 0, (int)m_omxAudio.GetAudioRenderingLatency(), (int)m_hints_current.samplerate);
380       #endif
381       if(Decode(pPacket, m_speed > DVD_PLAYSPEED_NORMAL || m_speed < 0 || bPacketDrop))
382       {
383         if (m_stalled && (m_omxAudio.GetCacheTime() > (AUDIO_BUFFER_SECONDS * 0.75f)))
384         {
385           CLog::Log(LOGINFO, "COMXPlayerAudio - Switching to normal playback");
386           m_stalled = false;
387           if(m_av_clock->HasVideo() && m_av_clock->OMXAudioBuffer())
388             m_av_clock->OMXAudioBufferStop();
389         }
390       }
391       // hard unlock audio out buffering
392       clock_gettime(CLOCK_REALTIME, &m_endtime);
393       //int iLevel = min(99,m_messageQueue.GetLevel() + MathUtils::round_int(100.0/8.0*GetCacheTime()));
394       if(/*iLevel < 10 &&*/ m_stalled && m_av_clock->OMXAudioBuffer() && (m_endtime.tv_sec - m_starttime.tv_sec) > 1)
395       {
396         m_stalled = false;
397         if(m_av_clock->HasVideo() && m_av_clock->OMXAudioBuffer())
398           m_av_clock->OMXAudioBufferStop();
399       }
400     }
401     else if (pMsg->IsType(CDVDMsg::GENERAL_SYNCHRONIZE))
402     {
403       if(((CDVDMsgGeneralSynchronize*)pMsg)->Wait( 100, SYNCSOURCE_AUDIO ))
404         CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::GENERAL_SYNCHRONIZE");
405       else
406         m_messageQueue.Put(pMsg->Acquire(), 1); /* push back as prio message, to process other prio messages */
407     }
408     else if (pMsg->IsType(CDVDMsg::GENERAL_RESYNC))
409     { //player asked us to set internal clock
410       CDVDMsgGeneralResync* pMsgGeneralResync = (CDVDMsgGeneralResync*)pMsg;
411       CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::GENERAL_RESYNC(%f, %d)", m_audioClock, pMsgGeneralResync->m_clock);
412       m_flush = false;
413     }
414     else if (pMsg->IsType(CDVDMsg::GENERAL_RESET))
415     {
416       CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::GENERAL_RESET");
417       if (m_pAudioCodec)
418         m_pAudioCodec->Reset();
419       m_av_clock->Lock();
420       m_av_clock->OMXStop(false);
421       m_omxAudio.Flush();
422       m_av_clock->OMXReset(false);
423       m_av_clock->UnLock();
424       m_started = false;
425     }
426     else if (pMsg->IsType(CDVDMsg::GENERAL_FLUSH))
427     {
428       CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::GENERAL_FLUSH");
429       m_av_clock->Lock();
430       m_av_clock->OMXStop(false);
431       m_omxAudio.Flush();
432       m_av_clock->OMXReset(false);
433       m_av_clock->UnLock();
434       m_stalled   = true;
435       m_started   = false;
436
437       if (m_pAudioCodec)
438         m_pAudioCodec->Reset();
439     }
440     else if (pMsg->IsType(CDVDMsg::PLAYER_STARTED))
441     {
442       CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::PLAYER_STARTED %d", m_started);
443       if(m_started)
444         m_messageParent.Put(new CDVDMsgInt(CDVDMsg::PLAYER_STARTED, DVDPLAYER_AUDIO));
445     }
446     else if (pMsg->IsType(CDVDMsg::PLAYER_DISPLAYTIME))
447     {
448       COMXPlayer::SPlayerState& state = ((CDVDMsgType<COMXPlayer::SPlayerState>*)pMsg)->m_value;
449
450       if(state.time_src == COMXPlayer::ETIMESOURCE_CLOCK)
451         state.time      = DVD_TIME_TO_MSEC(m_av_clock->OMXMediaTime(true));
452         //state.time      = DVD_TIME_TO_MSEC(m_av_clock->GetClock(state.timestamp) + state.time_offset);
453       else
454         state.timestamp = m_av_clock->GetAbsoluteClock();
455       state.player    = DVDPLAYER_AUDIO;
456       m_messageParent.Put(pMsg->Acquire());
457     }
458     else if (pMsg->IsType(CDVDMsg::GENERAL_EOF))
459     {
460       CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::GENERAL_EOF");
461       SubmitEOS();
462     }
463     else if (pMsg->IsType(CDVDMsg::GENERAL_DELAY))
464     {
465       if (m_speed != DVD_PLAYSPEED_PAUSE)
466       {
467         double timeout = static_cast<CDVDMsgDouble*>(pMsg)->m_value;
468
469         CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::GENERAL_DELAY(%f)", timeout);
470
471         timeout *= (double)DVD_PLAYSPEED_NORMAL / abs(m_speed);
472         timeout += m_av_clock->GetAbsoluteClock();
473
474         while(!m_bStop && m_av_clock->GetAbsoluteClock() < timeout)
475           Sleep(1);
476       }
477     }
478     else if (pMsg->IsType(CDVDMsg::PLAYER_SETSPEED))
479     {
480       if (m_speed != static_cast<CDVDMsgInt*>(pMsg)->m_value)
481       {
482         m_speed = static_cast<CDVDMsgInt*>(pMsg)->m_value;
483         CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::PLAYER_SETSPEED %d", m_speed);
484       }
485     }
486     else if (pMsg->IsType(CDVDMsg::AUDIO_SILENCE))
487     {
488       m_silence = static_cast<CDVDMsgBool*>(pMsg)->m_value;
489       if (m_silence)
490         CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::AUDIO_SILENCE(%f, 1)", m_audioClock);
491       else
492         CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::AUDIO_SILENCE(%f, 0)", m_audioClock);
493     }
494     else if (pMsg->IsType(CDVDMsg::GENERAL_STREAMCHANGE))
495     {
496       COMXMsgAudioCodecChange* msg(static_cast<COMXMsgAudioCodecChange*>(pMsg));
497       OpenStream(msg->m_hints, msg->m_codec);
498       msg->m_codec = NULL;
499     }
500
501     pMsg->Release();
502   }
503 }
504
505 void OMXPlayerAudio::Flush()
506 {
507   m_flush = true;
508   m_messageQueue.Flush();
509   m_messageQueue.Put( new CDVDMsg(CDVDMsg::GENERAL_FLUSH), 1);
510 }
511
512 void OMXPlayerAudio::WaitForBuffers()
513 {
514   // make sure there are no more packets available
515   m_messageQueue.WaitUntilEmpty();
516
517   // make sure almost all has been rendered
518   // leave 500ms to avound buffer underruns
519   double delay = GetCacheTime();
520   if(delay > 0.5)
521     Sleep((int)(1000 * (delay - 0.5)));
522 }
523
524 bool OMXPlayerAudio::Passthrough() const
525 {
526   return m_passthrough;
527 }
528
529 AEDataFormat OMXPlayerAudio::GetDataFormat(CDVDStreamInfo hints)
530 {
531   AEDataFormat dataFormat = AE_FMT_S16NE;
532   bool hdmi_passthrough_dts = false;
533   bool hdmi_passthrough_ac3 = false;
534
535   if (m_DllBcmHost.vc_tv_hdmi_audio_supported(EDID_AudioFormat_eAC3, 2, EDID_AudioSampleRate_e44KHz, EDID_AudioSampleSize_16bit ) == 0)
536     hdmi_passthrough_ac3 = true;
537   if (m_DllBcmHost.vc_tv_hdmi_audio_supported(EDID_AudioFormat_eDTS, 2, EDID_AudioSampleRate_e44KHz, EDID_AudioSampleSize_16bit ) == 0)
538     hdmi_passthrough_dts = true;
539
540   m_passthrough = false;
541   m_hw_decode   = false;
542
543   /* check our audio capabilties */
544
545   /* pathrought is overriding hw decode*/
546   if(AUDIO_IS_BITSTREAM(CSettings::Get().GetInt("audiooutput.mode")) && m_use_passthrough)
547   {
548     if(hints.codec == CODEC_ID_AC3 && CSettings::Get().GetBool("audiooutput.ac3passthrough") && hdmi_passthrough_ac3)
549     {
550       dataFormat = AE_FMT_AC3;
551       m_passthrough = true;
552     }
553     if(hints.codec == CODEC_ID_DTS && CSettings::Get().GetBool("audiooutput.dtspassthrough") && hdmi_passthrough_dts)
554     {
555       dataFormat = AE_FMT_DTS;
556       m_passthrough = true;
557     }
558   }
559
560   /* hw decode */
561   if(m_use_hw_decode && !m_passthrough)
562   {
563     if(hints.codec == CODEC_ID_AC3 && COMXAudio::CanHWDecode(m_hints.codec))
564     {
565       dataFormat = AE_FMT_AC3;
566       m_hw_decode = true;
567     }
568     if(hints.codec == CODEC_ID_DTS && COMXAudio::CanHWDecode(m_hints.codec))
569     {
570       dataFormat = AE_FMT_DTS;
571       m_hw_decode = true;
572     }
573   }
574
575   /* software path */
576   if(!m_passthrough && !m_hw_decode)
577   {
578     if (m_pAudioCodec && m_pAudioCodec->GetBitsPerSample() == 16)
579       dataFormat = AE_FMT_S16NE;
580     else
581       dataFormat = AE_FMT_FLOAT;
582   }
583
584   return dataFormat;
585 }
586
587 bool OMXPlayerAudio::OpenDecoder()
588 {
589   m_nChannels   = m_hints.channels;
590   m_passthrough = false;
591   m_hw_decode   = false;
592
593   bool bSendParent = false;
594
595   if(m_DecoderOpen)
596   {
597     WaitCompletion();
598     m_omxAudio.Deinitialize();
599     m_DecoderOpen = false;
600     bSendParent = true;
601   }
602
603   /* setup audi format for audio render */
604   m_format.m_sampleRate    = m_hints.samplerate;
605   m_format.m_channelLayout = m_pAudioCodec->GetChannelMap(); 
606   /* GetDataFormat is setting up evrything */
607   m_format.m_dataFormat = GetDataFormat(m_hints);
608
609   std::string device = "";
610   
611   if(CSettings::Get().GetInt("audiooutput.mode") == AUDIO_HDMI)
612     device = "hdmi";
613   else
614     device = "local";
615
616   m_av_clock->Lock();
617   m_av_clock->OMXStop(false);
618
619   bool bAudioRenderOpen = m_omxAudio.Initialize(m_format, device, m_av_clock, m_hints, m_passthrough, m_hw_decode);
620
621   m_codec_name = "";
622   m_bad_state  = !bAudioRenderOpen;
623   
624   if(!bAudioRenderOpen)
625   {
626     CLog::Log(LOGERROR, "OMXPlayerAudio : Error open audio output");
627     m_omxAudio.Deinitialize();
628   }
629   else
630   {
631     CLog::Log(LOGINFO, "Audio codec %s channels %d samplerate %d bitspersample %d\n",
632       m_codec_name.c_str(), m_nChannels, m_hints.samplerate, m_hints.bitspersample);
633   }
634
635   m_av_clock->OMXStateExecute(false);
636   m_av_clock->HasAudio(bAudioRenderOpen);
637   m_av_clock->OMXReset(false);
638   m_av_clock->UnLock();
639
640   m_started = false;
641
642   // TODO : Send FLUSH to parent, only if we had a valid open codec. 
643   // this is just a workaround to get the omx video decoder happy again
644   // This situation happens, for example where we have in the stream an audio codec change
645   if(bSendParent)
646     m_messageParent.Put(new CDVDMsg(CDVDMsg::GENERAL_FLUSH));
647
648   return bAudioRenderOpen;
649 }
650
651 void OMXPlayerAudio::CloseDecoder()
652 {
653   m_av_clock->Lock();
654   m_av_clock->OMXStop(false);
655   m_omxAudio.Deinitialize();
656   m_av_clock->HasAudio(false);
657   m_av_clock->OMXReset(false);
658   m_av_clock->UnLock();
659
660   m_DecoderOpen = false;
661 }
662
663 double OMXPlayerAudio::GetDelay()
664 {
665   return m_omxAudio.GetDelay();
666 }
667
668 double OMXPlayerAudio::GetCacheTime()
669 {
670   return m_omxAudio.GetCacheTime();
671 }
672
673 double OMXPlayerAudio::GetCacheTotal()
674 {
675   return m_omxAudio.GetCacheTotal();
676 }
677
678 void OMXPlayerAudio::SubmitEOS()
679 {
680   if(!m_bad_state)
681     m_omxAudio.SubmitEOS();
682 }
683
684 bool OMXPlayerAudio::IsEOS()
685 {
686   return m_bad_state || m_omxAudio.IsEOS();
687 }
688
689 void OMXPlayerAudio::WaitCompletion()
690 {
691   unsigned int nTimeOut = AUDIO_BUFFER_SECONDS * 1000;
692   while(nTimeOut)
693   {
694     if(IsEOS())
695     {
696       CLog::Log(LOGDEBUG, "%s::%s - got eos\n", CLASSNAME, __func__);
697       break;
698     }
699
700     if(nTimeOut == 0)
701     {
702       CLog::Log(LOGERROR, "%s::%s - wait for eos timed out\n", CLASSNAME, __func__);
703       break;
704     }
705     Sleep(50);
706     nTimeOut -= 50;
707   }
708 }
709
710 void OMXPlayerAudio::RegisterAudioCallback(IAudioCallback *pCallback)
711 {
712   m_omxAudio.RegisterAudioCallback(pCallback);
713 }
714
715 void OMXPlayerAudio::UnRegisterAudioCallback()
716 {
717   m_omxAudio.UnRegisterAudioCallback();
718 }
719
720 void OMXPlayerAudio::SetCurrentVolume(float fVolume)
721 {
722   m_omxAudio.SetCurrentVolume(fVolume);
723 }
724
725 void OMXPlayerAudio::SetSpeed(int speed)
726 {
727   if(m_messageQueue.IsInited())
728     m_messageQueue.Put( new CDVDMsgInt(CDVDMsg::PLAYER_SETSPEED, speed), 1 );
729   else
730     m_speed = speed;
731 }
732
733 int OMXPlayerAudio::GetAudioBitrate()
734 {
735   return (int)m_audioStats.GetBitrate();
736 }
737
738 std::string OMXPlayerAudio::GetPlayerInfo()
739 {
740   std::ostringstream s;
741   s << "aq:"     << setw(2) << min(99,m_messageQueue.GetLevel() + MathUtils::round_int(100.0/8.0*GetCacheTime())) << "%";
742   s << ", Kb/s:" << fixed << setprecision(2) << (double)GetAudioBitrate() / 1024.0;
743
744   return s.str();
745 }