What's this untitled slider doing on the Vista volume mixer?
Someone sent the following screen shot to one of our internal troubleshooting aliases. They wanted to know what the "Name Not Available" slider meant.
The audio system on Vista keeps track of the apps that are playing sounds (it has to, to be able to display the information on what apps are playing sounds :)). It keeps this information around for a period of time after the application has made the sound to enable the scenario where your computer makes a weird sound and you want to find out which application made the noise.
The system only keeps track of the PID for each application, it's the responsibility of the volume mixer to convert the PID to a reasonable name (the audio service can't track this information because of session 0 isolation).
This works great, but there's one possible problem: If an application exits between the time when the application made a noise and the system times out the fact that it played the noise, then the volume mixer has no way of knowing what the name of the application that made the noise was. In that case, it uses the "Name Not Available" text to give the user some information.
Comments
Anonymous
January 08, 2008
If that's the case, then why list in the mixer? Why would I want to change the volume of an application that has exited?Anonymous
January 08, 2008
Because while the mixer might not be able to figure out which app just made a noise, <i>you</i> might.Anonymous
January 08, 2008
What is the need of listing App in mixer anyway if I myself can figure it out. Is it possible to reduce the volume of the app even if it is already exited (for future use)? I guess no.Anonymous
January 08, 2008
The comment has been removedAnonymous
January 08, 2008
That's still not the reason to keep it in the mixer. What exactly is the purpose of it being there? Even if you knew what application made the sound what exactly will changing the volume after it exited do? It certainly won't be saved for the next time that application is launched, since neither the sound system nor the volume mixer know which application's volume you're adjusting. So, why exactly is it in the mixer? And what will happen if that PID is reused? Will the sound system use the old application's volume for the new application that just happened to get the same PID?Anonymous
January 08, 2008
I assume right now that volume settings are auto-remembered. If that's correct, how is the setting maintained, when the actual identity is unknown/fuzzy? If not, why is the slider for Name not disabled? I had previously assumed that it was for "weird", but still running, apps of some kind (like a binary with no top-level window).Anonymous
January 08, 2008
sandeep: exactly. If the app starts up again, the final volume from the mixer will be used for the app. And internally we keep the name of the executable, it's just that that information isn't available to sndvol (the reasons why are complicated).Anonymous
January 08, 2008
The comment has been removedAnonymous
January 08, 2008
It would be nice if we could find out what PID it was. This way, I could track it down to the .exe file and know for myself what app I would be changing if there were several of those...Anonymous
January 08, 2008
- "The system only keeps track of the PID for each application, it's the responsibility of the volume mixer to convert the PID to a reasonable name (the audio service can't track this information because of session 0 isolation)."
- "If the app starts up again, the final volume from the mixer will be used for the app."
- "And the identity is only fuzzy for the volume mixer, not for the audio subsystem." Ok, now I'm more confused. #1 and #3 appear to directly contradict each other. #2 seems impossible if the audio subsystem only knows the PID of the app, since it will have a different PID when it is started again. Now if the audio subsystem does know the app name (so it can save the volume label for next time), but only provides an API for the mixer to get the PID, then that would explain #2 and #3 (but begs the question of why there isn't an API for the mixer to get more detailed information, if it's already sitting there anyway). I can't reconcile this with #1, though.
Anonymous
January 08, 2008
yeah, that's why we can't have nice things. cannot it be named at least "Recently played app"? can't audio service keep app names in registry (yeah, that's not nice, but Vista have a lot of worser things)?Anonymous
January 08, 2008
Do you save volumes by exe name? I'm afraid to think what happens if that unidentified app was actually iexplore.exe.Anonymous
January 08, 2008
It seems there should be a better solution here. If the audio subsystem can persist the settings correctly for the next time the process starts even if you change the slider after it has closed, it must have more information than just the PID. It probably also has the exe name. If it can't persist the settings correctly I see no reason why the slider is even there. If it has the exe name, why not make that available to the volume mixer and have it display that? Failing all those things, having a "Why?" link to a help file that explains why the name is not available in simple terms below the "Name not available" text would've helped a lot too, and it would be consistent with Vista's UI which has help links all over the place (which users then completely ignore anyway :P ).Anonymous
January 09, 2008
The comment has been removedAnonymous
January 09, 2008
The comment has been removedAnonymous
January 09, 2008
Jonathan: Try it and see :). The full path to the EXE is included in the persisted value, so you'd have to actually replace the exe on the disk to confuse the system. Triangle: So? We took a look at the PID re-use issue and decided that it didn't make the bar for fixing the issue in Vista. The issue is real, so we deferred the fix for a future version of Windows (when we'll have more time to work on a more complete fix). It happens - every software project ever created has had bugs that weren't fixed before it released. Miral: I think I need to write another blog post explaining in more detail.Anonymous
January 09, 2008
The comment has been removedAnonymous
January 09, 2008
Maurits: Absolutely. And the thing that hands out process IDs does make an effort to avoid this (sort-of). But there is a limit to what it can do and stuff does happen.Anonymous
January 10, 2008
err.. an engineer-type decision that doesn't work well and possibly confuses the user frequently in the hope of some possible edge case when it might be useful. Absolutely revolting to have these sort of things still going in software 2007. Remove this ENTIRE debugging feature and keep-the-os-simple is the correct solution. Not more cruft with trying to find the correct name of the name, for that one guy in billion that knows to look in the sound mixer for figure which app made a beep. Please read The Inmates are Running the Assylum.Anonymous
January 10, 2008
The slider is a troubleshooting feature (in fact, the entire audio mixer is a troubleshooting feature). If we were to remove it, we'd get complaints "There's this app that keeps on making noises on my machine and I can't get it to stop".Anonymous
January 11, 2008
I would like to have a control panel which would allow me to view and adjust already existing persistent parameters for individual executables which did not play any sound in the current session. For example for program which plays a notification sound when some event happens (e.g. Alarm Clock, TV notifier) I can not adjust the volume before that event happens (at least I did not found a way to do it) nor check how loud it will be.Anonymous
January 12, 2008
The comment has been removedAnonymous
January 12, 2008
I think this feature makes sense. Let's say some app makes a sounds as it exits, so a user goes to the mixer to see what app could have made the sound. If they only see the currently running apps, they are liable to assume that one of those made the sound. If they see an unnamed app, they are able to see that some app other than those currently running could have been the culprit.Anonymous
January 15, 2008
The comment has been removedAnonymous
January 16, 2008
Hello Larry, is PID reuse really a concern? The PID is a DWORD, so there are 4 billion unique IDs before they need to be reused. Even if you create one process per second, every power supply I know needs to be replaced before a PID is reused. Or is the handle internally reused? Then why not give it a new PID? Maybe I'm missing something here, haven't cared much about CreateProcess and PIDs yet.Anonymous
January 16, 2008
Andre: A PID is essentially a handle, and as such it can be reused just like handles can be reused. On checked builds of Windows, there's actually code in the handle manager to enhance the likelihood that a handle gets re-used (I don't know if the same is true for PIDs).Anonymous
January 16, 2008
Also why don't you just use the process creation time (GetProcessTimes) to figure out if a PID has been reused?Anonymous
January 16, 2008
Thanks for your reply Larry. I understand that it makes sense to reuse processes internally but the handle manager could assign a new unique handle to it and also like on FreeBSD the PID could just be a counter. What's the rationale behind handle/PID reuse?Anonymous
January 16, 2008
It's more efficient. Ultimately a handle maps to an object. If the handle is just a counter, then you need to do a linear scan through your list of open objects until you find the object that matches the handle. If your handle is more complicated you can use a more sophisticated data structure to represent your handle. The downside of using a more sophisticated structure is that your handles can get re-used.Anonymous
January 17, 2008
I'm not aware of any Win32 functions that take a PID, they all want the handle. So why is the PID reused too? I would also be great if you could comment why you are not using the process creation time to figure out if a handle/PID has been reused.Anonymous
January 17, 2008
Andre: OpenProcess takes a PIDAnonymous
January 17, 2008
The comment has been removedAnonymous
January 17, 2008
The comment has been removedAnonymous
January 17, 2008
Keith: What text would you prefer to "Name not available"? We want to display the slider because the user has context that we don't (they know what apps they ran previously, we don't).Anonymous
January 17, 2008
Maybe something like "Recently closed application"?Anonymous
January 17, 2008
The comment has been removedAnonymous
January 21, 2008
Hey Larry, no reply?Anonymous
January 21, 2008
Andre: What's to reply?Anonymous
January 21, 2008
> Andre: What's to reply? Uh, yeah. If the path from suggester to listener was recently closed, then maybe "topic not available" is better than "recently closed discussion". Otherwise, I thought Andre's suggestion would be more understandable by users outside of Microsoft.Anonymous
January 21, 2008
I would also be great if you could comment why you are not using the process creation time to figure out if a handle/PID has been reused.Anonymous
January 24, 2008
Laaaaaaaaaaaaaaaaaarrrrrrrrrrrrrrrrrrrry! ;)Anonymous
February 15, 2008
I find this whole sound 'volume per app' ridiculous. I can't think of any useful application for it, except for eye candy and pleasing lazy users. I wish all this effort was put into filesystem (sorry Larry, didn't mean to underestimate your work), or fixing stupid bugs like file copy and poor network performance, which are essential for an OS. Another thing, this just increases the amount of 'user tracking' or 'instrumentation'. Without going into privacy issues, just think about the performance hit. On XP for example (I'm not touching Vista anytime soon) registry items like ShellNoRoam, MenuOrder, TrayNotify & PastIconsStreams get written and rewritten all the time, whether one wants their 'services' or not. I assume there are many similar (additional) things in Vista which, when added up, make the concept that is associatied with it - bloat.Anonymous
February 15, 2008
Grigi: Interesting. Our studies of XP customers showed pretty clearly that they were extremely annoyed that some applications (Certain media players were particular offenders) would change the master volume of the system instead of changing their own volume. The per-application volume feature came out of that. The reality is that every feature in Windows has people who like it and people who hate it. When my wife's riding instructor learned that she could control the volume of system sounds independantly from the volume of other applications, she was ecstatic. The extra "overhead" associated with per-application volume is negligable - there's a string that internally identifies an "application" (which is persisted in the registry, and rewritten 2 seconds after an application changes the volume), and a structure that tracks the volume of the application (and a number of other things, including all the audio streams for the application).Anonymous
February 15, 2008
Then the applications should have been forced to behave. I know, I know, it's always perceived as Microsoft's fault... maybe ban that behaviour and introduce a new 'proper' api... (hm... breaking compatibility - no win here). Or just keeping the old api, but nonfuctional (i.e. it doesn't change the volume)? Plenty of possibilities there... But I'm no programmer, just ordinary user who gets p****d off by the bloat creeping in every new version of windows... Take careAnonymous
February 15, 2008
Grigi: How do we "force" applications to behave? It's 3rd party code, we can't control it. What we CAN do is what we did - reset the system-wide behavior and make it local. Which is what you're complaining about.Anonymous
February 20, 2008
Thanks Larry. I have another puzzling problem. Q1. My application requires mic selected as input device while program startup.But i don't know how could i tell which is which while enumerating end point devices. Q2. Also, i have no idea how to disable capture monitoring, because i do not want to hear myself when speaking into my micphone. It will be very nice of you to answer these questions.Anonymous
February 20, 2008
Thanks larry! I am new to vista, and now i am deadly puzzled by two questions: my application requires mic selected as input device while program startup.But i don't know how could i tell which is which while enumerating end point devices. And also, i have no idea how to disable capture monitoring, because i do not want to hear myself when i am speaking into micphone. Could you help me? Many many thanks!!!Anonymous
February 21, 2008
Unfortunately, it's not easy to enable or disable capture monitoring because it's built into the hardware - there is sample code available on the MSDN web site that can get you close, but it's not trivial. To determine if a device is a microphone, you can get the device form factor property on the endpoint, that will let you know what kind of device the audio driver thinks the device is.Anonymous
February 21, 2008
I really appreciate your reply. Thanks very much! You said "it's not easy to enable or disable capture monitoring". Does that mean disabling capture monitoring is impossible? Is this new to Vista? Can XP do so? When i traverse a render endpoint's topology, i can find a subunit which is labeled as "Mic mute" by name, which is really what i am trying to find out, so i get the IAudioMute interface of that part and then mute it. But problem is i can not identify the part only by its name, because it varys with OS, right? So here i want an ID or something unique, is it impossible? " there is sample code available on the MSDN web site that can get you close". Larry, actually i searched the MSDN and still i didn't find anything that could help. Could you please give some hyperlink? You said "To determine if a device is a microphone, you can get the device form factor property on the endpoint", i have also tried that following these steps:
- Get IMMDevice interface of an endpoint.
- Get IPropertyStore interface of that endpoint.
- Get PKEY_AudioEndpoint_Association value using IPropertyStore. Here i assume the return value from step 3 could match something like KSNODETYPE_MICROPHONE,KSNODETYPE_DESKTOP_MICROPHONE,... which are defined in ksmedia.h. But actually i got value "VT_EMPTY". why? Later i tried getting EndpointFormFactor value of an endpoint during enumeration. This time i got an enum value "Microphone" from my mic device, but TV Tuner gave this value too. So this method doesn't work either?
Anonymous
February 21, 2008
The comment has been removedAnonymous
February 21, 2008
Thanks for your response! I did use PKEY_AudioEndpoint_FormFactor, but i got two devices that labeled themselves as "Microphone". one is Microphone and the other is TV Tuner. the latter is obviously what i don't want. So why i got two? i have read the actical about how to find a MUX. but i don't think that helps. My problem is how to determine whether a part is "mic mute" or not. I can find all parts, but i cann't tell which is which. Does that mean when i speak into micphone i can not prevent myself from hearing myself through speakers ? I can do this through Vista'UI manually.Anonymous
February 22, 2008
The comment has been removedAnonymous
February 24, 2008
Thanks for your patience! Now i've 2 questions:(. Q1. If name-matching is the only way to find 'Mic mute', it is of no use at all, because names are what used to display to users, and it is not safe to use names to determine a control. Names may vary on different drives and different hard devices. Simply put, it is NOT POSSIBLE to prevent users from hearing themselves through speakers programtically. Am i right this time ? Q2. You said "that's been the case since Windows 3.1". Doesn't this mean it is impossible to do so on XP? But i used to do this on XP using the following code(it wroks at least for my computer), but it doesn't work on vista at all(mxl.cConnections equals 1 on vista while 11 on XP). bool DisableCaptureMonitoring(DWORD& dwLineID){ MIXERLINE mxl; memset(&mxl, 0, sizeof(MIXERLINE)); mxl.cbStruct = sizeof(MIXERLINE); mxl.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS; if(MMSYSERR_NOERROR != ::mixerGetLineInfo((HMIXEROBJ)m_hMixer, &mxl, MIXER_GETLINEINFOF_COMPONENTTYPE)) return false; dwLineID = mxl.dwLineID; DWORD MicrophoneSourceLineIndex = 0; MIXERLINE MicrophoneLine; for (DWORD dwLine = 0; dwLine < mxl.cConnections; dwLine++) { memset(&MicrophoneLine, 0, sizeof(MIXERLINE)); MicrophoneLine.cbStruct = sizeof(MIXERLINE); MicrophoneLine.dwDestination = mxl.dwDestination; MicrophoneLine.dwSource = dwLine; if(MMSYSERR_NOERROR == mixerGetLineInfo((HMIXEROBJ)m_hMixer, &MicrophoneLine, MIXER_GETLINEINFOF_SOURCE)) { if (MicrophoneLine.dwComponentType == MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE) { //Unused MicrophoneSourceLineIndex = MicrophoneLine.dwSource; break; } } } if(mxl.cConnections <= 0 || MicrophoneSourceLineIndex == 0){ //error return false; } else{ // Set checkbox state in 'Recording Control' MIXERLINECONTROLS mlc = {0}; MIXERCONTROL mc = {0}; mlc.cbStruct = sizeof(MIXERLINECONTROLS); mlc.dwLineID = MicrophoneLine.dwLineID; mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_MUTE; mlc.cControls = 1; mlc.pamxctrl = &mc; mlc.cbmxctrl = sizeof(MIXERCONTROL); if( MMSYSERR_NOERROR != mixerGetLineControls((HMIXEROBJ) m_hMixer, &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE)){ return false; } MIXERCONTROLDETAILS mcd = {0}; MIXERCONTROLDETAILS_BOOLEAN mcb = {0}; mcb.fValue = true; mcd.cbStruct = sizeof(MIXERCONTROLDETAILS); mcd.dwControlID = mc.dwControlID; mcd.cChannels = 1; mcd.cMultipleItems = mc.cMultipleItems; mcd.paDetails = &mcb; mcd.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN); if( MMSYSERR_NOERROR != mixerSetControlDetails((HMIXEROBJ) m_hMixer, &mcd, MIXER_SETCONTROLDETAILSF_VALUE)){ return false; } return true; } }Anonymous
February 25, 2008
Aurora: Your code on XP is looking for a mute control on a microphone intput. You can do the same thing on Vista (actually, on Vista it's orders of magnitude easier - you activate IAudioEndpointVolume on the microphone input and call the SetMute API on the interface). I didn't realize you were trying to mute the microphone (which doesn't work on most microphones). I thought you were trying to mute the "Microphone" input on the render device. And on XP if you want to mute that control, you also have to match by name.Anonymous
February 25, 2008
The comment has been removedAnonymous
February 25, 2008
The comment has been removedAnonymous
February 26, 2008
Hey Larry why my vista vol mixer looks like this? Sp1 does not fix this. http://img523.imageshack.us/my.php?image=strangefx2.jpgAnonymous
February 26, 2008
Carlos, beats me - there were a couple of paint problems that could have caused that, I thought they were fixed in SP1, but possibly it was after then.Anonymous
February 26, 2008
The comment has been removedAnonymous
February 26, 2008
Aurora: Q2: That means that the endpoint is already muted (see the docs for the returns for that API). It lets you know that the call you made was a NOP (and, among other things, you're not going to get the notification). Q3: No, it means you need to match against the Mic Mute control that exists in your audio topology, just like I said you had to do.Anonymous
February 26, 2008
Larry, i would use the following steps to mute a microphone: ... spEnumerator->EnumAudioEndpoints(eCapture,...); then find MICROPHONE and mute it. But, if i mute microphone as you suggested, how can i use it to capture sounds? thanks!Anonymous
February 27, 2008
Aurora: You can't. But that's what your XP code did. I was just showing you how to do it on Vista.Anonymous
February 27, 2008
On vista I tried every way including mute micphone, all don't work except mute the "Mic mute" control. It seems that mute the "Mic mute" control is the ONLY way to do this, and matching name is the ONLY way to find the "Mic mute" control. Thanks, larry! You are really nice.Anonymous
March 02, 2008
Hi, lerry, When i use EXCLUDSIVE mode to create a stream, doesn't that mean the device cann't not be used by other applications except the stream itself ? For example , if i created an excluseive-mode stream successfully on my SPEAKERS, can i still hear the music played by windows media player?Anonymous
March 03, 2008
Aurora: Exclusive means that you own the device. That means that nobody else can render to it.Anonymous
March 04, 2008
Can different applications share the same session? If so, what's the way to manage volume per application, must i refer to stream volume?Anonymous
March 04, 2008
Can different applications share the same session? If so, what's the way to manage volume per application, must i refer to stream volume?Anonymous
March 04, 2008
Aurora: Yes, that's what the cross process stream initialization flag does. You have a multitude of ways you can manage volume: Per stream, per channel, and per session (I strongly recommend you avoid per channel). You need to figure out which is the right one for your application. See my posts on that subject (you can search for them).Anonymous
March 05, 2008
WAVEINCAPS and WAVEOUTCAPS , those two structures has a field declared like this: CHAR szPname[MAXPNAMELEN]; the macro MAXPNAMELEN is defined in mmsystem.h #define MAXPNAMELEN 32 /* max product name length including NULL) */ while in Vista, 32 bytes seems too short. When i use waveInGetDevCaps or waveOutGetDevCaps under vista, i usually got truncated names like "Realtek Digital Output (Realtek" ,which is exactly 31 characters long. Is this a bug?Anonymous
March 06, 2008
Aurora: Feel free to get in your time machine, set the time slider to 1991 and submit a bug to the Windows 3.0 team to get them to increase the size of the field. Unfortunately, it's quite difficult to fix structures which were defined 17 years ago.Anonymous
March 10, 2008
Hi, Larry, Could you please take a look at the following code and tell me why the IAudioEndpointVolumeCallback::OnNotify() could not receive anything? class CAudioEndpointVolumeCallback : public IAudioEndpointVolumeCallback{ ... ... // Callback method for endpoint-volume-change notifications. HRESULT STDMETHODCALLTYPE OnNotify(PAUDIO_VOLUME_NOTIFICATION_DATA pNotify){ return S_OK; } }; bool RegisterAudioEndpointVolumeCallBack(){ CComPtr<IAudioEndpointVolume> pEndPntVol; HRESULT hr ; CComPtr<IMMDeviceEnumerator> spEnumerator; hr = CoCreateInstance( __uuidof(MMDeviceEnumerator), NULL,CLSCTX_INPROC_SERVER, __uuidof(IMMDeviceEnumerator), (void**)&spEnumerator ); hr = spEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &CurrentOutputDevice); hr = m_CurrentOutputDevice->Activate( __uuidof(IAudioEndpointVolume),CLSCTX_ALL, NULL, (void**)&pEndPntVol); hr = pEndPntVol->RegisterControlChangeNotify( (IAudioEndpointVolumeCallback*)&EPVolEvents ); } CAudioEndpointVolumeCallback EPVolEvents; CComPtr<IMMDevice> CurrentOutputDevice; int _tmain(int argc, _TCHAR* argv[]) { CoInitialize(NULL); RegisterAudioEndpointVolumeCallBack(); //I let it stop to see the results while(1){ Sleep(1); }; CoUninitialize(); return 0; } The OnNotify function is NEVER called when i change endpoint volume in SndVol. could you give some hints? Thanks!Anonymous
March 10, 2008
Search my blog, there's a sample I posted a while ago that does that (it's a volume slider, but it should work).Anonymous
March 10, 2008
Thanks larry, i searched you blog and read your artical "Fun with the endpoint volume interfaces - closing the loop ", but i think it contains not enough information. Now i tried to create a new thread and put "RegisterAudioEndpointVolumeCallBack()" as the thread function, and i modified this function a little(i call Sleep(10) at the end of the function in a dead loop to prevent this thread from exit), this time it works, i can receive notifications when i change speaker volume and mute state. but i don't know why? Doesn't the RegisterControlChangeNotify() function requires a new thread?Anonymous
March 11, 2008
Aurora, it does - the system owns that thread though.Anonymous
March 11, 2008
Hi Larry, what do you mean by "the system owns that thread"? Does that mean i need not call CloseHandle() for that thread manually? In other words, all i need is to call IAudioEndpointVolume::UnregisterControlChangeNotify() ,and this will terminate that thread automatically, right?Anonymous
March 11, 2008
I mean that the thread that's used to call back into your application for the notification is owned by the system. The thread won't be terminated because it's a system managed threadpool thread - other things in the OS use it as well.Anonymous
March 12, 2008
I solved the problem. It's all because i declared a IAudioEndpointVolume using CComPtr, which automatically release the interface after the function. After i replaced it with "IAudioEndpointVolume *pEndPntVol;" and manually release it at proper time. Everything works fine. Thanks larry!Anonymous
March 13, 2008
Larry, when i saw the document of ISimpleAudioVolume, i doubt why must i retrieve this interface by creating a stream? Why cann't I get this interface just by specifying the guid of the session without creating any useless stream? Please let me know if i misunderstood all this. Thanks!Anonymous
March 14, 2008
Aurora: You don't need a stream to create the interface. You can use the IAudioSessionManager interface to access the simple volume for the current process.Anonymous
April 01, 2008
As someone who occasionally gets seemingly-random sounds on my PC and has tried to figure out what application was responsible for random noises from my PC, I'm very happy that MS has taken some steps that make this possible. Even if it's not exactly perfect. I'd much rather have some volume slider sometimes show up without a clear identifier than have sounds being played without being able to easily determine what was making hte sounds (or why). Thanks!