2023-01-11 21:49:22 +03:00
import { VoiceChangerWorkletProcessorRequest } from "./@types/voice-changer-worklet-processor" ;
2023-02-12 07:24:30 +03:00
import { WorkletSetting } from "./const" ;
2023-02-19 19:00:28 +03:00
import { io , Socket } from "socket.io-client" ;
import { DefaultEventsMap } from "@socket.io/component-emitter" ;
2023-01-11 21:49:22 +03:00
2023-02-12 11:07:28 +03:00
export type VoiceChangerWorkletListener = {
2023-01-05 05:45:42 +03:00
notifyVolume : ( vol : number ) = > void
2023-02-12 11:07:28 +03:00
notifyOutputRecordData : ( data : Float32Array [ ] ) = > void
2023-01-05 05:45:42 +03:00
}
2023-01-04 20:28:36 +03:00
export class VoiceChangerWorkletNode extends AudioWorkletNode {
2023-02-12 11:07:28 +03:00
private listener : VoiceChangerWorkletListener
2023-02-19 19:00:28 +03:00
private requestChunks : ArrayBuffer [ ] = [ ]
private socket : Socket < DefaultEventsMap , DefaultEventsMap > | null = null
2023-02-12 11:07:28 +03:00
constructor ( context : AudioContext , listener : VoiceChangerWorkletListener ) {
2023-01-04 20:28:36 +03:00
super ( context , "voice-changer-worklet-processor" ) ;
this . port . onmessage = this . handleMessage . bind ( this ) ;
2023-01-05 05:45:42 +03:00
this . listener = listener
2023-02-19 19:00:28 +03:00
this . createSocketIO ( )
2023-01-04 20:28:36 +03:00
console . log ( ` [worklet_node][voice-changer-worklet-processor] created. ` ) ;
}
2023-02-12 07:29:50 +03:00
postReceivedVoice = ( data : ArrayBuffer ) = > {
const req : VoiceChangerWorkletProcessorRequest = {
requestType : "voice" ,
voice : data ,
numTrancateTreshold : 0 ,
volTrancateThreshold : 0 ,
volTrancateLength : 0
}
this . port . postMessage ( req )
2023-01-04 20:28:36 +03:00
}
2023-02-19 19:00:28 +03:00
private createSocketIO = ( ) = > {
if ( this . socket ) {
this . socket . close ( )
}
// if (this.setting.protocol === "sio") {
// this.socket = io(this.setting.serverUrl + "/test");
this . socket = io ( "/test" ) ;
this . socket . on ( 'connect_error' , ( err ) = > {
console . log ( "connect exception !!!!!" )
// this.audioStreamerListeners.notifyException(VOICE_CHANGER_CLIENT_EXCEPTION.ERR_SIO_CONNECT_FAILED, `[SIO] rconnection failed ${err}`)
} )
this . socket . on ( 'connect' , ( ) = > {
// console.log(`[SIO] sonnect to ${this.setting.serverUrl}`)
console . log ( ` [SIO] ${ this . socket ? . id } ` )
} ) ;
this . socket . on ( 'response' , ( response : any [ ] ) = > {
const cur = Date . now ( )
const responseTime = cur - response [ 0 ]
const result = response [ 1 ] as ArrayBuffer
if ( result . byteLength < 128 * 2 ) {
console . log ( "tooshort!!" )
// this.audioStreamerListeners.notifyException(VOICE_CHANGER_CLIENT_EXCEPTION.ERR_SIO_INVALID_RESPONSE, `[SIO] recevied data is too short ${result.byteLength}`)
} else {
console . log ( "response!!!" )
this . postReceivedVoice ( response [ 1 ] )
// this.callbacks.onVoiceReceived(response[1])
// this.audioStreamerListeners.notifyResponseTime(responseTime)
}
} ) ;
// }
}
2023-01-04 20:28:36 +03:00
handleMessage ( event : any ) {
2023-01-05 05:45:42 +03:00
// console.log(`[Node:handleMessage_] `, event.data.volume);
2023-02-12 07:24:30 +03:00
if ( event . data . responseType === "volume" ) {
this . listener . notifyVolume ( event . data . volume as number )
} else if ( event . data . responseType === "recordData" ) {
2023-02-12 11:07:28 +03:00
this . listener . notifyOutputRecordData ( event . data . recordData as Float32Array [ ] )
2023-02-19 19:00:28 +03:00
} else if ( event . data . responseType === "inputData" ) {
const inputData = event . data . inputData as Float32Array
// console.log("receive input data", inputData)
const arrayBuffer = new ArrayBuffer ( inputData . length * 2 )
const dataView = new DataView ( arrayBuffer ) ;
for ( let i = 0 ; i < inputData . length ; i ++ ) {
let s = Math . max ( - 1 , Math . min ( 1 , inputData [ i ] ) ) ;
s = s < 0 ? s * 0x8000 : s * 0x7FFF
dataView . setInt16 ( i * 2 , s , true ) ;
}
this . requestChunks . push ( arrayBuffer )
//// リクエストバッファの中身が、リクエスト送信数と違う場合は処理終了。
if ( this . requestChunks . length < 32 ) {
return
}
console . log ( "sending..." )
// リクエスト用の入れ物を作成
const windowByteLength = this . requestChunks . reduce ( ( prev , cur ) = > {
return prev + cur . byteLength
} , 0 )
const newBuffer = new Uint8Array ( windowByteLength ) ;
// リクエストのデータをセット
this . requestChunks . reduce ( ( prev , cur ) = > {
newBuffer . set ( new Uint8Array ( cur ) , prev )
return prev + cur . byteLength
} , 0 )
this . sendBuffer ( newBuffer )
console . log ( "sended..." )
this . requestChunks = [ ]
2023-02-12 07:24:30 +03:00
} else {
console . warn ( ` [worklet_node][voice-changer-worklet-processor] unknown response ${ event . data . responseType } ` , event . data )
}
}
2023-02-19 19:00:28 +03:00
private sendBuffer = async ( newBuffer : Uint8Array ) = > {
const timestamp = Date . now ( )
// if (this.setting.protocol === "sio") {
if ( ! this . socket ) {
console . warn ( ` sio is not initialized ` )
return
}
// console.log("emit!")
this . socket . emit ( 'request_message' , [
timestamp ,
newBuffer . buffer ] ) ;
// } else {
// const res = await postVoice(
// this.setting.serverUrl + "/test",
// timestamp,
// newBuffer.buffer)
// if (res.byteLength < 128 * 2) {
// this.audioStreamerListeners.notifyException(VOICE_CHANGER_CLIENT_EXCEPTION.ERR_REST_INVALID_RESPONSE, `[REST] recevied data is too short ${res.byteLength}`)
// } else {
// this.callbacks.onVoiceReceived(res)
// this.audioStreamerListeners.notifyResponseTime(Date.now() - timestamp)
// }
// }
}
2023-02-12 07:24:30 +03:00
configure = ( setting : WorkletSetting ) = > {
const req : VoiceChangerWorkletProcessorRequest = {
requestType : "config" ,
voice : new ArrayBuffer ( 1 ) ,
numTrancateTreshold : setting.numTrancateTreshold ,
volTrancateThreshold : setting.volTrancateThreshold ,
volTrancateLength : setting.volTrancateLength
}
this . port . postMessage ( req )
}
startOutputRecordingWorklet = ( ) = > {
const req : VoiceChangerWorkletProcessorRequest = {
requestType : "startRecording" ,
voice : new ArrayBuffer ( 1 ) ,
numTrancateTreshold : 0 ,
volTrancateThreshold : 0 ,
volTrancateLength : 0
}
this . port . postMessage ( req )
}
stopOutputRecordingWorklet = ( ) = > {
const req : VoiceChangerWorkletProcessorRequest = {
requestType : "stopRecording" ,
voice : new ArrayBuffer ( 1 ) ,
numTrancateTreshold : 0 ,
volTrancateThreshold : 0 ,
volTrancateLength : 0
}
this . port . postMessage ( req )
2023-01-04 20:28:36 +03:00
}
}