Recherche avancée

Médias (0)

Mot : - Tags -/xmlrpc

Aucun média correspondant à vos critères n’est disponible sur le site.

Autres articles (60)

  • Submit enhancements and plugins

    13 avril 2011

    If you have developed a new extension to add one or more useful features to MediaSPIP, let us know and its integration into the core MedisSPIP functionality will be considered.
    You can use the development discussion list to request for help with creating a plugin. As MediaSPIP is based on SPIP - or you can use the SPIP discussion list SPIP-Zone.

  • Use, discuss, criticize

    13 avril 2011, par

    Talk to people directly involved in MediaSPIP’s development, or to people around you who could use MediaSPIP to share, enhance or develop their creative projects.
    The bigger the community, the more MediaSPIP’s potential will be explored and the faster the software will evolve.
    A discussion list is available for all exchanges between users.

  • MediaSPIP Player : problèmes potentiels

    22 février 2011, par

    Le lecteur ne fonctionne pas sur Internet Explorer
    Sur Internet Explorer (8 et 7 au moins), le plugin utilise le lecteur Flash flowplayer pour lire vidéos et son. Si le lecteur ne semble pas fonctionner, cela peut venir de la configuration du mod_deflate d’Apache.
    Si dans la configuration de ce module Apache vous avez une ligne qui ressemble à la suivante, essayez de la supprimer ou de la commenter pour voir si le lecteur fonctionne correctement : /** * GeSHi (C) 2004 - 2007 Nigel McNie, (...)

Sur d’autres sites (12202)

  • How to save audio chunks from client to ffmpeg readable file ?

    22 septembre 2023, par LuckOverflow

    I am live recording audio data from a TS React front-end and need to send it to the server, where it can be saved to a file so that ffmpeg can mix it. The front-end saves the mic data to a blob with type "mimeType : "audio/webm ; codecs=opus" when printed in the browser terminal. I send the exact object that I printed to the server, where logging it indicates it is a, or was passed as a, "Buffer" object.

    


    I have tried saving that Buffer as a webm file, but when I pass that file as an input to ffmpeg ffprobe, I get the error "Format matroska,webm detected only with a low score of 1..." and "EBML header parsing failed.." "Invalid data found when processing input." I have tried several other formats to no success.

    


    I need a way to transform this Buffer object to an audio file that can be mixed by ffmpeg. When I am finished, I also need to be able to do the reverse operation to send it in the same format to another client for playback, which is currently working.

    


    Code that records and sends the audio (TS React) :

    


    React Record

    


    const startRecording = async function () {
    inputStream = await navigator.mediaDevices.getUserMedia({ audio: true });
   
    mediaRecorder.current = new MediaRecorder(inputStream, { mimeType: "audio/webm; codecs=opus" });

    mediaRecorder.current.ondataavailable = e => {
      console.log(e.data)
      if (e.data.size > 0) {
        socket.emit("recording", e.data);
        console.log("Audio data recorded. Transmitting to server via socketio...");
      }
    };

    mediaRecorder.current.start(1000);
  };



    


    Code that receives and tries to save the Buffer to a file (JS Node.js) :

    


    Server Receive

    


    socket.on("recording", (chunk) => {
    console_log("Audio chunk recieved. Transmitting to frontend...");
    socket.broadcast.emit('listening', chunk);

    fs.writeFileSync('out.webm', chunk.toString());
    if (counter > 3) {
      console.log("Trying ffmpeg...");

      ffmpegInstance
        .input('out.webm')
        .complexFilter([
          {
            filter: 'amix'
          }])
        .save('./Music/FFMPEGSTREAM.mp3');
    }

    counter++;
  });


    


    fluent-ffmpeg interface package is includued in the server code, but I have been using ffmpeg in the terminal (Pop OS) to debug. The goal is to save the file to a ram disk and use fluent ffmpeg to mix before sending to a different client for playback. Currently I am just trying to save it to disk and get ffmpeg command line to work on it.

    


    Update :
Problem was that the chunk I was analyzing didn't have the header info. MediaRecorder encodes, then slices it up, not slices it up into your specified time slot and encodes. I have not found a good solution to this. Saving the file, without toString I believe, results in a playable webm when the header is properly included.

    


  • Recording audio with MediaRecorder on iPhone with Safari and Chrome only 1 second long ? Mimetype and FFMPEG problem ?

    9 mai 2023, par Avatar

    I am using MediaRecorder to record the Microphone audio on a website.

    


    Javascript :

    


    var blob;
var blob_url;
var stream;
var recorder;
var chunks;

var media = {
    tag: 'audio',
    type: 'audio/ogg',
    ext: '.ogg',
    gUM: {audio: true}
};

navigator.mediaDevices.getUserMedia(media.gUM).then(_stream => 
{
    stream = _stream;

    recorder = new MediaRecorder(stream);

    recorder.ondataavailable = e => 
    {
        // push data to chunks
        chunks.push(e.data);

        // recording has been stopped
        if(recorder.state == 'inactive') 
        {
            // audio data available
            blob = new Blob(chunks, {type: media.type });
            blob_url = URL.createObjectURL(blob);
            
            // send data to server
            uploadfile_audio();
        }
    };

    if(typeof(recorder)=='undefined')
    {
        alert('No microphone access');
        return;
    }

    chunks = [];
    recorder.start();
}


// when stop button is clicked
recorder.stop();
stream.getTracks().forEach( track => track.stop() );


    


    The audio stream (ogg format) is sent to the server.

    


    Since iPad/iPhone do not play ogg files, the recording file is converted to "mp3" using FFMPEG.

    


    This file is stored on the server.

    

    


    This works on Windows and MAC (Chrome and Safari), also on iPad (Safari) but not properly on iPhone (Chrome/Safari). Version : iPhone iOS 15.1.

    


    On iPhone the recording file is only 0:01 min in length. Size is always 17277 Bytes.

    


    What could be the issue ? (I cannot debug because I don't have a Mac.)

    


    Does the stream get interrupted ? Is the recording stopped after 1 second ?

    


    Update 1 :

    


    I have checked the incoming filesize of the browser-recorded file serverside. It seems to be coming in properly, because there are different sizes such as 184 kB.

    


    My guess is now that FFMPEG cannot handle the incoming file correctly. Which might have the wrong mimetype set in Javascript with type: 'audio/ogg',. Is another format needed ?

    


    The conversion code serverside :

    


    PHP

    


    $mp3file = shell_exec("ffmpeg -i ".$file_locationtmp." -vn -ar 44100 -ac 2 -b:a 128k ".$file_locationtmp.".mp3");


    


    I would need to find out the audio recording format used by iPhone but I couldn't.

    


    I tried to find the supporting mimetypes using https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder/isTypeSupported - however, it shows that NO mimetypes are supported on iPhone (neither in Chrome nor Safari).

    


    Update 2 :

    


    I used ffprobe to get the recording file information. It says Stream #0:0(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, mono, fltp, 2234 kb/s (default)

    


    Update 3 :

    


    It seems to be a problem with FFMPEG. See my new question How to convert AAC/MP4A to MP3 using FFMPEG in full length ? Audio file gets cut off after 1 second

    


  • Converting a voice recording into an mp3

    21 juillet 2023, par Raphael M

    For a vue.js messaging project, I'm using the wavesurfer.js library to record voice messages. However Google chrome gives me an audio/webm blob and Safari gives me an audio/mp4 blob.

    


    I'm trying to find a solution to transcode the blob into audio/mp3. I've tried several methods, including ffmpeg. However, ffmpeg gives me an error when compiling "npm run dev" : "Can't resolve '/node_modules/@ffmpeg/core/dist/ffmpeg-core.js'".

    


    "@ffmpeg/core": "^0.11.0",
"@ffmpeg/ffmpeg": "^0.11.6"


    


    I tried to downgrade ffmpeg

    


    "@ffmpeg/core": "^0.9.0",
"@ffmpeg/ffmpeg": "^0.9.8"


    


    I no longer get the error message when compiling, but when I want to convert my audio stream, the console displays a problem with SharedBuffer : "Uncaught (in promise) ReferenceError : SharedArrayBuffer is not defined".

    


    Here's my complete code below.
Is there a reliable way of transcoding the audio stream into mp3 ?

    


    Can you give me an example ?

    


    Thanks

    


    <template>&#xA;  <div class="left-panel">&#xA;    <header class="radial-blue">&#xA;      <div class="container">&#xA;        <h1 class="mb-30">Posez votre premi&#xE8;re question &#xE0; nos th&#xE9;rapeutes</h1>&#xA;        <p><b>Attention</b>, vous disposez seulement de 2 messages. Veillez &#xE0; les utiliser de mani&#xE8;re judicieuse !</p>&#xA;        <div class="available-messages">&#xA;          <div class="item disabled">&#xA;            <span>Message 1</span>&#xA;          </div>&#xA;          <div class="item">&#xA;            <span>Message 2</span>&#xA;          </div>&#xA;        </div>&#xA;      </div>&#xA;    </header>&#xA;  </div>&#xA;  <div class="right-panel">&#xA;    <div class="messagerie bg-light">&#xA;      <messaging ref="messagingComponent"></messaging>&#xA;      <footer>&#xA;        <button type="button"><img src="http://stackoverflow.com/assets/backoffice/images/record-start.svg" style='max-width: 300px; max-height: 300px' /></button>&#xA;        <div class="loading-animation">&#xA;          <img src="http://stackoverflow.com/assets/backoffice/images/record-loading.svg" style='max-width: 300px; max-height: 300px' />&#xA;        </div>&#xA;        <button type="button"><img src="http://stackoverflow.com/assets/backoffice/images/record-stop.svg" style='max-width: 300px; max-height: 300px' /></button>&#xA;        <div class="textarea gradient text-dark">&#xA;          <textarea placeholder="Posez votre question"></textarea>&#xA;        </div>&#xA;        <div class="loading-text">Chargement de votre microphone en cours...</div>&#xA;        <div class="loading-text">Envoi de votre message en cours...</div>&#xA;        <div ref="visualizer"></div>&#xA;        <button type="button"><img src="http://stackoverflow.com/assets/backoffice/images/send.svg" style='max-width: 300px; max-height: 300px' /></button>&#xA;        <div>&#xA;          {{ formatTimer() }}&#xA;        </div>&#xA;      </footer>&#xA;    </div>&#xA;  </div>&#xA;</template>&#xA;&#xA;<code class="echappe-js">&lt;script&gt;&amp;#xA;import Messaging from &quot;./Messaging.vue&quot;;&amp;#xA;import { createFFmpeg, fetchFile } from &amp;#x27;@ffmpeg/ffmpeg&amp;#x27;;&amp;#xA;&amp;#xA;export default {&amp;#xA;  data() {&amp;#xA;    return {&amp;#xA;      isMicrophoneLoading: false,&amp;#xA;      isSubmitLoading: false,&amp;#xA;      isMobile: false,&amp;#xA;      isMessagerie: false,&amp;#xA;      isRecording: false,&amp;#xA;      audioUrl: &amp;#x27;&amp;#x27;,&amp;#xA;      messageText: &amp;#x27;&amp;#x27;,&amp;#xA;      message:null,&amp;#xA;      wavesurfer: null,&amp;#xA;      access:(this.isMobile?&amp;#x27;denied&amp;#x27;:&amp;#x27;granted&amp;#x27;),&amp;#xA;      maxMinutes: 5,&amp;#xA;      orangeTimer: 3,&amp;#xA;      redTimer: 4,&amp;#xA;      timer: 0,&amp;#xA;      timerInterval: null,&amp;#xA;      ffmpeg: null,&amp;#xA;    };&amp;#xA;  },&amp;#xA;  components: {&amp;#xA;    Messaging,&amp;#xA;  },&amp;#xA;  mounted() {&amp;#xA;    this.checkScreenSize();&amp;#xA;    window.addEventListener(&amp;#x27;resize&amp;#x27;, this.checkScreenSize);&amp;#xA;&amp;#xA;    if(!this.isMobile)&amp;#xA;    {&amp;#xA;      this.$moment.locale(&amp;#x27;fr&amp;#x27;);&amp;#xA;      window.addEventListener(&amp;#x27;beforeunload&amp;#x27;, (event) =&gt; {&amp;#xA;        if (this.isMessagerie) {&amp;#xA;          event.preventDefault();&amp;#xA;          event.returnValue = &amp;#x27;&amp;#x27;;&amp;#xA;        }&amp;#xA;      });&amp;#xA;&amp;#xA;      this.initializeWaveSurfer();&amp;#xA;    }&amp;#xA;  },&amp;#xA;  beforeUnmount() {&amp;#xA;    window.removeEventListener(&amp;#x27;resize&amp;#x27;, this.checkScreenSize);&amp;#xA;  },&amp;#xA;  methods: {&amp;#xA;    checkScreenSize() {&amp;#xA;      this.isMobile = window.innerWidth &lt; 1200;&amp;#xA;&amp;#xA;      const windowHeight = window.innerHeight;&amp;#xA;      const navbarHeight = this.$navbarHeight;&amp;#xA;      let padding = parseInt(navbarHeight &amp;#x2B;181);&amp;#xA;&amp;#xA;      const messageListHeight = windowHeight - padding;&amp;#xA;      this.$refs.messagingComponent.$refs.messageList.style.height = messageListHeight &amp;#x2B; &amp;#x27;px&amp;#x27;;&amp;#xA;    },&amp;#xA;    showMessagerie() {&amp;#xA;      this.isMessagerie = true;&amp;#xA;      this.$refs.messagingComponent.scrollToBottom();&amp;#xA;    },&amp;#xA;    checkMicrophoneAccess() {&amp;#xA;      if (navigator.mediaDevices &amp;amp;&amp;amp; navigator.mediaDevices.getUserMedia) {&amp;#xA;&amp;#xA;        return navigator.mediaDevices.getUserMedia({audio: true})&amp;#xA;            .then(function (stream) {&amp;#xA;              stream.getTracks().forEach(function (track) {&amp;#xA;                track.stop();&amp;#xA;              });&amp;#xA;              return true;&amp;#xA;            })&amp;#xA;            .catch(function (error) {&amp;#xA;              console.error(&amp;#x27;Erreur lors de la demande d\&amp;#x27;acc&amp;#xE8;s au microphone:&amp;#x27;, error);&amp;#xA;              return false;&amp;#xA;            });&amp;#xA;      } else {&amp;#xA;        console.error(&amp;#x27;getUserMedia n\&amp;#x27;est pas support&amp;#xE9; par votre navigateur.&amp;#x27;);&amp;#xA;        return false;&amp;#xA;      }&amp;#xA;    },&amp;#xA;    initializeWaveSurfer() {&amp;#xA;      this.wavesurfer = this.$wavesurfer.create({&amp;#xA;        container: &amp;#x27;#visualizer&amp;#x27;,&amp;#xA;        barWidth: 3,&amp;#xA;        barHeight: 1.5,&amp;#xA;        height: 46,&amp;#xA;        responsive: true,&amp;#xA;        waveColor: &amp;#x27;rgba(108,115,202,0.3)&amp;#x27;,&amp;#xA;        progressColor: &amp;#x27;rgba(108,115,202,1)&amp;#x27;,&amp;#xA;        cursorColor: &amp;#x27;transparent&amp;#x27;&amp;#xA;      });&amp;#xA;&amp;#xA;      this.record = this.wavesurfer.registerPlugin(this.$recordPlugin.create());&amp;#xA;    },&amp;#xA;    startRecording() {&amp;#xA;      const _this = this;&amp;#xA;      this.isMicrophoneLoading = true;&amp;#xA;&amp;#xA;      setTimeout(() =&gt;&amp;#xA;      {&amp;#xA;        _this.checkMicrophoneAccess().then(function (accessible)&amp;#xA;        {&amp;#xA;          if (accessible) {&amp;#xA;            _this.record.startRecording();&amp;#xA;&amp;#xA;            _this.record.once(&amp;#x27;startRecording&amp;#x27;, () =&gt; {&amp;#xA;              _this.isMicrophoneLoading = false;&amp;#xA;              _this.isRecording = true;&amp;#xA;              _this.updateChildMessage( &amp;#x27;server&amp;#x27;, &amp;#x27;Allez-y ! Vous pouvez enregistrer votre message audio maintenant. La dur&amp;#xE9;e maximale autoris&amp;#xE9;e pour votre enregistrement est de 5 minutes.&amp;#x27;, &amp;#x27;text&amp;#x27;, &amp;#x27;&amp;#x27;, &amp;#x27;Message automatique&amp;#x27;);&amp;#xA;              _this.startTimer();&amp;#xA;            });&amp;#xA;          } else {&amp;#xA;            _this.isRecording = false;&amp;#xA;            _this.isMicrophoneLoading = false;&amp;#xA;            _this.$swal.fire({&amp;#xA;              title: &amp;#x27;Microphone non d&amp;#xE9;tect&amp;#xE9;&amp;#x27;,&amp;#xA;              html: &amp;#x27;&lt;p&gt;Le microphone de votre appareil est inaccessible ou l\&amp;#x27;acc&amp;#xE8;s a &amp;#xE9;t&amp;#xE9; refus&amp;#xE9;.&lt;/p&gt;&lt;p&gt;Merci de v&amp;#xE9;rifier les param&amp;#xE8;tres de votre navigateur afin de v&amp;#xE9;rifier les autorisations de votre microphone.&lt;/p&gt;&amp;#x27;,&amp;#xA;              footer: &amp;#x27;&lt;a href='http://stackoverflow.com/contact'&gt;Vous avez besoin d\&amp;#x27;aide ?&lt;/a&gt;&amp;#x27;,&amp;#xA;            });&amp;#xA;          }&amp;#xA;        });&amp;#xA;      }, 100);&amp;#xA;    },&amp;#xA;    stopRecording() {&amp;#xA;      this.stopTimer();&amp;#xA;      this.isRecording = false;&amp;#xA;      this.isSubmitLoading = true;&amp;#xA;      this.record.stopRecording();&amp;#xA;&amp;#xA;      this.record.once(&amp;#x27;stopRecording&amp;#x27;, () =&gt; {&amp;#xA;        const blobUrl = this.record.getRecordedUrl();&amp;#xA;        fetch(blobUrl).then(response =&gt; response.blob()).then(blob =&gt; {&amp;#xA;          this.uploadAudio(blob);&amp;#xA;        });&amp;#xA;      });&amp;#xA;    },&amp;#xA;    startTimer() {&amp;#xA;      this.timerInterval = setInterval(() =&gt; {&amp;#xA;        this.timer&amp;#x2B;&amp;#x2B;;&amp;#xA;        if (this.timer === this.maxMinutes * 60) {&amp;#xA;          this.stopRecording();&amp;#xA;        }&amp;#xA;      }, 1000);&amp;#xA;    },&amp;#xA;    stopTimer() {&amp;#xA;      clearInterval(this.timerInterval);&amp;#xA;      this.timer = 0;&amp;#xA;    },&amp;#xA;    formatTimer() {&amp;#xA;      const minutes = Math.floor(this.timer / 60);&amp;#xA;      const seconds = this.timer % 60;&amp;#xA;      const formattedMinutes = minutes &lt; 10 ? `0${minutes}` : minutes;&amp;#xA;      const formattedSeconds = seconds &lt; 10 ? `0${seconds}` : seconds;&amp;#xA;      return `${formattedMinutes}:${formattedSeconds}`;&amp;#xA;    },&amp;#xA;    async uploadAudio(blob)&amp;#xA;    {&amp;#xA;      const format = blob.type === &amp;#x27;audio/webm&amp;#x27; ? &amp;#x27;webm&amp;#x27; : &amp;#x27;mp4&amp;#x27;;&amp;#xA;&amp;#xA;      // Convert the blob to MP3&amp;#xA;      const mp3Blob = await this.convertToMp3(blob, format);&amp;#xA;&amp;#xA;      const s3 = new this.$AWS.S3({&amp;#xA;        accessKeyId: &amp;#x27;xxx&amp;#x27;,&amp;#xA;        secretAccessKey: &amp;#x27;xxx&amp;#x27;,&amp;#xA;        region: &amp;#x27;eu-west-1&amp;#x27;&amp;#xA;      });&amp;#xA;&amp;#xA;      var currentDate = new Date();&amp;#xA;      var filename = currentDate.getDate().toString() &amp;#x2B; &amp;#x27;-&amp;#x27; &amp;#x2B; currentDate.getMonth().toString() &amp;#x2B; &amp;#x27;-&amp;#x27; &amp;#x2B; currentDate.getFullYear().toString() &amp;#x2B; &amp;#x27;--&amp;#x27; &amp;#x2B; currentDate.getHours().toString() &amp;#x2B; &amp;#x27;-&amp;#x27; &amp;#x2B; currentDate.getMinutes().toString() &amp;#x2B; &amp;#x27;.mp4&amp;#x27;;&amp;#xA;&amp;#xA;      const params = {&amp;#xA;        Bucket: &amp;#x27;xxx/audio&amp;#x27;,&amp;#xA;        Key: filename,&amp;#xA;        Body: mp3Blob,&amp;#xA;        ACL: &amp;#x27;public-read&amp;#x27;,&amp;#xA;        ContentType: &amp;#x27;audio/mp3&amp;#x27;&amp;#xA;      }&amp;#xA;&amp;#xA;      s3.upload(params, (err, data) =&gt; {&amp;#xA;        if (err) {&amp;#xA;          console.error(&amp;#x27;Error uploading audio:&amp;#x27;, err)&amp;#xA;        } else {&amp;#xA;          const currentDate = this.$moment();&amp;#xA;          const timestamp = currentDate.format(&amp;#x27;dddd DD MMMM YYYY HH:mm&amp;#x27;);&amp;#xA;&amp;#xA;          this.updateChildMessage( &amp;#x27;client&amp;#x27;, &amp;#x27;&amp;#x27;, &amp;#x27;audio&amp;#x27;, mp3Blob, timestamp);&amp;#xA;          this.isSubmitLoading = false;&amp;#xA;        }&amp;#xA;      });&amp;#xA;    },&amp;#xA;    async convertToMp3(blob, format) {&amp;#xA;      const ffmpeg = createFFmpeg({ log: true });&amp;#xA;      await ffmpeg.load();&amp;#xA;&amp;#xA;      const inputPath = &amp;#x27;input.&amp;#x27; &amp;#x2B; format;&amp;#xA;      const outputPath = &amp;#x27;output.mp3&amp;#x27;;&amp;#xA;&amp;#xA;      ffmpeg.FS(&amp;#x27;writeFile&amp;#x27;, inputPath, await fetchFile(blob));&amp;#xA;&amp;#xA;      await ffmpeg.run(&amp;#x27;-i&amp;#x27;, inputPath, &amp;#x27;-acodec&amp;#x27;, &amp;#x27;libmp3lame&amp;#x27;, outputPath);&amp;#xA;&amp;#xA;      const mp3Data = ffmpeg.FS(&amp;#x27;readFile&amp;#x27;, outputPath);&amp;#xA;      const mp3Blob = new Blob([mp3Data.buffer], { type: &amp;#x27;audio/mp3&amp;#x27; });&amp;#xA;&amp;#xA;      ffmpeg.FS(&amp;#x27;unlink&amp;#x27;, inputPath);&amp;#xA;      ffmpeg.FS(&amp;#x27;unlink&amp;#x27;, outputPath);&amp;#xA;&amp;#xA;      return mp3Blob;&amp;#xA;    },&amp;#xA;    sendMessage() {&amp;#xA;      this.isSubmitLoading = true;&amp;#xA;      if (this.messageText.trim() !== &amp;#x27;&amp;#x27;) {&amp;#xA;        const emmet = &amp;#x27;client&amp;#x27;;&amp;#xA;        const text = this.escapeHTML(this.messageText)&amp;#xA;            .replace(/\n/g, &amp;#x27;&lt;br&gt;&amp;#x27;);&amp;#xA;&amp;#xA;        const currentDate = this.$moment();&amp;#xA;        const timestamp = currentDate.format(&amp;#x27;dddd DD MMMM YYYY HH:mm&amp;#x27;);&amp;#xA;&amp;#xA;        this.$nextTick(() =&gt; {&amp;#xA;          this.messageText = &amp;#x27;&amp;#x27;;&amp;#xA;&amp;#xA;          const textarea = document.getElementById(&amp;#x27;messageTextarea&amp;#x27;);&amp;#xA;          if (textarea) {&amp;#xA;            textarea.scrollTop = 0;&amp;#xA;            textarea.scrollLeft = 0;&amp;#xA;          }&amp;#xA;        });&amp;#xA;&amp;#xA;        this.updateChildMessage(emmet, text, &amp;#x27;text&amp;#x27;, &amp;#x27;&amp;#x27;, timestamp);&amp;#xA;        this.isSubmitLoading = false;&amp;#xA;      }&amp;#xA;    },&amp;#xA;    escapeHTML(text) {&amp;#xA;      const map = {&amp;#xA;        &amp;#x27;&amp;amp;&amp;#x27;: &amp;#x27;&amp;amp;amp;&amp;#x27;,&amp;#xA;        &amp;#x27;&lt;&amp;#x27;: &amp;#x27;&amp;amp;lt;&amp;#x27;,&amp;#xA;        &amp;#x27;&gt;&amp;#x27;: &amp;#x27;&amp;amp;gt;&amp;#x27;,&amp;#xA;        &amp;#x27;&quot;&amp;#x27;: &amp;#x27;&amp;amp;quot;&amp;#x27;,&amp;#xA;        &quot;&amp;#x27;&quot;: &amp;#x27;&amp;amp;#039;&amp;#x27;,&amp;#xA;        &quot;`&quot;: &amp;#x27;&amp;amp;#x60;&amp;#x27;,&amp;#xA;        &quot;/&quot;: &amp;#x27;&amp;amp;#x2F;&amp;#x27;&amp;#xA;      };&amp;#xA;      return text.replace(/[&amp;amp;&lt;&gt;&quot;&amp;#x27;`/]/g, (match) =&gt; map[match]);&amp;#xA;    },&amp;#xA;    updateChildMessage(emmet, text, type, blob, timestamp) {&amp;#xA;      const newMessage = {&amp;#xA;        id: this.$refs.messagingComponent.lastMessageId &amp;#x2B; 1,&amp;#xA;        emmet: emmet,&amp;#xA;        text: text,&amp;#xA;        type: type,&amp;#xA;        blob: blob,&amp;#xA;        timestamp: timestamp&amp;#xA;      };&amp;#xA;&amp;#xA;      this.$refs.messagingComponent.updateMessages(newMessage);&amp;#xA;    }&amp;#xA;  },&amp;#xA;};&amp;#xA;&lt;/script&gt;&#xA;

    &#xA;