Merge pull request #2703 from ace20022/cores_revised
[vuplus_xbmc] / xbmc / cores / AudioEngine / Sinks / AESinkDirectSound.cpp
index c69a846..944294b 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *      Copyright (C) 2010-2013 Team XBMC
- *      http://www.xbmc.org
+ *      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
@@ -35,6 +35,7 @@
 #include <Functiondiscoverykeys_devpkey.h>
 #include <Rpc.h>
 #include "cores/AudioEngine/Utils/AEUtil.h"
+#include "utils/StringUtils.h"
 #pragma comment(lib, "Rpcrt4.lib")
 
 extern HWND g_hWnd;
@@ -143,10 +144,14 @@ bool CAESinkDirectSound::Initialize(AEAudioFormat &format, std::string &device)
   LPGUID deviceGUID = NULL;
   RPC_CSTR wszUuid  = NULL;
   HRESULT hr = E_FAIL;
+  std::string strDeviceGUID = device;
   std::list<DSDevice> DSDeviceList;
   std::string deviceFriendlyName;
   DirectSoundEnumerate(DSEnumCallback, &DSDeviceList);
 
+  if(StringUtils::EndsWith(device, std::string("default")))
+    strDeviceGUID = GetDefaultDevice();
+
   for (std::list<DSDevice>::iterator itt = DSDeviceList.begin(); itt != DSDeviceList.end(); ++itt)
   {
     if ((*itt).lpGuid)
@@ -154,23 +159,27 @@ bool CAESinkDirectSound::Initialize(AEAudioFormat &format, std::string &device)
       hr = (UuidToString((*itt).lpGuid, &wszUuid));
       std::string sztmp = (char*)wszUuid;
       std::string szGUID = "{" + std::string(sztmp.begin(), sztmp.end()) + "}";
-      if (strcasecmp(szGUID.c_str(), device.c_str()) == 0)
+      if (strcasecmp(szGUID.c_str(), strDeviceGUID.c_str()) == 0)
       {
         deviceGUID = (*itt).lpGuid;
         deviceFriendlyName = (*itt).name.c_str();
         break;
       }
     }
-  if (hr == RPC_S_OK) RpcStringFree(&wszUuid);
+    if (hr == RPC_S_OK) RpcStringFree(&wszUuid);
   }
 
   hr = DirectSoundCreate(deviceGUID, &m_pDSound, NULL);
 
   if (FAILED(hr))
   {
-    CLog::Log(LOGERROR, __FUNCTION__": Failed to create the DirectSound device.");
-    CLog::Log(LOGERROR, __FUNCTION__": DSErr: %s", dserr2str(hr));
-    return false;
+    CLog::Log(LOGERROR, __FUNCTION__": Failed to create the DirectSound device %s with error %s, trying the default device.", deviceFriendlyName.c_str(), dserr2str(hr));
+    hr = DirectSoundCreate(NULL, &m_pDSound, NULL);
+    if (FAILED(hr))
+    {
+      CLog::Log(LOGERROR, __FUNCTION__": Failed to create the default DirectSound device with error %s.", dserr2str(hr));
+      return false;
+    }
   }
 
   HWND tmp_hWnd;
@@ -367,7 +376,7 @@ bool CAESinkDirectSound::IsCompatible(const AEAudioFormat &format, const std::st
   return false;
 }
 
-unsigned int CAESinkDirectSound::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio)
+unsigned int CAESinkDirectSound::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio, bool blocking)
 {
   if (!m_initialized)
     return 0;
@@ -386,10 +395,15 @@ unsigned int CAESinkDirectSound::AddPackets(uint8_t *data, unsigned int frames,
 
   while (GetSpace() < total)
   {
-    if (m_isDirtyDS)
+    if(m_isDirtyDS)
       return INT_MAX;
     else
-      return 0;
+    {
+      if(blocking)
+        Sleep(total * 1000 / m_AvgBytesPerSec);
+      else
+        return 0;
+    }
   }
 
   while (len)
@@ -398,7 +412,8 @@ unsigned int CAESinkDirectSound::AddPackets(uint8_t *data, unsigned int frames,
     DWORD size = 0, sizeWrap = 0;
     if (m_BufferOffset >= m_dwBufferLen) // Wrap-around manually
       m_BufferOffset = 0;
-    HRESULT res = m_pBuffer->Lock(m_BufferOffset, m_dwChunkSize, &start, &size, &startWrap, &sizeWrap, 0);
+    DWORD dwWriteBytes = std::min((int)m_dwChunkSize, (int)len);
+    HRESULT res = m_pBuffer->Lock(m_BufferOffset, dwWriteBytes, &start, &size, &startWrap, &sizeWrap, 0);
     if (DS_OK != res)
     {
       CLog::Log(LOGERROR, __FUNCTION__ ": Unable to lock buffer at offset %u. HRESULT: 0x%08x", m_BufferOffset, res);
@@ -436,6 +451,23 @@ void CAESinkDirectSound::Stop()
     m_pBuffer->Stop();
 }
 
+void CAESinkDirectSound::Drain()
+{
+  if (!m_initialized || m_isDirtyDS)
+    return;
+
+  m_pBuffer->Stop();
+  HRESULT res = m_pBuffer->SetCurrentPosition(0);
+  if (DS_OK != res)
+  {
+    CLog::Log(LOGERROR,__FUNCTION__ ": SetCurrentPosition failed. Unable to determine buffer status. HRESULT = 0x%08x", res);
+    m_isDirtyDS = true;
+    return;
+  }
+  m_BufferOffset = 0;
+  UpdateCacheStatus();
+}
+
 double CAESinkDirectSound::GetDelay()
 {
   if (!m_initialized)
@@ -478,6 +510,8 @@ void CAESinkDirectSound::EnumerateDevicesEx(AEDeviceInfoList &deviceInfoList, bo
 
   HRESULT                hr;
 
+  std::string strDD = GetDefaultDevice();
+
   /* See if we are on Windows XP */
   if (!g_sysinfo.IsWindowsVersionAtLeast(CSysInfo::WindowsVersionVista))
   {
@@ -512,6 +546,15 @@ void CAESinkDirectSound::EnumerateDevicesEx(AEDeviceInfoList &deviceInfoList, bo
       deviceInfo.m_sampleRates.push_back((DWORD) 96000);
 
       deviceInfoList.push_back(deviceInfo);
+
+      // add the default device with m_deviceName = default
+      if(strDD == deviceInfo.m_deviceName)
+      {
+        deviceInfo.m_deviceName = std::string("default");
+        deviceInfo.m_displayName = std::string("default");
+        deviceInfo.m_displayNameExtra = std::string("");
+        deviceInfoList.push_back(deviceInfo);
+      }
     }
 
     RpcStringFree(&cszGUID);
@@ -627,22 +670,14 @@ void CAESinkDirectSound::EnumerateDevicesEx(AEDeviceInfoList &deviceInfoList, bo
     deviceInfo.m_deviceType       = aeDeviceType;
 
     deviceInfoList.push_back(deviceInfo);
-  }
 
-  // since AE takes the first device in deviceInfoList as default audio device we need
-  // to sort it in order to use the real default device
-  if(deviceInfoList.size() > 1)
-  {
-    std::string strDD = GetDefaultDevice();
-    for (AEDeviceInfoList::iterator itt = deviceInfoList.begin(); itt != deviceInfoList.end(); ++itt)
+    // add the default device with m_deviceName = default
+    if(strDD == strDevName)
     {
-      CAEDeviceInfo devInfo = *itt;
-      if(devInfo.m_deviceName == strDD)
-      {
-        deviceInfoList.erase(itt);
-        deviceInfoList.insert(deviceInfoList.begin(), devInfo);
-        break;
-      }
+      deviceInfo.m_deviceName = std::string("default");
+      deviceInfo.m_displayName = std::string("default");
+      deviceInfo.m_displayNameExtra = std::string("");
+      deviceInfoList.push_back(deviceInfo);
     }
   }
 
@@ -677,10 +712,6 @@ void CAESinkDirectSound::CheckPlayStatus()
 bool CAESinkDirectSound::UpdateCacheStatus()
 {
   CSingleLock lock (m_runLock);
-  // TODO: Check to see if we may have cycled around since last time
-  unsigned int time = XbmcThreads::SystemClockMillis();
-  if (time == m_LastCacheCheck)
-    return true; // Don't recalc more frequently than once/ms (that is our max resolution anyway)
 
   DWORD playCursor = 0, writeCursor = 0;
   HRESULT res = m_pBuffer->GetCurrentPosition(&playCursor, &writeCursor); // Get the current playback and safe write positions
@@ -691,7 +722,6 @@ bool CAESinkDirectSound::UpdateCacheStatus()
     return false;
   }
 
-  m_LastCacheCheck = time;
   // Check the state of the ring buffer (P->O->W == underrun)
   // These are the logical situations that can occur
   // O: CurrentOffset  W: WriteCursor  P: PlayCursor
@@ -723,7 +753,8 @@ bool CAESinkDirectSound::UpdateCacheStatus()
       return false;
     }
   }
-  else m_BufferTimeouts = 0;
+  else 
+    m_BufferTimeouts = 0;
 
   // Calculate available space in the ring buffer
   if (playCursor == m_BufferOffset && m_BufferOffset ==  writeCursor) // Playback is stopped and we are all at the same place
@@ -910,4 +941,4 @@ bool CAESinkDirectSound::SoftResume()
 {
   /* Return false to force re-init by engine */
   return false;
-}
\ No newline at end of file
+}