summaryrefslogtreecommitdiff
path: root/src/tangara/audio/audio_fsm.hpp
blob: c30012d970f69e727158d99e0523ce540dfdf482 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/*
 * Copyright 2023 jacqueline <me@jacqueline.id.au>
 *
 * SPDX-License-Identifier: GPL-3.0-only
 */

#pragma once

#include <stdint.h>
#include <deque>
#include <memory>
#include <vector>

#include "audio/stream_cues.hpp"
#include "drivers/pcm_buffer.hpp"
#include "tinyfsm.hpp"

#include "audio/audio_decoder.hpp"
#include "audio/audio_events.hpp"
#include "audio/audio_sink.hpp"
#include "audio/bt_audio_output.hpp"
#include "audio/fatfs_stream_factory.hpp"
#include "audio/i2s_audio_output.hpp"
#include "audio/track_queue.hpp"
#include "database/database.hpp"
#include "database/tag_parser.hpp"
#include "database/track.hpp"
#include "drivers/display.hpp"
#include "drivers/gpios.hpp"
#include "drivers/i2s_dac.hpp"
#include "drivers/storage.hpp"
#include "system_fsm/service_locator.hpp"
#include "system_fsm/system_events.hpp"

namespace audio {

class AudioState : public tinyfsm::Fsm<AudioState> {
 public:
  virtual ~AudioState() {}

  virtual void entry() {}
  virtual void exit() {}

  /* Fallback event handler. Does nothing. */
  void react(const tinyfsm::Event& ev) {}

  void react(const QueueUpdate&);
  void react(const PlaySineWave&);
  void react(const SetTrack&);
  void react(const TogglePlayPause&);
  void react(const TtsPlaybackChanged&);

  void react(const internal::DecodingFinished&);
  void react(const internal::StreamStarted&);
  void react(const internal::StreamEnded&);
  virtual void react(const internal::StreamHeartbeat&) {}

  void react(const StepUpVolume&);
  void react(const StepDownVolume&);

  void react(const SetVolume&);
  void react(const SetVolumeLimit&);
  void react(const SetVolumeBalance&);

  void react(const OutputModeChanged&);

  virtual void react(const system_fsm::BootComplete&) {}
  virtual void react(const system_fsm::UnmountRequest&) {}
  virtual void react(const system_fsm::SdStateChanged&) {}
  virtual void react(const system_fsm::BluetoothEvent&);
  virtual void react(const system_fsm::HasPhonesChanged&);

 protected:
  auto updateOutputMode() -> void;
  auto emitPlaybackUpdate(bool paused) -> void;
  auto commitVolume() -> void;

  auto updateSavedPosition(std::string uri, uint32_t position) -> void;
  auto incrementPlayCount(std::string uri) -> void;

  static std::shared_ptr<system_fsm::ServiceLocator> sServices;

  static std::shared_ptr<FatfsStreamFactory> sStreamFactory;
  static std::unique_ptr<Decoder> sDecoder;
  static std::shared_ptr<SampleProcessor> sSampleProcessor;
  static std::shared_ptr<I2SAudioOutput> sI2SOutput;
  static std::shared_ptr<BluetoothAudioOutput> sBtOutput;
  static std::shared_ptr<IAudioOutput> sOutput;

  static std::unique_ptr<drivers::OutputBuffers> sDrainBuffers;

  static StreamCues sStreamCues;
  static std::optional<IAudioOutput::Format> sDrainFormat;

  static bool sIsPaused;
  static uint8_t sUpdateCounter;
  static bool sIsTtsPlaying;

 private:
  auto updateTrackData(std::string uri,
                       std::function<void(database::TrackData&)>) -> void;
};

namespace states {

class Uninitialised : public AudioState {
 public:
  void react(const system_fsm::BootComplete&) override;
  void react(const system_fsm::BluetoothEvent&) override{};

  using AudioState::react;
};

class Standby : public AudioState {
 public:
  void entry() override;
  void react(const system_fsm::UnmountRequest&) override;
  void react(const system_fsm::SdStateChanged&) override;

  using AudioState::react;
};

class Playback : public AudioState {
 public:
  void entry() override;
  void exit() override;

  void react(const system_fsm::SdStateChanged&) override;
  void react(const internal::StreamHeartbeat&) override;

  using AudioState::react;
};

}  // namespace states

}  // namespace audio