Kaynağa Gözat

#2331 Live video streaming

Alex Trofimov 5 yıl önce
ebeveyn
işleme
997b275825

+ 10 - 0
modules/boonex/stream/classes/BxStrmEngineNGINX.php

@@ -11,6 +11,11 @@
 
 class BxStrmEngineNGINX extends BxDol
 {
+    public function isSreamFromBrowser()
+    {
+        return false;
+    }
+
     public function getViewersNum($sStreamKey)
     {
         $sHost = getParam('bx_stream_server_host');
@@ -59,6 +64,11 @@ class BxStrmEngineNGINX extends BxDol
         list ($sBaseUrl, $sStreamKey) = $a;
         return $a['server'] . '/' . $a['key'];
     }
+
+    public function getWebrtcIngestUrl($sStreamKey)
+    {
+        return false;
+    }
 }
 
 /** @} */

+ 18 - 0
modules/boonex/stream/classes/BxStrmEngineOvenMediaEngine.php

@@ -11,6 +11,11 @@
 
 class BxStrmEngineOvenMediaEngine extends BxDol
 {
+    public function isSreamFromBrowser()
+    {
+        return true;
+    }
+
     public function getViewersNum($sStreamKey)
     {
         $a = $this->getStreamStats($sStreamKey);
@@ -85,6 +90,19 @@ class BxStrmEngineOvenMediaEngine extends BxDol
         return $this->_signUrl($sBaseUrl, $sPolicySecret);
     }
 
+    public function getWebrtcIngestUrl($sStreamKey)
+    {
+        $sHost = getParam('bx_stream_server_host');
+        $sApp = getParam('bx_stream_app');
+        $sPolicySecret = getParam('bx_stream_server_ome_policy_secret');
+
+        $sBaseUrl = "wss://$sHost:3334/$sApp/$sStreamKey?direction=send";
+        if (!$sPolicySecret)
+            return $sBaseUrl;
+
+        return $this->_signUrl($sBaseUrl, $sPolicySecret);
+    }
+
     protected function _signUrl($sBaseUrl, $sPolicySecret)
     {
         $sSignatureQueryKeyName = 'signature';

+ 22 - 1
modules/boonex/stream/classes/BxStrmModule.php

@@ -61,6 +61,10 @@ class BxStrmModule extends BxBaseModTextModule
         echo json_encode(['viewers' => $iNum !== false ? _t('_bx_stream_txt_viewers', (int)$iNum) : _t('_bx_stream_txt_wait_for_stream'), 'num' => $iNum]);
     }
 
+    public function serviceStreamBroadcast ($iContentId = 0)
+    {
+        return $this->_serviceTemplateFunc ('entryStreamBroadcast', $iContentId);
+    }
     public function serviceStreamViewers ($iContentId = 0)
     {
         return $this->_serviceTemplateFunc ('entryStreamViewers', $iContentId);
@@ -96,16 +100,33 @@ class BxStrmModule extends BxBaseModTextModule
                     'name' => 'url'.time(),
                     'caption' => _t('_bx_stream_form_entry_input_server'),
                     'value' => $a['server'],
+                    'attrs' => array('readonly' => 'readonly'),
                 ),
                 'key' => array(
                     'type' => 'password',
                     'name' => 'key'.time(),
                     'caption' => _t('_bx_stream_form_entry_input_stream_key'),
                     'value' => $a['key'],
+                    'attrs' => array('readonly' => 'readonly'),
                 ),
             ),
         );
-        
+
+        if ($this->getStreamEngine()->isSreamFromBrowser()) {
+            $sUrl = 'page.php?i=broadcast-stream&id=' . (int)$iContentId;
+            $sUrl = BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink($sUrl);
+            $aForm['inputs']['header_div'] = array (
+                'type' => 'custom',
+                'content' => _t('_bx_stream_manual_settings_or_stream_from_webcam'),
+            );
+            $aForm['inputs']['stream-from-webcam'] = array (
+                'type' => 'submit',
+                'name' => 'submit',
+                'value' => _t('_bx_stream_from_webcam'),
+                'attrs' => array('onclick' => 'document.location="' . bx_html_attribute($sUrl) . '"; return false;'),
+            );
+        }
+
         $oForm = new BxTemplFormView ($aForm);
         return $oForm->getCode();
     }

+ 90 - 0
modules/boonex/stream/classes/BxStrmTemplate.php

@@ -32,6 +32,96 @@ class BxStrmTemplate extends BxBaseModTextTemplate
         ));
     }
 
+    public function entryStreamBroadcast ($aContentInfo)
+    {
+        $oEngine = $this->getModule()->getStreamEngine();
+        if (!$oEngine->isSreamFromBrowser()) 
+            return MsgBox(_t('_bx_stream_from_webcam_not_supported'));
+
+        $CNF = &$this->getModule()->_oConfig->CNF;
+
+        return $this->parseHtmlByName('stream_broadcast_ome.html', array(
+            'suffix' => md5($aContentInfo[$CNF['FIELD_KEY']]),
+            'broadcast_url' => $oEngine->getWebrtcIngestUrl($aContentInfo[$CNF['FIELD_KEY']]),
+            'popup_share' => $this->popupShare($aContentInfo),
+            'popup_settings' => $this->popupSettings($aContentInfo),
+        ));
+    }
+
+    public function popupShare ($aContentInfo)
+    {
+        $CNF = &$this->getModule()->_oConfig->CNF;
+
+        $sUrlViewStream = 'page.php?i=' . $CNF['URI_VIEW_ENTRY'] . '&id=' . (int)$aContentInfo['id'];
+        $sUrlViewStream = BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink($sUrlViewStream);
+        $aForm = array(
+            'form_attrs' => array(
+                'name' => 'bx-stream-form-share',
+                'class' => 'bx-def-margin',
+            ),
+            'inputs' => array(
+                'url' => array(
+                    'type' => 'text',
+                    'name' => 'url'.time(),
+                    'caption' => '',
+                    'value' => $sUrlViewStream,
+                    'attrs' => array('readonly' => 'readonly'),
+                ),
+            ),
+        );
+        $oForm = new BxTemplFormView ($aForm);
+
+        return BxTemplFunctions::getInstance()->popupBox('bx-stream-popup-share', _t('_bx_stream_popup_share'), $oForm->getCode(), true);
+    }
+
+    public function popupSettings ($aContentInfo)
+    {
+        $CNF = &$this->getModule()->_oConfig->CNF;
+
+        $aForm = array(
+            'form_attrs' => array(
+                'name' => 'bx-stream-form-settings',
+            ),
+            'inputs' => array(
+                'audio' => array(
+                    'type' => 'select',
+                    'name' => 'audio',
+                    'caption' => _t('_bx_stream_field_audio_source'),
+                    'value' => '',
+                ),
+                'video' => array(
+                    'type' => 'select',
+                    'name' => 'video',
+                    'caption' => _t('_bx_stream_field_video_source'),
+                    'value' => '',
+                ),
+                'resolution' => array(
+                    'type' => 'select',
+                    'name' => 'resolution',
+                    'caption' => _t('_bx_stream_field_video_resolution'),
+                    'value' => '',
+                ),
+                'submit' => array(
+                    'type' => 'input_set',
+                    0 => array (
+                        'type' => 'submit',
+                        'name' => 'do_submit',
+                        'value' => _t('_Submit'),
+                    ),
+                    1 => array (
+                        'type' => 'reset',
+                        'name' => 'close',
+                        'value' => _t('_Cancel'),
+                        'attrs' => array('class' => 'bx-stream-popup-close bx-def-margin-sec-left'),
+                    ),
+                ),
+            ),
+        );
+        $oForm = new BxTemplFormView ($aForm);
+
+        return BxTemplFunctions::getInstance()->popupBox('bx-stream-popup-settings', _t('_bx_stream_popup_settings'), $oForm->getCode(), true);
+    }
+
     public function entryStreamViewers ($aContentInfo)
     {
         $CNF = &$this->getModule()->_oConfig->CNF;

+ 14 - 0
modules/boonex/stream/install/langs/en.xml

@@ -144,6 +144,9 @@
     <string name="_bx_stream_page_block_title_sys_entry_context"><![CDATA[Streamed in]]></string>
     <string name="_bx_stream_page_block_title_entry_context"><![CDATA[Streamed in]]></string>
 
+    <string name="_bx_stream_page_title_broadcast"><![CDATA[Broadcast with Webcam]]></string>
+    <string name="_bx_stream_page_block_title_broadcast"><![CDATA[Broadcast with Webcam]]></string>
+
     <string name="_bx_stream_menu_set_title_view_entry"><![CDATA[Stream Actions]]></string>
     <string name="_bx_stream_menu_title_view_entry"><![CDATA[Stream Actions]]></string>
     <string name="_bx_stream_menu_title_submenu"><![CDATA[Streams Submenu]]></string>
@@ -250,4 +253,15 @@
     <string name="_bx_stream_txt_wait_for_stream"><![CDATA[Waiting for live streaming...]]></string>
     <string name="_bx_stream_txt_live_now"><![CDATA[Live Now]]></string>
     <string name="_bx_stream_logs_ome_api"><![CDATA[OvenMediaEngine API Logs]]></string>
+    <string name="_bx_stream_from_webcam_not_supported"><![CDATA[Stream from webcam isn't supported in current streaming server]]></string>
+    <string name="_bx_stream_from_webcam"><![CDATA[Stream from Webcam]]></string>
+    <string name="_bx_stream_manual_settings_or_stream_from_webcam"><![CDATA[OR]]></string>
+    <string name="_bx_stream_start_streaming"><![CDATA[Start Streaming]]></string>
+    <string name="_bx_stream_stop_streaming"><![CDATA[Stop Streaming]]></string>
+
+    <string name="_bx_stream_popup_share"><![CDATA[Stream view URL]]></string>
+    <string name="_bx_stream_popup_settings"><![CDATA[Stream settings]]></string>
+    <string name="_bx_stream_field_audio_source"><![CDATA[Audio source]]></string>
+    <string name="_bx_stream_field_video_source"><![CDATA[Video source]]></string>
+    <string name="_bx_stream_field_video_resolution"><![CDATA[Video resolution]]></string>
 </resources>

+ 1 - 1
modules/boonex/stream/install/sql/disable.sql

@@ -4,7 +4,7 @@ DELETE FROM `top`, `toc`, `to` USING `sys_options_types` AS `top` LEFT JOIN `sys
 
 -- PAGES
 DELETE FROM `sys_objects_page` WHERE `module` = 'bx_stream';
-DELETE FROM `sys_pages_blocks` WHERE `module` = 'bx_stream' OR `object` IN('bx_stream_create_entry', 'bx_stream_edit_entry', 'bx_stream_delete_entry', 'bx_stream_view_entry', 'bx_stream_view_entry_comments', 'bx_stream_manage');
+DELETE FROM `sys_pages_blocks` WHERE `module` = 'bx_stream' OR `object` IN('bx_stream_create_entry', 'bx_stream_edit_entry', 'bx_stream_delete_entry', 'bx_stream_view_entry', 'bx_stream_broadcast', 'bx_stream_view_entry_comments', 'bx_stream_manage');
 
 -- MENU
 DELETE FROM `sys_objects_menu` WHERE `module` = 'bx_stream';

+ 9 - 0
modules/boonex/stream/install/sql/enable.sql

@@ -102,6 +102,15 @@ INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `t
 ('bx_stream_view_entry', 2, 'bx_stream', '', '_bx_stream_page_block_title_entry_reports', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_stream\";s:6:\"method\";s:14:\"entity_reports\";}', 0, 0, 1, 6);
 
 
+-- PAGE: broadcast
+
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_stream_broadcast', '', '_bx_stream_page_title_broadcast', 'bx_stream', 5, 2147483647, 1, 'broadcast-stream', '', '', '', '', 0, 1, 0, 'BxStrmPageEntry', 'modules/boonex/stream/classes/BxStrmPageEntry.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('bx_stream_broadcast', 1, 'bx_stream', '', '_bx_stream_page_block_title_viewers', 13, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_stream\";s:6:\"method\";s:14:\"stream_viewers\";}', 0, 0, 1, 1),
+('bx_stream_broadcast', 1, 'bx_stream', '', '_bx_stream_page_block_title_broadcast', 3, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_stream\";s:6:\"method\";s:16:\"stream_broadcast\";}', 0, 0, 1, 2);
+
 -- PAGE: view entry comments
 
 INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 

+ 22 - 0
modules/boonex/stream/template/css/main.css

@@ -9,3 +9,25 @@
     font-size:0.7rem;
     height:1.7rem;
 }
+
+.bx-stream-broadcast-wrapper {
+    text-align:center;
+}
+
+.bx-stream-broadcast-preview {
+    display:inline-block;
+    width:auto;
+    height:360px;
+    display:inline-block;
+    background-color:black;
+    border:1px solid #eee;
+}
+
+.bx-stream-broadcast-preview-live {
+    border:1px solid red;
+}
+
+.bx-stream-broadcast-controls button {
+    float:none;
+    display:inline-block;
+}

+ 57 - 168
modules/boonex/stream/template/images/icons/std-icon.svg

@@ -1,169 +1,58 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<svg
-   xmlns:dc="http://purl.org/dc/elements/1.1/"
-   xmlns:cc="http://creativecommons.org/ns#"
-   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-   xmlns:svg="http://www.w3.org/2000/svg"
-   xmlns="http://www.w3.org/2000/svg"
-   xmlns:xlink="http://www.w3.org/1999/xlink"
-   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
-   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
-   inkscape:version="1.0 (4035a4f, 2020-05-01)"
-   sodipodi:docname="std-icon.svg"
-   id="svg45"
-   version="1.1"
-   viewBox="0 0 64 64"
-   height="64px"
-   width="64px">
-  <metadata
-     id="metadata49">
-    <rdf:RDF>
-      <cc:Work
-         rdf:about="">
-        <dc:format>image/svg+xml</dc:format>
-        <dc:type
-           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
-      </cc:Work>
-    </rdf:RDF>
-  </metadata>
-  <sodipodi:namedview
-     inkscape:current-layer="svg45"
-     inkscape:window-maximized="0"
-     inkscape:window-y="23"
-     inkscape:window-x="0"
-     inkscape:cy="31.617339"
-     inkscape:cx="21.60618"
-     inkscape:zoom="2.2766005"
-     showgrid="false"
-     id="namedview47"
-     inkscape:window-height="855"
-     inkscape:window-width="1397"
-     inkscape:pageshadow="2"
-     inkscape:pageopacity="0"
-     guidetolerance="10"
-     gridtolerance="10"
-     objecttolerance="10"
-     borderopacity="1"
-     bordercolor="#666666"
-     pagecolor="#ffffff" />
-  <!-- Generator: Sketch 54.1 (76490) - https://sketchapp.com -->
-  <title
-     id="title10">posts</title>
-  <desc
-     id="desc12">Created with Sketch.</desc>
-  <defs
-     id="defs28">
-    <path
-       id="path-1"
-       d="M32,64 C46.0222222,64 53.8173667,64 58.9086889,58.9086889 C64,53.8173667 64,46.0222222 64,32 C64,17.9777778 64,10.1826333 58.9086889,5.09131111 C53.8173667,0 46.0222222,0 32,0 C17.9777778,0 10.1826333,0 5.09131111,5.09131111 C0,10.1826333 0,17.9777778 0,32 C0,46.0222222 0,53.8173667 5.09131111,58.9086889 C10.1826333,64 17.9777778,64 32,64 Z" />
-    <linearGradient
-       id="linearGradient-3"
-       y2="100%"
-       x2="50%"
-       y1="0%"
-       x1="50%">
-      <stop
-         id="stop15"
-         offset="0%"
-         stop-color="#FDFEFF" />
-      <stop
-         id="stop17"
-         offset="100%"
-         stop-opacity="0.9"
-         stop-color="#FBFCFD" />
-    </linearGradient>
-    <path
-       id="path-4"
-       d="M17.7777778,10.625 L17.7777778,0 L1.9047619,0 C0.849206349,0 0,0.8359375 0,1.875 L0,38.125 C0,39.1640625 0.849206349,40 1.9047619,40 L28.5714286,40 C29.6269841,40 30.4761905,39.1640625 30.4761905,38.125 L30.4761905,12.5 L19.6825397,12.5 C18.6349206,12.5 17.7777778,11.65625 17.7777778,10.625 Z M22.8571429,29.0625 C22.8571429,29.578125 22.4285714,30 21.9047619,30 L8.57142857,30 C8.04761905,30 7.61904762,29.578125 7.61904762,29.0625 L7.61904762,28.4375 C7.61904762,27.921875 8.04761905,27.5 8.57142857,27.5 L21.9047619,27.5 C22.4285714,27.5 22.8571429,27.921875 22.8571429,28.4375 L22.8571429,29.0625 Z M22.8571429,24.0625 C22.8571429,24.578125 22.4285714,25 21.9047619,25 L8.57142857,25 C8.04761905,25 7.61904762,24.578125 7.61904762,24.0625 L7.61904762,23.4375 C7.61904762,22.921875 8.04761905,22.5 8.57142857,22.5 L21.9047619,22.5 C22.4285714,22.5 22.8571429,22.921875 22.8571429,23.4375 L22.8571429,24.0625 Z M22.8571429,18.4375 L22.8571429,19.0625 C22.8571429,19.578125 22.4285714,20 21.9047619,20 L8.57142857,20 C8.04761905,20 7.61904762,19.578125 7.61904762,19.0625 L7.61904762,18.4375 C7.61904762,17.921875 8.04761905,17.5 8.57142857,17.5 L21.9047619,17.5 C22.4285714,17.5 22.8571429,17.921875 22.8571429,18.4375 Z M30.4761905,9.5234375 L30.4761905,10 L20.3174603,10 L20.3174603,0 L20.8015873,0 C21.3095238,0 21.7936508,0.1953125 22.1507937,0.546875 L29.9206349,8.203125 C30.2777778,8.5546875 30.4761905,9.03125 30.4761905,9.5234375 Z" />
-    <filter
-       id="filter-5"
-       filterUnits="objectBoundingBox"
-       height="110.0%"
-       width="113.1%"
-       y="-2.5%"
-       x="-6.6%">
-      <feOffset
-         id="feOffset21"
-         result="shadowOffsetOuter1"
-         in="SourceAlpha"
-         dy="1"
-         dx="0" />
-      <feGaussianBlur
-         id="feGaussianBlur23"
-         result="shadowBlurOuter1"
-         in="shadowOffsetOuter1"
-         stdDeviation="0.5" />
-      <feColorMatrix
-         id="feColorMatrix25"
-         in="shadowBlurOuter1"
-         type="matrix"
-         values="0 0 0 0 0   0 0 0 0 0   0 0 0 0 0  0 0 0 0.1 0" />
-    </filter>
-    <filter
-       id="filter1083"
-       inkscape:label="Drop Shadow"
-       style="color-interpolation-filters:sRGB;">
-      <feFlood
-         id="feFlood1073"
-         result="flood"
-         flood-color="rgb(255,255,255)"
-         flood-opacity="1" />
-      <feComposite
-         id="feComposite1075"
-         result="composite1"
-         operator="in"
-         in2="flood"
-         in="SourceGraphic" />
-      <feGaussianBlur
-         id="feGaussianBlur1077"
-         result="blur"
-         stdDeviation="3"
-         in="composite1" />
-      <feOffset
-         id="feOffset1079"
-         result="offset"
-         dy="0"
-         dx="0" />
-      <feComposite
-         id="feComposite1081"
-         result="composite2"
-         operator="over"
-         in2="offset"
-         in="SourceGraphic" />
-    </filter>
-  </defs>
-  <g
-     fill-rule="evenodd"
-     fill="none"
-     stroke-width="1"
-     stroke="none"
-     id="Page-1">
-    <g
-       transform="translate(-340.000000, -430.000000)"
-       id="Artboard">
-      <g
-         transform="translate(340.000000, 430.000000)"
-         id="posts">
-        <mask
-           fill="white"
-           id="mask-2">
-          <use
-             id="use30"
-             xlink:href="#path-1" />
-        </mask>
-        <use
-           xlink:href="#path-1"
-           fill="#00B356"
-           id="Path" />
-        <g
-           fill-rule="nonzero"
-           mask="url(#mask-2)"
-           id="file-alt" />
-      </g>
-    </g>
-  </g>
-  <path
-     style="stroke-width:0.0763876;fill:#ffffff;fill-opacity:1;filter:url(#filter1083)"
-     d="M 24.274588,24.125207 23.40606,23.276538 a 1.2558157,1.2558157 0 0 0 -1.833307,0.09931 12.896553,12.896553 0 0 0 0,16.585319 1.2558157,1.2558157 0 0 0 1.833307,0.09931 l 0.868528,-0.848672 a 1.1565114,1.1565114 0 0 0 0.09854,-1.568241 9.374312,9.374312 0 0 1 0,-11.950108 1.1572753,1.1572753 0 0 0 -0.09854,-1.568242 z M 18.198704,18.193694 17.33323,17.348081 a 1.2535238,1.2535238 0 0 0 -1.799697,0.07639 C 11.954764,21.356148 10,26.365662 10,31.668503 c 0,5.302841 1.954764,10.312352 5.533533,14.247853 a 1.2535238,1.2535238 0 0 0 1.799697,0.07639 l 0.865474,-0.845611 c 0.466728,-0.45833 0.462909,-1.175609 0.0275,-1.65838 a 17.590584,17.590584 0 0 1 0,-23.632095 c 0.435411,-0.486593 0.43923,-1.207693 -0.0275,-1.662965 z M 48.465842,17.42065 a 1.2535238,1.2535238 0 0 0 -1.799695,-0.0764 l -0.865475,0.849432 c -0.466729,0.458327 -0.46291,1.175608 -0.0275,1.659144 a 17.590584,17.590584 0 0 1 0,23.632094 c -0.43541,0.482772 -0.439229,1.203107 0.0275,1.65838 l 0.865475,0.845613 a 1.2535238,1.2535238 0 0 0 1.799695,-0.07639 c 3.578771,-3.93167 5.533533,-8.941181 5.533533,-14.244022 0,-5.302841 -1.954762,-10.312355 -5.533533,-14.247853 z m -16.466154,9.970136 a 4.277717,4.277717 0 1 0 4.277716,4.277717 4.277717,4.277717 0 0 0 -4.277716,-4.277717 z m 8.593627,-4.114248 -0.868529,0.848669 a 1.1572753,1.1572753 0 0 0 -0.09854,1.568241 9.374312,9.374312 0 0 1 0,11.950108 1.1572753,1.1572753 0 0 0 0.09854,1.568241 l 0.868529,0.848669 a 1.2558157,1.2558157 0 0 0 1.833308,-0.09931 12.896553,12.896553 0 0 0 0,-16.58532 1.2558157,1.2558157 0 0 0 -1.833308,-0.09931 z"
-     id="path51" />
+<svg width="256" height="256" viewBox="0 0 256 256" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M120 4.6188C124.95 1.76068 131.05 1.76068 136 4.6188L230.851 59.3812C235.802 62.2393 238.851 67.5214 238.851 73.2376V182.762C238.851 188.479 235.802 193.761 230.851 196.619L136 251.381C131.05 254.239 124.95 254.239 120 251.381L25.1487 196.619C20.1983 193.761 17.1488 188.479 17.1488 182.762L17.1488 73.2376C17.1488 67.5214 20.1983 62.2393 25.1488 59.3812L120 4.6188Z" fill="url(#paint0_linear)"/>
+<path d="M124.14 2.94736C124.049 3.28276 124 3.63568 124 3.99999V116.281C124 121.997 120.95 127.279 116 130.137L17.6913 186.896C17.3352 185.565 17.1484 184.177 17.1484 182.762V73.2376C17.1484 67.5213 20.198 62.2393 25.1484 59.3812L120 4.61879C121.313 3.86042 122.708 3.30328 124.14 2.94736Z" fill="white" fill-opacity="0.05"/>
+<path d="M131.86 2.94754C131.951 3.28289 132 3.63575 132 3.99999V116.625C132 122.341 135.05 127.623 140 130.481L238.226 187.192C238.635 185.771 238.851 184.282 238.851 182.762V73.2376C238.851 67.5213 235.801 62.2393 230.851 59.3812L136 4.61879C134.686 3.86055 133.292 3.30347 131.86 2.94754Z" fill="white" fill-opacity="0.05"/>
+<path d="M234.16 194.082L135.702 137.238C130.752 134.379 124.653 134.379 119.702 137.238L21.6248 193.863C22.6506 194.928 23.8323 195.859 25.1484 196.619L120 251.381C124.95 254.239 131.049 254.239 136 251.381L230.851 196.619C232.076 195.911 233.185 195.056 234.16 194.082Z" fill="white" fill-opacity="0.05"/>
+<path d="M154.445 81.7605C163.181 86.8039 174.004 84.9561 180.619 77.904C181.955 76.4801 184.277 76.2581 185.537 77.7501C196.489 90.7264 203.091 107.495 203.091 125.805C203.091 153.322 188.182 177.356 166.002 190.271C164.49 191.152 162.595 190.851 161.283 189.693C152.273 181.745 140.44 176.922 127.481 176.922C114.904 176.922 103.389 181.464 94.4852 188.996C93.1494 190.126 91.2486 190.388 89.7553 189.476C68.3131 176.385 54 152.766 54 125.805C54 84.6348 87.3751 51.2597 128.545 51.2597C133.313 51.2597 137.975 51.7072 142.493 52.5624C144.414 52.9258 145.36 55.0615 144.772 56.9253C141.833 66.242 145.634 76.6736 154.445 81.7605Z" fill="url(#paint1_linear)"/>
+<path d="M156.764 198.168C159.738 200.984 158.439 205.714 154.538 206.962C146.343 209.584 137.609 211 128.545 211C118.863 211 109.558 209.385 100.885 206.409C97.0111 205.08 95.8095 200.326 98.8405 197.571C106.405 190.696 116.454 186.506 127.481 186.506C138.823 186.506 149.13 190.94 156.764 198.168Z" fill="url(#paint2_linear)"/>
+<circle cx="128.546" cy="125.805" r="42.5974" fill="#374151"/>
+<g opacity="0.6">
+<circle cx="128.546" cy="125.805" r="34.0779" fill="url(#paint3_radial)"/>
+<circle cx="128.546" cy="125.805" r="34.0779" fill="url(#paint4_radial)" fill-opacity="0.8"/>
+</g>
+<circle cx="128.546" cy="125.805" r="34.0779" fill="url(#paint5_linear)"/>
+<rect x="182.095" y="59.7792" width="25.5584" height="25.5584" rx="12.7792" transform="rotate(120 182.095 59.7792)" fill="#FCA5A5"/>
+<path d="M124.14 253.525C124.049 253.189 124 252.836 124 252.472V140.191C124 134.475 120.95 129.193 116 126.335L17.6913 69.576C17.3352 70.9072 17.1484 72.2952 17.1484 73.7098V183.235C17.1484 188.951 20.198 194.233 25.1484 197.091L120 251.853C121.313 252.612 122.708 253.169 124.14 253.525Z" fill="url(#paint6_linear)" fill-opacity="0.05"/>
+<path d="M131.86 253.525C131.951 253.189 132 252.836 132 252.472V139.847C132 134.131 135.05 128.849 140 125.991L238.226 69.2802C238.635 70.7011 238.851 72.1901 238.851 73.7097V183.235C238.851 188.951 235.801 194.233 230.851 197.091L136 251.853C134.686 252.612 133.292 253.169 131.86 253.525Z" fill="url(#paint7_linear)" fill-opacity="0.05"/>
+<path d="M234.16 62.3904L135.702 119.235C130.752 122.093 124.653 122.093 119.702 119.235L21.6248 62.6095C22.6506 61.5443 23.8323 60.6132 25.1484 59.8533L120 5.09095C124.95 2.23283 131.049 2.23283 136 5.09095L230.851 59.8533C232.076 60.5606 233.185 61.4164 234.16 62.3904Z" fill="url(#paint8_linear)" fill-opacity="0.05"/>
+<defs>
+<linearGradient id="paint0_linear" x1="128" y1="0" x2="128" y2="256" gradientUnits="userSpaceOnUse">
+<stop stop-color="#F472B6"/>
+<stop offset="1" stop-color="#7C3AED"/>
+</linearGradient>
+<linearGradient id="paint1_linear" x1="128.545" y1="51.2597" x2="128.545" y2="191.701" gradientUnits="userSpaceOnUse">
+<stop stop-color="white"/>
+<stop offset="1" stop-color="white" stop-opacity="0.5"/>
+<stop offset="1" stop-color="white" stop-opacity="0.7"/>
+</linearGradient>
+<linearGradient id="paint2_linear" x1="127.764" y1="186.506" x2="127.764" y2="211" gradientUnits="userSpaceOnUse">
+<stop stop-color="white" stop-opacity="0.7"/>
+<stop offset="1" stop-color="white" stop-opacity="0.6"/>
+</linearGradient>
+<radialGradient id="paint3_radial" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(128.546 100.247) rotate(90) scale(59.6364 70.0849)">
+<stop stop-color="#7C3AED"/>
+<stop offset="0.901786" stop-color="#4C1D95"/>
+<stop offset="1" stop-color="#8B5CF6"/>
+</radialGradient>
+<radialGradient id="paint4_radial" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(128.546 102.909) rotate(90) scale(15.4416 34.7435)">
+<stop stop-color="white" stop-opacity="0.57"/>
+<stop offset="1" stop-color="white" stop-opacity="0"/>
+</radialGradient>
+<linearGradient id="paint5_linear" x1="128.546" y1="91.7272" x2="128.546" y2="159.883" gradientUnits="userSpaceOnUse">
+<stop stop-color="#60A5FA"/>
+<stop offset="1" stop-color="#60A5FA" stop-opacity="0.7"/>
+</linearGradient>
+<linearGradient id="paint6_linear" x1="128" y1="2.94736" x2="128" y2="253.525" gradientUnits="userSpaceOnUse">
+<stop stop-opacity="0.5"/>
+<stop offset="1"/>
+</linearGradient>
+<linearGradient id="paint7_linear" x1="128" y1="2.94736" x2="128" y2="253.525" gradientUnits="userSpaceOnUse">
+<stop stop-opacity="0.5"/>
+<stop offset="1"/>
+</linearGradient>
+<linearGradient id="paint8_linear" x1="128" y1="2.94736" x2="128" y2="253.525" gradientUnits="userSpaceOnUse">
+<stop stop-opacity="0.5"/>
+<stop offset="1"/>
+</linearGradient>
+</defs>
 </svg>

+ 113 - 0
modules/boonex/stream/template/stream_broadcast_ome.html

@@ -0,0 +1,113 @@
+<div class="bx-stream-broadcast-wrapper">
+    <video muted class="bx-stream-broadcast-preview" id="bx-stream-preview-__suffix__"></video>
+    <div class="bx-stream-broadcast-controls bx-def-margin-sec-top">
+        <button disabled id="bx-stream-start-__suffix__" class="bx-btn bx-btn-primary bx-btn-disabled"><bx_text:_bx_stream_start_streaming /></button>
+        <button disabled id="bx-stream-stop-__suffix__" class="bx-btn bx-btn-primary bx-btn-disabled bx-def-margin-sec-left"><bx_text:_bx_stream_stop_streaming /></button>
+        <button id="bx-stream-settings-__suffix__" class="bx-btn bx-def-margin-sec-left"><i class="sys-icon cog"></i></button>
+        <button id="bx-stream-share-__suffix__" class="bx-btn bx-def-margin-sec-left"><i class="sys-icon share"></i></button>
+    </div>
+</div>
+
+<script src="https://cdn.jsdelivr.net/npm/ovenlivekit@latest/dist/OvenLiveKit.min.js"></script>
+<script>
+    $('#bx-stream-share-__suffix__').click(function() {
+        $('#bx-stream-popup-share').dolPopup();
+    });
+    $('#bx-stream-settings-__suffix__').click(function() {
+        $('#bx-stream-popup-settings').dolPopup({'closeElement': '.bx-stream-popup-close'});
+    });
+
+    let fOnStreamingStop = function () {
+        $('#bx-stream-preview-__suffix__').removeClass('bx-stream-broadcast-preview-live');
+        $('#bx-stream-start-__suffix__').attr('disabled', false).removeClass('bx-btn-disabled');
+        $('#bx-stream-stop-__suffix__').attr('disabled', true).addClass('bx-btn-disabled');
+    };
+    $('#bx-stream-stop-__suffix__').click(function() {
+        if ('undefined' === typeof(oOvenLivekit__suffix__) || !oOvenLivekit__suffix__)
+            return;
+        fInit();
+    });
+
+    let fOnStreamingStart = function () {
+        $('#bx-stream-preview-__suffix__').addClass('bx-stream-broadcast-preview-live');
+        $('#bx-stream-start-__suffix__').attr('disabled', true).addClass('bx-btn-disabled');
+        $('#bx-stream-stop-__suffix__').attr('disabled', false).removeClass('bx-btn-disabled');
+    };
+    $('#bx-stream-start-__suffix__').click(function() {
+        if ('undefined' === typeof(oOvenLivekit__suffix__) || !oOvenLivekit__suffix__)
+            return;
+
+        // Get media stream from user device
+        oOvenLivekit__suffix__.getUserMedia().then(function () {
+            const oConnectionConfig = {
+                iceServers : null ,
+                iceTransportPolicy: null,
+                maxBitrate: null // is Kbps
+            }
+            // Got device stream and start streaming to OvenMediaEngine
+            oOvenLivekit__suffix__.startStreaming('__broadcast_url__', oConnectionConfig);
+
+            fOnStreamingStart();
+
+        }).catch(function (error) {
+            // Failed to get device stream.
+            console.log(error);
+        });
+    });
+
+    let fInit = function () {
+        if ('undefined' !== typeof(oOvenLivekit__suffix__) && oOvenLivekit__suffix__)
+            oOvenLivekit__suffix__.remove();
+        
+        // Lists the available media input and output devices
+        OvenLiveKit.getDevices().then(function (devices) {
+            // Got a list of user devices
+            console.log(devices);
+        }).catch(function (error) {
+            // Failed to get a list of user devices
+            console.log(error);
+        });
+
+        // Configuration
+        var oConfig = {
+            callbacks: {
+                error: function (error) {
+                    console.log("Error ---------------- ");
+                    console.log(error);
+                },
+                connected: function (event) {
+                    console.log("Connected ---------------- ");
+                    console.log(event);
+                },
+                connectionClosed: function (type, event) {
+                    console.log("ConnectionClosed ---------------- ");
+                    console.log(type);
+                    console.log(event);
+                },
+                iceStateChange: function (state) {
+                    console.log("IceStateChange ---------------- ");
+                    console.log(state);
+                }
+            }
+        }
+
+        // Initialize OvenLiveKit
+        oOvenLivekit__suffix__ = OvenLiveKit.create(oConfig);
+
+        // Attaching video element for playing device stream
+        oOvenLivekit__suffix__.attachMedia(document.getElementById('bx-stream-preview-__suffix__'));
+
+        oOvenLivekit__suffix__.getUserMedia().then(function () {
+            fOnStreamingStop(); // instead of init
+        }).catch(function (error) {
+            // Failed to get device stream.
+            console.log(error);
+        });
+    };
+    
+    $(document).ready(fInit);
+    
+</script>
+
+__popup_share__
+__popup_settings__