Merge pull request #26350 from jjd-uk/estuary_media_align
[xbmc.git] / xbmc / cores / AudioEngine / Sinks / AESinkAUDIOTRACK.cpp
blob7413d63f2e0e8f95fa7c6692ac53fbdb61ef5c08
1 /*
2 * Copyright (C) 2010-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.
7 */
9 #include "AESinkAUDIOTRACK.h"
11 #include "ServiceBroker.h"
12 #include "cores/AudioEngine/AESinkFactory.h"
13 #include "cores/AudioEngine/Utils/AEUtil.h"
14 #include "settings/AdvancedSettings.h"
15 #include "settings/Settings.h"
16 #include "settings/SettingsComponent.h"
17 #include "utils/StringUtils.h"
18 #include "utils/TimeUtils.h"
19 #include "utils/log.h"
21 #include "platform/android/activity/XBMCApp.h"
23 #include <numeric>
25 #include <androidjni/AudioFormat.h>
26 #include <androidjni/AudioManager.h>
27 #include <androidjni/AudioTrack.h>
28 #include <androidjni/Build.h>
29 #include <unistd.h>
31 // This is an alternative to the linear weighted delay smoothing
32 // advantages: only one history value needs to be stored
33 // in tests the linear weighted average smoother yield better results
34 //#define AT_USE_EXPONENTIAL_AVERAGING 1
36 using namespace jni;
38 using namespace std::chrono_literals;
40 // those are empirical values while the HD buffer
41 // is the max TrueHD package
42 const unsigned int MAX_RAW_AUDIO_BUFFER_HD = 61440;
43 const unsigned int MAX_RAW_AUDIO_BUFFER = 16384;
44 const unsigned int MOVING_AVERAGE_MAX_MEMBERS = 3;
45 const uint64_t UINT64_LOWER_BYTES = 0x00000000FFFFFFFF;
46 const uint64_t UINT64_UPPER_BYTES = 0xFFFFFFFF00000000;
48 static const AEChannel KnownChannels[] = {AE_CH_FL, AE_CH_FR, AE_CH_FC, AE_CH_LFE,
49 AE_CH_SL, AE_CH_SR, AE_CH_BL, AE_CH_BR,
50 AE_CH_BC, AE_CH_BLOC, AE_CH_BROC, AE_CH_NULL};
52 static int AEStreamFormatToATFormat(const CAEStreamInfo::DataType& dt)
54 switch (dt)
56 case CAEStreamInfo::STREAM_TYPE_AC3:
57 return CJNIAudioFormat::ENCODING_AC3;
58 case CAEStreamInfo::STREAM_TYPE_DTS_512:
59 case CAEStreamInfo::STREAM_TYPE_DTS_1024:
60 case CAEStreamInfo::STREAM_TYPE_DTS_2048:
61 case CAEStreamInfo::STREAM_TYPE_DTSHD_CORE:
62 return CJNIAudioFormat::ENCODING_DTS;
63 case CAEStreamInfo::STREAM_TYPE_DTSHD:
64 case CAEStreamInfo::STREAM_TYPE_DTSHD_MA:
65 return CJNIAudioFormat::ENCODING_DTS_HD;
66 case CAEStreamInfo::STREAM_TYPE_EAC3:
67 return CJNIAudioFormat::ENCODING_E_AC3;
68 case CAEStreamInfo::STREAM_TYPE_TRUEHD:
69 return CJNIAudioFormat::ENCODING_DOLBY_TRUEHD;
70 default:
71 return CJNIAudioFormat::ENCODING_PCM_16BIT;
75 static AEChannel AUDIOTRACKChannelToAEChannel(int atChannel)
77 AEChannel aeChannel;
79 /* cannot use switch since CJNIAudioFormat is populated at runtime */
81 if (atChannel == CJNIAudioFormat::CHANNEL_OUT_FRONT_LEFT) aeChannel = AE_CH_FL;
82 else if (atChannel == CJNIAudioFormat::CHANNEL_OUT_FRONT_RIGHT) aeChannel = AE_CH_FR;
83 else if (atChannel == CJNIAudioFormat::CHANNEL_OUT_FRONT_CENTER) aeChannel = AE_CH_FC;
84 else if (atChannel == CJNIAudioFormat::CHANNEL_OUT_LOW_FREQUENCY) aeChannel = AE_CH_LFE;
85 else if (atChannel == CJNIAudioFormat::CHANNEL_OUT_BACK_LEFT) aeChannel = AE_CH_BL;
86 else if (atChannel == CJNIAudioFormat::CHANNEL_OUT_BACK_RIGHT) aeChannel = AE_CH_BR;
87 else if (atChannel == CJNIAudioFormat::CHANNEL_OUT_SIDE_LEFT) aeChannel = AE_CH_SL;
88 else if (atChannel == CJNIAudioFormat::CHANNEL_OUT_SIDE_RIGHT) aeChannel = AE_CH_SR;
89 else if (atChannel == CJNIAudioFormat::CHANNEL_OUT_FRONT_LEFT_OF_CENTER) aeChannel = AE_CH_FLOC;
90 else if (atChannel == CJNIAudioFormat::CHANNEL_OUT_FRONT_RIGHT_OF_CENTER) aeChannel = AE_CH_FROC;
91 else if (atChannel == CJNIAudioFormat::CHANNEL_OUT_BACK_CENTER) aeChannel = AE_CH_BC;
92 else aeChannel = AE_CH_UNKNOWN1;
94 return aeChannel;
97 static CAEChannelInfo AUDIOTRACKChannelMaskToAEChannelMap(int atMask)
99 CAEChannelInfo info;
101 int mask = 0x1;
102 for (unsigned int i = 0; i < sizeof(int32_t) * 8; i++)
104 if (atMask & mask)
105 info += AUDIOTRACKChannelToAEChannel(mask);
106 mask <<= 1;
109 return info;
112 static int AEChannelMapToAUDIOTRACKChannelMask(CAEChannelInfo info)
114 info.ResolveChannels(CAEChannelInfo(KnownChannels));
116 // Sadly Android is quite limited these days with supported formats
117 // Therefore only distinguish between Stereo, 5.1 and 7.1
118 // simply by the number of speakers.
120 if (info.Count() > 6)
121 return CJNIAudioFormat::CHANNEL_OUT_7POINT1_SURROUND;
123 if (info.Count() > 2)
124 return CJNIAudioFormat::CHANNEL_OUT_5POINT1;
126 return CJNIAudioFormat::CHANNEL_OUT_STEREO;
129 jni::CJNIAudioTrack *CAESinkAUDIOTRACK::CreateAudioTrack(int stream, int sampleRate, int channelMask, int encoding, int bufferSize)
131 jni::CJNIAudioTrack *jniAt = NULL;
135 CJNIAudioAttributesBuilder attrBuilder;
136 attrBuilder.setUsage(CJNIAudioAttributes::USAGE_MEDIA);
137 attrBuilder.setContentType(CJNIAudioAttributes::CONTENT_TYPE_MUSIC);
139 CJNIAudioFormatBuilder fmtBuilder;
140 fmtBuilder.setChannelMask(channelMask);
141 fmtBuilder.setEncoding(encoding);
142 fmtBuilder.setSampleRate(sampleRate);
144 jniAt = new CJNIAudioTrack(attrBuilder.build(),
145 fmtBuilder.build(),
146 bufferSize,
147 CJNIAudioTrack::MODE_STREAM,
148 CJNIAudioManager::AUDIO_SESSION_ID_GENERATE);
150 catch (const std::invalid_argument& e)
152 CLog::Log(LOGINFO, "AESinkAUDIOTRACK - AudioTrack creation (channelMask {:#08x}): {}",
153 channelMask, e.what());
156 return jniAt;
159 int CAESinkAUDIOTRACK::AudioTrackWrite(char* audioData, int offsetInBytes, int sizeInBytes)
161 int written = 0;
162 if (m_jniAudioFormat == CJNIAudioFormat::ENCODING_PCM_FLOAT)
164 if (m_floatbuf.size() != (sizeInBytes - offsetInBytes) / sizeof(float))
165 m_floatbuf.resize((sizeInBytes - offsetInBytes) / sizeof(float));
166 memcpy(m_floatbuf.data(), audioData + offsetInBytes, sizeInBytes - offsetInBytes);
167 written = m_at_jni->write(m_floatbuf, 0, (sizeInBytes - offsetInBytes) / sizeof(float),
168 CJNIAudioTrack::WRITE_BLOCKING);
169 written *= sizeof(float);
171 else if (m_jniAudioFormat == CJNIAudioFormat::ENCODING_IEC61937)
173 if (m_shortbuf.size() != (sizeInBytes - offsetInBytes) / sizeof(int16_t))
174 m_shortbuf.resize((sizeInBytes - offsetInBytes) / sizeof(int16_t));
175 memcpy(m_shortbuf.data(), audioData + offsetInBytes, sizeInBytes - offsetInBytes);
176 written = m_at_jni->write(m_shortbuf, 0, (sizeInBytes - offsetInBytes) / sizeof(int16_t),
177 CJNIAudioTrack::WRITE_BLOCKING);
178 written *= sizeof(uint16_t);
180 else
182 if (static_cast<int>(m_charbuf.size()) != (sizeInBytes - offsetInBytes))
183 m_charbuf.resize(sizeInBytes - offsetInBytes);
184 memcpy(m_charbuf.data(), audioData + offsetInBytes, sizeInBytes - offsetInBytes);
185 written =
186 m_at_jni->write(m_charbuf, 0, sizeInBytes - offsetInBytes, CJNIAudioTrack::WRITE_BLOCKING);
189 return written;
192 int CAESinkAUDIOTRACK::AudioTrackWrite(char* audioData, int sizeInBytes, int64_t timestamp)
194 int written = 0;
195 std::vector<char> buf;
196 buf.reserve(sizeInBytes);
197 memcpy(buf.data(), audioData, sizeInBytes);
199 CJNIByteBuffer bytebuf = CJNIByteBuffer::wrap(buf);
200 written = m_at_jni->write(bytebuf.get_raw(), sizeInBytes, CJNIAudioTrack::WRITE_BLOCKING, timestamp);
202 return written;
205 CAEDeviceInfo CAESinkAUDIOTRACK::m_info;
206 CAEDeviceInfo CAESinkAUDIOTRACK::m_info_iec;
207 CAEDeviceInfo CAESinkAUDIOTRACK::m_info_raw;
208 bool CAESinkAUDIOTRACK::m_hasIEC = false;
209 std::set<unsigned int> CAESinkAUDIOTRACK::m_sink_sampleRates;
210 bool CAESinkAUDIOTRACK::m_sinkSupportsFloat = false;
211 bool CAESinkAUDIOTRACK::m_sinkSupportsMultiChannelFloat = false;
212 bool CAESinkAUDIOTRACK::m_passthrough_use_eac3 = false;
214 ////////////////////////////////////////////////////////////////////////////////////////////
215 CAESinkAUDIOTRACK::CAESinkAUDIOTRACK()
217 m_alignedS16 = NULL;
218 m_sink_frameSize = 0;
219 m_encoding = CJNIAudioFormat::ENCODING_PCM_16BIT;
220 m_audiotrackbuffer_sec = 0.0;
221 m_audiotrackbuffer_sec_orig = 0.0;
222 m_at_jni = NULL;
223 m_duration_written = 0;
224 m_headPos = 0;
225 m_stuckCounter = 0;
226 m_headPosOld = 0;
227 m_timestampPos = 0;
228 m_sink_sampleRate = 0;
229 m_passthrough = false;
230 m_min_buffer_size = 0;
233 CAESinkAUDIOTRACK::~CAESinkAUDIOTRACK()
235 Deinitialize();
238 bool CAESinkAUDIOTRACK::VerifySinkConfiguration(int sampleRate,
239 int channelMask,
240 int encoding,
241 bool isRaw)
243 int minBufferSize = CJNIAudioTrack::getMinBufferSize(sampleRate, channelMask, encoding);
244 bool supported = (minBufferSize > 0);
246 // make sure to have enough buffer as minimum might not be enough to open
247 if (!isRaw)
248 minBufferSize *= 2;
250 if (supported)
252 jni::CJNIAudioTrack* jniAt = CreateAudioTrack(CJNIAudioManager::STREAM_MUSIC, sampleRate,
253 channelMask, encoding, minBufferSize);
254 supported = (jniAt && jniAt->getState() == CJNIAudioTrack::STATE_INITIALIZED);
255 if (supported)
257 jniAt->pause();
258 jniAt->flush();
261 if (jniAt)
263 jniAt->release();
264 delete jniAt;
267 CLog::Log(LOGDEBUG, "VerifySinkConfiguration samplerate: {} mask: {} encoding: {} success: {}",
268 sampleRate, channelMask, encoding, supported ? "true" : "false");
269 return supported;
273 bool CAESinkAUDIOTRACK::IsSupported(int sampleRateInHz, int channelConfig, int encoding)
275 int ret = CJNIAudioTrack::getMinBufferSize( sampleRateInHz, channelConfig, encoding);
276 return (ret > 0);
279 bool CAESinkAUDIOTRACK::Initialize(AEAudioFormat &format, std::string &device)
282 // try to recover used device
283 if (!m_hasIEC)
284 m_info = m_info_raw;
285 else if (device == "Default" && !m_info.m_wantsIECPassthrough)
286 m_info = m_info_raw;
287 else if (device == "AudioTrack (RAW)")
288 m_info = m_info_raw;
289 else
290 m_info = m_info_iec;
292 m_format = format;
293 m_headPos = 0;
294 m_stuckCounter = 0;
295 m_headPosOld = 0;
296 m_timestampPos = 0;
297 m_linearmovingaverage.clear();
298 m_pause_ms = 0.0;
299 CLog::Log(LOGDEBUG,
300 "CAESinkAUDIOTRACK::Initialize requested: sampleRate {}; format: {}; channels: {}",
301 format.m_sampleRate, CAEUtil::DataFormatToStr(format.m_dataFormat),
302 format.m_channelLayout.Count());
304 int stream = CJNIAudioManager::STREAM_MUSIC;
305 m_encoding = CJNIAudioFormat::ENCODING_PCM_16BIT;
307 // If the device supports EAC3 passthrough, but not basic AC3 patthrough, send it as EAC3 (which is AC3 compatible) instead
308 if (!m_info.m_wantsIECPassthrough)
310 if ((m_format.m_streamInfo.m_type == CAEStreamInfo::STREAM_TYPE_AC3) && m_passthrough_use_eac3)
311 m_format.m_streamInfo.m_type = CAEStreamInfo::STREAM_TYPE_EAC3;
314 uint32_t distance = UINT32_MAX; // max upper distance, update at least ones to use one of our samplerates
315 for (auto& s : m_sink_sampleRates)
317 // prefer best match or alternatively something that divides nicely and
318 // is not too far away
319 uint32_t d = std::abs((int)m_format.m_sampleRate - (int)s) + 8 * (s > m_format.m_sampleRate ? (s % m_format.m_sampleRate) : (m_format.m_sampleRate % s));
320 if (d < distance)
322 m_sink_sampleRate = s;
323 distance = d;
324 CLog::Log(LOGDEBUG, "Updated SampleRate: {} Distance: {}", m_sink_sampleRate, d);
328 if (m_format.m_dataFormat == AE_FMT_RAW)
330 m_passthrough = true;
331 m_encoding = AEStreamFormatToATFormat(m_format.m_streamInfo.m_type);
332 m_format.m_channelLayout = AE_CH_LAYOUT_2_0;
334 if (m_format.m_streamInfo.m_type == CAEStreamInfo::STREAM_TYPE_DTSHD_MA)
336 // we keep the 48 khz sample rate, reason: Androids packer only packs DTS Core
337 // even if we ask for DTS-HD-MA it seems.
338 m_format.m_channelLayout = AE_CH_LAYOUT_7_1;
341 if (m_format.m_streamInfo.m_type == CAEStreamInfo::STREAM_TYPE_TRUEHD)
343 m_format.m_channelLayout = AE_CH_LAYOUT_7_1;
344 m_sink_sampleRate = 192000;
347 // EAC3 needs real samplerate not the modulation
348 if (m_format.m_streamInfo.m_type == CAEStreamInfo::STREAM_TYPE_EAC3)
349 m_sink_sampleRate = m_format.m_streamInfo.m_sampleRate;
351 if (m_info.m_wantsIECPassthrough)
353 m_format.m_dataFormat = AE_FMT_S16LE;
354 if (m_format.m_streamInfo.m_type == CAEStreamInfo::STREAM_TYPE_DTSHD ||
355 m_format.m_streamInfo.m_type == CAEStreamInfo::STREAM_TYPE_DTSHD_MA ||
356 m_format.m_streamInfo.m_type == CAEStreamInfo::STREAM_TYPE_TRUEHD)
357 m_sink_sampleRate = 192000;
359 // new Android N format
360 if (CJNIAudioFormat::ENCODING_IEC61937 != -1)
362 m_encoding = CJNIAudioFormat::ENCODING_IEC61937;
363 // this will be sent tunneled, therefore the IEC path needs e.g.
364 // 4 * m_format.m_streamInfo.m_sampleRate
365 if (m_format.m_streamInfo.m_type == CAEStreamInfo::STREAM_TYPE_EAC3)
366 m_sink_sampleRate = m_format.m_sampleRate;
369 // we are running on an old android version
370 // that does neither know AC3, DTS or whatever
371 // we will fallback to 16BIT passthrough
372 if (m_encoding == -1)
374 m_format.m_channelLayout = AE_CH_LAYOUT_2_0;
375 m_format.m_sampleRate = m_sink_sampleRate;
376 m_encoding = CJNIAudioFormat::ENCODING_PCM_16BIT;
377 CLog::Log(LOGDEBUG, "Fallback to PCM passthrough mode - this might not work!");
381 else
383 m_passthrough = false;
384 m_format.m_sampleRate = m_sink_sampleRate;
385 // this is temporarily opt-in via advancedsettings only
386 const bool allowMultiFloat =
387 CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_AllowMultiChannelFloat;
388 if (allowMultiFloat && m_sinkSupportsMultiChannelFloat)
390 m_encoding = CJNIAudioFormat::ENCODING_PCM_FLOAT;
391 m_format.m_dataFormat = AE_FMT_FLOAT;
393 else if (m_sinkSupportsFloat && m_format.m_channelLayout.Count() == 2)
395 m_encoding = CJNIAudioFormat::ENCODING_PCM_FLOAT;
396 m_format.m_dataFormat = AE_FMT_FLOAT;
398 else
400 m_encoding = CJNIAudioFormat::ENCODING_PCM_16BIT;
401 m_format.m_dataFormat = AE_FMT_S16LE;
405 m_superviseAudioDelay =
406 CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_superviseAudioDelay;
408 int atChannelMask = AEChannelMapToAUDIOTRACKChannelMask(m_format.m_channelLayout);
409 m_format.m_channelLayout = AUDIOTRACKChannelMaskToAEChannelMap(atChannelMask);
410 if (m_encoding == CJNIAudioFormat::ENCODING_IEC61937)
412 // keep above channel output if we do IEC61937 and got DTSHD or TrueHD by AudioEngine
413 if (m_format.m_streamInfo.m_type != CAEStreamInfo::STREAM_TYPE_DTSHD_MA && m_format.m_streamInfo.m_type != CAEStreamInfo::STREAM_TYPE_TRUEHD)
414 atChannelMask = CJNIAudioFormat::CHANNEL_OUT_STEREO;
417 bool retried = false;
418 while (!m_at_jni)
420 CLog::Log(LOGINFO, "Trying to open: samplerate: {}, channelMask: {}, encoding: {}",
421 m_sink_sampleRate, atChannelMask, m_encoding);
422 int min_buffer = CJNIAudioTrack::getMinBufferSize(m_sink_sampleRate,
423 atChannelMask,
424 m_encoding);
426 if (min_buffer < 0)
428 CLog::Log(LOGERROR,
429 "Minimum Buffer Size was: {} - disable passthrough (?) your hw does not support it",
430 min_buffer);
431 return false;
434 m_min_buffer_size = (unsigned int) min_buffer;
435 CLog::Log(LOGINFO, "Minimum size we need for stream: {} Bytes", m_min_buffer_size);
436 double rawlength_in_seconds = 0.0;
437 int multiplier = 1;
438 unsigned int ac3FrameSize = 1;
439 if (m_passthrough && !m_info.m_wantsIECPassthrough)
441 switch (m_format.m_streamInfo.m_type)
443 case CAEStreamInfo::STREAM_TYPE_TRUEHD:
444 m_min_buffer_size = MAX_RAW_AUDIO_BUFFER_HD;
445 m_format.m_frames = m_min_buffer_size;
446 rawlength_in_seconds = 8 * m_format.m_streamInfo.GetDuration() / 1000; // on average
447 break;
448 case CAEStreamInfo::STREAM_TYPE_DTSHD_MA:
449 case CAEStreamInfo::STREAM_TYPE_DTSHD:
450 // normal frame is max 2012 bytes + 2764 sub frame
451 m_min_buffer_size = 66432; //according to the buffer model of ISO/IEC13818-1
452 m_format.m_frames = m_min_buffer_size;
453 rawlength_in_seconds = 8 * m_format.m_streamInfo.GetDuration() / 1000; // average value
454 break;
455 case CAEStreamInfo::STREAM_TYPE_DTS_512:
456 case CAEStreamInfo::STREAM_TYPE_DTSHD_CORE:
457 // max 2012 bytes
458 // depending on sample rate between 156 ms and 312 ms
459 m_min_buffer_size = 16 * 2012;
460 m_format.m_frames = m_min_buffer_size;
461 rawlength_in_seconds = 16 * m_format.m_streamInfo.GetDuration() / 1000;
462 break;
463 case CAEStreamInfo::STREAM_TYPE_DTS_1024:
464 case CAEStreamInfo::STREAM_TYPE_DTS_2048:
465 m_min_buffer_size = 8 * 5462;
466 m_format.m_frames = m_min_buffer_size;
467 rawlength_in_seconds = 8 * m_format.m_streamInfo.GetDuration() / 1000;
468 break;
469 case CAEStreamInfo::STREAM_TYPE_AC3:
470 ac3FrameSize = m_format.m_streamInfo.m_frameSize;
471 if (ac3FrameSize == 0)
472 ac3FrameSize = 1536; // fallback if not set, e.g. Transcoding
473 m_min_buffer_size = std::max(m_min_buffer_size * 3, ac3FrameSize * 8);
474 m_format.m_frames = m_min_buffer_size;
475 multiplier = m_min_buffer_size / ac3FrameSize; // int division is wanted
476 rawlength_in_seconds = multiplier * m_format.m_streamInfo.GetDuration() / 1000;
477 break;
478 // EAC3 is currently not supported
479 case CAEStreamInfo::STREAM_TYPE_EAC3:
480 m_min_buffer_size = 2 * 10752; // least common multiple of 1792 and 1536
481 m_format.m_frames = m_min_buffer_size; // needs testing
482 rawlength_in_seconds = 8 * m_format.m_streamInfo.GetDuration() / 1000;
483 break;
484 default:
485 m_min_buffer_size = MAX_RAW_AUDIO_BUFFER;
486 m_format.m_frames = m_min_buffer_size;
487 rawlength_in_seconds = 0.4;
488 break;
491 CLog::Log(LOGDEBUG, "Opening Passthrough RAW Format: {} Sink SampleRate: {}",
492 CAEUtil::StreamTypeToStr(m_format.m_streamInfo.m_type), m_sink_sampleRate);
493 m_format.m_frameSize = 1;
494 m_sink_frameSize = m_format.m_frameSize;
496 else
498 m_format.m_frameSize = m_format.m_channelLayout.Count() * (CAEUtil::DataFormatToBits(m_format.m_dataFormat) / 8);
499 m_sink_frameSize = m_format.m_frameSize;
500 // aim at max 200 ms buffer and 50 ms periods but at least two periods of min_buffer
501 // make sure periods are actually not smaller than 32 ms (32, cause 32 * 2 = 64)
502 // but also lower than 64 ms
503 // which is large enough to not cause CPU hogging in case 32 ms periods are used
504 m_audiotrackbuffer_sec =
505 static_cast<double>(m_min_buffer_size) / (m_sink_frameSize * m_sink_sampleRate);
506 // the period calculation starts
507 // after the buffer division to get even division results
508 int c = 1;
509 if (m_audiotrackbuffer_sec > 0.25)
511 CLog::Log(LOGWARNING,
512 "Audiobuffer is already very large {:f} ms - Reducing to a sensible value",
513 1000.0 * m_audiotrackbuffer_sec);
514 int buffer_frames = m_sink_sampleRate / 4; // 250 ms
515 m_min_buffer_size = buffer_frames * m_sink_frameSize;
516 c = 5; // 50 ms
518 // update potential new buffertime
519 m_audiotrackbuffer_sec =
520 static_cast<double>(m_min_buffer_size) / (m_sink_frameSize * m_sink_sampleRate);
521 constexpr double max_time = 0.064;
522 constexpr double min_time = 0.032;
523 constexpr double target_duration = 0.128;
525 while (m_audiotrackbuffer_sec < target_duration)
527 m_min_buffer_size += min_buffer;
528 c++;
529 m_audiotrackbuffer_sec =
530 static_cast<double>(m_min_buffer_size) / (m_sink_frameSize * m_sink_sampleRate);
532 unsigned int period_size = m_min_buffer_size / c;
533 double period_time =
534 static_cast<double>(period_size) / (m_sink_frameSize * m_sink_sampleRate);
536 // This will result in minimum 32 ms
537 while (period_time >= max_time)
539 period_time /= 2;
540 period_size /= 2;
542 // If the audio track API gave us very low values increase them
543 // In this case the first loop would not have been run at all
544 while (period_time < min_time)
546 period_size *= 2;
547 period_time *= 2;
549 m_format.m_frames = static_cast<int>(period_size / m_format.m_frameSize);
551 CLog::Log(LOGINFO,
552 "Audiotrack buffer params are: period time = {:.3f} ms, period size = "
553 "{} bytes, num periods = {}",
554 period_time * 1000, period_size, m_min_buffer_size / period_size);
557 if (m_passthrough && !m_info.m_wantsIECPassthrough)
558 m_audiotrackbuffer_sec = rawlength_in_seconds;
560 CLog::Log(LOGINFO,
561 "Created Audiotrackbuffer with playing time of {:f} ms min buffer size: {} bytes",
562 m_audiotrackbuffer_sec * 1000, m_min_buffer_size);
564 m_audiotrackbuffer_sec_orig = m_audiotrackbuffer_sec;
566 m_jniAudioFormat = m_encoding;
567 m_at_jni = CreateAudioTrack(stream, m_sink_sampleRate, atChannelMask,
568 m_encoding, m_min_buffer_size);
570 if (!IsInitialized())
572 if (!m_passthrough)
574 if (atChannelMask != CJNIAudioFormat::CHANNEL_OUT_STEREO &&
575 atChannelMask != CJNIAudioFormat::CHANNEL_OUT_5POINT1)
577 atChannelMask = CJNIAudioFormat::CHANNEL_OUT_5POINT1;
578 CLog::Log(LOGDEBUG, "AESinkAUDIOTRACK - Retrying multichannel playback with a 5.1 layout");
579 continue;
581 else if (atChannelMask != CJNIAudioFormat::CHANNEL_OUT_STEREO)
583 atChannelMask = CJNIAudioFormat::CHANNEL_OUT_STEREO;
584 CLog::Log(LOGDEBUG, "AESinkAUDIOTRACK - Retrying with a stereo layout");
585 continue;
588 else
590 if (!retried)
592 retried = true;
593 CLog::Log(LOGWARNING, "AESinkAUDIOTRACK - Unable to open PT device - will retry once");
594 // Seems that some devices don't properly implement pause + flush, which during seek
595 // might open the device too fast - let's retry
596 usleep(200 * 1000);
597 continue;
600 CLog::Log(LOGERROR, "AESinkAUDIOTRACK - Unable to create AudioTrack");
601 Deinitialize();
602 return false;
604 const char* method = m_passthrough ? (m_info.m_wantsIECPassthrough ? "IEC (PT)" : "RAW (PT)") : "PCM";
605 CLog::Log(LOGINFO,
606 "CAESinkAUDIOTRACK::Initializing with: m_sampleRate: {} format: {} (AE) method: {} "
607 "stream-type: {} min_buffer_size: {} m_frames: {} m_frameSize: {} channels: {}",
608 m_sink_sampleRate, CAEUtil::DataFormatToStr(m_format.m_dataFormat), method,
609 m_passthrough ? CAEUtil::StreamTypeToStr(m_format.m_streamInfo.m_type) : "PCM-STREAM",
610 m_min_buffer_size, m_format.m_frames, m_format.m_frameSize,
611 m_format.m_channelLayout.Count());
613 format = m_format;
615 return true;
618 void CAESinkAUDIOTRACK::Deinitialize()
620 CLog::Log(LOGDEBUG, "CAESinkAUDIOTRACK::Deinitialize");
622 if (!m_at_jni)
623 return;
625 if (IsInitialized())
627 m_at_jni->pause();
628 m_at_jni->flush();
630 m_at_jni->release();
632 m_duration_written = 0;
633 m_headPos = 0;
634 m_headPosOld = 0;
635 m_timestampPos = 0;
636 m_stampTimer.SetExpired();
638 m_linearmovingaverage.clear();
640 delete m_at_jni;
641 m_at_jni = NULL;
642 m_delay = 0.0;
643 m_hw_delay = 0.0;
646 bool CAESinkAUDIOTRACK::IsInitialized()
648 return (m_at_jni && m_at_jni->getState() == CJNIAudioTrack::STATE_INITIALIZED);
651 void CAESinkAUDIOTRACK::GetDelay(AEDelayStatus& status)
653 if (!m_at_jni)
655 status.SetDelay(0);
656 return;
659 bool usesAdvancedLogging = CServiceBroker::GetLogging().CanLogComponent(LOGAUDIO);
660 // In their infinite wisdom, Google decided to make getPlaybackHeadPosition
661 // return a 32bit "int" that you should "interpret as unsigned." As such,
662 // for wrap safety, we need to do all ops on it in 32bit integer math.
664 uint32_t head_pos = (uint32_t)m_at_jni->getPlaybackHeadPosition();
666 // Wraparound
667 if ((uint32_t)(m_headPos & UINT64_LOWER_BYTES) > head_pos) // need to compute wraparound
668 m_headPos += (1ULL << 32); // add wraparound, e.g. 0x0000 FFFF FFFF -> 0x0001 FFFF FFFF
669 // clear lower 32 bit values, e.g. 0x0001 FFFF FFFF -> 0x0001 0000 0000
670 // and add head_pos which wrapped around, e.g. 0x0001 0000 0000 -> 0x0001 0000 0004
671 m_headPos = (m_headPos & UINT64_UPPER_BYTES) | (uint64_t)head_pos;
672 // check if sink is stuck
673 if (m_headPos == m_headPosOld)
674 m_stuckCounter++;
675 else
677 m_stuckCounter = 0;
678 m_headPosOld = m_headPos;
681 double gone = static_cast<double>(m_headPos) / m_sink_sampleRate;
683 // if sink is run dry without buffer time written anymore
684 if (gone > m_duration_written)
685 gone = m_duration_written;
687 double delay = m_duration_written - gone;
689 if (m_stampTimer.IsTimePast())
691 if (!m_at_jni->getTimestamp(m_timestamp))
693 CLog::Log(LOGDEBUG, "Could not acquire timestamp");
694 m_stampTimer.Set(100ms);
696 else
698 // check if frameposition is valid and nano timer less than 50 ms outdated
699 if (m_timestamp.get_framePosition() > 0 &&
700 (CurrentHostCounter() - m_timestamp.get_nanoTime()) < 50 * 1000 * 1000)
701 m_stampTimer.Set(1000ms);
702 else
703 m_stampTimer.Set(100ms);
706 if (usesAdvancedLogging)
707 CLog::Log(LOGINFO, "RAW Head-Position {}", m_headPos);
708 // check if last value was received less than 2 seconds ago
709 if (m_timestamp.get_framePosition() > 0 &&
710 (CurrentHostCounter() - m_timestamp.get_nanoTime()) < 2 * 1000 * 1000 * 1000)
712 if (usesAdvancedLogging)
714 CLog::Log(LOGINFO, "Framecounter: {} Time: {} Current-Time: {}",
715 (m_timestamp.get_framePosition() & UINT64_LOWER_BYTES), m_timestamp.get_nanoTime(),
716 CurrentHostCounter());
718 uint64_t delta = static_cast<uint64_t>(CurrentHostCounter() - m_timestamp.get_nanoTime());
719 uint64_t stamphead =
720 static_cast<uint64_t>(m_timestamp.get_framePosition() & UINT64_LOWER_BYTES) +
721 delta * m_sink_sampleRate / 1000000000.0;
722 // wrap around
723 // e.g. 0xFFFFFFFFFFFF0123 -> 0x0000000000002478
724 // because we only query each second the simple smaller comparison won't suffice
725 // as delay can fluctuate minimally
726 if (stamphead < m_timestampPos && (m_timestampPos - stamphead) > 0x7FFFFFFFFFFFFFFFULL)
728 uint64_t stamp = m_timestampPos;
729 stamp += (1ULL << 32);
730 stamphead = (stamp & UINT64_UPPER_BYTES) | stamphead;
731 CLog::Log(LOGDEBUG, "Wraparound happened old: {} new: {}", m_timestampPos, stamphead);
733 m_timestampPos = stamphead;
735 double playtime = m_timestampPos / static_cast<double>(m_sink_sampleRate);
737 if (usesAdvancedLogging)
739 CLog::Log(LOGINFO,
740 "Delay - Timestamp: {} (ms) delta: {} (ms) playtime: {} (ms) Duration: {} ms",
741 1000.0 * (m_duration_written - playtime), delta / 1000000.0, playtime * 1000,
742 m_duration_written * 1000);
743 CLog::Log(LOGINFO, "Head-Position {} Timestamp Position {} Delay-Offset: {} ms", m_headPos,
744 m_timestampPos,
745 1000.0 * (static_cast<int64_t>(m_headPos - m_timestampPos)) / m_sink_sampleRate);
747 double hw_delay = m_duration_written - playtime;
748 // correct by subtracting above measured delay, if lower delay gets automatically reduced
749 hw_delay -= delay;
750 // sometimes at the beginning of the stream m_timestampPos is more accurate and ahead of
751 // m_headPos - don't use the computed value then and wait
752 if (hw_delay > -1.0 && hw_delay < 1.0)
753 m_hw_delay = hw_delay;
754 else
755 m_hw_delay = 0.0;
756 if (usesAdvancedLogging)
758 CLog::Log(LOGINFO, "HW-Delay (1): {} ms", hw_delay * 1000);
762 delay += m_hw_delay;
764 if (usesAdvancedLogging)
766 CLog::Log(LOGINFO, "Combined Delay: {} ms", delay * 1000);
768 if (delay < 0.0)
769 delay = 0.0;
771 // the RAW hack for simulating pause bursts should not come
772 // into the way of hw delay
773 if (m_pause_ms > m_audiotrackbuffer_sec * 1000.0)
774 m_pause_ms = m_audiotrackbuffer_sec * 1000.0;
776 if (m_pause_ms > 0.0)
778 if (delay < m_audiotrackbuffer_sec)
779 delay = m_audiotrackbuffer_sec;
780 else
781 m_audiotrackbuffer_sec = delay;
783 const double d = GetMovingAverageDelay(delay);
785 // Audiotrack is caching more than we thought it would
786 if (d > m_audiotrackbuffer_sec)
787 m_audiotrackbuffer_sec = d;
789 // track delay in local member
790 m_delay = d;
791 if (usesAdvancedLogging)
793 CLog::Log(LOGINFO, "Delay Current: {:f} ms", d * 1000);
794 if (m_pause_ms > 0.0)
795 CLog::Log(LOGINFO, "Delay faked due to pause delay: {:f} ms", m_pause_ms);
797 status.SetDelay(d);
800 double CAESinkAUDIOTRACK::GetLatency()
802 return 0.0;
805 double CAESinkAUDIOTRACK::GetCacheTotal()
807 // total amount that the audio sink can buffer in units of seconds
808 return m_audiotrackbuffer_sec;
811 // this method is supposed to block until all frames are written to the device buffer
812 // when it returns ActiveAESink will take the next buffer out of a queue
813 unsigned int CAESinkAUDIOTRACK::AddPackets(uint8_t **data, unsigned int frames, unsigned int offset)
815 if (!IsInitialized())
816 return INT_MAX;
818 // If the sink did not move twice the buffer size at least 400 ms in time it was opened
819 // take action. Some sinks open with e.g. 128 ms nicely but under the
820 // hood need a bit more samples to start moving on sink start.
821 // Simple equation: N x stime packages in ms > 400 ms or 2 buffer sizes in ms
822 // will result in the error condition triggering.
824 const bool isRawPt = m_passthrough && !m_info.m_wantsIECPassthrough;
825 bool forceBlock = false;
826 if (!isRawPt)
828 const double max_stuck_delay_ms = std::max((m_audiotrackbuffer_sec_orig * 2000.0), 400.0);
829 const double stime_ms = 1000.0 * frames / m_format.m_sampleRate;
831 if (m_superviseAudioDelay)
833 if (m_stuckCounter * stime_ms > max_stuck_delay_ms)
835 CLog::Log(LOGERROR, "Sink got stuck with {:f} ms - ask AE for reopening",
836 max_stuck_delay_ms);
837 usleep(max_stuck_delay_ms * 1000);
838 return INT_MAX;
840 else if (m_stuckCounter * stime_ms >= m_audiotrackbuffer_sec_orig * 1000.0)
842 CLog::LogF(LOGDEBUG, "Sink filling too fast - throttleing - Fillstate: {} ms!",
843 (m_stuckCounter * stime_ms));
844 forceBlock = true;
849 // for debugging only - can be removed if everything is really stable
850 uint64_t startTime = CurrentHostCounter();
852 uint8_t *buffer = data[0]+offset*m_format.m_frameSize;
853 uint8_t *out_buf = buffer;
854 int size = frames * m_format.m_frameSize;
856 // write as many frames of audio as we can fit into our internal buffer.
857 int written = 0;
858 int loop_written = 0;
859 if (frames)
861 if (m_at_jni->getPlayState() != CJNIAudioTrack::PLAYSTATE_PLAYING)
862 m_at_jni->play();
864 bool retried = false;
865 int size_left = size;
866 while (written < size)
868 loop_written = AudioTrackWrite((char*)out_buf, 0, size_left);
869 written += loop_written;
870 size_left -= loop_written;
872 if (loop_written < 0)
874 CLog::Log(LOGERROR, "CAESinkAUDIOTRACK::AddPackets write returned error: {}",
875 loop_written);
876 return INT_MAX;
879 // if we could not add any data - sleep a bit and retry
880 if (loop_written == 0)
882 if (!retried)
884 retried = true;
885 double sleep_time = 0;
886 if (m_passthrough && !m_info.m_wantsIECPassthrough)
888 sleep_time = m_format.m_streamInfo.GetDuration();
889 usleep(sleep_time * 1000);
891 else
893 sleep_time = 1000.0 * m_format.m_frames / m_format.m_sampleRate;
894 usleep(sleep_time * 1000);
896 bool playing = m_at_jni->getPlayState() == CJNIAudioTrack::PLAYSTATE_PLAYING;
897 CLog::Log(LOGDEBUG, "Retried to write onto the sink - slept: {:f} playing: {}",
898 sleep_time, playing ? "yes" : "no");
899 continue;
901 else
903 CLog::Log(LOGDEBUG, "Repeatedly tried to write onto the sink - giving up");
904 break;
907 retried = false; // at least one time there was more than zero data written
908 if (m_passthrough && !m_info.m_wantsIECPassthrough)
910 if (written == size)
911 m_duration_written += m_format.m_streamInfo.GetDuration() / 1000;
912 else
914 CLog::Log(LOGDEBUG, "Error writing full package to sink, left: {}", size_left);
915 // Let AE wait some ms to come back
916 unsigned int written_frames = (unsigned int) (written/m_format.m_frameSize);
917 return written_frames;
920 else
922 double duration =
923 (static_cast<double>(loop_written) / m_format.m_frameSize) / m_format.m_sampleRate;
924 m_duration_written += duration;
927 // just try again to care for fragmentation
928 if (written < size)
929 out_buf = out_buf + loop_written;
931 loop_written = 0;
934 unsigned int written_frames = static_cast<unsigned int>(written / m_format.m_frameSize);
935 double time_to_add_ms = 1000.0 * (CurrentHostCounter() - startTime) / CurrentHostFrequency();
936 // Get Back in Sync with faked pause bursts
937 if (m_passthrough && !m_info.m_wantsIECPassthrough)
939 if (m_pause_ms > 0.0)
941 // Idea here is: Slowly correct the wrong buffer so that AE should not realize
942 // but do not underrun while doing so
943 double extra_sleep_ms = m_format.m_streamInfo.GetDuration() / 2.0 - time_to_add_ms;
944 if (extra_sleep_ms > 0)
946 CLog::Log(LOGDEBUG, "Sleeping for {:f}", extra_sleep_ms);
947 m_pause_ms -= extra_sleep_ms;
948 usleep(extra_sleep_ms * 1000);
950 if (m_pause_ms <= 0.0)
952 m_pause_ms = 0.0;
953 extra_sleep_ms = 0.0;
954 CLog::Log(LOGDEBUG, "Resetting pause bursts as buffer level was reached! (1)");
958 else
960 // waiting should only be done if sink is not run dry
961 double period_time = m_format.m_frames / static_cast<double>(m_sink_sampleRate);
962 if (m_delay >= (m_audiotrackbuffer_sec - period_time))
964 double time_should_ms = 1000.0 * written_frames / m_format.m_sampleRate;
965 double time_off = time_should_ms - time_to_add_ms;
966 if (time_off > 0)
967 usleep(time_off * 500); // sleep half the error on average away
970 if (forceBlock)
972 // Sink consumes too fast - block the frames minus they needed to add
973 // update time to add, so that above else case won't make us sleep twice the amount for the
974 // superviseaudiodelay use-case.
975 time_to_add_ms = 1000.0 * (CurrentHostCounter() - startTime) / CurrentHostFrequency();
976 double extra_sleep_ms = (1000.0 * frames / m_format.m_sampleRate) - time_to_add_ms;
977 if (extra_sleep_ms > 0.0)
979 CLog::LogF(LOGDEBUG, "Extra Sleeping for {:f}", extra_sleep_ms);
980 usleep(extra_sleep_ms * 1000);
983 return written_frames;
986 void CAESinkAUDIOTRACK::AddPause(unsigned int millis)
988 if (!m_at_jni)
989 return;
991 // just sleep out the frames
992 if (m_at_jni->getPlayState() != CJNIAudioTrack::PLAYSTATE_PAUSED)
993 m_at_jni->pause();
995 // This is a mixture to get it right between
996 // blocking, sleeping roughly and GetDelay smoothing
997 // In short: Shit in, shit out
998 usleep(millis * 1000);
999 m_pause_ms += millis;
1002 void CAESinkAUDIOTRACK::Drain()
1004 if (!m_at_jni)
1005 return;
1007 CLog::Log(LOGDEBUG, "Draining Audio");
1008 if (IsInitialized())
1010 m_at_jni->stop();
1011 // stay ready
1012 m_at_jni->pause();
1014 m_duration_written = 0;
1015 m_headPos = 0;
1016 m_stuckCounter = 0;
1017 m_timestampPos = 0;
1018 m_linearmovingaverage.clear();
1019 m_stampTimer.SetExpired();
1020 m_pause_ms = 0.0;
1023 void CAESinkAUDIOTRACK::Register()
1025 AE::AESinkRegEntry entry;
1026 entry.sinkName = "AUDIOTRACK";
1027 entry.createFunc = CAESinkAUDIOTRACK::Create;
1028 entry.enumerateFunc = CAESinkAUDIOTRACK::EnumerateDevicesEx;
1029 AE::CAESinkFactory::RegisterSink(entry);
1032 std::unique_ptr<IAESink> CAESinkAUDIOTRACK::Create(std::string& device,
1033 AEAudioFormat& desiredFormat)
1035 auto sink = std::make_unique<CAESinkAUDIOTRACK>();
1036 if (sink->Initialize(desiredFormat, device))
1037 return sink;
1039 return {};
1042 void CAESinkAUDIOTRACK::EnumerateDevicesEx(AEDeviceInfoList &list, bool force)
1044 // Clear everything
1045 m_info.m_channels.Reset();
1046 m_info.m_dataFormats.clear();
1047 m_info.m_sampleRates.clear();
1048 m_info.m_streamTypes.clear();
1049 m_sink_sampleRates.clear();
1051 m_info.m_deviceType = AE_DEVTYPE_PCM;
1052 m_info.m_deviceName = "AudioTrack (IEC)";
1053 m_info.m_displayName = "AudioTrack (IEC)";
1054 m_info.m_displayNameExtra = "Kodi IEC packer (recommended)";
1056 // Query IEC capabilities
1057 bool isRaw = false;
1058 if (CJNIAudioFormat::ENCODING_IEC61937 != -1)
1060 UpdateAvailablePCMCapabilities();
1061 UpdateAvailablePassthroughCapabilities(isRaw);
1063 if (!m_info.m_streamTypes.empty())
1065 m_info_iec = m_info;
1066 list.push_back(m_info_iec);
1067 m_hasIEC = true;
1071 // Query RAW capabilities
1072 isRaw = true;
1073 m_info.m_deviceName = "AudioTrack (RAW)";
1074 m_info.m_displayName = "AudioTrack (RAW)";
1075 m_info.m_displayNameExtra = "Android IEC packer";
1076 UpdateAvailablePCMCapabilities();
1077 UpdateAvailablePassthroughCapabilities(isRaw);
1078 m_info_raw = m_info;
1080 // no need to display two PCM sinks - as they are the same
1081 if (!list.empty())
1082 m_info_raw.m_onlyPassthrough = true;
1084 list.push_back(m_info_raw);
1087 void CAESinkAUDIOTRACK::UpdateAvailablePassthroughCapabilities(bool isRaw)
1089 m_info.m_deviceType = AE_DEVTYPE_HDMI;
1090 m_info.m_wantsIECPassthrough = false;
1091 m_info.m_dataFormats.push_back(AE_FMT_RAW);
1092 m_info.m_streamTypes.clear();
1093 bool supports_192khz = m_sink_sampleRates.find(192000) != m_sink_sampleRates.end();
1095 if (isRaw)
1097 bool canDoAC3 = false;
1099 if (CJNIAudioFormat::ENCODING_AC3 != -1)
1101 if (VerifySinkConfiguration(48000, CJNIAudioFormat::CHANNEL_OUT_STEREO,
1102 CJNIAudioFormat::ENCODING_AC3, true))
1104 m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_AC3);
1105 CLog::Log(LOGDEBUG, "Firmware implements AC3 RAW");
1107 canDoAC3 = true;
1111 // EAC3 working on shield, broken on FireTV
1112 if (CJNIAudioFormat::ENCODING_E_AC3 != -1)
1114 if (VerifySinkConfiguration(48000, CJNIAudioFormat::CHANNEL_OUT_STEREO,
1115 CJNIAudioFormat::ENCODING_E_AC3, true))
1117 m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_EAC3);
1118 CLog::Log(LOGDEBUG, "Firmware implements EAC3 RAW");
1120 if (!canDoAC3)
1121 m_passthrough_use_eac3 = true;
1125 if (CJNIAudioFormat::ENCODING_DTS != -1)
1127 if (VerifySinkConfiguration(48000, CJNIAudioFormat::CHANNEL_OUT_STEREO,
1128 CJNIAudioFormat::ENCODING_DTS, true))
1130 CLog::Log(LOGDEBUG, "Firmware implements DTS RAW");
1131 m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTSHD_CORE);
1132 m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTS_1024);
1133 m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTS_2048);
1134 m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTS_512);
1138 if (CJNIAudioFormat::ENCODING_DTS_HD != -1)
1140 if (VerifySinkConfiguration(48000, AEChannelMapToAUDIOTRACKChannelMask(AE_CH_LAYOUT_7_1),
1141 CJNIAudioFormat::ENCODING_DTS_HD, true))
1143 CLog::Log(LOGDEBUG, "Firmware implements DTS-HD RAW");
1144 m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTSHD);
1145 m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTSHD_MA);
1148 if (CJNIAudioFormat::ENCODING_DOLBY_TRUEHD != -1 && supports_192khz)
1150 if (VerifySinkConfiguration(192000, AEChannelMapToAUDIOTRACKChannelMask(AE_CH_LAYOUT_7_1),
1151 CJNIAudioFormat::ENCODING_DOLBY_TRUEHD, true))
1153 CLog::Log(LOGDEBUG, "Firmware implements TrueHD RAW");
1154 m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_TRUEHD);
1158 else
1160 // Android v24 and backports can do real IEC API
1161 if (CJNIAudioFormat::ENCODING_IEC61937 != -1)
1163 // check if we support opening an IEC sink at all:
1164 bool supports_iec = VerifySinkConfiguration(48000, CJNIAudioFormat::CHANNEL_OUT_STEREO,
1165 CJNIAudioFormat::ENCODING_IEC61937);
1166 if (supports_iec)
1168 m_info.m_wantsIECPassthrough = true;
1169 m_info.m_streamTypes.clear();
1170 m_info.m_dataFormats.push_back(AE_FMT_RAW);
1171 m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_AC3);
1172 m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTSHD_CORE);
1173 m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTS_1024);
1174 m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTS_2048);
1175 m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTS_512);
1176 CLog::Log(LOGDEBUG, "AESinkAUDIOTrack: Using IEC PT mode: {}",
1177 CJNIAudioFormat::ENCODING_IEC61937);
1178 CLog::Log(LOGDEBUG, "AC3 and DTS via IEC61937 is supported");
1179 if (supports_192khz)
1181 // Check for IEC 2 channel 192 khz PT DTS-HD-HR and E-AC3
1182 if (VerifySinkConfiguration(192000, CJNIAudioFormat::CHANNEL_OUT_STEREO,
1183 CJNIAudioFormat::ENCODING_IEC61937))
1185 m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_EAC3);
1186 m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTSHD);
1187 CLog::Log(LOGDEBUG, "E-AC3 and DTSHD-HR via IEC61937 is supported");
1189 // Check for IEC 8 channel 192 khz PT DTS-HD-MA and TrueHD
1190 int atChannelMask = AEChannelMapToAUDIOTRACKChannelMask(AE_CH_LAYOUT_7_1);
1191 if (VerifySinkConfiguration(192000, atChannelMask, CJNIAudioFormat::ENCODING_IEC61937))
1193 m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTSHD_MA);
1194 m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_TRUEHD);
1195 CLog::Log(LOGDEBUG, "DTSHD-MA and TrueHD via IEC61937 is supported");
1203 void CAESinkAUDIOTRACK::UpdateAvailablePCMCapabilities()
1205 m_info.m_channels = KnownChannels;
1207 // default fallback format
1208 m_info.m_dataFormats.push_back(AE_FMT_S16LE);
1209 unsigned int native_sampleRate = CJNIAudioTrack::getNativeOutputSampleRate(CJNIAudioManager::STREAM_MUSIC);
1210 m_sink_sampleRates.insert(native_sampleRate);
1212 int encoding = CJNIAudioFormat::ENCODING_PCM_16BIT;
1213 m_sinkSupportsFloat = VerifySinkConfiguration(native_sampleRate, CJNIAudioFormat::CHANNEL_OUT_STEREO, CJNIAudioFormat::ENCODING_PCM_FLOAT);
1215 m_sinkSupportsMultiChannelFloat =
1216 VerifySinkConfiguration(native_sampleRate, CJNIAudioFormat::CHANNEL_OUT_7POINT1_SURROUND,
1217 CJNIAudioFormat::ENCODING_PCM_FLOAT);
1219 if (m_sinkSupportsFloat)
1221 encoding = CJNIAudioFormat::ENCODING_PCM_FLOAT;
1222 m_info.m_dataFormats.push_back(AE_FMT_FLOAT);
1223 CLog::Log(LOGINFO, "Float is supported");
1225 if (m_sinkSupportsMultiChannelFloat)
1227 CLog::Log(LOGINFO, "Multi channel Float is supported");
1230 int test_sample[] = { 32000, 44100, 48000, 88200, 96000, 176400, 192000 };
1231 int test_sample_sz = sizeof(test_sample) / sizeof(int);
1233 for (int i = 0; i < test_sample_sz; ++i)
1235 if (IsSupported(test_sample[i], CJNIAudioFormat::CHANNEL_OUT_STEREO, encoding))
1237 m_sink_sampleRates.insert(test_sample[i]);
1238 CLog::Log(LOGDEBUG, "AESinkAUDIOTRACK - {} supported", test_sample[i]);
1241 std::copy(m_sink_sampleRates.begin(), m_sink_sampleRates.end(), std::back_inserter(m_info.m_sampleRates));
1244 double CAESinkAUDIOTRACK::GetMovingAverageDelay(double newestdelay)
1246 #if defined AT_USE_EXPONENTIAL_AVERAGING
1247 double old = 0.0;
1248 if (m_linearmovingaverage.empty()) // just for creating one space in list
1249 m_linearmovingaverage.push_back(newestdelay);
1250 else
1251 old = m_linearmovingaverage.front();
1253 const double alpha = 0.3;
1254 const double beta = 0.7;
1256 double d = alpha * newestdelay + beta * old;
1257 m_linearmovingaverage.at(0) = d;
1259 return d;
1260 #endif
1261 m_linearmovingaverage.push_back(newestdelay);
1263 // new values are in the back, old values are in the front
1264 // oldest value is removed if elements > MOVING_AVERAGE_MAX_MEMBERS
1265 // removing first element of a vector sucks - I know that
1266 // but hey - 10 elements - not 1 million
1267 size_t size = m_linearmovingaverage.size();
1268 if (size > MOVING_AVERAGE_MAX_MEMBERS)
1270 m_linearmovingaverage.pop_front();
1271 size--;
1273 double sum = std::accumulate(m_linearmovingaverage.begin(), m_linearmovingaverage.end(), 0.0);
1275 return sum / size;