|
@ -10,6 +10,7 @@ declare module 'vue' {
|
|||
404: typeof import('./src/components/errorMessage/404.vue')['default']
|
||||
500: typeof import('./src/components/errorMessage/500.vue')['default']
|
||||
AButton: typeof import('ant-design-vue/es')['Button']
|
||||
ACascader: typeof import('ant-design-vue/es')['Cascader']
|
||||
AConfigProvider: typeof import('ant-design-vue/es')['ConfigProvider']
|
||||
ADropdown: typeof import('ant-design-vue/es')['Dropdown']
|
||||
AForm: typeof import('ant-design-vue/es')['Form']
|
||||
|
|
23
index.html
|
@ -16,8 +16,31 @@
|
|||
|
||||
<script src="/haikang/h5player.min.js"></script>
|
||||
|
||||
|
||||
<!-- <script src=" ./public/cw/player/cmsplayer.js"></script>
|
||||
<script src=" ./public/cw/player/common.js"></script>
|
||||
<script src=" ./public/cw/player/pcm-player.js"></script>
|
||||
<script src=" ./public/cw/player/webgl.js"></script>
|
||||
<script src=" ./public/cw/player/cmstalk.js"></script>
|
||||
<script src=" ./public/cw/player/alawmulaw.js"></script>
|
||||
<script src=" ./public/cw/player/recorder-core.js"></script>
|
||||
<script src=" ./public/cw/js/moment.js"></script>
|
||||
<script src=" ./public/cw/js/jquery-3.4.1.min.js"></script> -->
|
||||
|
||||
<script src="/cw/js/moment.js"></script>
|
||||
<script src="/cw/js/jquery-2.2.3.min.js"></script>
|
||||
<script src="/cw/player/cmsplayer.js"></script>
|
||||
<script src="/cw/player/common.js"></script>
|
||||
<script src="/cw/player/pcm-player.js"></script>
|
||||
<script src="/cw/player/webgl.js"></script>
|
||||
<script src="/cw/player/cmstalk.js"></script>
|
||||
<script src="/cw/player/alawmulaw.js"></script>
|
||||
<script src="/cw/player/recorder-core.js"></script>
|
||||
|
||||
|
||||
<script type="module" src="/src/main.ts">
|
||||
|
||||
|
||||
</script>
|
||||
</body>
|
||||
|
||||
|
|
After Width: | Height: | Size: 413 KiB |
After Width: | Height: | Size: 239 B |
|
@ -0,0 +1 @@
|
|||
<svg t="1665647640241" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4863" width="32" height="32"><path d="M512 422.4c-70.4 0-128 57.6-128 128s57.6 128 128 128 128-57.6 128-128-57.6-128-128-128z" p-id="4864" fill="#ffffff"></path><path d="M940.8 198.4h-208V144c0-19.2-16-38.4-38.4-38.4h-368c-19.2 0-38.4 16-38.4 38.4v54.4H80c-28.8 0-51.2 22.4-51.2 51.2v620.8c0 28.8 22.4 51.2 51.2 51.2h860.8c28.8 0 51.2-22.4 51.2-51.2V249.6c0-28.8-22.4-51.2-51.2-51.2zM512 771.2c-121.6 0-220.8-99.2-220.8-220.8 0-121.6 99.2-220.8 220.8-220.8s220.8 99.2 220.8 220.8c0 121.6-99.2 220.8-220.8 220.8z m368-460.8H732.8v-35.2H880v35.2z" p-id="4865" fill="#ffffff"></path></svg>
|
After Width: | Height: | Size: 702 B |
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1646746198883" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3880" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><defs><style type="text/css"></style></defs><path d="M820.053333 205.077333a42.666667 42.666667 0 0 1 1.408 57.664l-2.538666 2.666667L562.837333 512l256.085334 246.613333a42.666667 42.666667 0 0 1-56.426667 63.893334l-2.773333-2.432L501.333333 571.221333 242.922667 820.074667a42.666667 42.666667 0 0 1-61.717334-58.816l2.538667-2.666667L439.808 512 183.744 265.386667a42.666667 42.666667 0 0 1 56.426667-63.893334l2.773333 2.432 258.368 248.832L759.744 203.925333a42.666667 42.666667 0 0 1 60.330667 1.152z" p-id="3881" fill="#ffffff"></path></svg>
|
After Width: | Height: | Size: 871 B |
|
@ -0,0 +1 @@
|
|||
<svg t="1665649555889" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2290" width="32" height="32"><path d="M511.883031 56.77603c-250.925838 0-455.090006 204.166167-455.090006 455.092005v244.611503c0 108.255456 88.059781 196.257252 196.258252 196.257252 80.037896 0 145.061751-65.020856 145.061752-145.002767V642.706536c0-79.978912-65.021856-145.061751-145.061752-145.061751a195.335496 195.335496 0 0 0-110.92975 34.643865v-20.417616c0-203.881242 165.881262-369.762504 369.760504-369.762504s369.760505 165.881262 369.760505 369.762504v20.421615a195.059568 195.059568 0 0 0-110.927752-34.643865c-79.978912 0-145.061751 65.082839-145.061751 145.061751v165.023488c0 79.978912 65.082839 145.002767 145.061751 145.002767 108.197471 0 196.258252-88.001796 196.258252-196.257252V511.871034c0.001-250.933836-204.164168-455.095004-455.090005-455.095004zM253.051277 582.976286a59.759243 59.759243 0 0 1 59.729252 59.73025v165.027487a59.711256 59.711256 0 0 1-59.729252 59.673266A111.070714 111.070714 0 0 1 142.121527 756.479538v-62.518516a111.08371 111.08371 0 0 1 110.92975-110.985736z m628.592258 173.503252A111.070714 111.070714 0 0 1 770.715784 867.408289a59.748246 59.748246 0 0 1-59.730251-59.673266V642.706536A59.796233 59.796233 0 0 1 770.715784 582.976286a111.082711 111.082711 0 0 1 110.927751 110.985736v62.518515z" p-id="2291" fill="#ffffff"></path></svg>
|
After Width: | Height: | Size: 1.4 KiB |
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1646745129934" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1383" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><defs><style type="text/css"></style></defs><path d="M768 298.666667h170.666667v85.333333h-256V128h85.333333v170.666667zM341.333333 384H85.333333V298.666667h170.666667V128h85.333333v256z m426.666667 341.333333v170.666667h-85.333333v-256h256v85.333333h-170.666667zM341.333333 640v256H256v-170.666667H85.333333v-85.333333h256z" p-id="1384" fill="#ffffff"></path></svg>
|
After Width: | Height: | Size: 688 B |
|
@ -0,0 +1 @@
|
|||
<svg id="图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 84 84"><defs><style>.cls-1{fill:#FFFFFF;}</style></defs><title>视频操作</title><path class="cls-1" d="M18,32V52a4.012,4.012,0,0,0,4,4H62a4.012,4.012,0,0,0,4-4V32a4.012,4.012,0,0,0-4-4H22A4.012,4.012,0,0,0,18,32Zm6,2H60V50H24ZM7,36a3,3,0,0,0,3-3V23a3,3,0,0,1,3-3H23a3,3,0,0,0,0-6H13a9.01,9.01,0,0,0-9,9V33A3,3,0,0,0,7,36ZM71,14H61a3,3,0,0,0,0,6H71a3,3,0,0,1,3,3V33a3,3,0,0,0,6,0V23A9.01,9.01,0,0,0,71,14Zm6,34a3,3,0,0,0-3,3V61a3,3,0,0,1-3,3H61a3,3,0,0,0,0,6H71a9.01,9.01,0,0,0,9-9V51A3,3,0,0,0,77,48ZM23,64H13a3,3,0,0,1-3-3V51a3,3,0,0,0-6,0V61a9.01,9.01,0,0,0,9,9H23a3,3,0,0,0,0-6Z"/></svg>
|
After Width: | Height: | Size: 682 B |
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1646745119141" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1430" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><defs><style type="text/css"></style></defs><path d="M213.333333 213.333333h213.333334V128H170.666667a42.666667 42.666667 0 0 0-42.666667 42.666667v256h85.333333V213.333333zM170.666667 896h256v-85.333333H213.333333v-213.333334H128v256a42.666667 42.666667 0 0 0 42.666667 42.666667z m725.333333-42.666667v-256h-85.333333v213.333334h-213.333334v85.333333h256a42.666667 42.666667 0 0 0 42.666667-42.666667zM597.333333 213.333333h213.333334v213.333334h85.333333V170.666667a42.666667 42.666667 0 0 0-42.666667-42.666667h-256v85.333333z" fill="#ffffff" p-id="1431"></path></svg>
|
After Width: | Height: | Size: 894 B |
After Width: | Height: | Size: 84 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 9.0 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 9.3 KiB |
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 23.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 64 64" style="enable-background:new 0 0 64 64;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
</style>
|
||||
<title>视频操作</title>
|
||||
<g>
|
||||
<path class="st0" d="M49.3,42.2c1.8-3,2.7-6.4,2.7-10.2v-4.6c0-0.6-0.2-1.2-0.7-1.6s-1-0.7-1.6-0.7s-1.2,0.2-1.6,0.7
|
||||
s-0.7,1-0.7,1.6V32c0,2.5-0.5,4.7-1.5,6.8L49.3,42.2z"/>
|
||||
<path class="st0" d="M31,43.5c1.7,0,3.2-0.3,4.6-0.9L19.3,26.4V32c0,3.2,1.1,5.9,3.4,8.2S27.8,43.5,31,43.5z"/>
|
||||
<path class="st0" d="M42.7,57.4h-9.3v-4.8c3.4-0.4,6.4-1.4,9.1-3.2L39,46.1c-2.4,1.4-5.1,2.1-8,2.1c-4.5,0-8.3-1.6-11.5-4.7
|
||||
c-3.2-3.2-4.8-7-4.8-11.4v-4.6c0-0.6-0.2-1.2-0.7-1.6c-0.5-0.5-1-0.7-1.6-0.7s-1.2,0.2-1.6,0.7c-0.5,0.5-0.7,1-0.7,1.6V32
|
||||
c0,5.3,1.8,9.9,5.4,13.9c3.6,3.9,8,6.2,13.3,6.8v4.8h-9.3c-0.6,0-1.2,0.2-1.6,0.7s-0.7,1-0.7,1.6s0.2,1.2,0.7,1.6s1,0.7,1.6,0.7
|
||||
h23.3c0.6,0,1.2-0.2,1.6-0.7s0.7-1,0.7-1.6s-0.2-1.2-0.7-1.6S43.3,57.4,42.7,57.4z"/>
|
||||
<path class="st0" d="M42.2,35.2c0.3-1,0.4-2.1,0.4-3.2V13.5c0-3.2-1.1-5.9-3.4-8.2S34.2,2,31,2s-6,1.1-8.2,3.4c-2,2-3.1,4.3-3.4,7
|
||||
L42.2,35.2z"/>
|
||||
</g>
|
||||
<path class="st0" d="M50.9,55.1l-42-42c-1.2-1.2-1.2-3,0-4.2l0,0c1.2-1.2,3-1.2,4.2,0L55.2,51c1.2,1.2,1.2,3,0,4.2l0,0
|
||||
C54,56.3,52.1,56.3,50.9,55.1z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.4 KiB |
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 23.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 64 64" style="enable-background:new 0 0 64 64;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
</style>
|
||||
<title>视频操作</title>
|
||||
<path class="st0" d="M52,27.4V32c0,5.3-1.8,9.9-5.4,13.9s-8,6.2-13.3,6.8v4.8h9.3c0.6,0,1.2,0.2,1.6,0.7c0.5,0.5,0.7,1,0.7,1.6
|
||||
s-0.2,1.2-0.7,1.6c-0.5,0.5-1,0.7-1.6,0.7H19.3c-0.6,0-1.2-0.2-1.6-0.7c-0.5-0.5-0.7-1-0.7-1.6s0.2-1.2,0.7-1.6
|
||||
c0.5-0.5,1-0.7,1.6-0.7h9.3v-4.8c-5.3-0.6-9.7-2.8-13.3-6.8c-3.5-4-5.3-8.6-5.3-13.9v-4.6c0-0.6,0.2-1.2,0.7-1.6
|
||||
c0.5-0.5,1-0.7,1.6-0.7s1.2,0.2,1.6,0.7c0.5,0.5,0.7,1,0.7,1.6V32c0,4.4,1.6,8.3,4.8,11.4c3.2,3.2,7,4.7,11.5,4.7s8.3-1.6,11.5-4.7
|
||||
c3.2-3.2,4.8-7,4.8-11.4v-4.6c0-0.6,0.2-1.2,0.7-1.6c0.5-0.5,1-0.7,1.6-0.7s1.2,0.2,1.6,0.7C51.8,26.2,52,26.8,52,27.4z M42.7,13.5
|
||||
V32c0,3.2-1.1,5.9-3.4,8.2c-2.3,2.3-5,3.4-8.2,3.4s-6-1.1-8.2-3.4s-3.4-5-3.4-8.2V13.5c0-3.2,1.1-5.9,3.4-8.2S27.8,2,31,2
|
||||
s6,1.1,8.2,3.4S42.7,10.4,42.7,13.5z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
|
@ -0,0 +1 @@
|
|||
<svg id="图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 84 84"><defs><style>.cls-1{fill:#FFFFFF;}</style></defs><title>视频操作</title><path class="cls-1" d="M44.269,12a4.385,4.385,0,0,0-2.5.816L23.264,27.05H16.71A7.625,7.625,0,0,0,9,34.542V49.525a7.625,7.625,0,0,0,7.71,7.491h6.554l18.5,14.234a3.387,3.387,0,0,0,2.161.75,3.96,3.96,0,0,0,4.007-3.746V15.813A3.625,3.625,0,0,0,44.269,12ZM41.936,61.779a1,1,0,0,1-1.61.792L26.922,52.26,25.3,51.016H16.71A1.634,1.634,0,0,1,15,49.525V34.542a1.634,1.634,0,0,1,1.71-1.492H25.3l1.618-1.244L40.326,21.5a1,1,0,0,1,1.61.792ZM67.78,42.845,74.125,36.5a3,3,0,0,0-4.243-4.243L63.537,38.6l-6.345-6.345A3,3,0,0,0,52.95,36.5L59.3,42.845,52.95,49.19a3,3,0,1,0,4.242,4.242l6.345-6.345,6.345,6.345a3.009,3.009,0,0,0,4.243,0h0a3.008,3.008,0,0,0,0-4.242Z"/></svg>
|
After Width: | Height: | Size: 826 B |
|
@ -0,0 +1 @@
|
|||
<svg id="图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 84 84"><defs><style>.cls-1{fill:#FFFFFF;}</style></defs><title>视频操作</title><path class="cls-1" d="M27,18a3.009,3.009,0,0,0-3,3V63a3,3,0,0,0,6,0V21A3.009,3.009,0,0,0,27,18Zm30,0a3.009,3.009,0,0,0-3,3V63a3,3,0,0,0,6,0V21A3.009,3.009,0,0,0,57,18Z"/></svg>
|
After Width: | Height: | Size: 349 B |
|
@ -0,0 +1 @@
|
|||
<svg id="图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 84 84"><defs><style>.cls-1{fill:#FFFFFF;}</style></defs><title>视频操作</title><path class="cls-1" d="M66,15H18A12.035,12.035,0,0,0,6,27V57A12.035,12.035,0,0,0,18,69H66A12.035,12.035,0,0,0,78,57V27A12.035,12.035,0,0,0,66,15Zm6,42a6.007,6.007,0,0,1-6,6H18a6.011,6.011,0,0,1-5.877-4.787l12.934-11.3a3.051,3.051,0,0,1,.976-.476,1.315,1.315,0,0,1,.319-.046.8.8,0,0,1,.595.308c2.918,2.919,6.069,6.484,6.186,6.616a5.184,5.184,0,0,0,3.538,1.855c.1.007.209.011.32.011a5.27,5.27,0,0,0,3.749-1.655c.675-.649,10.811-10.129,14.608-13.666l.115-.116a3.742,3.742,0,0,1,2.235-1.06,2.742,2.742,0,0,1,1.877,1.04C62.048,42.329,68.2,51.055,72,56.7Zm0-10.483a96.045,96.045,0,0,0-8.045-10.945,8.538,8.538,0,0,0-6.27-2.922,9.745,9.745,0,0,0-6.5,2.834c-.885.823-11.464,10.7-14.107,13.2-1.888-2.115-3.856-4.212-5.854-6.238a6.787,6.787,0,0,0-6.953-1.777A8.755,8.755,0,0,0,21.313,42.2l-.056.035L12,50.219V27a6.007,6.007,0,0,1,6-6H66a6.007,6.007,0,0,1,6,6ZM25,26a4,4,0,1,0,4,4A4,4,0,0,0,25,26Z"/></svg>
|
After Width: | Height: | Size: 1.0 KiB |
|
@ -0,0 +1 @@
|
|||
<svg id="图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 84 84"><defs><style>.cls-1{fill:#FFFFFF;}</style></defs><title>视频操作</title><path class="cls-1" d="M27,22.264,55.5,42,27,61.736V22.264M25.565,15A4.394,4.394,0,0,0,21,19.211V64.789A4.394,4.394,0,0,0,25.565,69a4.722,4.722,0,0,0,2.707-.847L61.179,45.364a4.018,4.018,0,0,0,0-6.728L28.272,15.847A4.722,4.722,0,0,0,25.565,15Z"/></svg>
|
After Width: | Height: | Size: 424 B |
|
@ -0,0 +1 @@
|
|||
<svg id="图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 84 84"><defs><style>.cls-1{fill:#FFFFFF;}</style></defs><title>视频操作</title><path class="cls-1" d="M73.4,40.52a3.12,3.12,0,0,0-3.138,3.094v.922a17.223,17.223,0,0,1-17.23,17.178H19.262v-6.7a.4.4,0,0,0-.239-.361.433.433,0,0,0-.46.064l-11.424,9.8a.388.388,0,0,0,0,.594L18.565,74.9a.429.429,0,0,0,.279.1.434.434,0,0,0,.179-.039.4.4,0,0,0,.239-.356v-6.7h33.77a23.463,23.463,0,0,0,23.5-23.371v-.922A3.118,3.118,0,0,0,73.4,40.52Zm3.462-21.626L65.435,9.1a.433.433,0,0,0-.279-.1.438.438,0,0,0-.178.038.4.4,0,0,0-.239.354v6.7H30.968a23.463,23.463,0,0,0-23.5,23.371v.921a3.135,3.135,0,0,0,6.269,0v-.921a17.225,17.225,0,0,1,17.23-17.179H64.739v6.7a.4.4,0,0,0,.241.36.415.415,0,0,0,.177.039.428.428,0,0,0,.277-.1l11.425-9.8a.4.4,0,0,0,.141-.3A.393.393,0,0,0,76.862,18.894ZM33.607,38.067a3.151,3.151,0,0,1-1.3-.281l-3.715-1.664-.49,4.041A14.237,14.237,0,1,0,42.229,27.727a14.3,14.3,0,0,0-4.677.783l-3.9,1.347,2.484,3.3a3.023,3.023,0,0,1,.618,1.827A3.121,3.121,0,0,1,33.607,38.067Zm9.147-3.088a8.973,8.973,0,0,0-.085-1.241,8.128,8.128,0,1,1-8.368,10.3A9.125,9.125,0,0,0,42.754,34.979Z"/></svg>
|
After Width: | Height: | Size: 1.1 KiB |
|
@ -0,0 +1 @@
|
|||
<svg id="图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 84 84"><defs><style>.cls-1{fill:#FFFFFF;}</style></defs><title>视频操作</title><path class="cls-1" d="M59.818,17.687a2.887,2.887,0,0,0-3.936,1.092A3.1,3.1,0,0,0,57.287,22.6,20.827,20.827,0,0,1,69.1,42.273a20.949,20.949,0,0,1-12.09,19.4,2.382,2.382,0,0,0-1.124,3.552,2.887,2.887,0,0,0,3.936,1.092,27.059,27.059,0,0,0,0-48.626Zm3.374,24.257a15.4,15.4,0,0,0-5.624-12.02,3.078,3.078,0,0,0-3.936.273,2.587,2.587,0,0,0,0,3.825,10.5,10.5,0,0,1,0,16.391c-1.124.819-1.124,2.732,0,3.278a2.77,2.77,0,0,0,3.936.273A15.4,15.4,0,0,0,63.192,41.944ZM44.269,12a4.385,4.385,0,0,0-2.5.816L23.264,27.05H16.71A7.625,7.625,0,0,0,9,34.542V49.525a7.625,7.625,0,0,0,7.71,7.491h6.554l18.5,14.234a3.387,3.387,0,0,0,2.161.75,3.96,3.96,0,0,0,4.007-3.746V15.813A3.625,3.625,0,0,0,44.269,12ZM41.936,61.779a1,1,0,0,1-1.61.792L26.922,52.26,25.3,51.016H16.71A1.634,1.634,0,0,1,15,49.525V34.542a1.634,1.634,0,0,1,1.71-1.492H25.3l1.618-1.244L40.326,21.5a1,1,0,0,1,1.61.792Z"/></svg>
|
After Width: | Height: | Size: 1.0 KiB |
|
@ -0,0 +1,5 @@
|
|||
(function(d,e){"object"===typeof exports&&"undefined"!==typeof module?e(exports):"function"===typeof define&&define.amd?define(["exports"],e):(d=d||self,e(d.alawmulaw={}))})(this,function(d){function e(a){a=-32768==a?-32767:a;var c=~a>>8&128;c||(a*=-1);32635<a&&(a=32635);if(256<=a){var b=k[a>>8&127];a=b<<4|a>>b+3&15}else a>>=4;return a^c^85}function f(a){var c=0;a^=85;a&128&&(a&=-129,c=-1);var b=((a&240)>>4)+4;a=4!=b?1<<b|(a&15)<<b-4|1<<b-5:a<<1|1;return-8*(0===c?a:-a)}function g(a){var c=a>>8&128;
|
||||
0!=c&&(a=-a);a+=132;32635<a&&(a=32635);var b=l[a>>7&255];return~(c|b<<4|a>>b+3&15)}function h(a){a=~a;var c=a>>4&7;c=m[c]+((a&15)<<c+3);0!=(a&128)&&(c=-c);return c}var k=[1,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7],n=Object.freeze({__proto__:null,encodeSample:e,decodeSample:f,encode:function(a){for(var c=
|
||||
new Uint8Array(a.length),b=0;b<a.length;b++)c[b]=e(a[b]);return c},decode:function(a){for(var c=new Int16Array(a.length),b=0;b<a.length;b++)c[b]=f(a[b]);return c}}),l=[0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
||||
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7],m=[0,132,396,924,1980,4092,8316,16764],p=Object.freeze({__proto__:null,encodeSample:g,decodeSample:h,encode:function(a){for(var c=new Uint8Array(a.length),b=0;b<a.length;b++)c[b]=g(a[b]);return c},decode:function(a){for(var c=new Int16Array(a.length),b=0;b<a.length;b++)c[b]=h(a[b]);return c}});d.alaw=n;d.mulaw=p;Object.defineProperty(d,
|
||||
"__esModule",{value:!0})});
|
|
@ -0,0 +1,234 @@
|
|||
function CmsTalk() {
|
||||
this.wasmLoaded = false;
|
||||
this.logger = new Logger("CmsTalk");
|
||||
this.urlBufferBuffer = null
|
||||
this.audioCache = null
|
||||
this.localAudioStream = null
|
||||
this.ws = null
|
||||
this.mediaRecorder = null
|
||||
this.audioBuffer = null
|
||||
|
||||
this.rec = null
|
||||
// this.recBlob = null;
|
||||
/**调用open打开录音请求好录音权限**/
|
||||
|
||||
this.RecorderOpen()
|
||||
}
|
||||
|
||||
CmsTalk.prototype.RecorderOpen = function () {
|
||||
|
||||
//recOpen我们可以选择性的弹一个对话框:为了防止移动端浏览器存在第三种情况:用户忽略,并且(或者国产系统UC系)浏览器没有任何回调
|
||||
var showDialog = function () {
|
||||
if (!/mobile/i.test(navigator.userAgent)) {
|
||||
return //只在移动端开启没有权限请求的检测
|
||||
}
|
||||
dialogCancel()
|
||||
|
||||
//显示弹框,应该使用自己的弹框方式
|
||||
var div = document.createElement("div")
|
||||
document.body.appendChild(div)
|
||||
div.innerHTML =
|
||||
"" +
|
||||
'<div class="waitDialog" style="z-index:99999;width:100%;height:100%;top:0;left:0;position:fixed;background:rgba(0,0,0,0.3);">' +
|
||||
'<div style="display:flex;height:100%;align-items:center;">' +
|
||||
'<div style="flex:1;"></div>' +
|
||||
'<div style="width:240px;background:#fff;padding:15px 20px;border-radius: 10px;">' +
|
||||
'<div style="padding-bottom:10px;">录音功能需要麦克风权限,请允许;如果未看到任何请求,请点击忽略~</div>' +
|
||||
'<div style="text-align:center;"><a onclick="waitDialogClick()" style="color:#0B1">忽略</a></div>' +
|
||||
"</div>" +
|
||||
'<div style="flex:1;"></div>' +
|
||||
"</div>" +
|
||||
"</div>"
|
||||
}
|
||||
var createDelayDialog = function () {
|
||||
dialogInt = setTimeout(function () {
|
||||
//定时8秒后打开弹窗,用于监测浏览器没有发起权限请求的情况,在open前放置定时器利于收到了回调能及时取消(不管open是同步还是异步回调的)
|
||||
showDialog()
|
||||
}, 8000)
|
||||
}
|
||||
var dialogInt
|
||||
var dialogCancel = function () {
|
||||
clearTimeout(dialogInt)
|
||||
|
||||
//关闭弹框,应该使用自己的弹框方式
|
||||
var elems = document.querySelectorAll(".waitDialog")
|
||||
for (var i = 0; i < elems.length; i++) {
|
||||
elems[i].parentNode.removeChild(elems[i])
|
||||
}
|
||||
}
|
||||
//recOpen弹框End
|
||||
|
||||
var formatMs = function (ms, all) {
|
||||
var f = Math.floor(ms / 60000),
|
||||
m = Math.floor(ms / 1000) % 60
|
||||
var s =
|
||||
(all || f > 0 ? (f < 10 ? "0" : "") + f + ":" : "") +
|
||||
(all || f > 0 || m > 0 ? ("0" + m).substr(-2) + "″" : "") +
|
||||
("00" + (ms % 1000)).substr(-3)
|
||||
return s
|
||||
}
|
||||
// var recOpen = function () {//一般在显示出录音按钮或相关的录音界面时进行此方法调用,后面用户点击开始录音时就能畅通无阻了
|
||||
this.newRec = Recorder({
|
||||
type: "pcm", sampleRate: 8000, bitRate: 16 //mp3格式,指定采样率hz、比特率kbps,其他参数使用默认配置;注意:是数字的参数必须提供数字,不要用字符串;需要使用的type类型,需提前把格式支持文件加载进来,比如使用wav格式需要提前加载wav.js编码引擎
|
||||
, onProcess: function (buffers, powerLevel, bufferDuration, bufferSampleRate, newBufferIdx, asyncEnd) {
|
||||
newBufferIdx = 0
|
||||
var newChunkInfo = Recorder.SampleData(buffers, 48000, 8000, this.prevChunkInfo);
|
||||
this.sendAudioData(newChunkInfo.data)
|
||||
this.prevChunkInfo = newChunkInfo
|
||||
for (let index = buffers.length - 1; index >= 0; index--) {
|
||||
buffers[index] = null;
|
||||
}
|
||||
}.bind(this)
|
||||
});
|
||||
|
||||
// createDelayDialog(); //我们可以选择性的弹一个对话框:为了防止移动端浏览器存在第三种情况:用户忽略,并且(或者国产系统UC系)浏览器没有任何回调,此处demo省略了弹窗的代码
|
||||
|
||||
|
||||
window.waitDialogClick = function () {
|
||||
dialogCancel();
|
||||
console.log("打开失败:权限请求被忽略,<span style='color:#f00'>用户主动点击的弹窗</span>", 1);
|
||||
};
|
||||
// };
|
||||
}
|
||||
|
||||
//打开麦克风授权获得相关资源
|
||||
CmsTalk.prototype.open = function (callback) {
|
||||
// dialogCancel(); //如果开启了弹框,此处需要取消
|
||||
if (this.rec){
|
||||
console.log("已打开录音设备,可以点击录制开始录音了", 2);
|
||||
callback(null)
|
||||
return
|
||||
}
|
||||
|
||||
this.newRec.open(function () {
|
||||
this.rec = this.newRec;
|
||||
console.log("已打开录音设备,可以点击录制开始录音了", 2);
|
||||
callback()
|
||||
}.bind(this), function (msg, isUserNotAllow) {
|
||||
//用户拒绝未授权或不支持
|
||||
// dialogCancel(); //如果开启了弹框,此处需要取消
|
||||
var log = (isUserNotAllow ? "UserNotAllow," : "") + "打开录音失败:" + msg;
|
||||
console.log(log);
|
||||
callback(log)
|
||||
})
|
||||
}
|
||||
|
||||
/**关闭录音,释放资源**/
|
||||
CmsTalk.prototype.recClose = function () {
|
||||
if (this.rec) {
|
||||
this.rec.close();
|
||||
this.rec = null
|
||||
console.log("已关闭");
|
||||
} else {
|
||||
console.log("未打开录音", 1);
|
||||
};
|
||||
};
|
||||
|
||||
/**开始录音**/
|
||||
CmsTalk.prototype.recStart = function () {//打开了录音后才能进行start、stop调用
|
||||
this.prevChunkInfo = null
|
||||
if (this.rec && Recorder.IsOpen()) {
|
||||
// this.recBlob = null;
|
||||
this.rec.start();
|
||||
console.log("已开始录音...");
|
||||
} else {
|
||||
console.log("未打开录音", 1);
|
||||
};
|
||||
};
|
||||
|
||||
/**暂停录音**/
|
||||
CmsTalk.prototype.recPause = function () {
|
||||
if (this.rec && Recorder.IsOpen()) {
|
||||
this.rec.pause();
|
||||
} else {
|
||||
console.log("未打开录音", 1);
|
||||
};
|
||||
};
|
||||
/**恢复录音**/
|
||||
CmsTalk.prototype.recResume = function () {
|
||||
if (this.rec && Recorder.IsOpen()) {
|
||||
this.rec.resume();
|
||||
} else {
|
||||
console.log("未打开录音", 1);
|
||||
};
|
||||
};
|
||||
|
||||
/**结束录音,得到音频文件**/
|
||||
CmsTalk.prototype.recStop = function () {
|
||||
if (!(this.rec && Recorder.IsOpen())) {
|
||||
console.log("未打开录音", 1);
|
||||
return;
|
||||
};
|
||||
this.rec.stop(null, null);
|
||||
};
|
||||
|
||||
CmsTalk.prototype.startTalk = function (url, callback) {
|
||||
this.open((err) => {
|
||||
if (err) {
|
||||
callback(err)
|
||||
} else {
|
||||
if (url.indexOf("http") != -1) {
|
||||
//方式1,可手动修改talk-server对应的地址
|
||||
this.ws = new WebSocket("ws://192.168.0.215:3000");
|
||||
this.ws.onmessage = function (msg) {
|
||||
console.log(msg);
|
||||
};
|
||||
this.ws.onopen = (ev) => {
|
||||
console.log("open")
|
||||
this.ws.send(url)
|
||||
|
||||
this.recStart()
|
||||
if (callback)
|
||||
callback(null)
|
||||
}
|
||||
}
|
||||
else {
|
||||
//方式2
|
||||
this.ws = new WebSocket(url);
|
||||
this.ws.onmessage = function (msg) {
|
||||
console.log(msg);
|
||||
};
|
||||
this.ws.onopen = (ev) => {
|
||||
console.log("open")
|
||||
this.recStart()
|
||||
if (callback)
|
||||
callback(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
|
||||
CmsTalk.prototype.stopTalk = function () {
|
||||
if (this.ws) {
|
||||
this.ws.close();
|
||||
this.ws = null
|
||||
}
|
||||
if (this.audioBuffer) {
|
||||
delete this.audioBuffer
|
||||
this.audioBuffer = null
|
||||
}
|
||||
this.recStop()
|
||||
// this.recClose()
|
||||
}
|
||||
|
||||
CmsTalk.prototype.sendAudioData = function (samples) {
|
||||
var u8Data = alawmulaw.alaw.encode(samples);
|
||||
if (!this.audioBuffer)
|
||||
this.audioBuffer = new Uint8Array([])
|
||||
|
||||
var tmpBuffer = new Uint8Array(this.audioBuffer.byteLength + u8Data.byteLength)
|
||||
tmpBuffer.set(this.audioBuffer, 0)
|
||||
tmpBuffer.set(u8Data, this.audioBuffer.byteLength)
|
||||
while (tmpBuffer.byteLength >= 480) {
|
||||
var d480 = tmpBuffer.subarray(0, 480);
|
||||
tmpBuffer = tmpBuffer.subarray(480);
|
||||
console.log("reserve ", tmpBuffer.length)
|
||||
if (this.ws)
|
||||
this.ws.send(d480)
|
||||
}
|
||||
this.audioBuffer = tmpBuffer
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
//Player request.
|
||||
const kCloseDecoderReq = 0;
|
||||
const kOpenDecoderReq = 1;
|
||||
const kRequestHeaderReq = 2;
|
||||
const kRequestBodyReq = 3;
|
||||
const kPauseGetUrlReq = 4;
|
||||
const kResumeGetUrlReq = 5;
|
||||
const kRequestLiveReq = 6;
|
||||
const kDecodeVideo = 7;
|
||||
|
||||
//CMSParser response.
|
||||
const kCMSHeaderRes = 8;
|
||||
const kVideoFrame = 9;
|
||||
const kAudioFrame = 10;
|
||||
const kImageFrame = 11;
|
||||
const kFinishDownload = 12;
|
||||
const kVideoBuffer = 13;
|
||||
const kCmsPartHeader = 14;
|
||||
|
||||
function Logger(module) {
|
||||
this.module = module;
|
||||
}
|
||||
|
||||
Logger.prototype.log = function (line) {
|
||||
console.log("[" + this.currentTimeStr() + "][" + this.module + "]" + line);
|
||||
}
|
||||
|
||||
Logger.prototype.logError = function (line) {
|
||||
// console.log("[" + this.currentTimeStr() + "][" + this.module + "][ER] " + line);
|
||||
}
|
||||
|
||||
Logger.prototype.logInfo = function (line) {
|
||||
// console.log("[" + this.currentTimeStr() + "][" + this.module + "][IF] " + line);
|
||||
}
|
||||
|
||||
Logger.prototype.logDebug = function (line) {
|
||||
// console.log("[" + this.currentTimeStr() + "][" + this.module + "][DT] " + line);
|
||||
}
|
||||
|
||||
Logger.prototype.currentTimeStr = function () {
|
||||
var now = new Date(Date.now());
|
||||
var year = now.getFullYear();
|
||||
var month = now.getMonth() + 1;
|
||||
var day = now.getDate();
|
||||
var hour = now.getHours();
|
||||
var min = now.getMinutes();
|
||||
var sec = now.getSeconds();
|
||||
var ms = now.getMilliseconds();
|
||||
return year + "-" + month + "-" + day + " " + hour + ":" + min + ":" + sec + ":" + ms;
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
prefix=/home/weixin/player3/ffmpeg/../WasmVideoPlayer-master/dist
|
||||
exec_prefix=${prefix}
|
||||
libdir=${prefix}/lib
|
||||
includedir=${prefix}/include
|
||||
|
||||
Name: libavcodec
|
||||
Description: FFmpeg codec library
|
||||
Version: 57.89.100
|
||||
Requires: libavutil >= 55.58.100
|
||||
Requires.private:
|
||||
Conflicts:
|
||||
Libs: -L${libdir} -lavcodec -s USE_SDL=2 -lm -pthreads
|
||||
Libs.private:
|
||||
Cflags: -I${includedir}
|
|
@ -0,0 +1,14 @@
|
|||
prefix=/home/weixin/player3/ffmpeg/../WasmVideoPlayer-master/dist
|
||||
exec_prefix=${prefix}
|
||||
libdir=${prefix}/lib
|
||||
includedir=${prefix}/include
|
||||
|
||||
Name: libavformat
|
||||
Description: FFmpeg container format library
|
||||
Version: 57.71.100
|
||||
Requires: libavcodec >= 57.89.100, libavutil >= 55.58.100
|
||||
Requires.private:
|
||||
Conflicts:
|
||||
Libs: -L${libdir} -lavformat -s USE_SDL=2 -lm -pthreads
|
||||
Libs.private:
|
||||
Cflags: -I${includedir}
|
|
@ -0,0 +1,14 @@
|
|||
prefix=/home/weixin/player3/ffmpeg/../WasmVideoPlayer-master/dist
|
||||
exec_prefix=${prefix}
|
||||
libdir=${prefix}/lib
|
||||
includedir=${prefix}/include
|
||||
|
||||
Name: libavutil
|
||||
Description: FFmpeg utility library
|
||||
Version: 55.58.100
|
||||
Requires:
|
||||
Requires.private:
|
||||
Conflicts:
|
||||
Libs: -L${libdir} -lavutil -lm
|
||||
Libs.private:
|
||||
Cflags: -I${includedir}
|
|
@ -0,0 +1,14 @@
|
|||
prefix=/home/weixin/player3/ffmpeg/../WasmVideoPlayer-master/dist
|
||||
exec_prefix=${prefix}
|
||||
libdir=${prefix}/lib
|
||||
includedir=${prefix}/include
|
||||
|
||||
Name: libswresample
|
||||
Description: FFmpeg audio resampling library
|
||||
Version: 2.7.100
|
||||
Requires: libavutil >= 55.58.100
|
||||
Requires.private:
|
||||
Conflicts:
|
||||
Libs: -L${libdir} -lswresample -lm
|
||||
Libs.private:
|
||||
Cflags: -I${includedir}
|
|
@ -0,0 +1,14 @@
|
|||
prefix=/home/weixin/player3/ffmpeg/../WasmVideoPlayer-master/dist
|
||||
exec_prefix=${prefix}
|
||||
libdir=${prefix}/lib
|
||||
includedir=${prefix}/include
|
||||
|
||||
Name: libswscale
|
||||
Description: FFmpeg image rescaling library
|
||||
Version: 4.6.100
|
||||
Requires: libavutil >= 55.58.100
|
||||
Requires.private:
|
||||
Conflicts:
|
||||
Libs: -L${libdir} -lswscale -lm
|
||||
Libs.private:
|
||||
Cflags: -I${includedir}
|
|
@ -0,0 +1,377 @@
|
|||
function CmsParser() {
|
||||
this.CMS_FLAG_FORMAT_FOUND = 0x01;
|
||||
this.CMS_FLAG_TRACK_FOUND = 0x02;
|
||||
this.CMS_FLAG_STOP_WHEN_ERROR = 0x04;
|
||||
|
||||
this.CMS_PART_UNKNOWN = 'na';
|
||||
this.CMS_PART_H264_i_FRAME = 'i';
|
||||
this.CMS_PART_H264_p_FRAME = 'p';
|
||||
this.CMS_PART_AUDIO = 'a';
|
||||
this.CMS_PART_JPG = 'j';
|
||||
|
||||
|
||||
this.CMS_E_HEADER_FIELD = 0;
|
||||
this.CMS_E_HEADER_END = 1;
|
||||
this.CMS_E_PART_HEADER = 2;
|
||||
this.CMS_E_PART_HEADER_FIELD = 3;
|
||||
this.CMS_E_PART_HEADER_END = 4;
|
||||
this.CMS_E_PART_END = 5;
|
||||
this.CMS_E_CHUNK = 6;
|
||||
this.CMS_E_PARSE_FAIL = 7;
|
||||
|
||||
|
||||
|
||||
this.CMS_HEADER = 0;
|
||||
this.CMS_DETECT_BOUNDARY = 1;
|
||||
this.CMS_PART_HEADER = 2;
|
||||
this.CMS_FINISHED = 3;
|
||||
this.CMS_FAIL = 4;
|
||||
|
||||
this.flag = 0;
|
||||
this.shift = 0;
|
||||
|
||||
this.line_buf = new Uint8Array(2000);
|
||||
this.line_buf_ptr = 0;
|
||||
this.state = this.CMS_HEADER;
|
||||
|
||||
this.cache = new Uint8Array(100); // for boundary
|
||||
this.cached_len = 0;
|
||||
|
||||
this.is_first_part = true;
|
||||
this.callback_context = null;
|
||||
this.callback = null;
|
||||
|
||||
this.boundary = null;
|
||||
this.boundary_size = 0;
|
||||
this.boundary_ptr = 0;
|
||||
|
||||
// boundary = strdup("\r\n----asdfasdf\r\n");
|
||||
// boundary.length = strlen(boundary);
|
||||
this._header = {
|
||||
hasAudio: false,
|
||||
hasVideo: false
|
||||
};
|
||||
this.parts = [];
|
||||
this.part = {
|
||||
header: {},
|
||||
shift: 0,
|
||||
chunks: []
|
||||
};
|
||||
};
|
||||
|
||||
CmsParser.prototype.fail = function (error) {
|
||||
this.emit(this.CMS_E_PARSE_FAIL, error);
|
||||
if (this.flag & this.CMS_FLAG_STOP_WHEN_ERROR) {
|
||||
this.state = this.CMS_FAIL;
|
||||
return true;
|
||||
} else {
|
||||
this.state = this.CMS_DETECT_BOUNDARY;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
CmsParser.prototype.parse = function (data) {
|
||||
var chunk = 0;
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
var ch = data[i];
|
||||
ch = String.fromCharCode(ch);
|
||||
this.shift++;
|
||||
switch (this.state) {
|
||||
case this.CMS_FAIL: {
|
||||
if (this.fail("CmsParser parse stoped.")) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
};
|
||||
case this.CMS_HEADER: {
|
||||
if (ch === '\r') {
|
||||
} else if (ch === '\n') {
|
||||
if (this.line_buf_ptr === 0) {
|
||||
this.emit(this.CMS_E_HEADER_END);
|
||||
if (!this.boundary) {
|
||||
if (this.fail("Boundary not found.")) {
|
||||
return;
|
||||
}
|
||||
} else if (!(this.flag & this.CMS_FLAG_FORMAT_FOUND)) {
|
||||
if (this.fail("Format not found.")) {
|
||||
return;
|
||||
}
|
||||
} else if (!(this.flag & this.CMS_FLAG_TRACK_FOUND)) {
|
||||
if (this.fail("Track not found.")) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
this.state = this.CMS_DETECT_BOUNDARY;
|
||||
this.boundary_ptr = 2;
|
||||
chunk = i + 1;
|
||||
}
|
||||
} else {
|
||||
var s = String.fromCharCode.apply(null, this.line_buf.slice(0, this.line_buf_ptr));
|
||||
s = s.split(":");
|
||||
var key = s.shift().trim();
|
||||
var value = s.join(":").trim();
|
||||
// console.log("cms header:", key, '=', value);
|
||||
if (key && value) {
|
||||
if (key === "boundary") {
|
||||
this.boundary = "\r\n--" + value + "\r\n";
|
||||
} else if (key === "format" && value === "cms") {
|
||||
this.flag = this.flag | this.CMS_FLAG_FORMAT_FOUND;
|
||||
} else if (key === "track") {
|
||||
this.flag = this.flag | this.CMS_FLAG_TRACK_FOUND;
|
||||
}
|
||||
var kv = {
|
||||
key: key,
|
||||
value: value
|
||||
};
|
||||
this.emit(this.CMS_E_HEADER_FIELD, kv);
|
||||
} else {
|
||||
if (this.fail("Invalid key value.")) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.line_buf_ptr = 0;
|
||||
this.line_buf.fill(0);
|
||||
} else {
|
||||
this.line_buf[this.line_buf_ptr] = ch.charCodeAt(0);
|
||||
this.line_buf_ptr++;
|
||||
}
|
||||
break;
|
||||
};
|
||||
case this.CMS_DETECT_BOUNDARY: {
|
||||
if (!this.boundary) {
|
||||
break;
|
||||
}
|
||||
if (ch == this.boundary[this.boundary_ptr]) {
|
||||
this.boundary_ptr++;
|
||||
} else if (this.boundary_ptr == 1 && ch == this.boundary[this.boundary_ptr - 1]) {
|
||||
|
||||
} else {
|
||||
if (this.cached_len > 0) {
|
||||
this.emit(this.CMS_E_CHUNK, this.cache.slice(0, this.cached_len));
|
||||
this.cached_len = 0;
|
||||
}
|
||||
this.boundary_ptr = 0;
|
||||
}
|
||||
if (this.boundary_ptr === this.boundary.length) {
|
||||
if (i - chunk >= (this.boundary.length - this.cached_len)) {
|
||||
var chunk_len = i - chunk - (this.boundary.length - this.cached_len) + 1;
|
||||
this.emit(this.CMS_E_CHUNK, data.slice(chunk, chunk + chunk_len));
|
||||
}
|
||||
this.cached_len = 0;
|
||||
if (this.is_first_part) {
|
||||
this.is_first_part = false;
|
||||
} else {
|
||||
this.emit(this.CMS_E_PART_END);
|
||||
}
|
||||
this.emit(this.CMS_E_PART_HEADER);
|
||||
|
||||
this.state = this.CMS_PART_HEADER;
|
||||
this.part = {
|
||||
header: {
|
||||
type: this.CMS_PART_UNKNOWN,
|
||||
track: -1,
|
||||
length: 0,
|
||||
ts: -1
|
||||
},
|
||||
shift: this.shift,
|
||||
chunks: []
|
||||
}
|
||||
chunk = i + 1;
|
||||
this.boundary_ptr = 0;
|
||||
this.line_buf_ptr = 0;
|
||||
this.line_buf[0] = 0;
|
||||
}
|
||||
break;
|
||||
};
|
||||
case this.CMS_PART_HEADER: {
|
||||
if (ch == '\r') {
|
||||
} else if (ch == '\n') {
|
||||
if (this.line_buf_ptr == 0) {
|
||||
this.emit(this.CMS_E_PART_HEADER_END);
|
||||
this.state = this.CMS_DETECT_BOUNDARY;
|
||||
chunk = i + 1;
|
||||
} else {
|
||||
var s = String.fromCharCode.apply(null, this.line_buf.slice(0, this.line_buf_ptr)).split(":");
|
||||
var key = s.shift().trim();
|
||||
var value = s.join(":").trim();
|
||||
// console.log("part header:", key, '=', value);
|
||||
if (key && value) {
|
||||
if (key === "f") {
|
||||
if (value === "i") {
|
||||
this.part.header.type = this.CMS_PART_H264_i_FRAME;
|
||||
} else if (value === "p") {
|
||||
this.part.header.type = this.CMS_PART_H264_p_FRAME;
|
||||
} else if (value === "a") {
|
||||
this.part.header.type = this.CMS_PART_AUDIO;
|
||||
} else if (value === "j") {
|
||||
this.part.header.type = this.CMS_PART_JPG;
|
||||
} else {
|
||||
console.error("Unknown frame type:", value);
|
||||
}
|
||||
} else if (key === "ts") {
|
||||
this.part.header.ts = parseInt(value, 10);
|
||||
} else if (key === "l") {
|
||||
this.part.header.length = parseInt(value, 10);
|
||||
} else if (key === "t") {
|
||||
this.part.header.track = parseInt(value, 10);
|
||||
}
|
||||
var kv = {
|
||||
key: key,
|
||||
value: value
|
||||
};
|
||||
this.emit(this.CMS_E_PART_HEADER_FIELD, kv);
|
||||
} else {
|
||||
if (this.fail("Part header Invalid key value.")) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.line_buf_ptr = 0;
|
||||
this.line_buf.fill(0);
|
||||
} else {
|
||||
if (this.line_buf_ptr < this.line_buf.length - 1) {
|
||||
this.line_buf[this.line_buf_ptr] = ch.charCodeAt(0);
|
||||
this.line_buf_ptr++;
|
||||
} else {
|
||||
if (this.fail("Part header line too long.")) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
};
|
||||
}
|
||||
}
|
||||
if (this.state == this.CMS_DETECT_BOUNDARY) {
|
||||
if (chunk < data.length) {
|
||||
if (this.boundary_ptr > 0) {
|
||||
this.cached_len = this.boundary_ptr;
|
||||
var pos = data.length - this.boundary_ptr;
|
||||
if (pos >= 0) {
|
||||
this.cache = data.slice(pos, this.cached_len);
|
||||
}
|
||||
}
|
||||
this.emit(this.CMS_E_CHUNK, data.slice(chunk, chunk + data.length - chunk - this.boundary_ptr));
|
||||
}
|
||||
}
|
||||
};
|
||||
CmsParser.prototype.set_callback = function (cb, context) {
|
||||
this.callback = cb;
|
||||
this.callback_context = context;
|
||||
};
|
||||
CmsParser.prototype.emit = function (e, data, size) {
|
||||
if (this.callback) {
|
||||
return this.callback(this, e, data, size, this.callback_context);
|
||||
} else {
|
||||
this.cache_data(e, data);
|
||||
}
|
||||
};
|
||||
|
||||
CmsParser.prototype.cache_data = function (e, data) {
|
||||
switch (e) {
|
||||
case this.CMS_E_HEADER_FIELD: {
|
||||
var key = data.key;
|
||||
var value = data.value;
|
||||
this._header[key] = value;
|
||||
if (key === 'track') {
|
||||
var tracks = value.split(';');
|
||||
this._header.tracks = [];
|
||||
for (var t = 0; t < tracks.length; t++) {
|
||||
var fields = tracks[t].split(',');
|
||||
var track = {};
|
||||
for (var j = 0; j < fields.length; j++) {
|
||||
var f = fields[j].split('=');
|
||||
var key = f.shift();
|
||||
var value = f.join('=');
|
||||
track[key] = value;
|
||||
if (key === 'codec') {
|
||||
if (value === 'alaw') {
|
||||
this._header.hasAudio = true;
|
||||
this._header.audioTrack = track;
|
||||
} else if (value === 'h264') {
|
||||
this._header.hasVideo = true;
|
||||
this._header.videoTrack = track;
|
||||
}
|
||||
}
|
||||
}
|
||||
this._header.tracks.push(track);
|
||||
}
|
||||
} else if (key === "duration") {
|
||||
this._header.duration = parseInt(value, 10);
|
||||
}
|
||||
break;
|
||||
};
|
||||
case this.CMS_E_HEADER_END: {
|
||||
this.header = this._header;
|
||||
break;
|
||||
};
|
||||
case this.CMS_E_PART_HEADER: {
|
||||
break;
|
||||
};
|
||||
case this.CMS_E_PART_HEADER_FIELD: {
|
||||
break;
|
||||
};
|
||||
case this.CMS_E_PART_HEADER_END: {
|
||||
break;
|
||||
};
|
||||
case this.CMS_E_PART_END: {
|
||||
var chunks = this.part.chunks;
|
||||
var size = 0;
|
||||
for (var i = 0; i < chunks.length; i++) {
|
||||
size = size + chunks[i].length;
|
||||
}
|
||||
this.part.data = new ArrayBuffer(size);
|
||||
var data = new Uint8Array(this.part.data);
|
||||
var shift = 0;
|
||||
for (var i = 0; i < chunks.length; i++) {
|
||||
data.set(chunks[i], shift);
|
||||
shift = shift + chunks[i].length;
|
||||
}
|
||||
this.parts.push(this.part);
|
||||
break;
|
||||
};
|
||||
case this.CMS_E_CHUNK: {
|
||||
this.part.chunks.push(data);
|
||||
break;
|
||||
};
|
||||
case this.CMS_E_PARSE_FAIL: {
|
||||
break;
|
||||
};
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = CmsParser;
|
||||
// var cms = new CmsParser();
|
||||
|
||||
// var fs = require('fs');
|
||||
// var f = fs.createReadStream("/home/gxy/work/cms/cms/tmp/ttt.cms");
|
||||
// f.on('end', function (err) {
|
||||
// console.log("end");
|
||||
// });
|
||||
// f.on('error', function (err) {
|
||||
// console.error(err);
|
||||
// });
|
||||
// f.on('data', function (chunk) {
|
||||
// cms.parse(chunk);
|
||||
// if (cms.header) {
|
||||
// console.log(cms.header);
|
||||
// cms.header = null;
|
||||
// }
|
||||
// var parts = cms.parts;
|
||||
// while (parts.length > 0) {
|
||||
// var part = parts.shift();
|
||||
// console.log(part.header);
|
||||
// var chunks = part.chunks;
|
||||
// var len = 0;
|
||||
// for (var i = 0; i < chunks.length; i++) {
|
||||
// len = len + chunks[i].length;
|
||||
// }
|
||||
// if (len !== part.header.length) {
|
||||
// console.log("mismatch: len=%d part.len=%d", len, part.header.length);
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
|
@ -0,0 +1,204 @@
|
|||
function PCMPlayer(option) {
|
||||
console.log("PCMPlayer new")
|
||||
this.init(option);
|
||||
}
|
||||
|
||||
PCMPlayer.prototype.init = function (option) {
|
||||
var defaults = {
|
||||
encoding: '16bitInt',
|
||||
channels: 1,
|
||||
sampleRate: 8000,
|
||||
flushingTime: 1000
|
||||
};
|
||||
this.option = Object.assign({}, defaults, option);
|
||||
this.samples = new Float32Array();
|
||||
this.flush = this.flush.bind(this);
|
||||
this.interval = setInterval(this.flush, this.option.flushingTime);
|
||||
this.maxValue = this.getMaxValue();
|
||||
this.typedArray = this.getTypedArray();
|
||||
this.createContext();
|
||||
this.lastBufferSource = null
|
||||
};
|
||||
|
||||
PCMPlayer.prototype.getMaxValue = function () {
|
||||
var encodings = {
|
||||
'8bitInt': 128,
|
||||
'16bitInt': 32768,
|
||||
'32bitInt': 2147483648,
|
||||
'32bitFloat': 1
|
||||
}
|
||||
|
||||
return encodings[this.option.encoding] ? encodings[this.option.encoding] : encodings['16bitInt'];
|
||||
};
|
||||
|
||||
PCMPlayer.prototype.getTypedArray = function () {
|
||||
var typedArrays = {
|
||||
'8bitInt': Int8Array,
|
||||
'16bitInt': Int16Array,
|
||||
'32bitInt': Int32Array,
|
||||
'32bitFloat': Float32Array
|
||||
}
|
||||
|
||||
return typedArrays[this.option.encoding] ? typedArrays[this.option.encoding] : typedArrays['16bitInt'];
|
||||
};
|
||||
|
||||
PCMPlayer.prototype.createContext = function () {
|
||||
this.audioCtx = new (window.AudioContext || window.webkitAudioContext)();
|
||||
this.gainNode = this.audioCtx.createGain();
|
||||
this.gainNode.gain.value = 1;
|
||||
this.gainNode.connect(this.audioCtx.destination);
|
||||
this.startTime = this.audioCtx.currentTime;
|
||||
};
|
||||
|
||||
PCMPlayer.prototype.isTypedArray = function (data) {
|
||||
return (data.byteLength && data.buffer && data.buffer.constructor == ArrayBuffer);
|
||||
};
|
||||
|
||||
PCMPlayer.prototype.feed = function (data) {
|
||||
if (!this.isTypedArray(data)) return;
|
||||
data = this.getFormatedValue(data);
|
||||
var tmp = new Float32Array(this.samples.length + data.length);
|
||||
tmp.set(this.samples, 0);
|
||||
tmp.set(data, this.samples.length);
|
||||
this.samples = tmp;
|
||||
};
|
||||
|
||||
PCMPlayer.prototype.getFormatedValue = function (data) {
|
||||
var data = new this.typedArray(data.buffer),
|
||||
float32 = new Float32Array(data.length),
|
||||
i;
|
||||
for (i = 0; i < data.length; i++) {
|
||||
float32[i] = data[i] / this.maxValue;
|
||||
}
|
||||
return float32;
|
||||
};
|
||||
|
||||
PCMPlayer.prototype.volume = function (volume) {
|
||||
this.gainNode.gain.value = volume;
|
||||
};
|
||||
|
||||
PCMPlayer.prototype.destroy = function () {
|
||||
console.log("PCMPlayer destroy")
|
||||
if (this.interval) {
|
||||
clearInterval(this.interval);
|
||||
}
|
||||
this.samples = null;
|
||||
this.audioCtx.close();
|
||||
this.audioCtx = null;
|
||||
};
|
||||
|
||||
PCMPlayer.prototype.flush = function () {
|
||||
// console.log("PCMPlayer.prototype.flush", this.samples.length)
|
||||
if (!this.samples.length) return;
|
||||
var bufferSource = this.audioCtx.createBufferSource(),
|
||||
length = this.samples.length / this.option.channels,
|
||||
audioBuffer = this.audioCtx.createBuffer(this.option.channels, length, this.option.sampleRate),
|
||||
audioData,
|
||||
channel,
|
||||
offset,
|
||||
i,
|
||||
decrement;
|
||||
|
||||
for (channel = 0; channel < this.option.channels; channel++) {
|
||||
audioData = audioBuffer.getChannelData(channel);
|
||||
offset = channel;
|
||||
decrement = 50;
|
||||
for (i = 0; i < length; i++) {
|
||||
audioData[i] = this.samples[offset];
|
||||
/* fadein */
|
||||
if (i < 50) {
|
||||
audioData[i] = (audioData[i] * i) / 50;
|
||||
}
|
||||
/* fadeout*/
|
||||
if (i >= (length - 51)) {
|
||||
audioData[i] = (audioData[i] * decrement--) / 50;
|
||||
}
|
||||
offset += this.option.channels;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.startTime < this.audioCtx.currentTime) {
|
||||
this.startTime = this.audioCtx.currentTime;
|
||||
}
|
||||
// console.log('start vs current '+this.startTime+' vs '+this.audioCtx.currentTime+' duration: '+audioBuffer.duration);
|
||||
bufferSource.buffer = audioBuffer;
|
||||
bufferSource.connect(this.gainNode);
|
||||
bufferSource.start(this.startTime);
|
||||
this.startTime += audioBuffer.duration;
|
||||
this.samples = new Float32Array();
|
||||
};
|
||||
|
||||
PCMPlayer.prototype.getTimestamp = function () {
|
||||
if (this.audioCtx) {
|
||||
return this.audioCtx.currentTime;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
PCMPlayer.prototype.play = function (data, flushcache) {
|
||||
if (!this.isTypedArray(data)) {
|
||||
return;
|
||||
}
|
||||
if (this.audioCtx.state === 'suspended') {
|
||||
return;
|
||||
}
|
||||
|
||||
data = this.getFormatedValue(data);
|
||||
if (!data.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
var bufferSource = this.audioCtx.createBufferSource();
|
||||
var length = data.length / this.option.channels;
|
||||
var audioBuffer = this.audioCtx.createBuffer(this.option.channels, length, this.option.sampleRate);
|
||||
|
||||
var audioData, channel, offset, i, decrement;
|
||||
|
||||
for (channel = 0; channel < this.option.channels; channel++) {
|
||||
audioData = audioBuffer.getChannelData(channel);
|
||||
offset = channel;
|
||||
decrement = 50;
|
||||
for (i = 0; i < length; i++) {
|
||||
audioData[i] = data[offset];
|
||||
/* fadein */
|
||||
if (i < 50) {
|
||||
audioData[i] = (audioData[i] * i) / 50;
|
||||
}
|
||||
/* fadeout*/
|
||||
if (i >= (length - 51)) {
|
||||
audioData[i] = (audioData[i] * decrement--) / 50;
|
||||
}
|
||||
offset += this.option.channels;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.startTime < this.audioCtx.currentTime) {
|
||||
this.startTime = this.audioCtx.currentTime;
|
||||
}
|
||||
|
||||
// console.log('start vs current '+this.startTime+' vs '+this.audioCtx.currentTime+' duration: '+audioBuffer.duration);
|
||||
bufferSource.buffer = audioBuffer;
|
||||
bufferSource.connect(this.gainNode);
|
||||
bufferSource.start(this.startTime);
|
||||
this.startTime += audioBuffer.duration - 0.008;
|
||||
// bufferSource.playbackRate(1.05)
|
||||
this.lastBufferSource = bufferSource
|
||||
};
|
||||
|
||||
PCMPlayer.prototype.pause = function () {
|
||||
if (this.audioCtx.state === 'running') {
|
||||
this.audioCtx.suspend()
|
||||
}
|
||||
}
|
||||
|
||||
PCMPlayer.prototype.resume = function () {
|
||||
if (this.audioCtx.state === 'suspended') {
|
||||
this.audioCtx.resume()
|
||||
}
|
||||
}
|
||||
|
||||
PCMPlayer.prototype.stop = function () {
|
||||
if (this.lastBufferSource)
|
||||
this.lastBufferSource.stop()
|
||||
}
|
|
@ -0,0 +1,150 @@
|
|||
function Texture(gl) {
|
||||
this.gl = gl;
|
||||
this.texture = gl.createTexture();
|
||||
gl.bindTexture(gl.TEXTURE_2D, this.texture);
|
||||
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
||||
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
||||
}
|
||||
|
||||
Texture.prototype.bind = function (n, program, name) {
|
||||
var gl = this.gl;
|
||||
gl.activeTexture([gl.TEXTURE0, gl.TEXTURE1, gl.TEXTURE2][n]);
|
||||
gl.bindTexture(gl.TEXTURE_2D, this.texture);
|
||||
gl.uniform1i(gl.getUniformLocation(program, name), n);
|
||||
};
|
||||
|
||||
Texture.prototype.fill = function (width, height, data) {
|
||||
var gl = this.gl;
|
||||
gl.bindTexture(gl.TEXTURE_2D, this.texture);
|
||||
gl.texImage2D(gl.TEXTURE_2D, 0, gl.LUMINANCE, width, height, 0, gl.LUMINANCE, gl.UNSIGNED_BYTE, data);
|
||||
};
|
||||
|
||||
function WebGLPlayer(canvas, options) {
|
||||
this.canvas = canvas;
|
||||
this.gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
|
||||
this.initGL(options);
|
||||
}
|
||||
|
||||
WebGLPlayer.prototype.initGL = function (options) {
|
||||
if (!this.gl) {
|
||||
// console.log("[ER] WebGL not supported.");
|
||||
return;
|
||||
}
|
||||
|
||||
var gl = this.gl;
|
||||
gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1);
|
||||
var program = gl.createProgram();
|
||||
var vertexShaderSource = [
|
||||
"attribute highp vec4 aVertexPosition;",
|
||||
"attribute vec2 aTextureCoord;",
|
||||
"varying highp vec2 vTextureCoord;",
|
||||
"void main(void) {",
|
||||
" gl_Position = aVertexPosition;",
|
||||
" vTextureCoord = aTextureCoord;",
|
||||
"}"
|
||||
].join("\n");
|
||||
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
|
||||
gl.shaderSource(vertexShader, vertexShaderSource);
|
||||
gl.compileShader(vertexShader);
|
||||
var fragmentShaderSource = [
|
||||
"precision highp float;",
|
||||
"varying lowp vec2 vTextureCoord;",
|
||||
"uniform sampler2D YTexture;",
|
||||
"uniform sampler2D UTexture;",
|
||||
"uniform sampler2D VTexture;",
|
||||
"const mat4 YUV2RGB = mat4",
|
||||
"(",
|
||||
" 1.1643828125, 0, 1.59602734375, -.87078515625,",
|
||||
" 1.1643828125, -.39176171875, -.81296875, .52959375,",
|
||||
" 1.1643828125, 2.017234375, 0, -1.081390625,",
|
||||
" 0, 0, 0, 1",
|
||||
");",
|
||||
"void main(void) {",
|
||||
" gl_FragColor = vec4( texture2D(YTexture, vTextureCoord).x, texture2D(UTexture, vTextureCoord).x, texture2D(VTexture, vTextureCoord).x, 1) * YUV2RGB;",
|
||||
"}"
|
||||
].join("\n");
|
||||
|
||||
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
|
||||
gl.shaderSource(fragmentShader, fragmentShaderSource);
|
||||
gl.compileShader(fragmentShader);
|
||||
gl.attachShader(program, vertexShader);
|
||||
gl.attachShader(program, fragmentShader);
|
||||
gl.linkProgram(program);
|
||||
gl.useProgram(program);
|
||||
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
||||
// console.log("[ER] Shader link failed.");
|
||||
}
|
||||
var vertexPositionAttribute = gl.getAttribLocation(program, "aVertexPosition");
|
||||
gl.enableVertexAttribArray(vertexPositionAttribute);
|
||||
var textureCoordAttribute = gl.getAttribLocation(program, "aTextureCoord");
|
||||
gl.enableVertexAttribArray(textureCoordAttribute);
|
||||
|
||||
var verticesBuffer = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, verticesBuffer);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([1.0, 1.0, 0.0, -1.0, 1.0, 0.0, 1.0, -1.0, 0.0, -1.0, -1.0, 0.0]), gl.STATIC_DRAW);
|
||||
gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);
|
||||
var texCoordBuffer = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0]), gl.STATIC_DRAW);
|
||||
gl.vertexAttribPointer(textureCoordAttribute, 2, gl.FLOAT, false, 0, 0);
|
||||
|
||||
gl.y = new Texture(gl);
|
||||
gl.u = new Texture(gl);
|
||||
gl.v = new Texture(gl);
|
||||
gl.y.bind(0, program, "YTexture");
|
||||
gl.u.bind(1, program, "UTexture");
|
||||
gl.v.bind(2, program, "VTexture");
|
||||
}
|
||||
|
||||
WebGLPlayer.prototype.renderFrame = function (videoFrame, width, height, uOffset, vOffset) {
|
||||
if (!this.gl) {
|
||||
// console.log("[ER] Render frame failed due to WebGL not supported.");
|
||||
return;
|
||||
}
|
||||
|
||||
var gl = this.gl;
|
||||
gl.canvas.width = width;
|
||||
gl.canvas.height = height;
|
||||
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
|
||||
gl.clearColor(0.0, 0.0, 0.0, 0.0);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
|
||||
gl.y.fill(width, height, videoFrame.subarray(0, uOffset));
|
||||
gl.u.fill(width >> 1, height >> 1, videoFrame.subarray(uOffset, uOffset + vOffset));
|
||||
gl.v.fill(width >> 1, height >> 1, videoFrame.subarray(uOffset + vOffset, videoFrame.length));
|
||||
|
||||
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
||||
};
|
||||
|
||||
WebGLPlayer.prototype.fullscreen = function () {
|
||||
var canvas = this.canvas;
|
||||
if (canvas.RequestFullScreen) {
|
||||
canvas.RequestFullScreen();
|
||||
} else if (canvas.webkitRequestFullScreen) {
|
||||
canvas.webkitRequestFullScreen();
|
||||
} else if (canvas.mozRequestFullScreen) {
|
||||
canvas.mozRequestFullScreen();
|
||||
} else if (canvas.msRequestFullscreen) {
|
||||
canvas.msRequestFullscreen();
|
||||
} else {
|
||||
alert("This browser doesn't supporter fullscreen");
|
||||
}
|
||||
};
|
||||
|
||||
WebGLPlayer.prototype.exitfullscreen = function (){
|
||||
if (document.exitFullscreen) {
|
||||
document.exitFullscreen();
|
||||
} else if (document.webkitExitFullscreen) {
|
||||
document.webkitExitFullscreen();
|
||||
} else if (document.mozCancelFullScreen) {
|
||||
document.mozCancelFullScreen();
|
||||
} else if (document.msExitFullscreen) {
|
||||
document.msExitFullscreen();
|
||||
} else {
|
||||
alert("Exit fullscreen doesn't work");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset='UTF-8'><meta name='viewport' content='width=device-width initial-scale=1'>
|
||||
<title>README</title>
|
||||
</head>
|
||||
<body><h3 id='丛文cms视频web播放器'>丛文CMS视频WEB播放器</h3>
|
||||
<h4 id='1简介'>1.简介</h4>
|
||||
<p>该Demo项目,目前支持丛文cms格式封装的基于H264\H265压缩格式的实时视频流,录像视频文件以及录像图片文件的播放。</p>
|
||||
<h4 id='2操作界面介绍'>2.操作界面介绍</h4>
|
||||
<p><img src="/public/help/realplayscreen.png" referrerpolicy="no-referrer"></p>
|
||||
<h5 id='播放实时视频本地模拟流)'>播放实时视频(本地模拟流)</h5>
|
||||
<p>此按钮为播放web服务器端一个本地丛文媒体流文件,适用于没有丛文服务器环境下,了解丛文web视频播放控件。</p>
|
||||
<h5 id='播放录像文件本地模拟流)'>播放录像文件(本地模拟流)</h5>
|
||||
<p>此按钮为回放web服务器端一个本地丛文媒体流文件,适用于没有丛文服务器环境下,了解丛文web视频播放控件。</p>
|
||||
<h5 id='播放实时视频请配置url)'>播放实时视频(请配置URL)</h5>
|
||||
<p>此按钮为播放实时视频,需要配合丛文服务器,需要配置从视频输出网关获取的视频拉取url。</p>
|
||||
<h5 id='播放视频对讲请配置url)'>播放视频对讲(请配置URL)</h5>
|
||||
<p>此按钮为播放实时视频并提供对讲功能,需要配合丛文服务器,需要配置从视频输出网关获取的视频拉取url和对讲url。</p>
|
||||
<p>需要先配置好上面的视频拉取url,然后配置下面的对讲rul,先拉取视频,才可以点击对讲按钮,进行对讲。</p>
|
||||
<h5 id='播放录像文件请配置url)'>播放录像文件(请配置URL)</h5>
|
||||
<p>此按钮为回放录像文件,需要配合丛文服务器,需要配置从视频输出网关获取的录像文件拉取url。</p>
|
||||
<p> </p>
|
||||
<h4 id='3功能说明'>3.功能说明</h4>
|
||||
<ul>
|
||||
<li><p>实时视频</p>
|
||||
<p>播放、暂停、恢复播放、监听、对讲、全屏</p>
|
||||
</li>
|
||||
<li><p>录像视频</p>
|
||||
<p>播放、暂停、恢复播放、播放进度跳转</p>
|
||||
</li>
|
||||
<li><p>图片回放</p>
|
||||
<p>播放、暂停、恢复播放、播放进度跳转、红点</p>
|
||||
<p> </p>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
<h4 id='4文件及目录说明'>4.文件及目录说明</h4>
|
||||
<p> </p>
|
||||
<figure><table>
|
||||
<thead>
|
||||
<tr><th>路径</th><th>说明</th></tr></thead>
|
||||
<tbody><tr><td>index.html</td><td>DEMO播放页面文件</td></tr><tr><td>/public/player/</td><td>播放控件脚本</td></tr><tr><td>/public/player/cmsplayer.js</td><td>cms播放器</td></tr><tr><td>/public/player/cmsparser.js</td><td>cms解封装器</td></tr><tr><td>/public/player/decoder.js</td><td>解码器</td></tr><tr><td>/public/player/pcm-player.js</td><td>pcm播放器</td></tr><tr><td>/public/player/webgl.js</td><td>图像渲染器</td></tr><tr><td>/public/images/</td><td>用到的图片文件夹</td></tr><tr><td>/public/js/moment.js</td><td>播放控件用到的js文件</td></tr><tr><td>/public/data/</td><td>本地丛文格式媒体文件,用于DEMO回放演示</td></tr></tbody>
|
||||
</table></figure>
|
||||
<p> </p>
|
||||
<h4 id='5集成及接口说明'>5.集成及接口说明</h4>
|
||||
<ol start='' >
|
||||
<li><h5 id='导入player播放支持组件文件夹'>导入player播放支持组件文件夹;</h5>
|
||||
</li>
|
||||
<li><h5 id='参考indexhtml在播放html页面head导入需要的脚本'>参考index.html,在播放html页面head导入需要的脚本:</h5>
|
||||
<script src="/public/player/cmsplayer.js"></script>
|
||||
<script src="/public/player/common.js"></script>
|
||||
<script src="/public/player/pcm-player.js"></script>
|
||||
<script src="/public/player/webgl.js"></script>
|
||||
<script src="/public/player/cmstalk.js"></script>
|
||||
<script src="/public/player/alawmulaw.js"></script>
|
||||
<script src="/public/player/recorder-core.js"></script>
|
||||
<script src="/public/js/moment.js"></script>
|
||||
</li>
|
||||
<li><h5 id='初始化播放器控件'>初始化播放器控件:</h5>
|
||||
<p><code>playerBox</code> 为 div id:</p>
|
||||
<pre><code class='language-javascript' lang='javascript'>self.player = new Player($("#playerBox"));
|
||||
</code></pre>
|
||||
</li>
|
||||
<li><h5 id='播放'>播放:</h5>
|
||||
<pre><code class='language-javascript' lang='javascript'>//url 播放地址
|
||||
//isLive 是否实时视频
|
||||
//alarmTime 告警红点时间戳
|
||||
self.player.play(url, isLive , alarmTime );
|
||||
</code></pre>
|
||||
</li>
|
||||
<li><h5 id='暂停播放'>暂停播放:</h5>
|
||||
<pre><code class='language-javascript' lang='javascript'>self.player.pause();
|
||||
</code></pre>
|
||||
</li>
|
||||
<li><h5 id='恢复播放'>恢复播放:</h5>
|
||||
<pre><code class='language-javascript' lang='javascript'>self.player.resume();
|
||||
</code></pre>
|
||||
</li>
|
||||
<li><h5 id='停止播放'>停止播放:</h5>
|
||||
<pre><code class='language-javascript' lang='javascript'>self.player.stop();
|
||||
</code></pre>
|
||||
</li>
|
||||
<li><h5 id='监听开始'>监听开始:</h5>
|
||||
<pre><code class='language-javascript' lang='javascript'>self.player.startListen();
|
||||
</code></pre>
|
||||
</li>
|
||||
<li><h5 id='监听结束'>监听结束:</h5>
|
||||
<pre><code class='language-javascript' lang='javascript'>self.player.stopListen();
|
||||
</code></pre>
|
||||
</li>
|
||||
<li><h5 id='全屏'>全屏:</h5>
|
||||
<pre><code class='language-javascript' lang='javascript'>self.player.fullscreen();
|
||||
</code></pre>
|
||||
</li>
|
||||
|
||||
</ol>
|
||||
<h4 id='6运行方法'>6.运行方法</h4>
|
||||
<h5 id='运行整合了win版nginx的'>运行整合了win版nginx的</h5>
|
||||
<p>直接运行nginx,然后打开浏览器,输入 <a href='http://localhost/index.html' target='_blank' class='url'>http://localhost/index.html</a></p>
|
||||
<h5 id='自己运行web服务器的'>自己运行web服务器的</h5>
|
||||
<p>拷贝 相关文件到 web 网站的根目录。</p>
|
||||
<h5 ></h5>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,146 @@
|
|||
### 丛文CMS视频WEB播放器
|
||||
|
||||
#### 1.简介
|
||||
|
||||
该Demo项目,目前支持丛文cms格式封装的基于H264\H265压缩格式的实时视频流,录像视频文件以及录像图片文件的播放。
|
||||
|
||||
#### 2.操作界面介绍
|
||||
|
||||
![](/home/ramon/Pictures/realplayscreen.png)
|
||||
|
||||
##### 播放实时视频(本地模拟流)
|
||||
|
||||
此按钮为播放web服务器端一个本地丛文媒体流文件,适用于没有丛文服务器环境下,了解丛文web视频播放控件。
|
||||
|
||||
##### 播放录像文件(本地模拟流)
|
||||
|
||||
此按钮为回放web服务器端一个本地丛文媒体流文件,适用于没有丛文服务器环境下,了解丛文web视频播放控件。
|
||||
|
||||
##### 播放实时视频(请配置URL)
|
||||
|
||||
此按钮为播放实时视频,需要配合丛文服务器,需要配置从视频输出网关获取的视频拉取url。
|
||||
|
||||
##### 播放视频对讲(请配置URL)
|
||||
|
||||
此按钮为播放实时视频并提供对讲功能,需要配合丛文服务器,需要配置从视频输出网关获取的视频拉取url和对讲url。
|
||||
|
||||
##### 播放录像文件(请配置URL)
|
||||
|
||||
此按钮为回放录像文件,需要配合丛文服务器,需要配置从视频输出网关获取的录像文件拉取url。
|
||||
|
||||
|
||||
|
||||
#### 3.功能说明
|
||||
|
||||
- 实时视频
|
||||
|
||||
播放、暂停、恢复播放、监听、对讲、全屏
|
||||
|
||||
- 录像视频
|
||||
|
||||
播放、暂停、恢复播放、播放进度跳转
|
||||
|
||||
- 图片回放
|
||||
|
||||
播放、暂停、恢复播放、播放进度跳转、红点
|
||||
|
||||
|
||||
|
||||
#### 4.文件及目录说明
|
||||
|
||||
|
||||
|
||||
| 路径 | 说明 |
|
||||
| ---------------------------- | -------------------------------------- |
|
||||
| index.html | DEMO播放页面文件 |
|
||||
| /public/player/ | 播放控件脚本 |
|
||||
| /public/player/cmsplayer.js | cms播放器 |
|
||||
| /public/player/cmsparser.js | cms解封装器 |
|
||||
| /public/player/decoder.js | 解码器 |
|
||||
| /public/player/pcm-player.js | pcm播放器 |
|
||||
| /public/player/webgl.js | 图像渲染器 |
|
||||
| /public/images/ | 用到的图片文件夹 |
|
||||
| /public/js/moment.js | 播放控件用到的js文件 |
|
||||
| /public/data/ | 本地丛文格式媒体文件,用于DEMO回放演示 |
|
||||
|
||||
|
||||
|
||||
#### 5.集成及接口说明
|
||||
|
||||
1. ##### 导入player播放支持组件文件夹;
|
||||
|
||||
2. ##### 参考index.html,在播放html页面head导入需要的脚本:
|
||||
|
||||
<script src="/public/player/cmsplayer.js"></script>
|
||||
<script src="/public/player/common.js"></script>
|
||||
<script src="/public/player/pcm-player.js"></script>
|
||||
<script src="/public/player/webgl.js"></script>
|
||||
<script src="/public/player/cmstalk.js"></script>
|
||||
<script src="/public/player/alawmulaw.js"></script>
|
||||
<script src="/public/player/recorder-core.js"></script>
|
||||
<script src="/public/js/moment.js"></script>
|
||||
|
||||
3. ##### 初始化播放器控件:
|
||||
|
||||
`playerBox` 为 div id:
|
||||
|
||||
```javascript
|
||||
self.player = new Player($("#playerBox"));
|
||||
```
|
||||
|
||||
4. ##### 播放:
|
||||
|
||||
```javascript
|
||||
//url 播放地址
|
||||
//isLive 是否实时视频
|
||||
//alarmTime 告警红点时间戳
|
||||
self.player.play(url, isLive , alarmTime );
|
||||
```
|
||||
|
||||
5. ##### 暂停播放:
|
||||
|
||||
```javascript
|
||||
self.player.pause();
|
||||
```
|
||||
|
||||
6. ##### 恢复播放:
|
||||
|
||||
```javascript
|
||||
self.player.resume();
|
||||
```
|
||||
|
||||
7. ##### 停止播放:
|
||||
|
||||
```javascript
|
||||
self.player.stop();
|
||||
```
|
||||
|
||||
8. ##### 监听开始:
|
||||
|
||||
```javascript
|
||||
self.player.startListen();
|
||||
```
|
||||
|
||||
9. ##### 监听结束:
|
||||
|
||||
```javascript
|
||||
self.player.stopListen();
|
||||
```
|
||||
|
||||
10. ##### 全屏:
|
||||
|
||||
```javascript
|
||||
self.player.fullscreen();
|
||||
```
|
||||
|
||||
#### 6.运行方法
|
||||
|
||||
##### 运行整合了win版nginx的
|
||||
|
||||
直接运行nginx,然后打开浏览器,输入 http://localhost/index.html
|
||||
|
||||
##### 自己运行web服务器的
|
||||
|
||||
拷贝 相关文件到 web 网站的根目录。
|
||||
|
||||
#####
|
|
@ -0,0 +1,107 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=0" />
|
||||
<title>CMS Player</title>
|
||||
<link rel="shortcut icon" href="#" />
|
||||
<script src="./public/player/cmsplayer.js"></script>
|
||||
<script src="./public/player/common.js"></script>
|
||||
<script src="./public/player/pcm-player.js"></script>
|
||||
<script src="./public/player/webgl.js"></script>
|
||||
<script src="./public/player/cmstalk.js"></script>
|
||||
<script src="./public/player/alawmulaw.js"></script>
|
||||
<script src="./public/player/recorder-core.js"></script>
|
||||
<script src="./public/js/moment.js"></script>
|
||||
<script src="./public/js/axios.min.js"></script>
|
||||
<script src="./public/js/jquery-2.2.3.min.js"></script>
|
||||
<style>
|
||||
html,
|
||||
body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
/* padding: 30px; */
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
div {
|
||||
user-select: none;
|
||||
-ms-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-html-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
ul li {
|
||||
height: 100%;
|
||||
float: left;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
#videoTimeTrack li {
|
||||
border-right: 1px solid #ccc;
|
||||
}
|
||||
|
||||
#videoTimeTrack li:first-child {
|
||||
border-left: 1px solid #ccc;
|
||||
}
|
||||
|
||||
#playerBox {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body ontouchstart>
|
||||
<div id="playerBox"></div>
|
||||
<script type="text/javascript">
|
||||
window.onload = function () {
|
||||
self.player = new Player($("#playerBox"));
|
||||
function getParams(key) {
|
||||
var reg = new RegExp("(^|&)" + key + "=([^&]*)(&|$)");
|
||||
var r = window.location.search.substr(1).match(reg);
|
||||
if (r != null) {
|
||||
return decodeURIComponent(r[2]); // 使用 decodeURIComponent 代替 unescape
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
var locationUrl = window.location.href;
|
||||
var id = getParams("id");
|
||||
var title = getParams("title");
|
||||
let requestBody = {
|
||||
pointId: id
|
||||
}
|
||||
console.log(window.location, locationUrl, id, title);
|
||||
try {
|
||||
let url = 'http://175.6.124.250:8083/multialarm/video/preview'
|
||||
|
||||
axios({
|
||||
method: 'post',
|
||||
url,
|
||||
data: { ...requestBody }
|
||||
}).then(res => {
|
||||
console.log(res);
|
||||
var PLAYURL = res.data.data.videoUrl
|
||||
self.player.play(PLAYURL, true, "");
|
||||
|
||||
}).catch(function (error) {
|
||||
console.log(error)
|
||||
})
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
|
||||
}
|
||||
$("html>head>title").html(title);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
After Width: | Height: | Size: 413 KiB |
After Width: | Height: | Size: 239 B |
|
@ -0,0 +1 @@
|
|||
<svg t="1665647640241" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4863" width="32" height="32"><path d="M512 422.4c-70.4 0-128 57.6-128 128s57.6 128 128 128 128-57.6 128-128-57.6-128-128-128z" p-id="4864" fill="#ffffff"></path><path d="M940.8 198.4h-208V144c0-19.2-16-38.4-38.4-38.4h-368c-19.2 0-38.4 16-38.4 38.4v54.4H80c-28.8 0-51.2 22.4-51.2 51.2v620.8c0 28.8 22.4 51.2 51.2 51.2h860.8c28.8 0 51.2-22.4 51.2-51.2V249.6c0-28.8-22.4-51.2-51.2-51.2zM512 771.2c-121.6 0-220.8-99.2-220.8-220.8 0-121.6 99.2-220.8 220.8-220.8s220.8 99.2 220.8 220.8c0 121.6-99.2 220.8-220.8 220.8z m368-460.8H732.8v-35.2H880v35.2z" p-id="4865" fill="#ffffff"></path></svg>
|
After Width: | Height: | Size: 702 B |
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1646746198883" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3880" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><defs><style type="text/css"></style></defs><path d="M820.053333 205.077333a42.666667 42.666667 0 0 1 1.408 57.664l-2.538666 2.666667L562.837333 512l256.085334 246.613333a42.666667 42.666667 0 0 1-56.426667 63.893334l-2.773333-2.432L501.333333 571.221333 242.922667 820.074667a42.666667 42.666667 0 0 1-61.717334-58.816l2.538667-2.666667L439.808 512 183.744 265.386667a42.666667 42.666667 0 0 1 56.426667-63.893334l2.773333 2.432 258.368 248.832L759.744 203.925333a42.666667 42.666667 0 0 1 60.330667 1.152z" p-id="3881" fill="#ffffff"></path></svg>
|
After Width: | Height: | Size: 871 B |
|
@ -0,0 +1 @@
|
|||
<svg t="1665649555889" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2290" width="32" height="32"><path d="M511.883031 56.77603c-250.925838 0-455.090006 204.166167-455.090006 455.092005v244.611503c0 108.255456 88.059781 196.257252 196.258252 196.257252 80.037896 0 145.061751-65.020856 145.061752-145.002767V642.706536c0-79.978912-65.021856-145.061751-145.061752-145.061751a195.335496 195.335496 0 0 0-110.92975 34.643865v-20.417616c0-203.881242 165.881262-369.762504 369.760504-369.762504s369.760505 165.881262 369.760505 369.762504v20.421615a195.059568 195.059568 0 0 0-110.927752-34.643865c-79.978912 0-145.061751 65.082839-145.061751 145.061751v165.023488c0 79.978912 65.082839 145.002767 145.061751 145.002767 108.197471 0 196.258252-88.001796 196.258252-196.257252V511.871034c0.001-250.933836-204.164168-455.095004-455.090005-455.095004zM253.051277 582.976286a59.759243 59.759243 0 0 1 59.729252 59.73025v165.027487a59.711256 59.711256 0 0 1-59.729252 59.673266A111.070714 111.070714 0 0 1 142.121527 756.479538v-62.518516a111.08371 111.08371 0 0 1 110.92975-110.985736z m628.592258 173.503252A111.070714 111.070714 0 0 1 770.715784 867.408289a59.748246 59.748246 0 0 1-59.730251-59.673266V642.706536A59.796233 59.796233 0 0 1 770.715784 582.976286a111.082711 111.082711 0 0 1 110.927751 110.985736v62.518515z" p-id="2291" fill="#ffffff"></path></svg>
|
After Width: | Height: | Size: 1.4 KiB |
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1646745129934" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1383" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><defs><style type="text/css"></style></defs><path d="M768 298.666667h170.666667v85.333333h-256V128h85.333333v170.666667zM341.333333 384H85.333333V298.666667h170.666667V128h85.333333v256z m426.666667 341.333333v170.666667h-85.333333v-256h256v85.333333h-170.666667zM341.333333 640v256H256v-170.666667H85.333333v-85.333333h256z" p-id="1384" fill="#ffffff"></path></svg>
|
After Width: | Height: | Size: 688 B |
|
@ -0,0 +1 @@
|
|||
<svg id="图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 84 84"><defs><style>.cls-1{fill:#FFFFFF;}</style></defs><title>视频操作</title><path class="cls-1" d="M18,32V52a4.012,4.012,0,0,0,4,4H62a4.012,4.012,0,0,0,4-4V32a4.012,4.012,0,0,0-4-4H22A4.012,4.012,0,0,0,18,32Zm6,2H60V50H24ZM7,36a3,3,0,0,0,3-3V23a3,3,0,0,1,3-3H23a3,3,0,0,0,0-6H13a9.01,9.01,0,0,0-9,9V33A3,3,0,0,0,7,36ZM71,14H61a3,3,0,0,0,0,6H71a3,3,0,0,1,3,3V33a3,3,0,0,0,6,0V23A9.01,9.01,0,0,0,71,14Zm6,34a3,3,0,0,0-3,3V61a3,3,0,0,1-3,3H61a3,3,0,0,0,0,6H71a9.01,9.01,0,0,0,9-9V51A3,3,0,0,0,77,48ZM23,64H13a3,3,0,0,1-3-3V51a3,3,0,0,0-6,0V61a9.01,9.01,0,0,0,9,9H23a3,3,0,0,0,0-6Z"/></svg>
|
After Width: | Height: | Size: 682 B |
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1646745119141" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1430" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><defs><style type="text/css"></style></defs><path d="M213.333333 213.333333h213.333334V128H170.666667a42.666667 42.666667 0 0 0-42.666667 42.666667v256h85.333333V213.333333zM170.666667 896h256v-85.333333H213.333333v-213.333334H128v256a42.666667 42.666667 0 0 0 42.666667 42.666667z m725.333333-42.666667v-256h-85.333333v213.333334h-213.333334v85.333333h256a42.666667 42.666667 0 0 0 42.666667-42.666667zM597.333333 213.333333h213.333334v213.333334h85.333333V170.666667a42.666667 42.666667 0 0 0-42.666667-42.666667h-256v85.333333z" fill="#ffffff" p-id="1431"></path></svg>
|
After Width: | Height: | Size: 894 B |
After Width: | Height: | Size: 84 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 9.0 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 9.3 KiB |
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 23.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 64 64" style="enable-background:new 0 0 64 64;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
</style>
|
||||
<title>视频操作</title>
|
||||
<g>
|
||||
<path class="st0" d="M49.3,42.2c1.8-3,2.7-6.4,2.7-10.2v-4.6c0-0.6-0.2-1.2-0.7-1.6s-1-0.7-1.6-0.7s-1.2,0.2-1.6,0.7
|
||||
s-0.7,1-0.7,1.6V32c0,2.5-0.5,4.7-1.5,6.8L49.3,42.2z"/>
|
||||
<path class="st0" d="M31,43.5c1.7,0,3.2-0.3,4.6-0.9L19.3,26.4V32c0,3.2,1.1,5.9,3.4,8.2S27.8,43.5,31,43.5z"/>
|
||||
<path class="st0" d="M42.7,57.4h-9.3v-4.8c3.4-0.4,6.4-1.4,9.1-3.2L39,46.1c-2.4,1.4-5.1,2.1-8,2.1c-4.5,0-8.3-1.6-11.5-4.7
|
||||
c-3.2-3.2-4.8-7-4.8-11.4v-4.6c0-0.6-0.2-1.2-0.7-1.6c-0.5-0.5-1-0.7-1.6-0.7s-1.2,0.2-1.6,0.7c-0.5,0.5-0.7,1-0.7,1.6V32
|
||||
c0,5.3,1.8,9.9,5.4,13.9c3.6,3.9,8,6.2,13.3,6.8v4.8h-9.3c-0.6,0-1.2,0.2-1.6,0.7s-0.7,1-0.7,1.6s0.2,1.2,0.7,1.6s1,0.7,1.6,0.7
|
||||
h23.3c0.6,0,1.2-0.2,1.6-0.7s0.7-1,0.7-1.6s-0.2-1.2-0.7-1.6S43.3,57.4,42.7,57.4z"/>
|
||||
<path class="st0" d="M42.2,35.2c0.3-1,0.4-2.1,0.4-3.2V13.5c0-3.2-1.1-5.9-3.4-8.2S34.2,2,31,2s-6,1.1-8.2,3.4c-2,2-3.1,4.3-3.4,7
|
||||
L42.2,35.2z"/>
|
||||
</g>
|
||||
<path class="st0" d="M50.9,55.1l-42-42c-1.2-1.2-1.2-3,0-4.2l0,0c1.2-1.2,3-1.2,4.2,0L55.2,51c1.2,1.2,1.2,3,0,4.2l0,0
|
||||
C54,56.3,52.1,56.3,50.9,55.1z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.4 KiB |
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 23.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 64 64" style="enable-background:new 0 0 64 64;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
</style>
|
||||
<title>视频操作</title>
|
||||
<path class="st0" d="M52,27.4V32c0,5.3-1.8,9.9-5.4,13.9s-8,6.2-13.3,6.8v4.8h9.3c0.6,0,1.2,0.2,1.6,0.7c0.5,0.5,0.7,1,0.7,1.6
|
||||
s-0.2,1.2-0.7,1.6c-0.5,0.5-1,0.7-1.6,0.7H19.3c-0.6,0-1.2-0.2-1.6-0.7c-0.5-0.5-0.7-1-0.7-1.6s0.2-1.2,0.7-1.6
|
||||
c0.5-0.5,1-0.7,1.6-0.7h9.3v-4.8c-5.3-0.6-9.7-2.8-13.3-6.8c-3.5-4-5.3-8.6-5.3-13.9v-4.6c0-0.6,0.2-1.2,0.7-1.6
|
||||
c0.5-0.5,1-0.7,1.6-0.7s1.2,0.2,1.6,0.7c0.5,0.5,0.7,1,0.7,1.6V32c0,4.4,1.6,8.3,4.8,11.4c3.2,3.2,7,4.7,11.5,4.7s8.3-1.6,11.5-4.7
|
||||
c3.2-3.2,4.8-7,4.8-11.4v-4.6c0-0.6,0.2-1.2,0.7-1.6c0.5-0.5,1-0.7,1.6-0.7s1.2,0.2,1.6,0.7C51.8,26.2,52,26.8,52,27.4z M42.7,13.5
|
||||
V32c0,3.2-1.1,5.9-3.4,8.2c-2.3,2.3-5,3.4-8.2,3.4s-6-1.1-8.2-3.4s-3.4-5-3.4-8.2V13.5c0-3.2,1.1-5.9,3.4-8.2S27.8,2,31,2
|
||||
s6,1.1,8.2,3.4S42.7,10.4,42.7,13.5z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
|
@ -0,0 +1 @@
|
|||
<svg id="图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 84 84"><defs><style>.cls-1{fill:#FFFFFF;}</style></defs><title>视频操作</title><path class="cls-1" d="M44.269,12a4.385,4.385,0,0,0-2.5.816L23.264,27.05H16.71A7.625,7.625,0,0,0,9,34.542V49.525a7.625,7.625,0,0,0,7.71,7.491h6.554l18.5,14.234a3.387,3.387,0,0,0,2.161.75,3.96,3.96,0,0,0,4.007-3.746V15.813A3.625,3.625,0,0,0,44.269,12ZM41.936,61.779a1,1,0,0,1-1.61.792L26.922,52.26,25.3,51.016H16.71A1.634,1.634,0,0,1,15,49.525V34.542a1.634,1.634,0,0,1,1.71-1.492H25.3l1.618-1.244L40.326,21.5a1,1,0,0,1,1.61.792ZM67.78,42.845,74.125,36.5a3,3,0,0,0-4.243-4.243L63.537,38.6l-6.345-6.345A3,3,0,0,0,52.95,36.5L59.3,42.845,52.95,49.19a3,3,0,1,0,4.242,4.242l6.345-6.345,6.345,6.345a3.009,3.009,0,0,0,4.243,0h0a3.008,3.008,0,0,0,0-4.242Z"/></svg>
|
After Width: | Height: | Size: 826 B |
|
@ -0,0 +1 @@
|
|||
<svg id="图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 84 84"><defs><style>.cls-1{fill:#FFFFFF;}</style></defs><title>视频操作</title><path class="cls-1" d="M27,18a3.009,3.009,0,0,0-3,3V63a3,3,0,0,0,6,0V21A3.009,3.009,0,0,0,27,18Zm30,0a3.009,3.009,0,0,0-3,3V63a3,3,0,0,0,6,0V21A3.009,3.009,0,0,0,57,18Z"/></svg>
|
After Width: | Height: | Size: 349 B |
|
@ -0,0 +1 @@
|
|||
<svg id="图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 84 84"><defs><style>.cls-1{fill:#FFFFFF;}</style></defs><title>视频操作</title><path class="cls-1" d="M66,15H18A12.035,12.035,0,0,0,6,27V57A12.035,12.035,0,0,0,18,69H66A12.035,12.035,0,0,0,78,57V27A12.035,12.035,0,0,0,66,15Zm6,42a6.007,6.007,0,0,1-6,6H18a6.011,6.011,0,0,1-5.877-4.787l12.934-11.3a3.051,3.051,0,0,1,.976-.476,1.315,1.315,0,0,1,.319-.046.8.8,0,0,1,.595.308c2.918,2.919,6.069,6.484,6.186,6.616a5.184,5.184,0,0,0,3.538,1.855c.1.007.209.011.32.011a5.27,5.27,0,0,0,3.749-1.655c.675-.649,10.811-10.129,14.608-13.666l.115-.116a3.742,3.742,0,0,1,2.235-1.06,2.742,2.742,0,0,1,1.877,1.04C62.048,42.329,68.2,51.055,72,56.7Zm0-10.483a96.045,96.045,0,0,0-8.045-10.945,8.538,8.538,0,0,0-6.27-2.922,9.745,9.745,0,0,0-6.5,2.834c-.885.823-11.464,10.7-14.107,13.2-1.888-2.115-3.856-4.212-5.854-6.238a6.787,6.787,0,0,0-6.953-1.777A8.755,8.755,0,0,0,21.313,42.2l-.056.035L12,50.219V27a6.007,6.007,0,0,1,6-6H66a6.007,6.007,0,0,1,6,6ZM25,26a4,4,0,1,0,4,4A4,4,0,0,0,25,26Z"/></svg>
|
After Width: | Height: | Size: 1.0 KiB |
|
@ -0,0 +1 @@
|
|||
<svg id="图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 84 84"><defs><style>.cls-1{fill:#FFFFFF;}</style></defs><title>视频操作</title><path class="cls-1" d="M27,22.264,55.5,42,27,61.736V22.264M25.565,15A4.394,4.394,0,0,0,21,19.211V64.789A4.394,4.394,0,0,0,25.565,69a4.722,4.722,0,0,0,2.707-.847L61.179,45.364a4.018,4.018,0,0,0,0-6.728L28.272,15.847A4.722,4.722,0,0,0,25.565,15Z"/></svg>
|
After Width: | Height: | Size: 424 B |
|
@ -0,0 +1 @@
|
|||
<svg id="图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 84 84"><defs><style>.cls-1{fill:#FFFFFF;}</style></defs><title>视频操作</title><path class="cls-1" d="M73.4,40.52a3.12,3.12,0,0,0-3.138,3.094v.922a17.223,17.223,0,0,1-17.23,17.178H19.262v-6.7a.4.4,0,0,0-.239-.361.433.433,0,0,0-.46.064l-11.424,9.8a.388.388,0,0,0,0,.594L18.565,74.9a.429.429,0,0,0,.279.1.434.434,0,0,0,.179-.039.4.4,0,0,0,.239-.356v-6.7h33.77a23.463,23.463,0,0,0,23.5-23.371v-.922A3.118,3.118,0,0,0,73.4,40.52Zm3.462-21.626L65.435,9.1a.433.433,0,0,0-.279-.1.438.438,0,0,0-.178.038.4.4,0,0,0-.239.354v6.7H30.968a23.463,23.463,0,0,0-23.5,23.371v.921a3.135,3.135,0,0,0,6.269,0v-.921a17.225,17.225,0,0,1,17.23-17.179H64.739v6.7a.4.4,0,0,0,.241.36.415.415,0,0,0,.177.039.428.428,0,0,0,.277-.1l11.425-9.8a.4.4,0,0,0,.141-.3A.393.393,0,0,0,76.862,18.894ZM33.607,38.067a3.151,3.151,0,0,1-1.3-.281l-3.715-1.664-.49,4.041A14.237,14.237,0,1,0,42.229,27.727a14.3,14.3,0,0,0-4.677.783l-3.9,1.347,2.484,3.3a3.023,3.023,0,0,1,.618,1.827A3.121,3.121,0,0,1,33.607,38.067Zm9.147-3.088a8.973,8.973,0,0,0-.085-1.241,8.128,8.128,0,1,1-8.368,10.3A9.125,9.125,0,0,0,42.754,34.979Z"/></svg>
|
After Width: | Height: | Size: 1.1 KiB |
|
@ -0,0 +1 @@
|
|||
<svg id="图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 84 84"><defs><style>.cls-1{fill:#FFFFFF;}</style></defs><title>视频操作</title><path class="cls-1" d="M59.818,17.687a2.887,2.887,0,0,0-3.936,1.092A3.1,3.1,0,0,0,57.287,22.6,20.827,20.827,0,0,1,69.1,42.273a20.949,20.949,0,0,1-12.09,19.4,2.382,2.382,0,0,0-1.124,3.552,2.887,2.887,0,0,0,3.936,1.092,27.059,27.059,0,0,0,0-48.626Zm3.374,24.257a15.4,15.4,0,0,0-5.624-12.02,3.078,3.078,0,0,0-3.936.273,2.587,2.587,0,0,0,0,3.825,10.5,10.5,0,0,1,0,16.391c-1.124.819-1.124,2.732,0,3.278a2.77,2.77,0,0,0,3.936.273A15.4,15.4,0,0,0,63.192,41.944ZM44.269,12a4.385,4.385,0,0,0-2.5.816L23.264,27.05H16.71A7.625,7.625,0,0,0,9,34.542V49.525a7.625,7.625,0,0,0,7.71,7.491h6.554l18.5,14.234a3.387,3.387,0,0,0,2.161.75,3.96,3.96,0,0,0,4.007-3.746V15.813A3.625,3.625,0,0,0,44.269,12ZM41.936,61.779a1,1,0,0,1-1.61.792L26.922,52.26,25.3,51.016H16.71A1.634,1.634,0,0,1,15,49.525V34.542a1.634,1.634,0,0,1,1.71-1.492H25.3l1.618-1.244L40.326,21.5a1,1,0,0,1,1.61.792Z"/></svg>
|
After Width: | Height: | Size: 1.0 KiB |
|
@ -0,0 +1,5 @@
|
|||
(function(d,e){"object"===typeof exports&&"undefined"!==typeof module?e(exports):"function"===typeof define&&define.amd?define(["exports"],e):(d=d||self,e(d.alawmulaw={}))})(this,function(d){function e(a){a=-32768==a?-32767:a;var c=~a>>8&128;c||(a*=-1);32635<a&&(a=32635);if(256<=a){var b=k[a>>8&127];a=b<<4|a>>b+3&15}else a>>=4;return a^c^85}function f(a){var c=0;a^=85;a&128&&(a&=-129,c=-1);var b=((a&240)>>4)+4;a=4!=b?1<<b|(a&15)<<b-4|1<<b-5:a<<1|1;return-8*(0===c?a:-a)}function g(a){var c=a>>8&128;
|
||||
0!=c&&(a=-a);a+=132;32635<a&&(a=32635);var b=l[a>>7&255];return~(c|b<<4|a>>b+3&15)}function h(a){a=~a;var c=a>>4&7;c=m[c]+((a&15)<<c+3);0!=(a&128)&&(c=-c);return c}var k=[1,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7],n=Object.freeze({__proto__:null,encodeSample:e,decodeSample:f,encode:function(a){for(var c=
|
||||
new Uint8Array(a.length),b=0;b<a.length;b++)c[b]=e(a[b]);return c},decode:function(a){for(var c=new Int16Array(a.length),b=0;b<a.length;b++)c[b]=f(a[b]);return c}}),l=[0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
||||
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7],m=[0,132,396,924,1980,4092,8316,16764],p=Object.freeze({__proto__:null,encodeSample:g,decodeSample:h,encode:function(a){for(var c=new Uint8Array(a.length),b=0;b<a.length;b++)c[b]=g(a[b]);return c},decode:function(a){for(var c=new Int16Array(a.length),b=0;b<a.length;b++)c[b]=h(a[b]);return c}});d.alaw=n;d.mulaw=p;Object.defineProperty(d,
|
||||
"__esModule",{value:!0})});
|
|
@ -0,0 +1,234 @@
|
|||
function CmsTalk() {
|
||||
this.wasmLoaded = false;
|
||||
this.logger = new Logger("CmsTalk");
|
||||
this.urlBufferBuffer = null
|
||||
this.audioCache = null
|
||||
this.localAudioStream = null
|
||||
this.ws = null
|
||||
this.mediaRecorder = null
|
||||
this.audioBuffer = null
|
||||
|
||||
this.rec = null
|
||||
// this.recBlob = null;
|
||||
/**调用open打开录音请求好录音权限**/
|
||||
|
||||
this.RecorderOpen()
|
||||
}
|
||||
|
||||
CmsTalk.prototype.RecorderOpen = function () {
|
||||
|
||||
//recOpen我们可以选择性的弹一个对话框:为了防止移动端浏览器存在第三种情况:用户忽略,并且(或者国产系统UC系)浏览器没有任何回调
|
||||
var showDialog = function () {
|
||||
if (!/mobile/i.test(navigator.userAgent)) {
|
||||
return //只在移动端开启没有权限请求的检测
|
||||
}
|
||||
dialogCancel()
|
||||
|
||||
//显示弹框,应该使用自己的弹框方式
|
||||
var div = document.createElement("div")
|
||||
document.body.appendChild(div)
|
||||
div.innerHTML =
|
||||
"" +
|
||||
'<div class="waitDialog" style="z-index:99999;width:100%;height:100%;top:0;left:0;position:fixed;background:rgba(0,0,0,0.3);">' +
|
||||
'<div style="display:flex;height:100%;align-items:center;">' +
|
||||
'<div style="flex:1;"></div>' +
|
||||
'<div style="width:240px;background:#fff;padding:15px 20px;border-radius: 10px;">' +
|
||||
'<div style="padding-bottom:10px;">录音功能需要麦克风权限,请允许;如果未看到任何请求,请点击忽略~</div>' +
|
||||
'<div style="text-align:center;"><a onclick="waitDialogClick()" style="color:#0B1">忽略</a></div>' +
|
||||
"</div>" +
|
||||
'<div style="flex:1;"></div>' +
|
||||
"</div>" +
|
||||
"</div>"
|
||||
}
|
||||
var createDelayDialog = function () {
|
||||
dialogInt = setTimeout(function () {
|
||||
//定时8秒后打开弹窗,用于监测浏览器没有发起权限请求的情况,在open前放置定时器利于收到了回调能及时取消(不管open是同步还是异步回调的)
|
||||
showDialog()
|
||||
}, 8000)
|
||||
}
|
||||
var dialogInt
|
||||
var dialogCancel = function () {
|
||||
clearTimeout(dialogInt)
|
||||
|
||||
//关闭弹框,应该使用自己的弹框方式
|
||||
var elems = document.querySelectorAll(".waitDialog")
|
||||
for (var i = 0; i < elems.length; i++) {
|
||||
elems[i].parentNode.removeChild(elems[i])
|
||||
}
|
||||
}
|
||||
//recOpen弹框End
|
||||
|
||||
var formatMs = function (ms, all) {
|
||||
var f = Math.floor(ms / 60000),
|
||||
m = Math.floor(ms / 1000) % 60
|
||||
var s =
|
||||
(all || f > 0 ? (f < 10 ? "0" : "") + f + ":" : "") +
|
||||
(all || f > 0 || m > 0 ? ("0" + m).substr(-2) + "″" : "") +
|
||||
("00" + (ms % 1000)).substr(-3)
|
||||
return s
|
||||
}
|
||||
// var recOpen = function () {//一般在显示出录音按钮或相关的录音界面时进行此方法调用,后面用户点击开始录音时就能畅通无阻了
|
||||
this.newRec = Recorder({
|
||||
type: "pcm", sampleRate: 8000, bitRate: 16 //mp3格式,指定采样率hz、比特率kbps,其他参数使用默认配置;注意:是数字的参数必须提供数字,不要用字符串;需要使用的type类型,需提前把格式支持文件加载进来,比如使用wav格式需要提前加载wav.js编码引擎
|
||||
, onProcess: function (buffers, powerLevel, bufferDuration, bufferSampleRate, newBufferIdx, asyncEnd) {
|
||||
newBufferIdx = 0
|
||||
var newChunkInfo = Recorder.SampleData(buffers, 48000, 8000, this.prevChunkInfo);
|
||||
this.sendAudioData(newChunkInfo.data)
|
||||
this.prevChunkInfo = newChunkInfo
|
||||
for (let index = buffers.length - 1; index >= 0; index--) {
|
||||
buffers[index] = null;
|
||||
}
|
||||
}.bind(this)
|
||||
});
|
||||
|
||||
// createDelayDialog(); //我们可以选择性的弹一个对话框:为了防止移动端浏览器存在第三种情况:用户忽略,并且(或者国产系统UC系)浏览器没有任何回调,此处demo省略了弹窗的代码
|
||||
|
||||
|
||||
window.waitDialogClick = function () {
|
||||
dialogCancel();
|
||||
console.log("打开失败:权限请求被忽略,<span style='color:#f00'>用户主动点击的弹窗</span>", 1);
|
||||
};
|
||||
// };
|
||||
}
|
||||
|
||||
//打开麦克风授权获得相关资源
|
||||
CmsTalk.prototype.open = function (callback) {
|
||||
// dialogCancel(); //如果开启了弹框,此处需要取消
|
||||
if (this.rec){
|
||||
console.log("已打开录音设备,可以点击录制开始录音了", 2);
|
||||
callback(null)
|
||||
return
|
||||
}
|
||||
|
||||
this.newRec.open(function () {
|
||||
this.rec = this.newRec;
|
||||
console.log("已打开录音设备,可以点击录制开始录音了", 2);
|
||||
callback()
|
||||
}.bind(this), function (msg, isUserNotAllow) {
|
||||
//用户拒绝未授权或不支持
|
||||
// dialogCancel(); //如果开启了弹框,此处需要取消
|
||||
var log = (isUserNotAllow ? "UserNotAllow," : "") + "打开录音失败:" + msg;
|
||||
console.log(log);
|
||||
callback(log)
|
||||
})
|
||||
}
|
||||
|
||||
/**关闭录音,释放资源**/
|
||||
CmsTalk.prototype.recClose = function () {
|
||||
if (this.rec) {
|
||||
this.rec.close();
|
||||
this.rec = null
|
||||
console.log("已关闭");
|
||||
} else {
|
||||
console.log("未打开录音", 1);
|
||||
};
|
||||
};
|
||||
|
||||
/**开始录音**/
|
||||
CmsTalk.prototype.recStart = function () {//打开了录音后才能进行start、stop调用
|
||||
this.prevChunkInfo = null
|
||||
if (this.rec && Recorder.IsOpen()) {
|
||||
// this.recBlob = null;
|
||||
this.rec.start();
|
||||
console.log("已开始录音...");
|
||||
} else {
|
||||
console.log("未打开录音", 1);
|
||||
};
|
||||
};
|
||||
|
||||
/**暂停录音**/
|
||||
CmsTalk.prototype.recPause = function () {
|
||||
if (this.rec && Recorder.IsOpen()) {
|
||||
this.rec.pause();
|
||||
} else {
|
||||
console.log("未打开录音", 1);
|
||||
};
|
||||
};
|
||||
/**恢复录音**/
|
||||
CmsTalk.prototype.recResume = function () {
|
||||
if (this.rec && Recorder.IsOpen()) {
|
||||
this.rec.resume();
|
||||
} else {
|
||||
console.log("未打开录音", 1);
|
||||
};
|
||||
};
|
||||
|
||||
/**结束录音,得到音频文件**/
|
||||
CmsTalk.prototype.recStop = function () {
|
||||
if (!(this.rec && Recorder.IsOpen())) {
|
||||
console.log("未打开录音", 1);
|
||||
return;
|
||||
};
|
||||
this.rec.stop(null, null);
|
||||
};
|
||||
|
||||
CmsTalk.prototype.startTalk = function (url, callback) {
|
||||
this.open((err) => {
|
||||
if (err) {
|
||||
callback(err)
|
||||
} else {
|
||||
if (url.indexOf("http") != -1) {
|
||||
//方式1,可手动修改talk-server对应的地址
|
||||
this.ws = new WebSocket("ws://192.168.0.215:3000");
|
||||
this.ws.onmessage = function (msg) {
|
||||
console.log(msg);
|
||||
};
|
||||
this.ws.onopen = (ev) => {
|
||||
console.log("open")
|
||||
this.ws.send(url)
|
||||
|
||||
this.recStart()
|
||||
if (callback)
|
||||
callback(null)
|
||||
}
|
||||
}
|
||||
else {
|
||||
//方式2
|
||||
this.ws = new WebSocket(url);
|
||||
this.ws.onmessage = function (msg) {
|
||||
console.log(msg);
|
||||
};
|
||||
this.ws.onopen = (ev) => {
|
||||
console.log("open")
|
||||
this.recStart()
|
||||
if (callback)
|
||||
callback(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
|
||||
CmsTalk.prototype.stopTalk = function () {
|
||||
if (this.ws) {
|
||||
this.ws.close();
|
||||
this.ws = null
|
||||
}
|
||||
if (this.audioBuffer) {
|
||||
delete this.audioBuffer
|
||||
this.audioBuffer = null
|
||||
}
|
||||
this.recStop()
|
||||
// this.recClose()
|
||||
}
|
||||
|
||||
CmsTalk.prototype.sendAudioData = function (samples) {
|
||||
var u8Data = alawmulaw.alaw.encode(samples);
|
||||
if (!this.audioBuffer)
|
||||
this.audioBuffer = new Uint8Array([])
|
||||
|
||||
var tmpBuffer = new Uint8Array(this.audioBuffer.byteLength + u8Data.byteLength)
|
||||
tmpBuffer.set(this.audioBuffer, 0)
|
||||
tmpBuffer.set(u8Data, this.audioBuffer.byteLength)
|
||||
while (tmpBuffer.byteLength >= 480) {
|
||||
var d480 = tmpBuffer.subarray(0, 480);
|
||||
tmpBuffer = tmpBuffer.subarray(480);
|
||||
console.log("reserve ", tmpBuffer.length)
|
||||
if (this.ws)
|
||||
this.ws.send(d480)
|
||||
}
|
||||
this.audioBuffer = tmpBuffer
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
//Player request.
|
||||
const kCloseDecoderReq = 0;
|
||||
const kOpenDecoderReq = 1;
|
||||
const kRequestHeaderReq = 2;
|
||||
const kRequestBodyReq = 3;
|
||||
const kPauseGetUrlReq = 4;
|
||||
const kResumeGetUrlReq = 5;
|
||||
const kRequestLiveReq = 6;
|
||||
const kDecodeVideo = 7;
|
||||
|
||||
//CMSParser response.
|
||||
const kCMSHeaderRes = 8;
|
||||
const kVideoFrame = 9;
|
||||
const kAudioFrame = 10;
|
||||
const kImageFrame = 11;
|
||||
const kFinishDownload = 12;
|
||||
const kVideoBuffer = 13;
|
||||
const kCmsPartHeader = 14;
|
||||
|
||||
function Logger(module) {
|
||||
this.module = module;
|
||||
}
|
||||
|
||||
Logger.prototype.log = function (line) {
|
||||
console.log("[" + this.currentTimeStr() + "][" + this.module + "]" + line);
|
||||
}
|
||||
|
||||
Logger.prototype.logError = function (line) {
|
||||
// console.log("[" + this.currentTimeStr() + "][" + this.module + "][ER] " + line);
|
||||
}
|
||||
|
||||
Logger.prototype.logInfo = function (line) {
|
||||
// console.log("[" + this.currentTimeStr() + "][" + this.module + "][IF] " + line);
|
||||
}
|
||||
|
||||
Logger.prototype.logDebug = function (line) {
|
||||
// console.log("[" + this.currentTimeStr() + "][" + this.module + "][DT] " + line);
|
||||
}
|
||||
|
||||
Logger.prototype.currentTimeStr = function () {
|
||||
var now = new Date(Date.now());
|
||||
var year = now.getFullYear();
|
||||
var month = now.getMonth() + 1;
|
||||
var day = now.getDate();
|
||||
var hour = now.getHours();
|
||||
var min = now.getMinutes();
|
||||
var sec = now.getSeconds();
|
||||
var ms = now.getMilliseconds();
|
||||
return year + "-" + month + "-" + day + " " + hour + ":" + min + ":" + sec + ":" + ms;
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
prefix=/home/weixin/player3/ffmpeg/../WasmVideoPlayer-master/dist
|
||||
exec_prefix=${prefix}
|
||||
libdir=${prefix}/lib
|
||||
includedir=${prefix}/include
|
||||
|
||||
Name: libavcodec
|
||||
Description: FFmpeg codec library
|
||||
Version: 57.89.100
|
||||
Requires: libavutil >= 55.58.100
|
||||
Requires.private:
|
||||
Conflicts:
|
||||
Libs: -L${libdir} -lavcodec -s USE_SDL=2 -lm -pthreads
|
||||
Libs.private:
|
||||
Cflags: -I${includedir}
|
|
@ -0,0 +1,14 @@
|
|||
prefix=/home/weixin/player3/ffmpeg/../WasmVideoPlayer-master/dist
|
||||
exec_prefix=${prefix}
|
||||
libdir=${prefix}/lib
|
||||
includedir=${prefix}/include
|
||||
|
||||
Name: libavformat
|
||||
Description: FFmpeg container format library
|
||||
Version: 57.71.100
|
||||
Requires: libavcodec >= 57.89.100, libavutil >= 55.58.100
|
||||
Requires.private:
|
||||
Conflicts:
|
||||
Libs: -L${libdir} -lavformat -s USE_SDL=2 -lm -pthreads
|
||||
Libs.private:
|
||||
Cflags: -I${includedir}
|
|
@ -0,0 +1,14 @@
|
|||
prefix=/home/weixin/player3/ffmpeg/../WasmVideoPlayer-master/dist
|
||||
exec_prefix=${prefix}
|
||||
libdir=${prefix}/lib
|
||||
includedir=${prefix}/include
|
||||
|
||||
Name: libavutil
|
||||
Description: FFmpeg utility library
|
||||
Version: 55.58.100
|
||||
Requires:
|
||||
Requires.private:
|
||||
Conflicts:
|
||||
Libs: -L${libdir} -lavutil -lm
|
||||
Libs.private:
|
||||
Cflags: -I${includedir}
|
|
@ -0,0 +1,14 @@
|
|||
prefix=/home/weixin/player3/ffmpeg/../WasmVideoPlayer-master/dist
|
||||
exec_prefix=${prefix}
|
||||
libdir=${prefix}/lib
|
||||
includedir=${prefix}/include
|
||||
|
||||
Name: libswresample
|
||||
Description: FFmpeg audio resampling library
|
||||
Version: 2.7.100
|
||||
Requires: libavutil >= 55.58.100
|
||||
Requires.private:
|
||||
Conflicts:
|
||||
Libs: -L${libdir} -lswresample -lm
|
||||
Libs.private:
|
||||
Cflags: -I${includedir}
|
|
@ -0,0 +1,14 @@
|
|||
prefix=/home/weixin/player3/ffmpeg/../WasmVideoPlayer-master/dist
|
||||
exec_prefix=${prefix}
|
||||
libdir=${prefix}/lib
|
||||
includedir=${prefix}/include
|
||||
|
||||
Name: libswscale
|
||||
Description: FFmpeg image rescaling library
|
||||
Version: 4.6.100
|
||||
Requires: libavutil >= 55.58.100
|
||||
Requires.private:
|
||||
Conflicts:
|
||||
Libs: -L${libdir} -lswscale -lm
|
||||
Libs.private:
|
||||
Cflags: -I${includedir}
|
|
@ -0,0 +1,377 @@
|
|||
function CmsParser() {
|
||||
this.CMS_FLAG_FORMAT_FOUND = 0x01;
|
||||
this.CMS_FLAG_TRACK_FOUND = 0x02;
|
||||
this.CMS_FLAG_STOP_WHEN_ERROR = 0x04;
|
||||
|
||||
this.CMS_PART_UNKNOWN = 'na';
|
||||
this.CMS_PART_H264_i_FRAME = 'i';
|
||||
this.CMS_PART_H264_p_FRAME = 'p';
|
||||
this.CMS_PART_AUDIO = 'a';
|
||||
this.CMS_PART_JPG = 'j';
|
||||
|
||||
|
||||
this.CMS_E_HEADER_FIELD = 0;
|
||||
this.CMS_E_HEADER_END = 1;
|
||||
this.CMS_E_PART_HEADER = 2;
|
||||
this.CMS_E_PART_HEADER_FIELD = 3;
|
||||
this.CMS_E_PART_HEADER_END = 4;
|
||||
this.CMS_E_PART_END = 5;
|
||||
this.CMS_E_CHUNK = 6;
|
||||
this.CMS_E_PARSE_FAIL = 7;
|
||||
|
||||
|
||||
|
||||
this.CMS_HEADER = 0;
|
||||
this.CMS_DETECT_BOUNDARY = 1;
|
||||
this.CMS_PART_HEADER = 2;
|
||||
this.CMS_FINISHED = 3;
|
||||
this.CMS_FAIL = 4;
|
||||
|
||||
this.flag = 0;
|
||||
this.shift = 0;
|
||||
|
||||
this.line_buf = new Uint8Array(2000);
|
||||
this.line_buf_ptr = 0;
|
||||
this.state = this.CMS_HEADER;
|
||||
|
||||
this.cache = new Uint8Array(100); // for boundary
|
||||
this.cached_len = 0;
|
||||
|
||||
this.is_first_part = true;
|
||||
this.callback_context = null;
|
||||
this.callback = null;
|
||||
|
||||
this.boundary = null;
|
||||
this.boundary_size = 0;
|
||||
this.boundary_ptr = 0;
|
||||
|
||||
// boundary = strdup("\r\n----asdfasdf\r\n");
|
||||
// boundary.length = strlen(boundary);
|
||||
this._header = {
|
||||
hasAudio: false,
|
||||
hasVideo: false
|
||||
};
|
||||
this.parts = [];
|
||||
this.part = {
|
||||
header: {},
|
||||
shift: 0,
|
||||
chunks: []
|
||||
};
|
||||
};
|
||||
|
||||
CmsParser.prototype.fail = function (error) {
|
||||
this.emit(this.CMS_E_PARSE_FAIL, error);
|
||||
if (this.flag & this.CMS_FLAG_STOP_WHEN_ERROR) {
|
||||
this.state = this.CMS_FAIL;
|
||||
return true;
|
||||
} else {
|
||||
this.state = this.CMS_DETECT_BOUNDARY;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
CmsParser.prototype.parse = function (data) {
|
||||
var chunk = 0;
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
var ch = data[i];
|
||||
ch = String.fromCharCode(ch);
|
||||
this.shift++;
|
||||
switch (this.state) {
|
||||
case this.CMS_FAIL: {
|
||||
if (this.fail("CmsParser parse stoped.")) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
};
|
||||
case this.CMS_HEADER: {
|
||||
if (ch === '\r') {
|
||||
} else if (ch === '\n') {
|
||||
if (this.line_buf_ptr === 0) {
|
||||
this.emit(this.CMS_E_HEADER_END);
|
||||
if (!this.boundary) {
|
||||
if (this.fail("Boundary not found.")) {
|
||||
return;
|
||||
}
|
||||
} else if (!(this.flag & this.CMS_FLAG_FORMAT_FOUND)) {
|
||||
if (this.fail("Format not found.")) {
|
||||
return;
|
||||
}
|
||||
} else if (!(this.flag & this.CMS_FLAG_TRACK_FOUND)) {
|
||||
if (this.fail("Track not found.")) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
this.state = this.CMS_DETECT_BOUNDARY;
|
||||
this.boundary_ptr = 2;
|
||||
chunk = i + 1;
|
||||
}
|
||||
} else {
|
||||
var s = String.fromCharCode.apply(null, this.line_buf.slice(0, this.line_buf_ptr));
|
||||
s = s.split(":");
|
||||
var key = s.shift().trim();
|
||||
var value = s.join(":").trim();
|
||||
// console.log("cms header:", key, '=', value);
|
||||
if (key && value) {
|
||||
if (key === "boundary") {
|
||||
this.boundary = "\r\n--" + value + "\r\n";
|
||||
} else if (key === "format" && value === "cms") {
|
||||
this.flag = this.flag | this.CMS_FLAG_FORMAT_FOUND;
|
||||
} else if (key === "track") {
|
||||
this.flag = this.flag | this.CMS_FLAG_TRACK_FOUND;
|
||||
}
|
||||
var kv = {
|
||||
key: key,
|
||||
value: value
|
||||
};
|
||||
this.emit(this.CMS_E_HEADER_FIELD, kv);
|
||||
} else {
|
||||
if (this.fail("Invalid key value.")) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.line_buf_ptr = 0;
|
||||
this.line_buf.fill(0);
|
||||
} else {
|
||||
this.line_buf[this.line_buf_ptr] = ch.charCodeAt(0);
|
||||
this.line_buf_ptr++;
|
||||
}
|
||||
break;
|
||||
};
|
||||
case this.CMS_DETECT_BOUNDARY: {
|
||||
if (!this.boundary) {
|
||||
break;
|
||||
}
|
||||
if (ch == this.boundary[this.boundary_ptr]) {
|
||||
this.boundary_ptr++;
|
||||
} else if (this.boundary_ptr == 1 && ch == this.boundary[this.boundary_ptr - 1]) {
|
||||
|
||||
} else {
|
||||
if (this.cached_len > 0) {
|
||||
this.emit(this.CMS_E_CHUNK, this.cache.slice(0, this.cached_len));
|
||||
this.cached_len = 0;
|
||||
}
|
||||
this.boundary_ptr = 0;
|
||||
}
|
||||
if (this.boundary_ptr === this.boundary.length) {
|
||||
if (i - chunk >= (this.boundary.length - this.cached_len)) {
|
||||
var chunk_len = i - chunk - (this.boundary.length - this.cached_len) + 1;
|
||||
this.emit(this.CMS_E_CHUNK, data.slice(chunk, chunk + chunk_len));
|
||||
}
|
||||
this.cached_len = 0;
|
||||
if (this.is_first_part) {
|
||||
this.is_first_part = false;
|
||||
} else {
|
||||
this.emit(this.CMS_E_PART_END);
|
||||
}
|
||||
this.emit(this.CMS_E_PART_HEADER);
|
||||
|
||||
this.state = this.CMS_PART_HEADER;
|
||||
this.part = {
|
||||
header: {
|
||||
type: this.CMS_PART_UNKNOWN,
|
||||
track: -1,
|
||||
length: 0,
|
||||
ts: -1
|
||||
},
|
||||
shift: this.shift,
|
||||
chunks: []
|
||||
}
|
||||
chunk = i + 1;
|
||||
this.boundary_ptr = 0;
|
||||
this.line_buf_ptr = 0;
|
||||
this.line_buf[0] = 0;
|
||||
}
|
||||
break;
|
||||
};
|
||||
case this.CMS_PART_HEADER: {
|
||||
if (ch == '\r') {
|
||||
} else if (ch == '\n') {
|
||||
if (this.line_buf_ptr == 0) {
|
||||
this.emit(this.CMS_E_PART_HEADER_END);
|
||||
this.state = this.CMS_DETECT_BOUNDARY;
|
||||
chunk = i + 1;
|
||||
} else {
|
||||
var s = String.fromCharCode.apply(null, this.line_buf.slice(0, this.line_buf_ptr)).split(":");
|
||||
var key = s.shift().trim();
|
||||
var value = s.join(":").trim();
|
||||
// console.log("part header:", key, '=', value);
|
||||
if (key && value) {
|
||||
if (key === "f") {
|
||||
if (value === "i") {
|
||||
this.part.header.type = this.CMS_PART_H264_i_FRAME;
|
||||
} else if (value === "p") {
|
||||
this.part.header.type = this.CMS_PART_H264_p_FRAME;
|
||||
} else if (value === "a") {
|
||||
this.part.header.type = this.CMS_PART_AUDIO;
|
||||
} else if (value === "j") {
|
||||
this.part.header.type = this.CMS_PART_JPG;
|
||||
} else {
|
||||
console.error("Unknown frame type:", value);
|
||||
}
|
||||
} else if (key === "ts") {
|
||||
this.part.header.ts = parseInt(value, 10);
|
||||
} else if (key === "l") {
|
||||
this.part.header.length = parseInt(value, 10);
|
||||
} else if (key === "t") {
|
||||
this.part.header.track = parseInt(value, 10);
|
||||
}
|
||||
var kv = {
|
||||
key: key,
|
||||
value: value
|
||||
};
|
||||
this.emit(this.CMS_E_PART_HEADER_FIELD, kv);
|
||||
} else {
|
||||
if (this.fail("Part header Invalid key value.")) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.line_buf_ptr = 0;
|
||||
this.line_buf.fill(0);
|
||||
} else {
|
||||
if (this.line_buf_ptr < this.line_buf.length - 1) {
|
||||
this.line_buf[this.line_buf_ptr] = ch.charCodeAt(0);
|
||||
this.line_buf_ptr++;
|
||||
} else {
|
||||
if (this.fail("Part header line too long.")) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
};
|
||||
}
|
||||
}
|
||||
if (this.state == this.CMS_DETECT_BOUNDARY) {
|
||||
if (chunk < data.length) {
|
||||
if (this.boundary_ptr > 0) {
|
||||
this.cached_len = this.boundary_ptr;
|
||||
var pos = data.length - this.boundary_ptr;
|
||||
if (pos >= 0) {
|
||||
this.cache = data.slice(pos, this.cached_len);
|
||||
}
|
||||
}
|
||||
this.emit(this.CMS_E_CHUNK, data.slice(chunk, chunk + data.length - chunk - this.boundary_ptr));
|
||||
}
|
||||
}
|
||||
};
|
||||
CmsParser.prototype.set_callback = function (cb, context) {
|
||||
this.callback = cb;
|
||||
this.callback_context = context;
|
||||
};
|
||||
CmsParser.prototype.emit = function (e, data, size) {
|
||||
if (this.callback) {
|
||||
return this.callback(this, e, data, size, this.callback_context);
|
||||
} else {
|
||||
this.cache_data(e, data);
|
||||
}
|
||||
};
|
||||
|
||||
CmsParser.prototype.cache_data = function (e, data) {
|
||||
switch (e) {
|
||||
case this.CMS_E_HEADER_FIELD: {
|
||||
var key = data.key;
|
||||
var value = data.value;
|
||||
this._header[key] = value;
|
||||
if (key === 'track') {
|
||||
var tracks = value.split(';');
|
||||
this._header.tracks = [];
|
||||
for (var t = 0; t < tracks.length; t++) {
|
||||
var fields = tracks[t].split(',');
|
||||
var track = {};
|
||||
for (var j = 0; j < fields.length; j++) {
|
||||
var f = fields[j].split('=');
|
||||
var key = f.shift();
|
||||
var value = f.join('=');
|
||||
track[key] = value;
|
||||
if (key === 'codec') {
|
||||
if (value === 'alaw') {
|
||||
this._header.hasAudio = true;
|
||||
this._header.audioTrack = track;
|
||||
} else if (value === 'h264') {
|
||||
this._header.hasVideo = true;
|
||||
this._header.videoTrack = track;
|
||||
}
|
||||
}
|
||||
}
|
||||
this._header.tracks.push(track);
|
||||
}
|
||||
} else if (key === "duration") {
|
||||
this._header.duration = parseInt(value, 10);
|
||||
}
|
||||
break;
|
||||
};
|
||||
case this.CMS_E_HEADER_END: {
|
||||
this.header = this._header;
|
||||
break;
|
||||
};
|
||||
case this.CMS_E_PART_HEADER: {
|
||||
break;
|
||||
};
|
||||
case this.CMS_E_PART_HEADER_FIELD: {
|
||||
break;
|
||||
};
|
||||
case this.CMS_E_PART_HEADER_END: {
|
||||
break;
|
||||
};
|
||||
case this.CMS_E_PART_END: {
|
||||
var chunks = this.part.chunks;
|
||||
var size = 0;
|
||||
for (var i = 0; i < chunks.length; i++) {
|
||||
size = size + chunks[i].length;
|
||||
}
|
||||
this.part.data = new ArrayBuffer(size);
|
||||
var data = new Uint8Array(this.part.data);
|
||||
var shift = 0;
|
||||
for (var i = 0; i < chunks.length; i++) {
|
||||
data.set(chunks[i], shift);
|
||||
shift = shift + chunks[i].length;
|
||||
}
|
||||
this.parts.push(this.part);
|
||||
break;
|
||||
};
|
||||
case this.CMS_E_CHUNK: {
|
||||
this.part.chunks.push(data);
|
||||
break;
|
||||
};
|
||||
case this.CMS_E_PARSE_FAIL: {
|
||||
break;
|
||||
};
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = CmsParser;
|
||||
// var cms = new CmsParser();
|
||||
|
||||
// var fs = require('fs');
|
||||
// var f = fs.createReadStream("/home/gxy/work/cms/cms/tmp/ttt.cms");
|
||||
// f.on('end', function (err) {
|
||||
// console.log("end");
|
||||
// });
|
||||
// f.on('error', function (err) {
|
||||
// console.error(err);
|
||||
// });
|
||||
// f.on('data', function (chunk) {
|
||||
// cms.parse(chunk);
|
||||
// if (cms.header) {
|
||||
// console.log(cms.header);
|
||||
// cms.header = null;
|
||||
// }
|
||||
// var parts = cms.parts;
|
||||
// while (parts.length > 0) {
|
||||
// var part = parts.shift();
|
||||
// console.log(part.header);
|
||||
// var chunks = part.chunks;
|
||||
// var len = 0;
|
||||
// for (var i = 0; i < chunks.length; i++) {
|
||||
// len = len + chunks[i].length;
|
||||
// }
|
||||
// if (len !== part.header.length) {
|
||||
// console.log("mismatch: len=%d part.len=%d", len, part.header.length);
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
|
@ -0,0 +1,204 @@
|
|||
function PCMPlayer(option) {
|
||||
console.log("PCMPlayer new")
|
||||
this.init(option);
|
||||
}
|
||||
|
||||
PCMPlayer.prototype.init = function (option) {
|
||||
var defaults = {
|
||||
encoding: '16bitInt',
|
||||
channels: 1,
|
||||
sampleRate: 8000,
|
||||
flushingTime: 1000
|
||||
};
|
||||
this.option = Object.assign({}, defaults, option);
|
||||
this.samples = new Float32Array();
|
||||
this.flush = this.flush.bind(this);
|
||||
this.interval = setInterval(this.flush, this.option.flushingTime);
|
||||
this.maxValue = this.getMaxValue();
|
||||
this.typedArray = this.getTypedArray();
|
||||
this.createContext();
|
||||
this.lastBufferSource = null
|
||||
};
|
||||
|
||||
PCMPlayer.prototype.getMaxValue = function () {
|
||||
var encodings = {
|
||||
'8bitInt': 128,
|
||||
'16bitInt': 32768,
|
||||
'32bitInt': 2147483648,
|
||||
'32bitFloat': 1
|
||||
}
|
||||
|
||||
return encodings[this.option.encoding] ? encodings[this.option.encoding] : encodings['16bitInt'];
|
||||
};
|
||||
|
||||
PCMPlayer.prototype.getTypedArray = function () {
|
||||
var typedArrays = {
|
||||
'8bitInt': Int8Array,
|
||||
'16bitInt': Int16Array,
|
||||
'32bitInt': Int32Array,
|
||||
'32bitFloat': Float32Array
|
||||
}
|
||||
|
||||
return typedArrays[this.option.encoding] ? typedArrays[this.option.encoding] : typedArrays['16bitInt'];
|
||||
};
|
||||
|
||||
PCMPlayer.prototype.createContext = function () {
|
||||
this.audioCtx = new (window.AudioContext || window.webkitAudioContext)();
|
||||
this.gainNode = this.audioCtx.createGain();
|
||||
this.gainNode.gain.value = 1;
|
||||
this.gainNode.connect(this.audioCtx.destination);
|
||||
this.startTime = this.audioCtx.currentTime;
|
||||
};
|
||||
|
||||
PCMPlayer.prototype.isTypedArray = function (data) {
|
||||
return (data.byteLength && data.buffer && data.buffer.constructor == ArrayBuffer);
|
||||
};
|
||||
|
||||
PCMPlayer.prototype.feed = function (data) {
|
||||
if (!this.isTypedArray(data)) return;
|
||||
data = this.getFormatedValue(data);
|
||||
var tmp = new Float32Array(this.samples.length + data.length);
|
||||
tmp.set(this.samples, 0);
|
||||
tmp.set(data, this.samples.length);
|
||||
this.samples = tmp;
|
||||
};
|
||||
|
||||
PCMPlayer.prototype.getFormatedValue = function (data) {
|
||||
var data = new this.typedArray(data.buffer),
|
||||
float32 = new Float32Array(data.length),
|
||||
i;
|
||||
for (i = 0; i < data.length; i++) {
|
||||
float32[i] = data[i] / this.maxValue;
|
||||
}
|
||||
return float32;
|
||||
};
|
||||
|
||||
PCMPlayer.prototype.volume = function (volume) {
|
||||
this.gainNode.gain.value = volume;
|
||||
};
|
||||
|
||||
PCMPlayer.prototype.destroy = function () {
|
||||
console.log("PCMPlayer destroy")
|
||||
if (this.interval) {
|
||||
clearInterval(this.interval);
|
||||
}
|
||||
this.samples = null;
|
||||
this.audioCtx.close();
|
||||
this.audioCtx = null;
|
||||
};
|
||||
|
||||
PCMPlayer.prototype.flush = function () {
|
||||
// console.log("PCMPlayer.prototype.flush", this.samples.length)
|
||||
if (!this.samples.length) return;
|
||||
var bufferSource = this.audioCtx.createBufferSource(),
|
||||
length = this.samples.length / this.option.channels,
|
||||
audioBuffer = this.audioCtx.createBuffer(this.option.channels, length, this.option.sampleRate),
|
||||
audioData,
|
||||
channel,
|
||||
offset,
|
||||
i,
|
||||
decrement;
|
||||
|
||||
for (channel = 0; channel < this.option.channels; channel++) {
|
||||
audioData = audioBuffer.getChannelData(channel);
|
||||
offset = channel;
|
||||
decrement = 50;
|
||||
for (i = 0; i < length; i++) {
|
||||
audioData[i] = this.samples[offset];
|
||||
/* fadein */
|
||||
if (i < 50) {
|
||||
audioData[i] = (audioData[i] * i) / 50;
|
||||
}
|
||||
/* fadeout*/
|
||||
if (i >= (length - 51)) {
|
||||
audioData[i] = (audioData[i] * decrement--) / 50;
|
||||
}
|
||||
offset += this.option.channels;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.startTime < this.audioCtx.currentTime) {
|
||||
this.startTime = this.audioCtx.currentTime;
|
||||
}
|
||||
// console.log('start vs current '+this.startTime+' vs '+this.audioCtx.currentTime+' duration: '+audioBuffer.duration);
|
||||
bufferSource.buffer = audioBuffer;
|
||||
bufferSource.connect(this.gainNode);
|
||||
bufferSource.start(this.startTime);
|
||||
this.startTime += audioBuffer.duration;
|
||||
this.samples = new Float32Array();
|
||||
};
|
||||
|
||||
PCMPlayer.prototype.getTimestamp = function () {
|
||||
if (this.audioCtx) {
|
||||
return this.audioCtx.currentTime;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
PCMPlayer.prototype.play = function (data, flushcache) {
|
||||
if (!this.isTypedArray(data)) {
|
||||
return;
|
||||
}
|
||||
if (this.audioCtx.state === 'suspended') {
|
||||
return;
|
||||
}
|
||||
|
||||
data = this.getFormatedValue(data);
|
||||
if (!data.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
var bufferSource = this.audioCtx.createBufferSource();
|
||||
var length = data.length / this.option.channels;
|
||||
var audioBuffer = this.audioCtx.createBuffer(this.option.channels, length, this.option.sampleRate);
|
||||
|
||||
var audioData, channel, offset, i, decrement;
|
||||
|
||||
for (channel = 0; channel < this.option.channels; channel++) {
|
||||
audioData = audioBuffer.getChannelData(channel);
|
||||
offset = channel;
|
||||
decrement = 50;
|
||||
for (i = 0; i < length; i++) {
|
||||
audioData[i] = data[offset];
|
||||
/* fadein */
|
||||
if (i < 50) {
|
||||
audioData[i] = (audioData[i] * i) / 50;
|
||||
}
|
||||
/* fadeout*/
|
||||
if (i >= (length - 51)) {
|
||||
audioData[i] = (audioData[i] * decrement--) / 50;
|
||||
}
|
||||
offset += this.option.channels;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.startTime < this.audioCtx.currentTime) {
|
||||
this.startTime = this.audioCtx.currentTime;
|
||||
}
|
||||
|
||||
// console.log('start vs current '+this.startTime+' vs '+this.audioCtx.currentTime+' duration: '+audioBuffer.duration);
|
||||
bufferSource.buffer = audioBuffer;
|
||||
bufferSource.connect(this.gainNode);
|
||||
bufferSource.start(this.startTime);
|
||||
this.startTime += audioBuffer.duration - 0.008;
|
||||
// bufferSource.playbackRate(1.05)
|
||||
this.lastBufferSource = bufferSource
|
||||
};
|
||||
|
||||
PCMPlayer.prototype.pause = function () {
|
||||
if (this.audioCtx.state === 'running') {
|
||||
this.audioCtx.suspend()
|
||||
}
|
||||
}
|
||||
|
||||
PCMPlayer.prototype.resume = function () {
|
||||
if (this.audioCtx.state === 'suspended') {
|
||||
this.audioCtx.resume()
|
||||
}
|
||||
}
|
||||
|
||||
PCMPlayer.prototype.stop = function () {
|
||||
if (this.lastBufferSource)
|
||||
this.lastBufferSource.stop()
|
||||
}
|