Decouple play/pause from output on/off

I think this was the cause of toggling play/pause making audio go away.
Or at least I can't repro that bug anymore, anyway.
custom
jacqueline 2 years ago
parent 96ea6cef88
commit 7523772886
  1. 7
      src/audio/audio_fsm.cpp
  2. 4
      src/audio/bt_audio_output.cpp
  3. 15
      src/audio/i2s_audio_output.cpp
  4. 8
      src/audio/include/audio_sink.hpp
  5. 2
      src/audio/include/bt_audio_output.hpp
  6. 3
      src/audio/include/i2s_audio_output.hpp
  7. 47
      src/drivers/i2s_dac.cpp
  8. 3
      src/drivers/include/i2s_dac.hpp

@ -81,6 +81,7 @@ void AudioState::react(const OutputModeChanged& ev) {
// TODO: handle SetInUse // TODO: handle SetInUse
ESP_LOGI(kTag, "output mode changed"); ESP_LOGI(kTag, "output mode changed");
auto new_mode = sServices->nvs().OutputMode(); auto new_mode = sServices->nvs().OutputMode();
sOutput->SetMode(IAudioOutput::Modes::kOff);
switch (new_mode) { switch (new_mode) {
case drivers::NvsStorage::Output::kBluetooth: case drivers::NvsStorage::Output::kBluetooth:
sOutput = sBtOutput; sOutput = sBtOutput;
@ -89,6 +90,7 @@ void AudioState::react(const OutputModeChanged& ev) {
sOutput = sI2SOutput; sOutput = sI2SOutput;
break; break;
} }
sOutput->SetMode(IAudioOutput::Modes::kOnPaused);
} }
namespace states { namespace states {
@ -125,6 +127,7 @@ void Uninitialised::react(const system_fsm::BootComplete& ev) {
} else { } else {
sOutput = sBtOutput; sOutput = sBtOutput;
} }
sOutput->SetMode(IAudioOutput::Modes::kOnPaused);
sSampleConverter.reset(new SampleConverter()); sSampleConverter.reset(new SampleConverter());
sSampleConverter->SetOutput(sOutput); sSampleConverter->SetOutput(sOutput);
@ -170,7 +173,7 @@ void Standby::react(const TogglePlayPause& ev) {
void Playback::entry() { void Playback::entry() {
ESP_LOGI(kTag, "beginning playback"); ESP_LOGI(kTag, "beginning playback");
sOutput->SetInUse(true); sOutput->SetMode(IAudioOutput::Modes::kOnPlaying);
events::System().Dispatch(PlaybackStarted{}); events::System().Dispatch(PlaybackStarted{});
events::Ui().Dispatch(PlaybackStarted{}); events::Ui().Dispatch(PlaybackStarted{});
@ -181,7 +184,7 @@ void Playback::exit() {
// TODO(jacqueline): Second case where it's useful to wait for the i2s buffer // TODO(jacqueline): Second case where it's useful to wait for the i2s buffer
// to drain. // to drain.
vTaskDelay(pdMS_TO_TICKS(10)); vTaskDelay(pdMS_TO_TICKS(10));
sOutput->SetInUse(false); sOutput->SetMode(IAudioOutput::Modes::kOnPaused);
events::System().Dispatch(PlaybackFinished{}); events::System().Dispatch(PlaybackFinished{});
events::Ui().Dispatch(PlaybackFinished{}); events::Ui().Dispatch(PlaybackFinished{});

@ -33,8 +33,8 @@ BluetoothAudioOutput::BluetoothAudioOutput(StreamBufferHandle_t s,
BluetoothAudioOutput::~BluetoothAudioOutput() {} BluetoothAudioOutput::~BluetoothAudioOutput() {}
auto BluetoothAudioOutput::SetInUse(bool in_use) -> void { auto BluetoothAudioOutput::SetMode(Modes mode) -> void {
if (in_use) { if (mode == Modes::kOnPlaying) {
bluetooth_.SetSource(stream()); bluetooth_.SetSource(stream());
} else { } else {
bluetooth_.SetSource(nullptr); bluetooth_.SetSource(nullptr);

@ -48,6 +48,7 @@ I2SAudioOutput::I2SAudioOutput(StreamBufferHandle_t s,
: IAudioOutput(s), : IAudioOutput(s),
expander_(expander), expander_(expander),
dac_(std::move(dac)), dac_(std::move(dac)),
current_mode_(Modes::kOff),
current_config_(), current_config_(),
left_difference_(0), left_difference_(0),
current_volume_(0), current_volume_(0),
@ -60,12 +61,18 @@ I2SAudioOutput::~I2SAudioOutput() {
dac_->SetSource(nullptr); dac_->SetSource(nullptr);
} }
auto I2SAudioOutput::SetInUse(bool in_use) -> void { auto I2SAudioOutput::SetMode(Modes mode) -> void {
if (in_use) { if (mode == current_mode_) {
dac_->Start(); return;
} else { }
if (mode == Modes::kOff) {
dac_->Stop(); dac_->Stop();
return;
} else if (current_mode_ == Modes::kOff) {
dac_->Start();
} }
current_mode_ = mode;
dac_->SetPaused(mode == Modes::kOnPaused);
} }
auto I2SAudioOutput::SetVolumeImbalance(int_fast8_t balance) -> void { auto I2SAudioOutput::SetVolumeImbalance(int_fast8_t balance) -> void {

@ -31,11 +31,17 @@ class IAudioOutput {
virtual ~IAudioOutput() {} virtual ~IAudioOutput() {}
enum class Modes {
kOff,
kOnPaused,
kOnPlaying,
};
/* /*
* Indicates whether this output is currently being sent samples. If this is * Indicates whether this output is currently being sent samples. If this is
* false, the output should place itself into a low power state. * false, the output should place itself into a low power state.
*/ */
virtual auto SetInUse(bool) -> void = 0; virtual auto SetMode(Modes) -> void = 0;
virtual auto SetVolumeImbalance(int_fast8_t balance) -> void = 0; virtual auto SetVolumeImbalance(int_fast8_t balance) -> void = 0;
virtual auto SetVolume(uint_fast8_t percent) -> void = 0; virtual auto SetVolume(uint_fast8_t percent) -> void = 0;

@ -24,7 +24,7 @@ class BluetoothAudioOutput : public IAudioOutput {
BluetoothAudioOutput(StreamBufferHandle_t, drivers::Bluetooth& bt); BluetoothAudioOutput(StreamBufferHandle_t, drivers::Bluetooth& bt);
~BluetoothAudioOutput(); ~BluetoothAudioOutput();
auto SetInUse(bool) -> void override; auto SetMode(Modes) -> void override;
auto SetVolumeImbalance(int_fast8_t balance) -> void override; auto SetVolumeImbalance(int_fast8_t balance) -> void override;
auto SetVolume(uint_fast8_t percent) -> void override; auto SetVolume(uint_fast8_t percent) -> void override;

@ -25,7 +25,7 @@ class I2SAudioOutput : public IAudioOutput {
std::unique_ptr<drivers::I2SDac> dac); std::unique_ptr<drivers::I2SDac> dac);
~I2SAudioOutput(); ~I2SAudioOutput();
auto SetInUse(bool) -> void override; auto SetMode(Modes) -> void override;
auto SetMaxVolume(uint16_t) -> void; auto SetMaxVolume(uint16_t) -> void;
auto SetVolumeDb(uint16_t) -> void; auto SetVolumeDb(uint16_t) -> void;
@ -46,6 +46,7 @@ class I2SAudioOutput : public IAudioOutput {
drivers::IGpios& expander_; drivers::IGpios& expander_;
std::unique_ptr<drivers::I2SDac> dac_; std::unique_ptr<drivers::I2SDac> dac_;
Modes current_mode_;
std::optional<Format> current_config_; std::optional<Format> current_config_;
int_fast8_t left_difference_; int_fast8_t left_difference_;
uint16_t current_volume_; uint16_t current_volume_;

@ -111,38 +111,23 @@ I2SDac::~I2SDac() {
auto I2SDac::Start() -> void { auto I2SDac::Start() -> void {
std::lock_guard<std::mutex> lock(configure_mutex_); std::lock_guard<std::mutex> lock(configure_mutex_);
gpio_.WriteSync(IGpios::Pin::kAmplifierUnmute, false);
// Ensure the DAC powers up to a muted state.
wm8523::WriteRegister(wm8523::Register::kPsCtrl, 0b10);
// Enable MCLK; this has the side effect of triggering the DAC's startup
// sequence.
i2s_channel_enable(i2s_handle_);
i2s_active_ = true;
wm8523::WriteRegister(wm8523::Register::kPsCtrl, 0b11); wm8523::WriteRegister(wm8523::Register::kPsCtrl, 0b11);
gpio_.WriteSync(IGpios::Pin::kAmplifierUnmute, true);
} }
auto I2SDac::Stop() -> void { auto I2SDac::Stop() -> void {
std::lock_guard<std::mutex> lock(configure_mutex_); std::lock_guard<std::mutex> lock(configure_mutex_);
set_channel(false);
// Mute the DAC.
wm8523::WriteRegister(wm8523::Register::kPsCtrl, 0b10);
vTaskDelay(pdMS_TO_TICKS(5));
// Silence the output.
gpio_.WriteSync(IGpios::Pin::kAmplifierUnmute, false);
vTaskDelay(pdMS_TO_TICKS(5));
// Turn everything off.
wm8523::WriteRegister(wm8523::Register::kPsCtrl, 0b0); wm8523::WriteRegister(wm8523::Register::kPsCtrl, 0b0);
i2s_channel_disable(i2s_handle_); }
i2s_active_ = false;
gpio_.WriteSync(IGpios::Pin::kAmplifierEnable, false); auto I2SDac::SetPaused(bool paused) -> void {
if (paused) {
gpio_.WriteSync(IGpios::Pin::kAmplifierUnmute, false);
set_channel(false);
} else {
set_channel(true);
gpio_.WriteSync(IGpios::Pin::kAmplifierUnmute, true);
}
} }
auto I2SDac::Reconfigure(Channels ch, BitsPerSample bps, SampleRate rate) auto I2SDac::Reconfigure(Channels ch, BitsPerSample bps, SampleRate rate)
@ -261,4 +246,16 @@ auto I2SDac::SetSource(StreamBufferHandle_t buffer) -> void {
} }
} }
auto I2SDac::set_channel(bool enabled) -> void {
if (i2s_active_ == enabled) {
return;
}
i2s_active_ = enabled;
if (enabled) {
i2s_channel_enable(i2s_handle_);
} else {
i2s_channel_disable(i2s_handle_);
}
}
} // namespace drivers } // namespace drivers

@ -46,6 +46,7 @@ class I2SDac {
auto Start() -> void; auto Start() -> void;
auto Stop() -> void; auto Stop() -> void;
auto SetPaused(bool) -> void;
enum Channels { enum Channels {
CHANNELS_MONO, CHANNELS_MONO,
@ -75,6 +76,8 @@ class I2SDac {
I2SDac& operator=(const I2SDac&) = delete; I2SDac& operator=(const I2SDac&) = delete;
private: private:
auto set_channel(bool) -> void;
IGpios& gpio_; IGpios& gpio_;
i2s_chan_handle_t i2s_handle_; i2s_chan_handle_t i2s_handle_;
bool i2s_active_; bool i2s_active_;

Loading…
Cancel
Save