aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRainer Hochecker <fernetmenta@online.de>2013-10-31 23:29:28 -0700
committerRainer Hochecker <fernetmenta@online.de>2013-10-31 23:29:28 -0700
commitc9df5c3a88b5e513e790b127b8d064b004463765 (patch)
treec12bc7f2425775c6a66147f8a75f5b155590f493
parent64ef7b9a36627ffd7b37dff32a8e8f1389cf6d7b (diff)
parentdff3ebdb077528cb293760c559eb2e74de47ade4 (diff)
Merge pull request #3455 from FernetMenta/audiopage
new audio settings
-rw-r--r--XBMC.xcodeproj/project.pbxproj2
-rwxr-xr-xlanguage/English/strings.po91
-rw-r--r--project/VS2010Express/XBMC.vcxproj6
-rw-r--r--project/VS2010Express/XBMC.vcxproj.filters18
-rw-r--r--system/settings/darwin.xml6
-rw-r--r--system/settings/rbp.xml96
-rw-r--r--system/settings/settings.xml227
-rw-r--r--system/settings/win32.xml20
-rw-r--r--xbmc/Application.cpp11
-rw-r--r--xbmc/cores/AudioEngine/AEFactory.cpp69
-rw-r--r--xbmc/cores/AudioEngine/AEFactory.h8
-rw-r--r--xbmc/cores/AudioEngine/AESinkFactory.cpp6
-rw-r--r--xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp100
-rw-r--r--xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.h11
-rw-r--r--xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.cpp50
-rw-r--r--xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.h5
-rw-r--r--xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAE.cpp58
-rw-r--r--xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAE.h6
-rw-r--r--xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAEHALOSX.cpp2
-rw-r--r--xbmc/cores/AudioEngine/Engines/PiAudio/PiAudioAE.cpp89
-rw-r--r--xbmc/cores/AudioEngine/Engines/PiAudio/PiAudioAE.h12
-rw-r--r--xbmc/cores/AudioEngine/Engines/SoftAE/SoftAE.cpp1548
-rw-r--r--xbmc/cores/AudioEngine/Engines/SoftAE/SoftAE.h253
-rw-r--r--xbmc/cores/AudioEngine/Engines/SoftAE/SoftAESound.cpp114
-rw-r--r--xbmc/cores/AudioEngine/Engines/SoftAE/SoftAESound.h57
-rw-r--r--xbmc/cores/AudioEngine/Engines/SoftAE/SoftAEStream.cpp687
-rw-r--r--xbmc/cores/AudioEngine/Engines/SoftAE/SoftAEStream.h161
-rw-r--r--xbmc/cores/AudioEngine/Interfaces/AE.h15
-rw-r--r--xbmc/cores/AudioEngine/Makefile.in4
-rw-r--r--xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp18
-rw-r--r--xbmc/cores/AudioEngine/Utils/AEUtil.h9
-rw-r--r--xbmc/cores/AudioEngine/Utils/AEWAVLoader.cpp4
-rw-r--r--xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp7
-rw-r--r--xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPassthrough.cpp28
-rw-r--r--xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPassthroughFFmpeg.cpp17
-rw-r--r--xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp30
-rw-r--r--xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.h2
-rw-r--r--xbmc/cores/dvdplayer/DVDPlayerAudio.cpp10
-rw-r--r--xbmc/cores/omxplayer/OMXAudio.cpp13
-rw-r--r--xbmc/cores/omxplayer/OMXPlayerAudio.cpp35
-rw-r--r--xbmc/cores/omxplayer/OMXPlayerAudio.h2
-rw-r--r--xbmc/cores/paplayer/DVDPlayerCodec.cpp3
-rw-r--r--xbmc/cores/playercorefactory/PlayerCoreFactory.cpp10
-rw-r--r--xbmc/settings/AdvancedSettings.cpp14
-rw-r--r--xbmc/settings/AdvancedSettings.h7
-rw-r--r--xbmc/settings/Settings.cpp14
-rw-r--r--xbmc/video/dialogs/GUIDialogAudioSubtitleSettings.cpp20
-rw-r--r--xbmc/video/dialogs/GUIDialogAudioSubtitleSettings.h2
48 files changed, 677 insertions, 3300 deletions
diff --git a/XBMC.xcodeproj/project.pbxproj b/XBMC.xcodeproj/project.pbxproj
index 044538cf6b..c5c4be598d 100644
--- a/XBMC.xcodeproj/project.pbxproj
+++ b/XBMC.xcodeproj/project.pbxproj
@@ -4180,7 +4180,6 @@
DFB0F471161B747500D744F4 /* AddonsOperations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AddonsOperations.h; sourceTree = "<group>"; };
DFB15B2015F8FB8100CDF0DE /* SDLMain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLMain.h; sourceTree = "<group>"; };
DFB15B2115F8FB8100CDF0DE /* SDLMain.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = SDLMain.mm; sourceTree = "<group>"; };
- DFB65F6415373AE7006B8FF1 /* AEAudioFormat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AEAudioFormat.h; sourceTree = "<group>"; };
DFB65F6515373AE7006B8FF1 /* AEFactory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AEFactory.cpp; sourceTree = "<group>"; };
DFB65F6615373AE7006B8FF1 /* AEFactory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AEFactory.h; sourceTree = "<group>"; };
DFB65F6A15373AE7006B8FF1 /* AEEncoderFFmpeg.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AEEncoderFFmpeg.cpp; sourceTree = "<group>"; };
@@ -7015,7 +7014,6 @@
DFB65F6C15373AE7006B8FF1 /* Engines */,
DFB65F8815373AE7006B8FF1 /* Interfaces */,
DFB65FA215373AE7006B8FF1 /* Utils */,
- DFB65F6415373AE7006B8FF1 /* AEAudioFormat.h */,
DFB65F6515373AE7006B8FF1 /* AEFactory.cpp */,
DFB65F6615373AE7006B8FF1 /* AEFactory.h */,
);
diff --git a/language/English/strings.po b/language/English/strings.po
index 4d3e6ff54f..74be31cc42 100755
--- a/language/English/strings.po
+++ b/language/English/strings.po
@@ -1242,10 +1242,7 @@ msgctxt "#298"
msgid "Bookmarks"
msgstr ""
-#: system/settings/settings.xml
-msgctxt "#299"
-msgid "AAC capable receiver"
-msgstr ""
+#empty string with id 299
msgctxt "#300"
msgid "MP1 capable receiver"
@@ -1393,17 +1390,17 @@ msgstr ""
#: system/settings/settings.xml
msgctxt "#337"
-msgid "Audio output"
+msgid "Output configuration"
msgstr ""
#: system/settings/settings.xml
msgctxt "#338"
-msgid "Analogue"
+msgid "Fixed"
msgstr ""
#: system/settings/settings.xml
msgctxt "#339"
-msgid "Optical/Coax"
+msgid "Optimized"
msgstr ""
msgctxt "#340"
@@ -1447,7 +1444,7 @@ msgstr ""
#: system/settings/settings.xml
msgctxt "#348"
-msgid "Multichannel LPCM capable receiver"
+msgid "Enable passthrough"
msgstr ""
#: system/settings/settings.xml
@@ -1780,12 +1777,12 @@ msgstr ""
#: system/settings/settings.xml
msgctxt "#420"
-msgid "HDMI"
+msgid "Best Match"
msgstr ""
#: system/settings/settings.xml
msgctxt "#421"
-msgid "Stream silence when idle"
+msgid "Keep audio device alive"
msgstr ""
msgctxt "#422"
@@ -1937,7 +1934,10 @@ msgctxt "#457"
msgid "Switch view"
msgstr ""
-#empty string with id 458
+#: system/settings/settings.xml
+msgctxt "#458"
+msgid "Limit sampling rate (kHz)"
+msgstr ""
msgctxt "#459"
msgid "Subs"
@@ -6080,7 +6080,15 @@ msgctxt "#13553"
msgid "%.1f Seconds"
msgstr ""
-#empty strings from id 13554 to 13599
+msgctxt "#13554"
+msgid "%d Minute"
+msgstr ""
+
+msgctxt "#13555"
+msgid "%d Minutes"
+msgstr ""
+
+#empty strings from id 13556 to 13599
#: system/settings/darwin.xml
msgctxt "#13600"
@@ -12442,7 +12450,7 @@ msgstr ""
#: system/settings/settings.xml
msgctxt "#34111"
-msgid "When activated silence is output in order to keep alive receiver, otherwise sink is drained in idle state"
+msgid "Select the behaviour when no sound is required for either playback or GUI sounds. [Always] - continuous inaudible signal is output, this keeps the receiving audio device alive for any new sounds, however this might also block sound from other applications. [1- 10 Minutes] - same as Always except that after the selected period of time audio enters a suspended state [Off] - audio output enters a suspended state. Note - sounds can be missed if audio enters suspended state."
msgstr ""
#empty strings from id 34112 to 34119
@@ -12471,8 +12479,38 @@ msgctxt "#34123"
msgid "Never"
msgstr ""
-#empty strings from id 34124 to 34200
-#34124-34200 reserved for future use
+#. SPDIF max sampling rate
+#: system/settings/settings.xml
+msgctxt "#34124"
+msgid "44.1"
+msgstr ""
+
+#. SPDIF max sampling rate
+#: system/settings/settings.xml
+msgctxt "#34125"
+msgid "48.0"
+msgstr ""
+
+#. SPDIF max sampling rate
+#: system/settings/settings.xml
+msgctxt "#34126"
+msgid "88.2"
+msgstr ""
+
+#. SPDIF max sampling rate
+#: system/settings/settings.xml
+msgctxt "#34127"
+msgid "96.0"
+msgstr ""
+
+#. SPDIF max sampling rate
+#: system/settings/settings.xml
+msgctxt "#34128"
+msgid "192.0"
+msgstr ""
+
+#empty strings from id 34129 to 34200
+#34129-34200 reserved for future use
#: xbmc\PlayListPlayer.cpp
msgctxt "#34201"
@@ -13215,7 +13253,7 @@ msgstr ""
#: system/settings/settings.xml
msgctxt "#36169"
-msgid "Resampling and other sound processing quality. Low quality is fast, higher quality will consume more CPU."
+msgid "Select the quality of resampling for cases where the audio output needs to be at a different sampling rate from that used by the source. [Low] is fast and will have minimal impact on system resources such as the use of the CPU, [Medium] & [High] will use progressively more system resources."
msgstr ""
#: system/settings/settings.xml
@@ -14175,12 +14213,12 @@ msgstr ""
#: system/settings/settings.xml
msgctxt "#36361"
-msgid "Type of connection to the audio equipment."
+msgid "Select how the properties of the audio output are set: [Fixed] - output properties are set to the specified sampling rate & speaker configuration at all times; [Best Match] - output properties are set to always be as close a match to the source properties as possible; [Optimized] - output properties are set at the start of playback and will not change if the properties of the source changes."
msgstr ""
#: system/settings/settings.xml
msgctxt "#36362"
-msgid "Select your physical speaker layout."
+msgid "Select the maximum number of audio channels/speakers available for audio decoded."
msgstr ""
#: system/settings/settings.xml
@@ -14190,7 +14228,7 @@ msgstr ""
#: system/settings/settings.xml
msgctxt "#36364"
-msgid "Upmix 2 channel stereo sources so the number of audio channels matches the number of speakers."
+msgid "Select to enable upmixing of 2 channel stereo sources to the number of audio channels specified by the speaker configuration."
msgstr ""
#: system/settings/settings.xml
@@ -14203,14 +14241,14 @@ msgctxt "#36366"
msgid "Select this option if your receiver is capable of decoding DTS streams."
msgstr ""
-#: system/settings/settings.xml
+#: system/settings/darwin_osx.xml
msgctxt "#36367"
-msgid "Select this option if your receiver is capable of decoding AAC streams."
+msgid "Select the maximum number of audio channels/speakers available for audio decoded. If optical/coax digital outputs are used this must be set to 2.0"
msgstr ""
#: system/settings/settings.xml
msgctxt "#36368"
-msgid "Select this option if your receiver is capable of decoding LPCM streams."
+msgid "Select to enable the passthrough audio options for playback of encoded audio such as Dolby Digital."
msgstr ""
#: system/settings/settings.xml
@@ -14225,12 +14263,12 @@ msgstr ""
#: system/settings/settings.xml
msgctxt "#36371"
-msgid "Select the device you use to play audio decoded by XBMC such as mp3's and FLAC."
+msgid "Select the device to be used for playback of audio that has been decoded such as mp3"
msgstr ""
#: system/settings/settings.xml
msgctxt "#36372"
-msgid "Select the device you use to play encoded formats, these are any of the formats checked above in the 'capable receiver' options."
+msgid "Select the device to be used for playback of encoded formats, these are any of the formats below in the 'capable receiver' options."
msgstr ""
#: system/settings/settings.xml
@@ -14556,7 +14594,10 @@ msgctxt "#36522"
msgid "Use preferred mode"
msgstr ""
-#empty string with id 36523
+#: system/settings/settings.xml
+msgctxt "#36523"
+msgid "Maximum sampling rate for spdif or sampling rate for fixed output configuration"
+msgstr ""
#: system/settings/settings.xml
msgctxt "#36524"
diff --git a/project/VS2010Express/XBMC.vcxproj b/project/VS2010Express/XBMC.vcxproj
index e90b2968c7..390e06993a 100644
--- a/project/VS2010Express/XBMC.vcxproj
+++ b/project/VS2010Express/XBMC.vcxproj
@@ -393,9 +393,6 @@
<ClCompile Include="..\..\xbmc\cores\AudioEngine\Engines\ActiveAE\ActiveAESink.cpp" />
<ClCompile Include="..\..\xbmc\cores\AudioEngine\Engines\ActiveAE\ActiveAESound.cpp" />
<ClCompile Include="..\..\xbmc\cores\AudioEngine\Engines\ActiveAE\ActiveAEStream.cpp" />
- <ClCompile Include="..\..\xbmc\cores\AudioEngine\Engines\SoftAE\SoftAE.cpp" />
- <ClCompile Include="..\..\xbmc\cores\AudioEngine\Engines\SoftAE\SoftAESound.cpp" />
- <ClCompile Include="..\..\xbmc\cores\AudioEngine\Engines\SoftAE\SoftAEStream.cpp" />
<ClCompile Include="..\..\xbmc\cores\AudioEngine\Sinks\AESinkDirectSound.cpp" />
<ClCompile Include="..\..\xbmc\cores\AudioEngine\Sinks\AESinkNULL.cpp" />
<ClCompile Include="..\..\xbmc\cores\AudioEngine\Sinks\AESinkProfiler.cpp" />
@@ -1055,9 +1052,6 @@
<ClInclude Include="..\..\xbmc\cores\AudioEngine\Engines\ActiveAE\ActiveAESink.h" />
<ClInclude Include="..\..\xbmc\cores\AudioEngine\Engines\ActiveAE\ActiveAESound.h" />
<ClInclude Include="..\..\xbmc\cores\AudioEngine\Engines\ActiveAE\ActiveAEStream.h" />
- <ClInclude Include="..\..\xbmc\cores\AudioEngine\Engines\SoftAE\SoftAE.h" />
- <ClInclude Include="..\..\xbmc\cores\AudioEngine\Engines\SoftAE\SoftAESound.h" />
- <ClInclude Include="..\..\xbmc\cores\AudioEngine\Engines\SoftAE\SoftAEStream.h" />
<ClInclude Include="..\..\xbmc\cores\AudioEngine\Interfaces\AE.h" />
<ClInclude Include="..\..\xbmc\cores\AudioEngine\Interfaces\AEEncoder.h" />
<ClInclude Include="..\..\xbmc\cores\AudioEngine\Interfaces\AESink.h" />
diff --git a/project/VS2010Express/XBMC.vcxproj.filters b/project/VS2010Express/XBMC.vcxproj.filters
index 570fb6f160..74e82c44ac 100644
--- a/project/VS2010Express/XBMC.vcxproj.filters
+++ b/project/VS2010Express/XBMC.vcxproj.filters
@@ -2316,15 +2316,6 @@
<ClCompile Include="..\..\xbmc\cores\AudioEngine\AESinkFactory.cpp">
<Filter>cores\AudioEngine</Filter>
</ClCompile>
- <ClCompile Include="..\..\xbmc\cores\AudioEngine\Engines\SoftAE\SoftAE.cpp">
- <Filter>cores\AudioEngine\Engines</Filter>
- </ClCompile>
- <ClCompile Include="..\..\xbmc\cores\AudioEngine\Engines\SoftAE\SoftAESound.cpp">
- <Filter>cores\AudioEngine\Engines</Filter>
- </ClCompile>
- <ClCompile Include="..\..\xbmc\cores\AudioEngine\Engines\SoftAE\SoftAEStream.cpp">
- <Filter>cores\AudioEngine\Engines</Filter>
- </ClCompile>
<ClCompile Include="..\..\xbmc\cores\AudioEngine\Sinks\AESinkDirectSound.cpp">
<Filter>cores\AudioEngine\Sinks</Filter>
</ClCompile>
@@ -5377,15 +5368,6 @@
<ClInclude Include="..\..\xbmc\cores\AudioEngine\AESinkFactory.h">
<Filter>cores\AudioEngine</Filter>
</ClInclude>
- <ClInclude Include="..\..\xbmc\cores\AudioEngine\Engines\SoftAE\SoftAE.h">
- <Filter>cores\AudioEngine\Engines</Filter>
- </ClInclude>
- <ClInclude Include="..\..\xbmc\cores\AudioEngine\Engines\SoftAE\SoftAESound.h">
- <Filter>cores\AudioEngine\Engines</Filter>
- </ClInclude>
- <ClInclude Include="..\..\xbmc\cores\AudioEngine\Engines\SoftAE\SoftAEStream.h">
- <Filter>cores\AudioEngine\Engines</Filter>
- </ClInclude>
<ClInclude Include="..\..\xbmc\cores\AudioEngine\Interfaces\AE.h">
<Filter>cores\AudioEngine\Interfaces</Filter>
</ClInclude>
diff --git a/system/settings/darwin.xml b/system/settings/darwin.xml
index 817a99023f..180f0eeb15 100644
--- a/system/settings/darwin.xml
+++ b/system/settings/darwin.xml
@@ -8,9 +8,9 @@
</category>
<category id="audiooutput">
<group id="1">
- <setting id="audiooutput.passthroughaac">
- <visible>false</visible>
- </setting>
+ <setting id="audiooutput.channels" help="36367" />
+ </group>
+ <group id="3">
<setting id="audiooutput.truehdpassthrough">
<visible>false</visible>
</setting>
diff --git a/system/settings/rbp.xml b/system/settings/rbp.xml
index ddd6635bb6..166314a202 100644
--- a/system/settings/rbp.xml
+++ b/system/settings/rbp.xml
@@ -30,21 +30,67 @@
</setting>
</group>
</category>
- <category id="audiooutput">
+
+ <category id="audiooutput" label="772" help="36360">
<group id="1">
- <setting id="audiooutput.mode">
- <default>2</default> <!-- AUDIO_HDMI -->
+ <setting id="audiooutput.audiodevice">
+ <level>1</level>
+ <default>HDMI</default>
+ <constraints>
+ <options>audiodevices</options>
+ </constraints>
+ <control type="list" format="string" />
</setting>
- <setting id="audiooutput.channels">
+ <setting id="audiooutput.dualaudio" type="boolean" label="37017" help="36542">
+ <level>2</level>
+ <default>false</default>
+ <dependencies>
+ <dependency type="visible">
+ <condition on="property" name="aesettingvisible" setting="audiooutput.audiodevice">audiooutput.passthrough</condition>
+ </dependency>
+ </dependencies>
+ </setting>
+ <setting id="audiooutput.boostcentre" type="boolean" label="37018" help="36543">
+ <level>2</level>
+ <default>false</default>
+ </setting>
+ <setting id="audiooutput.config">
<visible>false</visible>
</setting>
<setting id="audiooutput.stereoupmix">
<visible>false</visible>
</setting>
- <setting id="audiooutput.passthroughaac">
+ <setting id="audiooutput.channels">
<visible>false</visible>
</setting>
- <setting id="audiooutput.multichannellpcm">
+ <setting id="audiooutput.streamsilence">
+ <level>2</level>
+ <default>0</default>
+ <dependencies>
+ <dependency type="visible">
+ <condition on="property" name="aesettingvisible" setting="audiooutput.audiodevice">audiooutput.streamsilence</condition>
+ </dependency>
+ </dependencies>
+ <constraints>
+ <options>audiostreamsilence</options>
+ </constraints>
+ <control type="spinner" format="string" />
+ </setting>
+ </group>
+ <group id="2">
+ <visible>false</visible>
+ </group>
+ <group id="3">
+ <setting id="audiooutput.passthrough">
+ <level>2</level>
+ <default>false</default>
+ <dependencies>
+ <dependency type="visible">
+ <condition on="property" name="aesettingvisible" setting="audiooutput.audiodevice">audiooutput.passthrough</condition>
+ </dependency>
+ </dependencies>
+ </setting>
+ <setting id="audiooutput.passthroughdevice">
<visible>false</visible>
</setting>
<setting id="audiooutput.truehdpassthrough">
@@ -57,49 +103,19 @@
<visible>false</visible>
</setting>
<setting id="audiooutput.ac3passthrough">
- <default>true</default>
<dependencies>
- <dependency type="enable">
- <and>
- <or>
- <condition setting="audiooutput.mode">1</condition> <!-- AUDIO_IEC958 -->
- <condition setting="audiooutput.mode">2</condition> <!-- AUDIO_HDMI -->
- </or>
- <condition setting="audiooutput.dualaudio">false</condition>
- </and>
+ <dependency type="visible">
+ <condition on="property" name="aesettingvisible" setting="audiooutput.audiodevice">audiooutput.ac3passthrough</condition>
</dependency>
</dependencies>
</setting>
<setting id="audiooutput.dtspassthrough">
- <default>true</default>
<dependencies>
- <dependency type="enable">
- <and>
- <or>
- <condition setting="audiooutput.mode">1</condition> <!-- AUDIO_IEC958 -->
- <condition setting="audiooutput.mode">2</condition> <!-- AUDIO_HDMI -->
- </or>
- <condition setting="audiooutput.dualaudio">false</condition>
- </and>
+ <dependency type="visible">
+ <condition on="property" name="aesettingvisible" setting="audiooutput.audiodevice">audiooutput.dtspassthrough</condition>
</dependency>
</dependencies>
</setting>
- <setting id="audiooutput.dualaudio" type="boolean" label="37017" help="36542">
- <level>2</level>
- <default>false</default>
- </setting>
- <setting id="audiooutput.boostcentre" type="boolean" label="37018" help="36543">
- <level>2</level>
- <default>false</default>
- </setting>
- </group>
- <group id="2">
- <visible>false</visible>
- </group>
- <group id="3">
- <setting id="audiooutput.guisoundmode">
- <visible>false</visible>
- </setting>
</group>
</category>
</section>
diff --git a/system/settings/settings.xml b/system/settings/settings.xml
index 528c09054e..d25dd72180 100644
--- a/system/settings/settings.xml
+++ b/system/settings/settings.xml
@@ -1972,17 +1972,20 @@
</category>
<category id="audiooutput" label="772" help="36360">
<group id="1">
- <setting id="audiooutput.mode" type="integer" label="337" help="36361">
- <level>1</level>
- <default>0</default> <!-- AUDIO_ANALOG -->
+ <setting id="audiooutput.audiodevice" type="string" label="545" help="36371">
+ <level>0</level>
+ <default>Default</default> <!-- will be properly set on startup -->
<constraints>
- <options>audiooutputmodes</options>
+ <options>audiodevices</options>
</constraints>
- <control type="spinner" format="string" />
+ <control type="list" format="string" />
</setting>
<setting id="audiooutput.channels" type="integer" label="34100" help="36362">
<level>0</level>
<default>1</default> <!-- AE_CH_LAYOUT_2_0 -->
+ <dependencies>
+ <dependency type="visible" on="property" name="aesettingvisible" setting="audiooutput.audiodevice">audiooutput.channels</dependency>
+ </dependencies>
<constraints>
<options>
<option label="34101">1</option> <!-- AE_CH_LAYOUT_2_0 -->
@@ -1997,14 +2000,48 @@
<option label="34110">10</option> <!-- AE_CH_LAYOUT_7_1 -->
</options>
</constraints>
- <updates>
- <update type="rename">audiooutput.channellayout</update>
- </updates>
<control type="spinner" format="string" />
</setting>
- <setting id="audiooutput.normalizelevels" type="boolean" label="346" help="36363">
+ <setting id="audiooutput.config" type="integer" label="337" help="36361">
<level>2</level>
- <default>true</default>
+ <default>2</default>
+ <constraints>
+ <options>
+ <option label="338">1</option>
+ <option label="339">2</option>
+ <option label="420">3</option>
+ </options>
+ </constraints>
+ <control type="spinner" format="integer" />
+ </setting>
+ <setting id="audiooutput.samplerate" type="integer" label="458" help="36523">
+ <level>2</level>
+ <default>48000</default>
+ <dependencies>
+ <dependency type="visible">
+ <and>
+ <condition on="property" name="aesettingvisible" setting="audiooutput.audiodevice">audiooutput.samplerate</condition>
+ <condition on="property" name="aesettingvisible" setting="audiooutput.config">audiooutput.samplerate</condition>
+ </and>
+ </dependency>
+ </dependencies>
+ <constraints>
+ <options>
+ <option label="34124">44100</option>
+ <option label="34125">48000</option>
+ <option label="34126">88200</option>
+ <option label="34127">96000</option>
+ <option label="34128">192000</option>
+ </options>
+ </constraints>
+ <control type="spinner" format="integer" />
+ </setting>
+ <setting id="audiooutput.stereoupmix" type="boolean" label="252" help="36364">
+ <level>2</level>
+ <default>false</default>
+ <dependencies>
+ <dependency type="visible" setting="audiooutput.channels" operator="!is">1</dependency>
+ </dependencies>
</setting>
<setting id="audiooutput.processquality" type="integer" label="13505" help="36169">
<requirement>HAS_AE_QUALITY_LEVELS</requirement>
@@ -2015,128 +2052,120 @@
</constraints>
<control type="spinner" format="string" />
</setting>
- <setting id="audiooutput.stereoupmix" type="boolean" label="252" help="36364">
- <level>2</level>
- <default>false</default>
+ <setting id="audiooutput.streamsilence" type="integer" label="421" help="34111">
+ <level>1</level>
+ <default>1</default>
+ <constraints>
+ <options>audiostreamsilence</options>
+ </constraints>
+ <control type="spinner" format="string" />
+ </setting>
+ </group>
+ <group id="2">
+ <setting id="audiooutput.guisoundmode" type="integer" label="34120" help="36373">
+ <level>0</level>
+ <default>1</default> <!-- AE_SOUND_IDLE -->
+ <constraints>
+ <options>
+ <option label="34121">1</option> <!-- AE_SOUND_IDLE -->
+ <option label="34122">2</option> <!-- AE_SOUND_ALWAYS -->
+ <option label="34123">0</option> <!-- AE_SOUND_OFF -->
+ </options>
+ </constraints>
+ <control type="spinner" format="string" />
</setting>
- <setting id="audiooutput.ac3passthrough" type="boolean" parent="audiooutput.mode" label="364" help="36365">
+ </group>
+ <group id="3">
+ <setting id="audiooutput.passthrough" type="boolean" label="348" help="36368">
<level>2</level>
- <default>true</default>
+ <default>false</default>
<dependencies>
- <dependency type="enable">
- <or>
- <condition setting="audiooutput.mode">1</condition> <!-- AUDIO_IEC958 -->
- <condition setting="audiooutput.mode">2</condition> <!-- AUDIO_HDMI -->
- </or>
+ <dependency type="visible">
+ <and>
+ <condition on="property" name="aesettingvisible" setting="audiooutput.audiodevice">audiooutput.passthrough</condition>
+ <condition on="property" name="aesettingvisible" setting="audiooutput.config">audiooutput.passthrough</condition>
+ </and>
</dependency>
</dependencies>
</setting>
- <setting id="audiooutput.eac3passthrough" type="boolean" parent="audiooutput.mode" label="448" help="37016">
+ <setting id="audiooutput.passthroughdevice" type="string" label="546" help="36372">
<level>2</level>
- <default>true</default>
+ <default>Default</default> <!-- will be properly set on startup -->
<dependencies>
- <dependency type="enable">
- <or>
- <condition setting="audiooutput.mode">1</condition> <!-- AUDIO_IEC958 -->
- <condition setting="audiooutput.mode">2</condition> <!-- AUDIO_HDMI -->
- </or>
+ <dependency type="visible">
+ <and>
+ <condition setting="audiooutput.passthrough" operator="is">true</condition>
+ <condition on="property" name="aesettingvisible" setting="audiooutput.passthrough">audiooutput.passthrough</condition>
+ <condition on="property" name="aesettingvisible" setting="audiooutput.config">audiooutput.passthrough</condition>
+ </and>
</dependency>
</dependencies>
- </setting>
- <setting id="audiooutput.dtspassthrough" type="boolean" parent="audiooutput.mode" label="254" help="36366">
+ <constraints>
+ <options>audiodevicespassthrough</options>
+ </constraints>
+ <control type="list" format="string" />
+ </setting>
+ <setting id="audiooutput.ac3passthrough" type="boolean" label="364" help="36365">
<level>2</level>
<default>true</default>
<dependencies>
- <dependency type="enable">
- <or>
- <condition setting="audiooutput.mode">1</condition> <!-- AUDIO_IEC958 -->
- <condition setting="audiooutput.mode">2</condition> <!-- AUDIO_HDMI -->
- </or>
+ <dependency type="visible">
+ <and>
+ <condition setting="audiooutput.passthrough" operator="is">true</condition>
+ <condition on="property" name="aesettingvisible" setting="audiooutput.config">audiooutput.passthrough</condition>
+ </and>
</dependency>
</dependencies>
</setting>
- <setting id="audiooutput.passthroughaac" type="boolean" parent="audiooutput.mode" label="299" help="36367">
+ <setting id="audiooutput.eac3passthrough" type="boolean" label="448" help="37016">
<level>2</level>
<default>false</default>
<dependencies>
- <dependency type="enable">
- <or>
- <condition setting="audiooutput.mode">1</condition> <!-- AUDIO_IEC958 -->
- <condition setting="audiooutput.mode">2</condition> <!-- AUDIO_HDMI -->
- </or>
+ <dependency type="visible">
+ <and>
+ <condition setting="audiooutput.passthrough" operator="is">true</condition>
+ <condition on="property" name="aesettingvisible" setting="audiooutput.config">audiooutput.passthrough</condition>
+ </and>
</dependency>
- </dependencies>
- </setting>
- <setting id="audiooutput.multichannellpcm" type="boolean" parent="audiooutput.mode" label="348" help="36368">
- <level>2</level>
- <default>true</default>
- <dependencies>
- <dependency type="enable" setting="audiooutput.mode">2</dependency> <!-- AUDIO_HDMI -->
- </dependencies>
+ </dependencies>
</setting>
- <setting id="audiooutput.truehdpassthrough" type="boolean" parent="audiooutput.mode" label="349" help="36369">
+ <setting id="audiooutput.dtspassthrough" type="boolean" label="254" help="36366">
<level>2</level>
- <default>true</default>
+ <default>false</default>
<dependencies>
- <dependency type="enable" setting="audiooutput.mode">2</dependency> <!-- AUDIO_HDMI -->
- </dependencies>
+ <dependency type="visible">
+ <and>
+ <condition setting="audiooutput.passthrough" operator="is">true</condition>
+ <condition on="property" name="aesettingvisible" setting="audiooutput.config">audiooutput.passthrough</condition>
+ </and>
+ </dependency>
+ </dependencies>
</setting>
- <setting id="audiooutput.dtshdpassthrough" type="boolean" parent="audiooutput.mode" label="347" help="36370">
+ <setting id="audiooutput.truehdpassthrough" type="boolean" label="349" help="36369">
<level>2</level>
- <default>true</default>
+ <default>false</default>
<dependencies>
- <dependency type="enable">
+ <dependency type="visible">
<and>
- <condition setting="audiooutput.dtspassthrough">true</condition>
- <condition setting="audiooutput.mode">2</condition> <!-- AUDIO_HDMI -->
+ <condition setting="audiooutput.passthrough" operator="is">true</condition>
+ <condition on="property" name="aesettingvisible" setting="audiooutput.config">audiooutput.truehdpassthrough</condition>
+ <condition on="property" name="aesettingvisible" setting="audiooutput.passthroughdevice">audiooutput.truehdpassthrough</condition>
</and>
</dependency>
- </dependencies>
- </setting>
- <setting id="audiooutput.streamsilence" type="boolean" label="421" help="34111">
- <level>2</level>
- <requirement>audiosupportsdrain</requirement>
- <default>true</default>
- </setting>
- </group>
- <group id="2">
- <setting id="audiooutput.audiodevice" type="string" label="545" help="36371">
- <level>2</level>
- <default>Default</default> <!-- will be properly set on startup -->
- <constraints>
- <options>audiodevices</options>
- </constraints>
- <control type="spinner" format="string" />
+ </dependencies>
</setting>
- <setting id="audiooutput.passthroughdevice" type="string" label="546" help="36372">
+ <setting id="audiooutput.dtshdpassthrough" type="boolean" label="347" help="36370">
<level>2</level>
- <default>Default</default> <!-- will be properly set on startup -->
- <constraints>
- <options>audiodevicespassthrough</options>
- </constraints>
+ <default>false</default>
<dependencies>
- <dependency type="enable">
- <or>
- <condition setting="audiooutput.mode">1</condition> <!-- AUDIO_IEC958 -->
- <condition setting="audiooutput.mode">2</condition> <!-- AUDIO_HDMI -->
- </or>
+ <dependency type="visible">
+ <and>
+ <condition setting="audiooutput.passthrough" operator="is">true</condition>
+ <condition on="property" name="aesettingvisible" setting="audiooutput.config">audiooutput.dtshdpassthrough</condition>
+ <condition on="property" name="aesettingvisible" setting="audiooutput.passthroughdevice">audiooutput.dtshdpassthrough</condition>
+ </and>
</dependency>
- </dependencies>
- <control type="spinner" format="string" />
- </setting>
- </group>
- <group id="3">
- <setting id="audiooutput.guisoundmode" type="integer" label="34120" help="36373">
- <level>0</level>
- <default>1</default> <!-- AE_SOUND_IDLE -->
- <constraints>
- <options>
- <option label="34121">1</option> <!-- AE_SOUND_IDLE -->
- <option label="34122">2</option> <!-- AE_SOUND_ALWAYS -->
- <option label="34123">0</option> <!-- AE_SOUND_OFF -->
- </options>
- </constraints>
- <control type="spinner" format="string" />
+ </dependencies>
</setting>
</group>
</category>
diff --git a/system/settings/win32.xml b/system/settings/win32.xml
index bb716a2edd..acf63d1164 100644
--- a/system/settings/win32.xml
+++ b/system/settings/win32.xml
@@ -40,15 +40,17 @@
</group>
</category>
<category id="audiooutput" label="772" help="36360">
- <group id="2">
+ <group id="1">
<setting id="audiooutput.audiodevice" type="string" label="545" help="36371">
- <level>2</level>
+ <level>1</level>
<default>DirectSound:default</default>
<constraints>
<options>audiodevices</options>
</constraints>
- <control type="spinner" format="string" />
+ <control type="list" format="string" />
</setting>
+ </group>
+ <group id="3">
<setting id="audiooutput.passthroughdevice" type="string" label="546" help="36372">
<level>2</level>
<default>DirectSound:default</default>
@@ -56,14 +58,14 @@
<options>audiodevicespassthrough</options>
</constraints>
<dependencies>
- <dependency type="enable">
- <or>
- <condition setting="audiooutput.mode">1</condition> <!-- AUDIO_IEC958 -->
- <condition setting="audiooutput.mode">2</condition> <!-- AUDIO_HDMI -->
- </or>
+ <dependency type="visible">
+ <and>
+ <condition on="property" name="aesettingvisible" setting="audiooutput.audiodevice">audiooutput.passthrough</condition>
+ <condition on="property" name="aesettingvisible" setting="audiooutput.config">audiooutput.passthrough</condition>
+ </and>
</dependency>
</dependencies>
- <control type="spinner" format="string" />
+ <control type="list" format="string" />
</setting>
</group>
</category>
diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp
index 0ca6243c70..e1465df1ce 100644
--- a/xbmc/Application.cpp
+++ b/xbmc/Application.cpp
@@ -1608,7 +1608,7 @@ void CApplication::OnSettingChanged(const CSetting *setting)
}
// this tells player whether to open an audio stream passthrough or PCM
// if this is changed, audio stream has to be reopened
- else if (settingId == "audiooutput.mode")
+ else if (settingId == "audiooutput.passthrough")
{
CApplicationMessenger::Get().MediaRestart(false);
return;
@@ -2762,13 +2762,8 @@ bool CApplication::OnAction(const CAction &action)
if (action.GetID() == ACTION_TOGGLE_DIGITAL_ANALOG)
{
- // TODO
- // revisit after new audio settings page have been implemented
- // makes no sense toggling a mode when you have three different settings
- int mode = CSettings::Get().GetInt("audiooutput.mode");
- if (++mode == 3)
- mode = 0;
- CSettings::Get().SetInt("audiooutput.mode", mode);
+ bool passthrough = CSettings::Get().GetBool("audiooutput.passthrough");
+ CSettings::Get().SetBool("audiooutput.passthrough", !passthrough);
if (g_windowManager.GetActiveWindow() == WINDOW_SETTINGS_SYSTEM)
{
diff --git a/xbmc/cores/AudioEngine/AEFactory.cpp b/xbmc/cores/AudioEngine/AEFactory.cpp
index 16fc7085c1..18288bc69d 100644
--- a/xbmc/cores/AudioEngine/AEFactory.cpp
+++ b/xbmc/cores/AudioEngine/AEFactory.cpp
@@ -26,7 +26,6 @@
#include "Engines/CoreAudio/CoreAudioAE.h"
#include "settings/SettingsManager.h"
#else
- #include "Engines/SoftAE/SoftAE.h"
#include "Engines/ActiveAE/ActiveAE.h"
#endif
@@ -40,6 +39,7 @@
#include "guilib/LocalizeStrings.h"
#include "settings/Setting.h"
+#include "settings/Settings.h"
#include "utils/StringUtils.h"
IAE* CAEFactory::AE = NULL;
@@ -72,9 +72,6 @@ bool CAEFactory::LoadEngine()
loaded = CAEFactory::LoadEngine(AE_ENGINE_PULSE);
#endif
- if (!loaded && engine == "SOFT" )
- loaded = CAEFactory::LoadEngine(AE_ENGINE_SOFT);
-
if (!loaded && engine == "ACTIVE")
loaded = CAEFactory::LoadEngine(AE_ENGINE_ACTIVE);
}
@@ -102,7 +99,6 @@ bool CAEFactory::LoadEngine(enum AEEngine engine)
#if defined(TARGET_DARWIN)
case AE_ENGINE_COREAUDIO: AE = new CCoreAudioAE(); break;
#else
- case AE_ENGINE_SOFT : AE = new CSoftAE(); break;
case AE_ENGINE_ACTIVE : AE = new ActiveAE::CActiveAE(); break;
#endif
#if defined(HAS_PULSEAUDIO)
@@ -238,18 +234,38 @@ std::string CAEFactory::GetDefaultDevice(bool passthrough)
return "default";
}
-bool CAEFactory::SupportsRaw()
+bool CAEFactory::SupportsRaw(AEDataFormat format)
{
+ // check if passthrough is enabled
+ if (!CSettings::Get().GetBool("audiooutput.passthrough"))
+ return false;
+
+ // fixed config disabled passthrough
+ if (CSettings::Get().GetInt("audiooutput.config") == AE_CONFIG_FIXED)
+ return false;
+
+ // check if the format is enabled in settings
+ if (format == AE_FMT_AC3 && !CSettings::Get().GetBool("audiooutput.ac3passthrough"))
+ return false;
+ if (format == AE_FMT_DTS && !CSettings::Get().GetBool("audiooutput.dtspassthrough"))
+ return false;
+ if (format == AE_FMT_EAC3 && !CSettings::Get().GetBool("audiooutput.eac3passthrough"))
+ return false;
+ if (format == AE_FMT_TRUEHD && !CSettings::Get().GetBool("audiooutput.truehdpassthrough"))
+ return false;
+ if (format == AE_FMT_DTSHD && !CSettings::Get().GetBool("audiooutput.dtshdpassthrough"))
+ return false;
+
if(AE)
- return AE->SupportsRaw();
+ return AE->SupportsRaw(format);
return false;
}
-bool CAEFactory::SupportsDrain()
+bool CAEFactory::SupportsSilenceTimeout()
{
if(AE)
- return AE->SupportsDrain();
+ return AE->SupportsSilenceTimeout();
return false;
}
@@ -339,15 +355,6 @@ void CAEFactory::SettingOptionsAudioDevicesPassthroughFiller(const CSetting *set
SettingOptionsAudioDevicesFillerGeneral(setting, list, current, true);
}
-void CAEFactory::SettingOptionsAudioOutputModesFiller(const CSetting *setting, std::vector< std::pair<std::string, int> > &list, int &current)
-{
- list.push_back(std::make_pair(g_localizeStrings.Get(338), AUDIO_ANALOG));
-#if !defined(TARGET_RASPBERRY_PI)
- list.push_back(std::make_pair(g_localizeStrings.Get(339), AUDIO_IEC958));
-#endif
- list.push_back(std::make_pair(g_localizeStrings.Get(420), AUDIO_HDMI));
-}
-
void CAEFactory::SettingOptionsAudioQualityLevelsFiller(const CSetting *setting, std::vector< std::pair<std::string, int> > &list, int &current)
{
if (!AE)
@@ -363,6 +370,24 @@ void CAEFactory::SettingOptionsAudioQualityLevelsFiller(const CSetting *setting,
list.push_back(std::make_pair(g_localizeStrings.Get(13509), AE_QUALITY_REALLYHIGH));
}
+void CAEFactory::SettingOptionsAudioStreamsilenceFiller(const CSetting *setting, std::vector< std::pair<std::string, int> > &list, int &current)
+{
+ if (!AE)
+ return;
+
+ list.push_back(std::make_pair(g_localizeStrings.Get(20422), XbmcThreads::EndTime::InfiniteValue));
+ list.push_back(std::make_pair(g_localizeStrings.Get(13551), 0));
+
+ if (AE->SupportsSilenceTimeout())
+ {
+ list.push_back(std::make_pair(StringUtils::Format(g_localizeStrings.Get(13554).c_str(), 1), 1));
+ for (int i = 2; i <= 10; i++)
+ {
+ list.push_back(std::make_pair(StringUtils::Format(g_localizeStrings.Get(13555).c_str(), i), i));
+ }
+ }
+}
+
void CAEFactory::SettingOptionsAudioDevicesFillerGeneral(const CSetting *setting, std::vector< std::pair<std::string, std::string> > &list, std::string &current, bool passthrough)
{
current = ((const CSettingString*)setting)->GetValue();
@@ -410,3 +435,11 @@ void CAEFactory::UnregisterAudioCallback()
if (AE)
AE->UnregisterAudioCallback();
}
+
+bool CAEFactory::IsSettingVisible(const std::string &condition, const std::string &value, const std::string &settingId)
+{
+ if (settingId.empty() || value.empty() || !AE)
+ return false;
+
+ return AE->IsSettingVisible(value);
+}
diff --git a/xbmc/cores/AudioEngine/AEFactory.h b/xbmc/cores/AudioEngine/AEFactory.h
index e3e8a3a30c..745ddc1333 100644
--- a/xbmc/cores/AudioEngine/AEFactory.h
+++ b/xbmc/cores/AudioEngine/AEFactory.h
@@ -29,7 +29,6 @@ class CSetting;
enum AEEngine
{
AE_ENGINE_NULL,
- AE_ENGINE_SOFT,
AE_ENGINE_COREAUDIO,
AE_ENGINE_PULSE,
AE_ENGINE_ACTIVE,
@@ -54,8 +53,8 @@ public:
static void EnumerateOutputDevices(AEDeviceList &devices, bool passthrough);
static void VerifyOutputDevice(std::string &device, bool passthrough);
static std::string GetDefaultDevice(bool passthrough);
- static bool SupportsRaw();
- static bool SupportsDrain();
+ static bool SupportsRaw(AEDataFormat format);
+ static bool SupportsSilenceTimeout();
/**
* Returns true if current AudioEngine supports at lest two basic quality levels
@@ -74,8 +73,9 @@ public:
static void SettingOptionsAudioDevicesFiller(const CSetting *setting, std::vector< std::pair<std::string, std::string> > &list, std::string &current);
static void SettingOptionsAudioDevicesPassthroughFiller(const CSetting *setting, std::vector< std::pair<std::string, std::string> > &list, std::string &current);
- static void SettingOptionsAudioOutputModesFiller(const CSetting *setting, std::vector< std::pair<std::string, int> > &list, int &current);
static void SettingOptionsAudioQualityLevelsFiller(const CSetting *setting, std::vector< std::pair<std::string, int> > &list, int &current);
+ static void SettingOptionsAudioStreamsilenceFiller(const CSetting *setting, std::vector< std::pair<std::string, int> > &list, int &current);
+ static bool IsSettingVisible(const std::string &condition, const std::string &value, const std::string &settingId);
static void RegisterAudioCallback(IAudioCallback* pCallback);
static void UnregisterAudioCallback();
diff --git a/xbmc/cores/AudioEngine/AESinkFactory.cpp b/xbmc/cores/AudioEngine/AESinkFactory.cpp
index 906a824818..e7fb9a3416 100644
--- a/xbmc/cores/AudioEngine/AESinkFactory.cpp
+++ b/xbmc/cores/AudioEngine/AESinkFactory.cpp
@@ -101,8 +101,7 @@ IAESink *CAESinkFactory::Create(std::string &device, AEAudioFormat &desiredForma
#if defined(TARGET_WINDOWS)
- if ((driver.empty() ||
- driver == "WASAPI") && !g_advancedSettings.m_audioForceDirectSound)
+ if (driver == "WASAPI")
TRY_SINK(WASAPI)
else
TRY_SINK(DirectSound) // always fall back to DirectSound
@@ -141,8 +140,7 @@ void CAESinkFactory::EnumerateEx(AESinkInfoList &list, bool force)
{
#if defined(TARGET_WINDOWS)
ENUMERATE_SINK(DirectSound, force);
- if (!g_advancedSettings.m_audioForceDirectSound)
- ENUMERATE_SINK(WASAPI, force);
+ ENUMERATE_SINK(WASAPI, force);
#elif defined(TARGET_ANDROID)
ENUMERATE_SINK(AUDIOTRACK, force);
#elif defined(TARGET_LINUX) || defined(TARGET_FREEBSD)
diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp
index 1879c5dd84..991c086e7e 100644
--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp
+++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp
@@ -411,7 +411,7 @@ void CActiveAE::StateMachine(int signal, Protocol *port, Message *msg)
m_extDeferData = true;
return;
case CActiveAEControlProtocol::DISPLAYLOST:
- if (m_settings.mode == AUDIO_HDMI)
+ if (m_sink.GetDeviceType(m_mode == MODE_PCM ? m_settings.device : m_settings.passthoughdevice) == AE_DEVTYPE_HDMI)
{
UnconfigureSink();
m_stats.SetSuspended(true);
@@ -1243,7 +1243,7 @@ void CActiveAE::ApplySettingsToFormat(AEAudioFormat &format, AudioSettings &sett
*mode = MODE_PCM;
// raw pass through
- if (m_settings.mode != AUDIO_ANALOG && AE_IS_RAW(format.m_dataFormat))
+ if (AE_IS_RAW(format.m_dataFormat))
{
if ((format.m_dataFormat == AE_FMT_AC3 && !settings.ac3passthrough) ||
(format.m_dataFormat == AE_FMT_EAC3 && !settings.eac3passthrough) ||
@@ -1257,9 +1257,8 @@ void CActiveAE::ApplySettingsToFormat(AEAudioFormat &format, AudioSettings &sett
*mode = MODE_RAW;
}
// transcode
- else if (m_settings.mode != AUDIO_ANALOG &&
+ else if (settings.passthrough &&
settings.ac3passthrough &&
- (!settings.multichannellpcm || (m_settings.mode != AUDIO_HDMI)) &&
!m_streams.empty() &&
(format.m_channelLayout.Count() > 2 || settings.stereoupmix))
{
@@ -1280,7 +1279,8 @@ void CActiveAE::ApplySettingsToFormat(AEAudioFormat &format, AudioSettings &sett
// which would cause a short audio drop-out if we changed the sink
if ((format.m_channelLayout.Count() > 2) ||
settings.stereoupmix ||
- (m_stats.GetWaterLevel() > 0 && m_internalFormat.m_channelLayout.Count() > 2 && !g_advancedSettings.m_audioAudiophile))
+ (settings.config == AE_CONFIG_FIXED) ||
+ (m_stats.GetWaterLevel() > 0 && m_internalFormat.m_channelLayout.Count() > 2 && (settings.config != AE_CONFIG_MATCH)))
{
CAEChannelInfo stdLayout;
switch (settings.channels)
@@ -1299,30 +1299,28 @@ void CActiveAE::ApplySettingsToFormat(AEAudioFormat &format, AudioSettings &sett
case 10: stdLayout = AE_CH_LAYOUT_7_1; break;
}
- if (g_advancedSettings.m_audioAudiophile)
+ if (m_settings.config == AE_CONFIG_MATCH)
format.m_channelLayout.ResolveChannels(stdLayout);
else
format.m_channelLayout = stdLayout;
}
- if (m_settings.mode == AUDIO_IEC958 && format.m_sampleRate > 48000)
+ if (m_sink.GetDeviceType(m_settings.device) == AE_DEVTYPE_IEC958)
{
- format.m_sampleRate = 48000;
- CLog::Log(LOGINFO, "CActiveAE::ApplySettings - limit samplerate for SPDIF to %d", format.m_sampleRate);
+ if (format.m_sampleRate > m_settings.samplerate)
+ {
+ format.m_sampleRate = m_settings.samplerate;
+ CLog::Log(LOGINFO, "CActiveAE::ApplySettings - limit samplerate for SPDIF to %d", format.m_sampleRate);
+ }
+ format.m_channelLayout = AE_CH_LAYOUT_2_0;
}
- if (g_advancedSettings.m_audioResample)
+ if (m_settings.config == AE_CONFIG_FIXED)
{
- format.m_sampleRate = g_advancedSettings.m_audioResample;
+ format.m_sampleRate = m_settings.samplerate;
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;
- }
-
// sinks may not support mono
if (format.m_channelLayout.Count() == 1)
{
@@ -1541,7 +1539,7 @@ bool CActiveAE::RunStages()
// TODO: find better solution for this
// gapless bites audiophile
- if (g_advancedSettings.m_audioAudiophile)
+ if (m_settings.config == AE_CONFIG_MATCH)
Configure(&slave->m_format);
(*it)->m_streamSlave = NULL;
@@ -1964,17 +1962,18 @@ void CActiveAE::LoadSettings()
m_settings.device = CSettings::Get().GetString("audiooutput.audiodevice");
m_settings.passthoughdevice = CSettings::Get().GetString("audiooutput.passthroughdevice");
- m_settings.mode = CSettings::Get().GetInt("audiooutput.mode");
+ m_settings.config = CSettings::Get().GetInt("audiooutput.config");
m_settings.channels = CSettings::Get().GetInt("audiooutput.channels");
+ m_settings.samplerate = CSettings::Get().GetInt("audiooutput.samplerate");
m_settings.stereoupmix = CSettings::Get().GetBool("audiooutput.stereoupmix");
+
+ m_settings.passthrough = m_settings.config == AE_CONFIG_FIXED ? false : CSettings::Get().GetBool("audiooutput.passthrough");
m_settings.ac3passthrough = CSettings::Get().GetBool("audiooutput.ac3passthrough");
m_settings.eac3passthrough = CSettings::Get().GetBool("audiooutput.eac3passthrough");
m_settings.truehdpassthrough = CSettings::Get().GetBool("audiooutput.truehdpassthrough");
m_settings.dtspassthrough = CSettings::Get().GetBool("audiooutput.dtspassthrough");
m_settings.dtshdpassthrough = CSettings::Get().GetBool("audiooutput.dtshdpassthrough");
- m_settings.aacpassthrough = CSettings::Get().GetBool("audiooutput.passthroughaac");
- m_settings.multichannellpcm = CSettings::Get().GetBool("audiooutput.multichannellpcm");
m_settings.resampleQuality = static_cast<AEQuality>(CSettings::Get().GetInt("audiooutput.processquality"));
}
@@ -2033,29 +2032,40 @@ void CActiveAE::OnSettingsChange(const std::string& setting)
{
if (setting == "audiooutput.passthroughdevice" ||
setting == "audiooutput.audiodevice" ||
- setting == "audiooutput.mode" ||
+ setting == "audiooutput.config" ||
setting == "audiooutput.ac3passthrough" ||
setting == "audiooutput.eac3passthrough" ||
setting == "audiooutput.dtspassthrough" ||
- setting == "audiooutput.passthroughaac" ||
setting == "audiooutput.truehdpassthrough" ||
setting == "audiooutput.dtshdpassthrough" ||
setting == "audiooutput.channels" ||
- setting == "audiooutput.multichannellpcm" ||
setting == "audiooutput.stereoupmix" ||
setting == "audiooutput.streamsilence" ||
- setting == "audiooutput.processquality")
+ setting == "audiooutput.processquality" ||
+ setting == "audiooutput.passthrough" ||
+ setting == "audiooutput.samplerate")
{
m_controlPort.SendOutMessage(CActiveAEControlProtocol::RECONFIGURE);
}
}
-bool CActiveAE::SupportsRaw()
+bool CActiveAE::SupportsRaw(AEDataFormat format)
{
+ if (!m_sink.HasPassthroughDevice())
+ return false;
+
+ // those formats require HDMI
+ if (format == AE_FMT_DTSHD || format == AE_FMT_TRUEHD)
+ {
+ if(m_sink.GetDeviceType(CSettings::Get().GetString("audiooutput.passthroughdevice")) != AE_DEVTYPE_HDMI)
+ return false;
+ }
+
+ // TODO: check ELD?
return true;
}
-bool CActiveAE::SupportsDrain()
+bool CActiveAE::SupportsSilenceTimeout()
{
return true;
}
@@ -2068,6 +2078,42 @@ bool CActiveAE::SupportsQualityLevel(enum AEQuality level)
return false;
}
+bool CActiveAE::IsSettingVisible(const std::string &settingId)
+{
+ if (settingId == "audiooutput.samplerate")
+ {
+ if (m_sink.GetDeviceType(CSettings::Get().GetString("audiooutput.audiodevice")) == AE_DEVTYPE_IEC958)
+ return true;
+ if (CSettings::Get().GetInt("audiooutput.config") == AE_CONFIG_FIXED)
+ return true;
+ }
+ else if (settingId == "audiooutput.channels")
+ {
+ if (m_sink.GetDeviceType(CSettings::Get().GetString("audiooutput.audiodevice")) != AE_DEVTYPE_IEC958)
+ return true;
+ }
+ else if (settingId == "audiooutput.passthrough")
+ {
+ if (m_sink.HasPassthroughDevice() && CSettings::Get().GetInt("audiooutput.config") != AE_CONFIG_FIXED)
+ return true;
+ }
+ else if (settingId == "audiooutput.truehdpassthrough")
+ {
+ if (m_sink.HasPassthroughDevice() &&
+ CSettings::Get().GetInt("audiooutput.config") != AE_CONFIG_FIXED &&
+ m_sink.GetDeviceType(CSettings::Get().GetString("audiooutput.passthroughdevice")) == AE_DEVTYPE_HDMI)
+ return true;
+ }
+ else if (settingId == "audiooutput.dtshdpassthrough")
+ {
+ if (m_sink.HasPassthroughDevice() &&
+ CSettings::Get().GetInt("audiooutput.config") != AE_CONFIG_FIXED &&
+ m_sink.GetDeviceType(CSettings::Get().GetString("audiooutput.passthroughdevice")) == AE_DEVTYPE_HDMI)
+ return true;
+ }
+ return false;
+}
+
void CActiveAE::Shutdown()
{
Dispose();
diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.h b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.h
index d684a448de..e3e772a2ac 100644
--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.h
+++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.h
@@ -48,16 +48,16 @@ struct AudioSettings
std::string device;
std::string driver;
std::string passthoughdevice;
- int mode;
int channels;
bool ac3passthrough;
bool eac3passthrough;
bool dtspassthrough;
- bool aacpassthrough;
bool truehdpassthrough;
bool dtshdpassthrough;
- bool multichannellpcm;
bool stereoupmix;
+ bool passthrough;
+ int config;
+ unsigned int samplerate;
AEQuality resampleQuality;
};
@@ -214,9 +214,10 @@ public:
virtual void EnumerateOutputDevices(AEDeviceList &devices, bool passthrough);
virtual std::string GetDefaultDevice(bool passthrough);
- virtual bool SupportsRaw();
- virtual bool SupportsDrain();
+ virtual bool SupportsRaw(AEDataFormat format);
+ virtual bool SupportsSilenceTimeout();
virtual bool SupportsQualityLevel(enum AEQuality level);
+ virtual bool IsSettingVisible(const std::string &settingId);
virtual void RegisterAudioCallback(IAudioCallback* pCallback);
virtual void UnregisterAudioCallback();
diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.cpp
index 1dec4f5fd7..d2a8d127f8 100644
--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.cpp
+++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.cpp
@@ -90,6 +90,37 @@ bool CActiveAESink::HasVolume()
return m_sink->HasVolume();
}
+AEDeviceType CActiveAESink::GetDeviceType(const std::string &device)
+{
+ std::string dev = device;
+ std::string dri;
+ CAESinkFactory::ParseDevice(dev, dri);
+ for (AESinkInfoList::iterator itt = m_sinkInfoList.begin(); itt != m_sinkInfoList.end(); ++itt)
+ {
+ for (AEDeviceInfoList::iterator itt2 = itt->m_deviceInfoList.begin(); itt2 != itt->m_deviceInfoList.end(); ++itt2)
+ {
+ CAEDeviceInfo& info = *itt2;
+ if (info.m_deviceName == dev)
+ return info.m_deviceType;
+ }
+ }
+ return AE_DEVTYPE_PCM;
+}
+
+bool CActiveAESink::HasPassthroughDevice()
+{
+ for (AESinkInfoList::iterator itt = m_sinkInfoList.begin(); itt != m_sinkInfoList.end(); ++itt)
+ {
+ for (AEDeviceInfoList::iterator itt2 = itt->m_deviceInfoList.begin(); itt2 != itt->m_deviceInfoList.end(); ++itt2)
+ {
+ CAEDeviceInfo& info = *itt2;
+ if (info.m_deviceType != AE_DEVTYPE_PCM)
+ return true;
+ }
+ }
+ return false;
+}
+
enum SINK_STATES
{
S_TOP = 0, // 0
@@ -132,7 +163,7 @@ void CActiveAESink::StateMachine(int signal, Protocol *port, Message *msg)
m_device = *(data->device);
}
m_extError = false;
- m_extSilence = false;
+ m_extSilenceTimer = 0;
ReturnBuffers();
OpenSink();
@@ -235,10 +266,14 @@ void CActiveAESink::StateMachine(int signal, Protocol *port, Message *msg)
switch (signal)
{
case CSinkControlProtocol::SILENCEMODE:
- m_extSilence = *(bool*)msg->data;
- if (CSettings::Get().GetBool("audiooutput.streamsilence"))
- m_extSilence = true;
- if (m_extSilence)
+ bool silencemode;
+ silencemode = *(bool*)msg->data;
+ if (silencemode)
+ m_extSilenceTimeout = XbmcThreads::EndTime::InfiniteValue;
+ else
+ m_extSilenceTimeout = CSettings::Get().GetInt("audiooutput.streamsilence") * 60000;
+ m_extSilenceTimer.Set(m_extSilenceTimeout);
+ if (!m_extSilenceTimer.IsTimePast())
{
m_state = S_TOP_CONFIGURED_SILENCE;
m_extTimeout = 0;
@@ -280,6 +315,7 @@ void CActiveAESink::StateMachine(int signal, Protocol *port, Message *msg)
{
m_state = S_TOP_CONFIGURED_PLAY;
m_extTimeout = delay / 2;
+ m_extSilenceTimer.Set(m_extSilenceTimeout);
}
return;
default:
@@ -372,7 +408,7 @@ void CActiveAESink::StateMachine(int signal, Protocol *port, Message *msg)
switch (signal)
{
case CSinkControlProtocol::TIMEOUT:
- if (m_extSilence)
+ if (!m_extSilenceTimer.IsTimePast())
{
m_state = S_TOP_CONFIGURED_SILENCE;
m_extTimeout = 0;
@@ -404,6 +440,8 @@ void CActiveAESink::StateMachine(int signal, Protocol *port, Message *msg)
m_sink = NULL;
m_state = S_TOP_CONFIGURED_SUSPEND;
}
+ else
+ m_state = S_TOP_CONFIGURED_PLAY;
m_extTimeout = 0;
return;
default:
diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.h b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.h
index 59bad57e26..52f4a17db3 100644
--- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.h
+++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAESink.h
@@ -89,6 +89,8 @@ public:
void Start();
void Dispose();
bool HasVolume();
+ AEDeviceType GetDeviceType(const std::string &device);
+ bool HasPassthroughDevice();
CSinkControlProtocol m_controlPort;
CSinkDataProtocol m_dataPort;
@@ -114,7 +116,8 @@ protected:
bool m_bStateMachineSelfTrigger;
int m_extTimeout;
bool m_extError;
- bool m_extSilence;
+ int m_extSilenceTimeout;
+ XbmcThreads::EndTime m_extSilenceTimer;
CSampleBuffer m_sampleOfSilence;
uint8_t *m_convertBuffer;
diff --git a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAE.cpp b/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAE.cpp
index 990163c046..d57dd5a3a7 100644
--- a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAE.cpp
+++ b/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAE.cpp
@@ -240,17 +240,14 @@ bool CCoreAudioAE::OpenCoreAudio(unsigned int sampleRate, bool forceRaw,
case 10: m_stdChLayout = AE_CH_LAYOUT_7_1; break;
}
#endif
- // force optical/coax to 2.0 output channels
- if (!m_rawPassthrough && !m_transcode && CSettings::Get().GetInt("audiooutput.mode") == AUDIO_IEC958)
- m_stdChLayout = AE_CH_LAYOUT_2_0;
// setup the desired format
m_format.m_channelLayout = CAEChannelInfo(m_stdChLayout);
// if there is an audio resample rate set, use it.
- if (g_advancedSettings.m_audioResample && !m_rawPassthrough)
+ if (CSettings::Get().GetInt("audiooutput.config") == AE_CONFIG_FIXED && !m_rawPassthrough)
{
- sampleRate = g_advancedSettings.m_audioResample;
+ sampleRate = CSettings::Get().GetInt("audiooutput.samplerate");
CLog::Log(LOGINFO, "CCoreAudioAE::passthrough - Forcing samplerate to %d", sampleRate);
}
@@ -406,11 +403,13 @@ void CCoreAudioAE::OnSettingsChange(const std::string& setting)
setting == "audiooutput.custompassthrough" ||
setting == "audiooutput.audiodevice" ||
setting == "audiooutput.customdevice" ||
- setting == "audiooutput.mode" ||
setting == "audiooutput.ac3passthrough" ||
+ setting == "audiooutput.eac3passthrough" ||
setting == "audiooutput.dtspassthrough" ||
- setting == "audiooutput.channels" ||
- setting == "audiooutput.multichannellpcm")
+ setting == "audiooutput.channels" ||
+ setting == "audiooutput.samplerate" ||
+ setting == "audiooutput.config" ||
+ setting == "audiooutput.passthrough" )
{
// only reinit the engine if we not
// suspended (resume will initialize
@@ -508,8 +507,30 @@ void CCoreAudioAE::SetSoundMode(const int mode)
StopAllSounds();
}
-bool CCoreAudioAE::SupportsRaw()
+bool CCoreAudioAE::SupportsRaw(AEDataFormat format)
{
+ switch(format)
+ {
+ case AE_FMT_AC3:
+ case AE_FMT_DTS:
+ case AE_FMT_EAC3:
+ case AE_FMT_LPCM:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool CCoreAudioAE::IsSettingVisible(const std::string &settingId)
+{
+ if (settingId == "audiooutput.samplerate")
+ {
+ if (CSettings::Get().GetInt("audiooutput.config") == AE_CONFIG_FIXED)
+ return true;
+ else
+ return false;
+ }
+
return true;
}
@@ -534,20 +555,17 @@ IAEStream* CCoreAudioAE::MakeStream(enum AEDataFormat dataFormat,
CLog::Log(LOGINFO, "CCoreAudioAE::MakeStream - %s, %u, %u, %s",
CAEUtil::DataFormatToStr(dataFormat), sampleRate, encodedSamplerate, ((std::string)channelInfo).c_str());
+ bool multichannelpcm = CSettings::Get().GetInt("audiooutput.channels") > AE_CH_LAYOUT_2_0; //if more then 2 channels are set - assume lpcm capability
+#if defined(TARGET_DARWIN_IOS)
+ multichannelpcm = false;
+#endif
// determine if we need to transcode this audio
// when we're called, we'll either get the audio in an encoded form (COREAUDIO_IS_RAW==true)
// that we can passthrough based on user options, or we'll get it unencoded
// if it's unencoded, and is 5.1, we'll transcode it to AC3 if possible
- bool transcode = CSettings::Get().GetBool("audiooutput.ac3passthrough") &&
- (
- (CSettings::Get().GetInt("audiooutput.mode") == AUDIO_IEC958) ||
- (
- (CSettings::Get().GetInt("audiooutput.mode") == AUDIO_HDMI) &&
- !CSettings::Get().GetBool("audiooutput.multichannellpcm")
- )
- ) &&
- !COREAUDIO_IS_RAW(dataFormat) &&
- (channelInfo.Count() == 6);
+ bool transcode = CSettings::Get().GetBool("audiooutput.passthrough") && CSettings::Get().GetBool("audiooutput.ac3passthrough") && !multichannelpcm &&
+ !COREAUDIO_IS_RAW(dataFormat) &&
+ (channelInfo.Count() == 6);
CCoreAudioAEStream *stream = new CCoreAudioAEStream(dataFormat, sampleRate, encodedSamplerate, channelLayout, options, transcode);
CSingleLock streamLock(m_streamLock);
@@ -748,7 +766,7 @@ void CCoreAudioAE::MixSounds(float *buffer, unsigned int samples)
void CCoreAudioAE::GarbageCollect()
{
#if defined(TARGET_DARWIN_OSX)
- if (g_advancedSettings.m_streamSilence)
+ if (CSettings::Get().GetInt("audiooutput.streamsilence") != 0)
return;
if (!m_streamsPlaying && m_playing_sounds.empty())
diff --git a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAE.h b/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAE.h
index 5e9d6942d5..f31dadab75 100644
--- a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAE.h
+++ b/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAE.h
@@ -91,9 +91,9 @@ public:
virtual void SetMute(const bool enabled);
virtual bool IsMuted();
virtual void SetSoundMode(const int mode);
-
-
- virtual bool SupportsRaw();
+ virtual bool SupportsRaw(AEDataFormat format);
+ virtual bool IsSettingVisible(const std::string &settingId);
+ virtual bool SupportsDrain() { return true; }
CCoreAudioAEHAL* GetHAL();
diff --git a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAEHALOSX.cpp b/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAEHALOSX.cpp
index 52b2272a2d..3728d5faf1 100644
--- a/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAEHALOSX.cpp
+++ b/xbmc/cores/AudioEngine/Engines/CoreAudio/CoreAudioAEHALOSX.cpp
@@ -95,7 +95,7 @@ bool CCoreAudioAEHALOSX::InitializePCM(ICoreAudioSource *pSource, AEAudioFormat
AudioChannelLayoutTag layout = g_LayoutMap[ CSettings::Get().GetInt("audiooutput.channels") ];
// force optical/coax to 2.0 output channels
- if (!m_Passthrough && CSettings::Get().GetInt("audiooutput.mode") == AUDIO_IEC958)
+ if (!m_Passthrough && CSettings::Get().GetInt("audiooutput.channels") == AE_CH_LAYOUT_2_0)
layout = g_LayoutMap[1];
if (!m_audioGraph->Open(pSource, format, outputDevice, allowMixing, layout, m_initVolume ))
diff --git a/xbmc/cores/AudioEngine/Engines/PiAudio/PiAudioAE.cpp b/xbmc/cores/AudioEngine/Engines/PiAudio/PiAudioAE.cpp
index 6bcd69d0c7..ccf40b0ea8 100644
--- a/xbmc/cores/AudioEngine/Engines/PiAudio/PiAudioAE.cpp
+++ b/xbmc/cores/AudioEngine/Engines/PiAudio/PiAudioAE.cpp
@@ -32,6 +32,7 @@ using namespace PiAudioAE;
#endif
CPiAudioAE::CPiAudioAE()
+: CThread("CPiAudio")
{
}
@@ -42,13 +43,39 @@ CPiAudioAE::~CPiAudioAE()
bool CPiAudioAE::Initialize()
{
UpdateStreamSilence();
+ Create();
return true;
}
+void CPiAudioAE::Process()
+{
+ while(!m_bStop)
+ {
+ /* thread just currently checks once a second if it's time to disable streamsilence */
+ Sleep(1000);
+
+ if (m_extSilenceTimer.IsTimePast())
+ {
+ UpdateStreamSilence(false);
+ m_extSilenceTimer.Set(XbmcThreads::EndTime::InfiniteValue);
+ }
+ }
+}
+
void CPiAudioAE::UpdateStreamSilence()
{
+ if (CSettings::Get().GetInt("audiooutput.streamsilence") > 0)
+ m_extSilenceTimeout = CSettings::Get().GetInt("audiooutput.streamsilence") * 60000;
+ else
+ m_extSilenceTimeout = XbmcThreads::EndTime::InfiniteValue;
+ m_extSilenceTimer.Set(m_extSilenceTimeout);
+ UpdateStreamSilence(CSettings::Get().GetString("audiooutput.audiodevice") == "HDMI" &&
+ CSettings::Get().GetInt("audiooutput.streamsilence") != 0);
+}
+
+void CPiAudioAE::UpdateStreamSilence(bool enable)
+{
#if defined(TARGET_RASPBERRY_PI)
- bool enable = CSettings::Get().GetBool("audiooutput.streamsilence");
char response[80] = "";
char command[80] = "";
sprintf(command, "force_audio hdmi %d", enable);
@@ -93,6 +120,8 @@ IAEStream *CPiAudioAE::MakeStream(enum AEDataFormat dataFormat, unsigned int sam
IAEStream *CPiAudioAE::FreeStream(IAEStream *stream)
{
+ // will retrigger the streamsilence timer
+ UpdateStreamSilence();
return NULL;
}
@@ -105,23 +134,73 @@ void CPiAudioAE::FreeSound(IAESound *sound)
{
}
-bool CPiAudioAE::SupportsRaw()
+bool CPiAudioAE::SupportsRaw(AEDataFormat format)
{
- return true;
+ bool supported = false;
+#if defined(TARGET_RASPBERRY_PI)
+ if (CSettings::Get().GetString("audiooutput.audiodevice") == "HDMI")
+ {
+ if (!CSettings::Get().GetBool("audiooutput.dualaudio"))
+ {
+ DllBcmHost m_DllBcmHost;
+ m_DllBcmHost.Load();
+ if (format == AE_FMT_AC3 && CSettings::Get().GetBool("audiooutput.ac3passthrough") &&
+ m_DllBcmHost.vc_tv_hdmi_audio_supported(EDID_AudioFormat_eAC3, 2, EDID_AudioSampleRate_e44KHz, EDID_AudioSampleSize_16bit ) == 0)
+ supported = true;
+ if (format == AE_FMT_DTS && CSettings::Get().GetBool("audiooutput.dtspassthrough") &&
+ m_DllBcmHost.vc_tv_hdmi_audio_supported(EDID_AudioFormat_eDTS, 2, EDID_AudioSampleRate_e44KHz, EDID_AudioSampleSize_16bit ) == 0)
+ supported = true;
+ m_DllBcmHost.Unload();
+ }
+ }
+#endif
+ return supported;
}
-bool CPiAudioAE::SupportsDrain()
+bool CPiAudioAE::SupportsSilenceTimeout()
{
return true;
}
void CPiAudioAE::OnSettingsChange(const std::string& setting)
{
- if (setting == "audiooutput.streamsilence")
+ if (setting == "audiooutput.streamsilence" || setting == "audiooutput.audiodevice")
UpdateStreamSilence();
}
void CPiAudioAE::EnumerateOutputDevices(AEDeviceList &devices, bool passthrough)
{
+ if (!passthrough)
+ {
+ devices.push_back(AEDevice("Analogue", "Analogue"));
+ devices.push_back(AEDevice("HDMI", "HDMI"));
+ }
+}
+
+std::string CPiAudioAE::GetDefaultDevice(bool passthrough)
+{
+ return "HDMI";
}
+bool CPiAudioAE::IsSettingVisible(const std::string &settingId)
+{
+ if (settingId == "audiooutput.samplerate")
+ return true;
+
+ if (CSettings::Get().GetString("audiooutput.audiodevice") == "HDMI")
+ {
+ if (settingId == "audiooutput.passthrough")
+ return true;
+ if (settingId == "audiooutput.dtspassthrough")
+ return true;
+ if (settingId == "audiooutput.ac3passthrough")
+ return true;
+ if (settingId == "audiooutput.channels")
+ return true;
+ if (settingId == "audiooutput.dualaudio")
+ return true;
+ if (settingId == "audiooutput.streamsilence")
+ return true;
+ }
+ return false;
+}
diff --git a/xbmc/cores/AudioEngine/Engines/PiAudio/PiAudioAE.h b/xbmc/cores/AudioEngine/Engines/PiAudio/PiAudioAE.h
index 419241b9c1..944fba89d5 100644
--- a/xbmc/cores/AudioEngine/Engines/PiAudio/PiAudioAE.h
+++ b/xbmc/cores/AudioEngine/Engines/PiAudio/PiAudioAE.h
@@ -29,13 +29,14 @@
namespace PiAudioAE
{
-class CPiAudioAE : public IAE
+class CPiAudioAE : public IAE, public CThread
{
protected:
friend class ::CAEFactory;
CPiAudioAE();
virtual ~CPiAudioAE();
virtual bool Initialize();
+ virtual void Process();
public:
virtual bool Suspend();
@@ -58,17 +59,22 @@ public:
virtual void GarbageCollect() {};
virtual void EnumerateOutputDevices(AEDeviceList &devices, bool passthrough);
+ virtual std::string GetDefaultDevice(bool passthrough);
+ virtual bool IsSettingVisible(const std::string &settingId);
- virtual bool SupportsRaw();
- virtual bool SupportsDrain();
+ virtual bool SupportsRaw(AEDataFormat format);
+ virtual bool SupportsSilenceTimeout();
virtual void OnLostDevice() {}
virtual void OnResetDevice() {}
protected:
void UpdateStreamSilence();
+ void UpdateStreamSilence(bool enable);
// polled via the interface
float m_aeVolume;
bool m_aeMuted;
+ int m_extSilenceTimeout;
+ XbmcThreads::EndTime m_extSilenceTimer;
};
};
diff --git a/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAE.cpp b/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAE.cpp
deleted file mode 100644
index 555ba2d345..0000000000
--- a/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAE.cpp
+++ /dev/null
@@ -1,1548 +0,0 @@
-/*
- * 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
- * <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <string.h>
-#include <sstream>
-#include <iterator>
-
-#include "system.h"
-#include "utils/log.h"
-#include "utils/TimeUtils.h"
-#include "utils/MathUtils.h"
-#include "utils/EndianSwap.h"
-#include "threads/SingleLock.h"
-#include "settings/AdvancedSettings.h"
-#include "settings/Settings.h"
-
-#include "SoftAE.h"
-#include "SoftAESound.h"
-#include "SoftAEStream.h"
-#include "AESinkFactory.h"
-#include "Interfaces/AESink.h"
-#include "Utils/AEUtil.h"
-#include "Encoders/AEEncoderFFmpeg.h"
-
-using namespace std;
-
-/* Define idle wait time based on platform in milliseconds */
-/* Higher wait times reduce thread CPU overhead when in */
-/* idle or Suspend() modes */
-#if defined (TARGET_WINDOWS) || defined (TARGET_LINUX) || \
- defined (TARGET_DARWIN_OSX) || defined (TARGET_FREEBSD)
-#define SOFTAE_IDLE_WAIT_MSEC 50 // shorter sleep for HTPC's
-#elif defined (TARGET_RASPBERRY_PI) || defined (TARGET_ANDROID)
-#define SOFTAE_IDLE_WAIT_MSEC 100 // longer for R_PI and Android
-#else
-#define SOFTAE_IDLE_WAIT_MSEC 100 // catchall for undefined platforms
-#endif
-
-CSoftAE::CSoftAE():
- m_thread (NULL ),
- m_audiophile (true ),
- m_running (false ),
- m_reOpen (false ),
- m_sinkIsSuspended (false ),
- m_isSuspended (false ),
- m_softSuspend (false ),
- m_softSuspendTimeout (XbmcThreads::EndTime::InfiniteValue),
- m_volume (1.0 ),
- m_sink (NULL ),
- m_sinkBlockTime (0 ),
- m_transcode (false ),
- m_rawPassthrough (false ),
- m_soundMode (AE_SOUND_OFF),
- m_streamsPlaying (false ),
- m_encoder (NULL ),
- m_converted (NULL ),
- m_convertedSize (0 ),
- m_masterStream (NULL ),
- m_outputStageFn (NULL ),
- m_streamStageFn (NULL )
-{
- unsigned int c_retry = 5;
- 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();
-}
-
-CSoftAE::~CSoftAE()
-{
- Deinitialize();
-
- /* free the streams */
- CSingleLock streamLock(m_streamLock);
- while (!m_streams.empty())
- {
- CSoftAEStream *s = m_streams.front();
- delete s;
- }
-
- /* free the sounds */
- CSingleLock soundLock(m_soundLock);
- while (!m_sounds.empty())
- {
- CSoftAESound *s = m_sounds.front();
- m_sounds.pop_front();
- delete s;
- }
-}
-
-IAESink *CSoftAE::GetSink(AEAudioFormat &newFormat, bool passthrough, std::string &device)
-{
- device = passthrough ? m_passthroughDevice : m_device;
-
- /* if we are raw, force the sample rate */
- if (AE_IS_RAW(newFormat.m_dataFormat))
- {
- switch (newFormat.m_dataFormat)
- {
- case AE_FMT_AC3:
- case AE_FMT_DTS:
- break;
-
- case AE_FMT_EAC3:
- newFormat.m_sampleRate = 192000;
- break;
-
- case AE_FMT_TRUEHD:
- case AE_FMT_DTSHD:
- newFormat.m_sampleRate = 192000;
- break;
-
- default:
- break;
- }
- }
-
- IAESink *sink = CAESinkFactory::Create(device, newFormat, passthrough);
- return sink;
-}
-
-/* this method MUST be called while holding m_streamLock */
-inline CSoftAEStream *CSoftAE::GetMasterStream()
-{
- /* remove any destroyed streams first */
- for (StreamList::iterator itt = m_streams.begin(); itt != m_streams.end();)
- {
- CSoftAEStream *stream = *itt;
- if (stream->IsDestroyed())
- {
- RemoveStream(m_playingStreams, stream);
- RemoveStream(m_streams , stream);
- delete stream;
- continue;
- }
- ++itt;
- }
-
- if (!m_newStreams.empty())
- return m_newStreams.back();
-
- if (!m_streams.empty())
- return m_streams.back();
-
- return NULL;
-}
-
-/* save method to call outside of the main thread, use this one */
-void CSoftAE::OpenSink()
-{
- m_reOpenEvent.Reset();
- m_reOpen = true;
- m_reOpenEvent.Wait();
- m_wake.Set();
-}
-
-void CSoftAE::InternalCloseSink()
-{
- /* close the old sink if it was open */
- if (m_sink)
- {
- CExclusiveLock sinkLock(m_sinkLock);
- m_sink->Drain();
- m_sink->Deinitialize();
- delete m_sink;
- m_sink = NULL;
- }
-}
-/* this must NEVER be called from outside the main thread or Initialization */
-void CSoftAE::InternalOpenSink()
-{
- /* save off our raw/passthrough mode for checking */
- bool wasTranscode = m_transcode;
- bool wasRawPassthrough = m_rawPassthrough;
- bool reInit = false;
-
- LoadSettings();
-
- /* initialize for analog output */
- m_rawPassthrough = false;
- m_streamStageFn = &CSoftAE::RunStreamStage;
- m_outputStageFn = &CSoftAE::RunOutputStage;
-
- /* initialize the new format for basic 2.0 output */
- AEAudioFormat newFormat;
- newFormat.m_dataFormat = AE_FMT_FLOAT;
- newFormat.m_sampleRate = 44100;
- newFormat.m_encodedRate = 0;
- newFormat.m_channelLayout = m_stereoUpmix ? m_stdChLayout : AE_CH_LAYOUT_2_0;
- newFormat.m_frames = 0;
- newFormat.m_frameSamples = 0;
- newFormat.m_frameSize = 0;
-
- CSingleLock streamLock(m_streamLock);
-
- m_masterStream = GetMasterStream();
- if (m_masterStream)
- {
- /* choose the sample rate & channel layout based on the master stream */
- newFormat.m_sampleRate = m_masterStream->GetSampleRate();
- if (!m_stereoUpmix)
- newFormat.m_channelLayout = m_masterStream->m_initChannelLayout;
-
- if (m_masterStream->IsRaw())
- {
- newFormat.m_sampleRate = m_masterStream->GetSampleRate();
- newFormat.m_encodedRate = m_masterStream->GetEncodedSampleRate();
- newFormat.m_dataFormat = m_masterStream->GetDataFormat();
- newFormat.m_channelLayout = m_masterStream->m_initChannelLayout;
- m_rawPassthrough = true;
- m_streamStageFn = &CSoftAE::RunRawStreamStage;
- m_outputStageFn = &CSoftAE::RunRawOutputStage;
- }
- else
- {
- if (!m_transcode)
- newFormat.m_channelLayout.ResolveChannels(m_stdChLayout);
- else
- {
- if (m_masterStream->m_initChannelLayout == AE_CH_LAYOUT_2_0)
- m_transcode = false;
- m_encoderInitSampleRateMul = 1.0 / newFormat.m_sampleRate;
- }
- }
-
- /* if the stream is paused we cant use it for anything else */
- if (m_masterStream->m_paused)
- m_masterStream = NULL;
- }
- else
- m_transcode = false;
-
- if (!m_rawPassthrough && m_transcode)
- newFormat.m_dataFormat = AE_FMT_AC3;
-
- streamLock.Leave();
-
- std::string device, driver;
- if (m_transcode || m_rawPassthrough)
- device = m_passthroughDevice;
- else
- device = m_device;
-
- CAESinkFactory::ParseDevice(device, driver);
- if (driver.empty() && m_sink)
- driver = m_sink->GetName();
-
- if (m_rawPassthrough)
- CLog::Log(LOGINFO, "CSoftAE::InternalOpenSink - RAW passthrough enabled");
- else if (m_transcode)
- CLog::Log(LOGINFO, "CSoftAE::InternalOpenSink - Transcode passthrough enabled");
-
- /*
- try to use 48000hz if we are going to transcode, this prevents the sink
- from being re-opened repeatedly when switching sources, which locks up
- some receivers & crappy integrated sound drivers. Check for as.xml override
- */
- if (m_transcode && !m_rawPassthrough)
- {
- enum AEChannel ac3Layout[3] = {AE_CH_RAW, AE_CH_RAW, AE_CH_NULL};
- newFormat.m_channelLayout = ac3Layout;
- m_outputStageFn = &CSoftAE::RunTranscodeStage;
- if (!g_advancedSettings.m_allowTranscode44100)
- newFormat.m_sampleRate = 48000;
- }
-
- /*
- if there is an audio resample rate set, use it, this MAY NOT be honoured as
- the audio sink may not support the requested format, and may change it.
- */
- if (g_advancedSettings.m_audioResample)
- {
- newFormat.m_sampleRate = g_advancedSettings.m_audioResample;
- CLog::Log(LOGINFO, "CSoftAE::InternalOpenSink - Forcing samplerate to %d", newFormat.m_sampleRate);
- }
-
- /* only re-open the sink if its not compatible with what we need */
- 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(newFormat, device))
- {
- CLog::Log(LOGINFO, "CSoftAE::InternalOpenSink - sink incompatible, re-starting");
-
- /* take the sink lock */
- CExclusiveLock sinkLock(m_sinkLock);
-
- reInit = true;
- //close the sink cause it gets reinited
- InternalCloseSink();
-
- /* 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;
-
- /* create the new sink */
- m_sink = GetSink(newFormat, m_transcode || m_rawPassthrough, device);
-
- /* perform basic sanity checks on the format returned by the sink */
- ASSERT(newFormat.m_channelLayout.Count() > 0);
- ASSERT(newFormat.m_dataFormat <= AE_FMT_FLOAT);
- ASSERT(newFormat.m_frames > 0);
- ASSERT(newFormat.m_frameSamples > 0);
- ASSERT(newFormat.m_frameSize == (CAEUtil::DataFormatToBits(newFormat.m_dataFormat) >> 3) * newFormat.m_channelLayout.Count());
- ASSERT(newFormat.m_sampleRate > 0);
-
- CLog::Log(LOGDEBUG, "CSoftAE::InternalOpenSink - %s Initialized:", m_sink->GetName());
- CLog::Log(LOGDEBUG, " Output Device : %s", m_deviceFriendlyName.c_str());
- CLog::Log(LOGDEBUG, " Sample Rate : %d", newFormat.m_sampleRate);
- CLog::Log(LOGDEBUG, " Sample Format : %s", CAEUtil::DataFormatToStr(newFormat.m_dataFormat));
- CLog::Log(LOGDEBUG, " Channel Count : %d", newFormat.m_channelLayout.Count());
- CLog::Log(LOGDEBUG, " Channel Layout: %s", ((std::string)newFormat.m_channelLayout).c_str());
- CLog::Log(LOGDEBUG, " Frames : %d", newFormat.m_frames);
- CLog::Log(LOGDEBUG, " Frame Samples : %d", newFormat.m_frameSamples);
- CLog::Log(LOGDEBUG, " Frame Size : %d", newFormat.m_frameSize);
-
- m_sinkFormat = newFormat;
- m_sinkFormatSampleRateMul = 1.0 / (double)newFormat.m_sampleRate;
- m_sinkBlockSize = newFormat.m_frames * newFormat.m_frameSize;
- m_sinkBlockTime = 1000 * newFormat.m_frames / newFormat.m_sampleRate;
- // check if sink controls volume, if so, init the volume.
- m_sinkHandlesVolume = m_sink->HasVolume();
- if (m_sinkHandlesVolume)
- m_sink->SetVolume(m_volume);
-
- /* invalidate the buffer */
- m_buffer.Empty();
- }
- else
- CLog::Log(LOGINFO, "CSoftAE::InternalOpenSink - keeping old sink with : %s, %s, %dhz",
- CAEUtil::DataFormatToStr(newFormat.m_dataFormat),
- ((std::string)newFormat.m_channelLayout).c_str(),
- newFormat.m_sampleRate);
-
- reInit = (reInit || m_chLayout != m_sinkFormat.m_channelLayout);
- m_chLayout = m_sinkFormat.m_channelLayout;
-
- size_t neededBufferSize = 0;
- if (m_rawPassthrough)
- {
- if (!wasRawPassthrough)
- m_buffer.Empty();
-
- m_convertFn = NULL;
- m_bytesPerSample = CAEUtil::DataFormatToBits(m_sinkFormat.m_dataFormat) >> 3;
- m_frameSize = m_sinkFormat.m_frameSize;
- m_frameSizeMul = 1.0 / (double)m_frameSize;
- neededBufferSize = m_sinkFormat.m_frames * m_sinkFormat.m_frameSize;
- }
- else
- {
- /* if we are transcoding */
- if (m_transcode)
- {
- if (!wasTranscode || wasRawPassthrough)
- {
- /* invalidate the buffer */
- m_buffer.Empty();
- if (m_encoder)
- m_encoder->Reset();
- }
-
- /* configure the encoder */
- AEAudioFormat encoderFormat;
- encoderFormat.m_dataFormat = AE_FMT_FLOAT;
- encoderFormat.m_sampleRate = m_sinkFormat.m_sampleRate;
- encoderFormat.m_encodedRate = 0;
- encoderFormat.m_channelLayout = m_chLayout;
- encoderFormat.m_frames = 0;
- encoderFormat.m_frameSamples = 0;
- encoderFormat.m_frameSize = 0;
-
- if (!m_encoder || !m_encoder->IsCompatible(encoderFormat))
- {
- m_buffer.Empty();
- SetupEncoder(encoderFormat);
- m_encoderFormat = encoderFormat;
- if (encoderFormat.m_frameSize > 0)
- m_encoderFrameSizeMul = 1.0 / (double)m_sinkFormat.m_frameSize;
- else
- m_encoderFrameSizeMul = 1.0;
- }
-
- /* remap directly to the format we need for encode */
- reInit = (reInit || m_chLayout != m_encoderFormat.m_channelLayout);
- m_chLayout = m_encoderFormat.m_channelLayout;
- m_convertFn = CAEConvert::FrFloat(m_encoderFormat.m_dataFormat);
- neededBufferSize = m_encoderFormat.m_frames * sizeof(float) * m_chLayout.Count();
- CLog::Log(LOGDEBUG, "CSoftAE::InternalOpenSink - Encoding using layout: %s", ((std::string)m_chLayout).c_str());
- }
- else
- {
- m_convertFn = CAEConvert::FrFloat(m_sinkFormat.m_dataFormat);
- neededBufferSize = m_sinkFormat.m_frames * sizeof(float) * m_chLayout.Count();
- CLog::Log(LOGDEBUG, "CSoftAE::InternalOpenSink - Using speaker layout: %s", CAEUtil::GetStdChLayoutName(m_stdChLayout));
- }
-
- m_bytesPerSample = CAEUtil::DataFormatToBits(AE_FMT_FLOAT) >> 3;
- m_frameSize = m_bytesPerSample * m_chLayout.Count();
- m_frameSizeMul = 1.0 / (double)m_frameSize;
- }
-
- CLog::Log(LOGDEBUG, "CSoftAE::InternalOpenSink - Internal Buffer Size: %d", (int)neededBufferSize);
- if (m_buffer.Size() < neededBufferSize)
- m_buffer.Alloc(neededBufferSize);
-
- if (reInit)
- {
- if (!m_rawPassthrough)
- {
- /* re-init incompatible sounds */
- CSingleLock soundLock(m_soundLock);
- for (SoundList::iterator itt = m_sounds.begin(); itt != m_sounds.end(); ++itt)
- {
- CSoftAESound *sound = *itt;
- if (!sound->IsCompatible())
- {
- StopSound(sound);
- sound->Initialize();
- }
- }
- }
-
- /* re-init streams */
- streamLock.Enter();
- for (StreamList::iterator itt = m_streams.begin(); itt != m_streams.end(); ++itt)
- (*itt)->Initialize();
- streamLock.Leave();
- }
-
- /* any new streams need to be initialized */
- for (StreamList::iterator itt = m_newStreams.begin(); itt != m_newStreams.end(); ++itt)
- {
- (*itt)->Initialize();
- m_streams.push_back(*itt);
- if (!(*itt)->m_paused)
- m_playingStreams.push_back(*itt);
- }
- m_newStreams.clear();
- m_streamsPlaying = !m_playingStreams.empty();
-
- m_softSuspend = false;
-
- /* notify any event listeners that we are done */
- m_reOpen = false;
- m_reOpenEvent.Set();
- m_wake.Set();
-}
-
-void CSoftAE::ResetEncoder()
-{
- if (m_encoder)
- m_encoder->Reset();
- m_encodedBuffer.Empty();
-}
-
-bool CSoftAE::SetupEncoder(AEAudioFormat &format)
-{
- ResetEncoder();
- delete m_encoder;
- m_encoder = NULL;
-
- if (!m_transcode)
- return false;
-
- m_encoder = new CAEEncoderFFmpeg();
- if (m_encoder->Initialize(format))
- return true;
-
- delete m_encoder;
- m_encoder = NULL;
- return false;
-}
-
-void CSoftAE::Shutdown()
-{
- Deinitialize();
-}
-
-bool CSoftAE::Initialize()
-{
- CSingleLock lock(m_threadLock);
- InternalOpenSink();
- m_running = true;
- m_thread = new CThread(this, "SoftAE");
- m_thread->Create();
- m_thread->SetPriority(THREAD_PRIORITY_ABOVE_NORMAL);
- return true;
-}
-
-void CSoftAE::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")
- {
- OpenSink();
- }
-
- if (setting == "audiooutput.normalizelevels" || setting == "audiooutput.stereoupmix")
- {
- /* re-init stream reamppers */
- CSingleLock streamLock(m_streamLock);
- for (StreamList::iterator itt = m_streams.begin(); itt != m_streams.end(); ++itt)
- (*itt)->InitializeRemap();
- }
-}
-
-void CSoftAE::LoadSettings()
-{
- m_audiophile = g_advancedSettings.m_audioAudiophile;
- if (m_audiophile)
- CLog::Log(LOGINFO, "CSoftAE::LoadSettings - Audiophile switch enabled");
-
- m_stereoUpmix = CSettings::Get().GetBool("audiooutput.stereoupmix");
- if (m_stereoUpmix)
- CLog::Log(LOGINFO, "CSoftAE::LoadSettings - Stereo upmix is enabled");
-
- /* load the configuration */
- m_stdChLayout = AE_CH_LAYOUT_2_0;
- switch (CSettings::Get().GetInt("audiooutput.channels"))
- {
- default:
- case 0: m_stdChLayout = AE_CH_LAYOUT_2_0; break; /* dont alow 1_0 output */
- case 1: m_stdChLayout = AE_CH_LAYOUT_2_0; break;
- case 2: m_stdChLayout = AE_CH_LAYOUT_2_1; break;
- case 3: m_stdChLayout = AE_CH_LAYOUT_3_0; break;
- case 4: m_stdChLayout = AE_CH_LAYOUT_3_1; break;
- case 5: m_stdChLayout = AE_CH_LAYOUT_4_0; break;
- case 6: m_stdChLayout = AE_CH_LAYOUT_4_1; break;
- case 7: m_stdChLayout = AE_CH_LAYOUT_5_0; break;
- case 8: m_stdChLayout = AE_CH_LAYOUT_5_1; break;
- case 9: m_stdChLayout = AE_CH_LAYOUT_7_0; break;
- case 10: m_stdChLayout = AE_CH_LAYOUT_7_1; break;
- }
-
- // force optical/coax to 2.0 output channels
- if (!m_rawPassthrough && CSettings::Get().GetInt("audiooutput.mode") == AUDIO_IEC958)
- m_stdChLayout = AE_CH_LAYOUT_2_0;
-
- /* get the output devices and ensure they exist */
- m_device = CSettings::Get().GetString("audiooutput.audiodevice");
- m_passthroughDevice = CSettings::Get().GetString("audiooutput.passthroughdevice");
- VerifySoundDevice(m_device , false);
- VerifySoundDevice(m_passthroughDevice, true );
-
- m_transcode = (
- CSettings::Get().GetBool("audiooutput.ac3passthrough") /*||
- CSettings::Get().GetBool("audiooutput.dtspassthrough") */
- ) && (
- (CSettings::Get().GetInt("audiooutput.mode") == AUDIO_IEC958) ||
- (CSettings::Get().GetInt("audiooutput.mode") == AUDIO_HDMI && !CSettings::Get().GetBool("audiooutput.multichannellpcm"))
- );
-}
-
-void CSoftAE::VerifySoundDevice(std::string& device, bool passthrough)
-{
- /* check that the specified device exists */
- std::string firstDevice;
- 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 deviceName = sinkInfo.m_sinkName + ":" + devInfo.m_deviceName;
-
- /* remember the first device so we can default to it if required */
- if (firstDevice.empty())
- firstDevice = deviceName;
-
- if (device == deviceName)
- return;
- }
- }
-
- /* if the device wasnt found, set it to the first viable output */
- device = firstDevice;
-}
-
-inline void CSoftAE::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 CSoftAE::Deinitialize()
-{
- CSingleLock lock(m_threadLock);
- if (m_thread)
- {
- Stop();
- m_thread->StopThread(true);
- delete m_thread;
- m_thread = NULL;
- }
- lock.Leave();
-
- CExclusiveLock sinkLock(m_sinkLock);
- if (m_sink)
- {
- /* shutdown the sink */
- m_sink->Deinitialize();
- delete m_sink;
- m_sink = NULL;
- }
-
- delete m_encoder;
- m_encoder = NULL;
- ResetEncoder();
- m_buffer.DeAlloc();
-
- _aligned_free(m_converted);
- m_converted = NULL;
- m_convertedSize = 0;
-
- m_sinkInfoList.clear();
-}
-
-void CSoftAE::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 CSoftAE::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";
-}
-
-bool CSoftAE::SupportsRaw()
-{
- /* CSoftAE supports raw formats */
- return true;
-}
-
-void CSoftAE::PauseStream(CSoftAEStream *stream)
-{
- CSingleLock streamLock(m_streamLock);
- RemoveStream(m_playingStreams, stream);
- stream->m_paused = true;
-
- m_reOpen = true;
- m_wake.Set();
-}
-
-void CSoftAE::ResumeStream(CSoftAEStream *stream)
-{
- CSingleLock streamLock(m_streamLock);
- m_playingStreams.push_back(stream);
- stream->m_paused = false;
- streamLock.Leave();
-
- m_streamsPlaying = true;
- m_reOpen = true;
- m_wake.Set();
-}
-
-void CSoftAE::Stop()
-{
- m_running = false;
- m_isSuspended = false;
- m_wake.Set();
-
- /* wait for the thread to stop */
- CSingleLock lock(m_runningLock);
-}
-
-void CSoftAE::SetSoundMode(const int mode)
-{
- m_soundMode = mode;
-
- /* stop all currently playing sounds if they are being turned off */
- if (mode == AE_SOUND_OFF || (mode == AE_SOUND_IDLE && m_streamsPlaying))
- StopAllSounds();
-}
-
-IAEStream *CSoftAE::MakeStream(enum AEDataFormat dataFormat, unsigned int sampleRate, unsigned int encodedSampleRate, CAEChannelInfo channelLayout, unsigned int options/* = 0 */)
-{
- CAEChannelInfo channelInfo(channelLayout);
- CLog::Log(LOGINFO, "CSoftAE::MakeStream - %s, %u, %s",
- CAEUtil::DataFormatToStr(dataFormat),
- sampleRate, ((std::string)channelInfo).c_str());
-
- /* ensure we have the encoded sample rate if the format is RAW */
- if (AE_IS_RAW(dataFormat))
- ASSERT(encodedSampleRate);
-
- CSingleLock streamLock(m_streamLock);
- CSoftAEStream *stream = new CSoftAEStream(dataFormat, sampleRate, encodedSampleRate, channelLayout, options, m_streamLock);
- m_newStreams.push_back(stream);
- streamLock.Leave();
- // this is really needed here
- OpenSink();
- return stream;
-}
-
-IAESound *CSoftAE::MakeSound(const std::string& file)
-{
- CSingleLock soundLock(m_soundLock);
-
- CSoftAESound *sound = new CSoftAESound(file);
- if (!sound->Initialize())
- {
- delete sound;
- return NULL;
- }
-
- m_sounds.push_back(sound);
- return sound;
-}
-
-void CSoftAE::PlaySound(IAESound *sound)
-{
- if (m_soundMode == AE_SOUND_OFF || (m_soundMode == AE_SOUND_IDLE && m_streamsPlaying))
- return;
-
- float *samples = ((CSoftAESound*)sound)->GetSamples();
- if (!samples)
- return;
-
- /* add the sound to the play list */
- CSingleLock soundSampleLock(m_soundSampleLock);
- SoundState ss = {
- ((CSoftAESound*)sound),
- samples,
- ((CSoftAESound*)sound)->GetSampleCount()
- };
- m_playing_sounds.push_back(ss);
-
- /* wake to play the sound */
- m_softSuspend = false;
- m_wake.Set();
-}
-
-void CSoftAE::FreeSound(IAESound *sound)
-{
- if (!sound)
- return;
-
- sound->Stop();
- CSingleLock soundLock(m_soundLock);
- for (SoundList::iterator itt = m_sounds.begin(); itt != m_sounds.end(); ++itt)
- if (*itt == sound)
- {
- m_sounds.erase(itt);
- break;
- }
-
- delete (CSoftAESound*)sound;
-}
-
-void CSoftAE::GarbageCollect()
-{
-}
-
-unsigned int CSoftAE::GetSampleRate()
-{
- if (m_transcode && m_encoder && !m_rawPassthrough)
- return m_encoderFormat.m_sampleRate;
-
- return m_sinkFormat.m_sampleRate;
-}
-
-void CSoftAE::StopSound(IAESound *sound)
-{
- CSingleLock lock(m_soundSampleLock);
- for (SoundStateList::iterator itt = m_playing_sounds.begin(); itt != m_playing_sounds.end(); )
- {
- if ((*itt).owner == sound)
- {
- (*itt).owner->ReleaseSamples();
- itt = m_playing_sounds.erase(itt);
- }
- else
- ++itt;
- }
-}
-
-IAEStream *CSoftAE::FreeStream(IAEStream *stream)
-{
- CSingleLock lock(m_streamLock);
- RemoveStream(m_playingStreams, (CSoftAEStream*)stream);
- RemoveStream(m_streams , (CSoftAEStream*)stream);
- // Reopen is old behaviour. Not opening when masterstream stops means clipping on S/PDIF.
- if(!m_isSuspended && (m_masterStream == stream))
- {
- m_reOpen = true;
- m_masterStream = NULL;
- }
-
- delete (CSoftAEStream*)stream;
- return NULL;
-}
-
-double CSoftAE::GetDelay()
-{
- double delayBuffer = 0.0, delaySink = 0.0, delayTranscoder = 0.0;
-
- CSharedLock sinkLock(m_sinkLock);
- if (m_sink)
- delaySink = m_sink->GetDelay();
-
- if (m_transcode && m_encoder && !m_rawPassthrough)
- {
- delayBuffer = (double)m_buffer.Used() * m_frameSizeMul * m_encoderInitSampleRateMul;
- delayTranscoder = m_encoder->GetDelay((double)m_encodedBuffer.Used() * m_encoderFrameSizeMul);
- }
- else
- delayBuffer = (double)m_buffer.Used() * m_frameSizeMul *m_sinkFormatSampleRateMul;
-
- return delayBuffer + delaySink + delayTranscoder;
-}
-
-double CSoftAE::GetCacheTime()
-{
- double timeBuffer = 0.0, timeSink = 0.0, timeTranscoder = 0.0;
-
- CSharedLock sinkLock(m_sinkLock);
- if (m_sink)
- timeSink = m_sink->GetCacheTime();
-
- if (m_transcode && m_encoder && !m_rawPassthrough)
- {
- timeBuffer = (double)m_buffer.Used() * m_frameSizeMul * m_encoderInitSampleRateMul;
- timeTranscoder = m_encoder->GetDelay((double)m_encodedBuffer.Used() * m_encoderFrameSizeMul);
- }
- else
- timeBuffer = (double)m_buffer.Used() * m_frameSizeMul *m_sinkFormatSampleRateMul;
-
- return timeBuffer + timeSink + timeTranscoder;
-}
-
-double CSoftAE::GetCacheTotal()
-{
- double timeBuffer = 0.0, timeSink = 0.0, timeTranscoder = 0.0;
-
- CSharedLock sinkLock(m_sinkLock);
- if (m_sink)
- timeSink = m_sink->GetCacheTotal();
-
- if (m_transcode && m_encoder && !m_rawPassthrough)
- {
- timeBuffer = (double)m_buffer.Size() * m_frameSizeMul * m_encoderInitSampleRateMul;
- timeTranscoder = m_encoder->GetDelay((double)m_encodedBuffer.Size() * m_encoderFrameSizeMul);
- }
- else
- timeBuffer = (double)m_buffer.Size() * m_frameSizeMul *m_sinkFormatSampleRateMul;
-
- return timeBuffer + timeSink + timeTranscoder;
-}
-
-bool CSoftAE::IsSuspended()
-{
- return m_isSuspended;
-}
-
-float CSoftAE::GetVolume()
-{
- return m_volume;
-}
-
-void CSoftAE::SetVolume(float volume)
-{
- m_volume = volume;
- if (!m_sinkHandlesVolume)
- return;
-
- CSharedLock sinkLock(m_sinkLock);
- if (m_sink)
- m_sink->SetVolume(m_volume);
-}
-
-void CSoftAE::StopAllSounds()
-{
- CSingleLock lock(m_soundSampleLock);
- while (!m_playing_sounds.empty())
- {
- SoundState *ss = &(*m_playing_sounds.begin());
- ss->owner->ReleaseSamples();
- m_playing_sounds.pop_front();
- }
-}
-
-bool CSoftAE::Suspend()
-{
- CLog::Log(LOGDEBUG, "CSoftAE::Suspend - Suspending AE processing");
- m_isSuspended = true;
-
- StopAllSounds();
-
- CSingleLock streamLock(m_streamLock);
- for (StreamList::iterator itt = m_playingStreams.begin(); itt != m_playingStreams.end(); ++itt)
- {
- CSoftAEStream *stream = *itt;
- stream->Flush();
- }
- streamLock.Leave();
- #if defined(TARGET_LINUX)
- /*workaround sinks not playing sound after resume */
- bool ret = true;
- if(m_sink)
- {
- /* Deinitialize and delete current m_sink */
- // we don't want that Run reopens our device, so we wait.
- m_saveSuspend.Reset();
- // wait until we are looping in ProcessSuspend()
- // this is more save to not come up unclean
- // we cannot wait forever
- ret = m_saveSuspend.WaitMSec(500);
- if(ret)
- {
- CLog::Log(LOGDEBUG, "CSoftAE::Suspend - After Event");
- CExclusiveLock sinkLock(m_sinkLock);
- // remove all the sinks
- for (AESinkInfoList::iterator itt = m_sinkInfoList.begin(); itt != m_sinkInfoList.end(); ++itt)
- {
- itt->m_deviceInfoList.pop_back();
- }
- InternalCloseSink();
- }
- else
- {
- CLog::Log(LOGDEBUG, "CSoftAE::Suspend - Unload failed will continue");
- m_saveSuspend.Reset();
- }
- }
- // The device list is now empty and must be reenumerated afterwards.
- if(ret)
- m_sinkInfoList.clear();
-
- // signal anybody, that we are gone now (beware of deadlocks)
- // we don't unset the fields here, to care for reinit after resume
- if(m_reOpen)
- m_reOpenEvent.Set();
- #endif
-
- return true;
-}
-
-bool CSoftAE::Resume()
-{
-#if defined(TARGET_LINUX)
- // We must make sure, that we don't return empty.
- if(m_sinkInfoList.empty())
- {
- CLog::Log(LOGDEBUG, "CSoftAE::Resume - Re Enumerating Sinks");
- CExclusiveLock sinkLock(m_sinkLock);
- // Forced enumeration - we are sure that we start completely fresh.
- CAESinkFactory::EnumerateEx(m_sinkInfoList, true);
- sinkLock.Leave(); // we leave here explicitly to not lock while printing new sinks
- PrintSinks();
- }
-#endif
- CLog::Log(LOGDEBUG, "CSoftAE::Resume - Resuming AE processing");
- m_isSuspended = false;
- // we flag reopen
- m_reOpen = true;
-
- return true;
-}
-
-void CSoftAE::Run()
-{
- /* we release this when we exit the thread unblocking anyone waiting on "Stop" */
- CSingleLock runningLock(m_runningLock);
- CLog::Log(LOGINFO, "CSoftAE::Run - Thread Started");
-
- bool hasAudio = false;
- while (m_running)
- {
- bool restart = false;
-
- /* with the new non blocking implementation - we just reOpen here, when it tells reOpen */
- if ((this->*m_outputStageFn)(hasAudio) > 0)
- hasAudio = false; /* taken some audio - reset our silence flag */
-
- /* if we have enough room in the buffer */
- if (m_buffer.Free() >= m_frameSize)
- {
- /* take some data for our use from the buffer */
- uint8_t *out = (uint8_t*)m_buffer.Take(m_frameSize);
- memset(out, 0, m_frameSize);
-
- /* run the stream stage */
- CSoftAEStream *oldMaster = m_masterStream;
- if ((this->*m_streamStageFn)(m_chLayout.Count(), out, restart) > 0)
- hasAudio = true; /* have some audio */
-
- /* if in audiophile mode and the master stream has changed, flag for restart */
- if (m_audiophile && oldMaster != m_masterStream)
- restart = true;
- }
-
- /* Handle idle or forced suspend */
- ProcessSuspend();
-
- /* if we are told to restart */
- if (m_reOpen || restart || !m_sink)
- {
- if(m_sinkIsSuspended && m_sink)
- {
- // hint for fritsch: remember lazy evaluation
- m_reOpen = !m_sink->SoftResume() || m_reOpen;
- m_sinkIsSuspended = false;
- CLog::Log(LOGDEBUG, "CSoftAE::Run - Sink was forgotten");
- }
- CLog::Log(LOGDEBUG, "CSoftAE::Run - Sink restart flagged");
- InternalOpenSink();
- }
-
-#if defined(TARGET_ANDROID)
- else if (m_playingStreams.empty()
- && m_playing_sounds.empty()
- && !g_advancedSettings.m_streamSilence)
- {
- // if we have nothing to do, take a dirt nap.
- // we do not have to take a lock just to check empty.
- // this keeps AE from sucking CPU if nothing is going on.
- m_wake.WaitMSec(SOFTAE_IDLE_WAIT_MSEC);
- }
-#endif
- }
-}
-
-void CSoftAE::AllocateConvIfNeeded(size_t convertedSize, bool prezero)
-{
- if (m_convertedSize < convertedSize)
- {
- _aligned_free(m_converted);
- m_converted = (uint8_t *)_aligned_malloc(convertedSize, 16);
- m_convertedSize = convertedSize;
- }
- if (prezero)
- memset(m_converted, 0x00, convertedSize);
-}
-
-unsigned int CSoftAE::MixSounds(float *buffer, unsigned int samples)
-{
- // no point doing anything if we have no sounds,
- // we do not have to take a lock just to check empty
- if (m_playing_sounds.empty())
- return 0;
-
- SoundStateList::iterator itt;
- unsigned int mixed = 0;
- CSingleLock lock(m_soundSampleLock);
- for (itt = m_playing_sounds.begin(); itt != m_playing_sounds.end(); )
- {
- SoundState *ss = &(*itt);
- float *out = buffer;
-
- /* no more frames, so remove it from the list */
- if (ss->sampleCount == 0)
- {
- ss->owner->ReleaseSamples();
- itt = m_playing_sounds.erase(itt);
- continue;
- }
-
- float volume = ss->owner->GetVolume();
- unsigned int mixSamples = std::min(ss->sampleCount, samples);
- #ifdef __SSE__
- CAEUtil::SSEMulAddArray(out, ss->samples, volume, mixSamples);
- #else
- float *sample_buffer = ss->samples;
- for (unsigned int i = 0; i < mixSamples; ++i)
- *out++ += *sample_buffer++ * volume;
- #endif
-
- ss->sampleCount -= mixSamples;
- ss->samples += mixSamples;
-
- ++itt;
- ++mixed;
- }
- return mixed;
-}
-
-bool CSoftAE::FinalizeSamples(float *buffer, unsigned int samples, bool hasAudio)
-{
- if (m_soundMode != AE_SOUND_OFF)
- hasAudio |= (MixSounds(buffer, samples) > 0);
-
- /* no need to process if we don't have audio (buffer is memset to 0) */
- if (!hasAudio)
- return false;
-
- if (m_muted)
- {
- memset(buffer, 0, samples * sizeof(float));
- return false;
- }
-
- /* deamplify */
- if (!m_sinkHandlesVolume && m_volume < 1.0)
- {
- #ifdef __SSE__
- CAEUtil::SSEMulArray(buffer, m_volume, samples);
- #else
- float *fbuffer = buffer;
- for (unsigned int i = 0; i < samples; i++)
- *fbuffer++ *= m_volume;
- #endif
- }
-
- /* check if we need to clamp */
- bool clamp = false;
- float *fbuffer = buffer;
- for (unsigned int i = 0; i < samples; i++, fbuffer++)
- {
- if (*fbuffer < -1.0f || *fbuffer > 1.0f)
- {
- clamp = true;
- break;
- }
- }
-
- /* if there were no samples outside of the range, dont clamp the buffer */
- if (!clamp)
- return true;
-
- CLog::Log(LOGDEBUG, "CSoftAE::FinalizeSamples - Clamping buffer of %d samples", samples);
- CAEUtil::ClampArray(buffer, samples);
- return true;
-}
-
-unsigned int CSoftAE::WriteSink(CAEBuffer& src, unsigned int src_len, uint8_t *data, bool hasAudio)
-{
- CExclusiveLock lock(m_sinkLock); /* lock to maintain delay consistency */
-
- XbmcThreads::EndTime timeout(m_sinkBlockTime * 2);
- while(m_sink && src.Used() >= src_len)
- {
- int frames = m_sink->AddPackets(data, m_sinkFormat.m_frames, hasAudio);
-
- /* Return value of INT_MAX signals error in sink - restart */
- if (frames == INT_MAX)
- {
- CLog::Log(LOGERROR, "CSoftAE::WriteSink - sink error - reinit flagged");
- m_reOpen = true;
- break;
- }
-
- if (frames)
- {
- src.Shift(NULL, src_len);
- return frames;
- }
-
- if(timeout.IsTimePast())
- {
- CLog::Log(LOGERROR, "CSoftAE::WriteSink - sink blocked- reinit flagged");
- m_reOpen = true;
- break;
- }
-
- lock.Leave();
- Sleep(m_sinkBlockTime / 4);
- lock.Enter();
- }
- return 0;
-}
-
-int CSoftAE::RunOutputStage(bool hasAudio)
-{
- const unsigned int needSamples = m_sinkFormat.m_frames * m_sinkFormat.m_channelLayout.Count();
- const size_t needBytes = needSamples * sizeof(float);
- if (m_buffer.Used() < needBytes)
- return 0;
-
- void *data = m_buffer.Raw(needBytes);
- hasAudio = FinalizeSamples((float*)data, needSamples, hasAudio);
-
- if (m_convertFn)
- {
- const unsigned int convertedBytes = m_sinkFormat.m_frames * m_sinkFormat.m_frameSize;
- AllocateConvIfNeeded(convertedBytes, !hasAudio);
- if (hasAudio)
- m_convertFn((float*)data, needSamples, m_converted);
- data = m_converted;
- }
-
- return WriteSink(m_buffer, needBytes, (uint8_t*)data, hasAudio);
-}
-
-int CSoftAE::RunRawOutputStage(bool hasAudio)
-{
- if(m_buffer.Used() < m_sinkBlockSize)
- return 0;
-
- void *data = m_buffer.Raw(m_sinkBlockSize);
-
- if (CAEUtil::S16NeedsByteSwap(AE_FMT_S16NE, m_sinkFormat.m_dataFormat))
- {
- /*
- * It would really be preferable to handle this at packing stage, so that
- * it could byteswap the data efficiently without wasting CPU time on
- * swapping the huge IEC 61937 zero padding between frames (or not
- * byteswap at all, if there are two byteswaps).
- *
- * Unfortunately packing is done on a higher level and we can't easily
- * tell it the needed format from here, so do it here for now (better than
- * nothing)...
- */
- AllocateConvIfNeeded(m_sinkBlockSize, !hasAudio);
- if (hasAudio)
- Endian_Swap16_buf((uint16_t *)m_converted, (uint16_t *)data, m_sinkBlockSize / 2);
- data = m_converted;
- }
-
- return WriteSink(m_buffer, m_sinkBlockSize, (uint8_t*)data, hasAudio);
-}
-
-int CSoftAE::RunTranscodeStage(bool hasAudio)
-{
- if (!m_encoder) return 0;
-
- /* if we dont have enough samples to encode yet, return */
- unsigned int block = m_encoderFormat.m_frames * m_encoderFormat.m_frameSize;
- unsigned int sinkBlock = m_sinkFormat.m_frames * m_sinkFormat.m_frameSize;
-
- int encodedFrames = 0;
- if (m_buffer.Used() >= block && m_encodedBuffer.Used() < sinkBlock * 2)
- {
- hasAudio = FinalizeSamples((float*)m_buffer.Raw(block), m_encoderFormat.m_frameSamples, hasAudio);
-
- void *buffer;
- if (m_convertFn)
- {
- unsigned int newsize = m_encoderFormat.m_frames * m_encoderFormat.m_frameSize;
- AllocateConvIfNeeded(newsize, !hasAudio);
- if (hasAudio)
- m_convertFn((float*)m_buffer.Raw(block),
- m_encoderFormat.m_frames * m_encoderFormat.m_channelLayout.Count(), m_converted);
- buffer = m_converted;
- }
- else
- buffer = m_buffer.Raw(block);
-
- encodedFrames = m_encoder->Encode((float*)buffer, m_encoderFormat.m_frames);
-
- uint8_t *packet;
- unsigned int size = m_encoder->GetData(&packet);
-
- CExclusiveLock sinkLock(m_sinkLock); /* lock to maintain delay consistency */
-
- /* if there is not enough space for another encoded packet enlarge the buffer */
- if (m_encodedBuffer.Free() < size)
- m_encodedBuffer.ReAlloc(m_encodedBuffer.Used() + size);
-
- m_buffer.Shift(NULL, encodedFrames * m_encoderFormat.m_frameSize);
- m_encodedBuffer.Push(packet, size);
- }
-
- /* if we have enough data to write */
- if (m_encodedBuffer.Used() >= sinkBlock)
- WriteSink(m_encodedBuffer, sinkBlock, (uint8_t*)m_encodedBuffer.Raw(sinkBlock), hasAudio);
-
- return encodedFrames;
-}
-
-void CSoftAE::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());
- }
- }
-}
-
-unsigned int CSoftAE::RunRawStreamStage(unsigned int channelCount, void *out, bool &restart)
-{
- StreamList resumeStreams;
- static StreamList::iterator itt;
- CSingleLock streamLock(m_streamLock);
- /* handle playing streams */
- for (itt = m_playingStreams.begin(); itt != m_playingStreams.end(); ++itt)
- {
- CSoftAEStream *sitt = *itt;
- if (sitt == m_masterStream)
- continue;
-
- /* consume data from streams even though we cant use it */
- uint8_t *frame = sitt->GetFrame();
-
- /* flag the stream's slave to be resumed if it has drained */
- if (!frame && sitt->IsDrained() && sitt->m_slave && sitt->m_slave->IsPaused())
- resumeStreams.push_back(sitt);
- }
-
- /* nothing to do if we dont have a master stream */
- if (!m_masterStream)
- return 0;
-
- /* get the frame and append it to the output */
- uint8_t *frame = m_masterStream->GetFrame();
- unsigned int mixed;
- if (frame)
- {
- mixed = 1;
- memcpy(out, frame, m_sinkFormat.m_frameSize);
- }
- else
- {
- mixed = 0;
- if (m_masterStream->IsDrained() && m_masterStream->m_slave && m_masterStream->m_slave->IsPaused())
- resumeStreams.push_back(m_masterStream);
- }
-
- ResumeSlaveStreams(resumeStreams);
- return mixed;
-}
-
-unsigned int CSoftAE::RunStreamStage(unsigned int channelCount, void *out, bool &restart)
-{
- // no point doing anything if we have no streams,
- // we do not have to take a lock just to check empty
- if (m_playingStreams.empty())
- return 0;
-
- float *dst = (float*)out;
- unsigned int mixed = 0;
-
- /* identify the master stream */
- CSingleLock streamLock(m_streamLock);
-
- /* mix in any running streams */
- StreamList resumeStreams;
- for (StreamList::iterator itt = m_playingStreams.begin(); itt != m_playingStreams.end(); ++itt)
- {
- CSoftAEStream *stream = *itt;
-
- float *frame = (float*)stream->GetFrame();
- if (!frame && stream->IsDrained() && stream->m_slave && stream->m_slave->IsPaused())
- resumeStreams.push_back(stream);
-
- if (!frame)
- continue;
-
- float volume = stream->GetVolume() * stream->GetReplayGain() * stream->RunLimiter(frame, channelCount);
- #ifdef __SSE__
- if (channelCount > 1)
- CAEUtil::SSEMulAddArray(dst, frame, volume, channelCount);
- else
- #endif
- {
- for (unsigned int i = 0; i < channelCount; ++i)
- *dst++ += *frame++ * volume;
- }
-
- ++mixed;
- }
-
- ResumeSlaveStreams(resumeStreams);
- return mixed;
-}
-
-inline void CSoftAE::ResumeSlaveStreams(const StreamList &streams)
-{
- if (streams.empty())
- return;
-
- /* resume any streams that need to be */
- for (StreamList::const_iterator itt = streams.begin(); itt != streams.end(); ++itt)
- {
- CSoftAEStream *stream = *itt;
- m_playingStreams.push_back(stream->m_slave);
- stream->m_slave->m_paused = false;
- stream->m_slave = NULL;
- }
-}
-
-inline void CSoftAE::RemoveStream(StreamList &streams, CSoftAEStream *stream)
-{
- StreamList::iterator f = std::find(streams.begin(), streams.end(), stream);
- if (f != streams.end())
- streams.erase(f);
-
- if (streams == m_playingStreams)
- m_streamsPlaying = !m_playingStreams.empty();
-}
-
-inline void CSoftAE::ProcessSuspend()
-{
-#if defined(TARGET_WINDOWS) || defined(TARGET_LINUX)
- if (!m_softSuspend && m_playingStreams.empty() && m_playing_sounds.empty() &&
- !g_advancedSettings.m_streamSilence)
- {
- m_softSuspend = true;
- m_softSuspendTimeout.Set(10000); //10.0 second delay for softSuspend
- Sleep(10);
- }
-
-#endif
- /* idle while in Suspend() state until Resume() called */
- /* idle if nothing to play and user hasn't enabled */
- /* continuous streaming (silent stream) in as.xml */
- /* In case of Suspend stay in there until Resume is called from outer thread */
- while (m_isSuspended || ((m_softSuspend && m_softSuspendTimeout.IsTimePast()) &&
- m_running && !m_reOpen))
- {
- if (!m_isSuspended && m_sink && !m_sinkIsSuspended)
- {
- /* put the sink in Suspend mode */
- CExclusiveLock sinkLock(m_sinkLock);
- if (m_sink && !m_sink->SoftSuspend())
- {
- m_sinkIsSuspended = false; //sink cannot be suspended
- m_softSuspend = false; //break suspend loop
- break;
- }
- else
- {
- CLog::Log(LOGDEBUG, "Suspended the Sink");
- m_sinkIsSuspended = true; //sink has suspended processing
- }
- sinkLock.Leave();
- }
- // Signal that the Suspend can go on now.
- // Idea: Outer thread calls Suspend() - but
- // because of AddPackets does not care about locks, we must make
- // sure, that our school bus (AE::Run) is currently driving through
- // some gas station, before we move away the sink.
- if(m_isSuspended)
- m_saveSuspend.Set();
-
- /* idle for platform-defined time */
- m_wake.WaitMSec(SOFTAE_IDLE_WAIT_MSEC);
-
- /* check if we need to resume for stream or sound or somebody wants to open us
- * the suspend checks are only there to:
- * a) not run out of softSuspend directly when we are sleeping
- * b) nail(!) the thread during real Suspend into this method
- * Note: It is not enough to check the streams buffer, cause it might not be filled yet
- * We have to check after ProcessSuspending() if the sink is still in softsleep and resume it
- */
- if (!m_isSuspended && (!m_playingStreams.empty() || !m_playing_sounds.empty()))
- {
- // the sink might still be not initialized after Resume of real suspend
- m_reOpen = m_sink && (!m_sink->SoftResume() || m_reOpen); // sink returns false if it requires reinit (worthless with current implementation)
- m_sinkIsSuspended = false; //sink processing data
- m_softSuspend = false; //break suspend loop (under some conditions)
- CLog::Log(LOGDEBUG, "Resumed the Sink");
- break;
- }
- }
-}
-
diff --git a/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAE.h b/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAE.h
deleted file mode 100644
index 4415f76d23..0000000000
--- a/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAE.h
+++ /dev/null
@@ -1,253 +0,0 @@
-#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
- * <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <list>
-#include <vector>
-#include <map>
-
-#include "system.h"
-#include "threads/Thread.h"
-#include "threads/CriticalSection.h"
-#include "threads/SharedSection.h"
-#include "threads/SystemClock.h"
-
-#include "Interfaces/ThreadedAE.h"
-#include "Utils/AEBuffer.h"
-#include "Utils/AEAudioFormat.h"
-#include "AESinkFactory.h"
-
-#include "SoftAEStream.h"
-#include "SoftAESound.h"
-
-#include "cores/IAudioCallback.h"
-
-/* forward declarations */
-class IAESink;
-class IAEEncoder;
-
-class CSoftAE : public IThreadedAE
-{
-protected:
- friend class CAEFactory;
- CSoftAE();
- virtual ~CSoftAE();
-
-public:
- virtual void Shutdown();
- virtual bool Initialize();
- virtual void OnSettingsChange(const std::string& setting);
-
- virtual void Run();
- virtual void Stop();
- virtual bool Suspend();
- virtual bool Resume();
- virtual bool IsSuspended();
- virtual double GetDelay();
-
- virtual float GetVolume();
- virtual void SetVolume(const float volume);
- virtual void SetMute(const bool enabled) { m_muted = enabled; }
- virtual bool IsMuted() { return m_muted; }
- 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);
- void PlaySound(IAESound *sound);
- void StopSound(IAESound *sound);
-
- /* free's sounds that have expired */
- virtual void GarbageCollect();
-
- /* these are for the streams so they can provide compatible data */
- unsigned int GetSampleRate ();
- unsigned int GetChannelCount () {return m_chLayout.Count() ;}
- CAEChannelInfo& GetChannelLayout() {return m_chLayout ;}
- enum AEStdChLayout GetStdChLayout () {return m_stdChLayout ;}
- unsigned int GetFrames () {return m_sinkFormat.m_frames ;}
- unsigned int GetFrameSize () {return m_frameSize ;}
-
- /* these are for streams that are in RAW mode */
- const AEAudioFormat* GetSinkAudioFormat() {return &m_sinkFormat ;}
- enum AEDataFormat GetSinkDataFormat () {return m_sinkFormat.m_dataFormat ;}
- CAEChannelInfo& GetSinkChLayout () {return m_sinkFormat.m_channelLayout;}
- unsigned int GetSinkFrameSize () {return m_sinkFormat.m_frameSize ;}
-
- /* for streams so they can calc cachetimes correct */
- double GetCacheTime();
- double GetCacheTotal();
-
- virtual void EnumerateOutputDevices(AEDeviceList &devices, bool passthrough);
- virtual std::string GetDefaultDevice(bool passthrough);
- virtual bool SupportsRaw();
-
- /* internal stream methods */
- void PauseStream (CSoftAEStream *stream);
- void ResumeStream(CSoftAEStream *stream);
-
-private:
- CThread *m_thread;
-
- CSoftAEStream *GetMasterStream();
-
- void LoadSettings();
- void VerifySoundDevice(std::string &device, bool passthrough);
- void OpenSink();
-
- void InternalOpenSink();
- void InternalCloseSink();
- void ResetEncoder();
- bool SetupEncoder(AEAudioFormat &format);
- void Deinitialize();
-
- inline void ProcessSuspend(); /* enter suspend state if nothing to play and sink allows */
-
- inline void GetDeviceFriendlyName(std::string &device);
-
- IAESink *GetSink(AEAudioFormat &desiredFormat, bool passthrough, std::string &device);
- void StopAllSounds();
-
- enum AEStdChLayout m_stdChLayout;
- std::string m_device;
- std::string m_passthroughDevice;
- std::string m_deviceFriendlyName;
- bool m_audiophile;
- bool m_stereoUpmix;
-
- /* internal vars */
- bool m_running, m_reOpen;
- bool m_sinkIsSuspended; /* The sink is in unusable state, e.g. SoftSuspended */
- bool m_isSuspended; /* engine suspended by external function to release audio context */
- bool m_softSuspend; /* latches after last stream or sound played for timer below for idle */
- XbmcThreads::EndTime m_softSuspendTimeout; /* timer to hold sink open before soft suspend for idle */
- CEvent m_reOpenEvent;
- CEvent m_wake;
- CEvent m_saveSuspend;
-
- CCriticalSection m_runningLock; /* released when the thread exits */
- CCriticalSection m_streamLock; /* m_streams lock */
- CCriticalSection m_soundLock; /* m_sounds lock */
- CCriticalSection m_soundSampleLock; /* m_playing_sounds lock */
- CSharedSection m_sinkLock; /* lock for m_sink on re-open */
- CCriticalSection m_threadLock; /* locked while starting/stopping the thread */
-
- /* the current configuration */
- float m_volume;
- bool m_muted;
- CAEChannelInfo m_chLayout;
- unsigned int m_frameSize;
- double m_frameSizeMul;
-
- /* the sink, its format information, and conversion function */
- AESinkInfoList m_sinkInfoList;
- IAESink *m_sink;
- AEAudioFormat m_sinkFormat;
- double m_sinkFormatSampleRateMul;
- unsigned int m_sinkBlockSize;
- unsigned int m_sinkBlockTime;
- bool m_sinkHandlesVolume;
- AEAudioFormat m_encoderFormat;
- double m_encoderFrameSizeMul;
- double m_encoderInitSampleRateMul;
- unsigned int m_bytesPerSample;
- CAEConvert::AEConvertFrFn m_convertFn;
-
- /* currently playing sounds */
- typedef struct {
- CSoftAESound *owner;
- float *samples;
- unsigned int sampleCount;
- } SoundState;
-
- typedef std::vector<CSoftAEStream*> StreamList;
- typedef std::list <CSoftAESound* > SoundList;
- typedef std::list <SoundState > SoundStateList;
-
- /* the streams, sounds, output buffer and output buffer fill size */
- bool m_transcode;
- bool m_rawPassthrough;
- StreamList m_newStreams, m_streams, m_playingStreams;
- SoundList m_sounds;
- SoundStateList m_playing_sounds;
- int m_soundMode;
- bool m_streamsPlaying;
-
- /* this will contain either float, or uint8_t depending on if we are in raw mode or not */
- CAEBuffer m_buffer;
-
- /* the encoder */
- IAEEncoder *m_encoder;
- CAEBuffer m_encodedBuffer;
-
- /* the output conversion buffer */
- uint8_t *m_converted;
- size_t m_convertedSize;
-
- void AllocateConvIfNeeded(size_t convertedSize, bool prezero = false);
-
- /* thread run stages */
-
- /*! \brief Mix UI sounds into the current stream.
- \param buffer the buffer to mix into.
- \param samples the number of samples in the buffer.
- \return the number of sounds mixed into the buffer.
- */
- unsigned int MixSounds (float *buffer, unsigned int samples);
-
- /*! \brief Finalize samples ready for sending to the output device.
- Mixes in any UI sounds, applies volume adjustment, and clamps to [-1,1].
- \param buffer the audio data.
- \param samples the number of samples in the buffer.
- \param hasAudio whether we have audio from a stream (true) or silence (false)
- \return true if we have audio to output, false if we have only silence.
- */
- bool FinalizeSamples (float *buffer, unsigned int samples, bool hasAudio);
-
- CSoftAEStream *m_masterStream;
-
- /*! \brief Run the output stage on the audio.
- Prepares streamed data, mixes in any UI sounds, converts to a format suitable
- for the sink, then outputs to the sink.
- \param hasAudio whether or not we have audio (true) or silence (false).
- \return the number of samples sent to the sink.
- */
- int (CSoftAE::*m_outputStageFn)(bool);
- int RunOutputStage (bool hasAudio);
- int RunRawOutputStage(bool hasAudio);
- int RunTranscodeStage(bool hasAudio);
-
- unsigned int (CSoftAE::*m_streamStageFn)(unsigned int channelCount, void *out, bool &restart);
- unsigned int RunRawStreamStage (unsigned int channelCount, void *out, bool &restart);
- unsigned int RunStreamStage (unsigned int channelCount, void *out, bool &restart);
-
- void ResumeSlaveStreams(const StreamList &streams);
- void RunNormalizeStage (unsigned int channelCount, void *out, unsigned int mixed);
-
- void RemoveStream(StreamList &streams, CSoftAEStream *stream);
- void PrintSinks();
-
- unsigned int WriteSink(CAEBuffer& src, unsigned int src_len, uint8_t *data, bool hasAudio);
-};
-
diff --git a/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAESound.cpp b/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAESound.cpp
deleted file mode 100644
index 5fcaccf62c..0000000000
--- a/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAESound.cpp
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * 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
- * <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "Interfaces/AESound.h"
-
-#include <samplerate.h>
-#include "threads/SingleLock.h"
-#include "utils/log.h"
-#include "utils/EndianSwap.h"
-
-#include "AEFactory.h"
-#include "Utils/AEAudioFormat.h"
-
-#include "SoftAE.h"
-#include "SoftAESound.h"
-
-/* typecast AE to CSoftAE */
-#define AE (*((CSoftAE*)CAEFactory::GetEngine()))
-
-CSoftAESound::CSoftAESound(const std::string &filename) :
- IAESound (filename),
- m_filename (filename),
- m_volume (1.0f ),
- m_inUse (0 )
-{
- m_wavLoader.Load(filename);
-}
-
-CSoftAESound::~CSoftAESound()
-{
-}
-
-void CSoftAESound::DeInitialize()
-{
-}
-
-bool CSoftAESound::IsCompatible()
-{
- if (!m_wavLoader.IsValid())
- return false;
-
- return m_wavLoader.IsCompatible(AE.GetSampleRate(), AE.GetChannelLayout());
-}
-
-bool CSoftAESound::Initialize()
-{
- if (!m_wavLoader.IsValid())
- return false;
-
- return m_wavLoader.Initialize(
- AE.GetSampleRate (),
- AE.GetChannelLayout(),
- AE.GetStdChLayout ()
- );
-}
-
-unsigned int CSoftAESound::GetSampleCount()
-{
- CSingleLock cs(m_critSection);
- if (m_wavLoader.IsValid())
- return m_wavLoader.GetSampleCount();
- return 0;
-}
-
-float* CSoftAESound::GetSamples()
-{
- CSingleLock cs(m_critSection);
- if (!m_wavLoader.IsValid())
- return NULL;
-
- ++m_inUse;
- return m_wavLoader.GetSamples();
-}
-
-void CSoftAESound::ReleaseSamples()
-{
- CSingleLock cs(m_critSection);
- ASSERT(m_inUse > 0);
- --m_inUse;
-}
-
-bool CSoftAESound::IsPlaying()
-{
- CSingleLock cs(m_critSection);
- return (m_inUse > 0);
-}
-
-void CSoftAESound::Play()
-{
- AE.PlaySound(this);
-}
-
-void CSoftAESound::Stop()
-{
- AE.StopSound(this);
-}
-
diff --git a/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAESound.h b/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAESound.h
deleted file mode 100644
index cd50c0b475..0000000000
--- a/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAESound.h
+++ /dev/null
@@ -1,57 +0,0 @@
-#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
- * <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "utils/StdString.h"
-#include "threads/CriticalSection.h"
-#include "threads/SharedSection.h"
-#include "Interfaces/AESound.h"
-#include "Utils/AEWAVLoader.h"
-
-class CSoftAESound : public IAESound
-{
-public:
- CSoftAESound (const std::string &filename);
- virtual ~CSoftAESound();
-
- virtual void DeInitialize();
- virtual bool Initialize();
-
- 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 ; }
-
- bool IsCompatible();
- unsigned int GetSampleCount();
-
- /* ReleaseSamples must be called for each time GetSamples has been called */
- virtual float* GetSamples ();
- void ReleaseSamples();
-private:
- CCriticalSection m_critSection;
- std::string m_filename;
- CAEWAVLoader m_wavLoader;
- float m_volume;
- int m_inUse;
-};
-
diff --git a/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAEStream.cpp b/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAEStream.cpp
deleted file mode 100644
index b5c2da33ba..0000000000
--- a/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAEStream.cpp
+++ /dev/null
@@ -1,687 +0,0 @@
-/*
- * 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
- * <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "system.h"
-#include "threads/SingleLock.h"
-#include "utils/log.h"
-#include "utils/MathUtils.h"
-
-#include "AEFactory.h"
-#include "Utils/AEUtil.h"
-
-#include "SoftAE.h"
-#include "SoftAEStream.h"
-
-#ifdef TARGET_WINDOWS
-#pragma comment(lib, "libsamplerate-0.lib")
-#endif
-
-/* typecast AE to CSoftAE */
-#define AE (*((CSoftAE*)CAEFactory::GetEngine()))
-
-using namespace std;
-
-CSoftAEStream::CSoftAEStream(enum AEDataFormat dataFormat, unsigned int sampleRate, unsigned int encodedSampleRate, CAEChannelInfo channelLayout, unsigned int options, CCriticalSection& lock) :
- m_lock (lock ),
- m_resampleRatio (1.0 ),
- m_internalRatio (1.0 ),
- m_convertBuffer (NULL ),
- m_valid (false),
- m_delete (false),
- m_volume (1.0f ),
- m_rgain (1.0f ),
- m_refillBuffer (0 ),
- m_convertFn (NULL ),
- m_ssrc (NULL ),
- m_framesBuffered (0 ),
- m_newPacket (NULL ),
- m_packet (NULL ),
- m_vizPacketPos (NULL ),
- m_draining (false),
- m_vizBufferSamples(0 ),
- m_audioCallback (NULL ),
- m_fadeRunning (false),
- m_slave (NULL )
-{
- m_ssrcData.data_out = NULL;
-
- m_initDataFormat = dataFormat;
- m_initSampleRate = sampleRate;
- m_initEncodedSampleRate = encodedSampleRate;
- m_initChannelLayout = channelLayout;
- m_chLayoutCount = channelLayout.Count();
- m_forceResample = (options & AESTREAM_FORCE_RESAMPLE) != 0;
- m_paused = (options & AESTREAM_PAUSED) != 0;
- m_autoStart = (options & AESTREAM_AUTOSTART) != 0;
-
- if (m_autoStart)
- m_paused = true;
-
- ASSERT(m_initChannelLayout.Count());
-}
-
-void CSoftAEStream::InitializeRemap()
-{
- CSingleLock lock(m_lock);
-
- if (!AE_IS_RAW(m_initDataFormat))
- {
- /* re-init the remappers */
- m_remap .Initialize(m_initChannelLayout, AE.GetChannelLayout() , false, false, AE.GetStdChLayout());
- m_vizRemap.Initialize(m_initChannelLayout, CAEChannelInfo(AE_CH_LAYOUT_2_0), false, true);
-
- /*
- if the layout has changed we need to drop data that was already remapped
- */
- if (AE.GetChannelLayout() != m_aeChannelLayout)
- {
- InternalFlush();
- m_aeChannelLayout = AE.GetChannelLayout();
- m_samplesPerFrame = AE.GetChannelLayout().Count();
- m_aeBytesPerFrame = AE_IS_RAW(m_initDataFormat) ? m_bytesPerFrame : (m_samplesPerFrame * sizeof(float));
- }
- }
-}
-
-void CSoftAEStream::Initialize()
-{
- CSingleLock lock(m_lock);
-
- if (m_valid)
- {
- InternalFlush();
- delete m_newPacket;
-
- if (m_convert)
- _aligned_free(m_convertBuffer);
-
- if (m_resample)
- {
- _aligned_free(m_ssrcData.data_out);
- m_ssrcData.data_out = NULL;
- }
- }
-
- enum AEDataFormat useDataFormat = m_initDataFormat;
- if (AE_IS_RAW(m_initDataFormat))
- {
- /* we are raw, which means we need to work in the output format */
- useDataFormat = AE.GetSinkDataFormat();
- m_initChannelLayout = AE.GetSinkChLayout ();
- m_samplesPerFrame = m_initChannelLayout.Count();
- }
- else
- {
- if (!m_initChannelLayout.Count())
- {
- m_valid = false;
- return;
- }
- m_samplesPerFrame = AE.GetChannelLayout().Count();
- }
-
- m_bytesPerSample = (CAEUtil::DataFormatToBits(useDataFormat) >> 3);
- m_bytesPerFrame = m_bytesPerSample * m_initChannelLayout.Count();
-
- m_aeChannelLayout = AE.GetChannelLayout();
- m_aeBytesPerFrame = AE_IS_RAW(m_initDataFormat) ? m_bytesPerFrame : (m_samplesPerFrame * sizeof(float));
- // set the waterlevel to 75 percent of the number of frames per second.
- // this lets us drain the main buffer down futher before flagging an underrun.
- m_waterLevel = AE.GetSampleRate() - (AE.GetSampleRate() / 4);
- m_refillBuffer = m_waterLevel;
-
- m_format.m_dataFormat = useDataFormat;
- m_format.m_sampleRate = m_initSampleRate;
- m_format.m_encodedRate = m_initEncodedSampleRate;
- m_format.m_channelLayout = m_initChannelLayout;
- m_format.m_frames = m_initSampleRate / 8;
- m_format.m_frameSamples = m_format.m_frames * m_initChannelLayout.Count();
- m_format.m_frameSize = m_bytesPerFrame;
-
- m_newPacket = new PPacket();
- if (AE_IS_RAW(m_initDataFormat))
- m_newPacket->data.Alloc(m_format.m_frames * m_format.m_frameSize);
- else
- {
- if (
- !m_remap .Initialize(m_initChannelLayout, m_aeChannelLayout , false, false, AE.GetStdChLayout()) ||
- !m_vizRemap.Initialize(m_initChannelLayout, CAEChannelInfo(AE_CH_LAYOUT_2_0), false, true))
- {
- m_valid = false;
- return;
- }
-
- m_newPacket->data.Alloc(m_format.m_frameSamples * sizeof(float));
- }
-
- m_packet = NULL;
-
- m_inputBuffer.Alloc(m_format.m_frames * m_format.m_frameSize);
-
- m_resample = (m_forceResample || m_initSampleRate != AE.GetSampleRate()) && !AE_IS_RAW(m_initDataFormat);
- m_convert = m_initDataFormat != AE_FMT_FLOAT && !AE_IS_RAW(m_initDataFormat);
-
- /* if we need to convert, set it up */
- if (m_convert)
- {
- /* get the conversion function and allocate a buffer for the data */
- CLog::Log(LOGDEBUG, "CSoftAEStream::CSoftAEStream - Converting from %s to AE_FMT_FLOAT", CAEUtil::DataFormatToStr(m_initDataFormat));
- m_convertFn = CAEConvert::ToFloat(m_initDataFormat);
- if (m_convertFn)
- m_convertBuffer = (float*)_aligned_malloc(m_format.m_frameSamples * sizeof(float), 16);
- else
- m_valid = false;
- }
- else
- m_convertBuffer = (float*)m_inputBuffer.Raw(m_format.m_frames * m_format.m_frameSize);
-
- /* if we need to resample, set it up */
- if (m_resample)
- {
- int err;
- m_ssrc = src_new(SRC_SINC_MEDIUM_QUALITY, m_initChannelLayout.Count(), &err);
- m_ssrcData.data_in = m_convertBuffer;
- m_internalRatio = (double)AE.GetSampleRate() / (double)m_initSampleRate;
- m_ssrcData.src_ratio = m_internalRatio;
- m_ssrcData.data_out = (float*)_aligned_malloc(m_format.m_frameSamples * (int)std::ceil(m_ssrcData.src_ratio) * sizeof(float), 16);
- m_ssrcData.output_frames = m_format.m_frames * (long)std::ceil(m_ssrcData.src_ratio);
- m_ssrcData.end_of_input = 0;
- // we must buffer the same amount as before but taking the source sample rate into account
- // there is no reason to decrease the buffer for upsampling
- if (m_internalRatio < 1)
- {
- m_waterLevel *= (1.0 / m_internalRatio);
- m_refillBuffer = m_waterLevel;
- }
- }
-
- m_limiter.SetSamplerate(AE.GetSampleRate());
-
- m_chLayoutCount = m_format.m_channelLayout.Count();
- m_valid = true;
-}
-
-void CSoftAEStream::Destroy()
-{
- CSingleLock lock(m_lock);
-
- m_valid = false;
- m_delete = true;
-}
-
-CSoftAEStream::~CSoftAEStream()
-{
- CSingleLock lock(m_lock);
-
- InternalFlush();
- if (m_convert)
- _aligned_free(m_convertBuffer);
-
- if (m_resample)
- {
- _aligned_free(m_ssrcData.data_out);
- src_delete(m_ssrc);
- m_ssrc = NULL;
- }
-
- delete m_newPacket;
- delete m_packet;
-
- CLog::Log(LOGDEBUG, "CSoftAEStream::~CSoftAEStream - Destructed");
-}
-
-unsigned int CSoftAEStream::GetSpace()
-{
- CSingleLock lock(m_lock);
-
- if (!m_valid || m_draining)
- return 0;
-
- if (m_framesBuffered >= m_waterLevel)
- return 0;
-
- return m_inputBuffer.Free() + (std::max(0U, (m_waterLevel - m_framesBuffered)) * m_format.m_frameSize);
-}
-
-unsigned int CSoftAEStream::AddData(void *data, unsigned int size)
-{
- CSingleLock lock(m_lock);
-
- if (!m_valid || size == 0 || data == NULL)
- return 0;
-
- /* if the stream is draining */
- if (m_draining)
- {
- /* if the stream has finished draining, cork it */
- if (m_packet && !m_packet->data.Used() && m_outBuffer.empty())
- m_draining = false;
- else
- return 0;
- }
-
- /* dont ever take more then GetSpace advertises */
- size = std::min(size, GetSpace());
- if (size == 0)
- return 0;
-
- unsigned int taken = 0;
- while(size)
- {
- unsigned int copy = std::min((unsigned int)m_inputBuffer.Free(), size);
- if (copy > 0)
- {
- m_inputBuffer.Push(data, copy);
- size -= copy;
- taken += copy;
- data = (uint8_t*)data + copy;
- }
-
- if (m_inputBuffer.Free() == 0)
- {
- unsigned int consumed = ProcessFrameBuffer();
- m_inputBuffer.Shift(NULL, consumed);
- }
- }
-
- lock.Leave();
-
- /* if the stream is flagged to autoStart when the buffer is full, then do it */
- if (m_autoStart && m_framesBuffered >= m_waterLevel)
- Resume();
-
- return taken;
-}
-
-unsigned int CSoftAEStream::ProcessFrameBuffer()
-{
- uint8_t *data;
- unsigned int frames, consumed, sampleSize;
-
- /* convert the data if we need to */
- unsigned int samples;
- if (m_convert)
- {
- data = (uint8_t*)m_convertBuffer;
- samples = m_convertFn(
- (uint8_t*)m_inputBuffer.Raw(m_inputBuffer.Used()),
- m_inputBuffer.Used() / m_bytesPerSample,
- m_convertBuffer
- );
- sampleSize = sizeof(float);
- }
- else
- {
- data = (uint8_t*)m_inputBuffer.Raw(m_inputBuffer.Used());
- samples = m_inputBuffer.Used() / m_bytesPerSample;
- sampleSize = m_bytesPerSample;
- }
-
- if (samples == 0)
- return 0;
-
- /* resample it if we need to */
- if (m_resample)
- {
- m_ssrcData.input_frames = samples / m_chLayoutCount;
- if (src_process(m_ssrc, &m_ssrcData) != 0)
- return 0;
- data = (uint8_t*)m_ssrcData.data_out;
- frames = m_ssrcData.output_frames_gen;
- consumed = m_ssrcData.input_frames_used * m_bytesPerFrame;
- if (!frames)
- return consumed;
-
- samples = frames * m_chLayoutCount;
- }
- else
- {
- data = (uint8_t*)m_convertBuffer;
- frames = samples / m_chLayoutCount;
- consumed = frames * m_bytesPerFrame;
- }
-
- if (m_refillBuffer)
- {
- if (frames > m_refillBuffer)
- m_refillBuffer = 0;
- else
- m_refillBuffer -= frames;
- }
-
- /* buffer the data */
- m_framesBuffered += frames;
- const unsigned int inputBlockSize = m_format.m_frames * m_format.m_channelLayout.Count() * sampleSize;
-
- size_t remaining = samples * sampleSize;
- while (remaining)
- {
- size_t copy = std::min(m_newPacket->data.Free(), remaining);
- m_newPacket->data.Push(data, copy);
- data += copy;
- remaining -= copy;
-
- /* wait till we have a full packet, or no more data before processing the packet */
- if ((!m_draining || remaining) && m_newPacket->data.Free() > 0)
- continue;
-
- /* if we have a full block of data */
- if (AE_IS_RAW(m_initDataFormat))
- {
- m_outBuffer.push_back(m_newPacket);
- m_newPacket = new PPacket();
- m_newPacket->data.Alloc(inputBlockSize);
- continue;
- }
-
- /* make a new packet for downmix/remap */
- PPacket *pkt = new PPacket();
-
- /* downmix/remap the data */
- size_t frames = m_newPacket->data.Used() / m_format.m_channelLayout.Count() / sizeof(float);
- size_t used = frames * m_aeChannelLayout.Count() * sizeof(float);
- pkt->data.Alloc(used);
- m_remap.Remap(
- (float*)m_newPacket->data.Raw (m_newPacket->data.Used()),
- (float*)pkt ->data.Take(used),
- frames
- );
-
- /* downmix for the viz if we have one */
- if (m_audioCallback)
- {
- size_t vizUsed = frames * 2 * sizeof(float);
- pkt->vizData.Alloc(vizUsed);
- m_vizRemap.Remap(
- (float*)m_newPacket->data .Raw (m_newPacket->data.Used()),
- (float*)pkt ->vizData.Take(vizUsed),
- frames
- );
- }
-
- /* add the packet to the output */
- m_outBuffer.push_back(pkt);
- m_newPacket->data.Empty();
- }
-
- return consumed;
-}
-
-uint8_t* CSoftAEStream::GetFrame()
-{
- CSingleLock lock(m_lock);
-
- /* if we are fading, this runs even if we have underrun as it is time based */
- if (m_fadeRunning)
- {
- m_volume += m_fadeStep;
- m_volume = std::min(1.0f, std::max(0.0f, m_volume));
- if (m_fadeDirUp)
- {
- if (m_volume >= m_fadeTarget)
- m_fadeRunning = false;
- }
- else
- {
- if (m_volume <= m_fadeTarget)
- m_fadeRunning = false;
- }
- }
-
- /* if we have been deleted or are refilling but not draining */
- if (!m_valid || m_delete || (m_refillBuffer && !m_draining))
- return NULL;
-
- /* if the packet is empty, advance to the next one */
- if (!m_packet || m_packet->data.CursorEnd())
- {
- delete m_packet;
- m_packet = NULL;
-
- /* no more packets, return null */
- if (m_outBuffer.empty())
- {
- if (m_draining)
- return NULL;
- else
- {
- /* underrun, we need to refill our buffers */
- CLog::Log(LOGDEBUG, "CSoftAEStream::GetFrame - Underrun");
- ASSERT(m_waterLevel > m_framesBuffered);
- m_refillBuffer = m_waterLevel - m_framesBuffered;
- return NULL;
- }
- }
-
- /* get the next packet */
- m_packet = m_outBuffer.front();
- m_outBuffer.pop_front();
- }
-
- /* fetch one frame of data */
- uint8_t *ret = (uint8_t*)m_packet->data.CursorRead(m_aeBytesPerFrame);
-
- /* we have a frame, if we have a viz we need to hand the data to it */
- if (m_audioCallback && !m_packet->vizData.CursorEnd())
- {
- float *vizData = (float*)m_packet->vizData.CursorRead(2 * sizeof(float));
- memcpy(m_vizBuffer + m_vizBufferSamples, vizData, 2 * sizeof(float));
- m_vizBufferSamples += 2;
- if (m_vizBufferSamples == 512)
- {
- m_audioCallback->OnAudioData(m_vizBuffer, 512);
- m_vizBufferSamples = 0;
- }
- }
-
- --m_framesBuffered;
- return ret;
-}
-
-double CSoftAEStream::GetDelay()
-{
- CSingleLock lock(m_lock);
-
- if (m_delete)
- return 0.0;
-
- double delay = AE.GetDelay();
- delay += (double)(m_inputBuffer.Used() / m_format.m_frameSize) / (double)m_format.m_sampleRate;
- delay += (double)m_framesBuffered / (double)AE.GetSampleRate();
- return delay;
-}
-
-double CSoftAEStream::GetCacheTime()
-{
- CSingleLock lock(m_lock);
-
- if (m_delete)
- return 0.0;
-
- double time = AE.GetCacheTime();
- time += (double)(m_inputBuffer.Used() / m_format.m_frameSize) / (double)m_format.m_sampleRate;
- time += (double)m_framesBuffered / (double)AE.GetSampleRate();
- return time;
-}
-
-double CSoftAEStream::GetCacheTotal()
-{
- CSingleLock lock(m_lock);
-
- if (m_delete)
- return 0.0;
-
- double total = AE.GetCacheTotal();
- total += (double)(m_inputBuffer.Size() / m_format.m_frameSize) / (double)m_format.m_sampleRate;
- total += (double)m_waterLevel / (double)AE.GetSampleRate();
- return total;
-}
-
-void CSoftAEStream::Pause()
-{
- CSingleLock lock(m_lock);
-
- if (m_paused)
- return;
- m_paused = true;
- AE.PauseStream(this);
-}
-
-void CSoftAEStream::Resume()
-{
- CSingleLock lock(m_lock);
-
- if (!m_paused)
- return;
- m_paused = false;
- m_autoStart = false;
- AE.ResumeStream(this);
-}
-
-void CSoftAEStream::Drain(bool wait)
-{
- CSingleLock lock(m_lock);
- m_draining = true;
-}
-
-bool CSoftAEStream::IsDrained()
-{
- CSingleLock lock(m_lock);
- return (m_draining && !m_packet && m_outBuffer.empty());
-}
-
-void CSoftAEStream::Flush()
-{
- CLog::Log(LOGDEBUG, "CSoftAEStream::Flush");
- CSingleLock lock(m_lock);
- InternalFlush();
-
- /* internal flush does not do this as these samples are still valid if we are re-initializing */
- m_inputBuffer.Empty();
-}
-
-void CSoftAEStream::InternalFlush()
-{
- /* reset the resampler */
- if (m_resample)
- {
- m_ssrcData.end_of_input = 0;
- src_reset(m_ssrc);
- }
-
- /* invalidate any incoming samples */
- m_newPacket->data.Empty();
-
- /*
- clear the current buffered packet, we cant delete the data as it may be
- in use by the AE thread, so we just seek to the end of the buffer
- */
- if (m_packet)
- m_packet->data.CursorSeek(m_packet->data.Size());
-
- /* clear any other buffered packets */
- while (!m_outBuffer.empty())
- {
- PPacket *p = m_outBuffer.front();
- m_outBuffer.pop_front();
- delete p;
- }
-
- /* reset our counts */
- m_framesBuffered = 0;
- m_refillBuffer = m_waterLevel;
- m_draining = false;
-}
-
-double CSoftAEStream::GetResampleRatio()
-{
- CSingleLock lock(m_lock);
- if (!m_resample)
- return 1.0f;
-
- return m_ssrcData.src_ratio;
-}
-
-bool CSoftAEStream::SetResampleRatio(double ratio)
-{
- if (!m_resample)
- return false;
-
- CSingleLock lock(m_lock);
-
- int oldRatioInt = (int)std::ceil(m_ssrcData.src_ratio);
-
- m_resampleRatio = ratio;
-
- src_set_ratio(m_ssrc, m_resampleRatio * m_internalRatio);
- m_ssrcData.src_ratio = m_resampleRatio * m_internalRatio;
-
- //Check the resample buffer size and resize if necessary.
- if (oldRatioInt < std::ceil(m_ssrcData.src_ratio))
- {
- _aligned_free(m_ssrcData.data_out);
- m_ssrcData.data_out = (float*)_aligned_malloc(m_format.m_frameSamples * (int)std::ceil(m_ssrcData.src_ratio) * sizeof(float), 16);
- m_ssrcData.output_frames = m_format.m_frames * (long)std::ceil(m_ssrcData.src_ratio);
- }
- return true;
-}
-
-void CSoftAEStream::RegisterAudioCallback(IAudioCallback* pCallback)
-{
- CSingleLock lock(m_lock);
- m_vizBufferSamples = 0;
- m_audioCallback = pCallback;
- if (m_audioCallback)
- m_audioCallback->OnInitialize(2, m_initSampleRate, 32);
-}
-
-void CSoftAEStream::UnRegisterAudioCallback()
-{
- CSingleLock lock(m_lock);
- m_audioCallback = NULL;
- m_vizBufferSamples = 0;
-}
-
-void CSoftAEStream::FadeVolume(float from, float target, unsigned int time)
-{
- /* can't fade a RAW stream */
- if (AE_IS_RAW(m_initDataFormat))
- return;
-
- CSingleLock lock(m_lock);
- float delta = target - from;
- m_fadeDirUp = target > from;
- m_fadeTarget = target;
- m_fadeStep = delta / (((float)AE.GetSampleRate() / 1000.0f) * (float)time);
- m_fadeRunning = true;
-}
-
-bool CSoftAEStream::IsFading()
-{
- CSingleLock lock(m_lock);
- return m_fadeRunning;
-}
-
-void CSoftAEStream::RegisterSlave(IAEStream *slave)
-{
- CSingleLock lock(m_lock);
- m_slave = (CSoftAEStream*)slave;
-}
-
diff --git a/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAEStream.h b/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAEStream.h
deleted file mode 100644
index 9ee607c4cc..0000000000
--- a/xbmc/cores/AudioEngine/Engines/SoftAE/SoftAEStream.h
+++ /dev/null
@@ -1,161 +0,0 @@
-#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
- * <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <samplerate.h>
-#include <list>
-
-#include "threads/SharedSection.h"
-
-#include "Utils/AEAudioFormat.h"
-#include "Interfaces/AEStream.h"
-#include "Utils/AEConvert.h"
-#include "Utils/AERemap.h"
-#include "Utils/AEBuffer.h"
-#include "Utils/AELimiter.h"
-
-class IAEPostProc;
-class CSoftAEStream : public IAEStream
-{
-protected:
- friend class CSoftAE;
- CSoftAEStream(enum AEDataFormat format, unsigned int sampleRate, unsigned int encodedSamplerate, CAEChannelInfo channelLayout, unsigned int options, CCriticalSection& lock);
- virtual ~CSoftAEStream();
-
- void Initialize();
- void InitializeRemap();
- void Destroy();
- uint8_t* GetFrame();
-
- bool IsPaused () { return m_paused; }
- bool IsDestroyed() { return m_delete; }
- bool IsValid () { return m_valid; }
- const bool IsRaw() const { return AE_IS_RAW(m_initDataFormat); }
-
-public:
- virtual unsigned int GetSpace ();
- virtual unsigned int AddData (void *data, unsigned int size);
- virtual double GetDelay ();
- virtual bool IsBuffering () { return m_refillBuffer > 0; }
- virtual double GetCacheTime ();
- virtual double GetCacheTotal ();
-
- virtual void Pause ();
- virtual void Resume ();
- virtual void Drain (bool wait);
- virtual bool IsDraining () { return m_draining; }
- virtual bool IsDrained ();
- virtual void Flush ();
-
- virtual float GetVolume () { return m_volume; }
- virtual float GetReplayGain () { return m_rgain ; }
- virtual float GetAmplification() { return m_limiter.GetAmplification(); }
- virtual void SetVolume (float volume) { m_volume = std::max( 0.0f, std::min(1.0f, volume)); }
- virtual void SetReplayGain (float factor) { m_rgain = std::max( 0.0f, factor); }
- virtual void SetAmplification(float amplify){ m_limiter.SetAmplification(amplify); }
-
- virtual float RunLimiter(float* frame, int channels) { return m_limiter.Run(&frame, channels); }
-
- virtual const unsigned int GetFrameSize () const { return m_format.m_frameSize; }
- virtual const unsigned int GetChannelCount() const { return m_initChannelLayout.Count(); }
-
- virtual const unsigned int GetSampleRate () const { return m_initSampleRate; }
- virtual const unsigned int GetEncodedSampleRate() const { return m_initEncodedSampleRate; }
- virtual const enum AEDataFormat GetDataFormat () const { return m_initDataFormat; }
-
- 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);
-private:
- void InternalFlush();
- void CheckResampleBuffers();
-
- CCriticalSection& m_lock;
- enum AEDataFormat m_initDataFormat;
- unsigned int m_initSampleRate;
- unsigned int m_initEncodedSampleRate;
- CAEChannelInfo m_initChannelLayout;
- unsigned int m_chLayoutCount;
-
- typedef struct
- {
- CAEBuffer data;
- CAEBuffer vizData;
- } PPacket;
-
- AEAudioFormat m_format;
-
- bool m_forceResample; /* true if we are to force resample even when the rates match */
- bool m_resample; /* true if the audio needs to be resampled */
- double m_resampleRatio; /* user specified resample ratio */
- double m_internalRatio; /* internal resample ratio */
- bool m_convert; /* true if the bitspersample needs converting */
- float *m_convertBuffer; /* buffer for converted data */
- bool m_valid; /* true if the stream is valid */
- bool m_delete; /* true if CSoftAE is to free this object */
- CAERemap m_remap; /* the remapper */
- float m_volume; /* the volume level */
- float m_rgain; /* replay gain level */
- unsigned int m_waterLevel; /* the fill level to fall below before calling the data callback */
- unsigned int m_refillBuffer; /* how many frames that need to be buffered before we return any frames */
-
- CAEConvert::AEConvertToFn m_convertFn;
-
- CAEBuffer m_inputBuffer;
- unsigned int m_bytesPerSample;
- unsigned int m_bytesPerFrame;
- unsigned int m_samplesPerFrame;
- CAEChannelInfo m_aeChannelLayout;
- unsigned int m_aeBytesPerFrame;
- SRC_STATE *m_ssrc;
- SRC_DATA m_ssrcData;
- unsigned int m_framesBuffered;
- std::list<PPacket*> m_outBuffer;
- unsigned int ProcessFrameBuffer();
- PPacket *m_newPacket;
- PPacket *m_packet;
- uint8_t *m_packetPos;
- float *m_vizPacketPos;
- bool m_paused;
- bool m_autoStart;
- bool m_draining;
- CAELimiter m_limiter;
-
- /* vizualization internals */
- CAERemap m_vizRemap;
- float m_vizBuffer[512];
- unsigned int m_vizBufferSamples;
- IAudioCallback *m_audioCallback;
-
- /* fade values */
- bool m_fadeRunning;
- bool m_fadeDirUp;
- float m_fadeStep;
- float m_fadeTarget;
- unsigned int m_fadeTime;
-
- /* slave stream */
- CSoftAEStream *m_slave;
-};
-
diff --git a/xbmc/cores/AudioEngine/Interfaces/AE.h b/xbmc/cores/AudioEngine/Interfaces/AE.h
index b1f30085e8..d2f895cddc 100644
--- a/xbmc/cores/AudioEngine/Interfaces/AE.h
+++ b/xbmc/cores/AudioEngine/Interfaces/AE.h
@@ -41,6 +41,11 @@ class IAudioCallback;
#define AE_SOUND_IDLE 1 /* only play sounds while no streams are running */
#define AE_SOUND_ALWAYS 2 /* always play sounds */
+/* config options */
+#define AE_CONFIG_FIXED 1
+#define AE_CONFIG_AUTO 2
+#define AE_CONFIG_MATCH 3
+
enum AEQuality
{
AE_QUALITY_UNKNOWN = -1, /* Unset, unknown or incorrect quality level */
@@ -198,13 +203,13 @@ public:
* @see CAEPackIEC61937::CAEPackIEC61937()
* @returns true if the AudioEngine is capable of RAW output
*/
- virtual bool SupportsRaw() { return false; }
+ virtual bool SupportsRaw(AEDataFormat format) { return false; }
/**
* Returns true if the AudioEngine supports drain mode which is not streaming silence when idle
* @returns true if the AudioEngine is capable of drain mode
*/
- virtual bool SupportsDrain() { return false; }
+ virtual bool SupportsSilenceTimeout() { return false; }
virtual void RegisterAudioCallback(IAudioCallback* pCallback) {}
@@ -215,5 +220,11 @@ public:
* @return true if specified quality level is supported, otherwise false
*/
virtual bool SupportsQualityLevel(enum AEQuality level) { return false; }
+
+ /**
+ * AE decides whether this settings should be displayed
+ * @return true if AudioEngine wants to display this setting
+ */
+ virtual bool IsSettingVisible(const std::string &settingId) {return false; }
};
diff --git a/xbmc/cores/AudioEngine/Makefile.in b/xbmc/cores/AudioEngine/Makefile.in
index c2d7ffae4a..c1d53f55ea 100644
--- a/xbmc/cores/AudioEngine/Makefile.in
+++ b/xbmc/cores/AudioEngine/Makefile.in
@@ -39,10 +39,6 @@ SRCS += AESinkFactory.cpp
SRCS += Sinks/AESinkNULL.cpp
SRCS += Sinks/AESinkProfiler.cpp
-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
diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp
index 623c035f2f..94e2c5ba48 100644
--- a/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp
+++ b/xbmc/cores/AudioEngine/Sinks/AESinkWASAPI.cpp
@@ -500,12 +500,7 @@ unsigned int CAESinkWASAPI::AddPackets(uint8_t *data, unsigned int frames, bool
return INT_MAX;
}
- /* Inject one buffer of silence if sink has just opened */
- /* to avoid losing start of stream or GUI sound */
- if (g_advancedSettings.m_streamSilence)
- memcpy(buf, data, NumFramesRequested * m_format.m_frameSize); //fill buffer with audio
- else
- memset(buf, 0, NumFramesRequested * m_format.m_frameSize); //fill buffer with silence
+ memset(buf, 0, NumFramesRequested * m_format.m_frameSize); //fill buffer with silence
hr = m_pRenderClient->ReleaseBuffer(NumFramesRequested, flags); //pass back to audio driver
if (FAILED(hr))
@@ -520,7 +515,7 @@ unsigned int CAESinkWASAPI::AddPackets(uint8_t *data, unsigned int frames, bool
if (FAILED(hr))
CLog::Log(LOGERROR, __FUNCTION__": AudioClient Start Failed");
m_running = true; //signal that we're processing frames
- return g_advancedSettings.m_streamSilence ? NumFramesRequested : 0U;
+ return 0U;
}
#ifndef _DEBUG
@@ -545,15 +540,8 @@ unsigned int CAESinkWASAPI::AddPackets(uint8_t *data, unsigned int frames, bool
{
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;
- }
+ return INT_MAX;
}
}
diff --git a/xbmc/cores/AudioEngine/Utils/AEUtil.h b/xbmc/cores/AudioEngine/Utils/AEUtil.h
index ef67b3451c..c6a31841e4 100644
--- a/xbmc/cores/AudioEngine/Utils/AEUtil.h
+++ b/xbmc/cores/AudioEngine/Utils/AEUtil.h
@@ -49,15 +49,6 @@
#define MEMALIGN(b, x) __declspec(align(b)) x
#endif
-#define AUDIO_IS_BITSTREAM(x) ((x) == AUDIO_IEC958 || (x) == AUDIO_HDMI)
-
-enum AudioOutputs
-{
- AUDIO_ANALOG = 0,
- AUDIO_IEC958,
- AUDIO_HDMI
-};
-
// AV sync options
enum AVSync
{
diff --git a/xbmc/cores/AudioEngine/Utils/AEWAVLoader.cpp b/xbmc/cores/AudioEngine/Utils/AEWAVLoader.cpp
index c8a521c80d..de9029b44f 100644
--- a/xbmc/cores/AudioEngine/Utils/AEWAVLoader.cpp
+++ b/xbmc/cores/AudioEngine/Utils/AEWAVLoader.cpp
@@ -32,6 +32,10 @@
#include "AEUtil.h"
#include "AERemap.h"
+#ifdef TARGET_WINDOWS
+#pragma comment(lib, "libsamplerate-0.lib")
+#endif
+
typedef struct
{
char chunk_id[4];
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp
index ae3916bfd3..69992cc341 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp
@@ -74,10 +74,9 @@ bool CDVDAudioCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options
return false;
}
-#if defined(TARGET_DARWIN)
- int audioMode = CSettings::Get().GetInt("audiooutput.mode");
- if (audioMode == AUDIO_HDMI)
- m_bLpcmMode = CSettings::Get().GetBool("audiooutput.multichannellpcm");
+#if defined(TARGET_DARWIN_OSX)
+ if (CSettings::Get().GetInt("audiooutput.channels") > AE_CH_LAYOUT_2_0)
+ m_bLpcmMode = true;
#endif
m_pCodecContext = m_dllAvCodec.avcodec_alloc_context3(pCodec);
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPassthrough.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPassthrough.cpp
index ebb81384f2..5338c71fe7 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPassthrough.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPassthrough.cpp
@@ -40,29 +40,11 @@ CDVDAudioCodecPassthrough::~CDVDAudioCodecPassthrough(void)
bool CDVDAudioCodecPassthrough::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options)
{
- /* dont open if AE doesnt support RAW */
- if (!CAEFactory::SupportsRaw())
- return false;
-
- bool bSupportsAC3Out = false;
- bool bSupportsEAC3Out = false;
- bool bSupportsDTSOut = false;
- bool bSupportsTrueHDOut = false;
- bool bSupportsDTSHDOut = false;
-
- int audioMode = CSettings::Get().GetInt("audiooutput.mode");
- if (AUDIO_IS_BITSTREAM(audioMode))
- {
- bSupportsAC3Out = CSettings::Get().GetBool("audiooutput.ac3passthrough");
- bSupportsEAC3Out = CSettings::Get().GetBool("audiooutput.eac3passthrough");
- bSupportsDTSOut = CSettings::Get().GetBool("audiooutput.dtspassthrough");
- }
-
- if (audioMode == AUDIO_HDMI)
- {
- bSupportsTrueHDOut = CSettings::Get().GetBool("audiooutput.truehdpassthrough");
- bSupportsDTSHDOut = CSettings::Get().GetBool("audiooutput.dtshdpassthrough" ) && bSupportsDTSOut;
- }
+ bool bSupportsAC3Out = CAEFactory::SupportsRaw(AE_FMT_AC3);
+ bool bSupportsEAC3Out = CAEFactory::SupportsRaw(AE_FMT_EAC3);
+ bool bSupportsDTSOut = CAEFactory::SupportsRaw(AE_FMT_DTS);
+ bool bSupportsTrueHDOut = CAEFactory::SupportsRaw(AE_FMT_TRUEHD);
+ bool bSupportsDTSHDOut = CAEFactory::SupportsRaw(AE_FMT_DTSHD);
/* only get the dts core from the parser if we don't support dtsHD */
m_info.SetCoreOnly(!bSupportsDTSHDOut);
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPassthroughFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPassthroughFFmpeg.cpp
index a9f3d409f0..f49b5b5a7f 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPassthroughFFmpeg.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPassthroughFFmpeg.cpp
@@ -25,6 +25,7 @@
#include "settings/MediaSettings.h"
#include "settings/Settings.h"
#include "utils/log.h"
+#include "cores/AudioEngine/AEFactory.h"
//These values are forced to allow spdif out
#define OUT_SAMPLESIZE 16
@@ -293,17 +294,17 @@ bool CDVDAudioCodecPassthroughFFmpeg::SupportsFormat(CDVDStreamInfo &hints)
bool CDVDAudioCodecPassthroughFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options)
{
- int audioMode = CSettings::Get().GetInt("audiooutput.mode");
-
// TODO - move this stuff somewhere else
- if (AUDIO_IS_BITSTREAM(audioMode))
+ bool m_bSupportsAC3Out = CAEFactory::SupportsRaw(AE_FMT_AC3);
+ bool m_bSupportsEAC3Out = CAEFactory::SupportsRaw(AE_FMT_EAC3);
+ bool m_bSupportsDTSOut = CAEFactory::SupportsRaw(AE_FMT_DTS);
+
+ if ((hints.codec == AV_CODEC_ID_AC3 && !m_bSupportsAC3Out) ||
+ (hints.codec == AV_CODEC_ID_EAC3 && !m_bSupportsEAC3Out) ||
+ (hints.codec == AV_CODEC_ID_DTS && !m_bSupportsDTSOut))
{
- m_bSupportsAC3Out = CSettings::Get().GetBool("audiooutput.ac3passthrough");
- m_bSupportsDTSOut = CSettings::Get().GetBool("audiooutput.dtspassthrough");
- m_bSupportsAACOut = CSettings::Get().GetBool("audiooutput.passthroughaac");
- }
- else
return false;
+ }
// TODO - this is only valid for video files, and should be moved somewhere else
if( hints.channels == 2 && CMediaSettings::Get().GetCurrentVideoSettings().m_OutputToAllSpeakers )
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp b/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp
index 183e2c5163..4864e47438 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp
@@ -325,28 +325,26 @@ CDVDVideoCodec* CDVDFactoryCodec::CreateVideoCodec(CDVDStreamInfo &hint, unsigne
return NULL;
}
-CDVDAudioCodec* CDVDFactoryCodec::CreateAudioCodec( CDVDStreamInfo &hint, bool passthrough /* = true */)
+CDVDAudioCodec* CDVDFactoryCodec::CreateAudioCodec( CDVDStreamInfo &hint)
{
CDVDAudioCodec* pCodec = NULL;
CDVDCodecOptions options;
- if (passthrough)
- {
+ // try passthrough first
#if defined(TARGET_DARWIN_OSX) || defined(TARGET_DARWIN_IOS)
- switch(hint.codec)
- {
- case AV_CODEC_ID_AC3:
- case AV_CODEC_ID_DTS:
- pCodec = OpenCodec( new CDVDAudioCodecPassthroughFFmpeg(), hint, options );
- if( pCodec ) return pCodec;
- break;
- default:
- break;
- }
-#endif
- pCodec = OpenCodec( new CDVDAudioCodecPassthrough(), hint, options );
- if( pCodec ) return pCodec;
+ switch(hint.codec)
+ {
+ case AV_CODEC_ID_AC3:
+ case AV_CODEC_ID_DTS:
+ pCodec = OpenCodec( new CDVDAudioCodecPassthroughFFmpeg(), hint, options );
+ if( pCodec ) return pCodec;
+ break;
+ default:
+ break;
}
+#endif
+ pCodec = OpenCodec( new CDVDAudioCodecPassthrough(), hint, options );
+ if( pCodec ) return pCodec;
switch (hint.codec)
{
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.h b/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.h
index f7c03daed5..f7ce44cb33 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.h
+++ b/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.h
@@ -36,7 +36,7 @@ class CDVDFactoryCodec
{
public:
static CDVDVideoCodec* CreateVideoCodec(CDVDStreamInfo &hint, unsigned int surfaces = 0, const std::vector<ERenderFormat>& formats = std::vector<ERenderFormat>());
- static CDVDAudioCodec* CreateAudioCodec(CDVDStreamInfo &hint, bool passthrough = true );
+ static CDVDAudioCodec* CreateAudioCodec(CDVDStreamInfo &hint );
static CDVDOverlayCodec* CreateOverlayCodec(CDVDStreamInfo &hint );
static CDVDAudioCodec* OpenCodec(CDVDAudioCodec* pCodec, CDVDStreamInfo &hint, CDVDCodecOptions &options );
diff --git a/xbmc/cores/dvdplayer/DVDPlayerAudio.cpp b/xbmc/cores/dvdplayer/DVDPlayerAudio.cpp
index 38a53e7f67..df3df14672 100644
--- a/xbmc/cores/dvdplayer/DVDPlayerAudio.cpp
+++ b/xbmc/cores/dvdplayer/DVDPlayerAudio.cpp
@@ -145,10 +145,8 @@ CDVDPlayerAudio::~CDVDPlayerAudio()
bool CDVDPlayerAudio::OpenStream( CDVDStreamInfo &hints )
{
- bool passthrough = AUDIO_IS_BITSTREAM(CSettings::Get().GetInt("audiooutput.mode"));
-
CLog::Log(LOGNOTICE, "Finding audio codec for: %i", hints.codec);
- CDVDAudioCodec* codec = CDVDFactoryCodec::CreateAudioCodec(hints, passthrough);
+ CDVDAudioCodec* codec = CDVDFactoryCodec::CreateAudioCodec(hints);
if( !codec )
{
CLog::Log(LOGERROR, "Unsupported audio codec");
@@ -868,12 +866,8 @@ void CDVDPlayerAudio::WaitForBuffers()
bool CDVDPlayerAudio::SwitchCodecIfNeeded()
{
- // check if passthrough is disabled
- if (!AUDIO_IS_BITSTREAM(CSettings::Get().GetInt("audiooutput.mode")))
- return false;
-
CLog::Log(LOGDEBUG, "CDVDPlayerAudio: Sample rate changed, checking for passthrough");
- CDVDAudioCodec *codec = CDVDFactoryCodec::CreateAudioCodec(m_streaminfo, true);
+ CDVDAudioCodec *codec = CDVDFactoryCodec::CreateAudioCodec(m_streaminfo);
if (!codec || codec->NeedPassthrough() == m_pAudioCodec->NeedPassthrough()) {
// passthrough state has not changed
delete codec;
diff --git a/xbmc/cores/omxplayer/OMXAudio.cpp b/xbmc/cores/omxplayer/OMXAudio.cpp
index c6ab3b9b60..764f26a604 100644
--- a/xbmc/cores/omxplayer/OMXAudio.cpp
+++ b/xbmc/cores/omxplayer/OMXAudio.cpp
@@ -39,6 +39,7 @@
#include "settings/Settings.h"
#include "guilib/LocalizeStrings.h"
#include "cores/AudioEngine/Utils/AEConvert.h"
+#include "cores/AudioEngine/AEFactory.h"
using namespace std;
@@ -205,12 +206,12 @@ bool COMXAudio::PortSettingsChanged()
if(!m_omx_splitter.Initialize("OMX.broadcom.audio_splitter", OMX_IndexParamAudioInit))
return false;
}
- if (CSettings::Get().GetBool("audiooutput.dualaudio") || CSettings::Get().GetInt("audiooutput.mode") == AUDIO_ANALOG)
+ if (CSettings::Get().GetBool("audiooutput.dualaudio") || CSettings::Get().GetString("audiooutput.audiodevice") == "Analogue")
{
if(!m_omx_render_analog.Initialize("OMX.broadcom.audio_render", OMX_IndexParamAudioInit))
return false;
}
- if (CSettings::Get().GetBool("audiooutput.dualaudio") || CSettings::Get().GetInt("audiooutput.mode") == AUDIO_HDMI)
+ if (CSettings::Get().GetBool("audiooutput.dualaudio") || CSettings::Get().GetString("audiooutput.audiodevice") == "HDMI")
{
if(!m_omx_render_hdmi.Initialize("OMX.broadcom.audio_render", OMX_IndexParamAudioInit))
return false;
@@ -235,6 +236,8 @@ bool COMXAudio::PortSettingsChanged()
m_pcm_output.eChannelMapping[0] = OMX_AUDIO_ChannelLF;
m_pcm_output.eChannelMapping[1] = OMX_AUDIO_ChannelRF;
m_pcm_output.nChannels = 2;
+ /* limit samplerate (through resampling) if requested */
+ m_pcm_output.nSamplingRate = std::min((int)m_pcm_output.nSamplingRate, CSettings::Get().GetInt("audiooutput.samplerate"));
m_pcm_output.nPortIndex = m_omx_mixer.GetOutputPort();
omx_err = m_omx_mixer.SetParameter(OMX_IndexParamAudioPcm, &m_pcm_output);
@@ -774,6 +777,9 @@ bool COMXAudio::Initialize(AEAudioFormat format, OMXClock *clock, CDVDStreamInfo
CLog::Log(LOGDEBUG, "COMXAudio::Initialize device passthrough %d hwdecode %d",
m_Passthrough, m_HWDecode);
+ /* dummy call to inform PiAudioAE that audo is active */
+ CAEFactory::MakeStream((enum AEDataFormat)0, 0, 0, (CAEChannelInfo)0, 0);
+
return true;
}
@@ -840,6 +846,9 @@ bool COMXAudio::Deinitialize()
m_last_pts = DVD_NOPTS_VALUE;
+ /* dummy call to inform PiAudioAE that audo is inactive */
+ CAEFactory::FreeStream(0);
+
return true;
}
diff --git a/xbmc/cores/omxplayer/OMXPlayerAudio.cpp b/xbmc/cores/omxplayer/OMXPlayerAudio.cpp
index 08b432fed4..999ce402a9 100644
--- a/xbmc/cores/omxplayer/OMXPlayerAudio.cpp
+++ b/xbmc/cores/omxplayer/OMXPlayerAudio.cpp
@@ -42,6 +42,7 @@
#include "OMXPlayer.h"
#include "linux/RBP.h"
+#include "cores/AudioEngine/AEFactory.h"
#include <iostream>
#include <sstream>
@@ -83,7 +84,6 @@ OMXPlayerAudio::OMXPlayerAudio(OMXClock *av_clock, CDVDMessageQueue& parent)
m_messageQueue.SetMaxDataSize((small_mem ? 3:6) * 1024 * 1024);
m_messageQueue.SetMaxTimeSize(8.0);
- m_use_passthrough = false;
m_passthrough = false;
m_use_hw_decode = false;
m_hw_decode = false;
@@ -95,15 +95,10 @@ OMXPlayerAudio::OMXPlayerAudio(OMXClock *av_clock, CDVDMessageQueue& parent)
OMXPlayerAudio::~OMXPlayerAudio()
{
CloseStream(false);
-
- m_DllBcmHost.Unload();
}
bool OMXPlayerAudio::OpenStream(CDVDStreamInfo &hints)
{
- if(!m_DllBcmHost.Load())
- return false;
-
m_bad_state = false;
COMXAudioCodecOMX *codec = new COMXAudioCodecOMX();
@@ -146,8 +141,6 @@ void OMXPlayerAudio::OpenStream(CDVDStreamInfo &hints, COMXAudioCodecOMX *codec)
m_flush = false;
m_nChannels = 0;
m_stalled = m_messageQueue.GetPacketCount(CDVDMsg::DEMUXER_PACKET) == 0;
- m_use_passthrough = (CSettings::Get().GetInt("audiooutput.mode") == AUDIO_HDMI &&
- !CSettings::Get().GetBool("audiooutput.dualaudio")) ? true : false ;
m_use_hw_decode = g_advancedSettings.m_omxHWAudioDecode;
m_format.m_dataFormat = GetDataFormat(m_hints);
m_format.m_sampleRate = 0;
@@ -511,13 +504,6 @@ bool OMXPlayerAudio::Passthrough() const
AEDataFormat OMXPlayerAudio::GetDataFormat(CDVDStreamInfo hints)
{
AEDataFormat dataFormat = AE_FMT_S16NE;
- bool hdmi_passthrough_dts = false;
- bool hdmi_passthrough_ac3 = false;
-
- if (m_DllBcmHost.vc_tv_hdmi_audio_supported(EDID_AudioFormat_eAC3, 2, EDID_AudioSampleRate_e44KHz, EDID_AudioSampleSize_16bit ) == 0)
- hdmi_passthrough_ac3 = true;
- if (m_DllBcmHost.vc_tv_hdmi_audio_supported(EDID_AudioFormat_eDTS, 2, EDID_AudioSampleRate_e44KHz, EDID_AudioSampleSize_16bit ) == 0)
- hdmi_passthrough_dts = true;
m_passthrough = false;
m_hw_decode = false;
@@ -525,18 +511,15 @@ AEDataFormat OMXPlayerAudio::GetDataFormat(CDVDStreamInfo hints)
/* check our audio capabilties */
/* pathrought is overriding hw decode*/
- if(AUDIO_IS_BITSTREAM(CSettings::Get().GetInt("audiooutput.mode")) && m_use_passthrough)
+ if(hints.codec == AV_CODEC_ID_AC3 && CAEFactory::SupportsRaw(AE_FMT_AC3))
{
- if(hints.codec == AV_CODEC_ID_AC3 && CSettings::Get().GetBool("audiooutput.ac3passthrough") && hdmi_passthrough_ac3)
- {
- dataFormat = AE_FMT_AC3;
- m_passthrough = true;
- }
- if(hints.codec == AV_CODEC_ID_DTS && CSettings::Get().GetBool("audiooutput.dtspassthrough") && hdmi_passthrough_dts)
- {
- dataFormat = AE_FMT_DTS;
- m_passthrough = true;
- }
+ dataFormat = AE_FMT_AC3;
+ m_passthrough = true;
+ }
+ if(hints.codec == AV_CODEC_ID_DTS && CAEFactory::SupportsRaw(AE_FMT_DTS))
+ {
+ dataFormat = AE_FMT_DTS;
+ m_passthrough = true;
}
/* hw decode */
diff --git a/xbmc/cores/omxplayer/OMXPlayerAudio.h b/xbmc/cores/omxplayer/OMXPlayerAudio.h
index 394f3091ca..685a6863d1 100644
--- a/xbmc/cores/omxplayer/OMXPlayerAudio.h
+++ b/xbmc/cores/omxplayer/OMXPlayerAudio.h
@@ -50,7 +50,6 @@ protected:
OMXClock *m_av_clock;
COMXAudio m_omxAudio;
std::string m_codec_name;
- bool m_use_passthrough;
bool m_passthrough;
bool m_use_hw_decode;
bool m_hw_decode;
@@ -70,7 +69,6 @@ protected:
int m_nChannels;
bool m_DecoderOpen;
- DllBcmHost m_DllBcmHost;
bool m_bad_state;
virtual void OnStartup();
diff --git a/xbmc/cores/paplayer/DVDPlayerCodec.cpp b/xbmc/cores/paplayer/DVDPlayerCodec.cpp
index 355589f4cb..5bd7ec18c0 100644
--- a/xbmc/cores/paplayer/DVDPlayerCodec.cpp
+++ b/xbmc/cores/paplayer/DVDPlayerCodec.cpp
@@ -145,8 +145,7 @@ bool DVDPlayerCodec::Init(const CStdString &strFile, unsigned int filecache)
CDVDStreamInfo hint(*pStream, true);
- bool passthrough = AUDIO_IS_BITSTREAM(CSettings::Get().GetInt("audiooutput.mode"));
- m_pAudioCodec = CDVDFactoryCodec::CreateAudioCodec(hint, passthrough);
+ m_pAudioCodec = CDVDFactoryCodec::CreateAudioCodec(hint);
if (!m_pAudioCodec)
{
CLog::Log(LOGERROR, "%s: Could not create audio codec", __FUNCTION__);
diff --git a/xbmc/cores/playercorefactory/PlayerCoreFactory.cpp b/xbmc/cores/playercorefactory/PlayerCoreFactory.cpp
index 8e7a0f5b87..16319b91c6 100644
--- a/xbmc/cores/playercorefactory/PlayerCoreFactory.cpp
+++ b/xbmc/cores/playercorefactory/PlayerCoreFactory.cpp
@@ -37,6 +37,7 @@
#include "PlayerCoreConfig.h"
#include "PlayerSelectionRule.h"
#include "guilib/LocalizeStrings.h"
+#include "cores/AudioEngine/AEFactory.h"
#define PLAYERCOREFACTORY_XML "playercorefactory.xml"
@@ -189,13 +190,8 @@ void CPlayerCoreFactory::GetPlayers( const CFileItem& item, VECPLAYERCORES &vecC
if (bAdd)
{
- if( CSettings::Get().GetInt("audiooutput.mode") == AUDIO_ANALOG )
- {
- CLog::Log(LOGDEBUG, "CPlayerCoreFactory::GetPlayers: adding PAPlayer (%d)", EPC_PAPLAYER);
- vecCores.push_back(EPC_PAPLAYER);
- }
- else if (url.GetFileType().Equals("ac3")
- || url.GetFileType().Equals("dts"))
+ if ((url.GetFileType().Equals("ac3") && !CAEFactory::SupportsRaw(AE_FMT_AC3))
+ || (url.GetFileType().Equals("dts") && !CAEFactory::SupportsRaw(AE_FMT_DTS)))
{
CLog::Log(LOGDEBUG, "CPlayerCoreFactory::GetPlayers: adding DVDPlayer (%d)", EPC_DVDPLAYER);
vecCores.push_back(EPC_DVDPLAYER);
diff --git a/xbmc/settings/AdvancedSettings.cpp b/xbmc/settings/AdvancedSettings.cpp
index 0f30d84442..619490d29b 100644
--- a/xbmc/settings/AdvancedSettings.cpp
+++ b/xbmc/settings/AdvancedSettings.cpp
@@ -115,12 +115,6 @@ void CAdvancedSettings::Initialize()
m_ac3Gain = 12.0f;
m_audioApplyDrc = true;
m_dvdplayerIgnoreDTSinWAV = false;
- m_audioResample = 0;
- m_allowTranscode44100 = false;
- m_audioForceDirectSound = false;
- m_audioAudiophile = false;
- m_allChannelStereo = false;
- m_streamSilence = false;
//default hold time of 25 ms, this allows a 20 hertz sine to pass undistorted
m_limiterHold = 0.025f;
@@ -502,14 +496,6 @@ void CAdvancedSettings::ParseSettingsFile(const CStdString &file)
XMLUtils::GetInt(pElement, "percentseekforwardbig", m_musicPercentSeekForwardBig, 0, 100);
XMLUtils::GetInt(pElement, "percentseekbackwardbig", m_musicPercentSeekBackwardBig, -100, 0);
- XMLUtils::GetInt(pElement, "resample", m_audioResample, 0, 192000);
- XMLUtils::GetBoolean(pElement, "allowtranscode44100", m_allowTranscode44100);
- XMLUtils::GetBoolean(pElement, "forceDirectSound", m_audioForceDirectSound);
- XMLUtils::GetBoolean(pElement, "audiophile", m_audioAudiophile);
- XMLUtils::GetBoolean(pElement, "allchannelstereo", m_allChannelStereo);
- XMLUtils::GetBoolean(pElement, "streamsilence", m_streamSilence);
- XMLUtils::GetString(pElement, "transcodeto", m_audioTranscodeTo);
-
TiXmlElement* pAudioExcludes = pElement->FirstChildElement("excludefromlisting");
if (pAudioExcludes)
GetCustomRegexps(pAudioExcludes, m_audioExcludeFromListingRegExps);
diff --git a/xbmc/settings/AdvancedSettings.h b/xbmc/settings/AdvancedSettings.h
index e6e02ad29a..d46ee0bc85 100644
--- a/xbmc/settings/AdvancedSettings.h
+++ b/xbmc/settings/AdvancedSettings.h
@@ -138,13 +138,6 @@ class CAdvancedSettings : public ISettingCallback, public ISettingsHandler
CStdString m_audioDefaultPlayer;
float m_audioPlayCountMinimumPercent;
bool m_dvdplayerIgnoreDTSinWAV;
- int m_audioResample;
- bool m_allowTranscode44100;
- bool m_audioForceDirectSound;
- bool m_audioAudiophile;
- bool m_allChannelStereo;
- bool m_streamSilence;
- CStdString m_audioTranscodeTo;
float m_limiterHold;
float m_limiterRelease;
diff --git a/xbmc/settings/Settings.cpp b/xbmc/settings/Settings.cpp
index d328c28fb8..57ba0c1e66 100644
--- a/xbmc/settings/Settings.cpp
+++ b/xbmc/settings/Settings.cpp
@@ -372,7 +372,7 @@ void CSettings::Uninitialize()
m_settingsManager->UnregisterSettingOptionsFiller("aequalitylevels");
m_settingsManager->UnregisterSettingOptionsFiller("audiodevices");
m_settingsManager->UnregisterSettingOptionsFiller("audiodevicespassthrough");
- m_settingsManager->UnregisterSettingOptionsFiller("audiooutputmodes");
+ m_settingsManager->UnregisterSettingOptionsFiller("audiostreamsilence");
m_settingsManager->UnregisterSettingOptionsFiller("charsets");
m_settingsManager->UnregisterSettingOptionsFiller("epgguideviews");
m_settingsManager->UnregisterSettingOptionsFiller("fontheights");
@@ -687,7 +687,7 @@ void CSettings::InitializeOptionFillers()
m_settingsManager->RegisterSettingOptionsFiller("aequalitylevels", CAEFactory::SettingOptionsAudioQualityLevelsFiller);
m_settingsManager->RegisterSettingOptionsFiller("audiodevices", CAEFactory::SettingOptionsAudioDevicesFiller);
m_settingsManager->RegisterSettingOptionsFiller("audiodevicespassthrough", CAEFactory::SettingOptionsAudioDevicesPassthroughFiller);
- m_settingsManager->RegisterSettingOptionsFiller("audiooutputmodes", CAEFactory::SettingOptionsAudioOutputModesFiller);
+ m_settingsManager->RegisterSettingOptionsFiller("audiostreamsilence", CAEFactory::SettingOptionsAudioStreamsilenceFiller);
m_settingsManager->RegisterSettingOptionsFiller("charsets", CCharsetConverter::SettingOptionsCharsetsFiller);
m_settingsManager->RegisterSettingOptionsFiller("epgguideviews", PVR::CGUIWindowPVRGuide::SettingOptionsEpgGuideViewFiller);
m_settingsManager->RegisterSettingOptionsFiller("fonts", GUIFontManager::SettingOptionsFontsFiller);
@@ -797,9 +797,6 @@ void CSettings::InitializeConditions()
if (g_application.IsStandAlone())
m_settingsManager->AddCondition("isstandalone");
- if (CAEFactory::SupportsDrain())
- m_settingsManager->AddCondition("audiosupportsdrain");
-
if(CAEFactory::SupportsQualitySetting())
m_settingsManager->AddCondition("has_ae_quality_levels");
@@ -824,6 +821,7 @@ void CSettings::InitializeConditions()
m_settingsManager->AddCondition("profilehassettingslocked", ProfileHasSettingsLocked);
m_settingsManager->AddCondition("profilehasvideoslocked", ProfileHasVideosLocked);
m_settingsManager->AddCondition("profilelockmode", ProfileLockMode);
+ m_settingsManager->AddCondition("aesettingvisible", CAEFactory::IsSettingVisible);
}
void CSettings::InitializeISettingsHandlers()
@@ -889,7 +887,9 @@ void CSettings::InitializeISettingCallbacks()
m_settingsManager->RegisterCallback(&CStereoscopicsManager::Get(), settingSet);
settingSet.clear();
- settingSet.insert("audiooutput.mode");
+ settingSet.insert("audiooutput.config");
+ settingSet.insert("audiooutput.samplerate");
+ settingSet.insert("audiooutput.passthrough");
settingSet.insert("audiooutput.channels");
settingSet.insert("audiooutput.processquality");
settingSet.insert("audiooutput.guisoundmode");
@@ -897,10 +897,8 @@ void CSettings::InitializeISettingCallbacks()
settingSet.insert("audiooutput.ac3passthrough");
settingSet.insert("audiooutput.eac3passthrough");
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("audiooutput.streamsilence");
diff --git a/xbmc/video/dialogs/GUIDialogAudioSubtitleSettings.cpp b/xbmc/video/dialogs/GUIDialogAudioSubtitleSettings.cpp
index 0dd0075a44..5d0f2eff8d 100644
--- a/xbmc/video/dialogs/GUIDialogAudioSubtitleSettings.cpp
+++ b/xbmc/video/dialogs/GUIDialogAudioSubtitleSettings.cpp
@@ -96,14 +96,13 @@ void CGUIDialogAudioSubtitleSettings::CreateSettings()
if (SupportsAudioFeature(IPC_AUD_SELECT_STREAM))
AddAudioStreams(AUDIO_SETTINGS_STREAM);
- // only show stuff available in digital mode if we have digital output
+ // TODO: remove this setting
if (SupportsAudioFeature(IPC_AUD_OUTPUT_STEREO))
- AddBool(AUDIO_SETTINGS_OUTPUT_TO_ALL_SPEAKERS, 252, &CMediaSettings::Get().GetCurrentVideoSettings().m_OutputToAllSpeakers, AUDIO_IS_BITSTREAM(CSettings::Get().GetInt("audiooutput.mode")));
+ AddBool(AUDIO_SETTINGS_OUTPUT_TO_ALL_SPEAKERS, 252, &CMediaSettings::Get().GetCurrentVideoSettings().m_OutputToAllSpeakers, true);
- int settings[3] = { 338, 339, 420 }; //ANALOG, IEC958, HDMI
- m_outputmode = CSettings::Get().GetInt("audiooutput.mode");
+ m_outputmode = CSettings::Get().GetBool("audiooutput.passthrough");
if (SupportsAudioFeature(IPC_AUD_SELECT_OUTPUT))
- AddSpin(AUDIO_SETTINGS_DIGITAL_ANALOG, 337, &m_outputmode, 3, settings);
+ AddBool(AUDIO_SETTINGS_DIGITAL_ANALOG, 348, &m_outputmode);
AddSeparator(7);
m_subtitleVisible = g_application.m_pPlayer->GetSubtitleVisible();
@@ -275,16 +274,9 @@ void CGUIDialogAudioSubtitleSettings::OnSettingChanged(SettingInfo &setting)
}
else if (setting.id == AUDIO_SETTINGS_DIGITAL_ANALOG)
{
- bool bitstream = false;
+ CSettings::Get().SetBool("audiooutput.passthrough", !m_outputmode);
- switch(m_outputmode)
- {
- case 0: CSettings::Get().SetInt("audiooutput.mode", AUDIO_ANALOG ); break;
- case 1: CSettings::Get().SetInt("audiooutput.mode", AUDIO_IEC958 ); bitstream = true; break;
- case 2: CSettings::Get().SetInt("audiooutput.mode", AUDIO_HDMI ); bitstream = true; break;
- }
-
- EnableSettings(AUDIO_SETTINGS_OUTPUT_TO_ALL_SPEAKERS, bitstream);
+ EnableSettings(AUDIO_SETTINGS_OUTPUT_TO_ALL_SPEAKERS, true);
EnableSettings(AUDIO_SETTINGS_VOLUME, !g_application.m_pPlayer->IsPassthrough());
}
else if (setting.id == SUBTITLE_SETTINGS_ENABLE)
diff --git a/xbmc/video/dialogs/GUIDialogAudioSubtitleSettings.h b/xbmc/video/dialogs/GUIDialogAudioSubtitleSettings.h
index ad5f3f18b7..f8c578e584 100644
--- a/xbmc/video/dialogs/GUIDialogAudioSubtitleSettings.h
+++ b/xbmc/video/dialogs/GUIDialogAudioSubtitleSettings.h
@@ -47,7 +47,7 @@ protected:
float m_volume;
int m_audioStream;
int m_subtitleStream;
- int m_outputmode;
+ bool m_outputmode;
bool m_subtitleVisible;
Features m_audioCaps;
Features m_subCaps;