@osobh/reactar
Version:
AR Library for React Native and Expo
138 lines (117 loc) • 3.91 kB
text/typescript
// 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;
}
}
}