@thumbmarkjs/thumbmarkjs
Version:
   • 2.13 kB
text/typescript
import { componentInterface } from '../../factory'
// Get the OfflineAudioContext constructor if available
const OfflineAudioContextClass = typeof window !== 'undefined'
? (window.OfflineAudioContext || (window as any).webkitOfflineAudioContext)
: null;
export default async function getAudio(): Promise<componentInterface | null> {
// Check if OfflineAudioContext is available
if (!OfflineAudioContextClass) {
return null;
}
return createAudioFingerprint();
}
async function createAudioFingerprint(): Promise<componentInterface> {
const resultPromise = new Promise<componentInterface>((resolve, reject) => {
try {
// Set up audio parameters
const sampleRate = 44100;
const numSamples = 5000;
const audioContext = new OfflineAudioContextClass!(1, numSamples, sampleRate);
const audioBuffer = audioContext.createBufferSource();
const oscillator = audioContext.createOscillator();
oscillator.frequency.value = 1000;
const compressor = audioContext.createDynamicsCompressor();
compressor.threshold.value = -50;
compressor.knee.value = 40;
compressor.ratio.value = 12;
compressor.attack.value = 0;
compressor.release.value = 0.2;
oscillator.connect(compressor);
compressor.connect(audioContext.destination);
oscillator.start();
let samples: Float32Array;
audioContext.oncomplete = event => {
samples = event.renderedBuffer.getChannelData(0);
resolve(
{
'sampleHash': calculateHash(samples),
'maxChannels': audioContext.destination.maxChannelCount,
'channelCountMode': audioBuffer.channelCountMode,
}
);
};
audioContext.startRendering();
} catch (error) {
reject(error);
}
});
return resultPromise;
}
function calculateHash(samples: Float32Array) {
let hash = 0;
for (let i = 0; i < samples.length; ++i) {
hash += Math.abs(samples[i]);
}
return hash;
}