LCOV - code coverage report
Current view: top level - media/server/service/source - SessionServerManager.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 100.0 % 140 140
Test Date: 2026-09-11 17:36:12 Functions: 100.0 % 17 17

            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 "SessionServerManager.h"
      21              : #include "IApplicationManagementServer.h"
      22              : #include "IIpcFactory.h"
      23              : #include "ISessionManagementServer.h"
      24              : #include "RialtoServerLogging.h"
      25              : 
      26              : #include <algorithm>
      27              : #include <stdexcept>
      28              : #include <utility>
      29              : 
      30              : namespace
      31              : {
      32            5 : inline bool isNumber(const std::string &text)
      33              : {
      34           10 :     return std::find_if(text.begin(), text.end(), [](const auto &letter) { return !std::isdigit(letter); }) == text.end();
      35              : }
      36              : } // namespace
      37              : 
      38              : namespace firebolt::rialto::server::service
      39              : {
      40           28 : SessionServerManager::SessionServerManager(const ipc::IIpcFactory &ipcFactory, IPlaybackService &playbackService,
      41              :                                            ICdmService &cdmService, IControlService &controlService,
      42           28 :                                            std::unique_ptr<IHeartbeatProcedureFactory> &&heartbeatProcedureFactory)
      43           28 :     : m_playbackService{playbackService}, m_cdmService{cdmService}, m_controlService{controlService},
      44           28 :       m_heartbeatProcedureFactory{std::move(heartbeatProcedureFactory)},
      45           28 :       m_applicationManagementServer{ipcFactory.createApplicationManagementServer(*this)},
      46           28 :       m_sessionManagementServer{ipcFactory.createSessionManagementServer(playbackService, cdmService, controlService)},
      47           56 :       m_isServiceRunning{true}, m_currentState{common::SessionServerState::UNINITIALIZED}
      48              : {
      49           28 :     RIALTO_SERVER_LOG_INFO("Starting Rialto Server Service");
      50              : }
      51              : 
      52           56 : SessionServerManager::~SessionServerManager()
      53              : {
      54           28 :     RIALTO_SERVER_LOG_INFO("Stopping Rialto Server Service");
      55              : 
      56              :     // The following reset() will ensure that the thread ApplicationManagementServer::m_ipcServerThread
      57              :     // isn't currently calling any methods within this class (while it is being destructed)
      58              :     // Particularly, the mentioned thread is responsible for calling the method
      59              :     // SessionServerManager::teardownService() which then triggers a call to this destuctor
      60              :     // after it calls stopService()
      61           28 :     m_applicationManagementServer.reset();
      62              : 
      63           28 :     stopService();
      64           56 : }
      65              : 
      66            7 : bool SessionServerManager::initialize(int argc, char *argv[])
      67              : try
      68              : {
      69            7 :     if (argc != 2)
      70              :     {
      71            2 :         RIALTO_SERVER_LOG_ERROR("Wrong number of arguments. Rialto Server Service will close now.");
      72            2 :         return false;
      73              :     }
      74           10 :     std::string socketStr{argv[1]};
      75            5 :     if (!isNumber(socketStr))
      76              :     {
      77            1 :         RIALTO_SERVER_LOG_ERROR("Rialto App Management socket is not a number.");
      78            1 :         return false;
      79              :     }
      80            4 :     if (!m_applicationManagementServer->initialize(std::stoi(socketStr)))
      81              :     {
      82            1 :         RIALTO_SERVER_LOG_ERROR("Initialization of Application Management server failed.");
      83            1 :         return false;
      84              :     }
      85            2 :     m_applicationManagementServer->start();
      86            2 :     return m_applicationManagementServer->sendStateChangedEvent(common::SessionServerState::UNINITIALIZED);
      87            5 : }
      88            1 : catch (const std::exception &e)
      89              : {
      90            1 :     RIALTO_SERVER_LOG_ERROR("Exception caught during service initialization: %s", e.what());
      91            1 :     return false;
      92              : }
      93              : 
      94            1 : void SessionServerManager::startService()
      95              : {
      96            1 :     std::unique_lock<std::mutex> lock{m_serviceMutex};
      97            3 :     m_serviceCv.wait(lock, [this]() { return !m_isServiceRunning; });
      98            1 : }
      99              : 
     100           32 : void SessionServerManager::stopService()
     101              : {
     102           32 :     std::unique_lock<std::mutex> lock{m_serviceMutex};
     103           32 :     if (m_isServiceRunning)
     104              :     {
     105           28 :         m_isServiceRunning = false;
     106           28 :         m_serviceCv.notify_one();
     107              :     }
     108           32 : }
     109              : 
     110            3 : bool SessionServerManager::configureIpc(const std::string &socketName, unsigned int socketPermissions,
     111              :                                         const std::string &socketOwner, const std::string &socketGroup)
     112              : {
     113            3 :     if (!m_sessionManagementServer->initialize(socketName, socketPermissions, socketOwner, socketGroup))
     114              :     {
     115            1 :         RIALTO_SERVER_LOG_ERROR("configureIpc failed - SessionManagementServer failed to initialize");
     116            1 :         return false;
     117              :     }
     118            2 :     return true;
     119              : }
     120              : 
     121            2 : bool SessionServerManager::configureIpc(int32_t socketFd)
     122              : {
     123            2 :     if (!m_sessionManagementServer->initialize(socketFd))
     124              :     {
     125            1 :         RIALTO_SERVER_LOG_ERROR("configureIpc failed - SessionManagementServer failed to initialize");
     126            1 :         return false;
     127              :     }
     128            1 :     return true;
     129              : }
     130              : 
     131            3 : bool SessionServerManager::configureServices(const common::SessionServerState &state,
     132              :                                              const common::MaxResourceCapabilitites &maxResource,
     133              :                                              const std::string &clientDisplayName, const std::string &appName)
     134              : {
     135            3 :     m_sessionManagementServer->start();
     136            3 :     m_playbackService.setMaxPlaybacks(maxResource.maxPlaybacks);
     137            3 :     m_playbackService.setMaxWebAudioPlayers(maxResource.maxWebAudioPlayers);
     138            3 :     m_playbackService.setClientDisplayName(clientDisplayName);
     139            3 :     m_playbackService.setResourceManagerAppName(appName);
     140            3 :     return setState(state);
     141              : }
     142              : 
     143           22 : bool SessionServerManager::setState(const common::SessionServerState &state)
     144              : {
     145           22 :     switch (state)
     146              :     {
     147            7 :     case common::SessionServerState::ACTIVE:
     148              :     {
     149            7 :         return switchToActive();
     150              :     }
     151            8 :     case common::SessionServerState::INACTIVE:
     152              :     {
     153            8 :         return switchToInactive();
     154              :     }
     155            5 :     case common::SessionServerState::NOT_RUNNING:
     156              :     case common::SessionServerState::SUSPENDED:
     157              :     {
     158            5 :         return teardownService(state);
     159              :     }
     160            2 :     default:
     161              :     {
     162            2 :         RIALTO_SERVER_LOG_ERROR("SetState failed - unsupported state");
     163            2 :         m_applicationManagementServer->sendStateChangedEvent(common::SessionServerState::ERROR);
     164              :     }
     165              :     }
     166            2 :     return false;
     167              : }
     168              : 
     169            1 : void SessionServerManager::setLogLevels(RIALTO_DEBUG_LEVEL defaultLogLevels, RIALTO_DEBUG_LEVEL clientLogLevels,
     170              :                                         RIALTO_DEBUG_LEVEL sessionServerLogLevels, RIALTO_DEBUG_LEVEL ipcLogLevels,
     171              :                                         RIALTO_DEBUG_LEVEL serverManagerLogLevels, RIALTO_DEBUG_LEVEL commonLogLevels)
     172              : {
     173            1 :     firebolt::rialto::logging::setLogLevels(RIALTO_COMPONENT_DEFAULT, defaultLogLevels);
     174            1 :     firebolt::rialto::logging::setLogLevels(RIALTO_COMPONENT_CLIENT, clientLogLevels);
     175            1 :     firebolt::rialto::logging::setLogLevels(RIALTO_COMPONENT_SERVER, sessionServerLogLevels);
     176            1 :     firebolt::rialto::logging::setLogLevels(RIALTO_COMPONENT_IPC, ipcLogLevels);
     177            1 :     firebolt::rialto::logging::setLogLevels(RIALTO_COMPONENT_SERVER_MANAGER, serverManagerLogLevels);
     178            1 :     firebolt::rialto::logging::setLogLevels(RIALTO_COMPONENT_COMMON, commonLogLevels);
     179            1 :     m_sessionManagementServer->setLogLevels(defaultLogLevels, clientLogLevels, ipcLogLevels, commonLogLevels);
     180              : }
     181              : 
     182            2 : bool SessionServerManager::ping(std::int32_t id, const std::shared_ptr<IAckSender> &ackSender)
     183              : {
     184            2 :     auto heartbeatProcedure{m_heartbeatProcedureFactory->createHeartbeatProcedure(ackSender, id)};
     185              : 
     186              :     // Check all rialto server internal threads
     187            2 :     m_cdmService.ping(heartbeatProcedure);
     188            2 :     m_playbackService.ping(heartbeatProcedure);
     189              : 
     190              :     // Check all Rialto Clients
     191            4 :     return m_controlService.ping(heartbeatProcedure);
     192            2 : }
     193              : 
     194            7 : bool SessionServerManager::switchToActive()
     195              : {
     196            7 :     const auto currentState{m_currentState.load()};
     197            7 :     if (currentState == common::SessionServerState::ACTIVE)
     198              :     {
     199            1 :         RIALTO_SERVER_LOG_DEBUG("Session server already in Active state.");
     200            1 :         return true;
     201              :     }
     202            6 :     if (!m_playbackService.switchToActive())
     203              :     {
     204            1 :         RIALTO_SERVER_LOG_ERROR("Player service failed to switch to active state");
     205            1 :         return false;
     206              :     }
     207            5 :     if (!m_cdmService.switchToActive())
     208              :     {
     209            1 :         RIALTO_SERVER_LOG_ERROR("Cdm service failed to switch to active state");
     210            1 :         m_playbackService.switchToInactive();
     211            1 :         return false;
     212              :     }
     213            4 :     if (m_applicationManagementServer->sendStateChangedEvent(common::SessionServerState::ACTIVE))
     214              :     {
     215            3 :         m_controlService.setApplicationState(ApplicationState::RUNNING);
     216            3 :         m_sessionManagementServer->notifyApplicationStateChanged(ApplicationState::RUNNING);
     217            3 :         m_currentState.store(common::SessionServerState::ACTIVE);
     218            3 :         RIALTO_SERVER_LOG_MIL("RialtoServer state is ACTIVE now");
     219            3 :         return true;
     220              :     }
     221            1 :     m_playbackService.switchToInactive();
     222            1 :     m_cdmService.switchToInactive();
     223            1 :     return false;
     224              : }
     225              : 
     226            8 : bool SessionServerManager::switchToInactive()
     227              : {
     228            8 :     const auto currentState{m_currentState.load()};
     229            8 :     if (currentState == common::SessionServerState::INACTIVE)
     230              :     {
     231            1 :         RIALTO_SERVER_LOG_DEBUG("Session server already in Inactive state.");
     232            1 :         return true;
     233              :     }
     234            7 :     m_playbackService.switchToInactive();
     235            7 :     m_cdmService.switchToInactive();
     236              :     // Record INACTIVE memory snapshot immediately after resource teardown,
     237              :     // before the manager ACK — ensures we capture it even if the socket breaks.
     238            7 :     m_sessionManagementServer->notifyApplicationStateChanged(ApplicationState::INACTIVE);
     239            7 :     if (m_applicationManagementServer->sendStateChangedEvent(common::SessionServerState::INACTIVE))
     240              :     {
     241            4 :         m_controlService.setApplicationState(ApplicationState::INACTIVE);
     242            4 :         m_currentState.store(common::SessionServerState::INACTIVE);
     243            4 :         RIALTO_SERVER_LOG_MIL("RialtoServer state is INACTIVE now");
     244            4 :         return true;
     245              :     }
     246            3 :     if (currentState == common::SessionServerState::ACTIVE)
     247              :     {
     248            1 :         if (!m_playbackService.switchToActive())
     249              :         {
     250            1 :             RIALTO_SERVER_LOG_WARN("Player service failed to switch to active state");
     251              :         }
     252            1 :         if (!m_cdmService.switchToActive())
     253              :         {
     254            1 :             RIALTO_SERVER_LOG_WARN("Cdm service failed to switch to active state");
     255              :         }
     256              :     }
     257            3 :     return false;
     258              : }
     259              : 
     260            5 : bool SessionServerManager::teardownService(const common::SessionServerState &state)
     261              : {
     262            5 :     RIALTO_SERVER_LOG_MIL("RialtoServer tear down requested");
     263            9 :     if (m_currentState.load() == common::SessionServerState::NOT_RUNNING ||
     264            4 :         m_currentState.load() == common::SessionServerState::SUSPENDED)
     265              :     {
     266            1 :         RIALTO_SERVER_LOG_DEBUG("Session server already in NotRunning or Suspended state.");
     267            1 :         return true;
     268              :     }
     269              :     // Free resources before sending notification to ServerManager
     270            4 :     m_playbackService.switchToInactive();
     271            4 :     m_cdmService.switchToInactive();
     272            4 :     m_controlService.setApplicationState(ApplicationState::UNKNOWN);
     273              : 
     274            4 :     bool result{true};
     275            4 :     if (m_applicationManagementServer->sendStateChangedEvent(state))
     276              :     {
     277            3 :         m_currentState.store(state);
     278              :     }
     279              :     else
     280              :     {
     281            1 :         result = false;
     282              :     }
     283              : 
     284              :     // stopService() needs to be the last command of this method.
     285              :     // It triggers destruction of SessionServerManager and therefore
     286              :     // some member variables may not be valid after this command
     287            4 :     stopService(); // This HAS TO BE LAST (see above)
     288            4 :     return result;
     289              : }
     290              : } // namespace firebolt::rialto::server::service
        

Generated by: LCOV version 2.0-1