2 * Copyright (C) 2012-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
9 #include "RetroPlayerAudio.h"
11 #include "ServiceBroker.h"
12 #include "cores/AudioEngine/Interfaces/AE.h"
13 #include "cores/AudioEngine/Interfaces/AEStream.h"
14 #include "cores/AudioEngine/Utils/AEChannelInfo.h"
15 #include "cores/AudioEngine/Utils/AEUtil.h"
16 #include "cores/RetroPlayer/audio/AudioTranslator.h"
17 #include "cores/RetroPlayer/process/RPProcessInfo.h"
18 #include "utils/log.h"
23 using namespace RETRO
;
25 const double MAX_DELAY
= 0.3; // seconds
27 CRetroPlayerAudio::CRetroPlayerAudio(CRPProcessInfo
& processInfo
)
28 : m_processInfo(processInfo
), m_pAudioStream(nullptr)
30 CLog::Log(LOGDEBUG
, "RetroPlayer[AUDIO]: Initializing audio");
33 CRetroPlayerAudio::~CRetroPlayerAudio()
35 CLog::Log(LOGDEBUG
, "RetroPlayer[AUDIO]: Deinitializing audio");
40 bool CRetroPlayerAudio::OpenStream(const StreamProperties
& properties
)
42 const AudioStreamProperties
& audioProperties
=
43 static_cast<const AudioStreamProperties
&>(properties
);
45 const AEDataFormat pcmFormat
= CAudioTranslator::TranslatePCMFormat(audioProperties
.format
);
46 if (pcmFormat
== AE_FMT_INVALID
)
48 CLog::Log(LOGERROR
, "RetroPlayer[AUDIO]: Unknown PCM format: {}",
49 static_cast<int>(audioProperties
.format
));
53 unsigned int iSampleRate
= static_cast<unsigned int>(std::round(audioProperties
.sampleRate
));
56 CLog::Log(LOGERROR
, "RetroPlayer[AUDIO]: Invalid samplerate: {:f}", audioProperties
.sampleRate
);
60 CAEChannelInfo channelLayout
;
61 for (auto it
= audioProperties
.channelMap
.begin(); it
!= audioProperties
.channelMap
.end(); ++it
)
63 AEChannel channel
= CAudioTranslator::TranslateAudioChannel(*it
);
64 if (channel
== AE_CH_NULL
)
67 channelLayout
+= channel
;
70 if (!channelLayout
.IsLayoutValid())
72 CLog::Log(LOGERROR
, "RetroPlayer[AUDIO]: Empty channel layout");
76 if (m_pAudioStream
!= nullptr)
79 IAE
* audioEngine
= CServiceBroker::GetActiveAE();
80 if (audioEngine
== nullptr)
85 "RetroPlayer[AUDIO]: Creating audio stream, format = {}, sample rate = {}, channels = {}",
86 CAEUtil::DataFormatToStr(pcmFormat
), iSampleRate
, channelLayout
.Count());
88 AEAudioFormat audioFormat
;
89 audioFormat
.m_dataFormat
= pcmFormat
;
90 audioFormat
.m_sampleRate
= iSampleRate
;
91 audioFormat
.m_channelLayout
= channelLayout
;
92 m_pAudioStream
= audioEngine
->MakeStream(audioFormat
);
94 if (m_pAudioStream
== nullptr)
96 CLog::Log(LOGERROR
, "RetroPlayer[AUDIO]: Failed to create audio stream");
100 m_processInfo
.SetAudioChannels(audioFormat
.m_channelLayout
);
101 m_processInfo
.SetAudioSampleRate(audioFormat
.m_sampleRate
);
102 m_processInfo
.SetAudioBitsPerSample(CAEUtil::DataFormatToUsedBits(audioFormat
.m_dataFormat
));
107 void CRetroPlayerAudio::AddStreamData(const StreamPacket
& packet
)
109 const AudioStreamPacket
& audioPacket
= static_cast<const AudioStreamPacket
&>(packet
);
115 const double delaySecs
= m_pAudioStream
->GetDelay();
117 const size_t frameSize
= m_pAudioStream
->GetChannelCount() *
118 (CAEUtil::DataFormatToBits(m_pAudioStream
->GetDataFormat()) >> 3);
120 const unsigned int frameCount
= static_cast<unsigned int>(audioPacket
.size
/ frameSize
);
122 if (delaySecs
> MAX_DELAY
)
124 m_pAudioStream
->Flush();
125 CLog::Log(LOGDEBUG
, "RetroPlayer[AUDIO]: Audio delay ({:0.2f} ms) is too high - flushing",
129 m_pAudioStream
->AddData(&audioPacket
.data
, 0, frameCount
, nullptr);
134 void CRetroPlayerAudio::CloseStream()
138 CLog::Log(LOGDEBUG
, "RetroPlayer[AUDIO]: Closing audio stream");
140 m_pAudioStream
.reset();