@jaak.ai/stamps 2.0.0-dev.53 → 2.0.0-dev.54

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,6 +6,7 @@ export class CameraService {
6
6
  deviceType = 'desktop';
7
7
  preferredCameraFacing = null;
8
8
  preferredCamera = 'auto';
9
+ isManuallySelected = false;
9
10
  constructor(logger, eventBus, preferredCamera = 'auto') {
10
11
  this.logger = logger;
11
12
  this.eventBus = eventBus;
@@ -52,6 +53,11 @@ export class CameraService {
52
53
  }))
53
54
  });
54
55
  this.setInitialCameraPreference();
56
+ this.logger.state('PREFERENCIA_INICIAL_APLICADA', {
57
+ selectedCameraId: this.selectedCameraId,
58
+ preferredCameraFacing: this.preferredCameraFacing,
59
+ preferredCamera: this.preferredCamera
60
+ });
55
61
  this.eventBus.emit('camera-changed', this.selectedCameraId);
56
62
  return this.availableCameras;
57
63
  }
@@ -77,6 +83,7 @@ export class CameraService {
77
83
  }
78
84
  this.selectedCameraId = cameraId;
79
85
  this.updatePreferredFacing(camera);
86
+ this.isManuallySelected = true; // Mark as manually selected
80
87
  this.savePreference();
81
88
  this.eventBus.emit('camera-changed', cameraId);
82
89
  }
@@ -84,12 +91,31 @@ export class CameraService {
84
91
  return this.preferredCameraFacing;
85
92
  }
86
93
  async setupCamera(constraints) {
87
- const finalConstraints = constraints || await this.getMaxResolution();
88
- const stream = await navigator.mediaDevices.getUserMedia({
89
- video: finalConstraints,
90
- audio: false
91
- });
92
- return stream;
94
+ try {
95
+ const finalConstraints = constraints || await this.getMaxResolution();
96
+ const stream = await navigator.mediaDevices.getUserMedia({
97
+ video: finalConstraints,
98
+ audio: false
99
+ });
100
+ return stream;
101
+ }
102
+ catch (error) {
103
+ this.logger.error('Error en setupCamera, intentando con restricciones básicas:', error);
104
+ // Fallback to basic constraints if getMaxResolution fails
105
+ const basicConstraints = {
106
+ width: { ideal: 1280 },
107
+ height: { ideal: 720 }
108
+ };
109
+ // Only add facingMode if not on desktop to avoid OverconstrainedError
110
+ if (this.deviceType !== 'desktop' && this.preferredCameraFacing) {
111
+ basicConstraints.facingMode = this.preferredCameraFacing;
112
+ }
113
+ this.logger.state('USANDO_RESTRICCIONES_BASICAS', { constraints: basicConstraints });
114
+ return await navigator.mediaDevices.getUserMedia({
115
+ video: basicConstraints,
116
+ audio: false
117
+ });
118
+ }
93
119
  }
94
120
  async switchCamera(cameraId) {
95
121
  const selectedCamera = this.availableCameras.find(cam => cam.deviceId === cameraId);
@@ -101,7 +127,8 @@ export class CameraService {
101
127
  await this.setSelectedCamera(cameraId);
102
128
  this.logger.state('CAMARA_CAMBIADA', {
103
129
  label: selectedCamera.label,
104
- deviceId: selectedCamera.deviceId
130
+ deviceId: selectedCamera.deviceId,
131
+ isManuallySelected: this.isManuallySelected
105
132
  });
106
133
  }
107
134
  async flipToNextCamera() {
@@ -183,6 +210,13 @@ export class CameraService {
183
210
  setInitialCameraPreference() {
184
211
  if (this.availableCameras.length === 0)
185
212
  return;
213
+ // Clear any existing localStorage preferences to ensure fresh start
214
+ localStorage.removeItem('jaak-stamps-camera-preference');
215
+ this.logger.state('APLICANDO_PREFERENCIA_INICIAL', {
216
+ preferredCamera: this.preferredCamera,
217
+ availableCamerasCount: this.availableCameras.length
218
+ });
219
+ this.isManuallySelected = false; // Reset manual selection flag
186
220
  if (this.preferredCamera === 'front') {
187
221
  this.selectFrontCamera();
188
222
  }
@@ -195,23 +229,56 @@ export class CameraService {
195
229
  }
196
230
  selectFrontCamera() {
197
231
  this.preferredCameraFacing = 'user';
198
- const frontCamera = this.availableCameras.find(camera => camera.label.toLowerCase().includes('front') ||
199
- camera.label.toLowerCase().includes('user') ||
200
- camera.label.toLowerCase().includes('selfie') ||
201
- !camera.label.toLowerCase().includes('back') && !camera.label.toLowerCase().includes('rear'));
232
+ this.logger.state('BUSCANDO_CAMARA_FRONTAL', {
233
+ availableCameras: this.availableCameras.map(cam => ({
234
+ id: cam.deviceId,
235
+ label: cam.label
236
+ }))
237
+ });
238
+ const frontCamera = this.availableCameras.find(camera => {
239
+ const label = camera.label.toLowerCase();
240
+ return label.includes('front') ||
241
+ label.includes('user') ||
242
+ label.includes('selfie') ||
243
+ label.includes('frontal') ||
244
+ (!label.includes('back') && !label.includes('rear') && !label.includes('environment'));
245
+ });
246
+ // If not found, use the first camera (usually front on mobile)
202
247
  this.selectedCameraId = frontCamera ? frontCamera.deviceId : this.availableCameras[0].deviceId;
203
248
  this.logger.state('CAMARA_FRONTAL_SELECCIONADA', {
249
+ found: !!frontCamera,
204
250
  label: frontCamera?.label || this.availableCameras[0].label,
205
251
  deviceId: this.selectedCameraId
206
252
  });
207
253
  }
208
254
  selectBackCamera() {
209
255
  this.preferredCameraFacing = 'environment';
210
- const backCamera = this.availableCameras.find(camera => camera.label.toLowerCase().includes('back') ||
211
- camera.label.toLowerCase().includes('rear') ||
212
- camera.label.toLowerCase().includes('environment'));
256
+ this.logger.state('BUSCANDO_CAMARA_TRASERA', {
257
+ availableCameras: this.availableCameras.map(cam => ({
258
+ id: cam.deviceId,
259
+ label: cam.label
260
+ }))
261
+ });
262
+ // Try to find rear camera with multiple detection methods
263
+ let backCamera = this.availableCameras.find(camera => {
264
+ const label = camera.label.toLowerCase();
265
+ return label.includes('back') ||
266
+ label.includes('rear') ||
267
+ label.includes('environment') ||
268
+ label.includes('trasera') ||
269
+ label.includes('posterior');
270
+ });
271
+ // If not found by label, try to use the last camera (usually rear on mobile)
272
+ if (!backCamera && this.availableCameras.length > 1) {
273
+ backCamera = this.availableCameras[this.availableCameras.length - 1];
274
+ this.logger.state('USANDO_ULTIMA_CAMARA_COMO_TRASERA', {
275
+ label: backCamera.label,
276
+ deviceId: backCamera.deviceId
277
+ });
278
+ }
213
279
  this.selectedCameraId = backCamera ? backCamera.deviceId : this.availableCameras[0].deviceId;
214
280
  this.logger.state('CAMARA_TRASERA_SELECCIONADA', {
281
+ found: !!backCamera,
215
282
  label: backCamera?.label || this.availableCameras[0].label,
216
283
  deviceId: this.selectedCameraId
217
284
  });
@@ -222,8 +289,10 @@ export class CameraService {
222
289
  this.logger.state('CAMARA_AUTO_SELECCIONADA_MOBILE', { type: 'rear' });
223
290
  }
224
291
  else {
225
- this.selectedCameraId = this.availableCameras[0].deviceId;
292
+ // For desktop, prefer front camera (usually built-in webcam)
293
+ this.selectFrontCamera();
226
294
  this.logger.state('CAMARA_AUTO_SELECCIONADA_DESKTOP', {
295
+ type: 'front',
227
296
  label: this.availableCameras[0].label,
228
297
  deviceId: this.selectedCameraId
229
298
  });
@@ -237,15 +306,60 @@ export class CameraService {
237
306
  }
238
307
  async getMaxResolution() {
239
308
  try {
309
+ // Ensure device type is detected before determining constraints
310
+ if (!this.deviceType || this.deviceType === 'desktop') {
311
+ await this.detectDeviceType();
312
+ }
240
313
  const videoConstraints = {};
241
- if (this.selectedCameraId) {
314
+ this.logger.state('CONFIGURANDO_CONSTRAINS_CAMARA', {
315
+ selectedCameraId: this.selectedCameraId,
316
+ preferredCameraFacing: this.preferredCameraFacing,
317
+ preferredCamera: this.preferredCamera,
318
+ deviceType: this.deviceType,
319
+ isManuallySelected: this.isManuallySelected
320
+ });
321
+ if (this.isManuallySelected && this.selectedCameraId) {
322
+ // When manually selected, use deviceId for exact camera selection
242
323
  videoConstraints.deviceId = { exact: this.selectedCameraId };
324
+ this.logger.state('USANDO_CAMARA_MANUAL', {
325
+ deviceId: this.selectedCameraId
326
+ });
243
327
  }
244
328
  else if (this.preferredCameraFacing) {
245
- videoConstraints.facingMode = this.preferredCameraFacing;
329
+ // Use facingMode for initial preference-based selection
330
+ // Use 'ideal' instead of 'exact' to avoid OverconstrainedError on desktop
331
+ const facingConstraint = this.deviceType === 'desktop'
332
+ ? { ideal: this.preferredCameraFacing }
333
+ : { exact: this.preferredCameraFacing };
334
+ videoConstraints.facingMode = facingConstraint;
335
+ this.logger.state('USANDO_FACING_CONSTRAINT', {
336
+ facingMode: this.preferredCameraFacing,
337
+ constraintType: this.deviceType === 'desktop' ? 'ideal' : 'exact'
338
+ });
339
+ }
340
+ else if (this.selectedCameraId) {
341
+ videoConstraints.deviceId = { exact: this.selectedCameraId };
342
+ this.logger.state('USANDO_CAMARA_SELECCIONADA', {
343
+ deviceId: this.selectedCameraId
344
+ });
246
345
  }
247
346
  else {
248
- videoConstraints.facingMode = "environment";
347
+ // Use preferredCamera setting to determine default facing mode
348
+ if (this.preferredCamera === 'front') {
349
+ videoConstraints.facingMode = "user";
350
+ }
351
+ else if (this.preferredCamera === 'back') {
352
+ videoConstraints.facingMode = "environment";
353
+ }
354
+ else {
355
+ // Auto mode: use environment for mobile/tablet, user for desktop
356
+ videoConstraints.facingMode = (this.deviceType === 'mobile' || this.deviceType === 'tablet') ? "environment" : "user";
357
+ }
358
+ this.logger.state('USANDO_PREFERENCIA_CONFIGURADA', {
359
+ facingMode: videoConstraints.facingMode,
360
+ preferredCamera: this.preferredCamera,
361
+ deviceType: this.deviceType
362
+ });
249
363
  }
250
364
  const tempStream = await navigator.mediaDevices.getUserMedia({
251
365
  video: videoConstraints
@@ -277,6 +391,10 @@ export class CameraService {
277
391
  }
278
392
  catch (err) {
279
393
  this.logger.warn('No se pudieron obtener capacidades de cámara, usando configuración de respaldo');
394
+ // Ensure device type is detected before determining constraints
395
+ if (!this.deviceType || this.deviceType === 'desktop') {
396
+ await this.detectDeviceType();
397
+ }
280
398
  const isTablet = /iPad|Android/i.test(navigator.userAgent) && window.innerWidth >= 768;
281
399
  const fallbackConstraints = {
282
400
  width: { ideal: isTablet ? 1280 : 1920 },
@@ -284,14 +402,33 @@ export class CameraService {
284
402
  };
285
403
  // Apply basic focus settings even for fallback
286
404
  this.applyBasicFocusSettings(fallbackConstraints);
287
- if (this.selectedCameraId) {
405
+ if (this.isManuallySelected && this.selectedCameraId) {
406
+ // When manually selected, use deviceId for exact camera selection
288
407
  fallbackConstraints.deviceId = { exact: this.selectedCameraId };
289
408
  }
290
409
  else if (this.preferredCameraFacing) {
291
- fallbackConstraints.facingMode = this.preferredCameraFacing;
410
+ // Use facingMode for initial preference-based selection
411
+ // Use 'ideal' instead of 'exact' to avoid OverconstrainedError on desktop
412
+ const facingConstraint = this.deviceType === 'desktop'
413
+ ? { ideal: this.preferredCameraFacing }
414
+ : { exact: this.preferredCameraFacing };
415
+ fallbackConstraints.facingMode = facingConstraint;
416
+ }
417
+ else if (this.selectedCameraId) {
418
+ fallbackConstraints.deviceId = { exact: this.selectedCameraId };
292
419
  }
293
420
  else {
294
- fallbackConstraints.facingMode = "environment";
421
+ // Use preferredCamera setting to determine default facing mode
422
+ if (this.preferredCamera === 'front') {
423
+ fallbackConstraints.facingMode = "user";
424
+ }
425
+ else if (this.preferredCamera === 'back') {
426
+ fallbackConstraints.facingMode = "environment";
427
+ }
428
+ else {
429
+ // Auto mode: use environment for mobile/tablet, user for desktop
430
+ fallbackConstraints.facingMode = (this.deviceType === 'mobile' || this.deviceType === 'tablet') ? "environment" : "user";
431
+ }
295
432
  }
296
433
  return fallbackConstraints;
297
434
  }
@@ -1 +1 @@
1
- {"version":3,"file":"CameraService.js","sourceRoot":"","sources":["../../src/services/CameraService.ts"],"names":[],"mappings":"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","sourcesContent":["import { ICameraService, CameraInfo, CameraPreference } from './interfaces/ICameraService';\nimport { ILogger } from './interfaces/ILogger';\nimport { IEventBus } from './interfaces/IEventBus';\n\nexport class CameraService implements ICameraService {\n private availableCameras: MediaDeviceInfo[] = [];\n private selectedCameraId: string | null = null;\n private deviceType: 'mobile' | 'desktop' | 'tablet' = 'desktop';\n private preferredCameraFacing: 'environment' | 'user' | null = null;\n private preferredCamera: 'auto' | 'front' | 'back' = 'auto';\n\n constructor(\n private logger: ILogger,\n private eventBus: IEventBus,\n preferredCamera: 'auto' | 'front' | 'back' = 'auto'\n ) {\n this.preferredCamera = preferredCamera;\n }\n\n async detectDeviceType(): Promise<'mobile' | 'desktop' | 'tablet'> {\n const userAgent = navigator.userAgent;\n const isMobile = /Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent);\n const isTablet = /iPad|Android/i.test(userAgent) && window.innerWidth >= 768;\n \n if (isTablet) {\n this.deviceType = 'tablet';\n } else if (isMobile) {\n this.deviceType = 'mobile';\n } else {\n this.deviceType = 'desktop';\n }\n \n this.logger.state('DISPOSITIVO_DETECTADO', {\n deviceType: this.deviceType,\n userAgent: navigator.userAgent,\n screenDimensions: { width: window.innerWidth, height: window.innerHeight }\n });\n \n return this.deviceType;\n }\n\n async enumerateDevices(): Promise<MediaDeviceInfo[]> {\n try {\n const permissionStatus = await this.checkCameraPermission();\n \n if (permissionStatus === 'denied') {\n this.logger.error('Permiso de cámara denegado por el usuario');\n return [];\n }\n \n if (permissionStatus === 'prompt') {\n const tempStream = await navigator.mediaDevices.getUserMedia({ video: true });\n tempStream.getTracks().forEach(track => track.stop());\n }\n \n const devices = await navigator.mediaDevices.enumerateDevices();\n this.availableCameras = devices.filter(device => device.kind === 'videoinput');\n \n this.logger.state('CAMARAS_DETECTADAS', {\n count: this.availableCameras.length,\n cameras: this.availableCameras.map(cam => ({\n id: cam.deviceId,\n label: cam.label || 'Unknown Camera'\n }))\n });\n \n this.setInitialCameraPreference();\n this.eventBus.emit('camera-changed', this.selectedCameraId);\n \n return this.availableCameras;\n } catch (error) {\n this.logger.error('Error al enumerar cámaras disponibles:', error);\n this.handleCameraPermissionError(error);\n return [];\n }\n }\n\n getAvailableCameras(): MediaDeviceInfo[] {\n return [...this.availableCameras];\n }\n\n isMultipleCamerasAvailable(): boolean {\n return this.availableCameras.length > 1;\n }\n\n getSelectedCameraId(): string | null {\n return this.selectedCameraId;\n }\n\n async setSelectedCamera(cameraId: string): Promise<void> {\n const camera = this.availableCameras.find(cam => cam.deviceId === cameraId);\n if (!camera) {\n throw new Error(`Camera with ID ${cameraId} not found`);\n }\n \n this.selectedCameraId = cameraId;\n this.updatePreferredFacing(camera);\n this.savePreference();\n this.eventBus.emit('camera-changed', cameraId);\n }\n\n getPreferredFacing(): 'environment' | 'user' | null {\n return this.preferredCameraFacing;\n }\n\n async setupCamera(constraints?: MediaTrackConstraints): Promise<MediaStream> {\n const finalConstraints = constraints || await this.getMaxResolution();\n \n const stream = await navigator.mediaDevices.getUserMedia({\n video: finalConstraints,\n audio: false\n });\n\n return stream;\n }\n\n async switchCamera(cameraId: string): Promise<void> {\n const selectedCamera = this.availableCameras.find(cam => cam.deviceId === cameraId);\n if (!selectedCamera) {\n this.logger.warn('Cámara seleccionada no encontrada, re-enumerando dispositivos...');\n await this.enumerateDevices();\n return;\n }\n \n await this.setSelectedCamera(cameraId);\n this.logger.state('CAMARA_CAMBIADA', { \n label: selectedCamera.label, \n deviceId: selectedCamera.deviceId \n });\n }\n\n async flipToNextCamera(): Promise<void> {\n if (!this.isMultipleCamerasAvailable()) return;\n \n const currentIndex = this.availableCameras.findIndex(\n camera => camera.deviceId === this.selectedCameraId\n );\n \n const nextIndex = (currentIndex + 1) % this.availableCameras.length;\n const nextCamera = this.availableCameras[nextIndex];\n \n await this.switchCamera(nextCamera.deviceId);\n }\n\n savePreference(): void {\n try {\n const preference: CameraPreference = {\n cameraId: this.selectedCameraId!,\n facing: this.preferredCameraFacing,\n timestamp: Date.now()\n };\n \n localStorage.setItem('jaak-stamps-camera-preference', JSON.stringify(preference));\n this.logger.state('PREFERENCIA_CAMARA_GUARDADA', preference);\n } catch (error) {\n this.logger.warn('Error al guardar preferencia de cámara:', error);\n }\n }\n\n loadPreference(): void {\n try {\n const saved = localStorage.getItem('jaak-stamps-camera-preference');\n if (saved) {\n const preference: CameraPreference = JSON.parse(saved);\n \n const isStillAvailable = this.availableCameras.some(\n camera => camera.deviceId === preference.cameraId\n );\n \n if (isStillAvailable) {\n this.selectedCameraId = preference.cameraId;\n this.preferredCameraFacing = preference.facing;\n this.logger.state('PREFERENCIA_CAMARA_CARGADA', preference);\n }\n }\n } catch (error) {\n this.logger.warn('Error al cargar preferencia de cámara:', error);\n }\n }\n\n isRearCamera(stream: MediaStream): boolean {\n const videoTrack = stream.getVideoTracks()[0];\n if (!videoTrack) return false;\n \n const settings = videoTrack.getSettings();\n return settings.facingMode === 'environment';\n }\n\n getCameraInfo(): {\n availableCameras: CameraInfo[];\n selectedCameraId: string | null;\n deviceType: string;\n isMultipleCamerasAvailable: boolean;\n preferredFacing: 'environment' | 'user' | null;\n } {\n return {\n availableCameras: this.availableCameras.map(camera => ({\n id: camera.deviceId,\n label: camera.label || 'Unknown Camera',\n selected: camera.deviceId === this.selectedCameraId\n })),\n selectedCameraId: this.selectedCameraId,\n deviceType: this.deviceType,\n isMultipleCamerasAvailable: this.isMultipleCamerasAvailable(),\n preferredFacing: this.preferredCameraFacing\n };\n }\n\n private async checkCameraPermission(): Promise<'granted' | 'denied' | 'prompt'> {\n try {\n if (!navigator.permissions) {\n return 'prompt';\n }\n \n const permission = await navigator.permissions.query({ name: 'camera' as PermissionName });\n return permission.state;\n } catch (error) {\n this.logger.warn('No se pudo verificar permisos de cámara:', error);\n return 'prompt';\n }\n }\n\n private handleCameraPermissionError(error: any): void {\n this.availableCameras = [];\n this.eventBus.emit('error', new Error(`Camera permission error: ${error.message}`));\n }\n\n private setInitialCameraPreference(): void {\n if (this.availableCameras.length === 0) return;\n \n if (this.preferredCamera === 'front') {\n this.selectFrontCamera();\n } else if (this.preferredCamera === 'back') {\n this.selectBackCamera();\n } else {\n this.selectAutoCamera();\n }\n }\n\n private selectFrontCamera(): void {\n this.preferredCameraFacing = 'user';\n \n const frontCamera = this.availableCameras.find(camera => \n camera.label.toLowerCase().includes('front') || \n camera.label.toLowerCase().includes('user') ||\n camera.label.toLowerCase().includes('selfie') ||\n !camera.label.toLowerCase().includes('back') && !camera.label.toLowerCase().includes('rear')\n );\n \n this.selectedCameraId = frontCamera ? frontCamera.deviceId : this.availableCameras[0].deviceId;\n this.logger.state('CAMARA_FRONTAL_SELECCIONADA', { \n label: frontCamera?.label || this.availableCameras[0].label,\n deviceId: this.selectedCameraId \n });\n }\n\n private selectBackCamera(): void {\n this.preferredCameraFacing = 'environment';\n \n const backCamera = this.availableCameras.find(camera => \n camera.label.toLowerCase().includes('back') || \n camera.label.toLowerCase().includes('rear') ||\n camera.label.toLowerCase().includes('environment')\n );\n \n this.selectedCameraId = backCamera ? backCamera.deviceId : this.availableCameras[0].deviceId;\n this.logger.state('CAMARA_TRASERA_SELECCIONADA', { \n label: backCamera?.label || this.availableCameras[0].label,\n deviceId: this.selectedCameraId \n });\n }\n\n private selectAutoCamera(): void {\n if (this.deviceType === 'mobile' || this.deviceType === 'tablet') {\n this.selectBackCamera();\n this.logger.state('CAMARA_AUTO_SELECCIONADA_MOBILE', { type: 'rear' });\n } else {\n this.selectedCameraId = this.availableCameras[0].deviceId;\n this.logger.state('CAMARA_AUTO_SELECCIONADA_DESKTOP', { \n label: this.availableCameras[0].label, \n deviceId: this.selectedCameraId \n });\n }\n }\n\n private updatePreferredFacing(camera: MediaDeviceInfo): void {\n const isRearCamera = camera.label.toLowerCase().includes('back') || \n camera.label.toLowerCase().includes('rear') ||\n camera.label.toLowerCase().includes('environment');\n this.preferredCameraFacing = isRearCamera ? 'environment' : 'user';\n }\n\n private async getMaxResolution(): Promise<MediaTrackConstraints> {\n try {\n const videoConstraints: MediaTrackConstraints = {};\n \n if (this.selectedCameraId) {\n videoConstraints.deviceId = { exact: this.selectedCameraId };\n } else if (this.preferredCameraFacing) {\n videoConstraints.facingMode = this.preferredCameraFacing;\n } else {\n videoConstraints.facingMode = \"environment\";\n }\n \n const tempStream = await navigator.mediaDevices.getUserMedia({\n video: videoConstraints\n });\n \n const videoTrack = tempStream.getVideoTracks()[0];\n const capabilities = videoTrack.getCapabilities();\n tempStream.getTracks().forEach(track => track.stop());\n \n const constraints: MediaTrackConstraints = { ...videoConstraints };\n \n // Enhanced focus and image quality settings\n this.applyAdvancedCameraSettings(constraints, capabilities);\n \n if (capabilities.width && capabilities.height) {\n const maxWidth = Math.min(capabilities.width.max, 1920);\n const maxHeight = Math.min(capabilities.height.max, 1080);\n \n const isTablet = /iPad|Android/i.test(navigator.userAgent) && window.innerWidth >= 768;\n \n if (isTablet) {\n constraints.width = { ideal: Math.min(maxWidth, 1280) };\n constraints.height = { ideal: Math.min(maxHeight, 720) };\n } else {\n constraints.width = { ideal: maxWidth };\n constraints.height = { ideal: maxHeight };\n }\n }\n \n this.logger.state('CONFIGURACION_CAMARA_OPTIMIZADA', {\n constraints,\n capabilities: this.getCapabilitiesSummary(capabilities)\n });\n \n return constraints;\n } catch (err) {\n this.logger.warn('No se pudieron obtener capacidades de cámara, usando configuración de respaldo');\n \n const isTablet = /iPad|Android/i.test(navigator.userAgent) && window.innerWidth >= 768;\n const fallbackConstraints: MediaTrackConstraints = {\n width: { ideal: isTablet ? 1280 : 1920 },\n height: { ideal: isTablet ? 720 : 1080 }\n };\n \n // Apply basic focus settings even for fallback\n this.applyBasicFocusSettings(fallbackConstraints);\n \n if (this.selectedCameraId) {\n fallbackConstraints.deviceId = { exact: this.selectedCameraId };\n } else if (this.preferredCameraFacing) {\n fallbackConstraints.facingMode = this.preferredCameraFacing;\n } else {\n fallbackConstraints.facingMode = \"environment\";\n }\n \n return fallbackConstraints;\n }\n }\n\n private applyAdvancedCameraSettings(constraints: MediaTrackConstraints, capabilities: MediaTrackCapabilities): void {\n // Apply standard camera settings that are widely supported\n \n // Frame rate optimization\n if (capabilities.frameRate) {\n constraints.frameRate = {\n ideal: 30,\n min: 15,\n max: 60\n };\n }\n\n // Width and height constraints for optimal resolution\n if (capabilities.width && capabilities.height) {\n constraints.width = {\n ideal: Math.min(1920, capabilities.width.max || 1920),\n min: 640\n };\n constraints.height = {\n ideal: Math.min(1080, capabilities.height.max || 1080),\n min: 480\n };\n }\n\n // Apply enhanced constraints through advanced array for better browser compatibility\n const advancedConstraints: MediaTrackConstraintSet[] = [];\n \n // Try to set optimal settings through advanced constraints\n const advanced: any = {};\n \n // Focus mode - use 'any' type to bypass TypeScript limitations\n if ((capabilities as any).focusMode) {\n if ((capabilities as any).focusMode.includes('continuous')) {\n advanced.focusMode = 'continuous';\n } else if ((capabilities as any).focusMode.includes('single-shot')) {\n advanced.focusMode = 'single-shot';\n }\n }\n\n // Focus distance for close objects\n if ((capabilities as any).focusDistance) {\n advanced.focusDistance = {\n ideal: 0.4, // 40cm - optimal for document capture\n min: 0.2,\n max: 1.0\n };\n }\n\n // Zoom control\n if ((capabilities as any).zoom) {\n advanced.zoom = {\n ideal: 1.0,\n min: (capabilities as any).zoom.min,\n max: Math.min((capabilities as any).zoom.max, 3.0)\n };\n }\n\n // Add advanced constraints if any were set\n if (Object.keys(advanced).length > 0) {\n advancedConstraints.push(advanced);\n }\n\n if (advancedConstraints.length > 0) {\n constraints.advanced = advancedConstraints;\n }\n }\n\n private applyBasicFocusSettings(constraints: MediaTrackConstraints): void {\n // Apply basic focus settings when capabilities are not available\n // Use advanced constraints for non-standard properties\n const advanced: any = {\n focusMode: 'continuous',\n exposureMode: 'continuous',\n whiteBalanceMode: 'continuous'\n };\n \n if (!constraints.advanced) {\n constraints.advanced = [];\n }\n constraints.advanced.push(advanced);\n \n constraints.frameRate = { ideal: 30 };\n }\n\n private getCapabilitiesSummary(capabilities: MediaTrackCapabilities): any {\n return {\n hasAutoFocus: !!(capabilities as any).focusMode,\n hasFocusDistance: !!(capabilities as any).focusDistance,\n hasExposureControl: !!(capabilities as any).exposureMode,\n hasWhiteBalance: !!(capabilities as any).whiteBalanceMode,\n hasZoom: !!(capabilities as any).zoom,\n hasTorch: (capabilities as any).torch !== undefined,\n hasImageControls: !!((capabilities as any).brightness || (capabilities as any).contrast || (capabilities as any).saturation || (capabilities as any).sharpness),\n resolutionRange: capabilities.width && capabilities.height ? \n `${capabilities.width.min}x${capabilities.height.min} - ${capabilities.width.max}x${capabilities.height.max}` : 'unknown'\n };\n }\n\n // New method to enable torch/flash for better illumination\n async setTorchEnabled(enabled: boolean, stream?: MediaStream): Promise<boolean> {\n try {\n if (!stream) {\n this.logger.warn('No hay stream disponible para controlar el flash');\n return false;\n }\n\n const videoTrack = stream.getVideoTracks()[0];\n if (!videoTrack) {\n this.logger.warn('No hay track de video disponible');\n return false;\n }\n\n const capabilities = videoTrack.getCapabilities();\n if ((capabilities as any).torch === undefined) {\n this.logger.warn('El dispositivo no soporta control de flash');\n return false;\n }\n\n await videoTrack.applyConstraints({\n advanced: [{ torch: enabled } as any]\n });\n\n this.logger.state('FLASH_CONTROLADO', { enabled });\n return true;\n } catch (error) {\n this.logger.error('Error al controlar el flash:', error);\n return false;\n }\n }\n\n // Method to manually trigger focus on a specific point\n async focusAtPoint(x: number, y: number, stream?: MediaStream): Promise<boolean> {\n try {\n if (!stream) {\n this.logger.warn('No hay stream disponible para enfocar');\n return false;\n }\n\n const videoTrack = stream.getVideoTracks()[0];\n if (!videoTrack) {\n this.logger.warn('No hay track de video disponible');\n return false;\n }\n\n const capabilities = videoTrack.getCapabilities();\n if (!(capabilities as any).focusMode || !(capabilities as any).focusMode.includes('single-shot')) {\n this.logger.warn('El dispositivo no soporta enfoque manual');\n return false;\n }\n\n // Trigger single-shot focus\n await videoTrack.applyConstraints({\n advanced: [{ focusMode: 'single-shot' } as any]\n });\n\n // Return to continuous focus after a short delay\n setTimeout(async () => {\n try {\n await videoTrack.applyConstraints({\n advanced: [{ focusMode: 'continuous' } as any]\n });\n } catch (error) {\n this.logger.warn('Error al volver a enfoque continuo:', error);\n }\n }, 1000);\n\n this.logger.state('ENFOQUE_MANUAL_ACTIVADO', { x, y });\n return true;\n } catch (error) {\n this.logger.error('Error al enfocar manualmente:', error);\n return false;\n }\n }\n}"]}
1
+ {"version":3,"file":"CameraService.js","sourceRoot":"","sources":["../../src/services/CameraService.ts"],"names":[],"mappings":"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","sourcesContent":["import { ICameraService, CameraInfo, CameraPreference } from './interfaces/ICameraService';\nimport { ILogger } from './interfaces/ILogger';\nimport { IEventBus } from './interfaces/IEventBus';\n\nexport class CameraService implements ICameraService {\n private availableCameras: MediaDeviceInfo[] = [];\n private selectedCameraId: string | null = null;\n private deviceType: 'mobile' | 'desktop' | 'tablet' = 'desktop';\n private preferredCameraFacing: 'environment' | 'user' | null = null;\n private preferredCamera: 'auto' | 'front' | 'back' = 'auto';\n private isManuallySelected: boolean = false;\n\n constructor(\n private logger: ILogger,\n private eventBus: IEventBus,\n preferredCamera: 'auto' | 'front' | 'back' = 'auto'\n ) {\n this.preferredCamera = preferredCamera;\n }\n\n async detectDeviceType(): Promise<'mobile' | 'desktop' | 'tablet'> {\n const userAgent = navigator.userAgent;\n const isMobile = /Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent);\n const isTablet = /iPad|Android/i.test(userAgent) && window.innerWidth >= 768;\n \n if (isTablet) {\n this.deviceType = 'tablet';\n } else if (isMobile) {\n this.deviceType = 'mobile';\n } else {\n this.deviceType = 'desktop';\n }\n \n this.logger.state('DISPOSITIVO_DETECTADO', {\n deviceType: this.deviceType,\n userAgent: navigator.userAgent,\n screenDimensions: { width: window.innerWidth, height: window.innerHeight }\n });\n \n return this.deviceType;\n }\n\n async enumerateDevices(): Promise<MediaDeviceInfo[]> {\n try {\n const permissionStatus = await this.checkCameraPermission();\n \n if (permissionStatus === 'denied') {\n this.logger.error('Permiso de cámara denegado por el usuario');\n return [];\n }\n \n if (permissionStatus === 'prompt') {\n const tempStream = await navigator.mediaDevices.getUserMedia({ video: true });\n tempStream.getTracks().forEach(track => track.stop());\n }\n \n const devices = await navigator.mediaDevices.enumerateDevices();\n this.availableCameras = devices.filter(device => device.kind === 'videoinput');\n \n this.logger.state('CAMARAS_DETECTADAS', {\n count: this.availableCameras.length,\n cameras: this.availableCameras.map(cam => ({\n id: cam.deviceId,\n label: cam.label || 'Unknown Camera'\n }))\n });\n \n this.setInitialCameraPreference();\n \n this.logger.state('PREFERENCIA_INICIAL_APLICADA', {\n selectedCameraId: this.selectedCameraId,\n preferredCameraFacing: this.preferredCameraFacing,\n preferredCamera: this.preferredCamera\n });\n \n this.eventBus.emit('camera-changed', this.selectedCameraId);\n \n return this.availableCameras;\n } catch (error) {\n this.logger.error('Error al enumerar cámaras disponibles:', error);\n this.handleCameraPermissionError(error);\n return [];\n }\n }\n\n getAvailableCameras(): MediaDeviceInfo[] {\n return [...this.availableCameras];\n }\n\n isMultipleCamerasAvailable(): boolean {\n return this.availableCameras.length > 1;\n }\n\n getSelectedCameraId(): string | null {\n return this.selectedCameraId;\n }\n\n async setSelectedCamera(cameraId: string): Promise<void> {\n const camera = this.availableCameras.find(cam => cam.deviceId === cameraId);\n if (!camera) {\n throw new Error(`Camera with ID ${cameraId} not found`);\n }\n \n this.selectedCameraId = cameraId;\n this.updatePreferredFacing(camera);\n this.isManuallySelected = true; // Mark as manually selected\n this.savePreference();\n this.eventBus.emit('camera-changed', cameraId);\n }\n\n getPreferredFacing(): 'environment' | 'user' | null {\n return this.preferredCameraFacing;\n }\n\n async setupCamera(constraints?: MediaTrackConstraints): Promise<MediaStream> {\n try {\n const finalConstraints = constraints || await this.getMaxResolution();\n \n const stream = await navigator.mediaDevices.getUserMedia({\n video: finalConstraints,\n audio: false\n });\n\n return stream;\n } catch (error) {\n this.logger.error('Error en setupCamera, intentando con restricciones básicas:', error);\n \n // Fallback to basic constraints if getMaxResolution fails\n const basicConstraints: MediaTrackConstraints = {\n width: { ideal: 1280 },\n height: { ideal: 720 }\n };\n \n // Only add facingMode if not on desktop to avoid OverconstrainedError\n if (this.deviceType !== 'desktop' && this.preferredCameraFacing) {\n basicConstraints.facingMode = this.preferredCameraFacing;\n }\n \n this.logger.state('USANDO_RESTRICCIONES_BASICAS', { constraints: basicConstraints });\n \n return await navigator.mediaDevices.getUserMedia({\n video: basicConstraints,\n audio: false\n });\n }\n }\n\n async switchCamera(cameraId: string): Promise<void> {\n const selectedCamera = this.availableCameras.find(cam => cam.deviceId === cameraId);\n if (!selectedCamera) {\n this.logger.warn('Cámara seleccionada no encontrada, re-enumerando dispositivos...');\n await this.enumerateDevices();\n return;\n }\n \n await this.setSelectedCamera(cameraId);\n this.logger.state('CAMARA_CAMBIADA', { \n label: selectedCamera.label, \n deviceId: selectedCamera.deviceId,\n isManuallySelected: this.isManuallySelected\n });\n }\n\n async flipToNextCamera(): Promise<void> {\n if (!this.isMultipleCamerasAvailable()) return;\n \n const currentIndex = this.availableCameras.findIndex(\n camera => camera.deviceId === this.selectedCameraId\n );\n \n const nextIndex = (currentIndex + 1) % this.availableCameras.length;\n const nextCamera = this.availableCameras[nextIndex];\n \n await this.switchCamera(nextCamera.deviceId);\n }\n\n savePreference(): void {\n try {\n const preference: CameraPreference = {\n cameraId: this.selectedCameraId!,\n facing: this.preferredCameraFacing,\n timestamp: Date.now()\n };\n \n localStorage.setItem('jaak-stamps-camera-preference', JSON.stringify(preference));\n this.logger.state('PREFERENCIA_CAMARA_GUARDADA', preference);\n } catch (error) {\n this.logger.warn('Error al guardar preferencia de cámara:', error);\n }\n }\n\n loadPreference(): void {\n try {\n const saved = localStorage.getItem('jaak-stamps-camera-preference');\n if (saved) {\n const preference: CameraPreference = JSON.parse(saved);\n \n const isStillAvailable = this.availableCameras.some(\n camera => camera.deviceId === preference.cameraId\n );\n \n if (isStillAvailable) {\n this.selectedCameraId = preference.cameraId;\n this.preferredCameraFacing = preference.facing;\n this.logger.state('PREFERENCIA_CAMARA_CARGADA', preference);\n }\n }\n } catch (error) {\n this.logger.warn('Error al cargar preferencia de cámara:', error);\n }\n }\n\n isRearCamera(stream: MediaStream): boolean {\n const videoTrack = stream.getVideoTracks()[0];\n if (!videoTrack) return false;\n \n const settings = videoTrack.getSettings();\n return settings.facingMode === 'environment';\n }\n\n getCameraInfo(): {\n availableCameras: CameraInfo[];\n selectedCameraId: string | null;\n deviceType: string;\n isMultipleCamerasAvailable: boolean;\n preferredFacing: 'environment' | 'user' | null;\n } {\n return {\n availableCameras: this.availableCameras.map(camera => ({\n id: camera.deviceId,\n label: camera.label || 'Unknown Camera',\n selected: camera.deviceId === this.selectedCameraId\n })),\n selectedCameraId: this.selectedCameraId,\n deviceType: this.deviceType,\n isMultipleCamerasAvailable: this.isMultipleCamerasAvailable(),\n preferredFacing: this.preferredCameraFacing\n };\n }\n\n private async checkCameraPermission(): Promise<'granted' | 'denied' | 'prompt'> {\n try {\n if (!navigator.permissions) {\n return 'prompt';\n }\n \n const permission = await navigator.permissions.query({ name: 'camera' as PermissionName });\n return permission.state;\n } catch (error) {\n this.logger.warn('No se pudo verificar permisos de cámara:', error);\n return 'prompt';\n }\n }\n\n private handleCameraPermissionError(error: any): void {\n this.availableCameras = [];\n this.eventBus.emit('error', new Error(`Camera permission error: ${error.message}`));\n }\n\n private setInitialCameraPreference(): void {\n if (this.availableCameras.length === 0) return;\n \n // Clear any existing localStorage preferences to ensure fresh start\n localStorage.removeItem('jaak-stamps-camera-preference');\n \n this.logger.state('APLICANDO_PREFERENCIA_INICIAL', {\n preferredCamera: this.preferredCamera,\n availableCamerasCount: this.availableCameras.length\n });\n \n this.isManuallySelected = false; // Reset manual selection flag\n \n if (this.preferredCamera === 'front') {\n this.selectFrontCamera();\n } else if (this.preferredCamera === 'back') {\n this.selectBackCamera();\n } else {\n this.selectAutoCamera();\n }\n }\n\n private selectFrontCamera(): void {\n this.preferredCameraFacing = 'user';\n \n this.logger.state('BUSCANDO_CAMARA_FRONTAL', {\n availableCameras: this.availableCameras.map(cam => ({\n id: cam.deviceId,\n label: cam.label\n }))\n });\n \n const frontCamera = this.availableCameras.find(camera => {\n const label = camera.label.toLowerCase();\n return label.includes('front') || \n label.includes('user') ||\n label.includes('selfie') ||\n label.includes('frontal') ||\n (!label.includes('back') && !label.includes('rear') && !label.includes('environment'));\n });\n \n // If not found, use the first camera (usually front on mobile)\n this.selectedCameraId = frontCamera ? frontCamera.deviceId : this.availableCameras[0].deviceId;\n this.logger.state('CAMARA_FRONTAL_SELECCIONADA', { \n found: !!frontCamera,\n label: frontCamera?.label || this.availableCameras[0].label,\n deviceId: this.selectedCameraId \n });\n }\n\n private selectBackCamera(): void {\n this.preferredCameraFacing = 'environment';\n \n this.logger.state('BUSCANDO_CAMARA_TRASERA', {\n availableCameras: this.availableCameras.map(cam => ({\n id: cam.deviceId,\n label: cam.label\n }))\n });\n \n // Try to find rear camera with multiple detection methods\n let backCamera = this.availableCameras.find(camera => {\n const label = camera.label.toLowerCase();\n return label.includes('back') || \n label.includes('rear') ||\n label.includes('environment') ||\n label.includes('trasera') ||\n label.includes('posterior');\n });\n \n // If not found by label, try to use the last camera (usually rear on mobile)\n if (!backCamera && this.availableCameras.length > 1) {\n backCamera = this.availableCameras[this.availableCameras.length - 1];\n this.logger.state('USANDO_ULTIMA_CAMARA_COMO_TRASERA', {\n label: backCamera.label,\n deviceId: backCamera.deviceId\n });\n }\n \n this.selectedCameraId = backCamera ? backCamera.deviceId : this.availableCameras[0].deviceId;\n this.logger.state('CAMARA_TRASERA_SELECCIONADA', { \n found: !!backCamera,\n label: backCamera?.label || this.availableCameras[0].label,\n deviceId: this.selectedCameraId \n });\n }\n\n private selectAutoCamera(): void {\n if (this.deviceType === 'mobile' || this.deviceType === 'tablet') {\n this.selectBackCamera();\n this.logger.state('CAMARA_AUTO_SELECCIONADA_MOBILE', { type: 'rear' });\n } else {\n // For desktop, prefer front camera (usually built-in webcam)\n this.selectFrontCamera();\n this.logger.state('CAMARA_AUTO_SELECCIONADA_DESKTOP', { \n type: 'front',\n label: this.availableCameras[0].label, \n deviceId: this.selectedCameraId \n });\n }\n }\n\n private updatePreferredFacing(camera: MediaDeviceInfo): void {\n const isRearCamera = camera.label.toLowerCase().includes('back') || \n camera.label.toLowerCase().includes('rear') ||\n camera.label.toLowerCase().includes('environment');\n this.preferredCameraFacing = isRearCamera ? 'environment' : 'user';\n }\n\n private async getMaxResolution(): Promise<MediaTrackConstraints> {\n try {\n // Ensure device type is detected before determining constraints\n if (!this.deviceType || this.deviceType === 'desktop') {\n await this.detectDeviceType();\n }\n \n const videoConstraints: MediaTrackConstraints = {};\n \n this.logger.state('CONFIGURANDO_CONSTRAINS_CAMARA', {\n selectedCameraId: this.selectedCameraId,\n preferredCameraFacing: this.preferredCameraFacing,\n preferredCamera: this.preferredCamera,\n deviceType: this.deviceType,\n isManuallySelected: this.isManuallySelected\n });\n \n if (this.isManuallySelected && this.selectedCameraId) {\n // When manually selected, use deviceId for exact camera selection\n videoConstraints.deviceId = { exact: this.selectedCameraId };\n this.logger.state('USANDO_CAMARA_MANUAL', { \n deviceId: this.selectedCameraId\n });\n } else if (this.preferredCameraFacing) {\n // Use facingMode for initial preference-based selection\n // Use 'ideal' instead of 'exact' to avoid OverconstrainedError on desktop\n const facingConstraint = this.deviceType === 'desktop' \n ? { ideal: this.preferredCameraFacing }\n : { exact: this.preferredCameraFacing };\n videoConstraints.facingMode = facingConstraint;\n this.logger.state('USANDO_FACING_CONSTRAINT', { \n facingMode: this.preferredCameraFacing,\n constraintType: this.deviceType === 'desktop' ? 'ideal' : 'exact'\n });\n } else if (this.selectedCameraId) {\n videoConstraints.deviceId = { exact: this.selectedCameraId };\n this.logger.state('USANDO_CAMARA_SELECCIONADA', { \n deviceId: this.selectedCameraId\n });\n } else {\n // Use preferredCamera setting to determine default facing mode\n if (this.preferredCamera === 'front') {\n videoConstraints.facingMode = \"user\";\n } else if (this.preferredCamera === 'back') {\n videoConstraints.facingMode = \"environment\"; \n } else {\n // Auto mode: use environment for mobile/tablet, user for desktop\n videoConstraints.facingMode = (this.deviceType === 'mobile' || this.deviceType === 'tablet') ? \"environment\" : \"user\";\n }\n this.logger.state('USANDO_PREFERENCIA_CONFIGURADA', { \n facingMode: videoConstraints.facingMode,\n preferredCamera: this.preferredCamera,\n deviceType: this.deviceType\n });\n }\n \n const tempStream = await navigator.mediaDevices.getUserMedia({\n video: videoConstraints\n });\n \n const videoTrack = tempStream.getVideoTracks()[0];\n const capabilities = videoTrack.getCapabilities();\n tempStream.getTracks().forEach(track => track.stop());\n \n const constraints: MediaTrackConstraints = { ...videoConstraints };\n \n // Enhanced focus and image quality settings\n this.applyAdvancedCameraSettings(constraints, capabilities);\n \n if (capabilities.width && capabilities.height) {\n const maxWidth = Math.min(capabilities.width.max, 1920);\n const maxHeight = Math.min(capabilities.height.max, 1080);\n \n const isTablet = /iPad|Android/i.test(navigator.userAgent) && window.innerWidth >= 768;\n \n if (isTablet) {\n constraints.width = { ideal: Math.min(maxWidth, 1280) };\n constraints.height = { ideal: Math.min(maxHeight, 720) };\n } else {\n constraints.width = { ideal: maxWidth };\n constraints.height = { ideal: maxHeight };\n }\n }\n \n this.logger.state('CONFIGURACION_CAMARA_OPTIMIZADA', {\n constraints,\n capabilities: this.getCapabilitiesSummary(capabilities)\n });\n \n return constraints;\n } catch (err) {\n this.logger.warn('No se pudieron obtener capacidades de cámara, usando configuración de respaldo');\n \n // Ensure device type is detected before determining constraints\n if (!this.deviceType || this.deviceType === 'desktop') {\n await this.detectDeviceType();\n }\n \n const isTablet = /iPad|Android/i.test(navigator.userAgent) && window.innerWidth >= 768;\n const fallbackConstraints: MediaTrackConstraints = {\n width: { ideal: isTablet ? 1280 : 1920 },\n height: { ideal: isTablet ? 720 : 1080 }\n };\n \n // Apply basic focus settings even for fallback\n this.applyBasicFocusSettings(fallbackConstraints);\n \n if (this.isManuallySelected && this.selectedCameraId) {\n // When manually selected, use deviceId for exact camera selection\n fallbackConstraints.deviceId = { exact: this.selectedCameraId };\n } else if (this.preferredCameraFacing) {\n // Use facingMode for initial preference-based selection\n // Use 'ideal' instead of 'exact' to avoid OverconstrainedError on desktop\n const facingConstraint = this.deviceType === 'desktop' \n ? { ideal: this.preferredCameraFacing }\n : { exact: this.preferredCameraFacing };\n fallbackConstraints.facingMode = facingConstraint;\n } else if (this.selectedCameraId) {\n fallbackConstraints.deviceId = { exact: this.selectedCameraId };\n } else {\n // Use preferredCamera setting to determine default facing mode\n if (this.preferredCamera === 'front') {\n fallbackConstraints.facingMode = \"user\";\n } else if (this.preferredCamera === 'back') {\n fallbackConstraints.facingMode = \"environment\"; \n } else {\n // Auto mode: use environment for mobile/tablet, user for desktop\n fallbackConstraints.facingMode = (this.deviceType === 'mobile' || this.deviceType === 'tablet') ? \"environment\" : \"user\";\n }\n }\n \n return fallbackConstraints;\n }\n }\n\n private applyAdvancedCameraSettings(constraints: MediaTrackConstraints, capabilities: MediaTrackCapabilities): void {\n // Apply standard camera settings that are widely supported\n \n // Frame rate optimization\n if (capabilities.frameRate) {\n constraints.frameRate = {\n ideal: 30,\n min: 15,\n max: 60\n };\n }\n\n // Width and height constraints for optimal resolution\n if (capabilities.width && capabilities.height) {\n constraints.width = {\n ideal: Math.min(1920, capabilities.width.max || 1920),\n min: 640\n };\n constraints.height = {\n ideal: Math.min(1080, capabilities.height.max || 1080),\n min: 480\n };\n }\n\n // Apply enhanced constraints through advanced array for better browser compatibility\n const advancedConstraints: MediaTrackConstraintSet[] = [];\n \n // Try to set optimal settings through advanced constraints\n const advanced: any = {};\n \n // Focus mode - use 'any' type to bypass TypeScript limitations\n if ((capabilities as any).focusMode) {\n if ((capabilities as any).focusMode.includes('continuous')) {\n advanced.focusMode = 'continuous';\n } else if ((capabilities as any).focusMode.includes('single-shot')) {\n advanced.focusMode = 'single-shot';\n }\n }\n\n // Focus distance for close objects\n if ((capabilities as any).focusDistance) {\n advanced.focusDistance = {\n ideal: 0.4, // 40cm - optimal for document capture\n min: 0.2,\n max: 1.0\n };\n }\n\n // Zoom control\n if ((capabilities as any).zoom) {\n advanced.zoom = {\n ideal: 1.0,\n min: (capabilities as any).zoom.min,\n max: Math.min((capabilities as any).zoom.max, 3.0)\n };\n }\n\n // Add advanced constraints if any were set\n if (Object.keys(advanced).length > 0) {\n advancedConstraints.push(advanced);\n }\n\n if (advancedConstraints.length > 0) {\n constraints.advanced = advancedConstraints;\n }\n }\n\n private applyBasicFocusSettings(constraints: MediaTrackConstraints): void {\n // Apply basic focus settings when capabilities are not available\n // Use advanced constraints for non-standard properties\n const advanced: any = {\n focusMode: 'continuous',\n exposureMode: 'continuous',\n whiteBalanceMode: 'continuous'\n };\n \n if (!constraints.advanced) {\n constraints.advanced = [];\n }\n constraints.advanced.push(advanced);\n \n constraints.frameRate = { ideal: 30 };\n }\n\n private getCapabilitiesSummary(capabilities: MediaTrackCapabilities): any {\n return {\n hasAutoFocus: !!(capabilities as any).focusMode,\n hasFocusDistance: !!(capabilities as any).focusDistance,\n hasExposureControl: !!(capabilities as any).exposureMode,\n hasWhiteBalance: !!(capabilities as any).whiteBalanceMode,\n hasZoom: !!(capabilities as any).zoom,\n hasTorch: (capabilities as any).torch !== undefined,\n hasImageControls: !!((capabilities as any).brightness || (capabilities as any).contrast || (capabilities as any).saturation || (capabilities as any).sharpness),\n resolutionRange: capabilities.width && capabilities.height ? \n `${capabilities.width.min}x${capabilities.height.min} - ${capabilities.width.max}x${capabilities.height.max}` : 'unknown'\n };\n }\n\n // New method to enable torch/flash for better illumination\n async setTorchEnabled(enabled: boolean, stream?: MediaStream): Promise<boolean> {\n try {\n if (!stream) {\n this.logger.warn('No hay stream disponible para controlar el flash');\n return false;\n }\n\n const videoTrack = stream.getVideoTracks()[0];\n if (!videoTrack) {\n this.logger.warn('No hay track de video disponible');\n return false;\n }\n\n const capabilities = videoTrack.getCapabilities();\n if ((capabilities as any).torch === undefined) {\n this.logger.warn('El dispositivo no soporta control de flash');\n return false;\n }\n\n await videoTrack.applyConstraints({\n advanced: [{ torch: enabled } as any]\n });\n\n this.logger.state('FLASH_CONTROLADO', { enabled });\n return true;\n } catch (error) {\n this.logger.error('Error al controlar el flash:', error);\n return false;\n }\n }\n\n // Method to manually trigger focus on a specific point\n async focusAtPoint(x: number, y: number, stream?: MediaStream): Promise<boolean> {\n try {\n if (!stream) {\n this.logger.warn('No hay stream disponible para enfocar');\n return false;\n }\n\n const videoTrack = stream.getVideoTracks()[0];\n if (!videoTrack) {\n this.logger.warn('No hay track de video disponible');\n return false;\n }\n\n const capabilities = videoTrack.getCapabilities();\n if (!(capabilities as any).focusMode || !(capabilities as any).focusMode.includes('single-shot')) {\n this.logger.warn('El dispositivo no soporta enfoque manual');\n return false;\n }\n\n // Trigger single-shot focus\n await videoTrack.applyConstraints({\n advanced: [{ focusMode: 'single-shot' } as any]\n });\n\n // Return to continuous focus after a short delay\n setTimeout(async () => {\n try {\n await videoTrack.applyConstraints({\n advanced: [{ focusMode: 'continuous' } as any]\n });\n } catch (error) {\n this.logger.warn('Error al volver a enfoque continuo:', error);\n }\n }, 1000);\n\n this.logger.state('ENFOQUE_MANUAL_ACTIVADO', { x, y });\n return true;\n } catch (error) {\n this.logger.error('Error al enfocar manualmente:', error);\n return false;\n }\n }\n}"]}