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 TARGET_WINDOWS)
23 #elif defined(TARGET_WINDOWS)
27 #include "OMXPlayerAudio.h"
33 #include "linux/XMemUtils.h"
34 #include "utils/BitstreamStats.h"
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"
43 #include "OMXPlayer.h"
48 class COMXMsgAudioCodecChange : public CDVDMsg
51 COMXMsgAudioCodecChange(const CDVDStreamInfo &hints, COMXAudioCodecOMX* codec)
52 : CDVDMsg(GENERAL_STREAMCHANGE)
56 ~COMXMsgAudioCodecChange()
60 COMXAudioCodecOMX *m_codec;
61 CDVDStreamInfo m_hints;
64 OMXPlayerAudio::OMXPlayerAudio(OMXClock *av_clock, CDVDMessageQueue& parent)
65 : CThread("OMXPlayerAudio")
66 , m_messageQueue("audio")
67 , m_messageParent(parent)
69 m_av_clock = av_clock;
71 m_speed = DVD_PLAYSPEED_NORMAL;
75 m_buffer_empty = false;
77 m_DecoderOpen = false;
79 m_hints_current.Clear();
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;
92 OMXPlayerAudio::~OMXPlayerAudio()
96 m_DllBcmHost.Unload();
99 bool OMXPlayerAudio::OpenStream(CDVDStreamInfo &hints)
101 if(!m_DllBcmHost.Load())
106 COMXAudioCodecOMX *codec = new COMXAudioCodecOMX();
108 if(!codec || !codec->Open(hints))
110 CLog::Log(LOGERROR, "Unsupported audio codec");
111 delete codec; codec = NULL;
115 if(m_messageQueue.IsInited())
116 m_messageQueue.Put(new COMXMsgAudioCodecChange(hints, codec), 0);
119 OpenStream(hints, codec);
120 m_messageQueue.Init();
121 CLog::Log(LOGNOTICE, "Creating audio thread");
128 void OMXPlayerAudio::OpenStream(CDVDStreamInfo &hints, COMXAudioCodecOMX *codec)
130 SAFE_DELETE(m_pAudioCodec);
133 m_pAudioCodec = codec;
135 if(m_hints.bitspersample == 0)
136 m_hints.bitspersample = 16;
138 m_speed = DVD_PLAYSPEED_NORMAL;
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;
150 bool OMXPlayerAudio::CloseStream(bool bWaitForBuffers)
152 // wait until buffers are empty
153 if (bWaitForBuffers && m_speed > 0) m_messageQueue.WaitUntilEmpty();
155 m_messageQueue.Abort();
160 m_messageQueue.End();
164 m_pAudioCodec->Dispose();
165 delete m_pAudioCodec;
166 m_pAudioCodec = NULL;
171 m_speed = DVD_PLAYSPEED_NORMAL;
177 void OMXPlayerAudio::OnStartup()
181 void OMXPlayerAudio::OnExit()
183 CLog::Log(LOGNOTICE, "thread end: OMXPlayerAudio::OnExit()");
186 bool OMXPlayerAudio::CodecChange()
188 unsigned int old_bitrate = m_hints.bitrate;
189 unsigned int new_bitrate = m_hints_current.bitrate;
193 m_hints.channels = m_pAudioCodec->GetChannels();
194 m_hints.samplerate = m_pAudioCodec->GetSampleRate();
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;
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 ||
208 m_hints_current = m_hints;
215 bool OMXPlayerAudio::Decode(DemuxPacket *pkt, bool bDropPacket)
217 if(!pkt || m_bad_state || !m_pAudioCodec)
220 if(pkt->dts != DVD_NOPTS_VALUE)
221 m_audioClock = pkt->dts;
223 const uint8_t *data_dec = pkt->pData;
224 int data_len = pkt->iSize;
226 if(!OMX_IS_RAW(m_format.m_dataFormat))
228 while(!m_bStop && data_len > 0)
230 int len = m_pAudioCodec->Decode((BYTE *)data_dec, data_len);
231 if( (len < 0) || (len > data_len) )
233 m_pAudioCodec->Reset();
241 int decoded_size = m_pAudioCodec->GetData(&decoded);
248 m_audioStats.AddSampleBytes(decoded_size);
252 m_DecoderOpen = OpenDecoder();
259 // discard if flushing as clocks may be stopped and we'll never submit it
263 if(m_omxAudio.GetSpace() < (unsigned int)decoded_size)
271 // Zero out the frame data if we are supposed to silence the audio
273 memset(decoded, 0x0, decoded_size);
275 ret = m_omxAudio.AddPackets(decoded, decoded_size, m_audioClock, m_audioClock);
277 if(ret != decoded_size)
279 CLog::Log(LOGERROR, "error ret %d decoded_size %d\n", ret, decoded_size);
283 int n = (m_nChannels * m_hints.bitspersample * m_hints.samplerate)>>3;
285 m_audioClock += ((double)decoded_size * DVD_TIME_BASE) / n;
295 m_DecoderOpen = OpenDecoder();
305 if(m_omxAudio.GetSpace() < (unsigned int)pkt->iSize)
314 memset(pkt->pData, 0x0, pkt->iSize);
316 m_omxAudio.AddPackets(pkt->pData, pkt->iSize, m_audioClock, m_audioClock);
319 m_audioStats.AddSampleBytes(pkt->iSize);
328 if(m_omxAudio.GetCacheTime() < 0.1 /*&& min(99,m_messageQueue.GetLevel() + MathUtils::round_int(100.0/8.0*GetCacheTime())) > 10*/)
331 if(!m_av_clock->OMXAudioBuffer() && m_av_clock->HasVideo() && m_speed == DVD_PLAYSPEED_NORMAL)
333 clock_gettime(CLOCK_REALTIME, &m_starttime);
334 m_av_clock->OMXAudioBufferStart();
338 // signal to our parent that we have initialized
339 if(m_started == false)
342 m_messageParent.Put(new CDVDMsgInt(CDVDMsg::PLAYER_STARTED, DVDPLAYER_AUDIO));
348 void OMXPlayerAudio::Process()
350 m_audioStats.Start();
355 int priority = (m_speed == DVD_PLAYSPEED_PAUSE && m_started) ? 1 : 0;
358 MsgQueueReturnCode ret = m_messageQueue.Get(&pMsg, timeout, priority);
360 if (ret == MSGQ_TIMEOUT)
366 if (MSGQ_IS_ERROR(ret) || ret == MSGQ_ABORT)
372 if (pMsg->IsType(CDVDMsg::DEMUXER_PACKET))
374 DemuxPacket* pPacket = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacket();
375 bool bPacketDrop = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacketDrop();
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);
381 if(Decode(pPacket, m_speed > DVD_PLAYSPEED_NORMAL || m_speed < 0 || bPacketDrop))
383 if (m_stalled && (m_omxAudio.GetCacheTime() > (AUDIO_BUFFER_SECONDS * 0.75f)))
385 CLog::Log(LOGINFO, "COMXPlayerAudio - Switching to normal playback");
387 if(m_av_clock->HasVideo() && m_av_clock->OMXAudioBuffer())
388 m_av_clock->OMXAudioBufferStop();
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)
397 if(m_av_clock->HasVideo() && m_av_clock->OMXAudioBuffer())
398 m_av_clock->OMXAudioBufferStop();
401 else if (pMsg->IsType(CDVDMsg::GENERAL_SYNCHRONIZE))
403 if(((CDVDMsgGeneralSynchronize*)pMsg)->Wait( 100, SYNCSOURCE_AUDIO ))
404 CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::GENERAL_SYNCHRONIZE");
406 m_messageQueue.Put(pMsg->Acquire(), 1); /* push back as prio message, to process other prio messages */
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);
414 else if (pMsg->IsType(CDVDMsg::GENERAL_RESET))
416 CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::GENERAL_RESET");
418 m_pAudioCodec->Reset();
420 m_av_clock->OMXStop(false);
422 m_av_clock->OMXReset(false);
423 m_av_clock->UnLock();
426 else if (pMsg->IsType(CDVDMsg::GENERAL_FLUSH))
428 CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::GENERAL_FLUSH");
430 m_av_clock->OMXStop(false);
432 m_av_clock->OMXReset(false);
433 m_av_clock->UnLock();
438 m_pAudioCodec->Reset();
440 else if (pMsg->IsType(CDVDMsg::PLAYER_STARTED))
442 CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::PLAYER_STARTED %d", m_started);
444 m_messageParent.Put(new CDVDMsgInt(CDVDMsg::PLAYER_STARTED, DVDPLAYER_AUDIO));
446 else if (pMsg->IsType(CDVDMsg::PLAYER_DISPLAYTIME))
448 COMXPlayer::SPlayerState& state = ((CDVDMsgType<COMXPlayer::SPlayerState>*)pMsg)->m_value;
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);
454 state.timestamp = m_av_clock->GetAbsoluteClock();
455 state.player = DVDPLAYER_AUDIO;
456 m_messageParent.Put(pMsg->Acquire());
458 else if (pMsg->IsType(CDVDMsg::GENERAL_EOF))
460 CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::GENERAL_EOF");
463 else if (pMsg->IsType(CDVDMsg::GENERAL_DELAY))
465 if (m_speed != DVD_PLAYSPEED_PAUSE)
467 double timeout = static_cast<CDVDMsgDouble*>(pMsg)->m_value;
469 CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::GENERAL_DELAY(%f)", timeout);
471 timeout *= (double)DVD_PLAYSPEED_NORMAL / abs(m_speed);
472 timeout += m_av_clock->GetAbsoluteClock();
474 while(!m_bStop && m_av_clock->GetAbsoluteClock() < timeout)
478 else if (pMsg->IsType(CDVDMsg::PLAYER_SETSPEED))
480 if (m_speed != static_cast<CDVDMsgInt*>(pMsg)->m_value)
482 m_speed = static_cast<CDVDMsgInt*>(pMsg)->m_value;
483 CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::PLAYER_SETSPEED %d", m_speed);
486 else if (pMsg->IsType(CDVDMsg::AUDIO_SILENCE))
488 m_silence = static_cast<CDVDMsgBool*>(pMsg)->m_value;
490 CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::AUDIO_SILENCE(%f, 1)", m_audioClock);
492 CLog::Log(LOGDEBUG, "COMXPlayerAudio - CDVDMsg::AUDIO_SILENCE(%f, 0)", m_audioClock);
494 else if (pMsg->IsType(CDVDMsg::GENERAL_STREAMCHANGE))
496 COMXMsgAudioCodecChange* msg(static_cast<COMXMsgAudioCodecChange*>(pMsg));
497 OpenStream(msg->m_hints, msg->m_codec);
505 void OMXPlayerAudio::Flush()
508 m_messageQueue.Flush();
509 m_messageQueue.Put( new CDVDMsg(CDVDMsg::GENERAL_FLUSH), 1);
512 void OMXPlayerAudio::WaitForBuffers()
514 // make sure there are no more packets available
515 m_messageQueue.WaitUntilEmpty();
517 // make sure almost all has been rendered
518 // leave 500ms to avound buffer underruns
519 double delay = GetCacheTime();
521 Sleep((int)(1000 * (delay - 0.5)));
524 bool OMXPlayerAudio::Passthrough() const
526 return m_passthrough;
529 AEDataFormat OMXPlayerAudio::GetDataFormat(CDVDStreamInfo hints)
531 AEDataFormat dataFormat = AE_FMT_S16NE;
532 bool hdmi_passthrough_dts = false;
533 bool hdmi_passthrough_ac3 = false;
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;
540 m_passthrough = false;
543 /* check our audio capabilties */
545 /* pathrought is overriding hw decode*/
546 if(AUDIO_IS_BITSTREAM(CSettings::Get().GetInt("audiooutput.mode")) && m_use_passthrough)
548 if(hints.codec == CODEC_ID_AC3 && CSettings::Get().GetBool("audiooutput.ac3passthrough") && hdmi_passthrough_ac3)
550 dataFormat = AE_FMT_AC3;
551 m_passthrough = true;
553 if(hints.codec == CODEC_ID_DTS && CSettings::Get().GetBool("audiooutput.dtspassthrough") && hdmi_passthrough_dts)
555 dataFormat = AE_FMT_DTS;
556 m_passthrough = true;
561 if(m_use_hw_decode && !m_passthrough)
563 if(hints.codec == CODEC_ID_AC3 && COMXAudio::CanHWDecode(m_hints.codec))
565 dataFormat = AE_FMT_AC3;
568 if(hints.codec == CODEC_ID_DTS && COMXAudio::CanHWDecode(m_hints.codec))
570 dataFormat = AE_FMT_DTS;
576 if(!m_passthrough && !m_hw_decode)
578 if (m_pAudioCodec && m_pAudioCodec->GetBitsPerSample() == 16)
579 dataFormat = AE_FMT_S16NE;
581 dataFormat = AE_FMT_FLOAT;
587 bool OMXPlayerAudio::OpenDecoder()
589 m_nChannels = m_hints.channels;
590 m_passthrough = false;
593 bool bSendParent = false;
598 m_omxAudio.Deinitialize();
599 m_DecoderOpen = false;
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);
609 std::string device = "";
611 if(CSettings::Get().GetInt("audiooutput.mode") == AUDIO_HDMI)
617 m_av_clock->OMXStop(false);
619 bool bAudioRenderOpen = m_omxAudio.Initialize(m_format, device, m_av_clock, m_hints, m_passthrough, m_hw_decode);
622 m_bad_state = !bAudioRenderOpen;
624 if(!bAudioRenderOpen)
626 CLog::Log(LOGERROR, "OMXPlayerAudio : Error open audio output");
627 m_omxAudio.Deinitialize();
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);
635 m_av_clock->OMXStateExecute(false);
636 m_av_clock->HasAudio(bAudioRenderOpen);
637 m_av_clock->OMXReset(false);
638 m_av_clock->UnLock();
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
646 m_messageParent.Put(new CDVDMsg(CDVDMsg::GENERAL_FLUSH));
648 return bAudioRenderOpen;
651 void OMXPlayerAudio::CloseDecoder()
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();
660 m_DecoderOpen = false;
663 double OMXPlayerAudio::GetDelay()
665 return m_omxAudio.GetDelay();
668 double OMXPlayerAudio::GetCacheTime()
670 return m_omxAudio.GetCacheTime();
673 double OMXPlayerAudio::GetCacheTotal()
675 return m_omxAudio.GetCacheTotal();
678 void OMXPlayerAudio::SubmitEOS()
681 m_omxAudio.SubmitEOS();
684 bool OMXPlayerAudio::IsEOS()
686 return m_bad_state || m_omxAudio.IsEOS();
689 void OMXPlayerAudio::WaitCompletion()
691 unsigned int nTimeOut = AUDIO_BUFFER_SECONDS * 1000;
696 CLog::Log(LOGDEBUG, "%s::%s - got eos\n", CLASSNAME, __func__);
702 CLog::Log(LOGERROR, "%s::%s - wait for eos timed out\n", CLASSNAME, __func__);
710 void OMXPlayerAudio::RegisterAudioCallback(IAudioCallback *pCallback)
712 m_omxAudio.RegisterAudioCallback(pCallback);
715 void OMXPlayerAudio::UnRegisterAudioCallback()
717 m_omxAudio.UnRegisterAudioCallback();
720 void OMXPlayerAudio::SetCurrentVolume(float fVolume)
722 m_omxAudio.SetCurrentVolume(fVolume);
725 void OMXPlayerAudio::SetSpeed(int speed)
727 if(m_messageQueue.IsInited())
728 m_messageQueue.Put( new CDVDMsgInt(CDVDMsg::PLAYER_SETSPEED, speed), 1 );
733 int OMXPlayerAudio::GetAudioBitrate()
735 return (int)m_audioStats.GetBitrate();
738 std::string OMXPlayerAudio::GetPlayerInfo()
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;