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 "WebAudioPlayerModuleService.h"
21 : #include "IWebAudioPlayerService.h"
22 : #include "RialtoServerLogging.h"
23 : #include "WebAudioPlayerClient.h"
24 : #include <IIpcController.h>
25 : #include <algorithm>
26 : #include <cstdint>
27 :
28 : namespace
29 : {
30 5 : int generateHandle()
31 : {
32 : static int webAudioPlayerHandle{0};
33 5 : return webAudioPlayerHandle++;
34 : }
35 : } // namespace
36 :
37 : namespace firebolt::rialto::server::ipc
38 : {
39 1 : std::shared_ptr<IWebAudioPlayerModuleServiceFactory> IWebAudioPlayerModuleServiceFactory::createFactory()
40 : {
41 1 : std::shared_ptr<IWebAudioPlayerModuleServiceFactory> factory;
42 :
43 : try
44 : {
45 1 : factory = std::make_shared<WebAudioPlayerModuleServiceFactory>();
46 : }
47 0 : catch (const std::exception &e)
48 : {
49 0 : RIALTO_SERVER_LOG_ERROR("Failed to create the web audio player module service factory, reason: %s", e.what());
50 : }
51 :
52 1 : return factory;
53 : }
54 :
55 : std::shared_ptr<IWebAudioPlayerModuleService>
56 1 : WebAudioPlayerModuleServiceFactory::create(service::IWebAudioPlayerService &webAudioPlayerService) const
57 : {
58 1 : std::shared_ptr<IWebAudioPlayerModuleService> webAudioPlayerModule;
59 :
60 : try
61 : {
62 1 : webAudioPlayerModule = std::make_shared<WebAudioPlayerModuleService>(webAudioPlayerService);
63 : }
64 0 : catch (const std::exception &e)
65 : {
66 0 : RIALTO_SERVER_LOG_ERROR("Failed to create the web audio player module service, reason: %s", e.what());
67 : }
68 :
69 1 : return webAudioPlayerModule;
70 : }
71 :
72 28 : WebAudioPlayerModuleService::WebAudioPlayerModuleService(service::IWebAudioPlayerService &webAudioPlayerService)
73 28 : : m_webAudioPlayerService{webAudioPlayerService}
74 : {
75 : }
76 :
77 : WebAudioPlayerModuleService::~WebAudioPlayerModuleService() {}
78 :
79 2 : void WebAudioPlayerModuleService::clientConnected(const std::shared_ptr<::firebolt::rialto::ipc::IClient> &ipcClient)
80 : {
81 2 : RIALTO_SERVER_LOG_INFO("Client Connected!");
82 : {
83 2 : m_clientWebAudioPlayerHandles.emplace(ipcClient, std::set<int>());
84 : }
85 2 : ipcClient->exportService(shared_from_this());
86 : }
87 :
88 1 : void WebAudioPlayerModuleService::clientDisconnected(const std::shared_ptr<::firebolt::rialto::ipc::IClient> &ipcClient)
89 : {
90 1 : RIALTO_SERVER_LOG_INFO("Client disconnected!");
91 1 : std::set<int> webAudioPlayerHandles;
92 : {
93 1 : auto handleIter = m_clientWebAudioPlayerHandles.find(ipcClient);
94 1 : if (handleIter == m_clientWebAudioPlayerHandles.end())
95 : {
96 0 : RIALTO_SERVER_LOG_ERROR("unknown client disconnected");
97 0 : return;
98 : }
99 1 : webAudioPlayerHandles = handleIter->second; // copy to avoid deadlock
100 1 : m_clientWebAudioPlayerHandles.erase(handleIter);
101 : }
102 2 : for (const auto &webAudioPlayerHandle : webAudioPlayerHandles)
103 : {
104 1 : m_webAudioPlayerService.destroyWebAudioPlayer(webAudioPlayerHandle);
105 : }
106 : }
107 :
108 5 : void WebAudioPlayerModuleService::createWebAudioPlayer(::google::protobuf::RpcController *controller,
109 : const ::firebolt::rialto::CreateWebAudioPlayerRequest *request,
110 : ::firebolt::rialto::CreateWebAudioPlayerResponse *response,
111 : ::google::protobuf::Closure *done)
112 : {
113 5 : RIALTO_SERVER_LOG_DEBUG("entry:");
114 5 : auto ipcController = dynamic_cast<firebolt::rialto::ipc::IController *>(controller);
115 5 : if (!ipcController)
116 : {
117 0 : RIALTO_SERVER_LOG_ERROR("ipc library provided incompatible controller object");
118 0 : controller->SetFailed("ipc library provided incompatible controller object");
119 0 : done->Run();
120 0 : return;
121 : }
122 :
123 5 : std::shared_ptr<WebAudioConfig> config = std::make_shared<WebAudioConfig>();
124 5 : if (request->has_config())
125 : {
126 1 : if (request->config().has_pcm())
127 : {
128 1 : config->pcm.rate = request->config().pcm().rate();
129 1 : config->pcm.channels = request->config().pcm().channels();
130 1 : config->pcm.sampleSize = request->config().pcm().sample_size();
131 1 : config->pcm.isBigEndian = request->config().pcm().is_big_endian();
132 1 : config->pcm.isSigned = request->config().pcm().is_signed();
133 1 : config->pcm.isFloat = request->config().pcm().is_float();
134 : }
135 : }
136 5 : int handle = generateHandle();
137 : bool webAudioPlayerCreated =
138 10 : m_webAudioPlayerService.createWebAudioPlayer(handle,
139 10 : std::make_shared<WebAudioPlayerClient>(handle,
140 10 : ipcController->getClient()),
141 : request->audio_mime_type(), request->priority(), config);
142 5 : if (webAudioPlayerCreated)
143 : {
144 : // Assume that IPC library works well and client is present
145 4 : m_clientWebAudioPlayerHandles[ipcController->getClient()].insert(handle);
146 4 : response->set_web_audio_player_handle(handle);
147 : }
148 : else
149 : {
150 1 : RIALTO_SERVER_LOG_ERROR("Create web audio player failed");
151 1 : controller->SetFailed("Operation failed");
152 : }
153 5 : done->Run();
154 : }
155 :
156 2 : void WebAudioPlayerModuleService::destroyWebAudioPlayer(::google::protobuf::RpcController *controller,
157 : const ::firebolt::rialto::DestroyWebAudioPlayerRequest *request,
158 : ::firebolt::rialto::DestroyWebAudioPlayerResponse *response,
159 : ::google::protobuf::Closure *done)
160 : {
161 2 : RIALTO_SERVER_LOG_DEBUG("entry:");
162 2 : auto ipcController = dynamic_cast<firebolt::rialto::ipc::IController *>(controller);
163 2 : if (!ipcController)
164 : {
165 0 : RIALTO_SERVER_LOG_ERROR("ipc library provided incompatible controller object");
166 0 : controller->SetFailed("ipc library provided incompatible controller object");
167 0 : done->Run();
168 1 : return;
169 : }
170 2 : if (!m_webAudioPlayerService.destroyWebAudioPlayer(request->web_audio_player_handle()))
171 : {
172 1 : RIALTO_SERVER_LOG_ERROR("Destroy web audio player failed");
173 1 : controller->SetFailed("Operation failed");
174 1 : done->Run();
175 1 : return;
176 : }
177 1 : auto handleIter = m_clientWebAudioPlayerHandles.find(ipcController->getClient());
178 1 : if (handleIter != m_clientWebAudioPlayerHandles.end())
179 : {
180 0 : handleIter->second.erase(request->web_audio_player_handle());
181 : }
182 1 : done->Run();
183 : }
184 :
185 2 : void WebAudioPlayerModuleService::play(::google::protobuf::RpcController *controller,
186 : const ::firebolt::rialto::WebAudioPlayRequest *request,
187 : ::firebolt::rialto::WebAudioPlayResponse *response,
188 : ::google::protobuf::Closure *done)
189 : {
190 2 : RIALTO_SERVER_LOG_DEBUG("entry:");
191 2 : if (!m_webAudioPlayerService.play(request->web_audio_player_handle()))
192 : {
193 1 : RIALTO_SERVER_LOG_ERROR("play failed");
194 1 : controller->SetFailed("Operation failed");
195 : }
196 2 : done->Run();
197 : }
198 :
199 2 : void WebAudioPlayerModuleService::pause(::google::protobuf::RpcController *controller,
200 : const ::firebolt::rialto::WebAudioPauseRequest *request,
201 : ::firebolt::rialto::WebAudioPauseResponse *response,
202 : ::google::protobuf::Closure *done)
203 : {
204 2 : RIALTO_SERVER_LOG_DEBUG("entry:");
205 2 : if (!m_webAudioPlayerService.pause(request->web_audio_player_handle()))
206 : {
207 1 : RIALTO_SERVER_LOG_ERROR("pause failed");
208 1 : controller->SetFailed("Operation failed");
209 : }
210 2 : done->Run();
211 : }
212 :
213 2 : void WebAudioPlayerModuleService::setEos(::google::protobuf::RpcController *controller,
214 : const ::firebolt::rialto::WebAudioSetEosRequest *request,
215 : ::firebolt::rialto::WebAudioSetEosResponse *response,
216 : ::google::protobuf::Closure *done)
217 : {
218 2 : RIALTO_SERVER_LOG_DEBUG("entry:");
219 2 : if (!m_webAudioPlayerService.setEos(request->web_audio_player_handle()))
220 : {
221 1 : RIALTO_SERVER_LOG_ERROR("setEos failed");
222 1 : controller->SetFailed("Operation failed");
223 : }
224 2 : done->Run();
225 : }
226 :
227 2 : void WebAudioPlayerModuleService::getBufferAvailable(::google::protobuf::RpcController *controller,
228 : const ::firebolt::rialto::WebAudioGetBufferAvailableRequest *request,
229 : ::firebolt::rialto::WebAudioGetBufferAvailableResponse *response,
230 : ::google::protobuf::Closure *done)
231 : {
232 2 : RIALTO_SERVER_LOG_DEBUG("entry:");
233 :
234 2 : uint32_t availableFrames{};
235 2 : std::shared_ptr<WebAudioShmInfo> shmInfo = std::make_shared<WebAudioShmInfo>();
236 2 : if (!m_webAudioPlayerService.getBufferAvailable(request->web_audio_player_handle(), availableFrames, shmInfo))
237 : {
238 1 : RIALTO_SERVER_LOG_ERROR("getBufferAvailable failed");
239 1 : controller->SetFailed("Operation failed");
240 : }
241 : else
242 : {
243 1 : response->set_available_frames(availableFrames);
244 1 : auto responseShmInfo = response->mutable_shm_info();
245 1 : responseShmInfo->set_offset_main(shmInfo->offsetMain);
246 1 : responseShmInfo->set_length_main(shmInfo->lengthMain);
247 1 : responseShmInfo->set_offset_wrap(shmInfo->offsetWrap);
248 1 : responseShmInfo->set_length_wrap(shmInfo->lengthWrap);
249 : }
250 2 : done->Run();
251 : }
252 :
253 2 : void WebAudioPlayerModuleService::getBufferDelay(::google::protobuf::RpcController *controller,
254 : const ::firebolt::rialto::WebAudioGetBufferDelayRequest *request,
255 : ::firebolt::rialto::WebAudioGetBufferDelayResponse *response,
256 : ::google::protobuf::Closure *done)
257 : {
258 2 : RIALTO_SERVER_LOG_DEBUG("entry:");
259 :
260 2 : uint32_t delayFrames{};
261 2 : if (!m_webAudioPlayerService.getBufferDelay(request->web_audio_player_handle(), delayFrames))
262 : {
263 1 : RIALTO_SERVER_LOG_ERROR("getBufferDelay failed");
264 1 : controller->SetFailed("Operation failed");
265 : }
266 : else
267 : {
268 1 : response->set_delay_frames(delayFrames);
269 : }
270 2 : done->Run();
271 : }
272 :
273 2 : void WebAudioPlayerModuleService::writeBuffer(::google::protobuf::RpcController *controller,
274 : const ::firebolt::rialto::WebAudioWriteBufferRequest *request,
275 : ::firebolt::rialto::WebAudioWriteBufferResponse *response,
276 : ::google::protobuf::Closure *done)
277 : {
278 2 : RIALTO_SERVER_LOG_DEBUG("entry:");
279 2 : if (!m_webAudioPlayerService.writeBuffer(request->web_audio_player_handle(), request->number_of_frames(), nullptr))
280 : {
281 1 : RIALTO_SERVER_LOG_ERROR("writeBuffer failed");
282 1 : controller->SetFailed("Operation failed");
283 : }
284 2 : done->Run();
285 : }
286 :
287 2 : void WebAudioPlayerModuleService::getDeviceInfo(::google::protobuf::RpcController *controller,
288 : const ::firebolt::rialto::WebAudioGetDeviceInfoRequest *request,
289 : ::firebolt::rialto::WebAudioGetDeviceInfoResponse *response,
290 : ::google::protobuf::Closure *done)
291 : {
292 2 : RIALTO_SERVER_LOG_DEBUG("entry:");
293 :
294 2 : uint32_t preferredFrames{};
295 2 : uint32_t maximumFrames{};
296 2 : bool supportDeferredPlay{};
297 2 : if (!m_webAudioPlayerService.getDeviceInfo(request->web_audio_player_handle(), preferredFrames, maximumFrames,
298 : supportDeferredPlay))
299 : {
300 1 : RIALTO_SERVER_LOG_ERROR("getDeviceInfo failed");
301 1 : controller->SetFailed("Operation failed");
302 : }
303 : else
304 : {
305 1 : response->set_preferred_frames(preferredFrames);
306 1 : response->set_maximum_frames(maximumFrames);
307 1 : response->set_support_deferred_play(supportDeferredPlay);
308 : }
309 2 : done->Run();
310 : }
311 :
312 2 : void WebAudioPlayerModuleService::setVolume(::google::protobuf::RpcController *controller,
313 : const ::firebolt::rialto::WebAudioSetVolumeRequest *request,
314 : ::firebolt::rialto::WebAudioSetVolumeResponse *response,
315 : ::google::protobuf::Closure *done)
316 : {
317 2 : RIALTO_SERVER_LOG_DEBUG("entry:");
318 2 : if (!m_webAudioPlayerService.setVolume(request->web_audio_player_handle(), request->volume()))
319 : {
320 1 : RIALTO_SERVER_LOG_ERROR("setVolume failed");
321 1 : controller->SetFailed("Operation failed");
322 : }
323 2 : done->Run();
324 : }
325 :
326 2 : void WebAudioPlayerModuleService::getVolume(::google::protobuf::RpcController *controller,
327 : const ::firebolt::rialto::WebAudioGetVolumeRequest *request,
328 : ::firebolt::rialto::WebAudioGetVolumeResponse *response,
329 : ::google::protobuf::Closure *done)
330 : {
331 2 : RIALTO_SERVER_LOG_DEBUG("entry:");
332 :
333 2 : double volume{};
334 2 : if (!m_webAudioPlayerService.getVolume(request->web_audio_player_handle(), volume))
335 : {
336 1 : RIALTO_SERVER_LOG_ERROR("getVolume failed");
337 1 : controller->SetFailed("Operation failed");
338 : }
339 : else
340 : {
341 1 : response->set_volume(volume);
342 : }
343 2 : done->Run();
344 : }
345 :
346 : } // namespace firebolt::rialto::server::ipc
|