Normally, files have suffixes, such as: kunkun dribble.gif, kunkun dance.avi

But there are also files with or without suffixes. Try removing the suffix from kunkun’s dribble. GIF file and opening the file with a picture viewer to see kunkun’s superb skills as well.

This shows that changing the suffix of a file does not affect the content of the file itself. It also means that there’s something in the file’s data that identifies the type of file.

By saying so much above, I actually want to introduce the concept of Magic Number. To put it simply, Magic Number consists of the first few bytes of file data, which are the same for all files of the same type, so it can identify the type of a file. As these numbers are literally incomprehensible, they are called Magic Number (File Signatures).

Use Magic Number to determine the file type

First of all there’s a file URL that tells you this is an audio file, can you tell what kind of audio file it is?

const url = 'https://0345-1400187352-1256635546.cos.ap-shanghai.myqcloud.com/rychou/e3801cfc517873a5a5471241e1da1869'
Copy the code

Obviously not, because this file doesn’t have a suffix. Let’s see how Magic Number can be used to determine the type of audio file.

Find the Magic Number for different types of files

You can refer to the Magic Number Table to find the Magic Number of different types of files.

For example, if you search for MP3 files, the Magic Number of the MP3 file type is 49 44 33. Notice this is a hexadecimal number.

 // Common audio file magic number
const hexMap = {
 '494433': 'mp3'.'664c614300000022': 'flac'.'2321414d52': 'amr'.'fff1': 'aac'.'fff9': 'aac'.'4f67675300020000000000000000': 'oga'.'52494646xxxxxxxx57415645666d7420': 'wav'.'3026b2758e66cf11a6d900aa0062ce6c': 'wma'
}

// Determine the type using a hexadecimal string
const isAAC = hex= >!!!!! hexMap[hex.slice(0.4)]
const isMP3 = hex= >!!!!! hexMap[hex.slice(0.6)]
const isAMR = hex= >!!!!! hexMap[hex.slice(0.10)]
const isFLAC = hex= >!!!!! hexMap[hex.slice(0.16)]
const isWAV = hex= >!!!!! hexMap[hex.slice(0.32)]
const isWMA = hex= >!!!!! hexMap[hex.slice(0.32)]
const isOGA = hex= >!!!!! hexMap[hex.slice(0.28)]
Copy the code

Once the Magic Number of the file is found, it is easy to determine the type of the file.

Request file data and convert toArray Buffer

/** * load file * @param {string} url - audio file url * @returns {Promise} */
function loadFile(url) {
 return new Promise((resolve, reject) = > {
   const xhr = new XMLHttpRequest()
   xhr.onreadystatechange = function() {
     if (xhr.readyState === 4) {
       resolve(xhr)
     }
   }
   xhr.onerror = reject
   xhr.open('GET', url, true)
   xhr.responseType = 'arraybuffer'
   xhr.send(' ')})}Copy the code

Buffer converts to a hexadecimal string

/** * buffer to hexadecimal string * @param {ArrayBuffer} buffer * @returns */
function buf2hex(buffer) {
  // buffer is an ArrayBuffer
  return Array.prototype.map.call(new Uint8Array(buffer), x => ('00' + x.toString(16)).slice(2 -)).join(' ')}Copy the code

Determine type

function getAudioType(url) {
  return loadFile(url).then(xhr= > {
      const hex = buf2hex(buffer)
      if (isAAC(hex)) {
        return 'aac'
      } else if (isAMR(hex)) {
        return 'amr'
      } else if (isMP3(hex)) {
        return 'mp3'
      } else if (isFLAC(hex)) {
        return 'flac'
      } else if (isWAV(hex)) {
        return 'wav'
      } else if (isWMA(hex)) {
        return 'wma'
      } else if (isOGA(hex)) {
        return 'oga'
      } else {
        return false}})}Copy the code

After a series of operations, it can be concluded that the audio file is an AAC file.

conclusion

Not only audio files, but all file types can be determined by Magic Number. The principle is the same. As long as the Number can be found, the type can be determined regardless of whether the file suffix is present.

Finally, according to the above method and the actual requirements of the recent project, an NPM package — Audio-type-Detect for determining the type of audio files is written for your reference.