第13章 高级配置

在本章中,我们将深入学习RecordRTC的高级配置选项,包括性能优化、兼容性设置和安全配置等。

13.1 性能优化配置

通过合理的配置优化录制性能:

性能优化配置

// 性能优化配置选项
var performanceOptions = {
    type: 'video',
    mimeType: 'video/webm;codecs=vp9',
    
    // 视频性能配置
    video: {
        width: { ideal: 1280 },
        height: { ideal: 720 },
        frameRate: { ideal: 30, max: 30 }, // 限制帧率
        aspectRatio: 16/9
    },
    
    // Canvas性能配置
    canvas: {
        width: 1280,
        height: 720,
        // 禁用WebAssembly以提高兼容性
        disableWebAssembly: true,
        // 使用更高效的绘制方法
        useWham: false
    },
    
    // 时间切片优化
    timeSlice: 2000, // 2秒切片,平衡性能和内存
    
    // 禁用日志以提高性能
    disableLogs: true,
    
    // 设置合适的缓冲区大小
    bufferSize: 4096,
    
    // 音频性能配置
    numberOfAudioChannels: 1, // 单声道以减少处理负担
    sampleRate: 44100
};

// 根据设备性能动态调整配置
function getPerformanceOptimizedConfig(devicePerformance) {
    const baseConfig = {
        type: 'video',
        mimeType: 'video/webm'
    };
    
    switch(devicePerformance) {
        case 'high':
            // 高性能设备
            return Object.assign(baseConfig, {
                video: {
                    width: { ideal: 1920 },
                    height: { ideal: 1080 },
                    frameRate: { ideal: 30 }
                },
                canvas: {
                    width: 1920,
                    height: 1080
                },
                bitrate: 2048 * 1024 // 2Mbps
            });
            
        case 'medium':
            // 中等性能设备
            return Object.assign(baseConfig, {
                video: {
                    width: { ideal: 1280 },
                    height: { ideal: 720 },
                    frameRate: { ideal: 30 }
                },
                canvas: {
                    width: 1280,
                    height: 720
                },
                bitrate: 1024 * 1024 // 1Mbps
            });
            
        case 'low':
            // 低性能设备
            return Object.assign(baseConfig, {
                video: {
                    width: { ideal: 640 },
                    height: { ideal: 480 },
                    frameRate: { ideal: 15 }
                },
                canvas: {
                    width: 640,
                    height: 480
                },
                bitrate: 512 * 1024 // 0.5Mbps
            });
            
        default:
            return baseConfig;
    }
}

13.2 兼容性配置

确保在不同浏览器和设备上的兼容性:

兼容性配置

// 浏览器兼容性检测和配置
class CompatibilityConfig {
    static detectBrowser() {
        const userAgent = navigator.userAgent;
        
        if (userAgent.indexOf('Chrome') > -1) {
            return 'chrome';
        } else if (userAgent.indexOf('Firefox') > -1) {
            return 'firefox';
        } else if (userAgent.indexOf('Safari') > -1) {
            return 'safari';
        } else if (userAgent.indexOf('Edg') > -1) {
            return 'edge';
        } else {
            return 'unknown';
        }
    }
    
    static getBrowserSpecificConfig() {
        const browser = this.detectBrowser();
        const baseConfig = {
            type: 'video'
        };
        
        switch(browser) {
            case 'chrome':
                return Object.assign(baseConfig, {
                    mimeType: 'video/webm;codecs=vp9',
                    video: {
                        width: { ideal: 1280 },
                        height: { ideal: 720 }
                    }
                });
                
            case 'firefox':
                return Object.assign(baseConfig, {
                    mimeType: 'video/webm;codecs=vp8',
                    video: {
                        width: { ideal: 1280 },
                        height: { ideal: 720 }
                    }
                });
                
            case 'safari':
                return Object.assign(baseConfig, {
                    mimeType: 'video/mp4',
                    video: {
                        width: { ideal: 1280 },
                        height: { ideal: 720 }
                    }
                });
                
            case 'edge':
                return Object.assign(baseConfig, {
                    mimeType: 'video/webm;codecs=vp9',
                    video: {
                        width: { ideal: 1280 },
                        height: { ideal: 720 }
                    }
                });
                
            default:
                // 通用配置
                return Object.assign(baseConfig, {
                    mimeType: 'video/webm',
                    video: {
                        width: { max: 1280 },
                        height: { max: 720 }
                    }
                });
        }
    }
    
    static getMobileConfig() {
        const isMobile = /Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
        
        if (isMobile) {
            return {
                type: 'video',
                mimeType: 'video/webm',
                video: {
                    facingMode: 'user', // 默认前置摄像头
                    width: { ideal: 640 },
                    height: { ideal: 480 },
                    frameRate: { ideal: 24 }
                },
                canvas: {
                    width: 640,
                    height: 480
                },
                numberOfAudioChannels: 1,
                sampleRate: 22050 // 降低采样率以节省资源
            };
        }
        
        return null;
    }
}

// 使用兼容性配置
function getOptimalConfig() {
    // 检查是否为移动设备
    const mobileConfig = CompatibilityConfig.getMobileConfig();
    if (mobileConfig) {
        return mobileConfig;
    }
    
    // 获取浏览器特定配置
    return CompatibilityConfig.getBrowserSpecificConfig();
}

13.3 安全配置

确保录制过程中的数据安全:

安全配置

// 安全录制配置
class SecureRecordingConfig {
    static getSecureOptions() {
        return {
            type: 'video',
            mimeType: 'video/webm',
            
            // 视频安全配置
            video: {
                // 不要求特定设备以保护隐私
                // deviceId: undefined,
                
                // 限制分辨率以减少数据量
                width: { max: 1920 },
                height: { max: 1080 },
                
                // 启用隐私保护功能
                noiseSuppression: true,
                echoCancellation: true
            },
            
            // 音频安全配置
            numberOfAudioChannels: 1,
            sampleRate: 44100,
            
            // 禁用可能泄露信息的功能
            disableLogs: true,
            
            // 使用本地处理,避免数据上传
            ondataavailable: function(blob) {
                // 仅在本地处理数据
                console.log('数据块已生成,大小:', blob.size);
                
                // 可以选择不上传或加密后上传
                // this.handleSecureUpload(blob);
            }
        };
    }
    
    // 安全上传处理
    static handleSecureUpload(blob) {
        // 加密数据
        this.encryptAndUpload(blob)
            .then(response => {
                console.log('安全上传成功');
            })
            .catch(error => {
                console.error('上传失败:', error);
            });
    }
    
    // 数据加密和上传
    static async encryptAndUpload(blob) {
        // 这里可以实现数据加密逻辑
        // 例如使用Web Crypto API
        
        try {
            // 模拟加密过程
            const encryptedData = await this.encryptData(blob);
            
            // 上传加密数据
            const formData = new FormData();
            formData.append('data', encryptedData);
            formData.append('timestamp', Date.now());
            
            const response = await fetch('/api/secure-upload', {
                method: 'POST',
                body: formData
            });
            
            return response;
        } catch (error) {
            throw new Error('加密上传失败: ' + error.message);
        }
    }
    
    // 数据加密方法
    static async encryptData(blob) {
        // 使用Web Crypto API进行加密
        // 这里是简化示例
        const arrayBuffer = await blob.arrayBuffer();
        console.log('数据加密完成,原始大小:', arrayBuffer.byteLength);
        
        // 实际项目中应实现真正的加密逻辑
        return new Blob([arrayBuffer], { type: blob.type });
    }
    
    // 权限管理
    static async requestPermissions() {
        try {
            // 请求媒体权限
            const stream = await navigator.mediaDevices.getUserMedia({
                video: true,
                audio: true
            });
            
            // 立即停止流以保护隐私
            stream.getTracks().forEach(track => track.stop());
            
            return true;
        } catch (error) {
            console.error('权限请求失败:', error);
            return false;
        }
    }
}

13.4 内存管理配置

优化内存使用,防止内存泄漏:

内存管理配置

// 内存管理配置
class MemoryManagementConfig {
    static getMemoryOptimizedConfig() {
        return {
            type: 'video',
            mimeType: 'video/webm',
            
            // 时间切片配置以控制内存使用
            timeSlice: 1000, // 1秒切片
            
            // 限制缓冲区大小
            bufferSize: 2048,
            
            // 视频配置
            video: {
                width: { ideal: 1280 },
                height: { ideal: 720 }
            },
            
            // Canvas配置
            canvas: {
                width: 1280,
                height: 720,
                // 禁用可能消耗大量内存的功能
                disableWebAssembly: true
            },
            
            // 数据可用回调中及时处理数据
            ondataavailable: function(blob) {
                // 处理完数据后及时释放
                this.handleAndReleaseBlob(blob);
            }
        };
    }
    
    // 处理并释放Blob数据
    static handleAndReleaseBlob(blob) {
        // 处理数据
        console.log('处理数据块,大小:', blob.size);
        
        // 如果创建了URL,记得及时释放
        // const url = URL.createObjectURL(blob);
        // 使用完后: URL.revokeObjectURL(url);
    }
    
    // 内存监控
    static monitorMemory() {
        if (performance.memory) {
            const memoryInfo = performance.memory;
            console.log('内存使用情况:');
            console.log('- 总内存:', Math.round(memoryInfo.totalJSHeapSize / 1024 / 1024), 'MB');
            console.log('- 已使用:', Math.round(memoryInfo.usedJSHeapSize / 1024 / 1024), 'MB');
            console.log('- 限制:', Math.round(memoryInfo.jsHeapSizeLimit / 1024 / 1024), 'MB');
            
            // 如果内存使用过高,可以采取措施
            if (memoryInfo.usedJSHeapSize > memoryInfo.jsHeapSizeLimit * 0.8) {
                console.warn('内存使用接近限制,建议停止录制');
                return false;
            }
        }
        return true;
    }
    
    // 资源清理
    static cleanupResources(recorder, stream) {
        // 停止录制器
        if (recorder) {
            recorder.destroy();
        }
        
        // 停止媒体流
        if (stream) {
            stream.getTracks().forEach(track => {
                track.stop();
            });
        }
        
        // 强制垃圾回收(如果可用)
        if (window.gc) {
            window.gc();
        }
        
        console.log('资源清理完成');
    }
}

// 使用内存管理配置
function startMemoryOptimizedRecording(stream) {
    const config = MemoryManagementConfig.getMemoryOptimizedConfig();
    const recorder = RecordRTC(stream, config);
    
    // 定期监控内存
    const memoryCheckInterval = setInterval(() => {
        if (!MemoryManagementConfig.monitorMemory()) {
            // 内存使用过高,停止录制
            recorder.stopRecording();
            clearInterval(memoryCheckInterval);
        }
    }, 5000);
    
    // 录制结束后清理
    recorder.onstop = () => {
        clearInterval(memoryCheckInterval);
        MemoryManagementConfig.cleanupResources(recorder, stream);
    };
    
    recorder.startRecording();
    return recorder;
}

13.5 网络优化配置

在网络环境较差时的配置优化:

网络优化配置

// 网络优化配置
class NetworkOptimizedConfig {
    static getConnectionType() {
        if (navigator.connection) {
            return {
                type: navigator.connection.effectiveType,
                downlink: navigator.connection.downlink,
                rtt: navigator.connection.rtt
            };
        }
        return { type: 'unknown' };
    }
    
    static getNetworkAdaptiveConfig() {
        const connection = this.getConnectionType();
        const baseConfig = {
            type: 'video',
            mimeType: 'video/webm'
        };
        
        switch(connection.type) {
            case 'slow-2g':
            case '2g':
                // 极慢网络
                return Object.assign(baseConfig, {
                    video: {
                        width: { ideal: 320 },
                        height: { ideal: 240 },
                        frameRate: { ideal: 10 }
                    },
                    canvas: {
                        width: 320,
                        height: 240
                    },
                    bitrate: 256 * 1024, // 0.25Mbps
                    timeSlice: 3000, // 3秒切片
                    numberOfAudioChannels: 1,
                    sampleRate: 22050
                });
                
            case '3g':
                // 中等网络
                return Object.assign(baseConfig, {
                    video: {
                        width: { ideal: 640 },
                        height: { ideal: 480 },
                        frameRate: { ideal: 20 }
                    },
                    canvas: {
                        width: 640,
                        height: 480
                    },
                    bitrate: 512 * 1024, // 0.5Mbps
                    timeSlice: 2000, // 2秒切片
                    numberOfAudioChannels: 1,
                    sampleRate: 44100
                });
                
            case '4g':
            case 'wifi':
                // 快速网络
                return Object.assign(baseConfig, {
                    video: {
                        width: { ideal: 1280 },
                        height: { ideal: 720 },
                        frameRate: { ideal: 30 }
                    },
                    canvas: {
                        width: 1280,
                        height: 720
                    },
                    bitrate: 1024 * 1024, // 1Mbps
                    timeSlice: 1000, // 1秒切片
                    numberOfAudioChannels: 2,
                    sampleRate: 44100
                });
                
            default:
                // 默认配置
                return Object.assign(baseConfig, {
                    video: {
                        width: { ideal: 640 },
                        height: { ideal: 480 }
                    },
                    canvas: {
                        width: 640,
                        height: 480
                    },
                    bitrate: 512 * 1024,
                    timeSlice: 2000
                });
        }
    }
    
    // 断点续传配置
    static getResumableConfig() {
        return {
            type: 'video',
            mimeType: 'video/webm',
            timeSlice: 5000, // 5秒切片便于断点续传
            
            ondataavailable: function(blob) {
                // 保存数据块用于断点续传
                this.saveChunkForResume(blob);
            }
        };
    }
    
    // 保存数据块用于断点续传
    static saveChunkForResume(blob) {
        // 保存到本地存储或IndexedDB
        const chunkId = 'chunk_' + Date.now();
        const reader = new FileReader();
        
        reader.onload = function(e) {
            const arrayBuffer = e.target.result;
            // 保存到IndexedDB或其他存储
            localStorage.setItem(chunkId, JSON.stringify({
                data: Array.from(new Uint8Array(arrayBuffer)),
                timestamp: Date.now()
            }));
        };
        
        reader.readAsArrayBuffer(blob);
    }
    
    // 恢复录制
    static async resumeRecording() {
        // 从存储中恢复之前的数据块
        const chunks = [];
        for (let i = 0; i < localStorage.length; i++) {
            const key = localStorage.key(i);
            if (key.startsWith('chunk_')) {
                const chunkData = JSON.parse(localStorage.getItem(key));
                chunks.push(chunkData);
            }
        }
        
        console.log('恢复录制,找到', chunks.length, '个数据块');
        return chunks;
    }
}