PageRenderTime 30ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/llaudio/llstreamingaudio_fmod.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 356 lines | 242 code | 53 blank | 61 comment | 27 complexity | 726681fcfdb7f76fb029389bfd6b7fa0 MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file streamingaudio_fmod.cpp
  3. * @brief LLStreamingAudio_FMOD implementation
  4. *
  5. * $LicenseInfo:firstyear=2009&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #include "linden_common.h"
  27. #include "llmath.h"
  28. #include "fmod.h"
  29. #include "fmod_errors.h"
  30. #include "llstreamingaudio_fmod.h"
  31. class LLAudioStreamManagerFMOD
  32. {
  33. public:
  34. LLAudioStreamManagerFMOD(const std::string& url);
  35. int startStream();
  36. bool stopStream(); // Returns true if the stream was successfully stopped.
  37. bool ready();
  38. const std::string& getURL() { return mInternetStreamURL; }
  39. int getOpenState();
  40. protected:
  41. FSOUND_STREAM* mInternetStream;
  42. bool mReady;
  43. std::string mInternetStreamURL;
  44. };
  45. //---------------------------------------------------------------------------
  46. // Internet Streaming
  47. //---------------------------------------------------------------------------
  48. LLStreamingAudio_FMOD::LLStreamingAudio_FMOD() :
  49. mCurrentInternetStreamp(NULL),
  50. mFMODInternetStreamChannel(-1),
  51. mGain(1.0f)
  52. {
  53. // Number of milliseconds of audio to buffer for the audio card.
  54. // Must be larger than the usual Second Life frame stutter time.
  55. FSOUND_Stream_SetBufferSize(200);
  56. // Here's where we set the size of the network buffer and some buffering
  57. // parameters. In this case we want a network buffer of 16k, we want it
  58. // to prebuffer 40% of that when we first connect, and we want it
  59. // to rebuffer 80% of that whenever we encounter a buffer underrun.
  60. // Leave the net buffer properties at the default.
  61. //FSOUND_Stream_Net_SetBufferProperties(20000, 40, 80);
  62. }
  63. LLStreamingAudio_FMOD::~LLStreamingAudio_FMOD()
  64. {
  65. // nothing interesting/safe to do.
  66. }
  67. void LLStreamingAudio_FMOD::start(const std::string& url)
  68. {
  69. //if (!mInited)
  70. //{
  71. // llwarns << "startInternetStream before audio initialized" << llendl;
  72. // return;
  73. //}
  74. // "stop" stream but don't clear url, etc. in case url == mInternetStreamURL
  75. stop();
  76. if (!url.empty())
  77. {
  78. llinfos << "Starting internet stream: " << url << llendl;
  79. mCurrentInternetStreamp = new LLAudioStreamManagerFMOD(url);
  80. mURL = url;
  81. }
  82. else
  83. {
  84. llinfos << "Set internet stream to null" << llendl;
  85. mURL.clear();
  86. }
  87. }
  88. void LLStreamingAudio_FMOD::update()
  89. {
  90. // Kill dead internet streams, if possible
  91. std::list<LLAudioStreamManagerFMOD *>::iterator iter;
  92. for (iter = mDeadStreams.begin(); iter != mDeadStreams.end();)
  93. {
  94. LLAudioStreamManagerFMOD *streamp = *iter;
  95. if (streamp->stopStream())
  96. {
  97. llinfos << "Closed dead stream" << llendl;
  98. delete streamp;
  99. mDeadStreams.erase(iter++);
  100. }
  101. else
  102. {
  103. iter++;
  104. }
  105. }
  106. // Don't do anything if there are no streams playing
  107. if (!mCurrentInternetStreamp)
  108. {
  109. return;
  110. }
  111. int open_state = mCurrentInternetStreamp->getOpenState();
  112. if (!open_state)
  113. {
  114. // Stream is live
  115. // start the stream if it's ready
  116. if (mFMODInternetStreamChannel < 0)
  117. {
  118. mFMODInternetStreamChannel = mCurrentInternetStreamp->startStream();
  119. if (mFMODInternetStreamChannel != -1)
  120. {
  121. // Reset volume to previously set volume
  122. setGain(getGain());
  123. FSOUND_SetPaused(mFMODInternetStreamChannel, false);
  124. }
  125. }
  126. }
  127. switch(open_state)
  128. {
  129. default:
  130. case 0:
  131. // success
  132. break;
  133. case -1:
  134. // stream handle is invalid
  135. llwarns << "InternetStream - invalid handle" << llendl;
  136. stop();
  137. return;
  138. case -2:
  139. // opening
  140. break;
  141. case -3:
  142. // failed to open, file not found, perhaps
  143. llwarns << "InternetStream - failed to open" << llendl;
  144. stop();
  145. return;
  146. case -4:
  147. // connecting
  148. break;
  149. case -5:
  150. // buffering
  151. break;
  152. }
  153. }
  154. void LLStreamingAudio_FMOD::stop()
  155. {
  156. if (mFMODInternetStreamChannel != -1)
  157. {
  158. FSOUND_SetPaused(mFMODInternetStreamChannel, true);
  159. FSOUND_SetPriority(mFMODInternetStreamChannel, 0);
  160. mFMODInternetStreamChannel = -1;
  161. }
  162. if (mCurrentInternetStreamp)
  163. {
  164. llinfos << "Stopping internet stream: " << mCurrentInternetStreamp->getURL() << llendl;
  165. if (mCurrentInternetStreamp->stopStream())
  166. {
  167. delete mCurrentInternetStreamp;
  168. }
  169. else
  170. {
  171. llwarns << "Pushing stream to dead list: " << mCurrentInternetStreamp->getURL() << llendl;
  172. mDeadStreams.push_back(mCurrentInternetStreamp);
  173. }
  174. mCurrentInternetStreamp = NULL;
  175. //mURL.clear();
  176. }
  177. }
  178. void LLStreamingAudio_FMOD::pause(int pauseopt)
  179. {
  180. if (pauseopt < 0)
  181. {
  182. pauseopt = mCurrentInternetStreamp ? 1 : 0;
  183. }
  184. if (pauseopt)
  185. {
  186. if (mCurrentInternetStreamp)
  187. {
  188. stop();
  189. }
  190. }
  191. else
  192. {
  193. start(getURL());
  194. }
  195. }
  196. // A stream is "playing" if it has been requested to start. That
  197. // doesn't necessarily mean audio is coming out of the speakers.
  198. int LLStreamingAudio_FMOD::isPlaying()
  199. {
  200. if (mCurrentInternetStreamp)
  201. {
  202. return 1; // Active and playing
  203. }
  204. else if (!mURL.empty())
  205. {
  206. return 2; // "Paused"
  207. }
  208. else
  209. {
  210. return 0;
  211. }
  212. }
  213. F32 LLStreamingAudio_FMOD::getGain()
  214. {
  215. return mGain;
  216. }
  217. std::string LLStreamingAudio_FMOD::getURL()
  218. {
  219. return mURL;
  220. }
  221. void LLStreamingAudio_FMOD::setGain(F32 vol)
  222. {
  223. mGain = vol;
  224. if (mFMODInternetStreamChannel != -1)
  225. {
  226. vol = llclamp(vol * vol, 0.f, 1.f);
  227. int vol_int = llround(vol * 255.f);
  228. FSOUND_SetVolumeAbsolute(mFMODInternetStreamChannel, vol_int);
  229. }
  230. }
  231. ///////////////////////////////////////////////////////
  232. // manager of possibly-multiple internet audio streams
  233. LLAudioStreamManagerFMOD::LLAudioStreamManagerFMOD(const std::string& url) :
  234. mInternetStream(NULL),
  235. mReady(false)
  236. {
  237. mInternetStreamURL = url;
  238. mInternetStream = FSOUND_Stream_Open(url.c_str(), FSOUND_NORMAL | FSOUND_NONBLOCKING, 0, 0);
  239. if (!mInternetStream)
  240. {
  241. llwarns << "Couldn't open fmod stream, error "
  242. << FMOD_ErrorString(FSOUND_GetError())
  243. << llendl;
  244. mReady = false;
  245. return;
  246. }
  247. mReady = true;
  248. }
  249. int LLAudioStreamManagerFMOD::startStream()
  250. {
  251. // We need a live and opened stream before we try and play it.
  252. if (!mInternetStream || getOpenState())
  253. {
  254. llwarns << "No internet stream to start playing!" << llendl;
  255. return -1;
  256. }
  257. // Make sure the stream is set to 2D mode.
  258. FSOUND_Stream_SetMode(mInternetStream, FSOUND_2D);
  259. return FSOUND_Stream_PlayEx(FSOUND_FREE, mInternetStream, NULL, true);
  260. }
  261. bool LLAudioStreamManagerFMOD::stopStream()
  262. {
  263. if (mInternetStream)
  264. {
  265. int read_percent = 0;
  266. int status = 0;
  267. int bitrate = 0;
  268. unsigned int flags = 0x0;
  269. FSOUND_Stream_Net_GetStatus(mInternetStream, &status, &read_percent, &bitrate, &flags);
  270. bool close = true;
  271. switch (status)
  272. {
  273. case FSOUND_STREAM_NET_CONNECTING:
  274. close = false;
  275. break;
  276. case FSOUND_STREAM_NET_NOTCONNECTED:
  277. case FSOUND_STREAM_NET_BUFFERING:
  278. case FSOUND_STREAM_NET_READY:
  279. case FSOUND_STREAM_NET_ERROR:
  280. default:
  281. close = true;
  282. }
  283. if (close)
  284. {
  285. FSOUND_Stream_Close(mInternetStream);
  286. mInternetStream = NULL;
  287. return true;
  288. }
  289. else
  290. {
  291. return false;
  292. }
  293. }
  294. else
  295. {
  296. return true;
  297. }
  298. }
  299. int LLAudioStreamManagerFMOD::getOpenState()
  300. {
  301. int open_state = FSOUND_Stream_GetOpenState(mInternetStream);
  302. return open_state;
  303. }