LCOV - code coverage report
Current view: top level - media/client/main/source - ClientController.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 92.9 % 127 118
Test Date: 2026-03-18 08:38:49 Functions: 100.0 % 13 13

            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 "ClientController.h"
      21              : #include "RialtoClientLogging.h"
      22              : #include "SharedMemoryHandle.h"
      23              : #include <cstring>
      24              : #include <stdexcept>
      25              : #include <sys/mman.h>
      26              : #include <sys/un.h>
      27              : #include <unistd.h>
      28              : #include <utility>
      29              : 
      30              : namespace
      31              : {
      32              : // The following error would be reported if a client is deleted
      33              : // before unregisterClient() was called. Calling unregisterClient can
      34              : // be automated via a proxy class (like the class MediaPipelineProxy)
      35              : const std::string kClientPointerNotLocked{"A client could not be locked"};
      36              : }; // namespace
      37              : 
      38              : namespace firebolt::rialto::client
      39              : {
      40            1 : IClientControllerAccessor &IClientControllerAccessor::instance()
      41              : {
      42            1 :     static ClientControllerAccessor factory;
      43            1 :     return factory;
      44              : }
      45              : 
      46            1 : IClientController &ClientControllerAccessor::getClientController() const
      47              : {
      48            2 :     static ClientController ClientController{IControlIpcFactory::createFactory()};
      49            0 :     return ClientController;
      50              : }
      51              : 
      52           20 : ClientController::ClientController(const std::shared_ptr<IControlIpcFactory> &ControlIpcFactory)
      53           20 :     : m_currentState{ApplicationState::UNKNOWN}, m_registrationRequired{true}
      54              : {
      55           20 :     RIALTO_CLIENT_LOG_DEBUG("entry:");
      56              : 
      57           20 :     const char kSrcRev[] = SRCREV;
      58           20 :     const char kTags[] = TAGS;
      59              : 
      60              :     if (std::strlen(kSrcRev) > 0)
      61              :     {
      62              :         if (std::strlen(kTags) > 0)
      63              :         {
      64              :             RIALTO_CLIENT_LOG_MIL("Release Tag(s): %s (Commit ID: %s)", kTags, kSrcRev);
      65              :         }
      66              :         else
      67              :         {
      68           20 :             RIALTO_CLIENT_LOG_MIL("Release Tag(s): No Release Tags! (Commit ID: %s)", kSrcRev);
      69              :         }
      70              :     }
      71              :     else
      72              :     {
      73              :         RIALTO_CLIENT_LOG_WARN("Failed to get git commit ID!");
      74              :     }
      75              : 
      76           20 :     m_controlIpc = ControlIpcFactory->createControlIpc(this);
      77           19 :     if (nullptr == m_controlIpc)
      78              :     {
      79            1 :         throw std::runtime_error("Failed to create the ControlIpc object");
      80              :     }
      81           28 : }
      82              : 
      83           36 : ClientController::~ClientController()
      84              : {
      85           18 :     RIALTO_CLIENT_LOG_DEBUG("entry:");
      86              : 
      87           18 :     termSharedMemory();
      88           36 : }
      89              : 
      90           27 : std::shared_ptr<ISharedMemoryHandle> ClientController::getSharedMemoryHandle()
      91              : {
      92           27 :     std::lock_guard<std::mutex> lock{m_mutex};
      93           54 :     return m_shmHandle;
      94           27 : }
      95              : 
      96           13 : bool ClientController::registerClient(std::weak_ptr<IControlClient> client, ApplicationState &appState)
      97              : {
      98           13 :     std::shared_ptr<IControlClient> clientLocked = client.lock();
      99           13 :     if (!clientLocked)
     100              :     {
     101            1 :         RIALTO_CLIENT_LOG_ERROR("Client ptr is null");
     102            1 :         return false;
     103              :     }
     104              : 
     105           12 :     std::lock_guard<std::mutex> lock{m_mutex};
     106           12 :     if (m_registrationRequired)
     107              :     {
     108            9 :         if (!m_controlIpc->registerClient())
     109              :         {
     110            1 :             RIALTO_CLIENT_LOG_ERROR("Failed to register client");
     111            1 :             return false;
     112              :         }
     113              :     }
     114           11 :     m_registrationRequired = false;
     115              : 
     116           11 :     bool alreadyRegistered{std::find_if(m_clients.begin(), m_clients.end(),
     117            4 :                                         [&](auto &i)
     118              :                                         {
     119            4 :                                             std::shared_ptr<IControlClient> iLocked = i.lock();
     120            4 :                                             return (iLocked == clientLocked);
     121           26 :                                         }) != m_clients.end()};
     122           11 :     if (!alreadyRegistered)
     123            7 :         m_clients.push_back(client);
     124           11 :     appState = m_currentState;
     125              : 
     126           11 :     return true;
     127           13 : }
     128              : 
     129            1 : bool ClientController::unregisterClient(std::weak_ptr<IControlClient> client)
     130              : {
     131            1 :     std::shared_ptr<IControlClient> clientLocked = client.lock();
     132            1 :     if (!clientLocked)
     133              :     {
     134            0 :         RIALTO_CLIENT_LOG_ERROR("Client ptr is null");
     135            0 :         return false;
     136              :     }
     137              : 
     138            1 :     std::lock_guard<std::mutex> lock{m_mutex};
     139              : 
     140            1 :     bool found{false};
     141            1 :     for (auto i = m_clients.begin(); i != m_clients.end();)
     142              :     {
     143            1 :         std::shared_ptr<IControlClient> iLocked = i->lock();
     144            1 :         if (!iLocked)
     145              :         {
     146            0 :             RIALTO_CLIENT_LOG_ERROR("%s", kClientPointerNotLocked.c_str());
     147            0 :             i = m_clients.erase(i);
     148              :         }
     149            1 :         else if (iLocked == clientLocked)
     150              :         {
     151            1 :             i = m_clients.erase(i);
     152            1 :             found = true;
     153            1 :             break;
     154              :         }
     155              :         else
     156            0 :             ++i;
     157            1 :     }
     158              : 
     159            1 :     if (!found)
     160              :     {
     161            0 :         RIALTO_CLIENT_LOG_ERROR("Client not found");
     162            0 :         return false;
     163              :     }
     164              : 
     165            1 :     return true;
     166              : }
     167              : 
     168           11 : bool ClientController::initSharedMemory()
     169              : try
     170              : {
     171           11 :     std::lock_guard<std::mutex> lock{m_mutex};
     172           11 :     int32_t shmFd{-1};
     173           11 :     uint32_t shmBufferLen{0U};
     174           11 :     if (!m_controlIpc->getSharedMemory(shmFd, shmBufferLen))
     175              :     {
     176            1 :         RIALTO_CLIENT_LOG_ERROR("Failed to get the shared memory");
     177            1 :         return false;
     178              :     }
     179           10 :     m_shmHandle = std::make_shared<SharedMemoryHandle>(shmFd, shmBufferLen);
     180              : 
     181            8 :     RIALTO_CLIENT_LOG_INFO("Shared buffer was successfully initialised");
     182            8 :     return true;
     183           11 : }
     184            2 : catch (const std::exception &e)
     185              : {
     186            2 :     RIALTO_CLIENT_LOG_ERROR("Failed to initialise shared memory: %s", e.what());
     187            2 :     return false;
     188              : }
     189              : 
     190           25 : void ClientController::termSharedMemory()
     191              : {
     192           25 :     std::lock_guard<std::mutex> lock{m_mutex};
     193           25 :     m_shmHandle.reset();
     194              : }
     195              : 
     196           19 : void ClientController::notifyApplicationState(ApplicationState state)
     197              : {
     198              :     {
     199           19 :         std::lock_guard<std::mutex> lock{m_mutex};
     200           19 :         if (ApplicationState::UNKNOWN == state)
     201              :         {
     202            3 :             RIALTO_CLIENT_LOG_DEBUG("Application state changed to unknown. Client will have to register next time");
     203            3 :             m_registrationRequired = true;
     204              :         }
     205           19 :         if (m_currentState == state)
     206              :         {
     207            1 :             RIALTO_CLIENT_LOG_WARN("Rialto application state already set, %s", stateToString(m_currentState).c_str());
     208            1 :             return;
     209              :         }
     210           19 :     }
     211              : 
     212           18 :     switch (state)
     213              :     {
     214           11 :     case ApplicationState::RUNNING:
     215              :     {
     216           11 :         if (!initSharedMemory())
     217              :         {
     218            3 :             RIALTO_CLIENT_LOG_ERROR("Could not initalise the shared memory");
     219            3 :             return;
     220              :         }
     221              :         // Inform clients after memory initialisation
     222            8 :         changeStateAndNotifyClients(state);
     223            8 :         break;
     224              :     }
     225            7 :     case ApplicationState::INACTIVE:
     226              :     case ApplicationState::UNKNOWN:
     227              :     {
     228              :         // Inform clients before memory termination
     229            7 :         changeStateAndNotifyClients(state);
     230            7 :         termSharedMemory();
     231            7 :         break;
     232              :     }
     233              :     }
     234              : }
     235              : 
     236           31 : std::string ClientController::stateToString(ApplicationState state)
     237              : {
     238           31 :     switch (state)
     239              :     {
     240           14 :     case ApplicationState::RUNNING:
     241              :     {
     242           28 :         return "RUNNING";
     243              :     }
     244            5 :     case ApplicationState::INACTIVE:
     245              :     {
     246           10 :         return "INACTIVE";
     247              :     }
     248           12 :     case ApplicationState::UNKNOWN:
     249              :     default:
     250              :     {
     251           24 :         return "UNKNOWN";
     252              :     }
     253              :     }
     254              : }
     255              : 
     256           15 : void ClientController::changeStateAndNotifyClients(ApplicationState state)
     257              : {
     258           15 :     std::vector<std::shared_ptr<IControlClient>> currentClients;
     259              :     {
     260           15 :         std::lock_guard<std::mutex> lock{m_mutex};
     261           15 :         RIALTO_CLIENT_LOG_MIL("Rialto application state changed from %s to %s", stateToString(m_currentState).c_str(),
     262              :                               stateToString(state).c_str());
     263           15 :         m_currentState = state;
     264           22 :         for (const std::weak_ptr<IControlClient> &client : m_clients)
     265              :         {
     266            7 :             std::shared_ptr<IControlClient> clientLocked{client.lock()};
     267            7 :             if (clientLocked)
     268              :             {
     269            7 :                 currentClients.push_back(std::move(clientLocked));
     270              :             }
     271              :             else
     272              :             {
     273            0 :                 RIALTO_CLIENT_LOG_ERROR("%s", kClientPointerNotLocked.c_str());
     274              :             }
     275            7 :         }
     276           15 :     }
     277           22 :     for (const auto &client : currentClients)
     278              :     {
     279            7 :         client->notifyApplicationState(state);
     280              :     }
     281           15 : }
     282              : } // namespace firebolt::rialto::client
        

Generated by: LCOV version 2.0-1