@osobh/reactar
Version:
AR Library for React Native and Expo
172 lines • 5.8 kB
JavaScript
;
// 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