diff options
author | Rainer Hochecker <fernetmenta@online.de> | 2013-10-31 23:29:28 -0700 |
---|---|---|
committer | Rainer Hochecker <fernetmenta@online.de> | 2013-10-31 23:29:28 -0700 |
commit | c9df5c3a88b5e513e790b127b8d064b004463765 (patch) | |
tree | c12bc7f2425775c6a66147f8a75f5b155590f493 | |
parent | 64ef7b9a36627ffd7b37dff32a8e8f1389cf6d7b (diff) | |
parent | dff3ebdb077528cb293760c559eb2e74de47ade4 (diff) |
Merge pull request #3455 from FernetMenta/audiopage
new audio settings
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 ¤t) -{ - 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 ¤t) { 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 ¤t) +{ + 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 ¤t, 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 ¤t); static void SettingOptionsAudioDevicesPassthroughFiller(const CSetting *setting, std::vector< std::pair<std::string, std::string> > &list, std::string ¤t); - static void SettingOptionsAudioOutputModesFiller(const CSetting *setting, std::vector< std::pair<std::string, int> > &list, int ¤t); static void SettingOptionsAudioQualityLevelsFiller(const CSetting *setting, std::vector< std::pair<std::string, int> > &list, int ¤t); + static void SettingOptionsAudioStreamsilenceFiller(const CSetting *setting, std::vector< std::pair<std::string, int> > &list, int ¤t); + 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; |