diff --git a/src/audio/ngage/SDL_ngageaudio.cpp b/src/audio/ngage/SDL_ngageaudio.cpp index 687b2c597c..246ea2dd42 100644 --- a/src/audio/ngage/SDL_ngageaudio.cpp +++ b/src/audio/ngage/SDL_ngageaudio.cpp @@ -75,13 +75,17 @@ void CAudio::ConstructL(TInt aLatency) CAudio::~CAudio() { if (iStream) { + // Stop the processing thread before stopping the stream. + StopThread(); + iStream->Stop(); - while (iState != EStateDone) { - User::After(100000); // 100ms. - } + // MaoscBufferCopied(KErrAbort) can't fire here because the active + // scheduler is no longer pumping; force the state to avoid deadlock. + iState = EStateDone; delete iStream; + iStream = NULL; } } @@ -98,12 +102,9 @@ void CAudio::Start() } } - - void CAudio::RunL() { iTimerActive = EFalse; - } void CAudio::DoCancel() @@ -117,10 +118,8 @@ void CAudio::StartThread() TInt heapMinSize = 8192; // 8 KB initial heap size. TInt heapMaxSize = 1024 * 1024; // 1 MB maximum heap size. - TInt err = iProcess.Create(_L("ProcessThread"), ProcessThreadCB, KDefaultStackSize * 2, heapMinSize, heapMaxSize, this); - if (err == KErrNone) - { + if (err == KErrNone) { TThreadPriority prio = EPriorityLess; const char *prioHint = SDL_GetHint(SDL_HINT_AUDIO_NGAGE_PROCESS_PRIORITY); @@ -130,7 +129,6 @@ void CAudio::StartThread() RThread().SetPriority(prio); } - iProcess.SetPriority(prio); iProcess.Resume(); } else { @@ -148,42 +146,36 @@ void CAudio::StopThread() } /*************************************************** -* ProcessThreadCB - -* -* This thread calls the SDL mixer when the buffer is ready and self->iState == EStatePlaying (basically other than initial stated, when not writing) -* -* It only mixes, never calls WriteL -****************************************************/ + * ProcessThreadCB - + * + * This thread calls the SDL mixer when the buffer is ready and self->iState == EStatePlaying (basically other than initial stated, when not writing) + * + * It only mixes, never calls WriteL + ****************************************************/ TInt CAudio::ProcessThreadCB(TAny *aPtr) { CTrapCleanup *cleanup = CTrapCleanup::New(); if (!cleanup) return KErrNoMemory; - + CAudio *self = static_cast(aPtr); SDL_AudioDevice *device = NGAGE_GetAudioDeviceAddr(); - TInt processTick = 40000; // Default 40ms const char *tickHint = SDL_GetHint(SDL_HINT_AUDIO_NGAGE_PROCESS_TICK); - if (tickHint) - { + if (tickHint) { processTick = SDL_atoi(tickHint) * 1000; } - while (self->iStreamStarted) - { - if (self->iState == EStatePlaying && !self->iBufferReady) - { - /* Ask SDL to mix audio into buffer[fill_index]*/ + while (self->iStreamStarted) { + if (self->iState == EStatePlaying && !self->iBufferReady) { + /* Ask SDL to mix audio into buffer[fill_index]*/ SDL_PlaybackAudioThreadIterate(device); - /* Signal AudioThreadCB to write it*/ + /* Signal AudioThreadCB to write it*/ self->iBufferReady = ETrue; - } - else - { + } else { /*if we are not ready to obtain the mix data we sleep a bit this thread*/ User::After(processTick); } @@ -195,17 +187,17 @@ TInt CAudio::ProcessThreadCB(TAny *aPtr) static TBool gAudioRunning; /*************************************************** -* AudioThreadCB - -* -* This thread owns the scheduler and calls WriteL, wich queues the assigned sound buffer to be played -****************************************************/ + * AudioThreadCB - + * + * This thread owns the scheduler and calls WriteL, wich queues the assigned sound buffer to be played + ****************************************************/ TInt AudioThreadCB(TAny *aParams) { CTrapCleanup *cleanup = CTrapCleanup::New(); CActiveScheduler *scheduler = new CActiveScheduler(); CActiveScheduler::Install(scheduler); - + TRAPD(err, { TInt latency = *(TInt *)aParams; CAudio *audio = CAudio::NewL(latency); @@ -215,7 +207,6 @@ TInt AudioThreadCB(TAny *aParams) gAudioRunning = ETrue; audio->Start(); - TInt processTick = 5000; // Default 5ms const char *tickHint = SDL_GetHint(SDL_HINT_AUDIO_NGAGE_PROCESS_TICK); @@ -223,34 +214,27 @@ TInt AudioThreadCB(TAny *aParams) processTick = SDL_atoi(tickHint) * 1000; } - - while (gAudioRunning) - { + while (gAudioRunning) { TInt error; CActiveScheduler::RunIfReady(error, CActive::EPriorityIdle); - + /*there is some mix data sound ready*/ - if (audio->iBufferReady) - { + if (audio->iBufferReady) { audio->iBufferReady = EFalse; SDL_AudioDevice *device = NGAGE_GetAudioDeviceAddr(); - if (device && device->hidden) - { + if (device && device->hidden) { SDL_PrivateAudioData *phdata = (SDL_PrivateAudioData *)device->hidden; audio->iState = EStateWriting; /*sends the chuck mixed to the queue*/ audio->iBufDes.Set(phdata->buffer[phdata->fill_index], device->buffer_size, device->buffer_size); TRAPD(werr, audio->iStream->WriteL(audio->iBufDes)); - if (werr != KErrNone) - { + if (werr != KErrNone) { /*asks ProcessThreadCB to bring another mix chunk*/ audio->iState = EStatePlaying; - } - else - { + } else { /*swap buffers so while this buffer is being played we can get the mix of the next one if we can*/ phdata->fill_index = 1 - phdata->fill_index; } @@ -270,16 +254,15 @@ TInt AudioThreadCB(TAny *aParams) } /*************************************************** -* MaoscOpenComplete - -* -* Opens the audiostream -* -* *******************************************************/ + * MaoscOpenComplete - + * + * Opens the audiostream + * + * *******************************************************/ void CAudio::MaoscOpenComplete(TInt aError) { - if (aError == KErrNone) - { + if (aError == KErrNone) { /*setting the volume to max, users can change the volume later of their channels individually in code*/ iStream->SetVolume(iStream->MaxVolume()); iStreamStarted = ETrue; @@ -296,11 +279,8 @@ void CAudio::MaoscOpenComplete(TInt aError) /* Kickstart: device is guaranteed valid now*/ this->iState = EStatePlaying; - - } - else - { + } else { SDL_Log("Error: Failed to open audio stream: %d", aError); } } @@ -314,17 +294,12 @@ void CAudio::MaoscOpenComplete(TInt aError) void CAudio::MaoscBufferCopied(TInt aError, const TDesC8 & /*aBuffer*/) { - if (aError == KErrNone) - { + if (aError == KErrNone) { iState = EStatePlaying; - } - else if (aError == KErrAbort) - { + } else if (aError == KErrAbort) { /* The stream has been stopped.*/ iState = EStateDone; - } - else - { + } else { SDL_Log("Error: Failed to copy audio buffer: %d", aError); } } @@ -338,13 +313,12 @@ void CAudio::MaoscBufferCopied(TInt aError, const TDesC8 & /*aBuffer*/) void CAudio::MaoscPlayComplete(TInt aError) { - + /* If we finish due to an underflow, we'll need to restart playback. Normally KErrUnderlow is raised at stream end, but in our case the API should never see the stream end -- we are continuously feeding it more data! Many underflow errors mean that the latency target is too low.*/ - if (aError == KErrUnderflow) - { + if (aError == KErrUnderflow) { /* Restart the stream hardware */ iStream->Stop(); TInt ignoredError; @@ -355,22 +329,17 @@ void CAudio::MaoscPlayComplete(TInt aError) return; } else if (aError != KErrNone) { - } /* We shouldn't get here.*/ SDL_Log("%s: %d", SDL_FUNCTION, aError); } - - TBool AudioIsReady() { return gAudioRunning; } - - RThread audioThread; void InitAudio(TInt *aLatency) diff --git a/src/main/ngage/SDL_sysmain_main.cpp b/src/main/ngage/SDL_sysmain_main.cpp index 7fe7a9bf31..4e81c6d123 100644 --- a/src/main/ngage/SDL_sysmain_main.cpp +++ b/src/main/ngage/SDL_sysmain_main.cpp @@ -87,9 +87,15 @@ GLDEF_C TInt E32Main() TInt targetLatency = 225; InitAudio(&targetLatency); - // Wait until audio is ready. - while (!AudioIsReady()) { + // Wait until audio is ready (timeout after ~5 seconds). + TInt audioWaitMs = 0; + while (!AudioIsReady() && audioWaitMs < 5000) { User::After(100000); // 100ms. + audioWaitMs += 100; + } + if (!AudioIsReady()) { + SDL_Log("Error: Audio failed to initialise within timeout"); + User::Leave(KErrTimedOut); } // Create and start the rendering backend. @@ -104,8 +110,8 @@ GLDEF_C TInt E32Main() // Start the active scheduler to handle events. CActiveScheduler::Start(); - CleanupStack::PopAndDestroy(gRenderer); CleanupStack::PopAndDestroy(mainApp); + CleanupStack::PopAndDestroy(gRenderer); User::SwitchHeap(oldHeap); @@ -154,6 +160,7 @@ static bool callbacks_initialized = false; static void ShutdownApp(SDL_AppResult result) { + callbacks_initialized = false; DeinitAudio(); SDL_AppQuit(NULL, result); SDL_Quit();