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

Generated by: LCOV version 2.0-1