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,6 +96,60 @@ static void removeItemFromVector(std::vector<T>& v, T item)
}
}
void AudioMixerController::initTrack(Track* track, std::vector<Track*>& tracksToRemove)
{
uint32_t channelMask = audio_channel_out_mask_from_count(2);
int32_t name = _mixer->getTrackName(channelMask, AUDIO_FORMAT_PCM_16_BIT,
AUDIO_SESSION_OUTPUT_MIX);
if (name < 0)
{
// If we could not get the track name, it means that there're MAX_NUM_TRACKS tracks
// So ignore the new track.
tracksToRemove.push_back(track);
}
else
{
_mixer->setBufferProvider(name, track);
_mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MAIN_BUFFER,
_mixingBuffer.buf);
_mixer->setParameter(
name,
AudioMixer::TRACK,
AudioMixer::MIXER_FORMAT,
(void *) (uintptr_t) AUDIO_FORMAT_PCM_16_BIT);
_mixer->setParameter(
name,
AudioMixer::TRACK,
AudioMixer::FORMAT,
(void *) (uintptr_t) AUDIO_FORMAT_PCM_16_BIT);
_mixer->setParameter(
name,
AudioMixer::TRACK,
AudioMixer::MIXER_CHANNEL_MASK,
(void *) (uintptr_t) channelMask);
_mixer->setParameter(
name,
AudioMixer::TRACK,
AudioMixer::CHANNEL_MASK,
(void *) (uintptr_t) channelMask);
track->setState(Track::State::PLAYING);
track->setName(name);
_mixer->enable(name);
std::lock_guard<std::mutex> lk(track->_volumeDirtyMutex);
gain_minifloat_packed_t volume = track->getVolumeLR();
float lVolume = float_from_gain(gain_minifloat_unpack_left(volume));
float rVolume = float_from_gain(gain_minifloat_unpack_right(volume));
_mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0, &lVolume);
_mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1, &rVolume);
track->setVolumeDirty(false);
track->setInitialized(true);
}
}
void AudioMixerController::mixOneFrame()
{
_isMixingFrame = true;
@ -140,60 +194,17 @@ void AudioMixerController::mixOneFrame()
if (state == Track::State::IDLE)
{
uint32_t channelMask = audio_channel_out_mask_from_count(2);
int32_t name = _mixer->getTrackName(channelMask, AUDIO_FORMAT_PCM_16_BIT,
AUDIO_SESSION_OUTPUT_MIX);
if (name < 0)
{
// If we could not get the track name, it means that there're MAX_NUM_TRACKS tracks
// So ignore the new track.
tracksToRemove.push_back(track);
}
else
{
_mixer->setBufferProvider(name, track);
_mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MAIN_BUFFER,
_mixingBuffer.buf);
_mixer->setParameter(
name,
AudioMixer::TRACK,
AudioMixer::MIXER_FORMAT,
(void *) (uintptr_t) AUDIO_FORMAT_PCM_16_BIT);
_mixer->setParameter(
name,
AudioMixer::TRACK,
AudioMixer::FORMAT,
(void *) (uintptr_t) AUDIO_FORMAT_PCM_16_BIT);
_mixer->setParameter(
name,
AudioMixer::TRACK,
AudioMixer::MIXER_CHANNEL_MASK,
(void *) (uintptr_t) channelMask);
_mixer->setParameter(
name,
AudioMixer::TRACK,
AudioMixer::CHANNEL_MASK,
(void *) (uintptr_t) channelMask);
track->setState(Track::State::PLAYING);
track->setName(name);
_mixer->enable(name);
std::lock_guard<std::mutex> lk(track->_volumeDirtyMutex);
gain_minifloat_packed_t volume = track->getVolumeLR();
float lVolume = float_from_gain(gain_minifloat_unpack_left(volume));
float rVolume = float_from_gain(gain_minifloat_unpack_right(volume));
_mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0, &lVolume);
_mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1, &rVolume);
track->setVolumeDirty(false);
}
initTrack(track, tracksToRemove);
}
else if (state == Track::State::PLAYING)
{
ALOG_ASSERT(track->getName() >= 0);
if (!track->isInitialized())
{
initTrack(track, tracksToRemove);
}
int name = track->getName();
ALOG_ASSERT(name >= 0);
std::lock_guard<std::mutex> lk(track->_volumeDirtyMutex);
@ -213,6 +224,11 @@ void AudioMixerController::mixOneFrame()
}
else if (state == Track::State::RESUMED)
{
if (!track->isInitialized())
{
initTrack(track, tracksToRemove);
}
if (track->getPrevState() == Track::State::PAUSED)
{
_mixer->enable(track->getName());
@ -220,29 +236,41 @@ void AudioMixerController::mixOneFrame()
}
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)
{
if (!track->isInitialized())
{
initTrack(track, tracksToRemove);
}
if (track->getPrevState() == Track::State::PLAYING || track->getPrevState() == Track::State::RESUMED)
{
_mixer->disable(track->getName());
}
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)
{
if (track->getPrevState() != Track::State::IDLE)
if (track->isInitialized())
{
_mixer->deleteTrackName(track->getName());
if (track->getPrevState() != Track::State::IDLE)
{
_mixer->deleteTrackName(track->getName());
}
else
{
ALOGV("Stop track (%p) while it's in IDLE state!", track);
}
}
else
{
ALOGV("Stop track (%p) while it's in IDLE state!", track);
ALOGV("Track (%p) hasn't been initialized yet!", track);
}
tracksToRemove.push_back(track);
}

View File

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

View File

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

View File

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

View File

@ -42,6 +42,7 @@ AudioEngineTests::AudioEngineTests()
ADD_TEST_CASE(AudioPerformanceTest);
ADD_TEST_CASE(AudioSwitchStateTest);
ADD_TEST_CASE(AudioSmallFileTest);
ADD_TEST_CASE(AudioPauseResumeAfterPlay);
}
namespace {
@ -803,3 +804,27 @@ std::string AudioSmallFileTest::subtitle() const
{
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;
};
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_) */