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 }

Generated on Tue Dec 13 14:47:25 2005 for guliverkli by  doxygen 1.4.5