Merge pull request #4441 from Memphiz/osxdevicereset
authorjmarshallnz <jcmarsha@gmail.com>
Sat, 22 Mar 2014 20:30:25 +0000 (09:30 +1300)
committerTrent Nelson <trent.a.b.nelson@gmail.com>
Mon, 24 Mar 2014 17:01:08 +0000 (11:01 -0600)
[osx] - fix issues with turning off/on tv when playback is paused

xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp
xbmc/cores/AudioEngine/Sinks/AESinkDARWINOSX.cpp
xbmc/windowing/osx/WinSystemOSX.h
xbmc/windowing/osx/WinSystemOSX.mm

index cd5396e..dfac0a4 100644 (file)
@@ -433,6 +433,7 @@ void CActiveAE::StateMachine(int signal, Protocol *port, Message *msg)
         case CActiveAEControlProtocol::DEVICECHANGE:
           time_t now;
           time(&now);
+          CLog::Log(LOGDEBUG,"CActiveAE - device change event");
           while (!m_extLastDeviceChange.empty() && (now - m_extLastDeviceChange.front() > 0))
           {
             m_extLastDeviceChange.pop();
@@ -444,6 +445,7 @@ void CActiveAE::StateMachine(int signal, Protocol *port, Message *msg)
           }
           m_extLastDeviceChange.push(now);
           UnconfigureSink();
+          m_controlPort.PurgeOut(CActiveAEControlProtocol::DEVICECHANGE);
           m_sink.EnumerateSinkList(true);
           LoadSettings();
           m_extError = false;
@@ -458,7 +460,6 @@ void CActiveAE::StateMachine(int signal, Protocol *port, Message *msg)
             m_state = AE_TOP_ERROR;
             m_extTimeout = 500;
           }
-          m_controlPort.PurgeOut(CActiveAEControlProtocol::DEVICECHANGE);
           return;
         case CActiveAEControlProtocol::PAUSESTREAM:
           CActiveAEStream *stream;
@@ -632,11 +633,13 @@ void CActiveAE::StateMachine(int signal, Protocol *port, Message *msg)
         switch (signal)
         {
         case CActiveAEControlProtocol::DISPLAYRESET:
+          CLog::Log(LOGDEBUG,"CActiveAE - display reset event");
           displayReset = true;
         case CActiveAEControlProtocol::INIT:
           m_extError = false;
           if (!displayReset)
           {
+            m_controlPort.PurgeOut(CActiveAEControlProtocol::DEVICECHANGE);
             m_sink.EnumerateSinkList(true);
             LoadSettings();
           }
index fc366b5..cc380e3 100644 (file)
@@ -414,18 +414,21 @@ bool CAESinkDARWINOSX::Initialize(AEAudioFormat &format, std::string &device)
   if (StringUtils::EqualsNoCase(device, "default"))
   {
     CCoreAudioHardware::GetOutputDeviceName(device);
+    deviceID = CCoreAudioHardware::GetDefaultOutputDevice();
     CLog::Log(LOGNOTICE, "%s: Opening default device %s", __PRETTY_FUNCTION__, device.c_str());
   }
-      
-  for (size_t i = 0; i < devices.size(); i++)
+  else
   {
-    if (device.find(devices[i].second.m_deviceName) != std::string::npos)
+    for (size_t i = 0; i < devices.size(); i++)
     {
-      m_info = devices[i].second;
-      deviceID = devices[i].first;
-      break;
+      if (device.find(devices[i].second.m_deviceName) != std::string::npos)
+      {
+        deviceID = devices[i].first;
+        break;
+      }
     }
   }
+
   if (!deviceID)
   {
     CLog::Log(LOGERROR, "%s: Unable to find device %s", __FUNCTION__, device.c_str());
index 6b9e0fb..04a5df3 100644 (file)
 
 #include "windowing/WinSystem.h"
 #include "threads/CriticalSection.h"
+#include "threads/Timer.h"
 
 typedef struct SDL_Surface SDL_Surface;
 
 class IDispResource;
 class CWinEventsOSX;
 
-class CWinSystemOSX : public CWinSystemBase
+class CWinSystemOSX : public CWinSystemBase, public ITimerCallback
 {
 public:
+
   CWinSystemOSX();
   virtual ~CWinSystemOSX();
 
+  // ITimerCallback interface
+  virtual void OnTimeout();
+
   // CWinSystemBase
   virtual bool InitWindowSystem();
   virtual bool DestroyWindowSystem();
@@ -69,7 +74,10 @@ public:
   
   void        WindowChangedScreen();
 
-  void CheckDisplayChanging(u_int32_t flags);
+  void        AnnounceOnLostDevice();
+  void        AnnounceOnResetDevice();
+  void        StartLostDeviceTimer();
+  void        StopLostDeviceTimer();
   
   void* GetCGLContextObj();
 
@@ -104,6 +112,7 @@ protected:
 
   CCriticalSection             m_resourceSection;
   std::vector<IDispResource*>  m_resources;
+  CTimer                       m_lostDeviceTimer;
 };
 
 #endif
index b1c7e8d..b225efd 100644 (file)
 
 
 #define MAX_DISPLAYS 32
+// if there was a devicelost callback
+// but no device reset for 3 secs
+// a timeout fires the reset callback
+// (for ensuring that e.x. AE isn't stuck)
+#define LOST_DEVICE_TIMEOUT_MS 3000
 static NSWindow* blankingWindows[MAX_DISPLAYS];
 
 void* CWinSystemOSX::m_lastOwnedContext = 0;
@@ -514,10 +519,18 @@ static void DisplayReconfigured(CGDirectDisplayID display,
   CGDisplayChangeSummaryFlags flags, void* userData)
 {
   CWinSystemOSX *winsys = (CWinSystemOSX*)userData;
-       if (!winsys)
+  if (!winsys)
     return;
 
-  if (flags & kCGDisplaySetModeFlag || flags & kCGDisplayBeginConfigurationFlag)
+  CLog::Log(LOGDEBUG, "CWinSystemOSX::DisplayReconfigured with flags %d", flags);
+
+  // we fire the callbacks on start of configuration
+  // or when the mode set was finished
+  // or when we are called with flags == 0 (which is undocumented but seems to happen
+  // on some macs - we treat it as device reset)
+
+  // first check if we need to call OnLostDevice
+  if (flags & kCGDisplayBeginConfigurationFlag)
   {
     // pre/post-reconfiguration changes
     RESOLUTION res = g_graphicsContext.GetVideoResolution();
@@ -532,22 +545,37 @@ static void DisplayReconfigured(CGDirectDisplayID display,
         pScreen = [[NSScreen screens] objectAtIndex:screenIdx];
     }
 
+    // kCGDisplayBeginConfigurationFlag is only fired while the screen is still
+    // valid
     if (pScreen)
     {
       CGDirectDisplayID xbmc_display = GetDisplayIDFromScreen(pScreen);
       if (xbmc_display == display)
       {
         // we only respond to changes on the display we are running on.
-        CLog::Log(LOGDEBUG, "CWinSystemOSX::DisplayReconfigured");
-        winsys->CheckDisplayChanging(flags);
+        winsys->AnnounceOnLostDevice();
+        winsys->StartLostDeviceTimer();
       }
     }
   }
+  else // the else case checks if we need to call OnResetDevice
+  {
+    // we fire if kCGDisplaySetModeFlag is set or if flags == 0
+    // (which is undocumented but seems to happen
+    // on some macs - we treat it as device reset)
+    // we also don't check the screen here as we might not even have
+    // one anymore (e.x. when tv is turned off)
+    if (flags & kCGDisplaySetModeFlag || flags == 0)
+    {
+      winsys->StopLostDeviceTimer(); // no need to timeout - we've got the callback
+      winsys->AnnounceOnResetDevice();
+    }
+  }
 }
 
 //---------------------------------------------------------------------------------
 //---------------------------------------------------------------------------------
-CWinSystemOSX::CWinSystemOSX() : CWinSystemBase()
+CWinSystemOSX::CWinSystemOSX() : CWinSystemBase(), m_lostDeviceTimer(this)
 {
   m_eWindowSystem = WINDOW_SYSTEM_OSX;
   m_glContext = 0;
@@ -566,6 +594,24 @@ CWinSystemOSX::~CWinSystemOSX()
 {
 };
 
+void CWinSystemOSX::StartLostDeviceTimer()
+{
+  if (m_lostDeviceTimer.IsRunning())
+    m_lostDeviceTimer.Restart();
+  else
+    m_lostDeviceTimer.Start(LOST_DEVICE_TIMEOUT_MS, false);
+}
+
+void CWinSystemOSX::StopLostDeviceTimer()
+{
+  m_lostDeviceTimer.Stop();
+}
+
+void CWinSystemOSX::OnTimeout()
+{
+  AnnounceOnResetDevice();
+}
+
 bool CWinSystemOSX::InitWindowSystem()
 {
   SDL_EnableUNICODE(1);
@@ -1689,25 +1735,22 @@ void CWinSystemOSX::WindowChangedScreen()
   m_movedToOtherScreen = true;
 }
 
-void CWinSystemOSX::CheckDisplayChanging(u_int32_t flags)
+void CWinSystemOSX::AnnounceOnLostDevice()
 {
-  if (flags)
-  {
-    CSingleLock lock(m_resourceSection);
-    // tell any shared resources
-    if (flags & kCGDisplayBeginConfigurationFlag)
-    {
-      CLog::Log(LOGDEBUG, "CWinSystemOSX::CheckDisplayChanging:OnLostDevice");
-      for (std::vector<IDispResource *>::iterator i = m_resources.begin(); i != m_resources.end(); i++)
-        (*i)->OnLostDevice();
-    }
-    if (flags & kCGDisplaySetModeFlag)
-    {
-      CLog::Log(LOGDEBUG, "CWinSystemOSX::CheckDisplayChanging:OnResetDevice");
-      for (std::vector<IDispResource *>::iterator i = m_resources.begin(); i != m_resources.end(); i++)
-        (*i)->OnResetDevice();
-    }
-  }
+  CSingleLock lock(m_resourceSection);
+  // tell any shared resources
+  CLog::Log(LOGDEBUG, "CWinSystemOSX::AnnounceOnLostDevice");
+  for (std::vector<IDispResource *>::iterator i = m_resources.begin(); i != m_resources.end(); i++)
+    (*i)->OnLostDevice();
+}
+
+void CWinSystemOSX::AnnounceOnResetDevice()
+{
+  CSingleLock lock(m_resourceSection);
+  // tell any shared resources
+  CLog::Log(LOGDEBUG, "CWinSystemOSX::AnnounceOnResetDevice");
+  for (std::vector<IDispResource *>::iterator i = m_resources.begin(); i != m_resources.end(); i++)
+    (*i)->OnResetDevice();
 }
 
 void* CWinSystemOSX::GetCGLContextObj()