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 116 : 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 116 : IClientController &clientController)
186 348 : : m_mediaPipelineClient(client), m_clientController{clientController}, m_currentAppState{ApplicationState::UNKNOWN},
187 116 : m_mediaFrameWriterFactory(mediaFrameWriterFactory), m_currentState(State::IDLE)
188 : {
189 116 : RIALTO_CLIENT_LOG_DEBUG("entry:");
190 :
191 116 : m_mediaPipelineIpc = mediaPipelineIpcFactory->createMediaPipelineIpc(this, videoRequirements);
192 :
193 116 : if (!m_mediaPipelineIpc)
194 : {
195 2 : throw std::runtime_error("Media player ipc could not be created");
196 : }
197 130 : }
198 :
199 226 : MediaPipeline::~MediaPipeline()
200 : {
201 114 : RIALTO_CLIENT_LOG_DEBUG("entry:");
202 :
203 114 : m_mediaPipelineIpc.reset();
204 226 : }
205 :
206 2 : bool MediaPipeline::load(MediaType type, const std::string &mimeType, const std::string &url)
207 : {
208 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
209 :
210 2 : return m_mediaPipelineIpc->load(type, mimeType, url);
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()
256 : {
257 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
258 :
259 2 : return m_mediaPipelineIpc->play();
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 7 : std::unique_lock<std::mutex> flushLock{m_flushMutex};
549 7 : if (m_mediaPipelineIpc->flush(sourceId, resetTime, async))
550 : {
551 6 : m_attachedSources.setFlushing(sourceId, true);
552 6 : flushLock.unlock();
553 :
554 : // Clear all need datas for flushed source
555 6 : std::lock_guard<std::mutex> lock{m_needDataRequestMapMutex};
556 8 : for (auto it = m_needDataRequestMap.begin(); it != m_needDataRequestMap.end();)
557 : {
558 2 : if (it->second->sourceId == sourceId)
559 : {
560 2 : it = m_needDataRequestMap.erase(it);
561 : }
562 : else
563 : {
564 0 : ++it;
565 : }
566 : }
567 6 : return true;
568 : }
569 1 : return false;
570 7 : }
571 :
572 2 : bool MediaPipeline::setSourcePosition(int32_t sourceId, int64_t position, bool resetTime, double appliedRate,
573 : uint64_t stopPosition)
574 : {
575 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
576 :
577 2 : return m_mediaPipelineIpc->setSourcePosition(sourceId, position, resetTime, appliedRate, stopPosition);
578 : }
579 :
580 2 : bool MediaPipeline::setSubtitleOffset(int32_t sourceId, int64_t position)
581 : {
582 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
583 :
584 2 : return m_mediaPipelineIpc->setSubtitleOffset(sourceId, position);
585 : }
586 :
587 2 : bool MediaPipeline::processAudioGap(int64_t position, uint32_t duration, int64_t discontinuityGap, bool audioAac)
588 : {
589 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
590 :
591 2 : return m_mediaPipelineIpc->processAudioGap(position, duration, discontinuityGap, audioAac);
592 : }
593 :
594 2 : bool MediaPipeline::setBufferingLimit(uint32_t limitBufferingMs)
595 : {
596 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
597 :
598 2 : return m_mediaPipelineIpc->setBufferingLimit(limitBufferingMs);
599 : }
600 :
601 2 : bool MediaPipeline::getBufferingLimit(uint32_t &limitBufferingMs)
602 : {
603 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
604 :
605 2 : return m_mediaPipelineIpc->getBufferingLimit(limitBufferingMs);
606 : }
607 :
608 2 : bool MediaPipeline::setUseBuffering(bool useBuffering)
609 : {
610 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
611 :
612 2 : return m_mediaPipelineIpc->setUseBuffering(useBuffering);
613 : }
614 :
615 2 : bool MediaPipeline::getUseBuffering(bool &useBuffering)
616 : {
617 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
618 :
619 2 : return m_mediaPipelineIpc->getUseBuffering(useBuffering);
620 : }
621 :
622 2 : bool MediaPipeline::switchSource(const std::unique_ptr<MediaSource> &source)
623 : {
624 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
625 :
626 2 : return m_mediaPipelineIpc->switchSource(source);
627 : }
628 :
629 5 : void MediaPipeline::discardNeedDataRequest(uint32_t needDataRequestId)
630 : {
631 : // Find the needDataRequest for this needDataRequestId
632 : // The needData request can be cancelled from another thread
633 : {
634 5 : std::lock_guard<std::mutex> lock{m_needDataRequestMapMutex};
635 :
636 5 : auto needDataRequestIt = m_needDataRequestMap.find(needDataRequestId);
637 5 : if (needDataRequestIt == m_needDataRequestMap.end())
638 : {
639 0 : RIALTO_CLIENT_LOG_INFO("Could not find need data request, with id %u", needDataRequestId);
640 : }
641 : else
642 : {
643 5 : RIALTO_CLIENT_LOG_INFO("Discarding need data request with id %u", needDataRequestId);
644 5 : m_needDataRequestMap.erase(needDataRequestIt);
645 : }
646 : }
647 : }
648 :
649 0 : std::weak_ptr<IMediaPipelineClient> MediaPipeline::getClient()
650 : {
651 0 : return m_mediaPipelineClient;
652 : }
653 :
654 4 : void MediaPipeline::updateState(NetworkState state)
655 : {
656 4 : State newState = m_currentState;
657 :
658 4 : switch (state)
659 : {
660 3 : case NetworkState::BUFFERING:
661 : case NetworkState::BUFFERING_PROGRESS:
662 : case NetworkState::STALLED:
663 : {
664 3 : newState = State::BUFFERING;
665 3 : break;
666 : }
667 0 : case NetworkState::FORMAT_ERROR:
668 : case NetworkState::NETWORK_ERROR:
669 : case NetworkState::DECODE_ERROR:
670 : {
671 0 : newState = State::FAILURE;
672 0 : break;
673 : }
674 1 : default:
675 : {
676 1 : break;
677 : }
678 : }
679 :
680 4 : RIALTO_CLIENT_LOG_DEBUG("Received network state '%s', old state '%s', new state '%s'", toString(state),
681 : toString(m_currentState), toString(newState));
682 4 : m_currentState = newState;
683 : }
684 :
685 68 : void MediaPipeline::updateState(PlaybackState state)
686 : {
687 68 : State newState = m_currentState;
688 :
689 68 : switch (state)
690 : {
691 50 : case PlaybackState::PLAYING:
692 : case PlaybackState::PAUSED:
693 : {
694 50 : newState = State::PLAYING;
695 50 : break;
696 : }
697 4 : case PlaybackState::SEEKING:
698 : {
699 4 : newState = State::SEEKING;
700 4 : break;
701 : }
702 3 : case PlaybackState::STOPPED:
703 : {
704 3 : newState = State::IDLE;
705 3 : break;
706 : }
707 3 : case PlaybackState::SEEK_DONE:
708 : {
709 3 : newState = State::BUFFERING;
710 3 : break;
711 : }
712 4 : case PlaybackState::END_OF_STREAM:
713 : {
714 4 : newState = State::END_OF_STREAM;
715 4 : break;
716 : }
717 3 : case PlaybackState::FAILURE:
718 : {
719 3 : newState = State::FAILURE;
720 3 : break;
721 : }
722 1 : default:
723 : {
724 1 : break;
725 : }
726 : }
727 :
728 68 : RIALTO_CLIENT_LOG_DEBUG("Received playback state '%s', old state '%s', new state '%s'", toString(state),
729 : toString(m_currentState), toString(newState));
730 68 : m_currentState = newState;
731 : }
732 :
733 68 : void MediaPipeline::notifyPlaybackState(PlaybackState state)
734 : {
735 68 : RIALTO_CLIENT_LOG_DEBUG("entry:");
736 :
737 68 : updateState(state);
738 :
739 68 : std::shared_ptr<IMediaPipelineClient> client = m_mediaPipelineClient.lock();
740 68 : if (client)
741 : {
742 68 : client->notifyPlaybackState(state);
743 : }
744 : }
745 :
746 0 : void MediaPipeline::notifyPosition(int64_t position)
747 : {
748 0 : RIALTO_CLIENT_LOG_DEBUG("entry:");
749 :
750 0 : std::shared_ptr<IMediaPipelineClient> client = m_mediaPipelineClient.lock();
751 0 : if (client)
752 : {
753 0 : client->notifyPosition(position);
754 : }
755 : }
756 :
757 4 : void MediaPipeline::notifyNetworkState(NetworkState state)
758 : {
759 4 : RIALTO_CLIENT_LOG_DEBUG("entry:");
760 :
761 4 : updateState(state);
762 :
763 4 : std::shared_ptr<IMediaPipelineClient> client = m_mediaPipelineClient.lock();
764 4 : if (client)
765 : {
766 4 : client->notifyNetworkState(state);
767 : }
768 : }
769 :
770 49 : void MediaPipeline::notifyNeedMediaData(int32_t sourceId, size_t frameCount, uint32_t requestId,
771 : const std::shared_ptr<MediaPlayerShmInfo> &shmInfo)
772 : {
773 49 : RIALTO_CLIENT_LOG_DEBUG("entry:");
774 :
775 : // If attach source is ongoing wait till it has completed so that all sources are attached
776 : {
777 49 : std::unique_lock<std::mutex> lock{m_attachSourceMutex};
778 49 : if (m_attachingSource)
779 0 : m_attachSourceCond.wait(lock, [this] { return !m_attachingSource; });
780 49 : }
781 :
782 49 : if (MediaSourceType::UNKNOWN == m_attachedSources.getType(sourceId))
783 : {
784 2 : RIALTO_CLIENT_LOG_WARN("NeedMediaData received for unknown source %d, ignoring request id %u", sourceId,
785 : requestId);
786 2 : return;
787 : }
788 47 : if (m_attachedSources.isFlushing(sourceId))
789 : {
790 1 : RIALTO_CLIENT_LOG_WARN("NeedMediaData received for flushing source %d, ignoring request id %u", sourceId,
791 : requestId);
792 1 : return;
793 : }
794 :
795 46 : switch (m_currentState)
796 : {
797 39 : case State::BUFFERING:
798 : case State::PLAYING:
799 : {
800 39 : std::shared_ptr<NeedDataRequest> needDataRequest = std::make_shared<NeedDataRequest>();
801 39 : needDataRequest->sourceId = sourceId;
802 39 : needDataRequest->shmInfo = shmInfo;
803 :
804 : {
805 39 : std::lock_guard<std::mutex> lock{m_needDataRequestMapMutex};
806 39 : if (ApplicationState::RUNNING != m_currentAppState)
807 : {
808 1 : RIALTO_CLIENT_LOG_INFO("NeedMediaData received in state != RUNNING, ignoring request id %u", requestId);
809 1 : break;
810 : }
811 38 : m_needDataRequestMap[requestId] = needDataRequest;
812 39 : }
813 :
814 38 : std::shared_ptr<IMediaPipelineClient> client = m_mediaPipelineClient.lock();
815 38 : if (client)
816 : {
817 38 : client->notifyNeedMediaData(sourceId, frameCount, requestId, nullptr);
818 : }
819 :
820 38 : break;
821 39 : }
822 1 : case State::SEEKING:
823 : {
824 1 : RIALTO_CLIENT_LOG_INFO("NeedMediaData received while seeking, ignoring request id %u", requestId);
825 1 : break;
826 : }
827 6 : case State::IDLE:
828 : case State::END_OF_STREAM:
829 : case State::FAILURE:
830 : default:
831 : {
832 6 : RIALTO_CLIENT_LOG_WARN("NeedMediaData received in unexpected state '%s', ignoring request id %u",
833 : toString(m_currentState), requestId);
834 6 : break;
835 : }
836 : }
837 : }
838 :
839 113 : void MediaPipeline::notifyApplicationState(ApplicationState state)
840 : {
841 113 : RIALTO_CLIENT_LOG_DEBUG("entry:");
842 113 : std::lock_guard<std::mutex> lock{m_needDataRequestMapMutex};
843 113 : m_currentAppState = state;
844 113 : if (ApplicationState::RUNNING != state)
845 : {
846 : // If shared memory in use, wait for it to finish before returning
847 4 : m_needDataRequestMap.clear();
848 : }
849 113 : }
850 :
851 1 : void MediaPipeline::notifyQos(int32_t sourceId, const QosInfo &qosInfo)
852 : {
853 1 : RIALTO_CLIENT_LOG_DEBUG("entry:");
854 :
855 1 : std::shared_ptr<IMediaPipelineClient> client = m_mediaPipelineClient.lock();
856 1 : if (client)
857 : {
858 1 : client->notifyQos(sourceId, qosInfo);
859 : }
860 : }
861 :
862 0 : void MediaPipeline::notifyBufferUnderflow(int32_t sourceId)
863 : {
864 0 : RIALTO_CLIENT_LOG_DEBUG("entry:");
865 :
866 0 : std::shared_ptr<IMediaPipelineClient> client = m_mediaPipelineClient.lock();
867 0 : if (client)
868 : {
869 0 : client->notifyBufferUnderflow(sourceId);
870 : }
871 : }
872 :
873 1 : void MediaPipeline::notifyPlaybackError(int32_t sourceId, PlaybackError error)
874 : {
875 1 : RIALTO_CLIENT_LOG_DEBUG("entry:");
876 :
877 1 : std::shared_ptr<IMediaPipelineClient> client = m_mediaPipelineClient.lock();
878 1 : if (client)
879 : {
880 1 : client->notifyPlaybackError(sourceId, error);
881 : }
882 : }
883 :
884 4 : void MediaPipeline::notifySourceFlushed(int32_t sourceId)
885 : {
886 4 : RIALTO_CLIENT_LOG_DEBUG("entry:");
887 : {
888 4 : std::lock_guard<std::mutex> lock{m_flushMutex};
889 4 : m_attachedSources.setFlushing(sourceId, false);
890 : }
891 4 : std::shared_ptr<IMediaPipelineClient> client = m_mediaPipelineClient.lock();
892 4 : if (client)
893 : {
894 4 : client->notifySourceFlushed(sourceId);
895 : }
896 :
897 4 : State expected = State::END_OF_STREAM;
898 4 : m_currentState.compare_exchange_strong(expected, State::BUFFERING);
899 : }
900 :
901 : }; // namespace firebolt::rialto::client
|