[WASAPI] set stream audio category
[xbmc.git] / xbmc / cores / AudioEngine / Sinks / AESinkAUDIOTRACK.cpp
blob149bc7a2681b55ce00b13b39df1f8c2785470c1d
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 <androidjni/AudioFormat.h>
24 #include <androidjni/AudioManager.h>
25 #include <androidjni/AudioTrack.h>
26 #include <androidjni/Build.h>
27 #include <unistd.h>
29 // This is an alternative to the linear weighted delay smoothing
30 // advantages: only one history value needs to be stored
31 // in tests the linear weighted average smoother yield better results
32 //#define AT_USE_EXPONENTIAL_AVERAGING 1
34 using namespace jni;
36 using namespace std::chrono_literals;
38 // those are empirical values while the HD buffer
39 // is the max TrueHD package
40 const unsigned int MAX_RAW_AUDIO_BUFFER_HD = 61440;
41 const unsigned int MAX_RAW_AUDIO_BUFFER = 16384;
42 const unsigned int MOVING_AVERAGE_MAX_MEMBERS = 3;
43 const uint64_t UINT64_LOWER_BYTES = 0x00000000FFFFFFFF;
44 const uint64_t UINT64_UPPER_BYTES = 0xFFFFFFFF00000000;
46 static const AEChannel KnownChannels[] = {AE_CH_FL, AE_CH_FR, AE_CH_FC, AE_CH_LFE,
47 AE_CH_SL, AE_CH_SR, AE_CH_BL, AE_CH_BR,
48 AE_CH_BC, AE_CH_BLOC, AE_CH_BROC, AE_CH_NULL};
50 static int AEStreamFormatToATFormat(const CAEStreamInfo::DataType& dt)
52 switch (dt)
54 case CAEStreamInfo::STREAM_TYPE_AC3:
55 return CJNIAudioFormat::ENCODING_AC3;
56 case CAEStreamInfo::STREAM_TYPE_DTS_512:
57 case CAEStreamInfo::STREAM_TYPE_DTS_1024:
58 case CAEStreamInfo::STREAM_TYPE_DTS_2048:
59 case CAEStreamInfo::STREAM_TYPE_DTSHD_CORE:
60 return CJNIAudioFormat::ENCODING_DTS;
61 case CAEStreamInfo::STREAM_TYPE_DTSHD:
62 case CAEStreamInfo::STREAM_TYPE_DTSHD_MA:
63 return CJNIAudioFormat::ENCODING_DTS_HD;
64 case CAEStreamInfo::STREAM_TYPE_EAC3:
65 return CJNIAudioFormat::ENCODING_E_AC3;
66 case CAEStreamInfo::STREAM_TYPE_TRUEHD:
67 return CJNIAudioFormat::ENCODING_DOLBY_TRUEHD;
68 default:
69 return CJNIAudioFormat::ENCODING_PCM_16BIT;
73 static AEChannel AUDIOTRACKChannelToAEChannel(int atChannel)
75 AEChannel aeChannel;
77 /* cannot use switch since CJNIAudioFormat is populated at runtime */
79 if (atChannel == CJNIAudioFormat::CHANNEL_OUT_FRONT_LEFT) aeChannel = AE_CH_FL;
80 else if (atChannel == CJNIAudioFormat::CHANNEL_OUT_FRONT_RIGHT) aeChannel = AE_CH_FR;
81 else if (atChannel == CJNIAudioFormat::CHANNEL_OUT_FRONT_CENTER) aeChannel = AE_CH_FC;
82 else if (atChannel == CJNIAudioFormat::CHANNEL_OUT_LOW_FREQUENCY) aeChannel = AE_CH_LFE;
83 else if (atChannel == CJNIAudioFormat::CHANNEL_OUT_BACK_LEFT) aeChannel = AE_CH_BL;
84 else if (atChannel == CJNIAudioFormat::CHANNEL_OUT_BACK_RIGHT) aeChannel = AE_CH_BR;
85 else if (atChannel == CJNIAudioFormat::CHANNEL_OUT_SIDE_LEFT) aeChannel = AE_CH_SL;
86 else if (atChannel == CJNIAudioFormat::CHANNEL_OUT_SIDE_RIGHT) aeChannel = AE_CH_SR;
87 else if (atChannel == CJNIAudioFormat::CHANNEL_OUT_FRONT_LEFT_OF_CENTER) aeChannel = AE_CH_FLOC;
88 else if (atChannel == CJNIAudioFormat::CHANNEL_OUT_FRONT_RIGHT_OF_CENTER) aeChannel = AE_CH_FROC;
89 else if (atChannel == CJNIAudioFormat::CHANNEL_OUT_BACK_CENTER) aeChannel = AE_CH_BC;
90 else aeChannel = AE_CH_UNKNOWN1;
92 return aeChannel;
95 static CAEChannelInfo AUDIOTRACKChannelMaskToAEChannelMap(int atMask)
97 CAEChannelInfo info;
99 int mask = 0x1;
100 for (unsigned int i = 0; i < sizeof(int32_t) * 8; i++)
102 if (atMask & mask)
103 info += AUDIOTRACKChannelToAEChannel(mask);
104 mask <<= 1;
107 return info;
110 static int AEChannelMapToAUDIOTRACKChannelMask(CAEChannelInfo info)
112 info.ResolveChannels(CAEChannelInfo(KnownChannels));
114 // Sadly Android is quite limited these days with supported formats
115 // Therefore only distinguish between Stereo, 5.1 and 7.1
116 // simply by the number of speakers.
118 if (info.Count() > 6)
119 return CJNIAudioFormat::CHANNEL_OUT_7POINT1_SURROUND;
121 if (info.Count() > 2)
122 return CJNIAudioFormat::CHANNEL_OUT_5POINT1;
124 return CJNIAudioFormat::CHANNEL_OUT_STEREO;
127 jni::CJNIAudioTrack *CAESinkAUDIOTRACK::CreateAudioTrack(int stream, int sampleRate, int channelMask, int encoding, int bufferSize)
129 jni::CJNIAudioTrack *jniAt = NULL;
133 CJNIAudioAttributesBuilder attrBuilder;
134 attrBuilder.setUsage(CJNIAudioAttributes::USAGE_MEDIA);
135 attrBuilder.setContentType(CJNIAudioAttributes::CONTENT_TYPE_MUSIC);
137 CJNIAudioFormatBuilder fmtBuilder;
138 fmtBuilder.setChannelMask(channelMask);
139 fmtBuilder.setEncoding(encoding);
140 fmtBuilder.setSampleRate(sampleRate);
142 jniAt = new CJNIAudioTrack(attrBuilder.build(),
143 fmtBuilder.build(),
144 bufferSize,
145 CJNIAudioTrack::MODE_STREAM,
146 CJNIAudioManager::AUDIO_SESSION_ID_GENERATE);
148 catch (const std::invalid_argument& e)
150 CLog::Log(LOGINFO, "AESinkAUDIOTRACK - AudioTrack creation (channelMask {:#08x}): {}",
151 channelMask, e.what());
154 return jniAt;
157 int CAESinkAUDIOTRACK::AudioTrackWrite(char* audioData, int offsetInBytes, int sizeInBytes)
159 int written = 0;
160 if (m_jniAudioFormat == CJNIAudioFormat::ENCODING_PCM_FLOAT)
162 if (m_floatbuf.size() != (sizeInBytes - offsetInBytes) / sizeof(float))
163 m_floatbuf.resize((sizeInBytes - offsetInBytes) / sizeof(float));
164 memcpy(m_floatbuf.data(), audioData + offsetInBytes, sizeInBytes - offsetInBytes);
165 written = m_at_jni->write(m_floatbuf, 0, (sizeInBytes - offsetInBytes) / sizeof(float),
166 CJNIAudioTrack::WRITE_BLOCKING);
167 written *= sizeof(float);
169 else if (m_jniAudioFormat == CJNIAudioFormat::ENCODING_IEC61937)
171 if (m_shortbuf.size() != (sizeInBytes - offsetInBytes) / sizeof(int16_t))
172 m_shortbuf.resize((sizeInBytes - offsetInBytes) / sizeof(int16_t));
173 memcpy(m_shortbuf.data(), audioData + offsetInBytes, sizeInBytes - offsetInBytes);
174 written = m_at_jni->write(m_shortbuf, 0, (sizeInBytes - offsetInBytes) / sizeof(int16_t),
175 CJNIAudioTrack::WRITE_BLOCKING);
176 written *= sizeof(uint16_t);
178 else
180 if (static_cast<int>(m_charbuf.size()) != (sizeInBytes - offsetInBytes))
181 m_charbuf.resize(sizeInBytes - offsetInBytes);
182 memcpy(m_charbuf.data(), audioData + offsetInBytes, sizeInBytes - offsetInBytes);
183 written =
184 m_at_jni->write(m_charbuf, 0, sizeInBytes - offsetInBytes, CJNIAudioTrack::WRITE_BLOCKING);
187 return written;
190 int CAESinkAUDIOTRACK::AudioTrackWrite(char* audioData, int sizeInBytes, int64_t timestamp)
192 int written = 0;
193 std::vector<char> buf;
194 buf.reserve(sizeInBytes);
195 memcpy(buf.data(), audioData, sizeInBytes);
197 CJNIByteBuffer bytebuf = CJNIByteBuffer::wrap(buf);
198 written = m_at_jni->write(bytebuf.get_raw(), sizeInBytes, CJNIAudioTrack::WRITE_BLOCKING, timestamp);
200 return written;
203 CAEDeviceInfo CAESinkAUDIOTRACK::m_info;
204 CAEDeviceInfo CAESinkAUDIOTRACK::m_info_iec;
205 CAEDeviceInfo CAESinkAUDIOTRACK::m_info_raw;
206 bool CAESinkAUDIOTRACK::m_hasIEC = false;
207 std::set<unsigned int> CAESinkAUDIOTRACK::m_sink_sampleRates;
208 bool CAESinkAUDIOTRACK::m_sinkSupportsFloat = false;
209 bool CAESinkAUDIOTRACK::m_sinkSupportsMultiChannelFloat = false;
210 bool CAESinkAUDIOTRACK::m_passthrough_use_eac3 = false;
212 ////////////////////////////////////////////////////////////////////////////////////////////
213 CAESinkAUDIOTRACK::CAESinkAUDIOTRACK()
215 m_alignedS16 = NULL;
216 m_sink_frameSize = 0;
217 m_encoding = CJNIAudioFormat::ENCODING_PCM_16BIT;
218 m_audiotrackbuffer_sec = 0.0;
219 m_audiotrackbuffer_sec_orig = 0.0;
220 m_at_jni = NULL;
221 m_duration_written = 0;
222 m_headPos = 0;
223 m_stuckCounter = 0;
224 m_headPosOld = 0;
225 m_timestampPos = 0;
226 m_sink_sampleRate = 0;
227 m_passthrough = false;
228 m_min_buffer_size = 0;
231 CAESinkAUDIOTRACK::~CAESinkAUDIOTRACK()
233 Deinitialize();
236 bool CAESinkAUDIOTRACK::VerifySinkConfiguration(int sampleRate,
237 int channelMask,
238 int encoding,
239 bool isRaw)
241 int minBufferSize = CJNIAudioTrack::getMinBufferSize(sampleRate, channelMask, encoding);
242 bool supported = (minBufferSize > 0);
244 // make sure to have enough buffer as minimum might not be enough to open
245 if (!isRaw)
246 minBufferSize *= 2;
248 if (supported)
250 jni::CJNIAudioTrack* jniAt = CreateAudioTrack(CJNIAudioManager::STREAM_MUSIC, sampleRate,
251 channelMask, encoding, minBufferSize);
252 supported = (jniAt && jniAt->getState() == CJNIAudioTrack::STATE_INITIALIZED);
253 if (supported)
255 jniAt->pause();
256 jniAt->flush();
259 if (jniAt)
261 jniAt->release();
262 delete jniAt;
265 CLog::Log(LOGDEBUG, "VerifySinkConfiguration samplerate: {} mask: {} encoding: {} success: {}",
266 sampleRate, channelMask, encoding, supported ? "true" : "false");
267 return supported;
271 bool CAESinkAUDIOTRACK::IsSupported(int sampleRateInHz, int channelConfig, int encoding)
273 int ret = CJNIAudioTrack::getMinBufferSize( sampleRateInHz, channelConfig, encoding);
274 return (ret > 0);
277 bool CAESinkAUDIOTRACK::Initialize(AEAudioFormat &format, std::string &device)
280 // try to recover used device
281 if (!m_hasIEC)
282 m_info = m_info_raw;
283 else if (device == "Default" && !m_info.m_wantsIECPassthrough)
284 m_info = m_info_raw;
285 else if (device == "AudioTrack (RAW)")
286 m_info = m_info_raw;
287 else
288 m_info = m_info_iec;
290 m_format = format;
291 m_headPos = 0;
292 m_stuckCounter = 0;
293 m_headPosOld = 0;
294 m_timestampPos = 0;
295 m_linearmovingaverage.clear();
296 m_pause_ms = 0.0;
297 CLog::Log(LOGDEBUG,
298 "CAESinkAUDIOTRACK::Initialize requested: sampleRate {}; format: {}; channels: {}",
299 format.m_sampleRate, CAEUtil::DataFormatToStr(format.m_dataFormat),
300 format.m_channelLayout.Count());
302 int stream = CJNIAudioManager::STREAM_MUSIC;
303 m_encoding = CJNIAudioFormat::ENCODING_PCM_16BIT;
305 // If the device supports EAC3 passthrough, but not basic AC3 patthrough, send it as EAC3 (which is AC3 compatible) instead
306 if (!m_info.m_wantsIECPassthrough)
308 if ((m_format.m_streamInfo.m_type == CAEStreamInfo::STREAM_TYPE_AC3) && m_passthrough_use_eac3)
309 m_format.m_streamInfo.m_type = CAEStreamInfo::STREAM_TYPE_EAC3;
312 uint32_t distance = UINT32_MAX; // max upper distance, update at least ones to use one of our samplerates
313 for (auto& s : m_sink_sampleRates)
315 // prefer best match or alternatively something that divides nicely and
316 // is not too far away
317 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));
318 if (d < distance)
320 m_sink_sampleRate = s;
321 distance = d;
322 CLog::Log(LOGDEBUG, "Updated SampleRate: {} Distance: {}", m_sink_sampleRate, d);
326 if (m_format.m_dataFormat == AE_FMT_RAW)
328 m_passthrough = true;
329 m_encoding = AEStreamFormatToATFormat(m_format.m_streamInfo.m_type);
330 m_format.m_channelLayout = AE_CH_LAYOUT_2_0;
332 if (m_format.m_streamInfo.m_type == CAEStreamInfo::STREAM_TYPE_DTSHD_MA)
334 // we keep the 48 khz sample rate, reason: Androids packer only packs DTS Core
335 // even if we ask for DTS-HD-MA it seems.
336 m_format.m_channelLayout = AE_CH_LAYOUT_7_1;
339 if (m_format.m_streamInfo.m_type == CAEStreamInfo::STREAM_TYPE_TRUEHD)
341 m_format.m_channelLayout = AE_CH_LAYOUT_7_1;
342 m_sink_sampleRate = 192000;
345 // EAC3 needs real samplerate not the modulation
346 if (m_format.m_streamInfo.m_type == CAEStreamInfo::STREAM_TYPE_EAC3)
347 m_sink_sampleRate = m_format.m_streamInfo.m_sampleRate;
349 if (m_info.m_wantsIECPassthrough)
351 m_format.m_dataFormat = AE_FMT_S16LE;
352 if (m_format.m_streamInfo.m_type == CAEStreamInfo::STREAM_TYPE_DTSHD ||
353 m_format.m_streamInfo.m_type == CAEStreamInfo::STREAM_TYPE_DTSHD_MA ||
354 m_format.m_streamInfo.m_type == CAEStreamInfo::STREAM_TYPE_TRUEHD)
355 m_sink_sampleRate = 192000;
357 // new Android N format
358 if (CJNIAudioFormat::ENCODING_IEC61937 != -1)
360 m_encoding = CJNIAudioFormat::ENCODING_IEC61937;
361 // this will be sent tunneled, therefore the IEC path needs e.g.
362 // 4 * m_format.m_streamInfo.m_sampleRate
363 if (m_format.m_streamInfo.m_type == CAEStreamInfo::STREAM_TYPE_EAC3)
364 m_sink_sampleRate = m_format.m_sampleRate;
367 // we are running on an old android version
368 // that does neither know AC3, DTS or whatever
369 // we will fallback to 16BIT passthrough
370 if (m_encoding == -1)
372 m_format.m_channelLayout = AE_CH_LAYOUT_2_0;
373 m_format.m_sampleRate = m_sink_sampleRate;
374 m_encoding = CJNIAudioFormat::ENCODING_PCM_16BIT;
375 CLog::Log(LOGDEBUG, "Fallback to PCM passthrough mode - this might not work!");
379 else
381 m_passthrough = false;
382 m_format.m_sampleRate = m_sink_sampleRate;
383 // this is temporarily opt-in via advancedsettings only
384 const bool allowMultiFloat =
385 CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_AllowMultiChannelFloat;
386 if (allowMultiFloat && m_sinkSupportsMultiChannelFloat)
388 m_encoding = CJNIAudioFormat::ENCODING_PCM_FLOAT;
389 m_format.m_dataFormat = AE_FMT_FLOAT;
391 else if (m_sinkSupportsFloat && m_format.m_channelLayout.Count() == 2)
393 m_encoding = CJNIAudioFormat::ENCODING_PCM_FLOAT;
394 m_format.m_dataFormat = AE_FMT_FLOAT;
396 else
398 m_encoding = CJNIAudioFormat::ENCODING_PCM_16BIT;
399 m_format.m_dataFormat = AE_FMT_S16LE;
403 m_superviseAudioDelay =
404 CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_superviseAudioDelay;
406 int atChannelMask = AEChannelMapToAUDIOTRACKChannelMask(m_format.m_channelLayout);
407 m_format.m_channelLayout = AUDIOTRACKChannelMaskToAEChannelMap(atChannelMask);
408 if (m_encoding == CJNIAudioFormat::ENCODING_IEC61937)
410 // keep above channel output if we do IEC61937 and got DTSHD or TrueHD by AudioEngine
411 if (m_format.m_streamInfo.m_type != CAEStreamInfo::STREAM_TYPE_DTSHD_MA && m_format.m_streamInfo.m_type != CAEStreamInfo::STREAM_TYPE_TRUEHD)
412 atChannelMask = CJNIAudioFormat::CHANNEL_OUT_STEREO;
415 bool retried = false;
416 while (!m_at_jni)
418 CLog::Log(LOGINFO, "Trying to open: samplerate: {}, channelMask: {}, encoding: {}",
419 m_sink_sampleRate, atChannelMask, m_encoding);
420 int min_buffer = CJNIAudioTrack::getMinBufferSize(m_sink_sampleRate,
421 atChannelMask,
422 m_encoding);
424 if (min_buffer < 0)
426 CLog::Log(LOGERROR,
427 "Minimum Buffer Size was: {} - disable passthrough (?) your hw does not support it",
428 min_buffer);
429 return false;
432 m_min_buffer_size = (unsigned int) min_buffer;
433 CLog::Log(LOGINFO, "Minimum size we need for stream: {} Bytes", m_min_buffer_size);
434 double rawlength_in_seconds = 0.0;
435 int multiplier = 1;
436 unsigned int ac3FrameSize = 1;
437 if (m_passthrough && !m_info.m_wantsIECPassthrough)
439 switch (m_format.m_streamInfo.m_type)
441 case CAEStreamInfo::STREAM_TYPE_TRUEHD:
442 m_min_buffer_size = MAX_RAW_AUDIO_BUFFER_HD;
443 m_format.m_frames = m_min_buffer_size;
444 rawlength_in_seconds = 8 * m_format.m_streamInfo.GetDuration() / 1000; // on average
445 break;
446 case CAEStreamInfo::STREAM_TYPE_DTSHD_MA:
447 case CAEStreamInfo::STREAM_TYPE_DTSHD:
448 // normal frame is max 2012 bytes + 2764 sub frame
449 m_min_buffer_size = 66432; //according to the buffer model of ISO/IEC13818-1
450 m_format.m_frames = m_min_buffer_size;
451 rawlength_in_seconds = 8 * m_format.m_streamInfo.GetDuration() / 1000; // average value
452 break;
453 case CAEStreamInfo::STREAM_TYPE_DTS_512:
454 case CAEStreamInfo::STREAM_TYPE_DTSHD_CORE:
455 // max 2012 bytes
456 // depending on sample rate between 156 ms and 312 ms
457 m_min_buffer_size = 16 * 2012;
458 m_format.m_frames = m_min_buffer_size;
459 rawlength_in_seconds = 16 * m_format.m_streamInfo.GetDuration() / 1000;
460 break;
461 case CAEStreamInfo::STREAM_TYPE_DTS_1024:
462 case CAEStreamInfo::STREAM_TYPE_DTS_2048:
463 m_min_buffer_size = 8 * 5462;
464 m_format.m_frames = m_min_buffer_size;
465 rawlength_in_seconds = 8 * m_format.m_streamInfo.GetDuration() / 1000;
466 break;
467 case CAEStreamInfo::STREAM_TYPE_AC3:
468 ac3FrameSize = m_format.m_streamInfo.m_frameSize;
469 if (ac3FrameSize == 0)
470 ac3FrameSize = 1536; // fallback if not set, e.g. Transcoding
471 m_min_buffer_size = std::max(m_min_buffer_size * 3, ac3FrameSize * 8);
472 m_format.m_frames = m_min_buffer_size;
473 multiplier = m_min_buffer_size / ac3FrameSize; // int division is wanted
474 rawlength_in_seconds = multiplier * m_format.m_streamInfo.GetDuration() / 1000;
475 break;
476 // EAC3 is currently not supported
477 case CAEStreamInfo::STREAM_TYPE_EAC3:
478 m_min_buffer_size = 2 * 10752; // least common multiple of 1792 and 1536
479 m_format.m_frames = m_min_buffer_size; // needs testing
480 rawlength_in_seconds = 8 * m_format.m_streamInfo.GetDuration() / 1000;
481 break;
482 default:
483 m_min_buffer_size = MAX_RAW_AUDIO_BUFFER;
484 m_format.m_frames = m_min_buffer_size;
485 rawlength_in_seconds = 0.4;
486 break;
489 CLog::Log(LOGDEBUG, "Opening Passthrough RAW Format: {} Sink SampleRate: {}",
490 CAEUtil::StreamTypeToStr(m_format.m_streamInfo.m_type), m_sink_sampleRate);
491 m_format.m_frameSize = 1;
492 m_sink_frameSize = m_format.m_frameSize;
494 else
496 m_format.m_frameSize = m_format.m_channelLayout.Count() * (CAEUtil::DataFormatToBits(m_format.m_dataFormat) / 8);
497 m_sink_frameSize = m_format.m_frameSize;
498 // aim at max 200 ms buffer and 50 ms periods but at least two periods of min_buffer
499 // make sure periods are actually not smaller than 32 ms (32, cause 32 * 2 = 64)
500 // but also lower than 64 ms
501 // which is large enough to not cause CPU hogging in case 32 ms periods are used
502 m_audiotrackbuffer_sec =
503 static_cast<double>(m_min_buffer_size) / (m_sink_frameSize * m_sink_sampleRate);
504 // the period calculation starts
505 // after the buffer division to get even division results
506 int c = 1;
507 if (m_audiotrackbuffer_sec > 0.25)
509 CLog::Log(LOGWARNING,
510 "Audiobuffer is already very large {:f} ms - Reducing to a sensible value",
511 1000.0 * m_audiotrackbuffer_sec);
512 int buffer_frames = m_sink_sampleRate / 4; // 250 ms
513 m_min_buffer_size = buffer_frames * m_sink_frameSize;
514 c = 5; // 50 ms
516 // update potential new buffertime
517 m_audiotrackbuffer_sec =
518 static_cast<double>(m_min_buffer_size) / (m_sink_frameSize * m_sink_sampleRate);
519 constexpr double max_time = 0.064;
520 constexpr double min_time = 0.032;
521 constexpr double target_duration = 0.128;
523 while (m_audiotrackbuffer_sec < target_duration)
525 m_min_buffer_size += min_buffer;
526 c++;
527 m_audiotrackbuffer_sec =
528 static_cast<double>(m_min_buffer_size) / (m_sink_frameSize * m_sink_sampleRate);
530 unsigned int period_size = m_min_buffer_size / c;
531 double period_time =
532 static_cast<double>(period_size) / (m_sink_frameSize * m_sink_sampleRate);
534 // This will result in minimum 32 ms
535 while (period_time >= max_time)
537 period_time /= 2;
538 period_size /= 2;
540 // If the audio track API gave us very low values increase them
541 // In this case the first loop would not have been run at all
542 while (period_time < min_time)
544 period_size *= 2;
545 period_time *= 2;
547 m_format.m_frames = static_cast<int>(period_size / m_format.m_frameSize);
549 CLog::Log(LOGINFO,
550 "Audiotrack buffer params are: period time = {:.3f} ms, period size = "
551 "{} bytes, num periods = {}",
552 period_time * 1000, period_size, m_min_buffer_size / period_size);
555 if (m_passthrough && !m_info.m_wantsIECPassthrough)
556 m_audiotrackbuffer_sec = rawlength_in_seconds;
558 CLog::Log(LOGINFO,
559 "Created Audiotrackbuffer with playing time of {:f} ms min buffer size: {} bytes",
560 m_audiotrackbuffer_sec * 1000, m_min_buffer_size);
562 m_audiotrackbuffer_sec_orig = m_audiotrackbuffer_sec;
564 m_jniAudioFormat = m_encoding;
565 m_at_jni = CreateAudioTrack(stream, m_sink_sampleRate, atChannelMask,
566 m_encoding, m_min_buffer_size);
568 if (!IsInitialized())
570 if (!m_passthrough)
572 if (atChannelMask != CJNIAudioFormat::CHANNEL_OUT_STEREO &&
573 atChannelMask != CJNIAudioFormat::CHANNEL_OUT_5POINT1)
575 atChannelMask = CJNIAudioFormat::CHANNEL_OUT_5POINT1;
576 CLog::Log(LOGDEBUG, "AESinkAUDIOTRACK - Retrying multichannel playback with a 5.1 layout");
577 continue;
579 else if (atChannelMask != CJNIAudioFormat::CHANNEL_OUT_STEREO)
581 atChannelMask = CJNIAudioFormat::CHANNEL_OUT_STEREO;
582 CLog::Log(LOGDEBUG, "AESinkAUDIOTRACK - Retrying with a stereo layout");
583 continue;
586 else
588 if (!retried)
590 retried = true;
591 CLog::Log(LOGWARNING, "AESinkAUDIOTRACK - Unable to open PT device - will retry once");
592 // Seems that some devices don't properly implement pause + flush, which during seek
593 // might open the device too fast - let's retry
594 usleep(200 * 1000);
595 continue;
598 CLog::Log(LOGERROR, "AESinkAUDIOTRACK - Unable to create AudioTrack");
599 Deinitialize();
600 return false;
602 const char* method = m_passthrough ? (m_info.m_wantsIECPassthrough ? "IEC (PT)" : "RAW (PT)") : "PCM";
603 CLog::Log(LOGINFO,
604 "CAESinkAUDIOTRACK::Initializing with: m_sampleRate: {} format: {} (AE) method: {} "
605 "stream-type: {} min_buffer_size: {} m_frames: {} m_frameSize: {} channels: {}",
606 m_sink_sampleRate, CAEUtil::DataFormatToStr(m_format.m_dataFormat), method,
607 m_passthrough ? CAEUtil::StreamTypeToStr(m_format.m_streamInfo.m_type) : "PCM-STREAM",
608 m_min_buffer_size, m_format.m_frames, m_format.m_frameSize,
609 m_format.m_channelLayout.Count());
611 format = m_format;
613 return true;
616 void CAESinkAUDIOTRACK::Deinitialize()
618 CLog::Log(LOGDEBUG, "CAESinkAUDIOTRACK::Deinitialize");
620 if (!m_at_jni)
621 return;
623 if (IsInitialized())
625 m_at_jni->pause();
626 m_at_jni->flush();
628 m_at_jni->release();
630 m_duration_written = 0;
631 m_headPos = 0;
632 m_headPosOld = 0;
633 m_timestampPos = 0;
634 m_stampTimer.SetExpired();
636 m_linearmovingaverage.clear();
638 delete m_at_jni;
639 m_at_jni = NULL;
640 m_delay = 0.0;
641 m_hw_delay = 0.0;
644 bool CAESinkAUDIOTRACK::IsInitialized()
646 return (m_at_jni && m_at_jni->getState() == CJNIAudioTrack::STATE_INITIALIZED);
649 void CAESinkAUDIOTRACK::GetDelay(AEDelayStatus& status)
651 if (!m_at_jni)
653 status.SetDelay(0);
654 return;
657 bool usesAdvancedLogging = CServiceBroker::GetLogging().CanLogComponent(LOGAUDIO);
658 // In their infinite wisdom, Google decided to make getPlaybackHeadPosition
659 // return a 32bit "int" that you should "interpret as unsigned." As such,
660 // for wrap safety, we need to do all ops on it in 32bit integer math.
662 uint32_t head_pos = (uint32_t)m_at_jni->getPlaybackHeadPosition();
664 // Wraparound
665 if ((uint32_t)(m_headPos & UINT64_LOWER_BYTES) > head_pos) // need to compute wraparound
666 m_headPos += (1ULL << 32); // add wraparound, e.g. 0x0000 FFFF FFFF -> 0x0001 FFFF FFFF
667 // clear lower 32 bit values, e.g. 0x0001 FFFF FFFF -> 0x0001 0000 0000
668 // and add head_pos which wrapped around, e.g. 0x0001 0000 0000 -> 0x0001 0000 0004
669 m_headPos = (m_headPos & UINT64_UPPER_BYTES) | (uint64_t)head_pos;
670 // check if sink is stuck
671 if (m_headPos == m_headPosOld)
672 m_stuckCounter++;
673 else
675 m_stuckCounter = 0;
676 m_headPosOld = m_headPos;
679 double gone = static_cast<double>(m_headPos) / m_sink_sampleRate;
681 // if sink is run dry without buffer time written anymore
682 if (gone > m_duration_written)
683 gone = m_duration_written;
685 double delay = m_duration_written - gone;
687 if (m_stampTimer.IsTimePast())
689 if (!m_at_jni->getTimestamp(m_timestamp))
691 CLog::Log(LOGDEBUG, "Could not acquire timestamp");
692 m_stampTimer.Set(100ms);
694 else
696 // check if frameposition is valid and nano timer less than 50 ms outdated
697 if (m_timestamp.get_framePosition() > 0 &&
698 (CurrentHostCounter() - m_timestamp.get_nanoTime()) < 50 * 1000 * 1000)
699 m_stampTimer.Set(1000ms);
700 else
701 m_stampTimer.Set(100ms);
704 if (usesAdvancedLogging)
705 CLog::Log(LOGINFO, "RAW Head-Position {}", m_headPos);
706 // check if last value was received less than 2 seconds ago
707 if (m_timestamp.get_framePosition() > 0 &&
708 (CurrentHostCounter() - m_timestamp.get_nanoTime()) < 2 * 1000 * 1000 * 1000)
710 if (usesAdvancedLogging)
712 CLog::Log(LOGINFO, "Framecounter: {} Time: {} Current-Time: {}",
713 (m_timestamp.get_framePosition() & UINT64_LOWER_BYTES), m_timestamp.get_nanoTime(),
714 CurrentHostCounter());
716 uint64_t delta = static_cast<uint64_t>(CurrentHostCounter() - m_timestamp.get_nanoTime());
717 uint64_t stamphead =
718 static_cast<uint64_t>(m_timestamp.get_framePosition() & UINT64_LOWER_BYTES) +
719 delta * m_sink_sampleRate / 1000000000.0;
720 // wrap around
721 // e.g. 0xFFFFFFFFFFFF0123 -> 0x0000000000002478
722 // because we only query each second the simple smaller comparison won't suffice
723 // as delay can fluctuate minimally
724 if (stamphead < m_timestampPos && (m_timestampPos - stamphead) > 0x7FFFFFFFFFFFFFFFULL)
726 uint64_t stamp = m_timestampPos;
727 stamp += (1ULL << 32);
728 stamphead = (stamp & UINT64_UPPER_BYTES) | stamphead;
729 CLog::Log(LOGDEBUG, "Wraparound happened old: {} new: {}", m_timestampPos, stamphead);
731 m_timestampPos = stamphead;
733 double playtime = m_timestampPos / static_cast<double>(m_sink_sampleRate);
735 if (usesAdvancedLogging)
737 CLog::Log(LOGINFO,
738 "Delay - Timestamp: {} (ms) delta: {} (ms) playtime: {} (ms) Duration: {} ms",
739 1000.0 * (m_duration_written - playtime), delta / 1000000.0, playtime * 1000,
740 m_duration_written * 1000);
741 CLog::Log(LOGINFO, "Head-Position {} Timestamp Position {} Delay-Offset: {} ms", m_headPos,
742 m_timestampPos,
743 1000.0 * (static_cast<int64_t>(m_headPos - m_timestampPos)) / m_sink_sampleRate);
745 double hw_delay = m_duration_written - playtime;
746 // correct by subtracting above measured delay, if lower delay gets automatically reduced
747 hw_delay -= delay;
748 // sometimes at the beginning of the stream m_timestampPos is more accurate and ahead of
749 // m_headPos - don't use the computed value then and wait
750 if (hw_delay > -1.0 && hw_delay < 1.0)
751 m_hw_delay = hw_delay;
752 else
753 m_hw_delay = 0.0;
754 if (usesAdvancedLogging)
756 CLog::Log(LOGINFO, "HW-Delay (1): {} ms", hw_delay * 1000);
760 delay += m_hw_delay;
762 if (usesAdvancedLogging)
764 CLog::Log(LOGINFO, "Combined Delay: {} ms", delay * 1000);
766 if (delay < 0.0)
767 delay = 0.0;
769 // the RAW hack for simulating pause bursts should not come
770 // into the way of hw delay
771 if (m_pause_ms > 0.0)
773 double difference = (m_audiotrackbuffer_sec - delay) * 1000;
774 if (usesAdvancedLogging)
776 CLog::Log(LOGINFO, "Faking Pause-Bursts in Delay - returning smoothed {} ms Original {} ms",
777 m_audiotrackbuffer_sec * 1000, delay * 1000);
778 CLog::Log(LOGINFO, "Difference: {} ms m_pause_ms {}", difference, m_pause_ms);
780 // buffer not yet reached
781 if (difference > 0.0)
782 delay = m_audiotrackbuffer_sec;
783 else
785 CLog::Log(LOGINFO, "Resetting pause bursts as buffer level was reached! (2)");
786 m_pause_ms = 0.0;
790 const double d = GetMovingAverageDelay(delay);
792 // Audiotrack is caching more than we thought it would
793 if (d > m_audiotrackbuffer_sec)
794 m_audiotrackbuffer_sec = d;
796 // track delay in local member
797 m_delay = d;
798 if (usesAdvancedLogging)
800 CLog::Log(LOGINFO, "Delay Current: {:f} ms", d * 1000);
802 status.SetDelay(d);
805 double CAESinkAUDIOTRACK::GetLatency()
807 return 0.0;
810 double CAESinkAUDIOTRACK::GetCacheTotal()
812 // total amount that the audio sink can buffer in units of seconds
813 return m_audiotrackbuffer_sec;
816 // this method is supposed to block until all frames are written to the device buffer
817 // when it returns ActiveAESink will take the next buffer out of a queue
818 unsigned int CAESinkAUDIOTRACK::AddPackets(uint8_t **data, unsigned int frames, unsigned int offset)
820 if (!IsInitialized())
821 return INT_MAX;
823 // If the sink did not move twice the buffer size in time it was opened
824 // take action. Some sinks open with e.g. 128 ms nicely but under the
825 // hood need a bit more samples to start moving on sink start.
826 // Simple equation: N x stime packages in ms > 2 configured audiotrack_buffer in ms
827 // will result in the error condition triggering.
829 const bool isRawPt = m_passthrough && !m_info.m_wantsIECPassthrough;
830 if (!isRawPt)
832 const double max_stuck_delay_ms = m_audiotrackbuffer_sec_orig * 2000.0;
833 const double stime_ms = 1000.0 * frames / m_format.m_sampleRate;
835 if (m_superviseAudioDelay && (m_stuckCounter * stime_ms > max_stuck_delay_ms))
837 CLog::Log(LOGERROR, "Sink got stuck with {:f} ms - ask AE for reopening", max_stuck_delay_ms);
838 usleep(max_stuck_delay_ms * 1000);
839 return INT_MAX;
843 // for debugging only - can be removed if everything is really stable
844 uint64_t startTime = CurrentHostCounter();
846 uint8_t *buffer = data[0]+offset*m_format.m_frameSize;
847 uint8_t *out_buf = buffer;
848 int size = frames * m_format.m_frameSize;
850 // write as many frames of audio as we can fit into our internal buffer.
851 int written = 0;
852 int loop_written = 0;
853 if (frames)
855 if (m_at_jni->getPlayState() != CJNIAudioTrack::PLAYSTATE_PLAYING)
856 m_at_jni->play();
858 bool retried = false;
859 int size_left = size;
860 while (written < size)
862 loop_written = AudioTrackWrite((char*)out_buf, 0, size_left);
863 written += loop_written;
864 size_left -= loop_written;
866 if (loop_written < 0)
868 CLog::Log(LOGERROR, "CAESinkAUDIOTRACK::AddPackets write returned error: {}",
869 loop_written);
870 return INT_MAX;
873 // if we could not add any data - sleep a bit and retry
874 if (loop_written == 0)
876 if (!retried)
878 retried = true;
879 double sleep_time = 0;
880 if (m_passthrough && !m_info.m_wantsIECPassthrough)
882 sleep_time = m_format.m_streamInfo.GetDuration();
883 usleep(sleep_time * 1000);
885 else
887 sleep_time = 1000.0 * m_format.m_frames / m_format.m_sampleRate;
888 usleep(sleep_time * 1000);
890 bool playing = m_at_jni->getPlayState() == CJNIAudioTrack::PLAYSTATE_PLAYING;
891 CLog::Log(LOGDEBUG, "Retried to write onto the sink - slept: {:f} playing: {}",
892 sleep_time, playing ? "yes" : "no");
893 continue;
895 else
897 CLog::Log(LOGDEBUG, "Repeatedly tried to write onto the sink - giving up");
898 break;
901 retried = false; // at least one time there was more than zero data written
902 if (m_passthrough && !m_info.m_wantsIECPassthrough)
904 if (written == size)
905 m_duration_written += m_format.m_streamInfo.GetDuration() / 1000;
906 else
908 CLog::Log(LOGDEBUG, "Error writing full package to sink, left: {}", size_left);
909 // Let AE wait some ms to come back
910 unsigned int written_frames = (unsigned int) (written/m_format.m_frameSize);
911 return written_frames;
914 else
916 double duration =
917 (static_cast<double>(loop_written) / m_format.m_frameSize) / m_format.m_sampleRate;
918 m_duration_written += duration;
921 // just try again to care for fragmentation
922 if (written < size)
923 out_buf = out_buf + loop_written;
925 loop_written = 0;
928 unsigned int written_frames = static_cast<unsigned int>(written / m_format.m_frameSize);
929 double time_to_add_ms = 1000.0 * (CurrentHostCounter() - startTime) / CurrentHostFrequency();
930 if (m_passthrough && !m_info.m_wantsIECPassthrough)
932 // AT does not consume in a blocking way - it runs ahead and blocks
933 // exactly once with the last package for some 100 ms
934 double extra_sleep = 0.0;
935 if (time_to_add_ms < m_format.m_streamInfo.GetDuration())
936 extra_sleep = (m_format.m_streamInfo.GetDuration() - time_to_add_ms) / 2;
938 // if there is still place, just add it without blocking
939 if (m_delay < (m_audiotrackbuffer_sec - (m_format.m_streamInfo.GetDuration() / 1000.0)))
940 extra_sleep = 0;
942 if (m_pause_ms > 0.0)
944 extra_sleep = 0;
945 m_pause_ms -= m_format.m_streamInfo.GetDuration();
946 if (m_pause_ms <= 0.0)
948 m_pause_ms = 0.0;
949 CLog::Log(LOGINFO, "Resetting pause bursts as buffer level was reached! (1)");
952 else
954 if (m_delay > 0.3)
955 extra_sleep *= 2;
958 usleep(extra_sleep * 1000);
960 else
962 // waiting should only be done if sink is not run dry
963 double period_time = m_format.m_frames / static_cast<double>(m_sink_sampleRate);
964 if (m_delay >= (m_audiotrackbuffer_sec - period_time))
966 double time_should_ms = 1000.0 * written_frames / m_format.m_sampleRate;
967 double time_off = time_should_ms - time_to_add_ms;
968 if (time_off > 0)
969 usleep(time_off * 500); // sleep half the error on average away
973 return written_frames;
976 void CAESinkAUDIOTRACK::AddPause(unsigned int millis)
978 if (!m_at_jni)
979 return;
981 // just sleep out the frames
982 if (m_at_jni->getPlayState() != CJNIAudioTrack::PLAYSTATE_PAUSED)
983 m_at_jni->pause();
985 // This is a mixture to get it right between
986 // blocking, sleeping roughly and GetDelay smoothing
987 // In short: Shit in, shit out
988 usleep(millis * 1000);
989 m_pause_ms += millis;
992 void CAESinkAUDIOTRACK::Drain()
994 if (!m_at_jni)
995 return;
997 CLog::Log(LOGDEBUG, "Draining Audio");
998 if (IsInitialized())
1000 m_at_jni->stop();
1001 // stay ready
1002 m_at_jni->pause();
1004 m_duration_written = 0;
1005 m_headPos = 0;
1006 m_stuckCounter = 0;
1007 m_timestampPos = 0;
1008 m_linearmovingaverage.clear();
1009 m_stampTimer.SetExpired();
1010 m_pause_ms = 0.0;
1013 void CAESinkAUDIOTRACK::Register()
1015 AE::AESinkRegEntry entry;
1016 entry.sinkName = "AUDIOTRACK";
1017 entry.createFunc = CAESinkAUDIOTRACK::Create;
1018 entry.enumerateFunc = CAESinkAUDIOTRACK::EnumerateDevicesEx;
1019 AE::CAESinkFactory::RegisterSink(entry);
1022 std::unique_ptr<IAESink> CAESinkAUDIOTRACK::Create(std::string& device,
1023 AEAudioFormat& desiredFormat)
1025 auto sink = std::make_unique<CAESinkAUDIOTRACK>();
1026 if (sink->Initialize(desiredFormat, device))
1027 return sink;
1029 return {};
1032 void CAESinkAUDIOTRACK::EnumerateDevicesEx(AEDeviceInfoList &list, bool force)
1034 // Clear everything
1035 m_info.m_channels.Reset();
1036 m_info.m_dataFormats.clear();
1037 m_info.m_sampleRates.clear();
1038 m_info.m_streamTypes.clear();
1039 m_sink_sampleRates.clear();
1041 m_info.m_deviceType = AE_DEVTYPE_PCM;
1042 m_info.m_deviceName = "AudioTrack (IEC)";
1043 m_info.m_displayName = "AudioTrack (IEC)";
1044 m_info.m_displayNameExtra = "Kodi IEC packer (recommended)";
1046 // Query IEC capabilities
1047 bool isRaw = false;
1048 if (CJNIAudioFormat::ENCODING_IEC61937 != -1)
1050 UpdateAvailablePCMCapabilities();
1051 UpdateAvailablePassthroughCapabilities(isRaw);
1053 if (!m_info.m_streamTypes.empty())
1055 m_info_iec = m_info;
1056 list.push_back(m_info_iec);
1057 m_hasIEC = true;
1061 // Query RAW capabilities
1062 isRaw = true;
1063 m_info.m_deviceName = "AudioTrack (RAW)";
1064 m_info.m_displayName = "AudioTrack (RAW)";
1065 m_info.m_displayNameExtra = "Android IEC packer";
1066 UpdateAvailablePCMCapabilities();
1067 UpdateAvailablePassthroughCapabilities(isRaw);
1068 m_info_raw = m_info;
1070 // no need to display two PCM sinks - as they are the same
1071 if (!list.empty())
1072 m_info_raw.m_onlyPassthrough = true;
1074 list.push_back(m_info_raw);
1077 void CAESinkAUDIOTRACK::UpdateAvailablePassthroughCapabilities(bool isRaw)
1079 m_info.m_deviceType = AE_DEVTYPE_HDMI;
1080 m_info.m_wantsIECPassthrough = false;
1081 m_info.m_dataFormats.push_back(AE_FMT_RAW);
1082 m_info.m_streamTypes.clear();
1083 bool supports_192khz = m_sink_sampleRates.find(192000) != m_sink_sampleRates.end();
1085 if (isRaw)
1087 bool canDoAC3 = false;
1089 if (CJNIAudioFormat::ENCODING_AC3 != -1)
1091 if (VerifySinkConfiguration(48000, CJNIAudioFormat::CHANNEL_OUT_STEREO,
1092 CJNIAudioFormat::ENCODING_AC3, true))
1094 m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_AC3);
1095 CLog::Log(LOGDEBUG, "Firmware implements AC3 RAW");
1097 canDoAC3 = true;
1101 // EAC3 working on shield, broken on FireTV
1102 if (CJNIAudioFormat::ENCODING_E_AC3 != -1)
1104 if (VerifySinkConfiguration(48000, CJNIAudioFormat::CHANNEL_OUT_STEREO,
1105 CJNIAudioFormat::ENCODING_E_AC3, true))
1107 m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_EAC3);
1108 CLog::Log(LOGDEBUG, "Firmware implements EAC3 RAW");
1110 if (!canDoAC3)
1111 m_passthrough_use_eac3 = true;
1115 if (CJNIAudioFormat::ENCODING_DTS != -1)
1117 if (VerifySinkConfiguration(48000, CJNIAudioFormat::CHANNEL_OUT_STEREO,
1118 CJNIAudioFormat::ENCODING_DTS, true))
1120 CLog::Log(LOGDEBUG, "Firmware implements DTS RAW");
1121 m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTSHD_CORE);
1122 m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTS_1024);
1123 m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTS_2048);
1124 m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTS_512);
1128 if (CJNIAudioFormat::ENCODING_DTS_HD != -1)
1130 if (VerifySinkConfiguration(48000, AEChannelMapToAUDIOTRACKChannelMask(AE_CH_LAYOUT_7_1),
1131 CJNIAudioFormat::ENCODING_DTS_HD, true))
1133 CLog::Log(LOGDEBUG, "Firmware implements DTS-HD RAW");
1134 m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTSHD);
1135 m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTSHD_MA);
1138 if (CJNIAudioFormat::ENCODING_DOLBY_TRUEHD != -1 && supports_192khz)
1140 if (VerifySinkConfiguration(192000, AEChannelMapToAUDIOTRACKChannelMask(AE_CH_LAYOUT_7_1),
1141 CJNIAudioFormat::ENCODING_DOLBY_TRUEHD, true))
1143 CLog::Log(LOGDEBUG, "Firmware implements TrueHD RAW");
1144 m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_TRUEHD);
1148 else
1150 // Android v24 and backports can do real IEC API
1151 if (CJNIAudioFormat::ENCODING_IEC61937 != -1)
1153 // check if we support opening an IEC sink at all:
1154 bool supports_iec = VerifySinkConfiguration(48000, CJNIAudioFormat::CHANNEL_OUT_STEREO,
1155 CJNIAudioFormat::ENCODING_IEC61937);
1156 if (supports_iec)
1158 m_info.m_wantsIECPassthrough = true;
1159 m_info.m_streamTypes.clear();
1160 m_info.m_dataFormats.push_back(AE_FMT_RAW);
1161 m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_AC3);
1162 m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTSHD_CORE);
1163 m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTS_1024);
1164 m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTS_2048);
1165 m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTS_512);
1166 CLog::Log(LOGDEBUG, "AESinkAUDIOTrack: Using IEC PT mode: {}",
1167 CJNIAudioFormat::ENCODING_IEC61937);
1168 CLog::Log(LOGDEBUG, "AC3 and DTS via IEC61937 is supported");
1169 if (supports_192khz)
1171 // Check for IEC 2 channel 192 khz PT DTS-HD-HR and E-AC3
1172 if (VerifySinkConfiguration(192000, CJNIAudioFormat::CHANNEL_OUT_STEREO,
1173 CJNIAudioFormat::ENCODING_IEC61937))
1175 m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_EAC3);
1176 m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTSHD);
1177 CLog::Log(LOGDEBUG, "E-AC3 and DTSHD-HR via IEC61937 is supported");
1179 // Check for IEC 8 channel 192 khz PT DTS-HD-MA and TrueHD
1180 int atChannelMask = AEChannelMapToAUDIOTRACKChannelMask(AE_CH_LAYOUT_7_1);
1181 if (VerifySinkConfiguration(192000, atChannelMask, CJNIAudioFormat::ENCODING_IEC61937))
1183 m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_DTSHD_MA);
1184 m_info.m_streamTypes.push_back(CAEStreamInfo::STREAM_TYPE_TRUEHD);
1185 CLog::Log(LOGDEBUG, "DTSHD-MA and TrueHD via IEC61937 is supported");
1193 void CAESinkAUDIOTRACK::UpdateAvailablePCMCapabilities()
1195 m_info.m_channels = KnownChannels;
1197 // default fallback format
1198 m_info.m_dataFormats.push_back(AE_FMT_S16LE);
1199 unsigned int native_sampleRate = CJNIAudioTrack::getNativeOutputSampleRate(CJNIAudioManager::STREAM_MUSIC);
1200 m_sink_sampleRates.insert(native_sampleRate);
1202 int encoding = CJNIAudioFormat::ENCODING_PCM_16BIT;
1203 m_sinkSupportsFloat = VerifySinkConfiguration(native_sampleRate, CJNIAudioFormat::CHANNEL_OUT_STEREO, CJNIAudioFormat::ENCODING_PCM_FLOAT);
1205 m_sinkSupportsMultiChannelFloat =
1206 VerifySinkConfiguration(native_sampleRate, CJNIAudioFormat::CHANNEL_OUT_7POINT1_SURROUND,
1207 CJNIAudioFormat::ENCODING_PCM_FLOAT);
1209 if (m_sinkSupportsFloat)
1211 encoding = CJNIAudioFormat::ENCODING_PCM_FLOAT;
1212 m_info.m_dataFormats.push_back(AE_FMT_FLOAT);
1213 CLog::Log(LOGINFO, "Float is supported");
1215 if (m_sinkSupportsMultiChannelFloat)
1217 CLog::Log(LOGINFO, "Multi channel Float is supported");
1220 int test_sample[] = { 32000, 44100, 48000, 88200, 96000, 176400, 192000 };
1221 int test_sample_sz = sizeof(test_sample) / sizeof(int);
1223 for (int i = 0; i < test_sample_sz; ++i)
1225 if (IsSupported(test_sample[i], CJNIAudioFormat::CHANNEL_OUT_STEREO, encoding))
1227 m_sink_sampleRates.insert(test_sample[i]);
1228 CLog::Log(LOGDEBUG, "AESinkAUDIOTRACK - {} supported", test_sample[i]);
1231 std::copy(m_sink_sampleRates.begin(), m_sink_sampleRates.end(), std::back_inserter(m_info.m_sampleRates));
1234 double CAESinkAUDIOTRACK::GetMovingAverageDelay(double newestdelay)
1236 #if defined AT_USE_EXPONENTIAL_AVERAGING
1237 double old = 0.0;
1238 if (m_linearmovingaverage.empty()) // just for creating one space in list
1239 m_linearmovingaverage.push_back(newestdelay);
1240 else
1241 old = m_linearmovingaverage.front();
1243 const double alpha = 0.3;
1244 const double beta = 0.7;
1246 double d = alpha * newestdelay + beta * old;
1247 m_linearmovingaverage.at(0) = d;
1249 return d;
1250 #endif
1252 m_linearmovingaverage.push_back(newestdelay);
1254 // new values are in the back, old values are in the front
1255 // oldest value is removed if elements > MOVING_AVERAGE_MAX_MEMBERS
1256 // removing first element of a vector sucks - I know that
1257 // but hey - 10 elements - not 1 million
1258 size_t size = m_linearmovingaverage.size();
1259 if (size > MOVING_AVERAGE_MAX_MEMBERS)
1261 m_linearmovingaverage.pop_front();
1262 size--;
1264 // m_{LWMA}^{(n)}(t) = \frac{2}{n (n+1)} \sum_{i=1}^n i \; x(t-n+i)
1265 const double denom = 2.0 / (size * (size + 1));
1266 double sum = 0.0;
1267 for (size_t i = 0; i < m_linearmovingaverage.size(); i++)
1268 sum += (i + 1) * m_linearmovingaverage.at(i);
1270 return sum * denom;