Line data Source code
1 : /*
2 : * If not stated otherwise in this file or this component's LICENSE file the
3 : * following copyright and licenses apply:
4 : *
5 : * Copyright 2022 Sky UK
6 : *
7 : * Licensed under the Apache License, Version 2.0 (the "License");
8 : * you may not use this file except in compliance with the License.
9 : * You may obtain a copy of the License at
10 : *
11 : * http://www.apache.org/licenses/LICENSE-2.0
12 : *
13 : * Unless required by applicable law or agreed to in writing, software
14 : * distributed under the License is distributed on an "AS IS" BASIS,
15 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 : * See the License for the specific language governing permissions and
17 : * limitations under the License.
18 : */
19 :
20 : #include <inttypes.h>
21 : #include <stdexcept>
22 : #include <stdint.h>
23 :
24 : #include "KeyIdMap.h"
25 : #include "MediaPipeline.h"
26 : #include "MediaPipelineProxy.h"
27 : #include "RialtoClientLogging.h"
28 :
29 : namespace
30 : {
31 155 : const char *toString(const firebolt::rialto::client::MediaPipeline::State &state)
32 : {
33 155 : switch (state)
34 : {
35 49 : case firebolt::rialto::client::MediaPipeline::State::IDLE:
36 49 : return "IDLE";
37 8 : case firebolt::rialto::client::MediaPipeline::State::BUFFERING:
38 8 : return "BUFFERING";
39 72 : case firebolt::rialto::client::MediaPipeline::State::PLAYING:
40 72 : return "PLAYING";
41 8 : case firebolt::rialto::client::MediaPipeline::State::SEEKING:
42 8 : return "SEEKING";
43 8 : case firebolt::rialto::client::MediaPipeline::State::FAILURE:
44 8 : return "FAILURE";
45 10 : case firebolt::rialto::client::MediaPipeline::State::END_OF_STREAM:
46 10 : return "END_OF_STREAM";
47 : }
48 0 : return "UNKNOWN";
49 : }
50 :
51 68 : const char *toString(const firebolt::rialto::PlaybackState &state)
52 : {
53 68 : switch (state)
54 : {
55 1 : case firebolt::rialto::PlaybackState::IDLE:
56 1 : return "IDLE";
57 50 : case firebolt::rialto::PlaybackState::PLAYING:
58 50 : return "PLAYING";
59 0 : case firebolt::rialto::PlaybackState::PAUSED:
60 0 : return "PAUSED";
61 4 : case firebolt::rialto::PlaybackState::SEEKING:
62 4 : return "SEEKING";
63 3 : case firebolt::rialto::PlaybackState::SEEK_DONE:
64 3 : return "SEEK_DONE";
65 3 : case firebolt::rialto::PlaybackState::STOPPED:
66 3 : return "STOPPED";
67 4 : case firebolt::rialto::PlaybackState::END_OF_STREAM:
68 4 : return "END_OF_STREAM";
69 3 : case firebolt::rialto::PlaybackState::FAILURE:
70 3 : return "FAILURE";
71 0 : case firebolt::rialto::PlaybackState::UNKNOWN:
72 0 : return "UNKNOWN";
73 : }
74 0 : return "UNKNOWN";
75 : }
76 :
77 4 : const char *toString(const firebolt::rialto::NetworkState &state)
78 : {
79 4 : switch (state)
80 : {
81 1 : case firebolt::rialto::NetworkState::IDLE:
82 1 : return "IDLE";
83 3 : case firebolt::rialto::NetworkState::BUFFERING:
84 3 : return "BUFFERING";
85 0 : case firebolt::rialto::NetworkState::BUFFERING_PROGRESS:
86 0 : return "BUFFERING_PROGRESS";
87 0 : case firebolt::rialto::NetworkState::BUFFERED:
88 0 : return "BUFFERED";
89 0 : case firebolt::rialto::NetworkState::STALLED:
90 0 : return "STALLED";
91 0 : case firebolt::rialto::NetworkState::FORMAT_ERROR:
92 0 : return "FORMAT_ERROR";
93 0 : case firebolt::rialto::NetworkState::NETWORK_ERROR:
94 0 : return "NETWORK_ERROR";
95 0 : case firebolt::rialto::NetworkState::DECODE_ERROR:
96 0 : return "DECODE_ERROR";
97 0 : case firebolt::rialto::NetworkState::UNKNOWN:
98 0 : return "UNKNOWN";
99 : }
100 0 : return "UNKNOWN";
101 : }
102 : } // namespace
103 :
104 : namespace firebolt::rialto
105 : {
106 3 : std::shared_ptr<IMediaPipelineFactory> IMediaPipelineFactory::createFactory()
107 : {
108 3 : std::shared_ptr<IMediaPipelineFactory> factory;
109 :
110 : try
111 : {
112 3 : factory = std::make_shared<MediaPipelineFactory>();
113 : }
114 0 : catch (const std::exception &e)
115 : {
116 0 : RIALTO_CLIENT_LOG_ERROR("Failed to create the media player factory, reason: %s", e.what());
117 : }
118 :
119 3 : return factory;
120 : }
121 :
122 0 : std::unique_ptr<IMediaPipeline> MediaPipelineFactory::createMediaPipeline(std::weak_ptr<IMediaPipelineClient> client,
123 : const VideoRequirements &videoRequirements) const
124 : {
125 0 : return createMediaPipeline(client, videoRequirements, {}, {});
126 : }
127 :
128 : std::unique_ptr<IMediaPipeline>
129 3 : MediaPipelineFactory::createMediaPipeline(std::weak_ptr<IMediaPipelineClient> client,
130 : const VideoRequirements &videoRequirements,
131 : std::weak_ptr<client::IMediaPipelineIpcFactory> mediaPipelineIpcFactory,
132 : std::weak_ptr<client::IClientController> clientController) const
133 : {
134 3 : std::unique_ptr<IMediaPipeline> mediaPipeline;
135 : try
136 : {
137 3 : std::shared_ptr<client::IMediaPipelineIpcFactory> mediaPipelineIpcFactoryLocked = mediaPipelineIpcFactory.lock();
138 3 : std::shared_ptr<client::IClientController> clientControllerLocked = clientController.lock();
139 : firebolt::rialto::client::IClientController &cc =
140 3 : clientControllerLocked ? *clientControllerLocked
141 0 : : client::IClientControllerAccessor::instance().getClientController();
142 :
143 : auto mp{std::make_shared<client::MediaPipeline>(client, videoRequirements,
144 3 : mediaPipelineIpcFactoryLocked
145 7 : ? mediaPipelineIpcFactoryLocked
146 : : client::IMediaPipelineIpcFactory::getFactory(),
147 10 : common::IMediaFrameWriterFactory::getFactory(), cc)};
148 2 : mediaPipeline = std::move(std::make_unique<client::MediaPipelineProxy>(mp, cc));
149 6 : }
150 2 : catch (const std::exception &e)
151 : {
152 2 : RIALTO_CLIENT_LOG_ERROR("Failed to create the media player, reason: %s", e.what());
153 : }
154 :
155 3 : return mediaPipeline;
156 : }
157 :
158 : }; // namespace firebolt::rialto
159 :
160 : namespace firebolt::rialto::client
161 : {
162 5 : MediaPipelineProxy::MediaPipelineProxy(const std::shared_ptr<IMediaPipelineAndIControlClient> &mediaPipeline,
163 5 : IClientController &clientController)
164 5 : : m_mediaPipeline{mediaPipeline}, m_clientController{clientController}
165 : {
166 5 : ApplicationState state{ApplicationState::UNKNOWN};
167 5 : if (!m_clientController.registerClient(m_mediaPipeline, state))
168 : {
169 2 : throw std::runtime_error("Failed to register client with clientController");
170 : }
171 3 : m_mediaPipeline->notifyApplicationState(state);
172 7 : }
173 :
174 5 : MediaPipelineProxy::~MediaPipelineProxy()
175 : {
176 3 : if (!m_clientController.unregisterClient(m_mediaPipeline))
177 : {
178 0 : RIALTO_CLIENT_LOG_WARN("Failed to unregister client with clientController");
179 : }
180 5 : }
181 :
182 120 : MediaPipeline::MediaPipeline(std::weak_ptr<IMediaPipelineClient> client, const VideoRequirements &videoRequirements,
183 : const std::shared_ptr<IMediaPipelineIpcFactory> &mediaPipelineIpcFactory,
184 : const std::shared_ptr<common::IMediaFrameWriterFactory> &mediaFrameWriterFactory,
185 120 : IClientController &clientController)
186 360 : : m_mediaPipelineClient(client), m_clientController{clientController}, m_currentAppState{ApplicationState::UNKNOWN},
187 120 : m_mediaFrameWriterFactory(mediaFrameWriterFactory), m_currentState(State::IDLE), m_attachingSource(false)
188 : {
189 120 : RIALTO_CLIENT_LOG_DEBUG("entry:");
190 :
191 120 : m_mediaPipelineIpc = mediaPipelineIpcFactory->createMediaPipelineIpc(this, videoRequirements);
192 :
193 120 : if (!m_mediaPipelineIpc)
194 : {
195 2 : throw std::runtime_error("Media player ipc could not be created");
196 : }
197 134 : }
198 :
199 234 : MediaPipeline::~MediaPipeline()
200 : {
201 118 : RIALTO_CLIENT_LOG_DEBUG("entry:");
202 :
203 118 : m_mediaPipelineIpc.reset();
204 234 : }
205 :
206 2 : bool MediaPipeline::load(MediaType type, const std::string &mimeType, const std::string &url, bool isLive)
207 : {
208 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
209 :
210 2 : return m_mediaPipelineIpc->load(type, mimeType, url, isLive);
211 : }
212 :
213 39 : bool MediaPipeline::attachSource(const std::unique_ptr<IMediaPipeline::MediaSource> &source)
214 : {
215 39 : RIALTO_CLIENT_LOG_DEBUG("entry:");
216 :
217 : // We should not process needDatas while attach source is ongoing
218 : {
219 39 : std::unique_lock<std::mutex> lock{m_attachSourceMutex};
220 39 : m_attachingSource = true;
221 : }
222 :
223 39 : int32_t sourceId = -1;
224 :
225 39 : bool status = m_mediaPipelineIpc->attachSource(source, sourceId);
226 39 : if (status)
227 : {
228 38 : source->setId(sourceId);
229 38 : m_attachedSources.add(sourceId, source->getType());
230 : }
231 :
232 : // Unblock needDatas
233 : {
234 39 : std::unique_lock<std::mutex> lock{m_attachSourceMutex};
235 39 : m_attachingSource = false;
236 39 : m_attachSourceCond.notify_all();
237 : }
238 39 : return status;
239 : }
240 :
241 5 : bool MediaPipeline::removeSource(int32_t id)
242 : {
243 5 : RIALTO_CLIENT_LOG_DEBUG("entry:");
244 5 : m_attachedSources.remove(id);
245 5 : return m_mediaPipelineIpc->removeSource(id);
246 : }
247 :
248 2 : bool MediaPipeline::allSourcesAttached()
249 : {
250 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
251 :
252 2 : return m_mediaPipelineIpc->allSourcesAttached();
253 : }
254 :
255 2 : bool MediaPipeline::play(bool &async)
256 : {
257 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
258 :
259 2 : return m_mediaPipelineIpc->play(async);
260 : }
261 :
262 2 : bool MediaPipeline::pause()
263 : {
264 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
265 :
266 2 : return m_mediaPipelineIpc->pause();
267 : }
268 :
269 0 : bool MediaPipeline::stop()
270 : {
271 0 : RIALTO_CLIENT_LOG_DEBUG("entry:");
272 :
273 0 : m_currentState = State::IDLE;
274 :
275 0 : return m_mediaPipelineIpc->stop();
276 : }
277 :
278 2 : bool MediaPipeline::setPlaybackRate(double rate)
279 : {
280 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
281 :
282 2 : return m_mediaPipelineIpc->setPlaybackRate(rate);
283 : }
284 :
285 7 : bool MediaPipeline::setPosition(int64_t position)
286 : {
287 7 : switch (m_currentState)
288 : {
289 5 : case State::PLAYING:
290 : case State::BUFFERING:
291 : case State::SEEKING:
292 : case State::END_OF_STREAM:
293 : {
294 5 : return handleSetPosition(position);
295 : }
296 2 : case State::IDLE:
297 : case State::FAILURE:
298 : default:
299 : {
300 2 : RIALTO_CLIENT_LOG_WARN("SetPosition received in unexpected state '%s'", toString(m_currentState));
301 2 : return false;
302 : }
303 : }
304 : }
305 :
306 2 : bool MediaPipeline::getPosition(int64_t &position)
307 : {
308 2 : return m_mediaPipelineIpc->getPosition(position);
309 : }
310 :
311 2 : bool MediaPipeline::setImmediateOutput(int32_t sourceId, bool immediateOutput)
312 : {
313 2 : return m_mediaPipelineIpc->setImmediateOutput(sourceId, immediateOutput);
314 : }
315 :
316 2 : bool MediaPipeline::getImmediateOutput(int32_t sourceId, bool &immediateOutput)
317 : {
318 2 : return m_mediaPipelineIpc->getImmediateOutput(sourceId, immediateOutput);
319 : }
320 :
321 2 : bool MediaPipeline::getStats(int32_t sourceId, uint64_t &renderedFrames, uint64_t &droppedFrames)
322 : {
323 2 : return m_mediaPipelineIpc->getStats(sourceId, renderedFrames, droppedFrames);
324 : }
325 :
326 5 : bool MediaPipeline::handleSetPosition(int64_t position)
327 : {
328 : // needData requests no longer valid
329 : {
330 5 : std::lock_guard<std::mutex> lock{m_needDataRequestMapMutex};
331 5 : m_needDataRequestMap.clear();
332 : }
333 5 : return m_mediaPipelineIpc->setPosition(position);
334 : }
335 :
336 2 : bool MediaPipeline::setVideoWindow(uint32_t x, uint32_t y, uint32_t width, uint32_t height)
337 : {
338 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
339 :
340 2 : return m_mediaPipelineIpc->setVideoWindow(x, y, width, height);
341 : }
342 :
343 27 : bool MediaPipeline::haveData(MediaSourceStatus status, uint32_t needDataRequestId)
344 : {
345 27 : RIALTO_CLIENT_LOG_DEBUG("entry:");
346 :
347 27 : switch (m_currentState)
348 : {
349 22 : case State::BUFFERING:
350 : case State::PLAYING:
351 : {
352 22 : return handleHaveData(status, needDataRequestId);
353 : }
354 2 : case State::SEEKING:
355 : {
356 2 : RIALTO_CLIENT_LOG_INFO("HaveData received while seeking, discarding NeedData request %u", needDataRequestId);
357 2 : discardNeedDataRequest(needDataRequestId);
358 2 : return true;
359 : }
360 3 : case State::IDLE:
361 : case State::END_OF_STREAM:
362 : case State::FAILURE:
363 : default:
364 : {
365 3 : RIALTO_CLIENT_LOG_WARN("HaveData received in unexpected state '%s', discarding NeedData request %u",
366 : toString(m_currentState), needDataRequestId);
367 3 : discardNeedDataRequest(needDataRequestId);
368 3 : return false;
369 : }
370 : }
371 : }
372 :
373 22 : bool MediaPipeline::handleHaveData(MediaSourceStatus status, uint32_t needDataRequestId)
374 : {
375 22 : RIALTO_CLIENT_LOG_DEBUG("entry:");
376 :
377 22 : std::shared_ptr<NeedDataRequest> needDataRequest;
378 :
379 : // Find the needDataRequest for this needDataRequestId
380 : // The needData request can be cancelled from another thread
381 : {
382 22 : std::lock_guard<std::mutex> lock{m_needDataRequestMapMutex};
383 :
384 22 : auto needDataRequestIt = m_needDataRequestMap.find(needDataRequestId);
385 22 : if (needDataRequestIt == m_needDataRequestMap.end())
386 : {
387 : // Return success here as the data written is just ignored
388 19 : RIALTO_CLIENT_LOG_WARN("Could not find need data request, with id %u", needDataRequestId);
389 19 : return true;
390 : }
391 :
392 3 : needDataRequest = needDataRequestIt->second;
393 3 : m_needDataRequestMap.erase(needDataRequestIt);
394 22 : }
395 3 : if (m_attachedSources.isFlushing(needDataRequest->sourceId))
396 : {
397 0 : RIALTO_CLIENT_LOG_WARN("Source %d is flushing. Ignoring need data request, with id %u",
398 : needDataRequest->sourceId, needDataRequestId);
399 0 : return true;
400 : }
401 :
402 3 : uint32_t numFrames = needDataRequest->frameWriter ? needDataRequest->frameWriter->getNumFrames() : 0;
403 3 : return m_mediaPipelineIpc->haveData(status, numFrames, needDataRequestId);
404 22 : }
405 :
406 53 : AddSegmentStatus MediaPipeline::addSegment(uint32_t needDataRequestId, const std::unique_ptr<MediaSegment> &mediaSegment)
407 : {
408 53 : RIALTO_CLIENT_LOG_DEBUG("entry:");
409 :
410 53 : if (nullptr == mediaSegment || nullptr == mediaSegment->getData())
411 : {
412 2 : return AddSegmentStatus::ERROR;
413 : }
414 :
415 51 : std::lock_guard<std::mutex> lock{m_needDataRequestMapMutex};
416 51 : auto needDataRequestIt = m_needDataRequestMap.find(needDataRequestId);
417 51 : if (needDataRequestIt == m_needDataRequestMap.end())
418 : {
419 0 : RIALTO_CLIENT_LOG_ERROR("Could not find need data request, with id %u", needDataRequestId);
420 0 : return AddSegmentStatus::ERROR;
421 : }
422 :
423 51 : std::shared_ptr<NeedDataRequest> needDataRequest = needDataRequestIt->second;
424 51 : std::shared_ptr<ISharedMemoryHandle> shmHandle = m_clientController.getSharedMemoryHandle();
425 51 : if (nullptr == shmHandle || nullptr == shmHandle->getShm())
426 : {
427 2 : RIALTO_CLIENT_LOG_ERROR("Shared buffer no longer valid");
428 2 : return AddSegmentStatus::ERROR;
429 : }
430 :
431 : // This block of code is only for playready apps using rialto c++ interface
432 : // Widevine apps and playready apps using rialto-ocdm set MediaSegment::keyId earlier
433 49 : if (mediaSegment->isEncrypted())
434 : {
435 2 : auto keyId = KeyIdMap::instance().get(mediaSegment->getMediaKeySessionId());
436 2 : if (!keyId.empty() && mediaSegment->getKeyId().empty())
437 : {
438 1 : RIALTO_CLIENT_LOG_DEBUG("Adding Playready keyID to media segment");
439 1 : mediaSegment->setKeyId(keyId);
440 : }
441 2 : }
442 :
443 49 : if (!needDataRequest->frameWriter)
444 : {
445 17 : if (firebolt::rialto::MediaSourceType::UNKNOWN != mediaSegment->getType())
446 : {
447 16 : needDataRequest->frameWriter =
448 32 : m_mediaFrameWriterFactory->createFrameWriter(shmHandle->getShm(), needDataRequest->shmInfo);
449 : }
450 : else
451 : {
452 1 : RIALTO_CLIENT_LOG_ERROR("Unrecognised type %u", static_cast<uint32_t>(mediaSegment->getType()));
453 1 : return AddSegmentStatus::ERROR;
454 : }
455 :
456 16 : if (!needDataRequest->frameWriter)
457 : {
458 1 : RIALTO_CLIENT_LOG_ERROR("Could not create frame writer");
459 1 : return AddSegmentStatus::ERROR;
460 : }
461 : }
462 :
463 47 : return needDataRequest->frameWriter->writeFrame(mediaSegment);
464 51 : }
465 :
466 2 : bool MediaPipeline::renderFrame()
467 : {
468 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
469 2 : return m_mediaPipelineIpc->renderFrame();
470 : }
471 :
472 3 : bool MediaPipeline::setVolume(double targetVolume, uint32_t volumeDuration, EaseType easeType)
473 : {
474 3 : RIALTO_CLIENT_LOG_DEBUG("entry:");
475 3 : return m_mediaPipelineIpc->setVolume(targetVolume, volumeDuration, easeType);
476 : }
477 :
478 2 : bool MediaPipeline::getVolume(double ¤tVolume)
479 : {
480 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
481 2 : return m_mediaPipelineIpc->getVolume(currentVolume);
482 : }
483 :
484 2 : bool MediaPipeline::setMute(int32_t sourceId, bool mute)
485 : {
486 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
487 2 : return m_mediaPipelineIpc->setMute(sourceId, mute);
488 : }
489 :
490 2 : bool MediaPipeline::getMute(int32_t sourceId, bool &mute)
491 : {
492 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
493 2 : return m_mediaPipelineIpc->getMute(sourceId, mute);
494 : }
495 :
496 2 : bool MediaPipeline::setTextTrackIdentifier(const std::string &textTrackIdentifier)
497 : {
498 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
499 2 : return m_mediaPipelineIpc->setTextTrackIdentifier(textTrackIdentifier);
500 : }
501 :
502 2 : bool MediaPipeline::getTextTrackIdentifier(std::string &textTrackIdentifier)
503 : {
504 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
505 2 : return m_mediaPipelineIpc->getTextTrackIdentifier(textTrackIdentifier);
506 : }
507 :
508 2 : bool MediaPipeline::setLowLatency(bool lowLatency)
509 : {
510 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
511 2 : return m_mediaPipelineIpc->setLowLatency(lowLatency);
512 : }
513 :
514 2 : bool MediaPipeline::setSync(bool sync)
515 : {
516 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
517 2 : return m_mediaPipelineIpc->setSync(sync);
518 : }
519 :
520 2 : bool MediaPipeline::getSync(bool &sync)
521 : {
522 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
523 2 : return m_mediaPipelineIpc->getSync(sync);
524 : }
525 :
526 2 : bool MediaPipeline::setSyncOff(bool syncOff)
527 : {
528 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
529 2 : return m_mediaPipelineIpc->setSyncOff(syncOff);
530 : }
531 :
532 2 : bool MediaPipeline::setStreamSyncMode(int32_t sourceId, int32_t streamSyncMode)
533 : {
534 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
535 2 : return m_mediaPipelineIpc->setStreamSyncMode(sourceId, streamSyncMode);
536 : }
537 :
538 2 : bool MediaPipeline::getStreamSyncMode(int32_t &streamSyncMode)
539 : {
540 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
541 2 : return m_mediaPipelineIpc->getStreamSyncMode(streamSyncMode);
542 : }
543 :
544 7 : bool MediaPipeline::flush(int32_t sourceId, bool resetTime, bool &async)
545 : {
546 7 : RIALTO_CLIENT_LOG_DEBUG("entry:");
547 :
548 : {
549 7 : std::unique_lock<std::mutex> flushLock{m_flushMutex};
550 7 : if (!m_mediaPipelineIpc->flush(sourceId, resetTime, async))
551 : {
552 1 : return false;
553 : }
554 6 : m_attachedSources.setFlushing(sourceId, true);
555 7 : }
556 :
557 : // Clear all need datas for flushed source
558 6 : std::lock_guard<std::mutex> lock{m_needDataRequestMapMutex};
559 8 : for (auto it = m_needDataRequestMap.begin(); it != m_needDataRequestMap.end();)
560 : {
561 2 : if (it->second->sourceId == sourceId)
562 : {
563 2 : it = m_needDataRequestMap.erase(it);
564 : }
565 : else
566 : {
567 0 : ++it;
568 : }
569 : }
570 6 : return true;
571 : }
572 :
573 2 : bool MediaPipeline::setSourcePosition(int32_t sourceId, int64_t position, bool resetTime, double appliedRate,
574 : uint64_t stopPosition)
575 : {
576 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
577 :
578 2 : return m_mediaPipelineIpc->setSourcePosition(sourceId, position, resetTime, appliedRate, stopPosition);
579 : }
580 :
581 2 : bool MediaPipeline::setSubtitleOffset(int32_t sourceId, int64_t position)
582 : {
583 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
584 :
585 2 : return m_mediaPipelineIpc->setSubtitleOffset(sourceId, position);
586 : }
587 :
588 2 : bool MediaPipeline::processAudioGap(int64_t position, uint32_t duration, int64_t discontinuityGap, bool audioAac)
589 : {
590 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
591 :
592 2 : return m_mediaPipelineIpc->processAudioGap(position, duration, discontinuityGap, audioAac);
593 : }
594 :
595 2 : bool MediaPipeline::setBufferingLimit(uint32_t limitBufferingMs)
596 : {
597 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
598 :
599 2 : return m_mediaPipelineIpc->setBufferingLimit(limitBufferingMs);
600 : }
601 :
602 2 : bool MediaPipeline::getBufferingLimit(uint32_t &limitBufferingMs)
603 : {
604 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
605 :
606 2 : return m_mediaPipelineIpc->getBufferingLimit(limitBufferingMs);
607 : }
608 :
609 2 : bool MediaPipeline::setUseBuffering(bool useBuffering)
610 : {
611 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
612 :
613 2 : return m_mediaPipelineIpc->setUseBuffering(useBuffering);
614 : }
615 :
616 2 : bool MediaPipeline::getUseBuffering(bool &useBuffering)
617 : {
618 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
619 :
620 2 : return m_mediaPipelineIpc->getUseBuffering(useBuffering);
621 : }
622 :
623 2 : bool MediaPipeline::switchSource(const std::unique_ptr<MediaSource> &source)
624 : {
625 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
626 :
627 2 : return m_mediaPipelineIpc->switchSource(source);
628 : }
629 :
630 2 : bool MediaPipeline::getDuration(int64_t &duration)
631 : {
632 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
633 :
634 2 : return m_mediaPipelineIpc->getDuration(duration);
635 : }
636 :
637 5 : void MediaPipeline::discardNeedDataRequest(uint32_t needDataRequestId)
638 : {
639 : // Find the needDataRequest for this needDataRequestId
640 : // The needData request can be cancelled from another thread
641 : {
642 5 : std::lock_guard<std::mutex> lock{m_needDataRequestMapMutex};
643 :
644 5 : auto needDataRequestIt = m_needDataRequestMap.find(needDataRequestId);
645 5 : if (needDataRequestIt == m_needDataRequestMap.end())
646 : {
647 0 : RIALTO_CLIENT_LOG_INFO("Could not find need data request, with id %u", needDataRequestId);
648 : }
649 : else
650 : {
651 5 : RIALTO_CLIENT_LOG_INFO("Discarding need data request with id %u", needDataRequestId);
652 5 : m_needDataRequestMap.erase(needDataRequestIt);
653 : }
654 : }
655 : }
656 :
657 0 : std::weak_ptr<IMediaPipelineClient> MediaPipeline::getClient()
658 : {
659 0 : return m_mediaPipelineClient;
660 : }
661 :
662 4 : void MediaPipeline::updateState(NetworkState state)
663 : {
664 4 : State newState = m_currentState;
665 :
666 4 : switch (state)
667 : {
668 3 : case NetworkState::BUFFERING:
669 : case NetworkState::BUFFERING_PROGRESS:
670 : case NetworkState::STALLED:
671 : {
672 3 : newState = State::BUFFERING;
673 3 : break;
674 : }
675 0 : case NetworkState::FORMAT_ERROR:
676 : case NetworkState::NETWORK_ERROR:
677 : case NetworkState::DECODE_ERROR:
678 : {
679 0 : newState = State::FAILURE;
680 0 : break;
681 : }
682 1 : default:
683 : {
684 1 : break;
685 : }
686 : }
687 :
688 4 : RIALTO_CLIENT_LOG_DEBUG("Received network state '%s', old state '%s', new state '%s'", toString(state),
689 : toString(m_currentState), toString(newState));
690 4 : m_currentState = newState;
691 : }
692 :
693 68 : void MediaPipeline::updateState(PlaybackState state)
694 : {
695 68 : State newState = m_currentState;
696 :
697 68 : switch (state)
698 : {
699 50 : case PlaybackState::PLAYING:
700 : case PlaybackState::PAUSED:
701 : {
702 50 : newState = State::PLAYING;
703 50 : break;
704 : }
705 4 : case PlaybackState::SEEKING:
706 : {
707 4 : newState = State::SEEKING;
708 4 : break;
709 : }
710 3 : case PlaybackState::STOPPED:
711 : {
712 3 : newState = State::IDLE;
713 3 : break;
714 : }
715 3 : case PlaybackState::SEEK_DONE:
716 : {
717 3 : newState = State::BUFFERING;
718 3 : break;
719 : }
720 4 : case PlaybackState::END_OF_STREAM:
721 : {
722 4 : newState = State::END_OF_STREAM;
723 4 : break;
724 : }
725 3 : case PlaybackState::FAILURE:
726 : {
727 3 : newState = State::FAILURE;
728 3 : break;
729 : }
730 1 : default:
731 : {
732 1 : break;
733 : }
734 : }
735 :
736 68 : RIALTO_CLIENT_LOG_DEBUG("Received playback state '%s', old state '%s', new state '%s'", toString(state),
737 : toString(m_currentState), toString(newState));
738 68 : m_currentState = newState;
739 : }
740 :
741 68 : void MediaPipeline::notifyPlaybackState(PlaybackState state)
742 : {
743 68 : RIALTO_CLIENT_LOG_DEBUG("entry:");
744 :
745 68 : updateState(state);
746 :
747 68 : std::shared_ptr<IMediaPipelineClient> client = m_mediaPipelineClient.lock();
748 68 : if (client)
749 : {
750 68 : client->notifyPlaybackState(state);
751 : }
752 : }
753 :
754 0 : void MediaPipeline::notifyPosition(int64_t position)
755 : {
756 0 : RIALTO_CLIENT_LOG_DEBUG("entry:");
757 :
758 0 : std::shared_ptr<IMediaPipelineClient> client = m_mediaPipelineClient.lock();
759 0 : if (client)
760 : {
761 0 : client->notifyPosition(position);
762 : }
763 : }
764 :
765 4 : void MediaPipeline::notifyNetworkState(NetworkState state)
766 : {
767 4 : RIALTO_CLIENT_LOG_DEBUG("entry:");
768 :
769 4 : updateState(state);
770 :
771 4 : std::shared_ptr<IMediaPipelineClient> client = m_mediaPipelineClient.lock();
772 4 : if (client)
773 : {
774 4 : client->notifyNetworkState(state);
775 : }
776 : }
777 :
778 49 : void MediaPipeline::notifyNeedMediaData(int32_t sourceId, size_t frameCount, uint32_t requestId,
779 : const std::shared_ptr<MediaPlayerShmInfo> &shmInfo)
780 : {
781 49 : RIALTO_CLIENT_LOG_DEBUG("entry:");
782 :
783 : // If attach source is ongoing wait till it has completed so that all sources are attached
784 : {
785 49 : std::unique_lock<std::mutex> lock{m_attachSourceMutex};
786 49 : if (m_attachingSource)
787 0 : m_attachSourceCond.wait(lock, [this] { return !m_attachingSource; });
788 49 : }
789 :
790 49 : if (MediaSourceType::UNKNOWN == m_attachedSources.getType(sourceId))
791 : {
792 2 : RIALTO_CLIENT_LOG_WARN("NeedMediaData received for unknown source %d, ignoring request id %u", sourceId,
793 : requestId);
794 2 : return;
795 : }
796 47 : if (m_attachedSources.isFlushing(sourceId))
797 : {
798 1 : RIALTO_CLIENT_LOG_WARN("NeedMediaData received for flushing source %d, ignoring request id %u", sourceId,
799 : requestId);
800 1 : return;
801 : }
802 :
803 46 : switch (m_currentState)
804 : {
805 39 : case State::BUFFERING:
806 : case State::PLAYING:
807 : {
808 39 : std::shared_ptr<NeedDataRequest> needDataRequest = std::make_shared<NeedDataRequest>();
809 39 : needDataRequest->sourceId = sourceId;
810 39 : needDataRequest->shmInfo = shmInfo;
811 :
812 : {
813 39 : std::lock_guard<std::mutex> lock{m_needDataRequestMapMutex};
814 39 : if (ApplicationState::RUNNING != m_currentAppState)
815 : {
816 1 : RIALTO_CLIENT_LOG_INFO("NeedMediaData received in state != RUNNING, ignoring request id %u", requestId);
817 1 : break;
818 : }
819 38 : m_needDataRequestMap[requestId] = std::move(needDataRequest);
820 39 : }
821 :
822 38 : std::shared_ptr<IMediaPipelineClient> client = m_mediaPipelineClient.lock();
823 38 : if (client)
824 : {
825 38 : client->notifyNeedMediaData(sourceId, frameCount, requestId, nullptr);
826 : }
827 :
828 38 : break;
829 39 : }
830 1 : case State::SEEKING:
831 : {
832 1 : RIALTO_CLIENT_LOG_INFO("NeedMediaData received while seeking, ignoring request id %u", requestId);
833 1 : break;
834 : }
835 6 : case State::IDLE:
836 : case State::END_OF_STREAM:
837 : case State::FAILURE:
838 : default:
839 : {
840 6 : RIALTO_CLIENT_LOG_WARN("NeedMediaData received in unexpected state '%s', ignoring request id %u",
841 : toString(m_currentState), requestId);
842 6 : break;
843 : }
844 : }
845 : }
846 :
847 117 : void MediaPipeline::notifyApplicationState(ApplicationState state)
848 : {
849 117 : RIALTO_CLIENT_LOG_DEBUG("entry:");
850 117 : std::lock_guard<std::mutex> lock{m_needDataRequestMapMutex};
851 117 : m_currentAppState = state;
852 117 : if (ApplicationState::RUNNING != state)
853 : {
854 : // If shared memory in use, wait for it to finish before returning
855 4 : m_needDataRequestMap.clear();
856 : }
857 117 : }
858 :
859 1 : void MediaPipeline::notifyQos(int32_t sourceId, const QosInfo &qosInfo)
860 : {
861 1 : RIALTO_CLIENT_LOG_DEBUG("entry:");
862 :
863 1 : std::shared_ptr<IMediaPipelineClient> client = m_mediaPipelineClient.lock();
864 1 : if (client)
865 : {
866 1 : client->notifyQos(sourceId, qosInfo);
867 : }
868 : }
869 :
870 0 : void MediaPipeline::notifyBufferUnderflow(int32_t sourceId)
871 : {
872 0 : RIALTO_CLIENT_LOG_DEBUG("entry:");
873 :
874 0 : std::shared_ptr<IMediaPipelineClient> client = m_mediaPipelineClient.lock();
875 0 : if (client)
876 : {
877 0 : client->notifyBufferUnderflow(sourceId);
878 : }
879 : }
880 :
881 1 : void MediaPipeline::notifyFirstFrameReceived(int32_t sourceId)
882 : {
883 1 : RIALTO_CLIENT_LOG_DEBUG("entry:");
884 :
885 1 : std::shared_ptr<IMediaPipelineClient> client = m_mediaPipelineClient.lock();
886 1 : if (client)
887 : {
888 1 : client->notifyFirstFrameReceived(sourceId);
889 : }
890 : }
891 :
892 1 : void MediaPipeline::notifyPlaybackError(int32_t sourceId, PlaybackError error)
893 : {
894 1 : RIALTO_CLIENT_LOG_DEBUG("entry:");
895 :
896 1 : std::shared_ptr<IMediaPipelineClient> client = m_mediaPipelineClient.lock();
897 1 : if (client)
898 : {
899 1 : client->notifyPlaybackError(sourceId, error);
900 : }
901 : }
902 :
903 4 : void MediaPipeline::notifySourceFlushed(int32_t sourceId)
904 : {
905 4 : RIALTO_CLIENT_LOG_DEBUG("entry:");
906 : {
907 4 : std::lock_guard<std::mutex> lock{m_flushMutex};
908 4 : m_attachedSources.setFlushing(sourceId, false);
909 : }
910 4 : std::shared_ptr<IMediaPipelineClient> client = m_mediaPipelineClient.lock();
911 4 : if (client)
912 : {
913 4 : client->notifySourceFlushed(sourceId);
914 : }
915 :
916 4 : State expected = State::END_OF_STREAM;
917 4 : m_currentState.compare_exchange_strong(expected, State::BUFFERING);
918 : }
919 :
920 1 : void MediaPipeline::notifyPlaybackInfo(const PlaybackInfo &playbackInfo)
921 : {
922 1 : RIALTO_CLIENT_LOG_DEBUG("entry:");
923 :
924 1 : std::shared_ptr<IMediaPipelineClient> client = m_mediaPipelineClient.lock();
925 1 : if (client)
926 : {
927 1 : client->notifyPlaybackInfo(playbackInfo);
928 : }
929 : }
930 :
931 : }; // namespace firebolt::rialto::client
|