225 lines
6.3 KiB
Vue
225 lines
6.3 KiB
Vue
![]() |
<template>
|
|||
|
<div class="my-vue-audio-recorder">
|
|||
|
<button
|
|||
|
v-if="!recorder"
|
|||
|
@click.prevent="record()"
|
|||
|
class="btn start-record-btn"
|
|||
|
>
|
|||
|
<svg class="icon icon-Component-85--1">
|
|||
|
<use xlink:href="#icon-Component-85--1"></use>
|
|||
|
</svg>
|
|||
|
</button>
|
|||
|
|
|||
|
<button v-else @click.prevent="stop()" class="btn send-record-btn">
|
|||
|
<svg class="icon icon-Component-236--1">
|
|||
|
<use xlink:href="#icon-Component-236--1"></use>
|
|||
|
</svg>
|
|||
|
</button>
|
|||
|
<button
|
|||
|
@click.prevent="cancel()"
|
|||
|
class="btn remove-record-btn"
|
|||
|
:class="{ recording: recorder }"
|
|||
|
>
|
|||
|
<svg class="icon icon-Component-295--1">
|
|||
|
<use xlink:href="#icon-Component-295--1"></use>
|
|||
|
</svg>
|
|||
|
</button>
|
|||
|
</div>
|
|||
|
</template>
|
|||
|
|
|||
|
<script>
|
|||
|
// import "assets/common/js/RecordRTC.js";
|
|||
|
|
|||
|
/**
|
|||
|
* @vue-data {Object|null} [newAudio=null] - صدای جدید
|
|||
|
* @vue-data {Object|null} [recorder=null] - ضبط کننده
|
|||
|
* @vue-data {Boolean} [saveAudio=false] - نشان میدهد که آیا صدای ضبط شده ذخیره شود یا خیر
|
|||
|
* @vue-data {Array} [recordedChunks=[]] - تکههای صدای ضبط شده
|
|||
|
*/
|
|||
|
|
|||
|
export default {
|
|||
|
mounted() {
|
|||
|
// this.uuid = Math.floor(Math.random() * 100);
|
|||
|
// addJsCssFileToDom("/js/RecordRTC.js", "js", this.uuid);
|
|||
|
// this.getLocalStream();
|
|||
|
},
|
|||
|
destroy() {
|
|||
|
this.recorder?.removeEventListener("dataavailable", onDataAvailable);
|
|||
|
this.recorder?.removeEventListener("stop", onStopRecording);
|
|||
|
},
|
|||
|
data() {
|
|||
|
return {
|
|||
|
newAudio: null,
|
|||
|
recorder: null,
|
|||
|
saveAudio: false,
|
|||
|
recordedChunks: [],
|
|||
|
};
|
|||
|
},
|
|||
|
computed: {
|
|||
|
// newAudioURL() {
|
|||
|
// return URL.createObjectURL(this.newAudio);
|
|||
|
// },
|
|||
|
},
|
|||
|
methods: {
|
|||
|
/**
|
|||
|
* هنگامی که دادههای صوتی در دسترس هستند، این متد اجرا میشود.
|
|||
|
* تکههای ضبط شده را ذخیره کرده و یک رویداد ارسال میکند.
|
|||
|
*
|
|||
|
* @param {Event} e - رویداد دادههای موجود
|
|||
|
*/
|
|||
|
onDataAvailable(e) {
|
|||
|
this.recordedChunks = [];
|
|||
|
|
|||
|
this.$emit("onStream");
|
|||
|
|
|||
|
if (e.data.size > 0) {
|
|||
|
this.recordedChunks.push(e.data);
|
|||
|
}
|
|||
|
},
|
|||
|
/**
|
|||
|
* توقف ضبط و پردازش جریان رسانهای.
|
|||
|
* تکههای ضبط شده را به یک Blob تبدیل کرده و آن را ارسال میکند.
|
|||
|
*
|
|||
|
* @param {Event} mediaStream2 - رویداد جریان رسانهای
|
|||
|
*/
|
|||
|
onStopRecording(mediaStream2) {
|
|||
|
this.newAudio = new Blob(this.recordedChunks);
|
|||
|
this.recorder.stop();
|
|||
|
|
|||
|
const audioTracks = mediaStream2.target.stream.getAudioTracks();
|
|||
|
|
|||
|
audioTracks.forEach((element) => {
|
|||
|
element.stop();
|
|||
|
});
|
|||
|
|
|||
|
this.recorder = null;
|
|||
|
|
|||
|
if (this.saveAudio) this.$emit("send", this.newAudio);
|
|||
|
},
|
|||
|
/**
|
|||
|
* شروع ضبط صدا.
|
|||
|
* درخواست دسترسی به میکروفون کاربر و شروع ضبط صدا.
|
|||
|
*/
|
|||
|
async record() {
|
|||
|
this.newAudio = null;
|
|||
|
|
|||
|
try {
|
|||
|
const mediaStream = await navigator.mediaDevices.getUserMedia({
|
|||
|
audio: true,
|
|||
|
video: false,
|
|||
|
});
|
|||
|
|
|||
|
// const options = { mimeType: "audio/webm" };
|
|||
|
// this.recorder = new MediaRecorder(mediaStream, options);
|
|||
|
this.recorder = new MediaRecorder(mediaStream);
|
|||
|
this.recorder.start();
|
|||
|
|
|||
|
this.recorder.addEventListener("dataavailable", this.onDataAvailable);
|
|||
|
|
|||
|
this.recorder.addEventListener("stop", this.onStopRecording);
|
|||
|
} catch (err) {
|
|||
|
mySwalToast({
|
|||
|
title:
|
|||
|
"مرورگر شما از قابلیت ارسال صدا پشتیبانی نمیکند.لطفا مرورگر خود را به آخرین ورژن ارتقا دهید.",
|
|||
|
icon: "error",
|
|||
|
timer: 7000,
|
|||
|
});
|
|||
|
}
|
|||
|
},
|
|||
|
/**
|
|||
|
* توقف ضبط و ذخیره فایل صوتی.
|
|||
|
*/
|
|||
|
stop() {
|
|||
|
this.saveAudio = true;
|
|||
|
this.recorder.stop();
|
|||
|
},
|
|||
|
/**
|
|||
|
* لغو ضبط بدون ذخیره فایل صوتی.
|
|||
|
*/
|
|||
|
cancel() {
|
|||
|
this.saveAudio = false;
|
|||
|
this.recorder.stop();
|
|||
|
},
|
|||
|
|
|||
|
// با استفاده از پلاگین
|
|||
|
// getLocalStream() {
|
|||
|
// try {
|
|||
|
// navigator.mediaDevices
|
|||
|
// .getUserMedia({
|
|||
|
// video: false,
|
|||
|
// audio: true,
|
|||
|
// })
|
|||
|
// .then(async function (stream) {
|
|||
|
// let recorder = RecordRTC(stream, {
|
|||
|
// type: "audio",
|
|||
|
// });
|
|||
|
// recorder.startRecording();
|
|||
|
|
|||
|
// const sleep = (m) => new Promise((r) => setTimeout(r, m));
|
|||
|
// await sleep(3000);
|
|||
|
|
|||
|
// recorder.stopRecording(function () {
|
|||
|
// let blob = recorder.getBlob();
|
|||
|
// invokeSaveAsDialog(blob);
|
|||
|
// });
|
|||
|
// });
|
|||
|
|
|||
|
// navigator.mediaDevices
|
|||
|
// .getUserMedia({ video: false, audio: true })
|
|||
|
// .then((stream) => {
|
|||
|
// window.localStream = stream; // A
|
|||
|
// window.localAudio.srcObject = stream; // B
|
|||
|
// window.localAudio.autoplay = true; // C
|
|||
|
// })
|
|||
|
// .catch((err) => {
|
|||
|
// console.error(`you got an error: ${err}`);
|
|||
|
// });
|
|||
|
// } catch (err) {
|
|||
|
// let localStream = new MediaStream();
|
|||
|
// let localAudioTrack;
|
|||
|
// let localVideoTrack;
|
|||
|
// let localVideo;
|
|||
|
// const userMediaConstraints = {
|
|||
|
// video: true,
|
|||
|
// audio: true,
|
|||
|
// };
|
|||
|
// navigator.mediaDevices = localStream;
|
|||
|
// .getUserMedia(userMediaConstraints)
|
|||
|
// .then((stream) => {
|
|||
|
// localAudioTrack = stream.getAudioTracks()[0];
|
|||
|
// localAudioTrack.enabled = true;
|
|||
|
// localStream.addTrack(localAudioTrack);
|
|||
|
// });
|
|||
|
// }
|
|||
|
// },
|
|||
|
},
|
|||
|
};
|
|||
|
</script>
|
|||
|
|
|||
|
<style scoped lang="scss">
|
|||
|
// .vue-audio-recorder {
|
|||
|
// position: relative;
|
|||
|
// background-color: #4db6ac;
|
|||
|
// border-radius: 50%;
|
|||
|
// width: 64px;
|
|||
|
// height: 64px;
|
|||
|
// display: inline-block;
|
|||
|
// cursor: pointer;
|
|||
|
// -webkit-box-shadow: 0 0 0 0 rgba(232,76,61,.7);
|
|||
|
// box-shadow: 0 0 0 0 rgba(232,76,61,.7);
|
|||
|
|
|||
|
// width: 1.9em;
|
|||
|
// height: 1.9em;
|
|||
|
// padding: 0.5em;
|
|||
|
// background-size: 70%;
|
|||
|
// background-position: center center;
|
|||
|
// background-repeat: no-repeat;
|
|||
|
|
|||
|
// &.active {
|
|||
|
// background-color: #ef5350;
|
|||
|
// -webkit-animation: pulse 1.25s cubic-bezier(.66,0,0,1) infinite;
|
|||
|
// animation: pulse 1.25s cubic-bezier(.66,0,0,1) infinite;
|
|||
|
// }
|
|||
|
// }
|
|||
|
</style>
|