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 2023 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 <cstring>
21 : #include <limits.h>
22 : #include <mutex>
23 : #include <stdexcept>
24 :
25 : #include "IWebAudioPlayerIpc.h"
26 : #include "IWebAudioPlayerIpcClient.h"
27 : #include "RialtoClientLogging.h"
28 : #include "WebAudioPlayer.h"
29 : #include "WebAudioPlayerProxy.h"
30 :
31 : namespace firebolt::rialto
32 : {
33 2 : std::shared_ptr<IWebAudioPlayerFactory> IWebAudioPlayerFactory::createFactory()
34 : {
35 2 : std::shared_ptr<IWebAudioPlayerFactory> factory;
36 :
37 : try
38 : {
39 2 : factory = std::make_shared<WebAudioPlayerFactory>();
40 : }
41 0 : catch (const std::exception &e)
42 : {
43 0 : RIALTO_CLIENT_LOG_ERROR("Failed to create the web audio player factory, reason: %s", e.what());
44 : }
45 :
46 2 : return factory;
47 : }
48 :
49 : std::unique_ptr<IWebAudioPlayer>
50 0 : WebAudioPlayerFactory::createWebAudioPlayer(std::weak_ptr<IWebAudioPlayerClient> client, const std::string &audioMimeType,
51 : const uint32_t priority, std::weak_ptr<const WebAudioConfig> config) const
52 : {
53 0 : return createWebAudioPlayer(client, audioMimeType, priority, config, {}, {});
54 : }
55 :
56 : std::unique_ptr<IWebAudioPlayer>
57 2 : WebAudioPlayerFactory::createWebAudioPlayer(std::weak_ptr<IWebAudioPlayerClient> client, const std::string &audioMimeType,
58 : const uint32_t priority, std::weak_ptr<const WebAudioConfig> config,
59 : std::weak_ptr<client::IWebAudioPlayerIpcFactory> webAudioPlayerIpcFactory,
60 : std::weak_ptr<client::IClientController> clientController) const
61 : {
62 2 : std::unique_ptr<IWebAudioPlayer> webAudioPlayer;
63 : try
64 : {
65 : std::shared_ptr<client::IWebAudioPlayerIpcFactory> webAudioPlayerIpcFactoryLocked =
66 2 : webAudioPlayerIpcFactory.lock();
67 2 : std::shared_ptr<client::IClientController> clientControllerLocked = clientController.lock();
68 : client::IClientController &cc = clientControllerLocked
69 2 : ? *clientControllerLocked
70 2 : : client::IClientControllerAccessor::instance().getClientController();
71 :
72 : auto wap{std::make_shared<client::WebAudioPlayer>(client, audioMimeType, priority, config,
73 : webAudioPlayerIpcFactoryLocked
74 3 : ? webAudioPlayerIpcFactoryLocked
75 2 : : client::IWebAudioPlayerIpcFactory::getFactory(),
76 2 : cc)};
77 1 : webAudioPlayer = std::make_unique<WebAudioPlayerProxy>(wap, cc);
78 3 : }
79 1 : catch (const std::exception &e)
80 : {
81 1 : RIALTO_CLIENT_LOG_ERROR("Failed to create the web audio player, reason: %s", e.what());
82 : }
83 :
84 2 : return webAudioPlayer;
85 : }
86 :
87 4 : WebAudioPlayerProxy::WebAudioPlayerProxy(const std::shared_ptr<IWebAudioPlayerAndIControlClient> &ptr,
88 4 : client::IClientController &clientController)
89 4 : : m_webAudioPlayer(ptr), m_clientController{clientController}
90 : {
91 4 : ApplicationState state{ApplicationState::UNKNOWN};
92 4 : if (!m_clientController.registerClient(m_webAudioPlayer, state))
93 : {
94 1 : throw std::runtime_error("Failed to register client with clientController");
95 : }
96 3 : m_webAudioPlayer->notifyApplicationState(state);
97 5 : }
98 :
99 4 : WebAudioPlayerProxy::~WebAudioPlayerProxy()
100 : {
101 3 : if (!m_clientController.unregisterClient(m_webAudioPlayer))
102 : {
103 0 : RIALTO_CLIENT_LOG_WARN("Failed to unregister client with clientController");
104 : }
105 4 : }
106 :
107 : }; // namespace firebolt::rialto
108 :
109 : namespace firebolt::rialto::client
110 : {
111 32 : WebAudioPlayer::WebAudioPlayer(std::weak_ptr<IWebAudioPlayerClient> client, const std::string &audioMimeType,
112 : const uint32_t priority, std::weak_ptr<const WebAudioConfig> webAudioConfig,
113 : const std::shared_ptr<IWebAudioPlayerIpcFactory> &webAudioPlayerIpcFactory,
114 32 : IClientController &clientController)
115 96 : : m_webAudioPlayerClient(client), m_clientController{clientController}, m_bytesPerFrame{0},
116 32 : m_currentAppState{ApplicationState::UNKNOWN}
117 : {
118 32 : RIALTO_CLIENT_LOG_DEBUG("entry:");
119 :
120 32 : if (audioMimeType == "audio/x-raw")
121 : {
122 32 : std::shared_ptr<const WebAudioConfig> kConfig = webAudioConfig.lock();
123 32 : if (!kConfig)
124 : {
125 0 : throw std::runtime_error("Config is null for 'audio/x-raw'");
126 : }
127 32 : m_bytesPerFrame = kConfig->pcm.channels * (kConfig->pcm.sampleSize / CHAR_BIT);
128 32 : if (m_bytesPerFrame == 0)
129 : {
130 0 : throw std::runtime_error("Bytes per frame cannot be 0, channels " + std::to_string(kConfig->pcm.channels) +
131 0 : ", sampleSize " + std::to_string(kConfig->pcm.sampleSize));
132 : }
133 32 : }
134 :
135 32 : if (!webAudioPlayerIpcFactory)
136 : {
137 0 : throw std::runtime_error("Web audio player ipc factory could not be null");
138 : }
139 :
140 : m_webAudioPlayerIpc =
141 32 : webAudioPlayerIpcFactory->createWebAudioPlayerIpc(this, audioMimeType, priority, webAudioConfig);
142 32 : if (!m_webAudioPlayerIpc)
143 : {
144 3 : throw std::runtime_error("Web audio player ipc could not be created");
145 : }
146 44 : }
147 :
148 56 : WebAudioPlayer::~WebAudioPlayer()
149 : {
150 29 : RIALTO_CLIENT_LOG_DEBUG("entry:");
151 :
152 29 : m_webAudioPlayerIpc.reset();
153 56 : }
154 :
155 2 : bool WebAudioPlayer::play()
156 : {
157 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
158 :
159 2 : return m_webAudioPlayerIpc->play();
160 : }
161 :
162 2 : bool WebAudioPlayer::pause()
163 : {
164 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
165 :
166 2 : return m_webAudioPlayerIpc->pause();
167 : }
168 :
169 2 : bool WebAudioPlayer::setEos()
170 : {
171 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
172 :
173 2 : return m_webAudioPlayerIpc->setEos();
174 : }
175 :
176 9 : bool WebAudioPlayer::getBufferAvailable(uint32_t &availableFrames, std::shared_ptr<WebAudioShmInfo> &)
177 : {
178 9 : RIALTO_CLIENT_LOG_DEBUG("entry:");
179 9 : std::lock_guard<std::mutex> bufLocker(m_bufLock);
180 9 : if (!m_webAudioShmInfo)
181 : {
182 9 : m_webAudioShmInfo = std::make_shared<WebAudioShmInfo>();
183 : }
184 18 : return m_webAudioPlayerIpc->getBufferAvailable(availableFrames, m_webAudioShmInfo);
185 9 : }
186 :
187 2 : bool WebAudioPlayer::getBufferDelay(uint32_t &delayFrames)
188 : {
189 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
190 :
191 2 : return m_webAudioPlayerIpc->getBufferDelay(delayFrames);
192 : }
193 :
194 8 : bool WebAudioPlayer::writeBuffer(const uint32_t numberOfFrames, void *data)
195 : {
196 8 : RIALTO_CLIENT_LOG_DEBUG("entry:");
197 :
198 8 : std::lock_guard<std::mutex> bufLocker(m_bufLock);
199 8 : if (!m_webAudioShmInfo)
200 : {
201 1 : RIALTO_CLIENT_LOG_ERROR("Web audio shared info is null!");
202 1 : return false;
203 : }
204 :
205 7 : uint32_t dataLength = numberOfFrames * m_bytesPerFrame;
206 7 : uint32_t availableDataLength = m_webAudioShmInfo->lengthMain + m_webAudioShmInfo->lengthWrap;
207 7 : if (dataLength > availableDataLength)
208 : {
209 1 : RIALTO_CLIENT_LOG_ERROR("The number of frames to write exceeds the available space!");
210 1 : return false;
211 : }
212 :
213 6 : if (ApplicationState::RUNNING != m_currentAppState)
214 : {
215 1 : RIALTO_CLIENT_LOG_ERROR("Current ApplicationState is not RUNNING!");
216 1 : return false;
217 : }
218 :
219 5 : std::shared_ptr<ISharedMemoryHandle> shmHandle = m_clientController.getSharedMemoryHandle();
220 5 : if (nullptr == shmHandle || nullptr == shmHandle->getShm())
221 : {
222 2 : RIALTO_CLIENT_LOG_ERROR("Shared buffer no longer valid");
223 2 : return false;
224 : }
225 :
226 3 : if (dataLength > m_webAudioShmInfo->lengthMain)
227 : {
228 1 : std::memcpy(shmHandle->getShm() + m_webAudioShmInfo->offsetMain, data, m_webAudioShmInfo->lengthMain);
229 1 : std::memcpy(shmHandle->getShm() + m_webAudioShmInfo->offsetWrap,
230 1 : reinterpret_cast<uint8_t *>(data) + m_webAudioShmInfo->lengthMain,
231 1 : dataLength - m_webAudioShmInfo->lengthMain);
232 : }
233 : else
234 : {
235 2 : std::memcpy(shmHandle->getShm() + m_webAudioShmInfo->offsetMain, data, dataLength);
236 : }
237 3 : return m_webAudioPlayerIpc->writeBuffer(numberOfFrames);
238 8 : }
239 :
240 2 : bool WebAudioPlayer::getDeviceInfo(uint32_t &preferredFrames, uint32_t &maximumFrames, bool &supportDeferredPlay)
241 : {
242 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
243 :
244 2 : return m_webAudioPlayerIpc->getDeviceInfo(preferredFrames, maximumFrames, supportDeferredPlay);
245 : }
246 :
247 2 : bool WebAudioPlayer::setVolume(double volume)
248 : {
249 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
250 :
251 2 : return m_webAudioPlayerIpc->setVolume(volume);
252 : }
253 :
254 2 : bool WebAudioPlayer::getVolume(double &volume)
255 : {
256 2 : RIALTO_CLIENT_LOG_DEBUG("entry:");
257 :
258 2 : return m_webAudioPlayerIpc->getVolume(volume);
259 : }
260 :
261 0 : std::weak_ptr<IWebAudioPlayerClient> WebAudioPlayer::getClient()
262 : {
263 0 : return m_webAudioPlayerClient;
264 : }
265 :
266 1 : void WebAudioPlayer::notifyState(WebAudioPlayerState state)
267 : {
268 1 : std::shared_ptr<IWebAudioPlayerClient> client = m_webAudioPlayerClient.lock();
269 1 : if (client)
270 : {
271 1 : client->notifyState(state);
272 : }
273 : }
274 :
275 28 : void WebAudioPlayer::notifyApplicationState(ApplicationState state)
276 : {
277 28 : m_currentAppState = state;
278 : }
279 :
280 : }; // namespace firebolt::rialto::client
|