1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | #include <cassert> |
13 | #include <sstream> |
14 | #include <stdexcept> |
15 | #include <string> |
16 | |
17 | #include "../audio/audio_system.hpp" |
18 | #include "../audio/audio.hpp" |
19 | #include "../errors.hpp" |
20 | #include "../io/io_response.hpp" |
21 | #include "../messages.h" |
22 | #include "player_state.hpp" |
23 | #include "player.hpp" |
24 | |
25 | Player::Player(const AudioSystem &audio_system, const Player::TP &time_parser) |
26 | : file(audio_system), |
27 | position(), |
28 | state(), |
29 | time_parser(time_parser), |
30 | end_sink(nullptr) |
31 | { |
32 | } |
33 | |
34 | bool Player::Update() |
35 | { |
36 | if (CurrentStateIn(PlayerState::AUDIO_PLAYING_STATES)) { |
37 | PlaybackUpdate(); |
38 | } |
39 | if (CurrentStateIn(PlayerState::AUDIO_LOADED_STATES)) { |
40 | this->file.Update(); |
41 | } |
42 | return IsRunning(); |
43 | } |
44 | |
45 | void Player::PlaybackUpdate() |
46 | { |
47 | if (this->file.IsStopped()) { |
48 | if (this->end_sink != nullptr) { |
49 | this->end_sink->Respond(ResponseCode::END, ""); |
50 | } |
51 | Stop(); |
52 | Seek("0"); |
53 | } else { |
54 | UpdatePosition(); |
55 | } |
56 | } |
57 | |
58 | void Player::WelcomeClient(ResponseSink &client) const |
59 | { |
60 | client.Respond(ResponseCode::OHAI, MSG_OHAI); |
61 | client.Respond(ResponseCode::FEATURES, MSG_FEATURES); |
62 | this->file.Emit(client); |
63 | this->position.Emit(client); |
64 | this->state.Emit(client); |
65 | } |
66 | |
67 | void Player::SetResponseSink(ResponseSink &sink) |
68 | { |
69 | this->file.SetResponseSink(sink); |
70 | this->position.SetResponseSink(sink); |
71 | this->state.SetResponseSink(sink); |
72 | this->end_sink = &sink; |
73 | } |
74 | |
75 | |
76 | |
77 | |
78 | |
79 | bool Player::Eject() |
80 | { |
81 | if (CurrentStateIn(PlayerState::AUDIO_LOADED_STATES)) { |
82 | this->file.Eject(); |
83 | SetState(PlayerState::State::EJECTED); |
84 | return true; |
85 | } |
86 | return false; |
87 | } |
88 | |
89 | bool Player::Load(const std::string &path) |
90 | { |
91 | bool valid = !path.empty(); |
92 | if (valid) { |
93 | try |
94 | { |
95 | this->file.Load(path); |
96 | ResetPosition(); |
97 | Debug() << "Loaded " << path << std::endl; |
98 | SetState(PlayerState::State::STOPPED); |
99 | } |
100 | catch (FileError &) |
101 | { |
102 | |
103 | Eject(); |
104 | valid = false; |
105 | } |
106 | catch (Error &) |
107 | { |
108 | |
109 | |
110 | Eject(); |
111 | throw; |
112 | } |
113 | } |
114 | return valid; |
115 | } |
116 | |
117 | bool Player::Play() |
118 | { |
119 | if (CurrentStateIn({ PlayerState::State::STOPPED })) { |
120 | this->file.Start(); |
121 | SetState(PlayerState::State::PLAYING); |
122 | return true; |
123 | } |
124 | return false; |
125 | } |
126 | |
127 | bool Player::Quit() |
128 | { |
129 | Eject(); |
130 | SetState(PlayerState::State::QUITTING); |
131 | |
132 | return true; |
133 | } |
134 | |
135 | bool Player::Seek(const std::string &time_str) |
136 | { |
137 | if (CurrentStateIn(PlayerState::AUDIO_LOADED_STATES)) { |
138 | bool success = true; |
139 | std::chrono::microseconds position(0); |
140 | |
141 | try |
| This statement is never executed |
142 | { |
143 | position = this->time_parser.Parse(time_str); |
144 | } |
145 | catch (std::out_of_range) |
146 | { |
147 | success = false; |
148 | } |
149 | |
150 | if (success) { |
151 | this->file.SeekToPosition(position); |
152 | this->ResetPosition(); |
153 | this->UpdatePosition(); |
154 | } |
155 | return success; |
156 | } |
157 | return false; |
158 | } |
159 | |
160 | bool Player::Stop() |
161 | { |
162 | if (CurrentStateIn(PlayerState::AUDIO_PLAYING_STATES)) { |
163 | this->file.Stop(); |
164 | SetState(PlayerState::State::STOPPED); |
165 | return true; |
166 | } |
167 | return false; |
168 | } |