Fixed wind dsp and implemented a DSP that mimics removed FMOD::Channel::getWaveData func.
Fixed crash if fmod profiling was enabled. Fixed crash due to failing to check if resulting utf string from stream metadata was zero-length before calling std::string::back.
This commit is contained in:
@@ -321,10 +321,6 @@ bool LLAudioEngine_FMODEX::init(const S32 num_channels, void* userdata)
|
|||||||
if(mEnableProfiler)
|
if(mEnableProfiler)
|
||||||
{
|
{
|
||||||
fmod_flags |= FMOD_INIT_ENABLE_PROFILE;
|
fmod_flags |= FMOD_INIT_ENABLE_PROFILE;
|
||||||
mSystem->createChannelGroup("None", &mChannelGroups[AUDIO_TYPE_NONE]);
|
|
||||||
mSystem->createChannelGroup("SFX", &mChannelGroups[AUDIO_TYPE_SFX]);
|
|
||||||
mSystem->createChannelGroup("UI", &mChannelGroups[AUDIO_TYPE_UI]);
|
|
||||||
mSystem->createChannelGroup("Ambient", &mChannelGroups[AUDIO_TYPE_AMBIENT]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if LL_LINUX
|
#if LL_LINUX
|
||||||
@@ -437,6 +433,14 @@ bool LLAudioEngine_FMODEX::init(const S32 num_channels, void* userdata)
|
|||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (mEnableProfiler)
|
||||||
|
{
|
||||||
|
mSystem->createChannelGroup("None", &mChannelGroups[AUDIO_TYPE_NONE]);
|
||||||
|
mSystem->createChannelGroup("SFX", &mChannelGroups[AUDIO_TYPE_SFX]);
|
||||||
|
mSystem->createChannelGroup("UI", &mChannelGroups[AUDIO_TYPE_UI]);
|
||||||
|
mSystem->createChannelGroup("Ambient", &mChannelGroups[AUDIO_TYPE_AMBIENT]);
|
||||||
|
}
|
||||||
|
|
||||||
// set up our favourite FMOD-native streaming audio implementation if none has already been added
|
// set up our favourite FMOD-native streaming audio implementation if none has already been added
|
||||||
if (!getStreamingAudioImpl()) // no existing implementation added
|
if (!getStreamingAudioImpl()) // no existing implementation added
|
||||||
setStreamingAudioImpl(new LLStreamingAudio_FMODEX(mSystem));
|
setStreamingAudioImpl(new LLStreamingAudio_FMODEX(mSystem));
|
||||||
|
|||||||
@@ -49,6 +49,8 @@
|
|||||||
|
|
||||||
#include "sound_ids.h"
|
#include "sound_ids.h"
|
||||||
|
|
||||||
|
#include <bitset>
|
||||||
|
|
||||||
#if LL_WINDOWS //Some ugly code to make missing fmod.dll not cause a fatal error.
|
#if LL_WINDOWS //Some ugly code to make missing fmod.dll not cause a fatal error.
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
@@ -77,7 +79,7 @@ bool attemptDelayLoad()
|
|||||||
|
|
||||||
static bool sVerboseDebugging = false;
|
static bool sVerboseDebugging = false;
|
||||||
|
|
||||||
FMOD_RESULT F_CALLBACK windCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int outchannels);
|
FMOD_RESULT F_CALLBACK windCallback(FMOD_DSP_STATE *dsp_state, float *originalbuffer, float *newbuffer, unsigned int length, int inchannels, int *outchannels);
|
||||||
|
|
||||||
FMOD::ChannelGroup *LLAudioEngine_FMODSTUDIO::mChannelGroups[LLAudioEngine::AUDIO_TYPE_COUNT] = {0};
|
FMOD::ChannelGroup *LLAudioEngine_FMODSTUDIO::mChannelGroups[LLAudioEngine::AUDIO_TYPE_COUNT] = {0};
|
||||||
|
|
||||||
@@ -314,14 +316,10 @@ bool LLAudioEngine_FMODSTUDIO::init(const S32 num_channels, void* userdata)
|
|||||||
result = mSystem->setSoftwareChannels(num_channels + 2);
|
result = mSystem->setSoftwareChannels(num_channels + 2);
|
||||||
Check_FMOD_Error(result,"FMOD::System::setSoftwareChannels");
|
Check_FMOD_Error(result,"FMOD::System::setSoftwareChannels");
|
||||||
|
|
||||||
U32 fmod_flags = FMOD_INIT_NORMAL | FMOD_INIT_3D_RIGHTHANDED;
|
U32 fmod_flags = FMOD_INIT_NORMAL | FMOD_INIT_3D_RIGHTHANDED | FMOD_INIT_THREAD_UNSAFE;
|
||||||
if(mEnableProfiler)
|
if(mEnableProfiler)
|
||||||
{
|
{
|
||||||
fmod_flags |= FMOD_INIT_PROFILE_ENABLE;
|
fmod_flags |= FMOD_INIT_PROFILE_ENABLE;
|
||||||
mSystem->createChannelGroup("None", &mChannelGroups[AUDIO_TYPE_NONE]);
|
|
||||||
mSystem->createChannelGroup("SFX", &mChannelGroups[AUDIO_TYPE_SFX]);
|
|
||||||
mSystem->createChannelGroup("UI", &mChannelGroups[AUDIO_TYPE_UI]);
|
|
||||||
mSystem->createChannelGroup("Ambient", &mChannelGroups[AUDIO_TYPE_AMBIENT]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if LL_LINUX
|
#if LL_LINUX
|
||||||
@@ -423,7 +421,7 @@ bool LLAudioEngine_FMODSTUDIO::init(const S32 num_channels, void* userdata)
|
|||||||
Ok, the speaker mode selected isn't supported by this soundcard. Switch it
|
Ok, the speaker mode selected isn't supported by this soundcard. Switch it
|
||||||
back to stereo...
|
back to stereo...
|
||||||
*/
|
*/
|
||||||
result = mSystem->setSoftwareFormat(44100, FMOD_SPEAKERMODE_STEREO, 2);
|
result = mSystem->setSoftwareFormat(44100, FMOD_SPEAKERMODE_STEREO, 0);
|
||||||
Check_FMOD_Error(result,"Error falling back to stereo mode");
|
Check_FMOD_Error(result,"Error falling back to stereo mode");
|
||||||
/*
|
/*
|
||||||
... and re-init.
|
... and re-init.
|
||||||
@@ -434,6 +432,14 @@ bool LLAudioEngine_FMODSTUDIO::init(const S32 num_channels, void* userdata)
|
|||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (mEnableProfiler)
|
||||||
|
{
|
||||||
|
mSystem->createChannelGroup("None", &mChannelGroups[AUDIO_TYPE_NONE]);
|
||||||
|
mSystem->createChannelGroup("SFX", &mChannelGroups[AUDIO_TYPE_SFX]);
|
||||||
|
mSystem->createChannelGroup("UI", &mChannelGroups[AUDIO_TYPE_UI]);
|
||||||
|
mSystem->createChannelGroup("Ambient", &mChannelGroups[AUDIO_TYPE_AMBIENT]);
|
||||||
|
}
|
||||||
|
|
||||||
// set up our favourite FMOD-native streaming audio implementation if none has already been added
|
// set up our favourite FMOD-native streaming audio implementation if none has already been added
|
||||||
if (!getStreamingAudioImpl()) // no existing implementation added
|
if (!getStreamingAudioImpl()) // no existing implementation added
|
||||||
setStreamingAudioImpl(new LLStreamingAudio_FMODSTUDIO(mSystem));
|
setStreamingAudioImpl(new LLStreamingAudio_FMODSTUDIO(mSystem));
|
||||||
@@ -536,46 +542,50 @@ LLAudioChannel * LLAudioEngine_FMODSTUDIO::createChannel()
|
|||||||
|
|
||||||
bool LLAudioEngine_FMODSTUDIO::initWind()
|
bool LLAudioEngine_FMODSTUDIO::initWind()
|
||||||
{
|
{
|
||||||
//mNextWindUpdate = 0.0;
|
mNextWindUpdate = 0.0;
|
||||||
|
|
||||||
//if (!mWindDSP)
|
if (!mWindDSP)
|
||||||
//{
|
{
|
||||||
// FMOD_DSP_DESCRIPTION dspdesc;
|
FMOD_DSP_DESCRIPTION dspdesc;
|
||||||
// memset(&dspdesc, 0, sizeof(FMOD_DSP_DESCRIPTION)); //Set everything to zero
|
memset(&dspdesc, 0, sizeof(FMOD_DSP_DESCRIPTION)); //Set everything to zero
|
||||||
// strncpy(dspdesc.name,"Wind Unit", sizeof(dspdesc.name)); //Set name to "Wind Unit"
|
dspdesc.pluginsdkversion = FMOD_PLUGIN_SDK_VERSION;
|
||||||
// dspdesc.read = &windCallback; //Assign callback.
|
strncpy(dspdesc.name,"Wind Unit", sizeof(dspdesc.name)); //Set name to "Wind Unit"
|
||||||
// if(Check_FMOD_Error(mSystem->createDSP(&dspdesc, &mWindDSP), "FMOD::createDSP"))
|
dspdesc.numoutputbuffers = 1;
|
||||||
// return false;
|
dspdesc.read = &windCallback; //Assign callback.
|
||||||
|
if(Check_FMOD_Error(mSystem->createDSP(&dspdesc, &mWindDSP), "FMOD::createDSP"))
|
||||||
|
return false;
|
||||||
|
|
||||||
// if(mWindGen)
|
if(mWindGen)
|
||||||
// delete mWindGen;
|
delete mWindGen;
|
||||||
//
|
|
||||||
// int frequency = 44100;
|
|
||||||
// mSystem->getSoftwareFormat(&frequency, NULL, NULL);
|
|
||||||
// mWindGen = new LLWindGen<MIXBUFFERFORMAT>((U32)frequency);
|
|
||||||
// mWindDSP->setUserData((void*)mWindGen);
|
|
||||||
//}
|
|
||||||
|
|
||||||
//if (mWindDSP)
|
int frequency = 44100;
|
||||||
//{
|
mSystem->getSoftwareFormat(&frequency, NULL, NULL);
|
||||||
// mSystem->playDSP(mWindDSP, NULL, false, 0);
|
mWindGen = new LLWindGen<MIXBUFFERFORMAT>((U32)frequency);
|
||||||
// return true;
|
mWindDSP->setUserData((void*)mWindGen);
|
||||||
//}
|
}
|
||||||
|
|
||||||
|
if (mWindDSP)
|
||||||
|
{
|
||||||
|
mSystem->playDSP(mWindDSP, NULL, false, 0);
|
||||||
|
FMOD_SPEAKERMODE mode;
|
||||||
|
mSystem->getSoftwareFormat(NULL, &mode, NULL);
|
||||||
|
mWindDSP->setChannelFormat(FMOD_CHANNELMASK_STEREO, 2, mode);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void LLAudioEngine_FMODSTUDIO::cleanupWind()
|
void LLAudioEngine_FMODSTUDIO::cleanupWind()
|
||||||
{
|
{
|
||||||
//if (mWindDSP)
|
if (mWindDSP)
|
||||||
//{
|
{
|
||||||
// mWindDSP->remove();
|
mWindDSP->release();
|
||||||
// mWindDSP->release();
|
mWindDSP = NULL;
|
||||||
// mWindDSP = NULL;
|
}
|
||||||
//}
|
|
||||||
|
|
||||||
//delete mWindGen;
|
delete mWindGen;
|
||||||
//mWindGen = NULL;
|
mWindGen = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -289,6 +289,8 @@ void LLStreamingAudio_FMODEX::update()
|
|||||||
case(FMOD_TAGDATATYPE_STRING):
|
case(FMOD_TAGDATATYPE_STRING):
|
||||||
{
|
{
|
||||||
std::string out = rawstr_to_utf8(std::string((char*)tag.data,tag.datalen));
|
std::string out = rawstr_to_utf8(std::string((char*)tag.data,tag.datalen));
|
||||||
|
if (out.length() && out.back() == 0)
|
||||||
|
out.pop_back();
|
||||||
(*mMetaData)[name]=out;
|
(*mMetaData)[name]=out;
|
||||||
llinfos << tag.name << "(RAW): " << out << llendl;
|
llinfos << tag.name << "(RAW): " << out << llendl;
|
||||||
}
|
}
|
||||||
@@ -299,6 +301,8 @@ void LLStreamingAudio_FMODEX::update()
|
|||||||
if (tag.datalen > 3 && ((char*)tag.data)[0] == 0xEF && ((char*)tag.data)[1] == 0xBB && ((char*)tag.data)[2] == 0xBF)
|
if (tag.datalen > 3 && ((char*)tag.data)[0] == 0xEF && ((char*)tag.data)[1] == 0xBB && ((char*)tag.data)[2] == 0xBF)
|
||||||
offs = 3;
|
offs = 3;
|
||||||
std::string out((char*)tag.data + offs, tag.datalen - offs);
|
std::string out((char*)tag.data + offs, tag.datalen - offs);
|
||||||
|
if (out.length() && out.back() == 0)
|
||||||
|
out.pop_back();
|
||||||
(*mMetaData)[name] = out;
|
(*mMetaData)[name] = out;
|
||||||
llinfos << tag.name << "(UTF8): " << out << llendl;
|
llinfos << tag.name << "(UTF8): " << out << llendl;
|
||||||
}
|
}
|
||||||
@@ -306,6 +310,8 @@ void LLStreamingAudio_FMODEX::update()
|
|||||||
case(FMOD_TAGDATATYPE_STRING_UTF16):
|
case(FMOD_TAGDATATYPE_STRING_UTF16):
|
||||||
{
|
{
|
||||||
std::string out = utf16input_to_utf8((char*)tag.data, tag.datalen, UTF16);
|
std::string out = utf16input_to_utf8((char*)tag.data, tag.datalen, UTF16);
|
||||||
|
if (out.length() && out.back() == 0)
|
||||||
|
out.pop_back();
|
||||||
(*mMetaData)[name] = out;
|
(*mMetaData)[name] = out;
|
||||||
llinfos << tag.name << "(UTF16): " << out << llendl;
|
llinfos << tag.name << "(UTF16): " << out << llendl;
|
||||||
}
|
}
|
||||||
@@ -313,6 +319,8 @@ void LLStreamingAudio_FMODEX::update()
|
|||||||
case(FMOD_TAGDATATYPE_STRING_UTF16BE):
|
case(FMOD_TAGDATATYPE_STRING_UTF16BE):
|
||||||
{
|
{
|
||||||
std::string out = utf16input_to_utf8((char*)tag.data, tag.datalen, UTF16BE);
|
std::string out = utf16input_to_utf8((char*)tag.data, tag.datalen, UTF16BE);
|
||||||
|
if (out.length() && out.back() == 0)
|
||||||
|
out.pop_back();
|
||||||
(*mMetaData)[name] = out;
|
(*mMetaData)[name] = out;
|
||||||
llinfos << tag.name << "(UTF16BE): " << out << llendl;
|
llinfos << tag.name << "(UTF16BE): " << out << llendl;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,17 +33,25 @@
|
|||||||
#include "linden_common.h"
|
#include "linden_common.h"
|
||||||
|
|
||||||
#include "llmath.h"
|
#include "llmath.h"
|
||||||
|
#include "llthread.h"
|
||||||
|
|
||||||
#include "fmod.hpp"
|
#include "fmod.hpp"
|
||||||
#include "fmod_errors.h"
|
#include "fmod_errors.h"
|
||||||
|
|
||||||
#include "llstreamingaudio_fmodstudio.h"
|
#include "llstreamingaudio_fmodstudio.h"
|
||||||
|
|
||||||
|
inline bool Check_FMOD_Error(FMOD_RESULT result, const char *string)
|
||||||
|
{
|
||||||
|
if (result == FMOD_OK)
|
||||||
|
return false;
|
||||||
|
LL_WARNS("AudioImpl") << string << " Error: " << FMOD_ErrorString(result) << LL_ENDL;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
class LLAudioStreamManagerFMODSTUDIO
|
class LLAudioStreamManagerFMODSTUDIO
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
LLAudioStreamManagerFMODSTUDIO(FMOD::System *system, const std::string& url);
|
LLAudioStreamManagerFMODSTUDIO(FMOD::System *system, FMOD::ChannelGroup *group, const std::string& url);
|
||||||
FMOD::Channel* startStream();
|
FMOD::Channel* startStream();
|
||||||
bool stopStream(); // Returns true if the stream was successfully stopped.
|
bool stopStream(); // Returns true if the stream was successfully stopped.
|
||||||
bool ready();
|
bool ready();
|
||||||
@@ -55,12 +63,55 @@ protected:
|
|||||||
FMOD::System* mSystem;
|
FMOD::System* mSystem;
|
||||||
FMOD::Channel* mStreamChannel;
|
FMOD::Channel* mStreamChannel;
|
||||||
FMOD::Sound* mInternetStream;
|
FMOD::Sound* mInternetStream;
|
||||||
|
FMOD::ChannelGroup* mChannelGroup;
|
||||||
bool mReady;
|
bool mReady;
|
||||||
|
|
||||||
std::string mInternetStreamURL;
|
std::string mInternetStreamURL;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
LLGlobalMutex gWaveDataMutex; //Just to be extra strict.
|
||||||
|
const U32 WAVE_BUFFER_SIZE = 1024;
|
||||||
|
U32 gWaveBufferMinSize = 0;
|
||||||
|
F32 gWaveDataBuffer[WAVE_BUFFER_SIZE] = { 0.f };
|
||||||
|
U32 gWaveDataBufferSize = 0;
|
||||||
|
|
||||||
|
FMOD_RESULT F_CALLBACK waveDataCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int *outchannels)
|
||||||
|
{
|
||||||
|
if (!length || !inchannels)
|
||||||
|
return FMOD_OK;
|
||||||
|
memcpy(outbuffer, inbuffer, length * inchannels * sizeof(float));
|
||||||
|
|
||||||
|
static std::vector<F32> local_buf;
|
||||||
|
if (local_buf.size() < length)
|
||||||
|
local_buf.resize(length, 0.f);
|
||||||
|
|
||||||
|
for (U32 i = 0; i < length; ++i)
|
||||||
|
{
|
||||||
|
F32 total = 0.f;
|
||||||
|
for (S32 j = 0; j < inchannels; ++j)
|
||||||
|
{
|
||||||
|
total += inbuffer[i*inchannels + j];
|
||||||
|
}
|
||||||
|
local_buf[i] = total / inchannels;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
LLMutexLock lock(gWaveDataMutex);
|
||||||
|
|
||||||
|
for (U32 i = length; i > 0; --i)
|
||||||
|
{
|
||||||
|
if (++gWaveDataBufferSize > WAVE_BUFFER_SIZE)
|
||||||
|
{
|
||||||
|
if (gWaveBufferMinSize)
|
||||||
|
memcpy(gWaveDataBuffer + WAVE_BUFFER_SIZE - gWaveBufferMinSize, gWaveDataBuffer, gWaveBufferMinSize * sizeof(float));
|
||||||
|
gWaveDataBufferSize = 1 + gWaveBufferMinSize;
|
||||||
|
}
|
||||||
|
gWaveDataBuffer[WAVE_BUFFER_SIZE - gWaveDataBufferSize] = local_buf[i - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FMOD_OK;
|
||||||
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
// Internet Streaming
|
// Internet Streaming
|
||||||
@@ -72,11 +123,14 @@ LLStreamingAudio_FMODSTUDIO::LLStreamingAudio_FMODSTUDIO(FMOD::System *system) :
|
|||||||
mGain(1.0f),
|
mGain(1.0f),
|
||||||
mMetaData(NULL)
|
mMetaData(NULL)
|
||||||
{
|
{
|
||||||
|
FMOD_RESULT result;
|
||||||
|
|
||||||
// Number of milliseconds of audio to buffer for the audio card.
|
// Number of milliseconds of audio to buffer for the audio card.
|
||||||
// Must be larger than the usual Second Life frame stutter time.
|
// Must be larger than the usual Second Life frame stutter time.
|
||||||
const U32 buffer_seconds = 10; //sec
|
const U32 buffer_seconds = 10; //sec
|
||||||
const U32 estimated_bitrate = 128; //kbit/sec
|
const U32 estimated_bitrate = 128; //kbit/sec
|
||||||
mSystem->setStreamBufferSize(estimated_bitrate * buffer_seconds * 128/*bytes/kbit*/, FMOD_TIMEUNIT_RAWBYTES);
|
result = mSystem->setStreamBufferSize(estimated_bitrate * buffer_seconds * 128/*bytes/kbit*/, FMOD_TIMEUNIT_RAWBYTES);
|
||||||
|
Check_FMOD_Error(result, "FMOD::System::setStreamBufferSize");
|
||||||
|
|
||||||
// Here's where we set the size of the network buffer and some buffering
|
// Here's where we set the size of the network buffer and some buffering
|
||||||
// parameters. In this case we want a network buffer of 16k, we want it
|
// parameters. In this case we want a network buffer of 16k, we want it
|
||||||
@@ -85,11 +139,36 @@ LLStreamingAudio_FMODSTUDIO::LLStreamingAudio_FMODSTUDIO(FMOD::System *system) :
|
|||||||
|
|
||||||
// Leave the net buffer properties at the default.
|
// Leave the net buffer properties at the default.
|
||||||
//FSOUND_Stream_Net_SetBufferProperties(20000, 40, 80);
|
//FSOUND_Stream_Net_SetBufferProperties(20000, 40, 80);
|
||||||
|
|
||||||
|
result = system->createChannelGroup("stream", &mStreamGroup);
|
||||||
|
Check_FMOD_Error(result,"FMOD::System::createChannelGroup");
|
||||||
|
|
||||||
|
FMOD_DSP_DESCRIPTION dspdesc;
|
||||||
|
memset(&dspdesc, 0, sizeof(FMOD_DSP_DESCRIPTION)); //Zero out everything
|
||||||
|
dspdesc.pluginsdkversion = FMOD_PLUGIN_SDK_VERSION;
|
||||||
|
strncpy(dspdesc.name, "Waveform", sizeof(dspdesc.name));
|
||||||
|
dspdesc.numoutputbuffers = 1;
|
||||||
|
dspdesc.read = &waveDataCallback; //Assign callback.
|
||||||
|
|
||||||
|
result = system->createDSP(&dspdesc, &mStreamDSP);
|
||||||
|
Check_FMOD_Error(result, "FMOD::System::createDSPByType");
|
||||||
|
result = mStreamGroup->addDSP(FMOD_CHANNELCONTROL_DSP_TAIL, mStreamDSP);
|
||||||
|
Check_FMOD_Error(result, "FMOD::ChannelGroup::addDSP");
|
||||||
|
mStreamDSP->setActive(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LLStreamingAudio_FMODSTUDIO::~LLStreamingAudio_FMODSTUDIO()
|
LLStreamingAudio_FMODSTUDIO::~LLStreamingAudio_FMODSTUDIO()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
if (mStreamGroup)
|
||||||
|
{
|
||||||
|
if (mStreamDSP)
|
||||||
|
mStreamGroup->removeDSP(mStreamDSP);
|
||||||
|
mStreamGroup->release();
|
||||||
|
}
|
||||||
|
if (mStreamDSP)
|
||||||
|
mStreamDSP->release();
|
||||||
// nothing interesting/safe to do.
|
// nothing interesting/safe to do.
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,7 +189,7 @@ void LLStreamingAudio_FMODSTUDIO::start(const std::string& url)
|
|||||||
if(mDeadStreams.empty())
|
if(mDeadStreams.empty())
|
||||||
{
|
{
|
||||||
llinfos << "Starting internet stream: " << url << llendl;
|
llinfos << "Starting internet stream: " << url << llendl;
|
||||||
mCurrentInternetStreamp = new LLAudioStreamManagerFMODSTUDIO(mSystem,url);
|
mCurrentInternetStreamp = new LLAudioStreamManagerFMODSTUDIO(mSystem, mStreamGroup, url);
|
||||||
mURL = url;
|
mURL = url;
|
||||||
mMetaData = new LLSD;
|
mMetaData = new LLSD;
|
||||||
}
|
}
|
||||||
@@ -127,6 +206,45 @@ void LLStreamingAudio_FMODSTUDIO::start(const std::string& url)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum utf_endian_type_t
|
||||||
|
{
|
||||||
|
UTF16LE,
|
||||||
|
UTF16BE,
|
||||||
|
UTF16
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string utf16input_to_utf8(char* input, U32 len, utf_endian_type_t type)
|
||||||
|
{
|
||||||
|
if (type == UTF16)
|
||||||
|
{
|
||||||
|
type = UTF16BE; //Default
|
||||||
|
if (len > 2)
|
||||||
|
{
|
||||||
|
//Parse and strip BOM.
|
||||||
|
if ((input[0] == 0xFE && input[1] == 0xFF) ||
|
||||||
|
(input[0] == 0xFF && input[1] == 0xFE))
|
||||||
|
{
|
||||||
|
input += 2;
|
||||||
|
len -= 2;
|
||||||
|
type = input[0] == 0xFE ? UTF16BE : UTF16LE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
llutf16string out_16((U16*)input, len / 2);
|
||||||
|
if (len % 2)
|
||||||
|
{
|
||||||
|
out_16.push_back((input)[len - 1] << 8);
|
||||||
|
}
|
||||||
|
if (type == UTF16BE)
|
||||||
|
{
|
||||||
|
for (llutf16string::iterator i = out_16.begin(); i < out_16.end(); ++i)
|
||||||
|
{
|
||||||
|
llutf16string::value_type v = *i;
|
||||||
|
*i = ((v & 0x00FF) << 8) | ((v & 0xFF00) >> 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return utf16str_to_utf8str(out_16);
|
||||||
|
}
|
||||||
|
|
||||||
void LLStreamingAudio_FMODSTUDIO::update()
|
void LLStreamingAudio_FMODSTUDIO::update()
|
||||||
{
|
{
|
||||||
@@ -157,7 +275,7 @@ void LLStreamingAudio_FMODSTUDIO::update()
|
|||||||
{
|
{
|
||||||
llassert_always(mCurrentInternetStreamp == NULL);
|
llassert_always(mCurrentInternetStreamp == NULL);
|
||||||
llinfos << "Starting internet stream: " << mPendingURL << llendl;
|
llinfos << "Starting internet stream: " << mPendingURL << llendl;
|
||||||
mCurrentInternetStreamp = new LLAudioStreamManagerFMODSTUDIO(mSystem,mPendingURL);
|
mCurrentInternetStreamp = new LLAudioStreamManagerFMODSTUDIO(mSystem,mStreamGroup, mPendingURL);
|
||||||
mURL = mPendingURL;
|
mURL = mPendingURL;
|
||||||
mMetaData = new LLSD;
|
mMetaData = new LLSD;
|
||||||
mPendingURL.clear();
|
mPendingURL.clear();
|
||||||
@@ -184,6 +302,8 @@ void LLStreamingAudio_FMODSTUDIO::update()
|
|||||||
{
|
{
|
||||||
// Reset volume to previously set volume
|
// Reset volume to previously set volume
|
||||||
setGain(getGain());
|
setGain(getGain());
|
||||||
|
if (mStreamDSP)
|
||||||
|
mStreamDSP->setActive(true);
|
||||||
mFMODInternetStreamChannelp->setPaused(false);
|
mFMODInternetStreamChannelp->setPaused(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -216,23 +336,27 @@ void LLStreamingAudio_FMODSTUDIO::update()
|
|||||||
switch(tag.type) //Crappy tag translate table.
|
switch(tag.type) //Crappy tag translate table.
|
||||||
{
|
{
|
||||||
case(FMOD_TAGTYPE_ID3V2):
|
case(FMOD_TAGTYPE_ID3V2):
|
||||||
if(name == "TIT2") name = "TITLE";
|
if (!LLStringUtil::compareInsensitive(name, "TIT2")) name = "TITLE";
|
||||||
else if(name == "TPE1") name = "ARTIST";
|
else if(name == "TPE1") name = "ARTIST";
|
||||||
break;
|
break;
|
||||||
case(FMOD_TAGTYPE_ASF):
|
case(FMOD_TAGTYPE_ASF):
|
||||||
if(name == "Title") name = "TITLE";
|
if (!LLStringUtil::compareInsensitive(name, "Title")) name = "TITLE";
|
||||||
else if(name == "WM/AlbumArtist") name = "ARTIST";
|
else if (!LLStringUtil::compareInsensitive(name, "WM/AlbumArtist")) name = "ARTIST";
|
||||||
break;
|
break;
|
||||||
case(FMOD_TAGTYPE_FMOD):
|
case(FMOD_TAGTYPE_FMOD):
|
||||||
if (!strcmp(tag.name, "Sample Rate Change"))
|
if (!LLStringUtil::compareInsensitive(name, "Sample Rate Change"))
|
||||||
{
|
{
|
||||||
llinfos << "Stream forced changing sample rate to " << *((float *)tag.data) << llendl;
|
llinfos << "Stream forced changing sample rate to " << *((float *)tag.data) << llendl;
|
||||||
mFMODInternetStreamChannelp->setFrequency(*((float *)tag.data));
|
mFMODInternetStreamChannelp->setFrequency(*((float *)tag.data));
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
default:
|
default:
|
||||||
|
if (!LLStringUtil::compareInsensitive(name, "TITLE") ||
|
||||||
|
!LLStringUtil::compareInsensitive(name, "ARTIST"))
|
||||||
|
LLStringUtil::toUpper(name);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(tag.datatype)
|
switch(tag.datatype)
|
||||||
{
|
{
|
||||||
case(FMOD_TAGDATATYPE_INT):
|
case(FMOD_TAGDATATYPE_INT):
|
||||||
@@ -246,25 +370,40 @@ void LLStreamingAudio_FMODSTUDIO::update()
|
|||||||
case(FMOD_TAGDATATYPE_STRING):
|
case(FMOD_TAGDATATYPE_STRING):
|
||||||
{
|
{
|
||||||
std::string out = rawstr_to_utf8(std::string((char*)tag.data,tag.datalen));
|
std::string out = rawstr_to_utf8(std::string((char*)tag.data,tag.datalen));
|
||||||
|
if (out.length() && out.back() == 0)
|
||||||
|
out.pop_back();
|
||||||
(*mMetaData)[name]=out;
|
(*mMetaData)[name]=out;
|
||||||
llinfos << tag.name << ": " << out << llendl;
|
llinfos << tag.name << "(RAW): " << out << llendl;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case(FMOD_TAGDATATYPE_STRING_UTF8) :
|
||||||
|
{
|
||||||
|
U8 offs = 0;
|
||||||
|
if (tag.datalen > 3 && ((char*)tag.data)[0] == 0xEF && ((char*)tag.data)[1] == 0xBB && ((char*)tag.data)[2] == 0xBF)
|
||||||
|
offs = 3;
|
||||||
|
std::string out((char*)tag.data + offs, tag.datalen - offs);
|
||||||
|
if (out.length() && out.back() == 0)
|
||||||
|
out.pop_back();
|
||||||
|
(*mMetaData)[name] = out;
|
||||||
|
llinfos << tag.name << "(UTF8): " << out << llendl;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case(FMOD_TAGDATATYPE_STRING_UTF16):
|
case(FMOD_TAGDATATYPE_STRING_UTF16):
|
||||||
{
|
{
|
||||||
std::string out((char*)tag.data,tag.datalen);
|
std::string out = utf16input_to_utf8((char*)tag.data, tag.datalen, UTF16);
|
||||||
(*mMetaData)[std::string(tag.name)]=out;
|
if (out.length() && out.back() == 0)
|
||||||
llinfos << tag.name << ": " << out << llendl;
|
out.pop_back();
|
||||||
|
(*mMetaData)[name] = out;
|
||||||
|
llinfos << tag.name << "(UTF16): " << out << llendl;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case(FMOD_TAGDATATYPE_STRING_UTF16BE):
|
case(FMOD_TAGDATATYPE_STRING_UTF16BE):
|
||||||
{
|
{
|
||||||
std::string out((char*)tag.data,tag.datalen);
|
std::string out = utf16input_to_utf8((char*)tag.data, tag.datalen, UTF16BE);
|
||||||
U16* buf = (U16*)out.c_str();
|
if (out.length() && out.back() == 0)
|
||||||
for(U32 j = 0; j < out.size()/2; ++j)
|
out.pop_back();
|
||||||
(((buf[j] & 0xff)<<8) | ((buf[j] & 0xff00)>>8));
|
(*mMetaData)[name] = out;
|
||||||
(*mMetaData)[std::string(tag.name)]=out;
|
llinfos << tag.name << "(UTF16BE): " << out << llendl;
|
||||||
llinfos << tag.name << ": " << out << llendl;
|
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -300,6 +439,15 @@ void LLStreamingAudio_FMODSTUDIO::stop()
|
|||||||
delete mMetaData;
|
delete mMetaData;
|
||||||
mMetaData = NULL;
|
mMetaData = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mStreamDSP)
|
||||||
|
{
|
||||||
|
mSystem->lockDSP();
|
||||||
|
mStreamDSP->setActive(false);
|
||||||
|
gWaveDataBufferSize = 0;
|
||||||
|
mSystem->unlockDSP();
|
||||||
|
}
|
||||||
|
|
||||||
if (mFMODInternetStreamChannelp)
|
if (mFMODInternetStreamChannelp)
|
||||||
{
|
{
|
||||||
mFMODInternetStreamChannelp->setPaused(true);
|
mFMODInternetStreamChannelp->setPaused(true);
|
||||||
@@ -390,38 +538,40 @@ void LLStreamingAudio_FMODSTUDIO::setGain(F32 vol)
|
|||||||
|
|
||||||
/*virtual*/ bool LLStreamingAudio_FMODSTUDIO::getWaveData(float* arr, S32 count, S32 stride/*=1*/)
|
/*virtual*/ bool LLStreamingAudio_FMODSTUDIO::getWaveData(float* arr, S32 count, S32 stride/*=1*/)
|
||||||
{
|
{
|
||||||
//if(!mFMODInternetStreamChannelp || !mCurrentInternetStreamp)
|
if (count > (WAVE_BUFFER_SIZE / 2))
|
||||||
// return false;
|
LL_ERRS("AudioImpl") << "Count=" << count << " exceeds WAVE_BUFFER_SIZE/2=" << WAVE_BUFFER_SIZE << LL_ENDL;
|
||||||
|
|
||||||
//bool muted=false;
|
if(!mFMODInternetStreamChannelp || !mCurrentInternetStreamp)
|
||||||
//mFMODInternetStreamChannelp->getMute(&muted);
|
|
||||||
//if(muted)
|
|
||||||
// return false;
|
|
||||||
|
|
||||||
//static std::vector<float> local_array(count); //Have to have an extra buffer to mix channels. Bleh.
|
|
||||||
//if(count > (S32)local_array.size()) //Expand the array if needed. Try to minimize allocation calls, so don't ever shrink.
|
|
||||||
// local_array.resize(count);
|
|
||||||
|
|
||||||
//if( mFMODInternetStreamChannelp->getWaveData(&local_array[0],count,0) == FMOD_OK &&
|
|
||||||
// mFMODInternetStreamChannelp->getWaveData(&arr[0],count,1) == FMOD_OK )
|
|
||||||
//{
|
|
||||||
// for(S32 i = count-1;i>=0;i-=stride)
|
|
||||||
// {
|
|
||||||
// arr[i] += local_array[i];
|
|
||||||
// arr[i] *= .5f;
|
|
||||||
// }
|
|
||||||
// return true;
|
|
||||||
//}
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
bool muted = false;
|
||||||
|
mFMODInternetStreamChannelp->getMute(&muted);
|
||||||
|
if(muted)
|
||||||
|
return false;
|
||||||
|
{
|
||||||
|
U32 buff_size;
|
||||||
|
{
|
||||||
|
LLMutexLock lock(gWaveDataMutex);
|
||||||
|
gWaveBufferMinSize = count;
|
||||||
|
buff_size = gWaveDataBufferSize;
|
||||||
|
if (!buff_size)
|
||||||
|
return false;
|
||||||
|
memcpy(arr, gWaveDataBuffer + WAVE_BUFFER_SIZE - buff_size, llmin(U32(count), buff_size) * sizeof(float));
|
||||||
|
}
|
||||||
|
if (buff_size < U32(count))
|
||||||
|
memset(arr + buff_size, 0, (count - buff_size) * sizeof(float));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////
|
||||||
// manager of possibly-multiple internet audio streams
|
// manager of possibly-multiple internet audio streams
|
||||||
|
|
||||||
LLAudioStreamManagerFMODSTUDIO::LLAudioStreamManagerFMODSTUDIO(FMOD::System *system, const std::string& url) :
|
LLAudioStreamManagerFMODSTUDIO::LLAudioStreamManagerFMODSTUDIO(FMOD::System *system, FMOD::ChannelGroup *group, const std::string& url) :
|
||||||
mSystem(system),
|
mSystem(system),
|
||||||
mStreamChannel(NULL),
|
mStreamChannel(NULL),
|
||||||
mInternetStream(NULL),
|
mInternetStream(NULL),
|
||||||
|
mChannelGroup(group),
|
||||||
mReady(false)
|
mReady(false)
|
||||||
{
|
{
|
||||||
mInternetStreamURL = url;
|
mInternetStreamURL = url;
|
||||||
@@ -452,7 +602,7 @@ FMOD::Channel *LLAudioStreamManagerFMODSTUDIO::startStream()
|
|||||||
if(mStreamChannel)
|
if(mStreamChannel)
|
||||||
return mStreamChannel; //Already have a channel for this stream.
|
return mStreamChannel; //Already have a channel for this stream.
|
||||||
|
|
||||||
mSystem->playSound(mInternetStream, NULL, true, &mStreamChannel);
|
mSystem->playSound(mInternetStream, mChannelGroup, true, &mStreamChannel);
|
||||||
return mStreamChannel;
|
return mStreamChannel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,6 +45,9 @@ namespace FMOD
|
|||||||
{
|
{
|
||||||
class System;
|
class System;
|
||||||
class Channel;
|
class Channel;
|
||||||
|
class ChannelGroup;
|
||||||
|
class ChannelGroup;
|
||||||
|
class DSP;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Interfaces
|
//Interfaces
|
||||||
@@ -65,10 +68,11 @@ class LLStreamingAudio_FMODSTUDIO : public LLStreamingAudioInterface
|
|||||||
|
|
||||||
/*virtual*/ bool supportsMetaData(){return true;}
|
/*virtual*/ bool supportsMetaData(){return true;}
|
||||||
/*virtual*/ const LLSD *getMetaData(){return mMetaData;} //return NULL if not playing.
|
/*virtual*/ const LLSD *getMetaData(){return mMetaData;} //return NULL if not playing.
|
||||||
/*virtual*/ bool supportsWaveData(){return false;}
|
/*virtual*/ bool supportsWaveData(){return true;}
|
||||||
/*virtual*/ bool getWaveData(float* arr, S32 count, S32 stride = 1);
|
/*virtual*/ bool getWaveData(float* arr, S32 count, S32 stride = 1);
|
||||||
/*virtual*/ bool supportsAdjustableBufferSizes(){return true;}
|
/*virtual*/ bool supportsAdjustableBufferSizes(){return true;}
|
||||||
/*virtual*/ void setBufferSizes(U32 streambuffertime, U32 decodebuffertime);
|
/*virtual*/ void setBufferSizes(U32 streambuffertime, U32 decodebuffertime);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FMOD::System *mSystem;
|
FMOD::System *mSystem;
|
||||||
|
|
||||||
@@ -81,6 +85,9 @@ private:
|
|||||||
F32 mGain;
|
F32 mGain;
|
||||||
|
|
||||||
LLSD *mMetaData;
|
LLSD *mMetaData;
|
||||||
|
|
||||||
|
FMOD::ChannelGroup* mStreamGroup;
|
||||||
|
FMOD::DSP* mStreamDSP;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user