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