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