muaz-khan / RecordRTC

RecordRTC is WebRTC JavaScript library for audio/video as well as screen activity recording. It supports Chrome, Firefox, Opera, Android, and Microsoft Edge. Platforms: Linux, Mac and Windows.
https://www.webrtc-experiment.com/RecordRTC/
MIT License
6.49k stars 1.75k forks source link

Can't get last timeSlice blob from a streamed wav file #752

Open scotfang opened 3 years ago

scotfang commented 3 years ago

Hi, thanks for creating and maintaining this awesome tool! I have a feature request, or maybe there is a way to do this and I just don't know how.

Per code below, I am streaming a wav file to RecordRTC, and calling ondataavailable's callback every 300ms. This all works fine, except that I'm pretty sure the very last timeSlice before the wav file ends does not trigger ondataavailable's callback, because the last timeSlice is shorter than 300ms perhaps.

As a workaround, I tried using getBlobl() inside recordRTC.stopRecording(), but that returns the entire blob, not just the last timeSlice. That doesn't help me much, because I want to measure real-time streaming metrics with my application through 300ms (or less) blobs.

Is there any way to retrieve the last timeSlice's blob of a stream when it ends? Thanks!!

    const audio = new Audio( wav_file );
    let stream = audio.captureStream();
    console.log("got stream")
    const recordRTC = RecordRTC(stream, {
      type: "audio",
      mimeType: "audio/wav",
      recorderType: RecordRTC.StereoAudioRecorder,
      bufferSize: 2048,
      desiredSampRate: 16000,
      numberOfAudioChannels: 1,
      timeSlice: 300,
      ondataavailable: this.onAudioData,
      disableLogs: true,
    })
    audio.onended = (event) => {
      console.log('audio ended');
      recordRTC.stopRecording(() => {
          let blob = recordRTC.getBlob();
          this.onAudioData(blob)
      });
    };
    audio.play().then(() => {
      recordRTC.startRecording();
    })
sahilmcompro commented 2 years ago

Hi @scotfang, I am facing this exact problem right now (except the stream in my case is User Mic and timeslice interval is 5000, which don't matter, I hope). So I want to know if you found any solution/workaround for this?

I tried to research about it a bit but didn't find any solutions, however, on stack overflow, it is recommended to use Stop & Start.

Thanks!

scotfang commented 2 years ago

What I did eventually is I expose looper() inside the internal recorder and call it when the audio ends.

On Tue, Aug 3, 2021 at 11:11 PM Sahil Malik @.***> wrote:

Hi @scotfang https://github.com/scotfang, I am facing this exact problem right now (except the stream in my case is User Mic and timeslice interval is 1000, which don't matter, I hope). So I want to know if you found any solution/workaround for this?

I tried to research about it a bit but didn't find any solutions, however, on stack overflow, it is recommended to use Stop & Start.

Thanks!

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/muaz-khan/RecordRTC/issues/752#issuecomment-892391946, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAKE3RWR2LFCLLHEUTBAUGDT3DKYZANCNFSM47HDJCJQ . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&utm_campaign=notification-email .

lukemtl commented 2 years ago

I was able to get it by using the Blob.slice() method and tracking the total size of all the blobs that I got from ondataavailable.

Globally:

let sizeOnDataAvailable = 0;

Then in your code where you handle dataavailable events:

ondataavailable: function(blob) {      
   // your code for handling the blob chunk here, and then concatenate the size...

    sizeOnDataAvailable += blob.size;
}

Then, when you call stopRecording, to get the last blob you can have this callback:

recordAudio.stopRecording( () => {
      blob = recordAudio.getBlob();           //this is the entire recording

      var endBlob = blob.slice(sizeOnDataAvailable, blob.size, 'audio/wav');   
     //this is the last chunk; add code here to handle it

     sizeOnDataAvailable = 0; 
 });

Hope it works for people!

EDIT make sure to reset the size tracking variable if you want to repeat the process (added in the code)

sahilmcompro commented 1 year ago

Hi @lukemtl,

The above is a good workaround, but it doesn't work with large recordings (around half hour) on low-end mobile devices. I started the whole timeslice thing because generating the whole blob at the end was the cause of the crash.

AlbaChloe commented 1 month ago

I was able to get it by using the Blob.slice() method and tracking the total size of all the blobs that I got from ondataavailable.

Globally:

let sizeOnDataAvailable = 0;

Then in your code where you handle dataavailable events:

ondataavailable: function(blob) {      
   // your code for handling the blob chunk here, and then concatenate the size...

    sizeOnDataAvailable += blob.size;
}

Then, when you call stopRecording, to get the last blob you can have this callback:

recordAudio.stopRecording( () => {
      blob = recordAudio.getBlob();           //this is the entire recording

      var endBlob = blob.slice(sizeOnDataAvailable, blob.size, 'audio/wav');   
     //this is the last chunk; add code here to handle it

     sizeOnDataAvailable = 0; 
 });

Hope it works for people!

EDIT make sure to reset the size tracking variable if you want to repeat the process (added in the code)

thanks a lot! this saved me🥳🥳caz i got undefined from getArrayOfBlobs of getInternalRecorder(), probably beacause my recorderType is set to be StereoAudioRecorder, and if i use MediaStreamRecorder, getArrayOfBlobs will work well, but i need wav file