Merge pull request #3925 from popcornmix/piaudio_sink
authorhuceke <ebsi4711@gmail.com>
Sun, 5 Jan 2014 17:09:43 +0000 (09:09 -0800)
committerhuceke <ebsi4711@gmail.com>
Sun, 5 Jan 2014 17:09:43 +0000 (09:09 -0800)
[rbp] Add Pi audio sink for ActiveAE

16 files changed:
system/settings/rbp.xml
xbmc/cores/AudioEngine/AEFactory.cpp
xbmc/cores/AudioEngine/AESinkFactory.cpp
xbmc/cores/AudioEngine/Engines/PiAudio/PiAudioAE.cpp [deleted file]
xbmc/cores/AudioEngine/Engines/PiAudio/PiAudioAE.h [deleted file]
xbmc/cores/AudioEngine/Makefile.in
xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp [new file with mode: 0644]
xbmc/cores/AudioEngine/Sinks/AESinkPi.h [new file with mode: 0644]
xbmc/cores/omxplayer/OMXAudio.cpp
xbmc/cores/omxplayer/OMXAudio.h
xbmc/cores/omxplayer/OMXPlayer.cpp
xbmc/cores/omxplayer/OMXPlayerAudio.cpp
xbmc/cores/omxplayer/omxplayer_advancedsettings.xml
xbmc/cores/playercorefactory/PlayerCoreConfig.h
xbmc/linux/RBP.cpp
xbmc/linux/RBP.h

index cfdeea6..3af681d 100644 (file)
         </setting>
       </group>
     </category>
-
-    <category id="audiooutput" label="772" help="36360">
+    <category id="audiooutput">
       <group id="1">
-        <setting id="audiooutput.audiodevice">
-          <level>1</level>
-          <default>HDMI</default>
-          <constraints>
-            <options>audiodevices</options>
-          </constraints>
-          <control type="list" format="string" />
-        </setting>
         <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>
-          <control type="toggle" />
-        </setting>
-        <setting id="audiooutput.boostcentre" type="boolean" label="37018" help="36543">
-          <level>2</level>
-          <default>false</default>
           <control type="toggle" />
         </setting>
-        <setting id="audiooutput.config">
-          <visible>false</visible>
-        </setting>
-        <setting id="audiooutput.stereoupmix">
-          <visible>false</visible>
-        </setting>
-        <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">
-          <visible>false</visible>
-        </setting>
-        <setting id="audiooutput.dtshdpassthrough">
-          <visible>false</visible>
-        </setting>
-        <setting id="audiooutput.eac3passthrough">
-          <visible>false</visible>
-        </setting>
-        <setting id="audiooutput.ac3passthrough">
-          <dependencies>
-            <dependency type="visible">
-              <condition on="property" name="aesettingvisible" setting="audiooutput.audiodevice">audiooutput.ac3passthrough</condition>
-            </dependency>
-          </dependencies>
-        </setting>
-        <setting id="audiooutput.dtspassthrough">
-          <dependencies>
-            <dependency type="visible">
-              <condition on="property" name="aesettingvisible" setting="audiooutput.audiodevice">audiooutput.dtspassthrough</condition>
-            </dependency>
-          </dependencies>
-        </setting>
       </group>
     </category>
   </section>
index e798e0f..b76d304 100644 (file)
   #include "Engines/PulseAE/PulseAE.h"
 #endif
 
-#if defined(TARGET_RASPBERRY_PI)
-  #include "Engines/PiAudio/PiAudioAE.h"
-#endif
-
 #include "guilib/LocalizeStrings.h"
 #include "settings/lib/Setting.h"
 #include "settings/Settings.h"
@@ -55,9 +51,7 @@ bool CAEFactory::LoadEngine()
 {
   bool loaded = false;
 
-#if defined(TARGET_RASPBERRY_PI)
-  return CAEFactory::LoadEngine(AE_ENGINE_PIAUDIO);
-#elif defined(TARGET_DARWIN)
+#if defined(TARGET_DARWIN)
   return CAEFactory::LoadEngine(AE_ENGINE_COREAUDIO);
 #endif
 
@@ -104,9 +98,6 @@ bool CAEFactory::LoadEngine(enum AEEngine engine)
 #if defined(HAS_PULSEAUDIO)
     case AE_ENGINE_PULSE    : AE = new CPulseAE(); break;
 #endif
-#if defined(TARGET_RASPBERRY_PI)
-    case AE_ENGINE_PIAUDIO  : AE = new PiAudioAE::CPiAudioAE(); break;
-#endif
     default:
       return false;
   }
index e7fb9a3..7dc504b 100644 (file)
@@ -25,6 +25,8 @@
   #include "Sinks/AESinkDirectSound.h"
 #elif defined(TARGET_ANDROID)
   #include "Sinks/AESinkAUDIOTRACK.h"
+#elif defined(TARGET_RASPBERRY_PI)
+  #include "Sinks/AESinkPi.h"
 #elif defined(TARGET_LINUX) || defined(TARGET_FREEBSD)
   #if defined(HAS_ALSA)
     #include "Sinks/AESinkALSA.h"
@@ -55,6 +57,8 @@ void CAESinkFactory::ParseDevice(std::string &device, std::string &driver)
         driver == "DIRECTSOUND" ||
 #elif defined(TARGET_ANDROID)
         driver == "AUDIOTRACK"  ||
+#elif defined(TARGET_RASPBERRY_PI)
+        driver == "Pi"          ||
 #elif defined(TARGET_LINUX) || defined(TARGET_FREEBSD)
   #if defined(HAS_ALSA)
         driver == "ALSA"        ||
@@ -110,6 +114,10 @@ IAESink *CAESinkFactory::Create(std::string &device, AEAudioFormat &desiredForma
   if (driver.empty() || driver == "AUDIOTRACK")
     TRY_SINK(AUDIOTRACK)
 
+#elif defined(TARGET_RASPBERRY_PI)
+  if (driver.empty() || driver == "Pi")
+    TRY_SINK(Pi)
+
 #elif defined(TARGET_LINUX) || defined(TARGET_FREEBSD)
   #if defined(HAS_ALSA)
   if (driver.empty() || driver == "ALSA")
@@ -143,6 +151,8 @@ void CAESinkFactory::EnumerateEx(AESinkInfoList &list, bool force)
   ENUMERATE_SINK(WASAPI, force);
 #elif defined(TARGET_ANDROID)
     ENUMERATE_SINK(AUDIOTRACK, force);
+#elif defined(TARGET_RASPBERRY_PI)
+    ENUMERATE_SINK(Pi, force);
 #elif defined(TARGET_LINUX) || defined(TARGET_FREEBSD)
   #if defined(HAS_ALSA)
     ENUMERATE_SINK(ALSA, force);
diff --git a/xbmc/cores/AudioEngine/Engines/PiAudio/PiAudioAE.cpp b/xbmc/cores/AudioEngine/Engines/PiAudio/PiAudioAE.cpp
deleted file mode 100644 (file)
index ccf40b0..0000000
+++ /dev/null
@@ -1,206 +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 "PiAudioAE.h"
-
-using namespace PiAudioAE;
-#include "Utils/AEUtil.h"
-
-#include "settings/Settings.h"
-#include "settings/AdvancedSettings.h"
-#include "windowing/WindowingFactory.h"
-
-#if defined(TARGET_RASPBERRY_PI)
-#include "linux/RBP.h"
-#endif
-
-CPiAudioAE::CPiAudioAE()
-: CThread("CPiAudio")
-{
-}
-
-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)
-  char response[80] = "";
-  char command[80] = "";
-  sprintf(command, "force_audio hdmi %d", enable);
-  vc_gencmd(response, sizeof response, command);
-#endif
-}
-
-bool CPiAudioAE::Suspend()
-{
-  return true;
-}
-
-bool CPiAudioAE::Resume()
-{
-  return true;
-}
-
-float CPiAudioAE::GetVolume()
-{
-  return m_aeVolume;
-}
-
-void CPiAudioAE::SetVolume(const float volume)
-{
-  m_aeVolume = std::max( 0.0f, std::min(1.0f, volume));
-}
-
-void CPiAudioAE::SetMute(const bool enabled)
-{
-  m_aeMuted = enabled;
-}
-
-bool CPiAudioAE::IsMuted()
-{
-  return m_aeMuted;
-}
-
-IAEStream *CPiAudioAE::MakeStream(enum AEDataFormat dataFormat, unsigned int sampleRate, unsigned int encodedSampleRate, CAEChannelInfo channelLayout, unsigned int options)
-{
-  return NULL;
-}
-
-IAEStream *CPiAudioAE::FreeStream(IAEStream *stream)
-{
-  // will retrigger the streamsilence timer
-  UpdateStreamSilence();
-  return NULL;
-}
-
-IAESound *CPiAudioAE::MakeSound(const std::string& file)
-{
-  return NULL;
-}
-
-void CPiAudioAE::FreeSound(IAESound *sound)
-{
-}
-
-bool CPiAudioAE::SupportsRaw(AEDataFormat format)
-{
-  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::SupportsSilenceTimeout()
-{
-  return true;
-}
-
-void CPiAudioAE::OnSettingsChange(const std::string& setting)
-{
-  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
deleted file mode 100644 (file)
index 944fba8..0000000
+++ /dev/null
@@ -1,80 +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 "system.h"
-#include "threads/Thread.h"
-
-#include "Interfaces/AEStream.h"
-#include "Interfaces/AESound.h"
-#include "AEFactory.h"
-
-namespace PiAudioAE
-{
-
-class CPiAudioAE : public IAE, public CThread
-{
-protected:
-  friend class ::CAEFactory;
-  CPiAudioAE();
-  virtual ~CPiAudioAE();
-  virtual bool  Initialize();
-  virtual void Process();
-
-public:
-  virtual bool   Suspend();
-  virtual bool   Resume();
-  virtual void   OnSettingsChange(const std::string& setting);
-
-  virtual float GetVolume();
-  virtual void  SetVolume(const float volume);
-  virtual void  SetMute(const bool enabled);
-  virtual bool  IsMuted();
-  virtual void  SetSoundMode(const int mode) {}
-
-  /* returns a new stream for data in the specified format */
-  virtual IAEStream *MakeStream(enum AEDataFormat dataFormat, unsigned int sampleRate, unsigned int encodedSampleRate, CAEChannelInfo channelLayout, unsigned int options = 0);
-  virtual IAEStream *FreeStream(IAEStream *stream);
-
-  /* returns a new sound object */
-  virtual IAESound *MakeSound(const std::string& file);
-  virtual void      FreeSound(IAESound *sound);
-
-  virtual void GarbageCollect() {};
-  virtual void EnumerateOutputDevices(AEDeviceList &devices, bool passthrough);
-  virtual std::string GetDefaultDevice(bool passthrough);
-  virtual bool IsSettingVisible(const std::string &settingId);
-
-  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;
-};
-};
index c1d53f5..7f87410 100644 (file)
@@ -39,6 +39,8 @@ SRCS += AESinkFactory.cpp
 SRCS += Sinks/AESinkNULL.cpp
 SRCS += Sinks/AESinkProfiler.cpp
 
+SRCS += Sinks/AESinkPi.cpp
+
 SRCS += Engines/ActiveAE/ActiveAE.cpp
 SRCS += Engines/ActiveAE/ActiveAESink.cpp
 SRCS += Engines/ActiveAE/ActiveAEStream.cpp
@@ -46,8 +48,6 @@ SRCS += Engines/ActiveAE/ActiveAESound.cpp
 SRCS += Engines/ActiveAE/ActiveAEResample.cpp
 SRCS += Engines/ActiveAE/ActiveAEBuffer.cpp
 
-SRCS += Engines/PiAudio/PiAudioAE.cpp
-
 ifeq (@USE_ANDROID@,1)
 SRCS += Sinks/AESinkAUDIOTRACK.cpp
 else
diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp
new file mode 100644 (file)
index 0000000..72beba4
--- /dev/null
@@ -0,0 +1,293 @@
+/*
+ *      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"
+
+#if defined(TARGET_RASPBERRY_PI)
+
+#include <stdint.h>
+#include <limits.h>
+
+#include "AESinkPi.h"
+#include "cores/AudioEngine/Utils/AEUtil.h"
+#include "utils/log.h"
+#include "settings/Settings.h"
+#include "linux/RBP.h"
+
+#define CLASSNAME "CAESinkPi"
+
+#define NUM_OMX_BUFFERS 2
+#define AUDIO_PLAYBUFFER (1.0/20.0)
+
+CAEDeviceInfo CAESinkPi::m_info;
+
+CAESinkPi::CAESinkPi() :
+    m_sinkbuffer_size(0),
+    m_sinkbuffer_sec_per_byte(0),
+    m_Initialized(false),
+    m_submitted(0)
+{
+}
+
+CAESinkPi::~CAESinkPi()
+{
+}
+
+void CAESinkPi::SetAudioDest()
+{
+  OMX_ERRORTYPE omx_err   = OMX_ErrorNone;
+  OMX_CONFIG_BRCMAUDIODESTINATIONTYPE audioDest;
+  OMX_INIT_STRUCTURE(audioDest);
+  if (CSettings::Get().GetString("audiooutput.audiodevice") == "Pi:Analogue")
+    strncpy((char *)audioDest.sName, "local", strlen("local"));
+  else
+    strncpy((char *)audioDest.sName, "hdmi", strlen("hdmi"));
+  omx_err = m_omx_render.SetConfig(OMX_IndexConfigBrcmAudioDestination, &audioDest);
+  if (omx_err != OMX_ErrorNone)
+    CLog::Log(LOGERROR, "%s::%s - m_omx_render.SetConfig omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
+}
+
+bool CAESinkPi::Initialize(AEAudioFormat &format, std::string &device)
+{
+  m_initDevice = device;
+  m_initFormat = format;
+  // setup for a 50ms sink feed from SoftAE
+  format.m_dataFormat    = AE_FMT_S16NE;
+  format.m_frames        = format.m_sampleRate * AUDIO_PLAYBUFFER;
+  format.m_frameSamples  = format.m_channelLayout.Count();
+  format.m_frameSize     = format.m_frameSamples * (CAEUtil::DataFormatToBits(format.m_dataFormat) >> 3);
+  format.m_sampleRate    = std::max(8000U, std::min(96000U, format.m_sampleRate));
+
+  m_format = format;
+
+  m_sinkbuffer_size = format.m_frameSize * format.m_frames * NUM_OMX_BUFFERS;
+  m_sinkbuffer_sec_per_byte = 1.0 / (double)(format.m_frameSize * format.m_sampleRate);
+
+  CLog::Log(LOGDEBUG, "%s:%s Format:%d Channels:%d Samplerate:%d framesize:%d bufsize:%d bytes/s=%.2f", CLASSNAME, __func__,
+                format.m_dataFormat, format.m_channelLayout.Count(), format.m_sampleRate, format.m_frameSize, m_sinkbuffer_size, 1.0/m_sinkbuffer_sec_per_byte);
+
+  // This may be called before Application calls g_RBP.Initialise, so call it here too
+  g_RBP.Initialize();
+
+  CLog::Log(LOGDEBUG, "%s:%s", CLASSNAME, __func__);
+
+  OMX_ERRORTYPE omx_err   = OMX_ErrorNone;
+
+  if (!m_omx_render.Initialize("OMX.broadcom.audio_render", OMX_IndexParamAudioInit))
+    CLog::Log(LOGERROR, "%s::%s - m_omx_render.Initialize omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
+
+  OMX_INIT_STRUCTURE(m_pcm_input);
+  m_pcm_input.nPortIndex            = m_omx_render.GetInputPort();
+  m_pcm_input.eNumData              = OMX_NumericalDataSigned;
+  m_pcm_input.eEndian               = OMX_EndianLittle;
+  m_pcm_input.bInterleaved          = OMX_TRUE;
+  m_pcm_input.nBitPerSample         = 16;
+  m_pcm_input.ePCMMode              = OMX_AUDIO_PCMModeLinear;
+  m_pcm_input.nChannels             = m_format.m_frameSamples;
+  m_pcm_input.nSamplingRate         = m_format.m_sampleRate;
+  m_pcm_input.eChannelMapping[0] = OMX_AUDIO_ChannelLF;
+  m_pcm_input.eChannelMapping[1] = OMX_AUDIO_ChannelRF;
+  m_pcm_input.eChannelMapping[2] = OMX_AUDIO_ChannelMax;
+
+  omx_err = m_omx_render.SetParameter(OMX_IndexParamAudioPcm, &m_pcm_input);
+  if (omx_err != OMX_ErrorNone)
+    CLog::Log(LOGERROR, "%s::%s - error m_omx_render SetParameter omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
+
+  m_omx_render.ResetEos();
+
+  SetAudioDest();
+
+  // set up the number/size of buffers for decoder input
+  OMX_PARAM_PORTDEFINITIONTYPE port_param;
+  OMX_INIT_STRUCTURE(port_param);
+  port_param.nPortIndex = m_omx_render.GetInputPort();
+
+  omx_err = m_omx_render.GetParameter(OMX_IndexParamPortDefinition, &port_param);
+  if (omx_err != OMX_ErrorNone)
+    CLog::Log(LOGERROR, "%s:%s - error get OMX_IndexParamPortDefinition (input) omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
+
+  port_param.nBufferCountActual = std::max((unsigned int)port_param.nBufferCountMin, (unsigned int)NUM_OMX_BUFFERS);
+  port_param.nBufferSize = m_sinkbuffer_size / port_param.nBufferCountActual;
+
+  omx_err = m_omx_render.SetParameter(OMX_IndexParamPortDefinition, &port_param);
+  if (omx_err != OMX_ErrorNone)
+    CLog::Log(LOGERROR, "%s:%s - error set OMX_IndexParamPortDefinition (intput) omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
+
+  omx_err = m_omx_render.AllocInputBuffers();
+  if (omx_err != OMX_ErrorNone)
+    CLog::Log(LOGERROR, "%s:%s - Error alloc buffers 0x%08x", CLASSNAME, __func__, omx_err);
+
+  omx_err = m_omx_render.SetStateForComponent(OMX_StateExecuting);
+  if (omx_err != OMX_ErrorNone)
+    CLog::Log(LOGERROR, "%s:%s - m_omx_render OMX_StateExecuting omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
+
+  m_Initialized = true;
+  return true;
+}
+
+
+void CAESinkPi::Deinitialize()
+{
+  CLog::Log(LOGDEBUG, "%s:%s", CLASSNAME, __func__);
+  if (m_Initialized)
+  {
+    m_omx_render.FlushAll();
+    m_omx_render.Deinitialize();
+    m_Initialized = false;
+  }
+}
+
+bool CAESinkPi::IsCompatible(const AEAudioFormat &format, const std::string &device)
+{
+  bool compatible =
+      /* compare against the requested format and the real format */
+      (m_initFormat.m_sampleRate    == format.m_sampleRate    || m_format.m_sampleRate    == format.m_sampleRate   ) &&
+      (m_initFormat.m_dataFormat    == format.m_dataFormat    || m_format.m_dataFormat    == format.m_dataFormat   ) &&
+      (m_initFormat.m_channelLayout == format.m_channelLayout || m_format.m_channelLayout == format.m_channelLayout) &&
+      (m_initDevice == device);
+  CLog::Log(LOGDEBUG, "%s:%s Format:%d Channels:%d Samplerate:%d = %d", CLASSNAME, __func__, format.m_dataFormat, format.m_channelLayout.Count(), format.m_sampleRate, compatible);
+  return compatible;
+}
+
+double CAESinkPi::GetDelay()
+{
+  OMX_PARAM_U32TYPE param;
+  OMX_INIT_STRUCTURE(param);
+
+  if (!m_Initialized)
+    return 0.0;
+
+  param.nPortIndex = m_omx_render.GetInputPort();
+
+  OMX_ERRORTYPE omx_err = m_omx_render.GetConfig(OMX_IndexConfigAudioRenderingLatency, &param);
+
+  if (omx_err != OMX_ErrorNone)
+  {
+    CLog::Log(LOGERROR, "%s::%s - error getting OMX_IndexConfigAudioRenderingLatency error 0x%08x",
+      CLASSNAME, __func__, omx_err);
+  }
+  double sinkbuffer_seconds_to_empty = m_sinkbuffer_sec_per_byte * param.nU32 * m_format.m_frameSize;
+  return sinkbuffer_seconds_to_empty;
+}
+
+double CAESinkPi::GetCacheTime()
+{
+  return GetDelay();
+}
+
+double CAESinkPi::GetCacheTotal()
+{
+  double audioplus_buffer = AUDIO_PLAYBUFFER;
+  return m_sinkbuffer_sec_per_byte * (double)m_sinkbuffer_size + audioplus_buffer;
+}
+
+unsigned int CAESinkPi::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio, bool blocking)
+{
+  unsigned int sent = 0;
+
+  if (!m_Initialized)
+    return frames;
+
+  OMX_ERRORTYPE omx_err   = OMX_ErrorNone;
+  OMX_BUFFERHEADERTYPE *omx_buffer = NULL;
+  while (sent < frames)
+  {
+    int timeout = blocking ? 1000 : 0;
+
+    // delay compared to maximum we'd like (to keep lag low)
+    double delay = GetDelay();
+    bool too_laggy = delay - AUDIO_PLAYBUFFER > 0.0;
+    omx_buffer = too_laggy ? NULL : m_omx_render.GetInputBuffer(timeout);
+
+    if (omx_buffer == NULL)
+    {
+      if (too_laggy)
+      {
+        Sleep((int)((delay - AUDIO_PLAYBUFFER) * 1000.0));
+        continue;
+      }
+      if (blocking)
+        CLog::Log(LOGERROR, "COMXAudio::Decode timeout");
+      break;
+    }
+
+    omx_buffer->nFilledLen = std::min(omx_buffer->nAllocLen, (frames - sent) * m_format.m_frameSize);
+    omx_buffer->nTimeStamp = ToOMXTime(0);
+    omx_buffer->nFlags = 0;
+    memcpy(omx_buffer->pBuffer, (uint8_t *)data + sent * m_format.m_frameSize, omx_buffer->nFilledLen);
+    sent += omx_buffer->nFilledLen / m_format.m_frameSize;
+
+    if (sent == frames)
+      omx_buffer->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME;
+
+    if (delay <= 0.0 && m_submitted)
+      CLog::Log(LOGERROR, "%s:%s Underrun (delay:%.2f frames:%d)", CLASSNAME, __func__, delay, frames);
+
+    omx_err = m_omx_render.EmptyThisBuffer(omx_buffer);
+    if (omx_err != OMX_ErrorNone)
+      CLog::Log(LOGERROR, "%s:%s frames=%d err=%x", CLASSNAME, __func__, frames, omx_err);
+    m_submitted += omx_buffer->nFilledLen;
+  }
+
+  return sent;
+}
+
+void CAESinkPi::Drain()
+{
+  int delay = (int)(GetDelay() * 1000.0);
+  if (delay)
+    Sleep(delay);
+  CLog::Log(LOGDEBUG, "%s:%s delay:%dms now:%dms", CLASSNAME, __func__, delay, (int)(GetDelay() * 1000.0));
+}
+
+void CAESinkPi::EnumerateDevicesEx(AEDeviceInfoList &list, bool force)
+{
+  m_info.m_channels.Reset();
+  m_info.m_dataFormats.clear();
+  m_info.m_sampleRates.clear();
+
+  m_info.m_deviceType = AE_DEVTYPE_HDMI;
+  m_info.m_deviceName = "HDMI";
+  m_info.m_displayName = "HDMI";
+  m_info.m_displayNameExtra = "";
+  m_info.m_channels += AE_CH_FL;
+  m_info.m_channels += AE_CH_FR;
+  m_info.m_sampleRates.push_back(48000);
+  m_info.m_dataFormats.push_back(AE_FMT_S16LE);
+
+  list.push_back(m_info);
+
+  m_info.m_channels.Reset();
+  m_info.m_dataFormats.clear();
+  m_info.m_sampleRates.clear();
+
+  m_info.m_deviceType = AE_DEVTYPE_PCM;
+  m_info.m_deviceName = "Analogue";
+  m_info.m_displayName = "Analogue";
+  m_info.m_displayNameExtra = "";
+  m_info.m_channels += AE_CH_FL;
+  m_info.m_channels += AE_CH_FR;
+  m_info.m_sampleRates.push_back(48000);
+  m_info.m_dataFormats.push_back(AE_FMT_S16LE);
+
+  list.push_back(m_info);
+}
+
+#endif
diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkPi.h b/xbmc/cores/AudioEngine/Sinks/AESinkPi.h
new file mode 100644 (file)
index 0000000..1f33115
--- /dev/null
@@ -0,0 +1,65 @@
+#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 "system.h"
+
+#if defined(TARGET_RASPBERRY_PI)
+
+#include "cores/AudioEngine/Interfaces/AESink.h"
+#include "Utils/AEDeviceInfo.h"
+
+#include "cores/omxplayer/OMXAudio.h"
+
+class CAESinkPi : public IAESink
+{
+public:
+  virtual const char *GetName() { return "SinkPi"; }
+
+  CAESinkPi();
+  virtual ~CAESinkPi();
+
+  virtual bool Initialize(AEAudioFormat &format, std::string &device);
+  virtual void Deinitialize();
+  virtual bool IsCompatible(const AEAudioFormat &format, const std::string &device);
+
+  virtual double       GetDelay        ();
+  virtual double       GetCacheTime    ();
+  virtual double       GetCacheTotal   ();
+  virtual unsigned int AddPackets      (uint8_t *data, unsigned int frames, bool hasAudio, bool blocking = false);
+  virtual void         Drain           ();
+
+  static void          EnumerateDevicesEx(AEDeviceInfoList &list, bool force = false);
+private:
+  void                 SetAudioDest();
+
+  std::string          m_initDevice;
+  AEAudioFormat        m_initFormat;
+  AEAudioFormat        m_format;
+  unsigned int         m_sinkbuffer_size;  ///< total size of the buffer
+  double               m_sinkbuffer_sec_per_byte;
+  static CAEDeviceInfo m_info;
+  bool                 m_Initialized;
+  uint32_t             m_submitted;
+  OMX_AUDIO_PARAM_PCMMODETYPE m_pcm_input;
+  COMXCoreComponent    m_omx_render;
+};
+
+#endif
index dbd065f..440a26e 100644 (file)
@@ -83,17 +83,16 @@ COMXAudio::COMXAudio() :
   m_submitted_eos   (false  ),
   m_failed_eos      (false  )
 {
-  m_vizBufferSize   = m_vizRemapBufferSize = VIS_PACKET_SIZE * sizeof(float);
-  m_vizRemapBuffer  = (uint8_t *)_aligned_malloc(m_vizRemapBufferSize,16);
-  m_vizBuffer       = (uint8_t *)_aligned_malloc(m_vizBufferSize,16);
+  CAEFactory::Suspend();
+  while (!CAEFactory::IsSuspended())
+    Sleep(10);
 }
 
 COMXAudio::~COMXAudio()
 {
   Deinitialize();
 
-  _aligned_free(m_vizRemapBuffer);
-  _aligned_free(m_vizBuffer);
+  CAEFactory::Resume();
 }
 
 bool COMXAudio::PortSettingsChanged()
@@ -118,12 +117,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().GetString("audiooutput.audiodevice") == "Analogue")
+  if (CSettings::Get().GetBool("audiooutput.dualaudio") || CSettings::Get().GetString("audiooutput.audiodevice") == "Pi:Analogue")
   {
     if(!m_omx_render_analog.Initialize("OMX.broadcom.audio_render", OMX_IndexParamAudioInit))
       return false;
   }
-  if (CSettings::Get().GetBool("audiooutput.dualaudio") || CSettings::Get().GetString("audiooutput.audiodevice") == "HDMI")
+  if (CSettings::Get().GetBool("audiooutput.dualaudio") || CSettings::Get().GetString("audiooutput.audiodevice") != "Pi:Analogue")
   {
     if(!m_omx_render_hdmi.Initialize("OMX.broadcom.audio_render", OMX_IndexParamAudioInit))
       return false;
@@ -471,7 +470,7 @@ bool COMXAudio::Initialize(AEAudioFormat format, OMXClock *clock, CDVDStreamInfo
     enum PCMChannels outLayout[OMX_AUDIO_MAXCHANNELS];
     enum PCMLayout layout = (enum PCMLayout)std::max(0, CSettings::Get().GetInt("audiooutput.channels")-1);
     // ignore layout setting for analogue
-    if (CSettings::Get().GetBool("audiooutput.dualaudio") || CSettings::Get().GetString("audiooutput.audiodevice") == "Analogue")
+    if (CSettings::Get().GetBool("audiooutput.dualaudio") || CSettings::Get().GetString("audiooutput.audiodevice") == "Pi:Analogue")
       layout = PCM_LAYOUT_2_0;
 
     // force out layout to stereo if input is not multichannel - it gives the receiver a chance to upmix
@@ -487,8 +486,6 @@ bool COMXAudio::Initialize(AEAudioFormat format, OMXClock *clock, CDVDStreamInfo
     m_wave_header.dwChannelMask = channelMap;
     BuildChannelMapOMX(m_input_channels, channelMap);
     BuildChannelMapOMX(m_output_channels, GetChannelLayout(layout));
-
-    m_vizRemap.Initialize(GetAEChannelLayout(channelMap), CAEChannelInfo(AE_CH_LAYOUT_2_0), false, true);
   }
 
   m_SampleRate    = m_format.m_sampleRate;
@@ -690,9 +687,6 @@ 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;
 }
 
@@ -752,9 +746,6 @@ bool COMXAudio::Deinitialize()
   m_extradata = NULL;
   m_extrasize = 0;
 
-  while(!m_vizqueue.empty())
-    m_vizqueue.pop();
-
   m_dllAvUtil.Unload();
 
   while(!m_ampqueue.empty())
@@ -764,9 +755,6 @@ bool COMXAudio::Deinitialize()
   m_submitted     = 0.0f;
   m_maxLevel      = 0.0f;
 
-  /* dummy call to inform PiAudioAE that audo is inactive */
-  CAEFactory::FreeStream(0);
-
   return true;
 }
 
@@ -874,62 +862,6 @@ bool COMXAudio::ApplyVolume(void)
   return true;
 }
 
-void COMXAudio::VizPacket(const void* data, unsigned int len, double pts)
-{
-    /* input samples */
-    unsigned int vizBufferSamples = len / (CAEUtil::DataFormatToBits(m_format.m_dataFormat) >> 3);
-
-    /* input frames */
-    unsigned int frames = vizBufferSamples / m_InputChannels;
-    float *floatBuffer = (float *)data;
-
-    if (m_format.m_dataFormat != AE_FMT_FLOAT)
-    {
-      CAEConvert::AEConvertToFn m_convertFn = CAEConvert::ToFloat(m_format.m_dataFormat);
-
-      /* check convert buffer */
-      CheckOutputBufferSize((void **)&m_vizBuffer, &m_vizBufferSize, vizBufferSamples * (CAEUtil::DataFormatToBits(AE_FMT_FLOAT) >> 3));
-
-      /* convert to float */
-      m_convertFn((uint8_t *)data, vizBufferSamples, (float *)m_vizBuffer);
-      floatBuffer = (float *)m_vizBuffer;
-    }
-
-    // Viz channel count is 2
-    CheckOutputBufferSize((void **)&m_vizRemapBuffer, &m_vizRemapBufferSize, frames * 2 * sizeof(float));
-
-    /* remap */
-    m_vizRemap.Remap(floatBuffer, (float*)m_vizRemapBuffer, frames);
-
-    /* output samples */
-    vizBufferSamples = vizBufferSamples / m_InputChannels * 2;
-
-    /* viz size is limited */
-    if(vizBufferSamples > VIS_PACKET_SIZE)
-      vizBufferSamples = VIS_PACKET_SIZE;
-
-    vizblock_t v;
-    v.pts = pts;
-    v.num_samples = vizBufferSamples;
-    memcpy(v.samples, m_vizRemapBuffer, vizBufferSamples * sizeof(float));
-    m_vizqueue.push(v);
-
-    double stamp = m_av_clock->OMXMediaTime();
-    while(!m_vizqueue.empty())
-    {
-      vizblock_t &v = m_vizqueue.front();
-      /* if packet has almost reached media time (allow time for rendering delay) then display it */
-      /* we'll also consume if queue gets unexpectedly long to avoid filling memory */
-      if (v.pts == DVD_NOPTS_VALUE || v.pts - stamp < DVD_SEC_TO_TIME(1.0/30.0) || v.pts - stamp > DVD_SEC_TO_TIME(15.0))
-      {
-         m_pCallback->OnAudioData(v.samples, v.num_samples);
-         m_vizqueue.pop();
-      }
-      else break;
-   }
-}
-
-
 //***********************************************************************************************
 unsigned int COMXAudio::AddPackets(const void* data, unsigned int len)
 {
@@ -947,9 +879,6 @@ unsigned int COMXAudio::AddPackets(const void* data, unsigned int len, double dt
     return len;
   }
 
-  if (m_pCallback && len && !(m_Passthrough || m_HWDecode))
-    VizPacket(data, len, pts);
-
   if(m_eEncoding == OMX_AUDIO_CodingDTS && m_LostSync && (m_Passthrough || m_HWDecode))
   {
     int skip = SyncDTS((uint8_t *)data, len);
index 1a223e1..804bd2a 100644 (file)
@@ -98,7 +98,6 @@ public:
   bool BadState() { return !m_Initialized; };
   unsigned int GetAudioRenderingLatency();
   float GetMaxLevel(double &pts);
-  void VizPacket(const void* data, unsigned int len, double pts);
 
   void BuildChannelMap(enum PCMChannels *channelMap, uint64_t layout);
   int BuildChannelMapCEA(enum PCMChannels *channelMap, uint64_t layout);
@@ -135,19 +134,8 @@ private:
   int           m_extrasize;
   // stuff for visualisation
   double        m_last_pts;
-  int           m_vizBufferSize;
-  uint8_t       *m_vizBuffer;
-  int           m_vizRemapBufferSize;
-  uint8_t       *m_vizRemapBuffer;
-  CAERemap      m_vizRemap;
   bool          m_submitted_eos;
   bool          m_failed_eos;
-  typedef struct {
-    int num_samples;
-    float samples[VIS_PACKET_SIZE];
-    double pts;
-  } vizblock_t;
-  std::queue<vizblock_t> m_vizqueue;
 
   typedef struct {
     double pts;
index 7e2199a..e391c0e 100644 (file)
@@ -3303,17 +3303,7 @@ bool COMXPlayer::OpenVideoStream(int iStream, int source, bool reset)
   if(m_CurrentVideo.id    < 0
   || m_CurrentVideo.hint != hint)
   {
-    // for music file, don't open artwork as video
-    bool disabled = false;
-    CStdString extension = URIUtils::GetExtension(m_filename);
-    StringUtils::ToLower(extension);
-    if (!extension.empty() && g_advancedSettings.m_musicExtensions.find(extension) != std::string::npos)
-    {
-      CLog::Log(LOGWARNING, "%s - Ignoring video in audio filetype:%s", __FUNCTION__, m_filename.c_str());
-      disabled = true;
-    }
-
-    if (disabled || !m_omxPlayerVideo.OpenStream(hint))
+    if (!m_omxPlayerVideo.OpenStream(hint))
     {
       /* mark stream as disabled, to disallaw further attempts */
       CLog::Log(LOGWARNING, "%s - Unsupported stream %d. Stream disabled.", __FUNCTION__, iStream);
index 7949ebc..27dbb5d 100644 (file)
@@ -511,12 +511,12 @@ AEDataFormat OMXPlayerAudio::GetDataFormat(CDVDStreamInfo hints)
   /* check our audio capabilties */
 
   /* pathrought is overriding hw decode*/
-  if(hints.codec == AV_CODEC_ID_AC3 && CAEFactory::SupportsRaw(AE_FMT_AC3))
+  if(hints.codec == AV_CODEC_ID_AC3 && CAEFactory::SupportsRaw(AE_FMT_AC3) && !CSettings::Get().GetBool("audiooutput.dualaudio"))
   {
     dataFormat = AE_FMT_AC3;
     m_passthrough = true;
   }
-  if(hints.codec == AV_CODEC_ID_DTS && CAEFactory::SupportsRaw(AE_FMT_DTS))
+  if(hints.codec == AV_CODEC_ID_DTS && CAEFactory::SupportsRaw(AE_FMT_DTS) && !CSettings::Get().GetBool("audiooutput.dualaudio"))
   {
     dataFormat = AE_FMT_DTS;
     m_passthrough = true;
index 4995b32..77c6a15 100644 (file)
@@ -4,8 +4,4 @@
     <defaultplayer>omxplayer</defaultplayer>
     <defaultdvdplayer>omxplayer</defaultdvdplayer>
   </video>
-  <audio>
-    <defaultplayer>omxplayer</defaultplayer>
-    <streamsilence>false</streamsilence>
-  </audio>
 </advancedsettings>
index 7a5d4e7..27f0bec 100644 (file)
@@ -93,14 +93,10 @@ public:
         pPlayer = new COMXPlayer(callback); 
         CLog::Log(LOGINFO, "Created player %s for core %d / OMXPlayer forced as DVDPlayer", "OMXPlayer", m_eCore);
         break;
-      case EPC_PAPLAYER: 
-        pPlayer = new COMXPlayer(callback); 
-        CLog::Log(LOGINFO, "Created player %s for core %d / OMXPlayer forced as PAPLayer", "OMXPlayer", m_eCore);
-        break;
 #else
       case EPC_DVDPLAYER: pPlayer = new CDVDPlayer(callback); break;
-      case EPC_PAPLAYER: pPlayer = new PAPlayer(callback); break;
 #endif
+      case EPC_PAPLAYER: pPlayer = new PAPlayer(callback); break;
       case EPC_EXTPLAYER: pPlayer = new CExternalPlayer(callback); break;
 #if defined(HAS_OMXPLAYER)
       case EPC_OMXPLAYER: pPlayer = new COMXPlayer(callback); break;
index ef48935..9479259 100644 (file)
@@ -42,6 +42,10 @@ CRBP::~CRBP()
 
 bool CRBP::Initialize()
 {
+  CSingleLock lock (m_critSection);
+  if (m_initialized)
+    return true;
+
   m_initialized = m_DllBcmHost->Load();
   if(!m_initialized)
     return false;
index f742934..9d527db 100644 (file)
@@ -37,6 +37,7 @@
 #if defined(TARGET_RASPBERRY_PI)
 #include "DllBCM.h"
 #include "OMXCore.h"
+#include "threads/CriticalSection.h"
 
 class CRBP
 {
@@ -63,6 +64,7 @@ private:
   int        m_gpu_mem;
   COMXCore   *m_OMX;
   class DllLibOMXCore;
+  CCriticalSection m_critSection;
 };
 
 extern CRBP g_RBP;