1 /*
2  *  Copyright (C) 2005-2018 Team Kodi
3  *  This file is part of Kodi - https://kodi.tv
4  *
5  *  SPDX-License-Identifier: GPL-2.0-or-later
6  *  See LICENSES/README.md for more information.
7  */
8 
9 #pragma once
10 
11 #include "IEventScannerCallback.h"
12 #include "bus/PeripheralBus.h"
13 #include "devices/Peripheral.h"
14 #include "interfaces/IAnnouncer.h"
15 #include "messaging/IMessageTarget.h"
16 #include "settings/lib/ISettingCallback.h"
17 #include "threads/CriticalSection.h"
18 #include "threads/Thread.h"
19 #include "utils/Observer.h"
20 
21 #include <memory>
22 #include <vector>
23 
24 class CFileItemList;
25 class CInputManager;
26 class CSetting;
27 class CSettingsCategory;
28 class TiXmlElement;
29 class CAction;
30 class CKey;
31 
32 namespace KODI
33 {
34 namespace GAME
35 {
36 class CControllerManager;
37 }
38 
39 namespace JOYSTICK
40 {
41 class IButtonMapper;
42 }
43 } // namespace KODI
44 
45 namespace PERIPHERALS
46 {
47 class CEventScanner;
48 
49 class CPeripherals : public ISettingCallback,
50                      public Observable,
51                      public KODI::MESSAGING::IMessageTarget,
52                      public IEventScannerCallback,
53                      public ANNOUNCEMENT::IAnnouncer
54 {
55 public:
56   explicit CPeripherals(CInputManager& inputManager,
57                         KODI::GAME::CControllerManager& controllerProfiles);
58 
59   ~CPeripherals() override;
60 
61   /*!
62    * @brief Initialise the peripherals manager.
63    */
64   void Initialise();
65 
66   /*!
67    * @brief Clear all data known by the peripherals manager.
68    */
69   void Clear();
70 
71   /*!
72    * @brief Get the instance of the peripheral at the given location.
73    * @param strLocation The location.
74    * @param busType The bus to query. Default (PERIPHERAL_BUS_UNKNOWN) searches all busses.
75    * @return The peripheral or NULL if it wasn't found.
76    */
77   PeripheralPtr GetPeripheralAtLocation(const std::string& strLocation,
78                                         PeripheralBusType busType = PERIPHERAL_BUS_UNKNOWN) const;
79 
80   /*!
81    * @brief Check whether a peripheral is present at the given location.
82    * @param strLocation The location.
83    * @param busType The bus to query. Default (PERIPHERAL_BUS_UNKNOWN) searches all busses.
84    * @return True when a peripheral was found, false otherwise.
85    */
86   bool HasPeripheralAtLocation(const std::string& strLocation,
87                                PeripheralBusType busType = PERIPHERAL_BUS_UNKNOWN) const;
88 
89   /*!
90    * @brief Get the bus that holds the device with the given location.
91    * @param strLocation The location.
92    * @return The bus or NULL if no device was found.
93    */
94   PeripheralBusPtr GetBusWithDevice(const std::string& strLocation) const;
95 
96   /*!
97    * @brief Check if any busses support the given feature
98    * @param feature The feature to check for
99    * @return True if a bus supports the feature, false otherwise
100    */
101   bool SupportsFeature(PeripheralFeature feature) const;
102 
103   /*!
104    * @brief Get all peripheral instances that have the given feature.
105    * @param results The list of results.
106    * @param feature The feature to search for.
107    * @param busType The bus to query. Default (PERIPHERAL_BUS_UNKNOWN) searches all busses.
108    * @return The number of devices that have been found.
109    */
110   int GetPeripheralsWithFeature(PeripheralVector& results,
111                                 const PeripheralFeature feature,
112                                 PeripheralBusType busType = PERIPHERAL_BUS_UNKNOWN) const;
113 
114   size_t GetNumberOfPeripherals() const;
115 
116   /*!
117    * @brief Check whether there is at least one device present with the given feature.
118    * @param feature The feature to check for.
119    * @param busType The bus to query. Default (PERIPHERAL_BUS_UNKNOWN) searches all busses.
120    * @return True when at least one device was found with this feature, false otherwise.
121    */
122   bool HasPeripheralWithFeature(const PeripheralFeature feature,
123                                 PeripheralBusType busType = PERIPHERAL_BUS_UNKNOWN) const;
124 
125   /*!
126    * @brief Called when a device has been added to a bus.
127    * @param bus The bus the device was added to.
128    * @param peripheral The peripheral that has been added.
129    */
130   void OnDeviceAdded(const CPeripheralBus& bus, const CPeripheral& peripheral);
131 
132   /*!
133    * @brief Called when a device has been deleted from a bus.
134    * @param bus The bus from which the device removed.
135    * @param peripheral The peripheral that has been removed.
136    */
137   void OnDeviceDeleted(const CPeripheralBus& bus, const CPeripheral& peripheral);
138 
139   /*!
140    * @brief Creates a new instance of a peripheral.
141    * @param bus The bus on which this peripheral is present.
142    * @param result The scan result from the device scanning code.
143    * @return The new peripheral or NULL if it could not be created.
144    */
145   void CreatePeripheral(CPeripheralBus& bus, const PeripheralScanResult& result);
146 
147   /*!
148    * @brief Add the settings that are defined in the mappings file to the peripheral (if there is
149    * anything defined).
150    * @param peripheral The peripheral to get the settings for.
151    */
152   void GetSettingsFromMapping(CPeripheral& peripheral) const;
153 
154   /*!
155    * @brief Trigger a device scan on all known busses
156    */
157   void TriggerDeviceScan(const PeripheralBusType type = PERIPHERAL_BUS_UNKNOWN);
158 
159   /*!
160    * @brief Get the instance of a bus given it's type.
161    * @param type The bus type.
162    * @return The bus or NULL if it wasn't found.
163    */
164   PeripheralBusPtr GetBusByType(const PeripheralBusType type) const;
165 
166   /*!
167    * @brief Get all fileitems for a path.
168    * @param strPath The path to the directory to get the items from.
169    * @param items The item list.
170    */
171   void GetDirectory(const std::string& strPath, CFileItemList& items) const;
172 
173   /*!
174    * @brief Get the instance of a peripheral given it's path.
175    * @param strPath The path to the peripheral.
176    * @return The peripheral or NULL if it wasn't found.
177    */
178   PeripheralPtr GetByPath(const std::string& strPath) const;
179 
180   /*!
181    * @brief Try to let one of the peripherals handle an action.
182    * @param action The change to handle.
183    * @return True when this change was handled by a peripheral (and should not be handled by
184    * anything else), false otherwise.
185    */
186   bool OnAction(const CAction& action);
187 
188   /*!
189    * @brief Check whether there's a peripheral that reports to be muted.
190    * @return True when at least one peripheral reports to be muted, false otherwise.
191    */
192   bool IsMuted();
193 
194   /*!
195    * @brief Try to toggle the mute status via a peripheral.
196    * @return True when this change was handled by a peripheral (and should not be handled by
197    * anything else), false otherwise.
198    */
199   bool ToggleMute();
200 
201   /*!
202    * @brief Try to toggle the playing device state via a peripheral.
203    * @param mode Whether to activate, put on standby or toggle the source.
204    * @return True when the playing device has been switched on, false otherwise.
205    */
206   bool ToggleDeviceState(const CecStateChange mode = STATE_SWITCH_TOGGLE);
207 
208   /*!
209    * @brief Try to mute the audio via a peripheral.
210    * @return True when this change was handled by a peripheral (and should not be handled by
211    * anything else), false otherwise.
212    */
Mute()213   bool Mute()
214   {
215     return ToggleMute();
216   } //! @todo CEC only supports toggling the mute status at this time
217 
218   /*!
219    * @brief Try to unmute the audio via a peripheral.
220    * @return True when this change was handled by a peripheral (and should not be handled by
221    * anything else), false otherwise.
222    */
UnMute()223   bool UnMute()
224   {
225     return ToggleMute();
226   } //! @todo CEC only supports toggling the mute status at this time
227 
228   /*!
229    * @brief Try to get a keypress from a peripheral.
230    * @param frameTime The current frametime.
231    * @param key The fetched key.
232    * @return True when a keypress was fetched, false otherwise.
233    */
234   bool GetNextKeypress(float frameTime, CKey& key);
235 
236   /*!
237    * @brief Register with the event scanner to control scan timing
238    * @return A handle that unregisters itself when expired
239    */
240   EventPollHandlePtr RegisterEventPoller();
241 
242   /*!
243    * @brief Register with the event scanner to disable event processing
244    * @return A handle that unregisters itself when expired
245    */
246   EventLockHandlePtr RegisterEventLock();
247 
248   /*!
249    *
250    */
251   void OnUserNotification();
252 
253   /*!
254    * @brief Request peripherals with the specified feature to perform a quick test
255    * @return true if any peripherals support the feature, false otherwise
256    */
257   void TestFeature(PeripheralFeature feature);
258 
259   /*!
260    * \brief Request all devices with power-off support to power down
261    */
262   void PowerOffDevices();
263 
SupportsCEC()264   bool SupportsCEC() const
265   {
266 #if defined(HAVE_LIBCEC)
267     return true;
268 #else
269     return false;
270 #endif
271   }
272 
273   // implementation of IEventScannerCallback
274   void ProcessEvents(void) override;
275 
276   /*!
277    * \brief Initialize button mapping
278    *
279    * This command enables button mapping on all busses. Button maps allow
280    * connect events from the driver to the higher-level features used by
281    * controller profiles.
282    *
283    * If user input is required, a blocking dialog may be shown.
284    */
285   void EnableButtonMapping();
286 
287   /*!
288    * \brief Get an add-on that can provide button maps for a device
289    * \return An add-on that provides button maps, or empty if no add-on is found
290    */
291   PeripheralAddonPtr GetAddonWithButtonMap(const CPeripheral* device);
292 
293   /*!
294    * \brief Reset all button maps to the defaults for all devices and the given controller
295    * \param controllerId The controller profile to reset
296    * @todo Add a device parameter to allow resetting button maps per-device
297    */
298   void ResetButtonMaps(const std::string& controllerId);
299 
300   /*!
301    * \brief Register a button mapper interface
302    * \param mapper The button mapper
303    *
304    * Clients implementing the IButtonMapper interface call
305    * \ref CPeripherals::RegisterJoystickButtonMapper to register themselves
306    * as eligible for button mapping commands.
307    *
308    * When registering the mapper is forwarded to all peripherals. See
309    * \ref CPeripheral::RegisterJoystickButtonMapper for what is done to the
310    * mapper after being given to the peripheral.
311    */
312   void RegisterJoystickButtonMapper(KODI::JOYSTICK::IButtonMapper* mapper);
313 
314   /*!
315    * \brief Unregister a button mapper interface
316    * \param mapper The button mapper
317    */
318   void UnregisterJoystickButtonMapper(KODI::JOYSTICK::IButtonMapper* mapper);
319 
320   // implementation of ISettingCallback
321   void OnSettingChanged(const std::shared_ptr<const CSetting>& setting) override;
322   void OnSettingAction(const std::shared_ptr<const CSetting>& setting) override;
323 
324   // implementation of IMessageTarget
325   void OnApplicationMessage(KODI::MESSAGING::ThreadMessage* pMsg) override;
326   int GetMessageMask() override;
327 
328   // implementation of IAnnouncer
329   void Announce(ANNOUNCEMENT::AnnouncementFlag flag,
330                 const std::string& sender,
331                 const std::string& message,
332                 const CVariant& data) override;
333 
334   /*!
335    * \brief Access the input manager passed to the constructor
336    */
GetInputManager()337   CInputManager& GetInputManager() { return m_inputManager; }
338 
339   /*!
340    * \brief Access controller profiles through the construction parameter
341    */
GetControllerProfiles()342   KODI::GAME::CControllerManager& GetControllerProfiles() { return m_controllerProfiles; }
343 
344 private:
345   bool LoadMappings();
346   bool GetMappingForDevice(const CPeripheralBus& bus, PeripheralScanResult& result) const;
347   static void GetSettingsFromMappingsFile(
348       TiXmlElement* xmlNode, std::map<std::string, PeripheralDeviceSetting>& m_settings);
349 
350   void OnDeviceChanged();
351 
352   // Construction parameters
353   CInputManager& m_inputManager;
354   KODI::GAME::CControllerManager& m_controllerProfiles;
355 
356 #if !defined(HAVE_LIBCEC)
357   bool m_bMissingLibCecWarningDisplayed = false;
358 #endif
359   std::vector<PeripheralBusPtr> m_busses;
360   std::vector<PeripheralDeviceMapping> m_mappings;
361   std::unique_ptr<CEventScanner> m_eventScanner;
362   mutable CCriticalSection m_critSectionBusses;
363   mutable CCriticalSection m_critSectionMappings;
364 };
365 } // namespace PERIPHERALS
366