Recently listened to the group of small partners to share the screen recording of the relevant content -MediaRecorder, and then successfully access to an internal project.

Today share with you how to useMediaRecorder, a few lines of code to achieve the screen recording function, and the actual scene may encounter problems.

Let me experience

Introduce the MediaRecorder

MediaRecorder is the MediaStream Recording API for easy Recording of media interface, he needs to call the MediaRecorder() constructor to instantiate.

This interface also exposes many methods and configuration items. If you are interested, you can click here to view them

This section mainly introduces some common methods according to the process.

1. Permission application

// Obtain the user screen recording permission
const stream = await navigator.mediaDevices.getDisplayMedia({
      video: true
    })
Copy the code

2. Confirm the recorded video type

// Verify the screen recording file types supported by the current environment
const mime = MediaRecorder.isTypeSupported('video/webm; codecs=vp9')?'video/webm; codecs=vp9' : 'video/webm'

Copy the code

Instantiate MediaRecorder

// The mimeType of step 2 and step 1stream are required
const mediaRecorder = new MediaRecorder(stream, {
    mimeType: mime
  })
Copy the code

3. Event monitoring

  • dataavailable

This event is emitted after recording is stopped (prior to onStop) and can be used to retrieve recorded media resources (a available Blob object is provided in the data property of the event)

  • stop

Used to handle the stop event. This event is triggered when a media recording ends, a MediaStream ends, and dataavailable is triggered.

  // Used to store recorded BLOB data
  const chunks = []
  mediaRecorder.addEventListener('dataavailable'.function (e) {
    chunks.push(e.data)
  })
  mediaRecorder.addEventListener('stop'.() = > {
    const blob = new Blob(chunks, {
      type: chunks[0].type
    })
    // Get the available URL
    const url = URL.createObjectURL(blob)
    // Get the temporary recording file path and perform your operation
    // ...
  }
Copy the code

4. Trigger the recording behavior

  mediaRecorder.start()
Copy the code

The scene of actual combat

This application scenario is in an internal quality management platform. During the steps of asking questions, problems are described through screen recording. During the process, some common problems are encountered, so I would like to share with you.

The conventional steps of pasting images in rich text are to paste and upload, and then get a URL to display them. However, for videos, uploading immediately after recording is really a little bad user experience, and there is a waste of resources.

So we upload and replace them as we save them.

As mentioned, in the onStop callback, we can take a BLOB stream and generate a temporary path that we can preview.

When we save, we need to do two things:

1. Upload the rich text content with the video tag SRC pointing to a temporary file to our own server and get a real URL.

Rich text description replaces the corresponding temporary path with the real URL.

Code implementation

export function backTraceNode(el) {
  if(! el? .children? .length) {return [el]
  }
  return [el, ...Array.from(el.children).map(backTraceNode)].flat()
}
// 1. Extract the temporary path of bolB file from the HTML string
const getVideoListByHtml = (html) = > {
  const dom = document.createElement('div')
  dom.innerHTML = html
  return backTraceNode(dom)
    .filter((item) = > item.nodeName === 'VIDEO')
    .map((v) = > v.src)
}

// 2. Generate the corresponding File according to the temporary path
const getFileFromBlobUrl = async (blobUrlList) => {
  const pList = list.map((url) = > {
    return fetch(url)
  })
  const data = await Promise.all(pList)
  const blobList = data.map((v) = > v.blob())
  const res = await Promise.all(blobList)
  return res.map(blob= >{
    return new File([blob], 'video.webm', { type: 'video/webm'})})}// upload the file and replace the corresponding URL
const replaceVideoUrl = (html, hashUrlMapList) = > {
  const dom = document.createElement('div')
  dom.innerHTML = html
  const videoList = backTraceNode(dom).filter((item) = > item.nodeName === 'VIDEO')
  videoList.forEach((el) = > {
    el.src = 'https:' + findUrlByHash(el.src, hashUrlMapList)
  })
  return dom.innerHTML
}
Copy the code

Matters needing attention

  • compatibilityUnfriendly, so far only inChromeCan meet the application scenarios. Other browsers either do not support the API or do not support recording screen file types. However, you can obtain the support level of the current browser in advance. If you are not satisfied, you can design the interaction level. For example, if you do not support this feature, hide it or give a message.
const isSupportRecorder = () = > {
  const types = ['video/webm; codecs=vp9'.'video/webm']
  const isTypeSupport = types.some((v) = > MediaRecorder.isTypeSupported(v))
  const isApiSupport = Boolean(navigator.mediaDevices)
  return isApiSupport && isTypeSupport
 }
Copy the code
  • For security reasons, apply for permissions at the browser level (navigator.mediaDevices), supported onlyhttpsorlocalhost
  • When replacing rich text content, if multiple temporary files exist, replace them with hash based on the corresponding names. Otherwise, videos may be out of order.

reference

  • Developer.mozilla.org/zh-CN/docs/…
  • www.wangeditor.com/doc