parent
e53dfc4cc5
commit
4c88fcc4a5
@ -0,0 +1,79 @@ |
||||
#include "audio_element_handle.hpp" |
||||
#include "audio_element.hpp" |
||||
#include "freertos/projdefs.h" |
||||
|
||||
namespace audio { |
||||
|
||||
AudioElementHandle::AudioElementHandle(std::unique_ptr<TaskHandle_t> task, |
||||
std::shared_ptr<IAudioElement> element) |
||||
: task_(std::move(task)), element_(std::move(element)) {} |
||||
|
||||
AudioElementHandle::~AudioElementHandle() { |
||||
Quit(); |
||||
} |
||||
|
||||
auto AudioElementHandle::CurrentState() -> ElementState { |
||||
return element_->ElementState(); |
||||
} |
||||
|
||||
auto AudioElementHandle::PlayPause(enum PlayPause state) -> void { |
||||
ElementState s = CurrentState(); |
||||
if (state == PLAY && s == STATE_PAUSE) { |
||||
// Ensure we actually finished any previous pause command.
|
||||
// TODO: really?
|
||||
PauseSync(); |
||||
SetStateAndWakeUp(STATE_RUN); |
||||
return; |
||||
} |
||||
if (state == PAUSE && s == STATE_RUN) { |
||||
element_->ElementState(STATE_PAUSE); |
||||
SetStateAndWakeUp(STATE_PAUSE); |
||||
return; |
||||
} |
||||
} |
||||
|
||||
auto AudioElementHandle::Quit() -> void { |
||||
SetStateAndWakeUp(STATE_QUIT); |
||||
} |
||||
|
||||
auto AudioElementHandle::PauseSync() -> void { |
||||
PlayPause(PAUSE); |
||||
MonitorUtilState(eSuspended); |
||||
} |
||||
|
||||
auto AudioElementHandle::QuitSync() -> void { |
||||
Quit(); |
||||
MonitorUtilState(eDeleted); |
||||
} |
||||
|
||||
auto AudioElementHandle::MonitorUtilState(eTaskState desired) -> void { |
||||
while (eTaskGetState(task_.get()) != desired) { |
||||
WakeUpTask(); |
||||
vTaskDelay(pdMS_TO_TICKS(1)); |
||||
} |
||||
} |
||||
|
||||
auto AudioElementHandle::SetStateAndWakeUp(ElementState state) -> void { |
||||
element_->ElementState(state); |
||||
WakeUpTask(); |
||||
} |
||||
|
||||
auto AudioElementHandle::WakeUpTask() -> void { |
||||
// TODO: various races where the task isn't blocked yet, but there is a block
|
||||
// between now and its next element state check. Also think about chunk blocks
|
||||
// nested in element bodies.
|
||||
// Maybe we need a big mutex or semaphore somewhere in here.
|
||||
switch (eTaskGetState(task_.get())) { |
||||
case eBlocked: |
||||
// TODO: when is this safe?
|
||||
xTaskAbortDelay(task_.get()); |
||||
break; |
||||
case eSuspended: |
||||
vTaskResume(task_.get()); |
||||
break; |
||||
default: |
||||
return; |
||||
} |
||||
} |
||||
|
||||
} // namespace audio
|
@ -0,0 +1,41 @@ |
||||
#pragma once |
||||
|
||||
#include <memory> |
||||
#include "audio_element.hpp" |
||||
|
||||
namespace audio { |
||||
|
||||
class AudioElementHandle { |
||||
public: |
||||
AudioElementHandle(std::unique_ptr<TaskHandle_t> task, |
||||
std::shared_ptr<IAudioElement> element); |
||||
~AudioElementHandle(); |
||||
|
||||
auto CurrentState() -> ElementState; |
||||
|
||||
// TODO: think about this contract. Would it ever make sense to pause and
|
||||
// then walk away? Things could keep running for a whole loop if data comes
|
||||
// through, so probably not?
|
||||
enum PlayPause { |
||||
PLAY, |
||||
PAUSE, |
||||
}; |
||||
auto PlayPause(PlayPause state) -> void; |
||||
auto Quit() -> void; |
||||
|
||||
auto PauseSync() -> void; |
||||
auto QuitSync() -> void; |
||||
|
||||
AudioElementHandle(const AudioElementHandle&) = delete; |
||||
AudioElementHandle& operator=(const AudioElementHandle&) = delete; |
||||
|
||||
private: |
||||
std::unique_ptr<TaskHandle_t> task_; |
||||
std::shared_ptr<IAudioElement> element_; |
||||
|
||||
auto MonitorUtilState(eTaskState desired) -> void; |
||||
auto SetStateAndWakeUp(ElementState state) -> void; |
||||
auto WakeUpTask() -> void; |
||||
}; |
||||
|
||||
} // namespace audio
|
Loading…
Reference in new issue