I've got my computer(Windows 7) hooked up to the TV, and i very often change output device for sound between Digital Audio (S/PDIF)(High definition audio device) and my headset (2- Corsair CA-HS1 USB Headset)
I wanna be able to execute a batch/script file who changes this for me so i don't have to "right click volume > playback devices > "Mark output device" and click "set default".
I know it's a luxury problem, but hey, maybe I can learn something from someone?
All help appreciated!
This is how I set 'Line 1' as the playback device:
start /min "" G:\......\nircmd.exe setdefaultsounddevice "Line 1"
NirCmd is a small command-line utility which you can download that allows you to do some useful tasks without displaying any user interface.
I had the exact same requirement as yourself, and AFTER stumbling across your posting I found the following:
https://web.archive.org/web/20131231034118/http://downloadsquad.switched.com/2010/06/16/windows-7-tip-how-to-change-the-default-audio-device-with-a-hot/
Unfortunately it's not a native Windows function; it requires the download of a small open-source scripting tool called AutoHotKey, but it works nicely and only requires a small amount of memory (1 ~ 2.5Mb)
The script provided in the original article doesn't work for me. It's searching for Enabled/Disabled devices and changing that value, as opposed to changing the default device.
I've edited it to switch between 2 default devices now.
It works by opening your Sound control panel (mmsys.cpl), then scrolling down the list of playback devices to the second item in the list (that's the {Down 2} part).
This is because my Speakers are the second item in my list.
It then checks to see if the device is default or not. If not, it sets it as the default and closes the window. If it's already the default, it scrolls down another 2 times and sets that as the default.
So, you'll need to ammend the {Down 2} lines to fit your own list of devices.
#+a::
Run, mmsys.cpl
WinWait,Sound
ControlSend,SysListView321,{Down 2}
ControlGet, selectedDevice, List, Focused, SysListView321
Loop, Parse, selectedDevice, %A_Tab%
if a_index <> 3
continue
else
{
if A_LoopField <> Default Device
{
ControlClick,&Set Default
ControlClick,OK
WinWaitClose
SoundPlay, *-1
return
}
else
{
ControlSend,SysListView321,{Down 2}
ControlClick,&Set Default
ControlClick,OK
WinWaitClose
SoundPlay, *-1
return
}
}
To follow up on Dale Newton's post, NirCmd is a great way to do this. On top of that if you pair it with AutoHotKey you can create an executable that will change your devices without opening pesky CMD windows every time you run it. For example, I have two sources that I switch between all the time, one is my headphones and they other is my monitor. For my monitor I created an ahk script that does this:
#NoEnv
SendMode Input
SetWorkingDir %A_ScriptDir% ;I have nircmd in the same folder as these scripts
Run, nircmd setdefaultsounddevice "Acer X34-8" 1
Run, nircmd setdefaultsounddevice "Acer X34-8" 2
And another for my headphones with the last two lines changed to:
Run, nircmd setdefaultsounddevice "Headset Earphone" 1
Run, nircmd setdefaultsounddevice "Headset Earphone" 2
Afterwards you can compile each ahk script into an exe and bind each exe to a keyboard macro so you can execute them with a couple key presses. Personally I am using a Corsair K95 so I use their software to bind these to my 'G' keys.
Also to note, if you are in your sound preferences you can rename any of the devices to avoid naming conflicts.
I had a HDMI device that keeps changing it's name, so none of the existing solutions worked for me.
I eventually ended up with this powershell and use of the NirCmd app.
#File: TV.ps1
$name = "SMART*"
# list active audio playback devices. (Note for cature devices change Render to Capture)
$device = Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\MMDevices\Audio\Render\*\" | where {$_."DeviceState" -eq 1} | foreach-object -Process {(Get-ItemPropertyValue -Path ($_.PSPath + "\Properties\") -Name "{a45c254e-df1c-4efd-8020-67d146a850e0},2")} | Where-Object {$_ -like $name}
C:\bin\NIRCMDC setdefaultsounddevice $device 1
C:\bin\NIRCMDC setdefaultsounddevice $device 2
As far as I understand there is no way to do this programmatically. This is a deliberate design, since Microsoft does not want applications to override audio setting set by user.
You will find same answer here but if you solutions that manipulate windows you can have a look here.
The following script is written in Windows 7 and uses sendkeys. It is based on other snippets I found but adds to them to ensure selection is consistent and stray windows are not left displayed.
You may want to adjust SleepTime for your system if it still plays up.
Call the script using a shortcut with the index of the item you wish to select in the Playback Devices window as first parameter.
You can create a new 'toolbar' on your 'taskbar' to select each device with a single click:
Taskbar toolbar picture
'===============================================================================
'This script uses sendkeys to select the Sound Output device
'First parameter should be the desired device number in 'Playback Devices' list
'===============================================================================
Option Explicit
Const SleepTime = 200
Dim WindSh
'===============================================================================
'MAIN ROTUINE
'===============================================================================
'Check the command line input
if ( Wscript.Arguments.Count <> 1) then
MsgBox "You must provide a single integer argument representing the device number", vbinformation + vbokonly, Wscript.ScriptName
Wscript.Quit 1
elseif ( false = IsNumeric( Wscript.Arguments.Item(0) ) ) then
MsgBox "The argument provided was not an integer number: " & Wscript.Arguments.Item(0), vbinformation + vbokonly, Wscript.ScriptName
Wscript.Quit 2
End If
set WindSh = CreateObject("Wscript.Shell")
WindSh.run("control.exe mmsys.cpl")
do while (WindSh.AppActivate("Sound") = false)
WScript.Sleep SleepTime
loop
WindSh.sendkeys("{DOWN " & Clng( Wscript.Arguments.Item(0) ) & "}")
WScript.Sleep SleepTime
WindSh.sendkeys("{TAB 2}")
WScript.Sleep SleepTime
WindSh.sendkeys("{ENTER}")
WScript.Sleep SleepTime
WindSh.sendkeys("%{F4}")
WScript.Sleep SleepTime
if (WindSh.AppActivate("Sound") = true) then
WindSh.sendkeys("%{F4}")
end if
Might not be related to switching the audio device around via script, but I also have my computer hooked up to my TV via HDMI.
When I want to watch video files on the TV I use Media Player Classic Home Cinema - this lets me specify the audio device for MPH:HC in the options without switching over my default sound device on the entire computer.
If your usage is similar to mine maybe MPC:HC will solve your problem for you.
Note that if you use nircmd setdefaultsounddevice speakers in an enterprise or educational environment login script, the sound will still come out from the speakers when headphones are plugged in.
Related
My audio system is simple: two speakers in the rear panel--front left(FL) ,front right(FR) ,headphone in the front panel. The primitive status is as below--primitive status:
In this status , sound can be heared from FL,FR,and headphone.
I find a strange fact that master,front,surround in alsamixer changed into MM status when to click M on LFE,i move the cursor on LFE,and click M,LFE changed into MM,at the same time master,front,surround all changed into MM status !No sound can be heared !
And i click M for the second time on LFE,all status changed as below:
Let's go on from the primitive status,and unplug line from rear panel,no sound in headphone! The status in alsamixer gui is as below:
Now re-plug the line in the rear panel,the status in alsamixer gui turns into :
Please give an explanation in detail.
To see what's going on:
In one terminal window, run alsactl monitor.
In another terminal window, run alsamixer.
As you mute/unmute things in alsamixer, you can see the control commands in the monitor window. You should see multiple switch commands show up when you mute the LFE.
The reason this is happening is because of the pulseaudio profile in use by alsamixer.
Profiles are located in /usr/share/pulseaudio/alsa-mixer/profile-sets/*.conf
Paths are located in /usr/share/pulseaudio/alsa-mixer/paths/*.conf
So which ones are in use? You can check that with pacmd info | grep "active", which may produce something like:
active port: <analog-output-speaker>
active port: <analog-input-headphone-mic>
active profile: <output:analog-stereo+input:analog-stereo>
Ok, so the output mapping is analog-stereo. I can find this in /usr/share/pulseaudio/alsa-mixer/profile-sets/default.conf. It contains the following:
[Mapping analog-stereo]
device-strings = front:%f hw:%f
channel-map = left,right
paths-output = analog-output analog-output-lineout analog-output-speaker analog-output-headphones analog-output-headphones-2
paths-input = analog-input-front-mic analog-input-rear-mic analog-input-internal-mic analog-input-dock-mic analog-input analog-input-mic analog-input-linein analog-input-aux analog-input-video analog-input-tvtuner analog-input-fm analog-input-mic-line analog-input-headphone-mic analog-input-headset-mic
priority = 10
The real control is under /usr/share/pulseaudio/alsa-mixer/paths/analog-output-speaker.conf. You can read /usr/share/pulseaudio/alsa-mixer/paths/analog-output.conf.common for details, where we see two important sections:
; When a device shall be muted/unmuted *all* elements listed in a path
; file with "switch = mute" will be toggled.
(there's a bit of a caveat to this one. It seems that unmuting does NOT toggle other elements in the path)
and
; [Element ...] # For each element that we shall control
...
; switch = ignore | mute | off | on | select # What to do with this switch: ignore it, make it follow mute status,
; # always set it to off, always to on, or make it selectable as port.
; # If set to 'select' you need to define an Option section for on
; # and off
...
So now, if we want to adjust an element such that it's always on, always off, or simply ignores muting, we would set the corresponding switch= values in the Element of interest.
If you want to adjust the behavior of the headphones when activating that path (i.e. when plugging them in), change the Element values in paths/analog-output-headphones.conf
Is there a way to retreive the loaded monitors color profile with Applescript, or at least with command-line, as I can use command-line in Applescript?
I'm talking about the loaded color profile of all plugged monitors, the ones defined in "System Preferences -> displays -> color"
EDIT: I would like to get the name of the ICC profile, i.e. what is selected in "System Preferences" -> displays -> color", for each connected screen.
Try either of these:
tell application "Image Events" to display profile of displays as list
tell application "Image Events" to display profile of display 1
You can get more (but not many) details in the Image Events dictionary under Image Suite.
Display 0 and Display 1 both seem to produce the same result (built-in display). Display 2 would refer to an external display. I have a very simple set-up so depending upon yours, you may have to experiment.
Getting the display name is the main issue in pre-Catalina systems if you are wanting to match up display names with their color profiles, but results from the system_profiler utility can be massaged to get the names in earlier systems. A little AppleScriptObjC will get the rest:
use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions
on run -- example
set screenProfiles to ""
set theScreens to current application's NSScreen's screens
set displayNames to getDisplayNames(theScreens) -- handle older systems
repeat with i from 1 to (count theScreens)
set profile to localizedName of colorSpace of item i of theScreens
set displayName to item i of displayNames
set screenProfiles to screenProfiles & "Name: " & displayName & return & "Profile: " & profile & return & return
end repeat
display dialog screenProfiles with title "Screen Color Profiles"
end run
to getDisplayNames(screenList)
set theNames to {}
if (get system attribute "sys2") > 14 then -- 10.15 Catalina and later
repeat with screen in screenList
set end of theNames to localizedName of screen
end repeat
else -- munge system profiler data
set displayKey to "<key>_IODisplayEDID</key>"
set nameKey to "<key>_name</key>" & return & tab & tab & tab & tab & tab & tab & "<string>"
set displayInfo to do shell script "system_profiler -xml SPDisplaysDataType"
set {tempTID, AppleScript's text item delimiters} to {AppleScript's text item delimiters, displayKey}
set {displayItems, AppleScript's text item delimiters} to {text items of displayInfo, tempTID}
repeat with anItem in rest of displayItems
set here to (offset of nameKey in anItem) + (length of nameKey)
set there to (offset of "</string>" in (text here thru -1 of anItem)) - 1
set end of theNames to text here thru (here + there - 1) of anItem
end repeat
end if
return theNames
end getDisplayNames
The NSScreen documentation has a discussion about the primary screen in the list.
I am not suggesting or making any technical suggestion here as I am not qualified to do so and am hugely impressed by the work you all do.
The way I understand windows CM (colour management) is that while many profiles for many devices (including paper) are held in the appropriate folder only one can be used as the system profile. For the monitor profile only what ever is 'set' as the system profile is wanted or needed. If a new monitor profile is created (via calibration) then that system profile will be replaced.
I have an USBhub (D-Link DUB-H7) connected to my laptop with Windows 10. Connected to the hub are 4 identical PEAK dongles to talk to a CANbus. Now, my problem is to programmatically identify these 4 seperate dongles and knowing which one is which. The dongles are fixed in the hub.
To start I downloaded and installed USBDeview to view my devices. In the program I can see my 4 PCAN-USB dongles and I can see that their Instance ID are different. That's good, now I have my identifier. However, once I try to get the ID's with Python things aren't looking good. This is my following test program:
import win32com.client
wmi = win32com.client.GetObject("winmgmts:")
input("Connect the hub")
dongle_list = [(usb.name, usb.DeviceID) for usb in wmi.InstancesOf("Win32_USBHub")]
input("Disconnect the hub")
nod_list = [(usb.name, usb.DeviceID) for usb in wmi.InstancesOf("Win32_USBHub")]
diff = list(set(dongle_list) - set(nod_list))
for d in diff:
print(d)
Running this gives me only 2 new usb devices and the ID's point to the USBhub rather than the dongles connected to the hub. I also tried with wmi.InstancesOf("CIM_USBDevice") but the result stays the same.
('Generic USB Hub', 'USB\\VID_05E3&PID_0608\\5&4A43CD6&0&4')
('Generic USB Hub', 'USB\\VID_05E3&PID_0608\\6&9EBFB9C&0&4')
So how can I retrieve the usb information of the devices connected to the USBhub using Python or powershell/cmd invoked by Python?
Another route I was thinking I could take is by using port identifiers. If I disconnect a dongle I can see that it was connected to Port_#0001.Hub_#000x, where is x is a positive integer. So maybe I could poll the port to see if the dongle is connected and then I too know which one is which (dongles are fixed in the hub). Although I think that using the Instance ID is more foolproof.
I ended up creating a powershell command and invoke that using Python. I noticed however that the InstanceID's are hardware addresses of the the USBhub and not the dongles.
I also noticed that the dongles sometimes switch their addresses related on how they were connected. So I also needed to disable them and enable them again in the order I want.
This is what I have now:
poll_cmd = """
$ret = (Get-PnpDevice | ? {($_.description -like "*pcan*") -and ($_.status -eq "ok")} | sort instanceid).instanceid;
$ret | % {Disable-PnpDevice $_ -Confirm:$False};
$ret | % {Start-Sleep -Seconds 1; Enable-PnpDevice $_ -Confirm:$False};
$ret
"""
usbs = (
subprocess.check_output(["powershell.exe", poll_cmd])
.decode()
.strip()
.split("\r\n")
)
usbs holds the list of usb dongles I'm interested in.
However this gave me one more problem: UAC. I need admin rights to enable the usbs. And used the top answer from Request UAC elevation from within a Python script? to give my program admin rights.
We have a Linux device which has a speaker and MIC devices. These devices are shared among different modules - example a VOIP call can use speaker, a hazard Warning system can use speaker, a Voice prompt can use a speaker etc:
There seems to be a function in ALSA which uses pcm to provide the status.
int snd_pcm_status (snd_pcm_t * pcm, snd_pcm_status_t * status)
However the *pcm is returned by snd_pcm_open. We do not want to open the device as we would like to know the status of the device using its "name"
Alsa API is here
How can we check if a resource/device is busy without opening it and using its name?
The same information for playback stream X of device Y on card Z is available in the file /proc/asound/cardZ/pcmYp/subX/status; when the device is not open, it just says "closed".
Please note that you cannot use this information to decide if you can open the device, because some other process could have openend it just after you've read this information. The only way to check if you can open it is to actually try.
Though it requires /dev/dsp, this seems to work:
#!/bin/dash
## If the speaker is not used by any, returns 0, and prints "free"
## Otherwise, returns 1 and prints "not free"
iExit (){
trap '' 0
exit $1
}
iCatch (){
# The speaker is already in use
echo not free
iExit 1
}
trap iCatch 0
{
exec 3>&1 1>/dev/dsp
# If the execution reaches here, the speaker is not used by any
# Otherwise, it's catched by iCatch
exec 1>&3
echo free
iExit 0
} 2>/dev/null
Without PulseAudio, it seems on some PC only one output is accepted at one time; on others simultaneous playbacks are allowed. But even in the latter case, the above code works.
NB: The above code does not work with bash; for bash, simply use if/else rather than trap.
NB 2: /dev/dsp may be lacking depending on the kernel configuration.
I've been googling for quite a long time and I just can't find any information on how to get screen_number for every screen connected to computer. Here I found a list of macros and some of them (like for example ScreenOfDisplay(display, screen_number) ) use argument screen_number. However there is no such macro that could give me a list of those numbers (one for every connected screen). I know how to get number of default screen (DefaultScreen() ) and count of all screens ( ScreenCount() ) but what about other screens? I noticed that screen_number of default screen is 0, although I have only one screen connected to my computer so I can't really test what happens when there are more of them. I think that screen_number could be assigned in a very simple way which is screen_number=0 for first screen,screen_number=1 for second,screen_number=2 for third and so on but as I said... I can't test wheather it's true and even if I had multiple screens how could I be sure that it works like this for all computers .Please ,if anyone of you has more experience with X11 and knows all details about how it works,tell me if I am right.
The ScreenCount(dpy) macro and int XScreenCount(Display*) function both return the number of screens connected to the display. Valid screen numbers are 0 to ScreenCount(dpy)-1. Macros in Xlib.h confirm:
#define ScreenCount(dpy) (((_XPrivDisplay)dpy)->nscreens)
#define ScreenOfDisplay(dpy, scr) (&((_XPrivDisplay)dpy)->screens[scr])
Your source (2.2.1. Display Macros) provides enough information. Normally the default screen-number is 0, e.g., when connecting to the local host you could use :0.0 as indicated in the documentation for XOpenDisplay.
That is "normally". If you run VNC, normally that runs on a different display (the first 0 in the simple connection string shown).
But (reading the documentation), when an application calls XOpenDisplay, it asks for the given screen-number (which the X server may/may not honor):
screen_number
Specifies the screen to be used on that server. Multiple screens can be controlled by a single X server. The screen_number sets an internal variable that can be accessed by using the DefaultScreen() macro or the XDefaultScreen() function if you are using languages other than C (see "Display Macros").