@@ -15,7 +15,7 @@ type VoiceRecorderProps = {
1515export function VoiceRecorder ( { onRecordingComplete, isProcessing } : VoiceRecorderProps ) {
1616 const { settings } = useSettings ( ) ;
1717 const [ isRecording , setIsRecording ] = useState ( false ) ;
18- const [ hasPermission , setHasPermission ] = useState < boolean | null > ( null ) ;
18+ const [ hasPermission , setHasPermission ] = useState ( true ) ; // Assume true, will be updated on error
1919 const mediaRecorderRef = useRef < MediaRecorder | null > ( null ) ;
2020 const audioChunksRef = useRef < Blob [ ] > ( [ ] ) ;
2121 const silenceTimerRef = useRef < NodeJS . Timeout | null > ( null ) ;
@@ -24,30 +24,6 @@ export function VoiceRecorder({ onRecordingComplete, isProcessing }: VoiceRecord
2424 const streamRef = useRef < MediaStream | null > ( null ) ;
2525 const spacebarHeldRef = useRef ( false ) ;
2626
27- const checkMicPermission = useCallback ( async ( ) => {
28- try {
29- // Check permission status without prompting
30- const permissionStatus = await navigator . permissions . query ( { name : 'microphone' as PermissionName } ) ;
31- if ( permissionStatus . state === 'granted' ) {
32- setHasPermission ( true ) ;
33- } else if ( permissionStatus . state === 'denied' ) {
34- setHasPermission ( false ) ;
35- } else {
36- setHasPermission ( null ) ; // Prompt needed
37- }
38- permissionStatus . onchange = ( ) => {
39- setHasPermission ( permissionStatus . state === 'granted' ) ;
40- } ;
41- } catch ( error ) {
42- console . error ( "Permissions API not supported, falling back to getUserMedia check" , error ) ;
43- setHasPermission ( null ) ; // Fallback to prompt on action
44- }
45- } , [ ] ) ;
46-
47- useEffect ( ( ) => {
48- checkMicPermission ( ) ;
49- } , [ checkMicPermission ] ) ;
50-
5127 const stopSilenceTimer = ( ) => {
5228 if ( silenceTimerRef . current ) {
5329 clearTimeout ( silenceTimerRef . current ) ;
@@ -67,21 +43,17 @@ export function VoiceRecorder({ onRecordingComplete, isProcessing }: VoiceRecord
6743 } , [ ] ) ;
6844
6945 const stopRecording = useCallback ( ( ) => {
70- if ( mediaRecorderRef . current && isRecording ) {
46+ if ( mediaRecorderRef . current && mediaRecorderRef . current . state === "recording" ) {
7147 mediaRecorderRef . current . stop ( ) ;
72- setIsRecording ( false ) ;
7348 }
74- } , [ isRecording ] ) ;
49+ // We set isRecording to false in the onstop handler
50+ } , [ ] ) ;
7551
7652 const startRecording = useCallback ( async ( ) => {
7753 if ( isRecording || isProcessing ) return ;
78-
79- if ( hasPermission === false ) {
80- alert ( 'Microphone access is denied. Please enable it in your browser settings.' ) ;
81- return ;
82- }
8354
8455 try {
56+ // Directly request microphone access. This is the key change to trigger the prompt.
8557 const stream = await navigator . mediaDevices . getUserMedia ( { audio : true } ) ;
8658 streamRef . current = stream ;
8759 setHasPermission ( true ) ;
@@ -96,13 +68,20 @@ export function VoiceRecorder({ onRecordingComplete, isProcessing }: VoiceRecord
9668 } ;
9769
9870 mediaRecorderRef . current . onstop = ( ) => {
71+ setIsRecording ( false ) ;
9972 stopSilenceTimer ( ) ;
10073 if ( audioChunksRef . current . length > 0 ) {
10174 const audioBlob = new Blob ( audioChunksRef . current , { type : 'audio/webm' } ) ;
10275 onRecordingComplete ( audioBlob ) ;
10376 }
10477 stopMediaStream ( ) ;
10578 } ;
79+
80+ mediaRecorderRef . current . onerror = ( event ) => {
81+ console . error ( 'MediaRecorder error:' , event ) ;
82+ setIsRecording ( false ) ;
83+ stopMediaStream ( ) ;
84+ }
10685
10786 mediaRecorderRef . current . start ( ) ;
10887 setIsRecording ( true ) ;
@@ -142,9 +121,9 @@ export function VoiceRecorder({ onRecordingComplete, isProcessing }: VoiceRecord
142121 } catch ( error ) {
143122 console . error ( 'Error accessing microphone:' , error ) ;
144123 setHasPermission ( false ) ;
145- alert ( 'Could not access microphone. Please check permissions and try again .' ) ;
124+ alert ( 'Could not access microphone. Please enable it in your browser settings and refresh the page .' ) ;
146125 }
147- } , [ isRecording , isProcessing , hasPermission , settings . micMode , settings . intelligentStopDuration , onRecordingComplete , stopMediaStream , stopRecording ] ) ;
126+ } , [ isRecording , isProcessing , settings . micMode , settings . intelligentStopDuration , onRecordingComplete , stopMediaStream , stopRecording ] ) ;
148127
149128
150129 useEffect ( ( ) => {
@@ -209,7 +188,7 @@ export function VoiceRecorder({ onRecordingComplete, isProcessing }: VoiceRecord
209188 onPointerDown = { handlePointerDown }
210189 onPointerUp = { handlePointerUp }
211190 onPointerLeave = { handlePointerUp } // Stop if user's finger leaves the button
212- disabled = { isProcessing || ( hasPermission === null && settings . micMode === 'tap' ) }
191+ disabled = { isProcessing || ! hasPermission }
213192 size = "lg"
214193 className = { cn (
215194 'w-20 h-20 rounded-full transition-all duration-300 ease-in-out touch-none' ,
@@ -229,4 +208,4 @@ export function VoiceRecorder({ onRecordingComplete, isProcessing }: VoiceRecord
229208 ) ;
230209}
231210
232-
211+
0 commit comments