国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Unity-WebGL基于JS實現(xiàn)網(wǎng)頁錄音

這篇具有很好參考價值的文章主要介紹了Unity-WebGL基于JS實現(xiàn)網(wǎng)頁錄音。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

? ? ? 因為該死的Unity不支持WebGL的麥克風(fēng),所以只能向網(wǎng)頁借力,用網(wǎng)頁原生的navigator.getUserMedia錄音,然后傳音頻流給Unity進行轉(zhuǎn)AudioClip播放。

? ? ? 還有一點非常重要:能有同事借力就直接問,厚著臉皮上,我自己悶頭兩天帶加班,不如同事譚老哥加起來提供幫助的倆小時,很感謝他,雖然是他們該做的,但我一直沒提出,而且我方向錯了??????

版本:

Unity:2021.3.6f1

Github庫:UnityWebGLMicrophone

相關(guān)代碼

Unity端的.cs ?.jslibWebGL端的.js.

.jslib

WebGLRecorder.jslib

這個需要放在UnityPlugins文件夾下

mergeInto(LibraryManager.library, {
    StartRecord: function(){
        StartRecord();
    },
    StopRecord: function(){
        StopRecord();
    },
});

.cs

WAV.cs

public class WAV
{
    static float bytesToFloat(byte firstByte, byte secondByte)
    {
        short s = (short)((secondByte << 8) | firstByte);
        return s / 32768.0F;
    }

    static int bytesToInt(byte[] bytes, int offset = 0)
    {
        int value = 0;
        for (int i = 0; i < 4; i++)
        {
            value |= ((int)bytes[offset + i]) << (i * 8);
        }
        return value;
    }

    public float[] LeftChannel { get; internal set; }
    public float[] RightChannel { get; internal set; }
    public int ChannelCount { get; internal set; }
    public int SampleCount { get; internal set; }
    public int Frequency { get; internal set; }

    public WAV(byte[] wav)
    {
        ChannelCount = wav[22];

        Frequency = bytesToInt(wav, 24);

        int pos = 12;

        while (!(wav[pos] == 100 && wav[pos + 1] == 97 && wav[pos + 2] == 116 && wav[pos + 3] == 97))
        {
            pos += 4;
            int chunkSize = wav[pos] + wav[pos + 1] * 256 + wav[pos + 2] * 65536 + wav[pos + 3] * 16777216;
            pos += 4 + chunkSize;
        }
        pos += 8;

        SampleCount = (wav.Length - pos) / 2;
        if (ChannelCount == 2) SampleCount /= 2;

        LeftChannel = new float[SampleCount];
        if (ChannelCount == 2) RightChannel = new float[SampleCount];
        else RightChannel = null;

        int i = 0;

        int maxInput = wav.Length - (RightChannel == null ? 1 : 3);
        while ((i < SampleCount) && (pos < maxInput))
        {
            LeftChannel[i] = bytesToFloat(wav[pos], wav[pos + 1]);
            pos += 2;
            if (ChannelCount == 2)
            {
                RightChannel[i] = bytesToFloat(wav[pos], wav[pos + 1]);
                pos += 2;
            }
            i++;
        }

    }

    public override string ToString()
    {
        return string.Format("[WAV: LeftChannel={0}, RightChannel={1}, ChannelCount={2}, SampleCount={3}, Frequency={4}]", LeftChannel, RightChannel, ChannelCount, SampleCount, Frequency);
    }

}

SignalManager.cs

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using UnityEngine;
using UnityEngine.UI;

public class SignalManager : MonoBehaviour
{
    public Button StartRecorder;
    public Button EndRecorder;
    AudioSource m_audioSource;
    void Start()
    {
        m_audioSource = gameObject.AddComponent<AudioSource>();
        StartRecorder.onClick.AddListener(StartRecorderFunc);
        EndRecorder.onClick.AddListener(EndRecorderFunc);
    }

    #region UnityToJs
    [DllImport("__Internal")]
    private static extern void StartRecord();
    [DllImport("__Internal")]
    private static extern void StopRecord();
    void StartRecorderFunc()
    {
        StartRecord();
    }
    void EndRecorderFunc()
    {
        StopRecord();
    }
    #endregion

    #region JsToUnity
    #region Data
    /// <summary>
    ///需獲取數(shù)據(jù)的數(shù)目
    /// </summary>
    private int m_valuePartCount = 0;
    /// <summary>
    /// 獲取的數(shù)據(jù)數(shù)目
    /// </summary>
    private int m_getDataLength = 0;
    /// <summary>
    /// 獲取的數(shù)據(jù)長度
    /// </summary>
    private int m_audioLength = 0;
    /// <summary>
    /// 獲取的數(shù)據(jù)
    /// </summary>
    private string[] m_audioData = null;

    /// <summary>
    /// 當(dāng)前音頻
    /// </summary>
    public static AudioClip m_audioClip = null;

    /// <summary>
    /// 音頻片段存放列表
    /// </summary>
    private List<byte[]> m_audioClipDataList = new List<byte[]>();

    /// <summary>
    /// 片段結(jié)束標(biāo)記
    /// </summary>
    private string m_currentRecorderSign;
    /// <summary>
    /// 音頻頻率
    /// </summary>
    private int m_audioFrequency;

    /// <summary>
    /// 單次最大錄制時間
    /// </summary>
    private const int maxRecordTime = 30;
    #endregion

    public void GetAudioData(string _audioDataString)
    {
        if (_audioDataString.Contains("Head"))
        {
            string[] _headValue = _audioDataString.Split('|');
            m_valuePartCount = int.Parse(_headValue[1]);
            m_audioLength = int.Parse(_headValue[2]);
            m_currentRecorderSign = _headValue[3];
            m_audioData = new string[m_valuePartCount];
            m_getDataLength = 0;
            Debug.Log("接收數(shù)據(jù)頭:" + m_valuePartCount + "   " + m_audioLength);
        }
        else if (_audioDataString.Contains("Part"))
        {
            string[] _headValue = _audioDataString.Split('|');
            int _dataIndex = int.Parse(_headValue[1]);
            m_audioData[_dataIndex] = _headValue[2];
            m_getDataLength++;
            if (m_getDataLength == m_valuePartCount)
            {
                StringBuilder stringBuilder = new StringBuilder();
                for (int i = 0; i < m_audioData.Length; i++)
                {
                    stringBuilder.Append(m_audioData[i]);
                }
                string _audioDataValue = stringBuilder.ToString();
                Debug.Log("接收長度:" + _audioDataValue.Length + " 需接收長度:" + m_audioLength);
                int _index = _audioDataValue.LastIndexOf(',');
                string _value = _audioDataValue.Substring(_index + 1, _audioDataValue.Length - _index - 1);
                byte[] data = Convert.FromBase64String(_value);
                Debug.Log("已接收長度 :" + data.Length);

                if (m_currentRecorderSign == "end")
                {
                    int _audioLength = data.Length;
                    for (int i = 0; i < m_audioClipDataList.Count; i++)
                    {
                        _audioLength += m_audioClipDataList[i].Length;
                    }
                    byte[] _audioData = new byte[_audioLength];
                    Debug.Log("總長度 :" + _audioLength);
                    int _audioIndex = 0;
                    data.CopyTo(_audioData, _audioIndex);
                    _audioIndex += data.Length;
                    Debug.Log("已賦值0:" + _audioIndex);
                    for (int i = 0; i < m_audioClipDataList.Count; i++)
                    {
                        m_audioClipDataList[i].CopyTo(_audioData, _audioIndex);
                        _audioIndex += m_audioClipDataList[i].Length;
                        Debug.Log("已賦值 :" + _audioIndex);
                    }

                    WAV wav = new WAV(_audioData);
                    AudioClip _audioClip = AudioClip.Create("TestWAV", wav.SampleCount, 1, wav.Frequency, false);
                    _audioClip.SetData(wav.LeftChannel, 0);

                    m_audioClip = _audioClip;
                    Debug.Log("音頻設(shè)置成功,已設(shè)置到unity。" + m_audioClip.length + "  " + m_audioClip.name);

                    m_audioSource.clip = m_audioClip;
                    m_audioSource.Play();

                    m_audioClipDataList.Clear();
                }
                else
                    m_audioClipDataList.Add(data);

                m_audioData = null;
            }
        }
    }
    #endregion
}

.js

AddToIndex.js

這個腳本中的內(nèi)容直接增加到index.html文件中

    <script src="./recorder.wav.min.js"></script>

      // 全局錄音實例
      let RecorderIns = null;
      //全局Unity實例   (全局找 unityInstance , 然后等于它就行)
      let UnityIns = null;

      // 初始化 ,   記得調(diào)用
      function initRecord(opt = {}) {
        let defaultOpt = {
          serviceCode: "asr_aword",
          audioFormat: "wav",
          sampleRate: 16000,
          sampleBit: 16,
          audioChannels: 1,
          bitRate: 96000,
          audioData: null,
          punctuation: "true",
          model: null,
          intermediateResult: null,
          maxStartSilence: null,
          maxEndSilence: null,
        };

        let options = Object.assign({}, defaultOpt, opt);

        let sampleRate = options.sampleRate || 8000;
        let bitRate = parseInt(options.bitRate / 1000) || 16;
        if (RecorderIns) {
          RecorderIns.close();
        }

        RecorderIns = Recorder({
          type: "wav",
          sampleRate: sampleRate,
          bitRate: bitRate,
          onProcess(buffers, powerLevel, bufferDuration, bufferSampleRate) {
            // 60秒時長限制
            const LEN = 59 * 1000;
            if (bufferDuration > LEN) {
              RecorderIns.recStop();
            }
          },
        });
        RecorderIns.open(
          () => {
            // 打開麥克風(fēng)授權(quán)獲得相關(guān)資源
            console.log("打開麥克風(fēng)成功");
          },
          (msg, isUserNotAllow) => {
            // 用戶拒絕未授權(quán)或不支持
            console.log((isUserNotAllow ? "UserNotAllow," : "") + "無法錄音:" + msg);
          }
        );
      }

      // 開始
      function StartRecord() {
        RecorderIns.start();
      }
      // 結(jié)束
      function StopRecord() {
        RecorderIns.stop(
          (blob, duration) => {
            console.log(
              blob,
              window.URL.createObjectURL(blob),
              "時長:" + duration + "ms"
            );
            sendWavData(blob)
          },
          (msg) => {
            console.log("錄音失敗:" + msg);
          }
        );
      }
      
      // 切片像unity發(fā)送音頻數(shù)據(jù)
      function sendWavData(blob) {
        var reader = new FileReader();
        reader.onload = function (e) {
          var _value = reader.result;
          var _partLength = 8192;
          var _length = parseInt(_value.length / _partLength);
          if (_length * _partLength < _value.length) _length += 1;
          var _head = "Head|" + _length.toString() + "|" + _value.length.toString() + "|end" ;
          // 發(fā)送數(shù)據(jù)頭
          UnityIns.SendMessage("SignalManager", "GetAudioData", _head);
          for (var i = 0; i < _length; i++) {
            var _sendValue = "";
            if (i < _length - 1) {
              _sendValue = _value.substr(i * _partLength, _partLength);
            } else {
              _sendValue = _value.substr(
                i * _partLength,
                _value.length - i * _partLength
              );
            }
            _sendValue = "Part|" + i.toString() + "|" + _sendValue;
            // 發(fā)送分片數(shù)據(jù)
            UnityIns.SendMessage("SignalManager", "GetAudioData", _sendValue);
          }
          _value = null;
        };
        reader.readAsDataURL(blob);
      }

recorder.wav.min.js

這個直接創(chuàng)建腳本放到index.html同級目錄下

/*
錄音
https://github.com/xiangyuecn/Recorder
src: recorder-core.js,engine/wav.js
*/
!function(h){"use strict";var d=function(){},A=function(e){return new t(e)};A.IsOpen=function(){var e=A.Stream;if(e){var t=e.getTracks&&e.getTracks()||e.audioTracks||[],n=t[0];if(n){var r=n.readyState;return"live"==r||r==n.LIVE}}return!1},A.BufferSize=4096,A.Destroy=function(){for(var e in F("Recorder Destroy"),g(),n)n[e]()};var n={};A.BindDestroy=function(e,t){n[e]=t},A.Support=function(){var e=h.AudioContext;if(e||(e=h.webkitAudioContext),!e)return!1;var t=navigator.mediaDevices||{};return t.getUserMedia||(t=navigator).getUserMedia||(t.getUserMedia=t.webkitGetUserMedia||t.mozGetUserMedia||t.msGetUserMedia),!!t.getUserMedia&&(A.Scope=t,A.Ctx&&"closed"!=A.Ctx.state||(A.Ctx=new e,A.BindDestroy("Ctx",function(){var e=A.Ctx;e&&e.close&&(e.close(),A.Ctx=0)})),!0)};var S=function(e){var t=(e=e||A).BufferSize||A.BufferSize,n=A.Ctx,r=e.Stream,a=r._m=n.createMediaStreamSource(r),o=r._p=(n.createScriptProcessor||n.createJavaScriptNode).call(n,t,1,1);a.connect(o),o.connect(n.destination);var f=r._call;o.onaudioprocess=function(e){for(var t in f){for(var n=e.inputBuffer.getChannelData(0),r=n.length,a=new Int16Array(r),o=0,s=0;s<r;s++){var i=Math.max(-1,Math.min(1,n[s]));i=i<0?32768*i:32767*i,a[s]=i,o+=Math.abs(i)}for(var c in f)f[c](a,o);return}}},g=function(e){var t=(e=e||A)==A,n=e.Stream;if(n&&(n._m&&(n._m.disconnect(),n._p.disconnect(),n._p.onaudioprocess=n._p=n._m=null),t)){for(var r=n.getTracks&&n.getTracks()||n.audioTracks||[],a=0;a<r.length;a++){var o=r[a];o.stop&&o.stop()}n.stop&&n.stop()}e.Stream=0};A.SampleData=function(e,t,n,r,a){r||(r={});var o=r.index||0,s=r.offset||0,i=r.frameNext||[];a||(a={});var c=a.frameSize||1;a.frameType&&(c="mp3"==a.frameType?1152:1);for(var f=0,u=o;u<e.length;u++)f+=e[u].length;f=Math.max(0,f-Math.floor(s));var l=t/n;1<l?f=Math.floor(f/l):(l=1,n=t),f+=i.length;for(var v=new Int16Array(f),p=0,u=0;u<i.length;u++)v[p]=i[u],p++;for(var m=e.length;o<m;o++){for(var h=e[o],u=s,d=h.length;u<d;){var S=Math.floor(u),g=Math.ceil(u),_=u-S,y=h[S],I=g<d?h[g]:(e[o+1]||[y])[0]||0;v[p]=y+(I-y)*_,p++,u+=l}s=u-d}i=null;var M=v.length%c;if(0<M){var x=2*(v.length-M);i=new Int16Array(v.buffer.slice(x)),v=new Int16Array(v.buffer.slice(0,x))}return{index:o,offset:s,frameNext:i,sampleRate:n,data:v}},A.PowerLevel=function(e,t){var n=e/t||0;return n<1251?Math.round(n/1250*10):Math.round(Math.min(100,Math.max(0,100*(1+Math.log(n/1e4)/Math.log(10)))))};var F=function(e,t){var n=new Date,r=("0"+n.getMinutes()).substr(-2)+":"+("0"+n.getSeconds()).substr(-2)+"."+("00"+n.getMilliseconds()).substr(-3),a=["["+r+" Recorder]"+e],o=arguments,s=2,i=console.log;for("number"==typeof t?i=1==t?console.error:3==t?console.warn:i:s=1;s<o.length;s++)a.push(o[s]);i.apply(console,a)};A.CLog=F;var r=0;function t(e){this.id=++r,A.Traffic&&A.Traffic();var t={type:"mp3",bitRate:16,sampleRate:16e3,onProcess:d};for(var n in e)t[n]=e[n];this.set=t,this._S=9,this.Sync={O:9,C:9}}A.Sync={O:9,C:9},A.prototype=t.prototype={_streamStore:function(){return this.set.sourceStream?this:A},open:function(e,n){var t=this,r=t._streamStore();e=e||d;var a=function(e,t){F("錄音open失?。?+e+",isUserNotAllow:"+(t=!!t),1),n&&n(e,t)},o=function(){F("open成功"),e(),t._SO=0},s=r.Sync,i=++s.O,c=s.C;t._O=t._O_=i,t._SO=t._S;var f=function(){if(c!=s.C||!t._O){var e="open被取消";return i==s.O?t.close():e="open被中斷",a(e),!0}},u=t.envCheck({envName:"H5",canProcess:!0});if(u)a("不能錄音:"+u);else if(t.set.sourceStream){if(!A.Support())return void a("不支持此瀏覽器從流中獲取錄音");g(r),t.Stream=t.set.sourceStream,t.Stream._call={};try{S(r)}catch(e){return void a("從流中打開錄音失?。?+e.message)}o()}else{var l=function(e,t){try{h.top.a}catch(e){return void a('無權(quán)錄音(跨域,請嘗試給iframe添加麥克風(fēng)訪問策略,如allow="camera;microphone")')}/Permission|Allow/i.test(e)?a("用戶拒絕了錄音權(quán)限",!0):!1===h.isSecureContext?a("無權(quán)錄音(需https)"):/Found/i.test(e)?a(t+",無可用麥克風(fēng)"):a(t)};if(A.IsOpen())o();else if(A.Support()){var v=function(e){(A.Stream=e)._call={},f()||setTimeout(function(){f()||(A.IsOpen()?(S(),o()):a("錄音功能無效:無音頻流"))},100)},p=function(e){var t=e.name||e.message||e.code+":"+e;F("請求錄音權(quán)限錯誤",1,e),l(t,"無法錄音:"+t)},m=A.Scope.getUserMedia({audio:t.set.audioTrackSet||!0},v,p);m&&m.then&&m.then(v)[e&&"catch"](p)}else l("","此瀏覽器不支持錄音")}},close:function(e){e=e||d;var t=this._streamStore();this._stop();var n=t.Sync;if(this._O=0,this._O_!=n.O)return F("close被忽略",3),void e();n.C++,g(t),F("close"),e()},mock:function(e,t){var n=this;return n._stop(),n.isMock=1,n.mockEnvInfo=null,n.buffers=[e],n.recSize=e.length,n.srcSampleRate=t,n},envCheck:function(e){var t,n=this.set;return t||(this[n.type+"_envCheck"]?t=this[n.type+"_envCheck"](e,n):n.takeoffEncodeChunk&&(t=n.type+"類型不支持設(shè)置takeoffEncodeChunk")),t||""},envStart:function(e,t){var n=this,r=n.set;if(n.isMock=e?1:0,n.mockEnvInfo=e,n.buffers=[],n.recSize=0,n.envInLast=0,n.envInFirst=0,n.envInFix=0,n.envInFixTs=[],r.sampleRate=Math.min(t,r.sampleRate),n.srcSampleRate=t,n.engineCtx=0,n[r.type+"_start"]){var a=n.engineCtx=n[r.type+"_start"](r);a&&(a.pcmDatas=[],a.pcmSize=0)}},envResume:function(){this.envInFixTs=[]},envIn:function(e,t){var a=this,o=a.set,s=a.engineCtx,n=a.srcSampleRate,r=e.length,i=A.PowerLevel(t,r),c=a.buffers,f=c.length;c.push(e);var u=c,l=f,v=Date.now(),p=Math.round(r/n*1e3);a.envInLast=v,1==a.buffers.length&&(a.envInFirst=v-p);var m=a.envInFixTs;m.splice(0,0,{t:v,d:p});for(var h=v,d=0,S=0;S<m.length;S++){var g=m[S];if(3e3<v-g.t){m.length=S;break}h=g.t,d+=g.d}var _=m[1],y=v-h;if(y/3<y-d&&(_&&1e3<y||6<=m.length)){var I=v-_.t-p;if(p/5<I){var M=!o.disableEnvInFix;if(F("["+v+"]"+(M?"":"未")+"補償"+I+"ms",3),a.envInFix+=I,M){var x=new Int16Array(I*n/1e3);r+=x.length,c.push(x)}}}var k=a.recSize,C=r,w=k+C;if(a.recSize=w,s){var R=A.SampleData(c,n,o.sampleRate,s.chunkInfo);s.chunkInfo=R,w=(k=s.pcmSize)+(C=R.data.length),s.pcmSize=w,c=s.pcmDatas,f=c.length,c.push(R.data),n=R.sampleRate}var b=Math.round(w/n*1e3),T=c.length,z=u.length,D=function(){for(var e=O?0:-C,t=null==c[0],n=f;n<T;n++){var r=c[n];null==r?t=1:(e+=r.length,s&&r.length&&a[o.type+"_encode"](s,r))}if(t&&s)for(n=l,u[0]&&(n=0);n<z;n++)u[n]=null;t&&(e=O?C:0,c[0]=null),s?s.pcmSize+=e:a.recSize+=e},O=o.onProcess(c,i,b,n,f,D);if(!0===O){var U=0;for(S=f;S<T;S++)null==c[S]?U=1:c[S]=new Int16Array(0);U?F("未進入異步前不能清除buffers",3):s?s.pcmSize-=C:a.recSize-=C}else D()},start:function(){var e=this,t=A.Ctx,n=1;if(e.set.sourceStream?e.Stream||(n=0):A.IsOpen()||(n=0),n)if(F("開始錄音"),e._stop(),e.state=0,e.envStart(null,t.sampleRate),e._SO&&e._SO+1!=e._S)F("start被中斷",3);else{e._SO=0;var r=function(){e.state=1,e.resume()};"suspended"==t.state?t.resume().then(function(){F("ctx resume"),r()}):r()}else F("未open",1)},pause:function(){this.state&&(this.state=2,F("pause"),delete this._streamStore().Stream._call[this.id])},resume:function(){var n=this;n.state&&(n.state=1,F("resume"),n.envResume(),n._streamStore().Stream._call[n.id]=function(e,t){1==n.state&&n.envIn(e,t)})},_stop:function(e){var t=this,n=t.set;t.isMock||t._S++,t.state&&(t.pause(),t.state=0),!e&&t[n.type+"_stop"]&&(t[n.type+"_stop"](t.engineCtx),t.engineCtx=0)},stop:function(n,t,e){var r,a=this,o=a.set;F("Stop "+(a.envInLast?a.envInLast-a.envInFirst+"ms 補"+a.envInFix+"ms":"-"));var s=function(){a._stop(),e&&a.close()},i=function(e){F("結(jié)束錄音失敗:"+e,1),t&&t(e),s()},c=function(e,t){if(F("結(jié)束錄音 編碼"+(Date.now()-r)+"ms 音頻"+t+"ms/"+e.size+"b"),o.takeoffEncodeChunk)F("啟用takeoffEncodeChunk后stop返回的blob長度為0不提供音頻數(shù)據(jù)",3);else if(e.size<Math.max(100,t/2))return void i("生成的"+o.type+"無效");n&&n(e,t),s()};if(!a.isMock){if(!a.state)return void i("未開始錄音");a._stop(!0)}var f=a.recSize;if(f)if(a.buffers[0])if(a[o.type]){if(a.isMock){var u=a.envCheck(a.mockEnvInfo||{envName:"mock",canProcess:!1});if(u)return void i("錄音錯誤:"+u)}var l=a.engineCtx;if(a[o.type+"_complete"]&&l){var v=Math.round(l.pcmSize/o.sampleRate*1e3);return r=Date.now(),void a[o.type+"_complete"](l,function(e){c(e,v)},i)}r=Date.now();var p=A.SampleData(a.buffers,a.srcSampleRate,o.sampleRate);o.sampleRate=p.sampleRate;var m=p.data;v=Math.round(m.length/o.sampleRate*1e3),F("采樣"+f+"->"+m.length+" 花:"+(Date.now()-r)+"ms"),setTimeout(function(){r=Date.now(),a[o.type](m,function(e){c(e,v)},function(e){i(e)})})}else i("未加載"+o.type+"編碼器");else i("音頻被釋放");else i("未采集到錄音")}},h.Recorder&&h.Recorder.Destroy(),(h.Recorder=A).LM="2021-08-03 20:01:03",A.TrafficImgUrl="",A.Traffic=function(){var e=A.TrafficImgUrl;if(e){var t=A.Traffic,n=location.href.replace(/#.*/,"");if(0==e.indexOf("http://")&&(e=/^https:/i.test(n)?"https:"+e:"http:"+e),!t[n]){t[n]=1;var r=new Image;r.src=e,F("Traffic Analysis Image: Recorder.TrafficImgUrl="+A.TrafficImgUrl)}}}}(window),"function"==typeof define&&define.amd&&define(function(){return Recorder}),"object"==typeof module&&module.exports&&(module.exports=Recorder),function(){"use strict";Recorder.prototype.enc_wav={stable:!0,testmsg:"支持位數(shù)8位、16位(填在比特率里面),采樣率取值無限制"},Recorder.prototype.wav=function(e,t,n){var r=this.set,a=e.length,o=r.sampleRate,s=8==r.bitRate?8:16,i=a*(s/8),c=new ArrayBuffer(44+i),f=new DataView(c),u=0,l=function(e){for(var t=0;t<e.length;t++,u++)f.setUint8(u,e.charCodeAt(t))},v=function(e){f.setUint16(u,e,!0),u+=2},p=function(e){f.setUint32(u,e,!0),u+=4};if(l("RIFF"),p(36+i),l("WAVE"),l("fmt "),p(16),v(1),v(1),p(o),p(o*(s/8)),v(s/8),v(s),l("data"),p(i),8==s)for(var m=0;m<a;m++,u++){var h=128+(e[m]>>8);f.setInt8(u,h,!0)}else for(m=0;m<a;m++,u+=2)f.setInt16(u,e[m],!0);t(new Blob([f.buffer],{type:"audio/wav"}))}}();

參考鏈接:

Recorder用于html5錄音? (recorder-core.js,engine/wav.js

Unity WebGL基于js通信實現(xiàn)網(wǎng)頁錄音? (sendWAVData.js,GetAudioData.cs,WAV.cs


希望大家:點贊,留言,關(guān)注咯~ ? ?

????????文章來源地址http://www.zghlxwxcb.cn/news/detail-400657.html

嘮家常

  • Xiaohei.Wang(Wenhao)的今日分享結(jié)束啦,小伙伴們你們get到了么,你們有沒有更好的辦法呢,可以評論區(qū)留言分享,也可以加我的QQ:841298494 (記得備注),大家一起進步。

今日無推薦

  • 客官,看完get之后記得點贊喲!
  • 小伙伴你還想要別的知識?好的呀,分享給你們??
  • 小黑的雜貨鋪,想要什么都有,客官不進來喝杯茶么?

到了這里,關(guān)于Unity-WebGL基于JS實現(xiàn)網(wǎng)頁錄音的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • unity webgl網(wǎng)頁運行后屏幕模糊,UI無響應(yīng)問題解決

    【記一個莫名其妙的問題】 工具:Unity 2019.4.40f1c1 先前Unity打包apk,設(shè)置了最大幀率15 在Project Settings -Quality中設(shè)置了Other-VSync Count:Don’t Sync 運行后,幀率穩(wěn)定在100上下,呵呵 后來在代碼中加了一行: 問題解決 今天,準(zhǔn)備再打一個webgl包 打包運行后,打開網(wǎng)頁,畫面停留在

    2024年02月06日
    瀏覽(15)
  • unity webGL與js 交互(獲取地址欄URL)

    unity webGL與js 交互(獲取地址欄URL)

    1.unity傳值給js unity中: js中: 2.js傳值給unity 參數(shù)一 Cookie:場景中物體的名稱 (最上層父物體名字,否則無法成功傳值) 參數(shù)二 OnCookie_Callback:方法名稱 參數(shù)三 result:值 unity中: 完整: unity場景中物體的名稱 ?untiy代碼: js代碼:

    2024年02月04日
    瀏覽(23)
  • Unity打包瀏覽器端網(wǎng)頁HTML(WebGL)以及部署到Tomcat瀏覽器訪問報錯問題解決

    Unity打包瀏覽器端網(wǎng)頁HTML(WebGL)以及部署到Tomcat瀏覽器訪問報錯問題解決

    Unity 默認打包是 PC 端客戶端程序,想要打包瀏覽器可以訪問的 WebGL 網(wǎng)頁,需要修改一些配置。 我使用的 Unity 版本是 2021.3.24f1 。 1.1 點擊 File —— Build Settings... 1.2 點擊 Add Open Scenes .把全部場景加入 Scene In Build 列表中 網(wǎng)上說不全部加進去會找不到需要跳轉(zhuǎn)的場景,我還沒涉

    2024年02月16日
    瀏覽(26)
  • js前端實現(xiàn)語言識別(asr)與錄音

    js前端實現(xiàn)語言識別(asr)與錄音

    實習(xí)的時候,領(lǐng)導(dǎo)要求驗證一下在web前端實現(xiàn)錄音和語音識別,查了一下發(fā)現(xiàn)網(wǎng)上有關(guān)語音識別也就是語音轉(zhuǎn)文字幾乎沒有任何教程。 其實有一種方案,前端先錄音然后把錄音傳到后端,后端在請求如百度語音轉(zhuǎn)文字的api進行識別,但是這種就需要再寫個后端。如果直接前端

    2024年02月11日
    瀏覽(12)
  • 利用RecordRTC.js實現(xiàn)H5錄音功能

    利用RecordRTC.js實現(xiàn)H5錄音功能

    前言: 最近遇到 要語音轉(zhuǎn)文字 的需求,語音轉(zhuǎn)文字肯定要先搞定錄音功能,在網(wǎng)上找了好久沒找到具體的?RecordRTC.js 插件的使用方法,最后只能對著 github 上開源代碼小試了一下,錄音功能好使所以就記錄一下叭 一、RecordRTC.js 源碼指路 https://github.com/muaz-khan/RecordRTC 二、功

    2024年02月05日
    瀏覽(12)
  • Unity如何實現(xiàn)Microphone實時錄音的頻率數(shù)據(jù)提取

    Unity如何實現(xiàn)Microphone實時錄音的頻率數(shù)據(jù)提取

    Unity中使用Microphone可以通過麥克風(fēng)錄制AudioClip音頻,我們可以通過它實現(xiàn)錄音功能,然后可以通過錄入的音頻數(shù)據(jù)對音頻進行分析,比如音量大小,頻率高低,等等。 我們今天就來分析一下音頻的高音低音。 科普:一般人們習(xí)慣將音響劃分一定的頻段如高音、中音和低音等

    2024年02月11日
    瀏覽(17)
  • vue3實現(xiàn)H5網(wǎng)頁錄音并上傳(mp3、wav)兼容Android、iOS和PC端

    使用 Recorder插件 可以在HTML5網(wǎng)頁中進行錄音,錄音完成后得到blob文件對象,然后將blob上傳到服務(wù)器;項目使用的vue3.0版本(這個插件同時支持vue2.0、也支持uniapp,很強!?。浺暨^程中會顯示可視化波形,同時能夠做到兼容PC端、Android、和iOS,一次編碼 到處運行,哈哈

    2024年02月08日
    瀏覽(33)
  • 基于Unity開發(fā)WebGL項目加載AB包(三)

    基于Unity開發(fā)WebGL項目加載AB包(三)

    在前兩篇文章中,我們分別了解了WebGL如何通過StreamingAssets加載AB包資源(鏈接:基于Unity開發(fā)WebGL項目加載AB包(一)_梵高先森丶的博客-CSDN博客)和如何通過局域網(wǎng)(本地服務(wù)器)加載AB包資源(鏈接:基于Unity開發(fā)WebGL項目加載AB包(二)_梵高先森丶的博客-CSDN博客),那么本文,

    2024年02月13日
    瀏覽(23)
  • 有趣且重要的JS知識合集(18)瀏覽器實現(xiàn)前端錄音功能

    有趣且重要的JS知識合集(18)瀏覽器實現(xiàn)前端錄音功能

    兼容多個瀏覽器下的前端錄音功能,實現(xiàn)六大錄音功能: 1、開始錄音 2、暫停錄音 3、繼續(xù)錄音 4、結(jié)束錄音 5、播放錄音 6、上傳錄音 初始狀態(tài): 開始錄音: 結(jié)束錄音: 錄音流程 : 示例中的三個按鈕其實包含了六個上述功能,點擊開始時開始錄音,可以暫停/結(jié)束錄音,此

    2024年02月04日
    瀏覽(22)
  • 基于Unity+Vue3通信交互的WebGL項目發(fā)布實踐

    基于Unity+Vue3通信交互的WebGL項目發(fā)布實踐

    問題背景 我們最近需要把unity開發(fā)的pc項目遷移到web端,因為unity支持發(fā)布webgl。所以按照以往的開發(fā)流程,都是項目開發(fā)完成就發(fā)布webgl部署到服務(wù)器。 突然有一天,測試人員提出說為什么我們做的網(wǎng)頁跟別人的不太一樣呢?具體看下面兩張圖: 1、unity使用ugui做的界面發(fā)布

    2024年04月17日
    瀏覽(30)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包