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 121 : 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 121 : IClientController &clientController)
186 363 : : m_mediaPipelineClient(client), m_clientController{clientController}, m_currentAppState{ApplicationState::UNKNOWN},
187 121 : m_mediaFrameWriterFactory(mediaFrameWriterFactory), m_currentState(State::IDLE)
188 : {
189 121 : RIALTO_CLIENT_LOG_DEBUG("entry:");
190 :
191 121 : m_mediaPipelineIpc = mediaPipelineIpcFactory->createMediaPipelineIpc(this, videoRequirements);
192 :
193 121 : if (!m_mediaPipelineIpc)
194 : {
195 2 : throw std::runtime_error("Media player ipc could not be created");
196 : }
197 135 : }
198 :
199 236 : MediaPipeline::~MediaPipeline()
200 : {
201 119 : RIALTO_CLIENT_LOG_DEBUG("entry:");
202 :
203 119 : m_mediaPipelineIpc.reset();
204 236 : }
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(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::setReportDecodeErrors(int32_t sourceId, bool reportDecodeErrors)
317 : {
318 2 : return m_mediaPipelineIpc->setReportDecodeErrors(sourceId, reportDecodeErrors);
319 : }
320 :
321 2 : bool MediaPipeline::getQueuedFrames(int32_t sourceId, uint32_t &queuedFrames)
322 : {
323 2 : return m_mediaPipelineIpc->getQueuedFrames(sourceId, queuedFrames);
324 : }
325 :
326 2 : bool MediaPipeline::getImmediateOutput(int32_t sourceId, bool &immediateOutput)
327 : {
328 2 : return m_mediaPipelineIpc->getImmediateOutput(sourceId, immediateOutput);
329 : }
330 :
331 2 : bool MediaPipeline::getStats(int32_t sourceId, uint64_t &renderedFrames, uint64_t &droppedFrames)
332 : {
333 2 : return m_mediaPipelineIpc->getStats(sourceId, renderedFrames, droppedFrames);
334 : }
335 :
336 5 : bool MediaPipeline::handleSetPosition(int64_t position)
337 : {
338 : // needData requests no longer valid
339 : {
340 5 : std::lock_guard<std::mutex> lock{m_needDataRequestMapMutex};
341 5 : m_needDataRequestMap.clear();
342 : }
343 5 : return m_mediaPipelineIpc->setPosition(position);
344 : }
345 :
346 2 : bool MediaPipeline::setVideoWindow(uint32_t x, uint32_t y, uint32_t width, uint32_t height)
347 : {
348 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
349 :
350 2 : return m_mediaPipelineIpc->setVideoWindow(x, y, width, height);
351 : }
352 :
353 27 : bool MediaPipeline::haveData(MediaSourceStatus status, uint32_t needDataRequestId)
354 : {
355 27 : RIALTO_CLIENT_LOG_DEBUG("entry:");
356 :
357 27 : switch (m_currentState)
358 : {
359 22 : case State::BUFFERING:
360 : case State::PLAYING:
361 : {
362 22 : return handleHaveData(status, needDataRequestId);
363 : }
364 2 : case State::SEEKING:
365 : {
366 2 : RIALTO_CLIENT_LOG_INFO("HaveData received while seeking, discarding NeedData request %u", needDataRequestId);
367 2 : discardNeedDataRequest(needDataRequestId);
368 2 : return true;
369 : }
370 3 : case State::IDLE:
371 : case State::END_OF_STREAM:
372 : case State::FAILURE:
373 : default:
374 : {
375 3 : RIALTO_CLIENT_LOG_WARN("HaveData received in unexpected state '%s', discarding NeedData request %u",
376 : toString(m_currentState), needDataRequestId);
377 3 : discardNeedDataRequest(needDataRequestId);
378 3 : return false;
379 : }
380 : }
381 : }
382 :
383 22 : bool MediaPipeline::handleHaveData(MediaSourceStatus status, uint32_t needDataRequestId)
384 : {
385 22 : RIALTO_CLIENT_LOG_DEBUG("entry:");
386 :
387 22 : std::shared_ptr<NeedDataRequest> needDataRequest;
388 :
389 : // Find the needDataRequest for this needDataRequestId
390 : // The needData request can be cancelled from another thread
391 : {
392 22 : std::lock_guard<std::mutex> lock{m_needDataRequestMapMutex};
393 :
394 22 : auto needDataRequestIt = m_needDataRequestMap.find(needDataRequestId);
395 22 : if (needDataRequestIt == m_needDataRequestMap.end())
396 : {
397 : // Return success here as the data written is just ignored
398 19 : RIALTO_CLIENT_LOG_WARN("Could not find need data request, with id %u", needDataRequestId);
399 19 : return true;
400 : }
401 :
402 3 : needDataRequest = needDataRequestIt->second;
403 3 : m_needDataRequestMap.erase(needDataRequestIt);
404 22 : }
405 3 : if (m_attachedSources.isFlushing(needDataRequest->sourceId))
406 : {
407 0 : RIALTO_CLIENT_LOG_WARN("Source %d is flushing. Ignoring need data request, with id %u",
408 : needDataRequest->sourceId, needDataRequestId);
409 0 : return true;
410 : }
411 :
412 3 : uint32_t numFrames = needDataRequest->frameWriter ? needDataRequest->frameWriter->getNumFrames() : 0;
413 3 : return m_mediaPipelineIpc->haveData(status, numFrames, needDataRequestId);
414 22 : }
415 :
416 53 : AddSegmentStatus MediaPipeline::addSegment(uint32_t needDataRequestId, const std::unique_ptr<MediaSegment> &mediaSegment)
417 : {
418 53 : RIALTO_CLIENT_LOG_DEBUG("entry:");
419 :
420 53 : if (nullptr == mediaSegment || nullptr == mediaSegment->getData())
421 : {
422 2 : return AddSegmentStatus::ERROR;
423 : }
424 :
425 51 : std::lock_guard<std::mutex> lock{m_needDataRequestMapMutex};
426 51 : auto needDataRequestIt = m_needDataRequestMap.find(needDataRequestId);
427 51 : if (needDataRequestIt == m_needDataRequestMap.end())
428 : {
429 0 : RIALTO_CLIENT_LOG_ERROR("Could not find need data request, with id %u", needDataRequestId);
430 0 : return AddSegmentStatus::ERROR;
431 : }
432 :
433 51 : std::shared_ptr<NeedDataRequest> needDataRequest = needDataRequestIt->second;
434 51 : std::shared_ptr<ISharedMemoryHandle> shmHandle = m_clientController.getSharedMemoryHandle();
435 51 : if (nullptr == shmHandle || nullptr == shmHandle->getShm())
436 : {
437 2 : RIALTO_CLIENT_LOG_ERROR("Shared buffer no longer valid");
438 2 : return AddSegmentStatus::ERROR;
439 : }
440 :
441 : // This block of code is only for playready apps using rialto c++ interface
442 : // Widevine apps and playready apps using rialto-ocdm set MediaSegment::keyId earlier
443 49 : if (mediaSegment->isEncrypted())
444 : {
445 2 : auto keyId = KeyIdMap::instance().get(mediaSegment->getMediaKeySessionId());
446 2 : if (!keyId.empty() && mediaSegment->getKeyId().empty())
447 : {
448 1 : RIALTO_CLIENT_LOG_DEBUG("Adding Playready keyID to media segment");
449 1 : mediaSegment->setKeyId(keyId);
450 : }
451 2 : }
452 :
453 49 : if (!needDataRequest->frameWriter)
454 : {
455 17 : if (firebolt::rialto::MediaSourceType::UNKNOWN != mediaSegment->getType())
456 : {
457 16 : needDataRequest->frameWriter =
458 32 : m_mediaFrameWriterFactory->createFrameWriter(shmHandle->getShm(), needDataRequest->shmInfo);
459 : }
460 : else
461 : {
462 1 : RIALTO_CLIENT_LOG_ERROR("Unrecognised type %u", static_cast<uint32_t>(mediaSegment->getType()));
463 1 : return AddSegmentStatus::ERROR;
464 : }
465 :
466 16 : if (!needDataRequest->frameWriter)
467 : {
468 1 : RIALTO_CLIENT_LOG_ERROR("Could not create frame writer");
469 1 : return AddSegmentStatus::ERROR;
470 : }
471 : }
472 :
473 47 : return needDataRequest->frameWriter->writeFrame(mediaSegment);
474 51 : }
475 :
476 2 : bool MediaPipeline::renderFrame()
477 : {
478 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
479 2 : return m_mediaPipelineIpc->renderFrame();
480 : }
481 :
482 3 : bool MediaPipeline::setVolume(double targetVolume, uint32_t volumeDuration, EaseType easeType)
483 : {
484 3 : RIALTO_CLIENT_LOG_DEBUG("entry:");
485 3 : return m_mediaPipelineIpc->setVolume(targetVolume, volumeDuration, easeType);
486 : }
487 :
488 2 : bool MediaPipeline::getVolume(double ¤tVolume)
489 : {
490 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
491 2 : return m_mediaPipelineIpc->getVolume(currentVolume);
492 : }
493 :
494 2 : bool MediaPipeline::setMute(int32_t sourceId, bool mute)
495 : {
496 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
497 2 : return m_mediaPipelineIpc->setMute(sourceId, mute);
498 : }
499 :
500 2 : bool MediaPipeline::getMute(int32_t sourceId, bool &mute)
501 : {
502 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
503 2 : return m_mediaPipelineIpc->getMute(sourceId, mute);
504 : }
505 :
506 2 : bool MediaPipeline::setTextTrackIdentifier(const std::string &textTrackIdentifier)
507 : {
508 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
509 2 : return m_mediaPipelineIpc->setTextTrackIdentifier(textTrackIdentifier);
510 : }
511 :
512 2 : bool MediaPipeline::getTextTrackIdentifier(std::string &textTrackIdentifier)
513 : {
514 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
515 2 : return m_mediaPipelineIpc->getTextTrackIdentifier(textTrackIdentifier);
516 : }
517 :
518 2 : bool MediaPipeline::setLowLatency(bool lowLatency)
519 : {
520 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
521 2 : return m_mediaPipelineIpc->setLowLatency(lowLatency);
522 : }
523 :
524 2 : bool MediaPipeline::setSync(bool sync)
525 : {
526 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
527 2 : return m_mediaPipelineIpc->setSync(sync);
528 : }
529 :
530 2 : bool MediaPipeline::getSync(bool &sync)
531 : {
532 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
533 2 : return m_mediaPipelineIpc->getSync(sync);
534 : }
535 :
536 2 : bool MediaPipeline::setSyncOff(bool syncOff)
537 : {
538 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
539 2 : return m_mediaPipelineIpc->setSyncOff(syncOff);
540 : }
541 :
542 2 : bool MediaPipeline::setStreamSyncMode(int32_t sourceId, int32_t streamSyncMode)
543 : {
544 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
545 2 : return m_mediaPipelineIpc->setStreamSyncMode(sourceId, streamSyncMode);
546 : }
547 :
548 2 : bool MediaPipeline::getStreamSyncMode(int32_t &streamSyncMode)
549 : {
550 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
551 2 : return m_mediaPipelineIpc->getStreamSyncMode(streamSyncMode);
552 : }
553 :
554 7 : bool MediaPipeline::flush(int32_t sourceId, bool resetTime, bool &async)
555 : {
556 7 : RIALTO_CLIENT_LOG_DEBUG("entry:");
557 :
558 7 : std::unique_lock<std::mutex> flushLock{m_flushMutex};
559 7 : if (m_mediaPipelineIpc->flush(sourceId, resetTime, async))
560 : {
561 6 : m_attachedSources.setFlushing(sourceId, true);
562 6 : flushLock.unlock();
563 :
564 : // Clear all need datas for flushed source
565 6 : std::lock_guard<std::mutex> lock{m_needDataRequestMapMutex};
566 8 : for (auto it = m_needDataRequestMap.begin(); it != m_needDataRequestMap.end();)
567 : {
568 2 : if (it->second->sourceId == sourceId)
569 : {
570 2 : it = m_needDataRequestMap.erase(it);
571 : }
572 : else
573 : {
574 0 : ++it;
575 : }
576 : }
577 6 : return true;
578 : }
579 1 : return false;
580 7 : }
581 :
582 2 : bool MediaPipeline::setSourcePosition(int32_t sourceId, int64_t position, bool resetTime, double appliedRate,
583 : uint64_t stopPosition)
584 : {
585 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
586 :
587 2 : return m_mediaPipelineIpc->setSourcePosition(sourceId, position, resetTime, appliedRate, stopPosition);
588 : }
589 :
590 2 : bool MediaPipeline::setSubtitleOffset(int32_t sourceId, int64_t position)
591 : {
592 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
593 :
594 2 : return m_mediaPipelineIpc->setSubtitleOffset(sourceId, position);
595 : }
596 :
597 2 : bool MediaPipeline::processAudioGap(int64_t position, uint32_t duration, int64_t discontinuityGap, bool audioAac)
598 : {
599 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
600 :
601 2 : return m_mediaPipelineIpc->processAudioGap(position, duration, discontinuityGap, audioAac);
602 : }
603 :
604 2 : bool MediaPipeline::setBufferingLimit(uint32_t limitBufferingMs)
605 : {
606 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
607 :
608 2 : return m_mediaPipelineIpc->setBufferingLimit(limitBufferingMs);
609 : }
610 :
611 2 : bool MediaPipeline::getBufferingLimit(uint32_t &limitBufferingMs)
612 : {
613 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
614 :
615 2 : return m_mediaPipelineIpc->getBufferingLimit(limitBufferingMs);
616 : }
617 :
618 2 : bool MediaPipeline::setUseBuffering(bool useBuffering)
619 : {
620 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
621 :
622 2 : return m_mediaPipelineIpc->setUseBuffering(useBuffering);
623 : }
624 :
625 2 : bool MediaPipeline::getUseBuffering(bool &useBuffering)
626 : {
627 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
628 :
629 2 : return m_mediaPipelineIpc->getUseBuffering(useBuffering);
630 : }
631 :
632 2 : bool MediaPipeline::switchSource(const std::unique_ptr<MediaSource> &source)
633 : {
634 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
635 :
636 2 : return m_mediaPipelineIpc->switchSource(source);
637 : }
638 :
639 5 : void MediaPipeline::discardNeedDataRequest(uint32_t needDataRequestId)
640 : {
641 : // Find the needDataRequest for this needDataRequestId
642 : // The needData request can be cancelled from another thread
643 : {
644 5 : std::lock_guard<std::mutex> lock{m_needDataRequestMapMutex};
645 :
646 5 : auto needDataRequestIt = m_needDataRequestMap.find(needDataRequestId);
647 5 : if (needDataRequestIt == m_needDataRequestMap.end())
648 : {
649 0 : RIALTO_CLIENT_LOG_INFO("Could not find need data request, with id %u", needDataRequestId);
650 : }
651 : else
652 : {
653 5 : RIALTO_CLIENT_LOG_INFO("Discarding need data request with id %u", needDataRequestId);
654 5 : m_needDataRequestMap.erase(needDataRequestIt);
655 : }
656 : }
657 : }
658 :
659 0 : std::weak_ptr<IMediaPipelineClient> MediaPipeline::getClient()
660 : {
661 0 : return m_mediaPipelineClient;
662 : }
663 :
664 4 : void MediaPipeline::updateState(NetworkState state)
665 : {
666 4 : State newState = m_currentState;
667 :
668 4 : switch (state)
669 : {
670 3 : case NetworkState::BUFFERING:
671 : case NetworkState::BUFFERING_PROGRESS:
672 : case NetworkState::STALLED:
673 : {
674 3 : newState = State::BUFFERING;
675 3 : break;
676 : }
677 0 : case NetworkState::FORMAT_ERROR:
678 : case NetworkState::NETWORK_ERROR:
679 : case NetworkState::DECODE_ERROR:
680 : {
681 0 : newState = State::FAILURE;
682 0 : break;
683 : }
684 1 : default:
685 : {
686 1 : break;
687 : }
688 : }
689 :
690 4 : RIALTO_CLIENT_LOG_DEBUG("Received network state '%s', old state '%s', new state '%s'", toString(state),
691 : toString(m_currentState), toString(newState));
692 4 : m_currentState = newState;
693 : }
694 :
695 68 : void MediaPipeline::updateState(PlaybackState state)
696 : {
697 68 : State newState = m_currentState;
698 :
699 68 : switch (state)
700 : {
701 50 : case PlaybackState::PLAYING:
702 : case PlaybackState::PAUSED:
703 : {
704 50 : newState = State::PLAYING;
705 50 : break;
706 : }
707 4 : case PlaybackState::SEEKING:
708 : {
709 4 : newState = State::SEEKING;
710 4 : break;
711 : }
712 3 : case PlaybackState::STOPPED:
713 : {
714 3 : newState = State::IDLE;
715 3 : break;
716 : }
717 3 : case PlaybackState::SEEK_DONE:
718 : {
719 3 : newState = State::BUFFERING;
720 3 : break;
721 : }
722 4 : case PlaybackState::END_OF_STREAM:
723 : {
724 4 : newState = State::END_OF_STREAM;
725 4 : break;
726 : }
727 3 : case PlaybackState::FAILURE:
728 : {
729 3 : newState = State::FAILURE;
730 3 : break;
731 : }
732 1 : default:
733 : {
734 1 : break;
735 : }
736 : }
737 :
738 68 : RIALTO_CLIENT_LOG_DEBUG("Received playback state '%s', old state '%s', new state '%s'", toString(state),
739 : toString(m_currentState), toString(newState));
740 68 : m_currentState = newState;
741 : }
742 :
743 68 : void MediaPipeline::notifyPlaybackState(PlaybackState state)
744 : {
745 68 : RIALTO_CLIENT_LOG_DEBUG("entry:");
746 :
747 68 : updateState(state);
748 :
749 68 : std::shared_ptr<IMediaPipelineClient> client = m_mediaPipelineClient.lock();
750 68 : if (client)
751 : {
752 68 : client->notifyPlaybackState(state);
753 : }
754 : }
755 :
756 0 : void MediaPipeline::notifyPosition(int64_t position)
757 : {
758 0 : RIALTO_CLIENT_LOG_DEBUG("entry:");
759 :
760 0 : std::shared_ptr<IMediaPipelineClient> client = m_mediaPipelineClient.lock();
761 0 : if (client)
762 : {
763 0 : client->notifyPosition(position);
764 : }
765 : }
766 :
767 4 : void MediaPipeline::notifyNetworkState(NetworkState state)
768 : {
769 4 : RIALTO_CLIENT_LOG_DEBUG("entry:");
770 :
771 4 : updateState(state);
772 :
773 4 : std::shared_ptr<IMediaPipelineClient> client = m_mediaPipelineClient.lock();
774 4 : if (client)
775 : {
776 4 : client->notifyNetworkState(state);
777 : }
778 : }
779 :
780 49 : void MediaPipeline::notifyNeedMediaData(int32_t sourceId, size_t frameCount, uint32_t requestId,
781 : const std::shared_ptr<MediaPlayerShmInfo> &shmInfo)
782 : {
783 49 : RIALTO_CLIENT_LOG_DEBUG("entry:");
784 :
785 : // If attach source is ongoing wait till it has completed so that all sources are attached
786 : {
787 49 : std::unique_lock<std::mutex> lock{m_attachSourceMutex};
788 49 : if (m_attachingSource)
789 0 : m_attachSourceCond.wait(lock, [this] { return !m_attachingSource; });
790 49 : }
791 :
792 49 : if (MediaSourceType::UNKNOWN == m_attachedSources.getType(sourceId))
793 : {
794 2 : RIALTO_CLIENT_LOG_WARN("NeedMediaData received for unknown source %d, ignoring request id %u", sourceId,
795 : requestId);
796 2 : return;
797 : }
798 47 : if (m_attachedSources.isFlushing(sourceId))
799 : {
800 1 : RIALTO_CLIENT_LOG_WARN("NeedMediaData received for flushing source %d, ignoring request id %u", sourceId,
801 : requestId);
802 1 : return;
803 : }
804 :
805 46 : switch (m_currentState)
806 : {
807 39 : case State::BUFFERING:
808 : case State::PLAYING:
809 : {
810 39 : std::shared_ptr<NeedDataRequest> needDataRequest = std::make_shared<NeedDataRequest>();
811 39 : needDataRequest->sourceId = sourceId;
812 39 : needDataRequest->shmInfo = shmInfo;
813 :
814 : {
815 39 : std::lock_guard<std::mutex> lock{m_needDataRequestMapMutex};
816 39 : if (ApplicationState::RUNNING != m_currentAppState)
817 : {
818 1 : RIALTO_CLIENT_LOG_INFO("NeedMediaData received in state != RUNNING, ignoring request id %u", requestId);
819 1 : break;
820 : }
821 38 : m_needDataRequestMap[requestId] = needDataRequest;
822 39 : }
823 :
824 38 : std::shared_ptr<IMediaPipelineClient> client = m_mediaPipelineClient.lock();
825 38 : if (client)
826 : {
827 38 : client->notifyNeedMediaData(sourceId, frameCount, requestId, nullptr);
828 : }
829 :
830 38 : break;
831 39 : }
832 1 : case State::SEEKING:
833 : {
834 1 : RIALTO_CLIENT_LOG_INFO("NeedMediaData received while seeking, ignoring request id %u", requestId);
835 1 : break;
836 : }
837 6 : case State::IDLE:
838 : case State::END_OF_STREAM:
839 : case State::FAILURE:
840 : default:
841 : {
842 6 : RIALTO_CLIENT_LOG_WARN("NeedMediaData received in unexpected state '%s', ignoring request id %u",
843 : toString(m_currentState), requestId);
844 6 : break;
845 : }
846 : }
847 : }
848 :
849 118 : void MediaPipeline::notifyApplicationState(ApplicationState state)
850 : {
851 118 : RIALTO_CLIENT_LOG_DEBUG("entry:");
852 118 : std::lock_guard<std::mutex> lock{m_needDataRequestMapMutex};
853 118 : m_currentAppState = state;
854 118 : if (ApplicationState::RUNNING != state)
855 : {
856 : // If shared memory in use, wait for it to finish before returning
857 4 : m_needDataRequestMap.clear();
858 : }
859 118 : }
860 :
861 1 : void MediaPipeline::notifyQos(int32_t sourceId, const QosInfo &qosInfo)
862 : {
863 1 : RIALTO_CLIENT_LOG_DEBUG("entry:");
864 :
865 1 : std::shared_ptr<IMediaPipelineClient> client = m_mediaPipelineClient.lock();
866 1 : if (client)
867 : {
868 1 : client->notifyQos(sourceId, qosInfo);
869 : }
870 : }
871 :
872 0 : void MediaPipeline::notifyBufferUnderflow(int32_t sourceId)
873 : {
874 0 : RIALTO_CLIENT_LOG_DEBUG("entry:");
875 :
876 0 : std::shared_ptr<IMediaPipelineClient> client = m_mediaPipelineClient.lock();
877 0 : if (client)
878 : {
879 0 : client->notifyBufferUnderflow(sourceId);
880 : }
881 : }
882 :
883 1 : void MediaPipeline::notifyPlaybackError(int32_t sourceId, PlaybackError error)
884 : {
885 1 : RIALTO_CLIENT_LOG_DEBUG("entry:");
886 :
887 1 : std::shared_ptr<IMediaPipelineClient> client = m_mediaPipelineClient.lock();
888 1 : if (client)
889 : {
890 1 : client->notifyPlaybackError(sourceId, error);
891 : }
892 : }
893 :
894 4 : void MediaPipeline::notifySourceFlushed(int32_t sourceId)
895 : {
896 4 : RIALTO_CLIENT_LOG_DEBUG("entry:");
897 : {
898 4 : std::lock_guard<std::mutex> lock{m_flushMutex};
899 4 : m_attachedSources.setFlushing(sourceId, false);
900 : }
901 4 : std::shared_ptr<IMediaPipelineClient> client = m_mediaPipelineClient.lock();
902 4 : if (client)
903 : {
904 4 : client->notifySourceFlushed(sourceId);
905 : }
906 :
907 4 : State expected = State::END_OF_STREAM;
908 4 : m_currentState.compare_exchange_strong(expected, State::BUFFERING);
909 : }
910 :
911 1 : void MediaPipeline::notifyPlaybackInfo(const PlaybackInfo &playbackInfo)
912 : {
913 1 : RIALTO_CLIENT_LOG_DEBUG("entry:");
914 :
915 1 : std::shared_ptr<IMediaPipelineClient> client = m_mediaPipelineClient.lock();
916 1 : if (client)
917 : {
918 1 : client->notifyPlaybackInfo(playbackInfo);
919 : }
920 : }
921 :
922 : }; // namespace firebolt::rialto::client
|