Search code examples
javascriptphptelegram-bot

Telegram not plays recorded in Safari voice


Hello I have a small web app where the customer can leave a feedback of the restaurant. There is possible to record a voice note. When I record voice in Chrome, Firefox, Opera. On Mac or Windows everything works and I can hear the voice sent to telegram bot. But record in Safari voice plays without any voice. In IOS the same problem in both Chrome and Safari browsers.

Here is my code:

  const mic_btn = document.querySelector("#record__button");
  const playback = document.querySelector(".playback");
  const voiceRemove = document.getElementById("removeVoive");
  const voiceBody = document.querySelector(".record__body");
  const openRecorder = document.querySelector(".record__open-recorder");

  let counter = document.getElementById("counter");

  openRecorder.addEventListener("click", () => {
    voiceBody.classList.add("_active");
    setupAudio();
  });

  mic_btn.addEventListener("click", toggleMic);

  voiceRemove.addEventListener("click", () => {
    voiceRemove.classList.remove("_active");
    playback.classList.remove("_active");
    playback.src = "";
    counter.innerHTML = "1:00";
  });

  let can_record = false;
  let is_recording = false;
  let recorder = null;

  let chuncs = [];
  let voice = [];

  function setupAudio() {
    console.log("Sterted");
    if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
      navigator.mediaDevices
        .getUserMedia({
          audio: true,
        })
        .then(setupStream)
        .catch((err) => {
          console.error(err);
        });
    }
  }

  function setupStream(stream) {
    recorder = new MediaRecorder(stream);

    recorder.ondataavailable = (e) => {
      chuncs.push(e.data);
      voice.push(e.data);
    };
    recorder.onstop = () => {
      const blob = new Blob(chuncs, { type: "audio/wav" });
      chuncs = [];
      const audioUrl = window.URL.createObjectURL(blob);
      
      playback.src = audioUrl;
      playback.classList.add("_active");
      voiceRemove.classList.add("_active");
    };

      can_record = true;
  }

  let count;
  let recordingInterval;

  function toggleMic() {
    if (!can_record) return;

    is_recording = !is_recording;

    if (is_recording) {
      recorder.start();
      mic_btn.classList.add("is-recording");
      count = true;
      if (count) {
        recordingInterval = setInterval(() => {
          recorder.stop();
          mic_btn.classList.remove("is-recording");
          count = false;
        }, 60000);
      }
      tick();
    } else {
      recorder.stop();
      mic_btn.classList.remove("is-recording");
      count = false;
      clearInterval(recordingInterval);
    }
  }
  // Timer
  let seconds = 60;

  // Count down timer function
  function tick() {
    if (count) {
      seconds--;
      counter.innerHTML = "0:" + (seconds < 10 ? "0" : "") + String(seconds);
      if (seconds > 0) {
        setTimeout(tick, 1000);
      }
    } else {
      seconds = 60;
    }
  }

  const form = document.getElementById('form-main');
  
  form.addEventListener('submit', formSend);

  async function formSend(e) {
    e.preventDefault(); 
    
    const audioBlob = new Blob(voice, { type: 'audio/mp4; codecs=opus'  });
    voice = [];

    let error = formValidate(form);
    let formData = new FormData(form);
    formData.append('image', formImage.files[0]);
    formData.append("audio_file", audioBlob, "voice.mp4");
    
    if (error === 0) {
      form.classList.add('_sending');

      let response = await fetch('/save', {
          method: 'POST',
          cache: 'no-cache',
          body: formData,
        });
        if (response.ok) {
          let result = await response.json();
          form.reset();
          form.classList.remove('_sending');
           
        } else {
         console.log('Error');
         form.classList.remove('_sending');
        } 
      } else {
        console.error('error');
      }
    }

And PHP:

if (isset($_FILES["audio_file"])) {
    $voice = $_FILES["audio_file"];
    $voice_tmp = $voice["tmp_name"];
    $voice_name = $voice["name"];

    // File info
    $temp_voice = explode(".", $voice_name);
    $new_voice_name = round(microtime(true)) . '.' . end($temp_voice);
}
// Save voice  and sending to a telegram
if (!empty($voice_name) && $voice['error'] === UPLOAD_ERR_OK) {
    $upload_voice_path = 'assets/uploads/audio/'; 
    $upload_voice_path = $upload_voice_path.basename( $new_voice_name );
    // debug($upload_voice_path);
    move_uploaded_file( $voice_tmp, $upload_voice_path );
    // Send audio to telegram
    send_to_telegram($api_token, 'sendAudio', $chat_id, 'audio', $upload_voice_path);
}

function send_to_telegram($api_token, $send_type, $chat_id, $type, $file_path) {
    // Sending file to telegrab bot
    $bot_url = "https://api.telegram.org/bot" . $api_token ."/";
    $url = $bot_url . $send_type ."?chat_id=" . $chat_id ;
    $post_fields = ['chat_id'   => $chat_id,
    $type     => new CURLFile(realpath($file_path)),
];
    $ch = curl_init(); 
    curl_setopt($ch, CURLOPT_HTTPHEADER, array(
        "Content-Type:multipart/form-data"
    ));
    curl_setopt($ch, CURLOPT_URL, $url); 
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 
    curl_setopt($ch, CURLOPT_POSTFIELDS, $post_fields); 
    $output = curl_exec($ch);
}

I’ve tried change codecs, file format, but I still have the same problem


Solution

  • I think the problem is not about Telegram or your PHP code. When The PHP code can convey the recorded audio by Google Chrome to the Telegram bot, it means the Backend things are fine.

    You should check your Safari browser with online mic test tools such as webcammictest.com to ensure it's okay.

    If it's okay, then you should make compatible your audio recorder JavaScript code to fix the problem.

    I hope it helps.