2 * Copyright (C) 2005-2013 Team XBMC
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)
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.
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/>.
21 #if (defined HAVE_CONFIG_H) && (!defined WIN32)
27 #include "OMXPlayerAudio.h"
33 #include "linux/XMemUtils.h"
34 #include "utils/BitstreamStats.h"
35 #include "settings/GUISettings.h"
36 #include "settings/Settings.h"
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"
44 #include "OMXPlayer.h"
49 class COMXMsgAudioCodecChange : public CDVDMsg
52 COMXMsgAudioCodecChange(const CDVDStreamInfo &hints, COMXAudioCodecOMX* codec)
53 : CDVDMsg(GENERAL_STREAMCHANGE)
57 ~COMXMsgAudioCodecChange()
61 COMXAudioCodecOMX *m_codec;
62 CDVDStreamInfo m_hints;
65 OMXPlayerAudio::OMXPlayerAudio(OMXClock *av_clock, CDVDMessageQueue& parent)
66 : CThread("COMXPlayerAudio")
67 , m_messageQueue("audio")
68 , m_messageParent(parent)
70 m_av_clock = av_clock;
72 m_speed = DVD_PLAYSPEED_NORMAL;
76 m_buffer_empty = false;
78 m_DecoderOpen = false;
79 m_freq = CurrentHostFrequency();
82 m_hints_current.Clear();
84 m_av_clock->SetMasterClock(false);
86 m_messageQueue.SetMaxDataSize(3 * 1024 * 1024);
87 m_messageQueue.SetMaxTimeSize(8.0);
91 OMXPlayerAudio::~OMXPlayerAudio()
95 m_DllBcmHost.Unload();
98 bool OMXPlayerAudio::OpenStream(CDVDStreamInfo &hints)
100 if(!m_DllBcmHost.Load())
105 COMXAudioCodecOMX *codec = new COMXAudioCodecOMX();
107 if(!codec || !codec->Open(hints))
109 CLog::Log(LOGERROR, "Unsupported audio codec");
110 delete codec; codec = NULL;
114 if(m_messageQueue.IsInited())
115 m_messageQueue.Put(new COMXMsgAudioCodecChange(hints, codec), 0);
118 OpenStream(hints, codec);
119 m_messageQueue.Init();
120 CLog::Log(LOGNOTICE, "Creating audio thread");
127 void OMXPlayerAudio::OpenStream(CDVDStreamInfo &hints, COMXAudioCodecOMX *codec)
129 SAFE_DELETE(m_pAudioCodec);
132 m_pAudioCodec = codec;
134 if(m_hints.bitspersample == 0)
135 m_hints.bitspersample = 16;
137 m_speed = DVD_PLAYSPEED_NORMAL;
144 m_prevskipped = false;
147 m_errortime = CurrentHostCounter();
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;
159 bool OMXPlayerAudio::CloseStream(bool bWaitForBuffers)
161 // wait until buffers are empty
162 if (bWaitForBuffers && m_speed > 0) m_messageQueue.WaitUntilEmpty();
164 m_messageQueue.Abort();
169 m_messageQueue.End();
173 m_pAudioCodec->Dispose();
174 delete m_pAudioCodec;
175 m_pAudioCodec = NULL;
180 m_speed = DVD_PLAYSPEED_NORMAL;
186 void OMXPlayerAudio::OnStartup()
190 void OMXPlayerAudio::OnExit()
192 CLog::Log(LOGNOTICE, "thread end: OMXPlayerAudio::OnExit()");
197 void OMXPlayerAudio::HandleSyncError(double duration)
199 double clock = m_av_clock->GetClock();
200 double error = m_audioClock - clock;
203 if( fabs(error) > DVD_MSEC_TO_TIME(100) || m_syncclock )
205 m_av_clock->Discontinuity(clock+error);
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);
216 m_errortime = m_av_clock->CurrentHostCounter();
221 if (m_speed != DVD_PLAYSPEED_NORMAL)
228 m_errortime = m_av_clock->CurrentHostCounter();
232 //check if measured error for 1 second
233 now = m_av_clock->CurrentHostCounter();
234 if ((now - m_errortime) >= m_freq)
237 m_error = m_errorbuff / m_errorcount;
242 if (m_synctype == SYNC_DISCON)
246 if (m_av_clock->GetRefreshRate(&limit) > 0)
248 //when the videoreferenceclock is running, the discontinuity limit is one vblank period
249 limit *= DVD_TIME_BASE;
251 //make error a multiple of limit, rounded towards zero,
252 //so it won't interfere with the sync methods in CXBMCRenderManager::WaitPresentTime
254 error = limit * floor(m_error / limit);
256 error = limit * ceil(m_error / limit);
260 limit = DVD_MSEC_TO_TIME(10);
265 limit = DVD_MSEC_TO_TIME(10);
269 if (fabs(error) > limit - 0.001)
271 m_av_clock->Discontinuity(clock+error);
273 if(m_speed == DVD_PLAYSPEED_NORMAL)
274 CLog::Log(LOGDEBUG, "COMXPlayerAudio:: Discontinuity - was:%f, should be:%f, error:%f", clock, clock+error, error);
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))
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));
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);
299 bool OMXPlayerAudio::CodecChange()
301 unsigned int old_bitrate = m_hints.bitrate;
302 unsigned int new_bitrate = m_hints_current.bitrate;
306 m_hints.channels = m_pAudioCodec->GetChannels();
307 m_hints.samplerate = m_pAudioCodec->GetSampleRate();
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;
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 ||
321 m_hints_current = m_hints;
328 bool OMXPlayerAudio::Decode(DemuxPacket *pkt, bool bDropPacket)
330 if(!pkt || m_bad_state || !m_pAudioCodec)
333 if(pkt->dts != DVD_NOPTS_VALUE)
334 m_audioClock = pkt->dts;
336 const uint8_t *data_dec = pkt->pData;
337 int data_len = pkt->iSize;
339 if(!OMX_IS_RAW(m_format.m_dataFormat))
341 while(!m_bStop && data_len > 0)
343 int len = m_pAudioCodec->Decode((BYTE *)data_dec, data_len);
344 if( (len < 0) || (len > data_len) )
346 m_pAudioCodec->Reset();
354 int decoded_size = m_pAudioCodec->GetData(&decoded);
361 m_audioStats.AddSampleBytes(decoded_size);
365 m_DecoderOpen = OpenDecoder();
374 CSingleLock lock(m_flushLock);
380 if(m_omxAudio.GetSpace() < (unsigned int)pkt->iSize)
388 // Zero out the frame data if we are supposed to silence the audio
390 memset(decoded, 0x0, decoded_size);
392 ret = m_omxAudio.AddPackets(decoded, decoded_size, m_audioClock, m_audioClock);
394 if(ret != decoded_size)
396 CLog::Log(LOGERROR, "error ret %d decoded_size %d\n", ret, decoded_size);
400 int n = (m_nChannels * m_hints.bitspersample * m_hints.samplerate)>>3;
402 m_audioClock += ((double)decoded_size * DVD_TIME_BASE) / n;
404 if(m_speed == DVD_PLAYSPEED_NORMAL)
405 HandleSyncError((((double)decoded_size * DVD_TIME_BASE) / n));
415 m_DecoderOpen = OpenDecoder();
424 CSingleLock lock(m_flushLock);
430 if(m_omxAudio.GetSpace() < (unsigned int)pkt->iSize)
439 memset(pkt->pData, 0x0, pkt->iSize);
441 m_omxAudio.AddPackets(pkt->pData, pkt->iSize, m_audioClock, m_audioClock);
444 if(m_speed == DVD_PLAYSPEED_NORMAL)
447 m_audioStats.AddSampleBytes(pkt->iSize);
456 if(m_omxAudio.GetCacheTime() < 0.1 /*&& min(99,m_messageQueue.GetLevel() + MathUtils::round_int(100.0/8.0*GetCacheTime())) > 10*/)
459 if(!m_av_clock->OMXAudioBuffer() && m_av_clock->HasVideo() && m_speed == DVD_PLAYSPEED_NORMAL)
461 clock_gettime(CLOCK_REALTIME, &m_starttime);
462 m_av_clock->OMXAudioBufferStart();
466 // signal to our parent that we have initialized
467 if(m_started == false)
470 m_messageParent.Put(new CDVDMsgInt(CDVDMsg::PLAYER_STARTED, DVDPLAYER_AUDIO));
476 void OMXPlayerAudio::Process()
478 m_audioStats.Start();
483 int priority = (m_speed == DVD_PLAYSPEED_PAUSE && m_started) ? 1 : 0;
486 MsgQueueReturnCode ret = m_messageQueue.Get(&pMsg, timeout, priority);
488 if (ret == MSGQ_TIMEOUT)
494 if (MSGQ_IS_ERROR(ret) || ret == MSGQ_ABORT)
500 if (pMsg->IsType(CDVDMsg::DEMUXER_PACKET))
502 DemuxPacket* pPacket = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacket();
503 bool bPacketDrop = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacketDrop();
505 if(Decode(pPacket, m_speed > DVD_PLAYSPEED_NORMAL || m_speed < 0 || bPacketDrop))
507 if (m_stalled && (m_omxAudio.GetCacheTime() > (AUDIO_BUFFER_SECONDS * 0.75f)))
509 CLog::Log(LOGINFO, "COMXPlayerAudio - Switching to normal playback");
511 if(m_av_clock->HasVideo() && m_av_clock->OMXAudioBuffer())
512 m_av_clock->OMXAudioBufferStop();
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)
521 if(m_av_clock->HasVideo() && m_av_clock->OMXAudioBuffer())
522 m_av_clock->OMXAudioBufferStop();
525 else if (pMsg->IsType(CDVDMsg::GENERAL_SYNCHRONIZE))
527 if(((CDVDMsgGeneralSynchronize*)pMsg)->Wait( 100, SYNCSOURCE_AUDIO ))
528 CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::GENERAL_SYNCHRONIZE");
530 m_messageQueue.Put(pMsg->Acquire(), 1); /* push back as prio message, to process other prio messages */
532 else if (pMsg->IsType(CDVDMsg::GENERAL_RESYNC))
533 { //player asked us to set internal clock
534 CDVDMsgGeneralResync* pMsgGeneralResync = (CDVDMsgGeneralResync*)pMsg;
536 if (pMsgGeneralResync->m_timestamp != DVD_NOPTS_VALUE)
537 m_audioClock = pMsgGeneralResync->m_timestamp;
539 if (pMsgGeneralResync->m_clock)
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);
546 CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::GENERAL_RESYNC(%f, 0)", m_audioClock);
548 else if (pMsg->IsType(CDVDMsg::GENERAL_RESET))
550 CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::GENERAL_RESET");
552 m_pAudioCodec->Reset();
554 m_av_clock->OMXStop(false);
556 m_av_clock->OMXReset(false);
557 m_av_clock->UnLock();
560 else if (pMsg->IsType(CDVDMsg::GENERAL_FLUSH))
562 CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::GENERAL_FLUSH");
564 m_av_clock->OMXStop(false);
566 m_av_clock->OMXReset(false);
567 m_av_clock->UnLock();
573 m_pAudioCodec->Reset();
575 else if (pMsg->IsType(CDVDMsg::PLAYER_STARTED))
578 m_messageParent.Put(new CDVDMsgInt(CDVDMsg::PLAYER_STARTED, DVDPLAYER_AUDIO));
580 else if (pMsg->IsType(CDVDMsg::GENERAL_EOF))
582 CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::GENERAL_EOF");
585 else if (pMsg->IsType(CDVDMsg::GENERAL_DELAY))
587 if (m_speed != DVD_PLAYSPEED_PAUSE)
589 double timeout = static_cast<CDVDMsgDouble*>(pMsg)->m_value;
591 CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::GENERAL_DELAY(%f)", timeout);
593 timeout *= (double)DVD_PLAYSPEED_NORMAL / abs(m_speed);
594 timeout += m_av_clock->GetAbsoluteClock();
596 while(!m_bStop && m_av_clock->GetAbsoluteClock() < timeout)
600 else if (pMsg->IsType(CDVDMsg::PLAYER_SETSPEED))
602 CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::PLAYER_SETSPEED");
603 m_speed = static_cast<CDVDMsgInt*>(pMsg)->m_value;
604 if (m_speed != DVD_PLAYSPEED_NORMAL)
609 else if (pMsg->IsType(CDVDMsg::AUDIO_SILENCE))
611 m_silence = static_cast<CDVDMsgBool*>(pMsg)->m_value;
613 CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::AUDIO_SILENCE(%f, 1)", m_audioClock);
615 CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::AUDIO_SILENCE(%f, 0)", m_audioClock);
617 else if (pMsg->IsType(CDVDMsg::GENERAL_STREAMCHANGE))
619 COMXMsgAudioCodecChange* msg(static_cast<COMXMsgAudioCodecChange*>(pMsg));
620 OpenStream(msg->m_hints, msg->m_codec);
628 void OMXPlayerAudio::Flush()
630 CSingleLock lock(m_flushLock);
632 m_messageQueue.Flush();
633 m_messageQueue.Put( new CDVDMsg(CDVDMsg::GENERAL_FLUSH), 1);
636 void OMXPlayerAudio::WaitForBuffers()
638 // make sure there are no more packets available
639 m_messageQueue.WaitUntilEmpty();
641 // make sure almost all has been rendered
642 // leave 500ms to avound buffer underruns
643 double delay = GetCacheTime();
645 Sleep((int)(1000 * (delay - 0.5)));
648 bool OMXPlayerAudio::Passthrough() const
650 return m_passthrough;
653 AEDataFormat OMXPlayerAudio::GetDataFormat(CDVDStreamInfo hints)
655 AEDataFormat dataFormat = AE_FMT_S16NE;
656 bool hdmi_passthrough_dts = false;
657 bool hdmi_passthrough_ac3 = false;
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);
665 m_passthrough = false;
668 /* check our audio capabilties */
670 /* pathrought is overriding hw decode*/
671 if(AUDIO_IS_BITSTREAM(g_guiSettings.GetInt("audiooutput.mode")) && m_use_passthrough)
673 if(hints.codec == CODEC_ID_AC3 && g_guiSettings.GetBool("audiooutput.ac3passthrough") && hdmi_passthrough_ac3)
675 dataFormat = AE_FMT_AC3;
676 m_passthrough = true;
678 if(hints.codec == CODEC_ID_DTS && g_guiSettings.GetBool("audiooutput.dtspassthrough") && hdmi_passthrough_dts)
680 dataFormat = AE_FMT_DTS;
681 m_passthrough = true;
686 if(m_use_hw_decode && !m_passthrough)
688 if(hints.codec == CODEC_ID_AC3 && COMXAudio::CanHWDecode(m_hints.codec))
690 dataFormat = AE_FMT_AC3;
693 if(hints.codec == CODEC_ID_DTS && COMXAudio::CanHWDecode(m_hints.codec))
695 dataFormat = AE_FMT_DTS;
701 if(!m_passthrough && !m_hw_decode)
703 /* 6 channel have to be mapped to 8 for PCM */
706 dataFormat = AE_FMT_S16NE;
712 bool OMXPlayerAudio::OpenDecoder()
714 m_nChannels = m_hints.channels;
715 m_passthrough = false;
718 bool bSendParent = false;
723 m_omxAudio.Deinitialize();
724 m_DecoderOpen = false;
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);
734 std::string device = "";
736 if(g_guiSettings.GetInt("audiooutput.mode") == AUDIO_HDMI)
742 m_av_clock->OMXStop(false);
744 bool bAudioRenderOpen = m_omxAudio.Initialize(m_format, device, m_av_clock, m_hints, m_passthrough, m_hw_decode);
747 m_bad_state = !bAudioRenderOpen;
749 if(!bAudioRenderOpen)
751 CLog::Log(LOGERROR, "OMXPlayerAudio : Error open audio output");
752 m_omxAudio.Deinitialize();
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);
760 m_av_clock->OMXStateExecute(false);
761 m_av_clock->HasAudio(bAudioRenderOpen);
762 m_av_clock->OMXReset(false);
763 m_av_clock->UnLock();
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
771 m_messageParent.Put(new CDVDMsg(CDVDMsg::GENERAL_FLUSH));
773 return bAudioRenderOpen;
776 void OMXPlayerAudio::CloseDecoder()
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();
785 m_DecoderOpen = false;
788 double OMXPlayerAudio::GetDelay()
790 return m_omxAudio.GetDelay();
793 double OMXPlayerAudio::GetCacheTime()
795 return m_omxAudio.GetCacheTime();
798 void OMXPlayerAudio::WaitCompletion()
800 if(!m_send_eos && !m_bad_state)
801 m_omxAudio.WaitCompletion();
805 void OMXPlayerAudio::RegisterAudioCallback(IAudioCallback *pCallback)
807 m_omxAudio.RegisterAudioCallback(pCallback);
810 void OMXPlayerAudio::UnRegisterAudioCallback()
812 m_omxAudio.UnRegisterAudioCallback();
815 void OMXPlayerAudio::SetCurrentVolume(float fVolume)
817 m_omxAudio.SetCurrentVolume(fVolume);
820 void OMXPlayerAudio::SetSpeed(int speed)
822 if(m_messageQueue.IsInited())
823 m_messageQueue.Put( new CDVDMsgInt(CDVDMsg::PLAYER_SETSPEED, speed), 1 );
828 int OMXPlayerAudio::GetAudioBitrate()
830 return (int)m_audioStats.GetBitrate();
833 std::string OMXPlayerAudio::GetPlayerInfo()
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;