aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llaudio/llstreamingaudio_fmod.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--linden/indra/llaudio/llstreamingaudio_fmod.cpp362
1 files changed, 362 insertions, 0 deletions
diff --git a/linden/indra/llaudio/llstreamingaudio_fmod.cpp b/linden/indra/llaudio/llstreamingaudio_fmod.cpp
new file mode 100644
index 0000000..a71a872
--- /dev/null
+++ b/linden/indra/llaudio/llstreamingaudio_fmod.cpp
@@ -0,0 +1,362 @@
1/**
2 * @file streamingaudio_fmod.cpp
3 * @brief LLStreamingAudio_FMOD implementation
4 *
5 * $LicenseInfo:firstyear=2009&license=viewergpl$
6 *
7 * Copyright (c) 2009, Linden Research, Inc.
8 *
9 * Second Life Viewer Source Code
10 * The source code in this file ("Source Code") is provided by Linden Lab
11 * to you under the terms of the GNU General Public License, version 2.0
12 * ("GPL"), unless you have obtained a separate licensing agreement
13 * ("Other License"), formally executed by you and Linden Lab. Terms of
14 * the GPL can be found in doc/GPL-license.txt in this distribution, or
15 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
16 *
17 * There are special exceptions to the terms and conditions of the GPL as
18 * it is applied to this Source Code. View the full text of the exception
19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
22 *
23 * By copying, modifying or distributing this software, you acknowledge
24 * that you have read and understood your obligations described above,
25 * and agree to abide by those obligations.
26 *
27 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
28 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
29 * COMPLETENESS OR PERFORMANCE.
30 * $/LicenseInfo$
31 */
32
33#include "linden_common.h"
34
35#include "llmath.h"
36
37#include "fmod.h"
38#include "fmod_errors.h"
39
40#include "llstreamingaudio_fmod.h"
41
42
43class LLAudioStreamManagerFMOD
44{
45public:
46 LLAudioStreamManagerFMOD(const std::string& url);
47 int startStream();
48 bool stopStream(); // Returns true if the stream was successfully stopped.
49 bool ready();
50
51 const std::string& getURL() { return mInternetStreamURL; }
52
53 int getOpenState();
54protected:
55 FSOUND_STREAM* mInternetStream;
56 bool mReady;
57
58 std::string mInternetStreamURL;
59};
60
61
62
63//---------------------------------------------------------------------------
64// Internet Streaming
65//---------------------------------------------------------------------------
66LLStreamingAudio_FMOD::LLStreamingAudio_FMOD() :
67 mCurrentInternetStreamp(NULL),
68 mFMODInternetStreamChannel(-1),
69 mGain(1.0f)
70{
71 // Number of milliseconds of audio to buffer for the audio card.
72 // Must be larger than the usual Second Life frame stutter time.
73 FSOUND_Stream_SetBufferSize(200);
74
75 // Here's where we set the size of the network buffer and some buffering
76 // parameters. In this case we want a network buffer of 16k, we want it
77 // to prebuffer 40% of that when we first connect, and we want it
78 // to rebuffer 80% of that whenever we encounter a buffer underrun.
79
80 // Leave the net buffer properties at the default.
81 //FSOUND_Stream_Net_SetBufferProperties(20000, 40, 80);
82}
83
84
85LLStreamingAudio_FMOD::~LLStreamingAudio_FMOD()
86{
87 // nothing interesting/safe to do.
88}
89
90
91void LLStreamingAudio_FMOD::start(const std::string& url)
92{
93 //if (!mInited)
94 //{
95 // llwarns << "startInternetStream before audio initialized" << llendl;
96 // return;
97 //}
98
99 // "stop" stream but don't clear url, etc. in case url == mInternetStreamURL
100 stop();
101
102 if (!url.empty())
103 {
104 llinfos << "Starting internet stream: " << url << llendl;
105 mCurrentInternetStreamp = new LLAudioStreamManagerFMOD(url);
106 mURL = url;
107 }
108 else
109 {
110 llinfos << "Set internet stream to null" << llendl;
111 mURL.clear();
112 }
113}
114
115
116void LLStreamingAudio_FMOD::update()
117{
118 // Kill dead internet streams, if possible
119 std::list<LLAudioStreamManagerFMOD *>::iterator iter;
120 for (iter = mDeadStreams.begin(); iter != mDeadStreams.end();)
121 {
122 LLAudioStreamManagerFMOD *streamp = *iter;
123 if (streamp->stopStream())
124 {
125 llinfos << "Closed dead stream" << llendl;
126 delete streamp;
127 mDeadStreams.erase(iter++);
128 }
129 else
130 {
131 iter++;
132 }
133 }
134
135 // Don't do anything if there are no streams playing
136 if (!mCurrentInternetStreamp)
137 {
138 return;
139 }
140
141 int open_state = mCurrentInternetStreamp->getOpenState();
142
143 if (!open_state)
144 {
145 // Stream is live
146
147 // start the stream if it's ready
148 if (mFMODInternetStreamChannel < 0)
149 {
150 mFMODInternetStreamChannel = mCurrentInternetStreamp->startStream();
151
152 if (mFMODInternetStreamChannel != -1)
153 {
154 // Reset volume to previously set volume
155 setGain(getGain());
156 FSOUND_SetPaused(mFMODInternetStreamChannel, false);
157 }
158 }
159 }
160
161 switch(open_state)
162 {
163 default:
164 case 0:
165 // success
166 break;
167 case -1:
168 // stream handle is invalid
169 llwarns << "InternetStream - invalid handle" << llendl;
170 stop();
171 return;
172 case -2:
173 // opening
174 break;
175 case -3:
176 // failed to open, file not found, perhaps
177 llwarns << "InternetSteam - failed to open" << llendl;
178 stop();
179 return;
180 case -4:
181 // connecting
182 break;
183 case -5:
184 // buffering
185 break;
186 }
187
188}
189
190void LLStreamingAudio_FMOD::stop()
191{
192 if (mFMODInternetStreamChannel != -1)
193 {
194 FSOUND_SetPaused(mFMODInternetStreamChannel, true);
195 FSOUND_SetPriority(mFMODInternetStreamChannel, 0);
196 mFMODInternetStreamChannel = -1;
197 }
198
199 if (mCurrentInternetStreamp)
200 {
201 llinfos << "Stopping internet stream: " << mCurrentInternetStreamp->getURL() << llendl;
202 if (mCurrentInternetStreamp->stopStream())
203 {
204 delete mCurrentInternetStreamp;
205 }
206 else
207 {
208 llwarns << "Pushing stream to dead list: " << mCurrentInternetStreamp->getURL() << llendl;
209 mDeadStreams.push_back(mCurrentInternetStreamp);
210 }
211 mCurrentInternetStreamp = NULL;
212 //mURL.clear();
213 }
214}
215
216void LLStreamingAudio_FMOD::pause(int pauseopt)
217{
218 if (pauseopt < 0)
219 {
220 pauseopt = mCurrentInternetStreamp ? 1 : 0;
221 }
222
223 if (pauseopt)
224 {
225 if (mCurrentInternetStreamp)
226 {
227 stop();
228 }
229 }
230 else
231 {
232 start(getURL());
233 }
234}
235
236
237// A stream is "playing" if it has been requested to start. That
238// doesn't necessarily mean audio is coming out of the speakers.
239int LLStreamingAudio_FMOD::isPlaying()
240{
241 if (mCurrentInternetStreamp)
242 {
243 return 1; // Active and playing
244 }
245 else if (!mURL.empty())
246 {
247 return 2; // "Paused"
248 }
249 else
250 {
251 return 0;
252 }
253}
254
255
256F32 LLStreamingAudio_FMOD::getGain()
257{
258 return mGain;
259}
260
261
262std::string LLStreamingAudio_FMOD::getURL()
263{
264 return mURL;
265}
266
267
268void LLStreamingAudio_FMOD::setGain(F32 vol)
269{
270 mGain = vol;
271
272 if (mFMODInternetStreamChannel != -1)
273 {
274 vol = llclamp(vol, 0.f, 1.f);
275 int vol_int = llround(vol * 255.f);
276 FSOUND_SetVolumeAbsolute(mFMODInternetStreamChannel, vol_int);
277 }
278}
279
280
281///////////////////////////////////////////////////////
282// manager of possibly-multiple internet audio streams
283
284LLAudioStreamManagerFMOD::LLAudioStreamManagerFMOD(const std::string& url) :
285 mInternetStream(NULL),
286 mReady(false)
287{
288 mInternetStreamURL = url;
289 mInternetStream = FSOUND_Stream_Open(url.c_str(), FSOUND_NORMAL | FSOUND_NONBLOCKING, 0, 0);
290 if (!mInternetStream)
291 {
292 llwarns << "Couldn't open fmod stream, error "
293 << FMOD_ErrorString(FSOUND_GetError())
294 << llendl;
295 mReady = false;
296 return;
297 }
298
299 mReady = true;
300}
301
302int LLAudioStreamManagerFMOD::startStream()
303{
304 // We need a live and opened stream before we try and play it.
305 if (!mInternetStream || getOpenState())
306 {
307 llwarns << "No internet stream to start playing!" << llendl;
308 return -1;
309 }
310
311 // Make sure the stream is set to 2D mode.
312 FSOUND_Stream_SetMode(mInternetStream, FSOUND_2D);
313
314 return FSOUND_Stream_PlayEx(FSOUND_FREE, mInternetStream, NULL, true);
315}
316
317bool LLAudioStreamManagerFMOD::stopStream()
318{
319 if (mInternetStream)
320 {
321 int read_percent = 0;
322 int status = 0;
323 int bitrate = 0;
324 unsigned int flags = 0x0;
325 FSOUND_Stream_Net_GetStatus(mInternetStream, &status, &read_percent, &bitrate, &flags);
326
327 bool close = true;
328 switch (status)
329 {
330 case FSOUND_STREAM_NET_CONNECTING:
331 close = false;
332 break;
333 case FSOUND_STREAM_NET_NOTCONNECTED:
334 case FSOUND_STREAM_NET_BUFFERING:
335 case FSOUND_STREAM_NET_READY:
336 case FSOUND_STREAM_NET_ERROR:
337 default:
338 close = true;
339 }
340
341 if (close)
342 {
343 FSOUND_Stream_Close(mInternetStream);
344 mInternetStream = NULL;
345 return true;
346 }
347 else
348 {
349 return false;
350 }
351 }
352 else
353 {
354 return true;
355 }
356}
357
358int LLAudioStreamManagerFMOD::getOpenState()
359{
360 int open_state = FSOUND_Stream_GetOpenState(mInternetStream);
361 return open_state;
362}