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 <limits.h>
21 : #include <stdexcept>
22 :
23 : #include "RialtoServerLogging.h"
24 : #include "WebAudioPlayerServerInternal.h"
25 :
26 : namespace
27 : {
28 : constexpr uint32_t kPreferredFrames{640};
29 : constexpr std::chrono::milliseconds kWriteDataTimeMs{100};
30 : } // namespace
31 :
32 : namespace firebolt::rialto
33 : {
34 1 : std::shared_ptr<IWebAudioPlayerFactory> IWebAudioPlayerFactory::createFactory()
35 : {
36 1 : return server::IWebAudioPlayerServerInternalFactory::createFactory();
37 : }
38 : }; // namespace firebolt::rialto
39 :
40 : namespace firebolt::rialto::server
41 : {
42 2 : std::shared_ptr<IWebAudioPlayerServerInternalFactory> IWebAudioPlayerServerInternalFactory::createFactory()
43 : {
44 2 : std::shared_ptr<IWebAudioPlayerServerInternalFactory> factory;
45 :
46 : try
47 : {
48 2 : factory = std::make_shared<server::WebAudioPlayerServerInternalFactory>();
49 : }
50 0 : catch (const std::exception &e)
51 : {
52 0 : RIALTO_SERVER_LOG_ERROR("Failed to create the web audio player factory, reason: %s", e.what());
53 : }
54 :
55 2 : return factory;
56 : }
57 :
58 : std::unique_ptr<IWebAudioPlayer>
59 1 : WebAudioPlayerServerInternalFactory::createWebAudioPlayer(std::weak_ptr<IWebAudioPlayerClient> client,
60 : const std::string &audioMimeType, const uint32_t priority,
61 : std::weak_ptr<const WebAudioConfig> config) const
62 : {
63 1 : RIALTO_SERVER_LOG_ERROR(
64 : "This function can't be used by rialto server. Please use createWebAudioPlayerServerInternal");
65 1 : return nullptr;
66 : }
67 :
68 1 : std::unique_ptr<IWebAudioPlayerServerInternal> WebAudioPlayerServerInternalFactory::createWebAudioPlayerServerInternal(
69 : std::weak_ptr<IWebAudioPlayerClient> client, const std::string &audioMimeType, const uint32_t priority,
70 : std::weak_ptr<const WebAudioConfig> config, const std::shared_ptr<ISharedMemoryBuffer> &shmBuffer, int handle,
71 : const std::shared_ptr<IMainThreadFactory> &mainThreadFactory,
72 : const std::shared_ptr<IGstWebAudioPlayerFactory> &gstPlayerFactory,
73 : std::weak_ptr<common::ITimerFactory> timerFactory) const
74 : {
75 1 : std::unique_ptr<IWebAudioPlayerServerInternal> webAudioPlayer;
76 : try
77 : {
78 2 : webAudioPlayer = std::make_unique<server::WebAudioPlayerServerInternal>(client, audioMimeType, priority, config,
79 : shmBuffer, handle, mainThreadFactory,
80 1 : gstPlayerFactory, timerFactory);
81 : }
82 0 : catch (const std::exception &e)
83 : {
84 0 : RIALTO_SERVER_LOG_ERROR("Failed to create the web audio player, reason: %s", e.what());
85 : }
86 :
87 1 : return webAudioPlayer;
88 : }
89 :
90 39 : WebAudioPlayerServerInternal::WebAudioPlayerServerInternal(
91 : std::weak_ptr<IWebAudioPlayerClient> client, const std::string &audioMimeType, const uint32_t priority,
92 : std::weak_ptr<const WebAudioConfig> webAudioConfig, const std::shared_ptr<ISharedMemoryBuffer> &shmBuffer,
93 : int handle, const std::shared_ptr<IMainThreadFactory> &mainThreadFactory,
94 39 : const std::shared_ptr<IGstWebAudioPlayerFactory> &gstPlayerFactory, std::weak_ptr<common::ITimerFactory> timerFactory)
95 39 : : m_webAudioPlayerClient(client), m_shmBuffer{shmBuffer}, m_priority{priority}, m_shmId{handle}, m_shmPtr{nullptr},
96 39 : m_partitionOffset{0}, m_maxDataLength{0}, m_availableBuffer{}, m_expectWriteBuffer{false},
97 78 : m_timerFactory{timerFactory}, m_bytesPerFrame{0}, m_isEosRequested{false}
98 : {
99 39 : RIALTO_SERVER_LOG_DEBUG("entry:");
100 :
101 39 : if (audioMimeType == "audio/x-raw")
102 : {
103 38 : std::shared_ptr<const WebAudioConfig> kConfig = webAudioConfig.lock();
104 38 : if (kConfig == nullptr)
105 : {
106 1 : throw std::runtime_error("Config is null for 'audio/x-raw'");
107 : }
108 37 : m_bytesPerFrame = kConfig->pcm.channels * (kConfig->pcm.sampleSize / CHAR_BIT);
109 37 : if (m_bytesPerFrame == 0)
110 : {
111 3 : throw std::runtime_error("Bytes per frame cannot be 0, channels " + std::to_string(kConfig->pcm.channels) +
112 4 : ", sampleSize " + std::to_string(kConfig->pcm.sampleSize));
113 : }
114 38 : }
115 : else
116 : {
117 1 : throw std::runtime_error("Mimetype '" + audioMimeType + "' not supported");
118 : }
119 :
120 36 : m_mainThread = mainThreadFactory->getMainThread();
121 36 : if (!m_mainThread)
122 : {
123 1 : throw std::runtime_error("Failed to get the main thread");
124 : }
125 35 : m_mainThreadClientId = m_mainThread->registerClient();
126 :
127 35 : bool result = false;
128 35 : auto task = [&]() { result = initWebAudioPlayerInternal(audioMimeType, webAudioConfig, gstPlayerFactory); };
129 :
130 35 : m_mainThread->enqueueTaskAndWait(m_mainThreadClientId, task);
131 35 : if (!result)
132 : {
133 5 : throw std::runtime_error("WebAudioPlayerServerInternal construction failed");
134 : }
135 102 : }
136 :
137 35 : bool WebAudioPlayerServerInternal::initWebAudioPlayerInternal(
138 : const std::string &audioMimeType, std::weak_ptr<const WebAudioConfig> config,
139 : const std::shared_ptr<IGstWebAudioPlayerFactory> &gstPlayerFactory)
140 : {
141 35 : if (!m_shmBuffer->mapPartition(ISharedMemoryBuffer::MediaPlaybackType::WEB_AUDIO, m_shmId))
142 : {
143 1 : RIALTO_SERVER_LOG_ERROR("Unable to map shm partition");
144 1 : return false;
145 : }
146 :
147 34 : if (!(m_shmPtr = m_shmBuffer->getBuffer()))
148 : {
149 1 : RIALTO_SERVER_LOG_ERROR("Failed to get the data pointer for the shared memory");
150 1 : return false;
151 : }
152 :
153 : try
154 : {
155 33 : m_partitionOffset = m_shmBuffer->getDataOffset(ISharedMemoryBuffer::MediaPlaybackType::WEB_AUDIO, m_shmId,
156 33 : MediaSourceType::AUDIO);
157 : }
158 1 : catch (const std::exception &e)
159 : {
160 1 : RIALTO_SERVER_LOG_ERROR("Failed to get the data pointer of the partition");
161 1 : return false;
162 : }
163 :
164 32 : if (!(m_maxDataLength = m_shmBuffer->getMaxDataLen(ISharedMemoryBuffer::MediaPlaybackType::WEB_AUDIO, m_shmId,
165 32 : MediaSourceType::AUDIO)))
166 : {
167 1 : RIALTO_SERVER_LOG_ERROR("Failed to get the length of the partition");
168 1 : return false;
169 : }
170 :
171 31 : if (!initGstWebAudioPlayer(audioMimeType, config, gstPlayerFactory))
172 : {
173 1 : RIALTO_SERVER_LOG_ERROR("Failed to initalise the GstPlayer");
174 1 : return false;
175 : }
176 :
177 : // Set the available bytes
178 30 : m_availableBuffer.lengthMain = m_maxDataLength;
179 30 : m_availableBuffer.offsetMain = m_partitionOffset;
180 30 : m_availableBuffer.offsetWrap = m_partitionOffset;
181 :
182 30 : return true;
183 : }
184 :
185 60 : WebAudioPlayerServerInternal::~WebAudioPlayerServerInternal()
186 : {
187 30 : RIALTO_SERVER_LOG_DEBUG("entry:");
188 :
189 30 : auto task = [&]()
190 : {
191 30 : if (m_writeDataTimer && (m_writeDataTimer->isActive()))
192 : {
193 4 : m_writeDataTimer->cancel();
194 : }
195 :
196 30 : if (!m_shmBuffer->unmapPartition(ISharedMemoryBuffer::MediaPlaybackType::WEB_AUDIO, m_shmId))
197 : {
198 0 : RIALTO_SERVER_LOG_ERROR("Unable to unmap shm partition");
199 : }
200 :
201 30 : m_shmBuffer.reset();
202 30 : m_mainThread->unregisterClient(m_mainThreadClientId);
203 60 : };
204 30 : m_mainThread->enqueueTaskAndWait(m_mainThreadClientId, task);
205 60 : }
206 :
207 1 : bool WebAudioPlayerServerInternal::play()
208 : {
209 1 : RIALTO_SERVER_LOG_DEBUG("entry:");
210 :
211 1 : auto task = [&]() { m_gstPlayer->play(); };
212 :
213 1 : m_mainThread->enqueueTask(m_mainThreadClientId, task);
214 :
215 1 : return true;
216 : }
217 :
218 1 : bool WebAudioPlayerServerInternal::pause()
219 : {
220 1 : RIALTO_SERVER_LOG_DEBUG("entry:");
221 :
222 1 : auto task = [&]() { m_gstPlayer->pause(); };
223 :
224 1 : m_mainThread->enqueueTask(m_mainThreadClientId, task);
225 :
226 1 : return true;
227 : }
228 :
229 2 : bool WebAudioPlayerServerInternal::setEos()
230 : {
231 2 : RIALTO_SERVER_LOG_DEBUG("entry:");
232 :
233 2 : auto task = [&]()
234 : {
235 2 : if (0 != getQueuedFramesInShm())
236 : {
237 1 : m_isEosRequested = true;
238 : }
239 : else
240 : {
241 1 : m_gstPlayer->setEos();
242 : }
243 4 : };
244 :
245 2 : m_mainThread->enqueueTask(m_mainThreadClientId, task);
246 :
247 2 : return true;
248 : }
249 :
250 31 : bool WebAudioPlayerServerInternal::getBufferAvailable(uint32_t &availableFrames,
251 : std::shared_ptr<WebAudioShmInfo> &webAudioShmInfo)
252 : {
253 31 : RIALTO_SERVER_LOG_DEBUG("entry:");
254 :
255 31 : if (!webAudioShmInfo)
256 : {
257 0 : RIALTO_SERVER_LOG_ERROR("WebAudioShmInfo is null");
258 0 : return false;
259 : }
260 :
261 31 : auto task = [&]()
262 : {
263 31 : *webAudioShmInfo = m_availableBuffer;
264 31 : availableFrames = (m_availableBuffer.lengthMain + m_availableBuffer.lengthWrap) / m_bytesPerFrame;
265 :
266 : // A new getBufferAvailable shall overwrite the previous if writeBuffer is not called inbetween
267 31 : m_expectWriteBuffer = true;
268 62 : };
269 :
270 31 : m_mainThread->enqueueTaskAndWait(m_mainThreadClientId, task);
271 :
272 31 : return true;
273 : }
274 :
275 3 : bool WebAudioPlayerServerInternal::getBufferDelay(uint32_t &delayFrames)
276 : {
277 3 : RIALTO_SERVER_LOG_DEBUG("entry:");
278 :
279 3 : bool status = false;
280 3 : auto task = [&]()
281 : {
282 : // Gstreamer returns a uint64, so check the value first
283 3 : uint64_t queuedFrames = (m_gstPlayer->getQueuedBytes() / m_bytesPerFrame) + getQueuedFramesInShm();
284 3 : if (queuedFrames > std::numeric_limits<uint32_t>::max())
285 : {
286 1 : RIALTO_SERVER_LOG_ERROR("Queued frames are larger than the max uint32_t");
287 : }
288 : else
289 : {
290 2 : delayFrames = static_cast<uint32_t>(queuedFrames);
291 2 : status = true;
292 : }
293 6 : };
294 :
295 3 : m_mainThread->enqueueTaskAndWait(m_mainThreadClientId, task);
296 3 : return status;
297 : }
298 :
299 24 : bool WebAudioPlayerServerInternal::writeBuffer(const uint32_t numberOfFrames, void *data)
300 : {
301 24 : RIALTO_SERVER_LOG_DEBUG("entry:");
302 :
303 24 : bool result = false;
304 24 : auto task = [&]()
305 : {
306 : // data can be ignored, the frames should be written to the shared memory
307 24 : result = writeBufferInternal(numberOfFrames);
308 48 : };
309 :
310 24 : m_mainThread->enqueueTaskAndWait(m_mainThreadClientId, task);
311 :
312 24 : return result;
313 : }
314 :
315 24 : bool WebAudioPlayerServerInternal::writeBufferInternal(const uint32_t numberOfFrames)
316 : {
317 24 : if (!m_expectWriteBuffer)
318 : {
319 4 : RIALTO_SERVER_LOG_ERROR("No getBufferAvailable to match with this writeBuffer call");
320 4 : return false;
321 : }
322 20 : m_expectWriteBuffer = false;
323 :
324 : // Cancel timer
325 20 : if (m_writeDataTimer && (m_writeDataTimer->isActive()))
326 : {
327 7 : m_writeDataTimer->cancel();
328 7 : m_writeDataTimer = nullptr;
329 : }
330 :
331 : // Write stored frames first
332 20 : uint32_t numberOfBytesToWrite = numberOfFrames * m_bytesPerFrame;
333 20 : if (!writeStoredBuffers())
334 : {
335 : // Update the available buffer with the new data that will not be written to gst
336 2 : updateAvailableBuffer(numberOfBytesToWrite, 0);
337 : m_writeDataTimer =
338 6 : m_timerFactory->createTimer(kWriteDataTimeMs,
339 4 : std::bind(&WebAudioPlayerServerInternal::handleWriteDataTimer, this));
340 2 : return true;
341 : }
342 :
343 18 : if (0 == numberOfFrames)
344 : {
345 : // No frames to write to gst
346 2 : return true;
347 : }
348 :
349 : // Write new frames
350 16 : uint8_t *mainPtr = m_shmPtr + m_availableBuffer.offsetMain;
351 16 : uint8_t *wrapPtr = m_shmPtr + m_availableBuffer.offsetWrap;
352 16 : uint32_t mainLength = 0;
353 16 : uint32_t wrapLength = 0;
354 16 : if (numberOfBytesToWrite <= m_availableBuffer.lengthMain)
355 : {
356 14 : mainLength = numberOfBytesToWrite;
357 : }
358 : else
359 : {
360 2 : mainLength = m_availableBuffer.lengthMain;
361 2 : wrapLength = numberOfBytesToWrite - mainLength;
362 : }
363 :
364 16 : uint32_t newBytesWritten = m_gstPlayer->writeBuffer(mainPtr, mainLength, wrapPtr, wrapLength);
365 16 : updateAvailableBuffer(numberOfBytesToWrite, newBytesWritten);
366 16 : if (newBytesWritten != numberOfBytesToWrite)
367 : {
368 : m_writeDataTimer =
369 30 : m_timerFactory->createTimer(kWriteDataTimeMs,
370 30 : std::bind(&WebAudioPlayerServerInternal::handleWriteDataTimer, this));
371 : }
372 :
373 16 : return true;
374 : }
375 :
376 22 : bool WebAudioPlayerServerInternal::writeStoredBuffers()
377 : {
378 22 : uint8_t *mainPtr = nullptr;
379 22 : uint32_t mainLength = 0;
380 22 : uint8_t *wrapPtr = nullptr;
381 22 : uint32_t wrapLength = 0;
382 :
383 22 : if (m_availableBuffer.lengthWrap + m_availableBuffer.lengthMain == m_maxDataLength)
384 : {
385 : // No data stored
386 13 : return true;
387 : }
388 9 : else if (m_availableBuffer.lengthWrap != 0)
389 : {
390 : // Data stored in the shared memory has not wrapped, data only stored in the middle of the shared memory region
391 5 : uint32_t startOfDataOffset = m_availableBuffer.offsetWrap + m_availableBuffer.lengthWrap;
392 5 : mainPtr = m_shmPtr + startOfDataOffset;
393 5 : mainLength = m_availableBuffer.offsetMain - startOfDataOffset;
394 : }
395 : else
396 : {
397 : // Data stored in the shared memory has wrapped, data stored at the end and start of the shared memory region
398 4 : uint32_t startOfDataOffset = m_availableBuffer.offsetMain + m_availableBuffer.lengthMain;
399 4 : mainPtr = m_shmPtr + startOfDataOffset;
400 4 : mainLength = m_maxDataLength - (startOfDataOffset - m_partitionOffset);
401 : // Wrapped data stored at the start of the shared memory region up to where the availableBuffer starts
402 4 : wrapPtr = m_shmPtr + m_partitionOffset;
403 4 : wrapLength = m_availableBuffer.offsetMain - m_partitionOffset;
404 : }
405 :
406 9 : uint32_t storedBytesWritten = m_gstPlayer->writeBuffer(mainPtr, mainLength, wrapPtr, wrapLength);
407 :
408 : // Update available buffer with the bytes written to gst.
409 : // Bytes written to shm is 0 becuase they have already been handled.
410 9 : updateAvailableBuffer(0, storedBytesWritten);
411 :
412 9 : if (storedBytesWritten == mainLength + wrapLength)
413 : {
414 : // All data written to gstreamer
415 6 : if (m_isEosRequested)
416 : {
417 1 : m_gstPlayer->setEos();
418 1 : m_isEosRequested = false;
419 : }
420 6 : return true;
421 : }
422 :
423 3 : return false;
424 : }
425 :
426 27 : void WebAudioPlayerServerInternal::updateAvailableBuffer(uint32_t bytesWrittenToShm, uint32_t bytesWrittenToGst)
427 : {
428 27 : if (bytesWrittenToShm <= m_availableBuffer.lengthMain)
429 : {
430 : // Data written to the shared memory has not wrapped
431 24 : uint32_t offetRelativeToPartition = m_availableBuffer.offsetMain - m_partitionOffset;
432 24 : uint32_t storedDataLengthAtEndOfShm = m_maxDataLength - (offetRelativeToPartition + m_availableBuffer.lengthMain);
433 :
434 24 : m_availableBuffer.offsetMain = m_availableBuffer.offsetMain + bytesWrittenToShm;
435 24 : if (bytesWrittenToGst <= storedDataLengthAtEndOfShm)
436 : {
437 : // Data written to gst has not wrapped, data written is taken from the main buffer only
438 7 : m_availableBuffer.lengthMain = m_availableBuffer.lengthMain - bytesWrittenToShm + bytesWrittenToGst;
439 : }
440 : else
441 : {
442 : // Data written to gst has wrapped, data written is taken from the main buffer and wrapped buffer
443 17 : m_availableBuffer.lengthMain = m_availableBuffer.lengthMain - bytesWrittenToShm + storedDataLengthAtEndOfShm;
444 17 : m_availableBuffer.lengthWrap = m_availableBuffer.lengthWrap +
445 17 : (bytesWrittenToGst - storedDataLengthAtEndOfShm);
446 : }
447 : }
448 : else
449 : {
450 : // Data written to the shared memory has wrapped, available buffer should now point to where the wrapped buffer was
451 3 : uint32_t newDataLengthAtEndOfShm = m_availableBuffer.lengthMain;
452 :
453 3 : m_availableBuffer.offsetMain = m_availableBuffer.offsetWrap + (bytesWrittenToShm - m_availableBuffer.lengthMain);
454 3 : uint32_t newOffetRelativeToPartition = m_availableBuffer.offsetMain - m_partitionOffset;
455 3 : if (bytesWrittenToGst <= m_availableBuffer.lengthMain)
456 : {
457 : // Data written to gstreamer has not wrapped, data written is taken from the main buffer only
458 1 : m_availableBuffer.lengthMain = (m_availableBuffer.lengthWrap - newOffetRelativeToPartition) +
459 : bytesWrittenToGst;
460 1 : m_availableBuffer.lengthWrap = 0;
461 : }
462 : else
463 : {
464 : // Data written to gstreamer has wrapped, data written is taken from the main buffer and wrapped buffer
465 2 : m_availableBuffer.lengthMain = m_maxDataLength - newOffetRelativeToPartition;
466 2 : m_availableBuffer.lengthWrap = bytesWrittenToGst - newDataLengthAtEndOfShm;
467 : }
468 : }
469 27 : }
470 :
471 2 : bool WebAudioPlayerServerInternal::getDeviceInfo(uint32_t &preferredFrames, uint32_t &maximumFrames,
472 : bool &supportDeferredPlay)
473 : {
474 2 : RIALTO_SERVER_LOG_DEBUG("entry:");
475 :
476 : // Can be called from any thread
477 2 : maximumFrames = m_maxDataLength / m_bytesPerFrame;
478 2 : preferredFrames = std::min(kPreferredFrames, maximumFrames);
479 2 : supportDeferredPlay = true;
480 :
481 2 : return true;
482 : }
483 :
484 1 : bool WebAudioPlayerServerInternal::setVolume(double volume)
485 : {
486 1 : RIALTO_SERVER_LOG_DEBUG("entry:");
487 :
488 1 : auto task = [&, volume]() { m_gstPlayer->setVolume(volume); };
489 :
490 1 : m_mainThread->enqueueTask(m_mainThreadClientId, task);
491 :
492 1 : return true;
493 : }
494 :
495 2 : bool WebAudioPlayerServerInternal::getVolume(double &volume)
496 : {
497 2 : RIALTO_SERVER_LOG_DEBUG("entry:");
498 :
499 2 : bool result = false;
500 2 : auto task = [&]() { result = m_gstPlayer->getVolume(volume); };
501 :
502 2 : m_mainThread->enqueueTaskAndWait(m_mainThreadClientId, task);
503 :
504 2 : return result;
505 : }
506 :
507 0 : std::weak_ptr<IWebAudioPlayerClient> WebAudioPlayerServerInternal::getClient()
508 : {
509 0 : return m_webAudioPlayerClient;
510 : }
511 :
512 1 : void WebAudioPlayerServerInternal::notifyState(WebAudioPlayerState state)
513 : {
514 1 : RIALTO_SERVER_LOG_DEBUG("entry:");
515 :
516 2 : auto task = [&, state]()
517 : {
518 1 : if (m_webAudioPlayerClient)
519 : {
520 1 : m_webAudioPlayerClient->notifyState(state);
521 : }
522 2 : };
523 :
524 1 : m_mainThread->enqueueTask(m_mainThreadClientId, task);
525 : }
526 :
527 31 : bool WebAudioPlayerServerInternal::initGstWebAudioPlayer(const std::string &audioMimeType,
528 : std::weak_ptr<const WebAudioConfig> config,
529 : const std::shared_ptr<IGstWebAudioPlayerFactory> &gstPlayerFactory)
530 : {
531 31 : m_gstPlayer = gstPlayerFactory->createGstWebAudioPlayer(this, m_priority);
532 31 : if (!m_gstPlayer)
533 : {
534 1 : RIALTO_SERVER_LOG_ERROR("Failed to load gstreamer player");
535 1 : return false;
536 : }
537 :
538 30 : m_gstPlayer->setCaps(audioMimeType, config);
539 :
540 30 : return true;
541 : }
542 :
543 2 : void WebAudioPlayerServerInternal::handleWriteDataTimer()
544 : {
545 2 : RIALTO_SERVER_LOG_DEBUG("entry:");
546 :
547 2 : auto task = [&]()
548 : {
549 2 : if (!writeStoredBuffers())
550 : {
551 : // Not all data was written to gstreamer, restart the timer
552 : m_writeDataTimer =
553 3 : m_timerFactory->createTimer(kWriteDataTimeMs,
554 3 : std::bind(&WebAudioPlayerServerInternal::handleWriteDataTimer, this));
555 : }
556 : else
557 : {
558 1 : m_writeDataTimer = nullptr;
559 : }
560 2 : };
561 :
562 2 : m_mainThread->enqueueTask(m_mainThreadClientId, task);
563 : }
564 :
565 5 : uint32_t WebAudioPlayerServerInternal::getQueuedFramesInShm()
566 : {
567 5 : return (m_maxDataLength - (m_availableBuffer.lengthMain + m_availableBuffer.lengthWrap)) / m_bytesPerFrame;
568 : }
569 :
570 1 : void WebAudioPlayerServerInternal::ping(std::unique_ptr<IHeartbeatHandler> &&heartbeatHandler)
571 : {
572 1 : RIALTO_SERVER_LOG_DEBUG("entry:");
573 :
574 1 : auto task = [&]() { m_gstPlayer->ping(std::move(heartbeatHandler)); };
575 1 : m_mainThread->enqueueTaskAndWait(m_mainThreadClientId, task);
576 : }
577 : }; // namespace firebolt::rialto::server
|