Multi-threaded audio fixes

This commit is contained in:
erorcun 2021-06-26 23:59:40 +03:00
parent ab38b0089e
commit 05a29c7e6c
4 changed files with 107 additions and 114 deletions

View File

@ -1089,29 +1089,33 @@ CStream::FlagAsToBeProcessed(bool close)
gAudioThreadCv.notify_one(); gAudioThreadCv.notify_one();
} }
extern CStream *aStream[];
void audioFileOpsThread() void audioFileOpsThread()
{ {
std::queue<CStream*> m_streamsToDelete;
do do
{ {
CStream *stream; CStream *stream;
{ {
// Just a semaphore // Just a semaphore
std::unique_lock<std::mutex> queueMutex(gAudioThreadQueueMutex); std::unique_lock<std::mutex> queueMutex(gAudioThreadQueueMutex);
gAudioThreadCv.wait(queueMutex, [m_streamsToDelete] { return gStreamsToProcess.size() > 0 || m_streamsToDelete.size() > 0 || gAudioThreadTerm; }); gAudioThreadCv.wait(queueMutex, [] { return gStreamsToProcess.size() > 0 || gAudioThreadTerm; });
if (gAudioThreadTerm) if (gAudioThreadTerm)
return; return;
if (!gStreamsToProcess.empty()) { if (!gStreamsToProcess.empty()) {
stream = gStreamsToProcess.front(); stream = gStreamsToProcess.front();
gStreamsToProcess.pop(); gStreamsToProcess.pop();
} else { } else
// End of streams. Perform deleting streams continue;
while(!m_streamsToDelete.empty()) { }
CStream *stream = m_streamsToDelete.front();
m_streamsToDelete.pop(); std::unique_lock<std::mutex> lock(stream->m_mutex);
std::pair<ALuint, ALuint> buffers, *lastBufAddr;
bool insertBufsAfterCheck = false;
do {
if (!stream->IsOpened()) {
// We MUST do that here, because we release mutex for m_pSoundFile->Seek() and m_pSoundFile->Decode() since they're costly
if (stream->m_pSoundFile) { if (stream->m_pSoundFile) {
delete stream->m_pSoundFile; delete stream->m_pSoundFile;
stream->m_pSoundFile = nil; stream->m_pSoundFile = nil;
@ -1121,29 +1125,11 @@ void audioFileOpsThread()
free(stream->m_pBuffer); free(stream->m_pBuffer);
stream->m_pBuffer = nil; stream->m_pBuffer = nil;
} }
delete stream; lock.unlock();
} stream->m_closeCv.notify_one();
continue;
}
}
std::unique_lock<std::mutex> lock(stream->m_mutex);
std::pair<ALuint, ALuint> buffers, *lastBufAddr;
bool insertBufsAfterCheck = false;
do {
if (stream->m_nDeleteMe == 1) {
m_streamsToDelete.push(stream);
stream->m_nDeleteMe = 2;
break;
} else if (stream->m_nDeleteMe == 2) {
break; break;
} }
if (!stream->IsOpened())
break;
if (stream->m_bReset) if (stream->m_bReset)
break; break;
@ -1223,14 +1209,14 @@ void CStream::Terminate()
#endif #endif
} }
CStream::CStream(char *filename, ALuint *sources, ALuint (&buffers)[NUM_STREAMBUFFERS], uint32 overrideSampleRate) : CStream::CStream(ALuint *sources, ALuint (&buffers)[NUM_STREAMBUFFERS]) :
m_pAlSources(sources), m_pAlSources(sources),
m_alBuffers(buffers), m_alBuffers(buffers),
m_pBuffer(nil), m_pBuffer(nil),
m_bPaused(false), m_bPaused(false),
m_bActive(false), m_bActive(false),
#ifdef MULTITHREADED_AUDIO #ifdef MULTITHREADED_AUDIO
m_nDeleteMe(false), m_bIExist(false),
m_bDoSeek(false), m_bDoSeek(false),
m_SeekPos(0), m_SeekPos(0),
#endif #endif
@ -1242,6 +1228,31 @@ CStream::CStream(char *filename, ALuint *sources, ALuint (&buffers)[NUM_STREAMBU
m_nLoopCount(1) m_nLoopCount(1)
{ {
}
bool CStream::Open(const char* filename, uint32 overrideSampleRate)
{
if (IsOpened()) return false;
#ifdef MULTITHREADED_AUDIO
std::unique_lock<std::mutex> lock(m_mutex);
CStream *stream = this;
// Wait for thread to close old one. We can't close it here, because the thread might be running Decode() or Seek(), while mutex is released
m_closeCv.wait(lock, [this] { return m_pSoundFile == nil && m_pBuffer == nil; });
m_bDoSeek = false;
m_SeekPos = 0;
#endif
m_bPaused = false;
m_bActive = false;
m_bReset = false;
m_nVolume = 0;
m_nPan = 0;
m_nPosBeforeReset = 0;
m_nLoopCount = 1;
// Be case-insensitive on linux (from https://github.com/OneSadCookie/fcaseopen/) // Be case-insensitive on linux (from https://github.com/OneSadCookie/fcaseopen/)
#if !defined(_WIN32) #if !defined(_WIN32)
char *real = casepath(filename); char *real = casepath(filename);
@ -1278,7 +1289,7 @@ CStream::CStream(char *filename, ALuint *sources, ALuint (&buffers)[NUM_STREAMBU
else else
m_pSoundFile = nil; m_pSoundFile = nil;
if ( IsOpened() ) if ( m_pSoundFile && m_pSoundFile->IsOpened() )
{ {
uint32 bufSize = m_pSoundFile->GetBufferSize(); uint32 bufSize = m_pSoundFile->GetBufferSize();
if(bufSize != 0) { // Otherwise it's deferred if(bufSize != 0) { // Otherwise it's deferred
@ -1293,8 +1304,12 @@ CStream::CStream(char *filename, ALuint *sources, ALuint (&buffers)[NUM_STREAMBU
DEV("Buffer sec: %f\n", (float(m_pSoundFile->GetBufferSamples()) / float(m_pSoundFile->GetChannels())/ float(m_pSoundFile->GetSampleRate()))); DEV("Buffer sec: %f\n", (float(m_pSoundFile->GetBufferSamples()) / float(m_pSoundFile->GetChannels())/ float(m_pSoundFile->GetSampleRate())));
DEV("Length MS: %02d:%02d\n", (m_pSoundFile->GetLength() / 1000) / 60, (m_pSoundFile->GetLength() / 1000) % 60); DEV("Length MS: %02d:%02d\n", (m_pSoundFile->GetLength() / 1000) / 60, (m_pSoundFile->GetLength() / 1000) % 60);
} }
return; #ifdef MULTITHREADED_AUDIO
m_bIExist = true;
#endif
return true;
} }
return false;
} }
CStream::~CStream() CStream::~CStream()
@ -1304,18 +1319,21 @@ CStream::~CStream()
void CStream::Close() void CStream::Close()
{ {
if(!IsOpened()) return;
#ifdef MULTITHREADED_AUDIO #ifdef MULTITHREADED_AUDIO
{ {
std::lock_guard<std::mutex> lock(m_mutex); std::lock_guard<std::mutex> lock(m_mutex);
Stop(); Stop();
ClearBuffers(); ClearBuffers();
m_nDeleteMe = true; m_bIExist = false;
// clearing buffer queues are not needed. after m_nDeleteMe set, this stream is ded // clearing buffer queues are not needed. after m_bIExist is cleared, this stream is ded
} }
FlagAsToBeProcessed(true); FlagAsToBeProcessed(true);
#else #else
Stop(); Stop();
ClearBuffers(); ClearBuffers();
@ -1338,9 +1356,14 @@ bool CStream::HasSource()
return (m_pAlSources[0] != AL_NONE) && (m_pAlSources[1] != AL_NONE); return (m_pAlSources[0] != AL_NONE) && (m_pAlSources[1] != AL_NONE);
} }
// m_bIExist only written in main thread, thus mutex is not needed on main thread
bool CStream::IsOpened() bool CStream::IsOpened()
{ {
#ifdef MULTITHREADED_AUDIO
return m_bIExist;
#else
return m_pSoundFile && m_pSoundFile->IsOpened(); return m_pSoundFile && m_pSoundFile->IsOpened();
#endif
} }
bool CStream::IsPlaying() bool CStream::IsPlaying()

View File

@ -127,9 +127,10 @@ public:
std::mutex m_mutex; std::mutex m_mutex;
std::queue<std::pair<ALuint, ALuint>> m_fillBuffers; // left and right buffer std::queue<std::pair<ALuint, ALuint>> m_fillBuffers; // left and right buffer
tsQueue<std::pair<ALuint, ALuint>> m_queueBuffers; tsQueue<std::pair<ALuint, ALuint>> m_queueBuffers;
std::condition_variable m_closeCv;
bool m_bDoSeek; bool m_bDoSeek;
uint32 m_SeekPos; uint32 m_SeekPos;
uint8 m_nDeleteMe; // 1: add to delete list 2: already on delete list bool m_bIExist;
#endif #endif
void *m_pBuffer; void *m_pBuffer;
@ -163,8 +164,10 @@ public:
static void Initialise(); static void Initialise();
static void Terminate(); static void Terminate();
CStream(char *filename, ALuint *sources, ALuint (&buffers)[NUM_STREAMBUFFERS], uint32 overrideSampleRate = 32000); CStream(ALuint *sources, ALuint (&buffers)[NUM_STREAMBUFFERS]);
~CStream(); ~CStream();
void Delete();
bool Open(const char *filename, uint32 overrideSampleRate = 32000);
void Close(); void Close();
bool IsOpened(); bool IsOpened();

View File

@ -39,6 +39,7 @@
#ifdef MULTITHREADED_AUDIO #ifdef MULTITHREADED_AUDIO
#include <mutex> #include <mutex>
#include <queue> #include <queue>
#include <condition_variable>
#endif #endif
#include "oal/stream.h" #include "oal/stream.h"
@ -522,13 +523,10 @@ _FindMP3s(void)
} else } else
bShortcut = FALSE; bShortcut = FALSE;
aStream[0] = new CStream(filepath, ALStreamSources[0], ALStreamBuffers[0]); if (aStream[0] && aStream[0]->Open(filepath))
if (aStream[0] && aStream[0]->IsOpened())
{ {
total_ms = aStream[0]->GetLengthMS(); total_ms = aStream[0]->GetLengthMS();
aStream[0]->Close(); aStream[0]->Close();
aStream[0] = NULL;
OutputDebugString(fd.cFileName); OutputDebugString(fd.cFileName);
@ -596,13 +594,10 @@ _FindMP3s(void)
continue; continue;
} }
} }
aStream[0] = new CStream(filepath, ALStreamSources[0], ALStreamBuffers[0]); if (aStream[0] && aStream[0]->Open(filepath))
if (aStream[0] && aStream[0]->IsOpened())
{ {
total_ms = aStream[0]->GetLengthMS(); total_ms = aStream[0]->GetLengthMS();
aStream[0]->Close(); aStream[0]->Close();
aStream[0] = NULL;
OutputDebugString(fd.cFileName); OutputDebugString(fd.cFileName);
@ -656,13 +651,10 @@ _FindMP3s(void)
} else } else
bShortcut = FALSE; bShortcut = FALSE;
aStream[0] = new CStream(filepath, ALStreamSources[0], ALStreamBuffers[0]); if (aStream[0] && aStream[0]->Open(filepath))
if (aStream[0] && aStream[0]->IsOpened())
{ {
total_ms = aStream[0]->GetLengthMS(); total_ms = aStream[0]->GetLengthMS();
aStream[0]->Close(); aStream[0]->Close();
aStream[0] = NULL;
OutputDebugString(fd.cFileName); OutputDebugString(fd.cFileName);
@ -818,6 +810,9 @@ cSampleManager::Initialise(void)
EFXInit(); EFXInit();
for(int i = 0; i < MAX_STREAMS; i++)
aStream[i] = new CStream(ALStreamSources[i], ALStreamBuffers[i]);
CStream::Initialise(); CStream::Initialise();
{ {
@ -973,13 +968,10 @@ cSampleManager::Initialise(void)
for ( int32 i = 0; i < TOTAL_STREAMED_SOUNDS; i++ ) for ( int32 i = 0; i < TOTAL_STREAMED_SOUNDS; i++ )
{ {
aStream[0] = new CStream(StreamedNameTable[i], ALStreamSources[0], ALStreamBuffers[0], IsThisTrackAt16KHz(i) ? 16000 : 32000); if ( aStream[0] && aStream[0]->Open(StreamedNameTable[i], IsThisTrackAt16KHz(i) ? 16000 : 32000) )
if ( aStream[0] && aStream[0]->IsOpened() )
{ {
uint32 tatalms = aStream[0]->GetLengthMS(); uint32 tatalms = aStream[0]->GetLengthMS();
aStream[0]->Close(); aStream[0]->Close();
aStream[0] = NULL;
nStreamLength[i] = tatalms; nStreamLength[i] = tatalms;
} }
@ -1023,7 +1015,8 @@ cSampleManager::Initialise(void)
{ {
for ( int32 i = 0; i < MAX_STREAMS; i++ ) for ( int32 i = 0; i < MAX_STREAMS; i++ )
{ {
aStream[i] = NULL; aStream[i]->Close();
nStreamVolume[i] = 100; nStreamVolume[i] = 100;
nStreamPan[i] = 63; nStreamPan[i] = 63;
} }
@ -1110,14 +1103,7 @@ void
cSampleManager::Terminate(void) cSampleManager::Terminate(void)
{ {
for (int32 i = 0; i < MAX_STREAMS; i++) for (int32 i = 0; i < MAX_STREAMS; i++)
{ aStream[i]->Close();
CStream *stream = aStream[i];
if (stream)
{
stream->Close();
aStream[i] = NULL;
}
}
for ( int32 i = 0; i < NUM_CHANNELS; i++ ) for ( int32 i = 0; i < NUM_CHANNELS; i++ )
aChannel[i].Term(); aChannel[i].Term();
@ -1168,6 +1154,9 @@ cSampleManager::Terminate(void)
CStream::Terminate(); CStream::Terminate();
for(int32 i = 0; i < MAX_STREAMS; i++)
delete aStream[i];
if ( nSampleBankMemoryStartAddress[SFX_BANK_0] != 0 ) if ( nSampleBankMemoryStartAddress[SFX_BANK_0] != 0 )
{ {
free((void *)nSampleBankMemoryStartAddress[SFX_BANK_0]); free((void *)nSampleBankMemoryStartAddress[SFX_BANK_0]);
@ -1693,22 +1682,16 @@ cSampleManager::PreloadStreamedFile(uint32 nFile, uint8 nStream)
if ( nFile < TOTAL_STREAMED_SOUNDS ) if ( nFile < TOTAL_STREAMED_SOUNDS )
{ {
if ( aStream[nStream] ) CStream *stream = aStream[nStream];
{
aStream[nStream]->Close(); stream->Close();
aStream[nStream] = NULL;
}
strcpy(filename, StreamedNameTable[nFile]); strcpy(filename, StreamedNameTable[nFile]);
CStream *stream = new CStream(filename, ALStreamSources[nStream], ALStreamBuffers[nStream], IsThisTrackAt16KHz(nFile) ? 16000 : 32000); stream->Open(filename, IsThisTrackAt16KHz(nFile) ? 16000 : 32000);
ASSERT(stream != NULL);
aStream[nStream] = stream;
if ( !stream->Setup() ) if ( !stream->Setup() )
{ {
stream->Close(); stream->Close();
aStream[nStream] = NULL;
} }
} }
} }
@ -1720,7 +1703,7 @@ cSampleManager::PauseStream(bool8 nPauseFlag, uint8 nStream)
CStream *stream = aStream[nStream]; CStream *stream = aStream[nStream];
if ( stream ) if ( stream->IsOpened() )
{ {
stream->SetPause(nPauseFlag != FALSE); stream->SetPause(nPauseFlag != FALSE);
} }
@ -1733,14 +1716,11 @@ cSampleManager::StartPreloadedStreamedFile(uint8 nStream)
CStream *stream = aStream[nStream]; CStream *stream = aStream[nStream];
if ( stream )
{
if ( stream->IsOpened() ) if ( stream->IsOpened() )
{ {
stream->Start(); stream->Start();
} }
} }
}
bool8 bool8
cSampleManager::StartStreamedFile(uint32 nFile, uint32 nPos, uint8 nStream) cSampleManager::StartStreamedFile(uint32 nFile, uint32 nPos, uint8 nStream)
@ -1752,11 +1732,8 @@ cSampleManager::StartStreamedFile(uint32 nFile, uint32 nPos, uint8 nStream)
if ( nFile >= TOTAL_STREAMED_SOUNDS ) if ( nFile >= TOTAL_STREAMED_SOUNDS )
return FALSE; return FALSE;
if ( aStream[nStream] )
{
aStream[nStream]->Close(); aStream[nStream]->Close();
aStream[nStream] = NULL;
}
if ( nFile == STREAMED_SOUND_RADIO_MP3_PLAYER ) if ( nFile == STREAMED_SOUND_RADIO_MP3_PLAYER )
{ {
do do
@ -1773,10 +1750,9 @@ cSampleManager::StartStreamedFile(uint32 nFile, uint32 nPos, uint8 nStream)
nFile = 0; nFile = 0;
strcpy(filename, StreamedNameTable[nFile]); strcpy(filename, StreamedNameTable[nFile]);
CStream* stream = new CStream(filename, ALStreamSources[nStream], ALStreamBuffers[nStream], IsThisTrackAt16KHz(nFile) ? 16000 : 32000);
aStream[nStream] = stream;
CStream *stream = aStream[nStream];
stream->Open(filename, IsThisTrackAt16KHz(nFile) ? 16000 : 32000);
if ( stream->Setup() ) { if ( stream->Setup() ) {
stream->SetLoopCount(nStreamLoopedFlag[nStream] ? 0 : 1); stream->SetLoopCount(nStreamLoopedFlag[nStream] ? 0 : 1);
nStreamLoopedFlag[nStream] = TRUE; nStreamLoopedFlag[nStream] = TRUE;
@ -1788,19 +1764,18 @@ cSampleManager::StartStreamedFile(uint32 nFile, uint32 nPos, uint8 nStream)
return TRUE; return TRUE;
} else { } else {
stream->Close(); stream->Close();
aStream[nStream] = NULL;
} }
return FALSE; return FALSE;
} else { } else {
if (e->pLinkPath != NULL) if (e->pLinkPath != NULL)
aStream[nStream] = new CStream(e->pLinkPath, ALStreamSources[nStream], ALStreamBuffers[nStream], IsThisTrackAt16KHz(nFile) ? 16000 : 32000); aStream[nStream]->Open(e->pLinkPath, IsThisTrackAt16KHz(nFile) ? 16000 : 32000);
else { else {
strcpy(filename, _mp3DirectoryPath); strcpy(filename, _mp3DirectoryPath);
strcat(filename, e->aFilename); strcat(filename, e->aFilename);
aStream[nStream] = new CStream(filename, ALStreamSources[nStream], ALStreamBuffers[nStream]); aStream[nStream]->Open(filename);
} }
if (aStream[nStream]->Setup()) { if (aStream[nStream]->Setup()) {
@ -1813,7 +1788,6 @@ cSampleManager::StartStreamedFile(uint32 nFile, uint32 nPos, uint8 nStream)
return TRUE; return TRUE;
} else { } else {
aStream[nStream]->Close(); aStream[nStream]->Close();
aStream[nStream] = NULL;
} }
// fall through, start playing from another song // fall through, start playing from another song
} }
@ -1832,9 +1806,8 @@ cSampleManager::StartStreamedFile(uint32 nFile, uint32 nPos, uint8 nStream)
_bIsMp3Active = 0; _bIsMp3Active = 0;
strcpy(filename, StreamedNameTable[nFile]); strcpy(filename, StreamedNameTable[nFile]);
CStream* stream = new CStream(filename, ALStreamSources[nStream], ALStreamBuffers[nStream], IsThisTrackAt16KHz(nFile) ? 16000 : 32000); CStream* stream = aStream[nStream];
stream->Open(filename, IsThisTrackAt16KHz(nFile) ? 16000 : 32000);
aStream[nStream] = stream;
if (stream->Setup()) { if (stream->Setup()) {
stream->SetLoopCount(nStreamLoopedFlag[nStream] ? 0 : 1); stream->SetLoopCount(nStreamLoopedFlag[nStream] ? 0 : 1);
@ -1847,18 +1820,17 @@ cSampleManager::StartStreamedFile(uint32 nFile, uint32 nPos, uint8 nStream)
return TRUE; return TRUE;
} else { } else {
stream->Close(); stream->Close();
aStream[nStream] = NULL;
} }
return FALSE; return FALSE;
} }
} }
if (mp3->pLinkPath != NULL) if (mp3->pLinkPath != NULL)
aStream[nStream] = new CStream(mp3->pLinkPath, ALStreamSources[nStream], ALStreamBuffers[nStream], IsThisTrackAt16KHz(nFile) ? 16000 : 32000); aStream[nStream]->Open(mp3->pLinkPath, IsThisTrackAt16KHz(nFile) ? 16000 : 32000);
else { else {
strcpy(filename, _mp3DirectoryPath); strcpy(filename, _mp3DirectoryPath);
strcat(filename, mp3->aFilename); strcat(filename, mp3->aFilename);
aStream[nStream] = new CStream(filename, ALStreamSources[nStream], ALStreamBuffers[nStream], IsThisTrackAt16KHz(nFile) ? 16000 : 32000); aStream[nStream]->Open(filename, IsThisTrackAt16KHz(nFile) ? 16000 : 32000);
} }
if (aStream[nStream]->Setup()) { if (aStream[nStream]->Setup()) {
@ -1869,7 +1841,6 @@ cSampleManager::StartStreamedFile(uint32 nFile, uint32 nPos, uint8 nStream)
return TRUE; return TRUE;
} else { } else {
aStream[nStream]->Close(); aStream[nStream]->Close();
aStream[nStream] = NULL;
} }
} }
@ -1881,9 +1852,9 @@ cSampleManager::StartStreamedFile(uint32 nFile, uint32 nPos, uint8 nStream)
} }
strcpy(filename, StreamedNameTable[nFile]); strcpy(filename, StreamedNameTable[nFile]);
CStream *stream = new CStream(filename, ALStreamSources[nStream], ALStreamBuffers[nStream], IsThisTrackAt16KHz(nFile) ? 16000 : 32000); CStream *stream = aStream[nStream];
aStream[nStream] = stream; aStream[nStream]->Open(filename, IsThisTrackAt16KHz(nFile) ? 16000 : 32000);
if ( stream->Setup() ) { if ( stream->Setup() ) {
stream->SetLoopCount(nStreamLoopedFlag[nStream] ? 0 : 1); stream->SetLoopCount(nStreamLoopedFlag[nStream] ? 0 : 1);
@ -1896,7 +1867,6 @@ cSampleManager::StartStreamedFile(uint32 nFile, uint32 nPos, uint8 nStream)
return TRUE; return TRUE;
} else { } else {
stream->Close(); stream->Close();
aStream[nStream] = NULL;
} }
return FALSE; return FALSE;
} }
@ -1908,15 +1878,11 @@ cSampleManager::StopStreamedFile(uint8 nStream)
CStream *stream = aStream[nStream]; CStream *stream = aStream[nStream];
if ( stream )
{
stream->Close(); stream->Close();
aStream[nStream] = NULL;
if ( nStream == 0 ) if ( nStream == 0 )
_bIsMp3Active = FALSE; _bIsMp3Active = FALSE;
} }
}
int32 int32
cSampleManager::GetStreamedFilePosition(uint8 nStream) cSampleManager::GetStreamedFilePosition(uint8 nStream)
@ -1925,7 +1891,7 @@ cSampleManager::GetStreamedFilePosition(uint8 nStream)
CStream *stream = aStream[nStream]; CStream *stream = aStream[nStream];
if ( stream ) if ( stream->IsOpened() )
{ {
if ( _bIsMp3Active ) if ( _bIsMp3Active )
{ {
@ -1968,7 +1934,7 @@ cSampleManager::SetStreamedVolumeAndPan(uint8 nVolume, uint8 nPan, bool8 nEffect
CStream *stream = aStream[nStream]; CStream *stream = aStream[nStream];
if ( stream ) if ( stream->IsOpened() )
{ {
if ( nEffectFlag ) { if ( nEffectFlag ) {
if ( nStream == 1 || nStream == 2 ) if ( nStream == 1 || nStream == 2 )
@ -1998,7 +1964,7 @@ cSampleManager::IsStreamPlaying(uint8 nStream)
CStream *stream = aStream[nStream]; CStream *stream = aStream[nStream];
if ( stream ) if ( stream->IsOpened() )
{ {
if ( stream->IsPlaying() ) if ( stream->IsPlaying() )
return TRUE; return TRUE;
@ -2014,7 +1980,7 @@ cSampleManager::Service(void)
{ {
CStream *stream = aStream[i]; CStream *stream = aStream[i];
if ( stream ) if ( stream->IsOpened() )
stream->Update(); stream->Update();
} }
int refCount = CChannel::channelsThatNeedService; int refCount = CChannel::channelsThatNeedService;

View File

@ -399,7 +399,7 @@ static_assert(false, "SUPPORT_XBOX_SCRIPT and SUPPORT_MOBILE_SCRIPT are mutually
//#define PS2_AUDIO_PATHS // changes audio paths for cutscenes and radio to PS2 paths (needs vbdec on MSS builds) //#define PS2_AUDIO_PATHS // changes audio paths for cutscenes and radio to PS2 paths (needs vbdec on MSS builds)
//#define AUDIO_OAL_USE_SNDFILE // use libsndfile to decode WAVs instead of our internal decoder //#define AUDIO_OAL_USE_SNDFILE // use libsndfile to decode WAVs instead of our internal decoder
#define AUDIO_OAL_USE_MPG123 // use mpg123 to support mp3 files #define AUDIO_OAL_USE_MPG123 // use mpg123 to support mp3 files
#define MULTITHREADED_AUDIO #define MULTITHREADED_AUDIO // for streams. requires C++11 or later
#ifdef AUDIO_OPUS #ifdef AUDIO_OPUS
#define AUDIO_OAL_USE_OPUS // enable support of opus files #define AUDIO_OAL_USE_OPUS // enable support of opus files
@ -513,5 +513,6 @@ static_assert(false, "SUPPORT_XBOX_SCRIPT and SUPPORT_MOBILE_SCRIPT are mutually
#undef FREE_CAM #undef FREE_CAM
#undef BIG_IMG #undef BIG_IMG
#undef PS2_AUDIO_CHANNELS #undef PS2_AUDIO_CHANNELS
#undef MULTITHREADED_AUDIO
#undef RADIO_SCROLL_TO_PREV_STATION #undef RADIO_SCROLL_TO_PREV_STATION
#endif #endif