The architecture of our player uses a NON stop mixer that is hooked to a device for playback. When then attach files to the mixer as we wish them to play.. This is basically how we handle overlapping and fading of audio…
I’m trying to do the exact same thing with a shoutcast stream ( creating a virtual Playback device). To do this I use the NO Sound device and a decode mixer…
My problem is when I set up a thread to pull data through a mixed I pull the data to fast? How do I go about pulling data at the proper playback rate? SO I’m feeding my encoders and dsp as if I were playing the audio to a normal playback device?
I try and set up a thread to pull data through the mixer like so:
//Used as a null render thread data pump..
void NullStreamThreadProc( void *param )
{
char buffer[20000];
DWORD rtnlength = 0;
RcsDevice* pRender = (RcsDevice*)param;
if(pRender)
{
pRender->_bNullRender = true;
DWORD hMixer = pRender->_dwMixerHandle;
while ( hMixer != 0 && BASS_ChannelIsActive(hMixer) )
{
//IM ASSUMING I SHOULD PULL DATA HERE AT SOME CONSTANT RATE?
rtnlength = BASS_ChannelGetData(hMixer, buffer ,20000);
//There is no data in the mixer, wait for some..
if(buffer[0] == 0 )
Sleep(10);
}
//close render stream..
pRender->_bNullRender = false;
pRender->_hNullThread = 0;
}
else
{
assert(!"*** ERROR *** BASS - NullStreamThreadProc CALL - RCSDevice is NULL!");
}
_endthread();
}
Below is the core function used to create the virtual mixer device..
HSTREAM CRCSBassPlayer::VerifyVirtualOutputMixer( RcsDevice* pRCSDevice )
{
BOOL bStarted = FALSE;
HSTREAM mixerstream = 0;
if( pRCSDevice )
{
mixerstream = pRCSDevice->_dwMixerHandle;
//do we need to create one..
if( mixerstream == 0 && IS_RCSVIRTUALID(pRCSDevice->_DeviceId) )
{
BASS_SetDevice( 0 );
CCaster* pCaster = &(pRCSDevice->_VirtualOutputDeviceInfo.Caster);
if( pCaster )
{
DWORD dwFrequency = pCaster->EncoderSamplerate;
DWORD dwChannels = 2; //pCaster->EncoderChannels;
DWORD dwBitRate = pCaster->EncoderBitrate;
//Create a new mixer for the device (software mixing)
mixerstream = BASS_Mixer_StreamCreate(dwFrequency, dwChannels, BASS_SAMPLE_FLOAT| BASS_STREAM_DECODE | BASS_MIXER_NONSTOP);
//Create command line decoder...
CAtlString szEncoder= _T("lame -r -s 44100 -b 128 -");
LPCSTR encodetype = BASS_ENCODE_TYPE_MP3;
if( 0 == pCaster->xEncoderFormat.CollateNoCase( _T(CASTERFORMAT_MP3) ) )
{
szEncoder.Format( _T("lame -r -s %d -b %d -") ,dwFrequency , dwBitRate);
encodetype = BASS_ENCODE_TYPE_MP3;
}
HENCODE hEncoder = BASS_Encode_Start(mixerstream, CT2A(szEncoder), BASS_ENCODE_NOHEAD|BASS_ENCODE_AUTOFREE, NULL, 0);
if( hEncoder )
{
bool bServer = (0 == pCaster->xCasterType.CollateNoCase( _T(CASTERTYPE_SHOUTSERVER) ));
if( !bServer )
{
BASS_Encode_CastInit(hEncoder, CT2A(pCaster->CasterAddress), "", encodetype, CT2A(pCaster->PublishName), CT2A(pCaster->PublishURL)
, CT2A(pCaster->PublishGenre), CT2A(pCaster->PublishDesc), NULL, dwBitRate, pCaster->PublishPublic);
}
else
DWORD buffer = (DWORD)((double)dwBitRate * 125.0 * pCaster->CasterBuffer); //5 second buffer
bStarted = BASS_Encode_ServerInit (hEncoder, CT2A(pCaster->CasterAddress), buffer, buffer, 0, NULL, NULL); // start the server
}
}
else
{
int errorcode = BASS_ErrorGetCode();
CAtlString msg;
msg.Format(_T("Problem Creating Virtual: Output Device:#%d [`%s`] - Mixer:%d , Error Code: %d CommandLine: %s" )
, pRCSDevice->_DeviceId, pRCSDevice->_DeviceKey, mixerstream, errorcode, szEncoder);
m_Logger.LogIt(_T(__FUNCTION__), xLoggerLib::TCL_ERROR, msg.GetBuffer());
}
if( bStarted && mixerstream != 0)
{
//SPECIAL CASE: START THE NULL PLAYDEVICE THREAD!
{
//Don't start the thread until the mixer handle is assigned
pRCSDevice->_hNullThread = (HANDLE) _beginthread(NullStreamThreadProc, 0, (void*)pRCSDevice);
}
//Set up callback for encoder notifies...
BASS_Encode_SetNotify(hEncoder,EncoderNotify,0);
pRCSDevice->_dwMixerHandle = mixerstream;
CAtlString msg;
msg.Format(_T("Created: Output Device: %d, Mixer:%d [`%s`]"), pRCSDevice->_DeviceId, mixerstream, pRCSDevice->_DeviceKey);
m_Logger.LogIt(_T(__FUNCTION__), xLoggerLib::TCL_STATS, msg.GetBuffer());
}
else
{
int errorcode = BASS_ErrorGetCode();
CAtlString msg;
msg.Format(_T("Problem Creating Virtual: Output Device:#%d [`%s`] - Mixer:%d , Error Code: %d"), pRCSDevice->_DeviceId, pRCSDevice->_DeviceKey, mixerstream, errorcode);
m_Logger.LogIt(_T(__FUNCTION__), xLoggerLib::TCL_ERROR, msg.GetBuffer());
pRCSDevice->releaseHandles();
pRCSDevice->reset();
mixerstream = 0;
}
}
}
}
return mixerstream;
}