forked from zillevdr/vdr-plugin-softhddevice-drm
-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathstatemachine.h
More file actions
178 lines (155 loc) · 4.31 KB
/
Copy pathstatemachine.h
File metadata and controls
178 lines (155 loc) · 4.31 KB
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
// SPDX-License-Identifier: AGPL-3.0-or-later
/**
* @file statemachine.h
* Device State Machine and Event Handler Header File
*
* @copyright 2025 - 2026 by Andreas Baierl. All Rights Reserved.
*
* @license{AGPL-3.0-or-later}
*/
#ifndef __STATEMACHINE_H
#define __STATEMACHINE_H
#if __cplusplus < 201703L
#error "C++17 or higher is required"
#endif
#include <atomic>
#include <mutex>
#include <variant>
#include <vector>
#include <vdr/thread.h>
#include <vdr/tools.h>
#include "config.h"
#include "logger.h"
/**
* @addtogroup device
* @{
*/
// State machine definitions
// Implementing C++17 visitor pattern
template<class... Ts>
struct overload : Ts... { using Ts::operator()...; };
template<class... Ts> overload(Ts...) -> overload<Ts...>;
enum State {
STOP,
BUFFERING,
PLAY,
TRICK_SPEED,
DETACHED
};
enum BufferUnderrunType {
VIDEO,
AUDIO,
};
struct PlayEvent {};
struct PauseEvent {};
struct StopEvent {};
struct TrickSpeedEvent {
double speed;
bool active;
bool forward;
};
struct StillPictureEvent {
const uchar *data;
int size;
};
struct DetachEvent {};
struct AttachEvent {};
struct BufferUnderrunEvent {
BufferUnderrunType type;
};
struct BufferingThresholdReachedEvent {};
struct ScheduleResyncAtPtsMsEvent {
int64_t pts;
};
struct ResyncEvent {};
struct DisplayChangeEvent {
sDrmMode mode;
};
using Event = std::variant<
PlayEvent,
PauseEvent,
StopEvent,
TrickSpeedEvent,
StillPictureEvent,
DetachEvent,
AttachEvent,
BufferUnderrunEvent,
BufferingThresholdReachedEvent,
ScheduleResyncAtPtsMsEvent,
ResyncEvent,
DisplayChangeEvent
>;
inline const char* EventToString(const Event& e) {
return std::visit(overload{
[](const PlayEvent&) -> const char* { return "PlayEvent"; },
[](const PauseEvent&) -> const char* { return "PauseEvent"; },
[](const StopEvent&) -> const char* { return "StopEvent"; },
[](const TrickSpeedEvent&) -> const char* { return "TrickSpeedEvent"; },
[](const StillPictureEvent&) -> const char* { return "StillPictureEvent"; },
[](const DetachEvent&) -> const char* { return "DetachEvent"; },
[](const AttachEvent&) -> const char* { return "AttachEvent"; },
[](const BufferUnderrunEvent& e) -> const char* { return e.type == AUDIO ? "BufferUnderrunEvent: Audio" : "BufferUnderrunEvent: Video"; },
[](const BufferingThresholdReachedEvent&) -> const char* { return "BufferingThresholdReachedEvent"; },
[](const ScheduleResyncAtPtsMsEvent&) -> const char* { return "ScheduleResyncAtPtsMsEvent"; },
[](const ResyncEvent&) -> const char* { return "ResyncEvent"; },
[](const DisplayChangeEvent&) -> const char* { return "DisplayChangeEvent"; },
}, e);
}
inline const char* StateToString(State s) {
switch(s) {
case State::STOP: return "STOP";
case State::BUFFERING: return "BUFFERING";
case State::PLAY: return "PLAY";
case State::TRICK_SPEED: return "TRICK_SPEED";
case State::DETACHED: return "DETACHED";
}
return "Unknown";
}
/** @} */
class cSoftHdDevice;
/**
* State Machine Implementation
*
* Events can be pushed directly to the state machine (OnEventReceived())
* or can be pushed through the event handler queue.
* Pushing directly may block the calling thread until OnEventReceiced()
* returns. Pushing the event to the event handler queue avoids this locking
* but does not guarantee, that the event is processed immediately.
*
* The user may choose, which solution fits best for the present use case.
*
*
* @ingroup device
*/
class cStateMachine {
public:
cStateMachine(cSoftHdDevice *);
void OnEventReceived(const Event&);
State GetState(void) const { return m_state; };
void SetState(State state) { m_state = state; };
void ChangeState(State);
private:
cSoftHdDevice *m_pDevice; ///< pointer to the device
std::mutex m_mutex; ///< state machine mutex
std::atomic<State> m_state = DETACHED; ///< current state
};
/**
* Event handler thread
*
* Queues events and sends them to the state machine cStateMachine as the final event receiver
*
* @ingroup device
*/
class cEventHandler : public cThread {
public:
cEventHandler(cStateMachine *);
~cEventHandler(void);
void AddEvent(Event);
protected:
void Action(void);
private:
cStateMachine *m_pStateMachine; ///< pointer to state machine
std::mutex m_mutex; ///< queue mutex
std::vector<Event> m_eventQueue; ///< event fifo queue
};
#endif