import * as capture from "./capture" ; import * as net from "./net" ; import * as ui from "./ui" ; import * as waveform from "./waveform" ; export const supported = ! capture . isSafari ( ) ; interface Compressor { ac : AudioContext & { ecDestination ? : MediaStreamAudioDestinationNode ; } ; inputStream : MediaStream ; input : MediaStreamAudioSourceNode ; waveview : AudioNode ; compressor : AudioNode ; cp : Promise < unknown > ; pts : number ; buffer : Float32Array ; gain : GainNode ; } export const rtcCompression = { waveviewing : false , compressing : supported , gain : 1 , perUserGain : < { [ key ] : number ; } > { } , compressors : < Compressor [ ] > [ ] } ; export function createCompressor ( idx , ac , inputStream , wrapper ) { if ( rtcCompression . compressors [ idx ] ) destroyCompressor ( idx ) ; const com = { ac : ac , inputStream : inputStream , input : null , waveview : null , compressor : null , cp : Promise . all ( [ ] ) , pts : 0 , buffer : new Float32Array ( 0 ) , gain : null } ; const input = com . input = ac . createMediaStreamSource ( inputStream ) ; return Promise . all ( [ ] ) . then ( ( ) => { if ( supported ) { let waveviewCap ; let wf ; let compressorCap ; return Promise . all ( [ ] ) . then ( ( ) => { return capture . createCapture ( ac , { sampleRate : "sampleRate" , bufferSize : 1024 , workerCommand : { c : "max" } } ) ; } ) . then ( ret => { waveviewCap = ret ; com . waveview = waveviewCap . node ; wf = new waveform . Waveform ( "" + idx , ac . sampleRate / 1024 , wrapper , null ) ; waveviewCap . worker . onmessage = function ( ev ) { const max = ev . data . m ; wf . push ( max , ( max < 0.0001 ) ? 1 : 3 ) ; wf . updateWave ( max , true ) ; } ; return capture . createCapture ( ac , { sampleRate : "sampleRate" , bufferSize : 1024 , workerCommand : { c : "dynaudnorm" } } ) ; } ) . then ( ret => { compressorCap = ret ; com . compressor = compressorCap . node ; } ) ; } } ) . then ( ( ) => { const gain = com . gain = ac . createGain ( ) ; gain . gain . value = rtcCompression . gain * ( ( idx in rtcCompression . perUserGain ) ? rtcCompression . perUserGain [ idx ] : 1 ) ; let cur = input ; if ( com . waveview && rtcCompression . waveviewing ) { input . connect ( com . waveview ) ; cur = com . waveview ; } if ( com . compressor && rtcCompression . compressing ) { cur . connect ( com . compressor ) ; cur = com . compressor ; } cur . connect ( gain ) ; gain . connect ( ac . ecDestination ) ; const cs = rtcCompression . compressors ; while ( cs . length <= idx ) cs . push ( null ) ; cs [ idx ] = com ; return com ; } ) . catch ( net . promiseFail ( ) ) ; } export function destroyCompressor ( idx ) { const com = rtcCompression . compressors [ idx ] ; if ( ! com ) return ; rtcCompression . compressors [ idx ] = null ; let cur = com . input ; if ( com . waveview && rtcCompression . waveviewing ) { cur . disconnect ( com . waveview ) ; cur = com . waveview ; } if ( com . compressor && rtcCompression . compressing ) { cur . disconnect ( com . compressor ) ; cur = com . compressor ; } cur . disconnect ( com . gain ) ; com . gain . disconnect ( com . ac . ecDestination ) ; } function disconnectNodes ( ) { rtcCompression . compressors . forEach ( function ( com ) { if ( ! com ) return ; let cur = com . input ; if ( rtcCompression . waveviewing ) { cur . disconnect ( com . waveview ) ; cur = com . waveview ; } if ( rtcCompression . compressing ) { cur . disconnect ( com . compressor ) ; cur = com . compressor ; } cur . disconnect ( com . gain ) ; } ) ; } function reconnectNodes ( ) { rtcCompression . compressors . forEach ( function ( com ) { if ( ! com ) return ; let cur = com . input ; if ( rtcCompression . waveviewing ) { cur . connect ( com . waveview ) ; cur = com . waveview ; } if ( rtcCompression . compressing ) { cur . connect ( com . compressor ) ; cur = com . compressor ; } cur . connect ( com . gain ) ; } ) ; } export function setWaveviewing ( to ) { if ( rtcCompression . waveviewing === to || ! supported ) return ; disconnectNodes ( ) ; rtcCompression . waveviewing = to ; reconnectNodes ( ) ; } export function setCompressing ( to ) { if ( rtcCompression . compressing === to || ! supported ) return ; disconnectNodes ( ) ; rtcCompression . compressing = to ; reconnectNodes ( ) ; } export function setGlobalGain ( to ) { rtcCompression . gain = to ; for ( let idx = 0 ; idx < rtcCompression . compressors . length ; idx ++ ) { const com = rtcCompression . compressors [ idx ] ; if ( ! com ) continue ; const target = to * ( ( idx in rtcCompression . perUserGain ) ? rtcCompression . perUserGain [ idx ] : 1 ) ; com . gain . gain . setTargetAtTime ( target , 0 , 0.003 ) ; } } function setPerUserGain ( idx , to ) { rtcCompression . perUserGain [ idx ] = to ; const com = rtcCompression . compressors [ idx ] ; if ( ! com ) return ; const target = rtcCompression . gain * to ; com . gain . gain . setTargetAtTime ( target , 0 , 0.003 ) ; } ui . ui . outprocSetPerUserGain = setPerUserGain ;