AvCasterStore.cpp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806
  1. /*\
  2. |*| Copyright 2015-2016 bill-auger <https://github.com/bill-auger/av-caster/issues>
  3. |*|
  4. |*| This file is part of the AvCaster program.
  5. |*|
  6. |*| AvCaster is free software: you can redistribute it and/or modify
  7. |*| it under the terms of the GNU General Public License version 3
  8. |*| as published by the Free Software Foundation.
  9. |*|
  10. |*| AvCaster is distributed in the hope that it will be useful,
  11. |*| but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. |*| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. |*| GNU General Public License for more details.
  14. |*|
  15. |*| You should have received a copy of the GNU General Public License
  16. |*| along with AvCaster. If not, see <http://www.gnu.org/licenses/>.
  17. \*/
  18. #include "AvCasterStore.h"
  19. #include "Seeds.h"
  20. #include "../Controllers/AvCaster.h"
  21. #include "../Trace/TraceAvCasterStore.h"
  22. /* AvCasterStore private class methods */
  23. StringArray AvCasterStore::PropertyValues(ValueTree root_node , Identifier property_id)
  24. {
  25. int n_children = root_node.getNumChildren() ;
  26. StringArray values ;
  27. for (int child_n = 0 ; child_n < n_children ; ++child_n)
  28. {
  29. ValueTree child_node = root_node.getChild(child_n) ;
  30. String value = STRING(child_node[property_id]) ;
  31. values.add(value) ;
  32. }
  33. return values ;
  34. }
  35. /* AvCasterStore public instance methods */
  36. AvCasterStore::~AvCasterStore() { }
  37. /* AvCasterStore private instance methods */
  38. AvCasterStore::AvCasterStore()
  39. {
  40. // create shared config ValueTrees from persistent storage or defaults
  41. this->root = loadConfig() ; verifyConfig() ;
  42. this->presets = this->root.getOrCreateChildWithName(CONFIG::PRESETS_ID , nullptr) ;
  43. this->config = ValueTree(CONFIG::VOLATILE_CONFIG_ID) ;
  44. this->network = ValueTree(CONFIG::NETWORK_ID ) ;
  45. this->config.addChild (this->network , -1 , nullptr) ;
  46. this->root .removeChild(this->presets , nullptr) ; // ignore store events
  47. // validate and sanitize config
  48. verifyRoot() ; verifyPresets() ;
  49. sanitizeRoot() ; sanitizePresets() ;
  50. verifyRoot() ; verifyPresets() ;
  51. restoreTransients() ; loadPreset() ; storeConfig() ;
  52. // create or assign aliases to transient shared config ValueTrees
  53. this->chatters = ValueTree(CONFIG::CHATTERS_ID ) ;
  54. this->cameras = ValueTree(CONFIG::CAMERA_DEVICES_ID) ;
  55. this->audios = ValueTree(CONFIG::AUDIO_DEVICES_ID ) ;
  56. // detect hardware
  57. detectCaptureDevices() ; // detectDisplayDimensions() ; // TODO: (issue #2 issue #4)
  58. DEBUG_TRACE_DUMP_CONFIG_ALL
  59. }
  60. /* validations */
  61. void AvCasterStore::verifyConfig()
  62. {
  63. // verify or reset stored configuration
  64. bool was_storage_found = this->root.isValid() ;
  65. bool is_root_valid = this->root.hasType(CONFIG::STORAGE_ID) ;
  66. bool has_canonical_nodes = !hasDuplicatedNodes(this->root) ;
  67. if (!was_storage_found || !is_root_valid) this->root = Seeds::DefaultStore() ;
  68. else if (!has_canonical_nodes) removeConflictedNodes(this->root , CONFIG::PRESETS_ID) ;
  69. // verify schema version
  70. int stored_version = int(this->root[CONFIG::CONFIG_VERSION_ID]) ;
  71. bool do_versions_match = stored_version == CONFIG::CONFIG_VERSION ;
  72. if (!do_versions_match)
  73. {
  74. // TODO: convert (if ever necessary)
  75. File parent_dir = this->storageFile.getParentDirectory() ;
  76. File backup_file = parent_dir.getNonexistentChildFile(CONFIG::STORAGE_FILENAME , ".bak" , false) ;
  77. this->storageFile.copyFileTo(backup_file) ;
  78. this->root.removeProperty(CONFIG::CONFIG_VERSION_ID , nullptr) ;
  79. }
  80. DEBUG_TRACE_VERIFY_STORED_CONFIG
  81. }
  82. void AvCasterStore::verifyRoot()
  83. {
  84. // ensure missing properties exist
  85. verifyRootProperty(CONFIG::CONFIG_VERSION_ID , var(CONFIG::CONFIG_VERSION )) ;
  86. verifyRootProperty(CONFIG::PRESET_ID , var(CONFIG::DEFAULT_PRESET_IDX)) ;
  87. }
  88. void AvCasterStore::verifyPresets()
  89. {
  90. // ensure default preset configurations exist
  91. ValueTree file_preset_store = this->presets.getChild(CONFIG::FILE_PRESET_IDX) ;
  92. ValueTree rtmp_preset_store = this->presets.getChild(CONFIG::RTMP_PRESET_IDX) ;
  93. ValueTree lctv_preset_store = this->presets.getChild(CONFIG::LCTV_PRESET_IDX) ;
  94. if (!file_preset_store.isValid() || file_preset_store.getType() != CONFIG::FILE_PRESET_ID ||
  95. !rtmp_preset_store.isValid() || rtmp_preset_store.getType() != CONFIG::RTMP_PRESET_ID ||
  96. !lctv_preset_store.isValid() || lctv_preset_store.getType() != CONFIG::LCTV_PRESET_ID )
  97. restoreStaticPresets() ;
  98. // verify preset nodes
  99. for (int preset_n = 0 ; preset_n < this->presets.getNumChildren() ; ++preset_n)
  100. {
  101. ValueTree preset_store = this->presets.getChild(preset_n) ;
  102. ValueTree network_store = preset_store.getChildWithName(CONFIG::NETWORK_ID) ;
  103. this->config .copyPropertiesFrom(preset_store , nullptr) ;
  104. this->network.copyPropertiesFrom(network_store , nullptr) ;
  105. verifyPreset() ;
  106. preset_store .copyPropertiesFrom(this->config , nullptr) ;
  107. network_store.copyPropertiesFrom(this->network , nullptr) ;
  108. }
  109. }
  110. void AvCasterStore::verifyPreset()
  111. {
  112. DEBUG_TRACE_VERIFY_PRESET
  113. // ensure missing properties exist
  114. verifyPresetProperty (CONFIG::SCREEN_ID , var(CONFIG::DEFAULT_IS_SCREEN_ACTIVE )) ;
  115. verifyPresetProperty (CONFIG::CAMERA_ID , var(CONFIG::DEFAULT_IS_CAMERA_ACTIVE )) ;
  116. verifyPresetProperty (CONFIG::TEXT_ID , var(CONFIG::DEFAULT_IS_TEXT_ACTIVE )) ;
  117. verifyPresetProperty (CONFIG::IMAGE_ID , var(CONFIG::DEFAULT_IS_IMAGE_ACTIVE )) ;
  118. verifyPresetProperty (CONFIG::PREVIEW_ID , var(CONFIG::DEFAULT_IS_PREVIEW_ACTIVE)) ;
  119. verifyPresetProperty (CONFIG::AUDIO_ID , var(CONFIG::DEFAULT_IS_AUDIO_ACTIVE )) ;
  120. verifyPresetProperty (CONFIG::PRESET_NAME_ID , var(CONFIG::DEFAULT_PRESET_NAME )) ;
  121. verifyPresetProperty (CONFIG::CONFIG_PANE_ID , var(CONFIG::DEFAULT_CONFIG_PANE )) ;
  122. verifyPresetProperty (CONFIG::DISPLAY_N_ID , var(CONFIG::DEFAULT_DISPLAY_N )) ;
  123. verifyPresetProperty (CONFIG::SCREEN_N_ID , var(CONFIG::DEFAULT_SCREEN_N )) ;
  124. verifyPresetProperty (CONFIG::SCREENCAP_W_ID , var(CONFIG::DEFAULT_SCREENCAP_W )) ;
  125. verifyPresetProperty (CONFIG::SCREENCAP_H_ID , var(CONFIG::DEFAULT_SCREENCAP_H )) ;
  126. verifyPresetProperty (CONFIG::OFFSET_X_ID , var(CONFIG::DEFAULT_OFFSET_X )) ;
  127. verifyPresetProperty (CONFIG::OFFSET_Y_ID , var(CONFIG::DEFAULT_OFFSET_Y )) ;
  128. verifyPresetProperty (CONFIG::CAMERA_DEVICE_ID , var(CONFIG::DEFAULT_CAMERA_DEVICE_IDX)) ;
  129. verifyPresetProperty (CONFIG::CAMERA_RES_ID , var(CONFIG::DEFAULT_CAMERA_RES_IDX )) ;
  130. verifyPresetProperty (CONFIG::AUDIO_API_ID , var(CONFIG::DEFAULT_AUDIO_API_IDX )) ;
  131. verifyPresetProperty (CONFIG::AUDIO_DEVICE_ID , var(CONFIG::DEFAULT_AUDIO_DEVICE_IDX )) ;
  132. verifyPresetProperty (CONFIG::AUDIO_CODEC_ID , var(CONFIG::DEFAULT_AUDIO_CODEC_IDX )) ;
  133. verifyPresetProperty (CONFIG::N_CHANNELS_ID , var(CONFIG::DEFAULT_N_CHANNELS )) ;
  134. verifyPresetProperty (CONFIG::SAMPLERATE_ID , var(CONFIG::DEFAULT_SAMPLERATE_IDX )) ;
  135. verifyPresetProperty (CONFIG::AUDIO_BITRATE_ID , var(CONFIG::DEFAULT_AUDIO_BITRATE_IDX)) ;
  136. verifyPresetProperty (CONFIG::MOTD_TEXT_ID , var(CONFIG::DEFAULT_MOTD_TEXT )) ;
  137. verifyPresetProperty (CONFIG::TEXT_STYLE_ID , var(CONFIG::DEFAULT_TEXT_STYLE_IDX )) ;
  138. verifyPresetProperty (CONFIG::TEXT_POSITION_ID , var(CONFIG::DEFAULT_TEXT_POSITION_IDX)) ;
  139. verifyPresetProperty (CONFIG::IMAGE_LOC_ID , var(CONFIG::DEFAULT_IMAGE_LOCATION )) ;
  140. verifyPresetProperty (CONFIG::OUTPUT_SINK_ID , var(CONFIG::DEFAULT_OUTPUT_SINK_IDX )) ;
  141. verifyPresetProperty (CONFIG::OUTPUT_MUXER_ID , var(CONFIG::DEFAULT_OUTPUT_MUXER_IDX )) ;
  142. verifyPresetProperty (CONFIG::OUTPUT_W_ID , var(CONFIG::DEFAULT_OUTPUT_W )) ;
  143. verifyPresetProperty (CONFIG::OUTPUT_H_ID , var(CONFIG::DEFAULT_OUTPUT_H )) ;
  144. verifyPresetProperty (CONFIG::FRAMERATE_ID , var(CONFIG::DEFAULT_FRAMERATE_IDX )) ;
  145. verifyPresetProperty (CONFIG::VIDEO_BITRATE_ID , var(CONFIG::DEFAULT_VIDEO_BITRATE_IDX)) ;
  146. verifyPresetProperty (CONFIG::OUTPUT_DEST_ID , var(CONFIG::DEFAULT_OUTPUT_DEST )) ;
  147. verifyPresetChildNode(CONFIG::NETWORK_ID) ;
  148. verifyNetworkProperty(CONFIG::NETWORK_ID , var(CONFIG::DEFAULT_NETWORK )) ;
  149. verifyNetworkProperty(CONFIG::PORT_ID , var(CONFIG::DEFAULT_PORT )) ;
  150. verifyNetworkProperty(CONFIG::NICK_ID , var(CONFIG::DEFAULT_NICK )) ;
  151. verifyNetworkProperty(CONFIG::PASS_ID , var(CONFIG::DEFAULT_PASS )) ;
  152. verifyNetworkProperty(CONFIG::CHANNEL_ID , var(CONFIG::DEFAULT_CHANNEL )) ;
  153. verifyNetworkProperty(CONFIG::TIMESTAMPS_ID , var(CONFIG::DEFAULT_SHOW_TIMESTAMPS )) ;
  154. verifyNetworkProperty(CONFIG::JOINPARTS_ID , var(CONFIG::DEFAULT_SHOW_JOINPARTS )) ;
  155. verifyNetworkProperty(CONFIG::GREETING_ID , var(CONFIG::DEFAULT_GREETING )) ;
  156. // filter any rogue data
  157. filterRogueKeys (this->root , CONFIG::RootPersistentKeys() ) ;
  158. filterRogueKeys (this->config , CONFIG::PresetPersistentKeys() ) ;
  159. filterRogueKeys (this->network , CONFIG::NetworkPersistentKeys() ) ;
  160. filterRogueNodes(this->root , CONFIG::RootPersistentNodes() ) ;
  161. filterRogueNodes(this->config , CONFIG::PresetPersistentNodes() ) ;
  162. filterRogueNodes(this->network , CONFIG::NetworkPersistentNodes()) ;
  163. }
  164. void AvCasterStore::sanitizeRoot()
  165. {
  166. sanitizeRootComboProperty(CONFIG::PRESET_ID , presetsNames()) ;
  167. }
  168. void AvCasterStore::sanitizePresets()
  169. {
  170. DEBUG_TRACE_SANITIZE_PRESETS
  171. // sanitize user-defined preset configurations
  172. int n_presets = this->presets.getNumChildren() ;
  173. for (int preset_n = CONFIG::N_STATIC_PRESETS ; preset_n < n_presets ; ++preset_n)
  174. {
  175. ValueTree preset_store = this->presets.getChild(preset_n) ;
  176. this->config.copyPropertiesFrom(preset_store , nullptr) ; sanitizePreset() ;
  177. preset_store.copyPropertiesFrom(this->config , nullptr) ;
  178. }
  179. }
  180. void AvCasterStore::sanitizePreset()
  181. {
  182. sanitizePresetComboProperty(CONFIG::CAMERA_RES_ID , getCameraResolutions() ) ;
  183. sanitizePresetComboProperty(CONFIG::CAMERA_DEVICE_ID , cameraNames() ) ;
  184. sanitizePresetComboProperty(CONFIG::AUDIO_API_ID , CONFIG::AudioApis() ) ;
  185. sanitizePresetComboProperty(CONFIG::AUDIO_DEVICE_ID , audioNames() ) ;
  186. sanitizePresetComboProperty(CONFIG::AUDIO_CODEC_ID , CONFIG::AudioCodecs() ) ;
  187. sanitizePresetComboProperty(CONFIG::SAMPLERATE_ID , CONFIG::AudioSampleRates()) ;
  188. sanitizePresetComboProperty(CONFIG::AUDIO_BITRATE_ID , CONFIG::AudioBitRates() ) ;
  189. sanitizePresetComboProperty(CONFIG::TEXT_STYLE_ID , CONFIG::TextStyles() ) ;
  190. sanitizePresetComboProperty(CONFIG::TEXT_POSITION_ID , CONFIG::TextPositions() ) ;
  191. sanitizePresetComboProperty(CONFIG::OUTPUT_SINK_ID , CONFIG::OutputSinks() ) ;
  192. sanitizePresetComboProperty(CONFIG::OUTPUT_MUXER_ID , CONFIG::OutputMuxers() ) ;
  193. sanitizePresetComboProperty(CONFIG::FRAMERATE_ID , CONFIG::FrameRates() ) ;
  194. sanitizePresetComboProperty(CONFIG::VIDEO_BITRATE_ID , CONFIG::VideoBitRates() ) ;
  195. }
  196. void AvCasterStore::verifyChildNode(ValueTree config_store , Identifier a_node_id)
  197. {
  198. DEBUG_TRACE_VERIFY_MISSING_NODE
  199. if (!config_store.getChildWithName(a_node_id).isValid())
  200. config_store.addChild(ValueTree(a_node_id) , -1 , nullptr) ;
  201. }
  202. void AvCasterStore::verifyPresetChildNode(Identifier a_node_id)
  203. {
  204. verifyChildNode(this->config , a_node_id) ;
  205. }
  206. void AvCasterStore::verifyProperty(ValueTree config_store , Identifier a_key ,
  207. var a_default_value )
  208. {
  209. DEBUG_TRACE_VERIFY_MISSING_PROPERTY
  210. if (!config_store.hasProperty(a_key))
  211. config_store.setProperty(a_key , a_default_value , nullptr) ;
  212. }
  213. void AvCasterStore::verifyRootProperty(Identifier a_key , var a_default_value)
  214. {
  215. verifyProperty(this->root , a_key , a_default_value) ;
  216. }
  217. void AvCasterStore::verifyPresetProperty(Identifier a_key , var a_default_value)
  218. {
  219. verifyProperty(this->config , a_key , a_default_value) ;
  220. }
  221. void AvCasterStore::restoreStaticPresets()
  222. {
  223. ValueTree preset_seeds = Seeds::PresetSeeds() ;
  224. for (int preset_idx = 0 ; preset_idx < CONFIG::N_STATIC_PRESETS ; ++preset_idx)
  225. {
  226. ValueTree preset_seed = preset_seeds.getChild(0) ;
  227. Identifier preset_id = preset_seed.getType() ;
  228. ValueTree existing_preset = this->presets.getChild(preset_idx) ;
  229. if (existing_preset.hasType(preset_id) && existing_preset.isValid()) continue ;
  230. removeConflictedNodes(this->presets , preset_id) ;
  231. preset_seeds .removeChild(preset_seed , nullptr) ;
  232. this->presets.addChild (preset_seed , preset_idx , nullptr) ;
  233. }
  234. }
  235. bool AvCasterStore::hasDuplicatedNodes(ValueTree stored_config)
  236. {
  237. StringArray root_node_ids = CONFIG::RootPersistentNodes() ;
  238. StringArray preset_node_ids = CONFIG::PresetPersistentNodes() ;
  239. StringArray network_node_ids = CONFIG::NetworkPersistentNodes() ;
  240. int n_duplicated_nodes = 0 ;
  241. bool has_duplicates = false ;
  242. n_duplicated_nodes = nDuplicatedNodes(stored_config , root_node_ids) ;
  243. has_duplicates = has_duplicates || n_duplicated_nodes > root_node_ids.size() ;
  244. ValueTree presets_node = stored_config.getChildWithName(CONFIG::PRESETS_ID) ;
  245. for (int preset_n = 0 ; preset_n < presets_node.getNumChildren() ; ++preset_n)
  246. {
  247. ValueTree preset_node = presets_node.getChild(preset_n) ;
  248. n_duplicated_nodes = nDuplicatedNodes(preset_node , preset_node_ids) ;
  249. has_duplicates = has_duplicates || n_duplicated_nodes > preset_node_ids .size() ;
  250. ValueTree network_node = preset_node.getChildWithName(CONFIG::NETWORK_ID) ;
  251. n_duplicated_nodes = nDuplicatedNodes(network_node , network_node_ids) ;
  252. has_duplicates = has_duplicates || n_duplicated_nodes > network_node_ids.size() ;
  253. }
  254. return has_duplicates ;
  255. }
  256. int AvCasterStore::nDuplicatedNodes(ValueTree parent_node , StringArray node_ids)
  257. {
  258. int n_duplicated_nodes = 0 ;
  259. for (int node_n = 0 ; node_n < node_ids.size() ; ++node_n)
  260. {
  261. Identifier node_id = CONFIG::FilterId(node_ids[node_n] , APP::VALID_ID_CHARS) ;
  262. for (int child_n = 0 ; child_n < parent_node.getNumChildren() ; ++child_n)
  263. if (parent_node.getChild(child_n).hasType(node_id)) ++n_duplicated_nodes ;
  264. }
  265. return n_duplicated_nodes ;
  266. }
  267. void AvCasterStore::removeConflictedNodes(ValueTree parent_node , Identifier node_id)
  268. {
  269. ValueTree a_node ;
  270. while ((a_node = parent_node.getChildWithName(node_id)).isValid())
  271. parent_node.removeChild(a_node , nullptr) ;
  272. }
  273. void AvCasterStore::verifyNetworkProperty(Identifier a_key , var a_default_value)
  274. {
  275. ValueTree network_store = this->config.getChildWithName(CONFIG::NETWORK_ID) ;
  276. verifyProperty(network_store , a_key , a_default_value) ;
  277. }
  278. void AvCasterStore::filterRogueKeys(ValueTree parent_node , StringArray persistent_keys)
  279. {
  280. for (int key_n = 0 ; key_n < parent_node.getNumProperties() ; ++key_n)
  281. {
  282. String property_id = STRING(parent_node.getPropertyName(key_n)) ;
  283. DEBUG_TRACE_FILTER_ROGUE_KEY
  284. if (!persistent_keys.contains(property_id))
  285. parent_node.removeProperty( property_id , nullptr) ;
  286. }
  287. }
  288. void AvCasterStore::filterRogueNodes(ValueTree parent_node , StringArray persistent_node_ids)
  289. {
  290. for (int child_n = 0 ; child_n < parent_node.getNumChildren() ; ++child_n)
  291. {
  292. String node_id = STRING(parent_node.getChild(child_n).getType()) ;
  293. DEBUG_TRACE_FILTER_ROGUE_NODE
  294. if (!persistent_node_ids.contains(node_id))
  295. parent_node.removeChild(child_n , nullptr) ;
  296. }
  297. }
  298. void AvCasterStore::sanitizeIntProperty(ValueTree config_store , Identifier a_key ,
  299. int min_value , int max_value )
  300. {
  301. int a_value = int(config_store[a_key]) ;
  302. if (a_value < min_value || a_value > max_value)
  303. config_store.removeProperty(a_key , nullptr) ;
  304. DEBUG_TRACE_SANITIZE_INT_PROPERTY
  305. }
  306. void AvCasterStore::sanitizeRootComboProperty(Identifier a_key , StringArray options)
  307. {
  308. sanitizeIntProperty(this->root , a_key , 0 , options.size() - 1) ;
  309. }
  310. void AvCasterStore::sanitizePresetComboProperty(Identifier a_key , StringArray options)
  311. {
  312. sanitizeIntProperty(this->config , a_key , -1 , options.size() - 1) ;
  313. }
  314. void AvCasterStore::restoreTransients()
  315. {
  316. if (AvCaster::IsInitialized) return ; // NOTE: should be called only once on startup
  317. setValue(this->root , CONFIG::IS_PENDING_ID , CONFIG::DEFAULT_IS_PENDING) ;
  318. for (int preset_n = 0 ; preset_n < this->presets.getNumChildren() ; ++preset_n)
  319. restorePresetTransients(this->presets.getChild(preset_n)) ;
  320. restorePresetTransients(this->config) ;
  321. }
  322. void AvCasterStore::restorePresetTransients(ValueTree a_preset_store)
  323. {
  324. ValueTree network_store = a_preset_store.getChildWithName(CONFIG::NETWORK_ID ) ;
  325. // restore or reset properties
  326. setValue(a_preset_store , CONFIG::OUTPUT_ID , CONFIG::DEFAULT_IS_OUTPUT_ACTIVE) ;
  327. setValue(network_store , CONFIG::HOST_ID , CONFIG::DEFAULT_HOST ) ;
  328. setValue(network_store , CONFIG::RETRIES_ID , CONFIG::DEFAULT_N_RETRIES ) ;
  329. // restore or reset child nodes
  330. this->chatters.removeAllChildren(nullptr) ;
  331. }
  332. /* persistence */
  333. ValueTree AvCasterStore::loadConfig()
  334. {
  335. // load persistent storage
  336. this->storageDir = APP::appdataDir().getChildFile(CONFIG::STORAGE_DIRNAME ) ;
  337. this->storageFile = this->storageDir .getChildFile(CONFIG::STORAGE_FILENAME) ;
  338. FileInputStream* storage = new FileInputStream(this->storageFile) ;
  339. ValueTree root_node = (storage->openedOk()) ? ValueTree::readFromStream(*storage) :
  340. ValueTree::invalid ;
  341. delete storage ;
  342. return root_node ;
  343. }
  344. void AvCasterStore::storeConfig()
  345. {
  346. DEBUG_TRACE_STORE_CONFIG
  347. if (!this->root.isValid()) return ;
  348. // prepare storage directory
  349. this->storageDir .createDirectory() ;
  350. this->storageFile.deleteFile() ;
  351. ValueTree root_clone = this->root .createCopy() ;
  352. ValueTree presets_clone = this->presets.createCopy() ;
  353. // filter transient data and append presets and networks to persistent storage
  354. root_clone.removeProperty(CONFIG::IS_PENDING_ID , nullptr) ;
  355. root_clone.addChild (presets_clone , -1 , nullptr) ;
  356. for (int preset_n = 0 ; preset_n < presets_clone.getNumChildren() ; ++preset_n)
  357. {
  358. ValueTree preset_clone = presets_clone.getChild(preset_n) ;
  359. ValueTree network_clone = preset_clone .getChildWithName(CONFIG::NETWORK_ID ) ;
  360. preset_clone .removeProperty(CONFIG::OUTPUT_ID , nullptr) ;
  361. network_clone.removeProperty(CONFIG::HOST_ID , nullptr) ;
  362. network_clone.removeProperty(CONFIG::RETRIES_ID , nullptr) ;
  363. }
  364. DEBUG_TRACE_DUMP_CONFIG (root_clone , "root_clone")
  365. DEBUG_TRACE_DUMP_CONFIG_XML(root_clone , "root_clone")
  366. // marshall configuration out to persistent binary storage
  367. FileOutputStream* config_stream = new FileOutputStream(this->storageFile) ;
  368. if (!config_stream->failedToOpen()) root_clone.writeToStream(*config_stream) ;
  369. else AvCaster::Error(GUI::STORAGE_WRITE_ERROR_MSG) ;
  370. delete config_stream ;
  371. }
  372. void AvCasterStore::loadPreset()
  373. {
  374. int preset_idx = int(this->root[CONFIG::PRESET_ID]) ;
  375. ValueTree preset_store = this->presets.getChild(preset_idx) ;
  376. ValueTree network_store = preset_store.getChildWithName(CONFIG::NETWORK_ID) ;
  377. if (preset_idx == CONFIG::INVALID_IDX) return ; // renaming
  378. DEBUG_TRACE_LOAD_PRESET
  379. listen(false) ;
  380. this->config .copyPropertiesFrom(preset_store , nullptr) ;
  381. this->network .copyPropertiesFrom(network_store , nullptr) ;
  382. this->chatters.removeAllChildren(nullptr) ;
  383. listen(true) ;
  384. }
  385. void AvCasterStore::storePreset(String preset_name)
  386. {
  387. if (preset_name.isEmpty()) return ;
  388. Identifier preset_id = CONFIG::FilterId(preset_name , APP::VALID_ID_CHARS) ;
  389. ValueTree preset_store = this->presets.getOrCreateChildWithName(preset_id , nullptr) ;
  390. ValueTree network_store = preset_store .getOrCreateChildWithName(CONFIG::NETWORK_ID , nullptr) ;
  391. int preset_idx = this->presets.indexOf(preset_store) ;
  392. DEBUG_TRACE_STORE_PRESET
  393. DEBUG_TRACE_DUMP_CONFIG_XML(this->config , STRING(preset_id))
  394. #ifdef FIX_OUTPUT_RESOLUTION_TO_LARGEST_INPUT
  395. int fullscreen_w = int(this->config[CONFIG::SCREENCAP_W_ID]) ;
  396. int fullscreen_h = int(this->config[CONFIG::SCREENCAP_H_ID]) ;
  397. int output_w = int(this->config[CONFIG::OUTPUT_W_ID ]) ;
  398. int output_h = int(this->config[CONFIG::OUTPUT_H_ID ]) ;
  399. Point<int> resolution = AvCaster::GetCameraResolution() ;
  400. int camera_w = resolution.getX() ;
  401. int camera_h = resolution.getY() ;
  402. var fit_output_w = var(jmax(fullscreen_w , camera_w , output_w)) ;
  403. var fit_output_h = var(jmax(fullscreen_h , camera_h , output_h)) ;
  404. setValue(this->config , CONFIG::OUTPUT_W_ID , fit_output_w) ;
  405. setValue(this->config , CONFIG::OUTPUT_H_ID , fit_output_h) ;
  406. #endif // FIX_OUTPUT_RESOLUTION_TO_LARGEST_INPUT
  407. setValue(this->config , CONFIG::PRESET_NAME_ID , preset_name) ;
  408. preset_store .copyPropertiesFrom(this->config , nullptr) ;
  409. network_store.copyPropertiesFrom(this->network , nullptr) ;
  410. setValue(this->root , CONFIG::PRESET_ID , preset_idx ) ;
  411. }
  412. void AvCasterStore::renamePreset(String preset_name)
  413. {
  414. Identifier preset_id = CONFIG::FilterId(preset_name , APP::VALID_ID_CHARS) ;
  415. int preset_idx = int(this->root[CONFIG::PRESET_ID]) ;
  416. ValueTree conflict_store = this->presets.getChildWithName(preset_id) ;
  417. if (conflict_store.isValid()) return ;
  418. DEBUG_TRACE_RENAME_PRESET
  419. // destroy and re-create
  420. this->presets.removeChild(preset_idx , nullptr) ;
  421. setValue(this->root , CONFIG::PRESET_ID , CONFIG::INVALID_IDX) ; // force reload
  422. storePreset(preset_name) ;
  423. }
  424. void AvCasterStore::deletePreset()
  425. {
  426. int preset_idx = int(this->root[CONFIG::PRESET_ID]) ;
  427. if (this->presets.getNumChildren() <= 1) return ;
  428. DEBUG_TRACE_DELETE_PRESET
  429. this->presets.removeChild(preset_idx , nullptr) ;
  430. setValue(this->root , CONFIG::PRESET_ID , CONFIG::DEFAULT_PRESET_IDX) ;
  431. AvCaster::RefreshGui() ;
  432. }
  433. void AvCasterStore::resetPreset()
  434. {
  435. if (!AvCaster::IsStaticPreset()) return ;
  436. int preset_idx = int(this->root[CONFIG::PRESET_ID]) ;
  437. ValueTree preset_store = this->presets.getChild(preset_idx) ;
  438. ValueTree network_store = preset_store .getChildWithName(CONFIG::NETWORK_ID) ;
  439. ValueTree preset_seed = Seeds::PresetSeeds().getChild(preset_idx) ;
  440. ValueTree network_seed = preset_seed .getChildWithName(CONFIG::NETWORK_ID) ;
  441. // transfer default preset values
  442. preset_store .copyPropertiesFrom(preset_seed , nullptr) ;
  443. network_store.copyPropertiesFrom(network_seed , nullptr) ;
  444. restorePresetTransients(preset_store) ;
  445. loadPreset() ; AvCaster::RefreshGui() ;
  446. }
  447. /* runtime params */
  448. /*
  449. void AvCasterStore::detectDisplayDimensions()
  450. {
  451. // TODO: the JUCE way - does not reflect resolution changes (issue #2 issue #4)
  452. (see ComponentPeer::handleScreenSizeChange and/or Component::getParentMonitorArea)
  453. gStreamer handles resolution changes gracefully so this may not be strictly necessary
  454. Rectangle<int> area = Desktop::getInstance().getDisplays().getMainDisplay().totalArea ;
  455. this->desktopW = area.getWidth() ;
  456. this->desktopH = area.getHeight() ;
  457. Trace::TraceState("detected desktop dimensions " + String(this->desktopW) + "x" + String(this->desktopH)) ;
  458. }
  459. */
  460. void AvCasterStore::detectCaptureDevices()
  461. {
  462. #if JUCE_LINUX
  463. // TODO: query device for framerates and resolutions
  464. int camera_rate = CONFIG::DEFAULT_CAMERA_RATE ;
  465. String resolutions = CONFIG::CameraResolutions().joinIntoString(newLine) ;
  466. Array<File> device_info_dirs ;
  467. this->cameras.removeAllChildren(nullptr) ;
  468. if (APP::camerasDevDir().containsSubDirectories())
  469. APP::camerasDevDir().findChildFiles(device_info_dirs , File::findDirectories , false) ;
  470. File* device_info_dir = device_info_dirs.begin() ;
  471. while (device_info_dir != device_info_dirs.end())
  472. {
  473. String device_id = device_info_dir->getFileName() ;
  474. String friendly_name = device_info_dir->getChildFile("name").loadFileAsString().trim() ;
  475. String device_path = "/dev/" + device_id ;
  476. ValueTree device_info = ValueTree(Identifier(device_id)) ;
  477. device_info.setProperty(CONFIG::CAMERA_PATH_ID , var(device_path ) , nullptr) ;
  478. device_info.setProperty(CONFIG::CAMERA_NAME_ID , var(friendly_name) , nullptr) ;
  479. device_info.setProperty(CONFIG::CAMERA_RATE_ID , var(camera_rate ) , nullptr) ;
  480. device_info.setProperty(CONFIG::CAMERA_RESOLUTIONS_ID , var(resolutions ) , nullptr) ;
  481. this->cameras.addChild(device_info , -1 , nullptr) ;
  482. ++device_info_dir ;
  483. }
  484. /* mac and windows only (issue #6 issue #8)
  485. #else // JUCE_LINUX
  486. # if JUCE_WINDOWS || JUCE_MAC
  487. // Returns a list of the available cameras on this machine.
  488. StringArray video_devs = juce::CameraDevice::getAvailableDevices() ;
  489. LOG(video_devs.joinIntoString("\n")) ;
  490. while (video_devs.size())
  491. {
  492. LOG("video_devs=" + video_devs[0]) ;
  493. video_devs.remove(0) ;
  494. }
  495. */
  496. /* mac and windows only (issue #6 issue #8)
  497. You can open one of these devices by calling openDevice().
  498. static CameraDevice* CameraDevice::openDevice (
  499. int deviceIndex,
  500. int minWidth = 128,
  501. int minHeight = 64,
  502. int maxWidth = 1024,
  503. int maxHeight = 768
  504. )
  505. # endif // JUCE_WINDOWS || JUCE_MAC
  506. */
  507. #endif // JUCE_LINUX
  508. DEBUG_TRACE_DETECT_CAPTURE_DEVICES
  509. }
  510. /* event handlers */
  511. void AvCasterStore::listen(bool should_listen)
  512. {
  513. if (!AvCaster::IsInitialized) return ;
  514. DEBUG_TRACE_LISTEN
  515. if (should_listen) { this->root.addListener (this) ; this->config.addListener (this) ; }
  516. else { this->root.removeListener(this) ; this->config.removeListener(this) ; }
  517. }
  518. void AvCasterStore::valueTreePropertyChanged(ValueTree& a_node , const Identifier& a_key)
  519. {
  520. DEBUG_TRACE_CONFIG_TREE_CHANGED
  521. if (a_key == CONFIG::PRESET_ID) loadPreset() ;
  522. AvCaster::HandleConfigChanged(a_key) ;
  523. }
  524. /* getters/setters */
  525. bool AvCasterStore::isMediaToggleKey(const Identifier& a_key)
  526. {
  527. return CONFIG::MediaToggleKeys().contains(STRING(a_key)) ;
  528. }
  529. bool AvCasterStore::isPresetConfigKey(const Identifier& a_key)
  530. {
  531. return CONFIG::PresetConfigKeys().contains(STRING(a_key)) ;
  532. }
  533. void AvCasterStore::deactivateControl(const Identifier& a_key)
  534. {
  535. if (!isMediaToggleKey(a_key)) return ;
  536. listen(false) ;
  537. DEBUG_TRACE_DEACTIVATE_CONTROL
  538. setValue(this->config , a_key , var(false)) ;
  539. listen(true) ;
  540. }
  541. bool AvCasterStore::isKnownProperty(ValueTree a_node , const Identifier& a_key)
  542. {
  543. ValueTree a_parent_node = a_node.getParent() ;
  544. // TODO: cameras and audio nyi
  545. return (a_node == this->root ) ? CONFIG::RootKeys() .contains(a_key) :
  546. (a_node == this->config ) ? CONFIG::PresetKeys() .contains(a_key) :
  547. (a_node == this->network ) ? CONFIG::NetworkKeys().contains(a_key) :
  548. (a_parent_node == this->presets ) ? CONFIG::PresetKeys() .contains(a_key) :
  549. (a_parent_node == this->chatters) ? CONFIG::ChatterKeys().contains(a_key) :
  550. (a_parent_node == this->cameras ) ? CONFIG::CameraKeys() .contains(a_key) :
  551. (a_parent_node == this->audios ) ? CONFIG::AudioKeys() .contains(a_key) :
  552. false ;
  553. }
  554. void AvCasterStore::setProperty(ValueTree a_node , const Identifier& a_key ,
  555. const var a_value )
  556. {
  557. if (!a_node.isValid() || !isKnownProperty(a_node , a_key)) return ;
  558. DEBUG_TRACE_SET_PROPERTY // call this only from AvCasterStore->setValue() and AvCasterStore->setValueViaGui() for tracing correctness
  559. if (!AvCaster::IsInitialized || !AvCaster::DisabledFeatures.contains(a_key))
  560. a_node.setProperty(a_key , a_value , nullptr) ;
  561. }
  562. void AvCasterStore::setValue(ValueTree a_node , const Identifier& a_key ,
  563. const var a_value )
  564. {
  565. DEBUG_TRACE_STORE_SET_VALUE // call this only from AvCasterStore methods for tracing correctness
  566. setProperty(a_node , a_key , a_value) ;
  567. }
  568. void AvCasterStore::setValueViaGui(ValueTree a_node , const Identifier& a_key ,
  569. const var a_value )
  570. {
  571. DEBUG_TRACE_GUI_SET_VALUE // call this only from AvCaster methods for tracing correctness
  572. setProperty(a_node , a_key , a_value) ;
  573. }
  574. void AvCasterStore::updateChatters(StringArray active_nicks)
  575. {
  576. StringArray stored_nicks = getChatNicks() ;
  577. #ifdef PREFIX_CHAT_NICKS
  578. String network = String(this->network[NETWORK_ID]) ;
  579. String channel = String(this->network[CHANNEL_ID]) ;
  580. bool is_lctv = IRC::BITLBEE_HOSTS.contains(network) &&
  581. channel == IRC::BITLBEE_XMPP_CHANNEL ;
  582. String prefix = (is_lctv) ? GUI::LCTV_USER_PREFIX : GUI::IRC_USER_PREFIX ;
  583. String joined_nicks = active_nicks.joinIntoString("] " + prefix + "[") ;
  584. String prefixed_nicks = prefix + "[" + joined_nicks + "]" ;
  585. active_nicks = StringArray::fromTokens(prefixed_nicks , false) ;
  586. #endif // PREFIX_CHAT_NICKS
  587. DEBUG_TRACE_UPDATE_CHAT_NICKS_IN
  588. // add joining chatters
  589. for (int chatter_idx = 0 ; chatter_idx < active_nicks.size() ; ++chatter_idx)
  590. {
  591. String active_nick = active_nicks[chatter_idx] ;
  592. Identifier chatter_id = CONFIG::FilterId(active_nick , APP::VALID_NICK_CHARS) ;
  593. ValueTree chatter_store = this->chatters.getChildWithName(chatter_id) ;
  594. if (!chatter_store.isValid())
  595. {
  596. stored_nicks.add(active_nick) ; stored_nicks.sort(true) ;
  597. DEBUG_TRACE_ADD_CHAT_NICK
  598. chatter_store = ValueTree(chatter_id) ;
  599. chatter_store.setProperty(CONFIG::NICK_ID , var(active_nick) , nullptr) ;
  600. this->chatters.addChild(chatter_store , stored_nicks.indexOf(active_nick) , nullptr) ;
  601. }
  602. }
  603. // remove parting chatters
  604. for (int chatter_idx = 0 ; chatter_idx < stored_nicks.size() ; ++chatter_idx)
  605. {
  606. String stored_nick = stored_nicks[chatter_idx] ;
  607. Identifier chatter_id = CONFIG::FilterId(stored_nick , APP::VALID_NICK_CHARS) ;
  608. ValueTree chatter_store = this->chatters.getChildWithName(chatter_id) ;
  609. DEBUG_TRACE_REMOVE_CHAT_NICK
  610. if (!active_nicks.contains(stored_nick))
  611. this->chatters.removeChild(chatter_store , nullptr) ;
  612. }
  613. DEBUG_TRACE_UPDATE_CHAT_NICKS_OUT
  614. }
  615. StringArray AvCasterStore::presetsNames()
  616. {
  617. return PropertyValues(this->presets , CONFIG::PRESET_NAME_ID) ;
  618. }
  619. StringArray AvCasterStore::cameraNames()
  620. {
  621. return PropertyValues(this->cameras , CONFIG::CAMERA_NAME_ID) ;
  622. }
  623. StringArray AvCasterStore::audioNames()
  624. {
  625. return PropertyValues(this->audios , Identifier("TODO")) ;
  626. }
  627. ValueTree AvCasterStore::getCameraStore()
  628. {
  629. int camera_idx = int(this->config[CONFIG::CAMERA_DEVICE_ID]) ;
  630. return this->cameras.getChild(camera_idx) ;
  631. }
  632. StringArray AvCasterStore::getCameraResolutions()
  633. {
  634. ValueTree camera_store = getCameraStore() ;
  635. String resolutions = STRING(camera_store[CONFIG::CAMERA_RESOLUTIONS_ID]) ;
  636. return (camera_store.isValid()) ? StringArray::fromLines(resolutions) :
  637. CONFIG::CameraResolutions() ;
  638. }
  639. StringArray AvCasterStore::getChatNicks()
  640. {
  641. return AvCasterStore::PropertyValues(this->chatters , CONFIG::NICK_ID) ;
  642. }