UNPKG

@osobh/reactar

Version:

AR Library for React Native and Expo

172 lines 5.8 kB
"use strict"; // src/media/AudioManager.ts Object.defineProperty(exports, "__esModule", { value: true }); exports.AudioManager = void 0; const expo_av_1 = require("expo-av"); const events_1 = require("events"); const three_1 = require("three"); class AudioManager extends events_1.EventEmitter { constructor() { super(); this.audioSources = new Map(); this.listenerPosition = new three_1.Vector3(); this.isInitialized = false; } /** * Initializes the audio system */ async initialize() { try { await expo_av_1.Audio.setAudioModeAsync({ playsInSilentModeIOS: true, staysActiveInBackground: true, shouldDuckAndroid: true }); this.isInitialized = true; this.emit('initialized'); } catch (error) { this.emit('error', error); throw error; } } /** * Loads and creates a spatial audio source * @param id Unique identifier for the audio source * @param uri URI of the audio file to load * @param position Initial 3D position of the audio source * @param options Audio options */ async createAudioSource(id, uri, position, options = {}) { var _a, _b, _c, _d, _e; if (!this.isInitialized) { throw new Error('AudioManager must be initialized first'); } try { const { sound } = await expo_av_1.Audio.Sound.createAsync({ uri }, { shouldPlay: false, volume: (_a = options.volume) !== null && _a !== void 0 ? _a : 1.0, isLooping: (_b = options.loop) !== null && _b !== void 0 ? _b : false, }, undefined, true); const audioSource = { id, sound, position: position.clone(), maxDistance: (_c = options.maxDistance) !== null && _c !== void 0 ? _c : 50, refDistance: (_d = options.refDistance) !== null && _d !== void 0 ? _d : 1, rolloffFactor: (_e = options.rolloffFactor) !== null && _e !== void 0 ? _e : 1 }; this.audioSources.set(id, audioSource); this.updateAudioSourceVolume(audioSource); this.emit('audio-source-created', id); } catch (error) { this.emit('error', error); throw error; } } /** * Updates the position of an audio source * @param id Audio source identifier * @param position New position */ updateSourcePosition(id, position) { const source = this.audioSources.get(id); if (!source) { throw new Error(`Audio source ${id} not found`); } source.position.copy(position); this.updateAudioSourceVolume(source); } /** * Updates the listener's position (usually the camera/user position) * @param position New listener position */ updateListenerPosition(position) { this.listenerPosition.copy(position); this.audioSources.forEach(source => this.updateAudioSourceVolume(source)); } /** * Plays an audio source * @param id Audio source identifier */ async playSource(id) { const source = this.audioSources.get(id); if (!source) { throw new Error(`Audio source ${id} not found`); } try { await source.sound.playAsync(); } catch (error) { this.emit('error', error); throw error; } } /** * Stops an audio source * @param id Audio source identifier */ async stopSource(id) { const source = this.audioSources.get(id); if (!source) { throw new Error(`Audio source ${id} not found`); } try { await source.sound.stopAsync(); } catch (error) { this.emit('error', error); throw error; } } /** * Removes an audio source and cleans up its resources * @param id Audio source identifier */ async removeSource(id) { const source = this.audioSources.get(id); if (!source) { return; } try { await source.sound.unloadAsync(); this.audioSources.delete(id); this.emit('audio-source-removed', id); } catch (error) { this.emit('error', error); throw error; } } /** * Updates the volume of an audio source based on its distance from the listener * @param source Audio source to update */ updateAudioSourceVolume(source) { var _a, _b, _c; const distance = this.listenerPosition.distanceTo(source.position); const refDistance = (_a = source.refDistance) !== null && _a !== void 0 ? _a : 1; const maxDistance = (_b = source.maxDistance) !== null && _b !== void 0 ? _b : 50; const rolloffFactor = (_c = source.rolloffFactor) !== null && _c !== void 0 ? _c : 1; // Calculate volume using inverse distance model with rolloff let volume = 1.0; if (distance > refDistance) { volume = refDistance / (refDistance + rolloffFactor * (distance - refDistance)); } if (distance >= maxDistance) { volume = 0; } source.sound.setVolumeAsync(volume); } /** * Cleans up all audio resources */ async cleanup() { const promises = Array.from(this.audioSources.keys()).map(id => this.removeSource(id)); await Promise.all(promises); this.emit('cleanup-complete'); } } exports.AudioManager = AudioManager; //# sourceMappingURL=AudioManager.js.map