fix: stream stops and dies on underflow
This commit is contained in:
parent
ab7bf9c709
commit
cf561e78a8
@ -121,14 +121,7 @@ function on_hud_open()
|
||||
|
||||
stream = PCMStream(44100, 1, 16)
|
||||
stream:share("test-stream")
|
||||
local bytes = Bytearray(44100 / 8)
|
||||
for i=1,#bytes do
|
||||
local x = math.sin(i * 0.08) * 1 + 0
|
||||
bytes[i] = x
|
||||
end
|
||||
stream:feed(bytes)
|
||||
|
||||
audio.play_stream_2d("test-stream", 2.0, 1.0, "ui")
|
||||
streamid = audio.play_stream_2d("test-stream", 2.0, 1.0, "ui")
|
||||
end
|
||||
|
||||
function on_hud_render()
|
||||
|
||||
@ -164,9 +164,10 @@ std::unique_ptr<Speaker> ALStream::createSpeaker(bool loop, int channel) {
|
||||
for (uint i = 0; i < ALStream::STREAM_BUFFERS; i++) {
|
||||
uint free_buffer = al->getFreeBuffer();
|
||||
if (!preloadBuffer(free_buffer, loop)) {
|
||||
break;
|
||||
unusedBuffers.push(free_buffer);
|
||||
} else {
|
||||
AL_CHECK(alSourceQueueBuffers(free_source, 1, &free_buffer));
|
||||
}
|
||||
AL_CHECK(alSourceQueueBuffers(free_source, 1, &free_buffer));
|
||||
}
|
||||
return std::make_unique<ALSpeaker>(al, free_source, PRIORITY_HIGH, channel);
|
||||
}
|
||||
@ -213,11 +214,11 @@ void ALStream::unqueueBuffers(uint alsource) {
|
||||
uint ALStream::enqueueBuffers(uint alsource) {
|
||||
uint preloaded = 0;
|
||||
if (!unusedBuffers.empty()) {
|
||||
uint first_buffer = unusedBuffers.front();
|
||||
if (preloadBuffer(first_buffer, loop)) {
|
||||
uint firstBuffer = unusedBuffers.front();
|
||||
if (preloadBuffer(firstBuffer, loop)) {
|
||||
preloaded++;
|
||||
unusedBuffers.pop();
|
||||
AL_CHECK(alSourceQueueBuffers(alsource, 1, &first_buffer));
|
||||
AL_CHECK(alSourceQueueBuffers(alsource, 1, &firstBuffer));
|
||||
}
|
||||
}
|
||||
return preloaded;
|
||||
@ -227,14 +228,14 @@ void ALStream::update(double delta) {
|
||||
if (this->speaker == 0) {
|
||||
return;
|
||||
}
|
||||
auto p_speaker = audio::get_speaker(this->speaker);
|
||||
if (p_speaker == nullptr) {
|
||||
auto speaker = audio::get_speaker(this->speaker);
|
||||
if (speaker == nullptr) {
|
||||
this->speaker = 0;
|
||||
return;
|
||||
}
|
||||
ALSpeaker* alspeaker = dynamic_cast<ALSpeaker*>(p_speaker);
|
||||
ALSpeaker* alspeaker = dynamic_cast<ALSpeaker*>(speaker);
|
||||
assert(alspeaker != nullptr);
|
||||
if (alspeaker->stopped) {
|
||||
if (alspeaker->manuallyStopped) {
|
||||
this->speaker = 0;
|
||||
return;
|
||||
}
|
||||
@ -245,11 +246,11 @@ void ALStream::update(double delta) {
|
||||
uint preloaded = enqueueBuffers(alsource);
|
||||
|
||||
// alspeaker->stopped is assigned to false at ALSpeaker::play(...)
|
||||
if (p_speaker->isStopped() && !alspeaker->stopped) { //TODO: -V560 false-positive?
|
||||
if (preloaded || dynamic_cast<MemoryPCMStream*>(source.get())) {
|
||||
p_speaker->play();
|
||||
} else {
|
||||
p_speaker->stop();
|
||||
if (speaker->isStopped() && !alspeaker->manuallyStopped) { //TODO: -V560 false-positive?
|
||||
if (preloaded) {
|
||||
speaker->play();
|
||||
} else if (isStopOnEnd()){
|
||||
speaker->stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -290,6 +291,14 @@ void ALStream::setTime(duration_t time) {
|
||||
}
|
||||
}
|
||||
|
||||
bool ALStream::isStopOnEnd() const {
|
||||
return stopOnEnd;
|
||||
}
|
||||
|
||||
void ALStream::setStopOnEnd(bool flag) {
|
||||
stopOnEnd = flag;
|
||||
}
|
||||
|
||||
ALSpeaker::ALSpeaker(ALAudio* al, uint source, int priority, int channel)
|
||||
: al(al), priority(priority), channel(channel), source(source) {
|
||||
}
|
||||
@ -356,7 +365,7 @@ void ALSpeaker::setLoop(bool loop) {
|
||||
|
||||
void ALSpeaker::play() {
|
||||
paused = false;
|
||||
stopped = false;
|
||||
manuallyStopped = false;
|
||||
auto p_channel = get_channel(this->channel);
|
||||
AL_CHECK(alSourcef(
|
||||
source,
|
||||
@ -372,7 +381,7 @@ void ALSpeaker::pause() {
|
||||
}
|
||||
|
||||
void ALSpeaker::stop() {
|
||||
stopped = true;
|
||||
manuallyStopped = true;
|
||||
if (source) {
|
||||
AL_CHECK(alSourceStop(source));
|
||||
|
||||
@ -436,6 +445,11 @@ int ALSpeaker::getPriority() const {
|
||||
return priority;
|
||||
}
|
||||
|
||||
|
||||
bool ALSpeaker::isManuallyStopped() const {
|
||||
return manuallyStopped;
|
||||
}
|
||||
|
||||
static bool alc_enumeration_ext = false;
|
||||
|
||||
ALAudio::ALAudio(ALCdevice* device, ALCcontext* context)
|
||||
|
||||
@ -58,6 +58,7 @@ namespace audio {
|
||||
bool keepSource;
|
||||
char buffer[BUFFER_SIZE];
|
||||
bool loop = false;
|
||||
bool stopOnEnd = false;
|
||||
|
||||
bool preloadBuffer(uint buffer, bool loop);
|
||||
void unqueueBuffers(uint alsource);
|
||||
@ -80,6 +81,10 @@ namespace audio {
|
||||
void setTime(duration_t time) override;
|
||||
|
||||
static inline constexpr uint STREAM_BUFFERS = 3;
|
||||
|
||||
bool isStopOnEnd() const override;
|
||||
|
||||
void setStopOnEnd(bool stopOnEnd) override;
|
||||
};
|
||||
|
||||
class ALInputDevice : public InputDevice {
|
||||
@ -117,7 +122,7 @@ namespace audio {
|
||||
float volume = 0.0f;
|
||||
public:
|
||||
ALStream* stream = nullptr;
|
||||
bool stopped = true;
|
||||
bool manuallyStopped = true;
|
||||
bool paused = false;
|
||||
uint source;
|
||||
duration_t duration = 0.0f;
|
||||
@ -157,6 +162,8 @@ namespace audio {
|
||||
bool isRelative() const override;
|
||||
|
||||
int getPriority() const override;
|
||||
|
||||
bool isManuallyStopped() const override;
|
||||
};
|
||||
|
||||
class ALAudio : public Backend {
|
||||
|
||||
@ -61,6 +61,13 @@ namespace audio {
|
||||
|
||||
void setTime(duration_t time) override {
|
||||
}
|
||||
|
||||
bool isStopOnEnd() const override {
|
||||
return false;
|
||||
}
|
||||
|
||||
void setStopOnEnd(bool stopOnEnd) override {
|
||||
}
|
||||
};
|
||||
|
||||
class NoAudio : public Backend {
|
||||
|
||||
@ -464,8 +464,15 @@ void audio::update(double delta) {
|
||||
speaker->update(channel);
|
||||
}
|
||||
if (speaker->isStopped()) {
|
||||
streams.erase(it->first);
|
||||
it = speakers.erase(it);
|
||||
auto foundStream = streams.find(it->first);
|
||||
if (foundStream == streams.end() ||
|
||||
(!speaker->isManuallyStopped() &&
|
||||
foundStream->second->isStopOnEnd())) {
|
||||
streams.erase(it->first);
|
||||
it = speakers.erase(it);
|
||||
} else {
|
||||
it++;
|
||||
}
|
||||
} else {
|
||||
it++;
|
||||
}
|
||||
|
||||
@ -221,6 +221,9 @@ namespace audio {
|
||||
/// @brief Set playhead to the selected time
|
||||
/// @param time selected time
|
||||
virtual void setTime(duration_t time) = 0;
|
||||
|
||||
virtual bool isStopOnEnd() const = 0;
|
||||
virtual void setStopOnEnd(bool stopOnEnd) = 0;
|
||||
};
|
||||
|
||||
/// @brief Sound is an audio asset that supposed to support many
|
||||
@ -355,6 +358,8 @@ namespace audio {
|
||||
inline bool isStopped() const {
|
||||
return getState() == State::stopped;
|
||||
}
|
||||
|
||||
virtual bool isManuallyStopped() const = 0;
|
||||
};
|
||||
|
||||
class Backend {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user