1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
|
/**
* @file audioengine.h
* @brief Definition of LLAudioEngine base class abstracting the audio support
*
* $LicenseInfo:firstyear=2000&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_AUDIOENGINE_H
#define LL_AUDIOENGINE_H
#include <list>
#include <map>
#include <array>
#include "v3math.h"
#include "v3dmath.h"
#include "lltimer.h"
#include "lluuid.h"
#include "llframetimer.h"
#include "llassettype.h"
#include "llextendedstatus.h"
#include "lllistener.h"
const F32 LL_WIND_UPDATE_INTERVAL = 0.1f;
const F32 LL_WIND_UNDERWATER_CENTER_FREQ = 20.f;
const F32 ATTACHED_OBJECT_TIMEOUT = 5.0f;
const F32 DEFAULT_MIN_DISTANCE = 2.0f;
#define LL_MAX_AUDIO_CHANNELS 30
#define LL_MAX_AUDIO_BUFFERS 40 // Some extra for preloading, maybe?
class LLAudioSource;
class LLAudioData;
class LLAudioChannel;
class LLAudioChannelOpenAL;
class LLAudioBuffer;
class LLStreamingAudioInterface;
struct SoundData;
//
// LLAudioEngine definition
//
class LLAudioEngine
{
friend class LLAudioChannelOpenAL; // bleh. channel needs some listener methods.
public:
enum LLAudioType
{
AUDIO_TYPE_NONE = 0,
AUDIO_TYPE_SFX = 1,
AUDIO_TYPE_UI = 2,
AUDIO_TYPE_AMBIENT = 3,
AUDIO_TYPE_COUNT = 4 // last
};
enum LLAudioPlayState
{
// isInternetStreamPlaying() returns an *S32*, with
// 0 = stopped, 1 = playing, 2 = paused.
AUDIO_STOPPED = 0,
AUDIO_PLAYING = 1,
AUDIO_PAUSED = 2
};
LLAudioEngine();
virtual ~LLAudioEngine();
// initialization/startup/shutdown
virtual bool init(void *userdata, const std::string &app_title);
virtual std::string getDriverName(bool verbose) = 0;
virtual LLStreamingAudioInterface *createDefaultStreamingAudioImpl() const = 0;
virtual void shutdown();
// Used by the mechanics of the engine
//virtual void processQueue(const LLUUID &sound_guid);
virtual void setListener(LLVector3 pos,LLVector3 vel,LLVector3 up,LLVector3 at);
virtual void updateWind(LLVector3 direction, F32 camera_height_above_water) = 0;
virtual void idle();
virtual void updateChannels();
//
// "End user" functionality
//
virtual bool isWindEnabled();
virtual void enableWind(bool state_b);
// Use these for temporarily muting the audio system.
// Does not change buffers, initialization, etc. but
// stops playing new sounds.
void setMuted(bool muted);
bool getMuted() const { return mMuted; }
#ifdef USE_PLUGIN_MEDIA
LLPluginClassMedia* initializeMedia(const std::string& media_type);
#endif
F32 getMasterGain();
void setMasterGain(F32 gain);
F32 getSecondaryGain(S32 type);
void setSecondaryGain(S32 type, F32 gain);
F32 getInternetStreamGain();
virtual void setDopplerFactor(F32 factor);
virtual F32 getDopplerFactor();
virtual void setRolloffFactor(F32 factor);
virtual F32 getRolloffFactor();
virtual void setMaxWindGain(F32 gain);
// Methods actually related to setting up and removing sounds
// Owner ID is the owner of the object making the request
void triggerSound(const LLUUID &sound_id, const LLUUID& owner_id, const F32 gain,
const S32 type = LLAudioEngine::AUDIO_TYPE_NONE,
const LLVector3d &pos_global = LLVector3d::zero);
void triggerSound(SoundData& soundData);
bool preloadSound(const LLUUID &id);
void addAudioSource(LLAudioSource *asp);
void cleanupAudioSource(LLAudioSource *asp);
LLAudioSource *findAudioSource(const LLUUID &source_id);
LLAudioData *getAudioData(const LLUUID &audio_uuid);
// Internet stream implementation manipulation
LLStreamingAudioInterface *getStreamingAudioImpl();
void setStreamingAudioImpl(LLStreamingAudioInterface *impl);
// Internet stream methods - these will call down into the *mStreamingAudioImpl if it exists
void startInternetStream(const std::string& url);
void stopInternetStream();
void pauseInternetStream(S32 pause);
void updateInternetStream(); // expected to be called often
LLAudioPlayState isInternetStreamPlaying();
// use a value from 0.0 to 1.0, inclusive
void setInternetStreamGain(F32 vol);
std::string getInternetStreamURL();
// For debugging usage
virtual LLVector3 getListenerPos();
LLAudioBuffer *getFreeBuffer(); // Get a free buffer, or flush an existing one if you have to.
LLAudioChannel *getFreeChannel(const F32 priority); // Get a free channel or flush an existing one if your priority is higher
void cleanupBuffer(LLAudioBuffer *bufferp);
bool hasDecodedFile(const LLUUID &uuid);
bool hasLocalFile(const LLUUID &uuid);
bool updateBufferForData(LLAudioData *adp, const LLUUID &audio_uuid = LLUUID::null);
// Asset callback when we're retrieved a sound from the asset server.
void startNextTransfer();
static void assetCallback(const LLUUID &uuid, LLAssetType::EType type, void *user_data, S32 result_code, LLExtStat ext_status);
friend class LLPipeline; // For debugging
public:
F32 mMaxWindGain; // Hack. Public to set before fade in?
protected:
virtual LLAudioBuffer *createBuffer() = 0;
virtual LLAudioChannel *createChannel() = 0;
virtual bool initWind() = 0;
virtual void cleanupWind() = 0;
virtual void setInternalGain(F32 gain) = 0;
void commitDeferredChanges();
virtual void allocateListener() = 0;
// listener methods
virtual void setListenerPos(LLVector3 vec);
virtual void setListenerVelocity(LLVector3 vec);
virtual void orientListener(LLVector3 up, LLVector3 at);
virtual void translateListener(LLVector3 vec);
F64 mapWindVecToGain(LLVector3 wind_vec);
F64 mapWindVecToPitch(LLVector3 wind_vec);
F64 mapWindVecToPan(LLVector3 wind_vec);
protected:
LLListener *mListenerp;
bool mMuted;
void* mUserData;
S32 mLastStatus;
bool mEnableWind;
LLUUID mCurrentTransfer; // Audio file currently being transferred by the system
LLFrameTimer mCurrentTransferTimer;
// A list of all audio sources that are known to the viewer at this time.
// This is most likely a superset of the ones that we actually have audio
// data for, or are playing back.
typedef std::map<LLUUID, LLAudioSource *> source_map;
typedef std::map<LLUUID, LLAudioData *> data_map;
source_map mAllSources;
data_map mAllData;
std::array<LLAudioChannel*, LL_MAX_AUDIO_CHANNELS> mChannels;
// Buffers needs to change into a different data structure, as the number of buffers
// that we have active should be limited by RAM usage, not count.
std::array<LLAudioBuffer*, LL_MAX_AUDIO_BUFFERS> mBuffers;
F32 mMasterGain;
F32 mInternalGain; // Actual gain set; either mMasterGain or 0 when mMuted is true.
F32 mSecondaryGain[AUDIO_TYPE_COUNT];
F32 mNextWindUpdate;
LLFrameTimer mWindUpdateTimer;
private:
void setDefaults();
LLStreamingAudioInterface *mStreamingAudioImpl;
};
//
// Standard audio source. Can be derived from for special sources, such as those attached to objects.
//
class LLAudioSource
{
public:
// owner_id is the id of the agent responsible for making this sound
// play, for example, the owner of the object currently playing it
LLAudioSource(const LLUUID &id, const LLUUID& owner_id, const F32 gain, const S32 type = LLAudioEngine::AUDIO_TYPE_NONE);
virtual ~LLAudioSource();
virtual void update(); // Update this audio source
void updatePriority();
void preload(const LLUUID &audio_id); // Only used for preloading UI sounds, now.
void addAudioData(LLAudioData *adp, bool set_current = TRUE);
void setForcedPriority(const bool ambient) { mForcedPriority = ambient; }
bool isForcedPriority() const { return mForcedPriority; }
void setLoop(const bool loop) { mLoop = loop; }
bool isLoop() const { return mLoop; }
void setSyncMaster(const bool master) { mSyncMaster = master; }
bool isSyncMaster() const { return mSyncMaster; }
void setSyncSlave(const bool slave) { mSyncSlave = slave; }
bool isSyncSlave() const { return mSyncSlave; }
void setQueueSounds(const bool queue) { mQueueSounds = queue; }
bool isQueueSounds() const { return mQueueSounds; }
void setPlayedOnce(const bool played_once) { mPlayedOnce = played_once; }
void setType(S32 type) { mType = type; }
S32 getType() { return mType; }
void setPositionGlobal(const LLVector3d &position_global) { mPositionGlobal = position_global; }
LLVector3d getPositionGlobal() const { return mPositionGlobal; }
LLVector3 getVelocity() const { return mVelocity; }
F32 getPriority() const { return mPriority; }
// Gain should always be clamped between 0 and 1.
F32 getGain() const { return mGain; }
virtual void setGain(const F32 gain) { mGain = llclamp(gain, 0.f, 1.f); }
const LLUUID &getID() const { return mID; }
bool isDone() const;
bool isMuted() const { return mSourceMuted; }
LLAudioData *getCurrentData();
LLAudioData *getQueuedData();
LLAudioBuffer *getCurrentBuffer();
bool setupChannel();
// Stop the audio source, reset audio id even if muted
void stop();
// Start the audio source playing,
// takes mute into account to preserve previous id if nessesary
bool play(const LLUUID &audio_id);
bool hasPendingPreloads() const; // Has preloads that haven't been done yet
friend class LLAudioEngine;
friend class LLAudioChannel;
protected:
void setChannel(LLAudioChannel *channelp);
LLAudioChannel *getChannel() const { return mChannelp; }
protected:
LLUUID mID; // The ID of the source is that of the object if it's attached to an object.
LLUUID mOwnerID; // owner of the object playing the sound
F32 mPriority;
F32 mGain;
bool mSourceMuted;
bool mForcedPriority; // ignore mute, set high priority, researved for sound preview and UI
bool mLoop;
bool mSyncMaster;
bool mSyncSlave;
bool mQueueSounds;
bool mPlayedOnce;
bool mCorrupted;
S32 mType;
LLVector3d mPositionGlobal;
LLVector3 mVelocity;
//LLAudioSource *mSyncMasterp; // If we're a slave, the source that we're synced to.
LLAudioChannel *mChannelp; // If we're currently playing back, this is the channel that we're assigned to.
LLAudioData *mCurrentDatap;
LLAudioData *mQueuedDatap;
typedef std::map<LLUUID, LLAudioData *> data_map;
data_map mPreloadMap;
LLFrameTimer mAgeTimer;
};
//
// Generic metadata about a particular piece of audio data.
// The actual data is handled by the derived LLAudioBuffer classes which are
// derived for each audio engine.
//
class LLAudioData
{
public:
LLAudioData(const LLUUID &uuid);
bool load();
LLUUID getID() const { return mID; }
LLAudioBuffer *getBuffer() const { return mBufferp; }
bool hasLocalData() const { return mHasLocalData; }
bool hasDecodedData() const { return mHasDecodedData; }
bool hasCompletedDecode() const { return mHasCompletedDecode; }
bool hasDecodeFailed() const { return mHasDecodeFailed; }
bool hasWAVLoadFailed() const { return mHasWAVLoadFailed; }
void setHasLocalData(const bool hld) { mHasLocalData = hld; }
void setHasDecodedData(const bool hdd) { mHasDecodedData = hdd; }
void setHasCompletedDecode(const bool hcd) { mHasCompletedDecode = hcd; }
void setHasDecodeFailed(const bool hdf) { mHasDecodeFailed = hdf; }
void setHasWAVLoadFailed(const bool hwlf) { mHasWAVLoadFailed = hwlf; }
friend class LLAudioEngine; // Severe laziness, bad.
protected:
LLUUID mID;
LLAudioBuffer *mBufferp; // If this data is being used by the audio system, a pointer to the buffer will be set here.
bool mHasLocalData; // Set true if the encoded sound asset file is available locally
bool mHasDecodedData; // Set true if the decoded sound file is available on disk
bool mHasCompletedDecode; // Set true when the sound is decoded
bool mHasDecodeFailed; // Set true if decoding failed, meaning the sound asset is bad
bool mHasWAVLoadFailed; // Set true if loading the decoded WAV file failed, meaning the sound asset should be decoded instead if
// possible
};
//
// Base class for an audio channel, i.e. a channel which is capable of playing back a sound.
// Management of channels is done generically, methods for actually manipulating the channel
// are derived for each audio engine.
//
class LLAudioChannel
{
public:
LLAudioChannel();
virtual ~LLAudioChannel();
virtual void setSource(LLAudioSource *sourcep);
LLAudioSource *getSource() const { return mCurrentSourcep; }
void setSecondaryGain(F32 gain) { mSecondaryGain = gain; }
F32 getSecondaryGain() { return mSecondaryGain; }
friend class LLAudioEngine;
friend class LLAudioSource;
protected:
virtual void play() = 0;
virtual void playSynced(LLAudioChannel *channelp) = 0;
virtual void cleanup() = 0;
virtual bool isPlaying() = 0;
void setWaiting(const bool waiting) { mWaiting = waiting; }
bool isWaiting() const { return mWaiting; }
virtual bool updateBuffer(); // Check to see if the buffer associated with the source changed, and update if necessary.
virtual void update3DPosition() = 0;
virtual void updateLoop() = 0; // Update your loop/completion status, for use by queueing/syncing.
protected:
LLAudioSource *mCurrentSourcep;
LLAudioBuffer *mCurrentBufferp;
bool mLoopedThisFrame;
bool mWaiting; // Waiting for sync.
F32 mSecondaryGain;
};
// Basically an interface class to the engine-specific implementation
// of audio data that's ready for playback.
// Will likely get more complex as we decide to do stuff like real streaming audio.
class LLAudioBuffer
{
public:
virtual ~LLAudioBuffer() {};
virtual bool loadWAV(const std::string& filename) = 0;
virtual U32 getLength() = 0;
friend class LLAudioEngine;
friend class LLAudioChannel;
friend class LLAudioData;
protected:
bool mInUse;
LLAudioData *mAudioDatap;
LLFrameTimer mLastUseTimer;
};
struct SoundData
{
LLUUID audio_uuid;
LLUUID owner_id;
F32 gain;
S32 type;
LLVector3d pos_global;
SoundData(const LLUUID &audio_uuid,
const LLUUID& owner_id,
const F32 gain,
const S32 type = LLAudioEngine::AUDIO_TYPE_NONE,
const LLVector3d &pos_global = LLVector3d::zero) :
audio_uuid(audio_uuid),
owner_id(owner_id),
gain(gain),
type(type),
pos_global(pos_global)
{
}
};
extern LLAudioEngine* gAudiop;
#endif
|