bbb.lib.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  1. <?php
  2. /**
  3. * This script initiates a videoconference session, calling the BigBlueButton API
  4. * @package chamilo.plugin.bigbluebutton
  5. */
  6. class bbb {
  7. var $url;
  8. var $salt;
  9. var $api;
  10. var $user_complete_name = null;
  11. var $protocol = 'http://';
  12. var $debug = false;
  13. var $logout_url = null;
  14. var $plugin_enabled = false;
  15. function __construct() {
  16. // initialize video server settings from global settings
  17. $plugin = BBBPlugin::create();
  18. $bbb_plugin = $plugin->get('tool_enable');
  19. $bbb_host = $plugin->get('host');
  20. $bbb_salt = $plugin->get('salt');
  21. //$course_code = api_get_course_id();
  22. $this->logout_url = api_get_path(WEB_PLUGIN_PATH).'bbb/listing.php';
  23. $this->table = Database::get_main_table('plugin_bbb_meeting');
  24. if ($bbb_plugin == true) {
  25. $user_info = api_get_user_info();
  26. $this->user_complete_name = $user_info['complete_name'];
  27. $this->salt = $bbb_salt;
  28. $info = parse_url($bbb_host);
  29. $this->url = $bbb_host.'/bigbluebutton/';
  30. if (isset($info['scheme'])) {
  31. $this->protocol = $info['scheme'].'://';
  32. $this->url = str_replace($this->protocol, '', $this->url);
  33. }
  34. // Setting BBB api
  35. define('CONFIG_SECURITY_SALT', $this->salt);
  36. define('CONFIG_SERVER_BASE_URL', $this->url);
  37. $this->api = new BigBlueButtonBN();
  38. $this->plugin_enabled = true;
  39. }
  40. }
  41. function is_teacher() {
  42. return api_is_course_admin() || api_is_coach() || api_is_platform_admin();
  43. }
  44. /*
  45. * See this file in you BBB to set up default values
  46. /var/lib/tomcat6/webapps/bigbluebutton/WEB-INF/classes/bigbluebutton.properties
  47. *
  48. More record information:
  49. http://code.google.com/p/bigbluebutton/wiki/RecordPlaybackSpecification
  50. # Default maximum number of users a meeting can have.
  51. # Doesn't get enforced yet but is the default value when the create
  52. # API doesn't pass a value.
  53. defaultMaxUsers=20
  54. # Default duration of the meeting in minutes.
  55. # Current default is 0 (meeting doesn't end).
  56. defaultMeetingDuration=0
  57. # Remove the meeting from memory when the end API is called.
  58. # This allows 3rd-party apps to recycle the meeting right-away
  59. # instead of waiting for the meeting to expire (see below).
  60. removeMeetingWhenEnded=false
  61. # The number of minutes before the system removes the meeting from memory.
  62. defaultMeetingExpireDuration=1
  63. # The number of minutes the system waits when a meeting is created and when
  64. # a user joins. If after this period, a user hasn't joined, the meeting is
  65. # removed from memory.
  66. defaultMeetingCreateJoinDuration=5
  67. *
  68. */
  69. function create_meeting($params) {
  70. $params['c_id'] = api_get_course_int_id();
  71. $course_code = api_get_course_id();
  72. $attende_password = $params['attendee_pw'] = isset($params['moderator_pw']) ? $params['moderator_pw'] : api_get_course_id();
  73. $moderator_password = $params['moderator_pw'] = isset($params['moderator_pw']) ? $params['moderator_pw'] : $this->get_mod_meeting_password();
  74. $params['record'] = api_get_course_setting('big_blue_button_record_and_store', $course_code) == 1 ? true : false;
  75. $max = api_get_course_setting('big_blue_button_max_students_allowed', $course_code);
  76. $max = isset($max) ? $max : -1;
  77. $params['status'] = 1;
  78. if ($this->debug) error_log("enter create_meeting ".print_r($params, 1));
  79. $params['created_at'] = api_get_utc_datetime();
  80. $id = Database::insert($this->table, $params);
  81. if ($id) {
  82. if ($this->debug) error_log("create_meeting: $id ");
  83. $meeting_name = isset($params['meeting_name']) ? $params['meeting_name'] : api_get_course_id();
  84. $welcome_msg = isset($params['welcome_msg']) ? $params['welcome_msg'] : null;
  85. $record = isset($params['record']) && $params['record'] ? 'true' : 'false';
  86. $duration = isset($params['duration']) ? intval($params['duration']) : 0;
  87. $duration = 30;
  88. $bbb_params = array(
  89. 'meetingId' => $id, // REQUIRED
  90. 'meetingName' => $meeting_name, // REQUIRED
  91. 'attendeePw' => $attende_password, // Match this value in getJoinMeetingURL() to join as attendee.
  92. 'moderatorPw' => $moderator_password, // Match this value in getJoinMeetingURL() to join as moderator.
  93. 'welcomeMsg' => $welcome_msg, // ''= use default. Change to customize.
  94. 'dialNumber' => '', // The main number to call into. Optional.
  95. 'voiceBridge' => '0', // PIN to join voice. Optional.
  96. 'webVoice' => '', // Alphanumeric to join voice. Optional.
  97. 'logoutUrl' => $this->logout_url,
  98. 'maxParticipants' => $max, // Optional. -1 = unlimitted. Not supported in BBB. [number]
  99. 'record' => $record, // New. 'true' will tell BBB to record the meeting.
  100. 'duration' => $duration, // Default = 0 which means no set duration in minutes. [number]
  101. //'meta_category' => '', // Use to pass additional info to BBB server. See API docs.
  102. );
  103. if ($this->debug) error_log("create_meeting params: ".print_r($bbb_params,1));
  104. $result = $this->api->createMeetingWithXmlResponseArray($bbb_params);
  105. if (isset($result) && (string)$result['returncode'] == 'SUCCESS') {
  106. if ($this->debug) error_log("create_meeting result: ".print_r($result,1));
  107. return $this->join_meeting($meeting_name);
  108. }
  109. return $this->logout;
  110. }
  111. }
  112. function is_meeting_exist($meeting_name) {
  113. $course_id = api_get_course_int_id();
  114. $meeting_data = Database::select('*', $this->table, array('where' => array('c_id = ? AND meeting_name = ? AND status = 1 ' => array($course_id, $meeting_name))), 'first');
  115. if ($this->debug) error_log("is_meeting_exist ".print_r($meeting_data,1));
  116. if (empty($meeting_data)) {
  117. return false;
  118. } else {
  119. return true;
  120. }
  121. }
  122. /**
  123. * @todo implement moderator pass
  124. */
  125. function join_meeting($meeting_name) {
  126. $pass = $this->get_user_meeting_password();
  127. $meeting_data = Database::select('*', $this->table, array('where' => array('meeting_name = ? AND status = 1 ' => $meeting_name)), 'first');
  128. if (empty($meeting_data)) {
  129. if ($this->debug) error_log("meeting does not exist: $meeting_name ");
  130. return false;
  131. }
  132. $meeting_is_running_info = $this->api->isMeetingRunningWithXmlResponseArray($meeting_data['id']);
  133. $meeting_is_running = $meeting_is_running_info['running'] == 'true' ? true : false;
  134. if ($this->debug) error_log("meeting is running: ".$meeting_is_running);
  135. $params = array(
  136. 'meetingId' => $meeting_data['id'], // -- REQUIRED - The unique id for the meeting
  137. 'password' => $this->get_mod_meeting_password() // -- REQUIRED - The moderator password for the meeting
  138. );
  139. $meeting_info_exists = $this->get_meeting_info($params);
  140. if (isset($meeting_is_running) && $meeting_info_exists) {
  141. $joinParams = array(
  142. 'meetingId' => $meeting_data['id'], // -- REQUIRED - A unique id for the meeting
  143. 'username' => $this->user_complete_name, //-- REQUIRED - The name that will display for the user in the meeting
  144. 'password' => $pass, //-- REQUIRED - The attendee or moderator password, depending on what's passed here
  145. //'createTime' => api_get_utc_datetime(), //-- OPTIONAL - string. Leave blank ('') unless you set this correctly.
  146. 'userID' => api_get_user_id(), //-- OPTIONAL - string
  147. 'webVoiceConf' => '' // -- OPTIONAL - string
  148. );
  149. $url = $this->api->getJoinMeetingURL($joinParams);
  150. $url = $this->protocol.$url;
  151. } else {
  152. $url = $this->logout_url;
  153. }
  154. if ($this->debug) error_log("return url :".$url);
  155. return $url;
  156. }
  157. function get_meeting_info($params) {
  158. try {
  159. $result = $this->api->getMeetingInfoWithXmlResponseArray($params);
  160. if ($result == null) {
  161. if ($this->debug) error_log("Failed to get any response. Maybe we can't contact the BBB server.");
  162. } else {
  163. return $result;
  164. }
  165. } catch (Exception $e) {
  166. if ($this->debug) error_log('Caught exception: ', $e->getMessage(), "\n");
  167. }
  168. return false;
  169. }
  170. /**
  171. * Gets all the course meetings saved in the plugin_bbb_meeting table
  172. * @return string
  173. */
  174. function get_course_meetings() {
  175. $pass = $this->get_user_meeting_password();
  176. $meeting_list = Database::select('*', $this->table, array('where' => array('c_id = ? ' => api_get_course_int_id())));
  177. $new_meeting_list = array();
  178. $item = array();
  179. foreach ($meeting_list as $meeting_db) {
  180. $meeting_bbb = $this->get_meeting_info(array('meetingId' => $meeting_db['id'], 'password' => $pass));
  181. $meeting_bbb['end_url'] = api_get_self().'?action=end&id='.$meeting_db['id'];
  182. if ((string)$meeting_bbb['returncode'] == 'FAILED') {
  183. if ($meeting_db['status'] == 1) {
  184. $this->end_meeting($meeting_db['id']);
  185. }
  186. } else {
  187. $meeting_bbb['add_to_calendar_url'] = api_get_self().'?action=add_to_calendar&id='.$meeting_db['id'].'&start='.api_strtotime($meeting_db['created_at']);
  188. }
  189. $record_array = array();
  190. if ($meeting_db['record'] == 1) {
  191. $recordingParams = array(
  192. 'meetingId' => $meeting_db['id'], //-- OPTIONAL - comma separate if multiple ids
  193. );
  194. //To see the recording list in your BBB server do: bbb-record --list
  195. $records = $this->api->getRecordingsWithXmlResponseArray($recordingParams);
  196. if (!empty($records)) {
  197. $count = 1;
  198. if (isset($records['message']) && !empty($records['message'])) {
  199. if ($records['messageKey'] == 'noRecordings') {
  200. //$record_array[] = get_lang('ThereAreNotRecordingsForTheMeetings');
  201. } else {
  202. //$record_array[] = $records['message'];
  203. }
  204. } else {
  205. foreach ($records as $record) {
  206. if (is_array($record) && isset($record['recordId'])) {
  207. $url = Display::url(get_lang('ViewRecord'), $record['playbackFormatUrl'], array('target' => '_blank'));
  208. if ($this->is_teacher()) {
  209. $url .= Display::url(Display::return_icon('link.gif',get_lang('CopyToLinkTool')), api_get_self().'?action=copy_record_to_link_tool&id='.$meeting_db['id'].'&record_id='.$record['recordId']);
  210. $url .= Display::url(Display::return_icon('agenda.png',get_lang('AddToCalendar')), api_get_self().'?action=add_to_calendar&id='.$meeting_db['id'].'&start='.api_strtotime($meeting_db['created_at']).'&url='.$record['playbackFormatUrl']);
  211. $url .= Display::url(Display::return_icon('delete.png',get_lang('Delete')), api_get_self().'?action=delete_record&id='.$record['recordId']);
  212. }
  213. //$url .= api_get_self().'?action=publish&id='.$record['recordID'];
  214. $count++;
  215. $record_array[] = $url;
  216. } else {
  217. /*if (is_array($record) && isset($record['recordID']) && isset($record['playbacks'])) {
  218. //Fix the bbb timestamp
  219. //$record['startTime'] = substr($record['startTime'], 0, strlen($record['startTime']) -3);
  220. //$record['endTime'] = substr($record['endTime'], 0, strlen($record['endTime']) -3);
  221. //.' - '.api_convert_and_format_date($record['startTime']).' - '.api_convert_and_format_date($record['endTime'])
  222. foreach($record['playbacks'] as $item) {
  223. $url = Display::url(get_lang('ViewRecord'), $item['url'], array('target' => '_blank'));
  224. //$url .= Display::url(get_lang('DeleteRecord'), api_get_self().'?action=delete_record&'.$record['recordID']);
  225. if ($this->is_teacher()) {
  226. $url .= Display::url(Display::return_icon('link.gif',get_lang('CopyToLinkTool')), api_get_self().'?action=copy_record_to_link_tool&id='.$meeting_db['id'].'&record_id='.$record['recordID']);
  227. $url .= Display::url(Display::return_icon('agenda.png',get_lang('AddToCalendar')), api_get_self().'?action=add_to_calendar&id='.$meeting_db['id'].'&start='.api_strtotime($meeting_db['created_at']).'&url='.$item['url']);
  228. $url .= Display::url(Display::return_icon('delete.png',get_lang('Delete')), api_get_self().'?action=delete_record&id='.$record['recordID']);
  229. }
  230. //$url .= api_get_self().'?action=publish&id='.$record['recordID'];
  231. $count++;
  232. $record_array[] = $url;
  233. }
  234. }*/
  235. }
  236. }
  237. }
  238. }
  239. //var_dump($record_array);
  240. $item['show_links'] = implode('<br />', $record_array);
  241. }
  242. $item['created_at'] = api_convert_and_format_date($meeting_db['created_at']);
  243. //created_at
  244. $item['publish_url'] = api_get_self().'?action=publish&id='.$meeting_db['id'];
  245. $item['unpublish_url'] = api_get_self().'?action=unpublish&id='.$meeting_db['id'];
  246. if ($meeting_db['status'] == 1) {
  247. $joinParams = array(
  248. 'meetingId' => $meeting_db['id'], //-- REQUIRED - A unique id for the meeting
  249. 'username' => $this->user_complete_name, //-- REQUIRED - The name that will display for the user in the meeting
  250. 'password' => $pass, //-- REQUIRED - The attendee or moderator password, depending on what's passed here
  251. 'createTime' => '', //-- OPTIONAL - string. Leave blank ('') unless you set this correctly.
  252. 'userID' => '', // -- OPTIONAL - string
  253. 'webVoiceConf' => '' // -- OPTIONAL - string
  254. );
  255. $item['go_url'] = $this->protocol.$this->api->getJoinMeetingURL($joinParams);
  256. }
  257. $item = array_merge($item, $meeting_db, $meeting_bbb);
  258. $new_meeting_list[] = $item;
  259. }
  260. return $new_meeting_list;
  261. }
  262. function publish_meeting($id) {
  263. //return BigBlueButtonBN::setPublishRecordings($id, 'true', $this->url, $this->salt);
  264. }
  265. function unpublish_meeting($id) {
  266. //return BigBlueButtonBN::setPublishRecordings($id, 'false', $this->url, $this->salt);
  267. }
  268. function end_meeting($id) {
  269. $pass = $this->get_user_meeting_password();
  270. $endParams = array(
  271. 'meetingId' => $id, // REQUIRED - We have to know which meeting to end.
  272. 'password' => $pass, // REQUIRED - Must match moderator pass for meeting.
  273. );
  274. $this->api->endMeetingWithXmlResponseArray($endParams);
  275. Database::update($this->table, array('status' => 0, 'closed_at' => api_get_utc_datetime()), array('id = ? ' => $id));
  276. }
  277. function get_user_meeting_password() {
  278. if ($this->is_teacher()) {
  279. return $this->get_mod_meeting_password();
  280. } else {
  281. return api_get_course_id();
  282. }
  283. }
  284. function get_mod_meeting_password() {
  285. return api_get_course_id().'mod';
  286. }
  287. /**
  288. * Get users online in the current course room
  289. */
  290. function get_users_online_in_current_room() {
  291. $course_id = api_get_course_int_id();
  292. $meeting_data = Database::select('*', $this->table, array('where' => array('c_id = ? AND status = 1 ' => $course_id)), 'first');
  293. if (empty($meeting_data)) {
  294. return 0;
  295. }
  296. $pass = $this->get_mod_meeting_password();
  297. $info = $this->get_meeting_info(array('meetingId' => $meeting_data['id'], 'password' => $pass));
  298. if (!empty($info) && isset($info['participantCount'])) {
  299. return $info['participantCount'];
  300. }
  301. return 0;
  302. }
  303. function delete_record($ids) {
  304. $recordingParams = array(
  305. /*
  306. * NOTE: Set the recordId below to a valid id after you have created a recorded meeting,
  307. * and received back a real recordID back from your BBB server using the
  308. * getRecordingsWithXmlResponseArray method.
  309. */
  310. // REQUIRED - We have to know which recording:
  311. 'recordId' => $ids,
  312. );
  313. return $this->api->deleteRecordingsWithXmlResponseArray($recordingParams);
  314. }
  315. function copy_record_to_link_tool($id, $record_id) {
  316. require_once api_get_path(LIBRARY_PATH).'link.lib.php';
  317. $records = BigBlueButtonBN::getRecordingsArray($id, $this->url, $this->salt);
  318. if (!empty($records)) {
  319. foreach ($records as $record) {
  320. if ($record['recordID'] == $record_id) {
  321. if (is_array($record) && isset($record['recordID']) && isset($record['playbacks'])) {
  322. foreach ($record['playbacks'] as $item) {
  323. $link = new Link();
  324. $params['url'] = $item['url'];
  325. $params['title'] = 'bbb 1';
  326. $id = $link->save($params);
  327. return $id;
  328. }
  329. }
  330. }
  331. }
  332. }
  333. return false;
  334. }
  335. function is_server_running() {
  336. return true;
  337. //return BigBlueButtonBN::isServerRunning($this->protocol.$this->url);
  338. }
  339. }