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