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"
23 #include <androidjni/AudioFormat.h>
24 #include <androidjni/AudioManager.h>
25 #include <androidjni/AudioTrack.h>
26 #include <androidjni/Build.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
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
)
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
;
69 return CJNIAudioFormat::ENCODING_PCM_16BIT
;
73 static AEChannel
AUDIOTRACKChannelToAEChannel(int atChannel
)
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
;
95 static CAEChannelInfo
AUDIOTRACKChannelMaskToAEChannelMap(int atMask
)
100 for (unsigned int i
= 0; i
< sizeof(int32_t) * 8; i
++)
103 info
+= AUDIOTRACKChannelToAEChannel(mask
);
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(),
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());
157 int CAESinkAUDIOTRACK::AudioTrackWrite(char* audioData
, int offsetInBytes
, int sizeInBytes
)
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);
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
);
184 m_at_jni
->write(m_charbuf
, 0, sizeInBytes
- offsetInBytes
, CJNIAudioTrack::WRITE_BLOCKING
);
190 int CAESinkAUDIOTRACK::AudioTrackWrite(char* audioData
, int sizeInBytes
, int64_t timestamp
)
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
);
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()
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;
221 m_duration_written
= 0;
226 m_sink_sampleRate
= 0;
227 m_passthrough
= false;
228 m_min_buffer_size
= 0;
231 CAESinkAUDIOTRACK::~CAESinkAUDIOTRACK()
236 bool CAESinkAUDIOTRACK::VerifySinkConfiguration(int sampleRate
,
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
250 jni::CJNIAudioTrack
* jniAt
= CreateAudioTrack(CJNIAudioManager::STREAM_MUSIC
, sampleRate
,
251 channelMask
, encoding
, minBufferSize
);
252 supported
= (jniAt
&& jniAt
->getState() == CJNIAudioTrack::STATE_INITIALIZED
);
265 CLog::Log(LOGDEBUG
, "VerifySinkConfiguration samplerate: {} mask: {} encoding: {} success: {}",
266 sampleRate
, channelMask
, encoding
, supported
? "true" : "false");
271 bool CAESinkAUDIOTRACK::IsSupported(int sampleRateInHz
, int channelConfig
, int encoding
)
273 int ret
= CJNIAudioTrack::getMinBufferSize( sampleRateInHz
, channelConfig
, encoding
);
277 bool CAESinkAUDIOTRACK::Initialize(AEAudioFormat
&format
, std::string
&device
)
280 // try to recover used device
283 else if (device
== "Default" && !m_info
.m_wantsIECPassthrough
)
285 else if (device
== "AudioTrack (RAW)")
295 m_linearmovingaverage
.clear();
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
));
320 m_sink_sampleRate
= s
;
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!");
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
;
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;
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
,
427 "Minimum Buffer Size was: {} - disable passthrough (?) your hw does not support it",
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;
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
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
453 case CAEStreamInfo::STREAM_TYPE_DTS_512
:
454 case CAEStreamInfo::STREAM_TYPE_DTSHD_CORE
:
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;
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;
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;
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;
483 m_min_buffer_size
= MAX_RAW_AUDIO_BUFFER
;
484 m_format
.m_frames
= m_min_buffer_size
;
485 rawlength_in_seconds
= 0.4;
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
;
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
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
;
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
;
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
;
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
)
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
)
547 m_format
.m_frames
= static_cast<int>(period_size
/ m_format
.m_frameSize
);
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
;
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())
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");
579 else if (atChannelMask
!= CJNIAudioFormat::CHANNEL_OUT_STEREO
)
581 atChannelMask
= CJNIAudioFormat::CHANNEL_OUT_STEREO
;
582 CLog::Log(LOGDEBUG
, "AESinkAUDIOTRACK - Retrying with a stereo layout");
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
598 CLog::Log(LOGERROR
, "AESinkAUDIOTRACK - Unable to create AudioTrack");
602 const char* method
= m_passthrough
? (m_info
.m_wantsIECPassthrough
? "IEC (PT)" : "RAW (PT)") : "PCM";
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());
616 void CAESinkAUDIOTRACK::Deinitialize()
618 CLog::Log(LOGDEBUG
, "CAESinkAUDIOTRACK::Deinitialize");
630 m_duration_written
= 0;
634 m_stampTimer
.SetExpired();
636 m_linearmovingaverage
.clear();
644 bool CAESinkAUDIOTRACK::IsInitialized()
646 return (m_at_jni
&& m_at_jni
->getState() == CJNIAudioTrack::STATE_INITIALIZED
);
649 void CAESinkAUDIOTRACK::GetDelay(AEDelayStatus
& status
)
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();
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
)
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
);
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
);
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());
718 static_cast<uint64_t>(m_timestamp
.get_framePosition() & UINT64_LOWER_BYTES
) +
719 delta
* m_sink_sampleRate
/ 1000000000.0;
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
)
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
,
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
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
;
754 if (usesAdvancedLogging
)
756 CLog::Log(LOGINFO
, "HW-Delay (1): {} ms", hw_delay
* 1000);
762 if (usesAdvancedLogging
)
764 CLog::Log(LOGINFO
, "Combined Delay: {} ms", delay
* 1000);
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
;
785 CLog::Log(LOGINFO
, "Resetting pause bursts as buffer level was reached! (2)");
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
798 if (usesAdvancedLogging
)
800 CLog::Log(LOGINFO
, "Delay Current: {:f} ms", d
* 1000);
805 double CAESinkAUDIOTRACK::GetLatency()
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())
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
;
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);
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.
852 int loop_written
= 0;
855 if (m_at_jni
->getPlayState() != CJNIAudioTrack::PLAYSTATE_PLAYING
)
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: {}",
873 // if we could not add any data - sleep a bit and retry
874 if (loop_written
== 0)
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);
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");
897 CLog::Log(LOGDEBUG
, "Repeatedly tried to write onto the sink - giving up");
901 retried
= false; // at least one time there was more than zero data written
902 if (m_passthrough
&& !m_info
.m_wantsIECPassthrough
)
905 m_duration_written
+= m_format
.m_streamInfo
.GetDuration() / 1000;
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
;
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
923 out_buf
= out_buf
+ loop_written
;
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)))
942 if (m_pause_ms
> 0.0)
945 m_pause_ms
-= m_format
.m_streamInfo
.GetDuration();
946 if (m_pause_ms
<= 0.0)
949 CLog::Log(LOGINFO
, "Resetting pause bursts as buffer level was reached! (1)");
958 usleep(extra_sleep
* 1000);
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
;
969 usleep(time_off
* 500); // sleep half the error on average away
973 return written_frames
;
976 void CAESinkAUDIOTRACK::AddPause(unsigned int millis
)
981 // just sleep out the frames
982 if (m_at_jni
->getPlayState() != CJNIAudioTrack::PLAYSTATE_PAUSED
)
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()
997 CLog::Log(LOGDEBUG
, "Draining Audio");
1004 m_duration_written
= 0;
1008 m_linearmovingaverage
.clear();
1009 m_stampTimer
.SetExpired();
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
))
1032 void CAESinkAUDIOTRACK::EnumerateDevicesEx(AEDeviceInfoList
&list
, bool force
)
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
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
);
1061 // Query RAW capabilities
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
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();
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");
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");
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
);
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
);
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
1238 if (m_linearmovingaverage
.empty()) // just for creating one space in list
1239 m_linearmovingaverage
.push_back(newestdelay
);
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
;
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();
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));
1267 for (size_t i
= 0; i
< m_linearmovingaverage
.size(); i
++)
1268 sum
+= (i
+ 1) * m_linearmovingaverage
.at(i
);