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.
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"
25 #include <androidjni/AudioFormat.h>
26 #include <androidjni/AudioManager.h>
27 #include <androidjni/AudioTrack.h>
28 #include <androidjni/Build.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
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
)
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
;
71 return CJNIAudioFormat::ENCODING_PCM_16BIT
;
75 static AEChannel
AUDIOTRACKChannelToAEChannel(int atChannel
)
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
;
97 static CAEChannelInfo
AUDIOTRACKChannelMaskToAEChannelMap(int atMask
)
102 for (unsigned int i
= 0; i
< sizeof(int32_t) * 8; i
++)
105 info
+= AUDIOTRACKChannelToAEChannel(mask
);
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(),
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());
159 int CAESinkAUDIOTRACK::AudioTrackWrite(char* audioData
, int offsetInBytes
, int sizeInBytes
)
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);
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
);
186 m_at_jni
->write(m_charbuf
, 0, sizeInBytes
- offsetInBytes
, CJNIAudioTrack::WRITE_BLOCKING
);
192 int CAESinkAUDIOTRACK::AudioTrackWrite(char* audioData
, int sizeInBytes
, int64_t timestamp
)
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
);
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()
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;
223 m_duration_written
= 0;
228 m_sink_sampleRate
= 0;
229 m_passthrough
= false;
230 m_min_buffer_size
= 0;
233 CAESinkAUDIOTRACK::~CAESinkAUDIOTRACK()
238 bool CAESinkAUDIOTRACK::VerifySinkConfiguration(int sampleRate
,
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
252 jni::CJNIAudioTrack
* jniAt
= CreateAudioTrack(CJNIAudioManager::STREAM_MUSIC
, sampleRate
,
253 channelMask
, encoding
, minBufferSize
);
254 supported
= (jniAt
&& jniAt
->getState() == CJNIAudioTrack::STATE_INITIALIZED
);
267 CLog::Log(LOGDEBUG
, "VerifySinkConfiguration samplerate: {} mask: {} encoding: {} success: {}",
268 sampleRate
, channelMask
, encoding
, supported
? "true" : "false");
273 bool CAESinkAUDIOTRACK::IsSupported(int sampleRateInHz
, int channelConfig
, int encoding
)
275 int ret
= CJNIAudioTrack::getMinBufferSize( sampleRateInHz
, channelConfig
, encoding
);
279 bool CAESinkAUDIOTRACK::Initialize(AEAudioFormat
&format
, std::string
&device
)
282 // try to recover used device
285 else if (device
== "Default" && !m_info
.m_wantsIECPassthrough
)
287 else if (device
== "AudioTrack (RAW)")
297 m_linearmovingaverage
.clear();
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
));
322 m_sink_sampleRate
= s
;
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!");
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
;
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;
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
,
429 "Minimum Buffer Size was: {} - disable passthrough (?) your hw does not support it",
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;
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
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
455 case CAEStreamInfo::STREAM_TYPE_DTS_512
:
456 case CAEStreamInfo::STREAM_TYPE_DTSHD_CORE
:
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;
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;
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;
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;
485 m_min_buffer_size
= MAX_RAW_AUDIO_BUFFER
;
486 m_format
.m_frames
= m_min_buffer_size
;
487 rawlength_in_seconds
= 0.4;
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
;
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
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
;
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
;
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
;
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
)
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
)
549 m_format
.m_frames
= static_cast<int>(period_size
/ m_format
.m_frameSize
);
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
;
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())
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");
581 else if (atChannelMask
!= CJNIAudioFormat::CHANNEL_OUT_STEREO
)
583 atChannelMask
= CJNIAudioFormat::CHANNEL_OUT_STEREO
;
584 CLog::Log(LOGDEBUG
, "AESinkAUDIOTRACK - Retrying with a stereo layout");
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
600 CLog::Log(LOGERROR
, "AESinkAUDIOTRACK - Unable to create AudioTrack");
604 const char* method
= m_passthrough
? (m_info
.m_wantsIECPassthrough
? "IEC (PT)" : "RAW (PT)") : "PCM";
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());
618 void CAESinkAUDIOTRACK::Deinitialize()
620 CLog::Log(LOGDEBUG
, "CAESinkAUDIOTRACK::Deinitialize");
632 m_duration_written
= 0;
636 m_stampTimer
.SetExpired();
638 m_linearmovingaverage
.clear();
646 bool CAESinkAUDIOTRACK::IsInitialized()
648 return (m_at_jni
&& m_at_jni
->getState() == CJNIAudioTrack::STATE_INITIALIZED
);
651 void CAESinkAUDIOTRACK::GetDelay(AEDelayStatus
& status
)
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();
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
)
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
);
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
);
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());
720 static_cast<uint64_t>(m_timestamp
.get_framePosition() & UINT64_LOWER_BYTES
) +
721 delta
* m_sink_sampleRate
/ 1000000000.0;
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
)
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
,
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
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
;
756 if (usesAdvancedLogging
)
758 CLog::Log(LOGINFO
, "HW-Delay (1): {} ms", hw_delay
* 1000);
764 if (usesAdvancedLogging
)
766 CLog::Log(LOGINFO
, "Combined Delay: {} ms", delay
* 1000);
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
;
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
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
);
800 double CAESinkAUDIOTRACK::GetLatency()
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())
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;
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",
837 usleep(max_stuck_delay_ms
* 1000);
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
));
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.
858 int loop_written
= 0;
861 if (m_at_jni
->getPlayState() != CJNIAudioTrack::PLAYSTATE_PLAYING
)
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: {}",
879 // if we could not add any data - sleep a bit and retry
880 if (loop_written
== 0)
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);
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");
903 CLog::Log(LOGDEBUG
, "Repeatedly tried to write onto the sink - giving up");
907 retried
= false; // at least one time there was more than zero data written
908 if (m_passthrough
&& !m_info
.m_wantsIECPassthrough
)
911 m_duration_written
+= m_format
.m_streamInfo
.GetDuration() / 1000;
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
;
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
929 out_buf
= out_buf
+ loop_written
;
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)
953 extra_sleep_ms
= 0.0;
954 CLog::Log(LOGDEBUG
, "Resetting pause bursts as buffer level was reached! (1)");
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
;
967 usleep(time_off
* 500); // sleep half the error on average away
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
)
991 // just sleep out the frames
992 if (m_at_jni
->getPlayState() != CJNIAudioTrack::PLAYSTATE_PAUSED
)
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()
1007 CLog::Log(LOGDEBUG
, "Draining Audio");
1008 if (IsInitialized())
1014 m_duration_written
= 0;
1018 m_linearmovingaverage
.clear();
1019 m_stampTimer
.SetExpired();
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
))
1042 void CAESinkAUDIOTRACK::EnumerateDevicesEx(AEDeviceInfoList
&list
, bool force
)
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
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
);
1071 // Query RAW capabilities
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
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();
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");
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");
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
);
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
);
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
1248 if (m_linearmovingaverage
.empty()) // just for creating one space in list
1249 m_linearmovingaverage
.push_back(newestdelay
);
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
;
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();
1273 double sum
= std::accumulate(m_linearmovingaverage
.begin(), m_linearmovingaverage
.end(), 0.0);