Audio recive works perfect for opus voice, send fails (laggy)

TODO:
- Opus music
- Client volumes
- Some lagecy settings
canary
WolverinDEV 2018-03-02 23:39:12 +01:00
parent debab3baaf
commit 96c3aabec9
7 changed files with 300 additions and 222 deletions

View File

@ -3,11 +3,6 @@
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="978d055d-27d3-431a-bd34-e5e79bb273b3" name="Default" comment=""> <list default="true" id="978d055d-27d3-431a-bd34-e5e79bb273b3" name="Default" comment="">
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" afterPath="$PROJECT_DIR$/.idea/workspace.xml" /> <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" afterPath="$PROJECT_DIR$/.idea/workspace.xml" />
<change beforePath="$PROJECT_DIR$/asm/generated/TeaWeb-Native.js" afterPath="$PROJECT_DIR$/asm/generated/TeaWeb-Native.js" />
<change beforePath="$PROJECT_DIR$/asm/generated/libopus.js" afterPath="$PROJECT_DIR$/asm/generated/libopus.js" />
<change beforePath="$PROJECT_DIR$/asm/libs/opus" afterPath="$PROJECT_DIR$/asm/libs/opus" />
<change beforePath="$PROJECT_DIR$/asm/make_opus.sh" afterPath="$PROJECT_DIR$/asm/make_opus.sh" />
<change beforePath="$PROJECT_DIR$/asm/src/WebASMTest.cpp" afterPath="$PROJECT_DIR$/asm/src/WebASMTest.cpp" />
<change beforePath="$PROJECT_DIR$/js/codec/Codec.js" afterPath="$PROJECT_DIR$/js/codec/Codec.js" /> <change beforePath="$PROJECT_DIR$/js/codec/Codec.js" afterPath="$PROJECT_DIR$/js/codec/Codec.js" />
<change beforePath="$PROJECT_DIR$/js/codec/Codec.js.map" afterPath="$PROJECT_DIR$/js/codec/Codec.js.map" /> <change beforePath="$PROJECT_DIR$/js/codec/Codec.js.map" afterPath="$PROJECT_DIR$/js/codec/Codec.js.map" />
<change beforePath="$PROJECT_DIR$/js/codec/Codec.ts" afterPath="$PROJECT_DIR$/js/codec/Codec.ts" /> <change beforePath="$PROJECT_DIR$/js/codec/Codec.ts" afterPath="$PROJECT_DIR$/js/codec/Codec.ts" />
@ -24,21 +19,11 @@
</component> </component>
<component name="FileEditorManager"> <component name="FileEditorManager">
<leaf SIDE_TABS_SIZE_LIMIT_KEY="300"> <leaf SIDE_TABS_SIZE_LIMIT_KEY="300">
<file leaf-file-name="index.html" pinned="false" current-in-tab="false"> <file leaf-file-name="Codec.ts" pinned="false" current-in-tab="true">
<entry file="file://$PROJECT_DIR$/index.html">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="2898">
<caret line="161" column="19" lean-forward="false" selection-start-line="161" selection-start-column="19" selection-end-line="161" selection-end-column="19" />
<folding />
</state>
</provider>
</entry>
</file>
<file leaf-file-name="Codec.ts" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/js/codec/Codec.ts"> <entry file="file://$PROJECT_DIR$/js/codec/Codec.ts">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="751"> <state relative-caret-position="198">
<caret line="99" column="102" lean-forward="false" selection-start-line="99" selection-start-column="102" selection-end-line="99" selection-end-column="102" /> <caret line="14" column="35" lean-forward="true" selection-start-line="14" selection-start-column="35" selection-end-line="14" selection-end-column="35" />
<folding /> <folding />
</state> </state>
</provider> </provider>
@ -59,8 +44,8 @@
<file leaf-file-name="connection.ts" pinned="false" current-in-tab="false"> <file leaf-file-name="connection.ts" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/js/connection.ts"> <entry file="file://$PROJECT_DIR$/js/connection.ts">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="0"> <state relative-caret-position="612">
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" /> <caret line="34" column="24" lean-forward="true" selection-start-line="34" selection-start-column="24" selection-end-line="34" selection-end-column="24" />
<folding> <folding>
<element signature="n#!!doc" expanded="true" /> <element signature="n#!!doc" expanded="true" />
</folding> </folding>
@ -81,8 +66,18 @@
<file leaf-file-name="lib.es6.d.ts" pinned="false" current-in-tab="false"> <file leaf-file-name="lib.es6.d.ts" pinned="false" current-in-tab="false">
<entry file="file://$APPLICATION_HOME_DIR$/plugins/JavaScriptLanguage/jsLanguageServicesImpl/external/lib.es6.d.ts"> <entry file="file://$APPLICATION_HOME_DIR$/plugins/JavaScriptLanguage/jsLanguageServicesImpl/external/lib.es6.d.ts">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="442"> <state relative-caret-position="647">
<caret line="14435" column="40" lean-forward="false" selection-start-line="14435" selection-start-column="34" selection-end-line="14435" selection-end-column="40" /> <caret line="7148" column="4" lean-forward="false" selection-start-line="7148" selection-start-column="4" selection-end-line="7148" selection-end-column="4" />
<folding />
</state>
</provider>
</entry>
</file>
<file leaf-file-name="settings.ts" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/js/settings.ts">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="0">
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
<folding /> <folding />
</state> </state>
</provider> </provider>
@ -98,11 +93,11 @@
</provider> </provider>
</entry> </entry>
</file> </file>
<file leaf-file-name="voice.ts" pinned="false" current-in-tab="true"> <file leaf-file-name="voice.ts" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/js/voice.ts"> <entry file="file://$PROJECT_DIR$/js/voice.ts">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="1201"> <state relative-caret-position="594">
<caret line="320" column="33" lean-forward="false" selection-start-line="320" selection-start-column="33" selection-end-line="320" selection-end-column="33" /> <caret line="51" column="10" lean-forward="false" selection-start-line="51" selection-start-column="10" selection-end-line="51" selection-end-column="10" />
<folding /> <folding />
</state> </state>
</provider> </provider>
@ -118,18 +113,26 @@
</provider> </provider>
</entry> </entry>
</file> </file>
<file leaf-file-name="package.json" pinned="false" current-in-tab="false"> <file leaf-file-name="chat.ts" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/package.json"> <entry file="file://$PROJECT_DIR$/js/chat.ts">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="0"> <state relative-caret-position="513">
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" /> <caret line="32" column="41" lean-forward="false" selection-start-line="32" selection-start-column="41" selection-end-line="32" selection-end-column="41" />
<folding /> <folding>
<marker date="1519748729173" expanded="true" signature="1975:1985" ph="..." />
</folding>
</state> </state>
</provider> </provider>
</entry> </entry>
</file> </file>
</leaf> </leaf>
</component> </component>
<component name="FindInProjectRecents">
<findStrings>
<find>createBuffer</find>
<find>on_data</find>
</findStrings>
</component>
<component name="Git.Settings"> <component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" /> <option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
</component> </component>
@ -155,10 +158,10 @@
</component> </component>
<component name="PhpWorkspaceProjectConfiguration" backward_compatibility_performed="true" /> <component name="PhpWorkspaceProjectConfiguration" backward_compatibility_performed="true" />
<component name="ProjectFrameBounds" extendedState="6"> <component name="ProjectFrameBounds" extendedState="6">
<option name="x" value="2028" /> <option name="x" value="2918" />
<option name="y" value="357" /> <option name="y" value="-4" />
<option name="width" value="1855" /> <option name="width" value="1853" />
<option name="height" value="1084" /> <option name="height" value="1076" />
</component> </component>
<component name="ProjectView"> <component name="ProjectView">
<navigator currentView="ProjectPane" proportions="" version="1"> <navigator currentView="ProjectPane" proportions="" version="1">
@ -252,28 +255,30 @@
<option name="presentableId" value="Default" /> <option name="presentableId" value="Default" />
<updated>1519749313999</updated> <updated>1519749313999</updated>
<workItem from="1519749316100" duration="9698000" /> <workItem from="1519749316100" duration="9698000" />
<workItem from="1520012895408" duration="6591000" /> <workItem from="1520012895408" duration="13484000" />
</task> </task>
<servers /> <servers />
</component> </component>
<component name="TimeTrackingManager"> <component name="TimeTrackingManager">
<option name="totallyTimeSpent" value="16289000" /> <option name="totallyTimeSpent" value="23182000" />
</component> </component>
<component name="ToolWindowManager"> <component name="ToolWindowManager">
<frame x="2028" y="357" width="3777" height="2172" extended-state="6" /> <frame x="1985" y="-4" width="3775" height="2164" extended-state="6" />
<editor active="true" /> <editor active="true" />
<layout> <layout>
<window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" /> <window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" />
<window_info id="Messages" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="-1" side_tool="false" content_ui="tabs" />
<window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="true" content_ui="tabs" /> <window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="true" content_ui="tabs" />
<window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" /> <window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
<window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" /> <window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
<window_info id="npm" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="true" content_ui="tabs" /> <window_info id="npm" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="true" content_ui="tabs" />
<window_info id="Terminal" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" /> <window_info id="Terminal" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
<window_info id="TypeScript" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.32993197" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" /> <window_info id="TypeScript" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.32993197" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
<window_info id="Project" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.24980132" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" /> <window_info id="Project" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.24980132" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" />
<window_info id="Hierarchy" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.24980132" sideWeight="0.5" order="2" side_tool="false" content_ui="combo" /> <window_info id="Hierarchy" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.24980132" sideWeight="0.5" order="2" side_tool="false" content_ui="combo" />
<window_info id="Docker" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="false" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" /> <window_info id="Docker" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="false" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
<window_info id="Database" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" /> <window_info id="Database" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
<window_info id="Find" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
<window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" /> <window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
<window_info id="Favorites" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="true" content_ui="tabs" /> <window_info id="Favorites" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="true" content_ui="tabs" />
<window_info id="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" /> <window_info id="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
@ -281,7 +286,6 @@
<window_info id="Message" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" /> <window_info id="Message" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
<window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" /> <window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
<window_info id="Inspection" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="5" side_tool="false" content_ui="tabs" /> <window_info id="Inspection" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="5" side_tool="false" content_ui="tabs" />
<window_info id="Find" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
<window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" /> <window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
</layout> </layout>
</component> </component>
@ -336,7 +340,9 @@
<option name="myLimit" value="2678400000" /> <option name="myLimit" value="2678400000" />
</component> </component>
<component name="XDebuggerManager"> <component name="XDebuggerManager">
<breakpoint-manager /> <breakpoint-manager>
<option name="time" value="1" />
</breakpoint-manager>
<watches-manager /> <watches-manager />
</component> </component>
<component name="editorHistoryManager"> <component name="editorHistoryManager">
@ -460,16 +466,6 @@
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/js/connection.ts">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="0">
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
<folding>
<element signature="n#!!doc" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/js/client.ts"> <entry file="file://$PROJECT_DIR$/js/client.ts">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="0"> <state relative-caret-position="0">
@ -488,6 +484,14 @@
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/js/settings.ts">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="0">
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/js/ui/client.ts"> <entry file="file://$PROJECT_DIR$/js/ui/client.ts">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="324"> <state relative-caret-position="324">
@ -496,26 +500,46 @@
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/js/codec/Codec.ts"> <entry file="file://$PROJECT_DIR$/js/chat.ts">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="751"> <state relative-caret-position="513">
<caret line="99" column="102" lean-forward="false" selection-start-line="99" selection-start-column="102" selection-end-line="99" selection-end-column="102" /> <caret line="32" column="41" lean-forward="false" selection-start-line="32" selection-start-column="41" selection-end-line="32" selection-end-column="41" />
<folding /> <folding>
<marker date="1519748729173" expanded="true" signature="1975:1985" ph="..." />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/js/connection.ts">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="612">
<caret line="34" column="24" lean-forward="true" selection-start-line="34" selection-start-column="24" selection-end-line="34" selection-end-column="24" />
<folding>
<element signature="n#!!doc" expanded="true" />
</folding>
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$APPLICATION_HOME_DIR$/plugins/JavaScriptLanguage/jsLanguageServicesImpl/external/lib.es6.d.ts"> <entry file="file://$APPLICATION_HOME_DIR$/plugins/JavaScriptLanguage/jsLanguageServicesImpl/external/lib.es6.d.ts">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="442"> <state relative-caret-position="647">
<caret line="14435" column="40" lean-forward="false" selection-start-line="14435" selection-start-column="34" selection-end-line="14435" selection-end-column="40" /> <caret line="7148" column="4" lean-forward="false" selection-start-line="7148" selection-start-column="4" selection-end-line="7148" selection-end-column="4" />
<folding /> <folding />
</state> </state>
</provider> </provider>
</entry> </entry>
<entry file="file://$PROJECT_DIR$/js/voice.ts"> <entry file="file://$PROJECT_DIR$/js/voice.ts">
<provider selected="true" editor-type-id="text-editor"> <provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="1201"> <state relative-caret-position="594">
<caret line="320" column="33" lean-forward="false" selection-start-line="320" selection-start-column="33" selection-end-line="320" selection-end-column="33" /> <caret line="51" column="10" lean-forward="false" selection-start-line="51" selection-start-column="10" selection-end-line="51" selection-end-column="10" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/js/codec/Codec.ts">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="198">
<caret line="14" column="35" lean-forward="true" selection-start-line="14" selection-start-column="35" selection-end-line="14" selection-end-column="35" />
<folding /> <folding />
</state> </state>
</provider> </provider>

View File

@ -5,10 +5,13 @@ class SampleBuffer {
} }
} }
class Codec { class Codec {
constructor() { constructor(codecSampleRate) {
this.on_encoded_data = ($) => { }; this.on_encoded_data = ($) => { };
this._sampleBuffer = []; this._sampleBuffer = [];
this.sampleRate = 120; this.samplesPerUnit = 960;
this._codecSampleRate = codecSampleRate;
this._decodeResampler = new Resampler();
this._encodeResampler = new Resampler(codecSampleRate);
} }
bufferedSamples(max = 0) { bufferedSamples(max = 0) {
let value = 0; let value = 0;
@ -17,15 +20,19 @@ class Codec {
console.log(value + " / " + max); console.log(value + " / " + max);
return value; return value;
} }
encodeSamples(array) { encodeSamples(pcm) {
console.log("encode"); this._encodeResampler.resample(pcm).then(buffer => this.encodeSamples0(buffer))
this._sampleBuffer.push(new SampleBuffer(array)); .catch(error => console.error("Could not resample PCM data for codec. Error:" + error));
while (this.bufferedSamples(this.sampleRate) >= this.sampleRate) { }
let buffer = new Float32Array(this.sampleRate); encodeSamples0(buffer) {
console.log(buffer);
this._sampleBuffer.push(new SampleBuffer(buffer.getChannelData(0))); //TODO multi channel!
while (this.bufferedSamples(this.samplesPerUnit) >= this.samplesPerUnit) {
let buffer = new Float32Array(this.samplesPerUnit);
let index = 0; let index = 0;
while (index < this.sampleRate) { while (index < this.samplesPerUnit) {
let buf = this._sampleBuffer[0]; let buf = this._sampleBuffer[0];
let len = Math.min(buf.buffer.length - buf.index, this.sampleRate - index); let len = Math.min(buf.buffer.length - buf.index, this.samplesPerUnit - index);
buffer.set(buf.buffer.subarray(buf.index, buf.index + len)); buffer.set(buf.buffer.subarray(buf.index, buf.index + len));
index += len; index += len;
buf.index += len; buf.index += len;
@ -37,14 +44,17 @@ class Codec {
if (result instanceof Uint8Array) if (result instanceof Uint8Array)
this.on_encoded_data(result); this.on_encoded_data(result);
else else
return result; console.error("[Codec][" + this.name() + "] Could not encode buffer. Result: " + result);
} }
return true; return true;
} }
decodeSamples(data) {
return this.decode(data).then(buffer => this._decodeResampler.resample(buffer));
}
} }
class OpusCodec extends Codec { class OpusCodec extends Codec {
constructor() { constructor() {
super(); super(48000);
this.channelCount = 1; this.channelCount = 1;
} }
name() { name() {
@ -56,21 +66,25 @@ class OpusCodec extends Codec {
this.fn_encode = Module.cwrap("codec_opus_encode", "number", ["pointer", "pointer", "number", "number"]); this.fn_encode = Module.cwrap("codec_opus_encode", "number", ["pointer", "pointer", "number", "number"]);
this.nativeHandle = this.fn_newHandle(1); this.nativeHandle = this.fn_newHandle(1);
} }
deinitialise() { deinitialise() { } //TODO
}
decode(data) { decode(data) {
let maxBytes = 4096; return new Promise((resolve, reject) => {
let buffer = Module._malloc(maxBytes); let maxBytes = 4096;
let heapBytes = new Uint8Array(Module.HEAPU8.buffer, buffer, maxBytes); let buffer = Module._malloc(maxBytes);
heapBytes.set(data); let heapBytes = new Uint8Array(Module.HEAPU8.buffer, buffer, maxBytes);
let result = this.fn_decode(this.nativeHandle, heapBytes.byteOffset, data.byteLength, maxBytes); heapBytes.set(data);
if (result < 0) { let result = this.fn_decode(this.nativeHandle, heapBytes.byteOffset, data.byteLength, maxBytes);
if (result < 0) {
Module._free(buffer);
reject("invalid result on decode (" + result + ")");
return;
}
let buf = Module.HEAPF32.slice(heapBytes.byteOffset / 4, (heapBytes.byteOffset / 4) + (result * this.channelCount));
Module._free(buffer); Module._free(buffer);
return "invalid result on decode (" + result + ")"; let audioBuf = AudioController.globalContext.createBuffer(this.channelCount, result, this._codecSampleRate);
} audioBuf.copyToChannel(buf, 0);
let buf = Module.HEAPF32.slice(heapBytes.byteOffset / 4, (heapBytes.byteOffset / 4) + (result * this.channelCount)); resolve(audioBuf);
Module._free(buffer); });
return buf;
} }
encode(data) { encode(data) {
let maxBytes = data.byteLength; let maxBytes = data.byteLength;

File diff suppressed because one or more lines are too long

View File

@ -11,20 +11,27 @@ class SampleBuffer {
abstract class Codec { abstract class Codec {
on_encoded_data: (Uint8Array) => void = ($) => {}; on_encoded_data: (Uint8Array) => void = ($) => {};
protected _decodeResampler: Resampler;
protected _encodeResampler: Resampler;
protected _codecSampleRate: number;
protected _sampleBuffer: SampleBuffer[] = []; protected _sampleBuffer: SampleBuffer[] = [];
sampleRate: number = 120;
constructor(){} samplesPerUnit: number = 960;
protected constructor(codecSampleRate: number){
this._codecSampleRate = codecSampleRate;
this._decodeResampler = new Resampler();
this._encodeResampler = new Resampler(codecSampleRate);
}
abstract name() : string; abstract name() : string;
abstract initialise(); abstract initialise();
abstract deinitialise(); abstract deinitialise();
protected abstract decode(data: Uint8Array) : Promise<AudioBuffer>;
abstract decode(data: Uint8Array) : Float32Array | string;
protected abstract encode(data: Float32Array) : Uint8Array | string; protected abstract encode(data: Float32Array) : Uint8Array | string;
protected bufferedSamples(max: number = 0) : number { protected bufferedSamples(max: number = 0) : number {
let value = 0; let value = 0;
for(let i = 0; i < this._sampleBuffer.length && value < max; i++) for(let i = 0; i < this._sampleBuffer.length && value < max; i++)
@ -33,16 +40,21 @@ abstract class Codec {
return value; return value;
} }
encodeSamples(array: Float32Array) : boolean | string { encodeSamples(pcm: AudioBuffer) {
console.log("encode"); this._encodeResampler.resample(pcm).then(buffer => this.encodeSamples0(buffer))
this._sampleBuffer.push(new SampleBuffer(array)); .catch(error => console.error("Could not resample PCM data for codec. Error:" + error));
}
while(this.bufferedSamples(this.sampleRate) >= this.sampleRate) { private encodeSamples0(buffer: AudioBuffer) {
let buffer = new Float32Array(this.sampleRate); console.log(buffer);
this._sampleBuffer.push(new SampleBuffer(buffer.getChannelData(0))); //TODO multi channel!
while(this.bufferedSamples(this.samplesPerUnit) >= this.samplesPerUnit) {
let buffer = new Float32Array(this.samplesPerUnit);
let index = 0; let index = 0;
while(index < this.sampleRate) { while(index < this.samplesPerUnit) {
let buf = this._sampleBuffer[0]; let buf = this._sampleBuffer[0];
let len = Math.min(buf.buffer.length - buf.index, this.sampleRate - index); let len = Math.min(buf.buffer.length - buf.index, this.samplesPerUnit - index);
buffer.set(buf.buffer.subarray(buf.index, buf.index + len)); buffer.set(buf.buffer.subarray(buf.index, buf.index + len));
index += len; index += len;
buf.index += len; buf.index += len;
@ -53,10 +65,14 @@ abstract class Codec {
let result = this.encode(buffer); let result = this.encode(buffer);
if(result instanceof Uint8Array) this.on_encoded_data(result); if(result instanceof Uint8Array) this.on_encoded_data(result);
else return result; else console.error("[Codec][" + this.name() + "] Could not encode buffer. Result: " + result);
} }
return true; return true;
} }
decodeSamples(data: Uint8Array) : Promise<AudioBuffer> {
return this.decode(data).then(buffer => this._decodeResampler.resample(buffer));
}
} }
class OpusCodec extends Codec { class OpusCodec extends Codec {
@ -68,7 +84,7 @@ class OpusCodec extends Codec {
private fn_encode: any; private fn_encode: any;
constructor() { constructor() {
super(); super(48000);
} }
name(): string { name(): string {
@ -83,23 +99,27 @@ class OpusCodec extends Codec {
this.nativeHandle = this.fn_newHandle(1); this.nativeHandle = this.fn_newHandle(1);
} }
deinitialise() { deinitialise() { } //TODO
} decode(data: Uint8Array): Promise<AudioBuffer> {
return new Promise<AudioBuffer>((resolve, reject) => {
decode(data: Uint8Array): Float32Array | string { let maxBytes = 4096;
let maxBytes = 4096; let buffer = Module._malloc(maxBytes);
let buffer = Module._malloc(maxBytes); let heapBytes = new Uint8Array(Module.HEAPU8.buffer, buffer, maxBytes);
let heapBytes = new Uint8Array(Module.HEAPU8.buffer, buffer, maxBytes); heapBytes.set(data);
heapBytes.set(data); let result = this.fn_decode(this.nativeHandle, heapBytes.byteOffset, data.byteLength, maxBytes);
let result = this.fn_decode(this.nativeHandle, heapBytes.byteOffset, data.byteLength, maxBytes); if(result < 0) {
if(result < 0) { Module._free(buffer);
reject("invalid result on decode (" + result + ")");
return;
}
let buf = Module.HEAPF32.slice(heapBytes.byteOffset / 4, (heapBytes.byteOffset / 4) + (result * this.channelCount));
Module._free(buffer); Module._free(buffer);
return "invalid result on decode (" + result + ")";
} let audioBuf = AudioController.globalContext.createBuffer(this.channelCount, result, this._codecSampleRate);
let buf = Module.HEAPF32.slice(heapBytes.byteOffset / 4, (heapBytes.byteOffset / 4) + (result * this.channelCount)); audioBuf.copyToChannel(buf, 0);
Module._free(buffer); resolve(audioBuf);
return buf; });
} }
encode(data: Float32Array): Uint8Array | string { encode(data: Float32Array): Uint8Array | string {

View File

@ -1,17 +1,44 @@
/// <reference path="client.ts" /> /// <reference path="client.ts" />
class VoiceConnection { class VoiceConnection {
/*
private _voicePacketBuffer: Uint8Array[] = [];
private _voicePacketSender: NodeJS.Timer;
private _triggered = false;
*/
constructor(client) { constructor(client) {
this.vpacketId = 0;
this.client = client; this.client = client;
this.voiceRecorder = new VoiceRecorder(this); this.voiceRecorder = new VoiceRecorder(this);
this.voiceRecorder.on_data = data => this.sendPCMData(data); this.voiceRecorder.on_data = data => this.handleVoiceData(data);
this.codec = new OpusCodec(); this.codec = new OpusCodec();
this.codec.initialise(); this.codec.initialise();
this.codec.on_encoded_data = buffer => { this.codec.on_encoded_data = buffer => {
if (this.dataChannel) { if (this.dataChannel) {
console.log("Send buffer"); this.vpacketId++;
this.dataChannel.send(buffer); if (this.vpacketId > 65535)
this.vpacketId = 0;
let packet = new Uint8Array(buffer.byteLength + 2 + 3);
packet[0] = this.vpacketId < 6 ? 1 : 0; //Flag header
packet[1] = 0; //Flag fragmented
packet[2] = (this.vpacketId >> 8) & 0xFF; //HIGHT(voiceID)
packet[3] = (this.vpacketId >> 0) & 0xFF; //LOW (voiceID)
packet[4] = 4; //Codec
packet.set(buffer, 5);
//this._voicePacketBuffer.push(packet);
this.dataChannel.send(packet);
} }
}; };
/*
this._voicePacketSender = setInterval(() => {
if(this._voicePacketBuffer.length > 5 || this._triggered) {
let packet = this._voicePacketBuffer.pop_front();
if (packet) {
this.dataChannel.send(packet);
}
this._triggered = this._voicePacketBuffer.length > 0;
}
}, 20);
*/
} }
createSession() { createSession() {
const config = {}; const config = {};
@ -66,26 +93,24 @@ class VoiceConnection {
} }
onDataChannelMessage(message) { onDataChannelMessage(message) {
let bin = new Uint8Array(message.data); let bin = new Uint8Array(message.data);
let clientId = bin[0] << 8 | bin[1]; let clientId = bin[2] << 8 | bin[3];
console.log("Client id " + clientId); let packetId = bin[0] << 8 | bin[1];
let codec = bin[4];
console.log("Client id " + clientId + " PacketID " + packetId + " Codec: " + codec);
let client = this.client.channelTree.findClient(clientId); let client = this.client.channelTree.findClient(clientId);
if (!client) { if (!client) {
console.error("Having voice from unknown client? (ClientID: " + clientId + ")"); console.error("Having voice from unknown client? (ClientID: " + clientId + ")");
return; return;
} }
var encodedData = new Uint8Array(message.data, 4); var encodedData = new Uint8Array(message.data, 5);
let result = this.codec.decode(encodedData); this.codec.decodeSamples(encodedData).then(buffer => client.getAudioController().play(buffer)).catch(error => {
if (result instanceof Float32Array) console.error("Could not playback client's (" + clientId + ") audio (" + error + ")");
client.getAudioController().play(result); });
else
console.log("Invalid decode " + result);
} }
sendPCMData(data) { handleVoiceData(data) {
/* setTimeout(() => {
let result = this.codec.encodeSamples(data); this.codec.encodeSamples(data);
if(!result) console.error("Could not encode audio: " + result); }, 1);
*/
this.client.getClient().getAudioController().play(data);
} }
} }
class VoiceRecorder { class VoiceRecorder {
@ -100,8 +125,9 @@ class VoiceRecorder {
this.processor = this.audioContext.createScriptProcessor(VoiceRecorder.BUFFER_SIZE, VoiceRecorder.CHANNELS, VoiceRecorder.CHANNELS); this.processor = this.audioContext.createScriptProcessor(VoiceRecorder.BUFFER_SIZE, VoiceRecorder.CHANNELS, VoiceRecorder.CHANNELS);
const _this = this; const _this = this;
this.processor.addEventListener('audioprocess', ev => { this.processor.addEventListener('audioprocess', ev => {
console.log(ev.inputBuffer);
if (_this.microphoneStream) if (_this.microphoneStream)
this.on_data(ev.inputBuffer.getChannelData(VoiceRecorder.CHANNEL)); this.on_data(ev.inputBuffer);
}); });
//Not needed but make sure we have data for the preprocessor //Not needed but make sure we have data for the preprocessor
this.mute = this.audioContext.createGain(); this.mute = this.audioContext.createGain();
@ -156,10 +182,15 @@ class VoiceRecorder {
} }
VoiceRecorder.CHANNEL = 0; VoiceRecorder.CHANNEL = 0;
VoiceRecorder.CHANNELS = 1; VoiceRecorder.CHANNELS = 1;
VoiceRecorder.BUFFER_SIZE = 4096; VoiceRecorder.BUFFER_SIZE = 16384 / 2;
class AudioController { class AudioController {
static get globalContext() {
if (this._globalContext)
return this._globalContext;
this._globalContext = new AudioContext();
return this._globalContext;
}
constructor() { constructor() {
this.resambler = new Resampler();
this.speakerContext = AudioController.globalContext; this.speakerContext = AudioController.globalContext;
this.nextTime = 0; this.nextTime = 0;
this.last = 0; this.last = 0;
@ -169,23 +200,9 @@ class AudioController {
this.onSpeaking = function () { }; this.onSpeaking = function () { };
this.onSilence = function () { }; this.onSilence = function () { };
} }
static get globalContext() { play(buffer) {
if (this._globalContext) if (buffer.sampleRate != this.speakerContext.sampleRate)
return this._globalContext; console.warn("[AudioController] Source sample rate isnt equal to playback sample rate!");
this._globalContext = new AudioContext();
return this._globalContext;
}
play(pcm) {
//let buffer = this.speakerContext.createBuffer(1, 960, 48000);
//buffer.copyToChannel(pcm, 0);
this.resambler.resample(pcm, (buffer) => this.play0(buffer));
//this.play0(buffer);
}
play0(buffer) {
//960
console.log(buffer);
//let buffer = this.speakerContext.createBuffer(1, 960, 44100);
//buffer.copyToChannel(pcm, 0);
this.audioCache.push(buffer); this.audioCache.push(buffer);
let currentTime = new Date().getTime(); let currentTime = new Date().getTime();
if ((currentTime - this.last) > 50) { if ((currentTime - this.last) > 50) {
@ -207,8 +224,8 @@ class AudioController {
; ;
playCache(cache) { playCache(cache) {
while (cache.length) { while (cache.length) {
var buffer = cache.shift(); let buffer = cache.shift();
var source = this.speakerContext.createBufferSource(); let source = this.speakerContext.createBufferSource();
source.buffer = buffer; source.buffer = buffer;
source.connect(this.speakerContext.destination); source.connect(this.speakerContext.destination);
if (this.nextTime == 0) { if (this.nextTime == 0) {
@ -234,26 +251,19 @@ class AudioController {
} }
} }
class Resampler { class Resampler {
constructor() { constructor(targetSampleRate = 44100) {
this.targetSampleRate = targetSampleRate;
} }
resample(pcm, callback) { resample(buffer) {
/* if (buffer.sampleRate == this.targetSampleRate)
let buffer = AudioController.globalContext.createBuffer(1, pcm.length, 48000); return new Promise(resolve => resolve(buffer));
buffer.copyToChannel(pcm, 0); console.log(this.targetSampleRate);
callback(buffer); let context = new OfflineAudioContext(1, Math.ceil(buffer.length * this.targetSampleRate / buffer.sampleRate), this.targetSampleRate);
*/ let source = context.createBufferSource();
this.context = new OfflineAudioContext(1, 882, 44100);
let buffer = this.context.createBuffer(1, pcm.length, 48000);
buffer.copyToChannel(pcm, 0);
let source = this.context.createBufferSource();
source.buffer = buffer; source.buffer = buffer;
source.connect(this.context.destination); source.connect(context.destination);
source.start(0); source.start(0);
//console.log(source.buffer.getChannelData(0)); return context.startRendering();
this.context.startRendering().then(e => callback(e)).catch(error => {
console.error("Could not resample audio");
console.error(error);
});
} }
} }
//# sourceMappingURL=voice.js.map //# sourceMappingURL=voice.js.map

File diff suppressed because one or more lines are too long

View File

@ -9,19 +9,47 @@ class VoiceConnection {
start: number; start: number;
codec: Codec; codec: Codec;
vpacketId: number = 0;
/*
private _voicePacketBuffer: Uint8Array[] = [];
private _voicePacketSender: NodeJS.Timer;
private _triggered = false;
*/
constructor(client) { constructor(client) {
this.client = client; this.client = client;
this.voiceRecorder = new VoiceRecorder(this); this.voiceRecorder = new VoiceRecorder(this);
this.voiceRecorder.on_data = data => this.sendPCMData(data); this.voiceRecorder.on_data = data => this.handleVoiceData(data);
this.codec = new OpusCodec(); this.codec = new OpusCodec();
this.codec.initialise(); this.codec.initialise();
this.codec.on_encoded_data = buffer => { this.codec.on_encoded_data = buffer => {
if(this.dataChannel) { if(this.dataChannel) {
console.log("Send buffer"); this.vpacketId++;
this.dataChannel.send(buffer); if(this.vpacketId > 65535) this.vpacketId = 0;
let packet = new Uint8Array(buffer.byteLength + 2 + 3);
packet[0] = this.vpacketId < 6 ? 1 : 0; //Flag header
packet[1] = 0; //Flag fragmented
packet[2] = (this.vpacketId >> 8) & 0xFF; //HIGHT(voiceID)
packet[3] = (this.vpacketId >> 0) & 0xFF; //LOW (voiceID)
packet[4] = 4; //Codec
packet.set(buffer, 5);
//this._voicePacketBuffer.push(packet);
this.dataChannel.send(packet);
} }
}; };
/*
this._voicePacketSender = setInterval(() => {
if(this._voicePacketBuffer.length > 5 || this._triggered) {
let packet = this._voicePacketBuffer.pop_front();
if (packet) {
this.dataChannel.send(packet);
}
this._triggered = this._voicePacketBuffer.length > 0;
}
}, 20);
*/
} }
@ -87,36 +115,35 @@ class VoiceConnection {
onDataChannelMessage(message) { onDataChannelMessage(message) {
let bin = new Uint8Array(message.data); let bin = new Uint8Array(message.data);
let clientId = bin[0] << 8 | bin[1]; let clientId = bin[2] << 8 | bin[3];
console.log("Client id " + clientId); let packetId = bin[0] << 8 | bin[1];
let codec = bin[4];
console.log("Client id " + clientId + " PacketID " + packetId + " Codec: " + codec);
let client = this.client.channelTree.findClient(clientId); let client = this.client.channelTree.findClient(clientId);
if(!client) { if(!client) {
console.error("Having voice from unknown client? (ClientID: " + clientId + ")"); console.error("Having voice from unknown client? (ClientID: " + clientId + ")");
return; return;
} }
var encodedData = new Uint8Array(message.data, 4); var encodedData = new Uint8Array(message.data, 5);
let result = this.codec.decode(encodedData) this.codec.decodeSamples(encodedData).then(buffer => client.getAudioController().play(buffer)).catch(error => {
if(result instanceof Float32Array) console.error("Could not playback client's (" + clientId + ") audio (" + error + ")");
client.getAudioController().play(result); });
else console.log("Invalid decode " + result);
} }
private sendPCMData(data: any) { private handleVoiceData(data: AudioBuffer) {
/* setTimeout(() => {
let result = this.codec.encodeSamples(data); this.codec.encodeSamples(data);
if(!result) console.error("Could not encode audio: " + result); }, 1);
*/
this.client.getClient().getAudioController().play(data);
} }
} }
class VoiceRecorder { class VoiceRecorder {
private static readonly CHANNEL = 0; private static readonly CHANNEL = 0;
private static readonly CHANNELS = 1; private static readonly CHANNELS = 1;
private static readonly BUFFER_SIZE = 4096; private static readonly BUFFER_SIZE = 16384 / 2;
handle: VoiceConnection; handle: VoiceConnection;
on_data: (data: any) => void = (data) => {}; on_data: (data: AudioBuffer) => void = (data) => {};
private _recording: boolean = false; private _recording: boolean = false;
@ -137,8 +164,9 @@ class VoiceRecorder {
const _this = this; const _this = this;
this.processor.addEventListener('audioprocess', ev => { this.processor.addEventListener('audioprocess', ev => {
console.log(ev.inputBuffer);
if(_this.microphoneStream) if(_this.microphoneStream)
this.on_data(ev.inputBuffer.getChannelData(VoiceRecorder.CHANNEL)) this.on_data(ev.inputBuffer)
}); });
//Not needed but make sure we have data for the preprocessor //Not needed but make sure we have data for the preprocessor
@ -212,7 +240,6 @@ class AudioController {
init: boolean; init: boolean;
stimeout: NodeJS.Timer; stimeout: NodeJS.Timer;
resambler: Resampler = new Resampler();
//Events //Events
onSpeaking: () => void; onSpeaking: () => void;
onSilence: () => void; onSilence: () => void;
@ -229,18 +256,9 @@ class AudioController {
this.onSilence = function () { } this.onSilence = function () { }
} }
play(pcm: Float32Array) { play(buffer: AudioBuffer) {
//let buffer = this.speakerContext.createBuffer(1, 960, 48000); if(buffer.sampleRate != this.speakerContext.sampleRate)
//buffer.copyToChannel(pcm, 0); console.warn("[AudioController] Source sample rate isnt equal to playback sample rate!");
this.resambler.resample(pcm, (buffer: AudioBuffer) => this.play0(buffer));
//this.play0(buffer);
}
play0(buffer: AudioBuffer) {
//960
console.log(buffer);
//let buffer = this.speakerContext.createBuffer(1, 960, 44100);
//buffer.copyToChannel(pcm, 0);
this.audioCache.push(buffer); this.audioCache.push(buffer);
let currentTime = new Date().getTime(); let currentTime = new Date().getTime();
@ -265,8 +283,8 @@ class AudioController {
playCache(cache) { playCache(cache) {
while (cache.length) { while (cache.length) {
var buffer = cache.shift(); let buffer = cache.shift();
var source = this.speakerContext.createBufferSource(); let source = this.speakerContext.createBufferSource();
source.buffer = buffer; source.buffer = buffer;
source.connect(this.speakerContext.destination); source.connect(this.speakerContext.destination);
@ -294,32 +312,24 @@ class AudioController {
} }
class Resampler { class Resampler {
context: OfflineAudioContext; targetSampleRate: number;
constructor(){ constructor(targetSampleRate: number = 44100){
this.targetSampleRate = targetSampleRate;
} }
resample(pcm: Float32Array, callback: (AudioBuffer) => void) { resample(buffer: AudioBuffer) : Promise<AudioBuffer> {
/* if(buffer.sampleRate == this.targetSampleRate)
let buffer = AudioController.globalContext.createBuffer(1, pcm.length, 48000); return new Promise<AudioBuffer>(resolve => resolve(buffer));
buffer.copyToChannel(pcm, 0);
callback(buffer);
*/
this.context = new OfflineAudioContext(1, 882, 44100); console.log(this.targetSampleRate);
let buffer = this.context.createBuffer(1, pcm.length, 48000); let context = new OfflineAudioContext(1, Math.ceil(buffer.length * this.targetSampleRate / buffer.sampleRate), this.targetSampleRate);
buffer.copyToChannel(pcm, 0);
let source = this.context.createBufferSource(); let source = context.createBufferSource();
source.buffer = buffer; source.buffer = buffer;
source.connect(this.context.destination); source.connect(context.destination);
source.start(0); source.start(0);
//console.log(source.buffer.getChannelData(0));
this.context.startRendering().then(e => callback(e)).catch(error => {
console.error("Could not resample audio");
console.error(error);
});
return context.startRendering();
} }
} }