UNPKG

@osobh/reactar

Version:

AR Library for React Native and Expo

138 lines (117 loc) 3.91 kB
// src/media/MediaCapture.ts import { captureRef } from 'react-native-view-shot'; import * as FileSystem from 'expo-file-system'; import { EventEmitter } from 'events'; import { ViewProps } from 'react-native'; export interface MediaCaptureOptions { quality?: number; // 0 to 1 format?: 'jpg' | 'png'; result?: 'tmpfile' | 'base64' | 'data-uri'; } export interface RecordingOptions { quality?: number; // 0 to 1 maxDuration?: number; // in seconds maxFileSize?: number; // in bytes } export class MediaCapture extends EventEmitter { private isRecording: boolean = false; private recordingStartTime: number = 0; private mediaDirectory: string; constructor() { super(); this.mediaDirectory = `${FileSystem.documentDirectory}ar_media/`; this.ensureMediaDirectory(); } private async ensureMediaDirectory(): Promise<void> { const dirInfo = await FileSystem.getInfoAsync(this.mediaDirectory); if (!dirInfo.exists) { await FileSystem.makeDirectoryAsync(this.mediaDirectory, { intermediates: true }); } } /** * Captures a screenshot of the AR view * @param viewRef React ref to the view to capture * @param options Capture options * @returns Promise with the path to the saved image */ public async captureScreenshot( viewRef: React.RefObject<ViewProps>, options: MediaCaptureOptions = {} ): Promise<string> { try { const timestamp = Date.now(); const fileName = `ar_screenshot_${timestamp}.${options.format || 'jpg'}`; const filePath = `${this.mediaDirectory}${fileName}`; const uri = await captureRef(viewRef, { quality: options.quality || 0.8, format: options.format || 'jpg', result: 'tmpfile' }); await FileSystem.moveAsync({ from: uri, to: filePath }); this.emit('screenshot-captured', filePath); return filePath; } catch (error) { this.emit('error', error); throw error; } } /** * Starts recording the AR session * @param viewRef React ref to the view to record * @param options Recording options */ public startRecording( viewRef: React.RefObject<ViewProps>, options: RecordingOptions = {} ): void { if (this.isRecording) { throw new Error('Recording is already in progress'); } this.isRecording = true; this.recordingStartTime = Date.now(); this.emit('recording-started'); // TODO: Implement actual video recording using react-native-view-shot // This will require frame-by-frame capture and composition } /** * Stops the current recording * @returns Promise with the path to the saved video */ public async stopRecording(): Promise<string> { if (!this.isRecording) { throw new Error('No recording in progress'); } const timestamp = this.recordingStartTime; const fileName = `ar_recording_${timestamp}.mp4`; const filePath = `${this.mediaDirectory}${fileName}`; this.isRecording = false; this.recordingStartTime = 0; // TODO: Implement actual video recording stop and save logic this.emit('recording-stopped', filePath); return filePath; } /** * Cleans up old media files * @param maxAge Maximum age of files to keep (in milliseconds) */ public async cleanupOldFiles(maxAge: number): Promise<void> { try { const files = await FileSystem.readDirectoryAsync(this.mediaDirectory); const now = Date.now(); for (const file of files) { const filePath = `${this.mediaDirectory}${file}`; const fileInfo = await FileSystem.getInfoAsync(filePath); const modTime = (fileInfo as any).modificationTime; if (modTime && (now - modTime > maxAge)) { await FileSystem.deleteAsync(filePath); } } } catch (error) { this.emit('error', error); throw error; } } }