From 8cdf554a187d148be509f29d219ffe2571b25c25 Mon Sep 17 00:00:00 2001 From: verybadsoldier Date: Fri, 12 Jul 2013 22:33:45 +0200 Subject: [PATCH 1/5] deinitialize NFS before going to suspend --- ...nfsdeinit-and-wait-for-nic-on-wakeup.patch} | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) rename packages/mediacenter/xbmc/patches/12.2.0/{xbmc-990.24-smbdeinit-and-wait-for-nic-on-wakeup.patch => xbmc-990.24-smbnfsdeinit-and-wait-for-nic-on-wakeup.patch} (90%) diff --git a/packages/mediacenter/xbmc/patches/12.2.0/xbmc-990.24-smbdeinit-and-wait-for-nic-on-wakeup.patch b/packages/mediacenter/xbmc/patches/12.2.0/xbmc-990.24-smbnfsdeinit-and-wait-for-nic-on-wakeup.patch similarity index 90% rename from packages/mediacenter/xbmc/patches/12.2.0/xbmc-990.24-smbdeinit-and-wait-for-nic-on-wakeup.patch rename to packages/mediacenter/xbmc/patches/12.2.0/xbmc-990.24-smbnfsdeinit-and-wait-for-nic-on-wakeup.patch index 51c30b698d..fe17220717 100644 --- a/packages/mediacenter/xbmc/patches/12.2.0/xbmc-990.24-smbdeinit-and-wait-for-nic-on-wakeup.patch +++ b/packages/mediacenter/xbmc/patches/12.2.0/xbmc-990.24-smbnfsdeinit-and-wait-for-nic-on-wakeup.patch @@ -1,7 +1,7 @@ diff -rupN xbmc-upstream/xbmc/Application.cpp xbmc-vbs/xbmc/Application.cpp --- xbmc-upstream/xbmc/Application.cpp 2013-06-12 00:24:40.486262597 +0200 +++ xbmc-vbs/xbmc/Application.cpp 2013-06-12 01:23:11.948400122 +0200 -@@ -5907,3 +5907,33 @@ CPerformanceStats &CApplication::GetPerf +@@ -5907,3 +5907,37 @@ CPerformanceStats &CApplication::GetPerf } #endif @@ -12,6 +12,10 @@ diff -rupN xbmc-upstream/xbmc/Application.cpp xbmc-vbs/xbmc/Application.cpp +#if defined(HAS_FILESYSTEM_SMB) && !defined(_WIN32) + smb.Deinit(); +#endif ++ ++#if defined(HAS_FILESYSTEM_NFS) ++ gNfsConnection.Deinit(); ++#endif +} + +void CApplication::StopAddonServices() @@ -59,6 +63,18 @@ diff -rupN xbmc-upstream/xbmc/filesystem/SmbFile.cpp xbmc-vbs/xbmc/filesystem/Sm if (!m_context) { #ifdef TARGET_POSIX +diff -rupN xbmc-upstream/xbmc/filesystem/NFSFile.cpp xbmc-vbs/xbmc/filesystem/NFSFile.cpp +--- xbmc-upstream/xbmc/filesystem/NFSFile.cpp 2013-07-12 22:18:51.062605410 +0200 ++++ xbmc-vbs/xbmc/filesystem/NFSFile.cpp 2013-07-12 22:19:27.069861082 +0200 +@@ -308,6 +308,8 @@ + + void CNfsConnection::Deinit() + { ++ CLog::Log(LOGNOTICE,"CNfsConnection::Deinit"); ++ + if(m_pNfsContext && m_pLibNfs->IsLoaded()) + { + destroyOpenContexts(); diff -rupN xbmc-upstream/xbmc/powermanagement/PowerManager.cpp xbmc-vbs/xbmc/powermanagement/PowerManager.cpp --- xbmc-upstream/xbmc/powermanagement/PowerManager.cpp 2013-06-12 00:24:41.634276292 +0200 +++ xbmc-vbs/xbmc/powermanagement/PowerManager.cpp 2013-06-12 01:15:32.166859998 +0200 From 70a79c3363ea64d18fb55bb04105ca335ff58bd1 Mon Sep 17 00:00:00 2001 From: Stephan Raue Date: Sun, 14 Jul 2013 18:46:35 +0200 Subject: [PATCH 2/5] xbmc: update to xbmc-e565394 Signed-off-by: Stephan Raue --- packages/mediacenter/xbmc-theme-Confluence/meta | 2 +- packages/mediacenter/xbmc/meta | 2 +- .../xbmc-321-texturepacker-hostflags-and-rework.patch | 0 ...bmc-408-enable_PYTHONOPTIMIZE_with_external_Python-0.1.patch | 0 .../xbmc-453-add_openelec.tv_RSS_news-0.1.patch | 0 .../xbmc-602-add_as.xml_busy_dialog_delay_control.patch | 0 ...xbmc-990.15-depends-mark_our_wrapped_functions_as_used.patch | 0 .../{a1265f1 => e565394}/xbmc-995.01-xvba_support-4b0d4c0.patch | 0 .../{a1265f1 => e565394}/xbmc-995.10-disable-alt-tab.patch | 0 .../{a1265f1 => e565394}/xbmc-999.01-automake-1.13.patch | 0 10 files changed, 2 insertions(+), 2 deletions(-) rename packages/mediacenter/xbmc/patches/{a1265f1 => e565394}/xbmc-321-texturepacker-hostflags-and-rework.patch (100%) rename packages/mediacenter/xbmc/patches/{a1265f1 => e565394}/xbmc-408-enable_PYTHONOPTIMIZE_with_external_Python-0.1.patch (100%) rename packages/mediacenter/xbmc/patches/{a1265f1 => e565394}/xbmc-453-add_openelec.tv_RSS_news-0.1.patch (100%) rename packages/mediacenter/xbmc/patches/{a1265f1 => e565394}/xbmc-602-add_as.xml_busy_dialog_delay_control.patch (100%) rename packages/mediacenter/xbmc/patches/{a1265f1 => e565394}/xbmc-990.15-depends-mark_our_wrapped_functions_as_used.patch (100%) rename packages/mediacenter/xbmc/patches/{a1265f1 => e565394}/xbmc-995.01-xvba_support-4b0d4c0.patch (100%) rename packages/mediacenter/xbmc/patches/{a1265f1 => e565394}/xbmc-995.10-disable-alt-tab.patch (100%) rename packages/mediacenter/xbmc/patches/{a1265f1 => e565394}/xbmc-999.01-automake-1.13.patch (100%) diff --git a/packages/mediacenter/xbmc-theme-Confluence/meta b/packages/mediacenter/xbmc-theme-Confluence/meta index 92b89db7de..0f60c7c2e8 100644 --- a/packages/mediacenter/xbmc-theme-Confluence/meta +++ b/packages/mediacenter/xbmc-theme-Confluence/meta @@ -21,7 +21,7 @@ PKG_NAME="xbmc-theme-Confluence" PKG_VERSION="12.2.0" if [ "$XBMC" = "master" ]; then - PKG_VERSION="a1265f1" + PKG_VERSION="e565394" elif [ "$XBMC" = "xbmc-aml" ]; then PKG_VERSION="aml-frodo-d9119f2" fi diff --git a/packages/mediacenter/xbmc/meta b/packages/mediacenter/xbmc/meta index 22f6053ba7..cb256f7d84 100644 --- a/packages/mediacenter/xbmc/meta +++ b/packages/mediacenter/xbmc/meta @@ -21,7 +21,7 @@ PKG_NAME="xbmc" PKG_VERSION="12.2.0" if [ "$XBMC" = "master" ]; then - PKG_VERSION="a1265f1" + PKG_VERSION="e565394" elif [ "$XBMC" = "xbmc-aml" ]; then PKG_VERSION="aml-frodo-d9119f2" fi diff --git a/packages/mediacenter/xbmc/patches/a1265f1/xbmc-321-texturepacker-hostflags-and-rework.patch b/packages/mediacenter/xbmc/patches/e565394/xbmc-321-texturepacker-hostflags-and-rework.patch similarity index 100% rename from packages/mediacenter/xbmc/patches/a1265f1/xbmc-321-texturepacker-hostflags-and-rework.patch rename to packages/mediacenter/xbmc/patches/e565394/xbmc-321-texturepacker-hostflags-and-rework.patch diff --git a/packages/mediacenter/xbmc/patches/a1265f1/xbmc-408-enable_PYTHONOPTIMIZE_with_external_Python-0.1.patch b/packages/mediacenter/xbmc/patches/e565394/xbmc-408-enable_PYTHONOPTIMIZE_with_external_Python-0.1.patch similarity index 100% rename from packages/mediacenter/xbmc/patches/a1265f1/xbmc-408-enable_PYTHONOPTIMIZE_with_external_Python-0.1.patch rename to packages/mediacenter/xbmc/patches/e565394/xbmc-408-enable_PYTHONOPTIMIZE_with_external_Python-0.1.patch diff --git a/packages/mediacenter/xbmc/patches/a1265f1/xbmc-453-add_openelec.tv_RSS_news-0.1.patch b/packages/mediacenter/xbmc/patches/e565394/xbmc-453-add_openelec.tv_RSS_news-0.1.patch similarity index 100% rename from packages/mediacenter/xbmc/patches/a1265f1/xbmc-453-add_openelec.tv_RSS_news-0.1.patch rename to packages/mediacenter/xbmc/patches/e565394/xbmc-453-add_openelec.tv_RSS_news-0.1.patch diff --git a/packages/mediacenter/xbmc/patches/a1265f1/xbmc-602-add_as.xml_busy_dialog_delay_control.patch b/packages/mediacenter/xbmc/patches/e565394/xbmc-602-add_as.xml_busy_dialog_delay_control.patch similarity index 100% rename from packages/mediacenter/xbmc/patches/a1265f1/xbmc-602-add_as.xml_busy_dialog_delay_control.patch rename to packages/mediacenter/xbmc/patches/e565394/xbmc-602-add_as.xml_busy_dialog_delay_control.patch diff --git a/packages/mediacenter/xbmc/patches/a1265f1/xbmc-990.15-depends-mark_our_wrapped_functions_as_used.patch b/packages/mediacenter/xbmc/patches/e565394/xbmc-990.15-depends-mark_our_wrapped_functions_as_used.patch similarity index 100% rename from packages/mediacenter/xbmc/patches/a1265f1/xbmc-990.15-depends-mark_our_wrapped_functions_as_used.patch rename to packages/mediacenter/xbmc/patches/e565394/xbmc-990.15-depends-mark_our_wrapped_functions_as_used.patch diff --git a/packages/mediacenter/xbmc/patches/a1265f1/xbmc-995.01-xvba_support-4b0d4c0.patch b/packages/mediacenter/xbmc/patches/e565394/xbmc-995.01-xvba_support-4b0d4c0.patch similarity index 100% rename from packages/mediacenter/xbmc/patches/a1265f1/xbmc-995.01-xvba_support-4b0d4c0.patch rename to packages/mediacenter/xbmc/patches/e565394/xbmc-995.01-xvba_support-4b0d4c0.patch diff --git a/packages/mediacenter/xbmc/patches/a1265f1/xbmc-995.10-disable-alt-tab.patch b/packages/mediacenter/xbmc/patches/e565394/xbmc-995.10-disable-alt-tab.patch similarity index 100% rename from packages/mediacenter/xbmc/patches/a1265f1/xbmc-995.10-disable-alt-tab.patch rename to packages/mediacenter/xbmc/patches/e565394/xbmc-995.10-disable-alt-tab.patch diff --git a/packages/mediacenter/xbmc/patches/a1265f1/xbmc-999.01-automake-1.13.patch b/packages/mediacenter/xbmc/patches/e565394/xbmc-999.01-automake-1.13.patch similarity index 100% rename from packages/mediacenter/xbmc/patches/a1265f1/xbmc-999.01-automake-1.13.patch rename to packages/mediacenter/xbmc/patches/e565394/xbmc-999.01-automake-1.13.patch From b4b05f82a03a51ff560f324edbe63091f6a1c0a6 Mon Sep 17 00:00:00 2001 From: Stefan Saraev Date: Sun, 14 Jul 2013 20:56:04 +0300 Subject: [PATCH 3/5] sync unofficial --- packages/unofficial | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/unofficial b/packages/unofficial index d251ddd5d6..464a7aa0fc 160000 --- a/packages/unofficial +++ b/packages/unofficial @@ -1 +1 @@ -Subproject commit d251ddd5d62edbf8dc5e7313b1e762fdb4cc73b7 +Subproject commit 464a7aa0fc2b6c12042c2f302029d0bba1807f8f From 1a5ff2007a53212e2ea343203431205cef0059a7 Mon Sep 17 00:00:00 2001 From: Stefan Saraev Date: Sun, 14 Jul 2013 21:17:56 +0300 Subject: [PATCH 4/5] libXcursor: fix build depends closes #1629 --- packages/3rdparty/x11/lib/libXcursor/meta | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/3rdparty/x11/lib/libXcursor/meta b/packages/3rdparty/x11/lib/libXcursor/meta index fab6331a2e..121d2ce199 100644 --- a/packages/3rdparty/x11/lib/libXcursor/meta +++ b/packages/3rdparty/x11/lib/libXcursor/meta @@ -26,7 +26,7 @@ PKG_LICENSE="OSS" PKG_SITE="http://www.X.org" PKG_URL="http://xorg.freedesktop.org/archive/individual/lib/$PKG_NAME-$PKG_VERSION.tar.bz2" PKG_DEPENDS="libXfixes libXrender libX11" -PKG_BUILD_DEPENDS="toolchain" +PKG_BUILD_DEPENDS="toolchain libX11 libXfixes libXrender" PKG_PRIORITY="optional" PKG_SECTION="x11/lib" PKG_SHORTDESC="libXcursor: X Cursor Library" From 8efdf18b1890050dee335299f43bbbe6a8d22802 Mon Sep 17 00:00:00 2001 From: Stephan Raue Date: Sun, 14 Jul 2013 20:46:17 +0200 Subject: [PATCH 5/5] xbmc: update XVBA/VDPAU patch Signed-off-by: Stephan Raue --- ...=> xbmc-995.01-xvba_support-a3dbeb0.patch} | 7788 +++++++++++++++-- 1 file changed, 7196 insertions(+), 592 deletions(-) rename packages/mediacenter/xbmc/patches/e565394/{xbmc-995.01-xvba_support-4b0d4c0.patch => xbmc-995.01-xvba_support-a3dbeb0.patch} (74%) diff --git a/packages/mediacenter/xbmc/patches/e565394/xbmc-995.01-xvba_support-4b0d4c0.patch b/packages/mediacenter/xbmc/patches/e565394/xbmc-995.01-xvba_support-a3dbeb0.patch similarity index 74% rename from packages/mediacenter/xbmc/patches/e565394/xbmc-995.01-xvba_support-4b0d4c0.patch rename to packages/mediacenter/xbmc/patches/e565394/xbmc-995.01-xvba_support-a3dbeb0.patch index acc5f886b5..a5f62476bb 100644 --- a/packages/mediacenter/xbmc/patches/e565394/xbmc-995.01-xvba_support-4b0d4c0.patch +++ b/packages/mediacenter/xbmc/patches/e565394/xbmc-995.01-xvba_support-a3dbeb0.patch @@ -1,7 +1,6854 @@ -From 3f425f9680eeebd5b1bca7d8466b64d84325acad Mon Sep 17 00:00:00 2001 +From 16898b6bd8f19f416c9f4765ee20858fb42ead11 Mon Sep 17 00:00:00 2001 +From: fritsch +Date: Mon, 15 Apr 2013 20:27:39 +0200 +Subject: [PATCH 001/120] AE: Start of planar format internally + +--- + xbmc/cores/AudioEngine/AEAudioFormat.h | 7 +++++++ + xbmc/cores/AudioEngine/Utils/AEUtil.cpp | 14 ++++++++++++++ + 2 files changed, 21 insertions(+) + +diff --git a/xbmc/cores/AudioEngine/AEAudioFormat.h b/xbmc/cores/AudioEngine/AEAudioFormat.h +index 369811c..64be36f 100644 +--- a/xbmc/cores/AudioEngine/AEAudioFormat.h ++++ b/xbmc/cores/AudioEngine/AEAudioFormat.h +@@ -31,26 +31,33 @@ enum AEDataFormat + AE_FMT_INVALID = -1, + + AE_FMT_U8, ++ AE_FMT_U8P, + AE_FMT_S8, + + AE_FMT_S16BE, + AE_FMT_S16LE, + AE_FMT_S16NE, ++ AE_FMT_S16NEP, + + AE_FMT_S32BE, + AE_FMT_S32LE, + AE_FMT_S32NE, ++ AE_FMT_S32NEP, + + AE_FMT_S24BE4, + AE_FMT_S24LE4, + AE_FMT_S24NE4, /* S24 in 4 bytes */ ++ AE_FMT_S24NE4P, + + AE_FMT_S24BE3, + AE_FMT_S24LE3, + AE_FMT_S24NE3, /* S24 in 3 bytes */ ++ AE_FMT_S24NE3P, + + AE_FMT_DOUBLE, ++ AE_FMT_DOUBLEP, + AE_FMT_FLOAT, ++ AE_FMT_FLOATP, + + /* Bitstream formats */ + AE_FMT_AAC, +diff --git a/xbmc/cores/AudioEngine/Utils/AEUtil.cpp b/xbmc/cores/AudioEngine/Utils/AEUtil.cpp +index 6de84dc..3322226 100644 +--- a/xbmc/cores/AudioEngine/Utils/AEUtil.cpp ++++ b/xbmc/cores/AudioEngine/Utils/AEUtil.cpp +@@ -82,26 +82,33 @@ const unsigned int CAEUtil::DataFormatToBits(const enum AEDataFormat dataFormat) + static const unsigned int formats[AE_FMT_MAX] = + { + 8, /* U8 */ ++ 8, /* U8P */ + 8, /* S8 */ + + 16, /* S16BE */ + 16, /* S16LE */ + 16, /* S16NE */ ++ 16, /* S16NEP */ + + 32, /* S32BE */ + 32, /* S32LE */ + 32, /* S32NE */ ++ 32, /* S32NEP */ + + 32, /* S24BE */ + 32, /* S24LE */ + 32, /* S24NE */ ++ 32, /* S24NEP */ + + 24, /* S24BE3 */ + 24, /* S24LE3 */ + 24, /* S24NE3 */ ++ 24, /* S24NE3P*/ + + sizeof(double) << 3, /* DOUBLE */ ++ sizeof(double) << 3, /* DOUBLEP */ + sizeof(float ) << 3, /* FLOAT */ ++ sizeof(float ) << 3, /* FLOATP */ + + 16, /* AAC */ + 16, /* AC3 */ +@@ -123,26 +130,33 @@ const char* CAEUtil::DataFormatToStr(const enum AEDataFormat dataFormat) + static const char *formats[AE_FMT_MAX] = + { + "AE_FMT_U8", ++ "AE_FMT_U8P", + "AE_FMT_S8", + + "AE_FMT_S16BE", + "AE_FMT_S16LE", + "AE_FMT_S16NE", ++ "AE_FMT_S16NEP", + + "AE_FMT_S32BE", + "AE_FMT_S32LE", + "AE_FMT_S32NE", ++ "AE_FMT_S32NEP", + + "AE_FMT_S24BE4", + "AE_FMT_S24LE4", + "AE_FMT_S24NE4", /* S24 in 4 bytes */ ++ "AE_FMT_S24NE4P", + + "AE_FMT_S24BE3", + "AE_FMT_S24LE3", + "AE_FMT_S24NE3", /* S24 in 3 bytes */ ++ "AE_FMT_S24NE3P", + + "AE_FMT_DOUBLE", ++ "AE_FMT_DOUBLEP", + "AE_FMT_FLOAT", ++ "AE_FMT_FLOATP", + + /* for passthrough streams and the like */ + "AE_FMT_AAC", +-- +1.8.1.6 + + +From 7be39700ca76a23e1f51315a77e4fba5dfdfbc39 Mon Sep 17 00:00:00 2001 +From: Rainer Hochecker +Date: Fri, 31 May 2013 16:28:30 +0200 +Subject: [PATCH 002/120] AE: register callback for all audio settings + +--- + xbmc/settings/Settings.cpp | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/xbmc/settings/Settings.cpp b/xbmc/settings/Settings.cpp +index 65e685a..ee97753 100644 +--- a/xbmc/settings/Settings.cpp ++++ b/xbmc/settings/Settings.cpp +@@ -840,8 +840,18 @@ void CSettings::InitializeISettingCallbacks() + m_settingsManager->RegisterCallback(&CDisplaySettings::Get(), settingSet); + + settingSet.clear(); ++ settingSet.insert("audiooutput.mode"); + settingSet.insert("audiooutput.channels"); + settingSet.insert("audiooutput.guisoundmode"); ++ settingSet.insert("audiooutput.stereoupmix"); ++ settingSet.insert("audiooutput.ac3passthrough"); ++ settingSet.insert("audiooutput.dtspassthrough"); ++ settingSet.insert("audiooutput.passthroughaac"); ++ settingSet.insert("audiooutput.truehdpassthrough"); ++ settingSet.insert("audiooutput.dtshdpassthrough"); ++ settingSet.insert("audiooutput.multichannellpcm"); ++ settingSet.insert("audiooutput.audiodevice"); ++ settingSet.insert("audiooutput.passthroughdevice"); + settingSet.insert("lookandfeel.skin"); + settingSet.insert("lookandfeel.skinsettings"); + settingSet.insert("lookandfeel.font"); +-- +1.8.1.6 + + +From df0408008af793f9e726707e396b4c8d48f8038a Mon Sep 17 00:00:00 2001 +From: fritsch +Date: Sat, 8 Jun 2013 09:45:48 +0200 +Subject: [PATCH 003/120] AE: Make sure to reinit and to avoid races cause of + sleeping + +--- + xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp +index 9d3cefa..ef7637f 100644 +--- a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp ++++ b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp +@@ -1150,16 +1150,13 @@ bool CAESinkALSA::SoftSuspend() + bool CAESinkALSA::SoftResume() + { + // reinit all the clibber +- bool ret = true; // all fine + if(!m_pcm) + { + if (!snd_config) + snd_config_update(); +- +- ret = Initialize(m_initFormat, m_initDevice); + } +- //we want that AE loves us again - reinit when initialize failed +- return ret; // force reinit if false ++ // make sure that OpenInternalSink is done again ++ return false; + } + + void CAESinkALSA::sndLibErrorHandler(const char *file, int line, const char *function, int err, const char *fmt, ...) +-- +1.8.1.6 + + +From 4f5f3db325d1eb38d5b9e37ffeed0c30456141a4 Mon Sep 17 00:00:00 2001 +From: Rainer Hochecker +Date: Thu, 23 May 2013 10:05:11 +0200 +Subject: [PATCH 004/120] AESinkALSA: drop unneeded member + +--- + xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp | 11 ++++++----- + xbmc/cores/AudioEngine/Sinks/AESinkALSA.h | 1 - + 2 files changed, 6 insertions(+), 6 deletions(-) + +diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp +index ef7637f..474c7cc 100644 +--- a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp ++++ b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp +@@ -131,19 +131,20 @@ void CAESinkALSA::GetAESParams(AEAudioFormat format, std::string& params) + + bool CAESinkALSA::Initialize(AEAudioFormat &format, std::string &device) + { ++ CAEChannelInfo channelLayout; + m_initDevice = device; + m_initFormat = format; + + /* if we are raw, correct the data format */ + if (AE_IS_RAW(format.m_dataFormat)) + { +- m_channelLayout = GetChannelLayout(format); ++ channelLayout = GetChannelLayout(format); + format.m_dataFormat = AE_FMT_S16NE; + m_passthrough = true; + } + else + { +- m_channelLayout = GetChannelLayout(format); ++ channelLayout = GetChannelLayout(format); + m_passthrough = false; + } + #if defined(HAS_AMLPLAYER) || defined(HAS_LIBAMCODEC) +@@ -154,13 +155,13 @@ bool CAESinkALSA::Initialize(AEAudioFormat &format, std::string &device) + } + #endif + +- if (m_channelLayout.Count() == 0) ++ if (channelLayout.Count() == 0) + { + CLog::Log(LOGERROR, "CAESinkALSA::Initialize - Unable to open the requested channel layout"); + return false; + } + +- format.m_channelLayout = m_channelLayout; ++ format.m_channelLayout = channelLayout; + + AEDeviceType devType = AEDeviceTypeFromName(device); + +@@ -176,7 +177,7 @@ bool CAESinkALSA::Initialize(AEAudioFormat &format, std::string &device) + snd_config_t *config; + snd_config_copy(&config, snd_config); + +- if (!OpenPCMDevice(device, AESParams, m_channelLayout.Count(), &m_pcm, config)) ++ if (!OpenPCMDevice(device, AESParams, channelLayout.Count(), &m_pcm, config)) + { + CLog::Log(LOGERROR, "CAESinkALSA::Initialize - failed to initialize device \"%s\"", device.c_str()); + snd_config_delete(config); +diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.h b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.h +index e2b4e4f..73615a5 100644 +--- a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.h ++++ b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.h +@@ -64,7 +64,6 @@ class CAESinkALSA : public IAESink + unsigned int m_bufferSize; + double m_formatSampleRateMul; + bool m_passthrough; +- CAEChannelInfo m_channelLayout; + std::string m_device; + snd_pcm_t *m_pcm; + int m_timeout; +-- +1.8.1.6 + + +From a53de587ce8a071c252c394f5131a422daa76496 Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Sat, 27 Apr 2013 10:47:01 +0200 +Subject: [PATCH 005/120] ffmpeg: add methods to the interface needed for + resampling + +--- + lib/DllAvUtil.h | 14 ++++++++++++++ + lib/DllSwResample.h | 15 +++++++++++++++ + 2 files changed, 29 insertions(+) + +diff --git a/lib/DllAvUtil.h b/lib/DllAvUtil.h +index 1afee5e..bbe9be2 100644 +--- a/lib/DllAvUtil.h ++++ b/lib/DllAvUtil.h +@@ -95,6 +95,9 @@ class DllAvUtilInterface + virtual void av_dict_free(AVDictionary **pm) = 0; + virtual int av_samples_get_buffer_size (int *linesize, int nb_channels, int nb_samples, enum AVSampleFormat sample_fmt, int align) = 0; + virtual int64_t av_get_default_channel_layout(int nb_channels)=0; ++ virtual int av_samples_alloc(uint8_t **audio_data, int *linesize, int nb_channels, int nb_samples, enum AVSampleFormat sample_fmt, int align) = 0; ++ virtual int av_sample_fmt_is_planar(enum AVSampleFormat sample_fmt) = 0; ++ virtual int av_get_channel_layout_channel_index (uint64_t channel_layout, uint64_t channel) = 0; + }; + + #if defined (USE_EXTERNAL_FFMPEG) || (defined TARGET_DARWIN) +@@ -133,6 +136,10 @@ class DllAvUtilBase : public DllDynamic, DllAvUtilInterface + virtual int av_samples_get_buffer_size (int *linesize, int nb_channels, int nb_samples, enum AVSampleFormat sample_fmt, int align) + { return ::av_samples_get_buffer_size(linesize, nb_channels, nb_samples, sample_fmt, align); } + virtual int64_t av_get_default_channel_layout(int nb_channels) { return ::av_get_default_channel_layout(nb_channels); } ++ virtual int av_samples_alloc(uint8_t **audio_data, int *linesize, int nb_channels, int nb_samples, enum AVSampleFormat sample_fmt, int align) ++ { return ::av_samples_alloc(audio_data, linesize, nb_channels, nb_samples, sample_fmt, align); } ++ virtual int av_sample_fmt_is_planar(enum AVSampleFormat sample_fmt) { return ::av_sample_fmt_is_planar(sample_fmt); } ++ virtual int av_get_channel_layout_channel_index (uint64_t channel_layout, uint64_t channel) { return ::av_get_channel_layout_channel_index(channel_layout, channel); } + + // DLL faking. + virtual bool ResolveExports() { return true; } +@@ -178,6 +185,9 @@ class DllAvUtilBase : public DllDynamic, DllAvUtilInterface + DEFINE_METHOD1(void, av_dict_free, (AVDictionary **p1)); + DEFINE_METHOD5(int, av_samples_get_buffer_size, (int *p1, int p2, int p3, enum AVSampleFormat p4, int p5)) + DEFINE_METHOD1(int64_t, av_get_default_channel_layout, (int p1)) ++ DEFINE_METHOD6(int, av_samples_alloc, (uint8_t **p1, int *p2, int p3, int p4, enum AVSampleFormat p5, int p6)) ++ DEFINE_METHOD1(int, av_sample_fmt_is_planar, (enum AVSampleFormat p1)) ++ DEFINE_METHOD2(int, av_get_channel_layout_channel_index, (uint64_t p1, uint64_t p2)) + + public: + BEGIN_METHOD_RESOLVE() +@@ -206,6 +216,10 @@ class DllAvUtilBase : public DllDynamic, DllAvUtilInterface + RESOLVE_METHOD(av_dict_free) + RESOLVE_METHOD(av_samples_get_buffer_size) + RESOLVE_METHOD(av_get_default_channel_layout) ++ RESOLVE_METHOD(av_samples_alloc) ++ RESOLVE_METHOD(av_sample_fmt_is_planar) ++ RESOLVE_METHOD(av_get_channel_layout_channel_index) ++ + END_METHOD_RESOLVE() + }; + +diff --git a/lib/DllSwResample.h b/lib/DllSwResample.h +index e9613d3..320b3a7 100644 +--- a/lib/DllSwResample.h ++++ b/lib/DllSwResample.h +@@ -60,6 +60,9 @@ class DllSwResampleInterface + virtual int swr_init(struct SwrContext *s)=0; + virtual void swr_free(struct SwrContext **s)=0; + virtual int swr_convert(struct SwrContext *s, uint8_t **out, int out_count, const uint8_t **in , int in_count)=0; ++ virtual int64_t swr_get_delay(struct SwrContext *s, int64_t base) = 0; ++ virtual int swr_set_channel_mapping(struct SwrContext *s, const int *channel_map) = 0; ++ virtual int swr_set_matrix(struct SwrContext *s, const double *matrix, int stride) = 0; + }; + + #if (defined USE_EXTERNAL_FFMPEG) || (defined TARGET_DARWIN) +@@ -84,6 +87,9 @@ class DllSwResample : public DllDynamic, DllSwResampleInterface + virtual int swr_init(struct SwrContext *s) { return ::swr_init(s); } + virtual void swr_free(struct SwrContext **s){ return ::swr_free(s); } + virtual int swr_convert(struct SwrContext *s, uint8_t **out, int out_count, const uint8_t **in , int in_count){ return ::swr_convert(s, out, out_count, in, in_count); } ++ virtual int64_t swr_get_delay(struct SwrContext *s, int64_t base) { return ::swr_get_delay(s, base); } ++ virtual int swr_set_channel_mapping (struct SwrContext *s, const int *channel_map) { return ::swr_set_channel_mapping(s, channel_map); } ++ virtual int swr_set_matrix(struct SwrContext *s, const double *matrix, int stride) { return ::swr_set_matrix(s, matrix, stride); } + }; + #else + // Wrap the same API through libavresample. +@@ -114,6 +120,9 @@ class DllSwResample : public DllDynamic, DllSwResampleInterface + virtual int swr_init(struct SwrContext *s) { return ::avresample_open(s); } + virtual void swr_free(struct SwrContext **s){ ::avresample_close(*s); *s = NULL; } + virtual int swr_convert(struct SwrContext *s, uint8_t **out, int out_count, const uint8_t **in , int in_count){ return ::avresample_convert(s, out, 0, out_count, (uint8_t**)in, 0,in_count); } ++ virtual int64_t swr_get_delay(struct SwrContext *s, int64_t base){return ::swr_get_delay(s, base);} ++ virtual int swr_set_channel_mapping (struct SwrContext *s, const int *channel_map){return ::swr_set_channel_mapping(s, channel_map);} ++ virtual int swr_set_matrix(struct SwrContext *s, const double *matrix, int stride) { return ::swr_set_matrix(s, matrix, stride);} + }; + #endif + +@@ -129,12 +138,18 @@ class DllSwResample : public DllDynamic, DllSwResampleInterface + DEFINE_METHOD1(int, swr_init, (struct SwrContext *p1)) + DEFINE_METHOD1(void, swr_free, (struct SwrContext **p1)) + DEFINE_METHOD5(int, swr_convert, (struct SwrContext *p1, uint8_t **p2, int p3, const uint8_t **p4, int p5)) ++ DEFINE_METHOD2(int64_t, swr_get_delay, (struct SwrContext *p1, int64_t p2)) ++ DEFINE_METHOD2(int, swr_set_channel_mapping, (struct SwrContext *p1, const int *p2)) ++ DEFINE_METHOD3(int, swr_set_matrix, (struct SwrContext *p1, const double *p2, int p3)) + + BEGIN_METHOD_RESOLVE() + RESOLVE_METHOD(swr_alloc_set_opts) + RESOLVE_METHOD(swr_init) + RESOLVE_METHOD(swr_free) + RESOLVE_METHOD(swr_convert) ++ RESOLVE_METHOD(swr_get_delay) ++ RESOLVE_METHOD(swr_set_channel_mapping) ++ RESOLVE_METHOD(swr_set_matrix) + END_METHOD_RESOLVE() + + /* dependencies of libavformat */ +-- +1.8.1.6 + + +From be01097993a127b5fcb1cdcd60ff34768dcc9136 Mon Sep 17 00:00:00 2001 +From: Rainer Hochecker +Date: Wed, 26 Jun 2013 15:12:28 +0200 +Subject: [PATCH 006/120] AE: allow encoder to be fed with planar format + +--- + .../cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp | 66 +++++++++++++++++++++- + xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.h | 3 +- + xbmc/cores/AudioEngine/Interfaces/AEEncoder.h | 13 ++++- + 3 files changed, 78 insertions(+), 4 deletions(-) + +diff --git a/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp b/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp +index 99d9a47..36bae54 100644 +--- a/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp ++++ b/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.cpp +@@ -98,7 +98,7 @@ unsigned int CAEEncoderFFmpeg::BuildChannelLayout(const int64_t ffmap, CAEChanne + return layout.Count(); + } + +-bool CAEEncoderFFmpeg::Initialize(AEAudioFormat &format) ++bool CAEEncoderFFmpeg::Initialize(AEAudioFormat &format, bool allow_planar_input) + { + Reset(); + +@@ -150,6 +150,7 @@ bool CAEEncoderFFmpeg::Initialize(AEAudioFormat &format) + bool hasS32 = false; + bool hasS16 = false; + bool hasU8 = false; ++ bool hasFloatP = false; + bool hasUnknownFormat = false; + + for(int i = 0; codec->sample_fmts[i] != AV_SAMPLE_FMT_NONE; ++i) +@@ -161,6 +162,12 @@ bool CAEEncoderFFmpeg::Initialize(AEAudioFormat &format) + case AV_SAMPLE_FMT_S32: hasS32 = true; break; + case AV_SAMPLE_FMT_S16: hasS16 = true; break; + case AV_SAMPLE_FMT_U8 : hasU8 = true; break; ++ case AV_SAMPLE_FMT_FLTP: ++ if (allow_planar_input) ++ hasFloatP = true; ++ else ++ hasUnknownFormat = true; ++ break; + case AV_SAMPLE_FMT_NONE: return false; + default: hasUnknownFormat = true; break; + } +@@ -171,6 +178,11 @@ bool CAEEncoderFFmpeg::Initialize(AEAudioFormat &format) + m_CodecCtx->sample_fmt = AV_SAMPLE_FMT_FLT; + format.m_dataFormat = AE_FMT_FLOAT; + } ++ else if (hasFloatP) ++ { ++ m_CodecCtx->sample_fmt = AV_SAMPLE_FMT_FLTP; ++ format.m_dataFormat = AE_FMT_FLOATP; ++ } + else if (hasDouble) + { + m_CodecCtx->sample_fmt = AV_SAMPLE_FMT_DBL; +@@ -214,7 +226,6 @@ bool CAEEncoderFFmpeg::Initialize(AEAudioFormat &format) + return false; + } + +- format.m_dataFormat = AE_FMT_FLOAT; + format.m_frames = m_CodecCtx->frame_size; + format.m_frameSamples = m_CodecCtx->frame_size * m_CodecCtx->channels; + format.m_frameSize = m_CodecCtx->channels * (CAEUtil::DataFormatToBits(format.m_dataFormat) >> 3); +@@ -351,6 +362,57 @@ int CAEEncoderFFmpeg::Encode(float *data, unsigned int frames) + return m_NeededFrames; + } + ++int CAEEncoderFFmpeg::Encode(uint8_t *in, int in_size, uint8_t *out, int out_size) ++{ ++ int got_output; ++ AVFrame *frame; ++ ++ if (!m_CodecCtx) ++ return 0; ++ ++ /* allocate the input frame ++ * sadly, we have to alloc/dealloc it everytime since we have no guarantee the ++ * data argument will be constant over iterated calls and the frame needs to ++ * setup pointers inside data */ ++ frame = m_dllAvCodec.avcodec_alloc_frame(); ++ if (!frame) ++ return 0; ++ ++ frame->nb_samples = m_CodecCtx->frame_size; ++ frame->format = m_CodecCtx->sample_fmt; ++ frame->channel_layout = m_CodecCtx->channel_layout; ++ ++ m_dllAvCodec.avcodec_fill_audio_frame(frame, m_CodecCtx->channels, m_CodecCtx->sample_fmt, ++ in, in_size, 0); ++ ++ /* initialize the output packet */ ++ m_dllAvCodec.av_init_packet(&m_Pkt); ++ m_Pkt.size = out_size - IEC61937_DATA_OFFSET; ++ m_Pkt.data = out + IEC61937_DATA_OFFSET; ++ ++ /* encode it */ ++ int ret = m_dllAvCodec.avcodec_encode_audio2(m_CodecCtx, &m_Pkt, frame, &got_output); ++ ++ /* free temporary data */ ++ m_dllAvCodec.avcodec_free_frame(&frame); ++ ++ if (ret < 0 || !got_output) ++ { ++ CLog::Log(LOGERROR, "CAEEncoderFFmpeg::Encode - Encoding failed"); ++ return 0; ++ } ++ ++ /* pack it into an IEC958 frame */ ++ m_PackFunc(NULL, m_Pkt.size, out); ++ ++ /* free the packet */ ++ m_dllAvCodec.av_free_packet(&m_Pkt); ++ ++ /* return the number of frames used */ ++ return m_NeededFrames; ++} ++ ++ + int CAEEncoderFFmpeg::GetData(uint8_t **data) + { + int size; +diff --git a/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.h b/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.h +index d422ab6..2d442df 100644 +--- a/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.h ++++ b/xbmc/cores/AudioEngine/Encoders/AEEncoderFFmpeg.h +@@ -36,7 +36,7 @@ class CAEEncoderFFmpeg: public IAEEncoder + virtual ~CAEEncoderFFmpeg(); + + virtual bool IsCompatible(AEAudioFormat format); +- virtual bool Initialize(AEAudioFormat &format); ++ virtual bool Initialize(AEAudioFormat &format, bool allow_planar_input = false); + virtual void Reset(); + + virtual unsigned int GetBitRate (); +@@ -44,6 +44,7 @@ class CAEEncoderFFmpeg: public IAEEncoder + virtual unsigned int GetFrames (); + + virtual int Encode (float *data, unsigned int frames); ++ virtual int Encode (uint8_t *in, int in_size, uint8_t *out, int out_size); + virtual int GetData(uint8_t **data); + virtual double GetDelay(unsigned int bufferSize); + private: +diff --git a/xbmc/cores/AudioEngine/Interfaces/AEEncoder.h b/xbmc/cores/AudioEngine/Interfaces/AEEncoder.h +index e304908..0e6f1f8 100644 +--- a/xbmc/cores/AudioEngine/Interfaces/AEEncoder.h ++++ b/xbmc/cores/AudioEngine/Interfaces/AEEncoder.h +@@ -48,9 +48,10 @@ class IAEEncoder + /** + * Called to setup the encoder to accept data in the specified format + * @param format the desired audio format, may be changed to suit the encoder ++ * @param allow_planar_input allow engine to use with planar formats + * @return true on success, false on failure + */ +- virtual bool Initialize(AEAudioFormat &format) = 0; ++ virtual bool Initialize(AEAudioFormat &format, bool allow_planar_input = false) = 0; + + /** + * Reset the encoder for new data +@@ -84,6 +85,16 @@ class IAEEncoder + virtual int Encode(float *data, unsigned int frames) = 0; + + /** ++ * Encodes the supplied samples into a provided buffer ++ * @param in the PCM samples encoder requested format ++ * @param in_size input buffer size ++ * @param output buffer ++ * @param out_size output buffer size ++ * @return the number of samples consumed ++ */ ++ virtual int Encode (uint8_t *in, int in_size, uint8_t *out, int out_size) { return 0; }; ++ ++ /** + * Get the encoded data + * @param data return pointer to the buffer with the current encoded block + * @return the size in bytes of *data +-- +1.8.1.6 + + +From 6c7828f08a31febb7dff6d301b16d99b523197de Mon Sep 17 00:00:00 2001 +From: Rainer Hochecker +Date: Wed, 26 Jun 2013 15:13:22 +0200 +Subject: [PATCH 007/120] AE: alsa - close device in blocking mode, fixes + device busy + +--- + xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp +index 474c7cc..dbff176 100644 +--- a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp ++++ b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp +@@ -196,8 +196,8 @@ bool CAESinkALSA::Initialize(AEAudioFormat &format, std::string &device) + if (!InitializeHW(format) || !InitializeSW(format)) + return false; + +- snd_pcm_nonblock(m_pcm, 1); + snd_pcm_prepare (m_pcm); ++ snd_pcm_nonblock(m_pcm, 1); + + m_format = format; + m_formatSampleRateMul = 1.0 / (double)m_format.m_sampleRate; +@@ -436,10 +436,10 @@ bool CAESinkALSA::InitializeSW(AEAudioFormat &format) + + void CAESinkALSA::Deinitialize() + { +- Stop(); +- + if (m_pcm) + { ++ snd_pcm_nonblock(m_pcm, 0); ++ Stop(); + snd_pcm_close(m_pcm); + m_pcm = NULL; + } +-- +1.8.1.6 + + +From cacc59128514fe159ca6aed6049beaba45dadca3 Mon Sep 17 00:00:00 2001 +From: Rainer Hochecker +Date: Wed, 26 Jun 2013 18:48:30 +0200 +Subject: [PATCH 008/120] AE: alsa - set to prepared after drain + +--- + xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp +index dbff176..3497aef 100644 +--- a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp ++++ b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp +@@ -196,8 +196,8 @@ bool CAESinkALSA::Initialize(AEAudioFormat &format, std::string &device) + if (!InitializeHW(format) || !InitializeSW(format)) + return false; + +- snd_pcm_prepare (m_pcm); + snd_pcm_nonblock(m_pcm, 1); ++ snd_pcm_prepare (m_pcm); + + m_format = format; + m_formatSampleRateMul = 1.0 / (double)m_format.m_sampleRate; +@@ -574,6 +574,7 @@ void CAESinkALSA::Drain() + + snd_pcm_nonblock(m_pcm, 0); + snd_pcm_drain(m_pcm); ++ snd_pcm_prepare(m_pcm); + snd_pcm_nonblock(m_pcm, 1); + } + +-- +1.8.1.6 + + +From 6a745e90665ff9a654c64792406d23a46eacad8a Mon Sep 17 00:00:00 2001 +From: fritsch +Date: Fri, 5 Jul 2013 21:02:00 +0200 +Subject: [PATCH 009/120] AE: Add blocking option to AddPackets, makes Sink + behaviour choosable after c2493d5bf6bc2be2fb45f563affdd214bf9862fb + +--- + xbmc/cores/AudioEngine/Interfaces/AESink.h | 2 +- + xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp | 11 +++++++++-- + xbmc/cores/AudioEngine/Sinks/AESinkALSA.h | 2 +- + xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.cpp | 2 +- + xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.h | 2 +- + xbmc/cores/AudioEngine/Sinks/AESinkDirectSound.cpp | 4 ++-- + xbmc/cores/AudioEngine/Sinks/AESinkDirectSound.h | 2 +- + xbmc/cores/AudioEngine/Sinks/AESinkNULL.cpp | 2 +- + xbmc/cores/AudioEngine/Sinks/AESinkNULL.h | 2 +- + xbmc/cores/AudioEngine/Sinks/AESinkOSS.cpp | 2 +- + xbmc/cores/AudioEngine/Sinks/AESinkOSS.h | 2 +- + xbmc/cores/AudioEngine/Sinks/AESinkProfiler.cpp | 2 +- + xbmc/cores/AudioEngine/Sinks/AESinkProfiler.h | 2 +- + xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp | 2 +- + xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.h | 2 +- + 15 files changed, 24 insertions(+), 17 deletions(-) + +diff --git a/xbmc/cores/AudioEngine/Interfaces/AESink.h b/xbmc/cores/AudioEngine/Interfaces/AESink.h +index cb9c04b..65395bf 100644 +--- a/xbmc/cores/AudioEngine/Interfaces/AESink.h ++++ b/xbmc/cores/AudioEngine/Interfaces/AESink.h +@@ -71,7 +71,7 @@ class IAESink + /* + Adds packets to be sent out, this routine MUST block or sleep. + */ +- virtual unsigned int AddPackets(uint8_t *data, unsigned int frames, bool hasAudio) = 0; ++ virtual unsigned int AddPackets(uint8_t *data, unsigned int frames, bool hasAudio, bool blocking = false) = 0; + + /* + Drain the sink +diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp +index 3497aef..bfa1351 100644 +--- a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp ++++ b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp +@@ -497,7 +497,7 @@ double CAESinkALSA::GetCacheTotal() + return (double)m_bufferSize * m_formatSampleRateMul; + } + +-unsigned int CAESinkALSA::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio) ++unsigned int CAESinkALSA::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio, bool blocking) + { + if (!m_pcm) + { +@@ -518,7 +518,14 @@ unsigned int CAESinkALSA::AddPackets(uint8_t *data, unsigned int frames, bool ha + } + + if ((unsigned int)ret < frames) +- return 0; ++ if(blocking) ++ { ++ ret = snd_pcm_wait(m_pcm, m_timeout); ++ if (ret < 0) ++ HandleError("snd_pcm_wait", ret); ++ } ++ else ++ return 0; + + ret = snd_pcm_writei(m_pcm, (void*)data, frames); + if (ret < 0) +diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.h b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.h +index 73615a5..69c8a85 100644 +--- a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.h ++++ b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.h +@@ -47,7 +47,7 @@ class CAESinkALSA : public IAESink + virtual double GetDelay (); + virtual double GetCacheTime (); + virtual double GetCacheTotal (); +- virtual unsigned int AddPackets (uint8_t *data, unsigned int frames, bool hasAudio); ++ virtual unsigned int AddPackets (uint8_t *data, unsigned int frames, bool hasAudio, bool blocking = false); + virtual void Drain (); + virtual bool SoftSuspend(); + virtual bool SoftResume(); +diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.cpp +index c37bf2d..66e4c6a 100644 +--- a/xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.cpp ++++ b/xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.cpp +@@ -212,7 +212,7 @@ double CAESinkAUDIOTRACK::GetCacheTotal() + return m_sinkbuffer_sec + m_audiotrackbuffer_sec; + } + +-unsigned int CAESinkAUDIOTRACK::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio) ++unsigned int CAESinkAUDIOTRACK::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio, bool blocking) + { + // write as many frames of audio as we can fit into our internal buffer. + +diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.h b/xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.h +index d07ab8d..e923cd6 100644 +--- a/xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.h ++++ b/xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.h +@@ -39,7 +39,7 @@ class CAESinkAUDIOTRACK : public CThread, public IAESink + virtual double GetDelay (); + virtual double GetCacheTime (); + virtual double GetCacheTotal (); +- virtual unsigned int AddPackets (uint8_t *data, unsigned int frames, bool hasAudio); ++ virtual unsigned int AddPackets (uint8_t *data, unsigned int frames, bool hasAudio, bool blocking = false); + virtual void Drain (); + virtual bool HasVolume (); + virtual void SetVolume (float scale); +diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkDirectSound.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkDirectSound.cpp +index e3a3695..8df9cab 100644 +--- a/xbmc/cores/AudioEngine/Sinks/AESinkDirectSound.cpp ++++ b/xbmc/cores/AudioEngine/Sinks/AESinkDirectSound.cpp +@@ -367,7 +367,7 @@ bool CAESinkDirectSound::IsCompatible(const AEAudioFormat format, const std::str + return false; + } + +-unsigned int CAESinkDirectSound::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio) ++unsigned int CAESinkDirectSound::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio, bool blocking = false) + { + if (!m_initialized) + return 0; +@@ -910,4 +910,4 @@ bool CAESinkDirectSound::SoftResume() + { + /* Return false to force re-init by engine */ + return false; +-} +\ No newline at end of file ++} +diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkDirectSound.h b/xbmc/cores/AudioEngine/Sinks/AESinkDirectSound.h +index 944e598..f06e929 100644 +--- a/xbmc/cores/AudioEngine/Sinks/AESinkDirectSound.h ++++ b/xbmc/cores/AudioEngine/Sinks/AESinkDirectSound.h +@@ -42,7 +42,7 @@ class CAESinkDirectSound : public IAESink + virtual double GetDelay (); + virtual double GetCacheTime (); + virtual double GetCacheTotal (); +- virtual unsigned int AddPackets (uint8_t *data, unsigned int frames, bool hasAudio); ++ virtual unsigned int AddPackets (uint8_t *data, unsigned int frames, bool hasAudio, bool blocking = false); + virtual bool SoftSuspend (); + virtual bool SoftResume (); + static std::string GetDefaultDevice (); +diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkNULL.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkNULL.cpp +index 9f980f8..28cadcc 100644 +--- a/xbmc/cores/AudioEngine/Sinks/AESinkNULL.cpp ++++ b/xbmc/cores/AudioEngine/Sinks/AESinkNULL.cpp +@@ -99,7 +99,7 @@ double CAESinkNULL::GetCacheTotal() + return m_sinkbuffer_sec_per_byte * (double)m_sinkbuffer_size; + } + +-unsigned int CAESinkNULL::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio) ++unsigned int CAESinkNULL::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio, bool blocking) + { + unsigned int max_frames = (m_sinkbuffer_size - m_sinkbuffer_level) / m_sink_frameSize; + if (frames > max_frames) +diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkNULL.h b/xbmc/cores/AudioEngine/Sinks/AESinkNULL.h +index 47bf18f..09e49f0 100644 +--- a/xbmc/cores/AudioEngine/Sinks/AESinkNULL.h ++++ b/xbmc/cores/AudioEngine/Sinks/AESinkNULL.h +@@ -38,7 +38,7 @@ class CAESinkNULL : public CThread, public IAESink + virtual double GetDelay (); + virtual double GetCacheTime (); + virtual double GetCacheTotal (); +- virtual unsigned int AddPackets (uint8_t *data, unsigned int frames, bool hasAudio); ++ virtual unsigned int AddPackets (uint8_t *data, unsigned int frames, bool hasAudio, bool blocking = false); + virtual void Drain (); + + static void EnumerateDevices(AEDeviceList &devices, bool passthrough); +diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkOSS.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkOSS.cpp +index 00f57d0..97d1725 100644 +--- a/xbmc/cores/AudioEngine/Sinks/AESinkOSS.cpp ++++ b/xbmc/cores/AudioEngine/Sinks/AESinkOSS.cpp +@@ -408,7 +408,7 @@ double CAESinkOSS::GetDelay() + return (double)delay / (m_format.m_frameSize * m_format.m_sampleRate); + } + +-unsigned int CAESinkOSS::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio) ++unsigned int CAESinkOSS::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio, bool blocking) + { + int size = frames * m_format.m_frameSize; + if (m_fd == -1) +diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkOSS.h b/xbmc/cores/AudioEngine/Sinks/AESinkOSS.h +index ab1b457..18cadce 100644 +--- a/xbmc/cores/AudioEngine/Sinks/AESinkOSS.h ++++ b/xbmc/cores/AudioEngine/Sinks/AESinkOSS.h +@@ -41,7 +41,7 @@ class CAESinkOSS : public IAESink + virtual double GetDelay (); + virtual double GetCacheTime () { return 0.0; } /* FIXME */ + virtual double GetCacheTotal () { return 0.0; } /* FIXME */ +- virtual unsigned int AddPackets (uint8_t *data, unsigned int frames, bool hasAudio); ++ virtual unsigned int AddPackets (uint8_t *data, unsigned int frames, bool hasAudio, bool blocking = false); + virtual void Drain (); + static void EnumerateDevicesEx(AEDeviceInfoList &list, bool force = false); + private: +diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkProfiler.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkProfiler.cpp +index 7c01573..1cf4843 100644 +--- a/xbmc/cores/AudioEngine/Sinks/AESinkProfiler.cpp ++++ b/xbmc/cores/AudioEngine/Sinks/AESinkProfiler.cpp +@@ -71,7 +71,7 @@ double CAESinkProfiler::GetDelay() + return 0.0f; + } + +-unsigned int CAESinkProfiler::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio) ++unsigned int CAESinkProfiler::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio, bool blocking) + { + int64_t ts = CurrentHostCounter(); + CLog::Log(LOGDEBUG, "CAESinkProfiler::AddPackets - latency %f ms", (float)(ts - m_ts) / 1000000.0f); +diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkProfiler.h b/xbmc/cores/AudioEngine/Sinks/AESinkProfiler.h +index 621e0f3..814670a 100644 +--- a/xbmc/cores/AudioEngine/Sinks/AESinkProfiler.h ++++ b/xbmc/cores/AudioEngine/Sinks/AESinkProfiler.h +@@ -39,7 +39,7 @@ class CAESinkProfiler : public IAESink + virtual double GetDelay (); + virtual double GetCacheTime () { return 0.0; } + virtual double GetCacheTotal () { return 0.0; } +- virtual unsigned int AddPackets (uint8_t *data, unsigned int frames, bool hasAudio); ++ virtual unsigned int AddPackets (uint8_t *data, unsigned int frames, bool hasAudio, bool blocking = false); + virtual void Drain (); + static void EnumerateDevices(AEDeviceList &devices, bool passthrough); + private: +diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp +index 472366d..6d6e477 100644 +--- a/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp ++++ b/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp +@@ -423,7 +423,7 @@ double CAESinkWASAPI::GetCacheTotal() + return m_sinkLatency; + } + +-unsigned int CAESinkWASAPI::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio) ++unsigned int CAESinkWASAPI::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio, bool blocking) + { + if (!m_initialized) + return 0; +diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.h b/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.h +index 312866c..c88dd91 100644 +--- a/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.h ++++ b/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.h +@@ -42,7 +42,7 @@ class CAESinkWASAPI : public IAESink + virtual double GetDelay (); + virtual double GetCacheTime (); + virtual double GetCacheTotal (); +- virtual unsigned int AddPackets (uint8_t *data, unsigned int frames, bool hasAudio); ++ virtual unsigned int AddPackets (uint8_t *data, unsigned int frames, bool hasAudio, bool blocking = false); + virtual bool SoftSuspend (); + virtual bool SoftResume (); + static void EnumerateDevicesEx (AEDeviceInfoList &deviceInfoList, bool force = false); +-- +1.8.1.6 + + +From 6dc0c4756cedb4cb7d83a207c41fa4df0a6f3a85 Mon Sep 17 00:00:00 2001 +From: fritsch +Date: Sat, 6 Jul 2013 08:07:30 +0200 +Subject: [PATCH 010/120] AE: Give Sinks the possibility to be used in a + blocking way + +--- + xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.cpp | 5 ++++ + xbmc/cores/AudioEngine/Sinks/AESinkDirectSound.cpp | 11 +++++--- + xbmc/cores/AudioEngine/Sinks/AESinkOSS.cpp | 2 +- + xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp | 29 +++++++++++++++++++--- + 4 files changed, 40 insertions(+), 7 deletions(-) + +diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.cpp +index 66e4c6a..bd179d5 100644 +--- a/xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.cpp ++++ b/xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.cpp +@@ -243,6 +243,11 @@ unsigned int CAESinkAUDIOTRACK::AddPackets(uint8_t *data, unsigned int frames, b + break; + } + } ++ // AddPackets runs under a non-idled AE thread we must block or sleep. ++ // Trying to calc the optimal sleep is tricky so just a minimal sleep. ++ if(blocking) ++ Sleep(10); ++ + return hasAudio ? write_frames:frames; + } + +diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkDirectSound.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkDirectSound.cpp +index 8df9cab..6f4353d 100644 +--- a/xbmc/cores/AudioEngine/Sinks/AESinkDirectSound.cpp ++++ b/xbmc/cores/AudioEngine/Sinks/AESinkDirectSound.cpp +@@ -367,7 +367,7 @@ bool CAESinkDirectSound::IsCompatible(const AEAudioFormat format, const std::str + return false; + } + +-unsigned int CAESinkDirectSound::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio, bool blocking = false) ++unsigned int CAESinkDirectSound::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio, bool blocking) + { + if (!m_initialized) + return 0; +@@ -386,10 +386,15 @@ unsigned int CAESinkDirectSound::AddPackets(uint8_t *data, unsigned int frames, + + while (GetSpace() < total) + { +- if (m_isDirtyDS) ++ if(m_isDirtyDS) + return INT_MAX; + else +- return 0; ++ { ++ if(blocking) ++ Sleep(total * 1000 / m_AvgBytesPerSec); ++ else ++ return 0; ++ } + } + + while (len) +diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkOSS.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkOSS.cpp +index 97d1725..ab13671 100644 +--- a/xbmc/cores/AudioEngine/Sinks/AESinkOSS.cpp ++++ b/xbmc/cores/AudioEngine/Sinks/AESinkOSS.cpp +@@ -420,7 +420,7 @@ unsigned int CAESinkOSS::AddPackets(uint8_t *data, unsigned int frames, bool has + int wrote = write(m_fd, data, size); + if (wrote < 0) + { +- if(errno == EAGAIN || errno == EWOULDBLOCK) ++ if(!blocking && (errno == EAGAIN || errno == EWOULDBLOCK)) + return 0; + + CLog::Log(LOGERROR, "CAESinkOSS::AddPackets - Failed to write"); +diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp +index 6d6e477..5aebb47 100644 +--- a/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp ++++ b/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp +@@ -488,10 +488,33 @@ unsigned int CAESinkWASAPI::AddPackets(uint8_t *data, unsigned int frames, bool + #endif + + /* Wait for Audio Driver to tell us it's got a buffer available */ +- DWORD eventAudioCallback = WaitForSingleObject(m_needDataEvent, 0); ++ DWORD eventAudioCallback; ++ if(!blocking) ++ eventAudioCallback = WaitForSingleObject(m_needDataEvent, 0); ++ else ++ eventAudioCallback = WaitForSingleObject(m_needDataEvent, 1100); ++ ++ if (!blocking) ++ { ++ if(eventAudioCallback != WAIT_OBJECT_0) ++ return 0; ++ } ++ else ++ { ++ if(eventAudioCallback != WAIT_OBJECT_0 || !&buf) ++ { ++ /* Event handle timed out - flag sink as dirty for re-initializing */ ++ CLog::Log(LOGERROR, __FUNCTION__": Endpoint Buffer timed out"); ++ if (g_advancedSettings.m_streamSilence) ++ { ++ m_isDirty = true; //flag new device or re-init needed ++ Deinitialize(); ++ m_running = false; ++ return INT_MAX; ++ } ++ } ++ } + +- if (eventAudioCallback != WAIT_OBJECT_0) +- return 0; + + if (!m_running) + return 0; +-- +1.8.1.6 + + +From 0953ebde86870b738288d60596016a069728109c Mon Sep 17 00:00:00 2001 +From: Rainer Hochecker +Date: Sun, 7 Jul 2013 18:22:04 +0200 +Subject: [PATCH 011/120] AE: allow to register audio callback directly into + engine + +--- + xbmc/cores/AudioEngine/AEFactory.cpp | 12 ++++++++++++ + xbmc/cores/AudioEngine/AEFactory.h | 3 +++ + xbmc/cores/AudioEngine/Interfaces/AE.h | 5 +++++ + xbmc/cores/dvdplayer/DVDPlayer.h | 5 +++-- + xbmc/cores/paplayer/PAPlayer.cpp | 2 ++ + 5 files changed, 25 insertions(+), 2 deletions(-) + +diff --git a/xbmc/cores/AudioEngine/AEFactory.cpp b/xbmc/cores/AudioEngine/AEFactory.cpp +index 7141dd3..0befba9 100644 +--- a/xbmc/cores/AudioEngine/AEFactory.cpp ++++ b/xbmc/cores/AudioEngine/AEFactory.cpp +@@ -358,3 +358,15 @@ void CAEFactory::SettingOptionsAudioDevicesFillerGeneral(const CSetting *setting + if (!foundValue) + current = firstDevice; + } ++ ++void CAEFactory::RegisterAudioCallback(IAudioCallback* pCallback) ++{ ++ if (AE) ++ AE->RegisterAudioCallback(pCallback); ++} ++ ++void CAEFactory::UnregisterAudioCallback() ++{ ++ if (AE) ++ AE->UnregisterAudioCallback(); ++} +diff --git a/xbmc/cores/AudioEngine/AEFactory.h b/xbmc/cores/AudioEngine/AEFactory.h +index 56a1e27..9e15f79 100644 +--- a/xbmc/cores/AudioEngine/AEFactory.h ++++ b/xbmc/cores/AudioEngine/AEFactory.h +@@ -67,6 +67,9 @@ class CAEFactory + static void SettingOptionsAudioDevicesPassthroughFiller(const CSetting *setting, std::vector< std::pair > &list, std::string ¤t); + static void SettingOptionsAudioOutputModesFiller(const CSetting *setting, std::vector< std::pair > &list, int ¤t); + ++ static void RegisterAudioCallback(IAudioCallback* pCallback); ++ static void UnregisterAudioCallback(); ++ + private: + static bool LoadEngine(enum AEEngine engine); + static IAE *AE; +diff --git a/xbmc/cores/AudioEngine/Interfaces/AE.h b/xbmc/cores/AudioEngine/Interfaces/AE.h +index cbfa8ed..5741cd8 100644 +--- a/xbmc/cores/AudioEngine/Interfaces/AE.h ++++ b/xbmc/cores/AudioEngine/Interfaces/AE.h +@@ -34,6 +34,7 @@ + class IAEStream; + class IAESound; + class IAEPacketizer; ++class IAudioCallback; + + /* sound options */ + #define AE_SOUND_OFF 0 /* disable sounds */ +@@ -183,5 +184,9 @@ class IAE + * @returns true if the AudioEngine is capable of RAW output + */ + virtual bool SupportsRaw() { return false; } ++ ++ virtual void RegisterAudioCallback(IAudioCallback* pCallback) {} ++ ++ virtual void UnregisterAudioCallback() {} + }; + +diff --git a/xbmc/cores/dvdplayer/DVDPlayer.h b/xbmc/cores/dvdplayer/DVDPlayer.h +index ceb9996..6da30eb 100644 +--- a/xbmc/cores/dvdplayer/DVDPlayer.h ++++ b/xbmc/cores/dvdplayer/DVDPlayer.h +@@ -39,6 +39,7 @@ + #include "Edl.h" + #include "FileItem.h" + #include "threads/SingleLock.h" ++#include "cores/AudioEngine/AEFactory.h" + + + class CDVDInputStream; +@@ -185,8 +186,8 @@ class CDVDPlayer : public IPlayer, public CThread, public IDVDPlayer + virtual float GetPercentage(); + virtual float GetCachePercentage(); + +- virtual void RegisterAudioCallback(IAudioCallback* pCallback) { m_dvdPlayerAudio.RegisterAudioCallback(pCallback); } +- virtual void UnRegisterAudioCallback() { m_dvdPlayerAudio.UnRegisterAudioCallback(); } ++ virtual void RegisterAudioCallback(IAudioCallback* pCallback) { CAEFactory::RegisterAudioCallback(pCallback); m_dvdPlayerAudio.RegisterAudioCallback(pCallback); } ++ virtual void UnRegisterAudioCallback() { CAEFactory::UnregisterAudioCallback(); m_dvdPlayerAudio.UnRegisterAudioCallback(); } + virtual void SetVolume(float nVolume) { m_dvdPlayerAudio.SetVolume(nVolume); } + virtual void SetDynamicRangeCompression(long drc) { m_dvdPlayerAudio.SetDynamicRangeCompression(drc); } + virtual void GetAudioInfo(CStdString& strAudioInfo); +diff --git a/xbmc/cores/paplayer/PAPlayer.cpp b/xbmc/cores/paplayer/PAPlayer.cpp +index cfde8fb..c9d56ac 100644 +--- a/xbmc/cores/paplayer/PAPlayer.cpp ++++ b/xbmc/cores/paplayer/PAPlayer.cpp +@@ -717,6 +717,7 @@ void PAPlayer::OnExit() + void PAPlayer::RegisterAudioCallback(IAudioCallback* pCallback) + { + CSharedLock lock(m_streamsLock); ++ CAEFactory::RegisterAudioCallback(pCallback); + m_audioCallback = pCallback; + if (m_currentStream && m_currentStream->m_stream) + m_currentStream->m_stream->RegisterAudioCallback(pCallback); +@@ -725,6 +726,7 @@ void PAPlayer::RegisterAudioCallback(IAudioCallback* pCallback) + void PAPlayer::UnRegisterAudioCallback() + { + CSharedLock lock(m_streamsLock); ++ CAEFactory::UnregisterAudioCallback(); + /* only one stream should have the callback, but we do it to all just incase */ + for(StreamList::iterator itt = m_streams.begin(); itt != m_streams.end(); ++itt) + if ((*itt)->m_stream) +-- +1.8.1.6 + + +From 54451cd2c0d74d41415655779f0a6ab7999ff793 Mon Sep 17 00:00:00 2001 +From: Rainer Hochecker +Date: Mon, 1 Jul 2013 13:52:29 +0200 +Subject: [PATCH 012/120] AE: add parameter wait to drain, dvdplayer wants to + wait for the stream to be drained, papayer does not + +--- + xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAEStream.cpp | 2 +- + xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAEStream.h | 2 +- + xbmc/cores/AudioEngine/Engines/PulseAE/PulseAEStream.cpp | 2 +- + xbmc/cores/AudioEngine/Engines/PulseAE/PulseAEStream.h | 2 +- + xbmc/cores/AudioEngine/Engines/SoftAE/SoftAEStream.cpp | 2 +- + xbmc/cores/AudioEngine/Engines/SoftAE/SoftAEStream.h | 2 +- + xbmc/cores/AudioEngine/Interfaces/AEStream.h | 2 +- + xbmc/cores/dvdplayer/DVDAudio.cpp | 2 +- + xbmc/cores/paplayer/PAPlayer.cpp | 2 +- + 9 files changed, 9 insertions(+), 9 deletions(-) + +diff --git a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAEStream.cpp b/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAEStream.cpp +index a9422f7..073769a 100644 +--- a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAEStream.cpp ++++ b/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAEStream.cpp +@@ -603,7 +603,7 @@ void CCoreAudioAEStream::Resume() + m_paused = false; + } + +-void CCoreAudioAEStream::Drain() ++void CCoreAudioAEStream::Drain(bool wait) + { + m_draining = true; + } +diff --git a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAEStream.h b/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAEStream.h +index 18c52ed..1366808 100644 +--- a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAEStream.h ++++ b/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAEStream.h +@@ -73,7 +73,7 @@ class CCoreAudioAEStream : public IAEStream, public ICoreAudioSource + + virtual void Pause(); + virtual void Resume(); +- virtual void Drain(); ++ virtual void Drain(bool wait); + virtual void Flush(); + + virtual float GetVolume(); +diff --git a/xbmc/cores/AudioEngine/Engines/PulseAE/PulseAEStream.cpp b/xbmc/cores/AudioEngine/Engines/PulseAE/PulseAEStream.cpp +index 443c844..e1e1903 100644 +--- a/xbmc/cores/AudioEngine/Engines/PulseAE/PulseAEStream.cpp ++++ b/xbmc/cores/AudioEngine/Engines/PulseAE/PulseAEStream.cpp +@@ -386,7 +386,7 @@ void CPulseAEStream::Resume() + m_Paused = Cork(false); + } + +-void CPulseAEStream::Drain() ++void CPulseAEStream::Drain(bool wait) + { + if (!m_Initialized) + return; +diff --git a/xbmc/cores/AudioEngine/Engines/PulseAE/PulseAEStream.h b/xbmc/cores/AudioEngine/Engines/PulseAE/PulseAEStream.h +index 51aeda8..8d9435b 100644 +--- a/xbmc/cores/AudioEngine/Engines/PulseAE/PulseAEStream.h ++++ b/xbmc/cores/AudioEngine/Engines/PulseAE/PulseAEStream.h +@@ -48,7 +48,7 @@ class CPulseAEStream : public IAEStream + + virtual void Pause (); + virtual void Resume (); +- virtual void Drain (); ++ virtual void Drain (bool wait); + virtual void Flush (); + + virtual float GetVolume (); +diff --git a/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAEStream.cpp b/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAEStream.cpp +index 05ee1b0..b5c2da3 100644 +--- a/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAEStream.cpp ++++ b/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAEStream.cpp +@@ -555,7 +555,7 @@ void CSoftAEStream::Resume() + AE.ResumeStream(this); + } + +-void CSoftAEStream::Drain() ++void CSoftAEStream::Drain(bool wait) + { + CSingleLock lock(m_lock); + m_draining = true; +diff --git a/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAEStream.h b/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAEStream.h +index f7410e3..1475c83 100644 +--- a/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAEStream.h ++++ b/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAEStream.h +@@ -59,7 +59,7 @@ class CSoftAEStream : public IAEStream + + virtual void Pause (); + virtual void Resume (); +- virtual void Drain (); ++ virtual void Drain (bool wait); + virtual bool IsDraining () { return m_draining; } + virtual bool IsDrained (); + virtual void Flush (); +diff --git a/xbmc/cores/AudioEngine/Interfaces/AEStream.h b/xbmc/cores/AudioEngine/Interfaces/AEStream.h +index 67fa5e2..92d5fef 100644 +--- a/xbmc/cores/AudioEngine/Interfaces/AEStream.h ++++ b/xbmc/cores/AudioEngine/Interfaces/AEStream.h +@@ -97,7 +97,7 @@ class IAEStream + * Start draining the stream + * @note Once called AddData will not consume more data. + */ +- virtual void Drain() = 0; ++ virtual void Drain(bool wait) = 0; + + /** + * Returns true if the is stream draining +diff --git a/xbmc/cores/dvdplayer/DVDAudio.cpp b/xbmc/cores/dvdplayer/DVDAudio.cpp +index 3d77f0a..d304026 100644 +--- a/xbmc/cores/dvdplayer/DVDAudio.cpp ++++ b/xbmc/cores/dvdplayer/DVDAudio.cpp +@@ -298,7 +298,7 @@ void CDVDAudio::Drain() + Finish(); + CSingleLock lock (m_critSection); + if (m_pAudioStream) +- m_pAudioStream->Drain(); ++ m_pAudioStream->Drain(true); + } + + void CDVDAudio::RegisterAudioCallback(IAudioCallback* pCallback) +diff --git a/xbmc/cores/paplayer/PAPlayer.cpp b/xbmc/cores/paplayer/PAPlayer.cpp +index c9d56ac..f2e288c 100644 +--- a/xbmc/cores/paplayer/PAPlayer.cpp ++++ b/xbmc/cores/paplayer/PAPlayer.cpp +@@ -568,7 +568,7 @@ inline void PAPlayer::ProcessStreams(double &delay, double &buffer) + /* unregister the audio callback */ + si->m_stream->UnRegisterAudioCallback(); + si->m_decoder.Destroy(); +- si->m_stream->Drain(); ++ si->m_stream->Drain(false); + m_finishing.push_back(si); + return; + } +-- +1.8.1.6 + + +From 1b0dc8cf08199a1c1238f4639fafad666a1c148b Mon Sep 17 00:00:00 2001 +From: xbmc +Date: Mon, 25 Mar 2013 13:58:11 +0100 +Subject: [PATCH 013/120] ActiveAE: add new audio engine, co-author: fritsch + +--- + xbmc/cores/AudioEngine/AEFactory.cpp | 3 + + xbmc/cores/AudioEngine/AEFactory.h | 3 +- + .../AudioEngine/Engines/ActiveAE/ActiveAE.cpp | 2189 ++++++++++++++++++++ + xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.h | 332 +++ + .../Engines/ActiveAE/ActiveAEBuffer.cpp | 368 ++++ + .../AudioEngine/Engines/ActiveAE/ActiveAEBuffer.h | 110 + + .../Engines/ActiveAE/ActiveAEResample.cpp | 251 +++ + .../Engines/ActiveAE/ActiveAEResample.h | 61 + + .../AudioEngine/Engines/ActiveAE/ActiveAESink.cpp | 813 ++++++++ + .../AudioEngine/Engines/ActiveAE/ActiveAESink.h | 133 ++ + .../AudioEngine/Engines/ActiveAE/ActiveAESound.cpp | 164 ++ + .../AudioEngine/Engines/ActiveAE/ActiveAESound.h | 73 + + .../Engines/ActiveAE/ActiveAEStream.cpp | 357 ++++ + .../AudioEngine/Engines/ActiveAE/ActiveAEStream.h | 115 + + xbmc/cores/AudioEngine/Makefile.in | 7 + + xbmc/utils/ActorProtocol.cpp | 253 +++ + xbmc/utils/ActorProtocol.h | 87 + + xbmc/utils/Makefile.in | 1 + + 18 files changed, 5319 insertions(+), 1 deletion(-) + create mode 100644 xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp + create mode 100644 xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.h + create mode 100644 xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEBuffer.cpp + create mode 100644 xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEBuffer.h + create mode 100644 xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.cpp + create mode 100644 xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.h + create mode 100644 xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.cpp + create mode 100644 xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.h + create mode 100644 xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESound.cpp + create mode 100644 xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESound.h + create mode 100644 xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp + create mode 100644 xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.h + create mode 100644 xbmc/utils/ActorProtocol.cpp + create mode 100644 xbmc/utils/ActorProtocol.h + +diff --git a/xbmc/cores/AudioEngine/AEFactory.cpp b/xbmc/cores/AudioEngine/AEFactory.cpp +index 0befba9..4f9f566 100644 +--- a/xbmc/cores/AudioEngine/AEFactory.cpp ++++ b/xbmc/cores/AudioEngine/AEFactory.cpp +@@ -27,6 +27,8 @@ + #include "settings/SettingsManager.h" + #else + #include "Engines/SoftAE/SoftAE.h" ++ #include "Engines/ActiveAE/ActiveAE.h" ++ using namespace ActiveAE; + #endif + + #if defined(HAS_PULSEAUDIO) +@@ -99,6 +101,7 @@ bool CAEFactory::LoadEngine(enum AEEngine engine) + case AE_ENGINE_COREAUDIO: AE = new CCoreAudioAE(); break; + #else + case AE_ENGINE_SOFT : AE = new CSoftAE(); break; ++ case AE_ENGINE_ACTIVE : AE = new CActiveAE(); break; + #endif + #if defined(HAS_PULSEAUDIO) + case AE_ENGINE_PULSE : AE = new CPulseAE(); break; +diff --git a/xbmc/cores/AudioEngine/AEFactory.h b/xbmc/cores/AudioEngine/AEFactory.h +index 9e15f79..3059001 100644 +--- a/xbmc/cores/AudioEngine/AEFactory.h ++++ b/xbmc/cores/AudioEngine/AEFactory.h +@@ -31,7 +31,8 @@ enum AEEngine + AE_ENGINE_NULL, + AE_ENGINE_SOFT, + AE_ENGINE_COREAUDIO, +- AE_ENGINE_PULSE ++ AE_ENGINE_PULSE, ++ AE_ENGINE_ACTIVE + }; + + class CAEFactory +diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp +new file mode 100644 +index 0000000..dc79da7 +--- /dev/null ++++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp +@@ -0,0 +1,2189 @@ ++/* ++ * Copyright (C) 2010-2013 Team XBMC ++ * http://xbmc.org ++ * ++ * This Program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2, or (at your option) ++ * any later version. ++ * ++ * This Program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with XBMC; see the file COPYING. If not, see ++ * . ++ * ++ */ ++ ++#include "ActiveAE.h" ++ ++using namespace ActiveAE; ++#include "ActiveAESound.h" ++#include "ActiveAEStream.h" ++#include "Utils/AEUtil.h" ++#include "Encoders/AEEncoderFFmpeg.h" ++ ++#include "settings/Settings.h" ++#include "settings/AdvancedSettings.h" ++#include "windowing/WindowingFactory.h" ++ ++#define MAX_CACHE_LEVEL 0.5 // total cache time of stream in seconds ++#define MAX_WATER_LEVEL 0.25 // buffered time after stream stages in seconds ++ ++void CEngineStats::Reset(unsigned int sampleRate) ++{ ++ CSingleLock lock(m_lock); ++ m_sinkUpdate = XbmcThreads::SystemClockMillis(); ++ m_sinkDelay = 0; ++ m_sinkSampleRate = sampleRate; ++ m_bufferedSamples = 0; ++ m_suspended = false; ++} ++ ++void CEngineStats::UpdateSinkDelay(double delay, int samples) ++{ ++ CSingleLock lock(m_lock); ++ m_sinkUpdate = XbmcThreads::SystemClockMillis(); ++ m_sinkDelay = delay; ++ if (samples > m_bufferedSamples) ++ { ++ CLog::Log(LOGERROR, "CEngineStats::UpdateSinkDelay - inconsistency in buffer time"); ++ } ++ else ++ m_bufferedSamples -= samples; ++} ++ ++void CEngineStats::AddSamples(int samples, std::list &streams) ++{ ++ CSingleLock lock(m_lock); ++ m_bufferedSamples += samples; ++ ++ //update buffered time of streams ++ std::list::iterator it; ++ for(it=streams.begin(); it!=streams.end(); ++it) ++ { ++ float delay = 0; ++ std::deque::iterator itBuf; ++ for(itBuf=(*it)->m_processingSamples.begin(); itBuf!=(*it)->m_processingSamples.end(); ++itBuf) ++ { ++ delay += (float)(*itBuf)->pkt->nb_samples / (*itBuf)->pkt->config.sample_rate; ++ } ++ delay += (*it)->m_resampleBuffers->GetDelay(); ++ (*it)->m_bufferedTime = delay; ++ } ++} ++ ++float CEngineStats::GetDelay() ++{ ++ CSingleLock lock(m_lock); ++ unsigned int now = XbmcThreads::SystemClockMillis(); ++ float delay = m_sinkDelay - (double)(now-m_sinkUpdate) / 1000; ++ delay += (float)m_bufferedSamples / m_sinkSampleRate; ++ ++ return delay; ++} ++ ++float CEngineStats::GetDelay(CActiveAEStream *stream) ++{ ++ CSingleLock lock(m_lock); ++ unsigned int now = XbmcThreads::SystemClockMillis(); ++ float delay = m_sinkDelay - (double)(now-m_sinkUpdate) / 1000; ++ delay += (float)m_bufferedSamples / m_sinkSampleRate; ++ ++ delay += stream->m_bufferedTime; ++ return delay; ++} ++ ++float CEngineStats::GetCacheTime(CActiveAEStream *stream) ++{ ++ CSingleLock lock(m_lock); ++ float delay = (float)m_bufferedSamples / m_sinkSampleRate; ++ ++ delay += stream->m_bufferedTime; ++ return delay; ++} ++ ++float CEngineStats::GetCacheTotal(CActiveAEStream *stream) ++{ ++ return MAX_CACHE_LEVEL + m_sinkCacheTotal; ++} ++ ++float CEngineStats::GetWaterLevel() ++{ ++ return (float)m_bufferedSamples / m_sinkSampleRate; ++} ++ ++void CEngineStats::SetSuspended(bool state) ++{ ++ CSingleLock lock(m_lock); ++ m_suspended = state; ++} ++ ++bool CEngineStats::IsSuspended() ++{ ++ CSingleLock lock(m_lock); ++ return m_suspended; ++} ++ ++CActiveAE::CActiveAE() : ++ CThread("ActiveAE"), ++ m_controlPort("OutputControlPort", &m_inMsgEvent, &m_outMsgEvent), ++ m_dataPort("OutputDataPort", &m_inMsgEvent, &m_outMsgEvent), ++ m_sink(&m_outMsgEvent) ++{ ++ m_sinkBuffers = NULL; ++ m_silenceBuffers = NULL; ++ m_encoderBuffers = NULL; ++ m_vizBuffers = NULL; ++ m_volume = 1.0; ++ m_aeVolume = 1.0; ++ m_muted = false; ++ m_aeMuted = false; ++ m_mode = MODE_PCM; ++ m_encoder = NULL; ++ m_audioCallback = NULL; ++ m_vizInitialized = false; ++} ++ ++CActiveAE::~CActiveAE() ++{ ++ Dispose(); ++} ++ ++void CActiveAE::Dispose() ++{ ++#if defined(HAS_GLX) || defined(TARGET_DARWIN_OSX) ++ g_Windowing.Unregister(this); ++#endif ++ ++ m_bStop = true; ++ m_outMsgEvent.Set(); ++ StopThread(); ++ m_controlPort.Purge(); ++ m_dataPort.Purge(); ++ m_sink.Dispose(); ++ ++ m_dllAvFormat.Unload(); ++ m_dllAvCodec.Unload(); ++ m_dllAvUtil.Unload(); ++} ++ ++//----------------------------------------------------------------------------- ++// Behavior ++//----------------------------------------------------------------------------- ++ ++enum AE_STATES ++{ ++ AE_TOP = 0, // 0 ++ AE_TOP_ERROR, // 1 ++ AE_TOP_UNCONFIGURED, // 2 ++ AE_TOP_RECONFIGURING, // 3 ++ AE_TOP_CONFIGURED, // 4 ++ AE_TOP_CONFIGURED_SUSPEND, // 5 ++ AE_TOP_CONFIGURED_IDLE, // 6 ++ AE_TOP_CONFIGURED_PLAY, // 7 ++}; ++ ++int AE_parentStates[] = { ++ -1, ++ 0, //TOP_ERROR ++ 0, //TOP_UNCONFIGURED ++ 0, //TOP_CONFIGURED ++ 0, //TOP_RECONFIGURING ++ 4, //TOP_CONFIGURED_SUSPEND ++ 4, //TOP_CONFIGURED_IDLE ++ 4, //TOP_CONFIGURED_PLAY ++}; ++ ++void CActiveAE::StateMachine(int signal, Protocol *port, Message *msg) ++{ ++ for (int state = m_state; ; state = AE_parentStates[state]) ++ { ++ switch (state) ++ { ++ case AE_TOP: // TOP ++ if (port == &m_controlPort) ++ { ++ switch (signal) ++ { ++ case CActiveAEControlProtocol::GETSTATE: ++ msg->Reply(CActiveAEControlProtocol::ACC, &m_state, sizeof(m_state)); ++ return; ++ case CActiveAEControlProtocol::SOUNDMODE: ++ m_soundMode = *(int*)msg->data; ++ return; ++ case CActiveAEControlProtocol::VOLUME: ++ m_volume = *(float*)msg->data; ++ return; ++ case CActiveAEControlProtocol::MUTE: ++ m_muted = *(bool*)msg->data; ++ return; ++ default: ++ break; ++ } ++ } ++ else if (port == &m_dataPort) ++ { ++ switch (signal) ++ { ++ case CActiveAEDataProtocol::NEWSOUND: ++ CActiveAESound *sound; ++ sound = *(CActiveAESound**)msg->data; ++ if (sound) ++ { ++ m_sounds.push_back(sound); ++ ResampleSounds(); ++ } ++ return; ++ case CActiveAEDataProtocol::FREESTREAM: ++ CActiveAEStream *stream; ++ stream = *(CActiveAEStream**)msg->data; ++ DiscardStream(stream); ++ return; ++ case CActiveAEDataProtocol::FREESOUND: ++ sound = *(CActiveAESound**)msg->data; ++ DiscardSound(sound); ++ return; ++ case CActiveAEDataProtocol::DRAINSTREAM: ++ stream = *(CActiveAEStream**)msg->data; ++ stream->m_drain = true; ++ stream->m_resampleBuffers->m_drain = true; ++ msg->Reply(CActiveAEDataProtocol::ACC); ++ stream->m_streamPort->SendInMessage(CActiveAEDataProtocol::STREAMDRAINED); ++ return; ++ default: ++ break; ++ } ++ } ++ else if (&m_sink.m_dataPort) ++ { ++ switch (signal) ++ { ++ case CSinkDataProtocol::RETURNSAMPLE: ++ CSampleBuffer **buffer; ++ buffer = (CSampleBuffer**)msg->data; ++ if (buffer) ++ { ++ (*buffer)->Return(); ++ } ++ return; ++ default: ++ break; ++ } ++ } ++ { ++ std::string portName = port == NULL ? "timer" : port->portName; ++ CLog::Log(LOGWARNING, "CActiveAE::%s - signal: %d from port: %s not handled for state: %d", __FUNCTION__, signal, portName.c_str(), m_state); ++ } ++ return; ++ ++ case AE_TOP_ERROR: ++ break; ++ ++ case AE_TOP_UNCONFIGURED: ++ if (port == &m_controlPort) ++ { ++ switch (signal) ++ { ++ case CActiveAEControlProtocol::INIT: ++ m_extError = false; ++ m_sink.EnumerateSinkList(); ++ LoadSettings(); ++ Configure(); ++ msg->Reply(CActiveAEControlProtocol::ACC); ++ if (!m_extError) ++ { ++ m_state = AE_TOP_CONFIGURED_IDLE; ++ m_extTimeout = 0; ++ } ++ else ++ { ++ m_state = AE_TOP_ERROR; ++ } ++ return; ++ ++ default: ++ break; ++ } ++ } ++ break; ++ ++ case AE_TOP_RECONFIGURING: ++ if (port == NULL) // timeout ++ { ++ switch (signal) ++ { ++ case CActiveAEControlProtocol::TIMEOUT: ++ // drain ++ if (RunStages()) ++ { ++ m_extTimeout = 0; ++ return; ++ } ++ if (HasWork()) ++ { ++ m_extTimeout = 100; ++ return; ++ } ++ if (NeedReconfigureSink()) ++ DrainSink(); ++ Configure(); ++ if (!m_extError) ++ { ++ m_state = AE_TOP_CONFIGURED_PLAY; ++ m_extTimeout = 0; ++ } ++ else ++ { ++ m_state = AE_TOP_ERROR; ++ m_extTimeout = 1000; ++ } ++ m_dataPort.DeferOut(false); ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ case AE_TOP_CONFIGURED: ++ if (port == &m_controlPort) ++ { ++ switch (signal) ++ { ++ case CActiveAEControlProtocol::RECONFIGURE: ++ LoadSettings(); ++ if (!NeedReconfigureBuffers() && !NeedReconfigureSink()) ++ return; ++ m_state = AE_TOP_RECONFIGURING; ++ m_extTimeout = 0; ++ // don't accept any data until we are reconfigured ++ m_dataPort.DeferOut(true); ++ return; ++ case CActiveAEControlProtocol::SUSPEND: ++ UnconfigureSink(); ++ m_stats.SetSuspended(true); ++ m_state = AE_TOP_CONFIGURED_SUSPEND; ++ return; ++ case CActiveAEControlProtocol::DISPLAYLOST: ++ if (m_settings.mode == AUDIO_HDMI) ++ { ++ UnconfigureSink(); ++ m_stats.SetSuspended(true); ++ m_state = AE_TOP_CONFIGURED_SUSPEND; ++ } ++ return; ++ case CActiveAEControlProtocol::PAUSESTREAM: ++ CActiveAEStream *stream; ++ stream = *(CActiveAEStream**)msg->data; ++ stream->m_paused = true; ++ return; ++ case CActiveAEControlProtocol::RESUMESTREAM: ++ stream = *(CActiveAEStream**)msg->data; ++ stream->m_paused = false; ++ m_state = AE_TOP_CONFIGURED_PLAY; ++ m_extTimeout = 0; ++ return; ++ case CActiveAEControlProtocol::STREAMAMP: ++ MsgStreamParameter *par; ++ par = (MsgStreamParameter*)msg->data; ++ par->stream->m_limiter.SetAmplification(par->parameter.float_par); ++ return; ++ case CActiveAEControlProtocol::STREAMVOLUME: ++ par = (MsgStreamParameter*)msg->data; ++ par->stream->m_volume = par->parameter.float_par; ++ return; ++ case CActiveAEControlProtocol::STREAMRGAIN: ++ par = (MsgStreamParameter*)msg->data; ++ par->stream->m_rgain = par->parameter.float_par; ++ return; ++ case CActiveAEControlProtocol::STREAMRESAMPLERATIO: ++ par = (MsgStreamParameter*)msg->data; ++ if (par->stream->m_resampleBuffers) ++ { ++ par->stream->m_resampleBuffers->m_resampleRatio = par->parameter.double_par; ++ par->stream->m_resampleBuffers->m_changeRatio = true; ++ } ++ return; ++ case CActiveAEControlProtocol::STREAMFADE: ++ MsgStreamFade *fade; ++ fade = (MsgStreamFade*)msg->data; ++ fade->stream->m_fadingBase = fade->from; ++ fade->stream->m_fadingTarget = fade->target; ++ fade->stream->m_fadingTime = fade->millis; ++ fade->stream->m_fadingSamples = -1; ++ return; ++ case CActiveAEControlProtocol::STOPSOUND: ++ CActiveAESound *sound; ++ sound = *(CActiveAESound**)msg->data; ++ SStopSound(sound); ++ return; ++ default: ++ break; ++ } ++ } ++ else if (port == &m_dataPort) ++ { ++ switch (signal) ++ { ++ case CActiveAEDataProtocol::PLAYSOUND: ++ CActiveAESound *sound; ++ sound = *(CActiveAESound**)msg->data; ++ if (m_soundMode == AE_SOUND_OFF || ++ (m_soundMode == AE_SOUND_IDLE && !m_streams.empty())) ++ return; ++ if (sound) ++ { ++ SoundState st = {sound, 0}; ++ m_sounds_playing.push_back(st); ++ m_extTimeout = 0; ++ m_state = AE_TOP_CONFIGURED_PLAY; ++ } ++ return; ++ case CActiveAEDataProtocol::NEWSTREAM: ++ MsgStreamNew *streamMsg; ++ CActiveAEStream *stream; ++ streamMsg = (MsgStreamNew*)msg->data; ++ stream = CreateStream(streamMsg); ++ if(stream) ++ { ++ msg->Reply(CActiveAEDataProtocol::ACC, &stream, sizeof(CActiveAEStream*)); ++ Configure(); ++ m_extTimeout = 0; ++ m_state = AE_TOP_CONFIGURED_PLAY; ++ } ++ else ++ msg->Reply(CActiveAEDataProtocol::ERR); ++ return; ++ case CActiveAEDataProtocol::STREAMSAMPLE: ++ MsgStreamSample *msgData; ++ CSampleBuffer *samples; ++ msgData = (MsgStreamSample*)msg->data; ++ samples = msgData->stream->m_processingSamples.front(); ++ msgData->stream->m_processingSamples.pop_front(); ++ if (samples != msgData->buffer) ++ CLog::Log(LOGERROR, "CActiveAE - inconsistency in stream sample message"); ++ if (msgData->buffer->pkt->nb_samples == 0) ++ msgData->buffer->Return(); ++ else ++ msgData->stream->m_resampleBuffers->m_inputSamples.push_back(msgData->buffer); ++ m_extTimeout = 0; ++ m_state = AE_TOP_CONFIGURED_PLAY; ++ return; ++ case CActiveAEDataProtocol::FREESTREAM: ++ stream = *(CActiveAEStream**)msg->data; ++ DiscardStream(stream); ++ if (m_streams.empty()) ++ { ++ m_extDrainTimer.Set(m_stats.GetDelay() * 1000); ++ m_extDrain = true; ++ } ++ m_extTimeout = 0; ++ m_state = AE_TOP_CONFIGURED_PLAY; ++ return; ++ case CActiveAEDataProtocol::DRAINSTREAM: ++ stream = *(CActiveAEStream**)msg->data; ++ stream->m_drain = true; ++ stream->m_resampleBuffers->m_drain = true; ++ m_extTimeout = 0; ++ m_state = AE_TOP_CONFIGURED_PLAY; ++ msg->Reply(CActiveAEDataProtocol::ACC); ++ return; ++ case CActiveAEDataProtocol::FLUSHSTREAM: ++ stream = *(CActiveAEStream**)msg->data; ++ SFlushStream(stream); ++ msg->Reply(CActiveAEDataProtocol::ACC); ++ return; ++ default: ++ break; ++ } ++ } ++ else if (&m_sink.m_dataPort) ++ { ++ switch (signal) ++ { ++ case CSinkDataProtocol::RETURNSAMPLE: ++ CSampleBuffer **buffer; ++ buffer = (CSampleBuffer**)msg->data; ++ if (buffer) ++ { ++ (*buffer)->Return(); ++ } ++ m_extTimeout = 0; ++ m_state = AE_TOP_CONFIGURED_PLAY; ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ case AE_TOP_CONFIGURED_SUSPEND: ++ if (port == &m_controlPort) ++ { ++ bool displayReset = false; ++ switch (signal) ++ { ++ case CActiveAEControlProtocol::DISPLAYRESET: ++ displayReset = true; ++ case CActiveAEControlProtocol::INIT: ++ m_extError = false; ++ if (!displayReset) ++ { ++ m_sink.EnumerateSinkList(); ++ LoadSettings(); ++ } ++ Configure(); ++ if (!displayReset) ++ msg->Reply(CActiveAEControlProtocol::ACC); ++ if (!m_extError) ++ { ++ m_stats.SetSuspended(false); ++ m_state = AE_TOP_CONFIGURED_PLAY; ++ m_extTimeout = 0; ++ } ++ else ++ { ++ m_state = AE_TOP_ERROR; ++ } ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ case AE_TOP_CONFIGURED_IDLE: ++ if (port == NULL) // timeout ++ { ++ switch (signal) ++ { ++ case CActiveAEControlProtocol::TIMEOUT: ++ ResampleSounds(); ++ ClearDiscardedBuffers(); ++ if (m_extDrain) ++ { ++ if (m_extDrainTimer.IsTimePast()) ++ { ++ Configure(); ++ m_state = AE_TOP_CONFIGURED_PLAY; ++ m_extTimeout = 0; ++ } ++ else ++ m_extTimeout = m_extDrainTimer.MillisLeft(); ++ } ++ else ++ m_extTimeout = 5000; ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ case AE_TOP_CONFIGURED_PLAY: ++ if (port == NULL) // timeout ++ { ++ switch (signal) ++ { ++ case CActiveAEControlProtocol::TIMEOUT: ++ if (RunStages()) ++ { ++ m_extTimeout = 0; ++ return; ++ } ++ if (!m_extDrain && HasWork()) ++ { ++ ResampleSounds(); ++ ClearDiscardedBuffers(); ++ m_extTimeout = 100; ++ return; ++ } ++ m_extTimeout = 0; ++ m_state = AE_TOP_CONFIGURED_IDLE; ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ default: // we are in no state, should not happen ++ CLog::Log(LOGERROR, "CActiveAE::%s - no valid state: %d", __FUNCTION__, m_state); ++ return; ++ } ++ } // for ++} ++ ++void CActiveAE::Process() ++{ ++ Message *msg = NULL; ++ Protocol *port = NULL; ++ bool gotMsg; ++ bool deferData; ++ ++ m_state = AE_TOP_UNCONFIGURED; ++ m_extTimeout = 1000; ++ m_bStateMachineSelfTrigger = false; ++ m_extDrain = false; ++ ++ // start sink ++ m_sink.Start(); ++ ++ while (!m_bStop) ++ { ++ gotMsg = false; ++ deferData = (m_state == AE_TOP_CONFIGURED_SUSPEND); ++ ++ if (m_bStateMachineSelfTrigger) ++ { ++ m_bStateMachineSelfTrigger = false; ++ // self trigger state machine ++ StateMachine(msg->signal, port, msg); ++ if (!m_bStateMachineSelfTrigger) ++ { ++ msg->Release(); ++ msg = NULL; ++ } ++ continue; ++ } ++ // check control port ++ else if (m_controlPort.ReceiveOutMessage(&msg)) ++ { ++ gotMsg = true; ++ port = &m_controlPort; ++ } ++ else if (!deferData) ++ { ++ // check data port ++ if (m_dataPort.ReceiveOutMessage(&msg)) ++ { ++ gotMsg = true; ++ port = &m_dataPort; ++ } ++ // check sink data port ++ else if (m_sink.m_dataPort.ReceiveInMessage(&msg)) ++ { ++ gotMsg = true; ++ port = &m_sink.m_dataPort; ++ } ++ // stream data ports ++ else ++ { ++ std::list::iterator it; ++ for(it=m_streams.begin(); it!=m_streams.end(); ++it) ++ { ++ if((*it)->m_streamPort->ReceiveOutMessage(&msg)) ++ { ++ gotMsg = true; ++ port = &m_dataPort; ++ break; ++ } ++ } ++ } ++ } ++ ++ if (gotMsg) ++ { ++ StateMachine(msg->signal, port, msg); ++ if (!m_bStateMachineSelfTrigger) ++ { ++ msg->Release(); ++ msg = NULL; ++ } ++ continue; ++ } ++ ++ // wait for message ++ else if (m_outMsgEvent.WaitMSec(m_extTimeout)) ++ { ++ continue; ++ } ++ // time out ++ else ++ { ++ msg = m_controlPort.GetMessage(); ++ msg->signal = CActiveAEControlProtocol::TIMEOUT; ++ port = 0; ++ // signal timeout to state machine ++ StateMachine(msg->signal, port, msg); ++ if (!m_bStateMachineSelfTrigger) ++ { ++ msg->Release(); ++ msg = NULL; ++ } ++ } ++ } ++} ++ ++void CActiveAE::Configure() ++{ ++ bool initSink = false; ++ AEAudioFormat sinkInputFormat, inputFormat; ++ m_mode = MODE_PCM; ++ ++ if (m_streams.empty()) ++ { ++ inputFormat.m_dataFormat = AE_FMT_FLOAT; ++ inputFormat.m_sampleRate = 44100; ++ inputFormat.m_encodedRate = 0; ++ inputFormat.m_channelLayout = AE_CH_LAYOUT_2_0; ++ inputFormat.m_frames = 0; ++ inputFormat.m_frameSamples = 0; ++ inputFormat.m_frameSize = 0; ++ UnregisterAudioCallback(); ++ } ++ else ++ { ++ inputFormat = m_streams.front()->m_format; ++ } ++ ++ m_sinkRequestFormat = inputFormat; ++ ApplySettingsToFormat(m_sinkRequestFormat, m_settings); ++ std::string device = AE_IS_RAW(m_sinkRequestFormat.m_dataFormat) ? m_settings.passthoughdevice : m_settings.device; ++ std::string driver; ++ CAESinkFactory::ParseDevice(device, driver); ++ if (!m_sink.IsCompatible(m_sinkRequestFormat, device) || m_settings.driver.compare(driver) != 0) ++ { ++ InitSink(); ++ m_settings.driver = driver; ++ initSink = true; ++ m_stats.Reset(m_sinkFormat.m_sampleRate); ++ } ++ ++ if (m_silenceBuffers) ++ { ++ m_discardBufferPools.push_back(m_silenceBuffers); ++ m_silenceBuffers = NULL; ++ } ++ ++ // buffers for driving gui sounds if no streams are active ++ if (m_streams.empty()) ++ { ++ inputFormat = m_sinkFormat; ++ inputFormat.m_dataFormat = AE_FMT_FLOAT; ++ inputFormat.m_frameSize = inputFormat.m_channelLayout.Count() * ++ (CAEUtil::DataFormatToBits(inputFormat.m_dataFormat) >> 3); ++ m_silenceBuffers = new CActiveAEBufferPool(inputFormat); ++ m_silenceBuffers->Create(MAX_WATER_LEVEL*1000); ++ sinkInputFormat = inputFormat; ++ m_internalFormat = inputFormat; ++ ++ bool silence = false; ++ m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::SILENCEMODE, &silence, sizeof(bool)); ++ ++ if (m_encoder) ++ { ++ delete m_encoder; ++ m_encoder = NULL; ++ } ++ if (m_encoderBuffers) ++ { ++ m_discardBufferPools.push_back(m_encoderBuffers); ++ m_encoderBuffers = NULL; ++ } ++ if (m_vizBuffers) ++ { ++ m_discardBufferPools.push_back(m_vizBuffers); ++ m_vizBuffers = NULL; ++ } ++ } ++ // resample buffers for streams ++ else ++ { ++ bool silence = true; ++ m_sink.m_controlPort.SendOutMessage(CSinkControlProtocol::SILENCEMODE, &silence, sizeof(bool)); ++ ++ AEAudioFormat outputFormat; ++ if (AE_IS_RAW(inputFormat.m_dataFormat)) ++ { ++ outputFormat = inputFormat; ++ sinkInputFormat = m_sinkFormat; ++ m_mode = MODE_RAW; ++ } ++ // transcode ++ else if (m_settings.ac3passthrough && !m_settings.multichannellpcm) ++ { ++ outputFormat = inputFormat; ++ outputFormat.m_dataFormat = AE_FMT_FLOATP; ++ ++ if (g_advancedSettings.m_audioResample) ++ { ++ outputFormat.m_sampleRate = g_advancedSettings.m_audioResample; ++ CLog::Log(LOGINFO, "CActiveAE::Configure - Forcing samplerate to %d", inputFormat.m_sampleRate); ++ } ++ ++ // setup encoder ++ if (!m_encoder) ++ { ++ m_encoder = new CAEEncoderFFmpeg(); ++ m_encoder->Initialize(outputFormat, true); ++ m_encoderFormat = outputFormat; ++ } ++ else ++ outputFormat = m_encoderFormat; ++ ++ outputFormat.m_channelLayout = m_encoderFormat.m_channelLayout; ++ outputFormat.m_frames = m_encoderFormat.m_frames; ++ ++ // encoder buffer ++ if (m_encoder->GetCodecID() == CODEC_ID_AC3) ++ { ++ AEAudioFormat format; ++ format.m_channelLayout = AE_CH_LAYOUT_2_0; ++ format.m_dataFormat = AE_FMT_S16NE; ++ format.m_frameSize = 2* (CAEUtil::DataFormatToBits(format.m_dataFormat) >> 3); ++ format.m_frames = AC3_FRAME_SIZE; ++ format.m_sampleRate = 48000; ++ if (m_encoderBuffers && initSink) ++ { ++ m_discardBufferPools.push_back(m_encoderBuffers); ++ m_encoderBuffers = NULL; ++ } ++ if (!m_encoderBuffers) ++ { ++ m_encoderBuffers = new CActiveAEBufferPool(format); ++ m_encoderBuffers->Create(MAX_WATER_LEVEL*1000); ++ } ++ } ++ ++ m_mode = MODE_TRANSCODE; ++ sinkInputFormat = m_sinkFormat; ++ } ++ else ++ { ++ outputFormat = m_sinkFormat; ++ outputFormat.m_channelLayout = m_sinkRequestFormat.m_channelLayout; ++ outputFormat.m_channelLayout.ResolveChannels(m_sinkFormat.m_channelLayout); ++ outputFormat.m_dataFormat = AE_FMT_FLOAT; ++ outputFormat.m_frameSize = outputFormat.m_channelLayout.Count() * ++ (CAEUtil::DataFormatToBits(outputFormat.m_dataFormat) >> 3); ++ // TODO: adjust to decoder ++ sinkInputFormat = outputFormat; ++ } ++ m_internalFormat = outputFormat; ++ ++ std::list::iterator it; ++ for(it=m_streams.begin(); it!=m_streams.end(); ++it) ++ { ++ if (!(*it)->m_inputBuffers) ++ { ++ // align input buffers with period of sink ++ (*it)->m_format.m_frames = m_sinkFormat.m_frames * ((float)(*it)->m_format.m_sampleRate / m_sinkFormat.m_sampleRate); ++ ++ // create buffer pool ++ (*it)->m_inputBuffers = new CActiveAEBufferPool((*it)->m_format); ++ (*it)->m_inputBuffers->Create(MAX_CACHE_LEVEL*1000); ++ } ++ if (initSink && (*it)->m_resampleBuffers) ++ { ++ m_discardBufferPools.push_back((*it)->m_resampleBuffers); ++ (*it)->m_resampleBuffers = NULL; ++ } ++ if (!(*it)->m_resampleBuffers) ++ { ++ (*it)->m_resampleBuffers = new CActiveAEBufferPoolResample((*it)->m_inputBuffers->m_format, outputFormat); ++ (*it)->m_resampleBuffers->Create(MAX_CACHE_LEVEL*1000, false); ++ } ++ if (m_mode == MODE_TRANSCODE || m_streams.size() > 1) ++ (*it)->m_resampleBuffers->m_fillPackets = true; ++ } ++ ++ // buffers for viz ++ if (!AE_IS_RAW(inputFormat.m_dataFormat)) ++ { ++ if (initSink && m_vizBuffers) ++ { ++ m_discardBufferPools.push_back(m_vizBuffers); ++ m_vizBuffers = NULL; ++ } ++ if (!m_vizBuffers) ++ { ++ AEAudioFormat vizFormat = m_internalFormat; ++ vizFormat.m_channelLayout = AE_CH_LAYOUT_2_0; ++ vizFormat.m_dataFormat = AE_FMT_FLOAT; ++ m_vizBuffers = new CActiveAEBufferPoolResample(m_internalFormat, vizFormat); ++ // TODO use cache of sync + water level ++ m_vizBuffers->Create(2000, false); ++ } ++ } ++ } ++ ++ // resample buffers for sink ++ if (m_sinkBuffers && !m_sink.IsCompatible(m_sinkBuffers->m_format, device)) ++ { ++ m_discardBufferPools.push_back(m_sinkBuffers); ++ m_sinkBuffers = NULL; ++ } ++ if (!m_sinkBuffers) ++ { ++ m_sinkBuffers = new CActiveAEBufferPoolResample(sinkInputFormat, m_sinkFormat); ++ m_sinkBuffers->Create(MAX_WATER_LEVEL*1000, true); ++ } ++ ++ // reset gui sounds ++ std::vector::iterator it; ++ for (it = m_sounds.begin(); it != m_sounds.end(); ++it) ++ { ++ (*it)->SetConverted(false); ++ } ++ ++ ClearDiscardedBuffers(); ++ m_extDrain = false; ++} ++ ++CActiveAEStream* CActiveAE::CreateStream(MsgStreamNew *streamMsg) ++{ ++ // we only can handle a single pass through stream ++ if (!m_streams.empty()) ++ { ++ if (AE_IS_RAW(m_streams.front()->m_format.m_dataFormat) || AE_IS_RAW(streamMsg->format.m_dataFormat)) ++ return NULL; ++ } ++ ++ // create the stream ++ CActiveAEStream *stream; ++ stream = new CActiveAEStream(&streamMsg->format); ++ stream->m_streamPort = new CActiveAEDataProtocol("stream", ++ &stream->m_inMsgEvent, &m_outMsgEvent); ++ ++ // create buffer pool ++ stream->m_inputBuffers = NULL; // create in Configure when we know the sink format ++ stream->m_resampleBuffers = NULL; // create in Configure when we know the sink format ++ stream->m_statsLock = m_stats.GetLock(); ++ stream->m_fadingSamples = 0; ++ stream->m_started = false; ++ ++ if (streamMsg->options & AESTREAM_PAUSED) ++ stream->m_paused = true; ++ ++ m_streams.push_back(stream); ++ ++ return stream; ++} ++ ++void CActiveAE::DiscardStream(CActiveAEStream *stream) ++{ ++ std::list::iterator it; ++ for (it=m_streams.begin(); it!=m_streams.end(); ) ++ { ++ if (stream == (*it)) ++ { ++ while (!(*it)->m_processingSamples.empty()) ++ { ++ (*it)->m_processingSamples.front()->Return(); ++ (*it)->m_processingSamples.pop_front(); ++ } ++ m_discardBufferPools.push_back((*it)->m_inputBuffers); ++ m_discardBufferPools.push_back((*it)->m_resampleBuffers); ++ CLog::Log(LOGDEBUG, "CActiveAE::DiscardStream - audio stream deleted"); ++ delete (*it)->m_streamPort; ++ delete (*it); ++ it = m_streams.erase(it); ++ } ++ else ++ ++it; ++ } ++ ++ ClearDiscardedBuffers(); ++} ++ ++void CActiveAE::SFlushStream(CActiveAEStream *stream) ++{ ++ while (!stream->m_processingSamples.empty()) ++ { ++ stream->m_processingSamples.front()->Return(); ++ stream->m_processingSamples.pop_front(); ++ } ++ stream->m_resampleBuffers->Flush(); ++ stream->m_streamPort->Purge(); ++ stream->m_bufferedTime = 0.0; ++ stream->m_paused = true; ++} ++ ++void CActiveAE::ClearDiscardedBuffers() ++{ ++ std::list::iterator it; ++ for (it=m_discardBufferPools.begin(); it!=m_discardBufferPools.end(); ++it) ++ { ++ CActiveAEBufferPoolResample *rbuf = dynamic_cast(*it); ++ if (rbuf) ++ { ++ rbuf->Flush(); ++ } ++ // if all buffers have returned, we can delete the buffer pool ++ if ((*it)->m_allSamples.size() == (*it)->m_freeSamples.size()) ++ { ++ delete (*it); ++ CLog::Log(LOGDEBUG, "CActiveAE::ClearDiscardedBuffers - buffer pool deleted"); ++ m_discardBufferPools.erase(it); ++ return; ++ } ++ } ++} ++ ++void CActiveAE::SStopSound(CActiveAESound *sound) ++{ ++ std::list::iterator it; ++ for (it=m_sounds_playing.begin(); it!=m_sounds_playing.end(); ++it) ++ { ++ if (it->sound == sound) ++ { ++ m_sounds_playing.erase(it); ++ return; ++ } ++ } ++} ++ ++void CActiveAE::DiscardSound(CActiveAESound *sound) ++{ ++ SStopSound(sound); ++ ++ std::vector::iterator it; ++ for (it=m_sounds.begin(); it!=m_sounds.end(); ++it) ++ { ++ if ((*it) == sound) ++ { ++ m_sounds.erase(it); ++ return; ++ } ++ } ++} ++ ++float CActiveAE::CalcStreamAmplification(CActiveAEStream *stream, CSampleBuffer *buf) ++{ ++ float amp = 1.0f; ++ int nb_floats = buf->pkt->nb_samples * buf->pkt->config.channels / buf->pkt->planes; ++ float tamp; ++ for(int i=0; ipkt->planes; i++) ++ { ++ tamp = stream->m_limiter.Run((float*)buf->pkt->data[i], nb_floats); ++ amp = std::min(amp, tamp); ++ } ++ return amp; ++} ++ ++void CActiveAE::ApplySettingsToFormat(AEAudioFormat &format, AudioSettings &settings) ++{ ++ // raw pass through ++ if (m_settings.mode != AUDIO_ANALOG && AE_IS_RAW(format.m_dataFormat)) ++ { ++ if ((format.m_dataFormat == AE_FMT_AC3 && !settings.ac3passthrough) || ++ (format.m_dataFormat == AE_FMT_TRUEHD && !settings.truehdpassthrough) || ++ (format.m_dataFormat == AE_FMT_DTS && !settings.dtspassthrough) || ++ (format.m_dataFormat == AE_FMT_DTSHD && !settings.dtshdpassthrough)) ++ { ++ CLog::Log(LOGERROR, "CActiveAE::ApplySettingsToFormat - input audio format is wrong"); ++ } ++ } ++ // transcode ++ else if (m_settings.mode != AUDIO_ANALOG && settings.ac3passthrough && !settings.multichannellpcm && !m_streams.empty()) ++ { ++ format.m_dataFormat = AE_FMT_AC3; ++ format.m_sampleRate = 48000; ++ } ++ else ++ { ++ if ((format.m_channelLayout.Count() > 2) || settings.stereoupmix) ++ { ++ switch (settings.channels) ++ { ++ default: ++ case 0: format.m_channelLayout = AE_CH_LAYOUT_2_0; break; ++ case 1: format.m_channelLayout = AE_CH_LAYOUT_2_0; break; ++ case 2: format.m_channelLayout = AE_CH_LAYOUT_2_1; break; ++ case 3: format.m_channelLayout = AE_CH_LAYOUT_3_0; break; ++ case 4: format.m_channelLayout = AE_CH_LAYOUT_3_1; break; ++ case 5: format.m_channelLayout = AE_CH_LAYOUT_4_0; break; ++ case 6: format.m_channelLayout = AE_CH_LAYOUT_4_1; break; ++ case 7: format.m_channelLayout = AE_CH_LAYOUT_5_0; break; ++ case 8: format.m_channelLayout = AE_CH_LAYOUT_5_1; break; ++ case 9: format.m_channelLayout = AE_CH_LAYOUT_7_0; break; ++ case 10: format.m_channelLayout = AE_CH_LAYOUT_7_1; break; ++ } ++ } ++ ++ if (g_advancedSettings.m_audioResample) ++ { ++ format.m_sampleRate = g_advancedSettings.m_audioResample; ++ CLog::Log(LOGINFO, "CActiveAE::ApplySettings - Forcing samplerate to %d", format.m_sampleRate); ++ } ++ ++ // for IEC958 limit to 2 channels ++ if (m_settings.mode == AUDIO_IEC958) ++ { ++ format.m_channelLayout = AE_CH_LAYOUT_2_0; ++ } ++ ++ CAEChannelInfo stdLayout = format.m_channelLayout; ++ format.m_channelLayout.ResolveChannels(stdLayout); ++ } ++} ++ ++bool CActiveAE::NeedReconfigureBuffers() ++{ ++ AEAudioFormat newFormat = m_sinkRequestFormat; ++ ApplySettingsToFormat(newFormat, m_settings); ++ ++ if (newFormat.m_dataFormat != m_sinkRequestFormat.m_dataFormat || ++ newFormat.m_channelLayout != m_sinkRequestFormat.m_channelLayout || ++ newFormat.m_sampleRate != m_sinkRequestFormat.m_sampleRate) ++ return true; ++ ++ return false; ++} ++ ++bool CActiveAE::NeedReconfigureSink() ++{ ++ AEAudioFormat newFormat = m_sinkRequestFormat; ++ ApplySettingsToFormat(newFormat, m_settings); ++ ++ std::string device = AE_IS_RAW(newFormat.m_dataFormat) ? m_settings.passthoughdevice : m_settings.device; ++ std::string driver; ++ CAESinkFactory::ParseDevice(device, driver); ++ if (m_settings.driver.compare(driver) != 0) ++ return true; ++ ++ if (!m_sink.IsCompatible(newFormat, device)) ++ return true; ++ ++ return false; ++} ++ ++void CActiveAE::InitSink() ++{ ++ SinkConfig config; ++ config.format = m_sinkRequestFormat; ++ config.stats = &m_stats; ++ ++ // send message to sink ++ Message *reply; ++ if (m_sink.m_controlPort.SendOutMessageSync(CSinkControlProtocol::CONFIGURE, ++ &reply, ++ 5000, ++ &config, sizeof(config))) ++ { ++ bool success = reply->signal == CSinkControlProtocol::ACC ? true : false; ++ if (!success) ++ { ++ reply->Release(); ++ CLog::Log(LOGERROR, "ActiveAE::%s - returned error", __FUNCTION__); ++ m_extError = true; ++ return; ++ } ++ AEAudioFormat *data; ++ data = (AEAudioFormat*)reply->data; ++ if (data) ++ { ++ m_sinkFormat = *data; ++ } ++ reply->Release(); ++ } ++ else ++ { ++ CLog::Log(LOGERROR, "ActiveAE::%s - failed to init", __FUNCTION__); ++ m_extError = true; ++ return; ++ } ++ ++ m_inMsgEvent.Reset(); ++} ++ ++void CActiveAE::DrainSink() ++{ ++ // send message to sink ++ Message *reply; ++ if (m_sink.m_dataPort.SendOutMessageSync(CSinkDataProtocol::DRAIN, ++ &reply, ++ 2000)) ++ { ++ bool success = reply->signal == CSinkDataProtocol::ACC ? true : false; ++ if (!success) ++ { ++ reply->Release(); ++ CLog::Log(LOGERROR, "ActiveAE::%s - returned error on drain", __FUNCTION__); ++ m_extError = true; ++ return; ++ } ++ reply->Release(); ++ } ++ else ++ { ++ CLog::Log(LOGERROR, "ActiveAE::%s - failed to drain", __FUNCTION__); ++ m_extError = true; ++ return; ++ } ++} ++ ++void CActiveAE::UnconfigureSink() ++{ ++ // send message to sink ++ Message *reply; ++ if (m_sink.m_controlPort.SendOutMessageSync(CSinkControlProtocol::UNCONFIGURE, ++ &reply, ++ 2000)) ++ { ++ bool success = reply->signal == CSinkControlProtocol::ACC ? true : false; ++ if (!success) ++ { ++ CLog::Log(LOGERROR, "ActiveAE::%s - returned error", __FUNCTION__); ++ m_extError = true; ++ } ++ reply->Release(); ++ } ++ else ++ { ++ CLog::Log(LOGERROR, "ActiveAE::%s - failed to unconfigure", __FUNCTION__); ++ m_extError = true; ++ } ++ ++ m_inMsgEvent.Reset(); ++} ++ ++ ++bool CActiveAE::RunStages() ++{ ++ bool busy = false; ++ ++ // serve input streams ++ std::list::iterator it; ++ for (it = m_streams.begin(); it != m_streams.end(); ++it) ++ { ++ if ((*it)->m_resampleBuffers && !(*it)->m_paused) ++ busy = (*it)->m_resampleBuffers->ResampleBuffers(); ++ else if ((*it)->m_resampleBuffers && !(*it)->m_resampleBuffers->m_inputSamples.empty()) ++ { ++ CSingleLock lock((*it)->m_streamLock); ++ (*it)->m_streamIsBuffering = false; ++ } ++ ++ // provide buffers to stream ++ float time = m_stats.GetCacheTime((*it)); ++ CSampleBuffer *buffer; ++ if (!(*it)->m_drain) ++ { ++ while (time < MAX_CACHE_LEVEL && !(*it)->m_inputBuffers->m_freeSamples.empty()) ++ { ++ buffer = (*it)->m_inputBuffers->GetFreeBuffer(); ++ (*it)->m_processingSamples.push_back(buffer); ++ (*it)->m_streamPort->SendInMessage(CActiveAEDataProtocol::STREAMBUFFER, &buffer, sizeof(CSampleBuffer*)); ++ (*it)->IncFreeBuffers(); ++ time += (float)buffer->pkt->max_nb_samples / buffer->pkt->config.sample_rate; ++ } ++ } ++ else ++ { ++ if ((*it)->m_inputBuffers->m_allSamples.size() == (*it)->m_inputBuffers->m_freeSamples.size()) ++ { ++ (*it)->m_streamPort->SendInMessage(CActiveAEDataProtocol::STREAMDRAINED); ++ (*it)->m_drain = false; ++ (*it)->m_resampleBuffers->m_drain = false; ++ (*it)->m_started = false; ++ ++ // set variables being polled via stream interface ++ CSingleLock lock((*it)->m_streamLock); ++ if ((*it)->m_streamSlave) ++ { ++ ((CActiveAEStream*)(*it)->m_streamSlave)->m_paused = false;; ++ (*it)->m_streamSlave = NULL; ++ } ++ (*it)->m_streamDrained = true; ++ (*it)->m_streamDraining = false; ++ } ++ } ++ } ++ ++ if (m_stats.GetWaterLevel() < MAX_WATER_LEVEL && ++ (m_mode != MODE_TRANSCODE || (m_encoderBuffers && !m_encoderBuffers->m_freeSamples.empty()))) ++ { ++ // mix streams and sounds sounds ++ if (m_mode != MODE_RAW) ++ { ++ CSampleBuffer *out = NULL; ++ if (!m_sounds_playing.empty() && m_streams.empty()) ++ { ++ if (m_silenceBuffers && !m_silenceBuffers->m_freeSamples.empty()) ++ { ++ out = m_silenceBuffers->GetFreeBuffer(); ++ for (int i=0; ipkt->planes; i++) ++ { ++ memset(out->pkt->data[i], 0, out->pkt->linesize); ++ } ++ out->pkt->nb_samples = out->pkt->max_nb_samples; ++ } ++ } ++ ++ // mix streams ++ std::list::iterator it; ++ ++ // if we deal with more than a single stream, all streams ++ // must provide samples for mixing ++ bool allStreamsReady = true; ++ for (it = m_streams.begin(); it != m_streams.end(); ++it) ++ { ++ if ((*it)->m_paused || !(*it)->m_started || !(*it)->m_resampleBuffers) ++ continue; ++ ++ if ((*it)->m_resampleBuffers->m_outputSamples.empty()) ++ allStreamsReady = false; ++ } ++ ++ for (it = m_streams.begin(); it != m_streams.end() && allStreamsReady; ++it) ++ { ++ if ((*it)->m_paused || !(*it)->m_resampleBuffers) ++ continue; ++ ++ if (!(*it)->m_resampleBuffers->m_outputSamples.empty()) ++ { ++ (*it)->m_started = true; ++ ++ if (!out) ++ { ++ out = (*it)->m_resampleBuffers->m_outputSamples.front(); ++ (*it)->m_resampleBuffers->m_outputSamples.pop_front(); ++ ++ // volume for stream ++ float amp = (*it)->m_rgain * CalcStreamAmplification((*it), out); ++ ++ int nb_floats = out->pkt->nb_samples * out->pkt->config.channels / out->pkt->planes; ++ int nb_loops = 1; ++ float fadingStep; ++ ++ // fading ++ if ((*it)->m_fadingSamples == -1) ++ { ++ (*it)->m_fadingSamples = m_internalFormat.m_sampleRate * (float)(*it)->m_fadingTime / 1000.0f; ++ (*it)->m_volume = (*it)->m_fadingBase; ++ } ++ if ((*it)->m_fadingSamples > 0) ++ { ++ nb_floats = out->pkt->config.channels / out->pkt->planes; ++ nb_loops = out->pkt->nb_samples; ++ float delta = (*it)->m_fadingTarget - (*it)->m_fadingBase; ++ int samples = m_internalFormat.m_sampleRate * (float)(*it)->m_fadingTime / 1000.0f; ++ fadingStep = delta / samples; ++ } ++ for(int i=0; im_fadingSamples > 0) ++ { ++ (*it)->m_volume += fadingStep; ++ (*it)->m_fadingSamples--; ++ ++ if ((*it)->m_fadingSamples == 0) ++ { ++ // set variables being polled via stream interface ++ CSingleLock lock((*it)->m_streamLock); ++ (*it)->m_streamFading = false; ++ } ++ } ++ float volume = (*it)->m_volume * amp; ++ ++ for(int j=0; jpkt->planes; j++) ++ { ++#ifdef __SSE__ ++ CAEUtil::SSEMulArray((float*)out->pkt->data[j]+i*nb_floats, m_muted ? 0.0 : volume, nb_floats); ++#else ++ float* fbuffer = (float*) out->pkt->data[j]+i*nb_floats; ++ for (int k = 0; k < nb_floats; ++k) ++ *fbuffer++ *= m_muted ? 0.0 : volume; ++#endif ++ } ++ } ++ } ++ else ++ { ++ CSampleBuffer *mix = NULL; ++ mix = (*it)->m_resampleBuffers->m_outputSamples.front(); ++ (*it)->m_resampleBuffers->m_outputSamples.pop_front(); ++ ++ // volume for stream ++ float amp = (*it)->m_volume * (*it)->m_rgain * CalcStreamAmplification((*it), mix); ++ ++ int nb_floats = mix->pkt->nb_samples * mix->pkt->config.channels / mix->pkt->planes; ++ int nb_loops = 1; ++ float fadingStep; ++ ++ // fading ++ if ((*it)->m_fadingSamples == -1) ++ { ++ (*it)->m_fadingSamples = m_internalFormat.m_sampleRate * (float)(*it)->m_fadingTime / 1000.0f; ++ (*it)->m_volume = (*it)->m_fadingBase; ++ } ++ if ((*it)->m_fadingSamples > 0) ++ { ++ nb_floats = mix->pkt->config.channels / mix->pkt->planes; ++ nb_loops = mix->pkt->nb_samples; ++ float delta = (*it)->m_fadingTarget - (*it)->m_fadingBase; ++ int samples = m_internalFormat.m_sampleRate * (float)(*it)->m_fadingTime / 1000.0f; ++ fadingStep = delta / samples; ++ } ++ for(int i=0; im_fadingSamples > 0) ++ { ++ (*it)->m_volume += fadingStep; ++ (*it)->m_fadingSamples--; ++ ++ if ((*it)->m_fadingSamples == 0) ++ { ++ // set variables being polled via stream interface ++ CSingleLock lock((*it)->m_streamLock); ++ (*it)->m_streamFading = false; ++ } ++ } ++ float volume = (*it)->m_volume * amp; ++ ++ for(int j=0; jpkt->planes && jpkt->planes; j++) ++ { ++ float *dst = (float*)out->pkt->data[j]+i*nb_floats; ++ float *src = (float*)mix->pkt->data[j]+i*nb_floats; ++#ifdef __SSE__ ++ CAEUtil::SSEMulAddArray(dst, src, m_muted ? 0.0 : volume, nb_floats); ++#else ++ for (int k = 0; k < nb_floats; ++k) ++ *dst++ += *src++ * m_muted ? 0.0 : volume; ++#endif ++ } ++ } ++ mix->Return(); ++ } ++ busy = true; ++ } ++ } ++ ++ // process output buffer, gui sounds, encode, viz ++ if (out) ++ { ++ // mix gui sounds ++ MixSounds(*(out->pkt)); ++ Deamplify(*(out->pkt)); ++ ++ // viz ++ { ++ CSingleLock lock(m_vizLock); ++ if (m_audioCallback) ++ { ++ if (!m_vizInitialized) ++ { ++ m_audioCallback->OnInitialize(2, m_vizBuffers->m_format.m_sampleRate, 32); ++ m_vizInitialized = true; ++ } ++ ++ // if viz has no free buffer, it won't return current buffer "out" ++ if (!m_vizBuffers->m_freeSamples.empty()) ++ { ++ out->Acquire(); ++ m_vizBuffers->m_inputSamples.push_back(out); ++ } ++ else ++ CLog::Log(LOGWARNING,"ActiveAE::%s - viz ran out of free buffers", __FUNCTION__); ++ unsigned int now = XbmcThreads::SystemClockMillis(); ++ unsigned int timestamp = now + m_stats.GetDelay() * 1000; ++ m_vizBuffers->ResampleBuffers(timestamp); ++ while(!m_vizBuffers->m_outputSamples.empty()) ++ { ++ CSampleBuffer *buf = m_vizBuffers->m_outputSamples.front(); ++ if ((now - buf->timestamp) & 0x80000000) ++ break; ++ else ++ { ++ int submitted = 0; ++ int samples; ++ while(submitted < buf->pkt->nb_samples) ++ { ++ samples = std::min(512, buf->pkt->nb_samples-submitted); ++ m_audioCallback->OnAudioData((float*)(buf->pkt->data[0]+2*submitted), samples); ++ submitted += samples; ++ } ++ buf->Return(); ++ m_vizBuffers->m_outputSamples.pop_front(); ++ } ++ } ++ } ++ else if (m_vizBuffers) ++ m_vizBuffers->Flush(); ++ } ++ ++ // encode ++ if (m_mode == MODE_TRANSCODE && m_encoder) ++ { ++ CSampleBuffer *buf = m_encoderBuffers->GetFreeBuffer(); ++ int ret = m_encoder->Encode(out->pkt->data[0], out->pkt->planes*out->pkt->linesize, ++ buf->pkt->data[0], buf->pkt->planes*buf->pkt->linesize); ++ buf->pkt->nb_samples = buf->pkt->max_nb_samples; ++ out->Return(); ++ out = buf; ++ } ++ ++ // update stats ++ m_stats.AddSamples(out->pkt->nb_samples, m_streams); ++ m_sinkBuffers->m_inputSamples.push_back(out); ++ ++ busy = true; ++ } ++ } ++ // pass through ++ else ++ { ++ std::list::iterator it; ++ CSampleBuffer *buffer; ++ for (it = m_streams.begin(); it != m_streams.end(); ++it) ++ { ++ if (!(*it)->m_resampleBuffers->m_outputSamples.empty()) ++ { ++ buffer = (*it)->m_resampleBuffers->m_outputSamples.front(); ++ (*it)->m_resampleBuffers->m_outputSamples.pop_front(); ++ m_stats.AddSamples(buffer->pkt->nb_samples, m_streams); ++ m_sinkBuffers->m_inputSamples.push_back(buffer); ++ } ++ } ++ } ++ ++ // serve sink buffers ++ busy = m_sinkBuffers->ResampleBuffers(); ++ while(!m_sinkBuffers->m_outputSamples.empty()) ++ { ++ CSampleBuffer *out = NULL; ++ out = m_sinkBuffers->m_outputSamples.front(); ++ m_sinkBuffers->m_outputSamples.pop_front(); ++ m_sink.m_dataPort.SendOutMessage(CSinkDataProtocol::SAMPLE, ++ &out, sizeof(CSampleBuffer*)); ++ busy = true; ++ } ++ } ++ ++ return busy; ++} ++ ++bool CActiveAE::HasWork() ++{ ++ if (!m_sounds_playing.empty()) ++ return true; ++ if (!m_sinkBuffers->m_inputSamples.empty()) ++ return true; ++ if (!m_sinkBuffers->m_outputSamples.empty()) ++ return true; ++ ++ std::list::iterator it; ++ for (it = m_streams.begin(); it != m_streams.end(); ++it) ++ { ++ if (!(*it)->m_resampleBuffers->m_inputSamples.empty()) ++ return true; ++ if (!(*it)->m_resampleBuffers->m_outputSamples.empty()) ++ return true; ++ if (!(*it)->m_processingSamples.empty()) ++ return true; ++ } ++ ++ return false; ++} ++ ++void CActiveAE::MixSounds(CSoundPacket &dstSample) ++{ ++ if (m_sounds_playing.empty()) ++ return; ++ ++ float volume; ++ float *out; ++ float *sample_buffer; ++ int max_samples = dstSample.nb_samples; ++ ++ std::list::iterator it; ++ for (it = m_sounds_playing.begin(); it != m_sounds_playing.end(); ) ++ { ++ if (!it->sound->IsConverted()) ++ ResampleSound(it->sound); ++ int available_samples = it->sound->GetSound(false)->nb_samples - it->samples_played; ++ int mix_samples = std::min(max_samples, available_samples); ++ int start = it->samples_played * ++ m_dllAvUtil.av_get_bytes_per_sample(it->sound->GetSound(false)->config.fmt) * ++ it->sound->GetSound(false)->config.channels / ++ it->sound->GetSound(false)->planes; ++ ++ for(int j=0; jsound->GetVolume(); ++ out = (float*)dstSample.data[j]; ++ sample_buffer = (float*)(it->sound->GetSound(false)->data[j]+start); ++ int nb_floats = mix_samples * dstSample.config.channels / dstSample.planes; ++#ifdef __SSE__ ++ CAEUtil::SSEMulAddArray(out, sample_buffer, volume, nb_floats); ++#else ++ for (int k = 0; k < nb_floats; ++k) ++ *out++ += *sample_buffer++ * volume; ++#endif ++ } ++ ++ it->samples_played += mix_samples; ++ ++ // no more frames, so remove it from the list ++ if (it->samples_played >= it->sound->GetSound(false)->nb_samples) ++ { ++ it = m_sounds_playing.erase(it); ++ continue; ++ } ++ ++it; ++ } ++} ++ ++void CActiveAE::Deamplify(CSoundPacket &dstSample) ++{ ++ if (m_volume < 1.0) ++ { ++ float *buffer; ++ int nb_floats = dstSample.nb_samples * dstSample.config.channels / dstSample.planes; ++ ++ for(int j=0; jsignal == CActiveAEControlProtocol::ACC ? true : false; ++ reply->Release(); ++ if (!success) ++ { ++ CLog::Log(LOGERROR, "ActiveAE::%s - returned error", __FUNCTION__); ++ Dispose(); ++ return false; ++ } ++ } ++ else ++ { ++ CLog::Log(LOGERROR, "ActiveAE::%s - failed to init", __FUNCTION__); ++ Dispose(); ++ return false; ++ } ++ ++ // hook into windowing for receiving display reset events ++#if defined(HAS_GLX) || defined(TARGET_DARWIN_OSX) ++ g_Windowing.Register(this); ++#endif ++ ++ m_inMsgEvent.Reset(); ++ return true; ++} ++ ++void CActiveAE::EnumerateOutputDevices(AEDeviceList &devices, bool passthrough) ++{ ++ m_sink.EnumerateOutputDevices(devices, passthrough); ++} ++ ++std::string CActiveAE::GetDefaultDevice(bool passthrough) ++{ ++ return m_sink.GetDefaultDevice(passthrough); ++} ++ ++void CActiveAE::OnSettingsChange(const std::string& setting) ++{ ++ if (setting == "audiooutput.passthroughdevice" || ++ setting == "audiooutput.audiodevice" || ++ setting == "audiooutput.mode" || ++ setting == "audiooutput.ac3passthrough" || ++ setting == "audiooutput.dtspassthrough" || ++ setting == "audiooutput.passthroughaac" || ++ setting == "audiooutput.truehdpassthrough" || ++ setting == "audiooutput.dtshdpassthrough" || ++ setting == "audiooutput.channels" || ++ setting == "audiooutput.multichannellpcm" || ++ setting == "audiooutput.stereoupmix") ++ { ++ m_controlPort.SendOutMessage(CActiveAEControlProtocol::RECONFIGURE); ++ } ++} ++ ++bool CActiveAE::SupportsRaw() ++{ ++ return true; ++} ++ ++void CActiveAE::Shutdown() ++{ ++ Dispose(); ++} ++ ++bool CActiveAE::Suspend() ++{ ++ return m_controlPort.SendOutMessage(CActiveAEControlProtocol::SUSPEND); ++} ++ ++bool CActiveAE::Resume() ++{ ++ Message *reply; ++ if (m_controlPort.SendOutMessageSync(CActiveAEControlProtocol::INIT, ++ &reply, ++ 5000)) ++ { ++ bool success = reply->signal == CActiveAEControlProtocol::ACC ? true : false; ++ reply->Release(); ++ if (!success) ++ { ++ CLog::Log(LOGERROR, "ActiveAE::%s - returned error", __FUNCTION__); ++ return false; ++ } ++ } ++ else ++ { ++ CLog::Log(LOGERROR, "ActiveAE::%s - failed to init", __FUNCTION__); ++ return false; ++ } ++ ++ m_inMsgEvent.Reset(); ++ return true; ++} ++ ++bool CActiveAE::IsSuspended() ++{ ++ return m_stats.IsSuspended(); ++} ++ ++float CActiveAE::GetVolume() ++{ ++ return m_aeVolume; ++} ++ ++void CActiveAE::SetVolume(const float volume) ++{ ++ m_aeVolume = std::max( 0.0f, std::min(1.0f, volume)); ++ m_controlPort.SendOutMessage(CActiveAEControlProtocol::VOLUME, &m_aeVolume, sizeof(float)); ++} ++ ++void CActiveAE::SetMute(const bool enabled) ++{ ++ m_aeMuted = enabled; ++ m_controlPort.SendOutMessage(CActiveAEControlProtocol::MUTE, &m_aeMuted, sizeof(bool)); ++} ++ ++bool CActiveAE::IsMuted() ++{ ++ return m_aeMuted; ++} ++ ++void CActiveAE::SetSoundMode(const int mode) ++{ ++ int soundmode = mode; ++ m_controlPort.SendOutMessage(CActiveAEControlProtocol::SOUNDMODE, &soundmode, sizeof(int)); ++} ++ ++ ++void CActiveAE::OnLostDevice() ++{ ++// m_controlPort.SendOutMessage(CActiveAEControlProtocol::DISPLAYLOST); ++} ++ ++void CActiveAE::OnResetDevice() ++{ ++// m_controlPort.SendOutMessage(CActiveAEControlProtocol::DISPLAYRESET); ++} ++ ++//----------------------------------------------------------------------------- ++// Utils ++//----------------------------------------------------------------------------- ++ ++uint8_t **CActiveAE::AllocSoundSample(SampleConfig &config, int &samples, int &bytes_per_sample, int &planes, int &linesize) ++{ ++ uint8_t **buffer; ++ planes = m_dllAvUtil.av_sample_fmt_is_planar(config.fmt) ? config.channels : 1; ++ buffer = new uint8_t*[planes]; ++ m_dllAvUtil.av_samples_alloc(buffer, &linesize, config.channels, ++ samples, config.fmt, 0); ++ bytes_per_sample = m_dllAvUtil.av_get_bytes_per_sample(config.fmt); ++ return buffer; ++} ++ ++void CActiveAE::FreeSoundSample(uint8_t **data) ++{ ++ m_dllAvUtil.av_freep(data); ++ delete [] data; ++} ++ ++//----------------------------------------------------------------------------- ++// GUI Sounds ++//----------------------------------------------------------------------------- ++ ++/** ++ * load sound from an audio file and store original format ++ * register the sound in ActiveAE ++ * later when the engine is idle it will convert the sound to sink format ++ */ ++ ++#define SOUNDBUFFER_SIZE 20480 ++ ++IAESound *CActiveAE::MakeSound(const std::string& file) ++{ ++ AVFormatContext *fmt_ctx = NULL; ++ AVCodecContext *dec_ctx = NULL; ++ AVIOContext *io_ctx; ++ AVInputFormat *io_fmt; ++ AVCodec *dec = NULL; ++ int bit_rate; ++ CActiveAESound *sound = NULL; ++ SampleConfig config; ++ ++ sound = new CActiveAESound(file); ++ if (!sound->Prepare()) ++ return NULL; ++ int fileSize = sound->GetFileSize(); ++ ++ fmt_ctx = m_dllAvFormat.avformat_alloc_context(); ++ unsigned char* buffer = (unsigned char*)m_dllAvUtil.av_malloc(SOUNDBUFFER_SIZE+FF_INPUT_BUFFER_PADDING_SIZE); ++ io_ctx = m_dllAvFormat.avio_alloc_context(buffer, SOUNDBUFFER_SIZE, 0, ++ sound, CActiveAESound::Read, NULL, CActiveAESound::Seek); ++ io_ctx->max_packet_size = sound->GetChunkSize(); ++ if(io_ctx->max_packet_size) ++ io_ctx->max_packet_size *= SOUNDBUFFER_SIZE / io_ctx->max_packet_size; ++ ++ if(!sound->IsSeekPosible()) ++ io_ctx->seekable = 0; ++ ++ fmt_ctx->pb = io_ctx; ++ ++ m_dllAvFormat.av_probe_input_buffer(io_ctx, &io_fmt, file.c_str(), NULL, 0, 0); ++ if (!io_fmt) ++ { ++ m_dllAvFormat.avformat_close_input(&fmt_ctx); ++ delete sound; ++ return NULL; ++ } ++ ++ // find decoder ++ if (m_dllAvFormat.avformat_open_input(&fmt_ctx, file.c_str(), NULL, NULL) == 0) ++ { ++ fmt_ctx->flags |= AVFMT_FLAG_NOPARSE; ++ if (m_dllAvFormat.avformat_find_stream_info(fmt_ctx, NULL) >= 0) ++ { ++ dec_ctx = fmt_ctx->streams[0]->codec; ++ dec = m_dllAvCodec.avcodec_find_decoder(dec_ctx->codec_id); ++ config.sample_rate = dec_ctx->sample_rate; ++ bit_rate = dec_ctx->bit_rate; ++ config.channels = dec_ctx->channels; ++ config.channel_layout = dec_ctx->channel_layout; ++ } ++ } ++ if (dec == NULL) ++ { ++ m_dllAvFormat.avformat_close_input(&fmt_ctx); ++ delete sound; ++ return NULL; ++ } ++ ++ dec_ctx = m_dllAvCodec.avcodec_alloc_context3(dec); ++ dec_ctx->sample_rate = config.sample_rate; ++ dec_ctx->channels = config.channels; ++ if (!config.channel_layout) ++ config.channel_layout = m_dllAvUtil.av_get_default_channel_layout(config.channels); ++ dec_ctx->channel_layout = config.channel_layout; ++ ++ AVPacket avpkt; ++ AVFrame *decoded_frame = NULL; ++ decoded_frame = m_dllAvCodec.avcodec_alloc_frame(); ++ ++ if (m_dllAvCodec.avcodec_open2(dec_ctx, dec, NULL) >= 0) ++ { ++ bool init = false; ++ ++ // decode until eof ++ m_dllAvCodec.av_init_packet(&avpkt); ++ int len; ++ while (m_dllAvFormat.av_read_frame(fmt_ctx, &avpkt) >= 0) ++ { ++ int got_frame = 0; ++ len = m_dllAvCodec.avcodec_decode_audio4(dec_ctx, decoded_frame, &got_frame, &avpkt); ++ if (len < 0) ++ { ++ m_dllAvCodec.avcodec_close(dec_ctx); ++ m_dllAvUtil.av_free(dec_ctx); ++ m_dllAvUtil.av_free(&decoded_frame); ++ m_dllAvFormat.avformat_close_input(&fmt_ctx); ++ delete sound; ++ return NULL; ++ } ++ if (got_frame) ++ { ++ if (!init) ++ { ++ int samples = fileSize / m_dllAvUtil.av_get_bytes_per_sample(dec_ctx->sample_fmt) / config.channels; ++ config.fmt = dec_ctx->sample_fmt; ++ sound->InitSound(true, config, samples); ++ init = true; ++ } ++ sound->StoreSound(true, decoded_frame->extended_data, ++ decoded_frame->nb_samples, decoded_frame->linesize[0]); ++ } ++ } ++ m_dllAvCodec.avcodec_close(dec_ctx); ++ } ++ ++ m_dllAvUtil.av_free(dec_ctx); ++ m_dllAvUtil.av_free(decoded_frame); ++ m_dllAvFormat.avformat_close_input(&fmt_ctx); ++ ++ sound->Finish(); ++ ++ // register sound ++ m_dataPort.SendOutMessage(CActiveAEDataProtocol::NEWSOUND, &sound, sizeof(CActiveAESound*)); ++ ++ return sound; ++} ++ ++void CActiveAE::FreeSound(IAESound *sound) ++{ ++ m_dataPort.SendOutMessage(CActiveAEDataProtocol::FREESOUND, &sound, sizeof(CActiveAESound*)); ++} ++ ++void CActiveAE::PlaySound(CActiveAESound *sound) ++{ ++ m_dataPort.SendOutMessage(CActiveAEDataProtocol::PLAYSOUND, &sound, sizeof(CActiveAESound*)); ++} ++ ++void CActiveAE::StopSound(CActiveAESound *sound) ++{ ++ m_controlPort.SendOutMessage(CActiveAEControlProtocol::STOPSOUND, &sound, sizeof(CActiveAESound*)); ++} ++ ++/** ++ * resample sounds to destination format for mixing ++ * destination format is either format of stream or ++ * default sink format when no stream is playing ++ */ ++void CActiveAE::ResampleSounds() ++{ ++ std::vector::iterator it; ++ for (it = m_sounds.begin(); it != m_sounds.end(); ++it) ++ { ++ if (!(*it)->IsConverted()) ++ ResampleSound(*it); ++ } ++} ++ ++bool CActiveAE::ResampleSound(CActiveAESound *sound) ++{ ++ SampleConfig orig_config, dst_config; ++ uint8_t **dst_buffer; ++ int dst_samples; ++ ++ if (m_mode == MODE_RAW || m_internalFormat.m_dataFormat == AE_FMT_INVALID) ++ return false; ++ ++ if (!sound->GetSound(true)) ++ return false; ++ ++ orig_config = sound->GetSound(true)->config; ++ ++ dst_config.channel_layout = CActiveAEResample::GetAVChannelLayout(m_internalFormat.m_channelLayout); ++ dst_config.channels = m_internalFormat.m_channelLayout.Count(); ++ dst_config.sample_rate = m_internalFormat.m_sampleRate; ++ dst_config.fmt = CActiveAEResample::GetAVSampleFormat(m_internalFormat.m_dataFormat); ++ ++ CActiveAEResample *resampler = new CActiveAEResample(); ++ resampler->Init(dst_config.channel_layout, ++ dst_config.channels, ++ dst_config.sample_rate, ++ dst_config.fmt, ++ orig_config.channel_layout, ++ orig_config.channels, ++ orig_config.sample_rate, ++ orig_config.fmt, ++ NULL); ++ ++ dst_samples = resampler->CalcDstSampleCount(sound->GetSound(true)->nb_samples, ++ m_internalFormat.m_sampleRate, ++ orig_config.sample_rate); ++ ++ dst_buffer = sound->InitSound(false, dst_config, dst_samples); ++ if (!dst_buffer) ++ { ++ delete resampler; ++ return false; ++ } ++ int samples = resampler->Resample(dst_buffer, dst_samples, ++ sound->GetSound(true)->data, ++ sound->GetSound(true)->nb_samples); ++ ++ sound->GetSound(false)->nb_samples = samples; ++ ++ delete resampler; ++ sound->SetConverted(true); ++ return true; ++} ++ ++//----------------------------------------------------------------------------- ++// Streams ++//----------------------------------------------------------------------------- ++ ++IAEStream *CActiveAE::MakeStream(enum AEDataFormat dataFormat, unsigned int sampleRate, unsigned int encodedSampleRate, CAEChannelInfo channelLayout, unsigned int options) ++{ ++ //TODO: pass number of samples in audio packet ++ ++ AEAudioFormat format; ++ format.m_dataFormat = dataFormat; ++ format.m_sampleRate = sampleRate; ++ format.m_encodedRate = encodedSampleRate; ++ format.m_channelLayout = channelLayout; ++ format.m_frames = format.m_sampleRate / 10; ++ format.m_frameSize = format.m_channelLayout.Count() * ++ (CAEUtil::DataFormatToBits(format.m_dataFormat) >> 3); ++ ++ MsgStreamNew msg; ++ msg.format = format; ++ msg.options = options; ++ ++ Message *reply; ++ if (m_dataPort.SendOutMessageSync(CActiveAEDataProtocol::NEWSTREAM, ++ &reply,1000, ++ &msg, sizeof(MsgStreamNew))) ++ { ++ bool success = reply->signal == CActiveAEControlProtocol::ACC ? true : false; ++ if (success) ++ { ++ CActiveAEStream *stream = *(CActiveAEStream**)reply->data; ++ reply->Release(); ++ return stream; ++ } ++ reply->Release(); ++ } ++ ++ CLog::Log(LOGERROR, "ActiveAE::%s - could not create stream", __FUNCTION__); ++ return NULL; ++} ++ ++IAEStream *CActiveAE::FreeStream(IAEStream *stream) ++{ ++ m_dataPort.SendOutMessage(CActiveAEDataProtocol::FREESTREAM, &stream, sizeof(IAEStream*)); ++ return NULL; ++} ++ ++void CActiveAE::FlushStream(CActiveAEStream *stream) ++{ ++ Message *reply; ++ if (m_dataPort.SendOutMessageSync(CActiveAEDataProtocol::FLUSHSTREAM, ++ &reply,1000, ++ &stream, sizeof(CActiveAEStream*))) ++ { ++ bool success = reply->signal == CActiveAEDataProtocol::ACC ? true : false; ++ reply->Release(); ++ if (!success) ++ { ++ CLog::Log(LOGERROR, "CActiveAE::FlushStream - failed"); ++ } ++ } ++} ++ ++void CActiveAE::PauseStream(CActiveAEStream *stream, bool pause) ++{ ++ // TODO pause sink, needs api change ++ if (pause) ++ m_controlPort.SendOutMessage(CActiveAEControlProtocol::PAUSESTREAM, ++ &stream, sizeof(CActiveAEStream*)); ++ else ++ m_controlPort.SendOutMessage(CActiveAEControlProtocol::RESUMESTREAM, ++ &stream, sizeof(CActiveAEStream*)); ++} ++ ++void CActiveAE::SetStreamAmplification(CActiveAEStream *stream, float amplify) ++{ ++ MsgStreamParameter msg; ++ msg.stream = stream; ++ msg.parameter.float_par = amplify; ++ m_controlPort.SendOutMessage(CActiveAEControlProtocol::STREAMAMP, ++ &msg, sizeof(MsgStreamParameter)); ++} ++ ++void CActiveAE::SetStreamReplaygain(CActiveAEStream *stream, float rgain) ++{ ++ MsgStreamParameter msg; ++ msg.stream = stream; ++ msg.parameter.float_par = rgain; ++ m_controlPort.SendOutMessage(CActiveAEControlProtocol::STREAMRGAIN, ++ &msg, sizeof(MsgStreamParameter)); ++} ++ ++void CActiveAE::SetStreamVolume(CActiveAEStream *stream, float volume) ++{ ++ MsgStreamParameter msg; ++ msg.stream = stream; ++ msg.parameter.float_par = volume; ++ m_controlPort.SendOutMessage(CActiveAEControlProtocol::STREAMVOLUME, ++ &msg, sizeof(MsgStreamParameter)); ++} ++ ++void CActiveAE::SetStreamResampleRatio(CActiveAEStream *stream, double ratio) ++{ ++ MsgStreamParameter msg; ++ msg.stream = stream; ++ msg.parameter.double_par = ratio; ++ m_controlPort.SendOutMessage(CActiveAEControlProtocol::STREAMRESAMPLERATIO, ++ &msg, sizeof(MsgStreamParameter)); ++} ++ ++void CActiveAE::SetStreamFade(CActiveAEStream *stream, float from, float target, unsigned int millis) ++{ ++ MsgStreamFade msg; ++ msg.stream = stream; ++ msg.from = from; ++ msg.target = target; ++ msg.millis = millis; ++ m_controlPort.SendOutMessage(CActiveAEControlProtocol::STREAMFADE, ++ &msg, sizeof(MsgStreamFade)); ++} ++ ++void CActiveAE::RegisterAudioCallback(IAudioCallback* pCallback) ++{ ++ CSingleLock lock(m_vizLock); ++ m_audioCallback = pCallback; ++ m_vizInitialized = false; ++} ++ ++void CActiveAE::UnregisterAudioCallback() ++{ ++ CSingleLock lock(m_vizLock); ++ m_audioCallback = NULL; ++} +diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.h b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.h +new file mode 100644 +index 0000000..30da1ac +--- /dev/null ++++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.h +@@ -0,0 +1,332 @@ ++#pragma once ++/* ++ * Copyright (C) 2010-2013 Team XBMC ++ * http://xbmc.org ++ * ++ * This Program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2, or (at your option) ++ * any later version. ++ * ++ * This Program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with XBMC; see the file COPYING. If not, see ++ * . ++ * ++ */ ++ ++#include "system.h" ++#include "threads/Thread.h" ++ ++#include "ActiveAESink.h" ++#include "ActiveAEResample.h" ++#include "Interfaces/AEStream.h" ++#include "Interfaces/AESound.h" ++#include "AEFactory.h" ++#include "guilib/DispResource.h" ++ ++// ffmpeg ++#include "DllAvFormat.h" ++#include "DllAvCodec.h" ++#include "DllAvUtil.h" ++ ++class IAESink; ++class IAEEncoder; ++ ++namespace ActiveAE ++{ ++ ++class CActiveAESound; ++class CActiveAEStream; ++ ++struct AudioSettings ++{ ++ std::string device; ++ std::string driver; ++ std::string passthoughdevice; ++ int mode; ++ int channels; ++ bool ac3passthrough; ++ bool dtspassthrough; ++ bool aacpassthrough; ++ bool truehdpassthrough; ++ bool dtshdpassthrough; ++ bool multichannellpcm; ++ bool stereoupmix; ++}; ++ ++class CActiveAEControlProtocol : public Protocol ++{ ++public: ++ CActiveAEControlProtocol(std::string name, CEvent* inEvent, CEvent *outEvent) : Protocol(name, inEvent, outEvent) {}; ++ enum OutSignal ++ { ++ INIT = 0, ++ RECONFIGURE, ++ SUSPEND, ++ MUTE, ++ VOLUME, ++ PAUSESTREAM, ++ RESUMESTREAM, ++ STREAMRGAIN, ++ STREAMVOLUME, ++ STREAMAMP, ++ STREAMRESAMPLERATIO, ++ STREAMFADE, ++ STOPSOUND, ++ SOUNDMODE, ++ GETSTATE, ++ DISPLAYLOST, ++ DISPLAYRESET, ++ TIMEOUT, ++ }; ++ enum InSignal ++ { ++ ACC, ++ ERR, ++ STATS, ++ }; ++}; ++ ++class CActiveAEDataProtocol : public Protocol ++{ ++public: ++ CActiveAEDataProtocol(std::string name, CEvent* inEvent, CEvent *outEvent) : Protocol(name, inEvent, outEvent) {}; ++ enum OutSignal ++ { ++ NEWSOUND = 0, ++ PLAYSOUND, ++ FREESOUND, ++ NEWSTREAM, ++ FREESTREAM, ++ STREAMSAMPLE, ++ DRAINSTREAM, ++ FLUSHSTREAM, ++ }; ++ enum InSignal ++ { ++ ACC, ++ ERR, ++ STREAMBUFFER, ++ STREAMDRAINED, ++ }; ++}; ++ ++struct MsgStreamNew ++{ ++ AEAudioFormat format; ++ unsigned int options; ++}; ++ ++struct MsgStreamSample ++{ ++ CSampleBuffer *buffer; ++ CActiveAEStream *stream; ++}; ++ ++struct MsgStreamParameter ++{ ++ CActiveAEStream *stream; ++ union ++ { ++ float float_par; ++ double double_par; ++ } parameter; ++}; ++ ++struct MsgStreamFade ++{ ++ CActiveAEStream *stream; ++ float from; ++ float target; ++ unsigned int millis; ++}; ++ ++class CEngineStats ++{ ++public: ++ void Reset(unsigned int sampleRate); ++ void UpdateSinkDelay(double delay, int samples); ++ void AddSamples(int samples, std::list &streams); ++ float GetDelay(); ++ float GetDelay(CActiveAEStream *stream); ++ float GetCacheTime(CActiveAEStream *stream); ++ float GetCacheTotal(CActiveAEStream *stream); ++ float GetWaterLevel(); ++ void SetSuspended(bool state); ++ void SetSinkCacheTotal(float time) { m_sinkCacheTotal = time; } ++ bool IsSuspended(); ++ CCriticalSection *GetLock() { return &m_lock; } ++protected: ++ float m_sinkDelay; ++ float m_sinkCacheTotal; ++ int m_bufferedSamples; ++ unsigned int m_sinkSampleRate; ++ unsigned int m_sinkUpdate; ++ bool m_suspended; ++ CCriticalSection m_lock; ++}; ++ ++#if defined(HAS_GLX) || defined(TARGET_DARWIN_OSX) ++class CActiveAE : public IAE, public IDispResource, private CThread ++#else ++class CActiveAE : public IAE, private CThread ++#endif ++{ ++protected: ++ friend class ::CAEFactory; ++ friend class CActiveAESound; ++ friend class CActiveAEStream; ++ friend class CSoundPacket; ++ friend class CActiveAEBufferPoolResample; ++ CActiveAE(); ++ virtual ~CActiveAE(); ++ virtual bool Initialize(); ++ ++public: ++ virtual void Shutdown(); ++ virtual bool Suspend(); ++ virtual bool Resume(); ++ virtual bool IsSuspended(); ++ virtual void OnSettingsChange(const std::string& setting); ++ ++ virtual float GetVolume(); ++ virtual void SetVolume(const float volume); ++ virtual void SetMute(const bool enabled); ++ virtual bool IsMuted(); ++ virtual void SetSoundMode(const int mode); ++ ++ /* returns a new stream for data in the specified format */ ++ virtual IAEStream *MakeStream(enum AEDataFormat dataFormat, unsigned int sampleRate, unsigned int encodedSampleRate, CAEChannelInfo channelLayout, unsigned int options = 0); ++ virtual IAEStream *FreeStream(IAEStream *stream); ++ ++ /* returns a new sound object */ ++ virtual IAESound *MakeSound(const std::string& file); ++ virtual void FreeSound(IAESound *sound); ++ ++ virtual void GarbageCollect() {}; ++ ++ virtual void EnumerateOutputDevices(AEDeviceList &devices, bool passthrough); ++ virtual std::string GetDefaultDevice(bool passthrough); ++ virtual bool SupportsRaw(); ++ ++ virtual void RegisterAudioCallback(IAudioCallback* pCallback); ++ virtual void UnregisterAudioCallback(); ++ ++ virtual void OnLostDevice(); ++ virtual void OnResetDevice(); ++ ++protected: ++ void PlaySound(CActiveAESound *sound); ++ uint8_t **AllocSoundSample(SampleConfig &config, int &samples, int &bytes_per_sample, int &planes, int &linesize); ++ void FreeSoundSample(uint8_t **data); ++ float GetDelay(CActiveAEStream *stream) { return m_stats.GetDelay(stream); } ++ float GetCacheTime(CActiveAEStream *stream) { return m_stats.GetCacheTime(stream); } ++ float GetCacheTotal(CActiveAEStream *stream) { return m_stats.GetCacheTotal(stream); } ++ void FlushStream(CActiveAEStream *stream); ++ void PauseStream(CActiveAEStream *stream, bool pause); ++ void StopSound(CActiveAESound *sound); ++ void SetStreamAmplification(CActiveAEStream *stream, float amplify); ++ void SetStreamReplaygain(CActiveAEStream *stream, float rgain); ++ void SetStreamVolume(CActiveAEStream *stream, float volume); ++ void SetStreamResampleRatio(CActiveAEStream *stream, double ratio); ++ void SetStreamFade(CActiveAEStream *stream, float from, float target, unsigned int millis); ++ ++protected: ++ void Process(); ++ void StateMachine(int signal, Protocol *port, Message *msg); ++ void InitSink(); ++ void DrainSink(); ++ void UnconfigureSink(); ++ void Start(); ++ void Dispose(); ++ void LoadSettings(); ++ bool NeedReconfigureBuffers(); ++ bool NeedReconfigureSink(); ++ void ApplySettingsToFormat(AEAudioFormat &format, AudioSettings &settings); ++ void Configure(); ++ CActiveAEStream* CreateStream(MsgStreamNew *streamMsg); ++ void DiscardStream(CActiveAEStream *stream); ++ void SFlushStream(CActiveAEStream *stream); ++ void ClearDiscardedBuffers(); ++ void SStopSound(CActiveAESound *sound); ++ void DiscardSound(CActiveAESound *sound); ++ float CalcStreamAmplification(CActiveAEStream *stream, CSampleBuffer *buf); ++ ++ bool RunStages(); ++ bool HasWork(); ++ ++ void ResampleSounds(); ++ bool ResampleSound(CActiveAESound *sound); ++ void MixSounds(CSoundPacket &dstSample); ++ void Deamplify(CSoundPacket &dstSample); ++ ++ CEvent m_inMsgEvent; ++ CEvent m_outMsgEvent; ++ CActiveAEControlProtocol m_controlPort; ++ CActiveAEDataProtocol m_dataPort; ++ int m_state; ++ bool m_bStateMachineSelfTrigger; ++ int m_extTimeout; ++ bool m_extError; ++ bool m_extDrain; ++ XbmcThreads::EndTime m_extDrainTimer; ++ ++ enum ++ { ++ MODE_RAW, ++ MODE_TRANSCODE, ++ MODE_PCM ++ }m_mode; ++ ++ CActiveAESink m_sink; ++ AEAudioFormat m_sinkFormat; ++ AEAudioFormat m_sinkRequestFormat; ++ AEAudioFormat m_encoderFormat; ++ AEAudioFormat m_internalFormat; ++ AudioSettings m_settings; ++ CEngineStats m_stats; ++ IAEEncoder *m_encoder; ++ ++ // buffers ++ CActiveAEBufferPoolResample *m_sinkBuffers; ++ CActiveAEBufferPoolResample *m_vizBuffers; ++ CActiveAEBufferPool *m_silenceBuffers; // needed to drive gui sounds if we have no streams ++ CActiveAEBufferPool *m_encoderBuffers; ++ ++ // streams ++ std::list m_streams; ++ std::list m_discardBufferPools; ++ ++ // gui sounds ++ struct SoundState ++ { ++ CActiveAESound *sound; ++ int samples_played; ++ }; ++ std::list m_sounds_playing; ++ std::vector m_sounds; ++ int m_soundMode; ++ ++ float m_volume; ++ bool m_muted; ++ ++ // viz ++ IAudioCallback *m_audioCallback; ++ bool m_vizInitialized; ++ CCriticalSection m_vizLock; ++ ++ // ffmpeg ++ DllAvFormat m_dllAvFormat; ++ DllAvCodec m_dllAvCodec; ++ DllAvUtil m_dllAvUtil; ++ ++ // polled via the interface ++ float m_aeVolume; ++ bool m_aeMuted; ++}; ++}; +diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEBuffer.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEBuffer.cpp +new file mode 100644 +index 0000000..9a5f61e +--- /dev/null ++++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEBuffer.cpp +@@ -0,0 +1,368 @@ ++/* ++ * Copyright (C) 2010-2013 Team XBMC ++ * http://www.xbmc.org ++ * ++ * This Program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2, or (at your option) ++ * any later version. ++ * ++ * This Program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with XBMC; see the file COPYING. If not, see ++ * . ++ * ++ */ ++ ++#include "ActiveAEBuffer.h" ++#include "AEFactory.h" ++#include "ActiveAE.h" ++ ++using namespace ActiveAE; ++ ++/* typecast AE to CActiveAE */ ++#define AE (*((CActiveAE*)CAEFactory::GetEngine())) ++ ++CSoundPacket::CSoundPacket(SampleConfig conf, int samples) : config(conf) ++{ ++ data = AE.AllocSoundSample(config, samples, bytes_per_sample, planes, linesize); ++ max_nb_samples = samples; ++ nb_samples = 0; ++} ++ ++CSoundPacket::~CSoundPacket() ++{ ++ if (data) ++ AE.FreeSoundSample(data); ++} ++ ++CSampleBuffer::CSampleBuffer() : pkt(NULL), pool(NULL) ++{ ++ refCount = 0; ++} ++ ++CSampleBuffer::~CSampleBuffer() ++{ ++ if (pkt) ++ delete pkt; ++} ++ ++CSampleBuffer* CSampleBuffer::Acquire() ++{ ++ refCount++; ++ return this; ++} ++ ++void CSampleBuffer::Return() ++{ ++ refCount--; ++ if (pool && refCount <= 0) ++ pool->ReturnBuffer(this); ++} ++ ++CActiveAEBufferPool::CActiveAEBufferPool(AEAudioFormat format) ++{ ++ m_format = format; ++ if (AE_IS_RAW(m_format.m_dataFormat)) ++ m_format.m_dataFormat = AE_FMT_S16NE; ++} ++ ++CActiveAEBufferPool::~CActiveAEBufferPool() ++{ ++ CSampleBuffer *buffer; ++ while(!m_allSamples.empty()) ++ { ++ buffer = m_allSamples.front(); ++ m_allSamples.pop_front(); ++ delete buffer; ++ } ++} ++ ++CSampleBuffer* CActiveAEBufferPool::GetFreeBuffer() ++{ ++ CSampleBuffer* buf = NULL; ++ ++ if (!m_freeSamples.empty()) ++ { ++ buf = m_freeSamples.front(); ++ m_freeSamples.pop_front(); ++ buf->refCount = 1; ++ } ++ return buf; ++} ++ ++void CActiveAEBufferPool::ReturnBuffer(CSampleBuffer *buffer) ++{ ++ buffer->pkt->nb_samples = 0; ++ m_freeSamples.push_back(buffer); ++} ++ ++bool CActiveAEBufferPool::Create(unsigned int totaltime) ++{ ++ CSampleBuffer *buffer; ++ SampleConfig config; ++ config.fmt = CActiveAEResample::GetAVSampleFormat(m_format.m_dataFormat); ++ config.channels = m_format.m_channelLayout.Count(); ++ config.sample_rate = m_format.m_sampleRate; ++ config.channel_layout = CActiveAEResample::GetAVChannelLayout(m_format.m_channelLayout); ++ ++ unsigned int time = 0; ++ unsigned int buffertime = (m_format.m_frames*1000) / m_format.m_sampleRate; ++ unsigned int n = 0; ++ while (time < totaltime || n < 5) ++ { ++ buffer = new CSampleBuffer(); ++ buffer->pool = this; ++ buffer->pkt = new CSoundPacket(config, m_format.m_frames); ++ ++ m_allSamples.push_back(buffer); ++ m_freeSamples.push_back(buffer); ++ time += buffertime; ++ n++; ++ } ++ ++ return true; ++} ++ ++//----------------------------------------------------------------------------- ++ ++CActiveAEBufferPoolResample::CActiveAEBufferPoolResample(AEAudioFormat inputFormat, AEAudioFormat outputFormat) ++ : CActiveAEBufferPool(outputFormat) ++{ ++ m_inputFormat = inputFormat; ++ if (AE_IS_RAW(m_inputFormat.m_dataFormat)) ++ m_inputFormat.m_dataFormat = AE_FMT_S16NE; ++ m_resampler = NULL; ++ m_fillPackets = false; ++ m_drain = false; ++ m_empty = true; ++ m_procSample = NULL; ++ m_resampleRatio = 1.0; ++ m_changeRatio = false; ++} ++ ++CActiveAEBufferPoolResample::~CActiveAEBufferPoolResample() ++{ ++ if (m_resampler) ++ delete m_resampler; ++} ++ ++bool CActiveAEBufferPoolResample::Create(unsigned int totaltime, bool remap) ++{ ++ CActiveAEBufferPool::Create(totaltime); ++ ++ if (m_inputFormat.m_channelLayout != m_format.m_channelLayout || ++ m_inputFormat.m_sampleRate != m_format.m_sampleRate || ++ m_inputFormat.m_dataFormat != m_format.m_dataFormat) ++ { ++ m_resampler = new CActiveAEResample(); ++ m_resampler->Init(CActiveAEResample::GetAVChannelLayout(m_format.m_channelLayout), ++ m_format.m_channelLayout.Count(), ++ m_format.m_sampleRate, ++ CActiveAEResample::GetAVSampleFormat(m_format.m_dataFormat), ++ CActiveAEResample::GetAVChannelLayout(m_inputFormat.m_channelLayout), ++ m_inputFormat.m_channelLayout.Count(), ++ m_inputFormat.m_sampleRate, ++ CActiveAEResample::GetAVSampleFormat(m_inputFormat.m_dataFormat), ++ remap ? &m_format.m_channelLayout : NULL); ++ } ++ ++ // store output sampling rate, needed when ratio gets changed ++ m_outSampleRate = m_format.m_sampleRate; ++ ++ return true; ++} ++ ++void CActiveAEBufferPoolResample::ChangeRatio() ++{ ++// CLog::Log(LOGNOTICE,"---------- sample rate changed from: %d, to: %d", ++// m_outSampleRate, (int)(m_format.m_sampleRate * m_resampleRatio)); ++ ++ m_outSampleRate = m_format.m_sampleRate * m_resampleRatio; ++ ++ if (m_resampler) ++ delete m_resampler; ++ ++ m_resampler = new CActiveAEResample(); ++ m_resampler->Init(CActiveAEResample::GetAVChannelLayout(m_format.m_channelLayout), ++ m_format.m_channelLayout.Count(), ++ m_outSampleRate, ++ CActiveAEResample::GetAVSampleFormat(m_format.m_dataFormat), ++ CActiveAEResample::GetAVChannelLayout(m_inputFormat.m_channelLayout), ++ m_inputFormat.m_channelLayout.Count(), ++ m_inputFormat.m_sampleRate, ++ CActiveAEResample::GetAVSampleFormat(m_inputFormat.m_dataFormat), ++ NULL); ++ ++ m_changeRatio = false; ++} ++ ++bool CActiveAEBufferPoolResample::ResampleBuffers(unsigned int timestamp) ++{ ++ bool busy = false; ++ CSampleBuffer *in; ++ ++ if (m_changeRatio) ++ { ++ if ((unsigned int)(m_format.m_sampleRate * m_resampleRatio) == m_outSampleRate) ++ m_changeRatio = false; ++ } ++ ++ if (!m_resampler) ++ { ++ if (m_changeRatio) ++ { ++ ChangeRatio(); ++ return true; ++ } ++ while(!m_inputSamples.empty()) ++ { ++ in = m_inputSamples.front(); ++ m_inputSamples.pop_front(); ++ m_outputSamples.push_back(in); ++ busy = true; ++ } ++ } ++ else if (m_procSample || !m_freeSamples.empty()) ++ { ++ // GetBufferedSamples is not accurate because of rounding errors ++ int out_samples = m_resampler->GetBufferedSamples(); ++ int free_samples; ++ if (m_procSample) ++ free_samples = m_procSample->pkt->max_nb_samples - m_procSample->pkt->nb_samples; ++ else ++ free_samples = m_format.m_frames; ++ ++ bool skipInput = false; ++ // avoid that ffmpeg resample buffer grows too large ++ if (out_samples > free_samples * 2 && !m_empty) ++ skipInput = true; ++ ++ bool hasInput = !m_inputSamples.empty(); ++ ++ if (hasInput || skipInput || m_drain || m_changeRatio) ++ { ++ if (!m_procSample) ++ { ++ m_procSample = GetFreeBuffer(); ++ } ++ ++ if (hasInput && !skipInput && !m_changeRatio) ++ { ++ in = m_inputSamples.front(); ++ m_inputSamples.pop_front(); ++ } ++ else ++ in = NULL; ++ ++ int start = m_procSample->pkt->nb_samples * ++ m_procSample->pkt->bytes_per_sample * ++ m_procSample->pkt->config.channels / ++ m_procSample->pkt->planes; ++ ++ for(int i=0; ipkt->planes; i++) ++ { ++ m_planes[i] = m_procSample->pkt->data[i] + start; ++ } ++ ++ out_samples = m_resampler->Resample(m_planes, ++ m_procSample->pkt->max_nb_samples - m_procSample->pkt->nb_samples, ++ in ? in->pkt->data : NULL, ++ in ? in->pkt->nb_samples : 0); ++ m_procSample->pkt->nb_samples += out_samples; ++ busy = true; ++ m_empty = (out_samples == 0); ++ ++ if ((m_drain || m_changeRatio) && m_empty) ++ { ++ if (m_fillPackets && m_procSample->pkt->nb_samples != 0) ++ { ++ // pad with zero ++ start = m_procSample->pkt->nb_samples * ++ m_procSample->pkt->bytes_per_sample * ++ m_procSample->pkt->config.channels / ++ m_procSample->pkt->planes; ++ for(int i=0; ipkt->planes; i++) ++ { ++ memset(m_procSample->pkt->data[i]+start, 0, m_procSample->pkt->linesize-start); ++ } ++ } ++ m_procSample->timestamp = timestamp; ++ ++ // check if draining is finished ++ if (m_drain && m_procSample->pkt->nb_samples == 0) ++ { ++ m_procSample->Return(); ++ busy = false; ++ } ++ else ++ m_outputSamples.push_back(m_procSample); ++ ++ m_procSample = NULL; ++ if (m_changeRatio) ++ ChangeRatio(); ++ } ++ // some methods like encode require completely filled packets ++ else if (!m_fillPackets || (m_procSample->pkt->nb_samples == m_procSample->pkt->max_nb_samples)) ++ { ++ m_procSample->timestamp = timestamp; ++ m_outputSamples.push_back(m_procSample); ++ m_procSample = NULL; ++ } ++ ++ if (in) ++ in->Return(); ++ } ++ } ++ return busy; ++} ++ ++float CActiveAEBufferPoolResample::GetDelay() ++{ ++ float delay = 0; ++ std::deque::iterator itBuf; ++ ++ if (m_procSample) ++ delay += m_procSample->pkt->nb_samples / m_procSample->pkt->config.sample_rate; ++ ++ for(itBuf=m_inputSamples.begin(); itBuf!=m_inputSamples.end(); ++itBuf) ++ { ++ delay += (float)(*itBuf)->pkt->nb_samples / (*itBuf)->pkt->config.sample_rate; ++ } ++ ++ for(itBuf=m_outputSamples.begin(); itBuf!=m_outputSamples.end(); ++itBuf) ++ { ++ delay += (float)(*itBuf)->pkt->nb_samples / (*itBuf)->pkt->config.sample_rate; ++ } ++ ++ if (m_resampler) ++ { ++ int samples = m_resampler->GetBufferedSamples(); ++ delay += (float)samples / m_outSampleRate; ++ } ++ ++ return delay; ++} ++ ++void CActiveAEBufferPoolResample::Flush() ++{ ++ if (m_procSample) ++ { ++ m_procSample->Return(); ++ m_procSample = NULL; ++ } ++ while (!m_inputSamples.empty()) ++ { ++ m_inputSamples.front()->Return(); ++ m_inputSamples.pop_front(); ++ } ++ while (!m_outputSamples.empty()) ++ { ++ m_outputSamples.front()->Return(); ++ m_outputSamples.pop_front(); ++ } ++} +diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEBuffer.h b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEBuffer.h +new file mode 100644 +index 0000000..183c49e +--- /dev/null ++++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEBuffer.h +@@ -0,0 +1,110 @@ ++#pragma once ++/* ++ * Copyright (C) 2010-2013 Team XBMC ++ * http://xbmc.org ++ * ++ * This Program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2, or (at your option) ++ * any later version. ++ * ++ * This Program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with XBMC; see the file COPYING. If not, see ++ * . ++ * ++ */ ++ ++#include "DllAvUtil.h" ++#include "DllSwResample.h" ++#include "AEAudioFormat.h" ++#include ++ ++namespace ActiveAE ++{ ++ ++struct SampleConfig ++{ ++ AVSampleFormat fmt; ++ uint64_t channel_layout; ++ int channels; ++ int sample_rate; ++}; ++ ++/** ++ * the variables here follow ffmpeg naming ++ */ ++class CSoundPacket ++{ ++public: ++ CSoundPacket(SampleConfig conf, int samples); ++ ~CSoundPacket(); ++ uint8_t **data; // array with pointers to planes of data ++ SampleConfig config; ++ AEDataFormat internal_format; // used when carrying pass through ++ int bytes_per_sample; // bytes per sample and per channel ++ int linesize; // see ffmpeg, required for planar formats ++ int planes; // 1 for non planar formats, #channels for planar ++ int nb_samples; // number of frames used ++ int max_nb_samples; // max number of frames this packet can hold ++}; ++ ++class CActiveAEBufferPool; ++ ++class CSampleBuffer ++{ ++public: ++ CSampleBuffer(); ++ ~CSampleBuffer(); ++ CSampleBuffer *Acquire(); ++ void Return(); ++ CSoundPacket *pkt; ++ CActiveAEBufferPool *pool; ++ unsigned int timestamp; ++ int refCount; ++}; ++ ++class CActiveAEBufferPool ++{ ++public: ++ CActiveAEBufferPool(AEAudioFormat format); ++ virtual ~CActiveAEBufferPool(); ++ virtual bool Create(unsigned int totaltime); ++ CSampleBuffer *GetFreeBuffer(); ++ void ReturnBuffer(CSampleBuffer *buffer); ++ AEAudioFormat m_format; ++ std::deque m_allSamples; ++ std::deque m_freeSamples; ++}; ++ ++class CActiveAEResample; ++ ++class CActiveAEBufferPoolResample : public CActiveAEBufferPool ++{ ++public: ++ CActiveAEBufferPoolResample(AEAudioFormat inputFormat, AEAudioFormat outputFormat); ++ virtual ~CActiveAEBufferPoolResample(); ++ virtual bool Create(unsigned int totaltime, bool remap); ++ void ChangeRatio(); ++ bool ResampleBuffers(unsigned int timestamp = 0); ++ float GetDelay(); ++ void Flush(); ++ AEAudioFormat m_inputFormat; ++ std::deque m_inputSamples; ++ std::deque m_outputSamples; ++ CSampleBuffer *m_procSample; ++ CActiveAEResample *m_resampler; ++ uint8_t *m_planes[16]; ++ bool m_fillPackets; ++ bool m_drain; ++ bool m_empty; ++ bool m_changeRatio; ++ double m_resampleRatio; ++ unsigned int m_outSampleRate; ++}; ++ ++} +diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.cpp +new file mode 100644 +index 0000000..63df59c +--- /dev/null ++++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.cpp +@@ -0,0 +1,251 @@ ++/* ++ * Copyright (C) 2010-2013 Team XBMC ++ * http://xbmc.org ++ * ++ * This Program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2, or (at your option) ++ * any later version. ++ * ++ * This Program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with XBMC; see the file COPYING. If not, see ++ * . ++ * ++ */ ++ ++#include "ActiveAEResample.h" ++ ++using namespace ActiveAE; ++ ++CActiveAEResample::CActiveAEResample() ++{ ++ m_pContext = NULL; ++} ++ ++CActiveAEResample::~CActiveAEResample() ++{ ++ if (m_pContext) ++ m_dllSwResample.swr_free(&m_pContext); ++ ++ m_dllAvUtil.Unload(); ++ m_dllSwResample.Unload(); ++} ++ ++bool CActiveAEResample::Init(uint64_t dst_chan_layout, int dst_channels, int dst_rate, AVSampleFormat dst_fmt, uint64_t src_chan_layout, int src_channels, int src_rate, AVSampleFormat src_fmt, CAEChannelInfo *remapLayout) ++{ ++ if (!m_dllAvUtil.Load() || !m_dllSwResample.Load()) ++ return false; ++ ++ m_dst_chan_layout = dst_chan_layout; ++ m_dst_channels = dst_channels; ++ m_dst_rate = dst_rate; ++ m_dst_fmt = dst_fmt; ++ m_src_chan_layout = src_chan_layout; ++ m_src_channels = src_channels; ++ m_src_rate = src_rate; ++ m_src_fmt = src_fmt; ++ ++ if (m_dst_chan_layout == 0) ++ m_dst_chan_layout = m_dllAvUtil.av_get_default_channel_layout(m_dst_channels); ++ if (m_src_chan_layout == 0) ++ m_src_chan_layout = m_dllAvUtil.av_get_default_channel_layout(m_src_channels); ++ ++ m_pContext = m_dllSwResample.swr_alloc_set_opts(NULL, m_dst_chan_layout, m_dst_fmt, m_dst_rate, ++ m_src_chan_layout, m_src_fmt, m_src_rate, ++ 0, NULL); ++ ++ if(!m_pContext) ++ { ++ CLog::Log(LOGERROR, "CActiveAEResample::Init - create context failed"); ++ return false; ++ } ++ if (remapLayout) ++ { ++ // one-to-one mapping of channels ++ // remapLayout is the layout of the sink, if the channel is in our src layout ++ // the channel is mapped by setting coef 1.0 ++ memset(m_rematrix, 0, sizeof(m_rematrix)); ++ for (unsigned int out=0; outCount(); out++) ++ { ++ int idx = GetAVChannelIndex((*remapLayout)[out], m_src_chan_layout); ++ if (idx >= 0) ++ { ++ m_rematrix[out][idx] = 1.0; ++ } ++ } ++ ++ if (m_dllSwResample.swr_set_matrix(m_pContext, (const double*)m_rematrix, AE_CH_MAX) < 0) ++ { ++ CLog::Log(LOGERROR, "CActiveAEResample::Init - setting channel matrix failed"); ++ return false; ++ } ++ } ++ if(m_dllSwResample.swr_init(m_pContext) < 0) ++ { ++ CLog::Log(LOGERROR, "CActiveAEResample::Init - init resampler failed"); ++ return false; ++ } ++ return true; ++} ++ ++int CActiveAEResample::Resample(uint8_t **dst_buffer, int dst_samples, uint8_t **src_buffer, int src_samples) ++{ ++ int ret = m_dllSwResample.swr_convert(m_pContext, dst_buffer, dst_samples, (const uint8_t**)src_buffer, src_samples); ++ if (ret < 0) ++ { ++ CLog::Log(LOGERROR, "CActiveAEResample::Resample - resample failed"); ++ return 0; ++ } ++ return ret; ++} ++ ++int64_t CActiveAEResample::GetDelay(int64_t base) ++{ ++ return m_dllSwResample.swr_get_delay(m_pContext, base); ++} ++ ++int CActiveAEResample::GetBufferedSamples() ++{ ++ return m_dllAvUtil.av_rescale_rnd(m_dllSwResample.swr_get_delay(m_pContext, m_dst_rate), ++ m_src_rate, m_dst_rate, AV_ROUND_UP); ++} ++ ++int CActiveAEResample::CalcDstSampleCount(int src_samples, int dst_rate, int src_rate) ++{ ++ return m_dllAvUtil.av_rescale_rnd(src_samples, dst_rate, src_rate, AV_ROUND_UP); ++} ++ ++int CActiveAEResample::GetSrcBufferSize(int samples) ++{ ++ return m_dllAvUtil.av_samples_get_buffer_size(NULL, m_src_channels, samples, m_src_fmt, 1); ++} ++ ++int CActiveAEResample::GetDstBufferSize(int samples) ++{ ++ return m_dllAvUtil.av_samples_get_buffer_size(NULL, m_dst_channels, samples, m_dst_fmt, 1); ++} ++ ++uint64_t CActiveAEResample::GetAVChannelLayout(CAEChannelInfo &info) ++{ ++ uint64_t channelLayout = 0; ++ if (info.HasChannel(AE_CH_FL)) channelLayout |= AV_CH_FRONT_LEFT; ++ if (info.HasChannel(AE_CH_FR)) channelLayout |= AV_CH_FRONT_RIGHT; ++ if (info.HasChannel(AE_CH_FC)) channelLayout |= AV_CH_FRONT_CENTER; ++ if (info.HasChannel(AE_CH_LFE)) channelLayout |= AV_CH_LOW_FREQUENCY; ++ if (info.HasChannel(AE_CH_BL)) channelLayout |= AV_CH_BACK_LEFT; ++ if (info.HasChannel(AE_CH_BR)) channelLayout |= AV_CH_BACK_RIGHT; ++ if (info.HasChannel(AE_CH_FLOC)) channelLayout |= AV_CH_FRONT_LEFT_OF_CENTER; ++ if (info.HasChannel(AE_CH_FROC)) channelLayout |= AV_CH_FRONT_RIGHT_OF_CENTER; ++ if (info.HasChannel(AE_CH_BC)) channelLayout |= AV_CH_BACK_CENTER; ++ if (info.HasChannel(AE_CH_SL)) channelLayout |= AV_CH_SIDE_LEFT; ++ if (info.HasChannel(AE_CH_SR)) channelLayout |= AV_CH_SIDE_RIGHT; ++ if (info.HasChannel(AE_CH_TC)) channelLayout |= AV_CH_TOP_CENTER; ++ if (info.HasChannel(AE_CH_TFL)) channelLayout |= AV_CH_TOP_FRONT_LEFT; ++ if (info.HasChannel(AE_CH_TFC)) channelLayout |= AV_CH_TOP_FRONT_CENTER; ++ if (info.HasChannel(AE_CH_TFR)) channelLayout |= AV_CH_TOP_FRONT_RIGHT; ++ if (info.HasChannel(AE_CH_TBL)) channelLayout |= AV_CH_TOP_BACK_LEFT; ++ if (info.HasChannel(AE_CH_TBC)) channelLayout |= AV_CH_TOP_BACK_CENTER; ++ if (info.HasChannel(AE_CH_TBR)) channelLayout |= AV_CH_TOP_BACK_RIGHT; ++ ++ return channelLayout; ++} ++ ++//CAEChannelInfo CActiveAEResample::GetAEChannelLayout(uint64_t layout) ++//{ ++// CAEChannelInfo channelLayout; ++// channelLayout.Reset(); ++// ++// if (layout & AV_CH_FRONT_LEFT ) channelLayout += AE_CH_FL ; ++// if (layout & AV_CH_FRONT_RIGHT ) channelLayout += AE_CH_FR ; ++// if (layout & AV_CH_FRONT_CENTER ) channelLayout += AE_CH_FC ; ++// if (layout & AV_CH_LOW_FREQUENCY ) channelLayout += AE_CH_LFE ; ++// if (layout & AV_CH_BACK_LEFT ) channelLayout += AE_CH_BL ; ++// if (layout & AV_CH_BACK_RIGHT ) channelLayout += AE_CH_BR ; ++// if (layout & AV_CH_FRONT_LEFT_OF_CENTER ) channelLayout += AE_CH_FLOC; ++// if (layout & AV_CH_FRONT_RIGHT_OF_CENTER) channelLayout += AE_CH_FROC; ++// if (layout & AV_CH_BACK_CENTER ) channelLayout += AE_CH_BC ; ++// if (layout & AV_CH_SIDE_LEFT ) channelLayout += AE_CH_SL ; ++// if (layout & AV_CH_SIDE_RIGHT ) channelLayout += AE_CH_SR ; ++// if (layout & AV_CH_TOP_CENTER ) channelLayout += AE_CH_TC ; ++// if (layout & AV_CH_TOP_FRONT_LEFT ) channelLayout += AE_CH_TFL ; ++// if (layout & AV_CH_TOP_FRONT_CENTER ) channelLayout += AE_CH_TFC ; ++// if (layout & AV_CH_TOP_FRONT_RIGHT ) channelLayout += AE_CH_TFR ; ++// if (layout & AV_CH_TOP_BACK_LEFT ) channelLayout += AE_CH_BL ; ++// if (layout & AV_CH_TOP_BACK_CENTER ) channelLayout += AE_CH_BC ; ++// if (layout & AV_CH_TOP_BACK_RIGHT ) channelLayout += AE_CH_BR ; ++// ++// return channelLayout; ++//} ++ ++AVSampleFormat CActiveAEResample::GetAVSampleFormat(AEDataFormat format) ++{ ++ if (format == AE_FMT_U8) return AV_SAMPLE_FMT_U8; ++ else if (format == AE_FMT_S16NE) return AV_SAMPLE_FMT_S16; ++ else if (format == AE_FMT_S32NE) return AV_SAMPLE_FMT_S32; ++ else if (format == AE_FMT_FLOAT) return AV_SAMPLE_FMT_FLT; ++ else if (format == AE_FMT_DOUBLE) return AV_SAMPLE_FMT_DBL; ++ ++ else if (format == AE_FMT_U8P) return AV_SAMPLE_FMT_U8P; ++ else if (format == AE_FMT_S16NEP) return AV_SAMPLE_FMT_S16P; ++ else if (format == AE_FMT_S32NEP) return AV_SAMPLE_FMT_S32P; ++ else if (format == AE_FMT_FLOATP) return AV_SAMPLE_FMT_FLTP; ++ else if (format == AE_FMT_DOUBLEP) return AV_SAMPLE_FMT_DBLP; ++ ++ CLog::Log(LOGDEBUG, "CActiveAEResample::GetAVSampleFormat - format not supported"); ++ return AV_SAMPLE_FMT_FLT; ++} ++ ++AEDataFormat CActiveAEResample::GetAESampleFormat(AVSampleFormat format) ++{ ++ if (format == AV_SAMPLE_FMT_U8) return AE_FMT_U8; ++ else if (format == AV_SAMPLE_FMT_S16) return AE_FMT_S16NE; ++ else if (format == AV_SAMPLE_FMT_S32) return AE_FMT_S32NE; ++ else if (format == AV_SAMPLE_FMT_FLT) return AE_FMT_FLOAT; ++ else if (format == AV_SAMPLE_FMT_DBL) return AE_FMT_DOUBLE; ++ ++ else if (format == AV_SAMPLE_FMT_U8P) return AE_FMT_U8P; ++ else if (format == AV_SAMPLE_FMT_S16P) return AE_FMT_S16NEP; ++ else if (format == AV_SAMPLE_FMT_S32P) return AE_FMT_S32NEP; ++ else if (format == AV_SAMPLE_FMT_FLTP) return AE_FMT_FLOATP; ++ else if (format == AV_SAMPLE_FMT_DBLP) return AE_FMT_DOUBLEP; ++ ++ CLog::Log(LOGERROR, "CActiveAEResample::GetAESampleFormat - format not supported"); ++ return AE_FMT_INVALID; ++} ++ ++uint64_t CActiveAEResample::GetAVChannel(enum AEChannel aechannel) ++{ ++ switch (aechannel) ++ { ++ case AE_CH_FL: return AV_CH_FRONT_LEFT; ++ case AE_CH_FR: return AV_CH_FRONT_RIGHT; ++ case AE_CH_FC: return AV_CH_FRONT_CENTER; ++ case AE_CH_LFE: return AV_CH_LOW_FREQUENCY; ++ case AE_CH_BL: return AV_CH_BACK_LEFT; ++ case AE_CH_BR: return AV_CH_BACK_RIGHT; ++ case AE_CH_FLOC: return AV_CH_FRONT_LEFT_OF_CENTER; ++ case AE_CH_FROC: return AV_CH_FRONT_RIGHT_OF_CENTER; ++ case AE_CH_BC: return AV_CH_BACK_CENTER; ++ case AE_CH_SL: return AV_CH_SIDE_LEFT; ++ case AE_CH_SR: return AV_CH_SIDE_RIGHT; ++ case AE_CH_TC: return AV_CH_TOP_CENTER; ++ case AE_CH_TFL: return AV_CH_TOP_FRONT_LEFT; ++ case AE_CH_TFC: return AV_CH_TOP_FRONT_CENTER; ++ case AE_CH_TFR: return AV_CH_TOP_FRONT_RIGHT; ++ case AE_CH_TBL: return AV_CH_TOP_BACK_LEFT; ++ case AE_CH_TBC: return AV_CH_TOP_BACK_CENTER; ++ case AE_CH_TBR: return AV_CH_TOP_BACK_RIGHT; ++ default: ++ return 0; ++ } ++} ++ ++int CActiveAEResample::GetAVChannelIndex(enum AEChannel aechannel, uint64_t layout) ++{ ++ return m_dllAvUtil.av_get_channel_layout_channel_index(layout, GetAVChannel(aechannel)); ++} +diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.h b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.h +new file mode 100644 +index 0000000..fa95a1d +--- /dev/null ++++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.h +@@ -0,0 +1,61 @@ ++#pragma once ++/* ++ * Copyright (C) 2010-2013 Team XBMC ++ * http://xbmc.org ++ * ++ * This Program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2, or (at your option) ++ * any later version. ++ * ++ * This Program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with XBMC; see the file COPYING. If not, see ++ * . ++ * ++ */ ++ ++#include "DllAvUtil.h" ++#include "DllSwResample.h" ++#include "Utils/AEChannelInfo.h" ++#include "AEAudioFormat.h" ++#include "ActiveAEBuffer.h" ++ ++namespace ActiveAE ++{ ++ ++class CActiveAEResample ++{ ++public: ++ CActiveAEResample(); ++ virtual ~CActiveAEResample(); ++ bool Init(uint64_t dst_chan_layout, int dst_channels, int dst_rate, AVSampleFormat dst_fmt, uint64_t src_chan_layout, int src_channels, int src_rate, AVSampleFormat src_fmt, CAEChannelInfo *remapLayout = NULL); ++ int Resample(uint8_t **dst_buffer, int dst_samples, uint8_t **src_buffer, int src_samples); ++ int64_t GetDelay(int64_t base); ++ int GetBufferedSamples(); ++ int CalcDstSampleCount(int src_samples, int dst_rate, int src_rate); ++ int GetSrcBufferSize(int samples); ++ int GetDstBufferSize(int samples); ++ static uint64_t GetAVChannelLayout(CAEChannelInfo &info); ++// static CAEChannelInfo GetAEChannelLayout(uint64_t layout); ++ static AVSampleFormat GetAVSampleFormat(AEDataFormat format); ++ static AEDataFormat GetAESampleFormat(AVSampleFormat format); ++ static uint64_t GetAVChannel(enum AEChannel aechannel); ++ int GetAVChannelIndex(enum AEChannel aechannel, uint64_t layout); ++ ++protected: ++ DllAvUtil m_dllAvUtil; ++ DllSwResample m_dllSwResample; ++ uint64_t m_src_chan_layout, m_dst_chan_layout; ++ int m_src_rate, m_dst_rate; ++ int m_src_channels, m_dst_channels; ++ AVSampleFormat m_src_fmt, m_dst_fmt; ++ SwrContext *m_pContext; ++ double m_rematrix[AE_CH_MAX][AE_CH_MAX]; ++}; ++ ++} +diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.cpp +new file mode 100644 +index 0000000..252f431 +--- /dev/null ++++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.cpp +@@ -0,0 +1,813 @@ ++/* ++ * Copyright (C) 2010-2013 Team XBMC ++ * http://xbmc.org ++ * ++ * This Program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2, or (at your option) ++ * any later version. ++ * ++ * This Program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with XBMC; see the file COPYING. If not, see ++ * . ++ * ++ */ ++ ++#include ++ ++#include "ActiveAESink.h" ++#include "Utils/AEUtil.h" ++#include "utils/EndianSwap.h" ++#include "ActiveAE.h" ++ ++#include "settings/Settings.h" ++#include "settings/AdvancedSettings.h" ++ ++using namespace ActiveAE; ++ ++CActiveAESink::CActiveAESink(CEvent *inMsgEvent) : ++ CThread("AESink"), ++ m_controlPort("SinkControlPort", inMsgEvent, &m_outMsgEvent), ++ m_dataPort("SinkDataPort", inMsgEvent, &m_outMsgEvent) ++{ ++ m_inMsgEvent = inMsgEvent; ++ m_sink = NULL; ++ m_stats = NULL; ++ m_convertBuffer = NULL; ++} ++ ++void CActiveAESink::Start() ++{ ++ if (!IsRunning()) ++ { ++ Create(); ++ SetPriority(THREAD_PRIORITY_ABOVE_NORMAL); ++ } ++} ++ ++void CActiveAESink::Dispose() ++{ ++ m_bStop = true; ++ m_outMsgEvent.Set(); ++ StopThread(); ++ m_controlPort.Purge(); ++ m_dataPort.Purge(); ++ ++ if (m_sink) ++ { ++ m_sink->Drain(); ++ m_sink->Deinitialize(); ++ delete m_sink; ++ m_sink = NULL; ++ } ++ if (m_sampleOfSilence.pkt) ++ { ++ delete m_sampleOfSilence.pkt; ++ m_sampleOfSilence.pkt = NULL; ++ } ++ ++ delete m_sampleOfNoise.pkt; ++ m_sampleOfNoise.pkt = NULL; ++ ++ if (m_convertBuffer) ++ { ++ _aligned_free(m_convertBuffer); ++ m_convertBuffer = NULL; ++ } ++} ++ ++bool CActiveAESink::IsCompatible(const AEAudioFormat format, const std::string &device) ++{ ++ if (!m_sink) ++ return false; ++ return m_sink->IsCompatible(format, device); ++} ++ ++enum SINK_STATES ++{ ++ S_TOP = 0, // 0 ++ S_TOP_UNCONFIGURED, // 1 ++ S_TOP_CONFIGURED, // 2 ++ S_TOP_CONFIGURED_SUSPEND, // 3 ++ S_TOP_CONFIGURED_IDLE, // 4 ++ S_TOP_CONFIGURED_PLAY, // 5 ++ S_TOP_CONFIGURED_SILENCE, // 6 ++ S_TOP_CONFIGURED_WARMUP, // 7 ++}; ++ ++int SINK_parentStates[] = { ++ -1, ++ 0, //TOP_UNCONFIGURED ++ 0, //TOP_CONFIGURED ++ 2, //TOP_CONFIGURED_SUSPEND ++ 2, //TOP_CONFIGURED_IDLE ++ 2, //TOP_CONFIGURED_PLAY ++ 2, //TOP_CONFIGURED_SILENCE ++ 2, //TOP_CONFIGURED_WARMUP ++}; ++ ++void CActiveAESink::StateMachine(int signal, Protocol *port, Message *msg) ++{ ++ for (int state = m_state; ; state = SINK_parentStates[state]) ++ { ++ switch (state) ++ { ++ case S_TOP: // TOP ++ if (port == &m_controlPort) ++ { ++ switch (signal) ++ { ++ case CSinkControlProtocol::CONFIGURE: ++ SinkConfig *data; ++ data = (SinkConfig*)msg->data; ++ if (data) ++ { ++ m_requestedFormat = data->format; ++ m_stats = data->stats; ++ } ++ m_extError = false; ++ m_extSilence = false; ++ ReturnBuffers(); ++ OpenSink(); ++ ++ if (!m_extError) ++ { ++ m_stats->SetSinkCacheTotal(m_sink->GetCacheTotal()); ++ m_state = S_TOP_CONFIGURED_IDLE; ++ m_extTimeout = 10000; ++ msg->Reply(CSinkControlProtocol::ACC, &m_sinkFormat, sizeof(AEAudioFormat)); ++ } ++ else ++ { ++ m_state = S_TOP_UNCONFIGURED; ++ msg->Reply(CSinkControlProtocol::ERR); ++ } ++ return; ++ ++ case CSinkControlProtocol::UNCONFIGURE: ++ ReturnBuffers(); ++ if (m_sink) ++ { ++ m_sink->Drain(); ++ m_sink->Deinitialize(); ++ delete m_sink; ++ m_sink = NULL; ++ } ++ m_state = S_TOP_UNCONFIGURED; ++ msg->Reply(CSinkControlProtocol::ACC); ++ return; ++ ++ default: ++ break; ++ } ++ } ++ else if (port == &m_dataPort) ++ { ++ switch (signal) ++ { ++ case CSinkDataProtocol::DRAIN: ++ msg->Reply(CSinkDataProtocol::ACC); ++ m_state = S_TOP_UNCONFIGURED; ++ m_extTimeout = 0; ++ return; ++ default: ++ break; ++ } ++ } ++ { ++ std::string portName = port == NULL ? "timer" : port->portName; ++ CLog::Log(LOGWARNING, "CActiveAESink::%s - signal: %d form port: %s not handled for state: %d", __FUNCTION__, signal, portName.c_str(), m_state); ++ } ++ return; ++ ++ case S_TOP_UNCONFIGURED: ++ if (port == NULL) // timeout ++ { ++ switch (signal) ++ { ++ case CSinkControlProtocol::TIMEOUT: ++ m_extTimeout = 1000; ++ return; ++ default: ++ break; ++ } ++ } ++ else if (port == &m_dataPort) ++ { ++ switch (signal) ++ { ++ case CSinkDataProtocol::SAMPLE: ++ CSampleBuffer *samples; ++ int timeout; ++ samples = *((CSampleBuffer**)msg->data); ++ timeout = 1000*samples->pkt->nb_samples/samples->pkt->config.sample_rate; ++ Sleep(timeout); ++ msg->Reply(CSinkDataProtocol::RETURNSAMPLE, &samples, sizeof(CSampleBuffer*)); ++ m_extTimeout = 0; ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ case S_TOP_CONFIGURED: ++ if (port == &m_controlPort) ++ { ++ switch (signal) ++ { ++ case CSinkControlProtocol::SILENCEMODE: ++ m_extSilence = *(bool*)msg->data; ++ if (g_advancedSettings.m_streamSilence) ++ m_extSilence = true; ++ if (m_extSilence) ++ { ++ m_extCycleCounter = 5; ++ m_state = S_TOP_CONFIGURED_WARMUP; ++ m_extTimeout = 0; ++ } ++ return; ++ default: ++ break; ++ } ++ } ++ else if (port == &m_dataPort) ++ { ++ switch (signal) ++ { ++ case CSinkDataProtocol::DRAIN: ++ m_sink->Drain(); ++ msg->Reply(CSinkDataProtocol::ACC); ++ m_state = S_TOP_CONFIGURED_IDLE; ++ m_extTimeout = 10000; ++ return; ++ case CSinkDataProtocol::SAMPLE: ++ CSampleBuffer *samples; ++ unsigned int delay; ++ samples = *((CSampleBuffer**)msg->data); ++ delay = OutputSamples(samples); ++ msg->Reply(CSinkDataProtocol::RETURNSAMPLE, &samples, sizeof(CSampleBuffer*)); ++ if (m_extError) ++ { ++ m_sink->Deinitialize(); ++ delete m_sink; ++ m_sink = NULL; ++ m_state = S_TOP_CONFIGURED_SUSPEND; ++ m_extTimeout = 0; ++ } ++ else ++ { ++ m_state = S_TOP_CONFIGURED_PLAY; ++ m_extTimeout = delay / 2; ++ } ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ case S_TOP_CONFIGURED_SUSPEND: ++ if (port == &m_dataPort) ++ { ++ switch (signal) ++ { ++ case CSinkDataProtocol::SAMPLE: ++ m_extError = false; ++ OpenSink(); ++ OutputSamples(&m_sampleOfNoise); ++ m_state = S_TOP_CONFIGURED_PLAY; ++ m_extTimeout = 0; ++ m_bStateMachineSelfTrigger = true; ++ return; ++ case CSinkDataProtocol::DRAIN: ++ msg->Reply(CSinkDataProtocol::ACC); ++ return; ++ default: ++ break; ++ } ++ } ++ else if (port == NULL) // timeout ++ { ++ switch (signal) ++ { ++ case CSinkControlProtocol::TIMEOUT: ++ m_extTimeout = 10000; ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ case S_TOP_CONFIGURED_IDLE: ++ if (port == &m_dataPort) ++ { ++ switch (signal) ++ { ++ case CSinkDataProtocol::SAMPLE: ++ OutputSamples(&m_sampleOfNoise); ++ m_state = S_TOP_CONFIGURED_PLAY; ++ m_extTimeout = 0; ++ m_bStateMachineSelfTrigger = true; ++ return; ++ default: ++ break; ++ } ++ } ++ else if (port == NULL) // timeout ++ { ++ switch (signal) ++ { ++ case CSinkControlProtocol::TIMEOUT: ++ m_sink->Deinitialize(); ++ delete m_sink; ++ m_sink = NULL; ++ m_state = S_TOP_CONFIGURED_SUSPEND; ++ m_extTimeout = 10000; ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ case S_TOP_CONFIGURED_PLAY: ++ if (port == NULL) // timeout ++ { ++ switch (signal) ++ { ++ case CSinkControlProtocol::TIMEOUT: ++ if (m_extSilence) ++ { ++ m_state = S_TOP_CONFIGURED_SILENCE; ++ m_extTimeout = 0; ++ } ++ else ++ { ++ m_sink->Drain(); ++ m_state = S_TOP_CONFIGURED_IDLE; ++ m_extTimeout = 10000; ++ } ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ case S_TOP_CONFIGURED_SILENCE: ++ if (port == NULL) // timeout ++ { ++ switch (signal) ++ { ++ case CSinkControlProtocol::TIMEOUT: ++ unsigned int delay; ++ delay = OutputSamples(&m_sampleOfSilence); ++ m_extCycleCounter--; ++ if (m_extError) ++ { ++ m_sink->Deinitialize(); ++ delete m_sink; ++ m_sink = NULL; ++ m_state = S_TOP_CONFIGURED_SUSPEND; ++ } ++ else if(m_extCycleCounter <= 0) ++ { ++ m_extCycleCounter = 2; ++ m_state = S_TOP_CONFIGURED_WARMUP; ++ } ++ m_extTimeout = 0; ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ case S_TOP_CONFIGURED_WARMUP: ++ if (port == NULL) // timeout ++ { ++ switch (signal) ++ { ++ case CSinkControlProtocol::TIMEOUT: ++ unsigned int delay; ++ delay = OutputSamples(&m_sampleOfNoise); ++ m_extCycleCounter--; ++ if (m_extError) ++ { ++ m_sink->Deinitialize(); ++ delete m_sink; ++ m_sink = NULL; ++ m_state = S_TOP_CONFIGURED_SUSPEND; ++ } ++ else if(m_extCycleCounter <= 0) ++ { ++ m_extCycleCounter = 30; ++ m_state = S_TOP_CONFIGURED_SILENCE; ++ } ++ m_extTimeout = 0; ++ return; ++ default: ++ break; ++ } ++ } ++ break; ++ ++ default: // we are in no state, should not happen ++ CLog::Log(LOGERROR, "CActiveSink::%s - no valid state: %d", __FUNCTION__, m_state); ++ return; ++ } ++ } // for ++} ++ ++void CActiveAESink::Process() ++{ ++ Message *msg = NULL; ++ Protocol *port = NULL; ++ bool gotMsg; ++ ++ m_state = S_TOP_UNCONFIGURED; ++ m_extTimeout = 1000; ++ m_bStateMachineSelfTrigger = false; ++ ++ while (!m_bStop) ++ { ++ gotMsg = false; ++ ++ if (m_bStateMachineSelfTrigger) ++ { ++ m_bStateMachineSelfTrigger = false; ++ // self trigger state machine ++ StateMachine(msg->signal, port, msg); ++ if (!m_bStateMachineSelfTrigger) ++ { ++ msg->Release(); ++ msg = NULL; ++ } ++ continue; ++ } ++ // check control port ++ else if (m_controlPort.ReceiveOutMessage(&msg)) ++ { ++ gotMsg = true; ++ port = &m_controlPort; ++ } ++ // check data port ++ else if (m_dataPort.ReceiveOutMessage(&msg)) ++ { ++ gotMsg = true; ++ port = &m_dataPort; ++ } ++ ++ if (gotMsg) ++ { ++ StateMachine(msg->signal, port, msg); ++ if (!m_bStateMachineSelfTrigger) ++ { ++ msg->Release(); ++ msg = NULL; ++ } ++ continue; ++ } ++ ++ // wait for message ++ else if (m_outMsgEvent.WaitMSec(m_extTimeout)) ++ { ++ continue; ++ } ++ // time out ++ else ++ { ++ msg = m_controlPort.GetMessage(); ++ msg->signal = CSinkControlProtocol::TIMEOUT; ++ port = 0; ++ // signal timeout to state machine ++ StateMachine(msg->signal, port, msg); ++ if (!m_bStateMachineSelfTrigger) ++ { ++ msg->Release(); ++ msg = NULL; ++ } ++ } ++ } ++} ++ ++void CActiveAESink::EnumerateSinkList() ++{ ++ unsigned int c_retry = 5; ++ m_sinkInfoList.clear(); ++ CAESinkFactory::EnumerateEx(m_sinkInfoList); ++ while(m_sinkInfoList.size() == 0 && c_retry > 0) ++ { ++ CLog::Log(LOGNOTICE, "No Devices found - retry: %d", c_retry); ++ Sleep(2000); ++ c_retry--; ++ // retry the enumeration ++ CAESinkFactory::EnumerateEx(m_sinkInfoList, true); ++ } ++ CLog::Log(LOGNOTICE, "Found %lu Lists of Devices", m_sinkInfoList.size()); ++ PrintSinks(); ++} ++ ++void CActiveAESink::PrintSinks() ++{ ++ for (AESinkInfoList::iterator itt = m_sinkInfoList.begin(); itt != m_sinkInfoList.end(); ++itt) ++ { ++ CLog::Log(LOGNOTICE, "Enumerated %s devices:", itt->m_sinkName.c_str()); ++ int count = 0; ++ for (AEDeviceInfoList::iterator itt2 = itt->m_deviceInfoList.begin(); itt2 != itt->m_deviceInfoList.end(); ++itt2) ++ { ++ CLog::Log(LOGNOTICE, " Device %d", ++count); ++ CAEDeviceInfo& info = *itt2; ++ std::stringstream ss((std::string)info); ++ std::string line; ++ while(std::getline(ss, line, '\n')) ++ CLog::Log(LOGNOTICE, " %s", line.c_str()); ++ } ++ } ++} ++ ++void CActiveAESink::EnumerateOutputDevices(AEDeviceList &devices, bool passthrough) ++{ ++ for (AESinkInfoList::iterator itt = m_sinkInfoList.begin(); itt != m_sinkInfoList.end(); ++itt) ++ { ++ AESinkInfo sinkInfo = *itt; ++ for (AEDeviceInfoList::iterator itt2 = sinkInfo.m_deviceInfoList.begin(); itt2 != sinkInfo.m_deviceInfoList.end(); ++itt2) ++ { ++ CAEDeviceInfo devInfo = *itt2; ++ if (passthrough && devInfo.m_deviceType == AE_DEVTYPE_PCM) ++ continue; ++ ++ std::string device = sinkInfo.m_sinkName + ":" + devInfo.m_deviceName; ++ ++ std::stringstream ss; ++ ++ /* add the sink name if we have more then one sink type */ ++ if (m_sinkInfoList.size() > 1) ++ ss << sinkInfo.m_sinkName << ": "; ++ ++ ss << devInfo.m_displayName; ++ if (!devInfo.m_displayNameExtra.empty()) ++ ss << ", " << devInfo.m_displayNameExtra; ++ ++ devices.push_back(AEDevice(ss.str(), device)); ++ } ++ } ++} ++ ++std::string CActiveAESink::GetDefaultDevice(bool passthrough) ++{ ++ for (AESinkInfoList::iterator itt = m_sinkInfoList.begin(); itt != m_sinkInfoList.end(); ++itt) ++ { ++ AESinkInfo sinkInfo = *itt; ++ for (AEDeviceInfoList::iterator itt2 = sinkInfo.m_deviceInfoList.begin(); itt2 != sinkInfo.m_deviceInfoList.end(); ++itt2) ++ { ++ CAEDeviceInfo devInfo = *itt2; ++ if (passthrough && devInfo.m_deviceType == AE_DEVTYPE_PCM) ++ continue; ++ ++ std::string device = sinkInfo.m_sinkName + ":" + devInfo.m_deviceName; ++ return device; ++ } ++ } ++ return "default"; ++} ++ ++void CActiveAESink::GetDeviceFriendlyName(std::string &device) ++{ ++ m_deviceFriendlyName = "Device not found"; ++ /* Match the device and find its friendly name */ ++ for (AESinkInfoList::iterator itt = m_sinkInfoList.begin(); itt != m_sinkInfoList.end(); ++itt) ++ { ++ AESinkInfo sinkInfo = *itt; ++ for (AEDeviceInfoList::iterator itt2 = sinkInfo.m_deviceInfoList.begin(); itt2 != sinkInfo.m_deviceInfoList.end(); ++itt2) ++ { ++ CAEDeviceInfo& devInfo = *itt2; ++ if (devInfo.m_deviceName == device) ++ { ++ m_deviceFriendlyName = devInfo.m_displayName; ++ break; ++ } ++ } ++ } ++ return; ++} ++ ++void CActiveAESink::OpenSink() ++{ ++ std::string device, driver; ++ bool passthrough = AE_IS_RAW(m_requestedFormat.m_dataFormat); ++ if (passthrough) ++ device = CSettings::Get().GetString("audiooutput.passthroughdevice"); ++ else ++ device = CSettings::Get().GetString("audiooutput.audiodevice"); ++ ++ CAESinkFactory::ParseDevice(device, driver); ++ if (driver.empty() && m_sink) ++ driver = m_sink->GetName(); ++ ++ std::string sinkName; ++ if (m_sink) ++ { ++ sinkName = m_sink->GetName(); ++ std::transform(sinkName.begin(), sinkName.end(), sinkName.begin(), ::toupper); ++ } ++ ++ if (!m_sink || sinkName != driver || !m_sink->IsCompatible(m_requestedFormat, device)) ++ { ++ CLog::Log(LOGINFO, "CActiveAE::OpenSink - sink incompatible, re-starting"); ++ ++ if (m_sink) ++ { ++ m_sink->Drain(); ++ m_sink->Deinitialize(); ++ delete m_sink; ++ m_sink = NULL; ++ } ++ ++ // get the display name of the device ++ GetDeviceFriendlyName(device); ++ ++ // if we already have a driver, prepend it to the device string ++ if (!driver.empty()) ++ device = driver + ":" + device; ++ ++ // WARNING: this changes format and does not use passthrough ++ m_sinkFormat = m_requestedFormat; ++ m_sink = CAESinkFactory::Create(device, m_sinkFormat, passthrough); ++ ++ if (!m_sink) ++ { ++ m_extError = true; ++ return; ++ } ++ ++ CLog::Log(LOGDEBUG, "CActiveAE::OpenSink - %s Initialized:", m_sink->GetName()); ++ CLog::Log(LOGDEBUG, " Output Device : %s", m_deviceFriendlyName.c_str()); ++ CLog::Log(LOGDEBUG, " Sample Rate : %d", m_sinkFormat.m_sampleRate); ++ CLog::Log(LOGDEBUG, " Sample Format : %s", CAEUtil::DataFormatToStr(m_sinkFormat.m_dataFormat)); ++ CLog::Log(LOGDEBUG, " Channel Count : %d", m_sinkFormat.m_channelLayout.Count()); ++ CLog::Log(LOGDEBUG, " Channel Layout: %s", ((std::string)m_sinkFormat.m_channelLayout).c_str()); ++ CLog::Log(LOGDEBUG, " Frames : %d", m_sinkFormat.m_frames); ++ CLog::Log(LOGDEBUG, " Frame Samples : %d", m_sinkFormat.m_frameSamples); ++ CLog::Log(LOGDEBUG, " Frame Size : %d", m_sinkFormat.m_frameSize); ++ } ++ else ++ CLog::Log(LOGINFO, "CActiveAE::OpenSink - keeping old sink with : %s, %s, %dhz", ++ CAEUtil::DataFormatToStr(m_sinkFormat.m_dataFormat), ++ ((std::string)m_sinkFormat.m_channelLayout).c_str(), ++ m_sinkFormat.m_sampleRate); ++ ++ // init sample of silence ++ SampleConfig config; ++ config.fmt = CActiveAEResample::GetAVSampleFormat(m_sinkFormat.m_dataFormat); ++ config.channel_layout = CActiveAEResample::GetAVChannelLayout(m_sinkFormat.m_channelLayout); ++ config.channels = m_sinkFormat.m_channelLayout.Count(); ++ config.sample_rate = m_sinkFormat.m_sampleRate; ++ if (m_sampleOfSilence.pkt) ++ delete m_sampleOfSilence.pkt; ++ m_sampleOfSilence.pkt = new CSoundPacket(config, m_sinkFormat.m_frames); ++ m_sampleOfSilence.pkt->nb_samples = m_sampleOfSilence.pkt->max_nb_samples; ++ ++ // init sample of noise ++ delete m_sampleOfNoise.pkt; ++ m_sampleOfNoise.pkt = new CSoundPacket(config, m_sinkFormat.m_frames); ++ m_sampleOfNoise.pkt->nb_samples = m_sampleOfNoise.pkt->max_nb_samples; ++ if (!passthrough) ++ GenerateNoise(); ++ ++ if (m_convertBuffer) ++ { ++ _aligned_free(m_convertBuffer); ++ m_convertBuffer = NULL; ++ } ++ m_convertState = CHECK_CONVERT; ++} ++ ++void CActiveAESink::ReturnBuffers() ++{ ++ Message *msg = NULL; ++ CSampleBuffer *samples; ++ while (m_dataPort.ReceiveOutMessage(&msg)) ++ { ++ if (msg->signal == CSinkDataProtocol::SAMPLE) ++ { ++ samples = *((CSampleBuffer**)msg->data); ++ msg->Reply(CSinkDataProtocol::RETURNSAMPLE, &samples, sizeof(CSampleBuffer*)); ++ } ++ } ++} ++ ++unsigned int CActiveAESink::OutputSamples(CSampleBuffer* samples) ++{ ++ uint8_t *buffer = samples->pkt->data[0]; ++ unsigned int frames = samples->pkt->nb_samples; ++ unsigned int maxFrames; ++ int retry = 0; ++ int written = 0; ++ double sinkDelay = 0.0; ++ ++ switch(m_convertState) ++ { ++ case SKIP_CONVERT: ++ break; ++ case NEED_CONVERT: ++ buffer = Convert(samples); ++ break; ++ case NEED_BYTESWAP: ++ Endian_Swap16_buf((uint16_t *)buffer, (uint16_t *)buffer, frames * samples->pkt->config.channels); ++ break; ++ case CHECK_CONVERT: ++ ConvertInit(samples); ++ break; ++ default: ++ break; ++ } ++ ++ while(frames > 0) ++ { ++ maxFrames = std::min(frames, m_sinkFormat.m_frames); ++ written = m_sink->AddPackets(buffer, maxFrames, true, true); ++ if (written == 0) ++ { ++ Sleep(500*m_sinkFormat.m_frames/m_sinkFormat.m_sampleRate); ++ retry++; ++ if (retry > 4) ++ { ++ m_extError = true; ++ CLog::Log(LOGERROR, "CActiveAESink::OutputSamples - failed"); ++ return 0; ++ } ++ else ++ continue; ++ } ++ frames -= written; ++ buffer += written*m_sinkFormat.m_frameSize; ++ sinkDelay = m_sink->GetDelay(); ++ m_stats->UpdateSinkDelay(sinkDelay, samples->pool ? written : 0); ++ } ++ return sinkDelay*1000; ++} ++ ++void CActiveAESink::ConvertInit(CSampleBuffer* samples) ++{ ++ if (CActiveAEResample::GetAESampleFormat(samples->pkt->config.fmt) != m_sinkFormat.m_dataFormat) ++ { ++ m_convertFn = CAEConvert::FrFloat(m_sinkFormat.m_dataFormat); ++ if (m_convertBuffer) ++ _aligned_free(m_convertBuffer); ++ m_convertBuffer = (uint8_t*)_aligned_malloc(m_sinkFormat.m_frames * m_sinkFormat.m_channelLayout.Count() * m_sinkFormat.m_frameSize, 16); ++ memset(m_convertBuffer, 0, m_sinkFormat.m_frames * m_sinkFormat.m_channelLayout.Count() * m_sinkFormat.m_frameSize); ++ m_convertState = NEED_CONVERT; ++ } ++ else if (AE_IS_RAW(m_requestedFormat.m_dataFormat) && CAEUtil::S16NeedsByteSwap(AE_FMT_S16NE, m_sinkFormat.m_dataFormat)) ++ { ++ m_convertState = NEED_BYTESWAP; ++ } ++ else ++ m_convertState = SKIP_CONVERT; ++} ++ ++uint8_t* CActiveAESink::Convert(CSampleBuffer* samples) ++{ ++ unsigned int nb_samples = m_convertFn((float*)samples->pkt->data[0], samples->pkt->nb_samples * samples->pkt->config.channels, m_convertBuffer); ++ return m_convertBuffer; ++} ++ ++#define PI 3.1415926536f ++ ++void CActiveAESink::GenerateNoise() ++{ ++ int nb_floats = m_sinkFormat.m_frames*m_sinkFormat.m_channelLayout.Count(); ++ float *noise = new float[nb_floats]; ++ ++ float R1, R2; ++ for(int i=0; idata[0]); ++ } ++ else ++ { ++ memcpy(m_sampleOfNoise.pkt->data[0], noise, nb_floats*sizeof(float)); ++ } ++ delete [] noise; ++} +diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.h b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.h +new file mode 100644 +index 0000000..ae19f38 +--- /dev/null ++++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.h +@@ -0,0 +1,133 @@ ++#pragma once ++/* ++ * Copyright (C) 2010-2013 Team XBMC ++ * http://xbmc.org ++ * ++ * This Program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2, or (at your option) ++ * any later version. ++ * ++ * This Program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with XBMC; see the file COPYING. If not, see ++ * . ++ * ++ */ ++ ++#include "threads/Event.h" ++#include "threads/Thread.h" ++#include "utils/ActorProtocol.h" ++#include "Interfaces/AE.h" ++#include "Interfaces/AESink.h" ++#include "AESinkFactory.h" ++#include "ActiveAEResample.h" ++#include "Utils/AEConvert.h" ++ ++namespace ActiveAE ++{ ++using namespace Actor; ++ ++class CEngineStats; ++ ++struct SinkConfig ++{ ++ AEAudioFormat format; ++ CEngineStats *stats; ++}; ++ ++class CSinkControlProtocol : public Protocol ++{ ++public: ++ CSinkControlProtocol(std::string name, CEvent* inEvent, CEvent *outEvent) : Protocol(name, inEvent, outEvent) {}; ++ enum OutSignal ++ { ++ CONFIGURE, ++ UNCONFIGURE, ++ SILENCEMODE, ++ TIMEOUT, ++ }; ++ enum InSignal ++ { ++ ACC, ++ ERR, ++ STATS, ++ }; ++}; ++ ++class CSinkDataProtocol : public Protocol ++{ ++public: ++ CSinkDataProtocol(std::string name, CEvent* inEvent, CEvent *outEvent) : Protocol(name, inEvent, outEvent) {}; ++ enum OutSignal ++ { ++ SAMPLE = 0, ++ DRAIN, ++ }; ++ enum InSignal ++ { ++ RETURNSAMPLE, ++ ACC, ++ }; ++}; ++ ++class CActiveAESink : private CThread ++{ ++public: ++ CActiveAESink(CEvent *inMsgEvent); ++ void EnumerateSinkList(); ++ void EnumerateOutputDevices(AEDeviceList &devices, bool passthrough); ++ std::string GetDefaultDevice(bool passthrough); ++ void Start(); ++ void Dispose(); ++ bool IsCompatible(const AEAudioFormat format, const std::string &device); ++ CSinkControlProtocol m_controlPort; ++ CSinkDataProtocol m_dataPort; ++ ++protected: ++ void Process(); ++ void StateMachine(int signal, Protocol *port, Message *msg); ++ void PrintSinks(); ++ void GetDeviceFriendlyName(std::string &device); ++ void OpenSink(); ++ void ReturnBuffers(); ++ ++ unsigned int OutputSamples(CSampleBuffer* samples); ++ void ConvertInit(CSampleBuffer* samples); ++ inline uint8_t* Convert(CSampleBuffer* samples); ++ ++ void GenerateNoise(); ++ ++ CEvent m_outMsgEvent; ++ CEvent *m_inMsgEvent; ++ int m_state; ++ bool m_bStateMachineSelfTrigger; ++ int m_extTimeout; ++ bool m_extError; ++ bool m_extSilence; ++ int m_extCycleCounter; ++ ++ CSampleBuffer m_sampleOfSilence; ++ CSampleBuffer m_sampleOfNoise; ++ uint8_t *m_convertBuffer; ++ CAEConvert::AEConvertFrFn m_convertFn; ++ enum ++ { ++ CHECK_CONVERT, ++ NEED_CONVERT, ++ NEED_BYTESWAP, ++ SKIP_CONVERT, ++ } m_convertState; ++ ++ std::string m_deviceFriendlyName; ++ AESinkInfoList m_sinkInfoList; ++ IAESink *m_sink; ++ AEAudioFormat m_sinkFormat, m_requestedFormat; ++ CEngineStats *m_stats; ++}; ++ ++} +diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESound.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESound.cpp +new file mode 100644 +index 0000000..3d79761 +--- /dev/null ++++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESound.cpp +@@ -0,0 +1,164 @@ ++/* ++ * Copyright (C) 2010-2013 Team XBMC ++ * http://xbmc.org ++ * ++ * This Program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2, or (at your option) ++ * any later version. ++ * ++ * This Program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with XBMC; see the file COPYING. If not, see ++ * . ++ * ++ */ ++ ++#include "Interfaces/AESound.h" ++ ++#include "AEFactory.h" ++#include "AEAudioFormat.h" ++#include "ActiveAE.h" ++#include "ActiveAESound.h" ++#include "utils/log.h" ++#include "DllAvUtil.h" ++ ++using namespace ActiveAE; ++using namespace XFILE; ++ ++/* typecast AE to CActiveAE */ ++#define AE (*((CActiveAE*)CAEFactory::GetEngine())) ++ ++CActiveAESound::CActiveAESound(const std::string &filename) : ++ IAESound (filename), ++ m_filename (filename), ++ m_volume (1.0f ) ++{ ++ m_orig_sound = NULL; ++ m_dst_sound = NULL; ++ m_pFile = NULL; ++} ++ ++CActiveAESound::~CActiveAESound() ++{ ++ if (m_orig_sound) ++ delete m_orig_sound; ++ if (m_dst_sound) ++ delete m_dst_sound; ++ Finish(); ++} ++ ++void CActiveAESound::Play() ++{ ++ AE.PlaySound(this); ++} ++ ++void CActiveAESound::Stop() ++{ ++ AE.StopSound(this); ++} ++ ++bool CActiveAESound::IsPlaying() ++{ ++ // TODO ++ return false; ++} ++ ++uint8_t** CActiveAESound::InitSound(bool orig, SampleConfig config, int nb_samples) ++{ ++ CSoundPacket **info; ++ if (orig) ++ info = &m_orig_sound; ++ else ++ info = &m_dst_sound; ++ ++ if (*info) ++ delete *info; ++ *info = new CSoundPacket(config, nb_samples); ++ ++ (*info)->nb_samples = 0; ++ m_isConverted = false; ++ return (*info)->data; ++} ++ ++bool CActiveAESound::StoreSound(bool orig, uint8_t **buffer, int samples, int linesize) ++{ ++ CSoundPacket **info; ++ if (orig) ++ info = &m_orig_sound; ++ else ++ info = &m_dst_sound; ++ ++ if ((*info)->nb_samples + samples > (*info)->max_nb_samples) ++ { ++ CLog::Log(LOGERROR, "CActiveAESound::StoreSound - exceeded max samples"); ++ return false; ++ } ++ ++ int bytes_to_copy = samples * (*info)->bytes_per_sample * (*info)->config.channels; ++ bytes_to_copy /= (*info)->planes; ++ int start = (*info)->nb_samples * (*info)->bytes_per_sample * (*info)->config.channels; ++ start /= (*info)->planes; ++ ++ for (int i=0; i<(*info)->planes; i++) ++ { ++ memcpy((*info)->data[i]+start, buffer[i], bytes_to_copy); ++ } ++ (*info)->nb_samples += samples; ++ ++ return true; ++} ++ ++CSoundPacket *CActiveAESound::GetSound(bool orig) ++{ ++ if (orig) ++ return m_orig_sound; ++ else ++ return m_dst_sound; ++} ++ ++bool CActiveAESound::Prepare() ++{ ++ unsigned int flags = READ_TRUNCATED | READ_CHUNKED; ++ m_pFile = new CFile(); ++ ++ if (!m_pFile->Open(m_filename, flags)) ++ { ++ delete m_pFile; ++ m_pFile = NULL; ++ return false; ++ } ++ m_isSeekPosible = m_pFile->IoControl(IOCTRL_SEEK_POSSIBLE, NULL) != 0; ++ m_fileSize = m_pFile->GetLength(); ++ return true; ++} ++ ++void CActiveAESound::Finish() ++{ ++ delete m_pFile; ++ m_pFile = NULL; ++} ++ ++int CActiveAESound::GetChunkSize() ++{ ++ return m_pFile->GetChunkSize(); ++} ++ ++int CActiveAESound::Read(void *h, uint8_t* buf, int size) ++{ ++ CFile *pFile = static_cast(h)->m_pFile; ++ return pFile->Read(buf, size); ++} ++ ++offset_t CActiveAESound::Seek(void *h, offset_t pos, int whence) ++{ ++ CFile* pFile = static_cast(h)->m_pFile; ++ if(whence == AVSEEK_SIZE) ++ return pFile->GetLength(); ++ else ++ return pFile->Seek(pos, whence & ~AVSEEK_FORCE); ++} +diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESound.h b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESound.h +new file mode 100644 +index 0000000..7cdf76c +--- /dev/null ++++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESound.h +@@ -0,0 +1,73 @@ ++#pragma once ++/* ++ * Copyright (C) 2010-2013 Team XBMC ++ * http://xbmc.org ++ * ++ * This Program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2, or (at your option) ++ * any later version. ++ * ++ * This Program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with XBMC; see the file COPYING. If not, see ++ * . ++ * ++ */ ++ ++#include "utils/StdString.h" ++#include "Interfaces/AESound.h" ++#include "ActiveAEResample.h" ++#include "filesystem/File.h" ++ ++class DllAvUtil; ++ ++namespace ActiveAE ++{ ++ ++class CActiveAESound : public IAESound ++{ ++public: ++ CActiveAESound (const std::string &filename); ++ virtual ~CActiveAESound(); ++ ++ virtual void Play(); ++ virtual void Stop(); ++ virtual bool IsPlaying(); ++ ++ virtual void SetVolume(float volume) { m_volume = std::max(0.0f, std::min(1.0f, volume)); } ++ virtual float GetVolume() { return m_volume; } ++ ++ uint8_t** InitSound(bool orig, SampleConfig config, int nb_samples); ++ bool StoreSound(bool orig, uint8_t **buffer, int samples, int linesize); ++ CSoundPacket *GetSound(bool orig); ++ ++ bool IsConverted() { return m_isConverted; } ++ void SetConverted(bool state) { m_isConverted = state; } ++ ++ bool Prepare(); ++ void Finish(); ++ int GetChunkSize(); ++ int GetFileSize() { return m_fileSize; } ++ bool IsSeekPosible() { return m_isSeekPosible; } ++ ++ static int Read(void *h, uint8_t* buf, int size); ++ static offset_t Seek(void *h, offset_t pos, int whence); ++ ++protected: ++ std::string m_filename; ++ XFILE::CFile *m_pFile; ++ bool m_isSeekPosible; ++ int m_fileSize; ++ float m_volume; ++ ++ CSoundPacket *m_orig_sound; ++ CSoundPacket *m_dst_sound; ++ ++ bool m_isConverted; ++}; ++} +diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp +new file mode 100644 +index 0000000..e21b9d5 +--- /dev/null ++++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp +@@ -0,0 +1,357 @@ ++/* ++ * Copyright (C) 2010-2013 Team XBMC ++ * http://xbmc.org ++ * ++ * This Program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2, or (at your option) ++ * any later version. ++ * ++ * This Program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with XBMC; see the file COPYING. If not, see ++ * . ++ * ++ */ ++ ++#include "system.h" ++#include "threads/SingleLock.h" ++#include "utils/log.h" ++#include "utils/MathUtils.h" ++ ++#include "AEFactory.h" ++#include "Utils/AEUtil.h" ++ ++#include "ActiveAE.h" ++#include "ActiveAEStream.h" ++ ++using namespace ActiveAE; ++ ++/* typecast AE to CActiveAE */ ++#define AE (*((CActiveAE*)CAEFactory::GetEngine())) ++ ++ ++CActiveAEStream::CActiveAEStream(AEAudioFormat *format) ++{ ++ m_format = *format; ++ m_bufferedTime = 0; ++ m_currentBuffer = NULL; ++ m_drain = false; ++ m_paused = false; ++ m_rgain = 1.0; ++ m_volume = 1.0; ++ m_streamSpace = m_format.m_frameSize * m_format.m_frames; ++ m_streamDraining = false; ++ m_streamDrained = false; ++ m_streamFading = false; ++ m_streamFreeBuffers = 0; ++ m_streamIsBuffering = true; ++ m_streamSlave = NULL; ++} ++ ++CActiveAEStream::~CActiveAEStream() ++{ ++} ++ ++void CActiveAEStream::IncFreeBuffers() ++{ ++ CSingleLock lock(m_streamLock); ++ m_streamFreeBuffers++; ++} ++ ++void CActiveAEStream::DecFreeBuffers() ++{ ++ CSingleLock lock(m_streamLock); ++ m_streamFreeBuffers--; ++} ++ ++void CActiveAEStream::ResetFreeBuffers() ++{ ++ CSingleLock lock(m_streamLock); ++ m_streamFreeBuffers = 0; ++} ++ ++unsigned int CActiveAEStream::GetSpace() ++{ ++ CSingleLock lock(m_streamLock); ++ return m_streamFreeBuffers * m_streamSpace; ++} ++ ++unsigned int CActiveAEStream::AddData(void *data, unsigned int size) ++{ ++ Message *msg; ++ unsigned int copied = 0; ++ int bytesToCopy = size; ++ while(copied < size) ++ { ++ if (m_currentBuffer) ++ { ++ int start = m_currentBuffer->pkt->nb_samples * ++ m_currentBuffer->pkt->bytes_per_sample * ++ m_currentBuffer->pkt->config.channels / ++ m_currentBuffer->pkt->planes; ++ ++ int freeSamples = m_currentBuffer->pkt->max_nb_samples - m_currentBuffer->pkt->nb_samples; ++ int space = freeSamples * m_format.m_frameSize; ++ int bytes = std::min(bytesToCopy, space); ++ int samples = bytes / m_currentBuffer->pkt->bytes_per_sample / m_currentBuffer->pkt->config.channels; ++ //TODO: handle planar formats ++ memcpy(m_currentBuffer->pkt->data[0] + start, (uint8_t*)data+copied, bytes); ++ { ++ CSingleLock lock(*m_statsLock); ++ m_currentBuffer->pkt->nb_samples += samples; ++ m_bufferedTime += (double)samples / m_currentBuffer->pkt->config.sample_rate; ++ } ++ copied += bytes; ++ bytesToCopy -= bytes; ++ if (m_currentBuffer->pkt->nb_samples == m_currentBuffer->pkt->max_nb_samples) ++ { ++ MsgStreamSample msgData; ++ msgData.buffer = m_currentBuffer; ++ msgData.stream = this; ++ m_streamPort->SendOutMessage(CActiveAEDataProtocol::STREAMSAMPLE, &msgData, sizeof(MsgStreamSample)); ++ m_currentBuffer = NULL; ++ } ++ continue; ++ } ++ else if (m_streamPort->ReceiveInMessage(&msg)) ++ { ++ if (msg->signal == CActiveAEDataProtocol::STREAMBUFFER) ++ { ++ m_currentBuffer = *((CSampleBuffer**)msg->data); ++ msg->Release(); ++ DecFreeBuffers(); ++ continue; ++ } ++ else ++ { ++ CLog::Log(LOGERROR, "CActiveAEStream::AddData - unknown signal"); ++ msg->Release(); ++ break; ++ } ++ } ++ if (!m_inMsgEvent.WaitMSec(200)) ++ break; ++ } ++ return copied; ++} ++ ++double CActiveAEStream::GetDelay() ++{ ++ return AE.GetDelay(this); ++} ++ ++bool CActiveAEStream::IsBuffering() ++{ ++ CSingleLock lock(m_streamLock); ++ return m_streamIsBuffering; ++} ++ ++double CActiveAEStream::GetCacheTime() ++{ ++ return AE.GetCacheTime(this); ++} ++ ++double CActiveAEStream::GetCacheTotal() ++{ ++ return AE.GetCacheTotal(this); ++} ++ ++void CActiveAEStream::Pause() ++{ ++ AE.PauseStream(this, true); ++} ++ ++void CActiveAEStream::Resume() ++{ ++ AE.PauseStream(this, false); ++} ++ ++void CActiveAEStream::Drain(bool wait) ++{ ++ Message *msg; ++ CActiveAEStream *stream = this; ++ ++ m_streamDraining = true; ++ m_streamDrained = false; ++ ++ Message *reply; ++ if (m_streamPort->SendOutMessageSync(CActiveAEDataProtocol::DRAINSTREAM, ++ &reply,2000, ++ &stream, sizeof(CActiveAEStream*))) ++ { ++ bool success = reply->signal == CActiveAEDataProtocol::ACC ? true : false; ++ reply->Release(); ++ if (!success) ++ { ++ CLog::Log(LOGERROR, "CActiveAEStream::Drain - no acc"); ++ } ++ } ++ ++ if (m_currentBuffer) ++ { ++ MsgStreamSample msgData; ++ msgData.buffer = m_currentBuffer; ++ msgData.stream = this; ++ m_streamPort->SendOutMessage(CActiveAEDataProtocol::STREAMSAMPLE, &msgData, sizeof(MsgStreamSample)); ++ m_currentBuffer = NULL; ++ } ++ ++ XbmcThreads::EndTime timer(2000); ++ while (!timer.IsTimePast()) ++ { ++ if (m_streamPort->ReceiveInMessage(&msg)) ++ { ++ if (msg->signal == CActiveAEDataProtocol::STREAMBUFFER) ++ { ++ MsgStreamSample msgData; ++ msgData.stream = this; ++ msgData.buffer = *((CSampleBuffer**)msg->data); ++ msg->Reply(CActiveAEDataProtocol::STREAMSAMPLE, &msgData, sizeof(MsgStreamSample)); ++ DecFreeBuffers(); ++ continue; ++ } ++ else if (msg->signal == CActiveAEDataProtocol::STREAMDRAINED) ++ { ++ msg->Release(); ++ return; ++ } ++ } ++ else if (!wait) ++ return; ++ ++ m_inMsgEvent.WaitMSec(timer.MillisLeft()); ++ } ++ CLog::Log(LOGERROR, "CActiveAEStream::Drain - timeout out"); ++} ++ ++bool CActiveAEStream::IsDraining() ++{ ++ CSingleLock lock(m_streamLock); ++ return m_streamDraining; ++} ++ ++bool CActiveAEStream::IsDrained() ++{ ++ CSingleLock lock(m_streamLock); ++ return m_streamDrained; ++} ++ ++void CActiveAEStream::Flush() ++{ ++ if (m_currentBuffer) ++ { ++ MsgStreamSample msgData; ++ m_currentBuffer->pkt->nb_samples = 0; ++ msgData.buffer = m_currentBuffer; ++ msgData.stream = this; ++ m_streamPort->SendOutMessage(CActiveAEDataProtocol::STREAMSAMPLE, &msgData, sizeof(MsgStreamSample)); ++ m_currentBuffer = NULL; ++ } ++ AE.FlushStream(this); ++ ResetFreeBuffers(); ++} ++ ++float CActiveAEStream::GetAmplification() ++{ ++ return m_streamAmplify; ++} ++ ++void CActiveAEStream::SetAmplification(float amplify) ++{ ++ m_streamAmplify = amplify; ++ AE.SetStreamAmplification(this, m_streamAmplify); ++} ++ ++float CActiveAEStream::GetReplayGain() ++{ ++ return m_streamRgain; ++} ++ ++void CActiveAEStream::SetReplayGain(float factor) ++{ ++ m_streamRgain = std::max( 0.0f, factor); ++ AE.SetStreamReplaygain(this, m_streamRgain); ++} ++ ++float CActiveAEStream::GetVolume() ++{ ++ return m_streamVolume; ++} ++ ++void CActiveAEStream::SetVolume(float volume) ++{ ++ m_streamVolume = std::max( 0.0f, std::min(1.0f, volume)); ++ AE.SetStreamVolume(this, m_streamVolume); ++} ++ ++double CActiveAEStream::GetResampleRatio() ++{ ++ return m_streamResampleRatio; ++} ++ ++bool CActiveAEStream::SetResampleRatio(double ratio) ++{ ++ m_streamResampleRatio = ratio; ++ AE.SetStreamResampleRatio(this, m_streamResampleRatio); ++ return true; ++} ++ ++void CActiveAEStream::FadeVolume(float from, float target, unsigned int time) ++{ ++ if (time == 0) ++ return; ++ ++ m_streamFading = true; ++ AE.SetStreamFade(this, from, target, time); ++} ++ ++bool CActiveAEStream::IsFading() ++{ ++ CSingleLock lock(m_streamLock); ++ return m_streamFading; ++} ++ ++const unsigned int CActiveAEStream::GetFrameSize() const ++{ ++ return m_format.m_frameSize; ++} ++ ++const unsigned int CActiveAEStream::GetChannelCount() const ++{ ++ return m_format.m_channelLayout.Count(); ++} ++ ++const unsigned int CActiveAEStream::GetSampleRate() const ++{ ++ return m_format.m_sampleRate; ++} ++ ++const unsigned int CActiveAEStream::GetEncodedSampleRate() const ++{ ++ return m_format.m_encodedRate; ++} ++ ++const enum AEDataFormat CActiveAEStream::GetDataFormat() const ++{ ++ return m_format.m_dataFormat; ++} ++ ++void CActiveAEStream::RegisterAudioCallback(IAudioCallback* pCallback) ++{ ++} ++ ++void CActiveAEStream::UnRegisterAudioCallback() ++{ ++} ++ ++void CActiveAEStream::RegisterSlave(IAEStream *slave) ++{ ++ CSingleLock lock(m_streamLock); ++ m_streamSlave = slave; ++} ++ +diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.h b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.h +new file mode 100644 +index 0000000..b18d0f5 +--- /dev/null ++++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.h +@@ -0,0 +1,115 @@ ++#pragma once ++/* ++ * Copyright (C) 2010-2013 Team XBMC ++ * http://xbmc.org ++ * ++ * This Program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2, or (at your option) ++ * any later version. ++ * ++ * This Program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with XBMC; see the file COPYING. If not, see ++ * . ++ * ++ */ ++ ++#include "AEAudioFormat.h" ++#include "Interfaces/AEStream.h" ++#include "Utils/AELimiter.h" ++ ++namespace ActiveAE ++{ ++ ++class CActiveAEStream : public IAEStream ++{ ++protected: ++ friend class CActiveAE; ++ friend class CEngineStats; ++ CActiveAEStream(AEAudioFormat *format); ++ virtual ~CActiveAEStream(); ++ void FadingFinished(); ++ void IncFreeBuffers(); ++ void DecFreeBuffers(); ++ void ResetFreeBuffers(); ++ ++public: ++ virtual unsigned int GetSpace(); ++ virtual unsigned int AddData(void *data, unsigned int size); ++ virtual double GetDelay(); ++ virtual bool IsBuffering(); ++ virtual double GetCacheTime(); ++ virtual double GetCacheTotal(); ++ ++ virtual void Pause(); ++ virtual void Resume(); ++ virtual void Drain(bool wait); ++ virtual bool IsDraining(); ++ virtual bool IsDrained(); ++ virtual void Flush(); ++ ++ virtual float GetVolume(); ++ virtual float GetReplayGain(); ++ virtual float GetAmplification(); ++ virtual void SetVolume(float volume); ++ virtual void SetReplayGain(float factor); ++ virtual void SetAmplification(float amplify); ++ ++ virtual const unsigned int GetFrameSize() const; ++ virtual const unsigned int GetChannelCount() const; ++ ++ virtual const unsigned int GetSampleRate() const ; ++ virtual const unsigned int GetEncodedSampleRate() const; ++ virtual const enum AEDataFormat GetDataFormat() const; ++ ++ virtual double GetResampleRatio(); ++ virtual bool SetResampleRatio(double ratio); ++ virtual void RegisterAudioCallback(IAudioCallback* pCallback); ++ virtual void UnRegisterAudioCallback(); ++ virtual void FadeVolume(float from, float to, unsigned int time); ++ virtual bool IsFading(); ++ virtual void RegisterSlave(IAEStream *stream); ++ ++protected: ++ ++ AEAudioFormat m_format; ++ float m_streamVolume; ++ float m_streamRgain; ++ float m_streamAmplify; ++ double m_streamResampleRatio; ++ unsigned int m_streamSpace; ++ bool m_streamDraining; ++ bool m_streamDrained; ++ bool m_streamFading; ++ int m_streamFreeBuffers; ++ bool m_streamIsBuffering; ++ IAEStream *m_streamSlave; ++ CCriticalSection m_streamLock; ++ ++ // only accessed by engine ++ CActiveAEBufferPool *m_inputBuffers; ++ CActiveAEBufferPoolResample *m_resampleBuffers; ++ std::deque m_processingSamples; ++ CSampleBuffer *m_currentBuffer; ++ CActiveAEDataProtocol *m_streamPort; ++ CEvent m_inMsgEvent; ++ CCriticalSection *m_statsLock; ++ bool m_drain; ++ bool m_paused; ++ bool m_started; ++ CAELimiter m_limiter; ++ float m_volume; ++ float m_rgain; ++ float m_bufferedTime; ++ int m_fadingSamples; ++ float m_fadingBase; ++ float m_fadingTarget; ++ int m_fadingTime; ++}; ++} ++ +diff --git a/xbmc/cores/AudioEngine/Makefile.in b/xbmc/cores/AudioEngine/Makefile.in +index 833dfab..2e1a83d 100644 +--- a/xbmc/cores/AudioEngine/Makefile.in ++++ b/xbmc/cores/AudioEngine/Makefile.in +@@ -43,6 +43,13 @@ SRCS += Engines/SoftAE/SoftAE.cpp + SRCS += Engines/SoftAE/SoftAEStream.cpp + SRCS += Engines/SoftAE/SoftAESound.cpp + ++SRCS += Engines/ActiveAE/ActiveAE.cpp ++SRCS += Engines/ActiveAE/ActiveAESink.cpp ++SRCS += Engines/ActiveAE/ActiveAEStream.cpp ++SRCS += Engines/ActiveAE/ActiveAESound.cpp ++SRCS += Engines/ActiveAE/ActiveAEResample.cpp ++SRCS += Engines/ActiveAE/ActiveAEBuffer.cpp ++ + ifeq (@USE_ANDROID@,1) + SRCS += Sinks/AESinkAUDIOTRACK.cpp + else +diff --git a/xbmc/utils/ActorProtocol.cpp b/xbmc/utils/ActorProtocol.cpp +new file mode 100644 +index 0000000..cf4c26f +--- /dev/null ++++ b/xbmc/utils/ActorProtocol.cpp +@@ -0,0 +1,253 @@ ++/* ++ * Copyright (C) 2005-2013 Team XBMC ++ * http://www.xbmc.org ++ * ++ * This Program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2, or (at your option) ++ * any later version. ++ * ++ * This Program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with XBMC; see the file COPYING. If not, see ++ * . ++ * ++ */ ++ ++#include "ActorProtocol.h" ++ ++using namespace Actor; ++ ++void Message::Release() ++{ ++ bool skip; ++ origin->Lock(); ++ skip = isSync ? !isSyncFini : false; ++ isSyncFini = true; ++ origin->Unlock(); ++ ++ if (skip) ++ return; ++ ++ // free data buffer ++ if (data != buffer) ++ delete [] data; ++ ++ // delete event in case of sync message ++ if (event) ++ delete event; ++ ++ origin->ReturnMessage(this); ++} ++ ++bool Message::Reply(int sig, void *data /* = NULL*/, int size /* = 0 */) ++{ ++ if (!isSync) ++ { ++ if (isOut) ++ return origin->SendInMessage(sig, data, size); ++ else ++ return origin->SendOutMessage(sig, data, size); ++ } ++ ++ origin->Lock(); ++ ++ if (!isSyncTimeout) ++ { ++ Message *msg = origin->GetMessage(); ++ msg->signal = sig; ++ msg->isOut = !isOut; ++ replyMessage = msg; ++ if (data) ++ { ++ if (size > MSG_INTERNAL_BUFFER_SIZE) ++ msg->data = new uint8_t[size]; ++ else ++ msg->data = msg->buffer; ++ memcpy(msg->data, data, size); ++ } ++ } ++ ++ origin->Unlock(); ++ ++ if (event) ++ event->Set(); ++ ++ return true; ++} ++ ++Protocol::~Protocol() ++{ ++ Message *msg; ++ Purge(); ++ while (!freeMessageQueue.empty()) ++ { ++ msg = freeMessageQueue.front(); ++ freeMessageQueue.pop(); ++ delete msg; ++ } ++} ++ ++Message *Protocol::GetMessage() ++{ ++ Message *msg; ++ ++ CSingleLock lock(criticalSection); ++ ++ if (!freeMessageQueue.empty()) ++ { ++ msg = freeMessageQueue.front(); ++ freeMessageQueue.pop(); ++ } ++ else ++ msg = new Message(); ++ ++ msg->isSync = false; ++ msg->isSyncFini = false; ++ msg->isSyncTimeout = false; ++ msg->event = NULL; ++ msg->data = NULL; ++ msg->payloadSize = 0; ++ msg->replyMessage = NULL; ++ msg->origin = this; ++ ++ return msg; ++} ++ ++void Protocol::ReturnMessage(Message *msg) ++{ ++ CSingleLock lock(criticalSection); ++ ++ freeMessageQueue.push(msg); ++} ++ ++bool Protocol::SendOutMessage(int signal, void *data /* = NULL */, int size /* = 0 */, Message *outMsg /* = NULL */) ++{ ++ Message *msg; ++ if (outMsg) ++ msg = outMsg; ++ else ++ msg = GetMessage(); ++ ++ msg->signal = signal; ++ msg->isOut = true; ++ ++ if (data) ++ { ++ if (size > MSG_INTERNAL_BUFFER_SIZE) ++ msg->data = new uint8_t[size]; ++ else ++ msg->data = msg->buffer; ++ memcpy(msg->data, data, size); ++ } ++ ++ { CSingleLock lock(criticalSection); ++ outMessages.push(msg); ++ } ++ containerOutEvent->Set(); ++ ++ return true; ++} ++ ++bool Protocol::SendInMessage(int signal, void *data /* = NULL */, int size /* = 0 */, Message *outMsg /* = NULL */) ++{ ++ Message *msg; ++ if (outMsg) ++ msg = outMsg; ++ else ++ msg = GetMessage(); ++ ++ msg->signal = signal; ++ msg->isOut = false; ++ ++ if (data) ++ { ++ if (size > MSG_INTERNAL_BUFFER_SIZE) ++ msg->data = new uint8_t[size]; ++ else ++ msg->data = msg->buffer; ++ memcpy(msg->data, data, size); ++ } ++ ++ { CSingleLock lock(criticalSection); ++ inMessages.push(msg); ++ } ++ containerInEvent->Set(); ++ ++ return true; ++} ++ ++ ++bool Protocol::SendOutMessageSync(int signal, Message **retMsg, int timeout, void *data /* = NULL */, int size /* = 0 */) ++{ ++ Message *msg = GetMessage(); ++ msg->isOut = true; ++ msg->isSync = true; ++ msg->event = new CEvent; ++ msg->event->Reset(); ++ SendOutMessage(signal, data, size, msg); ++ ++ if (!msg->event->WaitMSec(timeout)) ++ { ++ msg->origin->Lock(); ++ if (msg->replyMessage) ++ *retMsg = msg->replyMessage; ++ else ++ { ++ *retMsg = NULL; ++ msg->isSyncTimeout = true; ++ } ++ msg->origin->Unlock(); ++ } ++ else ++ *retMsg = msg->replyMessage; ++ ++ msg->Release(); ++ ++ if (*retMsg) ++ return true; ++ else ++ return false; ++} ++ ++bool Protocol::ReceiveOutMessage(Message **msg) ++{ ++ CSingleLock lock(criticalSection); ++ ++ if (outMessages.empty() || outDefered) ++ return false; ++ ++ *msg = outMessages.front(); ++ outMessages.pop(); ++ ++ return true; ++} ++ ++bool Protocol::ReceiveInMessage(Message **msg) ++{ ++ CSingleLock lock(criticalSection); ++ ++ if (inMessages.empty() || inDefered) ++ return false; ++ ++ *msg = inMessages.front(); ++ inMessages.pop(); ++ ++ return true; ++} ++ ++ ++void Protocol::Purge() ++{ ++ Message *msg; ++ ++ while (ReceiveInMessage(&msg)) ++ msg->Release(); ++ ++ while (ReceiveOutMessage(&msg)) ++ msg->Release(); ++} +diff --git a/xbmc/utils/ActorProtocol.h b/xbmc/utils/ActorProtocol.h +new file mode 100644 +index 0000000..8ef3359 +--- /dev/null ++++ b/xbmc/utils/ActorProtocol.h +@@ -0,0 +1,87 @@ ++/* ++ * Copyright (C) 2005-2013 Team XBMC ++ * http://www.xbmc.org ++ * ++ * This Program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2, or (at your option) ++ * any later version. ++ * ++ * This Program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with XBMC; see the file COPYING. If not, see ++ * . ++ * ++ */ ++ ++#pragma once ++ ++#include "threads/Thread.h" ++#include "utils/log.h" ++#include ++#include "memory.h" ++ ++#define MSG_INTERNAL_BUFFER_SIZE 32 ++ ++namespace Actor ++{ ++ ++class Protocol; ++ ++class Message ++{ ++ friend class Protocol; ++public: ++ int signal; ++ bool isSync; ++ bool isSyncFini; ++ bool isOut; ++ bool isSyncTimeout; ++ int payloadSize; ++ uint8_t buffer[MSG_INTERNAL_BUFFER_SIZE]; ++ uint8_t *data; ++ Message *replyMessage; ++ Protocol *origin; ++ CEvent *event; ++ ++ void Release(); ++ bool Reply(int sig, void *data = NULL, int size = 0); ++ ++private: ++ Message() {isSync = false; data = NULL; event = NULL; replyMessage = NULL;}; ++}; ++ ++class Protocol ++{ ++public: ++ Protocol(std::string name, CEvent* inEvent, CEvent *outEvent) ++ : portName(name), inDefered(false), outDefered(false) {containerInEvent = inEvent; containerOutEvent = outEvent;}; ++ virtual ~Protocol(); ++ Message *GetMessage(); ++ void ReturnMessage(Message *msg); ++ bool SendOutMessage(int signal, void *data = NULL, int size = 0, Message *outMsg = NULL); ++ bool SendInMessage(int signal, void *data = NULL, int size = 0, Message *outMsg = NULL); ++ bool SendOutMessageSync(int signal, Message **retMsg, int timeout, void *data = NULL, int size = 0); ++ bool ReceiveOutMessage(Message **msg); ++ bool ReceiveInMessage(Message **msg); ++ void Purge(); ++ void DeferIn(bool value) {inDefered = value;}; ++ void DeferOut(bool value) {outDefered = value;}; ++ void Lock() {criticalSection.lock();}; ++ void Unlock() {criticalSection.unlock();}; ++ std::string portName; ++ ++protected: ++ CEvent *containerInEvent, *containerOutEvent; ++ CCriticalSection criticalSection; ++ std::queue outMessages; ++ std::queue inMessages; ++ std::queue freeMessageQueue; ++ bool inDefered, outDefered; ++}; ++ ++} +diff --git a/xbmc/utils/Makefile.in b/xbmc/utils/Makefile.in +index 694a9bd..ca49be2 100644 +--- a/xbmc/utils/Makefile.in ++++ b/xbmc/utils/Makefile.in +@@ -70,6 +70,7 @@ SRCS += Vector.cpp + SRCS += Weather.cpp + SRCS += XBMCTinyXML.cpp + SRCS += XMLUtils.cpp ++SRCS += ActorProtocol.cpp + + ifeq (@USE_OPENGLES@,1) + SRCS += AMLUtils.cpp +-- +1.8.1.6 + + +From aaa70a24dc188032d626a82092d82183e95303f6 Mon Sep 17 00:00:00 2001 +From: fritsch +Date: Sat, 8 Jun 2013 09:39:38 +0200 +Subject: [PATCH 014/120] ActiveAE: Make Factory aware of environment, change + global namespace + +--- + xbmc/cores/AudioEngine/AEFactory.cpp | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/xbmc/cores/AudioEngine/AEFactory.cpp b/xbmc/cores/AudioEngine/AEFactory.cpp +index 4f9f566..5adda5f 100644 +--- a/xbmc/cores/AudioEngine/AEFactory.cpp ++++ b/xbmc/cores/AudioEngine/AEFactory.cpp +@@ -28,7 +28,6 @@ + #else + #include "Engines/SoftAE/SoftAE.h" + #include "Engines/ActiveAE/ActiveAE.h" +- using namespace ActiveAE; + #endif + + #if defined(HAS_PULSEAUDIO) +@@ -69,6 +68,8 @@ bool CAEFactory::LoadEngine() + #endif + if (!loaded && engine == "SOFT" ) + loaded = CAEFactory::LoadEngine(AE_ENGINE_SOFT); ++ if (!loaded && engine == "ACTIVE") ++ loaded = CAEFactory::LoadEngine(AE_ENGINE_ACTIVE); + } + #endif + +@@ -101,7 +102,7 @@ bool CAEFactory::LoadEngine(enum AEEngine engine) + case AE_ENGINE_COREAUDIO: AE = new CCoreAudioAE(); break; + #else + case AE_ENGINE_SOFT : AE = new CSoftAE(); break; +- case AE_ENGINE_ACTIVE : AE = new CActiveAE(); break; ++ case AE_ENGINE_ACTIVE : AE = new ActiveAE::CActiveAE(); break; + #endif + #if defined(HAS_PULSEAUDIO) + case AE_ENGINE_PULSE : AE = new CPulseAE(); break; +-- +1.8.1.6 + + +From b3b2ffbc59448441f9afdeb45c0fd126656a74bd Mon Sep 17 00:00:00 2001 +From: unknown +Date: Thu, 11 Jul 2013 18:33:34 +0200 +Subject: [PATCH 016/120] AE: allow Windows to use ActiveAE via env + +--- + xbmc/cores/AudioEngine/AEFactory.cpp | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/xbmc/cores/AudioEngine/AEFactory.cpp b/xbmc/cores/AudioEngine/AEFactory.cpp +index 5adda5f..d5517f3 100644 +--- a/xbmc/cores/AudioEngine/AEFactory.cpp ++++ b/xbmc/cores/AudioEngine/AEFactory.cpp +@@ -73,6 +73,20 @@ bool CAEFactory::LoadEngine() + } + #endif + ++#if defined(TARGET_WINDOWS) ++ std::string engine; ++ if (getenv("AE_ENGINE")) ++ { ++ engine = (std::string)getenv("AE_ENGINE"); ++ std::transform(engine.begin(), engine.end(), engine.begin(), ::toupper); ++ ++ if (!loaded && engine == "SOFT" ) ++ loaded = CAEFactory::LoadEngine(AE_ENGINE_SOFT); ++ if (!loaded && engine == "ACTIVE") ++ loaded = CAEFactory::LoadEngine(AE_ENGINE_ACTIVE); ++ } ++#endif ++ + #if defined(HAS_PULSEAUDIO) + if (!loaded) + loaded = CAEFactory::LoadEngine(AE_ENGINE_PULSE); +-- +1.8.1.6 + + +From c1c001b40a648e8812678c5b994e9566c5a30ca2 Mon Sep 17 00:00:00 2001 From: Rainer Hochecker Date: Thu, 30 May 2013 10:56:06 +0200 -Subject: [PATCH 001/102] renderer: use fence for determination when a buffer +Subject: [PATCH 017/120] renderer: use fence for determination when a buffer is ready for reuse --- @@ -133,10 +6980,10 @@ index 28201a2..595ed8b 100644 1.8.1.6 -From 695d323854adbc1fef8c6b0f965a08b842877587 Mon Sep 17 00:00:00 2001 +From 2a6ca858bf5301d36102270c447912c1455ba1cf Mon Sep 17 00:00:00 2001 From: xbmc Date: Mon, 28 May 2012 10:34:39 +0200 -Subject: [PATCH 002/102] videoplayer: adapt lateness detection and dropping to +Subject: [PATCH 018/120] videoplayer: adapt lateness detection and dropping to buffering --- @@ -710,10 +7557,10 @@ index 5f763c0..9be23fb 100644 1.8.1.6 -From dc0f743e412bd0332671be8ff6b62975f321dded Mon Sep 17 00:00:00 2001 +From 14bd8098eea15a14ba62562d9575f2ee9767965b Mon Sep 17 00:00:00 2001 From: xbmc Date: Sun, 2 Sep 2012 16:05:21 +0200 -Subject: [PATCH 003/102] video player: present correct pts to user for a/v +Subject: [PATCH 019/120] video player: present correct pts to user for a/v sync (after buffering in renderer) --- @@ -781,10 +7628,10 @@ index 9be23fb..3c3e007 100644 1.8.1.6 -From 801f5ce03ba677ecfeed4b899ec3cfef62d189c1 Mon Sep 17 00:00:00 2001 +From d9d48dd1bb4db8f2a60a01ff4d1a0346467fc41c Mon Sep 17 00:00:00 2001 From: xbmc Date: Sat, 16 Feb 2013 18:25:53 +0100 -Subject: [PATCH 004/102] videoplayer: some rework and documentation +Subject: [PATCH 020/120] videoplayer: some rework and documentation --- .../dvdplayer/DVDCodecs/Video/DVDVideoCodec.h | 29 ++++++++++++++++++++-- @@ -895,10 +7742,10 @@ index ba99804..56b32b9 100644 1.8.1.6 -From cb666920ca7b008a2f0ed56df9f0229c254be4fe Mon Sep 17 00:00:00 2001 +From e28c8ab5d80c5865a9ac4df391020ab9a963cc5c Mon Sep 17 00:00:00 2001 From: xbmc Date: Sat, 7 Apr 2012 09:19:00 +0200 -Subject: [PATCH 005/102] vdpau: redesign +Subject: [PATCH 021/120] vdpau: redesign --- language/English/strings.po | 12 +- @@ -918,17 +7765,14 @@ Subject: [PATCH 005/102] vdpau: redesign xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 1 + xbmc/settings/AdvancedSettings.cpp | 8 +- xbmc/settings/AdvancedSettings.h | 4 +- - xbmc/utils/ActorProtocol.cpp | 253 ++ - xbmc/utils/ActorProtocol.h | 87 + - xbmc/utils/Makefile.in | 1 + + xbmc/utils/ActorProtocol.cpp | 4 + + xbmc/utils/ActorProtocol.h | 4 + xbmc/video/dialogs/GUIDialogVideoSettings.cpp | 2 +- xbmc/windowing/X11/WinSystemX11.h | 1 + - 22 files changed, 3911 insertions(+), 1230 deletions(-) - create mode 100644 xbmc/utils/ActorProtocol.cpp - create mode 100644 xbmc/utils/ActorProtocol.h + 21 files changed, 3578 insertions(+), 1230 deletions(-) diff --git a/language/English/strings.po b/language/English/strings.po -index e051b4d..b386d1f 100644 +index bb2272d..f2a0572 100644 --- a/language/English/strings.po +++ b/language/English/strings.po @@ -5767,7 +5767,15 @@ msgctxt "#13435" @@ -6658,371 +13502,35 @@ index 084fe8b..3a52878 100644 bool m_videoEnableHighQualityHwScalers; float m_videoAutoScaleMaxFps; diff --git a/xbmc/utils/ActorProtocol.cpp b/xbmc/utils/ActorProtocol.cpp -new file mode 100644 -index 0000000..e0cfd0e ---- /dev/null +index cf4c26f..e3090c3 100644 +--- a/xbmc/utils/ActorProtocol.cpp +++ b/xbmc/utils/ActorProtocol.cpp -@@ -0,0 +1,253 @@ -+/* +@@ -1,5 +1,9 @@ + /* ++<<<<<<< HEAD + * Copyright (C) 2005-2013 Team XBMC ++======= + * Copyright (C) 2005-2012 Team XBMC -+ * http://www.xbmc.org -+ * -+ * This Program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2, or (at your option) -+ * any later version. -+ * -+ * This Program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with XBMC; see the file COPYING. If not, see -+ * . -+ * -+ */ -+ -+#include "ActorProtocol.h" -+ -+using namespace Actor; -+ -+void Message::Release() -+{ -+ bool skip; -+ origin->Lock(); -+ skip = isSync ? !isSyncFini : false; -+ isSyncFini = true; -+ origin->Unlock(); -+ -+ if (skip) -+ return; -+ -+ // free data buffer -+ if (data != buffer) -+ delete [] data; -+ -+ // delete event in case of sync message -+ if (event) -+ delete event; -+ -+ origin->ReturnMessage(this); -+} -+ -+bool Message::Reply(int sig, void *data /* = NULL*/, int size /* = 0 */) -+{ -+ if (!isSync) -+ { -+ if (isOut) -+ return origin->SendInMessage(sig, data, size); -+ else -+ return origin->SendOutMessage(sig, data, size); -+ } -+ -+ origin->Lock(); -+ -+ if (!isSyncTimeout) -+ { -+ Message *msg = origin->GetMessage(); -+ msg->signal = sig; -+ msg->isOut = !isOut; -+ replyMessage = msg; -+ if (data) -+ { -+ if (size > MSG_INTERNAL_BUFFER_SIZE) -+ msg->data = new uint8_t[size]; -+ else -+ msg->data = msg->buffer; -+ memcpy(msg->data, data, size); -+ } -+ } -+ -+ origin->Unlock(); -+ -+ if (event) -+ event->Set(); -+ -+ return true; -+} -+ -+Protocol::~Protocol() -+{ -+ Message *msg; -+ Purge(); -+ while (!freeMessageQueue.empty()) -+ { -+ msg = freeMessageQueue.front(); -+ freeMessageQueue.pop(); -+ delete msg; -+ } -+} -+ -+Message *Protocol::GetMessage() -+{ -+ Message *msg; -+ -+ CSingleLock lock(criticalSection); -+ -+ if (!freeMessageQueue.empty()) -+ { -+ msg = freeMessageQueue.front(); -+ freeMessageQueue.pop(); -+ } -+ else -+ msg = new Message(); -+ -+ msg->isSync = false; -+ msg->isSyncFini = false; -+ msg->isSyncTimeout = false; -+ msg->event = NULL; -+ msg->data = NULL; -+ msg->payloadSize = 0; -+ msg->replyMessage = NULL; -+ msg->origin = this; -+ -+ return msg; -+} -+ -+void Protocol::ReturnMessage(Message *msg) -+{ -+ CSingleLock lock(criticalSection); -+ -+ freeMessageQueue.push(msg); -+} -+ -+bool Protocol::SendOutMessage(int signal, void *data /* = NULL */, int size /* = 0 */, Message *outMsg /* = NULL */) -+{ -+ Message *msg; -+ if (outMsg) -+ msg = outMsg; -+ else -+ msg = GetMessage(); -+ -+ msg->signal = signal; -+ msg->isOut = true; -+ -+ if (data) -+ { -+ if (size > MSG_INTERNAL_BUFFER_SIZE) -+ msg->data = new uint8_t[size]; -+ else -+ msg->data = msg->buffer; -+ memcpy(msg->data, data, size); -+ } -+ -+ { CSingleLock lock(criticalSection); -+ outMessages.push(msg); -+ } -+ containerOutEvent->Set(); -+ -+ return true; -+} -+ -+bool Protocol::SendInMessage(int signal, void *data /* = NULL */, int size /* = 0 */, Message *outMsg /* = NULL */) -+{ -+ Message *msg; -+ if (outMsg) -+ msg = outMsg; -+ else -+ msg = GetMessage(); -+ -+ msg->signal = signal; -+ msg->isOut = false; -+ -+ if (data) -+ { -+ if (size > MSG_INTERNAL_BUFFER_SIZE) -+ msg->data = new uint8_t[size]; -+ else -+ msg->data = msg->buffer; -+ memcpy(msg->data, data, size); -+ } -+ -+ { CSingleLock lock(criticalSection); -+ inMessages.push(msg); -+ } -+ containerInEvent->Set(); -+ -+ return true; -+} -+ -+ -+bool Protocol::SendOutMessageSync(int signal, Message **retMsg, int timeout, void *data /* = NULL */, int size /* = 0 */) -+{ -+ Message *msg = GetMessage(); -+ msg->isOut = true; -+ msg->isSync = true; -+ msg->event = new CEvent; -+ msg->event->Reset(); -+ SendOutMessage(signal, data, size, msg); -+ -+ if (!msg->event->WaitMSec(timeout)) -+ { -+ msg->origin->Lock(); -+ if (msg->replyMessage) -+ *retMsg = msg->replyMessage; -+ else -+ { -+ *retMsg = NULL; -+ msg->isSyncTimeout = true; -+ } -+ msg->origin->Unlock(); -+ } -+ else -+ *retMsg = msg->replyMessage; -+ -+ msg->Release(); -+ -+ if (*retMsg) -+ return true; -+ else -+ return false; -+} -+ -+bool Protocol::ReceiveOutMessage(Message **msg) -+{ -+ CSingleLock lock(criticalSection); -+ -+ if (outMessages.empty() || outDefered) -+ return false; -+ -+ *msg = outMessages.front(); -+ outMessages.pop(); -+ -+ return true; -+} -+ -+bool Protocol::ReceiveInMessage(Message **msg) -+{ -+ CSingleLock lock(criticalSection); -+ -+ if (inMessages.empty() || inDefered) -+ return false; -+ -+ *msg = inMessages.front(); -+ inMessages.pop(); -+ -+ return true; -+} -+ -+ -+void Protocol::Purge() -+{ -+ Message *msg; -+ -+ while (ReceiveInMessage(&msg)) -+ msg->Release(); -+ -+ while (ReceiveOutMessage(&msg)) -+ msg->Release(); -+} ++>>>>>>> b5471a2... vdpau: redesign + * http://www.xbmc.org + * + * This Program is free software; you can redistribute it and/or modify diff --git a/xbmc/utils/ActorProtocol.h b/xbmc/utils/ActorProtocol.h -new file mode 100644 -index 0000000..e7108ac ---- /dev/null +index 8ef3359..8c4038a 100644 +--- a/xbmc/utils/ActorProtocol.h +++ b/xbmc/utils/ActorProtocol.h -@@ -0,0 +1,87 @@ -+/* +@@ -1,5 +1,9 @@ + /* ++<<<<<<< HEAD + * Copyright (C) 2005-2013 Team XBMC ++======= + * Copyright (C) 2005-2012 Team XBMC -+ * http://www.xbmc.org -+ * -+ * This Program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2, or (at your option) -+ * any later version. -+ * -+ * This Program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with XBMC; see the file COPYING. If not, see -+ * . -+ * -+ */ -+ -+#pragma once -+ -+#include "threads/Thread.h" -+#include "utils/log.h" -+#include -+#include "memory.h" -+ -+#define MSG_INTERNAL_BUFFER_SIZE 32 -+ -+namespace Actor -+{ -+ -+class Protocol; -+ -+class Message -+{ -+ friend class Protocol; -+public: -+ int signal; -+ bool isSync; -+ bool isSyncFini; -+ bool isOut; -+ bool isSyncTimeout; -+ int payloadSize; -+ uint8_t buffer[MSG_INTERNAL_BUFFER_SIZE]; -+ uint8_t *data; -+ Message *replyMessage; -+ Protocol *origin; -+ CEvent *event; -+ -+ void Release(); -+ bool Reply(int sig, void *data = NULL, int size = 0); -+ -+private: -+ Message() {isSync = false; data = NULL; event = NULL; replyMessage = NULL;}; -+}; -+ -+class Protocol -+{ -+public: -+ Protocol(std::string name, CEvent* inEvent, CEvent *outEvent) -+ : portName(name), inDefered(false), outDefered(false) {containerInEvent = inEvent; containerOutEvent = outEvent;}; -+ virtual ~Protocol(); -+ Message *GetMessage(); -+ void ReturnMessage(Message *msg); -+ bool SendOutMessage(int signal, void *data = NULL, int size = 0, Message *outMsg = NULL); -+ bool SendInMessage(int signal, void *data = NULL, int size = 0, Message *outMsg = NULL); -+ bool SendOutMessageSync(int signal, Message **retMsg, int timeout, void *data = NULL, int size = 0); -+ bool ReceiveOutMessage(Message **msg); -+ bool ReceiveInMessage(Message **msg); -+ void Purge(); -+ void DeferIn(bool value) {inDefered = value;}; -+ void DeferOut(bool value) {outDefered = value;}; -+ void Lock() {criticalSection.lock();}; -+ void Unlock() {criticalSection.unlock();}; -+ std::string portName; -+ -+protected: -+ CEvent *containerInEvent, *containerOutEvent; -+ CCriticalSection criticalSection; -+ std::queue outMessages; -+ std::queue inMessages; -+ std::queue freeMessageQueue; -+ bool inDefered, outDefered; -+}; -+ -+} -diff --git a/xbmc/utils/Makefile.in b/xbmc/utils/Makefile.in -index 694a9bd..1b69c56 100644 ---- a/xbmc/utils/Makefile.in -+++ b/xbmc/utils/Makefile.in -@@ -70,6 +70,7 @@ SRCS += Vector.cpp - SRCS += Weather.cpp - SRCS += XBMCTinyXML.cpp - SRCS += XMLUtils.cpp -+SRCS += ActorProtocol.cpp - - ifeq (@USE_OPENGLES@,1) - SRCS += AMLUtils.cpp ++>>>>>>> b5471a2... vdpau: redesign + * http://www.xbmc.org + * + * This Program is free software; you can redistribute it and/or modify diff --git a/xbmc/video/dialogs/GUIDialogVideoSettings.cpp b/xbmc/video/dialogs/GUIDialogVideoSettings.cpp -index 908b911..40d8c61 100644 +index bd80082..27ed5ee 100644 --- a/xbmc/video/dialogs/GUIDialogVideoSettings.cpp +++ b/xbmc/video/dialogs/GUIDialogVideoSettings.cpp @@ -104,7 +104,7 @@ void CGUIDialogVideoSettings::CreateSettings() @@ -7050,10 +13558,10 @@ index e425327..3dae22c 100644 1.8.1.6 -From 940e0c007c1819a0433db73152d34e79bfe3a478 Mon Sep 17 00:00:00 2001 +From 1beab603bbf8e8dfc830686c3791cee2fdd69034 Mon Sep 17 00:00:00 2001 From: xbmc Date: Wed, 12 Dec 2012 09:52:17 +0100 -Subject: [PATCH 006/102] vdpau: make interop gl default and remove setting, +Subject: [PATCH 022/120] vdpau: make interop gl default and remove setting, rename and intvert interop yuv --- @@ -7062,7 +13570,7 @@ Subject: [PATCH 006/102] vdpau: make interop gl default and remove setting, 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/language/English/strings.po b/language/English/strings.po -index b386d1f..2938ce0 100644 +index f2a0572..eace353 100644 --- a/language/English/strings.po +++ b/language/English/strings.po @@ -5768,14 +5768,10 @@ msgid "Enable HQ Scalers for scalings above" @@ -7158,10 +13666,10 @@ index 89ac10e..c4d1a53 100644 1.8.1.6 -From a8c82958a62758ceed52249f3a4ac8bcbfa3490c Mon Sep 17 00:00:00 2001 +From 04b477cfe396088d7938c165fbc482f16c06d9df Mon Sep 17 00:00:00 2001 From: xbmc Date: Wed, 12 Dec 2012 18:34:47 +0100 -Subject: [PATCH 007/102] vdpau: drop studio level conversion +Subject: [PATCH 023/120] vdpau: drop studio level conversion --- xbmc/cores/VideoRenderers/LinuxRendererGL.cpp | 4 +- @@ -7313,10 +13821,10 @@ index c4d1a53..399da83 100644 1.8.1.6 -From 26de8bf477aaea18e9a5f21b5b924a96fdefbaa0 Mon Sep 17 00:00:00 2001 +From 906fb1ac0ee3abae868cb27174d21e312bd9be02 Mon Sep 17 00:00:00 2001 From: xbmc Date: Wed, 12 Dec 2012 20:28:49 +0100 -Subject: [PATCH 008/102] vdpau: observe ffmpeg tags for color space +Subject: [PATCH 024/120] vdpau: observe ffmpeg tags for color space --- xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 38 ++++++++++++++++++-------- @@ -7420,10 +13928,10 @@ index 5bee48b..ef99383 100644 1.8.1.6 -From 3ba7c9a1d77d84a0dd35646e2c7bec1fb6a58aae Mon Sep 17 00:00:00 2001 +From bde56ed93a92ee72b5694e4399b79fad2932b9cc Mon Sep 17 00:00:00 2001 From: xbmc Date: Sun, 27 Jan 2013 12:10:19 +0100 -Subject: [PATCH 009/102] vdpau: switch off de-interlacing on ff +Subject: [PATCH 025/120] vdpau: switch off de-interlacing on ff --- xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 5 +++-- @@ -7449,10 +13957,10 @@ index 4b2b4e8..c56dc9c 100644 1.8.1.6 -From 4af0c59b7e16604f3fd3096574f8696ffeae4ed8 Mon Sep 17 00:00:00 2001 +From 3c356c52a68f17fd54c6f0c916a0804a55c461eb Mon Sep 17 00:00:00 2001 From: xbmc Date: Sat, 2 Feb 2013 13:17:09 +0100 -Subject: [PATCH 010/102] vdpau: fix mp4 part2 decoding, activate by default +Subject: [PATCH 026/120] vdpau: fix mp4 part2 decoding, activate by default --- xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 3 +-- @@ -7492,10 +14000,10 @@ index c156b90..bd08884 100644 1.8.1.6 -From 80eda1fde90bf826e4128d95438e40c39e453daa Mon Sep 17 00:00:00 2001 +From 391c8d2c65b8bbd7593087db0d2fd5843dc592a8 Mon Sep 17 00:00:00 2001 From: xbmc Date: Sat, 2 Mar 2013 15:19:19 +0100 -Subject: [PATCH 011/102] vdpau: re-add limited range conversion +Subject: [PATCH 027/120] vdpau: re-add limited range conversion --- xbmc/cores/VideoRenderers/LinuxRendererGL.cpp | 4 +- @@ -7639,10 +14147,10 @@ index 4ffeeb5..f913a97 100644 1.8.1.6 -From c2fb9cd7c4975a93111d536926e812567bdff76a Mon Sep 17 00:00:00 2001 +From 1a1208d017ee657e98bc13bfb2284bc3fd827c67 Mon Sep 17 00:00:00 2001 From: xbmc Date: Tue, 25 Sep 2012 12:14:15 +0200 -Subject: [PATCH 012/102] linuxrenderer: drop method RenderMultiPass +Subject: [PATCH 028/120] linuxrenderer: drop method RenderMultiPass --- xbmc/cores/VideoRenderers/LinuxRendererGL.cpp | 9 ++------- @@ -7692,10 +14200,10 @@ index d72eb64..6b9046d 100644 1.8.1.6 -From 433a0dea19b9513ecd048255bc0ed56bf300e2fa Mon Sep 17 00:00:00 2001 +From e3d314166a93ef1951e936b5b6bc34d95376088b Mon Sep 17 00:00:00 2001 From: xbmc Date: Tue, 25 Sep 2012 13:20:47 +0200 -Subject: [PATCH 013/102] linuxrenderer: implement progressive weave for vdpau +Subject: [PATCH 029/120] linuxrenderer: implement progressive weave for vdpau --- xbmc/cores/VideoRenderers/LinuxRendererGL.cpp | 55 +++++++++++++++++++-------- @@ -7823,10 +14331,10 @@ index 6b9046d..4494eca 100644 1.8.1.6 -From 52c5ba4d05a90cb44702ee38954397e3f61fe01d Mon Sep 17 00:00:00 2001 +From 678d78876f5398504858585f2c20df379a5f439f Mon Sep 17 00:00:00 2001 From: fritsch Date: Thu, 28 Mar 2013 10:38:37 +0100 -Subject: [PATCH 014/102] VDPAU: silence compiler warnings +Subject: [PATCH 030/120] VDPAU: silence compiler warnings --- xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 19 ++++++++----------- @@ -7922,10 +14430,10 @@ index f913a97..e9ec3d2 100644 1.8.1.6 -From c6f5ff01df8481993302a56215bf8b8f7cbd45de Mon Sep 17 00:00:00 2001 +From ae0b5c14850e790d9e85492e860740e77b00a5f3 Mon Sep 17 00:00:00 2001 From: xbmc Date: Mon, 25 Feb 2013 08:47:10 +0100 -Subject: [PATCH 015/102] vdpau: release more resources on pre-cleanup +Subject: [PATCH 031/120] vdpau: release more resources on pre-cleanup --- xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 72 +++++++++++++++++++++++--- @@ -8063,10 +14571,10 @@ index ef99383..39047b5 100644 1.8.1.6 -From 9f1211ca3d1cbdc2e0eebacc54b0ea026c9462e5 Mon Sep 17 00:00:00 2001 +From 4bb5dc9797eba87f40fc171a1fa3676914e52186 Mon Sep 17 00:00:00 2001 From: xbmc Date: Wed, 6 Mar 2013 07:35:10 +0100 -Subject: [PATCH 016/102] vdpau: set deinterlacing method to auto, if default +Subject: [PATCH 032/120] vdpau: set deinterlacing method to auto, if default method not supported --- @@ -8098,10 +14606,10 @@ index 9850cf0..0a6a1dc 100644 1.8.1.6 -From 4b15b8414a6e20a01828a666216fe31e5d45787c Mon Sep 17 00:00:00 2001 +From 27dc27eeeb0bf859a3afbd68dca6921b0e696da5 Mon Sep 17 00:00:00 2001 From: xbmc Date: Sun, 21 Apr 2013 09:19:34 +0200 -Subject: [PATCH 017/102] vdpau: fix deadlock if decoder is closed while +Subject: [PATCH 033/120] vdpau: fix deadlock if decoder is closed while refresh rate changes --- @@ -8139,10 +14647,10 @@ index 0a6a1dc..4b4b3c3 100644 1.8.1.6 -From 2eea278d0c8c8f6158e6676d21a26ee9a092d7fe Mon Sep 17 00:00:00 2001 +From ec3a78f5a324200d906c3c837c4f7b7d5a1fbe99 Mon Sep 17 00:00:00 2001 From: Rainer Hochecker Date: Sat, 1 Jun 2013 11:21:19 +0200 -Subject: [PATCH 018/102] renderer: bump buffers to 5 +Subject: [PATCH 034/120] renderer: bump buffers to 5 --- xbmc/cores/VideoRenderers/BaseRenderer.h | 2 +- @@ -8165,10 +14673,10 @@ index fe1f577..527ecf1 100644 1.8.1.6 -From 912d0c67dfeaa6f6e578d22ebba47bce120b3510 Mon Sep 17 00:00:00 2001 +From a52b5fccc31fbb30033ada0d68710f4f9e026e40 Mon Sep 17 00:00:00 2001 From: xbmc Date: Mon, 28 May 2012 10:41:31 +0200 -Subject: [PATCH 019/102] videoplayer: update frametime, it might change due to +Subject: [PATCH 035/120] videoplayer: update frametime, it might change due to fps detection --- @@ -8192,10 +14700,10 @@ index 3c30d0b..347e888 100644 1.8.1.6 -From fccd6c931508b24549481be5506edfa75c453cf6 Mon Sep 17 00:00:00 2001 +From 893c978e92d984fc5f221a8c76e06d5226f92fdd Mon Sep 17 00:00:00 2001 From: xbmc Date: Mon, 28 May 2012 10:43:06 +0200 -Subject: [PATCH 020/102] videoplayer: give streams with invalid fps a chance +Subject: [PATCH 036/120] videoplayer: give streams with invalid fps a chance for fps detection --- @@ -8219,10 +14727,10 @@ index 347e888..1a17145 100644 1.8.1.6 -From a81d65436a5f17fa4f2a603202226f9e03559da3 Mon Sep 17 00:00:00 2001 +From 43038bb0e9387714f45a06c5893d714e2f645653 Mon Sep 17 00:00:00 2001 From: xbmc Date: Mon, 28 May 2012 10:49:05 +0200 -Subject: [PATCH 021/102] dvdplayer: allow rewinding at end of stream, do a +Subject: [PATCH 037/120] dvdplayer: allow rewinding at end of stream, do a seek after rewind --- @@ -8230,7 +14738,7 @@ Subject: [PATCH 021/102] dvdplayer: allow rewinding at end of stream, do a 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp -index c944164..d2c164d 100644 +index 974ebd1..b56423b 100644 --- a/xbmc/cores/dvdplayer/DVDPlayer.cpp +++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp @@ -1555,7 +1555,7 @@ void CDVDPlayer::HandlePlaySpeed() @@ -8259,10 +14767,10 @@ index c944164..d2c164d 100644 1.8.1.6 -From 032fcb7f890213fc98c6e4b87aa01b72cef00ed6 Mon Sep 17 00:00:00 2001 +From 11d775de444786677adf7ee9bbf8010729a7198c Mon Sep 17 00:00:00 2001 From: FernetMenta Date: Thu, 5 Jul 2012 15:22:05 +0200 -Subject: [PATCH 022/102] X11: ditch SDL for video and window events +Subject: [PATCH 038/120] X11: ditch SDL for video and window events --- xbmc/Application.cpp | 2 +- @@ -9746,10 +16254,10 @@ index 3dae22c..25faaef 100644 1.8.1.6 -From d0df3b13fea9db9398a735d7e62521792a979b47 Mon Sep 17 00:00:00 2001 +From 072d548f43ebb178ca9d2bd2669346f863547a72 Mon Sep 17 00:00:00 2001 From: FernetMenta Date: Thu, 5 Jul 2012 15:24:22 +0200 -Subject: [PATCH 023/102] X11: Add xbmc icon +Subject: [PATCH 039/120] X11: Add xbmc icon --- xbmc/windowing/X11/WinSystemX11.cpp | 126 +++++++++++++++++++++++++++++++++++- @@ -9938,10 +16446,10 @@ index 25faaef..c1e6cf1 100644 1.8.1.6 -From 65aebb38fe69e318e24f97463f36844f25df403d Mon Sep 17 00:00:00 2001 +From 19a7649f89e18a26bd19f210d4ab6609b8188618 Mon Sep 17 00:00:00 2001 From: xbmc Date: Sun, 20 May 2012 14:11:26 +0200 -Subject: [PATCH 024/102] X11: add SDL joystick until we have a better solution +Subject: [PATCH 040/120] X11: add SDL joystick until we have a better solution --- xbmc/windowing/WinEventsX11.cpp | 26 ++++++++++++++++++++++++++ @@ -9995,10 +16503,10 @@ index 5a8bbb8..5bc1de0 100644 1.8.1.6 -From fbf03404e591bded3b44f15c37361d1d8c5be329 Mon Sep 17 00:00:00 2001 +From 567720c46694331a46099657276eeea0444036dd Mon Sep 17 00:00:00 2001 From: Joakim Plate Date: Thu, 5 Jul 2012 12:35:55 +0200 -Subject: [PATCH 025/102] X11: factor out code handling device reset +Subject: [PATCH 041/120] X11: factor out code handling device reset notification --- @@ -10062,10 +16570,10 @@ index c1e6cf1..041ea55 100644 1.8.1.6 -From 0014004481658c3d6005125469b60e7bc72d327a Mon Sep 17 00:00:00 2001 +From 399b4e5eb4c7b5cc60f926c87a9fca5db8bcabcb Mon Sep 17 00:00:00 2001 From: FernetMenta Date: Thu, 5 Jul 2012 15:02:00 +0200 -Subject: [PATCH 026/102] X11: move xrandr events to WinEventsX11 +Subject: [PATCH 042/120] X11: move xrandr events to WinEventsX11 --- xbmc/windowing/WinEventsX11.cpp | 42 +++++++++++++++++++++++++++++++++++++ @@ -10209,10 +16717,10 @@ index fd51dc0..d495443 100644 1.8.1.6 -From 3ec9e9375843ab73c4ff0004ba1a49080fa2ffde Mon Sep 17 00:00:00 2001 +From e6ac06bcef620b0ba1a801de70a7100026c58205 Mon Sep 17 00:00:00 2001 From: FernetMenta Date: Thu, 12 Apr 2012 15:43:56 +0200 -Subject: [PATCH 027/102] xrandr: remove method RestoreState +Subject: [PATCH 043/120] xrandr: remove method RestoreState --- xbmc/windowing/X11/WinSystemX11.cpp | 13 +++++++++++-- @@ -10291,10 +16799,10 @@ index e3450fe..cf22fbf 100644 1.8.1.6 -From 3d946dacebecf4196f61ceed7818b0f600cf2596 Mon Sep 17 00:00:00 2001 +From 7851a002d04867ff712ee70754434c8bdd00d205 Mon Sep 17 00:00:00 2001 From: xbmc Date: Sun, 20 May 2012 13:17:10 +0200 -Subject: [PATCH 028/102] xrandr: observe orientation +Subject: [PATCH 044/120] xrandr: observe orientation --- xbmc/windowing/X11/WinSystemX11.cpp | 89 ++++++++++++++++++++++++++++++------- @@ -10509,10 +17017,10 @@ index cf22fbf..71ffab4 100644 1.8.1.6 -From b8e3cbb4018cb32cdfebf704259f314863ee368f Mon Sep 17 00:00:00 2001 +From f35862ec292d7b2a8a006fe652ad7478f24dd132 Mon Sep 17 00:00:00 2001 From: FernetMenta Date: Thu, 5 Jul 2012 11:54:15 +0200 -Subject: [PATCH 029/102] xrandr: allow getting info for multiple screen's +Subject: [PATCH 045/120] xrandr: allow getting info for multiple screen's Refactored by: Joakim Plate --- @@ -10687,10 +17195,10 @@ index 71ffab4..26c2653 100644 1.8.1.6 -From b49cf34b5fce8e4e81b373bb001ccda853431686 Mon Sep 17 00:00:00 2001 +From 590e8b59af389a15474571338b65ff0f8a4b8a89 Mon Sep 17 00:00:00 2001 From: FernetMenta Date: Thu, 5 Jul 2012 11:44:00 +0200 -Subject: [PATCH 030/102] X11: fix multi-head setups +Subject: [PATCH 046/120] X11: fix multi-head setups --- language/English/strings.po | 4 +- @@ -10705,7 +17213,7 @@ Subject: [PATCH 030/102] X11: fix multi-head setups 9 files changed, 229 insertions(+), 116 deletions(-) diff --git a/language/English/strings.po b/language/English/strings.po -index 2938ce0..f080947 100644 +index eace353..10568ca 100644 --- a/language/English/strings.po +++ b/language/English/strings.po @@ -999,7 +999,9 @@ msgctxt "#245" @@ -10874,10 +17382,10 @@ index 056fc07..fe91a74 100644 protected: CDisplaySettings(); diff --git a/xbmc/settings/Settings.cpp b/xbmc/settings/Settings.cpp -index 7c15049..aaa291b 100644 +index ee97753..63cdf0e 100644 --- a/xbmc/settings/Settings.cpp +++ b/xbmc/settings/Settings.cpp -@@ -365,6 +365,7 @@ void CSettings::Uninitialize() +@@ -374,6 +374,7 @@ void CSettings::Uninitialize() m_settingsManager->UnregisterSettingOptionsFiller("rendermethods"); m_settingsManager->UnregisterSettingOptionsFiller("resolutions"); m_settingsManager->UnregisterSettingOptionsFiller("screens"); @@ -10885,7 +17393,7 @@ index 7c15049..aaa291b 100644 m_settingsManager->UnregisterSettingOptionsFiller("shutdownstates"); m_settingsManager->UnregisterSettingOptionsFiller("startupwindows"); m_settingsManager->UnregisterSettingOptionsFiller("streamlanguages"); -@@ -668,6 +669,7 @@ void CSettings::InitializeOptionFillers() +@@ -677,6 +678,7 @@ void CSettings::InitializeOptionFillers() m_settingsManager->RegisterSettingOptionsFiller("rendermethods", CBaseRenderer::SettingOptionsRenderMethodsFiller); m_settingsManager->RegisterSettingOptionsFiller("resolutions", CDisplaySettings::SettingOptionsResolutionsFiller); m_settingsManager->RegisterSettingOptionsFiller("screens", CDisplaySettings::SettingOptionsScreensFiller); @@ -10893,7 +17401,7 @@ index 7c15049..aaa291b 100644 m_settingsManager->RegisterSettingOptionsFiller("shutdownstates", CPowerManager::SettingOptionsShutdownStatesFiller); m_settingsManager->RegisterSettingOptionsFiller("startupwindows", ADDON::CSkinInfo::SettingOptionsStartupWindowsFiller); m_settingsManager->RegisterSettingOptionsFiller("streamlanguages", CLangInfo::SettingOptionsStreamLanguagesFiller); -@@ -695,6 +697,9 @@ void CSettings::InitializeConditions() +@@ -704,6 +706,9 @@ void CSettings::InitializeConditions() #ifdef HAS_GL m_settingsManager->AddCondition("has_gl"); #endif @@ -10903,7 +17411,7 @@ index 7c15049..aaa291b 100644 #ifdef HAS_GLES m_settingsManager->AddCondition("has_gles"); #endif -@@ -828,6 +833,7 @@ void CSettings::InitializeISettingCallbacks() +@@ -837,6 +842,7 @@ void CSettings::InitializeISettingCallbacks() settingSet.insert("videoscreen.screen"); settingSet.insert("videoscreen.resolution"); settingSet.insert("videoscreen.screenmode"); @@ -11459,10 +17967,10 @@ index 0d4436b..0336b3b 100644 1.8.1.6 -From 57735c23ecfa91303458320a1bfcecdf4378698a Mon Sep 17 00:00:00 2001 +From 4cad89d71536a4e1ea5c709caf93d09c131dfe3e Mon Sep 17 00:00:00 2001 From: FernetMenta Date: Thu, 5 Jul 2012 11:36:32 +0200 -Subject: [PATCH 031/102] X11: remove all DefaultScreen and RootWindow macros +Subject: [PATCH 047/120] X11: remove all DefaultScreen and RootWindow macros --- xbmc/windowing/X11/WinSystemX11.cpp | 6 +++--- @@ -11530,10 +18038,10 @@ index 1bea366..cc39720 100644 1.8.1.6 -From 4f0e81c218442618f3ece62c2e9149d425e13edf Mon Sep 17 00:00:00 2001 +From e9295108e4c2d6ae7c035fee0f2c4320409dc94c Mon Sep 17 00:00:00 2001 From: FernetMenta Date: Thu, 5 Jul 2012 11:45:22 +0200 -Subject: [PATCH 032/102] X11: remove all DefaultScreen and RootWindow macros +Subject: [PATCH 048/120] X11: remove all DefaultScreen and RootWindow macros (VideoRefClock) Note this is on a separate display connection. @@ -11605,10 +18113,10 @@ index ca239cf..687e3ff 100644 1.8.1.6 -From c6fbd6d50781e1cd1ddda0df66788c6ff650455e Mon Sep 17 00:00:00 2001 +From e1a6a35c6e12b9f1e759371da90c539141569d27 Mon Sep 17 00:00:00 2001 From: xbmc Date: Wed, 20 Jun 2012 17:37:11 +0200 -Subject: [PATCH 033/102] X11: recreate gl context after output has changed +Subject: [PATCH 049/120] X11: recreate gl context after output has changed --- xbmc/windowing/X11/WinSystemX11.cpp | 24 ++++++++++++++---------- @@ -11759,10 +18267,10 @@ index cc39720..dda7b14 100644 1.8.1.6 -From bd831cf16e33dd24ea12f17608480d0ed1210ebe Mon Sep 17 00:00:00 2001 +From 4e3d5836dff1ed8c1be980303958f95a9487c1db Mon Sep 17 00:00:00 2001 From: FernetMenta Date: Thu, 5 Jul 2012 12:06:25 +0200 -Subject: [PATCH 034/102] X11: hook video reference clock in windowing +Subject: [PATCH 050/120] X11: hook video reference clock in windowing --- xbmc/video/VideoReferenceClock.cpp | 71 +++++++++++++++++++++++++++----------- @@ -11967,10 +18475,10 @@ index 1791570..bcabc9f 100644 1.8.1.6 -From 68bcd2002f60f3af647976647ffa93f106fbfd12 Mon Sep 17 00:00:00 2001 +From 67d6b86b9baa87e24d1a4f5594799c532201ad1d Mon Sep 17 00:00:00 2001 From: xbmc Date: Thu, 21 Jun 2012 17:26:51 +0200 -Subject: [PATCH 035/102] X11: fix video calibrations +Subject: [PATCH 051/120] X11: fix video calibrations --- xbmc/windowing/WinSystem.h | 1 + @@ -12062,10 +18570,10 @@ index 2227320..630c0e2 100644 1.8.1.6 -From f61b681ff6d899f400c7a81dedd5a84df5c22339 Mon Sep 17 00:00:00 2001 +From e18f7e7f7378fb38443ae630bd392cb85ed74f83 Mon Sep 17 00:00:00 2001 From: FernetMenta Date: Thu, 5 Jul 2012 12:00:26 +0200 -Subject: [PATCH 036/102] X11: deactivate screen saver on startup +Subject: [PATCH 052/120] X11: deactivate screen saver on startup --- xbmc/windowing/X11/WinSystemX11.cpp | 29 +++++++++++++++++++++++++++++ @@ -12135,10 +18643,10 @@ index 630c0e2..f78f613 100644 1.8.1.6 -From 4ae10748b188af4b958f6d7cf4026eb8392d93cf Mon Sep 17 00:00:00 2001 +From 04dc438ad60bbd8f4361d0294b09db10a0b2b927 Mon Sep 17 00:00:00 2001 From: FernetMenta Date: Thu, 5 Jul 2012 12:10:09 +0200 -Subject: [PATCH 037/102] X11: change method of going full-screen +Subject: [PATCH 053/120] X11: change method of going full-screen --- xbmc/windowing/X11/WinSystemX11.cpp | 9 ++++++++- @@ -12182,10 +18690,10 @@ index c643177..e1e1096 100644 1.8.1.6 -From 15fd7c225a1fedeeb0df0efa8c32d644e2ac1f7c Mon Sep 17 00:00:00 2001 +From a23457c2f28caa9e289e78fb6a40940aac02a452 Mon Sep 17 00:00:00 2001 From: xbmc Date: Thu, 28 Jun 2012 19:12:39 +0200 -Subject: [PATCH 038/102] X11: reset key repeat and key modifier on focus lost +Subject: [PATCH 054/120] X11: reset key repeat and key modifier on focus lost and gain --- @@ -12217,10 +18725,10 @@ index c58067b..c9f8a20 100644 1.8.1.6 -From e2cf3d4f4abc2e9ca108f0ab351e02499a384483 Mon Sep 17 00:00:00 2001 +From 6baa4227008e47184697e353afe5862c872fc856 Mon Sep 17 00:00:00 2001 From: Joakim Plate Date: Thu, 5 Jul 2012 14:18:46 +0200 -Subject: [PATCH 039/102] X11: replace custom utf8 to unicode with charset +Subject: [PATCH 055/120] X11: replace custom utf8 to unicode with charset convertor (squash to x11 events) --- @@ -12437,10 +18945,10 @@ index 6100933..72955ad 100644 1.8.1.6 -From fc75a6126c42b073f2f2aeb20518b8140be08de2 Mon Sep 17 00:00:00 2001 +From 980445d07a18ceae59d31cbd13999daf2191b210 Mon Sep 17 00:00:00 2001 From: Joakim Plate Date: Thu, 5 Jul 2012 14:23:54 +0200 -Subject: [PATCH 040/102] X11: fixed invalid usage of sizeof() (squash into x11 +Subject: [PATCH 056/120] X11: fixed invalid usage of sizeof() (squash into x11 changes) --- @@ -12504,10 +19012,10 @@ index 72955ad..102a076 100644 1.8.1.6 -From 47d1862cc17ce789e27765e619ff301eb796c4bd Mon Sep 17 00:00:00 2001 +From e07faa45207e51ad87a938eb90e1a7ffa3cb6b2a Mon Sep 17 00:00:00 2001 From: xbmc Date: Sat, 9 Jun 2012 18:23:53 +0200 -Subject: [PATCH 041/102] add missing keys to xbmc keytable +Subject: [PATCH 057/120] add missing keys to xbmc keytable --- xbmc/input/XBMC_keytable.cpp | 2 ++ @@ -12530,10 +19038,10 @@ index f18e9b1..066cd77 100644 1.8.1.6 -From 598a41f55d9931cfd96bb27c54640b1c7b057cb8 Mon Sep 17 00:00:00 2001 +From 2305c7525204667368a4bc178d2ba533572ce5ac Mon Sep 17 00:00:00 2001 From: xbmc Date: Fri, 16 Mar 2012 15:57:51 +0100 -Subject: [PATCH 042/102] videorefclock: temp deactivate of nv settings +Subject: [PATCH 058/120] videorefclock: temp deactivate of nv settings --- xbmc/video/VideoReferenceClock.cpp | 2 +- @@ -12556,10 +19064,10 @@ index 4287e8f..21f59b8 100644 1.8.1.6 -From 99e6d6d6e5f08851f5dea4d4b1977f21303bd6c9 Mon Sep 17 00:00:00 2001 +From 41964e6b27093a48da7a0c689cf2967bd7a0cf29 Mon Sep 17 00:00:00 2001 From: xbmc Date: Mon, 20 Aug 2012 09:09:09 +0200 -Subject: [PATCH 043/102] videorefclock: ask graphics context for refresh rate +Subject: [PATCH 059/120] videorefclock: ask graphics context for refresh rate --- xbmc/video/VideoReferenceClock.cpp | 3 ++- @@ -12590,10 +19098,10 @@ index 21f59b8..0156b2c 100644 1.8.1.6 -From 93948feffd07f438b759d62de16e6b60cca92efb Mon Sep 17 00:00:00 2001 +From 0a0f3fe5802d36371473e21a69fb4352f0992a57 Mon Sep 17 00:00:00 2001 From: xbmc Date: Mon, 9 Jul 2012 14:00:18 +0200 -Subject: [PATCH 044/102] X11: fix icon texture after +Subject: [PATCH 060/120] X11: fix icon texture after cc5ed3c2474084ebc0373a3046410e6f766e03f4 --- @@ -12701,10 +19209,10 @@ index e1e1096..ace57ff 100644 1.8.1.6 -From 392ae0d8960a9323557f73ceff9a7cf633426a1e Mon Sep 17 00:00:00 2001 +From 3bb6a3c15daa1a2dffc5fc19627c2f0e902c539e Mon Sep 17 00:00:00 2001 From: xbmc Date: Tue, 10 Jul 2012 11:14:12 +0200 -Subject: [PATCH 045/102] X11: check for window manager +Subject: [PATCH 061/120] X11: check for window manager --- xbmc/windowing/X11/WinSystemX11.cpp | 74 ++++++++++++++++++++++++++++++++++++- @@ -12825,10 +19333,10 @@ index f78f613..f479c27 100644 1.8.1.6 -From 9d1ff8a5de5c0446fb56a139c47ffcbe5aedadc7 Mon Sep 17 00:00:00 2001 +From 0bd65115c8ec32b5f5f83fd1bc285f5ea84ecb15 Mon Sep 17 00:00:00 2001 From: xbmc Date: Thu, 12 Jul 2012 11:11:47 +0200 -Subject: [PATCH 046/102] X11: dont set window on xrandr if no mode available +Subject: [PATCH 062/120] X11: dont set window on xrandr if no mode available --- xbmc/windowing/X11/WinSystemX11.cpp | 11 ++++++----- @@ -12865,10 +19373,10 @@ index 188864b..076ed82 100644 1.8.1.6 -From 53f160f7ae0e7cfb7ec2f31d8e5ccfd1f64307eb Mon Sep 17 00:00:00 2001 +From d7d76427fd99a6e6e4e255f853ca674b6406e399 Mon Sep 17 00:00:00 2001 From: xbmc Date: Thu, 26 Jul 2012 09:34:28 +0200 -Subject: [PATCH 047/102] X11: fix crash after a resolution change on startup +Subject: [PATCH 063/120] X11: fix crash after a resolution change on startup --- xbmc/windowing/X11/WinSystemX11.cpp | 3 ++- @@ -12892,10 +19400,10 @@ index 076ed82..ee339d9 100644 1.8.1.6 -From 97565ca19a795be538d8c934314d13558db1d0ce Mon Sep 17 00:00:00 2001 +From 7a52fca0ad9ae6580257fec98978804917d84faa Mon Sep 17 00:00:00 2001 From: xbmc Date: Sat, 15 Sep 2012 18:27:29 +0200 -Subject: [PATCH 048/102] X11: lock graphics context in NotifyXRREvent +Subject: [PATCH 064/120] X11: lock graphics context in NotifyXRREvent --- xbmc/windowing/X11/WinSystemX11.cpp | 2 ++ @@ -12918,10 +19426,10 @@ index ee339d9..d2dcccd 100644 1.8.1.6 -From cf66f5804bbb06de20978de888b2a976899d4938 Mon Sep 17 00:00:00 2001 +From 39582233d652d30690985dba0c3c6afaf2d6556c Mon Sep 17 00:00:00 2001 From: Rainer Hochecker Date: Sat, 8 Oct 2011 16:45:13 +0200 -Subject: [PATCH 049/102] ffmpeg: add xvba hwaccel +Subject: [PATCH 065/120] ffmpeg: add xvba hwaccel --- lib/ffmpeg/configure | 11 ++ @@ -13770,10 +20278,10 @@ index 1c00ac4..6437e29 100644 1.8.1.6 -From 96300b1dd6757bdfa825d67691edd73473f6f310 Mon Sep 17 00:00:00 2001 +From 87bbfa53e72ecb16e4dbdc5c21539401e1bfe09e Mon Sep 17 00:00:00 2001 From: xbmc Date: Thu, 12 Apr 2012 12:09:31 +0200 -Subject: [PATCH 050/102] xvba: add decoder +Subject: [PATCH 066/120] xvba: add decoder --- configure.in | 47 + @@ -13889,7 +20397,7 @@ index bd2934d..94f6455 100644 --enable-pthreads \ --enable-runtime-cpudetect \ diff --git a/language/English/strings.po b/language/English/strings.po -index f080947..62f7138 100644 +index 10568ca..d603702 100644 --- a/language/English/strings.po +++ b/language/English/strings.po @@ -5773,7 +5773,11 @@ msgctxt "#13436" @@ -17210,7 +23718,7 @@ index b7c4116..a370bd8 100644 }; diff --git a/xbmc/video/dialogs/GUIDialogVideoSettings.cpp b/xbmc/video/dialogs/GUIDialogVideoSettings.cpp -index 40d8c61..9cb1c5c 100644 +index 27ed5ee..007ad74 100644 --- a/xbmc/video/dialogs/GUIDialogVideoSettings.cpp +++ b/xbmc/video/dialogs/GUIDialogVideoSettings.cpp @@ -111,6 +111,7 @@ void CGUIDialogVideoSettings::CreateSettings() @@ -17225,10 +23733,10 @@ index 40d8c61..9cb1c5c 100644 1.8.1.6 -From 84cf3a0d4507c9fa23f9d5d03892ad61bae52518 Mon Sep 17 00:00:00 2001 +From 3927b4a02ffc72037a30166a149b0127ba6d8fe8 Mon Sep 17 00:00:00 2001 From: fritsch Date: Sun, 4 Nov 2012 16:24:10 +0100 -Subject: [PATCH 051/102] xvba: add string for available decoders - we are +Subject: [PATCH 067/120] xvba: add string for available decoders - we are important so make sure we are there --- @@ -17255,10 +23763,10 @@ index 1477264..37a5994 100644 1.8.1.6 -From a058ad8b964fc01b94843936bd8cf97fc6fed8a9 Mon Sep 17 00:00:00 2001 +From 168f5f992253b08beba775bad241e0722d7e2423 Mon Sep 17 00:00:00 2001 From: xbmc Date: Sat, 16 Jun 2012 12:46:30 +0200 -Subject: [PATCH 052/102] xvba: do not use vaapi if xvba is present +Subject: [PATCH 068/120] xvba: do not use vaapi if xvba is present --- xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp | 9 +++++++++ @@ -17288,10 +23796,10 @@ index 2343b11..f102cba 100644 1.8.1.6 -From fe378ad535ca96e1e25d777ca3c8c1c766ac8f2a Mon Sep 17 00:00:00 2001 +From e882055a9101ee9aca6e44683f8dcf20e0e8c75a Mon Sep 17 00:00:00 2001 From: xbmc Date: Thu, 23 Aug 2012 19:39:49 +0200 -Subject: [PATCH 053/102] ffmpeg: add av_find_default_stream_index to interface +Subject: [PATCH 069/120] ffmpeg: add av_find_default_stream_index to interface --- lib/DllAvFormat.h | 4 ++++ @@ -17337,10 +23845,10 @@ index ee41fa8..56605cb 100644 1.8.1.6 -From 7729acdc63484a032d20da5b609bdea88373d3f2 Mon Sep 17 00:00:00 2001 +From b0d63fcec25215eb75e299f04bdec333e5280569 Mon Sep 17 00:00:00 2001 From: fritsch Date: Sat, 13 Apr 2013 11:30:39 +0200 -Subject: [PATCH 054/102] XVBA: revisit draw functions +Subject: [PATCH 070/120] XVBA: revisit draw functions --- lib/ffmpeg/libavcodec/xvba_h264.c | 2 +- @@ -17377,10 +23885,10 @@ index bf3d9c2..ff35a28 100644 1.8.1.6 -From d9f4c8ca5a991f2edc6d2c2ae779c6cbb9f77d42 Mon Sep 17 00:00:00 2001 +From 6d13ff6b61a094a6096e80fc41b7ab110bee18c6 Mon Sep 17 00:00:00 2001 From: fritsch Date: Sat, 13 Apr 2013 12:06:02 +0200 -Subject: [PATCH 055/102] (ffmpeg): Make XVBA codec available +Subject: [PATCH 071/120] (ffmpeg): Make XVBA codec available --- lib/ffmpeg/libavcodec/vc1dec.c | 3 +++ @@ -17404,10 +23912,10 @@ index 2130c74..4d611f9 100644 1.8.1.6 -From 1cdb4ff2620c3b51a0f59431cfe033726213d3cb Mon Sep 17 00:00:00 2001 +From 882cc9482c118c64bb4fb2bbe26bf8bc6162cde9 Mon Sep 17 00:00:00 2001 From: fritsch Date: Sat, 13 Apr 2013 16:38:50 +0200 -Subject: [PATCH 056/102] ffmpeg: XVBA-VC1 use v->second_field instead of +Subject: [PATCH 072/120] ffmpeg: XVBA-VC1 use v->second_field instead of !s->first_field to make VC1 interlaced working --- @@ -17431,10 +23939,10 @@ index ff35a28..04e7983 100644 1.8.1.6 -From ecf87ec391f752b8ce43656e86fdf4c70f551937 Mon Sep 17 00:00:00 2001 +From 2dc265d9cbf9a862046e39fbc7501b6c5643b90c Mon Sep 17 00:00:00 2001 From: fritsch Date: Sat, 27 Apr 2013 17:36:15 +0200 -Subject: [PATCH 057/102] XVBA: Only set second_field when we are interlaced +Subject: [PATCH 073/120] XVBA: Only set second_field when we are interlaced and an interlaced field --- @@ -17458,10 +23966,10 @@ index 04e7983..eb90c12 100644 1.8.1.6 -From 765db9affdc0b8d9655db4a6dde877fe23fc74d2 Mon Sep 17 00:00:00 2001 +From 2a0242ad0ffb76b54742a4afab1bd8800f73dd53 Mon Sep 17 00:00:00 2001 From: fritsch Date: Sat, 27 Apr 2013 22:08:50 +0200 -Subject: [PATCH 058/102] xvba: translate picture_structure to a value xvba +Subject: [PATCH 074/120] xvba: translate picture_structure to a value xvba understands --- @@ -17544,10 +24052,10 @@ index eb90c12..c98dba5 100644 1.8.1.6 -From 3e3febf9599946020ec1ad3043118cf8882dfbd4 Mon Sep 17 00:00:00 2001 +From 65248d527c31071a62cc90c7c08561fbafebbbdb Mon Sep 17 00:00:00 2001 From: xbmc Date: Tue, 30 Apr 2013 21:18:55 +0200 -Subject: [PATCH 059/102] ffmpeg xvba: fix vc1 field interlace +Subject: [PATCH 075/120] ffmpeg xvba: fix vc1 field interlace --- lib/ffmpeg/libavcodec/xvba.c | 4 ++-- @@ -17599,10 +24107,10 @@ index c98dba5..e7a85a7 100644 1.8.1.6 -From 27694118feee9548df40b712500cc0fbae770b47 Mon Sep 17 00:00:00 2001 +From bc779b113f81ca5556ab6224f39df01a1776858b Mon Sep 17 00:00:00 2001 From: xbmc Date: Tue, 30 Apr 2013 21:19:07 +0200 -Subject: [PATCH 060/102] xvba: fix vc1 field interlace +Subject: [PATCH 076/120] xvba: fix vc1 field interlace --- xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp | 3 +++ @@ -17626,10 +24134,10 @@ index 43a331f..568632f 100644 1.8.1.6 -From 5cb9feb3d378f9c46b51581452ccbc481ce6ce14 Mon Sep 17 00:00:00 2001 +From fc7c680416899a757feae367465e6c4bd450a211 Mon Sep 17 00:00:00 2001 From: xbmc Date: Tue, 30 Apr 2013 21:40:55 +0200 -Subject: [PATCH 061/102] xvba: vc1 - honor psf +Subject: [PATCH 077/120] xvba: vc1 - honor psf --- xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp | 3 +++ @@ -17660,20 +24168,20 @@ index 568632f..1db9363 100644 1.8.1.6 -From 34cdb5c0db63df84dc601a8b5b57d6316c62a056 Mon Sep 17 00:00:00 2001 +From 0c5d9141dd96cd672cf34a81ed85ace3fd81dc4f Mon Sep 17 00:00:00 2001 From: xbmc Date: Sat, 4 May 2013 10:31:32 +0200 -Subject: [PATCH 062/102] xvba: squash me, settings +Subject: [PATCH 078/120] xvba: squash me, settings --- xbmc/settings/Settings.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/xbmc/settings/Settings.cpp b/xbmc/settings/Settings.cpp -index aaa291b..bca003a 100644 +index 63cdf0e..02eef76 100644 --- a/xbmc/settings/Settings.cpp +++ b/xbmc/settings/Settings.cpp -@@ -738,6 +738,9 @@ void CSettings::InitializeConditions() +@@ -747,6 +747,9 @@ void CSettings::InitializeConditions() #ifdef HAVE_LIBVDPAU m_settingsManager->AddCondition("have_libvdpau"); #endif @@ -17687,10 +24195,10 @@ index aaa291b..bca003a 100644 1.8.1.6 -From 4529fa75c62e7a91d93bd8ef38abad7da8a5415b Mon Sep 17 00:00:00 2001 +From 4c8d51caa9dafea84316f7ef2be30f6da3437023 Mon Sep 17 00:00:00 2001 From: fritsch Date: Fri, 24 May 2013 12:02:02 +0200 -Subject: [PATCH 063/102] XVBA: Limit video to 2048x1152 as this is the max all +Subject: [PATCH 079/120] XVBA: Limit video to 2048x1152 as this is the max all blocks can handle --- @@ -17720,10 +24228,10 @@ index 1db9363..54d7aea 100644 1.8.1.6 -From 8524cebfcfde67b40e6aec08d6e5f37952a3f070 Mon Sep 17 00:00:00 2001 +From f253a19754ae4681b1ef1b8a20bc54d433c69e64 Mon Sep 17 00:00:00 2001 From: xbmc Date: Mon, 20 Aug 2012 16:06:39 +0200 -Subject: [PATCH 064/102] dvdplayer: observe pts counter overflow +Subject: [PATCH 080/120] dvdplayer: observe pts counter overflow --- .../cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp | 198 ++++++++++++++++++++- @@ -18010,10 +24518,10 @@ index b78094e..17d2f7a 100644 1.8.1.6 -From f7bba8195ee608d1d37323fb621e18c6faef5e4b Mon Sep 17 00:00:00 2001 +From b6966559bfcb6d8247f9dcbe545a9c2249f304a4 Mon Sep 17 00:00:00 2001 From: xbmc Date: Tue, 2 Oct 2012 13:02:10 +0200 -Subject: [PATCH 065/102] dvdplayer: avoid short screen flicker caused by +Subject: [PATCH 081/120] dvdplayer: avoid short screen flicker caused by unnecessary reconfigure of renderer --- @@ -18046,10 +24554,10 @@ index 41e64a5..74b4391 100644 1.8.1.6 -From 194e21ab35ded27f327ae0837da7014dd68dfb1e Mon Sep 17 00:00:00 2001 +From 7e0a288445d9a411a65f50e3f58f419df637d9ad Mon Sep 17 00:00:00 2001 From: xbmc Date: Thu, 11 Oct 2012 12:05:50 +0200 -Subject: [PATCH 066/102] vdpau: advanced settings for auto deinterlacing +Subject: [PATCH 082/120] vdpau: advanced settings for auto deinterlacing --- xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 8 ++++---- @@ -18115,10 +24623,10 @@ index 3a52878..3e6901b 100644 1.8.1.6 -From 39b24d311dc59492752635899d73f2e404f74fac Mon Sep 17 00:00:00 2001 +From 75905003ddf0c49e0c8efb54ee562e1a1d6be316 Mon Sep 17 00:00:00 2001 From: xbmc Date: Fri, 2 Nov 2012 13:20:03 +0100 -Subject: [PATCH 067/102] player: fix rewind +Subject: [PATCH 083/120] player: fix rewind --- xbmc/cores/dvdplayer/DVDMessage.h | 5 ++++- @@ -18166,7 +24674,7 @@ index 3f65ced..ad434d2 100644 class CDVDMsgPlayerSeekChapter : public CDVDMsg diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp -index d2c164d..1846d40 100644 +index b56423b..cdc4b95 100644 --- a/xbmc/cores/dvdplayer/DVDPlayer.cpp +++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp @@ -1556,11 +1556,13 @@ void CDVDPlayer::HandlePlaySpeed() @@ -18271,10 +24779,10 @@ index d2c164d..1846d40 100644 UpdatePlayState(0); diff --git a/xbmc/cores/dvdplayer/DVDPlayer.h b/xbmc/cores/dvdplayer/DVDPlayer.h -index ceb9996..dad94c9 100644 +index 6da30eb..69b659b 100644 --- a/xbmc/cores/dvdplayer/DVDPlayer.h +++ b/xbmc/cores/dvdplayer/DVDPlayer.h -@@ -303,7 +303,7 @@ class CDVDPlayer : public IPlayer, public CThread, public IDVDPlayer +@@ -304,7 +304,7 @@ class CDVDPlayer : public IPlayer, public CThread, public IDVDPlayer bool GetCachingTimes(double& play_left, double& cache_left, double& file_offset); @@ -18283,7 +24791,7 @@ index ceb9996..dad94c9 100644 void HandleMessages(); void HandlePlaySpeed(); -@@ -352,8 +352,9 @@ class CDVDPlayer : public IPlayer, public CThread, public IDVDPlayer +@@ -353,8 +353,9 @@ class CDVDPlayer : public IPlayer, public CThread, public IDVDPlayer int m_playSpeed; struct SSpeedState { @@ -18333,10 +24841,10 @@ index 3c3e007..6ae3860 100644 1.8.1.6 -From 54cf251b01804dbb4484b08911aca11d3dc78a6b Mon Sep 17 00:00:00 2001 +From 01cab2fa720c32c295755f0d21efb6af2e9d5d5e Mon Sep 17 00:00:00 2001 From: xbmc Date: Fri, 23 Nov 2012 17:41:12 +0100 -Subject: [PATCH 068/102] xrandr: fix query for multiple screens +Subject: [PATCH 084/120] xrandr: fix query for multiple screens --- xbmc/windowing/X11/XRandR.cpp | 10 ++++++---- @@ -18377,10 +24885,10 @@ index 97b1e32..a3d3543 100644 1.8.1.6 -From 8ab34a11535ed7ed9b7cda38e09c0ca147387c88 Mon Sep 17 00:00:00 2001 +From c729728cddd9d5d673dd8290e61f05194091dc96 Mon Sep 17 00:00:00 2001 From: xbmc Date: Sun, 2 Dec 2012 15:46:55 +0100 -Subject: [PATCH 069/102] X11: add debug log to print out refresh after xrr +Subject: [PATCH 085/120] X11: add debug log to print out refresh after xrr event --- @@ -18408,10 +24916,10 @@ index d2dcccd..7403785 100644 1.8.1.6 -From dc8c7fbe173848a3007caf3a9c85469669051c7d Mon Sep 17 00:00:00 2001 +From 51949d1edc0d73a0e694d95aa5b13f96096c19cb Mon Sep 17 00:00:00 2001 From: xbmc Date: Tue, 11 Dec 2012 11:08:13 +0100 -Subject: [PATCH 070/102] X11: dont call XCloseDisplay on shutdown, it crashes +Subject: [PATCH 086/120] X11: dont call XCloseDisplay on shutdown, it crashes when powered doen by cec on ATI --- @@ -18436,10 +24944,10 @@ index 7403785..0e39867 100644 1.8.1.6 -From 69111a8676eeae2fd7dd727ff430e8f72de10dc4 Mon Sep 17 00:00:00 2001 +From bb5b4b390c8b5ef322a826b6ae21aaa7d21365e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9gory=20Coutant?= Date: Wed, 12 Dec 2012 19:49:47 +0100 -Subject: [PATCH 071/102] x11: support for multiple x screens +Subject: [PATCH 087/120] x11: support for multiple x screens --- xbmc/windowing/X11/XRandR.cpp | 2 +- @@ -18462,10 +24970,10 @@ index a3d3543..8846bc6 100644 1.8.1.6 -From c114410550cf702e040405a9a81b3877bb71f296 Mon Sep 17 00:00:00 2001 +From 9910e14b12a73069a08dfcedd845a5fcbf1793d2 Mon Sep 17 00:00:00 2001 From: xbmc Date: Mon, 24 Dec 2012 16:02:42 +0100 -Subject: [PATCH 072/102] pvr: increase changes counter of stream on stream +Subject: [PATCH 088/120] pvr: increase changes counter of stream on stream change, cosmetics after dd307930d39d92f145a01a16600cd00e01ec39be --- @@ -18499,10 +25007,10 @@ index 305ba07..3ad9792 100644 1.8.1.6 -From 4539f4f93769d87840bfffbc7455f721db55b38e Mon Sep 17 00:00:00 2001 +From 5259e6c6da5d419ccd00eedcdfbb520c2563fbd5 Mon Sep 17 00:00:00 2001 From: xbmc Date: Thu, 17 Jan 2013 16:03:22 +0100 -Subject: [PATCH 073/102] X11: add keymapping for XF86XK_Sleep +Subject: [PATCH 089/120] X11: add keymapping for XF86XK_Sleep --- xbmc/windowing/WinEventsX11.cpp | 1 + @@ -18524,10 +25032,10 @@ index 4a5aab4..da5d412 100644 1.8.1.6 -From d9b9f8e39cae0b5b42018427b1a84a507fb767c6 Mon Sep 17 00:00:00 2001 +From aa780253926d75fc655f1c68b6a9d4070f9f0a76 Mon Sep 17 00:00:00 2001 From: xbmc Date: Mon, 21 Jan 2013 09:00:19 +0100 -Subject: [PATCH 074/102] X11: remove toggle full screen after resume +Subject: [PATCH 090/120] X11: remove toggle full screen after resume --- xbmc/powermanagement/PowerManager.cpp | 5 ----- @@ -18553,10 +25061,10 @@ index f2a063f..f1e3c4f 100644 1.8.1.6 -From c629d743d0a700476937cb730a343528153426ea Mon Sep 17 00:00:00 2001 +From 48c4123199a0d72fa1e5376835ba1e37ba098c8c Mon Sep 17 00:00:00 2001 From: xbmc Date: Wed, 23 Jan 2013 17:03:02 +0100 -Subject: [PATCH 075/102] xrandr: set screen on mode change command +Subject: [PATCH 091/120] xrandr: set screen on mode change command --- xbmc/windowing/X11/XRandR.cpp | 2 +- @@ -18579,10 +25087,10 @@ index 8846bc6..e6d6240 100644 1.8.1.6 -From 8eb507a19cb21901d21814d8b9ab30ae7feac834 Mon Sep 17 00:00:00 2001 +From 6c45e086d7b8b64f3c242e27142ebb722fd7bc6e Mon Sep 17 00:00:00 2001 From: xbmc Date: Wed, 23 Jan 2013 17:03:39 +0100 -Subject: [PATCH 076/102] X11: recreate glx context when output changes +Subject: [PATCH 092/120] X11: recreate glx context when output changes --- xbmc/windowing/X11/WinSystemX11.cpp | 6 +++--- @@ -18633,10 +25141,10 @@ index f479c27..7345c06 100644 1.8.1.6 -From fc9e0ef3ca01feafe62d318e00fae4597c5d2d3d Mon Sep 17 00:00:00 2001 +From 6773b28acbcc4832190677a22c90e7b58cf641ef Mon Sep 17 00:00:00 2001 From: xbmc Date: Fri, 14 Dec 2012 14:19:15 +0100 -Subject: [PATCH 077/102] pvr: do not show selection dialog for a single menu +Subject: [PATCH 093/120] pvr: do not show selection dialog for a single menu hook --- @@ -18679,10 +25187,10 @@ index 2b43bcb..d07f23d 100644 1.8.1.6 -From 2a6c00739b48f743b7250c2cfd085df783b2471e Mon Sep 17 00:00:00 2001 +From 6279f69b3c2c829ae721837a871dfbf979a44bf4 Mon Sep 17 00:00:00 2001 From: xbmc Date: Sun, 3 Feb 2013 08:17:16 +0100 -Subject: [PATCH 078/102] X11: use default screen parameters if no output +Subject: [PATCH 094/120] X11: use default screen parameters if no output connected --- @@ -18786,10 +25294,10 @@ index d865cd7..97975dd 100644 1.8.1.6 -From bdb23df225dd086438cc163dc2341b6d8b7017a3 Mon Sep 17 00:00:00 2001 +From 1f51b9667e9b425598a330a7d971438b7aec0a7e Mon Sep 17 00:00:00 2001 From: xbmc Date: Sat, 23 Mar 2013 15:13:32 +0100 -Subject: [PATCH 079/102] X11: create parent window +Subject: [PATCH 095/120] X11: create parent window --- xbmc/windowing/X11/WinSystemX11.cpp | 69 +++++++++++++++++++++++-------------- @@ -19055,10 +25563,10 @@ index 7345c06..770ae84 100644 1.8.1.6 -From 93252a9917eefbe02f3013e340d5cea7c44b2ecd Mon Sep 17 00:00:00 2001 +From 04288c55b3eb01b5ba39bd7da7c8d7ea3e67e29f Mon Sep 17 00:00:00 2001 From: xbmc Date: Sun, 24 Mar 2013 12:30:12 +0100 -Subject: [PATCH 080/102] X11: use system key repeat rate instead of hardcoded +Subject: [PATCH 096/120] X11: use system key repeat rate instead of hardcoded one, taken from 58fd64b194e38b73b5f3132744bab35e994e7441 --- @@ -19260,10 +25768,10 @@ index 102a076..5b1f3fa 100644 1.8.1.6 -From 3ce0aabd6142f413046d6a91e10a1fd8bd67f418 Mon Sep 17 00:00:00 2001 +From 18b0fa15efb0564d5e64a520ef0dc51354a768d0 Mon Sep 17 00:00:00 2001 From: xbmc Date: Sun, 24 Mar 2013 16:04:48 +0100 -Subject: [PATCH 081/102] linux: use CLOCK_MONOTONIC_RAW as this is not subject +Subject: [PATCH 097/120] linux: use CLOCK_MONOTONIC_RAW as this is not subject to NTP --- @@ -19301,37 +25809,37 @@ index 8304ef6..ba27257 100644 1.8.1.6 -From 24d4e5ee8c9bf1054f2313853b39a430d82f63e1 Mon Sep 17 00:00:00 2001 +From ff344a3f82d0dae8e39251d87520d509cfb123e0 Mon Sep 17 00:00:00 2001 From: xbmc Date: Thu, 28 Mar 2013 15:18:53 +0100 -Subject: [PATCH 082/102] OMXPlayer: some caching fixes for pvr +Subject: [PATCH 098/120] OMXPlayer: some caching fixes for pvr --- xbmc/cores/omxplayer/OMXPlayer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xbmc/cores/omxplayer/OMXPlayer.cpp b/xbmc/cores/omxplayer/OMXPlayer.cpp -index 70a2405..db17114 100644 +index f20c399..c096f32 100644 --- a/xbmc/cores/omxplayer/OMXPlayer.cpp +++ b/xbmc/cores/omxplayer/OMXPlayer.cpp -@@ -2432,7 +2432,8 @@ void COMXPlayer::HandleMessages() - // 1. disable audio - // 2. skip frames and adjust their pts or the clock +@@ -2459,7 +2459,8 @@ void COMXPlayer::HandleMessages() + m_messenger.Put(new CDVDMsgPlayerSeek(DVD_TIME_TO_MSEC(m_clock.GetClock()), (speed < 0), true, false, false, true)); + m_playSpeed = speed; - m_caching = CACHESTATE_DONE; + if (m_caching != CACHESTATE_PVR && m_playSpeed != DVD_PLAYSPEED_NORMAL) + m_caching = CACHESTATE_DONE; m_clock.SetSpeed(speed); m_av_clock.OMXSetSpeed(speed); - m_omxPlayerAudio.SetSpeed(speed); + m_av_clock.OMXPause(); -- 1.8.1.6 -From 9eccfb9b772f299a6f2d1f1c16d76a4334a72efd Mon Sep 17 00:00:00 2001 +From 38974c764854c7191b6336d89827c5ee5d6e3174 Mon Sep 17 00:00:00 2001 From: xbmc Date: Thu, 28 Mar 2013 20:50:59 +0100 -Subject: [PATCH 083/102] fix incorrect display of fps when dr kicks in +Subject: [PATCH 099/120] fix incorrect display of fps when dr kicks in --- xbmc/Application.cpp | 3 ++- @@ -19358,10 +25866,10 @@ index a5603a2..ce0a147 100644 1.8.1.6 -From 2527c2473f8b22eb9ab3280ce69ed7043d46cf93 Mon Sep 17 00:00:00 2001 +From 9320c643038190eed1b3c68f403fb1381eac4f71 Mon Sep 17 00:00:00 2001 From: xbmc Date: Mon, 8 Apr 2013 11:18:31 +0200 -Subject: [PATCH 084/102] squash to dropping control +Subject: [PATCH 100/120] squash to dropping control --- xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 1 + @@ -19383,10 +25891,10 @@ index 11e0b26..3f915ce 100644 1.8.1.6 -From b1a241c4a8b0ba0b4c0710794920edd2f438b433 Mon Sep 17 00:00:00 2001 +From e642fd14bc1e9aa84969fef2b8fb7cc2fa4cbc86 Mon Sep 17 00:00:00 2001 From: xbmc Date: Thu, 11 Apr 2013 12:33:46 +0200 -Subject: [PATCH 085/102] pvr: try SwtichChannel when selecting a channel via +Subject: [PATCH 101/120] pvr: try SwtichChannel when selecting a channel via EPG --- @@ -19421,10 +25929,10 @@ index 6b999e4..256a295 100644 1.8.1.6 -From d74da440e8141c711135d5810dc6e742ced82918 Mon Sep 17 00:00:00 2001 +From 81af9728bd20d6799225749f53a293ded3c78f22 Mon Sep 17 00:00:00 2001 From: xbmc Date: Sat, 13 Apr 2013 08:32:06 +0200 -Subject: [PATCH 086/102] X11: fix mouse coverage +Subject: [PATCH 102/120] X11: fix mouse coverage --- xbmc/windowing/X11/WinSystemX11.cpp | 11 ++++++++--- @@ -19490,10 +25998,10 @@ index 770ae84..084f546 100644 1.8.1.6 -From ace8c4151e897275851377fca74251d17fa02692 Mon Sep 17 00:00:00 2001 +From b16758959d4ea789e547202c0de581fbdc9f56db Mon Sep 17 00:00:00 2001 From: Rainer Hochecker Date: Wed, 8 May 2013 13:14:58 +0200 -Subject: [PATCH 087/102] X11: fix incorrectly used screen num in desktop +Subject: [PATCH 103/120] X11: fix incorrectly used screen num in desktop resolution --- @@ -19528,10 +26036,10 @@ index bf95bc7..0221036 100644 1.8.1.6 -From c1da087395588fde44631f5604bc5f1585f5d3e2 Mon Sep 17 00:00:00 2001 +From 4d0abbd8f86044c16fc27b57aa8a136cc5456c4f Mon Sep 17 00:00:00 2001 From: Rainer Hochecker Date: Thu, 9 May 2013 12:07:09 +0200 -Subject: [PATCH 088/102] X11: do not overwrite user selected monitor with +Subject: [PATCH 104/120] X11: do not overwrite user selected monitor with fallback --- @@ -19656,10 +26164,10 @@ index 084f546..30f5fa0 100644 1.8.1.6 -From e18371b675ec3020107c0553ebdac80093d9d315 Mon Sep 17 00:00:00 2001 +From 34bcf3ae44ae6a4b83fe20ce3c17984e37959d75 Mon Sep 17 00:00:00 2001 From: Rainer Hochecker Date: Sun, 12 May 2013 10:50:30 +0200 -Subject: [PATCH 089/102] xrandr: add turn on/off to wrapper +Subject: [PATCH 105/120] xrandr: add turn on/off to wrapper --- xbmc/windowing/X11/XRandR.cpp | 78 +++++++++++++++++++++++++++++++++++++++---- @@ -19825,10 +26333,10 @@ index 26c2653..2741879 100644 1.8.1.6 -From b67090cc0554fbbcc35bfa48da95b076d69e05e3 Mon Sep 17 00:00:00 2001 +From 745f293c7ccbac0f19d578b6e111cb40daf8906e Mon Sep 17 00:00:00 2001 From: Rainer Hochecker Date: Sun, 19 May 2013 12:55:35 +0200 -Subject: [PATCH 090/102] xrandr: add GetPreferredMode to wrapper +Subject: [PATCH 106/120] xrandr: add GetPreferredMode to wrapper --- xbmc/windowing/X11/XRandR.cpp | 23 +++++++++++++++++++++++ @@ -19885,10 +26393,10 @@ index 2741879..24ad1d0 100644 1.8.1.6 -From 0ba1f1c3aa0d2550ef6fcf16d89302e3c1f47f02 Mon Sep 17 00:00:00 2001 +From ed467ea7523cb6f6fbf85b9d31107c6300fba8a4 Mon Sep 17 00:00:00 2001 From: Rainer Hochecker Date: Sat, 11 May 2013 17:12:12 +0200 -Subject: [PATCH 091/102] X11: multi-head improvement - poll for desired output +Subject: [PATCH 107/120] X11: multi-head improvement - poll for desired output if we do not get an xrr event --- @@ -19903,7 +26411,7 @@ Subject: [PATCH 091/102] X11: multi-head improvement - poll for desired output 8 files changed, 105 insertions(+), 12 deletions(-) diff --git a/language/English/strings.po b/language/English/strings.po -index 62f7138..7f21f0d 100644 +index d603702..79a3996 100644 --- a/language/English/strings.po +++ b/language/English/strings.po @@ -6232,7 +6232,7 @@ msgctxt "#14071" @@ -20169,10 +26677,10 @@ index 380a194..650a6ef 100644 1.8.1.6 -From 4670ba070193b0253bbc388bf0dd86eac420356c Mon Sep 17 00:00:00 2001 +From a69d038705bb1bf5400ee636a50ab7b7d8bee9af Mon Sep 17 00:00:00 2001 From: Rainer Hochecker Date: Wed, 15 May 2013 09:14:34 +0200 -Subject: [PATCH 092/102] X11: ignore mouse move event form other windows +Subject: [PATCH 108/120] X11: ignore mouse move event form other windows --- xbmc/windowing/WinEventsX11.cpp | 4 +++- @@ -20204,10 +26712,10 @@ index 879d8f2..2ec9b6f 100644 1.8.1.6 -From cd3d022a43a9466cc70c988379d4106b1936609c Mon Sep 17 00:00:00 2001 +From 22c0d6b6086515ac76d7b4e5623c59c7b1d1523f Mon Sep 17 00:00:00 2001 From: Rainer Hochecker Date: Sun, 2 Jun 2013 14:53:45 +0200 -Subject: [PATCH 093/102] vdpau: fix segfault caused by uninitialized member +Subject: [PATCH 109/120] vdpau: fix segfault caused by uninitialized member --- xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 1 + @@ -20229,10 +26737,10 @@ index fc4c030..9bafdd7 100644 1.8.1.6 -From 75584696969c243c39300c7ea9cf1b44b70497dc Mon Sep 17 00:00:00 2001 +From d63b245cec19b5375337b917da1612fb5f5a376d Mon Sep 17 00:00:00 2001 From: Rainer Hochecker Date: Tue, 11 Jun 2013 16:13:45 +0200 -Subject: [PATCH 094/102] vdpau: sync video mixer +Subject: [PATCH 110/120] vdpau: sync video mixer --- xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 15 +++++++++++++++ @@ -20268,10 +26776,10 @@ index 9bafdd7..55ef4dc 100644 1.8.1.6 -From f8df3a87c129a16af99cb16c2dab475362bd2b7a Mon Sep 17 00:00:00 2001 +From 29ece2fd859f50915578fc78e721e7b702c71107 Mon Sep 17 00:00:00 2001 From: Rainer Hochecker Date: Tue, 11 Jun 2013 16:20:29 +0200 -Subject: [PATCH 095/102] renderer: allow some lateness within vblank interval +Subject: [PATCH 111/120] renderer: allow some lateness within vblank interval --- xbmc/cores/VideoRenderers/RenderManager.cpp | 12 ++++++++++-- @@ -20331,10 +26839,10 @@ index 7a3a530..480e4dc 100644 1.8.1.6 -From a1d3e46f8441b352d02844593fe603be2a782866 Mon Sep 17 00:00:00 2001 +From fc99eaf2c71798ecb3841f6043626286c750b9cc Mon Sep 17 00:00:00 2001 From: Rainer Hochecker Date: Fri, 14 Jun 2013 09:23:22 +0200 -Subject: [PATCH 096/102] vdpau: calculate timestamp of second field when doing +Subject: [PATCH 112/120] vdpau: calculate timestamp of second field when doing deinterlacing --- @@ -20360,10 +26868,10 @@ index 55ef4dc..27d63f5 100644 1.8.1.6 -From a0edf31c4f4ab9385c56bd64fdb3e81096b20f38 Mon Sep 17 00:00:00 2001 +From de1036f61e6974d6d5c9b28a4d852862eae56bd2 Mon Sep 17 00:00:00 2001 From: Rainer Hochecker Date: Fri, 14 Jun 2013 10:46:58 +0200 -Subject: [PATCH 097/102] vdpau: comment debug log: long decoding time +Subject: [PATCH 113/120] vdpau: comment debug log: long decoding time --- xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 8 ++++---- @@ -20399,10 +26907,10 @@ index 27d63f5..593f96c 100644 1.8.1.6 -From 9eec193ac47dc3a84c6869e2c739d42bbfbf83c5 Mon Sep 17 00:00:00 2001 +From 0b3531fdba493d2f2fb50e0024fa03fc2c3c85c2 Mon Sep 17 00:00:00 2001 From: xbmc Date: Sun, 16 Jun 2013 13:22:58 +0200 -Subject: [PATCH 098/102] X11: another fix for mouse coverage +Subject: [PATCH 114/120] X11: another fix for mouse coverage --- xbmc/windowing/WinEventsX11.cpp | 6 ++++-- @@ -20435,10 +26943,10 @@ index 2ec9b6f..4ed978c 100644 1.8.1.6 -From 9022c37f0ee8b4a5e2403fcd38af9fefa8afe6cd Mon Sep 17 00:00:00 2001 +From 2ec93711fbca9c546a29ed2c7f3dc6ee38173e13 Mon Sep 17 00:00:00 2001 From: xbmc Date: Sun, 16 Jun 2013 13:23:19 +0200 -Subject: [PATCH 099/102] renderer: delete fence on uninit +Subject: [PATCH 115/120] renderer: delete fence on uninit --- xbmc/cores/VideoRenderers/LinuxRendererGL.cpp | 5 +++++ @@ -20465,10 +26973,10 @@ index c663423..858d39d 100644 1.8.1.6 -From 81d711412c2d5806a0e5c60582eace93c324b5a9 Mon Sep 17 00:00:00 2001 +From edffe3bc5afa89da9d1db58cc752f01e786eeaea Mon Sep 17 00:00:00 2001 From: Rainer Hochecker Date: Sun, 16 Jun 2013 14:28:01 +0200 -Subject: [PATCH 100/102] renderer: limit fence to vdpau +Subject: [PATCH 116/120] renderer: limit fence to vdpau --- xbmc/cores/VideoRenderers/LinuxRendererGL.cpp | 15 +++++++++------ @@ -20506,10 +27014,10 @@ index 858d39d..bb198f3 100644 1.8.1.6 -From f8464c54c772bb888d6b0a4ecc6dcd88d2f937bd Mon Sep 17 00:00:00 2001 +From 1a10092809cbc1d465f90ac2ed62c23a1d2b0475 Mon Sep 17 00:00:00 2001 From: Rainer Hochecker Date: Thu, 4 Jul 2013 16:38:26 +0200 -Subject: [PATCH 101/102] XVBA: replace CODEC_IS with AV_CODEC_ID +Subject: [PATCH 117/120] XVBA: replace CODEC_IS with AV_CODEC_ID --- xbmc/cores/dvdplayer/DVDCodecs/Video/XVBA.cpp | 14 +++++++------- @@ -20584,10 +27092,10 @@ index 54d7aea..5845dbf 100644 1.8.1.6 -From 4b0d4c0e721d260a0bee963d460eb17420050b89 Mon Sep 17 00:00:00 2001 +From f283aa4f4bc54ca786ef49d20546fabb47121cd9 Mon Sep 17 00:00:00 2001 From: Rainer Hochecker Date: Fri, 5 Jul 2013 12:14:00 +0200 -Subject: [PATCH 102/102] X11: set windows class name +Subject: [PATCH 118/120] X11: set windows class name --- xbmc/windowing/X11/WinSystemX11.cpp | 9 ++++++++- @@ -20628,3 +27136,99 @@ index 6b1ed87..30eff67 100644 -- 1.8.1.6 + +From 16699f98372b9468c17a11d8cae851704c42bf7c Mon Sep 17 00:00:00 2001 +From: Rainer Hochecker +Date: Sat, 13 Jul 2013 20:00:45 +0200 +Subject: [PATCH 119/120] VDPAU: revert sync mixer, does a busy wait + +--- + xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp | 31 +++++++++++++------------- + 1 file changed, 16 insertions(+), 15 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +index 593f96c..f630bcb 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VDPAU.cpp +@@ -1139,7 +1139,7 @@ void CVdpauRenderPicture::ReturnUnused() + // Mixer + //----------------------------------------------------------------------------- + CMixer::CMixer(CEvent *inMsgEvent) : +- CThread("Vdpau Mixer Thread"), ++ CThread("Vdpau Mixer"), + m_controlPort("ControlPort", inMsgEvent, &m_outMsgEvent), + m_dataPort("DataPort", inMsgEvent, &m_outMsgEvent) + { +@@ -2353,19 +2353,20 @@ void CMixer::ProcessPicture() + CheckStatus(vdp_st, __LINE__); + + // sync mixer, read blocks until output surface is written +- { +- uint32_t data[16]; +- VdpRect rect; +- rect.x0 = rect.y0 = 0; +- rect.x1 = rect.y1 = 1; +- uint32_t *pdata[] = {data}; +- uint32_t pitches[] = {4}; +- +- vdp_st = m_config.vdpProcs.vdp_output_surface_get_bits_native(m_processPicture.outputSurface, +- &rect, +- (void**)pdata, +- pitches); +- } ++ // this does a busy wait :( ++// { ++// uint32_t data[16]; ++// VdpRect rect; ++// rect.x0 = rect.y0 = 0; ++// rect.x1 = rect.y1 = 1; ++// uint32_t *pdata[] = {data}; ++// uint32_t pitches[] = {4}; ++// ++// vdp_st = m_config.vdpProcs.vdp_output_surface_get_bits_native(m_processPicture.outputSurface, ++// &rect, ++// (void**)pdata, ++// pitches); ++// } + + if (m_mixerfield != VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME) + { +@@ -2410,7 +2411,7 @@ bool CMixer::CheckStatus(VdpStatus vdp_st, int line) + // Output + //----------------------------------------------------------------------------- + COutput::COutput(CEvent *inMsgEvent) : +- CThread("Vdpau Output Thread"), ++ CThread("Vdpau Output"), + m_controlPort("OutputControlPort", inMsgEvent, &m_outMsgEvent), + m_dataPort("OutputDataPort", inMsgEvent, &m_outMsgEvent), + m_mixer(&m_outMsgEvent) +-- +1.8.1.6 + + +From 4c3839fa3d2984a6a20e98ce0f9f5c503138b4cf Mon Sep 17 00:00:00 2001 +From: fritsch +Date: Sun, 14 Jul 2013 14:21:52 +0200 +Subject: [PATCH 120/120] ActiveAE: Make ActiveAE default Audio Engine to get + it tested via ppa + +--- + xbmc/cores/AudioEngine/AEFactory.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/xbmc/cores/AudioEngine/AEFactory.cpp b/xbmc/cores/AudioEngine/AEFactory.cpp +index d5517f3..07b4095 100644 +--- a/xbmc/cores/AudioEngine/AEFactory.cpp ++++ b/xbmc/cores/AudioEngine/AEFactory.cpp +@@ -97,7 +97,7 @@ bool CAEFactory::LoadEngine() + loaded = CAEFactory::LoadEngine(AE_ENGINE_COREAUDIO); + #else + if (!loaded) +- loaded = CAEFactory::LoadEngine(AE_ENGINE_SOFT); ++ loaded = CAEFactory::LoadEngine(AE_ENGINE_ACTIVE); + #endif + + return loaded; +-- +1.8.1.6 +