audio_recorder.vue 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. <template>
  2. <div>
  3. <button class="record-button" @mousedown="startRecording" @mouseup="stopRecording">Hold to Record</button>
  4. <audio ref="audioPlayer"></audio>
  5. </div>
  6. </template>
  7. <script>
  8. export default {
  9. data() {
  10. return {
  11. isRecording: false,
  12. audioChunks: [],
  13. mediaRecorder: null,
  14. stream: null,
  15. audioURL: null,
  16. audioBlob: null,
  17. };
  18. },
  19. mounted() {
  20. this.requestMicrophonePermission();
  21. },
  22. watch: {
  23. audioBlob(newBlob, oldBlob) {
  24. if (newBlob && newBlob !== oldBlob) {
  25. this.emitBlob(); // Emit the blob when it's non-null and changes
  26. }
  27. },
  28. },
  29. methods: {
  30. async requestMicrophonePermission() {
  31. try {
  32. this.stream = await navigator.mediaDevices.getUserMedia({ audio: true });
  33. } catch (error) {
  34. console.error("Error accessing microphone:", error);
  35. }
  36. },
  37. async startRecording() {
  38. try {
  39. if (!this.stream) {
  40. await this.requestMicrophonePermission();
  41. }
  42. this.audioChunks = [];
  43. this.mediaRecorder = new MediaRecorder(this.stream);
  44. this.mediaRecorder.addEventListener("dataavailable", (event) => {
  45. if (event.data.size > 0) {
  46. this.audioChunks.push(event.data);
  47. }
  48. });
  49. this.mediaRecorder.start();
  50. this.isRecording = true;
  51. } catch (error) {
  52. console.error("Error accessing microphone:", error);
  53. }
  54. },
  55. stopRecording() {
  56. if (this.isRecording) {
  57. this.mediaRecorder.addEventListener("stop", () => {
  58. this.isRecording = false;
  59. this.saveBlob();
  60. // this.playRecordedAudio();
  61. });
  62. this.mediaRecorder.stop();
  63. }
  64. },
  65. async playRecordedAudio() {
  66. this.audioURL = window.URL.createObjectURL(this.audioBlob);
  67. this.$refs.audioPlayer.src = this.audioURL;
  68. this.$refs.audioPlayer.play();
  69. },
  70. saveBlob() {
  71. this.audioBlob = new Blob(this.audioChunks, { type: "audio/wav" });
  72. },
  73. emitBlob() {
  74. const reader = new FileReader();
  75. reader.onload = () => {
  76. const base64Data = reader.result.split(",")[1]; // Extracting base64 data from the result
  77. this.$emit("audio_ready", { audioBlobBase64: base64Data });
  78. };
  79. reader.readAsDataURL(this.audioBlob);
  80. },
  81. },
  82. };
  83. </script>
  84. <style scoped>
  85. .record-button {
  86. width: 100px;
  87. height: 100px;
  88. border-radius: 50%;
  89. background-color: red;
  90. color: white;
  91. border: 2px solid white;
  92. font-size: 16px;
  93. box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.3);
  94. transition: transform 0.2s, box-shadow 0.2s;
  95. }
  96. .record-button:active {
  97. transform: translateY(2px);
  98. box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.3);
  99. }
  100. </style>