Quantcast 7.3 Broken PlaySoundFile()/PlaySound() - WoWInterface
Thread Tools Display Modes
10-30-17, 06:17 AM   #1
ballistics1142
A Deviate Faerie Dragon
Join Date: Apr 2017
Posts: 14
Question 7.3 Broken PlaySoundFile()/PlaySound()

Hi,

I did a taint log to find what was the main cause of these lua errors(I'm aware of the logout/quit functions are now protected in 7.3), and apparently it's on the 4/9th line of my small addon.

This was an addon created for me by Afterafterlife @ https://www.reddit.com/r/wowaddons/c..._addon_sounds/

which i have shown below;

Code:
    -- This file is loaded from "!Play_Addon_Sounds.toc"
    
    local BlizzPlaySoundFile = PlaySoundFile; 
    function PlaySoundFile(fileName, track)
        BlizzPlaySoundFile(fileName, "MASTER");
    end
    
    local BlizzPlaySound = PlaySound;
    function PlaySound(fileName, track)
        --we don't need sounds here
        return;
    end
How do I change the arguments here on the code lines below to reference all SoundKitID's;

Code:
function PlaySoundFile(fileName, track)
Code:
 function PlaySound(fileName, track)
Any help will be greatly appreciated!
  Reply With Quote
10-30-17, 08:45 AM   #2
MunkDev
A Scalebane Royal Guard
 
MunkDev's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2015
Posts: 417
What you're doing is not safe. Any time the default UI calls your replacement functions the execution path becomes tainted afterwards. If the call to PlaySound is eventually followed by some protected function call from signed code down the path, then it's going to break.

In cases where you want to replace an API function, you need to make sure that the function isn't used in any execution path that ultimately does something protected.
__________________
  Reply With Quote
10-30-17, 03:11 PM   #3
ballistics1142
A Deviate Faerie Dragon
Join Date: Apr 2017
Posts: 14
Originally Posted by MunkDev View Post
What you're doing is not safe. Any time the default UI calls your replacement functions the execution path becomes tainted afterwards. If the call to PlaySound is eventually followed by some protected function call from signed code down the path, then it's going to break.

In cases where you want to replace an API function, you need to make sure that the function isn't used in any execution path that ultimately does something protected.
Ok so in that case, can you think of another way of achieving the same end result i'm looking for in that addon without breaking the execution path?
  Reply With Quote
10-30-17, 04:05 PM   #4
MunkDev
A Scalebane Royal Guard
 
MunkDev's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2015
Posts: 417
Unless Blizzard provides some CVar to disable PlaySound or add a dedicated UI sound channel, you can't really do much except replace sound files, if that still works. Replacing PlaySound with a tainted function will cause a ton of problems because it's used indiscriminately across the UI. As of 7.3, you probably can't even log out with this "fix" in place because of the sound played on the logout popup.
__________________

Last edited by MunkDev : 10-30-17 at 04:10 PM.
  Reply With Quote
10-30-17, 04:11 PM   #5
Fizzlemizz
I did that?
 
Fizzlemizz's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Dec 2011
Posts: 931
And as mentioned in your other thread, you can't alter the SOUNKIT table.
__________________
Fizzlemizz
Maintainer of Discord Unit Frames and Discord Art.
Author of FauxMazzle and Move Pad Plus.
  Reply With Quote
10-30-17, 04:26 PM   #6
ballistics1142
A Deviate Faerie Dragon
Join Date: Apr 2017
Posts: 14
Originally Posted by MunkDev View Post
As of 7.3, you probably can't even log out with this "fix" in place because of the sound played on the logout popup.
Yes that is exactly my issue at the moment.

Originally Posted by Fizzlemizz View Post
And as mentioned in your other thread, you can't alter the SOUNKIT table.
Ok I understand that completely now after more research.

So again with another question;

Can I use Ace3 Libraries to overcome this issue? Specifically "AceHook-3.0
Including AceHook functionality"
  Reply With Quote
10-30-17, 04:37 PM   #7
Fizzlemizz
I did that?
 
Fizzlemizz's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Dec 2011
Posts: 931
No, Ace uses exactly the same API as all other addons and as noted previously, hooking is used for calling one functon after another, not instead of.
__________________
Fizzlemizz
Maintainer of Discord Unit Frames and Discord Art.
Author of FauxMazzle and Move Pad Plus.
  Reply With Quote
10-30-17, 04:50 PM   #8
ballistics1142
A Deviate Faerie Dragon
Join Date: Apr 2017
Posts: 14
Originally Posted by Fizzlemizz View Post
No, Ace uses exactly the same API as all other addons and as noted previously, hooking is used for calling one functon after another, not instead of.
Thank you for the clarification. So I hate to admit but i'm getting the vibe i'm just going to have to swallow this issue until blizzard potentially remedies it.

Just had an idea;

What about allowing the blizzard ui sounds to go through except spell and music? Or would that be futile?

Last edited by ballistics1142 : 10-30-17 at 04:57 PM.
  Reply With Quote
10-30-17, 05:09 PM   #9
MunkDev
A Scalebane Royal Guard
 
MunkDev's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2015
Posts: 417
Actually, now that we're talking about sound kits, I remembered that PlaySound was replaced by PlaySoundkitID in 7.2(?) so you can actually mute sounds with a filthy little hack. PlaySoundkitID (and PlaySoundFile) both return handles in the form of an integer ID that increments on every call. So by hooking into PlaySound and playing another sound immediately after it you can figure out the sound handle ID and cancel it.


Lua Code:
  1. local mutex = false -- need this so it doesn't recurse when PlaySound is called from within
  2. hooksecurefunc('PlaySound', function(id)
  3.           if mutex then return end -- we called this time, just return
  4.           mutex = true -- flag mutex
  5.           -- play another sound to figure out the ID.
  6.           -- can't play the same sound because it's occupied by another handle.
  7.           local played, handle = PlaySound(id+1) -- just use the ID+1 to guarantee it's different
  8.           mutex = false -- unflag mutex
  9.           if played then
  10.                StopSound(handle-1) -- stop the sound you wanted to stop in the first place
  11.                StopSound(handle) -- stop your dummy sound
  12.           end
  13. end)

This should effectively do what you asked for, without replacing the function and without spreading taint.
__________________

Last edited by MunkDev : 10-30-17 at 05:35 PM.
  Reply With Quote
10-30-17, 05:57 PM   #10
Fizzlemizz
I did that?
 
Fizzlemizz's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Dec 2011
Posts: 931
That's sneaky and clever. Well done.
__________________
Fizzlemizz
Maintainer of Discord Unit Frames and Discord Art.
Author of FauxMazzle and Move Pad Plus.
  Reply With Quote
10-30-17, 06:44 PM   #11
Kanegasi
A Frostmaul Preserver
 
Kanegasi's Avatar
AddOn Author - Click to view addons
Join Date: Apr 2007
Posts: 284
It was a shame PlaySoundKitID was removed. I used this hack to silence some UI sounds and the UI never, as far as I knew, didn't even use KitID, so I hooked PlaySound and then used PlaySoundKitID to generate the handle+1. Instead of the variable switch you have, I went with adding an extra argument to PlaySound.

Lua Code:
  1. local blockedsounds={
  2.     igCharacterInfoClose=840,
  3.     igCharacterInfoOpen=839,
  4.     igMainMenuClose=851,
  5.     igMainMenuOpen=850,
  6.     igPlayerInvite=880,
  7.     igQuestListClose=876,
  8.     igQuestListOpen=875,
  9.     [839]=839,
  10.     [840]=840,
  11.     [850]=850,
  12.     [851]=851,
  13.     [875]=875,
  14.     [876]=876,
  15.     [880]=880,
  16. }
  17.  
  18. local function silence(name,handle,_,_,own)
  19.     if blockedsounds[name] and not own then
  20.         _,handle=PlaySound(64,'Master',false,nil,true)
  21.         if handle then
  22.             StopSound(handle) StopSound(handle-1)
  23.         end
  24.     end
  25. end
  26.  
  27. hooksecurefunc('PlaySound',silence)

I also have a framepool I left out that skips a frame then checks for a block variable and plays the sound anyways if the block variable is false. The sound names in the table were left in from when PlaySound used those, I kept them for history's sake.
  Reply With Quote
10-30-17, 10:14 PM   #12
ballistics1142
A Deviate Faerie Dragon
Join Date: Apr 2017
Posts: 14
Originally Posted by Kanegasi View Post
It was a shame PlaySoundKitID was removed. I used this hack to silence some UI sounds and the UI never, as far as I knew, didn't even use KitID, so I hooked PlaySound and then used PlaySoundKitID to generate the handle+1. Instead of the variable switch you have, I went with adding an extra argument to PlaySound.

Lua Code:
  1. local blockedsounds={
  2.     igCharacterInfoClose=840,
  3.     igCharacterInfoOpen=839,
  4.     igMainMenuClose=851,
  5.     igMainMenuOpen=850,
  6.     igPlayerInvite=880,
  7.     igQuestListClose=876,
  8.     igQuestListOpen=875,
  9.     [839]=839,
  10.     [840]=840,
  11.     [850]=850,
  12.     [851]=851,
  13.     [875]=875,
  14.     [876]=876,
  15.     [880]=880,
  16. }
  17.  
  18. local function silence(name,handle,_,_,own)
  19.     if blockedsounds[name] and not own then
  20.         _,handle=PlaySound(64,'Master',false,nil,true)
  21.         if handle then
  22.             StopSound(handle) StopSound(handle-1)
  23.         end
  24.     end
  25. end
  26.  
  27. hooksecurefunc('PlaySound',silence)

I also have a framepool I left out that skips a frame then checks for a block variable and plays the sound anyways if the block variable is false. The sound names in the table were left in from when PlaySound used those, I kept them for history's sake.

So before I go an further, is that example above a working revision?
  Reply With Quote
10-30-17, 11:15 PM   #13
MunkDev
A Scalebane Royal Guard
 
MunkDev's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2015
Posts: 417
If you want to mute all sounds, use this:
Lua Code:
  1. local dummy = false
  2. hooksecurefunc('PlaySound', function(id)
  3.         if dummy then return end
  4.         dummy = true
  5.         local played, handle = PlaySound(id+1)
  6.         if played then
  7.             StopSound(handle-1)
  8.             StopSound(handle)
  9.         end
  10.         dummy = false
  11. end)

If you want to allow unique sounds, like the talking head monologues or any other uncommon sound, but not UI sounds, use this:
Lua Code:
  1. local dummy, kit = false, {}
  2. for _, v in pairs(SOUNDKIT) do kit[v] = true end
  3.  
  4. hooksecurefunc('PlaySound', function(id)
  5.         if dummy or (not kit[id]) then return end
  6.         dummy = true
  7.         local played, handle = PlaySound(id+1)
  8.         if played then
  9.             StopSound(handle-1)
  10.             StopSound(handle)
  11.         end
  12.         dummy = false
  13. end)

If you want to mute specific sounds use Kanegasi's solution. They all work the same way.
__________________

Last edited by MunkDev : 10-30-17 at 11:41 PM.
  Reply With Quote
10-31-17, 06:56 AM   #14
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,277
Originally Posted by MunkDev View Post
If you want to mute all sounds, use this:
Lua Code:
  1. local dummy = false
  2. hooksecurefunc('PlaySound', function(id)
  3.         if dummy then return end
  4.         dummy = true
  5.         local played, handle = PlaySound(id+1)
  6.         if played then
  7.             StopSound(handle-1)
  8.             StopSound(handle)
  9.         end
  10.         dummy = false
  11. end)

If you want to allow unique sounds, like the talking head monologues or any other uncommon sound, but not UI sounds, use this:
Lua Code:
  1. local dummy, kit = false, {}
  2. for _, v in pairs(SOUNDKIT) do kit[v] = true end
  3.  
  4. hooksecurefunc('PlaySound', function(id)
  5.         if dummy or (not kit[id]) then return end
  6.         dummy = true
  7.         local played, handle = PlaySound(id+1)
  8.         if played then
  9.             StopSound(handle-1)
  10.             StopSound(handle)
  11.         end
  12.         dummy = false
  13. end)

If you want to mute specific sounds use Kanegasi's solution. They all work the same way.
The SOUNDKIT table is not nearly as complete as you would like it, mostly they just throw stuff into it that's used by the default UI.

Here is a complete table with old names and IDs that you can play with PlaySound:
https://github.com/Resike/BlizzardIn...ndKitNames.lua
  Reply With Quote
10-31-17, 11:05 AM   #15
ballistics1142
A Deviate Faerie Dragon
Join Date: Apr 2017
Posts: 14
Hey MunkDev,

Thanks for the suggestion. I'll get back to you on that!

Hey Resike,

Thanks aswell for your contribution of the soundkit table xD!

To everyone who wants to know what my results are, I will be sure to get back to you later!
  Reply With Quote
10-31-17, 11:27 AM   #16
Kanegasi
A Frostmaul Preserver
 
Kanegasi's Avatar
AddOn Author - Click to view addons
Join Date: Apr 2007
Posts: 284
Originally Posted by Resike View Post
Here is a complete table with old names and IDs that you can play with PlaySound:
https://github.com/Resike/BlizzardIn...ndKitNames.lua
I saw that name list in another thread here. Did you generate that? Is there a source or some way to extract that?
  Reply With Quote
10-31-17, 11:29 AM   #17
ballistics1142
A Deviate Faerie Dragon
Join Date: Apr 2017
Posts: 14
Originally Posted by Kanegasi View Post
I saw that name list in another thread here. Did you generate that? Is there a source or some way to extract that?
I know what your talking about as I believe I got this link off "Fizzlemizz" on here;

https://docs.google.com/spreadsheets...gid=1243506593
  Reply With Quote
10-31-17, 01:44 PM   #18
MunkDev
A Scalebane Royal Guard
 
MunkDev's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2015
Posts: 417
Originally Posted by Resike View Post
The SOUNDKIT table is not nearly as complete as you would like it, mostly they just throw stuff into it that's used by the default UI.
It encompasses all the sounds used by the default UI, which was the point of copying the entries. I wasn't saying it's complete in any sense.
One of the specifications was to allow addons to play sounds, and a lot of addons will likely use sounds (alerts etc) that are not in the soundkit table.
__________________

Last edited by MunkDev : 10-31-17 at 01:50 PM.
  Reply With Quote
10-31-17, 04:58 PM   #19
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,277
Originally Posted by Kanegasi View Post
I saw that name list in another thread here. Did you generate that? Is there a source or some way to extract that?
I did not generated myself since i would probably get the same table, but you can do it:

You can open the soundkitentry.db2 from the DBCFiles with WDBX then you can get the FileDataID for every SoundKitID, which would eventually point to a file name, if you crosscheck it with the lastly updated FileDataID. From there you need another table conversion from an older DBCFiles which helps with the Sound FilePath - SoundKit Name conversion, and tada.

Or you could just use the soundkitname.db2 and write the values out raw. But that's for non-masochists.

Last edited by Resike : 10-31-17 at 11:31 PM.
  Reply With Quote
11-02-17, 07:02 PM   #20
ballistics1142
A Deviate Faerie Dragon
Join Date: Apr 2017
Posts: 14
Originally Posted by MunkDev View Post
If you want to allow unique sounds, like the talking head monologues or any other uncommon sound, but not UI sounds, use this:
Lua Code:
  1. local dummy, kit = false, {}
  2. for _, v in pairs(SOUNDKIT) do kit[v] = true end
  3.  
  4. hooksecurefunc('PlaySound', function(id)
  5.         if dummy or (not kit[id]) then return end
  6.         dummy = true
  7.         local played, handle = PlaySound(id+1)
  8.         if played then
  9.             StopSound(handle-1)
  10.             StopSound(handle)
  11.         end
  12.         dummy = false
  13. end)
Can I use this and then add specific blizzard sounds to be allowed through?

Or would it be easier to change this addon(http://www.wowinterface.com/download...erts.html#info) to play through the "Master" channel whilst SFX are disabled under system>>>sounds in-game?

Last edited by ballistics1142 : 11-02-17 at 07:11 PM.
  Reply With Quote

WoWInterface » AddOns, Compilations, Macros » AddOn Help/Support » 7.3 Broken PlaySoundFile()/PlaySound()

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off