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