GCC Code Coverage Report


Directory: ./
File: playlist/PlaylistEntryBoth.cpp
Date: 2026-10-29 08:11:58
Exec Total Coverage
Lines: 130 180 72.2%
Functions: 12 14 85.7%
Branches: 153 368 41.6%

Line Branch Exec Source
1 /*
2 * This file is part of the Falcon Player (FPP) and is Copyright (C)
3 * 2013-2022 by the Falcon Player Developers.
4 *
5 * The Falcon Player (FPP) is free software, and is covered under
6 * multiple Open Source licenses. Please see the included 'LICENSES'
7 * file for descriptions of what files are covered by each license.
8 *
9 * This source file is covered under the LGPL v2.1 as described in the
10 * included LICENSE.LGPL file.
11 */
12
13 #include "fpp-pch.h"
14
15 #include "fpp-json.h"
16
17 #include <thread>
18
19 #include "../common.h"
20 #include "../log.h"
21
22 #include "PlaylistEntryBoth.h"
23 #include "mediadetails.h"
24 #include "../MultiSync.h"
25
26 // Longest the sequence waits for the media to become audible. Covers a cold
27 // audio output (~0.6 s on an AM335x, a PipeWire output stream gives up at 3 s)
28 // with margin; past it the sequence starts and the sync servo takes over.
29 static constexpr long long AUDIO_START_HOLD_MS = 4000;
30
31 39 PlaylistEntryBoth::PlaylistEntryBoth(Playlist* playlist, PlaylistEntryBase* parent) :
32 PlaylistEntryBase(playlist, parent),
33 39 m_duration(0),
34 39 m_mediaEntry(NULL),
35 39 m_sequenceEntry(NULL) {
36
1/2
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
39 LogDebug(VB_PLAYLIST, "PlaylistEntryBoth::PlaylistEntryBoth()\n");
37
38
1/2
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
39 m_type = "both";
39 39 }
40
41 76 PlaylistEntryBoth::~PlaylistEntryBoth() {
42
1/2
✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
38 if (m_sequenceEntry) {
43
1/2
✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
38 delete m_sequenceEntry;
44 }
45
1/2
✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
38 if (m_mediaOwned) {
46
1/2
✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
38 delete m_mediaOwned;
47 }
48 76 }
49
50 /*
51 *
52 */
53 39 int PlaylistEntryBoth::Init(Json::Value& config) {
54 39 LogDebug(VB_PLAYLIST, "PlaylistEntryBoth::Init()\n");
55
56
2/6
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 39 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
39 m_sequenceEntry = new PlaylistEntrySequence(m_parentPlaylist, this);
57
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 if (!m_sequenceEntry)
58 ✗ return 0;
59
60
2/6
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 39 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
39 m_mediaOwned = new PlaylistEntryMedia(m_parentPlaylist, this);
61 39 m_mediaEntry = m_mediaOwned;
62
63
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 if (!m_mediaEntry->Init(config)) {
64 // Media init failed — run sequence-only. The rest of this class
65 // already null-checks m_mediaEntry; the unconditional GetMediaName()
66 // call that used to sit below this branch dereferenced the pointer
67 // just nulled here.
68 ✗ delete m_mediaOwned;
69 ✗ m_mediaOwned = nullptr;
70 ✗ m_mediaEntry = nullptr;
71 } else {
72
1/2
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
39 m_mediaName = m_mediaEntry->GetMediaName();
73 }
74
75
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 if (!m_sequenceEntry->Init(config))
76 ✗ return 0;
77
78 39 m_sequenceName = m_sequenceEntry->GetSequenceName();
79 39 return PlaylistEntryBase::Init(config);
80 }
81
82 /*
83 *
84 */
85 46 int PlaylistEntryBoth::StartPlaying(void) {
86
1/2
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
46 LogDebug(VB_PLAYLIST, "PlaylistEntryBoth::StartPlaying()\n");
87
88
1/2
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
46 std::unique_lock<std::recursive_mutex> seqLock(m_mutex);
89
2/4
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 46 times.
46 if (!CanPlay()) {
90 ✗ FinishPlay();
91 ✗ return 0;
92 }
93
94 // The sequence may start later than this (held until the media is
95 // audible, or after a media offset), and Process() acts on whether it is
96 // started or finished. On a repeating playlist's next pass it still
97 // carries the last pass's "started and finished" -- which ended the entry
98 // at once, so a repeating playlist ran through every entry in a fraction
99 // of a second at the wrap and never played again.
100
1/2
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
46 m_sequenceEntry->ResetPlayState();
101
102 // Each pass decides afresh whether it has media.
103 46 m_mediaEntry = m_mediaOwned;
104
4/8
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 46 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 46 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 46 times.
46 if (m_mediaEntry && !m_mediaEntry->PreparePlay()) {
105 ✗ m_mediaEntry = nullptr;
106 }
107
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
46 if (!m_mediaEntry) {
108 ✗ LogDebug(VB_PLAYLIST, "Skipping media playlist entry, likely blacklisted audio: %s\n", m_mediaName.c_str());
109 }
110 // The media drives the timing when there is media; without it this pass,
111 // the sequence has to keep its own time.
112 46 m_sequenceEntry->setAdjustTiming(m_mediaEntry == nullptr);
113
2/4
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 46 times.
46 if (!m_sequenceEntry->PreparePlay()) {
114 ✗ LogDebug(VB_PLAYLIST, "Problems starting sequence: %s\n", m_sequenceEntry->GetSequenceName().c_str());
115 }
116
117
6/8
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 44 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 44 times.
46 if (multiSync->isMultiSyncEnabled() && m_mediaEntry && m_mediaEntry->m_openTime) {
118
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 long long st = GetMonotonicTimeMS() - m_mediaEntry->m_openTime;
119
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (st < PlaylistEntryMedia::m_openStartDelay) {
120 ✗ std::this_thread::sleep_for(std::chrono::milliseconds(PlaylistEntryMedia::m_openStartDelay - st - 2));
121 }
122 }
123
124 // With media, the sequence normally starts from Process() once the media
125 // is audible rather than here. Starting both together put the lights
126 // ahead of the sound by however long the audio output took to come up --
127 // most of a second on slow boards -- and they only caught up as the sync
128 // servo slowed them, which looks like the first second of audio is missing.
129
4/6
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 46 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 37 times.
✓ Branch 5 taken 9 times.
46 m_holdingForAudio = m_mediaEntry && m_mediaEntry->GetMediaOffsetMS() <= 0;
130
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
46 if (!m_mediaEntry) {
131 ✗ if (!m_sequenceEntry->StartPlaying()) {
132 ✗ LogDebug(VB_PLAYLIST, "Could not start sequence: %s\n", m_sequenceEntry->GetSequenceName().c_str());
133 ✗ FinishPlay();
134 ✗ return 0;
135 }
136 }
137
6/8
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 46 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 45 times.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 45 times.
46 if (m_mediaEntry && !m_mediaEntry->StartPlaying()) {
138
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 LogDebug(VB_PLAYLIST, "Could not start media: %s\n", m_mediaName.c_str());
139
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 m_mediaEntry->Stop();
140 1 m_mediaEntry = nullptr;
141 1 m_holdingForAudio = false;
142
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 m_sequenceEntry->Stop();
143
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 FinishPlay();
144 1 return 0;
145 }
146
1/2
✓ Branch 0 taken 45 times.
✗ Branch 1 not taken.
45 m_holdStartMS = GetMonotonicTimeMS();
147
148
1/2
✓ Branch 0 taken 45 times.
✗ Branch 1 not taken.
45 return PlaylistEntryBase::StartPlaying();
149 46 }
150
151 /*
152 *
153 */
154 121856 int PlaylistEntryBoth::Process(void) {
155
1/2
✓ Branch 0 taken 121856 times.
✗ Branch 1 not taken.
121856 LogExcess(VB_PLAYLIST, "PlaylistEntryBoth::Process()\n");
156
1/2
✓ Branch 0 taken 121856 times.
✗ Branch 1 not taken.
121856 std::unique_lock<std::recursive_mutex> seqLock(m_mutex);
157
158
1/2
✓ Branch 0 taken 121856 times.
✗ Branch 1 not taken.
121856 if (m_mediaEntry)
159
1/2
✓ Branch 0 taken 121856 times.
✗ Branch 1 not taken.
121856 m_mediaEntry->Process();
160
161
3/4
✓ Branch 0 taken 686 times.
✓ Branch 1 taken 121170 times.
✓ Branch 2 taken 686 times.
✗ Branch 3 not taken.
121856 if (m_holdingForAudio && m_mediaEntry) {
162
1/2
✓ Branch 0 taken 686 times.
✗ Branch 1 not taken.
686 long long held = GetMonotonicTimeMS() - m_holdStartMS;
163
6/8
✓ Branch 0 taken 686 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 650 times.
✓ Branch 3 taken 36 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 650 times.
✓ Branch 6 taken 36 times.
✓ Branch 7 taken 650 times.
686 if (m_mediaEntry->IsAudible() || held >= AUDIO_START_HOLD_MS) {
164 36 m_holdingForAudio = false;
165
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 36 times.
36 if (held >= AUDIO_START_HOLD_MS) {
166 ✗ LogWarn(VB_PLAYLIST, "No sound from %s after %lld ms, starting sequence %s anyway\n",
167 m_mediaName.c_str(), held, m_sequenceEntry->GetSequenceName().c_str());
168 } else {
169
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 LogDebug(VB_PLAYLIST, "Media audible after %lld ms, starting sequence %s\n",
170 held, m_sequenceEntry->GetSequenceName().c_str());
171 }
172
2/4
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 36 times.
36 if (!m_sequenceEntry->StartPlaying()) {
173 ✗ LogDebug(VB_PLAYLIST, "Could not start sequence: %s\n", m_sequenceEntry->GetSequenceName().c_str());
174 ✗ m_mediaEntry->Stop();
175 ✗ FinishPlay();
176 ✗ return PlaylistEntryBase::Process();
177 }
178 }
179 }
180
181
6/8
✓ Branch 0 taken 121856 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 121856 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1663 times.
✓ Branch 5 taken 120193 times.
✓ Branch 6 taken 1663 times.
✓ Branch 7 taken 120193 times.
121856 if (m_mediaEntry && m_mediaEntry->GetMediaOffsetMS() > 0) {
182
1/2
✓ Branch 0 taken 1663 times.
✗ Branch 1 not taken.
1663 long long ct = GetMonotonicTimeMS();
183 1663 long long df = ct - m_mediaEntry->m_startTime;
184
3/4
✓ Branch 0 taken 1663 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1548 times.
✓ Branch 3 taken 115 times.
1663 if (df > (m_mediaEntry->GetMediaOffsetMS() - m_sequenceEntry->GetSequenceFrameTime())) {
185
3/4
✓ Branch 0 taken 1548 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 1539 times.
1548 if (!m_sequenceEntry->IsStarted()) {
186
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 m_sequenceEntry->StartPlaying();
187 }
188 }
189 }
190
3/4
✓ Branch 0 taken 121856 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 121091 times.
✓ Branch 3 taken 765 times.
121856 if (m_sequenceEntry->IsStarted()) {
191
1/2
✓ Branch 0 taken 121091 times.
✗ Branch 1 not taken.
121091 m_sequenceEntry->Process();
192 }
193
194
6/8
✓ Branch 0 taken 121856 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 121856 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15 times.
✓ Branch 5 taken 121841 times.
✓ Branch 6 taken 15 times.
✓ Branch 7 taken 121841 times.
121856 if (m_mediaEntry && m_mediaEntry->IsFinished()) {
195
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 FinishPlay();
196
2/4
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
15 if (!m_sequenceEntry->IsFinished()) {
197
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 m_sequenceEntry->Stop();
198 }
199 }
200
201
8/12
✓ Branch 0 taken 121856 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 31 times.
✓ Branch 3 taken 121825 times.
✓ Branch 4 taken 31 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 31 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 31 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 31 times.
✓ Branch 11 taken 121825 times.
121856 if (m_sequenceEntry->IsFinished() && (!m_mediaEntry || !m_mediaEntry->HasExtraAtEnd())) {
202
1/2
✓ Branch 0 taken 31 times.
✗ Branch 1 not taken.
31 FinishPlay();
203
1/2
✓ Branch 0 taken 31 times.
✗ Branch 1 not taken.
31 if (m_mediaEntry)
204
1/2
✓ Branch 0 taken 31 times.
✗ Branch 1 not taken.
31 m_mediaEntry->Stop();
205 }
206
207 // FIXME PLAYLIST, handle sync in here somehow
208
209
1/2
✓ Branch 0 taken 121856 times.
✗ Branch 1 not taken.
121856 return PlaylistEntryBase::Process();
210 121856 }
211
212 /*
213 *
214 */
215 6 int PlaylistEntryBoth::Stop(void) {
216
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 LogDebug(VB_PLAYLIST, "PlaylistEntryBoth::Stop()\n");
217
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 std::unique_lock<std::recursive_mutex> seqLock(m_mutex);
218 6 m_holdingForAudio = false;
219
220
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (m_mediaEntry)
221
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 m_mediaEntry->Stop();
222
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 m_sequenceEntry->Stop();
223
224
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
12 return PlaylistEntryBase::Stop();
225 6 }
226
227 /*
228 *
229 */
230 ✗ void PlaylistEntryBoth::Dump(void) {
231 ✗ std::unique_lock<std::recursive_mutex> seqLock(m_mutex);
232 ✗ PlaylistEntryBase::Dump();
233
234 ✗ if (m_mediaEntry)
235 ✗ m_mediaEntry->Dump();
236 ✗ m_sequenceEntry->Dump();
237 ✗ }
238
239 1388 uint64_t PlaylistEntryBoth::GetLengthInMS() {
240
1/2
✓ Branch 0 taken 1388 times.
✗ Branch 1 not taken.
1388 std::unique_lock<std::recursive_mutex> seqLock(m_mutex);
241
3/4
✓ Branch 0 taken 1387 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1387 times.
✗ Branch 3 not taken.
1388 uint64_t m = m_mediaEntry ? m_mediaEntry->GetLengthInMS() : 0;
242
2/4
✓ Branch 0 taken 1388 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1388 times.
✗ Branch 3 not taken.
1388 uint64_t s = m_sequenceEntry ? m_sequenceEntry->GetLengthInMS() : 0;
243
3/4
✓ Branch 0 taken 1387 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1387 times.
1388 if (m && m < s) {
244 // media drives it, when media completes, we stop
245 ✗ return m;
246 }
247 1388 return s;
248 1388 }
249 2776 uint64_t PlaylistEntryBoth::GetElapsedMS() {
250
1/2
✓ Branch 0 taken 2776 times.
✗ Branch 1 not taken.
2776 std::unique_lock<std::recursive_mutex> seqLock(m_mutex);
251
2/2
✓ Branch 0 taken 2774 times.
✓ Branch 1 taken 2 times.
2776 if (m_mediaEntry) {
252
1/2
✓ Branch 0 taken 2774 times.
✗ Branch 1 not taken.
2774 return m_mediaEntry->GetElapsedMS();
253 }
254
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (m_sequenceEntry) {
255
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 return m_sequenceEntry->GetElapsedMS();
256 }
257 ✗ return 0;
258 2776 }
259
260 /*
261 *
262 */
263 130 Json::Value PlaylistEntryBoth::GetConfig(void) {
264
1/2
✓ Branch 0 taken 130 times.
✗ Branch 1 not taken.
130 std::unique_lock<std::recursive_mutex> seqLock(m_mutex);
265
1/2
✓ Branch 0 taken 130 times.
✗ Branch 1 not taken.
130 Json::Value result = PlaylistEntryBase::GetConfig();
266
267
2/2
✓ Branch 0 taken 129 times.
✓ Branch 1 taken 1 times.
130 if (m_mediaEntry) {
268
2/4
✓ Branch 0 taken 129 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 129 times.
✗ Branch 3 not taken.
129 result["media"] = m_mediaEntry->GetConfig();
269 } else {
270 // fake it so the display will display the times
271 // where the sequence is
272
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 result["media"] = m_sequenceEntry->GetConfig();
273 }
274
2/4
✓ Branch 0 taken 130 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 130 times.
✗ Branch 3 not taken.
130 result["sequence"] = m_sequenceEntry->GetConfig();
275
276 130 return result;
277 130 }
278
279 ✗ Json::Value PlaylistEntryBoth::GetMqttStatus(void) {
280 ✗ std::unique_lock<std::recursive_mutex> seqLock(m_mutex);
281 ✗ Json::Value result = PlaylistEntryBase::GetMqttStatus();
282 ✗ if (m_mediaEntry) {
283 ✗ uint64_t l = m_mediaEntry->GetLengthInMS();
284 ✗ uint64_t e = m_mediaEntry->GetElapsedMS();
285 ✗ result["secondsRemaining"] = (int)((l - e) / 1000);
286 ✗ result["secondsTotal"] = (int)(l / 1000);
287 ✗ result["secondsElapsed"] = (int)(e / 1000);
288 ✗ result["mediaName"] = m_mediaEntry->GetMediaName();
289 }
290 ✗ if (m_sequenceEntry) {
291 ✗ Json::Value se = m_sequenceEntry->GetMqttStatus();
292 ✗ result["sequenceName"] = se["sequenceName"];
293 ✗ result["secondsRemaining"] = se["secondsRemaining"];
294 ✗ result["secondsTotal"] = se["secondsTotal"];
295 ✗ result["secondsElapsed"] = se["secondsElapsed"];
296 ✗ }
297
298 ✗ result["mediaTitle"] = MediaDetails::INSTANCE.title;
299 ✗ result["mediaArtist"] = MediaDetails::INSTANCE.artist;
300
301 ✗ return result;
302 ✗ }
303
304 3 void PlaylistEntryBoth::Pause() {
305
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 std::unique_lock<std::recursive_mutex> seqLock(m_mutex);
306
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (m_mediaEntry)
307
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 m_mediaEntry->Pause();
308
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 m_sequenceEntry->Pause();
309 3 }
310 244117 bool PlaylistEntryBoth::IsPaused() {
311
1/2
✓ Branch 0 taken 244117 times.
✗ Branch 1 not taken.
244117 std::unique_lock<std::recursive_mutex> seqLock(m_mutex);
312
2/2
✓ Branch 0 taken 244115 times.
✓ Branch 1 taken 2 times.
244117 if (m_mediaEntry) {
313
1/2
✓ Branch 0 taken 244115 times.
✗ Branch 1 not taken.
244115 return m_mediaEntry->IsPaused();
314 }
315
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 return m_sequenceEntry->IsPaused();
316 244117 }
317 3 void PlaylistEntryBoth::Resume() {
318
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 std::unique_lock<std::recursive_mutex> seqLock(m_mutex);
319
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (m_mediaEntry)
320
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 m_mediaEntry->Resume();
321
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 m_sequenceEntry->Resume();
322 3 }
323