Spaces:
Building
Building
Update flare-ui/src/app/services/audio-stream.service.ts
Browse files
flare-ui/src/app/services/audio-stream.service.ts
CHANGED
@@ -64,75 +64,69 @@ export class AudioStreamService implements OnDestroy {
|
|
64 |
console.log('π€ [AudioStream] startRecording called', {
|
65 |
isAlreadyRecording: this.isRecording(),
|
66 |
hasStream: !!this.audioStream,
|
|
|
67 |
timestamp: new Date().toISOString()
|
68 |
});
|
69 |
|
70 |
-
|
71 |
-
|
72 |
-
console.warn('β οΈ [AudioStream] Already recording, ignoring start request');
|
73 |
return;
|
74 |
}
|
75 |
|
76 |
// Check browser support
|
77 |
if (!AudioStreamService.checkBrowserSupport()) {
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
// Check permission first
|
82 |
-
const permission = await this.checkMicrophonePermission();
|
83 |
-
if (permission === 'denied') {
|
84 |
-
throw this.createError('permission', 'Microphone permission denied');
|
85 |
}
|
86 |
-
|
87 |
-
// Request microphone access
|
88 |
try {
|
|
|
89 |
this.audioStream = await navigator.mediaDevices.getUserMedia(this.constraints);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
90 |
} catch (error: any) {
|
|
|
|
|
|
|
|
|
91 |
if (error.name === 'NotAllowedError' || error.name === 'PermissionDeniedError') {
|
92 |
-
|
93 |
} else if (error.name === 'NotFoundError' || error.name === 'DevicesNotFoundError') {
|
94 |
-
|
95 |
} else {
|
96 |
-
|
97 |
}
|
|
|
|
|
|
|
98 |
}
|
99 |
-
|
100 |
-
|
101 |
-
const options: MediaRecorderOptions = {
|
102 |
-
mimeType: this.getPreferredMimeType()
|
103 |
-
};
|
104 |
-
|
105 |
-
try {
|
106 |
-
this.mediaRecorder = new MediaRecorder(this.audioStream, options);
|
107 |
-
} catch (error) {
|
108 |
-
// Fallback to default options if preferred mime type fails
|
109 |
-
console.warn('Failed with preferred mime type, using defaults:', error);
|
110 |
-
this.mediaRecorder = new MediaRecorder(this.audioStream);
|
111 |
-
}
|
112 |
-
|
113 |
-
// Set up event handlers
|
114 |
-
this.setupMediaRecorderHandlers();
|
115 |
-
|
116 |
-
// Start volume monitoring
|
117 |
-
this.startVolumeMonitoring();
|
118 |
-
|
119 |
-
// Start recording with timeslice for real-time streaming
|
120 |
-
this.mediaRecorder.start(100); // Send chunks every 100ms
|
121 |
-
this.recordingStateSubject.next(true);
|
122 |
-
|
123 |
-
console.log('β
Audio recording started');
|
124 |
-
|
125 |
-
} catch (error: any) {
|
126 |
-
console.error('Failed to start recording:', error);
|
127 |
this.cleanup();
|
128 |
-
|
129 |
-
// Emit error
|
130 |
-
if (error.type) {
|
131 |
-
this.errorSubject.next(error);
|
132 |
-
} else {
|
133 |
-
this.errorSubject.next(this.createError('unknown', error.message || 'Failed to start recording', error));
|
134 |
-
}
|
135 |
-
|
136 |
throw error;
|
137 |
}
|
138 |
}
|
|
|
64 |
console.log('π€ [AudioStream] startRecording called', {
|
65 |
isAlreadyRecording: this.isRecording(),
|
66 |
hasStream: !!this.audioStream,
|
67 |
+
state: this.mediaRecorder?.state,
|
68 |
timestamp: new Date().toISOString()
|
69 |
});
|
70 |
|
71 |
+
if (this.mediaRecorder && this.mediaRecorder.state !== 'inactive') {
|
72 |
+
console.warn('Recording already in progress');
|
|
|
73 |
return;
|
74 |
}
|
75 |
|
76 |
// Check browser support
|
77 |
if (!AudioStreamService.checkBrowserSupport()) {
|
78 |
+
const error = this.createError('browser', 'Browser does not support audio recording');
|
79 |
+
this.errorSubject.next(error);
|
80 |
+
throw error;
|
|
|
|
|
|
|
|
|
81 |
}
|
82 |
+
|
|
|
83 |
try {
|
84 |
+
// Get audio stream
|
85 |
this.audioStream = await navigator.mediaDevices.getUserMedia(this.constraints);
|
86 |
+
console.log('β
[AudioStream] Got media stream');
|
87 |
+
|
88 |
+
// Create MediaRecorder with optimal MIME type
|
89 |
+
const mimeType = this.getPreferredMimeType();
|
90 |
+
const options: MediaRecorderOptions = {};
|
91 |
+
if (mimeType) {
|
92 |
+
options.mimeType = mimeType;
|
93 |
+
}
|
94 |
+
|
95 |
+
this.mediaRecorder = new MediaRecorder(this.audioStream, options);
|
96 |
+
console.log(`β
[AudioStream] MediaRecorder created with MIME type: ${mimeType || 'default'}`);
|
97 |
+
|
98 |
+
// Set up handlers
|
99 |
+
this.setupMediaRecorderHandlers();
|
100 |
+
|
101 |
+
// Start recording with timeslice for regular data chunks
|
102 |
+
// 100ms timeslice = 10 chunks per second
|
103 |
+
this.mediaRecorder.start(100);
|
104 |
+
|
105 |
+
this.recordingStateSubject.next(true);
|
106 |
+
console.log('β
[AudioStream] Recording started successfully');
|
107 |
+
|
108 |
+
// Start volume monitoring
|
109 |
+
this.startVolumeMonitoring();
|
110 |
+
|
111 |
} catch (error: any) {
|
112 |
+
console.error('β [AudioStream] getUserMedia error:', error);
|
113 |
+
|
114 |
+
let audioError: AudioStreamError;
|
115 |
+
|
116 |
if (error.name === 'NotAllowedError' || error.name === 'PermissionDeniedError') {
|
117 |
+
audioError = this.createError('permission', 'Microphone permission denied');
|
118 |
} else if (error.name === 'NotFoundError' || error.name === 'DevicesNotFoundError') {
|
119 |
+
audioError = this.createError('device', 'No microphone found');
|
120 |
} else {
|
121 |
+
audioError = this.createError('unknown', `Failed to access microphone: ${error.message}`, error);
|
122 |
}
|
123 |
+
|
124 |
+
this.errorSubject.next(audioError);
|
125 |
+
throw audioError;
|
126 |
}
|
127 |
+
} catch (error) {
|
128 |
+
console.error('β [AudioStream] startRecording error:', error);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
129 |
this.cleanup();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
130 |
throw error;
|
131 |
}
|
132 |
}
|