Line data Source code
1 : /*
2 : * Copyright (C) 2022 Sky UK
3 : *
4 : * This library is free software; you can redistribute it and/or
5 : * modify it under the terms of the GNU Lesser General Public
6 : * License as published by the Free Software Foundation;
7 : * version 2.1 of the License.
8 : *
9 : * This library is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 : * Lesser General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU Lesser General Public
15 : * License along with this library; if not, write to the Free Software
16 : * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 : */
18 :
19 : #include "GStreamerMSEMediaPlayerClient.h"
20 : #include "Constants.h"
21 : #include "GstreamerCatLog.h"
22 : #include "RialtoGStreamerMSEBaseSink.h"
23 : #include "RialtoGStreamerMSEBaseSinkPrivate.h"
24 : #include "RialtoGStreamerMSEVideoSink.h"
25 :
26 : #include <algorithm>
27 : #include <chrono>
28 : #include <thread>
29 :
30 : namespace
31 : {
32 : // The start time of segment might differ from the first sample which is injected.
33 : // That difference should not be bigger than 1 video / audio frame.
34 : // 1 second is probably erring on the side of caution, but should not have side effect.
35 : const int64_t segmentStartMaximumDiff = 1000000000;
36 : const int32_t UNKNOWN_STREAMS_NUMBER = -1;
37 :
38 0 : const char *toString(const firebolt::rialto::PlaybackError &error)
39 : {
40 0 : switch (error)
41 : {
42 0 : case firebolt::rialto::PlaybackError::DECRYPTION:
43 0 : return "DECRYPTION";
44 0 : case firebolt::rialto::PlaybackError::UNKNOWN:
45 0 : return "UNKNOWN";
46 : }
47 0 : return "UNKNOWN";
48 : }
49 0 : const char *toString(const firebolt::rialto::MediaSourceType &src)
50 : {
51 0 : switch (src)
52 : {
53 0 : case firebolt::rialto::MediaSourceType::AUDIO:
54 0 : return "AUDIO";
55 0 : case firebolt::rialto::MediaSourceType::VIDEO:
56 0 : return "VIDEO";
57 0 : case firebolt::rialto::MediaSourceType::SUBTITLE:
58 0 : return "SUBTITLE";
59 0 : case firebolt::rialto::MediaSourceType::UNKNOWN:
60 0 : return "UNKNOWN";
61 : }
62 0 : return "UNKNOWN";
63 : }
64 : } // namespace
65 : #define GST_CAT_DEFAULT rialtoGStreamerCat
66 270 : GStreamerMSEMediaPlayerClient::GStreamerMSEMediaPlayerClient(
67 : const std::shared_ptr<IMessageQueueFactory> &messageQueueFactory,
68 : const std::shared_ptr<firebolt::rialto::client::MediaPlayerClientBackendInterface> &MediaPlayerClientBackend,
69 270 : const uint32_t maxVideoWidth, const uint32_t maxVideoHeight)
70 270 : : m_backendQueue{messageQueueFactory->createMessageQueue()}, m_messageQueueFactory{messageQueueFactory},
71 270 : m_clientBackend(MediaPlayerClientBackend), m_duration(0), m_audioStreams{UNKNOWN_STREAMS_NUMBER},
72 270 : m_videoStreams{UNKNOWN_STREAMS_NUMBER}, m_subtitleStreams{UNKNOWN_STREAMS_NUMBER},
73 270 : m_videoRectangle{0, 0, 1920, 1080}, m_streamingStopped(false),
74 270 : m_maxWidth(maxVideoWidth == 0 ? DEFAULT_MAX_VIDEO_WIDTH : maxVideoWidth),
75 810 : m_maxHeight(maxVideoHeight == 0 ? DEFAULT_MAX_VIDEO_HEIGHT : maxVideoHeight)
76 : {
77 270 : m_backendQueue->start();
78 : }
79 :
80 270 : GStreamerMSEMediaPlayerClient::~GStreamerMSEMediaPlayerClient()
81 : {
82 270 : stopStreaming();
83 : }
84 :
85 422 : void GStreamerMSEMediaPlayerClient::stopStreaming()
86 : {
87 422 : if (!m_streamingStopped)
88 : {
89 270 : m_backendQueue->stop();
90 :
91 330 : for (auto &source : m_attachedSources)
92 : {
93 60 : source.second.m_bufferPuller->stop();
94 : }
95 :
96 270 : m_streamingStopped = true;
97 : }
98 422 : }
99 :
100 : // Deletes client backend -> this deletes mediapipeline object
101 154 : void GStreamerMSEMediaPlayerClient::destroyClientBackend()
102 : {
103 154 : m_clientBackend.reset();
104 : }
105 :
106 1 : void GStreamerMSEMediaPlayerClient::notifyDuration(int64_t duration)
107 : {
108 1 : m_backendQueue->postMessage(std::make_shared<SetDurationMessage>(duration, m_duration));
109 : }
110 :
111 1 : void GStreamerMSEMediaPlayerClient::notifyPosition(int64_t position)
112 : {
113 1 : m_backendQueue->postMessage(std::make_shared<SetPositionMessage>(position, m_attachedSources));
114 : }
115 :
116 : void GStreamerMSEMediaPlayerClient::notifyNativeSize(uint32_t width, uint32_t height, double aspect) {}
117 :
118 : void GStreamerMSEMediaPlayerClient::notifyNetworkState(firebolt::rialto::NetworkState state) {}
119 :
120 57 : void GStreamerMSEMediaPlayerClient::notifyPlaybackState(firebolt::rialto::PlaybackState state)
121 : {
122 57 : m_backendQueue->postMessage(std::make_shared<PlaybackStateMessage>(state, this));
123 : }
124 :
125 : void GStreamerMSEMediaPlayerClient::notifyVideoData(bool hasData) {}
126 :
127 : void GStreamerMSEMediaPlayerClient::notifyAudioData(bool hasData) {}
128 :
129 8 : void GStreamerMSEMediaPlayerClient::notifyNeedMediaData(
130 : int32_t sourceId, size_t frameCount, uint32_t needDataRequestId,
131 : const std::shared_ptr<firebolt::rialto::MediaPlayerShmInfo> & /*shmInfo*/)
132 : {
133 8 : m_backendQueue->postMessage(std::make_shared<NeedDataMessage>(sourceId, frameCount, needDataRequestId, this));
134 :
135 8 : return;
136 : }
137 :
138 : void GStreamerMSEMediaPlayerClient::notifyCancelNeedMediaData(int sourceId) {}
139 :
140 5 : void GStreamerMSEMediaPlayerClient::notifyQos(int32_t sourceId, const firebolt::rialto::QosInfo &qosInfo)
141 : {
142 5 : m_backendQueue->postMessage(std::make_shared<QosMessage>(sourceId, qosInfo, this));
143 : }
144 :
145 2 : void GStreamerMSEMediaPlayerClient::notifyBufferUnderflow(int32_t sourceId)
146 : {
147 2 : m_backendQueue->postMessage(std::make_shared<BufferUnderflowMessage>(sourceId, this));
148 : }
149 :
150 5 : void GStreamerMSEMediaPlayerClient::notifyPlaybackError(int32_t sourceId, firebolt::rialto::PlaybackError error)
151 : {
152 5 : m_backendQueue->postMessage(std::make_shared<PlaybackErrorMessage>(sourceId, error, this));
153 : }
154 :
155 5 : void GStreamerMSEMediaPlayerClient::notifySourceFlushed(int32_t sourceId)
156 : {
157 5 : m_backendQueue->postMessage(std::make_shared<SourceFlushedMessage>(sourceId, this));
158 : }
159 :
160 6 : void GStreamerMSEMediaPlayerClient::getPositionDo(int64_t *position, int32_t sourceId)
161 : {
162 6 : auto sourceIt = m_attachedSources.find(sourceId);
163 6 : if (sourceIt == m_attachedSources.end())
164 : {
165 1 : *position = -1;
166 1 : return;
167 : }
168 :
169 5 : if (m_clientBackend && m_clientBackend->getPosition(*position))
170 : {
171 3 : sourceIt->second.m_position = *position;
172 : }
173 : else
174 : {
175 2 : *position = sourceIt->second.m_position;
176 : }
177 : }
178 :
179 6 : int64_t GStreamerMSEMediaPlayerClient::getPosition(int32_t sourceId)
180 : {
181 : int64_t position;
182 12 : m_backendQueue->callInEventLoop([&]() { getPositionDo(&position, sourceId); });
183 6 : return position;
184 : }
185 :
186 5 : bool GStreamerMSEMediaPlayerClient::setImmediateOutput(int32_t sourceId, bool immediateOutput)
187 : {
188 5 : if (!m_clientBackend)
189 : {
190 1 : return false;
191 : }
192 :
193 4 : bool status{false};
194 8 : m_backendQueue->callInEventLoop([&]() { status = m_clientBackend->setImmediateOutput(sourceId, immediateOutput); });
195 4 : return status;
196 : }
197 :
198 4 : bool GStreamerMSEMediaPlayerClient::getImmediateOutput(int32_t sourceId, bool &immediateOutput)
199 : {
200 4 : if (!m_clientBackend)
201 : {
202 1 : return false;
203 : }
204 :
205 3 : bool status{false};
206 6 : m_backendQueue->callInEventLoop([&]() { status = m_clientBackend->getImmediateOutput(sourceId, immediateOutput); });
207 3 : return status;
208 : }
209 :
210 1 : bool GStreamerMSEMediaPlayerClient::getStats(int32_t sourceId, uint64_t &renderedFrames, uint64_t &droppedFrames)
211 : {
212 1 : if (!m_clientBackend)
213 : {
214 0 : return false;
215 : }
216 :
217 1 : bool status{false};
218 1 : m_backendQueue->callInEventLoop([&]()
219 1 : { status = m_clientBackend->getStats(sourceId, renderedFrames, droppedFrames); });
220 1 : return status;
221 : }
222 :
223 160 : bool GStreamerMSEMediaPlayerClient::createBackend()
224 : {
225 160 : bool result = false;
226 320 : m_backendQueue->callInEventLoop(
227 160 : [&]()
228 : {
229 160 : if (!m_clientBackend)
230 : {
231 1 : GST_ERROR("Client backend is NULL");
232 1 : result = false;
233 1 : return;
234 : }
235 159 : m_clientBackend->createMediaPlayerBackend(shared_from_this(), m_maxWidth, m_maxHeight);
236 :
237 159 : if (m_clientBackend->isMediaPlayerBackendCreated())
238 : {
239 154 : std::string utf8url = "mse://1";
240 154 : firebolt::rialto::MediaType mediaType = firebolt::rialto::MediaType::MSE;
241 462 : if (!m_clientBackend->load(mediaType, "", utf8url))
242 : {
243 1 : GST_ERROR("Could not load RialtoClient");
244 1 : return;
245 : }
246 153 : result = true;
247 154 : }
248 : else
249 : {
250 5 : GST_ERROR("Media player backend could not be created");
251 : }
252 : });
253 :
254 160 : return result;
255 : }
256 :
257 21 : StateChangeResult GStreamerMSEMediaPlayerClient::play(int32_t sourceId)
258 : {
259 21 : StateChangeResult result = StateChangeResult::NOT_ATTACHED;
260 42 : m_backendQueue->callInEventLoop(
261 21 : [&]()
262 : {
263 21 : auto sourceIt = m_attachedSources.find(sourceId);
264 21 : if (sourceIt == m_attachedSources.end())
265 : {
266 1 : GST_ERROR("Cannot play - there's no attached source with id %d", sourceId);
267 1 : result = StateChangeResult::NOT_ATTACHED;
268 3 : return;
269 : }
270 :
271 20 : if (m_serverPlaybackState == firebolt::rialto::PlaybackState::PLAYING)
272 : {
273 2 : GST_INFO("Server is already playing");
274 2 : sourceIt->second.m_state = ClientState::PLAYING;
275 :
276 6 : if (checkIfAllAttachedSourcesInStates({ClientState::PLAYING}))
277 : {
278 1 : m_clientState = ClientState::PLAYING;
279 : }
280 :
281 2 : result = StateChangeResult::SUCCESS_SYNC;
282 2 : return;
283 : }
284 :
285 18 : sourceIt->second.m_state = ClientState::AWAITING_PLAYING;
286 :
287 18 : if (m_clientState == ClientState::PAUSED)
288 : {
289 : // If one source is AWAITING_PLAYING, the other source can still be PLAYING.
290 : // This happends when we are switching out audio.
291 42 : if (checkIfAllAttachedSourcesInStates({ClientState::AWAITING_PLAYING, ClientState::PLAYING}))
292 : {
293 10 : GST_INFO("Sending play command");
294 10 : m_clientBackend->play();
295 10 : m_clientState = ClientState::AWAITING_PLAYING;
296 : }
297 : else
298 : {
299 4 : GST_DEBUG("Not all sources are ready to play");
300 : }
301 : }
302 : else
303 : {
304 4 : GST_WARNING("Not in PAUSED state in %u state", static_cast<uint32_t>(m_clientState));
305 : }
306 :
307 18 : result = StateChangeResult::SUCCESS_ASYNC;
308 18 : sourceIt->second.m_delegate->postAsyncStart();
309 : });
310 :
311 21 : return result;
312 : }
313 :
314 312 : StateChangeResult GStreamerMSEMediaPlayerClient::pause(int32_t sourceId)
315 : {
316 312 : StateChangeResult result = StateChangeResult::NOT_ATTACHED;
317 624 : m_backendQueue->callInEventLoop(
318 312 : [&]()
319 : {
320 312 : auto sourceIt = m_attachedSources.find(sourceId);
321 312 : if (sourceIt == m_attachedSources.end())
322 : {
323 146 : GST_WARNING("Cannot pause - there's no attached source with id %d", sourceId);
324 :
325 146 : result = StateChangeResult::NOT_ATTACHED;
326 146 : return;
327 : }
328 :
329 166 : if (m_serverPlaybackState == firebolt::rialto::PlaybackState::PAUSED &&
330 4 : m_clientState != ClientState::AWAITING_PLAYING && m_clientState != ClientState::AWAITING_PAUSED)
331 : {
332 : // if the server is already paused and we are not in async, we don't need to send pause command
333 2 : GST_INFO("Server is already paused");
334 2 : sourceIt->second.m_state = ClientState::PAUSED;
335 :
336 6 : if (checkIfAllAttachedSourcesInStates({ClientState::PAUSED}))
337 : {
338 1 : m_clientState = ClientState::PAUSED;
339 : }
340 :
341 2 : result = StateChangeResult::SUCCESS_SYNC;
342 : }
343 : else
344 : {
345 164 : sourceIt->second.m_state = ClientState::AWAITING_PAUSED;
346 :
347 164 : bool shouldPause = false;
348 164 : if (m_clientState == ClientState::READY)
349 : {
350 456 : if (checkIfAllAttachedSourcesInStates({ClientState::AWAITING_PAUSED}))
351 : {
352 144 : shouldPause = true;
353 : }
354 : else
355 : {
356 8 : GST_DEBUG("Not all attached sources are ready to pause");
357 : }
358 : }
359 12 : else if (m_clientState == ClientState::AWAITING_PLAYING || m_clientState == ClientState::PLAYING)
360 : {
361 9 : shouldPause = true;
362 : }
363 : else
364 : {
365 3 : GST_DEBUG("Cannot pause in %u state", static_cast<uint32_t>(m_clientState));
366 : }
367 :
368 164 : if (shouldPause)
369 : {
370 153 : GST_INFO("Sending pause command in %u state", static_cast<uint32_t>(m_clientState));
371 153 : m_clientBackend->pause();
372 153 : m_clientState = ClientState::AWAITING_PAUSED;
373 : }
374 :
375 164 : result = StateChangeResult::SUCCESS_ASYNC;
376 164 : sourceIt->second.m_delegate->postAsyncStart();
377 : }
378 : });
379 :
380 312 : return result;
381 : }
382 :
383 153 : void GStreamerMSEMediaPlayerClient::stop()
384 : {
385 306 : m_backendQueue->callInEventLoop([&]() { m_clientBackend->stop(); });
386 153 : }
387 :
388 4 : void GStreamerMSEMediaPlayerClient::setPlaybackRate(double rate)
389 : {
390 8 : m_backendQueue->callInEventLoop([&]() { m_clientBackend->setPlaybackRate(rate); });
391 4 : }
392 :
393 7 : void GStreamerMSEMediaPlayerClient::flush(int32_t sourceId, bool resetTime)
394 : {
395 14 : m_backendQueue->callInEventLoop(
396 7 : [&]()
397 : {
398 7 : bool async{true};
399 7 : auto sourceIt = m_attachedSources.find(sourceId);
400 7 : if (sourceIt == m_attachedSources.end())
401 : {
402 2 : GST_ERROR("Cannot flush - there's no attached source with id %d", sourceId);
403 3 : return;
404 : }
405 5 : if (!m_clientBackend->flush(sourceId, resetTime, async))
406 : {
407 1 : GST_ERROR("Flush operation failed for source with id %d", sourceId);
408 1 : return;
409 : }
410 4 : sourceIt->second.m_isFlushing = true;
411 4 : sourceIt->second.m_bufferPuller->stop();
412 :
413 4 : if (async)
414 : {
415 4 : GST_INFO("Flush request sent for async source %d. Sink will lose state now", sourceId);
416 4 : sourceIt->second.m_delegate->lostState();
417 :
418 4 : sourceIt->second.m_state = ClientState::AWAITING_PAUSED;
419 4 : if (m_clientState == ClientState::PLAYING)
420 : {
421 0 : m_clientState = ClientState::AWAITING_PLAYING;
422 : }
423 4 : else if (m_clientState == ClientState::PAUSED)
424 : {
425 1 : m_clientState = ClientState::AWAITING_PAUSED;
426 : }
427 : }
428 : });
429 7 : }
430 :
431 10 : void GStreamerMSEMediaPlayerClient::setSourcePosition(int32_t sourceId, int64_t position, bool resetTime,
432 : double appliedRate, uint64_t stopPosition)
433 : {
434 20 : m_backendQueue->callInEventLoop(
435 10 : [&]()
436 : {
437 10 : auto sourceIt = m_attachedSources.find(sourceId);
438 10 : if (sourceIt == m_attachedSources.end())
439 : {
440 1 : GST_ERROR("Cannot Set Source Position - there's no attached source with id %d", sourceId);
441 2 : return;
442 : }
443 9 : if (!m_clientBackend->setSourcePosition(sourceId, position, resetTime, appliedRate, stopPosition))
444 : {
445 1 : GST_ERROR("Set Source Position operation failed for source with id %d", sourceId);
446 1 : return;
447 : }
448 8 : sourceIt->second.m_position = position;
449 : });
450 10 : }
451 :
452 4 : void GStreamerMSEMediaPlayerClient::processAudioGap(int64_t position, uint32_t duration, int64_t discontinuityGap,
453 : bool audioAac)
454 : {
455 8 : m_backendQueue->callInEventLoop(
456 4 : [&]()
457 : {
458 4 : if (!m_clientBackend->processAudioGap(position, duration, discontinuityGap, audioAac))
459 : {
460 1 : GST_ERROR("Process Audio Gap operation failed");
461 1 : return;
462 : }
463 : });
464 4 : }
465 :
466 199 : bool GStreamerMSEMediaPlayerClient::attachSource(std::unique_ptr<firebolt::rialto::IMediaPipeline::MediaSource> &source,
467 : RialtoMSEBaseSink *rialtoSink,
468 : const std::shared_ptr<IPullModePlaybackDelegate> &delegate)
469 : {
470 199 : if (source->getType() != firebolt::rialto::MediaSourceType::AUDIO &&
471 212 : source->getType() != firebolt::rialto::MediaSourceType::VIDEO &&
472 13 : source->getType() != firebolt::rialto::MediaSourceType::SUBTITLE)
473 : {
474 1 : GST_WARNING_OBJECT(rialtoSink, "Invalid source type %u", static_cast<uint32_t>(source->getType()));
475 1 : return false;
476 : }
477 :
478 198 : bool result = false;
479 396 : m_backendQueue->callInEventLoop(
480 198 : [&]()
481 : {
482 198 : result = m_clientBackend->attachSource(source);
483 :
484 198 : if (result)
485 : {
486 197 : std::shared_ptr<BufferParser> bufferParser;
487 197 : if (source->getType() == firebolt::rialto::MediaSourceType::AUDIO)
488 : {
489 145 : bufferParser = std::make_shared<AudioBufferParser>();
490 : }
491 52 : else if (source->getType() == firebolt::rialto::MediaSourceType::VIDEO)
492 : {
493 40 : bufferParser = std::make_shared<VideoBufferParser>();
494 : }
495 12 : else if (source->getType() == firebolt::rialto::MediaSourceType::SUBTITLE)
496 : {
497 12 : bufferParser = std::make_shared<SubtitleBufferParser>();
498 : }
499 :
500 197 : std::shared_ptr<BufferPuller> bufferPuller = std::make_shared<BufferPuller>(m_messageQueueFactory,
501 0 : GST_ELEMENT_CAST(rialtoSink),
502 197 : bufferParser, delegate);
503 :
504 197 : if (m_attachedSources.find(source->getId()) == m_attachedSources.end())
505 : {
506 197 : m_attachedSources.emplace(source->getId(),
507 394 : AttachedSource(rialtoSink, bufferPuller, delegate, source->getType()));
508 :
509 197 : delegate->setSourceId(source->getId());
510 197 : bufferPuller->start();
511 : }
512 : }
513 :
514 198 : sendAllSourcesAttachedIfPossibleInternal();
515 198 : });
516 :
517 198 : return result;
518 : }
519 :
520 4 : void GStreamerMSEMediaPlayerClient::sendAllSourcesAttachedIfPossible()
521 : {
522 8 : m_backendQueue->callInEventLoop([&]() { sendAllSourcesAttachedIfPossibleInternal(); });
523 4 : }
524 :
525 202 : void GStreamerMSEMediaPlayerClient::sendAllSourcesAttachedIfPossibleInternal()
526 : {
527 202 : if (!m_wasAllSourcesAttachedSent && areAllStreamsAttached())
528 : {
529 : // RialtoServer doesn't support dynamic source attachment.
530 : // It means that when we notify that all sources were attached, we cannot add any more sources in the current session
531 150 : GST_INFO("All sources attached");
532 150 : m_clientBackend->allSourcesAttached();
533 150 : m_wasAllSourcesAttachedSent = true;
534 150 : m_clientState = ClientState::READY;
535 :
536 : // In playbin3 streams, confirmation about number of available sources comes after attaching the source,
537 : // so we need to check if all sources are ready to pause
538 450 : if (checkIfAllAttachedSourcesInStates({ClientState::AWAITING_PAUSED}))
539 : {
540 1 : GST_INFO("Sending pause command, because all attached sources are ready to pause");
541 1 : m_clientBackend->pause();
542 1 : m_clientState = ClientState::AWAITING_PAUSED;
543 : }
544 : }
545 202 : }
546 :
547 147 : void GStreamerMSEMediaPlayerClient::removeSource(int32_t sourceId)
548 : {
549 294 : m_backendQueue->callInEventLoop(
550 147 : [&]()
551 : {
552 147 : if (!m_clientBackend->removeSource(sourceId))
553 : {
554 1 : GST_WARNING("Remove source %d failed", sourceId);
555 : }
556 147 : m_attachedSources.erase(sourceId);
557 147 : });
558 : }
559 :
560 57 : void GStreamerMSEMediaPlayerClient::handlePlaybackStateChange(firebolt::rialto::PlaybackState state)
561 : {
562 57 : GST_DEBUG("Received state change to state %u", static_cast<uint32_t>(state));
563 114 : m_backendQueue->callInEventLoop(
564 57 : [&]()
565 : {
566 57 : m_serverPlaybackState = state;
567 57 : switch (state)
568 : {
569 50 : case firebolt::rialto::PlaybackState::PAUSED:
570 : case firebolt::rialto::PlaybackState::PLAYING:
571 : {
572 50 : if (state == firebolt::rialto::PlaybackState::PAUSED && m_clientState == ClientState::AWAITING_PAUSED)
573 : {
574 37 : m_clientState = ClientState::PAUSED;
575 : }
576 13 : else if (state == firebolt::rialto::PlaybackState::PLAYING &&
577 11 : m_clientState == ClientState::AWAITING_PLAYING)
578 : {
579 8 : m_clientState = ClientState::PLAYING;
580 : }
581 5 : else if (state == firebolt::rialto::PlaybackState::PLAYING &&
582 3 : m_clientState == ClientState::AWAITING_PAUSED)
583 : {
584 1 : GST_WARNING("Outdated Playback State change to PLAYING received. Discarding...");
585 1 : break;
586 : }
587 :
588 108 : for (auto &source : m_attachedSources)
589 : {
590 59 : if (state == firebolt::rialto::PlaybackState::PAUSED &&
591 46 : source.second.m_state == ClientState::AWAITING_PAUSED)
592 : {
593 43 : source.second.m_state = ClientState::PAUSED;
594 : }
595 16 : else if (state == firebolt::rialto::PlaybackState::PLAYING &&
596 13 : source.second.m_state == ClientState::AWAITING_PLAYING)
597 : {
598 10 : source.second.m_state = ClientState::PLAYING;
599 : }
600 59 : source.second.m_delegate->handleStateChanged(state);
601 : }
602 :
603 49 : break;
604 : }
605 4 : case firebolt::rialto::PlaybackState::END_OF_STREAM:
606 : {
607 8 : for (const auto &source : m_attachedSources)
608 : {
609 4 : source.second.m_delegate->handleEos();
610 : }
611 : }
612 4 : break;
613 1 : case firebolt::rialto::PlaybackState::SEEK_DONE:
614 : {
615 1 : GST_WARNING("firebolt::rialto::PlaybackState::SEEK_DONE notification not supported");
616 1 : break;
617 : }
618 1 : case firebolt::rialto::PlaybackState::FAILURE:
619 : {
620 2 : for (const auto &source : m_attachedSources)
621 : {
622 1 : source.second.m_delegate->handleError("Rialto server playback failed");
623 : }
624 2 : for (auto &source : m_attachedSources)
625 : {
626 1 : source.second.m_position = 0;
627 : }
628 :
629 1 : break;
630 : }
631 : break;
632 1 : default:
633 1 : break;
634 : }
635 57 : });
636 : }
637 :
638 5 : void GStreamerMSEMediaPlayerClient::handleSourceFlushed(int32_t sourceId)
639 : {
640 10 : m_backendQueue->callInEventLoop(
641 5 : [&]()
642 : {
643 5 : auto sourceIt = m_attachedSources.find(sourceId);
644 5 : if (sourceIt == m_attachedSources.end())
645 : {
646 1 : GST_ERROR("Cannot finish flush - there's no attached source with id %d", sourceId);
647 2 : return;
648 : }
649 4 : if (!sourceIt->second.m_isFlushing)
650 : {
651 1 : GST_ERROR("Cannot finish flush - source with id %d is not flushing!", sourceId);
652 1 : return;
653 : }
654 3 : sourceIt->second.m_isFlushing = false;
655 3 : sourceIt->second.m_bufferPuller->start();
656 3 : sourceIt->second.m_delegate->handleFlushCompleted();
657 : });
658 5 : }
659 :
660 7 : void GStreamerMSEMediaPlayerClient::setVideoRectangle(const std::string &rectangleString)
661 : {
662 14 : m_backendQueue->callInEventLoop(
663 7 : [&]()
664 : {
665 7 : if (!m_clientBackend || !m_clientBackend->isMediaPlayerBackendCreated())
666 : {
667 1 : GST_WARNING("Missing RialtoClient backend - can't set video window now");
668 3 : return;
669 : }
670 :
671 6 : if (rectangleString.empty())
672 : {
673 1 : GST_WARNING("Empty video rectangle string");
674 1 : return;
675 : }
676 :
677 5 : Rectangle rect = {0, 0, 0, 0};
678 5 : if (sscanf(rectangleString.c_str(), "%u,%u,%u,%u", &rect.x, &rect.y, &rect.width, &rect.height) != 4)
679 : {
680 1 : GST_WARNING("Invalid video rectangle values");
681 1 : return;
682 : }
683 :
684 4 : m_clientBackend->setVideoWindow(rect.x, rect.y, rect.width, rect.height);
685 4 : m_videoRectangle = rect;
686 : });
687 7 : }
688 :
689 4 : std::string GStreamerMSEMediaPlayerClient::getVideoRectangle()
690 : {
691 : char rectangle[64];
692 8 : m_backendQueue->callInEventLoop(
693 8 : [&]()
694 : {
695 4 : sprintf(rectangle, "%u,%u,%u,%u", m_videoRectangle.x, m_videoRectangle.y, m_videoRectangle.width,
696 : m_videoRectangle.height);
697 4 : });
698 :
699 8 : return std::string(rectangle);
700 : }
701 :
702 4 : bool GStreamerMSEMediaPlayerClient::renderFrame(int32_t sourceId)
703 : {
704 4 : bool result = false;
705 8 : m_backendQueue->callInEventLoop(
706 4 : [&]()
707 : {
708 4 : result = m_clientBackend->renderFrame();
709 4 : if (result)
710 : {
711 : // RialtoServer's video sink should drop PAUSED state due to skipping prerolled buffer in PAUSED state
712 3 : auto sourceIt = m_attachedSources.find(sourceId);
713 3 : if (sourceIt != m_attachedSources.end())
714 : {
715 3 : sourceIt->second.m_delegate->lostState();
716 : }
717 : }
718 4 : });
719 4 : return result;
720 : }
721 :
722 6 : void GStreamerMSEMediaPlayerClient::setVolume(double targetVolume, uint32_t volumeDuration,
723 : firebolt::rialto::EaseType easeType)
724 : {
725 12 : m_backendQueue->callInEventLoop([&]() { m_clientBackend->setVolume(targetVolume, volumeDuration, easeType); });
726 6 : }
727 :
728 5 : bool GStreamerMSEMediaPlayerClient::getVolume(double &volume)
729 : {
730 5 : bool status{false};
731 10 : m_backendQueue->callInEventLoop([&]() { status = m_clientBackend->getVolume(volume); });
732 5 : return status;
733 : }
734 :
735 7 : void GStreamerMSEMediaPlayerClient::setMute(bool mute, int32_t sourceId)
736 : {
737 14 : m_backendQueue->callInEventLoop([&]() { m_clientBackend->setMute(mute, sourceId); });
738 7 : }
739 :
740 3 : bool GStreamerMSEMediaPlayerClient::getMute(int sourceId)
741 : {
742 3 : bool mute{false};
743 6 : m_backendQueue->callInEventLoop([&]() { m_clientBackend->getMute(mute, sourceId); });
744 :
745 3 : return mute;
746 : }
747 :
748 3 : void GStreamerMSEMediaPlayerClient::setTextTrackIdentifier(const std::string &textTrackIdentifier)
749 : {
750 6 : m_backendQueue->callInEventLoop([&]() { m_clientBackend->setTextTrackIdentifier(textTrackIdentifier); });
751 3 : }
752 :
753 2 : std::string GStreamerMSEMediaPlayerClient::getTextTrackIdentifier()
754 : {
755 2 : std::string getTextTrackIdentifier;
756 4 : m_backendQueue->callInEventLoop([&]() { m_clientBackend->getTextTrackIdentifier(getTextTrackIdentifier); });
757 2 : return getTextTrackIdentifier;
758 : }
759 :
760 6 : bool GStreamerMSEMediaPlayerClient::setLowLatency(bool lowLatency)
761 : {
762 6 : if (!m_clientBackend)
763 : {
764 1 : return false;
765 : }
766 :
767 5 : bool status{false};
768 10 : m_backendQueue->callInEventLoop([&]() { status = m_clientBackend->setLowLatency(lowLatency); });
769 5 : return status;
770 : }
771 :
772 6 : bool GStreamerMSEMediaPlayerClient::setSync(bool sync)
773 : {
774 6 : if (!m_clientBackend)
775 : {
776 1 : return false;
777 : }
778 :
779 5 : bool status{false};
780 10 : m_backendQueue->callInEventLoop([&]() { status = m_clientBackend->setSync(sync); });
781 5 : return status;
782 : }
783 :
784 4 : bool GStreamerMSEMediaPlayerClient::getSync(bool &sync)
785 : {
786 4 : if (!m_clientBackend)
787 : {
788 1 : return false;
789 : }
790 :
791 3 : bool status{false};
792 6 : m_backendQueue->callInEventLoop([&]() { status = m_clientBackend->getSync(sync); });
793 3 : return status;
794 : }
795 :
796 6 : bool GStreamerMSEMediaPlayerClient::setSyncOff(bool syncOff)
797 : {
798 6 : if (!m_clientBackend)
799 : {
800 1 : return false;
801 : }
802 :
803 5 : bool status{false};
804 10 : m_backendQueue->callInEventLoop([&]() { status = m_clientBackend->setSyncOff(syncOff); });
805 5 : return status;
806 : }
807 :
808 10 : bool GStreamerMSEMediaPlayerClient::setStreamSyncMode(int32_t sourceId, int32_t streamSyncMode)
809 : {
810 10 : if (!m_clientBackend)
811 : {
812 1 : return false;
813 : }
814 :
815 9 : bool status{false};
816 18 : m_backendQueue->callInEventLoop([&]() { status = m_clientBackend->setStreamSyncMode(sourceId, streamSyncMode); });
817 9 : return status;
818 : }
819 :
820 4 : bool GStreamerMSEMediaPlayerClient::getStreamSyncMode(int32_t &streamSyncMode)
821 : {
822 4 : if (!m_clientBackend)
823 : {
824 1 : return false;
825 : }
826 :
827 3 : bool status{false};
828 6 : m_backendQueue->callInEventLoop([&]() { status = m_clientBackend->getStreamSyncMode(streamSyncMode); });
829 3 : return status;
830 : }
831 :
832 39 : ClientState GStreamerMSEMediaPlayerClient::getClientState()
833 : {
834 39 : ClientState state{ClientState::IDLE};
835 39 : m_backendQueue->callInEventLoop([&]() { state = m_clientState; });
836 39 : return state;
837 : }
838 :
839 166 : void GStreamerMSEMediaPlayerClient::handleStreamCollection(int32_t audioStreams, int32_t videoStreams,
840 : int32_t subtitleStreams)
841 : {
842 332 : m_backendQueue->callInEventLoop(
843 166 : [&]()
844 : {
845 166 : if (m_audioStreams == UNKNOWN_STREAMS_NUMBER)
846 163 : m_audioStreams = audioStreams;
847 166 : if (m_videoStreams == UNKNOWN_STREAMS_NUMBER)
848 162 : m_videoStreams = videoStreams;
849 166 : if (m_subtitleStreams == UNKNOWN_STREAMS_NUMBER)
850 162 : m_subtitleStreams = subtitleStreams;
851 :
852 166 : GST_INFO("Updated number of streams. New streams' numbers; video=%d, audio=%d, text=%d", m_videoStreams,
853 : m_audioStreams, m_subtitleStreams);
854 166 : });
855 : }
856 :
857 3 : void GStreamerMSEMediaPlayerClient::setBufferingLimit(uint32_t limitBufferingMs)
858 : {
859 3 : if (!m_clientBackend)
860 : {
861 0 : return;
862 : }
863 6 : m_backendQueue->callInEventLoop([&]() { m_clientBackend->setBufferingLimit(limitBufferingMs); });
864 : }
865 :
866 2 : uint32_t GStreamerMSEMediaPlayerClient::getBufferingLimit()
867 : {
868 2 : if (!m_clientBackend)
869 : {
870 0 : return kDefaultBufferingLimit;
871 : }
872 :
873 2 : uint32_t result{kDefaultBufferingLimit};
874 4 : m_backendQueue->callInEventLoop([&]() { m_clientBackend->getBufferingLimit(result); });
875 2 : return result;
876 : }
877 :
878 3 : void GStreamerMSEMediaPlayerClient::setUseBuffering(bool useBuffering)
879 : {
880 3 : if (!m_clientBackend)
881 : {
882 0 : return;
883 : }
884 6 : m_backendQueue->callInEventLoop([&]() { m_clientBackend->setUseBuffering(useBuffering); });
885 : }
886 :
887 2 : bool GStreamerMSEMediaPlayerClient::getUseBuffering()
888 : {
889 2 : if (!m_clientBackend)
890 : {
891 0 : return kDefaultUseBuffering;
892 : }
893 :
894 2 : bool result{kDefaultUseBuffering};
895 4 : m_backendQueue->callInEventLoop([&]() { m_clientBackend->getUseBuffering(result); });
896 2 : return result;
897 : }
898 :
899 3 : bool GStreamerMSEMediaPlayerClient::switchSource(const std::unique_ptr<firebolt::rialto::IMediaPipeline::MediaSource> &source)
900 : {
901 3 : bool result = false;
902 6 : m_backendQueue->callInEventLoop([&]() { result = m_clientBackend->switchSource(source); });
903 :
904 3 : return result;
905 : }
906 :
907 320 : bool GStreamerMSEMediaPlayerClient::checkIfAllAttachedSourcesInStates(const std::vector<ClientState> &states)
908 : {
909 640 : return std::all_of(m_attachedSources.begin(), m_attachedSources.end(), [states](const auto &source)
910 973 : { return std::find(states.begin(), states.end(), source.second.m_state) != states.end(); });
911 : }
912 :
913 201 : bool GStreamerMSEMediaPlayerClient::areAllStreamsAttached()
914 : {
915 201 : int32_t attachedVideoSources = 0;
916 201 : int32_t attachedAudioSources = 0;
917 201 : int32_t attachedSubtitleSources = 0;
918 412 : for (auto &source : m_attachedSources)
919 : {
920 211 : if (source.second.getType() == firebolt::rialto::MediaSourceType::VIDEO)
921 : {
922 40 : attachedVideoSources++;
923 : }
924 171 : else if (source.second.getType() == firebolt::rialto::MediaSourceType::AUDIO)
925 : {
926 159 : attachedAudioSources++;
927 : }
928 12 : else if (source.second.getType() == firebolt::rialto::MediaSourceType::SUBTITLE)
929 : {
930 12 : attachedSubtitleSources++;
931 : }
932 : }
933 :
934 351 : return attachedVideoSources == m_videoStreams && attachedAudioSources == m_audioStreams &&
935 351 : attachedSubtitleSources == m_subtitleStreams;
936 : }
937 :
938 8 : bool GStreamerMSEMediaPlayerClient::requestPullBuffer(int streamId, size_t frameCount, unsigned int needDataRequestId)
939 : {
940 8 : bool result = false;
941 16 : m_backendQueue->callInEventLoop(
942 8 : [&]()
943 : {
944 8 : auto sourceIt = m_attachedSources.find(streamId);
945 8 : if (sourceIt == m_attachedSources.end())
946 : {
947 1 : GST_ERROR("There's no attached source with id %d", streamId);
948 :
949 1 : result = false;
950 1 : return;
951 : }
952 7 : result = sourceIt->second.m_bufferPuller->requestPullBuffer(streamId, frameCount, needDataRequestId, this);
953 : });
954 :
955 8 : return result;
956 : }
957 :
958 5 : bool GStreamerMSEMediaPlayerClient::handleQos(int sourceId, firebolt::rialto::QosInfo qosInfo)
959 : {
960 5 : bool result = false;
961 10 : m_backendQueue->callInEventLoop(
962 5 : [&]()
963 : {
964 5 : auto sourceIt = m_attachedSources.find(sourceId);
965 5 : if (sourceIt == m_attachedSources.end())
966 : {
967 1 : result = false;
968 1 : return;
969 : }
970 4 : sourceIt->second.m_delegate->handleQos(qosInfo.processed, qosInfo.dropped);
971 4 : result = true;
972 : });
973 :
974 5 : return result;
975 : }
976 :
977 2 : bool GStreamerMSEMediaPlayerClient::handleBufferUnderflow(int sourceId)
978 : {
979 2 : bool result = false;
980 4 : m_backendQueue->callInEventLoop(
981 2 : [&]()
982 : {
983 2 : auto sourceIt = m_attachedSources.find(sourceId);
984 2 : if (sourceIt == m_attachedSources.end())
985 : {
986 1 : result = false;
987 1 : return;
988 : }
989 :
990 1 : rialto_mse_base_handle_rialto_server_sent_buffer_underflow(sourceIt->second.m_rialtoSink);
991 :
992 1 : result = true;
993 : });
994 :
995 2 : return result;
996 : }
997 :
998 5 : bool GStreamerMSEMediaPlayerClient::handlePlaybackError(int sourceId, firebolt::rialto::PlaybackError error)
999 : {
1000 5 : bool result = false;
1001 10 : m_backendQueue->callInEventLoop(
1002 5 : [&]()
1003 : {
1004 5 : auto sourceIt = m_attachedSources.find(sourceId);
1005 5 : if (sourceIt == m_attachedSources.end())
1006 : {
1007 1 : result = false;
1008 1 : return;
1009 : }
1010 :
1011 : // Even though rialto has only reported a non-fatal error, still fail the pipeline from rialto-gstreamer
1012 4 : GST_ERROR("Received Playback error '%s', posting error on %s sink", toString(error),
1013 : toString(sourceIt->second.getType()));
1014 4 : if (firebolt::rialto::PlaybackError::DECRYPTION == error)
1015 : {
1016 2 : sourceIt->second.m_delegate->handleError("Rialto dropped a frame that failed to decrypt",
1017 : GST_STREAM_ERROR_DECRYPT);
1018 : }
1019 : else
1020 : {
1021 2 : sourceIt->second.m_delegate->handleError("Rialto server playback failed");
1022 : }
1023 :
1024 4 : result = true;
1025 : });
1026 :
1027 5 : return result;
1028 : }
1029 :
1030 4 : firebolt::rialto::AddSegmentStatus GStreamerMSEMediaPlayerClient::addSegment(
1031 : unsigned int needDataRequestId, const std::unique_ptr<firebolt::rialto::IMediaPipeline::MediaSegment> &mediaSegment)
1032 : {
1033 : // rialto client's addSegment call is MT safe, so it's ok to call it from the Puller's thread
1034 4 : return m_clientBackend->addSegment(needDataRequestId, mediaSegment);
1035 : }
1036 :
1037 197 : BufferPuller::BufferPuller(const std::shared_ptr<IMessageQueueFactory> &messageQueueFactory, GstElement *rialtoSink,
1038 : const std::shared_ptr<BufferParser> &bufferParser,
1039 197 : const std::shared_ptr<IPullModePlaybackDelegate> &delegate)
1040 197 : : m_queue{messageQueueFactory->createMessageQueue()}, m_rialtoSink(rialtoSink), m_bufferParser(bufferParser),
1041 197 : m_delegate{delegate}
1042 : {
1043 : }
1044 :
1045 200 : void BufferPuller::start()
1046 : {
1047 200 : m_queue->start();
1048 : }
1049 :
1050 64 : void BufferPuller::stop()
1051 : {
1052 64 : m_queue->stop();
1053 : }
1054 :
1055 7 : bool BufferPuller::requestPullBuffer(int sourceId, size_t frameCount, unsigned int needDataRequestId,
1056 : GStreamerMSEMediaPlayerClient *player)
1057 : {
1058 21 : return m_queue->postMessage(std::make_shared<PullBufferMessage>(sourceId, frameCount, needDataRequestId, m_rialtoSink,
1059 21 : m_bufferParser, *m_queue, player, m_delegate));
1060 : }
1061 :
1062 8 : HaveDataMessage::HaveDataMessage(firebolt::rialto::MediaSourceStatus status, int sourceId,
1063 8 : unsigned int needDataRequestId, GStreamerMSEMediaPlayerClient *player)
1064 8 : : m_status(status), m_sourceId(sourceId), m_needDataRequestId(needDataRequestId), m_player(player)
1065 : {
1066 : }
1067 :
1068 8 : void HaveDataMessage::handle()
1069 : {
1070 8 : if (m_player->m_attachedSources.find(m_sourceId) == m_player->m_attachedSources.end())
1071 : {
1072 1 : GST_WARNING("Source id %d is invalid", m_sourceId);
1073 1 : return;
1074 : }
1075 :
1076 7 : m_player->m_clientBackend->haveData(m_status, m_needDataRequestId);
1077 : }
1078 :
1079 7 : PullBufferMessage::PullBufferMessage(int sourceId, size_t frameCount, unsigned int needDataRequestId,
1080 : GstElement *rialtoSink, const std::shared_ptr<BufferParser> &bufferParser,
1081 : IMessageQueue &pullerQueue, GStreamerMSEMediaPlayerClient *player,
1082 7 : const std::shared_ptr<IPullModePlaybackDelegate> &delegate)
1083 7 : : m_sourceId(sourceId), m_frameCount(frameCount), m_needDataRequestId(needDataRequestId), m_rialtoSink(rialtoSink),
1084 7 : m_bufferParser(bufferParser), m_pullerQueue(pullerQueue), m_player(player), m_delegate{delegate}
1085 : {
1086 : }
1087 :
1088 6 : void PullBufferMessage::handle()
1089 : {
1090 6 : bool isEos = false;
1091 6 : unsigned int addedSegments = 0;
1092 :
1093 8 : for (unsigned int frame = 0; frame < m_frameCount; ++frame)
1094 : {
1095 6 : GstRefSample sample = m_delegate->getFrontSample();
1096 6 : if (!sample)
1097 : {
1098 3 : if (m_delegate->isEos())
1099 : {
1100 1 : isEos = true;
1101 : }
1102 : else
1103 : {
1104 : // it's not a critical issue. It might be caused by receiving too many need data requests.
1105 2 : GST_INFO_OBJECT(m_rialtoSink, "Could not get a sample");
1106 : }
1107 3 : break;
1108 : }
1109 :
1110 : // we pass GstMapInfo's pointers on data buffers to RialtoClient
1111 : // so we need to hold it until RialtoClient copies them to shm
1112 3 : GstBuffer *buffer = sample.getBuffer();
1113 : GstMapInfo map;
1114 3 : if (!gst_buffer_map(buffer, &map, GST_MAP_READ))
1115 : {
1116 0 : GST_ERROR_OBJECT(m_rialtoSink, "Could not map buffer");
1117 0 : m_delegate->popSample();
1118 0 : continue;
1119 : }
1120 :
1121 : std::unique_ptr<firebolt::rialto::IMediaPipeline::MediaSegment> mseData =
1122 3 : m_bufferParser->parseBuffer(sample, buffer, map, m_sourceId);
1123 3 : if (!mseData)
1124 : {
1125 0 : GST_ERROR_OBJECT(m_rialtoSink, "No data returned from the parser");
1126 0 : gst_buffer_unmap(buffer, &map);
1127 0 : m_delegate->popSample();
1128 0 : continue;
1129 : }
1130 :
1131 3 : firebolt::rialto::AddSegmentStatus addSegmentStatus = m_player->addSegment(m_needDataRequestId, mseData);
1132 3 : if (addSegmentStatus == firebolt::rialto::AddSegmentStatus::NO_SPACE)
1133 : {
1134 1 : gst_buffer_unmap(buffer, &map);
1135 1 : GST_INFO_OBJECT(m_rialtoSink, "There's no space to add sample");
1136 1 : break;
1137 : }
1138 :
1139 2 : gst_buffer_unmap(buffer, &map);
1140 2 : m_delegate->popSample();
1141 2 : addedSegments++;
1142 7 : }
1143 :
1144 6 : firebolt::rialto::MediaSourceStatus status = firebolt::rialto::MediaSourceStatus::OK;
1145 6 : if (isEos)
1146 : {
1147 1 : status = firebolt::rialto::MediaSourceStatus::EOS;
1148 : }
1149 5 : else if (addedSegments == 0)
1150 : {
1151 3 : status = firebolt::rialto::MediaSourceStatus::NO_AVAILABLE_SAMPLES;
1152 : }
1153 :
1154 12 : m_player->m_backendQueue->postMessage(
1155 12 : std::make_shared<HaveDataMessage>(status, m_sourceId, m_needDataRequestId, m_player));
1156 6 : }
1157 :
1158 8 : NeedDataMessage::NeedDataMessage(int sourceId, size_t frameCount, unsigned int needDataRequestId,
1159 8 : GStreamerMSEMediaPlayerClient *player)
1160 8 : : m_sourceId(sourceId), m_frameCount(frameCount), m_needDataRequestId(needDataRequestId), m_player(player)
1161 : {
1162 : }
1163 :
1164 8 : void NeedDataMessage::handle()
1165 : {
1166 8 : if (!m_player->requestPullBuffer(m_sourceId, m_frameCount, m_needDataRequestId))
1167 : {
1168 2 : GST_ERROR("Failed to pull buffer for sourceId=%d and NeedDataRequestId %u", m_sourceId, m_needDataRequestId);
1169 4 : m_player->m_backendQueue->postMessage(
1170 2 : std::make_shared<HaveDataMessage>(firebolt::rialto::MediaSourceStatus::ERROR, m_sourceId,
1171 2 : m_needDataRequestId, m_player));
1172 : }
1173 8 : }
1174 :
1175 57 : PlaybackStateMessage::PlaybackStateMessage(firebolt::rialto::PlaybackState state, GStreamerMSEMediaPlayerClient *player)
1176 57 : : m_state(state), m_player(player)
1177 : {
1178 : }
1179 :
1180 57 : void PlaybackStateMessage::handle()
1181 : {
1182 57 : m_player->handlePlaybackStateChange(m_state);
1183 : }
1184 :
1185 5 : QosMessage::QosMessage(int sourceId, firebolt::rialto::QosInfo qosInfo, GStreamerMSEMediaPlayerClient *player)
1186 5 : : m_sourceId(sourceId), m_qosInfo(qosInfo), m_player(player)
1187 : {
1188 : }
1189 :
1190 5 : void QosMessage::handle()
1191 : {
1192 5 : if (!m_player->handleQos(m_sourceId, m_qosInfo))
1193 : {
1194 1 : GST_ERROR("Failed to handle qos for sourceId=%d", m_sourceId);
1195 : }
1196 5 : }
1197 :
1198 2 : BufferUnderflowMessage::BufferUnderflowMessage(int sourceId, GStreamerMSEMediaPlayerClient *player)
1199 2 : : m_sourceId(sourceId), m_player(player)
1200 : {
1201 : }
1202 :
1203 2 : void BufferUnderflowMessage::handle()
1204 : {
1205 2 : if (!m_player->handleBufferUnderflow(m_sourceId))
1206 : {
1207 1 : GST_ERROR("Failed to handle buffer underflow for sourceId=%d", m_sourceId);
1208 : }
1209 2 : }
1210 :
1211 5 : PlaybackErrorMessage::PlaybackErrorMessage(int sourceId, firebolt::rialto::PlaybackError error,
1212 5 : GStreamerMSEMediaPlayerClient *player)
1213 5 : : m_sourceId(sourceId), m_error(error), m_player(player)
1214 : {
1215 : }
1216 :
1217 5 : void PlaybackErrorMessage::handle()
1218 : {
1219 5 : if (!m_player->handlePlaybackError(m_sourceId, m_error))
1220 : {
1221 1 : GST_ERROR("Failed to handle playback error for sourceId=%d, error %s", m_sourceId, toString(m_error));
1222 : }
1223 5 : }
1224 :
1225 1 : SetPositionMessage::SetPositionMessage(int64_t newPosition, std::unordered_map<int32_t, AttachedSource> &attachedSources)
1226 1 : : m_newPosition(newPosition), m_attachedSources(attachedSources)
1227 : {
1228 : }
1229 :
1230 1 : void SetPositionMessage::handle()
1231 : {
1232 2 : for (auto &source : m_attachedSources)
1233 : {
1234 1 : source.second.setPosition(m_newPosition);
1235 : }
1236 : }
1237 :
1238 1 : SetDurationMessage::SetDurationMessage(int64_t newDuration, int64_t &targetDuration)
1239 1 : : m_newDuration(newDuration), m_targetDuration(targetDuration)
1240 : {
1241 : }
1242 :
1243 1 : void SetDurationMessage::handle()
1244 : {
1245 1 : m_targetDuration = m_newDuration;
1246 : }
1247 :
1248 5 : SourceFlushedMessage::SourceFlushedMessage(int32_t sourceId, GStreamerMSEMediaPlayerClient *player)
1249 5 : : m_sourceId{sourceId}, m_player{player}
1250 : {
1251 : }
1252 :
1253 5 : void SourceFlushedMessage::handle()
1254 : {
1255 5 : m_player->handleSourceFlushed(m_sourceId);
1256 : }
|