Diff of /xbmc/FileSystem/FileShoutcast.cpp [4d1e3f] .. [ed57a4] Maximize Restore

Repo status: analyzing...

  Switch to side-by-side view

--- a/xbmc/FileSystem/FileShoutcast.cpp
+++ b/xbmc/FileSystem/FileShoutcast.cpp
@@ -33,178 +33,33 @@
 #include "GUIWindowManager.h"
 #include "URL.h"
 #include "utils/TimeUtils.h"
-#include "LocalizeStrings.h"
 
 //////////////////////////////////////////////////////////////////////
 // Construction/Destruction
 //////////////////////////////////////////////////////////////////////
 
-// prevent inclusion of config.h from libshout
-#define __SRCONFIG_H__
-#include "lib/libshout/rip_manager.h"
-#include "lib/libshout/filelib.h"
-#undef __SRCONFIG_H__
-
-#include "RingBuffer.h"
-#include "ShoutcastRipFile.h"
 #include "utils/GUIInfoManager.h"
 #include "utils/log.h"
 
-//using namespace std; On VS2010 error_code conflicts with std::error_code
 using namespace XFILE;
 using namespace MUSIC_INFO;
 
-#ifndef HAS_SHOUTCAST
-extern "C"
-{
-  error_code rip_manager_start(void (*status_callback)(int message, void *data), RIP_MANAGER_OPTIONS *options) { return 0; }
-  void       rip_manager_stop() { }
-  void       set_rip_manager_options_defaults(RIP_MANAGER_OPTIONS*) {}
-  int        rip_manager_get_content_type() { return 0; }
-}
-#endif
-
-const int SHOUTCASTTIMEOUT = 60;
-static CRingBuffer m_ringbuf;
-
-static FileState m_fileState;
-static CShoutcastRipFile m_ripFile;
-
-
-static RIP_MANAGER_INFO m_ripInfo;
-static ERROR_INFO m_errorInfo;
-
-
-
-void rip_callback(int message, void *data)
-{
-  switch (message)
-  {
-    RIP_MANAGER_INFO *info;
-  case RM_UPDATE:
-    info = (RIP_MANAGER_INFO*)data;
-    memcpy(&m_ripInfo, info, sizeof(m_ripInfo));
-    if (info->status == RM_STATUS_BUFFERING)
-    {
-      m_fileState.bBuffering = true;
-    }
-    else if ( info->status == RM_STATUS_RIPPING)
-    {
-      m_ripFile.SetRipManagerInfo( &m_ripInfo );
-      m_fileState.bBuffering = false;
-    }
-    else if (info->status == RM_STATUS_RECONNECTING)
-  { }
-    break;
-  case RM_ERROR:
-    ERROR_INFO *errInfo;
-    errInfo = (ERROR_INFO*)data;
-    memcpy(&m_errorInfo, errInfo, sizeof(m_errorInfo));
-    m_fileState.bRipError = true;
-    OutputDebugString("error\n");
-    break;
-  case RM_DONE:
-    OutputDebugString("done\n");
-    m_fileState.bRipDone = true;
-    break;
-  case RM_NEW_TRACK:
-    char *trackName;
-    trackName = (char*) data;
-    m_ripFile.SetTrackname( trackName );
-    break;
-  case RM_STARTED:
-    m_fileState.bRipStarted = true;
-    OutputDebugString("Started\n");
-    break;
-  }
-
-}
-
-extern "C" {
-error_code filelib_write_show(char *buf, u_long size)
-{
-  if ((unsigned int)size > m_ringbuf.getSize())
-  {
-    CLog::Log(LOGERROR, "Shoutcast chunk too big: %lu", size);
-    return SR_ERROR_BUFFER_FULL;
-  }
-  while (m_ringbuf.getMaxWriteSize() < (unsigned int)size) Sleep(10);
-  m_ringbuf.WriteData(buf, size);
-  m_ripFile.Write( buf, size ); //will only write, if it has to
-  if (m_fileState.bBuffering)
-  {
-    if (rip_manager_get_content_type() == CONTENT_TYPE_OGG)
-    {
-      if (m_ringbuf.getMaxReadSize() > (m_ringbuf.getSize() / 8) )
-      {
-        // hack because ogg streams are very broke, force it to go.
-        m_fileState.bBuffering = false;
-      }
-    }
-  }
-
-  return SR_SUCCESS;
-}
-}
-
-CFileShoutcast* m_pShoutCastRipper = NULL;
-
 CFileShoutcast::CFileShoutcast()
 {
-  // FIXME: without this check
-  // the playback stops when CFile::Stat()
-  // or CFile::Exists() is called
-
-  // Do we already have another file
-  // using the ripper?
-  if (!m_pShoutCastRipper)
-  {
-    m_fileState.bBuffering = true;
-    m_fileState.bRipDone = false;
-    m_fileState.bRipStarted = false;
-    m_fileState.bRipError = false;
-    m_ringbuf.Create(1024*1024); // must be big enough. some stations use 192kbps.
-    m_pShoutCastRipper = this;
-  }
+  m_lastTime = CTimeUtils::GetTimeMS();
+  m_discarded = 0;
+  m_currint = 0;
+  m_buffer = NULL;
 }
 
 CFileShoutcast::~CFileShoutcast()
 {
-  // FIXME: without this check
-  // the playback stops when CFile::Stat()
-  // or CFile::Exists() is called
-
-  // Has this object initialized the ripper?
-  if (m_pShoutCastRipper==this)
-  {
-    rip_manager_stop();
-    m_pShoutCastRipper = NULL;
-    m_ripFile.Reset();
-    m_ringbuf.Destroy();
-  }
+  Close();
 }
-
-bool CFileShoutcast::CanRecord()
-{
-  if ( !m_fileState.bRipStarted )
-    return false;
-  return m_ripFile.CanRecord();
-}
-
-bool CFileShoutcast::Record()
-{
-  return m_ripFile.Record();
-}
-
-void CFileShoutcast::StopRecording()
-{
-  m_ripFile.StopRecording();
-}
-
 
 int64_t CFileShoutcast::GetPosition()
 {
-  return 0;
+  return m_file.GetPosition()-m_discarded;
 }
 
 int64_t CFileShoutcast::GetLength()
@@ -212,201 +67,50 @@
   return 0;
 }
 
-
 bool CFileShoutcast::Open(const CURL& url)
 {
-  m_lastTime = CTimeUtils::GetTimeMS();
+  CURL url2(url);
+  url2.SetProtocolOptions("noshout=true&Icy-MetaData=1");
 
-  CGUIDialogProgress* dlgProgress = NULL;
+  bool result=false;
+  if ((result=m_file.Open(url2.Get())))
+  {
+    m_tag.SetTitle(m_file.GetHttpHeader().GetValue("icy-name"));
+    if (m_tag.GetTitle().IsEmpty())
+      m_tag.SetTitle(m_file.GetHttpHeader().GetValue("ice-name")); // icecast
+    m_tag.SetGenre(m_file.GetHttpHeader().GetValue("icy-genre"));
+    if (m_tag.GetGenre().IsEmpty())
+      m_tag.SetGenre(m_file.GetHttpHeader().GetValue("ice-genre")); // icecast
+    m_tag.SetLoaded(true);
+    g_infoManager.SetCurrentSongTag(m_tag);
+  }
+  m_metaint = atoi(m_file.GetHttpHeader().GetValue("icy-metaint").c_str());
+  m_buffer = new char[16*255];
 
-  // dvdplayer can deadlock with progress dialog so check first
-  if (g_application.GetCurrentPlayer() == EPC_PAPLAYER)
-  {
-    dlgProgress = (CGUIDialogProgress*)g_windowManager.GetWindow(WINDOW_DIALOG_PROGRESS);
-  }
-
-  set_rip_manager_options_defaults(&m_opt);
-
-  strcpy(m_opt.output_directory, "./");
-  m_opt.proxyurl[0] = '\0';
-
-  // Use a proxy, if the GUI was configured as such
-  bool bProxyEnabled = g_guiSettings.GetBool("network.usehttpproxy");
-  if (bProxyEnabled)
-  {
-    const CStdString &strProxyServer = g_guiSettings.GetString("network.httpproxyserver");
-    const CStdString &strProxyPort = g_guiSettings.GetString("network.httpproxyport");
-    // Should we check for valid strings here
-#ifndef _LINUX
-    _snprintf( m_opt.proxyurl, MAX_URL_LEN, "http://%s:%s", strProxyServer.c_str(), strProxyPort.c_str() );
-#else
-    snprintf( m_opt.proxyurl, MAX_URL_LEN, "http://%s:%s", strProxyServer.c_str(), strProxyPort.c_str() );
-#endif
-  }
-
-  CStdString strUrl = url.Get();
-  strUrl.Replace("shout://", "http://");
-  strncpy(m_opt.url, strUrl.c_str(), MAX_URL_LEN);
-  sprintf(m_opt.useragent, "x%s", url.GetFileName().c_str());
-  if (dlgProgress)
-  {
-    dlgProgress->SetHeading(260);
-    dlgProgress->SetLine(0, 259);
-    dlgProgress->SetLine(1, strUrl);
-    dlgProgress->SetLine(2, "");
-    if (!dlgProgress->IsDialogRunning())
-      dlgProgress->StartModal();
-    dlgProgress->Progress();
-  }
-
-  if (rip_manager_start(rip_callback, &m_opt) != SR_SUCCESS)
-  {
-    if (dlgProgress) dlgProgress->Close();
-    return false;
-  }
-  int iShoutcastTimeout = 10 * SHOUTCASTTIMEOUT; //i.e: 10 * 10 = 100 * 100ms = 10s
-  int iCount = 0;
-  while (!m_fileState.bRipDone && !m_fileState.bRipStarted && !m_fileState.bRipError && (!dlgProgress || !dlgProgress->IsCanceled()))
-  {
-    if (iCount <= iShoutcastTimeout) //Normally, this isn't the problem,
-      //because if RIP_MANAGER fails, this would be here
-      //with m_fileState.bRipError
-    {
-      Sleep(100);
-    }
-    else
-    {
-      if (dlgProgress)
-      {
-        dlgProgress->SetLine(1, 257);
-        dlgProgress->SetLine(2, "Connection timed out...");
-        Sleep(1500);
-        dlgProgress->Close();
-      }
-      return false;
-    }
-    iCount++;
-  }
-
-  if (dlgProgress && dlgProgress->IsCanceled())
-  {
-     Close();
-     dlgProgress->Close();
-     return false;
-  }
-
-  /* store content type of stream */
-  m_mimetype = rip_manager_get_content_type();
-
-  //CHANGED CODE: Don't reset timer anymore.
-
-  while (!m_fileState.bRipDone && !m_fileState.bRipError && m_fileState.bBuffering && (!dlgProgress || !dlgProgress->IsCanceled()))
-  {
-    if (iCount <= iShoutcastTimeout) //Here is the real problem: Sometimes the buffer fills just to
-      //slowly, thus the quality of the stream will be bad, and should be
-      //aborted...
-    {
-      Sleep(100);
-      char szTmp[1024];
-      //g_dialog.SetCaption(0, "Shoutcast" );
-      sprintf(szTmp, g_localizeStrings.Get(23052).c_str(), m_ringbuf.getMaxReadSize());
-      if (dlgProgress)
-      {
-        dlgProgress->SetLine(2, szTmp );
-        dlgProgress->Progress();
-      }
-
-      sprintf(szTmp, "%s", m_ripInfo.filename);
-      for (int i = 0; i < (int)strlen(szTmp); i++)
-        szTmp[i] = tolower((unsigned char)szTmp[i]);
-      szTmp[50] = 0;
-      if (dlgProgress)
-      {
-        dlgProgress->SetLine(1, szTmp );
-        dlgProgress->Progress();
-      }
-    }
-    else //it's not really a connection timeout, but it's here,
-      //where things get boring, if connection is slow.
-      //trust me, i did a lot of testing... Doesn't happen often,
-      //but if it does it sucks to wait here forever.
-      //CHANGED: Other message here
-    {
-      if (dlgProgress)
-      {
-        dlgProgress->SetLine(1, 257);
-        dlgProgress->SetLine(2, "Connection to server too slow...");
-        dlgProgress->Close();
-      }
-      return false;
-    }
-    iCount++;
-  }
-  if (dlgProgress && dlgProgress->IsCanceled())
-  {
-     Close();
-     dlgProgress->Close();
-     return false;
-  }
-  if ( m_fileState.bRipError )
-  {
-    if (dlgProgress)
-    {
-      dlgProgress->SetLine(1, 257);
-      dlgProgress->SetLine(2, 16029);
-      CLog::Log(LOGERROR, "%s: error - %s", __FUNCTION__, m_errorInfo.error_str);
-      dlgProgress->Progress();
-
-      Sleep(1500);
-      dlgProgress->Close();
-    }
-    return false;
-  }
-  if (dlgProgress)
-  {
-    dlgProgress->SetLine(2, 261);
-    dlgProgress->Progress();
-    dlgProgress->Close();
-  }
-  return true;
+  return result;
 }
 
 unsigned int CFileShoutcast::Read(void* lpBuf, int64_t uiBufSize)
 {
-  if (m_fileState.bRipDone)
+  if (m_currint >= m_metaint && m_metaint > 0)
   {
-    OutputDebugString("Read done\n");
-    return 0;
+    unsigned char header;
+    m_file.Read(&header,1);
+    ReadTruncated(m_buffer, header*16);
+    ExtractTagInfo(m_buffer);
+    m_discarded += header*16+1;
+    m_currint = 0;
   }
-
-  int slept=0;
-  while (m_ringbuf.getMaxReadSize() <= 0)
-  {
-    Sleep(10);
-    if (slept += 10 > SHOUTCASTTIMEOUT*1000)
-      return -1;
-  }
-
-  int iRead = m_ringbuf.getMaxReadSize();
-  if (iRead > uiBufSize) iRead = (int)uiBufSize;
-  m_ringbuf.ReadData((char*)lpBuf, iRead);
-
   if (CTimeUtils::GetTimeMS() - m_lastTime > 500)
   {
     m_lastTime = CTimeUtils::GetTimeMS();
-    CMusicInfoTag tag;
-    GetMusicInfoTag(tag);
-    g_infoManager.SetCurrentSongTag(tag);
+    g_infoManager.SetCurrentSongTag(m_tag);
   }
-  return iRead;
-}
 
-void CFileShoutcast::outputTimeoutMessage(const char* message)
-{
-  //g_dialog.SetCaption(0, "Shoutcast"  );
-  //g_dialog.SetMessage(0,  message );
-  //g_dialog.Render();
-  Sleep(1500);
+  unsigned int toRead = std::min((unsigned int)uiBufSize,(unsigned int)m_metaint-m_currint);
+  toRead = m_file.Read(lpBuf,toRead);
+  m_currint += toRead;
+  return toRead;
 }
 
 int64_t CFileShoutcast::Seek(int64_t iFilePosition, int iWhence)
@@ -416,37 +120,25 @@
 
 void CFileShoutcast::Close()
 {
-  OutputDebugString("Shoutcast Stopping\n");
-  if ( m_ripFile.IsRecording() )
-    m_ripFile.StopRecording();
-  m_ringbuf.Clear();
-  rip_manager_stop();
-  m_ripFile.Reset();
-  OutputDebugString("Shoutcast Stopped\n");
+  delete[] m_buffer;
+  m_file.Close();
 }
 
-bool CFileShoutcast::IsRecording()
+void CFileShoutcast::ExtractTagInfo(const char* buf)
 {
-  return m_ripFile.IsRecording();
+  char temp[1024];
+  if (sscanf(buf,"StreamTitle='%[^']",temp) > 0)
+    m_tag.SetTitle(temp);
 }
 
-bool CFileShoutcast::GetMusicInfoTag(CMusicInfoTag& tag)
+void CFileShoutcast::ReadTruncated(char* buf2, int size)
 {
-  m_ripFile.GetMusicInfoTag(tag);
-  return true;
+  char* buf = buf2;
+  while (size > 0)
+  {
+    int read = m_file.Read(buf,size);
+    size -= read;
+    buf += read;
+  }
 }
 
-CStdString CFileShoutcast::GetContent()
-{
-  switch (m_mimetype)
-  {
-    case CONTENT_TYPE_MP3:
-      return "audio/mpeg";
-    case CONTENT_TYPE_OGG:
-      return "audio/ogg";
-    case CONTENT_TYPE_AAC:
-      return "audio/aac";
-    default:
-      return "application/octet-stream";
-  }
-}