Skip to content

Commit b0c39ba

Browse files
committed
feat: add UseMediaRecorder component
1 parent 0e58bf0 commit b0c39ba

File tree

13 files changed

+406
-105
lines changed

13 files changed

+406
-105
lines changed

.github/workflows/docs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,4 +58,4 @@ jobs:
5858
steps:
5959
- name: Deploy to GitHub Pages
6060
id: deployment
61-
uses: actions/deploy-pages@v4
61+
uses: actions/deploy-pages@v4

docs/examples.md

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ outline: deep
88

99
This is a basic example of how to use the `<script setup>` syntax in a Vue component.
1010

11-
1211
<script setup>
1312
import BasicExample from './basic-example.vue'
1413
import TimesliceExample from './timeslice-example.vue'
@@ -20,7 +19,6 @@ import TimesliceExample from './timeslice-example.vue'
2019

2120
<<< @/basic-example.vue
2221

23-
2422
## Set timeslice
2523

2624
You can control the timeslice of the data Blob creation. See [
@@ -30,5 +28,4 @@ stopping).
3028

3129
<TimesliceExample />
3230

33-
34-
<<< @/timeslice-example.vue {40}
31+
<<< @/timeslice-example.vue {40}

docs/index.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,9 @@ hero:
1010
text: Installation
1111
link: /installation
1212
- theme: secondary
13-
text: Usage
13+
text: Usage
1414
link: /usage
1515

16-
1716
features:
1817
- title: Plug & play
1918
icon: 🚀

docs/timeslice-example.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ const audio = computed(() => {
5353
<div style="display: flex; flex-direction: column">
5454
<label for="timeslice">
5555
Timeslice (ms):
56-
<input id="timeslice" type="number" v-model="timeslice"/>
56+
<input id="timeslice" v-model="timeslice" type="number">
5757
</label>
5858
<button style="border-radius: 5px; background-color: greenyellow; color: black" @click="handleStartClick">
5959
{{ startBtnText }}

docs/usage.md

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,24 @@ outline: deep
77
## `useMediaRecorder`
88

99
```vue
10-
1110
<script setup>
12-
import { useMediaRecorder } from '@orbisk/vue-use-media-recorder'
13-
14-
const {
15-
data,
16-
stream,
17-
start,
18-
pause,
19-
resume,
20-
stop,
21-
state,
22-
isSupported,
23-
isMimeTypeSupported,
24-
mimeType,
25-
mediaRecorder,
26-
} = useMediaRecorder({ constraints: { audio: true, video: true } })
27-
28-
start()
11+
import { useMediaRecorder } from '@orbisk/vue-use-media-recorder'
12+
13+
const {
14+
data,
15+
stream,
16+
start,
17+
pause,
18+
resume,
19+
stop,
20+
state,
21+
isSupported,
22+
isMimeTypeSupported,
23+
mimeType,
24+
mediaRecorder,
25+
} = useMediaRecorder({ constraints: { audio: true, video: true } })
26+
27+
start()
2928
</script>
3029
```
3130

@@ -71,10 +70,10 @@ Type: `mediaRecorderOptions?: MaybeRef<MediaRecorderOptions>`
7170

7271
```ts
7372
interface MediaRecorderOptions {
74-
audioBitsPerSecond?: number;
75-
bitsPerSecond?: number;
76-
mimeType?: string;
77-
videoBitsPerSecond?: number;
73+
audioBitsPerSecond?: number
74+
bitsPerSecond?: number
75+
mimeType?: string
76+
videoBitsPerSecond?: number
7877
}
7978
```
8079

playgrounds/nuxt/app/app.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@
55
<template>
66
<ClientOnly>
77
<RecorderDemo />
8+
<RecorderDemoComponent />
89
</ClientOnly>
910
</template>
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<script setup lang="ts">
2+
// import { UseMediaRecorder} from '@orbisk/vue-use-media-recorder' // TODO: why?
3+
4+
// function handleStop() {
5+
// stop()
6+
// const blob = new Blob(data.value)
7+
// const blobVideo = new Blob(data.value)
8+
// audio.value.src = URL.createObjectURL(blob)
9+
// video.value.src = URL.createObjectURL(blobVideo)
10+
// }
11+
12+
const stopped = ref(false)
13+
</script>
14+
15+
<template>
16+
<UseMediaRecorder :constraints="{ audio: true }" @stop="stopped = true" @start="stopped = false">
17+
<template #default="slotProps">
18+
<button @click="() => slotProps.start()">
19+
start
20+
</button>
21+
<button @click="slotProps.pause">
22+
pause
23+
</button>
24+
<button @click="slotProps.resume">
25+
resume
26+
</button>
27+
<button @click="slotProps.stop">
28+
stop
29+
</button>
30+
<audio controls>
31+
<source v-if="stopped" :src="URL.createObjectURL(new Blob(slotProps.data))">
32+
</audio>
33+
<pre>state: {{ slotProps.state }}</pre>
34+
<pre>supported: {{ slotProps.isSupported }}</pre>
35+
<pre>mime type: {{ slotProps.mimeType }}</pre>
36+
<pre>mime supported: {{ slotProps.isMimeTypeSupported }}</pre>
37+
<pre>data length: {{ slotProps.data?.length }}</pre>
38+
</template>
39+
</UseMediaRecorder>
40+
</template>

playgrounds/nuxt/app/components/recorder-demo.vue

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,38 +2,32 @@
22
const audio = ref()
33
const video = ref()
44
5-
const onStop = ()=>{
6-
console.log("onstop")
7-
}
85
const { start, stop, pause, resume, data, state, isMimeTypeSupported, isSupported, mimeType } = useMediaRecorder({
96
constraints: {
107
audio: true,
118
video: false,
129
},
13-
onStop,
10+
onStop: () => {
11+
const blob = new Blob(data.value)
12+
const blobVideo = new Blob(data.value)
13+
audio.value.src = URL.createObjectURL(blob)
14+
video.value.src = URL.createObjectURL(blobVideo)
15+
},
1416
})
15-
function handleStop() {
16-
console.log('stop')
17-
stop()
18-
const blob = new Blob(data.value)
19-
const blobVideo = new Blob(data.value)
20-
audio.value.src = URL.createObjectURL(blob)
21-
video.value.src = URL.createObjectURL(blobVideo)
22-
}
2317
</script>
2418

2519
<template>
2620
<div>
27-
<button @click="()=>start()">
21+
<button @click="() => start()">
2822
start
2923
</button>
30-
<button @click="pause">
24+
<button @click="() => pause()">
3125
pause
3226
</button>
33-
<button @click="resume">
27+
<button @click="() => resume()">
3428
resume
3529
</button>
36-
<button @click="handleStop">
30+
<button @click="() => stop()">
3731
stop
3832
</button>
3933
<audio ref="audio" controls />
@@ -42,6 +36,6 @@ function handleStop() {
4236
<pre>supported: {{ isSupported }}</pre>
4337
<pre>mime type: {{ mimeType }}</pre>
4438
<pre>mime supported: {{ isMimeTypeSupported }}</pre>
45-
<pre>data length: {{ data?.length}}</pre>
39+
<pre>data length: {{ data?.length }}</pre>
4640
</div>
4741
</template>

src/components/UseMediaRecorder.vue

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<script setup lang="ts">
2+
import { useMediaRecorder } from '@orbisk/vue-use-media-recorder'
3+
4+
const props = defineProps({
5+
constraints: {
6+
type: Object,
7+
required: true,
8+
validator(value: unknown): boolean {
9+
if (!value.audio && !value.video) {
10+
console.error('constraints must have at least one of audio or video')
11+
return false
12+
}
13+
},
14+
},
15+
mediaRecorderOptions: {
16+
type: Object,
17+
default: () => ({}),
18+
},
19+
})
20+
21+
const emit = defineEmits<{
22+
start: [ev: Event]
23+
stop: [ev: Event]
24+
pause: [ev: Event]
25+
resume: [ev: Event]
26+
error: [ev: Event]
27+
}>()
28+
29+
const onStart = (...args) => emit('start', ...args)
30+
const onStop = (...args) => emit('stop', ...args)
31+
const onPause = (...args) => emit('pause', ...args)
32+
const onResume = (...args) => emit('resume', ...args)
33+
const onError = (...args) => emit('error', ...args)
34+
35+
const {
36+
data,
37+
stream,
38+
mimeType,
39+
isSupported,
40+
isMimeTypeSupported,
41+
mediaRecorder,
42+
start,
43+
pause,
44+
resume,
45+
stop,
46+
state,
47+
48+
} = useMediaRecorder({ constraints: props.constraints, mediaRecorderOptions: props.mediaRecorderOptions, onStart, onResume, onPause, onStop, onError })
49+
50+
defineExpose({
51+
start,
52+
stop,
53+
resume,
54+
pause,
55+
})
56+
</script>
57+
58+
<template>
59+
<slot
60+
:data="data" :stream="stream" :mime-type="mimeType" :media-recorder="mediaRecorder" :is-supported="isSupported"
61+
:is-mime-type-supported="isMimeTypeSupported" :state="state" :start="start" :stop="stop" :pause="pause" :resume="resume"
62+
/>
63+
</template>

src/index.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
// Components
2-
// export { default as Toggle } from './components/Toggle.vue'
2+
export { default as UseMediaRecorder } from './components/UseMediaRecorder.vue'
33

44
// Plugin
55
export { default as MediaRecorderPlugin } from './plugin'
66

7+
// Types
8+
export type { MediaRecorderPluginOptions } from './types'
9+
710
// Composables
811
export { useMediaRecorder } from './useMediaRecorder'
9-
10-
// Types
11-
export type {MediaRecorderPluginOptions} from './types'
12-
export type {UseMediaRecorderReturn} from './useMediaRecorder'
12+
export type { UseMediaRecorderReturn } from './useMediaRecorder'

0 commit comments

Comments
 (0)