diff options
author | dolphin <dolphin@lindenlab.com> | 2013-04-18 15:59:22 -0700 |
---|---|---|
committer | dolphin <dolphin@lindenlab.com> | 2013-04-18 15:59:22 -0700 |
commit | eec08ef64c59fa7569c7418d40135d73338e1d8d (patch) | |
tree | 3b62188c704df9ea16484c497d68388ab2908b80 | |
parent | 56badfe3498b5eeefb5c06c4b0d51eb1c62ded9c (diff) | |
parent | ed2b5da8f1eb51e747f6d9f5a4fc535cbf7e69d9 (diff) |
Merge with viewer-development
36 files changed, 1400 insertions, 1607 deletions
@@ -72,35 +72,35 @@ b53a0576eec80614d7767ed72b40ed67aeff27c9 DRTVWR-38_2.5.2-release 461c8c65b5c799ddfe365422f9be9c0095d91e7d 2.6.0-beta1-tip 9e4641f4a7870c0f565a25a2971368d5a29516a1 2.6.0-beta2 9e4641f4a7870c0f565a25a2971368d5a29516a1 DRTVWR-41_2.6.0-beta2 +42f32494bac475d0737799346f6831558ae8bf5d 2.6.0-release +42f32494bac475d0737799346f6831558ae8bf5d DRTVWR-39_2.6.0-release c5bdef3aaa2744626aef3c217ce29e1900d357b3 2.6.1-beta1 c5bdef3aaa2744626aef3c217ce29e1900d357b3 2.6.1-start c5bdef3aaa2744626aef3c217ce29e1900d357b3 DRTVWR-43_2.6.1-beta1 +c9182ed77d427c759cfacf49a7b71a2e20d522aa 2.6.1-release +c9182ed77d427c759cfacf49a7b71a2e20d522aa DRTVWR-42_2.6.1-release 56b2778c743c2a964d82e1caf11084d76a87de2c 2.6.2-start d1203046bb653b763f835b04d184646949d8dd5c 2.6.2-beta1 d1203046bb653b763f835b04d184646949d8dd5c DRTVWR-45_2.6.2-beta1 -42f32494bac475d0737799346f6831558ae8bf5d 2.6.0-release -42f32494bac475d0737799346f6831558ae8bf5d DRTVWR-39_2.6.0-release -c9182ed77d427c759cfacf49a7b71a2e20d522aa 2.6.1-release -c9182ed77d427c759cfacf49a7b71a2e20d522aa DRTVWR-42_2.6.1-release +214180ad5714ce8392b82bbebcc92f4babd98300 2.6.2-release +214180ad5714ce8392b82bbebcc92f4babd98300 DRTVWR-44_2.6.2-release 52b2263ab28f0976c689fd0b76c55a9eb027cdbf end-of-develop.py ec32f1045e7c2644015245df3a9933620aa194b8 2.6.3-start d7fcefabdf32bb61a9ea6d6037c1bb26190a85bc 2.6.3-beta1 d7fcefabdf32bb61a9ea6d6037c1bb26190a85bc DRTVWR-47_2.6.3-beta1 0630e977504af5ea320c58d33cae4e1ddee793e9 2.6.3-beta2 0630e977504af5ea320c58d33cae4e1ddee793e9 DRTVWR-48_2.6.3-beta2 +8f2da1701c81a62352df2b8d413d27fb2cade9a6 2.6.3-release +8f2da1701c81a62352df2b8d413d27fb2cade9a6 DRTVWR-46_2.6.3-release 3178e311da3a8739a85363665006ea3c4610cad4 dons-headless-hackathon-work -214180ad5714ce8392b82bbebcc92f4babd98300 2.6.2-release -214180ad5714ce8392b82bbebcc92f4babd98300 DRTVWR-44_2.6.2-release 7db558aaa7c176f2022b3e9cfe38ac72f6d1fccd 2.6.5-beta1 7db558aaa7c176f2022b3e9cfe38ac72f6d1fccd DRTVWR-50_2.6.5-beta1 -8f2da1701c81a62352df2b8d413d27fb2cade9a6 2.6.3-release -8f2da1701c81a62352df2b8d413d27fb2cade9a6 DRTVWR-46_2.6.3-release 800cefce8d364ffdd2f383cbecb91294da3ea424 2.6.6-start bb1075286b3b147b1dae2e3d6b2d56f04ff03f35 2.6.6-beta1 bb1075286b3b147b1dae2e3d6b2d56f04ff03f35 DRTVWR-52_2.6.6-beta1 -5e349dbe9cc84ea5795af8aeb6d473a0af9d4953 2.6.8-start dac76a711da5f1489a01c1fa62ec97d99c25736d 2.6.6-release dac76a711da5f1489a01c1fa62ec97d99c25736d DRTVWR-51_2.6.6-release +5e349dbe9cc84ea5795af8aeb6d473a0af9d4953 2.6.8-start beafa8a9bd1d1b670b7523d865204dc4a4b38eef 2.6.8-beta1 beafa8a9bd1d1b670b7523d865204dc4a4b38eef DRTVWR-55_2.6.8-beta1 be2000b946f8cb3de5f44b2d419287d4c48ec4eb 2.6.8-release @@ -119,50 +119,50 @@ e67da2c6e3125966dd49eef98b36317afac1fcfe 2.6.9-start 9f79a6ed8fdcd2f3dac33ea6b3236eeb278dccfe 2.7.2-start e0dc8b741eaa27dcdfbc9e956bb2579b954d15eb 2.7.2-beta1 e0dc8b741eaa27dcdfbc9e956bb2579b954d15eb DRTVWR-63_2.7.2-beta1 -6a3e7e403bd19e45fdfc2fcc716867af3ab80861 2.7.3-start fe3a8e7973072ea62043c08b19b66626c1a720eb 2.7.1-release fe3a8e7973072ea62043c08b19b66626c1a720eb 2.7.2-release fe3a8e7973072ea62043c08b19b66626c1a720eb DRTVWR-60_2.7.1-release fe3a8e7973072ea62043c08b19b66626c1a720eb DRTVWR-62_2.7.2-release +6a3e7e403bd19e45fdfc2fcc716867af3ab80861 2.7.3-start 6af10678de4736222b2c3f7e010e984fb5b327de 2.7.4-start be963a4eef635542f9617d7f5fd22ba48fb71958 2.7.4-beta1 be963a4eef635542f9617d7f5fd22ba48fb71958 DRTVWR-67_2.7.4-beta1 +057f319dd8eccdf63a54d99686c68cdcb31b6abc 2.7.4-release +057f319dd8eccdf63a54d99686c68cdcb31b6abc DRTVWR-66_2.7.4-release 19a498fa62570f352d7d246f17e3c81cc1d82d8b 2.7.5-start 09984bfa6cae17e0f72d02b75c1b7393c65eecfc 2.7.5-beta1 09984bfa6cae17e0f72d02b75c1b7393c65eecfc DRTVWR-69_2.7.5-beta1 +6866d9df6efbd441c66451debd376d21211de39c 2.7.5-release +6866d9df6efbd441c66451debd376d21211de39c DRTVWR-68_2.7.5-release e1ed60913230dd64269a7f7fc52cbc6004f6d52c 2.8.0-beta1 e1ed60913230dd64269a7f7fc52cbc6004f6d52c 2.8.0-start e1ed60913230dd64269a7f7fc52cbc6004f6d52c DRTVWR-71_2.8.0-beta1 -057f319dd8eccdf63a54d99686c68cdcb31b6abc 2.7.4-release -057f319dd8eccdf63a54d99686c68cdcb31b6abc DRTVWR-66_2.7.4-release -6866d9df6efbd441c66451debd376d21211de39c 2.7.5-release -6866d9df6efbd441c66451debd376d21211de39c DRTVWR-68_2.7.5-release +493d9127ee50e84ba08a736a65a23ca86f7a5b01 2.8.0-release +493d9127ee50e84ba08a736a65a23ca86f7a5b01 DRTVWR-70_2.8.0-release 502f6a5deca9365ddae57db4f1e30172668e171e 2.8.1-start 2c7e459e0c883f8e406b932e41e60097e9ee077e 2.8.1-beta1 2c7e459e0c883f8e406b932e41e60097e9ee077e DRTVWR-73_2.8.1-beta1 -493d9127ee50e84ba08a736a65a23ca86f7a5b01 2.8.0-release -493d9127ee50e84ba08a736a65a23ca86f7a5b01 DRTVWR-70_2.8.0-release -54bc7823ad4e3a436fef79710f685a7372bbf795 2.8.2-start -ac0f1a132d35c02a58861d37cca75b0429ac9137 2.8.3-start 29e93d7e19991011bd12b5748142b11a5dcb4370 2.8.1-release 29e93d7e19991011bd12b5748142b11a5dcb4370 DRTVWR-72_2.8.1-release 4780e3bd2b3042f91be3426151f28c30d199bb3b 2.8.1-hotfix 4780e3bd2b3042f91be3426151f28c30d199bb3b DRTVWR-76_2.8.1-hotfix +54bc7823ad4e3a436fef79710f685a7372bbf795 2.8.2-start +ac0f1a132d35c02a58861d37cca75b0429ac9137 2.8.3-start 599677276b227357140dda35bea4a2c18e2e67b5 2.8.3-beta1 599677276b227357140dda35bea4a2c18e2e67b5 DRTVWR-75_2.8.3-beta1 +fb85792b84bf28428889c4cc966469d92e5dac4c 2.8.3-release +fb85792b84bf28428889c4cc966469d92e5dac4c DRTVWR-74_2.8.3-release 6b678ea52f90d5c14181661dcd2546e25bde483e 3.0.0-start b0be6ce3adfef3a014a2389d360539f8a86c5439 3.0.0-beta1 b0be6ce3adfef3a014a2389d360539f8a86c5439 DRTVWR-78_3.0.0-beta1 -fb85792b84bf28428889c4cc966469d92e5dac4c 2.8.3-release -fb85792b84bf28428889c4cc966469d92e5dac4c DRTVWR-74_2.8.3-release +1778f26b6d0ae762dec3ca37140f66620f2485d9 3.0.0-release +1778f26b6d0ae762dec3ca37140f66620f2485d9 DRTVWR-77_3.0.0-release 82a2079ffcb57ecb1b3849cb41376b443e1eb912 3.0.1-start 364fd63517fbacbbcb9129d096187171ba8c9e48 3.0.1-beta1 364fd63517fbacbbcb9129d096187171ba8c9e48 DRTVWR-81_3.0.1-beta1 f2412ecd6740803ea9452f1d17fd872e263a0df7 3.0.2-start 42784bf50fa01974bada2a1af3892ee09c93fcda 3.0.2-beta1 42784bf50fa01974bada2a1af3892ee09c93fcda DRTVWR-83_3.0.2-beta1 -1778f26b6d0ae762dec3ca37140f66620f2485d9 3.0.0-release -1778f26b6d0ae762dec3ca37140f66620f2485d9 DRTVWR-77_3.0.0-release e5c9af2d7980a99a71650be3a0cf7b2b3c3b897e 3.0.2-beta2 e5c9af2d7980a99a71650be3a0cf7b2b3c3b897e DRTVWR-86_3.0.2-beta2 b95ddac176ac944efdc85cbee94ac2e1eab44c79 3.0.3-start @@ -170,9 +170,9 @@ b95ddac176ac944efdc85cbee94ac2e1eab44c79 3.0.3-start 6694f3f062aa45f64ab391d25a3eb3d5eb1b0871 DRTVWR-85_3.0.3-beta1 61aa7974df089e8621fe9a4c69bcdefdb3cc208a 3.0.3-beta2 61aa7974df089e8621fe9a4c69bcdefdb3cc208a DRTVWR-89_3.0.3-beta2 -586907287be581817b2422b5137971b22d54ea48 3.0.4-start 0496d2f74043cf4e6058e76ac3db03d44cff42ce 3.0.3-release 0496d2f74043cf4e6058e76ac3db03d44cff42ce DRTVWR-84_3.0.3-release +586907287be581817b2422b5137971b22d54ea48 3.0.4-start 92a3aa04775438226399b19deee12ac3b5a62838 3.0.5-start c7282e59f374ee904bd793c3c444455e3399b0c5 3.1.0-start 2657fa785bbfac115852c41bd0adaff74c2ad5da 3.1.0-beta1 @@ -193,11 +193,11 @@ e440cd1dfbd128d7d5467019e497f7f803640ad6 DRTVWR-95_3.2.0-beta1 c4911ec8cd81e676dfd2af438b3e065407a94a7a 3.2.1-start 9e390d76807fa70d356b8716fb83b8ce42a629ef 3.2.1-beta1 9e390d76807fa70d356b8716fb83b8ce42a629ef DRTVWR-100_3.2.1-beta1 +a8c7030d6845186fac7c188be4323a0e887b4184 3.2.1-release +a8c7030d6845186fac7c188be4323a0e887b4184 DRTVWR-99_3.2.1-release 40b46edba007d15d0059c80864b708b99c1da368 3.2.2-start 523df3e67378541498d516d52af4402176a26bac 3.2.2-beta1 523df3e67378541498d516d52af4402176a26bac DRTVWR-102_3.2.2-beta1 -a8c7030d6845186fac7c188be4323a0e887b4184 3.2.1-release -a8c7030d6845186fac7c188be4323a0e887b4184 DRTVWR-99_3.2.1-release 80f3e30d8aa4d8f674a48bd742aaa6d8e9eae0b5 3.2.3-start 3fe994349fae64fc40874bb59db387131eb35a41 3.2.4-beta1 3fe994349fae64fc40874bb59db387131eb35a41 3.2.4-start @@ -248,57 +248,67 @@ bb9932a7a5fd00edf52d95f354e3b37ae6a942db DRTVWR-156 6414ecdabc5d89515b08d1f872cf923ed3a5523a DRTVWR-148 2a3965b3ad202df7ea25d2be689291bb14a1280e DRTVWR-155 24a7281bef42bd4430ceb25db8b195449c2c7de3 DRTVWR-153 +a716684aa7c07c440b1de5815b8a1f3dd3fd8bfb DRTVWR-159 +9a78ac13f047056f788c4734dd91aebfe30970e3 DRTVWR-157 5910f8063a7e1ddddf504c2f35ca831cc5e8f469 DRTVWR-160 f0a174c2adb4bc39b16722a61d7eeb4f2a1d4843 3.3.3-beta1 f0a174c2adb4bc39b16722a61d7eeb4f2a1d4843 DRTVWR-144 -2d6c0634b11e6f3df11002b8510a72a0433da00a DRTVWR-164 +089e5c84b2dece68f2b016c842ef9b5de4786842 DRTVWR-161 600f3b3920d94de805ac6dc8bb6def9c069dd360 DRTVWR-162 +c08e2ac17a99973b2a94477659220b99b8847ae2 DRTVWR-163 +2d6c0634b11e6f3df11002b8510a72a0433da00a DRTVWR-164 80b5e5e9775966d3839331ffa7a16a60f9d7c930 DRTVWR-165 fdcc08a4f20ae9bb060f4693c8980d216534efdf 3.3.3-beta2 af5f3e43e6e4424b1da19d9e16f6b853a7b822ed DRTVWR-169 4b3c68199a86cabaa5d9466d7b0f7e141e901d7a 3.3.3-beta3 6428242e124b523813bfaf4c45b3d422f0298c81 3.3.3-release -a716684aa7c07c440b1de5815b8a1f3dd3fd8bfb DRTVWR-159 -9a78ac13f047056f788c4734dd91aebfe30970e3 DRTVWR-157 -089e5c84b2dece68f2b016c842ef9b5de4786842 DRTVWR-161 -c08e2ac17a99973b2a94477659220b99b8847ae2 DRTVWR-163 b9d0170b62eb1c7c3adaa37a0b13a833e5e659f9 DRTVWR-171 050e48759337249130f684b4a21080b683f61732 DRTVWR-168 09ef7fd1b0781f33b8a3a9af6236b7bcb4831910 DRTVWR-170 f87bfbe0b62d26f451d02a47c80ebef6b9168fc2 DRTVWR-158 f91d003091a61937a044652c4c674447f7dcbb7a 3.3.4-beta1 +005dfe5c4c377207d065fb27858d2eb0b53b143a DRTVWR-167 bce218b2b45b730b22cc51e4807aa8b571cadef3 DRTVWR-173 cbea6356ce9cb0c313b6777f10c5c14783264fcc DRTVWR-174 82b5330bc8b17d0d4b598832e9c5a92e90075682 3.3.4-beta2 57d221de3df94f90b55204313c2cef044a3c0ae2 DRTVWR-176 eb539c65e6ee26eea2bf373af2d0f4b52dc91289 DRTVWR-177 a8057e1b9a1246b434a27405be35e030f7d28b0c 3.3.4-beta3 +888768f162d2c0a8de1dcc5fb9a08bd8bd120a6b DRTVWR-175 4281aa899fb2cedb7a9ca7ce91c5c29d4aa69594 DRTVWR-180 5c08e1d8edd871807153603b690e3ee9dbb548aa DRTVWR-183 6c75f220b103db1420919c8b635fe53e2177f318 3.3.4-beta4 9cd174d3a54d93d409a7c346a15b8bfb40fc58f4 DRTVWR-184 ab2ffc547c8a8950ff187c4f6c95e5334fab597b 3.3.4-beta5 28e100d0379a2b0710c57647a28fc5239d3d7b99 3.3.4-release -005dfe5c4c377207d065fb27858d2eb0b53b143a DRTVWR-167 -888768f162d2c0a8de1dcc5fb9a08bd8bd120a6b DRTVWR-175 a8b3eca451a9eaab59987efb0ab1c4217e3f2dcc DRTVWR-182 1f27cdfdc54246484f8afbbe42ce48e954175cbd 3.4.0-beta1 -9ee9387789701d597130f879d9011a4958753862 DRTVWR-189 +81f6b745ef27f5915fd07f988fdec9944f2bb73e DRTVWR-186 47f0d08ba7ade0a3905074009067c6d3df7e16ae DRTVWR-190 +cc953f00956be52cc64c30637bbeec310eea603f DRTVWR-181 +c04e68e1b0034fd0a20815ae24c77e5f8428e822 DRTVWR-188 +9ee9387789701d597130f879d9011a4958753862 DRTVWR-189 421126293dcbde918e0da027ca0ab9deb5b4fbf2 DRTVWR-192 +4b2c52aecb7a75de31dbb12d9f5b9a251d8707be DRTVWR-191 33a2fc7a910ae29ff8b4850316ed7fbff9f64d33 DRTVWR-195 e9732c739c8a72a590216951505ea9c76a526a84 DRTVWR-193 +78ca0bbf43a92e8914d4cfa87d69a6717ef7d4cf DRTVWR-194 7602f61c804a512764e349c034c02ddabeefebc4 DRTVWR-196 ae5c83dd61d2d37c45f1d5b8bf2b036d87599f1b DRTVWR-198 507bdfbd6bf844a511c1ffeda4baa80016ed1346 DRTVWR-197 b1dbb1a83f48f93f6f878cff9e52d2cb635e145c 3.4.0-beta2 37402e2b19af970d51b0a814d79892cc5647532b DRTVWR-200 182a9bf30e81070361bb020a78003b1cf398e79c 3.4.0-beta3 +248f4acd92a706c79e842bc83d80baa7369c0c2e DRTVWR-203 6dfb0fba782c9233dd95f24ec48146db0d3f210b DRTVWR-199 7c9102fb998885621919f2474a002c35b583539b 3.3.4-release2 7649a3dff5ec22d3727377e5f02efd0f421e4cb5 DRTVWR-201 84fb70dfe3444e75a44fb4bee43e2fc8221cebdd 3.4.0-beta4 +de3be913f68813a9bac7d1c671fef96d1159bcd6 DRTVWR-202 573e863be2f26d3687161def4b9fea9b7038dda8 3.4.0-beta5 +34dbbe2b00afe90352d3acf8290eb10ab90d1c8b oz-build-test-tag +6ee71714935ffcd159db3d4f5800c1929aac54e1 DRTVWR-205 +7b22c612fc756e0ea63b10b163e81d107f85dbf8 DRTVWR-206 8c9085066c78ed5f6c9379dc054c82a6fcdb1851 DRTVWR-207 351eea5f9dc192fc5ddea3b02958de97677a0a12 3.3.4-release3 af7b28e75bd5a629cd9e0dc46fb3f1757626f493 DRTVWR-212 @@ -309,6 +319,7 @@ ceed0b65a69f1eac20d523e0203320a32f9a3f3c DRTVWR-215 97977c67245f52db20eb15f1918cc0f24778cabc 3.4.0-release 5adb2b8f96c3cac88ad7c7d996d707f1b29df336 3.4.1-beta1 b3f74858a1c8720c82d0978f3877a3fc8ba459ec 3.4.1-beta1a +b61afe175b829c149d369524a4e974dfda99facf DRTVWR-219 2b779f233ee6f38c89cb921650c773a96e63da92 DRTVWR-220 0b9d95f4bfb6867cbf56eaec51633b0da2f1262d DRTVWR-221 e6e553761829dc0270eaaa712b7cb0622535b076 3.4.1-beta3 @@ -333,36 +344,31 @@ baf97f06ae17223614c5e31aa42e71d87cff07fe DRTVWR-236 b2f21e3442542283a80e7eaebae9f833e5a927b6 DRTVWR-237 3f9be82de642d468c5fc272cb9d96b46b5498402 3.4.1-beta12 e59ffd3fe0838ae6b09b242a6e9df71761b88f41 3.4.1-release -81f6b745ef27f5915fd07f988fdec9944f2bb73e DRTVWR-186 -cc953f00956be52cc64c30637bbeec310eea603f DRTVWR-181 -c04e68e1b0034fd0a20815ae24c77e5f8428e822 DRTVWR-188 -4b2c52aecb7a75de31dbb12d9f5b9a251d8707be DRTVWR-191 -78ca0bbf43a92e8914d4cfa87d69a6717ef7d4cf DRTVWR-194 -248f4acd92a706c79e842bc83d80baa7369c0c2e DRTVWR-203 -de3be913f68813a9bac7d1c671fef96d1159bcd6 DRTVWR-202 -34dbbe2b00afe90352d3acf8290eb10ab90d1c8b oz-build-test-tag -6ee71714935ffcd159db3d4f5800c1929aac54e1 DRTVWR-205 -7b22c612fc756e0ea63b10b163e81d107f85dbf8 DRTVWR-206 -b61afe175b829c149d369524a4e974dfda99facf DRTVWR-219 32896d5e920ca9a29256ff3b747c2e99752aa5ae DRTVWR-217 704bbae7b182a1f2811a47a054e680522966f54a 3.4.2-beta1 +d799593b53ed733862e9a13871e318e886469377 DRTVWR-208 +e497dcde7a3653e384eb223a8a460030e89c294c DRTVWR-223 288539fc0408ed4b69a99665de33bbbc2c3c08fe DRTVWR-216 e664473c16df1d82ffaff382e7b3e023da202d52 3.4.2-beta2 +93ab02d83f51e30a3cabad98aff89601befd9413 DRTVWR-240 0891d7a773a31397dcad48be3fa66531d567a821 DRTVWR-242 710785535362b3cb801b6a3dc4703be3373bd0cd 3.4.2-beta3 -e9a5886052433d5db9e504ffaca10890f9932979 DRTVWR-243 -73b84b9864dc650fe7c8fc9f52361450f0849004 3.4.2-beta4 -16310aabccf315870f7cc9bf966926c0ad6954fa 3.4.2-release -d799593b53ed733862e9a13871e318e886469377 DRTVWR-208 -e497dcde7a3653e384eb223a8a460030e89c294c DRTVWR-223 -93ab02d83f51e30a3cabad98aff89601befd9413 DRTVWR-240 2aa72e3372a83dece4df9cf72fb1e7c34f90b5e3 DRTVWR-209 f7bedce18ad52283e6072814db23318907261487 DRTVWR-238 7b64c96fbcadf360bd2feaae19d330166b70877c DRTVWR-210 +e9a5886052433d5db9e504ffaca10890f9932979 DRTVWR-243 +73b84b9864dc650fe7c8fc9f52361450f0849004 3.4.2-beta4 +16310aabccf315870f7cc9bf966926c0ad6954fa 3.4.2-release 5e4e4128b256525bafc07a62e35ae8527aaa9c9d DRTVWR-241 f1d3b3fcab28ed9ea532bf50db0ba96f5c8cc8e9 DRTVWR-232 4918b150e75df6b516fb6c2616d32043fa6b4cac DRTVWR-245 94ab2b49458ab372a95d2d6949fdf574f413068d 3.4.3-beta1 +4c3460cb1fb7c6da9965e09c734d282a8e9c81f0 DRTVWR-229 +f4481df42f9a4a92bf475a80f0c51d1a4bbdfd59 DRTVWR-246 +39c5204b6e800983a41ccac8ad6dc993120197c6 DRTVWR-247 +7c7d57d393e8ae7b61623279de06eb4a62ccae6a DRTVWR-249 +f72b50ef168c159d6e79e97aa2bcafaf8577ab99 DRTVWR-230 +b418be80903520c492e1173f3afbc4021cad5d07 DRTVWR-255 965b9a35e260c0f53be1a25f0db7abc8a67eaf47 DRTVWR-252 bb10adc4f76cf0067fca7075146f00cdc0740e9d DRTVWR-251 ab0aa2f6ba22b52fed30a2337197f589156edc75 DRTVWR-253 @@ -371,31 +377,25 @@ ab0aa2f6ba22b52fed30a2337197f589156edc75 DRTVWR-253 44e764a6ac9e672a4f3bce821a4b6a218590c374 DRTVWR-258 c23d734065ed593b2413385aecd8366d8e0ee96b DRTVWR-257 452ce96d4046dc05a3ecaecc203e2cc8ddd72e76 DRTVWR-259 +9aa1aa9f1fe13c194695a0b8f0af298296241dc2 DRTVWR-260 daca610d840625b5bebb966a57cb49581852c417 DRTVWR-265 9afbdc4e24cc04feacfb2b7a10b78a64f780901a DRTVWR-266 73280db02501f5ad041fc18b1eba68e73a81996c DRTVWR-267 870e2d79e0063fda87187f17bbc2747766733194 3.4.3-beta3 0a2ca6546b499239afeb66d17b2fadbcdbe36ab1 3.4.3-release -4c3460cb1fb7c6da9965e09c734d282a8e9c81f0 DRTVWR-229 -f4481df42f9a4a92bf475a80f0c51d1a4bbdfd59 DRTVWR-246 -39c5204b6e800983a41ccac8ad6dc993120197c6 DRTVWR-247 -7c7d57d393e8ae7b61623279de06eb4a62ccae6a DRTVWR-249 -f72b50ef168c159d6e79e97aa2bcafaf8577ab99 DRTVWR-230 -b418be80903520c492e1173f3afbc4021cad5d07 DRTVWR-255 -9aa1aa9f1fe13c194695a0b8f0af298296241dc2 DRTVWR-260 84fbaf2d4141bd161731430e760949dc787ca206 DRTVWR-244 083d2d36b5bb1c54fc3dd7caac0e7ac381a9cef0 3.4.4-beta1 +391a8c74cec7275c5d26c85ad108d4782a3e3dd9 DRTVWR-268 b634dec987c16e8c9c938e11e52591d9ead8fa9b DRTVWR-270 cd39255bd23330fd30c04105f2811e941d8524fe 3.4.4-beta2 2c4011bbc2b15b82198fd8b51f3a9fe765a08c4d DRTVWR-271 2f8a3ef687bc55828abcb17ac1ad7cde70536d7e 3.4.4-beta3 35cfd4cf5b895fa776592f2e630e330be7f0604e DRTVWR-273 +a36f1f354b02aa6e448ca13685de167d0a0a3d03 DRTVWR-272 +37dba00ad820de3a808d4039396b162a9c275b3e DRTVWR-269 c374035d459af3c03dea2dd90880dfc25de64706 DRTVWR-275 05d9f1dd7a954069af2a33abedb7713fa36a04cb 3.4.4-beta4 e1bb1ae7d8b12faeb37933a737c199cc9b9f89cc 3.4.4-release -391a8c74cec7275c5d26c85ad108d4782a3e3dd9 DRTVWR-268 -a36f1f354b02aa6e448ca13685de167d0a0a3d03 DRTVWR-272 -37dba00ad820de3a808d4039396b162a9c275b3e DRTVWR-269 7c6dfdc1b7a2ce0d8e3a8f3ce3058547ea065c0f DRTVWR-250 b9ff9730daa53a541925300cbd02bb14575a5705 DRTVWR-277 af6b711a97073431953b55ee808aaa09900c27e5 DRTVWR-276 @@ -405,6 +405,8 @@ c296133849d1f103c0e2abc41e6599daed00b67b DRTVWR-280 5df4802bec93c8d0a509946d826bb4c50c5442ec DRTVWR-281 7c1c33ba4cfd2d15ca51cc1ac440eca551331a4a DRTVWR-283 6b9c7dbebef793230d64e1b452577c8b142d4143 3.4.5-beta2 +37947e4f771f001b551581bf7cd0051c3153beed DRTVWR-282 +6482cceb91cda68b799f3e6cdc66d33bf123547a DRTVWR-284 ccf991e02dc2f63fb646324230d54832683f4a9b DRTVWR-286 2d849850558a5a0324b398d1c102d30bcbdfb88f DRTVWR-287 e06898df8644fe567bee94f817d03abc1c380993 3.4.5-beta3 @@ -417,8 +419,6 @@ b23419a2748483c98f3b84b630468a21c88feba5 DRTVWR-292 0a5d409161ef2a89b28c9a741051dd2dedc707d6 DRTVWR-297 852b69ef0b5fe6b13b69cc2217282cc64de6afab 3.4.5-beta5 a49c715243a36a8a380504d14cb7416b3039c956 3.4.5-release -37947e4f771f001b551581bf7cd0051c3153beed DRTVWR-282 -6482cceb91cda68b799f3e6cdc66d33bf123547a DRTVWR-284 092a9effbedd1a0276fa5ced520992ce00f96fbf CHUI-PV-0 279ef1dfc9b749a6cc499cf190fec0c090b6d682 DRTVWR-288 9b19edaf1d8ddf435f60fbbb444dd25db8f63953 3.5.0-beta1 @@ -435,3 +435,7 @@ fd6b510e83f56830e45670c428653134899d3e25 DRTVWR-305 5c6098fd17d40ee3a38ca6b64f6be9db7f61f0a8 3.5.0-beta7 adc360e6bf21390d2665380951d85937cd29a604 3.5.0-release 1ada73295ed0eaa4a772ef079c29f57069342c32 DRTVWR-310 +20cdf370f5c8be6193bef6fb3a81cc3f81275191 3.5.1-beta1 +2319904200de367646b9a9442239a38d52c1eeb5 DRTVWR-313 +9d8726eca785acad694564516f16dd639faf45c0 3.5.1-beta2 +78a8fe6abf331944d6b6bb1ce1024a6bc08141f4 DRTVWR-298 diff --git a/autobuild.xml b/autobuild.xml index 80a44ec75d..ba6b76e7b2 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -483,14 +483,14 @@ </map> </map> </map> - <key>fmod</key> + <key>fmodex</key> <map> <key>license</key> - <string>fmod</string> + <string>fmodex</string> <key>license_file</key> - <string>LICENSES/fmod.txt</string> + <string>LICENSES/fmodex.txt</string> <key>name</key> - <string>fmod</string> + <string>fmodex</string> <key>platforms</key> <map> <key>darwin</key> @@ -498,9 +498,9 @@ <key>archive</key> <map> <key>hash</key> - <string>61ead113e6479452e6b690c84b4e9d30</string> + <string>89a3df89da75444877cf3197416fed67</string> <key>url</key> - <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/3p-fmod-private/rev/221852/arch/Darwin/installer/fmod-3.75-darwin-20110222.tar.bz2</string> + <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/3p-fmodex-private/rev/270029/arch/Darwin/installer/fmodex-4.44-darwin-20130205.tar.bz2</string> </map> <key>name</key> <string>darwin</string> @@ -510,9 +510,9 @@ <key>archive</key> <map> <key>hash</key> - <string>0c61d643db54d2e5999be8254569d8b3</string> + <string>fd787931f49ece9bf99f4d1d1596f04b</string> <key>url</key> - <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/3p-fmod-private/rev/221852/arch/Linux/installer/fmod-3.75-linux-20110223.tar.bz2</string> + <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/3p-fmodex-private/rev/269984/arch/Linux/installer/fmodex-4.44-linux-20130205.tar.bz2</string> </map> <key>name</key> <string>linux</string> @@ -522,9 +522,9 @@ <key>archive</key> <map> <key>hash</key> - <string>d9a9a6ad86895353bcd63374a4c1a91d</string> + <string>9e0f62be63e74af18f670f864cac93da</string> <key>url</key> - <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/3p-fmod-private/rev/221852/arch/CYGWIN/installer/fmod-3.75-windows-20110222.tar.bz2</string> + <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/3p-fmodex-private/rev/270026/arch/CYGWIN/installer/fmodex-4.44-windows-20130205.tar.bz2</string> </map> <key>name</key> <string>windows</string> @@ -2531,7 +2531,6 @@ <string>"Visual Studio 10"</string> <string>-DUNATTENDED:BOOL=ON</string> <string>-DUSE_KDU=FALSE</string> - <string>-DFMOD=FALSE</string> </array> </map> <key>name</key> @@ -2620,7 +2619,6 @@ <string>-DUNATTENDED:BOOL=ON</string> <string>-DINSTALL_PROPRIETARY=FALSE</string> <string>-DUSE_KDU=FALSE</string> - <string>-DFMOD=FALSE</string> </array> </map> <key>name</key> @@ -2708,7 +2706,6 @@ <string>-DUNATTENDED:BOOL=ON</string> <string>-DINSTALL_PROPRIETARY=FALSE</string> <string>-DUSE_KDU=FALSE</string> - <string>-DFMOD=FALSE</string> </array> </map> <key>name</key> diff --git a/doc/contributions.txt b/doc/contributions.txt index 32dd3c1a2e..9f2f51f248 100644 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -299,6 +299,7 @@ ChickyBabes Zuzu Christopher Organiser Ciaran Laval Cinder Roxley + BUG-2326 STORM-1703 Clara Young Coaldust Numbers @@ -1067,10 +1068,12 @@ Sheet Spotter Shnurui Troughton Shyotl Kuhr MAINT-1138 + MAINT-2334 Siana Gearz STORM-960 STORM-1088 MAINT-1138 + MAINT-2334 sicarius Thorne Sicarius Toxx SignpostMarv Martin @@ -1088,6 +1091,8 @@ SLB Wirefly Slee Mayo SEC-1075 snowy Sidran +Sovereign Engineer + MAINT-2334 SpacedOut Frye VWR-34 VWR-45 @@ -1341,3 +1346,4 @@ Zoex Flanagan + diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt index a21fa90950..10a23ea068 100644 --- a/indra/cmake/CMakeLists.txt +++ b/indra/cmake/CMakeLists.txt @@ -24,12 +24,11 @@ set(cmake_SOURCE_FILES DragDrop.cmake EXPAT.cmake ExamplePlugin.cmake - FMOD.cmake FindAPR.cmake FindAutobuild.cmake FindBerkeleyDB.cmake FindCARes.cmake - FindFMOD.cmake + FindFMODEX.cmake FindGLH.cmake FindGoogleBreakpad.cmake FindGooglePerfTools.cmake @@ -40,6 +39,7 @@ set(cmake_SOURCE_FILES FindSCP.cmake FindXmlRpcEpi.cmake FindZLIB.cmake + FMODEX.cmake FreeType.cmake GLEXT.cmake GLH.cmake diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake index 338da4743e..ef529c32d3 100644 --- a/indra/cmake/Copy3rdPartyLibs.cmake +++ b/indra/cmake/Copy3rdPartyLibs.cmake @@ -62,10 +62,9 @@ if(WINDOWS) set(release_files ${release_files} libtcmalloc_minimal.dll) endif(USE_TCMALLOC) - if (FMOD) - set(debug_files ${debug_files} fmod.dll) - set(release_files ${release_files} fmod.dll) - endif (FMOD) + if (FMODEX) + set(release_files ${release_files} fmodex.dll) + endif (FMODEX) #******************************* # Copy MS C runtime dlls, required for packaging. @@ -222,8 +221,10 @@ elseif(DARWIN) libcollada14dom.dylib ) - # fmod is statically linked on darwin - set(fmod_files "") + if (FMODEX) + set(debug_files ${debug_files} libfmodexL.dylib) + set(release_files ${release_files} libfmodex.dylib) + endif (FMODEX) elseif(LINUX) # linux is weird, multiple side by side configurations aren't supported @@ -288,9 +289,9 @@ elseif(LINUX) set(release_files ${release_files} "libtcmalloc_minimal.so") endif (USE_TCMALLOC) - if (FMOD) - set(release_files ${release_files} "libfmod-3.75.so") - endif (FMOD) + if (FMODEX) + set(release_file ${release_files} "libfmodex.so") + endif (FMODEX) else(WINDOWS) message(STATUS "WARNING: unrecognized platform for staging 3rd party libs, skipping...") @@ -305,8 +306,6 @@ else(WINDOWS) set(release_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-linux/lib/release") set(release_files "") - set(fmod_files "") - set(debug_llkdu_src "") set(debug_llkdu_dst "") set(release_llkdu_src "") @@ -369,30 +368,6 @@ copy_if_different( ) set(third_party_targets ${third_party_targets} ${out_targets}) -if (FMOD_SDK_DIR) - copy_if_different( - ${FMOD_SDK_DIR} - "${CMAKE_CURRENT_BINARY_DIR}/Debug" - out_targets - ${fmod_files} - ) - set(all_targets ${all_targets} ${out_targets}) - copy_if_different( - ${FMOD_SDK_DIR} - "${CMAKE_CURRENT_BINARY_DIR}/Release" - out_targets - ${fmod_files} - ) - set(all_targets ${all_targets} ${out_targets}) - copy_if_different( - ${FMOD_SDK_DIR} - "${CMAKE_CURRENT_BINARY_DIR}/RelWithDbgInfo" - out_targets - ${fmod_files} - ) - set(all_targets ${all_targets} ${out_targets}) -endif (FMOD_SDK_DIR) - if(NOT STANDALONE) add_custom_target( stage_third_party_libs ALL diff --git a/indra/cmake/FMOD.cmake b/indra/cmake/FMOD.cmake deleted file mode 100644 index 3586c1160a..0000000000 --- a/indra/cmake/FMOD.cmake +++ /dev/null @@ -1,39 +0,0 @@ -# -*- cmake -*- - -# FMOD can be set when launching the make using the argument -DFMOD:BOOL=ON -# When building using proprietary binaries though (i.e. having access to LL private servers), -# we always build with FMOD. -# Open source devs should use the -DFMOD:BOOL=ON then if they want to build with FMOD, whether -# they are using STANDALONE or not. -if (INSTALL_PROPRIETARY) - set(FMOD ON CACHE BOOL "Use FMOD sound library.") -endif (INSTALL_PROPRIETARY) - -if (FMOD) - if (STANDALONE) - # In that case, we use the version of the library installed on the system - set(FMOD_FIND_REQUIRED ON) - include(FindFMOD) - else (STANDALONE) - if (FMOD_LIBRARY AND FMOD_INCLUDE_DIR) - # If the path have been specified in the arguments, use that - set(FMOD_LIBRARIES ${FMOD_LIBRARY}) - MESSAGE(STATUS "Using FMOD path: ${FMOD_LIBRARIES}, ${FMOD_INCLUDE_DIR}") - else (FMOD_LIBRARY AND FMOD_INCLUDE_DIR) - # If not, we're going to try to get the package listed in autobuild.xml - # Note: if you're not using INSTALL_PROPRIETARY, the package URL should be local (file:/// URL) - # as accessing the private LL location will fail if you don't have the credential - include(Prebuilt) - use_prebuilt_binary(fmod) - if (WINDOWS) - set(FMOD_LIBRARY fmod) - elseif (DARWIN) - set(FMOD_LIBRARY fmod) - elseif (LINUX) - set(FMOD_LIBRARY fmod-3.75) - endif (WINDOWS) - set(FMOD_LIBRARIES ${FMOD_LIBRARY}) - set(FMOD_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include) - endif (FMOD_LIBRARY AND FMOD_INCLUDE_DIR) - endif (STANDALONE) -endif (FMOD) diff --git a/indra/cmake/FMODEX.cmake b/indra/cmake/FMODEX.cmake new file mode 100644 index 0000000000..65bc1cabeb --- /dev/null +++ b/indra/cmake/FMODEX.cmake @@ -0,0 +1,46 @@ +# -*- cmake -*- + +# FMOD can be set when launching the make using the argument -DFMOD:BOOL=ON +# When building using proprietary binaries though (i.e. having access to LL private servers), +# we always build with FMODEX. +# Open source devs should use the -DFMODEX:BOOL=ON then if they want to build with FMOD, whether +# they are using STANDALONE or not. +if (INSTALL_PROPRIETARY) + set(FMODEX ON CACHE BOOL "Using FMOD Ex sound library.") +endif (INSTALL_PROPRIETARY) + +if (FMODEX) + if (STANDALONE) + # In that case, we use the version of the library installed on the system + set(FMODEX_FIND_REQUIRED ON) + include(FindFMODEX) + else (STANDALONE) + if (FMODEX_LIBRARY AND FMODEX_INCLUDE_DIR) + # If the path have been specified in the arguments, use that + set(FMODEX_LIBRARIES ${FMODEX_LIBRARY}) + MESSAGE(STATUS "Using FMODEX path: ${FMODEX_LIBRARIES}, ${FMODEX_INCLUDE_DIR}") + else (FMODEX_LIBRARY AND FMODEX_INCLUDE_DIR) + # If not, we're going to try to get the package listed in autobuild.xml + # Note: if you're not using INSTALL_PROPRIETARY, the package URL should be local (file:/// URL) + # as accessing the private LL location will fail if you don't have the credential + include(Prebuilt) + use_prebuilt_binary(fmodex) + if (WINDOWS) + set(FMODEX_LIBRARY + debug fmodexL_vc + optimized fmodex_vc) + elseif (DARWIN) + set(FMODEX_LIBRARY + debug fmodexL + optimized fmodex) + elseif (LINUX) + set(FMODEX_LIBRARY + debug fmodexL + optimized fmodex) + endif (WINDOWS) + set(FMODEX_LIBRARIES ${FMODEX_LIBRARY}) + set(FMODEX_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/fmodex) + endif (FMODEX_LIBRARY AND FMODEX_INCLUDE_DIR) + endif (STANDALONE) +endif (FMODEX) + diff --git a/indra/cmake/FindFMOD.cmake b/indra/cmake/FindFMOD.cmake deleted file mode 100644 index 1ebbc8c96e..0000000000 --- a/indra/cmake/FindFMOD.cmake +++ /dev/null @@ -1,44 +0,0 @@ -# -*- cmake -*- - -# - Find FMOD -# Find the FMOD includes and library -# This module defines -# FMOD_INCLUDE_DIR, where to find fmod.h and fmod_errors.h -# FMOD_LIBRARIES, the libraries needed to use FMOD. -# FMOD, If false, do not try to use FMOD. -# also defined, but not for general use are -# FMOD_LIBRARY, where to find the FMOD library. - -FIND_PATH(FMOD_INCLUDE_DIR fmod.h PATH_SUFFIXES fmod) - -SET(FMOD_NAMES ${FMOD_NAMES} fmod fmodvc fmodex fmod-3.75) -FIND_LIBRARY(FMOD_LIBRARY - NAMES ${FMOD_NAMES} - PATH_SUFFIXES fmod - ) - -IF (FMOD_LIBRARY AND FMOD_INCLUDE_DIR) - SET(FMOD_LIBRARIES ${FMOD_LIBRARY}) - SET(FMOD_FOUND "YES") -ELSE (FMOD_LIBRARY AND FMOD_INCLUDE_DIR) - SET(FMOD_FOUND "NO") -ENDIF (FMOD_LIBRARY AND FMOD_INCLUDE_DIR) - -IF (FMOD_FOUND) - IF (NOT FMOD_FIND_QUIETLY) - MESSAGE(STATUS "Found FMOD: ${FMOD_LIBRARIES}") - ENDIF (NOT FMOD_FIND_QUIETLY) -ELSE (FMOD_FOUND) - IF (FMOD_FIND_REQUIRED) - MESSAGE(FATAL_ERROR "Could not find FMOD library") - ENDIF (FMOD_FIND_REQUIRED) -ENDIF (FMOD_FOUND) - -# Deprecated declarations. -SET (NATIVE_FMOD_INCLUDE_PATH ${FMOD_INCLUDE_DIR} ) -GET_FILENAME_COMPONENT (NATIVE_FMOD_LIB_PATH ${FMOD_LIBRARY} PATH) - -MARK_AS_ADVANCED( - FMOD_LIBRARY - FMOD_INCLUDE_DIR - ) diff --git a/indra/cmake/FindFMODEX.cmake b/indra/cmake/FindFMODEX.cmake new file mode 100644 index 0000000000..b621727c0e --- /dev/null +++ b/indra/cmake/FindFMODEX.cmake @@ -0,0 +1,65 @@ +# -*- cmake -*- + +# - Find FMODEX +# Find the FMODEX includes and library +# This module defines +# FMODEX_INCLUDE_DIR, where to find fmod.h and fmod_errors.h +# FMODEX_LIBRARIES, the libraries needed to use FMODEX. +# FMODEX, If false, do not try to use FMODEX. +# also defined, but not for general use are +# FMODEX_LIBRARY, where to find the FMODEX library. + +FIND_PATH(FMODEX_INCLUDE_DIR fmod.h PATH_SUFFIXES fmod) + +SET(FMODEX_NAMES ${FMODEX_NAMES} fmodex fmodvc fmodexL_vc) +FIND_LIBRARY(FMODEX_LIBRARY + NAMES ${FMODEX_NAMES} + PATH_SUFFIXES fmodex + ) + +IF (FMODEX_SDK_DIR OR WINDOWS) + if(WINDOWS) + set(FMODEX_SDK_DIR "$ENV{PROGRAMFILES}/FMOD SoundSystem/FMOD Programmers API Windows" CACHE PATH "Path to FMODEX") + STRING(REGEX REPLACE "\\\\" "/" FMODEX_SDK_DIR ${FMODEX_SDK_DIR}) + endif(WINDOWS) + find_library(FMODEX_LIBRARY + fmodex_vc fmodexL_vc + PATHS + ${FMODEX_SDK_DIR}/api/lib + ${FMODEX_SDK_DIR}/api + ${FMODEX_SDK_DIR} + ) + find_path(FMODEX_INCLUDE_DIR fmod.h + ${FMODEX_SDK_DIR}/api/inc + ${FMODEX_SDK_DIR}/api + ${FMODEX_SDK_DIR} + ) + find_path(FMODEX_INCLUDE_DIR fmod.h + ${FMODEX_SDK_DIR}/api/inc + ${FMODEX_SDK_DIR}/api + ${FMODEX_SDK_DIR} + ) + IF (FMODEX_LIBRARY AND FMODEX_INCLUDE_DIR) + SET(FMODEX_LIBRARIES ${FMODEX_LIBRARY}) + SET(FMODEX_FOUND "YES") + endif (FMODEX_LIBRARY AND FMODEX_INCLUDE_DIR) +ENDIF (FMODEX_SDK_DIR OR WINDOWS) + +IF (FMODEX_FOUND) + IF (NOT FMODEX_FIND_QUIETLY) + MESSAGE(STATUS "Found FMODEX: ${FMODEX_LIBRARIES}") + ENDIF (NOT FMODEX_FIND_QUIETLY) +ELSE (FMODEX_FOUND) + IF (FMODEX_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "Could not find FMODEX library") + ENDIF (FMODEX_FIND_REQUIRED) +ENDIF (FMODEX_FOUND) + +# Deprecated declarations. +SET (NATIVE_FMODEX_INCLUDE_PATH ${FMODEX_INCLUDE_DIR} ) +GET_FILENAME_COMPONENT (NATIVE_FMODEX_LIB_PATH ${FMODEX_LIBRARY} PATH) + +MARK_AS_ADVANCED( + FMODEX_LIBRARY + FMODEX_INCLUDE_DIR + ) diff --git a/indra/llaudio/CMakeLists.txt b/indra/llaudio/CMakeLists.txt index 24d2531106..1b2bdb9888 100644 --- a/indra/llaudio/CMakeLists.txt +++ b/indra/llaudio/CMakeLists.txt @@ -5,7 +5,7 @@ project(llaudio) include(00-Common) include(Audio) include(LLAudio) -include(FMOD) +include(FMODEX) include(OPENAL) include(LLCommon) include(LLMath) @@ -24,7 +24,6 @@ include_directories( ${VORBIS_INCLUDE_DIRS} ${OPENAL_LIB_INCLUDE_DIRS} ${FREEAULT_LIB_INCLUDE_DIRS} - ${FMOD_INCLUDE_DIR} ) set(llaudio_SOURCE_FILES @@ -44,29 +43,22 @@ set(llaudio_HEADER_FILES llwindgen.h ) -if (FMOD) +if (FMODEX) include_directories( - ${FMOD_INCLUDE_DIR} + ${FMODEX_INCLUDE_DIR} ) - list(APPEND llaudio_SOURCE_FILES - llaudioengine_fmod.cpp - lllistener_fmod.cpp - llstreamingaudio_fmod.cpp + llaudioengine_fmodex.cpp + lllistener_fmodex.cpp + llstreamingaudio_fmodex.cpp ) list(APPEND llaudio_HEADER_FILES - llaudioengine_fmod.h - lllistener_fmod.h - llstreamingaudio_fmod.h + llaudioengine_fmodex.h + lllistener_fmodex.h + llstreamingaudio_fmodex.h ) - - if (LINUX OR DARWIN) - set_source_files_properties(llaudioengine_fmod.cpp - llstreamingaudio_fmod.cpp - COMPILE_FLAGS -Wno-write-strings) - endif (LINUX OR DARWIN) -endif (FMOD) +endif (FMODEX) if (OPENAL) list(APPEND llaudio_SOURCE_FILES diff --git a/indra/llaudio/llaudioengine.h b/indra/llaudio/llaudioengine.h index 99b96c3c38..da1629a1db 100644 --- a/indra/llaudio/llaudioengine.h +++ b/indra/llaudio/llaudioengine.h @@ -42,7 +42,6 @@ #include "lllistener.h" const F32 LL_WIND_UPDATE_INTERVAL = 0.1f; -const F32 LL_ROLLOFF_MULTIPLIER_UNDER_WATER = 5.f; // How much sounds are weaker under water const F32 LL_WIND_UNDERWATER_CENTER_FREQ = 20.f; const F32 ATTACHED_OBJECT_TIMEOUT = 5.0f; diff --git a/indra/llaudio/llaudioengine_fmod.cpp b/indra/llaudio/llaudioengine_fmod.cpp deleted file mode 100644 index a40de9fa68..0000000000 --- a/indra/llaudio/llaudioengine_fmod.cpp +++ /dev/null @@ -1,781 +0,0 @@ -/** - * @file audioengine_fmod.cpp - * @brief Implementation of LLAudioEngine class abstracting the audio support as a FMOD 3D implementation - * - * $LicenseInfo:firstyear=2002&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$ - */ - -#include "linden_common.h" - -#include "llstreamingaudio.h" -#include "llstreamingaudio_fmod.h" - -#include "llaudioengine_fmod.h" -#include "lllistener_fmod.h" - -#include "llerror.h" -#include "llmath.h" -#include "llrand.h" - -#include "fmod.h" -#include "fmod_errors.h" -#include "lldir.h" -#include "llapr.h" - -#include "sound_ids.h" - - -extern "C" { - void * F_CALLBACKAPI windCallback(void *originalbuffer, void *newbuffer, int length, void* userdata); -} - - -LLAudioEngine_FMOD::LLAudioEngine_FMOD() -{ - mInited = false; - mWindGen = NULL; - mWindDSP = NULL; -} - - -LLAudioEngine_FMOD::~LLAudioEngine_FMOD() -{ -} - - -bool LLAudioEngine_FMOD::init(const S32 num_channels, void* userdata) -{ - LLAudioEngine::init(num_channels, userdata); - - // Reserve one extra channel for the http stream. - if (!FSOUND_SetMinHardwareChannels(num_channels + 1)) - { - LL_WARNS("AppInit") << "FMOD::init[0](), error: " << FMOD_ErrorString(FSOUND_GetError()) << LL_ENDL; - } - - LL_DEBUGS("AppInit") << "LLAudioEngine_FMOD::init() initializing FMOD" << LL_ENDL; - - F32 version = FSOUND_GetVersion(); - if (version < FMOD_VERSION) - { - LL_WARNS("AppInit") << "Error : You are using the wrong FMOD version (" << version - << ")! You should be using FMOD " << FMOD_VERSION << LL_ENDL; - //return false; - } - - U32 fmod_flags = 0x0; - -#if LL_WINDOWS - // Windows needs to know which window is frontmost. - // This must be called before FSOUND_Init() per the FMOD docs. - // This could be used to let FMOD handle muting when we lose focus, - // but we don't actually want to do that because we want to distinguish - // between minimized and not-focused states. - if (!FSOUND_SetHWND(userdata)) - { - LL_WARNS("AppInit") << "Error setting FMOD window: " - << FMOD_ErrorString(FSOUND_GetError()) << LL_ENDL; - return false; - } - // Play audio when we don't have focus. - // (For example, IM client on top of us.) - // This means we also try to play audio when minimized, - // so we manually handle muting in that case. JC - fmod_flags |= FSOUND_INIT_GLOBALFOCUS; -#endif - -#if LL_LINUX - // initialize the FMOD engine - - // This is a hack to use only FMOD's basic FPU mixer - // when the LL_VALGRIND environmental variable is set, - // otherwise valgrind will fall over on FMOD's MMX detection - if (getenv("LL_VALGRIND")) /*Flawfinder: ignore*/ - { - LL_INFOS("AppInit") << "Pacifying valgrind in FMOD init." << LL_ENDL; - FSOUND_SetMixer(FSOUND_MIXER_QUALITY_FPU); - } - - // If we don't set an output method, Linux FMOD always - // decides on OSS and fails otherwise. So we'll manually - // try ESD, then OSS, then ALSA. - // Why this order? See SL-13250, but in short, OSS emulated - // on top of ALSA is ironically more reliable than raw ALSA. - // Ack, and ESD has more reliable failure modes - but has worse - // latency - than all of them, so wins for now. - bool audio_ok = false; - - if (!audio_ok) - { - if (NULL == getenv("LL_BAD_FMOD_ESD")) /*Flawfinder: ignore*/ - { - LL_DEBUGS("AppInit") << "Trying ESD audio output..." << LL_ENDL; - if(FSOUND_SetOutput(FSOUND_OUTPUT_ESD) && - FSOUND_Init(44100, num_channels, fmod_flags)) - { - LL_DEBUGS("AppInit") << "ESD audio output initialized OKAY" - << LL_ENDL; - audio_ok = true; - } else { - LL_WARNS("AppInit") << "ESD audio output FAILED to initialize: " - << FMOD_ErrorString(FSOUND_GetError()) << LL_ENDL; - } - } else { - LL_DEBUGS("AppInit") << "ESD audio output SKIPPED" << LL_ENDL; - } - } - if (!audio_ok) - { - if (NULL == getenv("LL_BAD_FMOD_OSS")) /*Flawfinder: ignore*/ - { - LL_DEBUGS("AppInit") << "Trying OSS audio output..." << LL_ENDL; - if(FSOUND_SetOutput(FSOUND_OUTPUT_OSS) && - FSOUND_Init(44100, num_channels, fmod_flags)) - { - LL_DEBUGS("AppInit") << "OSS audio output initialized OKAY" << LL_ENDL; - audio_ok = true; - } else { - LL_WARNS("AppInit") << "OSS audio output FAILED to initialize: " - << FMOD_ErrorString(FSOUND_GetError()) << LL_ENDL; - } - } else { - LL_DEBUGS("AppInit") << "OSS audio output SKIPPED" << LL_ENDL; - } - } - if (!audio_ok) - { - if (NULL == getenv("LL_BAD_FMOD_ALSA")) /*Flawfinder: ignore*/ - { - LL_DEBUGS("AppInit") << "Trying ALSA audio output..." << LL_ENDL; - if(FSOUND_SetOutput(FSOUND_OUTPUT_ALSA) && - FSOUND_Init(44100, num_channels, fmod_flags)) - { - LL_DEBUGS("AppInit") << "ALSA audio output initialized OKAY" << LL_ENDL; - audio_ok = true; - } else { - LL_WARNS("AppInit") << "ALSA audio output FAILED to initialize: " - << FMOD_ErrorString(FSOUND_GetError()) << LL_ENDL; - } - } else { - LL_DEBUGS("AppInit") << "OSS audio output SKIPPED" << LL_ENDL; - } - } - if (!audio_ok) - { - LL_WARNS("AppInit") << "Overall audio init failure." << LL_ENDL; - return false; - } - - // On Linux, FMOD causes a SIGPIPE for some netstream error - // conditions (an FMOD bug); ignore SIGPIPE so it doesn't crash us. - // NOW FIXED in FMOD 3.x since 2006-10-01. - //signal(SIGPIPE, SIG_IGN); - - // We're interested in logging which output method we - // ended up with, for QA purposes. - switch (FSOUND_GetOutput()) - { - case FSOUND_OUTPUT_NOSOUND: LL_DEBUGS("AppInit") << "Audio output: NoSound" << LL_ENDL; break; - case FSOUND_OUTPUT_OSS: LL_DEBUGS("AppInit") << "Audio output: OSS" << LL_ENDL; break; - case FSOUND_OUTPUT_ESD: LL_DEBUGS("AppInit") << "Audio output: ESD" << LL_ENDL; break; - case FSOUND_OUTPUT_ALSA: LL_DEBUGS("AppInit") << "Audio output: ALSA" << LL_ENDL; break; - default: LL_INFOS("AppInit") << "Audio output: Unknown!" << LL_ENDL; break; - }; - -#else // LL_LINUX - - // initialize the FMOD engine - if (!FSOUND_Init(44100, num_channels, fmod_flags)) - { - LL_WARNS("AppInit") << "Error initializing FMOD: " - << FMOD_ErrorString(FSOUND_GetError()) << LL_ENDL; - return false; - } - -#endif - - // set up our favourite FMOD-native streaming audio implementation if none has already been added - if (!getStreamingAudioImpl()) // no existing implementation added - setStreamingAudioImpl(new LLStreamingAudio_FMOD()); - - LL_DEBUGS("AppInit") << "LLAudioEngine_FMOD::init() FMOD initialized correctly" << LL_ENDL; - - mInited = true; - - return true; -} - - -std::string LLAudioEngine_FMOD::getDriverName(bool verbose) -{ - if (verbose) - { - F32 version = FSOUND_GetVersion(); - return llformat("FMOD version %f", version); - } - else - { - return "FMOD"; - } -} - - -void LLAudioEngine_FMOD::allocateListener(void) -{ - mListenerp = (LLListener *) new LLListener_FMOD(); - if (!mListenerp) - { - llwarns << "Listener creation failed" << llendl; - } -} - - -void LLAudioEngine_FMOD::shutdown() -{ - if (mWindDSP) - { - FSOUND_DSP_SetActive(mWindDSP,false); - FSOUND_DSP_Free(mWindDSP); - } - - stopInternetStream(); - - LLAudioEngine::shutdown(); - - llinfos << "LLAudioEngine_FMOD::shutdown() closing FMOD" << llendl; - FSOUND_Close(); - llinfos << "LLAudioEngine_FMOD::shutdown() done closing FMOD" << llendl; - - delete mListenerp; - mListenerp = NULL; -} - - -LLAudioBuffer * LLAudioEngine_FMOD::createBuffer() -{ - return new LLAudioBufferFMOD(); -} - - -LLAudioChannel * LLAudioEngine_FMOD::createChannel() -{ - return new LLAudioChannelFMOD(); -} - - -bool LLAudioEngine_FMOD::initWind() -{ - if (!mWindGen) - { - bool enable; - - switch (FSOUND_GetMixer()) - { - case FSOUND_MIXER_MMXP5: - case FSOUND_MIXER_MMXP6: - case FSOUND_MIXER_QUALITY_MMXP5: - case FSOUND_MIXER_QUALITY_MMXP6: - enable = (typeid(MIXBUFFERFORMAT) == typeid(S16)); - break; - case FSOUND_MIXER_BLENDMODE: - enable = (typeid(MIXBUFFERFORMAT) == typeid(S32)); - break; - case FSOUND_MIXER_QUALITY_FPU: - enable = (typeid(MIXBUFFERFORMAT) == typeid(F32)); - break; - default: - // FSOUND_GetMixer() does not return a valid mixer type on Darwin - LL_INFOS("AppInit") << "Unknown FMOD mixer type, assuming default" << LL_ENDL; - enable = true; - break; - } - - if (enable) - { - mWindGen = new LLWindGen<MIXBUFFERFORMAT>(FSOUND_GetOutputRate()); - } - else - { - LL_WARNS("AppInit") << "Incompatible FMOD mixer type, wind noise disabled" << LL_ENDL; - } - } - - mNextWindUpdate = 0.0; - - if (mWindGen && !mWindDSP) - { - mWindDSP = FSOUND_DSP_Create(&windCallback, FSOUND_DSP_DEFAULTPRIORITY_CLEARUNIT + 20, mWindGen); - } - if (mWindDSP) - { - FSOUND_DSP_SetActive(mWindDSP, true); - return true; - } - - return false; -} - - -void LLAudioEngine_FMOD::cleanupWind() -{ - if (mWindDSP) - { - FSOUND_DSP_SetActive(mWindDSP, false); - FSOUND_DSP_Free(mWindDSP); - mWindDSP = NULL; - } - - delete mWindGen; - mWindGen = NULL; -} - - -//----------------------------------------------------------------------- -void LLAudioEngine_FMOD::updateWind(LLVector3 wind_vec, F32 camera_height_above_water) -{ - LLVector3 wind_pos; - F64 pitch; - F64 center_freq; - - if (!mEnableWind) - { - return; - } - - if (mWindUpdateTimer.checkExpirationAndReset(LL_WIND_UPDATE_INTERVAL)) - { - - // wind comes in as Linden coordinate (+X = forward, +Y = left, +Z = up) - // need to convert this to the conventional orientation DS3D and OpenAL use - // where +X = right, +Y = up, +Z = backwards - - wind_vec.setVec(-wind_vec.mV[1], wind_vec.mV[2], -wind_vec.mV[0]); - - // cerr << "Wind update" << endl; - - pitch = 1.0 + mapWindVecToPitch(wind_vec); - center_freq = 80.0 * pow(pitch,2.5*(mapWindVecToGain(wind_vec)+1.0)); - - mWindGen->mTargetFreq = (F32)center_freq; - mWindGen->mTargetGain = (F32)mapWindVecToGain(wind_vec) * mMaxWindGain; - mWindGen->mTargetPanGainR = (F32)mapWindVecToPan(wind_vec); - } -} - -/* -//----------------------------------------------------------------------- -void LLAudioEngine_FMOD::setSourceMinDistance(U16 source_num, F64 distance) -{ - if (!mInited) - { - return; - } - if (mBuffer[source_num]) - { - mMinDistance[source_num] = (F32) distance; - if (!FSOUND_Sample_SetMinMaxDistance(mBuffer[source_num],mMinDistance[source_num], mMaxDistance[source_num])) - { - llwarns << "FMOD::setSourceMinDistance(" << source_num << "), error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl; - } - } -} - -//----------------------------------------------------------------------- -void LLAudioEngine_FMOD::setSourceMaxDistance(U16 source_num, F64 distance) -{ - if (!mInited) - { - return; - } - if (mBuffer[source_num]) - { - mMaxDistance[source_num] = (F32) distance; - if (!FSOUND_Sample_SetMinMaxDistance(mBuffer[source_num],mMinDistance[source_num], mMaxDistance[source_num])) - { - llwarns << "FMOD::setSourceMaxDistance(" << source_num << "), error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl; - } - } -} - -//----------------------------------------------------------------------- -void LLAudioEngine_FMOD::get3DParams(S32 source_num, S32 *volume, S32 *freq, S32 *inside, S32 *outside, LLVector3 *orient, S32 *out_volume, F32 *min_dist, F32 *max_dist) -{ - *volume = 0; - *freq = 0; - *inside = 0; - *outside = 0; - *orient = LLVector3::zero; - *out_volume = 0; - *min_dist = 0.f; - *max_dist = 0.f; -} - -*/ - - -//----------------------------------------------------------------------- -void LLAudioEngine_FMOD::setInternalGain(F32 gain) -{ - if (!mInited) - { - return; - } - - gain = llclamp( gain, 0.0f, 1.0f ); - FSOUND_SetSFXMasterVolume( llround( 255.0f * gain ) ); - - LLStreamingAudioInterface *saimpl = getStreamingAudioImpl(); - if ( saimpl ) - { - // fmod likes its streaming audio channel gain re-asserted after - // master volume change. - saimpl->setGain(saimpl->getGain()); - } -} - -// -// LLAudioChannelFMOD implementation -// - -LLAudioChannelFMOD::LLAudioChannelFMOD() : LLAudioChannel(), mChannelID(0), mLastSamplePos(0) -{ -} - - -LLAudioChannelFMOD::~LLAudioChannelFMOD() -{ - cleanup(); -} - - -bool LLAudioChannelFMOD::updateBuffer() -{ - if (LLAudioChannel::updateBuffer()) - { - // Base class update returned true, which means that we need to actually - // set up the channel for a different buffer. - - LLAudioBufferFMOD *bufferp = (LLAudioBufferFMOD *)mCurrentSourcep->getCurrentBuffer(); - - // Grab the FMOD sample associated with the buffer - FSOUND_SAMPLE *samplep = bufferp->getSample(); - if (!samplep) - { - // This is bad, there should ALWAYS be a sample associated with a legit - // buffer. - llerrs << "No FMOD sample!" << llendl; - return false; - } - - - // Actually play the sound. Start it off paused so we can do all the necessary - // setup. - mChannelID = FSOUND_PlaySoundEx(FSOUND_FREE, samplep, FSOUND_DSP_GetSFXUnit(), true); - - //llinfos << "Setting up channel " << std::hex << mChannelID << std::dec << llendl; - } - - // If we have a source for the channel, we need to update its gain. - if (mCurrentSourcep) - { - // SJB: warnings can spam and hurt framerate, disabling - if (!FSOUND_SetVolume(mChannelID, llround(getSecondaryGain() * mCurrentSourcep->getGain() * 255.0f))) - { -// llwarns << "LLAudioChannelFMOD::updateBuffer error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl; - } - - if (!FSOUND_SetLoopMode(mChannelID, mCurrentSourcep->isLoop() ? FSOUND_LOOP_NORMAL : FSOUND_LOOP_OFF)) - { -// llwarns << "Channel " << mChannelID << "Source ID: " << mCurrentSourcep->getID() -// << " at " << mCurrentSourcep->getPositionGlobal() << llendl; -// llwarns << "LLAudioChannelFMOD::updateBuffer error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl; - } - } - - return true; -} - - -void LLAudioChannelFMOD::update3DPosition() -{ - if (!mChannelID) - { - // We're not actually a live channel (i.e., we're not playing back anything) - return; - } - - LLAudioBufferFMOD *bufferp = (LLAudioBufferFMOD *)mCurrentBufferp; - if (!bufferp) - { - // We don't have a buffer associated with us (should really have been picked up - // by the above if. - return; - } - - if (mCurrentSourcep->isAmbient()) - { - // Ambient sound, don't need to do any positional updates. - bufferp->set3DMode(false); - } - else - { - // Localized sound. Update the position and velocity of the sound. - bufferp->set3DMode(true); - - LLVector3 float_pos; - float_pos.setVec(mCurrentSourcep->getPositionGlobal()); - if (!FSOUND_3D_SetAttributes(mChannelID, float_pos.mV, mCurrentSourcep->getVelocity().mV)) - { - LL_DEBUGS("FMOD") << "LLAudioChannelFMOD::update3DPosition error: " << FMOD_ErrorString(FSOUND_GetError()) << LL_ENDL; - } - } -} - - -void LLAudioChannelFMOD::updateLoop() -{ - if (!mChannelID) - { - // May want to clear up the loop/sample counters. - return; - } - - // - // Hack: We keep track of whether we looped or not by seeing when the - // sample position looks like it's going backwards. Not reliable; may - // yield false negatives. - // - U32 cur_pos = FSOUND_GetCurrentPosition(mChannelID); - if (cur_pos < (U32)mLastSamplePos) - { - mLoopedThisFrame = true; - } - mLastSamplePos = cur_pos; -} - - -void LLAudioChannelFMOD::cleanup() -{ - if (!mChannelID) - { - //llinfos << "Aborting cleanup with no channelID." << llendl; - return; - } - - //llinfos << "Cleaning up channel: " << mChannelID << llendl; - if (!FSOUND_StopSound(mChannelID)) - { - LL_DEBUGS("FMOD") << "LLAudioChannelFMOD::cleanup error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl; - } - - mCurrentBufferp = NULL; - mChannelID = 0; -} - - -void LLAudioChannelFMOD::play() -{ - if (!mChannelID) - { - llwarns << "Playing without a channelID, aborting" << llendl; - return; - } - - if (!FSOUND_SetPaused(mChannelID, false)) - { - llwarns << "LLAudioChannelFMOD::play error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl; - } - getSource()->setPlayedOnce(true); -} - - -void LLAudioChannelFMOD::playSynced(LLAudioChannel *channelp) -{ - LLAudioChannelFMOD *fmod_channelp = (LLAudioChannelFMOD*)channelp; - if (!(fmod_channelp->mChannelID && mChannelID)) - { - // Don't have channels allocated to both the master and the slave - return; - } - - U32 position = FSOUND_GetCurrentPosition(fmod_channelp->mChannelID) % mCurrentBufferp->getLength(); - // Try to match the position of our sync master - if (!FSOUND_SetCurrentPosition(mChannelID, position)) - { - llwarns << "LLAudioChannelFMOD::playSynced unable to set current position" << llendl; - } - - // Start us playing - play(); -} - - -bool LLAudioChannelFMOD::isPlaying() -{ - if (!mChannelID) - { - return false; - } - - return FSOUND_IsPlaying(mChannelID) && (!FSOUND_GetPaused(mChannelID)); -} - - - -// -// LLAudioBufferFMOD implementation -// - - -LLAudioBufferFMOD::LLAudioBufferFMOD() -{ - mSamplep = NULL; -} - - -LLAudioBufferFMOD::~LLAudioBufferFMOD() -{ - if (mSamplep) - { - // Clean up the associated FMOD sample if it exists. - FSOUND_Sample_Free(mSamplep); - mSamplep = NULL; - } -} - - -bool LLAudioBufferFMOD::loadWAV(const std::string& filename) -{ - // Try to open a wav file from disk. This will eventually go away, as we don't - // really want to block doing this. - if (filename.empty()) - { - // invalid filename, abort. - return false; - } - - if (!LLAPRFile::isExist(filename, NULL, LL_APR_RPB)) - { - // File not found, abort. - return false; - } - - if (mSamplep) - { - // If there's already something loaded in this buffer, clean it up. - FSOUND_Sample_Free(mSamplep); - mSamplep = NULL; - } - - // Load up the wav file into an fmod sample -#if LL_WINDOWS - // MikeS. - Loading the sound file manually and then handing it over to FMOD, - // since FMOD uses posix IO internally, - // which doesn't work with unicode file paths. - LLFILE* sound_file = LLFile::fopen(filename,"rb"); /* Flawfinder: ignore */ - if (sound_file) - { - fseek(sound_file,0,SEEK_END); - U32 file_length = ftell(sound_file); //Find the length of the file by seeking to the end and getting the offset - size_t read_count; - fseek(sound_file,0,SEEK_SET); //Seek back to the beginning - char* buffer = new char[file_length]; - llassert(buffer); - read_count = fread((void*)buffer,file_length,1,sound_file);//Load it.. - if(ferror(sound_file)==0 && (read_count == 1)){//No read error, and we got 1 chunk of our size... - unsigned int mode_flags = FSOUND_LOOP_NORMAL | FSOUND_LOADMEMORY; - //FSOUND_16BITS | FSOUND_MONO | FSOUND_LOADMEMORY | FSOUND_LOOP_NORMAL; - mSamplep = FSOUND_Sample_Load(FSOUND_UNMANAGED, buffer, mode_flags , 0, file_length); - } - delete[] buffer; - fclose(sound_file); - } -#else - mSamplep = FSOUND_Sample_Load(FSOUND_UNMANAGED, filename.c_str(), FSOUND_LOOP_NORMAL, 0, 0); -#endif - - if (!mSamplep) - { - // We failed to load the file for some reason. - llwarns << "Could not load data '" << filename << "': " - << FMOD_ErrorString(FSOUND_GetError()) << llendl; - - // - // If we EVER want to load wav files provided by end users, we need - // to rethink this! - // - // file is probably corrupt - remove it. - LLFile::remove(filename); - return false; - } - - // Everything went well, return true - return true; -} - - -U32 LLAudioBufferFMOD::getLength() -{ - if (!mSamplep) - { - return 0; - } - - return FSOUND_Sample_GetLength(mSamplep); -} - - -void LLAudioBufferFMOD::set3DMode(bool use3d) -{ - U16 current_mode = FSOUND_Sample_GetMode(mSamplep); - - if (use3d) - { - if (!FSOUND_Sample_SetMode(mSamplep, (current_mode & (~FSOUND_2D)))) - { - llwarns << "LLAudioBufferFMOD::set3DMode error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl; - } - } - else - { - if (!FSOUND_Sample_SetMode(mSamplep, current_mode | FSOUND_2D)) - { - llwarns << "LLAudioBufferFMOD::set3DMode error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl; - } - } -} - - -void * F_CALLBACKAPI windCallback(void *originalbuffer, void *newbuffer, int length, void* userdata) -{ - // originalbuffer = fmod's original mixbuffer. - // newbuffer = the buffer passed from the previous DSP unit. - // length = length in samples at this mix time. - // userdata = user parameter passed through in FSOUND_DSP_Create. - - LLWindGen<LLAudioEngine_FMOD::MIXBUFFERFORMAT> *windgen = - (LLWindGen<LLAudioEngine_FMOD::MIXBUFFERFORMAT> *)userdata; - - newbuffer = windgen->windGenerate((LLAudioEngine_FMOD::MIXBUFFERFORMAT *)newbuffer, length); - - return newbuffer; -} diff --git a/indra/llaudio/llaudioengine_fmodex.cpp b/indra/llaudio/llaudioengine_fmodex.cpp new file mode 100644 index 0000000000..5ec30c7d1d --- /dev/null +++ b/indra/llaudio/llaudioengine_fmodex.cpp @@ -0,0 +1,746 @@ +/** + * @file audioengine_fmodex.cpp + * @brief Implementation of LLAudioEngine class abstracting the audio + * support as a FMODEX implementation + * + * $LicenseInfo:firstyear=2002&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$ + */ + +#include "linden_common.h" + +#include "llstreamingaudio.h" +#include "llstreamingaudio_fmodex.h" + +#include "llaudioengine_fmodex.h" +#include "lllistener_fmodex.h" + +#include "llerror.h" +#include "llmath.h" +#include "llrand.h" + +#include "fmod.hpp" +#include "fmod_errors.h" +#include "lldir.h" +#include "llapr.h" + +#include "sound_ids.h" + +FMOD_RESULT F_CALLBACK windCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int outchannels); + +FMOD::ChannelGroup *LLAudioEngine_FMODEX::mChannelGroups[LLAudioEngine::AUDIO_TYPE_COUNT] = {0}; + +LLAudioEngine_FMODEX::LLAudioEngine_FMODEX(bool enable_profiler) +{ + mInited = false; + mWindGen = NULL; + mWindDSP = NULL; + mSystem = NULL; + mEnableProfiler = enable_profiler; +} + + +LLAudioEngine_FMODEX::~LLAudioEngine_FMODEX() +{ +} + + +inline bool Check_FMOD_Error(FMOD_RESULT result, const char *string) +{ + if(result == FMOD_OK) + return false; + llwarns << string << " Error: " << FMOD_ErrorString(result) << llendl; + return true; +} + +void* F_STDCALL decode_alloc(unsigned int size, FMOD_MEMORY_TYPE type, const char *sourcestr) +{ + if(type & FMOD_MEMORY_STREAM_DECODE) + { + llinfos << "Decode buffer size: " << size << llendl; + } + else if(type & FMOD_MEMORY_STREAM_FILE) + { + llinfos << "Strean buffer size: " << size << llendl; + } + return new char[size]; +} +void* F_STDCALL decode_realloc(void *ptr, unsigned int size, FMOD_MEMORY_TYPE type, const char *sourcestr) +{ + memset(ptr,0,size); + return ptr; +} +void F_STDCALL decode_dealloc(void *ptr, FMOD_MEMORY_TYPE type, const char *sourcestr) +{ + delete[] (char*)ptr; +} + +bool LLAudioEngine_FMODEX::init(const S32 num_channels, void* userdata) +{ + U32 version; + FMOD_RESULT result; + + LL_DEBUGS("AppInit") << "LLAudioEngine_FMODEX::init() initializing FMOD" << LL_ENDL; + + //result = FMOD::Memory_Initialize(NULL, 0, &decode_alloc, &decode_realloc, &decode_dealloc, FMOD_MEMORY_STREAM_DECODE | FMOD_MEMORY_STREAM_FILE); + //if(Check_FMOD_Error(result, "FMOD::Memory_Initialize")) + // return false; + + result = FMOD::System_Create(&mSystem); + if(Check_FMOD_Error(result, "FMOD::System_Create")) + return false; + + //will call LLAudioEngine_FMODEX::allocateListener, which needs a valid mSystem pointer. + LLAudioEngine::init(num_channels, userdata); + + result = mSystem->getVersion(&version); + Check_FMOD_Error(result, "FMOD::System::getVersion"); + + if (version < FMOD_VERSION) + { + LL_WARNS("AppInit") << "Error : You are using the wrong FMOD Ex version (" << version + << ")! You should be using FMOD Ex" << FMOD_VERSION << LL_ENDL; + } + + result = mSystem->setSoftwareFormat(44100, FMOD_SOUND_FORMAT_PCM16, 0, 0, FMOD_DSP_RESAMPLER_LINEAR); + Check_FMOD_Error(result,"FMOD::System::setSoftwareFormat"); + + // In this case, all sounds, PLUS wind and stream will be software. + result = mSystem->setSoftwareChannels(num_channels + 2); + Check_FMOD_Error(result,"FMOD::System::setSoftwareChannels"); + + U32 fmod_flags = FMOD_INIT_NORMAL; + if(mEnableProfiler) + { + fmod_flags |= FMOD_INIT_ENABLE_PROFILE; + mSystem->createChannelGroup("None", &mChannelGroups[AUDIO_TYPE_NONE]); + mSystem->createChannelGroup("SFX", &mChannelGroups[AUDIO_TYPE_SFX]); + mSystem->createChannelGroup("UI", &mChannelGroups[AUDIO_TYPE_UI]); + mSystem->createChannelGroup("Ambient", &mChannelGroups[AUDIO_TYPE_AMBIENT]); + } + +#if LL_LINUX + bool audio_ok = false; + + if (!audio_ok) + { + if (NULL == getenv("LL_BAD_FMOD_PULSEAUDIO")) /*Flawfinder: ignore*/ + { + LL_DEBUGS("AppInit") << "Trying PulseAudio audio output..." << LL_ENDL; + if(mSystem->setOutput(FMOD_OUTPUTTYPE_PULSEAUDIO) == FMOD_OK && + (result = mSystem->init(num_channels + 2, fmod_flags, 0)) == FMOD_OK) + { + LL_DEBUGS("AppInit") << "PulseAudio output initialized OKAY" << LL_ENDL; + audio_ok = true; + } + else + { + Check_FMOD_Error(result, "PulseAudio audio output FAILED to initialize"); + } + } + else + { + LL_DEBUGS("AppInit") << "PulseAudio audio output SKIPPED" << LL_ENDL; + } + } + if (!audio_ok) + { + if (NULL == getenv("LL_BAD_FMOD_ALSA")) /*Flawfinder: ignore*/ + { + LL_DEBUGS("AppInit") << "Trying ALSA audio output..." << LL_ENDL; + if(mSystem->setOutput(FMOD_OUTPUTTYPE_ALSA) == FMOD_OK && + (result = mSystem->init(num_channels + 2, fmod_flags, 0)) == FMOD_OK) + { + LL_DEBUGS("AppInit") << "ALSA audio output initialized OKAY" << LL_ENDL; + audio_ok = true; + } + else + { + Check_FMOD_Error(result, "ALSA audio output FAILED to initialize"); + } + } + else + { + LL_DEBUGS("AppInit") << "ALSA audio output SKIPPED" << LL_ENDL; + } + } + if (!audio_ok) + { + if (NULL == getenv("LL_BAD_FMOD_OSS")) /*Flawfinder: ignore*/ + { + LL_DEBUGS("AppInit") << "Trying OSS audio output..." << LL_ENDL; + if(mSystem->setOutput(FMOD_OUTPUTTYPE_OSS) == FMOD_OK && + (result = mSystem->init(num_channels + 2, fmod_flags, 0)) == FMOD_OK) + { + LL_DEBUGS("AppInit") << "OSS audio output initialized OKAY" << LL_ENDL; + audio_ok = true; + } + else + { + Check_FMOD_Error(result, "OSS audio output FAILED to initialize"); + } + } + else + { + LL_DEBUGS("AppInit") << "OSS audio output SKIPPED" << LL_ENDL; + } + } + if (!audio_ok) + { + LL_WARNS("AppInit") << "Overall audio init failure." << LL_ENDL; + return false; + } + + // We're interested in logging which output method we + // ended up with, for QA purposes. + FMOD_OUTPUTTYPE output_type; + mSystem->getOutput(&output_type); + switch (output_type) + { + case FMOD_OUTPUTTYPE_NOSOUND: + LL_INFOS("AppInit") << "Audio output: NoSound" << LL_ENDL; break; + case FMOD_OUTPUTTYPE_PULSEAUDIO: + LL_INFOS("AppInit") << "Audio output: PulseAudio" << LL_ENDL; break; + case FMOD_OUTPUTTYPE_ALSA: + LL_INFOS("AppInit") << "Audio output: ALSA" << LL_ENDL; break; + case FMOD_OUTPUTTYPE_OSS: + LL_INFOS("AppInit") << "Audio output: OSS" << LL_ENDL; break; + default: + LL_INFOS("AppInit") << "Audio output: Unknown!" << LL_ENDL; break; + }; +#else // LL_LINUX + + // initialize the FMOD engine + result = mSystem->init( num_channels + 2, fmod_flags, 0); + if (result == FMOD_ERR_OUTPUT_CREATEBUFFER) + { + /* + Ok, the speaker mode selected isn't supported by this soundcard. Switch it + back to stereo... + */ + result = mSystem->setSpeakerMode(FMOD_SPEAKERMODE_STEREO); + Check_FMOD_Error(result,"Error falling back to stereo mode"); + /* + ... and re-init. + */ + result = mSystem->init( num_channels + 2, fmod_flags, 0); + } + if(Check_FMOD_Error(result, "Error initializing FMOD Ex")) + return false; +#endif + + // set up our favourite FMOD-native streaming audio implementation if none has already been added + if (!getStreamingAudioImpl()) // no existing implementation added + setStreamingAudioImpl(new LLStreamingAudio_FMODEX(mSystem)); + + LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::init() FMOD Ex initialized correctly" << LL_ENDL; + + int r_numbuffers, r_samplerate, r_channels, r_bits; + unsigned int r_bufferlength; + char r_name[256]; + mSystem->getDSPBufferSize(&r_bufferlength, &r_numbuffers); + mSystem->getSoftwareFormat(&r_samplerate, NULL, &r_channels, NULL, NULL, &r_bits); + mSystem->getDriverInfo(0, r_name, 255, 0); + r_name[255] = '\0'; + int latency = (int)(1000.0f * r_bufferlength * r_numbuffers / r_samplerate); + + LL_INFOS("AppInit") << "FMOD device: "<< r_name << "\n" + << "FMOD Ex parameters: " << r_samplerate << " Hz * " << r_channels << " * " <<r_bits <<" bit\n" + << "\tbuffer " << r_bufferlength << " * " << r_numbuffers << " (" << latency <<"ms)" << LL_ENDL; + + mInited = true; + + return true; +} + + +std::string LLAudioEngine_FMODEX::getDriverName(bool verbose) +{ + llassert_always(mSystem); + if (verbose) + { + U32 version; + if(!Check_FMOD_Error(mSystem->getVersion(&version), "FMOD::System::getVersion")) + { + return llformat("FMOD Ex %1x.%02x.%02x", version >> 16, version >> 8 & 0x000000FF, version & 0x000000FF); + } + } + return "FMODEx"; +} + + +void LLAudioEngine_FMODEX::allocateListener(void) +{ + mListenerp = (LLListener *) new LLListener_FMODEX(mSystem); + if (!mListenerp) + { + llwarns << "Listener creation failed" << llendl; + } +} + + +void LLAudioEngine_FMODEX::shutdown() +{ + stopInternetStream(); + + llinfos << "About to LLAudioEngine::shutdown()" << llendl; + LLAudioEngine::shutdown(); + + llinfos << "LLAudioEngine_FMODEX::shutdown() closing FMOD Ex" << llendl; + mSystem->close(); + mSystem->release(); + llinfos << "LLAudioEngine_FMODEX::shutdown() done closing FMOD Ex" << llendl; + + delete mListenerp; + mListenerp = NULL; +} + + +LLAudioBuffer * LLAudioEngine_FMODEX::createBuffer() +{ + return new LLAudioBufferFMODEX(mSystem); +} + + +LLAudioChannel * LLAudioEngine_FMODEX::createChannel() +{ + return new LLAudioChannelFMODEX(mSystem); +} + +bool LLAudioEngine_FMODEX::initWind() +{ + mNextWindUpdate = 0.0; + + if (!mWindDSP) + { + FMOD_DSP_DESCRIPTION dspdesc; + memset(&dspdesc, 0, sizeof(FMOD_DSP_DESCRIPTION)); //Set everything to zero + strncpy(dspdesc.name,"Wind Unit", sizeof(dspdesc.name)); //Set name to "Wind Unit" + dspdesc.channels=2; + dspdesc.read = &windCallback; //Assign callback. + if(Check_FMOD_Error(mSystem->createDSP(&dspdesc, &mWindDSP), "FMOD::createDSP")) + return false; + + if(mWindGen) + delete mWindGen; + + float frequency = 44100; + mWindDSP->getDefaults(&frequency,0,0,0); + mWindGen = new LLWindGen<MIXBUFFERFORMAT>((U32)frequency); + mWindDSP->setUserData((void*)mWindGen); + } + + if (mWindDSP) + { + mSystem->playDSP(FMOD_CHANNEL_FREE, mWindDSP, false, 0); + return true; + } + return false; +} + + +void LLAudioEngine_FMODEX::cleanupWind() +{ + if (mWindDSP) + { + mWindDSP->remove(); + mWindDSP->release(); + mWindDSP = NULL; + } + + delete mWindGen; + mWindGen = NULL; +} + + +//----------------------------------------------------------------------- +void LLAudioEngine_FMODEX::updateWind(LLVector3 wind_vec, F32 camera_height_above_water) +{ + LLVector3 wind_pos; + F64 pitch; + F64 center_freq; + + if (!mEnableWind) + { + return; + } + + if (mWindUpdateTimer.checkExpirationAndReset(LL_WIND_UPDATE_INTERVAL)) + { + + // wind comes in as Linden coordinate (+X = forward, +Y = left, +Z = up) + // need to convert this to the conventional orientation DS3D and OpenAL use + // where +X = right, +Y = up, +Z = backwards + + wind_vec.setVec(-wind_vec.mV[1], wind_vec.mV[2], -wind_vec.mV[0]); + + // cerr << "Wind update" << endl; + + pitch = 1.0 + mapWindVecToPitch(wind_vec); + center_freq = 80.0 * pow(pitch,2.5*(mapWindVecToGain(wind_vec)+1.0)); + + mWindGen->mTargetFreq = (F32)center_freq; + mWindGen->mTargetGain = (F32)mapWindVecToGain(wind_vec) * mMaxWindGain; + mWindGen->mTargetPanGainR = (F32)mapWindVecToPan(wind_vec); + } +} + +//----------------------------------------------------------------------- +void LLAudioEngine_FMODEX::setInternalGain(F32 gain) +{ + if (!mInited) + { + return; + } + + gain = llclamp( gain, 0.0f, 1.0f ); + + FMOD::ChannelGroup *master_group; + mSystem->getMasterChannelGroup(&master_group); + + master_group->setVolume(gain); + + LLStreamingAudioInterface *saimpl = getStreamingAudioImpl(); + if ( saimpl ) + { + // fmod likes its streaming audio channel gain re-asserted after + // master volume change. + saimpl->setGain(saimpl->getGain()); + } +} + +// +// LLAudioChannelFMODEX implementation +// + +LLAudioChannelFMODEX::LLAudioChannelFMODEX(FMOD::System *system) : LLAudioChannel(), mSystemp(system), mChannelp(NULL), mLastSamplePos(0) +{ +} + + +LLAudioChannelFMODEX::~LLAudioChannelFMODEX() +{ + cleanup(); +} + +bool LLAudioChannelFMODEX::updateBuffer() +{ + if (LLAudioChannel::updateBuffer()) + { + // Base class update returned true, which means that we need to actually + // set up the channel for a different buffer. + + LLAudioBufferFMODEX *bufferp = (LLAudioBufferFMODEX *)mCurrentSourcep->getCurrentBuffer(); + + // Grab the FMOD sample associated with the buffer + FMOD::Sound *soundp = bufferp->getSound(); + if (!soundp) + { + // This is bad, there should ALWAYS be a sound associated with a legit + // buffer. + llerrs << "No FMOD sound!" << llendl; + return false; + } + + + // Actually play the sound. Start it off paused so we can do all the necessary + // setup. + if(!mChannelp) + { + FMOD_RESULT result = getSystem()->playSound(FMOD_CHANNEL_FREE, soundp, true, &mChannelp); + Check_FMOD_Error(result, "FMOD::System::playSound"); + } + + //llinfos << "Setting up channel " << std::hex << mChannelID << std::dec << llendl; + } + + // If we have a source for the channel, we need to update its gain. + if (mCurrentSourcep) + { + // SJB: warnings can spam and hurt framerate, disabling + //FMOD_RESULT result; + + mChannelp->setVolume(getSecondaryGain() * mCurrentSourcep->getGain()); + //Check_FMOD_Error(result, "FMOD::Channel::setVolume"); + + mChannelp->setMode(mCurrentSourcep->isLoop() ? FMOD_LOOP_NORMAL : FMOD_LOOP_OFF); + /*if(Check_FMOD_Error(result, "FMOD::Channel::setMode")) + { + S32 index; + mChannelp->getIndex(&index); + llwarns << "Channel " << index << "Source ID: " << mCurrentSourcep->getID() + << " at " << mCurrentSourcep->getPositionGlobal() << llendl; + }*/ + } + + return true; +} + + +void LLAudioChannelFMODEX::update3DPosition() +{ + if (!mChannelp) + { + // We're not actually a live channel (i.e., we're not playing back anything) + return; + } + + LLAudioBufferFMODEX *bufferp = (LLAudioBufferFMODEX *)mCurrentBufferp; + if (!bufferp) + { + // We don't have a buffer associated with us (should really have been picked up + // by the above if. + return; + } + + if (mCurrentSourcep->isAmbient()) + { + // Ambient sound, don't need to do any positional updates. + set3DMode(false); + } + else + { + // Localized sound. Update the position and velocity of the sound. + set3DMode(true); + + LLVector3 float_pos; + float_pos.setVec(mCurrentSourcep->getPositionGlobal()); + FMOD_RESULT result = mChannelp->set3DAttributes((FMOD_VECTOR*)float_pos.mV, (FMOD_VECTOR*)mCurrentSourcep->getVelocity().mV); + Check_FMOD_Error(result, "FMOD::Channel::set3DAttributes"); + } +} + + +void LLAudioChannelFMODEX::updateLoop() +{ + if (!mChannelp) + { + // May want to clear up the loop/sample counters. + return; + } + + // + // Hack: We keep track of whether we looped or not by seeing when the + // sample position looks like it's going backwards. Not reliable; may + // yield false negatives. + // + U32 cur_pos; + mChannelp->getPosition(&cur_pos,FMOD_TIMEUNIT_PCMBYTES); + + if (cur_pos < (U32)mLastSamplePos) + { + mLoopedThisFrame = true; + } + mLastSamplePos = cur_pos; +} + + +void LLAudioChannelFMODEX::cleanup() +{ + if (!mChannelp) + { + //llinfos << "Aborting cleanup with no channel handle." << llendl; + return; + } + + //llinfos << "Cleaning up channel: " << mChannelID << llendl; + Check_FMOD_Error(mChannelp->stop(),"FMOD::Channel::stop"); + + mCurrentBufferp = NULL; + mChannelp = NULL; +} + + +void LLAudioChannelFMODEX::play() +{ + if (!mChannelp) + { + llwarns << "Playing without a channel handle, aborting" << llendl; + return; + } + + Check_FMOD_Error(mChannelp->setPaused(false), "FMOD::Channel::pause"); + + getSource()->setPlayedOnce(true); + + if(LLAudioEngine_FMODEX::mChannelGroups[getSource()->getType()]) + mChannelp->setChannelGroup(LLAudioEngine_FMODEX::mChannelGroups[getSource()->getType()]); +} + + +void LLAudioChannelFMODEX::playSynced(LLAudioChannel *channelp) +{ + LLAudioChannelFMODEX *fmod_channelp = (LLAudioChannelFMODEX*)channelp; + if (!(fmod_channelp->mChannelp && mChannelp)) + { + // Don't have channels allocated to both the master and the slave + return; + } + + U32 cur_pos; + if(Check_FMOD_Error(mChannelp->getPosition(&cur_pos,FMOD_TIMEUNIT_PCMBYTES), "Unable to retrieve current position")) + return; + + cur_pos %= mCurrentBufferp->getLength(); + + // Try to match the position of our sync master + Check_FMOD_Error(mChannelp->setPosition(cur_pos,FMOD_TIMEUNIT_PCMBYTES),"Unable to set current position"); + + // Start us playing + play(); +} + + +bool LLAudioChannelFMODEX::isPlaying() +{ + if (!mChannelp) + { + return false; + } + + bool paused, playing; + mChannelp->getPaused(&paused); + mChannelp->isPlaying(&playing); + return !paused && playing; +} + + +// +// LLAudioChannelFMODEX implementation +// + + +LLAudioBufferFMODEX::LLAudioBufferFMODEX(FMOD::System *system) : mSystemp(system), mSoundp(NULL) +{ +} + + +LLAudioBufferFMODEX::~LLAudioBufferFMODEX() +{ + if(mSoundp) + { + mSoundp->release(); + mSoundp = NULL; + } +} + + +bool LLAudioBufferFMODEX::loadWAV(const std::string& filename) +{ + // Try to open a wav file from disk. This will eventually go away, as we don't + // really want to block doing this. + if (filename.empty()) + { + // invalid filename, abort. + return false; + } + + if (!LLAPRFile::isExist(filename, NULL, LL_APR_RPB)) + { + // File not found, abort. + return false; + } + + if (mSoundp) + { + // If there's already something loaded in this buffer, clean it up. + mSoundp->release(); + mSoundp = NULL; + } + + FMOD_MODE base_mode = FMOD_LOOP_NORMAL | FMOD_SOFTWARE; + FMOD_CREATESOUNDEXINFO exinfo; + memset(&exinfo,0,sizeof(exinfo)); + exinfo.cbsize = sizeof(exinfo); + exinfo.suggestedsoundtype = FMOD_SOUND_TYPE_WAV; //Hint to speed up loading. + // Load up the wav file into an fmod sample +#if LL_WINDOWS + FMOD_RESULT result = getSystem()->createSound((const char*)utf8str_to_utf16str(filename).c_str(), base_mode | FMOD_UNICODE, &exinfo, &mSoundp); +#else + FMOD_RESULT result = getSystem()->createSound(filename.c_str(), base_mode, &exinfo, &mSoundp); +#endif + + if (result != FMOD_OK) + { + // We failed to load the file for some reason. + llwarns << "Could not load data '" << filename << "': " << FMOD_ErrorString(result) << llendl; + + // + // If we EVER want to load wav files provided by end users, we need + // to rethink this! + // + // file is probably corrupt - remove it. + LLFile::remove(filename); + return false; + } + + // Everything went well, return true + return true; +} + + +U32 LLAudioBufferFMODEX::getLength() +{ + if (!mSoundp) + { + return 0; + } + + U32 length; + mSoundp->getLength(&length, FMOD_TIMEUNIT_PCMBYTES); + return length; +} + + +void LLAudioChannelFMODEX::set3DMode(bool use3d) +{ + FMOD_MODE current_mode; + if(mChannelp->getMode(¤t_mode) != FMOD_OK) + return; + FMOD_MODE new_mode = current_mode; + new_mode &= ~(use3d ? FMOD_2D : FMOD_3D); + new_mode |= use3d ? FMOD_3D : FMOD_2D; + + if(current_mode != new_mode) + { + mChannelp->setMode(new_mode); + } +} + + +FMOD_RESULT F_CALLBACK windCallback(FMOD_DSP_STATE *dsp_state, float *originalbuffer, float *newbuffer, unsigned int length, int inchannels, int outchannels) +{ + // originalbuffer = fmod's original mixbuffer. + // newbuffer = the buffer passed from the previous DSP unit. + // length = length in samples at this mix time. + // userdata = user parameter passed through in FSOUND_DSP_Create. + + LLWindGen<LLAudioEngine_FMODEX::MIXBUFFERFORMAT> *windgen; + FMOD::DSP *thisdsp = (FMOD::DSP *)dsp_state->instance; + + thisdsp->getUserData((void **)&windgen); + S32 channels, configwidth, configheight; + thisdsp->getInfo(0, 0, &channels, &configwidth, &configheight); + + windgen->windGenerate((LLAudioEngine_FMODEX::MIXBUFFERFORMAT *)newbuffer, length); + + return FMOD_OK; +} diff --git a/indra/llaudio/llaudioengine_fmod.h b/indra/llaudio/llaudioengine_fmodex.h index 4582a5d57e..415a9ed0ef 100644 --- a/indra/llaudio/llaudioengine_fmod.h +++ b/indra/llaudio/llaudioengine_fmodex.h @@ -1,7 +1,7 @@ /** - * @file audioengine_fmod.h - * @brief Definition of LLAudioEngine class abstracting the audio - * support as a FMOD 3D implementation + * @file audioengine_fmodex.h + * @brief Definition of LLAudioEngine class abstracting the audio + * support as a FMODEX implementation * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code @@ -25,26 +25,33 @@ * $/LicenseInfo$ */ -#ifndef LL_AUDIOENGINE_FMOD_H -#define LL_AUDIOENGINE_FMOD_H +#ifndef LL_AUDIOENGINE_FMODEX_H +#define LL_AUDIOENGINE_FMODEX_H #include "llaudioengine.h" -#include "lllistener_fmod.h" #include "llwindgen.h" -#include "fmod.h" - -class LLAudioStreamManagerFMOD; - -class LLAudioEngine_FMOD : public LLAudioEngine +//Stubs +class LLAudioStreamManagerFMODEX; +namespace FMOD +{ + class System; + class Channel; + class ChannelGroup; + class Sound; + class DSP; +} + +//Interfaces +class LLAudioEngine_FMODEX : public LLAudioEngine { public: - LLAudioEngine_FMOD(); - virtual ~LLAudioEngine_FMOD(); + LLAudioEngine_FMODEX(bool enable_profiler); + virtual ~LLAudioEngine_FMODEX(); // initialization/startup/shutdown virtual bool init(const S32 num_channels, void *user_data); - virtual std::string getDriverName(bool verbose); + virtual std::string getDriverName(bool verbose); virtual void allocateListener(); virtual void shutdown(); @@ -54,38 +61,33 @@ public: /*virtual*/void updateWind(LLVector3 direction, F32 camera_height_above_water); -#if LL_DARWIN - typedef S32 MIXBUFFERFORMAT; -#else - typedef S16 MIXBUFFERFORMAT; -#endif + typedef F32 MIXBUFFERFORMAT; + FMOD::System *getSystem() const {return mSystem;} protected: /*virtual*/ LLAudioBuffer *createBuffer(); // Get a free buffer, or flush an existing one if you have to. /*virtual*/ LLAudioChannel *createChannel(); // Create a new audio channel. /*virtual*/ void setInternalGain(F32 gain); -protected: - static signed char F_CALLBACKAPI callbackMetaData(char* name, char* value, void* userdata); - - //F32 mMinDistance[MAX_BUFFERS]; - //F32 mMaxDistance[MAX_BUFFERS]; bool mInited; - // On Windows, userdata is the HWND of the application window. - void* mUserData; - LLWindGen<MIXBUFFERFORMAT> *mWindGen; - FSOUND_DSPUNIT *mWindDSP; + + FMOD::DSP *mWindDSP; + FMOD::System *mSystem; + bool mEnableProfiler; + +public: + static FMOD::ChannelGroup *mChannelGroups[LLAudioEngine::AUDIO_TYPE_COUNT]; }; -class LLAudioChannelFMOD : public LLAudioChannel +class LLAudioChannelFMODEX : public LLAudioChannel { public: - LLAudioChannelFMOD(); - virtual ~LLAudioChannelFMOD(); + LLAudioChannelFMODEX(FMOD::System *audioengine); + virtual ~LLAudioChannelFMODEX(); protected: /*virtual*/ void play(); @@ -97,28 +99,30 @@ protected: /*virtual*/ void update3DPosition(); /*virtual*/ void updateLoop(); + void set3DMode(bool use3d); protected: - int mChannelID; + FMOD::System *getSystem() const {return mSystemp;} + FMOD::System *mSystemp; + FMOD::Channel *mChannelp; S32 mLastSamplePos; }; -class LLAudioBufferFMOD : public LLAudioBuffer +class LLAudioBufferFMODEX : public LLAudioBuffer { public: - LLAudioBufferFMOD(); - virtual ~LLAudioBufferFMOD(); + LLAudioBufferFMODEX(FMOD::System *audioengine); + virtual ~LLAudioBufferFMODEX(); /*virtual*/ bool loadWAV(const std::string& filename); /*virtual*/ U32 getLength(); - friend class LLAudioChannelFMOD; - - void set3DMode(bool use3d); -protected: - FSOUND_SAMPLE *getSample() { return mSamplep; } + friend class LLAudioChannelFMODEX; protected: - FSOUND_SAMPLE *mSamplep; + FMOD::System *getSystem() const {return mSystemp;} + FMOD::System *mSystemp; + FMOD::Sound *getSound() const{ return mSoundp; } + FMOD::Sound *mSoundp; }; -#endif // LL_AUDIOENGINE_FMOD_H +#endif // LL_AUDIOENGINE_FMODEX_H diff --git a/indra/llaudio/lllistener_fmod.cpp b/indra/llaudio/lllistener_fmodex.cpp index 0138f4345e..2509a7aebc 100644 --- a/indra/llaudio/lllistener_fmod.cpp +++ b/indra/llaudio/lllistener_fmodex.cpp @@ -1,7 +1,7 @@ /** - * @file listener_fmod.cpp - * @brief implementation of LISTENER class abstracting the audio - * support as a FMOD 3D implementation (windows only) + * @file listener_fmodex.cpp + * @brief Implementation of LISTENER class abstracting the audio + * support as a FMODEX implementation * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code @@ -27,24 +27,25 @@ #include "linden_common.h" #include "llaudioengine.h" -#include "lllistener_fmod.h" -#include "fmod.h" +#include "lllistener_fmodex.h" +#include "fmod.hpp" //----------------------------------------------------------------------- // constructor //----------------------------------------------------------------------- -LLListener_FMOD::LLListener_FMOD() +LLListener_FMODEX::LLListener_FMODEX(FMOD::System *system) { + mSystem = system; init(); } //----------------------------------------------------------------------- -LLListener_FMOD::~LLListener_FMOD() +LLListener_FMODEX::~LLListener_FMODEX() { } //----------------------------------------------------------------------- -void LLListener_FMOD::init(void) +void LLListener_FMODEX::init(void) { // do inherited LLListener::init(); @@ -53,31 +54,31 @@ void LLListener_FMOD::init(void) } //----------------------------------------------------------------------- -void LLListener_FMOD::translate(LLVector3 offset) +void LLListener_FMODEX::translate(LLVector3 offset) { LLListener::translate(offset); - FSOUND_3D_Listener_SetAttributes(mPosition.mV, NULL, mListenAt.mV[0],mListenAt.mV[1],mListenAt.mV[2], mListenUp.mV[0],mListenUp.mV[1],mListenUp.mV[2]); + mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV); } //----------------------------------------------------------------------- -void LLListener_FMOD::setPosition(LLVector3 pos) +void LLListener_FMODEX::setPosition(LLVector3 pos) { LLListener::setPosition(pos); - FSOUND_3D_Listener_SetAttributes(pos.mV, NULL, mListenAt.mV[0],mListenAt.mV[1],mListenAt.mV[2], mListenUp.mV[0],mListenUp.mV[1],mListenUp.mV[2]); + mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV); } //----------------------------------------------------------------------- -void LLListener_FMOD::setVelocity(LLVector3 vel) +void LLListener_FMODEX::setVelocity(LLVector3 vel) { LLListener::setVelocity(vel); - FSOUND_3D_Listener_SetAttributes(NULL, vel.mV, mListenAt.mV[0],mListenAt.mV[1],mListenAt.mV[2], mListenUp.mV[0],mListenUp.mV[1],mListenUp.mV[2]); + mSystem->set3DListenerAttributes(0, NULL, (FMOD_VECTOR*)mVelocity.mV, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV); } //----------------------------------------------------------------------- -void LLListener_FMOD::orient(LLVector3 up, LLVector3 at) +void LLListener_FMODEX::orient(LLVector3 up, LLVector3 at) { LLListener::orient(up, at); @@ -87,37 +88,46 @@ void LLListener_FMOD::orient(LLVector3 up, LLVector3 at) // since DX is left-handed and we (LL, OpenGL, OpenAL) are right-handed at = -at; - FSOUND_3D_Listener_SetAttributes(NULL, NULL, at.mV[0],at.mV[1],at.mV[2], up.mV[0],up.mV[1],up.mV[2]); + mSystem->set3DListenerAttributes(0, NULL, NULL, (FMOD_VECTOR*)at.mV, (FMOD_VECTOR*)up.mV); } //----------------------------------------------------------------------- -void LLListener_FMOD::commitDeferredChanges() +void LLListener_FMODEX::commitDeferredChanges() { - FSOUND_Update(); + mSystem->update(); } -void LLListener_FMOD::setRolloffFactor(F32 factor) +void LLListener_FMODEX::setRolloffFactor(F32 factor) { + //An internal FMODEx optimization skips 3D updates if there have not been changes to the 3D sound environment. + //Sadly, a change in rolloff is not accounted for, thus we must touch the listener properties as well. + //In short: Changing the position ticks a dirtyflag inside fmodex, which makes it not skip 3D processing next update call. + if(mRolloffFactor != factor) + { + LLVector3 pos = mVelocity - LLVector3(0.f,0.f,.1f); + mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)pos.mV, NULL, NULL, NULL); + mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mVelocity.mV, NULL, NULL, NULL); + } mRolloffFactor = factor; - FSOUND_3D_SetRolloffFactor(factor); + mSystem->set3DSettings(mDopplerFactor, 1.f, mRolloffFactor); } -F32 LLListener_FMOD::getRolloffFactor() +F32 LLListener_FMODEX::getRolloffFactor() { return mRolloffFactor; } -void LLListener_FMOD::setDopplerFactor(F32 factor) +void LLListener_FMODEX::setDopplerFactor(F32 factor) { mDopplerFactor = factor; - FSOUND_3D_SetDopplerFactor(factor); + mSystem->set3DSettings(mDopplerFactor, 1.f, mRolloffFactor); } -F32 LLListener_FMOD::getDopplerFactor() +F32 LLListener_FMODEX::getDopplerFactor() { return mDopplerFactor; } diff --git a/indra/llaudio/lllistener_fmod.h b/indra/llaudio/lllistener_fmodex.h index 818da05d51..073b65d53a 100644 --- a/indra/llaudio/lllistener_fmod.h +++ b/indra/llaudio/lllistener_fmodex.h @@ -1,5 +1,5 @@ /** - * @file listener_fmod.h + * @file listener_fmodex.h * @brief Description of LISTENER class abstracting the audio support * as an FMOD 3D implementation (windows and Linux) * @@ -25,16 +25,23 @@ * $/LicenseInfo$ */ -#ifndef LL_LISTENER_FMOD_H -#define LL_LISTENER_FMOD_H +#ifndef LL_LISTENER_FMODEX_H +#define LL_LISTENER_FMODEX_H #include "lllistener.h" -class LLListener_FMOD : public LLListener +//Stubs +namespace FMOD +{ + class System; +} + +//Interfaces +class LLListener_FMODEX : public LLListener { public: - LLListener_FMOD(); - virtual ~LLListener_FMOD(); + LLListener_FMODEX(FMOD::System *system); + virtual ~LLListener_FMODEX(); virtual void init(); virtual void translate(LLVector3 offset); @@ -47,8 +54,8 @@ class LLListener_FMOD : public LLListener virtual F32 getDopplerFactor(); virtual void setRolloffFactor(F32 factor); virtual F32 getRolloffFactor(); - protected: + FMOD::System *mSystem; F32 mDopplerFactor; F32 mRolloffFactor; }; diff --git a/indra/llaudio/llstreamingaudio.h b/indra/llaudio/llstreamingaudio.h index 20104af744..93479f9d59 100644 --- a/indra/llaudio/llstreamingaudio.h +++ b/indra/llaudio/llstreamingaudio.h @@ -45,6 +45,8 @@ class LLStreamingAudioInterface virtual void setGain(F32 vol) = 0; virtual F32 getGain() = 0; virtual std::string getURL() = 0; + virtual bool supportsAdjustableBufferSizes(){return false;} + virtual void setBufferSizes(U32 streambuffertime, U32 decodebuffertime){}; }; #endif // LL_STREAMINGAUDIO_H diff --git a/indra/llaudio/llstreamingaudio_fmod.cpp b/indra/llaudio/llstreamingaudio_fmodex.cpp index bcdea771a7..4a74267650 100644 --- a/indra/llaudio/llstreamingaudio_fmod.cpp +++ b/indra/llaudio/llstreamingaudio_fmodex.cpp @@ -1,8 +1,8 @@ /** - * @file streamingaudio_fmod.cpp - * @brief LLStreamingAudio_FMOD implementation + * @file streamingaudio_fmodex.cpp + * @brief LLStreamingAudio_FMODEX implementation * - * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. * @@ -28,25 +28,27 @@ #include "llmath.h" -#include "fmod.h" +#include "fmod.hpp" #include "fmod_errors.h" -#include "llstreamingaudio_fmod.h" +#include "llstreamingaudio_fmodex.h" -class LLAudioStreamManagerFMOD +class LLAudioStreamManagerFMODEX { public: - LLAudioStreamManagerFMOD(const std::string& url); - int startStream(); + LLAudioStreamManagerFMODEX(FMOD::System *system, const std::string& url); + FMOD::Channel* startStream(); bool stopStream(); // Returns true if the stream was successfully stopped. bool ready(); const std::string& getURL() { return mInternetStreamURL; } - int getOpenState(); + FMOD_OPENSTATE getOpenState(unsigned int* percentbuffered=NULL, bool* starving=NULL, bool* diskbusy=NULL); protected: - FSOUND_STREAM* mInternetStream; + FMOD::System* mSystem; + FMOD::Channel* mStreamChannel; + FMOD::Sound* mInternetStream; bool mReady; std::string mInternetStreamURL; @@ -57,14 +59,17 @@ protected: //--------------------------------------------------------------------------- // Internet Streaming //--------------------------------------------------------------------------- -LLStreamingAudio_FMOD::LLStreamingAudio_FMOD() : +LLStreamingAudio_FMODEX::LLStreamingAudio_FMODEX(FMOD::System *system) : + mSystem(system), mCurrentInternetStreamp(NULL), - mFMODInternetStreamChannel(-1), + mFMODInternetStreamChannelp(NULL), mGain(1.0f) { // Number of milliseconds of audio to buffer for the audio card. // Must be larger than the usual Second Life frame stutter time. - FSOUND_Stream_SetBufferSize(200); + const U32 buffer_seconds = 10; //sec + const U32 estimated_bitrate = 128; //kbit/sec + mSystem->setStreamBufferSize(estimated_bitrate * buffer_seconds * 128/*bytes/kbit*/, FMOD_TIMEUNIT_RAWBYTES); // Here's where we set the size of the network buffer and some buffering // parameters. In this case we want a network buffer of 16k, we want it @@ -76,13 +81,13 @@ LLStreamingAudio_FMOD::LLStreamingAudio_FMOD() : } -LLStreamingAudio_FMOD::~LLStreamingAudio_FMOD() +LLStreamingAudio_FMODEX::~LLStreamingAudio_FMODEX() { // nothing interesting/safe to do. } -void LLStreamingAudio_FMOD::start(const std::string& url) +void LLStreamingAudio_FMODEX::start(const std::string& url) { //if (!mInited) //{ @@ -96,7 +101,7 @@ void LLStreamingAudio_FMOD::start(const std::string& url) if (!url.empty()) { llinfos << "Starting internet stream: " << url << llendl; - mCurrentInternetStreamp = new LLAudioStreamManagerFMOD(url); + mCurrentInternetStreamp = new LLAudioStreamManagerFMODEX(mSystem,url); mURL = url; } else @@ -107,13 +112,13 @@ void LLStreamingAudio_FMOD::start(const std::string& url) } -void LLStreamingAudio_FMOD::update() +void LLStreamingAudio_FMODEX::update() { // Kill dead internet streams, if possible - std::list<LLAudioStreamManagerFMOD *>::iterator iter; + std::list<LLAudioStreamManagerFMODEX *>::iterator iter; for (iter = mDeadStreams.begin(); iter != mDeadStreams.end();) { - LLAudioStreamManagerFMOD *streamp = *iter; + LLAudioStreamManagerFMODEX *streamp = *iter; if (streamp->stopStream()) { llinfos << "Closed dead stream" << llendl; @@ -132,62 +137,66 @@ void LLStreamingAudio_FMOD::update() return; } - int open_state = mCurrentInternetStreamp->getOpenState(); + unsigned int progress; + bool starving; + bool diskbusy; + FMOD_OPENSTATE open_state = mCurrentInternetStreamp->getOpenState(&progress, &starving, &diskbusy); - if (!open_state) + if (open_state == FMOD_OPENSTATE_READY) { // Stream is live // start the stream if it's ready - if (mFMODInternetStreamChannel < 0) + if (!mFMODInternetStreamChannelp && + (mFMODInternetStreamChannelp = mCurrentInternetStreamp->startStream())) { - mFMODInternetStreamChannel = mCurrentInternetStreamp->startStream(); - - if (mFMODInternetStreamChannel != -1) - { - // Reset volume to previously set volume - setGain(getGain()); - FSOUND_SetPaused(mFMODInternetStreamChannel, false); - } + // Reset volume to previously set volume + setGain(getGain()); + mFMODInternetStreamChannelp->setPaused(false); + mLastStarved.stop(); } } - - switch(open_state) + else if(open_state == FMOD_OPENSTATE_ERROR) { - default: - case 0: - // success - break; - case -1: - // stream handle is invalid - llwarns << "InternetStream - invalid handle" << llendl; stop(); return; - case -2: - // opening - break; - case -3: - // failed to open, file not found, perhaps - llwarns << "InternetStream - failed to open" << llendl; - stop(); - return; - case -4: - // connecting - break; - case -5: - // buffering - break; } + if(mFMODInternetStreamChannelp) + { + FMOD::Sound *sound = NULL; + + if(mFMODInternetStreamChannelp->getCurrentSound(&sound) == FMOD_OK && sound) + { + if(starving) + { + if(!mLastStarved.getStarted()) + { + llinfos << "Stream starvation detected! Muting stream audio until it clears." << llendl; + llinfos << " (diskbusy="<<diskbusy<<")" << llendl; + llinfos << " (progress="<<progress<<")" << llendl; + mFMODInternetStreamChannelp->setMute(true); + } + mLastStarved.start(); + } + else if(mLastStarved.getStarted() && mLastStarved.getElapsedTimeF32() > 1.f) + { + mLastStarved.stop(); + mFMODInternetStreamChannelp->setMute(false); + } + } + } } -void LLStreamingAudio_FMOD::stop() +void LLStreamingAudio_FMODEX::stop() { - if (mFMODInternetStreamChannel != -1) + mLastStarved.stop(); + + if (mFMODInternetStreamChannelp) { - FSOUND_SetPaused(mFMODInternetStreamChannel, true); - FSOUND_SetPriority(mFMODInternetStreamChannel, 0); - mFMODInternetStreamChannel = -1; + mFMODInternetStreamChannelp->setPaused(true); + mFMODInternetStreamChannelp->setPriority(0); + mFMODInternetStreamChannelp = NULL; } if (mCurrentInternetStreamp) @@ -207,7 +216,7 @@ void LLStreamingAudio_FMOD::stop() } } -void LLStreamingAudio_FMOD::pause(int pauseopt) +void LLStreamingAudio_FMODEX::pause(int pauseopt) { if (pauseopt < 0) { @@ -230,7 +239,7 @@ void LLStreamingAudio_FMOD::pause(int pauseopt) // A stream is "playing" if it has been requested to start. That // doesn't necessarily mean audio is coming out of the speakers. -int LLStreamingAudio_FMOD::isPlaying() +int LLStreamingAudio_FMODEX::isPlaying() { if (mCurrentInternetStreamp) { @@ -247,44 +256,47 @@ int LLStreamingAudio_FMOD::isPlaying() } -F32 LLStreamingAudio_FMOD::getGain() +F32 LLStreamingAudio_FMODEX::getGain() { return mGain; } -std::string LLStreamingAudio_FMOD::getURL() +std::string LLStreamingAudio_FMODEX::getURL() { return mURL; } -void LLStreamingAudio_FMOD::setGain(F32 vol) +void LLStreamingAudio_FMODEX::setGain(F32 vol) { mGain = vol; - if (mFMODInternetStreamChannel != -1) + if (mFMODInternetStreamChannelp) { - vol = llclamp(vol * vol, 0.f, 1.f); - int vol_int = llround(vol * 255.f); - FSOUND_SetVolumeAbsolute(mFMODInternetStreamChannel, vol_int); + vol = llclamp(vol * vol, 0.f, 1.f); //should vol be squared here? + + mFMODInternetStreamChannelp->setVolume(vol); } } - /////////////////////////////////////////////////////// // manager of possibly-multiple internet audio streams -LLAudioStreamManagerFMOD::LLAudioStreamManagerFMOD(const std::string& url) : +LLAudioStreamManagerFMODEX::LLAudioStreamManagerFMODEX(FMOD::System *system, const std::string& url) : + mSystem(system), + mStreamChannel(NULL), mInternetStream(NULL), mReady(false) { mInternetStreamURL = url; - mInternetStream = FSOUND_Stream_Open(url.c_str(), FSOUND_NORMAL | FSOUND_NONBLOCKING, 0, 0); - if (!mInternetStream) + + FMOD_RESULT result = mSystem->createStream(url.c_str(), FMOD_2D | FMOD_NONBLOCKING | FMOD_MPEGSEARCH | FMOD_IGNORETAGS, 0, &mInternetStream); + + if (result!= FMOD_OK) { llwarns << "Couldn't open fmod stream, error " - << FMOD_ErrorString(FSOUND_GetError()) + << FMOD_ErrorString(result) << llendl; mReady = false; return; @@ -293,48 +305,42 @@ LLAudioStreamManagerFMOD::LLAudioStreamManagerFMOD(const std::string& url) : mReady = true; } -int LLAudioStreamManagerFMOD::startStream() +FMOD::Channel *LLAudioStreamManagerFMODEX::startStream() { // We need a live and opened stream before we try and play it. - if (!mInternetStream || getOpenState()) + if (!mInternetStream || getOpenState() != FMOD_OPENSTATE_READY) { llwarns << "No internet stream to start playing!" << llendl; - return -1; + return NULL; } - // Make sure the stream is set to 2D mode. - FSOUND_Stream_SetMode(mInternetStream, FSOUND_2D); + if(mStreamChannel) + return mStreamChannel; //Already have a channel for this stream. - return FSOUND_Stream_PlayEx(FSOUND_FREE, mInternetStream, NULL, true); + mSystem->playSound(FMOD_CHANNEL_FREE, mInternetStream, true, &mStreamChannel); + return mStreamChannel; } -bool LLAudioStreamManagerFMOD::stopStream() +bool LLAudioStreamManagerFMODEX::stopStream() { if (mInternetStream) { - int read_percent = 0; - int status = 0; - int bitrate = 0; - unsigned int flags = 0x0; - FSOUND_Stream_Net_GetStatus(mInternetStream, &status, &read_percent, &bitrate, &flags); + bool close = true; - switch (status) + switch (getOpenState()) { - case FSOUND_STREAM_NET_CONNECTING: + case FMOD_OPENSTATE_CONNECTING: close = false; break; - case FSOUND_STREAM_NET_NOTCONNECTED: - case FSOUND_STREAM_NET_BUFFERING: - case FSOUND_STREAM_NET_READY: - case FSOUND_STREAM_NET_ERROR: default: close = true; } if (close) { - FSOUND_Stream_Close(mInternetStream); + mInternetStream->release(); + mStreamChannel = NULL; mInternetStream = NULL; return true; } @@ -349,8 +355,19 @@ bool LLAudioStreamManagerFMOD::stopStream() } } -int LLAudioStreamManagerFMOD::getOpenState() +FMOD_OPENSTATE LLAudioStreamManagerFMODEX::getOpenState(unsigned int* percentbuffered, bool* starving, bool* diskbusy) +{ + FMOD_OPENSTATE state; + mInternetStream->getOpenState(&state, percentbuffered, starving, diskbusy); + return state; +} + +void LLStreamingAudio_FMODEX::setBufferSizes(U32 streambuffertime, U32 decodebuffertime) { - int open_state = FSOUND_Stream_GetOpenState(mInternetStream); - return open_state; + mSystem->setStreamBufferSize(streambuffertime/1000*128*128, FMOD_TIMEUNIT_RAWBYTES); + FMOD_ADVANCEDSETTINGS settings; + memset(&settings,0,sizeof(settings)); + settings.cbsize=sizeof(settings); + settings.defaultDecodeBufferSize = decodebuffertime;//ms + mSystem->setAdvancedSettings(&settings); } diff --git a/indra/llaudio/llstreamingaudio_fmod.h b/indra/llaudio/llstreamingaudio_fmodex.h index 9970f0d03b..42b6b3aaa8 100644 --- a/indra/llaudio/llstreamingaudio_fmod.h +++ b/indra/llaudio/llstreamingaudio_fmodex.h @@ -1,9 +1,8 @@ /** - * @file streamingaudio_fmod.h - * @author Tofu Linden - * @brief Definition of LLStreamingAudio_FMOD implementation + * @file streamingaudio_fmodex.h + * @brief Definition of LLStreamingAudio_FMODEX implementation * - * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. * @@ -25,20 +24,28 @@ * $/LicenseInfo$ */ -#ifndef LL_STREAMINGAUDIO_FMOD_H -#define LL_STREAMINGAUDIO_FMOD_H +#ifndef LL_STREAMINGAUDIO_FMODEX_H +#define LL_STREAMINGAUDIO_FMODEX_H #include "stdtypes.h" // from llcommon #include "llstreamingaudio.h" +#include "lltimer.h" -class LLAudioStreamManagerFMOD; +//Stubs +class LLAudioStreamManagerFMODEX; +namespace FMOD +{ + class System; + class Channel; +} -class LLStreamingAudio_FMOD : public LLStreamingAudioInterface +//Interfaces +class LLStreamingAudio_FMODEX : public LLStreamingAudioInterface { public: - LLStreamingAudio_FMOD(); - /*virtual*/ ~LLStreamingAudio_FMOD(); + LLStreamingAudio_FMODEX(FMOD::System *system); + /*virtual*/ ~LLStreamingAudio_FMODEX(); /*virtual*/ void start(const std::string& url); /*virtual*/ void stop(); @@ -49,14 +56,20 @@ class LLStreamingAudio_FMOD : public LLStreamingAudioInterface /*virtual*/ F32 getGain(); /*virtual*/ std::string getURL(); + /*virtual*/ bool supportsAdjustableBufferSizes(){return true;} + /*virtual*/ void setBufferSizes(U32 streambuffertime, U32 decodebuffertime); private: - LLAudioStreamManagerFMOD *mCurrentInternetStreamp; - int mFMODInternetStreamChannel; - std::list<LLAudioStreamManagerFMOD *> mDeadStreams; + FMOD::System *mSystem; + + LLAudioStreamManagerFMODEX *mCurrentInternetStreamp; + FMOD::Channel *mFMODInternetStreamChannelp; + std::list<LLAudioStreamManagerFMODEX *> mDeadStreams; std::string mURL; F32 mGain; + + LLTimer mLastStarved; }; -#endif // LL_STREAMINGAUDIO_FMOD_H +#endif // LL_STREAMINGAUDIO_FMODEX_H diff --git a/indra/llaudio/llvorbisencode.cpp b/indra/llaudio/llvorbisencode.cpp index 0e0c80a456..dfd5da12b3 100644 --- a/indra/llaudio/llvorbisencode.cpp +++ b/indra/llaudio/llvorbisencode.cpp @@ -35,7 +35,7 @@ #include "llapr.h" //#if LL_DARWIN -// MBW -- XXX -- Getting rid of SecondLifeVorbis for now -- no fmod means no name collisions. +// MBW -- XXX -- Getting rid of SecondLifeVorbis for now #if 0 #include "VorbisFramework.h" diff --git a/indra/llaudio/llwindgen.h b/indra/llaudio/llwindgen.h index b9cecb60a1..719b0ecbf2 100644 --- a/indra/llaudio/llwindgen.h +++ b/indra/llaudio/llwindgen.h @@ -27,6 +27,7 @@ #define WINDGEN_H #include "llcommon.h" +#include "llrand.h" template <class MIXBUFFERFORMAT_T> class LLWindGen @@ -54,7 +55,9 @@ public: } const U32 getInputSamplingRate() { return mInputSamplingRate; } - + const F32 getNextSample(); + const F32 getClampedSample(bool clamp, F32 sample); + // newbuffer = the buffer passed from the previous DSP unit. // numsamples = length in samples-per-channel at this mix time. // NOTE: generates L/R interleaved stereo @@ -89,7 +92,7 @@ public: // Start with white noise // This expression is fragile, rearrange it and it will break! - next_sample = (F32)rand() * (1.0f / (F32)(RAND_MAX / (U16_MAX / 8))) + (F32)(S16_MIN / 8); + next_sample = getNextSample(); // Apply a pinking filter // Magic numbers taken from PKE method at http://www.firstpr.com.au/dsp/pink-noise/ @@ -126,23 +129,13 @@ public: for (U8 i=mSubSamples; i && numsamples; --i, --numsamples) { mLastSample = mLastSample + delta; - S32 sample_right = (S32)(mLastSample * mCurrentPanGainR); - S32 sample_left = (S32)mLastSample - sample_right; + MIXBUFFERFORMAT_T sample_right = (MIXBUFFERFORMAT_T)getClampedSample(clip, mLastSample * mCurrentPanGainR); + MIXBUFFERFORMAT_T sample_left = (MIXBUFFERFORMAT_T)getClampedSample(clip, mLastSample - (F32)sample_right); - if (!clip) - { - *cursamplep = (MIXBUFFERFORMAT_T)sample_left; - ++cursamplep; - *cursamplep = (MIXBUFFERFORMAT_T)sample_right; - ++cursamplep; - } - else - { - *cursamplep = (MIXBUFFERFORMAT_T)llclamp(sample_left, (S32)S16_MIN, (S32)S16_MAX); - ++cursamplep; - *cursamplep = (MIXBUFFERFORMAT_T)llclamp(sample_right, (S32)S16_MIN, (S32)S16_MAX); - ++cursamplep; - } + *cursamplep = sample_left; + ++cursamplep; + *cursamplep = sample_right; + ++cursamplep; } } @@ -173,4 +166,9 @@ private: F32 mLastSample; }; +template<class T> inline const F32 LLWindGen<T>::getNextSample() { return (F32)rand() * (1.0f / (F32)(RAND_MAX / (U16_MAX / 8))) + (F32)(S16_MIN / 8); } +template<> inline const F32 LLWindGen<F32>::getNextSample() { return ll_frand()-.5f; } +template<class T> inline const F32 LLWindGen<T>::getClampedSample(bool clamp, F32 sample) { return clamp ? (F32)llclamp((S32)sample,(S32)S16_MIN,(S32)S16_MAX) : sample; } +template<> inline const F32 LLWindGen<F32>::getClampedSample(bool clamp, F32 sample) { return sample; } + #endif diff --git a/indra/llcommon/llversionviewer.h b/indra/llcommon/llversionviewer.h index ae5e3ecade..0ea130e86b 100644 --- a/indra/llcommon/llversionviewer.h +++ b/indra/llcommon/llversionviewer.h @@ -29,7 +29,7 @@ const S32 LL_VERSION_MAJOR = 3; const S32 LL_VERSION_MINOR = 5; -const S32 LL_VERSION_PATCH = 1; +const S32 LL_VERSION_PATCH = 2; const S32 LL_VERSION_BUILD = 264760; const char * const LL_CHANNEL = "Second Life Developer"; diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 2fd025cda4..f6c8e12140 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -10,7 +10,7 @@ include(DirectX) include(OpenSSL) include(DragDrop) include(EXPAT) -include(FMOD) +include(FMODEX) include(OPENAL) include(OpenGL) include(Hunspell) @@ -53,6 +53,10 @@ if (NOT HAVOK_TPV) add_subdirectory(${LLPHYSICSEXTENSIONS_SRC_DIR} llphysicsextensions) endif (NOT HAVOK_TPV) +if(FMODEX) + include_directories(${FMODEX_INCLUDE_DIR}) +endif(FMODEX) + include_directories( ${DBUSGLIB_INCLUDE_DIRS} ${JSONCPP_INCLUDE_DIR} @@ -62,7 +66,6 @@ include_directories( ${LLCOMMON_INCLUDE_DIRS} ${LLCOREHTTP_INCLUDE_DIRS} ${LLPHYSICS_INCLUDE_DIRS} - ${FMOD_INCLUDE_DIR} ${LLIMAGE_INCLUDE_DIRS} ${LLKDU_INCLUDE_DIRS} ${LLINVENTORY_INCLUDE_DIRS} @@ -1537,29 +1540,12 @@ endif (WINDOWS) if (OPENAL) set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_OPENAL") -endif (OPENAL) - -if (FMOD) - set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_FMOD") +endif (OPENAL) - if (DARWIN) - set(fmodwrapper_SOURCE_FILES fmodwrapper.cpp) - add_library(fmodwrapper SHARED ${fmodwrapper_SOURCE_FILES}) - set(fmodwrapper_needed_LIBRARIES ${FMOD_LIBRARY} ${CARBON_LIBRARY}) - set_target_properties( - fmodwrapper - PROPERTIES - BUILD_WITH_INSTALL_RPATH 1 - INSTALL_NAME_DIR "@executable_path/../Resources" - LINK_FLAGS "-unexported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/fmod_hidden_symbols.exp" - ) - set(FMODWRAPPER_LIBRARY fmodwrapper) - target_link_libraries(fmodwrapper ${fmodwrapper_needed_LIBRARIES}) - else (DARWIN) - # fmodwrapper unnecessary on linux or windows - set(FMODWRAPPER_LIBRARY ${FMOD_LIBRARY}) - endif (DARWIN) -endif (FMOD) +if (FMODEX) + set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_FMODEX") + set(FMODWRAPPER_LIBRARY ${FMODEX_LIBRARY}) +endif (FMODEX) set_source_files_properties(llstartup.cpp PROPERTIES COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS}") @@ -1640,9 +1626,6 @@ if (WINDOWS) ${SHARED_LIB_STAGING_DIR}/Release/openjpeg.dll ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/openjpeg.dll ${SHARED_LIB_STAGING_DIR}/Debug/openjpegd.dll - ${SHARED_LIB_STAGING_DIR}/Release/fmod.dll - ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/fmod.dll - ${SHARED_LIB_STAGING_DIR}/Debug/fmod.dll ${SHARED_LIB_STAGING_DIR}/Release/msvcr100.dll ${SHARED_LIB_STAGING_DIR}/Release/msvcp100.dll ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/msvcr100.dll @@ -1707,6 +1690,14 @@ if (WINDOWS) windows-updater ) + if (FMODEX) + list(APPEND COPY_INPUT_DEPENDENCIES + ${SHARED_LIB_STAGING_DIR}/Release/fmodex.dll + ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/fmodex.dll + ${SHARED_LIB_STAGING_DIR}/Debug/fmodexL.dll + ) + endif (FMODEX) + add_custom_command( OUTPUT ${CMAKE_CFG_INTDIR}/copy_touched.bat COMMAND ${PYTHON_EXECUTABLE} diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index f66d8fca5b..3281d347a7 100755 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -291,6 +291,17 @@ <key>Value</key> <real>1.0</real> </map> + <key>AudioLevelUnderwaterRolloff</key> + <map> + <key>Comment</key> + <string>Controls the distance-based dropoff of audio volume underwater(fraction or multiple of default audio rolloff)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>5.0</real> + </map> <key>AudioLevelSFX</key> <map> <key>Comment</key> @@ -14446,7 +14457,50 @@ <key>Value</key> <integer>0</integer> </map> - + <key>DisablePrecacheDelayAfterTeleporting</key> + <map> + <key>Comment</key> + <string>Disables the artificial delay in the viewer that precaches some incoming assets</string> + <key>Persist</key> + <integer>0</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> + <key>FMODExProfilerEnable</key> + <map> + <key>Comment</key> + <string>Enable profiler tool if using FMOD Ex</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> + <key>FMODExDecodeBufferSize</key> + <map> + <key>Comment</key> + <string>Sets the streaming decode buffer size (in milliseconds)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>U32</string> + <key>Value</key> + <integer>1000</integer> + </map> + <key>FMODExStreamBufferSize</key> + <map> + <key>Comment</key> + <string>Sets the streaming buffer size (in milliseconds)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>U32</string> + <key>Value</key> + <integer>7000</integer> + </map> <key>DisablePrecacheDelayAfterTeleporting</key> <map> <key>Comment</key> diff --git a/indra/newview/fmod_hidden_symbols.exp b/indra/newview/fmod_hidden_symbols.exp deleted file mode 100644 index 1e790255bc..0000000000 --- a/indra/newview/fmod_hidden_symbols.exp +++ /dev/null @@ -1,240 +0,0 @@ -_CarbonSndPlayDoubleBuffer -_ConvertFromIeeeExtended -__book_maptype1_quantvals -__book_unquantize -__float32_pack -__float32_unpack -__ilog -__make_words -_lpc_clear -_lpc_init -__vorbis_block_alloc -__vorbis_block_ripcord -__vorbis_apply_window -__vorbis_window_get -_vorbis_analysis_blockout -_vorbis_analysis_buffer -_vorbis_analysis_wrote -_vorbis_block_clear -_vorbis_block_init -_vorbis_dsp_clear -_vorbis_synthesis_blockin -_vorbis_synthesis_init -_vorbis_synthesis_pcmout -_vorbis_synthesis_read -_vorbis_packet_blocksize -_vorbis_synthesis -_vorbis_book_clear -_vorbis_book_decode -_vorbis_book_decodev_add -_vorbis_book_decodev_set -_vorbis_book_decodevs_add -_vorbis_book_decodevv_add -_vorbis_book_init_decode -_vorbis_comment_add -_vorbis_comment_add_tag -_vorbis_comment_clear -_vorbis_comment_init -_vorbis_comment_query -_vorbis_comment_query_count -_vorbis_coslook -_vorbis_fromdBlook -_vorbis_info_blocksize -_vorbis_info_clear -_vorbis_info_init -_vorbis_invsq2explook -_vorbis_invsqlook -_vorbis_lpc_from_curve -_vorbis_lpc_from_data -_vorbis_lpc_predict -_vorbis_lsp_to_curve -_vorbis_staticbook_clear -_vorbis_staticbook_destroy -_vorbis_staticbook_unpack -_vorbis_synthesis_headerin -_vorbis_synthesis_lapout -_vorbis_synthesis_restart -_vorbis_synthesis_trackonly -_vorbis_window -_ogg_packet_clear -_ogg_page_bos -_ogg_page_checksum_set -_ogg_page_continued -_ogg_page_eos -_ogg_page_granulepos -_ogg_page_packets -_ogg_page_pageno -_ogg_page_serialno -_ogg_page_version -_ogg_stream_reset_serialno -_ogg_stream_clear -_ogg_stream_destroy -_ogg_stream_eos -_ogg_stream_flush -_ogg_stream_init -_ogg_stream_packetout -_ogg_stream_packetpeek -_ogg_stream_pagein -_ogg_stream_pageout -_ogg_stream_reset -_ogg_sync_buffer -_ogg_sync_clear -_ogg_sync_destroy -_ogg_sync_init -_ogg_sync_pageout -_ogg_sync_pageseek -_ogg_sync_reset -_ogg_sync_wrote -_ov_bitrate -_ov_bitrate_instant -_ov_clear -_ov_comment -_ov_info -_ov_open -_ov_open_callbacks -_ov_pcm_seek -_ov_pcm_seek_page -_ov_pcm_tell -_ov_pcm_total -_ov_raw_seek -_ov_raw_tell -_ov_raw_total -_ov_read -_ov_read_float -_ov_seekable -_ov_serialnumber -_ov_streams -_ov_test -_ov_test_callbacks -_ov_test_open -_ov_time_seek -_ov_time_seek_page -_ov_time_tell -_ov_time_total -_ogg_toupper -_oggpackB_adv -_oggpackB_adv1 -_oggpackB_bits -_oggpackB_bytes -_oggpackB_get_buffer -_oggpackB_look -_oggpackB_look1 -_oggpackB_read -_oggpackB_read1 -_oggpackB_readinit -_oggpackB_reset -_oggpack_adv -_oggpack_adv1 -_oggpack_bits -_oggpack_bytes -_oggpack_get_buffer -_oggpack_look -_oggpack_look1 -_oggpack_read -_oggpack_read1 -_oggpack_readinit -_oggpack_reset -_ov_crosslap -_ov_pcm_seek_lap -_ov_pcm_seek_page_lap -_ov_raw_seek_lap -_ov_time_seek_lap -_ov_time_seek_page_lap -_II_step_one -_II_step_two -_MyRecComp -_SampleRates -_Sinfo -_ValidStepIndex -__Z11fmodwrapperv -__Z11fmodwrapperv.eh -__floor_P -__mapping_P -__residue_P -__ve_envelope_clear -__ve_envelope_init -__ve_envelope_mark -__ve_envelope_search -__ve_envelope_shift -__vi_gpsy_free -__vi_psy_free -__vorbis_window_init -__vp_ampmax_decay -__vp_couple -__vp_global_free -__vp_global_look -__vp_noise_normalize -__vp_noise_normalize_sort -__vp_noisemask -__vp_offset_and_mix -__vp_psy_clear -__vp_psy_init -__vp_quantize_couple_memo -__vp_quantize_couple_sort -__vp_remove_floor -__vp_tonemask -_alloc_0 -_alloc_1 -_alloc_2 -_alloc_3 -_alloc_4 -_bandInfo -_cdcallback -_cdchannel -_cdmode -_cdnumtracks -_cdstream -_cdtrack -_drft_backward -_drft_clear -_drft_forward -_drft_init -_eatwhite -_floor0_exportbundle -_floor1_exportbundle -_gFreeList -_gNMRecBusy -_gNMRecPtr -_gSilenceOnes -_gSilenceTwos -_longLimit -_mapping0_exportbundle -_mdct_backward -_mdct_clear -_mdct_forward -_mdct_init -_muls -_mystrdup -_res0_free_info -_res0_free_look -_res0_inverse -_res0_look -_res0_unpack -_res1_class -_res1_inverse -_res2_inverse -_residue0_exportbundle -_residue1_exportbundle -_residue2_exportbundle -_scale -_shortLimit -_tabsel_123 -_F_Free -_F_Malloc -_F_ReAlloc -_F_memcmp -_F_memmove -_F_strcat -_F_strchr -_F_strcmp -_F_strcpy -_F_stricmp -_F_strlen -_F_strncat -_F_strncmp -_F_strncpy -_F_strnicmp -_F_strstr -_F_strupr -_F_tolower -_F_toupper diff --git a/indra/newview/fmodwrapper.cpp b/indra/newview/fmodwrapper.cpp deleted file mode 100644 index 16f1d19a78..0000000000 --- a/indra/newview/fmodwrapper.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/** - * @file fmodwrapper.cpp - * @brief dummy source file for building a shared library to wrap libfmod.a - * - * $LicenseInfo:firstyear=2005&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$ - */ - -extern "C" -{ - void FSOUND_Init(void); -} - -void* fmodwrapper(void) -{ - // When building the fmodwrapper library, the linker doesn't seem to want to bring in libfmod.a unless I explicitly - // reference at least one symbol in the library. This seemed like the simplest way. - return (void*)&FSOUND_Init; -} diff --git a/indra/newview/linux_tools/wrapper.sh b/indra/newview/linux_tools/wrapper.sh index 1381e49c62..48b883e999 100755 --- a/indra/newview/linux_tools/wrapper.sh +++ b/indra/newview/linux_tools/wrapper.sh @@ -4,17 +4,17 @@ ## These options are for self-assisted troubleshooting during this beta ## testing phase; you should not usually need to touch them. +## - Avoids using any FMOD Ex audio driver. +#export LL_BAD_FMODEX_DRIVER=x ## - Avoids using any OpenAL audio driver. #export LL_BAD_OPENAL_DRIVER=x -## - Avoids using any FMOD audio driver. -#export LL_BAD_FMOD_DRIVER=x -## - Avoids using the FMOD ESD audio driver. -#export LL_BAD_FMOD_ESD=x -## - Avoids using the FMOD OSS audio driver. -#export LL_BAD_FMOD_OSS=x -## - Avoids using the FMOD ALSA audio driver. +## - Avoids using the FMOD Ex PulseAudio audio driver. +#export LL_BAD_FMOD_PULSEAUDIO=x +## - Avoids using the FMOD or FMOD Ex ALSA audio driver. #export LL_BAD_FMOD_ALSA=x +## - Avoids using the FMOD or FMOD Ex OSS audio driver. +#export LL_BAD_FMOD_OSS=x ## - Avoids the optional OpenGL extensions which have proven most problematic ## on some hardware. Disabling this option may cause BETTER PERFORMANCE but diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 03d9b683a4..49c553d0cc 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1708,19 +1708,7 @@ bool LLAppViewer::cleanup() gAudiop->setStreamingAudioImpl(NULL); // shut down the audio subsystem - - bool want_longname = false; - if (gAudiop->getDriverName(want_longname) == "FMOD") - { - // This hack exists because fmod likes to occasionally - // crash or hang forever when shutting down, for no - // apparent reason. - llwarns << "Hack, skipping FMOD audio engine cleanup" << llendflush; - } - else - { - gAudiop->shutdown(); - } + gAudiop->shutdown(); delete gAudiop; gAudiop = NULL; diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp index 3e0e82b579..113aa9a8f2 100644 --- a/indra/newview/llfloateravatarpicker.cpp +++ b/indra/newview/llfloateravatarpicker.cpp @@ -818,7 +818,14 @@ bool LLFloaterAvatarPicker::isSelectBtnEnabled() uuid_vec_t avatar_ids; std::vector<LLAvatarName> avatar_names; getSelectedAvatarData(list, avatar_ids, avatar_names); - return mOkButtonValidateSignal(avatar_ids); + if (avatar_ids.size() >= 1) + { + ret_val = mOkButtonValidateSignal(avatar_ids); + } + else + { + ret_val = false; + } } } diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 5e6175c4ed..a14a435156 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -37,8 +37,8 @@ #include "llviewermedia_streamingaudio.h" #include "llaudioengine.h" -#ifdef LL_FMOD -# include "llaudioengine_fmod.h" +#ifdef LL_FMODEX +# include "llaudioengine_fmodex.h" #endif #ifdef LL_OPENAL @@ -624,32 +624,32 @@ bool idle_startup() { gAudiop = NULL; -#ifdef LL_OPENAL +#ifdef LL_FMODEX if (!gAudiop #if !LL_WINDOWS - && NULL == getenv("LL_BAD_OPENAL_DRIVER") + && NULL == getenv("LL_BAD_FMODEX_DRIVER") #endif // !LL_WINDOWS ) { - gAudiop = (LLAudioEngine *) new LLAudioEngine_OpenAL(); + gAudiop = (LLAudioEngine *) new LLAudioEngine_FMODEX(gSavedSettings.getBOOL("FMODExProfilerEnable")); } #endif -#ifdef LL_FMOD +#ifdef LL_OPENAL if (!gAudiop #if !LL_WINDOWS - && NULL == getenv("LL_BAD_FMOD_DRIVER") + && NULL == getenv("LL_BAD_OPENAL_DRIVER") #endif // !LL_WINDOWS ) { - gAudiop = (LLAudioEngine *) new LLAudioEngine_FMOD(); + gAudiop = (LLAudioEngine *) new LLAudioEngine_OpenAL(); } #endif - + if (gAudiop) { #if LL_WINDOWS - // FMOD on Windows needs the window handle to stop playing audio + // FMOD Ex on Windows needs the window handle to stop playing audio // when window is minimized. JC void* window_handle = (HWND)gViewerWindow->getPlatformWindow(); #else diff --git a/indra/newview/llvieweraudio.cpp b/indra/newview/llvieweraudio.cpp index 564bf7997a..094694dc06 100644 --- a/indra/newview/llvieweraudio.cpp +++ b/indra/newview/llvieweraudio.cpp @@ -44,6 +44,8 @@ #include "llparcel.h" #include "llviewermessage.h" +#include "llstreamingaudio.h" + ///////////////////////////////////////////////////////// LLViewerAudio::LLViewerAudio() : @@ -102,6 +104,11 @@ void LLViewerAudio::startInternetStreamWithAutoFade(std::string streamURI) else { mFadeState = FADE_IN; + + LLStreamingAudioInterface *stream = gAudiop->getStreamingAudioImpl(); + if(stream && stream->supportsAdjustableBufferSizes()) + stream->setBufferSizes(gSavedSettings.getU32("FMODExStreamBufferSize"),gSavedSettings.getU32("FMODExDecodeBufferSize")); + gAudiop->startInternetStream(mNextStreamURI); startFading(); registerIdleListener(); @@ -157,6 +164,11 @@ bool LLViewerAudio::onIdleUpdate() if (!mNextStreamURI.empty()) { mFadeState = FADE_IN; + + LLStreamingAudioInterface *stream = gAudiop->getStreamingAudioImpl(); + if(stream && stream->supportsAdjustableBufferSizes()) + stream->setBufferSizes(gSavedSettings.getU32("FMODExStreamBufferSize"),gSavedSettings.getU32("FMODExDecodeBufferSize")); + gAudiop->startInternetStream(mNextStreamURI); startFading(); } @@ -386,7 +398,12 @@ void audio_update_volume(bool force_update) gAudiop->setMasterGain ( master_volume ); gAudiop->setDopplerFactor(gSavedSettings.getF32("AudioLevelDoppler")); - gAudiop->setRolloffFactor(gSavedSettings.getF32("AudioLevelRolloff")); + + if(!LLViewerCamera::getInstance()->cameraUnderWater()) + gAudiop->setRolloffFactor(gSavedSettings.getF32("AudioLevelRolloff")); + else + gAudiop->setRolloffFactor(gSavedSettings.getF32("AudioLevelUnderwaterRolloff")); + gAudiop->setMuted(mute_audio || progress_view_visible); //Play any deferred sounds when unmuted @@ -473,44 +490,22 @@ void audio_update_listener() void audio_update_wind(bool force_update) { #ifdef kAUDIO_ENABLE_WIND - // - // Extract height above water to modulate filter by whether above/below water - // + LLViewerRegion* region = gAgent.getRegion(); if (region) { - static F32 last_camera_water_height = -1000.f; - LLVector3 camera_pos = gAgentCamera.getCameraPositionAgent(); - F32 camera_water_height = camera_pos.mV[VZ] - region->getWaterHeight(); - - // - // Don't update rolloff factor unless water surface has been crossed - // - if (force_update || (last_camera_water_height * camera_water_height) < 0.f) - { - static LLUICachedControl<F32> rolloff("AudioLevelRolloff", 1.0f); - if (camera_water_height < 0.f) - { - gAudiop->setRolloffFactor(rolloff * LL_ROLLOFF_MULTIPLIER_UNDER_WATER); - } - else - { - gAudiop->setRolloffFactor(rolloff); - } - } - - // Scale down the contribution of weather-simulation wind to the - // ambient wind noise. Wind velocity averages 3.5 m/s, with gusts to 7 m/s - // whereas steady-state avatar walk velocity is only 3.2 m/s. - // Without this the world feels desolate on first login when you are - // standing still. - static LLUICachedControl<F32> wind_level("AudioLevelWind", 0.5f); - LLVector3 scaled_wind_vec = gWindVec * wind_level; - - // Mix in the avatar's motion, subtract because when you walk north, - // the apparent wind moves south. - LLVector3 final_wind_vec = scaled_wind_vec - gAgent.getVelocity(); - + // Scale down the contribution of weather-simulation wind to the + // ambient wind noise. Wind velocity averages 3.5 m/s, with gusts to 7 m/s + // whereas steady-state avatar walk velocity is only 3.2 m/s. + // Without this the world feels desolate on first login when you are + // standing still. + static LLUICachedControl<F32> wind_level("AudioLevelWind", 0.5f); + LLVector3 scaled_wind_vec = gWindVec * wind_level; + + // Mix in the avatar's motion, subtract because when you walk north, + // the apparent wind moves south. + LLVector3 final_wind_vec = scaled_wind_vec - gAgent.getVelocity(); + // rotate the wind vector to be listener (agent) relative gRelativeWindVec = gAgent.getFrameAgent().rotateToLocal( final_wind_vec ); @@ -543,8 +538,7 @@ void audio_update_wind(bool force_update) gAudiop->mMaxWindGain = llmax(gAudiop->mMaxWindGain - volume_delta, 0.f); } - last_camera_water_height = camera_water_height; - gAudiop->updateWind(gRelativeWindVec, camera_water_height); + gAudiop->updateWind(gRelativeWindVec, gAgentCamera.getCameraPositionAgent()[VZ] - gAgent.getRegion()->getWaterHeight()); } #endif } diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index 051f5f4485..a62f73deef 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -655,6 +655,7 @@ void settings_setup_listeners() gSavedSettings.getControl("AudioLevelVoice")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2)); gSavedSettings.getControl("AudioLevelDoppler")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2)); gSavedSettings.getControl("AudioLevelRolloff")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2)); + gSavedSettings.getControl("AudioLevelUnderwaterRolloff")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2)); gSavedSettings.getControl("MuteAudio")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2)); gSavedSettings.getControl("MuteMusic")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2)); gSavedSettings.getControl("MuteMedia")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2)); diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index fcf5af76ff..670272e7be 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -2697,24 +2697,33 @@ void LLViewerObject::processTaskInvFile(void** user_data, S32 error_code, LLExtS if(ft && (0 == error_code) && (object = gObjectList.findObject(ft->mTaskID))) { - object->loadTaskInvFile(ft->mFilename); + if (object->loadTaskInvFile(ft->mFilename)) + { - LLInventoryObject::object_list_t::iterator it = object->mInventory->begin(); - LLInventoryObject::object_list_t::iterator end = object->mInventory->end(); - std::list<LLUUID>& pending_lst = object->mPendingInventoryItemsIDs; + LLInventoryObject::object_list_t::iterator it = object->mInventory->begin(); + LLInventoryObject::object_list_t::iterator end = object->mInventory->end(); + std::list<LLUUID>& pending_lst = object->mPendingInventoryItemsIDs; - for (; it != end && pending_lst.size(); ++it) - { - LLViewerInventoryItem* item = dynamic_cast<LLViewerInventoryItem*>(it->get()); - if(item && item->getType() != LLAssetType::AT_CATEGORY) + for (; it != end && pending_lst.size(); ++it) { - std::list<LLUUID>::iterator id_it = std::find(pending_lst.begin(), pending_lst.begin(), item->getAssetUUID()); - if (id_it != pending_lst.end()) + LLViewerInventoryItem* item = dynamic_cast<LLViewerInventoryItem*>(it->get()); + if(item && item->getType() != LLAssetType::AT_CATEGORY) { - pending_lst.erase(id_it); + std::list<LLUUID>::iterator id_it = std::find(pending_lst.begin(), pending_lst.begin(), item->getAssetUUID()); + if (id_it != pending_lst.end()) + { + pending_lst.erase(id_it); + } } } } + else + { + // MAINT-2597 - crash when trying to edit a no-mod object + // Somehow get an contents inventory response, but with an invalid stream (possibly 0 size?) + // Stated repro was specific to no-mod objects so failing without user interaction should be safe. + llwarns << "Trying to load invalid task inventory file. Ignoring file contents." << llendl; + } } else { @@ -2726,7 +2735,7 @@ void LLViewerObject::processTaskInvFile(void** user_data, S32 error_code, LLExtS delete ft; } -void LLViewerObject::loadTaskInvFile(const std::string& filename) +BOOL LLViewerObject::loadTaskInvFile(const std::string& filename) { std::string filename_and_local_path = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, filename); llifstream ifs(filename_and_local_path); @@ -2773,8 +2782,11 @@ void LLViewerObject::loadTaskInvFile(const std::string& filename) { llwarns << "unable to load task inventory: " << filename_and_local_path << llendl; + return FALSE; } doInventoryCallback(); + + return TRUE; } void LLViewerObject::doInventoryCallback() diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index 728d279c39..316dbce7d0 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -656,7 +656,7 @@ protected: // static void processTaskInvFile(void** user_data, S32 error_code, LLExtStat ext_status); - void loadTaskInvFile(const std::string& filename); + BOOL loadTaskInvFile(const std::string& filename); void doInventoryCallback(); BOOL isOnMap(); diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 9fb6da166e..725670d33f 100755 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -803,14 +803,14 @@ void LLVOAvatar::debugAvatarRezTime(std::string notification_name, std::string c //------------------------------------------------------------------------ LLVOAvatar::~LLVOAvatar() { - if (!mFullyLoaded) - { + if (!mFullyLoaded) + { debugAvatarRezTime("AvatarRezLeftCloudNotification","left after ruth seconds as cloud"); - } - else - { + } + else + { debugAvatarRezTime("AvatarRezLeftNotification","left sometime after declouding"); - } + } logPendingPhases(); @@ -6024,6 +6024,11 @@ void LLVOAvatar::stopPhase(const std::string& phase_name, bool err_check) void LLVOAvatar::logPendingPhases() { + if (!isAgentAvatarValid()) + { + return; + } + for (LLViewerStats::phase_map_t::iterator it = getPhases().begin(); it != getPhases().end(); ++it) @@ -6058,6 +6063,11 @@ void LLVOAvatar::logPendingPhasesAllAvatars() void LLVOAvatar::logMetricsTimerRecord(const std::string& phase_name, F32 elapsed, bool completed) { + if (!isAgentAvatarValid()) + { + return; + } + LLSD record; record["timer_name"] = phase_name; record["avatar_id"] = getID(); @@ -6074,13 +6084,6 @@ void LLVOAvatar::logMetricsTimerRecord(const std::string& phase_name, F32 elapse record["is_using_server_bakes"] = ((bool) isUsingServerBakes()); record["is_self"] = isSelf(); - -#if 0 // verbose logging - std::ostringstream ostr; - ostr << LLSDNotationStreamer(record); - LL_DEBUGS("Avatar") << "record\n" << ostr.str() << llendl; -#endif - if (isAgentAvatarValid()) { gAgentAvatarp->addMetricsTimerRecord(record); diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 69248e26bc..e2b914aae8 100644 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -367,10 +367,14 @@ class WindowsManifest(ViewerManifest): print err.message print "Skipping COLLADA and GLOD libraries (assumming linked statically)" - - # Get fmod dll, continue if missing - if not self.path("fmod.dll"): - print "Skipping fmod.dll" + # Get fmodex dll, continue if missing + try: + if self.args['configuration'].lower() == 'debug': + self.path("fmodexL.dll") + else: + self.path("fmodex.dll") + except: + print "Skipping fmodex audio library(assuming other audio engine)" # For textures if self.args['configuration'].lower() == 'debug': @@ -743,6 +747,7 @@ class DarwinManifest(ViewerManifest): "libcollada14dom.dylib", "libexpat.1.5.2.dylib", "libexception_handler.dylib", + "libfmodex.dylib", "libGLOD.dylib", ): dylibs += path_optional(os.path.join(libdir, libfile), libfile) @@ -757,11 +762,7 @@ class DarwinManifest(ViewerManifest): 'SLVoice', ): self.path2basename(libdir, libfile) - - # FMOD for sound - libfile = "libfmodwrapper.dylib" - path_optional(os.path.join(self.args['configuration'], libfile), libfile) - + # our apps for app_bld_dir, app in (("mac_crash_logger", "mac-crash-logger.app"), ("mac_updater", "mac-updater.app"), @@ -1122,11 +1123,13 @@ class Linux_i686Manifest(LinuxManifest): pass try: - self.path("libfmod-3.75.so") + self.path("libfmodex-*.so") + self.path("libfmodex.so") pass except: - print "Skipping libfmod-3.75.so - not found" + print "Skipping libfmodex.so - not found" pass + self.end_prefix("lib") # Vivox runtimes |