You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
amarok/amarok/src/engine/helix/helix-sp/hspadvisesink.cpp

669 lines
18 KiB

/*
*
* This software is released under the provisions of the GPL version 2.
* see file "COPYING". If that file is not available, the full statement
* of the license can be found at
*
* http://www.fsf.org/licensing/licenses/gpl.txt
*
* Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved.
* Portions (c) Paul Cifarelli 2005
*/
#include <stdio.h>
#include "hxcomm.h"
#include "hxmon.h"
#include "hxcore.h"
#include "hxengin.h"
#include "hxclsnk.h"
#include "ihxpckts.h"
#include "hxausvc.h"
#include "helix-sp.h"
#include "hspadvisesink.h"
#include "utils.h"
#if defined(__cplusplus)
extern "C" {
#endif /* defined(__cplusplus) */
#if defined(__cplusplus)
}
#endif /* defined(__cplusplus) */
HSPClientAdviceSink::HSPClientAdviceSink(IUnknown* pUnknown, LONG32 lClientIndex, HelixSimplePlayer *pSplay)
: m_splayer(pSplay)
, m_lRefCount (0)
, m_lClientIndex (lClientIndex)
, m_pUnknown (NULL)
, m_pRegistry (NULL)
, m_pScheduler (NULL)
, m_position(0)
, m_duration(0)
, m_lCurrentBandwidth(0)
, m_lAverageBandwidth(0)
, m_bOnStop(0)
{
//m_splayer->bEnableAdviceSink = true;
if (pUnknown)
{
m_pUnknown = pUnknown;
m_pUnknown->AddRef();
if (HXR_OK != m_pUnknown->QueryInterface(IID_IHXRegistry, (void**)&m_pRegistry))
{
m_pRegistry = NULL;
}
if (HXR_OK != m_pUnknown->QueryInterface(IID_IHXScheduler, (void**)&m_pScheduler))
{
m_pScheduler = NULL;
}
IHXPlayer* pPlayer;
if(HXR_OK == m_pUnknown->QueryInterface(IID_IHXPlayer,
(void**)&pPlayer))
{
pPlayer->AddAdviseSink(this);
pPlayer->Release();
}
}
}
HSPClientAdviceSink::~HSPClientAdviceSink(void)
{
if (m_pScheduler)
{
m_pScheduler->Release();
m_pScheduler = NULL;
}
if (m_pRegistry)
{
m_pRegistry->Release();
m_pRegistry = NULL;
}
if (m_pUnknown)
{
m_pUnknown->Release();
m_pUnknown = NULL;
}
}
// *** IUnknown methods ***
/////////////////////////////////////////////////////////////////////////
// Method:
// IUnknown::QueryInterface
// Purpose:
// Implement this to export the interfaces supported by your
// object.
//
STDMETHODIMP HSPClientAdviceSink::QueryInterface(REFIID riid, void** ppvObj)
{
if (IsEqualIID(riid, IID_IUnknown))
{
AddRef();
*ppvObj = (IUnknown*)(IHXClientAdviseSink*)this;
return HXR_OK;
}
else if (IsEqualIID(riid, IID_IHXClientAdviseSink))
{
AddRef();
*ppvObj = (IHXClientAdviseSink*)this;
return HXR_OK;
}
*ppvObj = NULL;
return HXR_NOINTERFACE;
}
/////////////////////////////////////////////////////////////////////////
// Method:
// IUnknown::AddRef
// Purpose:
// Everyone usually implements this the same... feel free to use
// this implementation.
//
STDMETHODIMP_(ULONG32) HSPClientAdviceSink::AddRef()
{
return InterlockedIncrement(&m_lRefCount);
}
/////////////////////////////////////////////////////////////////////////
// Method:
// IUnknown::Release
// Purpose:
// Everyone usually implements this the same... feel free to use
// this implementation.
//
STDMETHODIMP_(ULONG32) HSPClientAdviceSink::Release()
{
if (InterlockedDecrement(&m_lRefCount) > 0)
{
return m_lRefCount;
}
delete this;
return 0;
}
/*
* IHXClientAdviseSink methods
*/
/************************************************************************
* Method:
* IHXClientAdviseSink::OnPosLength
* Purpose:
* Called to advise the client that the position or length of the
* current playback context has changed.
*/
STDMETHODIMP
HSPClientAdviceSink::OnPosLength(UINT32 ulPosition,
UINT32 ulLength)
{
if (m_splayer->bEnableAdviceSink)
{
m_splayer->print2stdout("OnPosLength(%ld, %ld)\n", ulPosition, ulLength);
}
m_position = ulPosition;
m_duration = ulLength;
return HXR_OK;
}
/************************************************************************
* Method:
* IHXClientAdviseSink::OnPresentationOpened
* Purpose:
* Called to advise the client a presentation has been opened.
*/
STDMETHODIMP HSPClientAdviceSink::OnPresentationOpened()
{
/*
if (m_splayer && m_splayer->xf().crossfading && m_lClientIndex == m_splayer->xf().toIndex)
{
m_splayer->print2stderr("Crossfading...\n");
m_splayer->xf().toStream = 0;
m_splayer->xf().toStream = m_splayer->getAudioPlayer(m_lClientIndex)->GetAudioStream(0);
if (m_splayer->xf().toStream)
{
m_splayer->print2stderr("Got Stream 2\n");
m_splayer->startCrossFade();
}
else
m_splayer->stop(m_lClientIndex);
}
*/
//m_splayer->bEnableAdviceSink = true;
if (m_splayer->bEnableAdviceSink)
{
m_splayer->print2stdout("OnPresentationOpened()\n");
}
return HXR_OK;
}
/************************************************************************
* Method:
* IHXClientAdviseSink::OnPresentationClosed
* Purpose:
* Called to advise the client a presentation has been closed.
*/
STDMETHODIMP HSPClientAdviceSink::OnPresentationClosed()
{
if (m_splayer->bEnableAdviceSink)
{
m_splayer->print2stdout("OnPresentationClosed()\n");
}
return HXR_OK;
}
void HSPClientAdviceSink::GetStatistics (char* pszRegistryKey)
{
char szRegistryValue[MAX_DISPLAY_NAME] = {0}; /* Flawfinder: ignore */
INT32 lValue = 0;
INT32 i = 0;
INT32 lStatistics = 8;
UINT32 *plValue;
// collect statistic
for (i = 0; i < lStatistics; i++)
{
plValue = NULL;
switch (i)
{
case 0:
SafeSprintf(szRegistryValue, MAX_DISPLAY_NAME, "%s.Normal", pszRegistryKey);
break;
case 1:
SafeSprintf(szRegistryValue, MAX_DISPLAY_NAME, "%s.Recovered", pszRegistryKey);
break;
case 2:
SafeSprintf(szRegistryValue, MAX_DISPLAY_NAME, "%s.Received", pszRegistryKey);
break;
case 3:
SafeSprintf(szRegistryValue, MAX_DISPLAY_NAME, "%s.Lost", pszRegistryKey);
break;
case 4:
SafeSprintf(szRegistryValue, MAX_DISPLAY_NAME, "%s.Late", pszRegistryKey);
break;
case 5:
SafeSprintf(szRegistryValue, MAX_DISPLAY_NAME, "%s.ClipBandwidth", pszRegistryKey);
break;
case 6:
SafeSprintf(szRegistryValue, MAX_DISPLAY_NAME, "%s.AverageBandwidth", pszRegistryKey);
plValue = &m_lAverageBandwidth;
break;
case 7:
SafeSprintf(szRegistryValue, MAX_DISPLAY_NAME, "%s.CurrentBandwidth", pszRegistryKey);
plValue = &m_lCurrentBandwidth;
break;
default:
break;
}
m_pRegistry->GetIntByName(szRegistryValue, lValue);
if (plValue)
{
if (m_bOnStop || lValue == 0)
{
lValue = *plValue;
}
else
{
*plValue = lValue;
}
}
if (m_splayer->bEnableAdviceSink || (m_splayer->bEnableVerboseMode && m_bOnStop))
{
m_splayer->print2stdout("%s = %ld\n", szRegistryValue, lValue);
}
}
}
void HSPClientAdviceSink::GetAllStatistics(void)
{
UINT32 unPlayerIndex = 0;
UINT32 unSourceIndex = 0;
UINT32 unStreamIndex = 0;
const char* pszRegistryPrefix = "Statistics";
char szRegistryName[MAX_DISPLAY_NAME] = {0}; /* Flawfinder: ignore */
// display the content of whole statistic registry
if (m_pRegistry)
{
// ok, let's start from the top (player)
SafeSprintf(szRegistryName, MAX_DISPLAY_NAME, "%s.Player%ld", pszRegistryPrefix, m_lClientIndex);
if (PT_COMPOSITE == m_pRegistry->GetTypeByName(szRegistryName))
{
// display player statistic
GetStatistics(szRegistryName);
SafeSprintf(szRegistryName, MAX_DISPLAY_NAME, "%s.Source%ld", szRegistryName, unSourceIndex);
while (PT_COMPOSITE == m_pRegistry->GetTypeByName(szRegistryName))
{
// display source statistic
GetStatistics(szRegistryName);
SafeSprintf(szRegistryName, MAX_DISPLAY_NAME, "%s.Stream%ld", szRegistryName, unStreamIndex);
while (PT_COMPOSITE == m_pRegistry->GetTypeByName(szRegistryName))
{
// display stream statistic
GetStatistics(szRegistryName);
unStreamIndex++;
SafeSprintf(szRegistryName, MAX_DISPLAY_NAME, "%s.Player%ld.Source%ld.Stream%ld",
pszRegistryPrefix, unPlayerIndex, unSourceIndex, unStreamIndex);
}
unSourceIndex++;
SafeSprintf(szRegistryName, MAX_DISPLAY_NAME, "%s.Player%ld.Source%ld",
pszRegistryPrefix, unPlayerIndex, unSourceIndex);
}
unPlayerIndex++;
SafeSprintf(szRegistryName, MAX_DISPLAY_NAME, "%s.Player%ld", pszRegistryPrefix, unPlayerIndex);
}
}
}
/************************************************************************
* Method:
* IHXClientAdviseSink::OnStatisticsChanged
* Purpose:
* Called to advise the client that the presentation statistics
* have changed.
*/
STDMETHODIMP HSPClientAdviceSink::OnStatisticsChanged(void)
{
char szBuff[1024]; /* Flawfinder: ignore */
HX_RESULT res = HXR_OK;
UINT16 uPlayer = 0;
//if(m_splayer->bEnableAdviceSink)
{
if(m_splayer->bEnableAdviceSink)
m_splayer->print2stdout("OnStatisticsChanged():\n");
SafeSprintf(szBuff, 1024, "Statistics.Player%u", uPlayer );
while( HXR_OK == res )
{
res = DumpRegTree( szBuff, uPlayer );
if ( HXR_OK == res )
{
//m_splayer->print2stderr("%d Title: %s\n", uPlayer, m_splayer->ppctrl[uPlayer]->md.title);
//m_splayer->print2stderr("%d Author: %s\n", uPlayer, m_splayer->ppctrl[uPlayer]->md.artist);
//m_splayer->print2stderr("%d Bitrate: %ld\n", uPlayer, m_splayer->ppctrl[uPlayer]->md.bitrate);
}
uPlayer++;
SafeSprintf(szBuff, 1024, "Statistics.Player%u", uPlayer );
}
}
return HXR_OK;
}
HX_RESULT HSPClientAdviceSink::DumpRegTree(const char* pszTreeName, UINT16 index )
{
const char* pszName = NULL;
ULONG32 ulRegID = 0;
HX_RESULT res = HXR_OK;
INT32 nVal = 0;
IHXBuffer* pBuff = NULL;
IHXValues* pValues = NULL;
int len;
bool title = false;
bool bw = false;
bool author = false;
//See if the name exists in the reg tree.
res = m_pRegistry->GetPropListByName( pszTreeName, pValues);
if( HXR_OK!=res || !pValues )
return HXR_FAIL;
//make sure this is a PT_COMPOSITE type reg entry.
if( PT_COMPOSITE != m_pRegistry->GetTypeByName(pszTreeName))
return HXR_FAIL;
//Print out the value of each member of this tree.
res = pValues->GetFirstPropertyULONG32( pszName, ulRegID );
while( HXR_OK == res )
{
title = false;
bw = false;
author = false;
len = strlen(pszName);
len -= strlen("Title");
if (len > 0 && !strcmp(&pszName[len], "Title"))
title = true;
len += strlen("Title");
len -= strlen("Author");
if (len > 0 && !strcmp(&pszName[len], "Author"))
author = true;
len += strlen("Author");
len -= strlen("AverageBandwidth");
if (len > 0 && !strcmp(&pszName[len], "AverageBandwidth"))
bw = true;
//We have at least one entry. See what type it is.
HXPropType pt = m_pRegistry->GetTypeById(ulRegID);
switch(pt)
{
case PT_COMPOSITE:
DumpRegTree(pszName, index);
break;
case PT_INTEGER :
nVal = 0;
m_pRegistry->GetIntById( ulRegID, nVal );
if(m_splayer->bEnableAdviceSink)
m_splayer->print2stdout("%s : %ld\n", pszName, nVal );
if (bw)
m_splayer->ppctrl[index]->md.bitrate = nVal;
break;
case PT_INTREF :
nVal = 0;
m_pRegistry->GetIntById( ulRegID, nVal );
if(m_splayer->bEnableAdviceSink)
m_splayer->print2stdout("%s : %ld\n", pszName, nVal );
if (bw)
m_splayer->ppctrl[index]->md.bitrate = nVal;
break;
case PT_STRING :
pBuff = NULL;
m_pRegistry->GetStrById( ulRegID, pBuff );
if(m_splayer->bEnableAdviceSink)
m_splayer->print2stdout("%s : \"", pszName );
if( pBuff )
if(m_splayer->bEnableAdviceSink)
m_splayer->print2stdout("%s", (const char *)(pBuff->GetBuffer()) );
if(m_splayer->bEnableAdviceSink)
m_splayer->print2stdout("\"\n" );
if (title && pBuff)
{
strncpy(m_splayer->ppctrl[index]->md.title, (const char *) (pBuff->GetBuffer()), 512);
m_splayer->ppctrl[index]->md.title[511] = '\0';
}
if (author && pBuff)
{
strncpy(m_splayer->ppctrl[index]->md.artist, (const char *) (pBuff->GetBuffer()), 512);
m_splayer->ppctrl[index]->md.artist[511] = '\0';
}
HX_RELEASE(pBuff);
break;
case PT_BUFFER :
if(m_splayer->bEnableAdviceSink)
m_splayer->print2stdout("%s %ld : BUFFER TYPE NOT SHOWN\n",
pszName, nVal );
break;
case PT_UNKNOWN:
if(m_splayer->bEnableAdviceSink)
m_splayer->print2stdout("%s Unkown registry type entry\n", pszName );
break;
default:
if(m_splayer->bEnableAdviceSink)
m_splayer->print2stdout("%s Unkown registry type entry\n", pszName );
break;
}
res = pValues->GetNextPropertyULONG32( pszName, ulRegID);
}
HX_RELEASE( pValues );
return HXR_OK;
}
/************************************************************************
* Method:
* IHXClientAdviseSink::OnPreSeek
* Purpose:
* Called by client engine to inform the client that a seek is
* about to occur. The render is informed the last time for the
* stream's time line before the seek, as well as the first new
* time for the stream's time line after the seek will be completed.
*
*/
STDMETHODIMP HSPClientAdviceSink::OnPreSeek( ULONG32 ulOldTime,
ULONG32 ulNewTime)
{
#if !defined(__TCS__)
if (m_splayer->bEnableAdviceSink)
{
m_splayer->print2stdout("OnPreSeek(%ld, %ld)\n", ulOldTime, ulNewTime);
}
#endif
return HXR_OK;
}
/************************************************************************
* Method:
* IHXClientAdviseSink::OnPostSeek
* Purpose:
* Called by client engine to inform the client that a seek has
* just occurred. The render is informed the last time for the
* stream's time line before the seek, as well as the first new
* time for the stream's time line after the seek.
*
*/
STDMETHODIMP HSPClientAdviceSink::OnPostSeek( ULONG32 ulOldTime,
ULONG32 ulNewTime)
{
if (m_splayer->bEnableAdviceSink)
{
m_splayer->print2stdout("OnPostSeek(%ld, %ld)\n", ulOldTime, ulNewTime);
}
return HXR_OK;
}
/************************************************************************
* Method:
* IHXClientAdviseSink::OnStop
* Purpose:
* Called by client engine to inform the client that a stop has
* just occurred.
*
*/
STDMETHODIMP HSPClientAdviceSink::OnStop(void)
{
HXTimeval now;
if (m_splayer->bEnableAdviceSink)
{
m_splayer->print2stdout("OnStop()\n");
}
if (m_splayer->bEnableVerboseMode)
{
m_splayer->print2stdout("Player %ld stopped.\n", m_lClientIndex);
m_bOnStop = true;
GetAllStatistics();
}
// Find out the current time and subtract the beginning time to
// figure out how many seconds we played
now = m_pScheduler->GetCurrentSchedulerTime();
m_ulStopTime = now.tv_sec;
m_splayer->m_ulNumSecondsPlayed = m_ulStopTime - m_ulStartTime;
m_position = m_duration = 0;
return HXR_OK;
}
/************************************************************************
* Method:
* IHXClientAdviseSink::OnPause
* Purpose:
* Called by client engine to inform the client that a pause has
* just occurred. The render is informed the last time for the
* stream's time line before the pause.
*
*/
STDMETHODIMP HSPClientAdviceSink::OnPause(ULONG32 ulTime)
{
if (m_splayer->bEnableAdviceSink)
{
m_splayer->print2stdout("OnPause(%ld)\n", ulTime);
}
return HXR_OK;
}
/************************************************************************
* Method:
* IHXClientAdviseSink::OnBegin
* Purpose:
* Called by client engine to inform the client that a begin or
* resume has just occurred. The render is informed the first time
* for the stream's time line after the resume.
*
*/
STDMETHODIMP HSPClientAdviceSink::OnBegin(ULONG32 ulTime)
{
HXTimeval now;
#if !defined(__TCS__)
if (m_splayer->bEnableAdviceSink)
{
m_splayer->print2stdout("OnBegin(%ld)\n", ulTime);
}
if (m_splayer->bEnableVerboseMode)
{
m_splayer->print2stdout("Player %ld beginning playback...\n", m_lClientIndex);
}
#endif
// Record the current time, so we can figure out many seconds we played
now = m_pScheduler->GetCurrentSchedulerTime();
m_ulStartTime = now.tv_sec;
return HXR_OK;
}
/************************************************************************
* Method:
* IHXClientAdviseSink::OnBuffering
* Purpose:
* Called by client engine to inform the client that buffering
* of data is occurring. The render is informed of the reason for
* the buffering (start-up of stream, seek has occurred, network
* congestion, etc.), as well as percentage complete of the
* buffering process.
*
*/
STDMETHODIMP HSPClientAdviceSink::OnBuffering(ULONG32 ulFlags,
UINT16 unPercentComplete)
{
if (m_splayer->bEnableAdviceSink)
{
m_splayer->print2stdout("OnBuffering(%ld, %d)\n", ulFlags, unPercentComplete);
}
m_splayer->onBuffering(unPercentComplete);
return HXR_OK;
}
/************************************************************************
* Method:
* IHXClientAdviseSink::OnContacting
* Purpose:
* Called by client engine to inform the client is contacting
* hosts(s).
*
*/
STDMETHODIMP HSPClientAdviceSink::OnContacting(const char* pHostName)
{
if (m_splayer->bEnableAdviceSink)
{
m_splayer->print2stdout("OnContacting(\"%s\")\n", pHostName);
}
m_splayer->onContacting(pHostName);
return HXR_OK;
}