- Main Page
- Namespaces
- Classes
- Files
- Directories

- File List
- File Members

# ShoutcastSource.cpp

    00001 /*
    00002  *      Copyright (C) 2003-2005 Gabest
    00003  *      http://www.gabest.org
    00004  *
    00005  *  This Program is free software; you can redistribute it and/or modify
    00006  *  it under the terms of the GNU General Public License as published by
    00007  *  the Free Software Foundation; either version 2, or (at your option)
    00008  *  any later version.
    00009  *
    00010  *  This Program is distributed in the hope that it will be useful,
    00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
    00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    00013  *  GNU General Public License for more details.
    00014  *
    00015  *  You should have received a copy of the GNU General Public License
    00016  *  along with GNU Make; see the file COPYING.  If not, write to
    00017  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
    00018  *  http://www.gnu.org/copyleft/gpl.html
    00019  *
    00020  */
    00021
    00022 #include "stdafx.h"
    00023 #include <initguid.h>
    00024 #include "shoutcastsource.h"
    00025 #include "..\..\..\DSUtil\DSUtil.h"
    00026 #include "..\..\..\..\include\moreuuids.h"
    00027
    00028 #define MAXFRAMESIZE ((144 * 320000 / 8000) + 1)
    00029 #define BUFFERS 2
    00030 #define MINBUFFERLENGTH 1000000i64
    00031 #define AVGBUFFERLENGTH 30000000i64
    00032 #define MAXBUFFERLENGTH 100000000i64
    00033
    00034 static const DWORD s_bitrate[2][16] =
    00035 {
    00036         {1,8,16,24,32,40,48,56,64,80,96,112,128,144,160,0},
    00037         {1,32,40,48,56,64,80,96,112,128,160,192,224,256,320,0}
    00038 };
    00039 static const DWORD s_freq[4][4] =
    00040 {
    00041         {11025,12000,8000,0},
    00042         {0,0,0,0},
    00043         {22050,24000,16000,0},
    00044         {44100,48000,32000,0}
    00045 };
    00046 static const BYTE s_channels[4] =
    00047 {
    00048         2,2,2,1 // stereo, joint stereo, dual, mono
    00049 };
    00050
    00051 typedef struct
    00052 {
    00053         WORD sync;
    00054         BYTE version;
    00055         BYTE layer;
    00056         DWORD bitrate;
    00057         DWORD freq;
    00058         BYTE channels;
    00059         DWORD framesize;
    00060
    00061         bool ExtractHeader(CSocket& socket)
    00062         {
    00063                 BYTE buff[4];
    00064                 if(4 != socket.Receive(buff, 4, MSG_PEEK))
    00065                         return(false);
    00066
    00067                 sync = (buff[0]<<4)|(buff[1]>>4)|1;
    00068                 version = (buff[1]>>3)&3;
    00069                 layer = 4 - ((buff[1]>>1)&3);
    00070                 bitrate = s_bitrate[version&1][buff[2]>>4]*1000;
    00071                 freq = s_freq[version][(buff[2]>>2)&3];
    00072                 channels = s_channels[(buff[3]>>6)&3];
    00073                 framesize = freq ? ((((version&1)?144:72) * bitrate / freq) + ((buff[2]>>1)&1)) : 0;
    00074
    00075                 return(sync == 0xfff && layer == 3 && bitrate != 0 && freq != 0);
    00076         }
    00077
    00078 } mp3hdr;
    00079
    00080 #ifdef REGISTER_FILTER
    00081
    00082 const AMOVIESETUP_MEDIATYPE sudPinTypesOut[] =
    00083 {
    00084         {&MEDIATYPE_Audio, &MEDIASUBTYPE_MP3},
    00085 };
    00086
    00087 const AMOVIESETUP_PIN sudOpPin[] =
    00088 {
    00089         {L"Output", FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, NULL, countof(sudPinTypesOut), sudPinTypesOut}
    00090 };
    00091
    00092 const AMOVIESETUP_FILTER sudFilter[] =
    00093 {
    00094         {&__uuidof(CShoutcastSource), L"ShoutcastSource", MERIT_UNLIKELY, countof(sudOpPin), sudOpPin}
    00095 };
    00096
    00097 CFactoryTemplate g_Templates[] =
    00098 {
    00099         {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance<CShoutcastSource>, NULL, &sudFilter[0]}
    00100 };
    00101
    00102 int g_cTemplates = countof(g_Templates);
    00103
    00104 STDAPI DllRegisterServer()
    00105 {
    00106         return AMovieDllRegisterServer2(TRUE);
    00107 }
    00108
    00109 STDAPI DllUnregisterServer()
    00110 {
    00111         return AMovieDllRegisterServer2(FALSE);
    00112 }
    00113
    00114 extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);
    00115
    00116 BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
    00117 {
    00118         if(dwReason == DLL_PROCESS_ATTACH)
    00119         {
    00120                 if(!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
    00121                 {
    00122                         AfxMessageBox(_T("AfxWinInit failed!"));
    00123                         return FALSE;
    00124                 }
    00125
    00126                 if(!AfxSocketInit(NULL))
    00127                 {
    00128                         AfxMessageBox(_T("AfxSocketInit failed!"));
    00129                         return FALSE;
    00130                 }
    00131         }
    00132         else if(dwReason == DLL_PROCESS_DETACH)
    00133         {
    00134                 AfxWinTerm();
    00135         }
    00136
    00137     return DllEntryPoint((HINSTANCE)hModule, dwReason, 0); // "DllMain" of the dshow baseclasses;
    00138 }
    00139
    00140 #endif
    00141
    00142 //
    00143 // CShoutcastSource
    00144 //
    00145
    00146 CShoutcastSource::CShoutcastSource(LPUNKNOWN lpunk, HRESULT* phr)
    00147         : CSource(NAME("CShoutcastSource"), lpunk, __uuidof(this))
    00148 {
    00149 #ifndef REGISTER_FILTER
    00150         AfxSocketInit();
    00151 #endif
    00152 }
    00153
    00154 CShoutcastSource::~CShoutcastSource()
    00155 {
    00156 }
    00157
    00158 STDMETHODIMP CShoutcastSource::NonDelegatingQueryInterface(REFIID riid, void** ppv)
    00159 {
    00160     CheckPointer(ppv, E_POINTER);
    00161
    00162         return
    00163                 QI(IFileSourceFilter)
    00164                 QI(IAMFilterMiscFlags)
    00165                 QI(IAMOpenProgress)
    00166                 QI2(IAMMediaContent)
    00167                 __super::NonDelegatingQueryInterface(riid, ppv);
    00168 }
    00169
    00170 // IFileSourceFilter
    00171
    00172 STDMETHODIMP CShoutcastSource::Load(LPCOLESTR pszFileName, const AM_MEDIA_TYPE* pmt)
    00173 {
    00174         if(GetPinCount() > 0)
    00175                 return VFW_E_ALREADY_CONNECTED;
    00176
    00177         HRESULT hr = E_OUTOFMEMORY;
    00178
    00179         if(!(new CShoutcastStream(pszFileName, this, &hr)) || FAILED(hr))
    00180                 return hr;
    00181
    00182         m_fn = pszFileName;
    00183
    00184         return S_OK;
    00185 }
    00186
    00187 STDMETHODIMP CShoutcastSource::GetCurFile(LPOLESTR* ppszFileName, AM_MEDIA_TYPE* pmt)
    00188 {
    00189         if(!ppszFileName) return E_POINTER;
    00190
    00191         if(!(*ppszFileName = (LPOLESTR)CoTaskMemAlloc((m_fn.GetLength()+1)*sizeof(WCHAR))))
    00192                 return E_OUTOFMEMORY;
    00193
    00194         wcscpy(*ppszFileName, m_fn);
    00195
    00196         return S_OK;
    00197 }
    00198
    00199 // IAMFilterMiscFlags
    00200
    00201 ULONG CShoutcastSource::GetMiscFlags()
    00202 {
    00203         return AM_FILTER_MISC_FLAGS_IS_SOURCE;
    00204 }
    00205
    00206 // IAMOpenProgress
    00207
    00208 STDMETHODIMP CShoutcastSource::QueryProgress(LONGLONG* pllTotal, LONGLONG* pllCurrent)
    00209 {
    00210         if(m_iPins == 1)
    00211         {
    00212         if(pllTotal) *pllTotal = 100;
    00213                 if(pllCurrent) *pllCurrent = ((CShoutcastStream*)m_paStreams[0])->GetBufferFullness();
    00214                 return S_OK;
    00215         }
    00216
    00217         return E_UNEXPECTED;
    00218 }
    00219
    00220 STDMETHODIMP CShoutcastSource::AbortOperation()
    00221 {
    00222         return E_NOTIMPL;
    00223 }
    00224
    00225 // IAMMediaContent
    00226
    00227 STDMETHODIMP CShoutcastSource::get_Title(BSTR* pbstrTitle)
    00228 {
    00229         CheckPointer(pbstrTitle, E_POINTER);
    00230
    00231         if(m_iPins == 1)
    00232         {
    00233                 *pbstrTitle = ((CShoutcastStream*)m_paStreams[0])->GetTitle().AllocSysString();
    00234                 return S_OK;
    00235         }
    00236
    00237         return E_UNEXPECTED;
    00238 }
    00239
    00240 // CShoutcastStream
    00241
    00242 CShoutcastStream::CShoutcastStream(const WCHAR* wfn, CShoutcastSource* pParent, HRESULT* phr)
    00243         : CSourceStream(NAME("ShoutcastStream"), phr, pParent, L"Output")
    00244         , m_fBuffering(false)
    00245 {
    00246         ASSERT(phr);
    00247
    00248         *phr = S_OK;
    00249
    00250         CString fn(wfn);
    00251         if(fn.Find(_T("://")) < 0) fn = _T("http://") + fn;
    00252
    00253 #if defined(REGISTER_FILTER) && defined(DEBUG)
    00254 //fn = _T("http://localhost:8000/");
    00255 //fn = _T("http://64.236.34.141/stream/1005");
    00256 //fn = _T("http://218.145.30.106:11000"); // 128kbps korean
    00257 //fn = _T("http://65.206.46.110:8020"); // 96kbps
    00258 //fn = _T("http://64.236.34.72:80/stream/1003");
    00259 fn = _T("http://64.236.34.72:80/stream/1011");
    00260 //fn = _T("http://218.145.30.106:11000");
    00261 //fn = _T("http://radio.sluchaj.com:8000/radio.ogg"); // ogg
    00262 // http://www.oddsock.org/icecast2yp/ // more ogg via icecast2
    00263 #endif
    00264
    00265         if(!m_url.CrackUrl(fn))
    00266         {
    00267                 *phr = E_FAIL;
    00268                 return;
    00269         }
    00270
    00271         if(m_url.GetUrlPathLength() == 0)
    00272                 m_url.SetUrlPath(_T("/"));
    00273
    00274         if(m_url.GetPortNumber() == ATL_URL_INVALID_PORT_NUMBER)
    00275                 m_url.SetPortNumber(ATL_URL_DEFAULT_HTTP_PORT);
    00276
    00277         if(m_url.GetScheme() != ATL_URL_SCHEME_HTTP)
    00278         {
    00279                 *phr = E_FAIL;
    00280                 return;
    00281         }
    00282
    00283         if(!m_socket.Create() || !m_socket.Connect(m_url))
    00284         {
    00285                 *phr = E_FAIL;
    00286                 return;
    00287         }
    00288
    00289         m_socket.Close();
    00290 }
    00291
    00292 CShoutcastStream::~CShoutcastStream()
    00293 {
    00294 }
    00295
    00296 void CShoutcastStream::EmptyBuffer()
    00297 {
    00298         CAutoLock cAutoLock(&m_queue);
    00299         m_queue.RemoveAll();
    00300 }
    00301
    00302 LONGLONG CShoutcastStream::GetBufferFullness()
    00303 {
    00304         CAutoLock cAutoLock(&m_queue);
    00305         if(!m_fBuffering) return 100;
    00306         if(m_queue.IsEmpty()) return 0;
    00307         LONGLONG ret = 100i64*(m_queue.GetTail().rtStart - m_queue.GetHead().rtStart) / AVGBUFFERLENGTH;
    00308         return(min(ret, 100));
    00309 }
    00310
    00311 CString CShoutcastStream::GetTitle()
    00312 {
    00313         CAutoLock cAutoLock(&m_queue);
    00314         return(m_title);
    00315 }
    00316
    00317 HRESULT CShoutcastStream::DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties)
    00318 {
    00319     ASSERT(pAlloc);
    00320     ASSERT(pProperties);
    00321
    00322     HRESULT hr = NOERROR;
    00323
    00324         pProperties->cBuffers = BUFFERS;
    00325         pProperties->cbBuffer = MAXFRAMESIZE;
    00326
    00327     ALLOCATOR_PROPERTIES Actual;
    00328     if(FAILED(hr = pAlloc->SetProperties(pProperties, &Actual))) return hr;
    00329
    00330     if(Actual.cbBuffer < pProperties->cbBuffer) return E_FAIL;
    00331     ASSERT(Actual.cBuffers == pProperties->cBuffers);
    00332
    00333     return NOERROR;
    00334 }
    00335
    00336 HRESULT CShoutcastStream::FillBuffer(IMediaSample* pSample)
    00337 {
    00338         HRESULT hr;
    00339
    00340         BYTE* pData = NULL;
    00341         if(FAILED(hr = pSample->GetPointer(&pData)) || !pData)
    00342                 return S_FALSE;
    00343
    00344         do
    00345         {
    00346                 // do we have to refill our buffer?
    00347                 {
    00348                         CAutoLock cAutoLock(&m_queue);
    00349                         if(!m_queue.IsEmpty() && m_queue.GetHead().rtStart < m_queue.GetTail().rtStart - MINBUFFERLENGTH)
    00350                                 break; // nope, that's great
    00351                 }
    00352
    00353                 TRACE(_T("START BUFFERING\n"));
    00354                 m_fBuffering = true;
    00355
    00356                 while(1)
    00357                 {
    00358                         if(fExitThread) // playback stopped?
    00359                                 return S_FALSE;
    00360
    00361                         Sleep(50);
    00362
    00363                         CAutoLock cAutoLock(&m_queue);
    00364                         if(!m_queue.IsEmpty() && m_queue.GetHead().rtStart < m_queue.GetTail().rtStart - AVGBUFFERLENGTH)
    00365                                 break; // this is enough
    00366                 }
    00367
    00368                 pSample->SetDiscontinuity(TRUE);
    00369
    00370                 DeliverBeginFlush();
    00371                 DeliverEndFlush();
    00372
    00373                 DeliverNewSegment(0, ~0, 1.0);
    00374
    00375                 TRACE(_T("END BUFFERING\n"));
    00376                 m_fBuffering = false;
    00377         }
    00378         while(false);
    00379
    00380         {
    00381                 CAutoLock cAutoLock(&m_queue);
    00382                 ASSERT(!m_queue.IsEmpty());
    00383                 if(!m_queue.IsEmpty())
    00384                 {
    00385                         mp3frame f = m_queue.RemoveHead();
    00386                         DWORD len = min(pSample->GetSize(), f.len);
    00387                         memcpy(pData, f.pData, len);
    00388                         pSample->SetActualDataLength(len);
    00389                         pSample->SetTime(&f.rtStart, &f.rtStop);
    00390                         m_title = f.title;
    00391                 }
    00392         }
    00393
    00394         pSample->SetSyncPoint(TRUE);
    00395
    00396         return S_OK;
    00397 }
    00398
    00399 HRESULT CShoutcastStream::GetMediaType(int iPosition, CMediaType* pmt)
    00400 {
    00401     CAutoLock cAutoLock(m_pFilter->pStateLock());
    00402
    00403     if(iPosition < 0) return E_INVALIDARG;
    00404     if(iPosition > 0) return VFW_S_NO_MORE_ITEMS;
    00405
    00406     pmt->SetType(&MEDIATYPE_Audio);
    00407     pmt->SetSubtype(&MEDIASUBTYPE_MP3);
    00408     pmt->SetFormatType(&FORMAT_WaveFormatEx);
    00409
    00410         WAVEFORMATEX* wfe = (WAVEFORMATEX*)pmt->AllocFormatBuffer(sizeof(WAVEFORMATEX));
    00411         memset(wfe, 0, sizeof(WAVEFORMATEX));
    00412         wfe->wFormatTag = (WORD)MEDIASUBTYPE_MP3.Data1;
    00413         wfe->nChannels = (WORD)m_socket.m_channels;
    00414         wfe->nSamplesPerSec = m_socket.m_freq;
    00415         wfe->nAvgBytesPerSec = m_socket.m_bitrate/8;
    00416         wfe->nBlockAlign = 1;
    00417         wfe->wBitsPerSample = 0;
    00418
    00419     return NOERROR;
    00420 }
    00421
    00422 HRESULT CShoutcastStream::CheckMediaType(const CMediaType* pmt)
    00423 {
    00424         if(pmt->majortype == MEDIATYPE_Audio
    00425         && pmt->subtype == MEDIASUBTYPE_MP3
    00426         && pmt->formattype == FORMAT_WaveFormatEx) return S_OK;
    00427
    00428         return E_INVALIDARG;
    00429 }
    00430
    00431 static UINT SocketThreadProc(LPVOID pParam)
    00432 {
    00433         return ((CShoutcastStream*)pParam)->SocketThreadProc();
    00434 }
    00435
    00436 UINT CShoutcastStream::SocketThreadProc()
    00437 {
    00438         fExitThread = false;
    00439
    00440         SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
    00441
    00442         AfxSocketInit();
    00443
    00444         CAutoVectorPtr<BYTE> pData;
    00445         if(!m_socket.Create() || !m_socket.Connect(m_url)
    00446         || !pData.Allocate(max(m_socket.m_metaint, MAXFRAMESIZE)))
    00447         {
    00448                 m_socket.Close();
    00449                 return 1;
    00450         }
    00451
    00452         REFERENCE_TIME m_rtSampleTime = 0;
    00453
    00454         while(!fExitThread)
    00455         {
    00456                 int len = MAXFRAMESIZE;
    00457                 len = m_socket.Receive(pData, len);
    00458                 if(len <= 0) break;
    00459
    00460                 mp3frame f(len);
    00461                 memcpy(f.pData, pData, len);
    00462                 f.rtStop = (f.rtStart = m_rtSampleTime) + (10000000i64 * len * 8/m_socket.m_bitrate);
    00463                 m_rtSampleTime = f.rtStop;
    00464                 f.title = m_socket.m_title;
    00465
    00466                 CAutoLock cAutoLock(&m_queue);
    00467                 m_queue.AddTail(f);
    00468         }
    00469
    00470         m_socket.Close();
    00471
    00472         return 0;
    00473 }
    00474
    00475 HRESULT CShoutcastStream::OnThreadCreate()
    00476 {
    00477         EmptyBuffer();
    00478
    00479         fExitThread = true;
    00480         m_hSocketThread = AfxBeginThread(::SocketThreadProc, this)->m_hThread;
    00481         while(fExitThread) Sleep(10);
    00482
    00483         return NOERROR;
    00484 }
    00485
    00486 HRESULT CShoutcastStream::OnThreadDestroy()
    00487 {
    00488         EmptyBuffer();
    00489
    00490         fExitThread = true;
    00491         m_socket.CancelBlockingCall();
    00492         WaitForSingleObject(m_hSocketThread, -1);
    00493
    00494         return NOERROR;
    00495 }
    00496
    00497 HRESULT CShoutcastStream::Inactive()
    00498 {
    00499         fExitThread = true;
    00500         return __super::Inactive();
    00501 }
    00502
    00503 //
    00504
    00505 int CShoutcastStream::CShoutcastSocket::Receive(void* lpBuf, int nBufLen, int nFlags)
    00506 {
    00507         if(nFlags&MSG_PEEK)
    00508                 return __super::Receive(lpBuf, nBufLen, nFlags);
    00509
    00510         if(m_metaint > 0 && m_nBytesRead + nBufLen > m_metaint)
    00511                 nBufLen = m_metaint - m_nBytesRead;
    00512
    00513         int len = __super::Receive(lpBuf, nBufLen, nFlags);
    00514         if(len <= 0) return len;
    00515
    00516         if((m_nBytesRead += len) == m_metaint)
    00517         {
    00518                 m_nBytesRead = 0;
    00519
    00520                 static BYTE buff[255*16], b = 0;
    00521                 memset(buff, 0, sizeof(buff));
    00522                 if(1 == __super::Receive(&b, 1) && b && b*16 == __super::Receive(buff, b*16))
    00523                 {
    00524                         CStringA str = (LPCSTR)buff, title("StreamTitle='");
    00525 TRACE(_T("Metainfo: %s\n"), CString(str));
    00526                         int i = str.Find(title);
    00527                         if(i >= 0)
    00528                         {
    00529                                 i += title.GetLength();
    00530                                 int j = str.Find('\'', i);
    00531                                 if(j > i) m_title = str.Mid(i, j - i);
    00532                         }
    00533                         else
    00534                         {
    00535 TRACE(_T("!!!!!!!!!Missing StreamTitle!!!!!!!!!\n"));
    00536                         }
    00537                 }
    00538         }
    00539         else if(m_metaint > 0)
    00540         {
    00541                 char* p = (char*)lpBuf;
    00542                 char* p0 = p;
    00543                 char* pend = p + len - 13;
    00544                 for(; p < pend; p++)
    00545                 {
    00546                         if(strncmp(p, "StreamTitle='", 13))
    00547                                 continue;
    00548
    00549 TRACE(_T("!!!!!!!!!StreamTitle found inside mp3 data!!!!!!!!! offset=%d\n"), p - p0);
    00550 TRACE(_T("resyncing...\n"));
    00551                         while(p-- > p0)
    00552                         {
    00553                                 if((BYTE)*p >= 0x20)
    00554                                         continue;
    00555
    00556 TRACE(_T("found possible length byte: %d, skipping %d bytes\n"), *p, 1 + *p*16);
    00557                                 p += 1 + *p*16;
    00558                                 len = (p0 + len) - p;
    00559 TRACE(_T("returning the remaining bytes in the packet: %d\n"), len);
    00560                                 if(len <= 0)
    00561                                 {
    00562 TRACE(_T("nothing to return, reading a bit more in\n"));
    00563                                         if(len < 0) __super::Receive(lpBuf, -len, nFlags);
    00564
    00565                                         int len = __super::Receive(lpBuf, nBufLen, nFlags);
    00566                                         if(len <= 0) return len;
    00567                                 }
    00568
    00569                                 m_nBytesRead = len;
    00570                                 memcpy(lpBuf, p, len);
    00571
    00572                                 break;
    00573                         }
    00574
    00575                         break;
    00576                 }
    00577         }
    00578
    00579         return len;
    00580 }
    00581
    00582 bool CShoutcastStream::CShoutcastSocket::Connect(CUrl& url)
    00583 {
    00584         if(!__super::Connect(url.GetHostName(), url.GetPortNumber()))
    00585                 return(false);
    00586
    00587         CStringA str;
    00588         str.Format(
    00589                 "GET %s HTTP/1.0\r\n"
    00590                 "Icy-MetaData:1\r\n"
    00591                 "User-Agent: shoutcastsource\r\n"
    00592                 "Host: %s\r\n"
    00593                 "Accept: */*\r\n"
    00594                 "Connection: Keep-Alive\r\n"
    00595                 "\r\n", CStringA(url.GetUrlPath()), CStringA(url.GetHostName()));
    00596
    00597         bool fOK = false;
    00598         bool fTryAgain = false;
    00599         int metaint = 0;
    00600
    00601         do
    00602         {
    00603                 int len = Send((BYTE*)(LPCSTR)str, str.GetLength());
    00604
    00605                 m_nBytesRead = 0;
    00606                 m_metaint = metaint = 0;
    00607                 m_bitrate = 0;
    00608
    00609                 str.Empty();
    00610                 BYTE cur = 0, prev = 0;
    00611                 while(Receive(&cur, 1) == 1 && cur && !(cur == '\n' && prev == '\n'))
    00612                 {
    00613                         if(cur == '\r')
    00614                                 continue;
    00615
    00616                         if(cur == '\n')
    00617                         {
    00618                                 str.MakeLower();
    00619                                 if(str.Find("icy 200 ok") >= 0) fOK = true;
    00620                                 else if(1 == sscanf(str, "icy-br:%d", &m_bitrate)) m_bitrate *= 1000;
    00621                                 else if(1 == sscanf(str, "icy-metaint:%d", &metaint)) metaint = metaint;
    00622                                 str.Empty();
    00623                         }
    00624                         else
    00625                         {
    00626                                 str += cur;
    00627                         }
    00628
    00629                         prev = cur;
    00630                         cur = 0;
    00631                 }
    00632
    00633                 if(!fOK && GetLastError() == WSAECONNRESET && !fTryAgain)
    00634                 {
    00635                         str.Format(
    00636                                 "GET %s HTTP/1.0\r\n"
    00637                                 "Icy-MetaData:1\r\n"
    00638                                 "Host: %s\r\n"
    00639                                 "Accept: */*\r\n"
    00640                                 "Connection: Keep-Alive\r\n"
    00641                                 "\r\n", CStringA(url.GetUrlPath()), CStringA(url.GetHostName()));
    00642
    00643                         fTryAgain = true;
    00644                 }
    00645                 else
    00646                 {
    00647                         fTryAgain = false;
    00648                 }
    00649         }
    00650         while(fTryAgain);
    00651
    00652         if(!fOK || m_bitrate == 0) {Close(); return(false);}
    00653
    00654         m_metaint = metaint;
    00655         m_nBytesRead = 0;
    00656
    00657         return(FindSync());
    00658 }
    00659
    00660 bool CShoutcastStream::CShoutcastSocket::FindSync()
    00661 {
    00662         m_freq = -1;
    00663         m_channels = -1;
    00664
    00665         BYTE b;
    00666         for(int i = MAXFRAMESIZE; i > 0; i--, Receive(&b, 1))
    00667         {
    00668                 mp3hdr h;
    00669                 if(h.ExtractHeader(*this) && m_bitrate == h.bitrate)
    00670                 {
    00671                         if(h.bitrate > 1) m_bitrate = h.bitrate;
    00672                         m_freq = h.freq;
    00673                         m_channels = h.channels;
    00674                         return(true);
    00675                 }
    00676         }
    00677
    00678         return(false);
    00679 }