Fixes crash while invoking pause&resume right after play2d. (#16406)

This commit is contained in:
James Chen 2016-08-22 09:43:06 +08:00 committed by minggo
parent 0fbc404cd9
commit 727c501285
6 changed files with 128 additions and 56 deletions

View File

@ -96,49 +96,7 @@ static void removeItemFromVector(std::vector<T>& v, T item)
} }
} }
void AudioMixerController::mixOneFrame() void AudioMixerController::initTrack(Track* track, std::vector<Track*>& tracksToRemove)
{
_isMixingFrame = true;
_activeTracksMutex.lock();
auto mixStart = clockNow();
std::vector<Track*> tracksToRemove;
tracksToRemove.reserve(_activeTracks.size());
// FOR TESTING BEGIN
// Track* track = _activeTracks[0];
//
// AudioBufferProvider::Buffer buffer;
// buffer.frameCount = _bufferSizeInFrames;
// status_t r = track->getNextBuffer(&buffer);
//// ALOG_ASSERT(buffer.frameCount == _mixing->size / 2, "buffer.frameCount:%d, _mixing->size/2:%d", buffer.frameCount, _mixing->size/2);
// if (r == NO_ERROR)
// {
// ALOGV("getNextBuffer succeed ...");
// memcpy(_mixing->buf, buffer.raw, _mixing->size);
// }
// if (buffer.raw == nullptr)
// {
// ALOGV("Play over ...");
// tracksToRemove.push_back(track);
// }
// else
// {
// track->releaseBuffer(&buffer);
// }
//
// _mixing->state = BufferState::FULL;
// _activeTracksMutex.unlock();
// FOR TESTING END
Track::State state;
// set up the tracks.
for (auto&& track : _activeTracks)
{
state = track->getState();
if (state == Track::State::IDLE)
{ {
uint32_t channelMask = audio_channel_out_mask_from_count(2); uint32_t channelMask = audio_channel_out_mask_from_count(2);
int32_t name = _mixer->getTrackName(channelMask, AUDIO_FORMAT_PCM_16_BIT, int32_t name = _mixer->getTrackName(channelMask, AUDIO_FORMAT_PCM_16_BIT,
@ -188,12 +146,65 @@ void AudioMixerController::mixOneFrame()
_mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1, &rVolume); _mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1, &rVolume);
track->setVolumeDirty(false); track->setVolumeDirty(false);
track->setInitialized(true);
} }
} }
void AudioMixerController::mixOneFrame()
{
_isMixingFrame = true;
_activeTracksMutex.lock();
auto mixStart = clockNow();
std::vector<Track*> tracksToRemove;
tracksToRemove.reserve(_activeTracks.size());
// FOR TESTING BEGIN
// Track* track = _activeTracks[0];
//
// AudioBufferProvider::Buffer buffer;
// buffer.frameCount = _bufferSizeInFrames;
// status_t r = track->getNextBuffer(&buffer);
//// ALOG_ASSERT(buffer.frameCount == _mixing->size / 2, "buffer.frameCount:%d, _mixing->size/2:%d", buffer.frameCount, _mixing->size/2);
// if (r == NO_ERROR)
// {
// ALOGV("getNextBuffer succeed ...");
// memcpy(_mixing->buf, buffer.raw, _mixing->size);
// }
// if (buffer.raw == nullptr)
// {
// ALOGV("Play over ...");
// tracksToRemove.push_back(track);
// }
// else
// {
// track->releaseBuffer(&buffer);
// }
//
// _mixing->state = BufferState::FULL;
// _activeTracksMutex.unlock();
// FOR TESTING END
Track::State state;
// set up the tracks.
for (auto&& track : _activeTracks)
{
state = track->getState();
if (state == Track::State::IDLE)
{
initTrack(track, tracksToRemove);
}
else if (state == Track::State::PLAYING) else if (state == Track::State::PLAYING)
{ {
ALOG_ASSERT(track->getName() >= 0); if (!track->isInitialized())
{
initTrack(track, tracksToRemove);
}
int name = track->getName(); int name = track->getName();
ALOG_ASSERT(name >= 0);
std::lock_guard<std::mutex> lk(track->_volumeDirtyMutex); std::lock_guard<std::mutex> lk(track->_volumeDirtyMutex);
@ -213,6 +224,11 @@ void AudioMixerController::mixOneFrame()
} }
else if (state == Track::State::RESUMED) else if (state == Track::State::RESUMED)
{ {
if (!track->isInitialized())
{
initTrack(track, tracksToRemove);
}
if (track->getPrevState() == Track::State::PAUSED) if (track->getPrevState() == Track::State::PAUSED)
{ {
_mixer->enable(track->getName()); _mixer->enable(track->getName());
@ -220,21 +236,28 @@ void AudioMixerController::mixOneFrame()
} }
else else
{ {
ALOGW("Previous state (%d) isn't PAUSED, couldn't resume!", track->getPrevState()); ALOGW("Previous state (%d) isn't PAUSED, couldn't resume!", static_cast<int>(track->getPrevState()));
} }
} }
else if (state == Track::State::PAUSED) else if (state == Track::State::PAUSED)
{ {
if (!track->isInitialized())
{
initTrack(track, tracksToRemove);
}
if (track->getPrevState() == Track::State::PLAYING || track->getPrevState() == Track::State::RESUMED) if (track->getPrevState() == Track::State::PLAYING || track->getPrevState() == Track::State::RESUMED)
{ {
_mixer->disable(track->getName()); _mixer->disable(track->getName());
} }
else else
{ {
ALOGW("Previous state (%d) isn't PLAYING, couldn't pause!", track->getPrevState()); ALOGW("Previous state (%d) isn't PLAYING, couldn't pause!", static_cast<int>(track->getPrevState()));
} }
} }
else if (state == Track::State::STOPPED) else if (state == Track::State::STOPPED)
{
if (track->isInitialized())
{ {
if (track->getPrevState() != Track::State::IDLE) if (track->getPrevState() != Track::State::IDLE)
{ {
@ -244,6 +267,11 @@ void AudioMixerController::mixOneFrame()
{ {
ALOGV("Stop track (%p) while it's in IDLE state!", track); ALOGV("Stop track (%p) while it's in IDLE state!", track);
} }
}
else
{
ALOGV("Track (%p) hasn't been initialized yet!", track);
}
tracksToRemove.push_back(track); tracksToRemove.push_back(track);
} }

View File

@ -54,7 +54,6 @@ public:
bool init(); bool init();
bool addTrack(Track* track); bool addTrack(Track* track);
bool hasPlayingTacks(); bool hasPlayingTacks();
void pause(); void pause();
@ -67,6 +66,7 @@ public:
private: private:
void destroy(); void destroy();
void initTrack(Track* track, std::vector<Track*>& tracksToRemove);
private: private:
int _bufferSizeInFrames; int _bufferSizeInFrames;

View File

@ -40,6 +40,7 @@ Track::Track(const PcmData &pcmData)
, _volume(1.0f) , _volume(1.0f)
, _isVolumeDirty(true) , _isVolumeDirty(true)
, _isLoop(false) , _isLoop(false)
, _isInitialized(false)
{ {
init(_pcmData.pcmBuffer->data(), _pcmData.numFrames, _pcmData.bitsPerSample / 8 * _pcmData.numChannels); init(_pcmData.pcmBuffer->data(), _pcmData.numFrames, _pcmData.bitsPerSample / 8 * _pcmData.numChannels);
} }

View File

@ -79,6 +79,12 @@ private:
inline void setVolumeDirty(bool isDirty) inline void setVolumeDirty(bool isDirty)
{ _isVolumeDirty = isDirty; }; { _isVolumeDirty = isDirty; };
inline bool isInitialized() const
{ return _isInitialized; };
inline void setInitialized(bool isInitialized)
{ _isInitialized = isInitialized; };
private: private:
PcmData _pcmData; PcmData _pcmData;
State _prevState; State _prevState;
@ -89,6 +95,7 @@ private:
bool _isVolumeDirty; bool _isVolumeDirty;
std::mutex _volumeDirtyMutex; std::mutex _volumeDirtyMutex;
bool _isLoop; bool _isLoop;
bool _isInitialized;
friend class AudioMixerController; friend class AudioMixerController;
}; };

View File

@ -42,6 +42,7 @@ AudioEngineTests::AudioEngineTests()
ADD_TEST_CASE(AudioPerformanceTest); ADD_TEST_CASE(AudioPerformanceTest);
ADD_TEST_CASE(AudioSwitchStateTest); ADD_TEST_CASE(AudioSwitchStateTest);
ADD_TEST_CASE(AudioSmallFileTest); ADD_TEST_CASE(AudioSmallFileTest);
ADD_TEST_CASE(AudioPauseResumeAfterPlay);
} }
namespace { namespace {
@ -803,3 +804,27 @@ std::string AudioSmallFileTest::subtitle() const
{ {
return "Should not crash"; return "Should not crash";
} }
/////////////////////////////////////////////////////////////////////////
bool AudioPauseResumeAfterPlay::init()
{
if (AudioEngineTestDemo::init())
{
int audioId = AudioEngine::play2d("audio/SoundEffectsFX009/FX082.mp3");
AudioEngine::pause(audioId);
AudioEngine::resume(audioId);
return true;
}
return false;
}
std::string AudioPauseResumeAfterPlay::title() const
{
return "pause & resume right after play2d";
}
std::string AudioPauseResumeAfterPlay::subtitle() const
{
return "Should not crash";
}

View File

@ -199,4 +199,15 @@ public:
virtual std::string subtitle() const override; virtual std::string subtitle() const override;
}; };
class AudioPauseResumeAfterPlay : public AudioEngineTestDemo
{
public:
CREATE_FUNC(AudioPauseResumeAfterPlay);
virtual bool init() override;
virtual std::string title() const override;
virtual std::string subtitle() const override;
};
#endif /* defined(__NEWAUDIOENGINE_TEST_H_) */ #endif /* defined(__NEWAUDIOENGINE_TEST_H_) */