diff options
Diffstat (limited to '')
-rw-r--r-- | linden/indra/llaudio/llaudioengine_fmod.cpp (renamed from linden/indra/llaudio/audioengine_fmod.cpp) | 361 |
1 files changed, 17 insertions, 344 deletions
diff --git a/linden/indra/llaudio/audioengine_fmod.cpp b/linden/indra/llaudio/llaudioengine_fmod.cpp index 938c2aa..85ae863 100644 --- a/linden/indra/llaudio/audioengine_fmod.cpp +++ b/linden/indra/llaudio/llaudioengine_fmod.cpp | |||
@@ -32,8 +32,11 @@ | |||
32 | 32 | ||
33 | #include "linden_common.h" | 33 | #include "linden_common.h" |
34 | 34 | ||
35 | #include "audioengine_fmod.h" | 35 | #include "llstreamingaudio.h" |
36 | #include "listener_fmod.h" | 36 | #include "llstreamingaudio_fmod.h" |
37 | |||
38 | #include "llaudioengine_fmod.h" | ||
39 | #include "lllistener_fmod.h" | ||
37 | 40 | ||
38 | #include "llerror.h" | 41 | #include "llerror.h" |
39 | #include "llmath.h" | 42 | #include "llmath.h" |
@@ -46,6 +49,7 @@ | |||
46 | 49 | ||
47 | #include "sound_ids.h" | 50 | #include "sound_ids.h" |
48 | 51 | ||
52 | |||
49 | extern "C" { | 53 | extern "C" { |
50 | void * F_CALLBACKAPI windCallback(void *originalbuffer, void *newbuffer, int length, void* userdata); | 54 | void * F_CALLBACKAPI windCallback(void *originalbuffer, void *newbuffer, int length, void* userdata); |
51 | } | 55 | } |
@@ -53,35 +57,9 @@ extern "C" { | |||
53 | FSOUND_DSPUNIT *gWindDSP = NULL; | 57 | FSOUND_DSPUNIT *gWindDSP = NULL; |
54 | 58 | ||
55 | 59 | ||
56 | // Safe strcpy | ||
57 | #if 0 //(unused) //LL_WINDOWS || LL_LINUX | ||
58 | static size_t strlcpy( char* dest, const char* src, size_t dst_size ) | ||
59 | { | ||
60 | size_t source_len = 0; | ||
61 | size_t min_len = 0; | ||
62 | if( dst_size > 0 ) | ||
63 | { | ||
64 | if( src ) | ||
65 | { | ||
66 | source_len = strlen(src); /*Flawfinder: ignore*/ | ||
67 | min_len = llmin( dst_size - 1, source_len ); | ||
68 | memcpy(dest, src, min_len); /*Flawfinder: ignore*/ | ||
69 | } | ||
70 | dest[min_len] = '\0'; | ||
71 | } | ||
72 | return source_len; | ||
73 | } | ||
74 | #else | ||
75 | // apple ships with the non-standard strlcpy in /usr/include/string.h: | ||
76 | // size_t strlcpy(char *, const char *, size_t); | ||
77 | #endif | ||
78 | |||
79 | |||
80 | LLAudioEngine_FMOD::LLAudioEngine_FMOD() | 60 | LLAudioEngine_FMOD::LLAudioEngine_FMOD() |
81 | { | 61 | { |
82 | mInited = false; | 62 | mInited = false; |
83 | mCurrentInternetStreamp = NULL; | ||
84 | mInternetStreamChannel = -1; | ||
85 | mWindGen = NULL; | 63 | mWindGen = NULL; |
86 | } | 64 | } |
87 | 65 | ||
@@ -93,8 +71,6 @@ LLAudioEngine_FMOD::~LLAudioEngine_FMOD() | |||
93 | 71 | ||
94 | bool LLAudioEngine_FMOD::init(const S32 num_channels, void* userdata) | 72 | bool LLAudioEngine_FMOD::init(const S32 num_channels, void* userdata) |
95 | { | 73 | { |
96 | mFadeIn = -10000; | ||
97 | |||
98 | LLAudioEngine::init(num_channels, userdata); | 74 | LLAudioEngine::init(num_channels, userdata); |
99 | 75 | ||
100 | // Reserve one extra channel for the http stream. | 76 | // Reserve one extra channel for the http stream. |
@@ -241,7 +217,9 @@ bool LLAudioEngine_FMOD::init(const S32 num_channels, void* userdata) | |||
241 | 217 | ||
242 | #endif | 218 | #endif |
243 | 219 | ||
244 | initInternetStream(); | 220 | // set up our favourite FMOD-native streaming audio implementation if none has already been added |
221 | if (!getStreamingAudioImpl()) // no existing implementation added | ||
222 | setStreamingAudioImpl(new LLStreamingAudio_FMOD()); | ||
245 | 223 | ||
246 | LL_DEBUGS("AppInit") << "LLAudioEngine_FMOD::init() FMOD initialized correctly" << LL_ENDL; | 224 | LL_DEBUGS("AppInit") << "LLAudioEngine_FMOD::init() FMOD initialized correctly" << LL_ENDL; |
247 | 225 | ||
@@ -296,13 +274,13 @@ void LLAudioEngine_FMOD::shutdown() | |||
296 | } | 274 | } |
297 | 275 | ||
298 | 276 | ||
299 | LLAudioBuffer *LLAudioEngine_FMOD::createBuffer() | 277 | LLAudioBuffer * LLAudioEngine_FMOD::createBuffer() |
300 | { | 278 | { |
301 | return new LLAudioBufferFMOD(); | 279 | return new LLAudioBufferFMOD(); |
302 | } | 280 | } |
303 | 281 | ||
304 | 282 | ||
305 | LLAudioChannel *LLAudioEngine_FMOD::createChannel() | 283 | LLAudioChannel * LLAudioEngine_FMOD::createChannel() |
306 | { | 284 | { |
307 | return new LLAudioChannelFMOD(); | 285 | return new LLAudioChannelFMOD(); |
308 | } | 286 | } |
@@ -432,10 +410,12 @@ void LLAudioEngine_FMOD::setInternalGain(F32 gain) | |||
432 | gain = llclamp( gain, 0.0f, 1.0f ); | 410 | gain = llclamp( gain, 0.0f, 1.0f ); |
433 | FSOUND_SetSFXMasterVolume( llround( 255.0f * gain ) ); | 411 | FSOUND_SetSFXMasterVolume( llround( 255.0f * gain ) ); |
434 | 412 | ||
435 | if ( mInternetStreamChannel != -1 ) | 413 | LLStreamingAudioInterface *saimpl = getStreamingAudioImpl(); |
414 | if ( saimpl ) | ||
436 | { | 415 | { |
437 | F32 clamp_internet_stream_gain = llclamp( mInternetStreamGain, 0.0f, 1.0f ); | 416 | // fmod likes its streaming audio channel gain re-asserted after |
438 | FSOUND_SetVolumeAbsolute( mInternetStreamChannel, llround( 255.0f * clamp_internet_stream_gain ) ); | 417 | // master volume change. |
418 | saimpl->setGain(saimpl->getGain()); | ||
439 | } | 419 | } |
440 | } | 420 | } |
441 | 421 | ||
@@ -660,7 +640,7 @@ bool LLAudioBufferFMOD::loadWAV(const std::string& filename) | |||
660 | return false; | 640 | return false; |
661 | } | 641 | } |
662 | 642 | ||
663 | if (!LLAPRFile::isExist(filename, NULL, LL_APR_RPB)) | 643 | if (!LLAPRFile::isExist(filename, LL_APR_RPB)) |
664 | { | 644 | { |
665 | // File not found, abort. | 645 | // File not found, abort. |
666 | return false; | 646 | return false; |
@@ -752,313 +732,6 @@ void LLAudioBufferFMOD::set3DMode(bool use3d) | |||
752 | } | 732 | } |
753 | 733 | ||
754 | 734 | ||
755 | |||
756 | //--------------------------------------------------------------------------- | ||
757 | // Internet Streaming | ||
758 | //--------------------------------------------------------------------------- | ||
759 | void LLAudioEngine_FMOD::initInternetStream() | ||
760 | { | ||
761 | // Number of milliseconds of audio to buffer for the audio card. | ||
762 | // Must be larger than the usual Second Life frame stutter time. | ||
763 | FSOUND_Stream_SetBufferSize(200); | ||
764 | |||
765 | // Here's where we set the size of the network buffer and some buffering | ||
766 | // parameters. In this case we want a network buffer of 16k, we want it | ||
767 | // to prebuffer 40% of that when we first connect, and we want it | ||
768 | // to rebuffer 80% of that whenever we encounter a buffer underrun. | ||
769 | |||
770 | // Leave the net buffer properties at the default. | ||
771 | //FSOUND_Stream_Net_SetBufferProperties(20000, 40, 80); | ||
772 | mInternetStreamURL.clear(); | ||
773 | } | ||
774 | |||
775 | |||
776 | void LLAudioEngine_FMOD::startInternetStream(const std::string& url) | ||
777 | { | ||
778 | if (!mInited) | ||
779 | { | ||
780 | llwarns << "startInternetStream before audio initialized" << llendl; | ||
781 | return; | ||
782 | } | ||
783 | |||
784 | // "stop" stream but don't clear url, etc. in calse url == mInternetStreamURL | ||
785 | stopInternetStream(); | ||
786 | if (!url.empty()) | ||
787 | { | ||
788 | llinfos << "Starting internet stream: " << url << llendl; | ||
789 | mCurrentInternetStreamp = new LLAudioStreamFMOD(url); | ||
790 | mInternetStreamURL = url; | ||
791 | } | ||
792 | else | ||
793 | { | ||
794 | llinfos << "Set internet stream to null" << llendl; | ||
795 | mInternetStreamURL.clear(); | ||
796 | } | ||
797 | } | ||
798 | |||
799 | |||
800 | signed char F_CALLBACKAPI LLAudioEngine_FMOD::callbackMetaData(char *name, char *value, void *userdata) | ||
801 | { | ||
802 | /* | ||
803 | LLAudioEngine_FMOD* self = (LLAudioEngine_FMOD*)userdata; | ||
804 | |||
805 | if (!strcmp("ARTIST", name)) | ||
806 | { | ||
807 | strlcpy(self->mInternetStreamArtist, value, 256); | ||
808 | self->mInternetStreamNewMetaData = true; | ||
809 | return true; | ||
810 | } | ||
811 | |||
812 | if (!strcmp("TITLE", name)) | ||
813 | { | ||
814 | strlcpy(self->mInternetStreamTitle, value, 256); | ||
815 | self->mInternetStreamNewMetaData = true; | ||
816 | return true; | ||
817 | } | ||
818 | */ | ||
819 | |||
820 | return true; | ||
821 | } | ||
822 | |||
823 | |||
824 | void LLAudioEngine_FMOD::updateInternetStream() | ||
825 | { | ||
826 | // Kill dead internet streams, if possible | ||
827 | std::list<LLAudioStreamFMOD *>::iterator iter; | ||
828 | for (iter = mDeadStreams.begin(); iter != mDeadStreams.end();) | ||
829 | { | ||
830 | LLAudioStreamFMOD *streamp = *iter; | ||
831 | if (streamp->stopStream()) | ||
832 | { | ||
833 | llinfos << "Closed dead stream" << llendl; | ||
834 | delete streamp; | ||
835 | mDeadStreams.erase(iter++); | ||
836 | } | ||
837 | else | ||
838 | { | ||
839 | iter++; | ||
840 | } | ||
841 | } | ||
842 | |||
843 | // Don't do anything if there are no streams playing | ||
844 | if (!mCurrentInternetStreamp) | ||
845 | { | ||
846 | return; | ||
847 | } | ||
848 | |||
849 | int open_state = mCurrentInternetStreamp->getOpenState(); | ||
850 | |||
851 | if (!open_state) | ||
852 | { | ||
853 | // Stream is live | ||
854 | |||
855 | |||
856 | // start the stream if it's ready | ||
857 | if (mInternetStreamChannel < 0) | ||
858 | { | ||
859 | mInternetStreamChannel = mCurrentInternetStreamp->startStream(); | ||
860 | |||
861 | if (mInternetStreamChannel != -1) | ||
862 | { | ||
863 | // Reset volume to previously set volume | ||
864 | setInternetStreamGain(mInternetStreamGain); | ||
865 | FSOUND_SetPaused(mInternetStreamChannel, false); | ||
866 | //FSOUND_Stream_Net_SetMetadataCallback(mInternetStream, callbackMetaData, this); | ||
867 | } | ||
868 | } | ||
869 | } | ||
870 | |||
871 | switch(open_state) | ||
872 | { | ||
873 | default: | ||
874 | case 0: | ||
875 | // success | ||
876 | break; | ||
877 | case -1: | ||
878 | // stream handle is invalid | ||
879 | llwarns << "InternetStream - invalid handle" << llendl; | ||
880 | stopInternetStream(); | ||
881 | return; | ||
882 | case -2: | ||
883 | // opening | ||
884 | //strlcpy(mInternetStreamArtist, "Opening", 256); | ||
885 | break; | ||
886 | case -3: | ||
887 | // failed to open, file not found, perhaps | ||
888 | llwarns << "InternetSteam - failed to open" << llendl; | ||
889 | stopInternetStream(); | ||
890 | return; | ||
891 | case -4: | ||
892 | // connecting | ||
893 | //strlcpy(mInternetStreamArtist, "Connecting", 256); | ||
894 | break; | ||
895 | case -5: | ||
896 | // buffering | ||
897 | //strlcpy(mInternetStreamArtist, "Buffering", 256); | ||
898 | break; | ||
899 | } | ||
900 | |||
901 | } | ||
902 | |||
903 | void LLAudioEngine_FMOD::stopInternetStream() | ||
904 | { | ||
905 | if (mInternetStreamChannel != -1) | ||
906 | { | ||
907 | FSOUND_SetPaused(mInternetStreamChannel, true); | ||
908 | FSOUND_SetPriority(mInternetStreamChannel, 0); | ||
909 | mInternetStreamChannel = -1; | ||
910 | } | ||
911 | |||
912 | if (mCurrentInternetStreamp) | ||
913 | { | ||
914 | llinfos << "Stopping internet stream: " << mCurrentInternetStreamp->getURL() << llendl; | ||
915 | if (mCurrentInternetStreamp->stopStream()) | ||
916 | { | ||
917 | delete mCurrentInternetStreamp; | ||
918 | } | ||
919 | else | ||
920 | { | ||
921 | llwarns << "Pushing stream to dead list: " << mCurrentInternetStreamp->getURL() << llendl; | ||
922 | mDeadStreams.push_back(mCurrentInternetStreamp); | ||
923 | } | ||
924 | mCurrentInternetStreamp = NULL; | ||
925 | //mInternetStreamURL.clear(); | ||
926 | } | ||
927 | } | ||
928 | |||
929 | void LLAudioEngine_FMOD::pauseInternetStream(int pause) | ||
930 | { | ||
931 | if (pause < 0) | ||
932 | { | ||
933 | pause = mCurrentInternetStreamp ? 1 : 0; | ||
934 | } | ||
935 | |||
936 | if (pause) | ||
937 | { | ||
938 | if (mCurrentInternetStreamp) | ||
939 | { | ||
940 | stopInternetStream(); | ||
941 | } | ||
942 | } | ||
943 | else | ||
944 | { | ||
945 | startInternetStream(mInternetStreamURL); | ||
946 | } | ||
947 | } | ||
948 | |||
949 | |||
950 | // A stream is "playing" if it has been requested to start. That | ||
951 | // doesn't necessarily mean audio is coming out of the speakers. | ||
952 | int LLAudioEngine_FMOD::isInternetStreamPlaying() | ||
953 | { | ||
954 | if (mCurrentInternetStreamp) | ||
955 | { | ||
956 | return 1; // Active and playing | ||
957 | } | ||
958 | else if (!mInternetStreamURL.empty()) | ||
959 | { | ||
960 | return 2; // "Paused" | ||
961 | } | ||
962 | else | ||
963 | { | ||
964 | return 0; | ||
965 | } | ||
966 | } | ||
967 | |||
968 | |||
969 | void LLAudioEngine_FMOD::setInternetStreamGain(F32 vol) | ||
970 | { | ||
971 | mInternetStreamGain = vol; | ||
972 | |||
973 | if (mInternetStreamChannel != -1) | ||
974 | { | ||
975 | vol = llclamp(vol, 0.f, 1.f); | ||
976 | int vol_int = llround(vol * 255.f); | ||
977 | FSOUND_SetVolumeAbsolute(mInternetStreamChannel, vol_int); | ||
978 | } | ||
979 | } | ||
980 | |||
981 | |||
982 | LLAudioStreamFMOD::LLAudioStreamFMOD(const std::string& url) : | ||
983 | mInternetStream(NULL), | ||
984 | mReady(false) | ||
985 | { | ||
986 | mInternetStreamURL = url; | ||
987 | mInternetStream = FSOUND_Stream_Open(url.c_str(), FSOUND_NORMAL | FSOUND_NONBLOCKING, 0, 0); | ||
988 | if (!mInternetStream) | ||
989 | { | ||
990 | llwarns << "Couldn't open fmod stream, error " | ||
991 | << FMOD_ErrorString(FSOUND_GetError()) | ||
992 | << llendl; | ||
993 | mReady = false; | ||
994 | return; | ||
995 | } | ||
996 | |||
997 | mReady = true; | ||
998 | } | ||
999 | |||
1000 | int LLAudioStreamFMOD::startStream() | ||
1001 | { | ||
1002 | // We need a live and opened stream before we try and play it. | ||
1003 | if (!mInternetStream || getOpenState()) | ||
1004 | { | ||
1005 | llwarns << "No internet stream to start playing!" << llendl; | ||
1006 | return -1; | ||
1007 | } | ||
1008 | |||
1009 | // Make sure the stream is set to 2D mode. | ||
1010 | FSOUND_Stream_SetMode(mInternetStream, FSOUND_2D); | ||
1011 | |||
1012 | return FSOUND_Stream_PlayEx(FSOUND_FREE, mInternetStream, NULL, true); | ||
1013 | } | ||
1014 | |||
1015 | bool LLAudioStreamFMOD::stopStream() | ||
1016 | { | ||
1017 | if (mInternetStream) | ||
1018 | { | ||
1019 | int read_percent = 0; | ||
1020 | int status = 0; | ||
1021 | int bitrate = 0; | ||
1022 | unsigned int flags = 0x0; | ||
1023 | FSOUND_Stream_Net_GetStatus(mInternetStream, &status, &read_percent, &bitrate, &flags); | ||
1024 | |||
1025 | bool close = true; | ||
1026 | switch (status) | ||
1027 | { | ||
1028 | case FSOUND_STREAM_NET_CONNECTING: | ||
1029 | close = false; | ||
1030 | break; | ||
1031 | case FSOUND_STREAM_NET_NOTCONNECTED: | ||
1032 | case FSOUND_STREAM_NET_BUFFERING: | ||
1033 | case FSOUND_STREAM_NET_READY: | ||
1034 | case FSOUND_STREAM_NET_ERROR: | ||
1035 | default: | ||
1036 | close = true; | ||
1037 | } | ||
1038 | |||
1039 | if (close) | ||
1040 | { | ||
1041 | FSOUND_Stream_Close(mInternetStream); | ||
1042 | mInternetStream = NULL; | ||
1043 | return true; | ||
1044 | } | ||
1045 | else | ||
1046 | { | ||
1047 | return false; | ||
1048 | } | ||
1049 | } | ||
1050 | else | ||
1051 | { | ||
1052 | return true; | ||
1053 | } | ||
1054 | } | ||
1055 | |||
1056 | int LLAudioStreamFMOD::getOpenState() | ||
1057 | { | ||
1058 | int open_state = FSOUND_Stream_GetOpenState(mInternetStream); | ||
1059 | return open_state; | ||
1060 | } | ||
1061 | |||
1062 | void * F_CALLBACKAPI windCallback(void *originalbuffer, void *newbuffer, int length, void* userdata) | 735 | void * F_CALLBACKAPI windCallback(void *originalbuffer, void *newbuffer, int length, void* userdata) |
1063 | { | 736 | { |
1064 | // originalbuffer = fmod's original mixbuffer. | 737 | // originalbuffer = fmod's original mixbuffer. |