llstreamingaudio_fmod.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:8k
源码类别:

游戏引擎

开发平台:

C++ Builder

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