Windows: Bluetooth Headset Connected but No Sound and No Microphone#
On Windows 10/11, the headset shows Connected, but the music stays on the laptop speakers and no application lists the microphone. Re-pairing fixes it, until the next time.
A Bluetooth headset is two independent device stacks, and the "Connected" badge only covers the Bluetooth link. This post reads both stacks from the registry, and restarts the single PnP device that is stuck.
A2DP carries music and creates the render endpoint (playback).
HFP (Hands-Free Profile, UUID 0000111E-0000-1000-8000-00805F9B34FB) carries calls and creates the capture endpoint (microphone).
Each profile is its own BTHENUM device node with its own audio endpoint:
flowchart LR
BT["Bluetooth link<br/>one MAC address"]
A2DP["BTHENUM node<br/>A2DP {0000110B}"]
HFP["BTHENUM node<br/>HFP {0000111E}"]
R["Render endpoint<br/>playback"]
C["Capture endpoint<br/>microphone"]
BT --> A2DP --> R
BT --> HFP --> C
The link can be up while one endpoint is stuck. The Bluetooth page only sees the link, and the Sound page only lists usable endpoints, so a stuck microphone just disappears.
After pairing, the BTHENUM nodes stay OK whether the headset is on or off, so Get-PnpDevice -Status OK cannot tell a live headset from a paired one that is switched off.
The endpoints are the real signal:
a headset is connected when either endpoint is ACTIVE, which matches what Settings shows;
the render and capture endpoints of one headset share the Bluetooth MAC in the instance path (..._38FBA04FE84A_C00000000 or DEV_38FBA04FE84A);
the capture side also gives the HFP node that the repair restarts.
Render endpoint
Capture endpoint
Verdict
Action
ACTIVE
ACTIVE
healthy
nothing
ACTIVE
not ACTIVE
call channel stuck
rebuild
not ACTIVE
ACTIVE
playback stuck
rebuild
ACTIVE
missing
no capture endpoint
re-pair
not ACTIVE
missing
possibly LE Audio
check LE Audio
No capture endpoint means the pairing or the profile enumeration is wrong; a restart will not create it.
Disable-PnpDevice followed by Enable-PnpDevice tears the stack down and lets the driver recreate its endpoints. It is Device Manager's disable/enable, so it needs an elevated shell.
Restart the HFP node from the capture endpoint's ancestor chain, wait 10 s, re-read the endpoints.
If any target is still broken, restart the MEDIA-class device that owns the endpoints (by name, falling back to Bluetooth.*Audio), wait 12 s. That device is often shared, so other headsets can drop for a moment.
# Diagnose and repair every connected headset with a broken audio path./fix-bluetooth-headset-audio.ps1# Diagnosis only: no change, no admin rights./fix-bluetooth-headset-audio.ps1-DiagnoseOnly
The script asks before changing anything, and re-launches itself elevated through UAC when needed.
<#.SYNOPSIS Bluetooth headset microphone (HFP) endpoints: diagnose -> confirm -> rebuild -> verify..DESCRIPTION Windows 10/11. No headset brand or UI language assumption: the A2DP and HFP device nodes are created by the Windows Bluetooth stack, not by the headset vendor. - Only connected headsets are inspected: the Bluetooth link must be up, and paired but disconnected devices are skipped. - Pairing: match the playback endpoint and the recording endpoint of the same headset by Bluetooth MAC address. - Verdict: either endpoint not ready means the headset is abnormal, which is the "connected but no sound / no microphone" case. - Locate: walk up the parent chain of the capture endpoint to find the HFP call device (standard UUID 0000111E). - Rebuild: restart the headset's HFP device first; if that is not enough, restart its parent audio device (Intel / Microsoft / any other stack)..PARAMETER Device Only handle headsets whose name contains this keyword. Empty = every connected headset whose audio path is abnormal..PARAMETER Force Skip the interactive confirmation..PARAMETER DiagnoseOnly Diagnose only, change nothing..PARAMETER All Ignore the connected test and include every paired Bluetooth headset..EXAMPLE .\fix-bluetooth-headset-audio.ps1 -DiagnoseOnly .\fix-bluetooth-headset-audio.ps1 .\fix-bluetooth-headset-audio.ps1 -Device FreeBuds .\fix-bluetooth-headset-audio.ps1 -All -DiagnoseOnly#>param([string]$Device='',[switch]$Force,[switch]$DiagnoseOnly,[switch]$All)$Root='HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\MMDevices\Audio'$P_NAME='{026e516e-b814-414b-83cd-856d6fef4822},2'$P_DESC='{a45c254e-df1c-4efd-8020-67d146a850e0},2'$P_PARENT='{b3f8fa53-0004-438e-9003-51a46e139bfc},39'$P_PARENTID='{b3f8fa53-0004-438e-9003-51a46e139bfc},2'$P_AUDIO='{b3f8fa53-0004-438e-9003-51a46e139bfc},6'$P_WAO='{b3f8fa53-0004-438e-9003-51a46e139bfc},26'$HFP_UUID='0000111E-0000-1000-8000-00805F9B34FB'functionGet-StateText([int]$s){switch($s){1{'ACTIVE ready'}2{'DISABLED disabled'}4{'NOTPRESENT not present'}8{'UNPLUGGED not connected'}default{"UNKNOWN($s)"}}}functionResolve-EpName($pr){$n=$nullif($pr.$P_NAME){$n=[string]$pr.$P_NAME}elseif($pr.$P_AUDIO-and($pr.$P_AUDIO-notmatch'Smart Sound|Bluetooth Audio|Audio Device|Audio Endpoint')){$n=[string]$pr.$P_AUDIO}elseif($pr.$P_WAO){$n=[string]$pr.$P_WAO}elseif($pr.$P_AUDIO){$n=[string]$pr.$P_AUDIO}if($n){$n=($n-replace'\s+Hands-?Free(\s+AG)?$','').Trim()}return$n}functionGet-EndpointList([string]$Kind){$path=Join-Path$Root$Kindif(-not(Test-Path-LiteralPath$path)){return@()}Get-ChildItem-LiteralPath$path-ErrorActionSilentlyContinue|ForEach-Object{$st=(Get-ItemProperty-LiteralPath$_.PSPath-ErrorActionSilentlyContinue).DeviceState$pr=Get-ItemProperty-LiteralPath"$($_.PSPath)\Properties"-ErrorActionSilentlyContinue$parents=@($pr.$P_PARENT)$parentId="$($pr.$P_PARENTID)"$isBt=$falseforeach($xin$parents){if("$x"-match'BTHENUM|BTHLEENUM'){$isBt=$true}}if($parentId-match'BTHENUM|BTHLEENUM'){$isBt=$true}$chainRaw=$null$hfpRaw=$parents|Where-Object{"$_"-match$HFP_UUID}|Select-Object-First1if($hfpRaw){$chainRaw="$hfpRaw"}elseif($parents.Count-gt0-and"$($parents[0])"-match'BTHENUM'){$chainRaw="$($parents[0])"}elseif($parentId-match'BTHENUM'){$chainRaw=$parentId}$mac=$nullforeach($srcin@($chainRaw,$parentId)){$s="$src"if(-not$s){continue}# Bluetooth device instances look like ...&EC1234567890_C00000000if($s-match'([0-9A-Fa-f]{12})_C[0-9A-Fa-f]{8}'){$mac=$matches[1].ToUpper();break}if($s-match'DEV_([0-9A-Fa-f]{12})'){$mac=$matches[1].ToUpper();break}}[pscustomobject]@{Kind=$KindId=$_.PSChildNameState=[int]$stName=Resolve-EpName$prDesc=$pr.$P_DESCIsBt=$isBtMac=$macHfpId=(("$chainRaw")-replace'^\{[^}]+\}\.','').Trim()AudioDev=$pr.$P_AUDIO}}}functionGet-PairedList{$caps=@(Get-EndpointList'Capture'|Where-Object{$_.IsBt})$rend=@(Get-EndpointList'Render'|Where-Object{$_.IsBt})foreach($ein$caps){if(-not$e.Mac){$e.Mac="N:$($e.Name)"}}foreach($ein$rend){if(-not$e.Mac){$e.Mac="N:$($e.Name)"}}$keys=@(@($caps|ForEach-Object{$_.Mac})+@($rend|ForEach-Object{$_.Mac})|Sort-Object-Unique)foreach($kin$keys){$c=$caps|Where-Object{$_.Mac-eq$k}|Sort-ObjectState|Select-Object-First1$r=$rend|Where-Object{$_.Mac-eq$k}|Sort-ObjectState|Select-Object-First1$nm=if($c-and$c.Name){$c.Name}elseif($r){$r.Name}else{$k}[pscustomobject]@{Key=$kName=$nm# Same test as the Connected label in Settings - Bluetooth & devices:# any audio endpoint ACTIVE means connected. The DEV_ / A2DP / HFP# device nodes stay OK after pairing and cannot tell connected from# disconnected.Connected=[bool](($All)-or($r-and$r.State-eq1)-or($c-and$c.State-eq1))RenderState=if($r){$r.State}else{4}CapState=if($c){$c.State}else{$null}HfpId=if($c){$c.HfpId}else{$null}AudioDev=if($c){$c.AudioDev}else{$null}}}}functionShow-Table([string]$Title){Write-Host''Write-Host"=== $Title ==="-ForegroundColorCyan$list=@(Get-PairedList)if($list.Count-eq0){Write-Host' no Bluetooth audio endpoint found'-ForegroundColorYellowreturn$list}$offCount=@($list|Where-Object{-not$_.Connected}).Count$shown=@($list|Where-Object{$_.Connected})if($shown.Count-eq0){Write-Host' no connected Bluetooth headset (paired but disconnected devices are skipped)'-ForegroundColorYellowreturn$list}$colHead=if($All){'Headset (all, disconnected included)'}else{'Headset (connected)'}Write-Host(' {0,-38} {1,-24} {2,-24} {3}'-f$colHead,'Render endpoint','Capture endpoint','Verdict')Write-Host(' '+('-'*100))-ForegroundColorDarkGrayforeach($ein$shown){if($e.RenderState-eq1){$rTxt='ACTIVE ok'}elseif($e.RenderState-eq8){$rTxt='UNPLUGGED not ready'}else{$rTxt=(Get-StateText$e.RenderState)}if($e.CapState-eq$null){$capTxt='no capture endpoint'if($e.RenderState-eq1){$verdict='abnormal: re-pair required';$color='Red'}else{$verdict='abnormal: possibly LE Audio';$color='Red'}}elseif($e.CapState-eq1){$capTxt='ACTIVE available'if($e.RenderState-eq1){$verdict='ok';$color='Green'}else{$verdict='abnormal: render endpoint down';$color='Yellow'}}else{$capTxt=(Get-StateText$e.CapState)$verdict='abnormal: call endpoint down';$color='Yellow'}Write-Host(' {0,-38} {1,-24} {2,-24} {3}'-f$e.Name,$rTxt,$capTxt,$verdict)-ForegroundColor$color}if($offCount-gt0){Write-Host" $offCount more paired but currently disconnected, skipped"-ForegroundColorDarkGray}return$list}functionReset-Pnp([string]$id,[string]$label){try{Disable-PnpDevice-InstanceId$id-Confirm:$false-ErrorActionStopStart-Sleep-Seconds2Enable-PnpDevice-InstanceId$id-Confirm:$false-ErrorActionStopWrite-Host" $label : OK"-ForegroundColorGreenreturn$true}catch{Write-Host" $label : FAILED - $($_.Exception.Message)"-ForegroundColorRedreturn$false}}functionConfirm-Step([string]$Prompt,[bool]$DefaultYes){if($Force){Write-Host'(-Force: confirmation skipped)'-ForegroundColorGray;return$true}$ans=$nulltry{$ans=Read-Host$Prompt}catch{return$false}if("$ans".Trim()-eq''){return$DefaultYes}return("$ans"-match'^[Yy]')}# ---------------- 1) Diagnose ----------------Write-Host'Bluetooth headset microphone endpoints - diagnose / repair'-ForegroundColorCyanif($Device){Write-Host"Name filter: $Device"-ForegroundColorGray}$list=Show-Table'Step 1: diagnose'$online=@($list|Where-Object{$_.Connected})$broken=@($online|Where-Object{($_.CapState-ne1)-or($_.RenderState-ne1)})$nopair=@($online|Where-Object{$_.CapState-eq$null})if($Device){$online=@($online|Where-Object{$_.Name-like"*$Device*"})$broken=@($broken|Where-Object{$_.Name-like"*$Device*"})$nopair=@($nopair|Where-Object{$_.Name-like"*$Device*"})}Write-Host''if($All){Write-Host(' {0} headset(s) inspected (-All ignores the connection state); audio path ok: {1} / abnormal: {2}'-f$online.Count,($online.Count-$broken.Count),$broken.Count)-ForegroundColorGray}else{Write-Host(' connected headsets: {0}; audio path ok: {1} / abnormal: {2}'-f$online.Count,($online.Count-$broken.Count),$broken.Count)-ForegroundColorGray}if($online.Count-eq0){if($Device){Write-Host"[verdict] no connected headset matches '$Device', nothing to do"-ForegroundColorGray}else{Write-Host'[verdict] no connected Bluetooth headset, nothing to do (paired but disconnected devices are skipped)'-ForegroundColorGray}}elseif($broken.Count-gt0){Write-Host'[verdict] a headset is connected but its sound or microphone endpoint is not ready -> rebuild'-ForegroundColorYellow}elseif($nopair.Count-gt0){Write-Host'[verdict] a headset is connected but has no capture endpoint -> remove the pairing and pair again'-ForegroundColorRed}else{Write-Host'[verdict] every connected headset has a healthy audio path'-ForegroundColorGreen}if($DiagnoseOnly){Write-Host''Write-Host'(-DiagnoseOnly: diagnosis only, nothing changed)'-ForegroundColorGrayreturn}# ---------------- 2) Confirm ----------------if($Force-and$broken.Count-eq0){$targets=$online}elseif($broken.Count-gt0){$targets=$broken}else{$targets=@()}if($targets.Count-eq0){Write-Host''Write-Host'nothing to rebuild, done.'-ForegroundColorGreenreturn}if($targets.Count-eq1){$ok=Confirm-Step"Rebuild [$($targets[0].Name)] (about 20 s, audio drops briefly). Continue? (Y/N, default Y)"$trueif(-not$ok){Write-Host'Cancelled, nothing changed.'-ForegroundColorGray;return}}else{Write-Host''Write-Host'Several connected headsets have a broken audio path:'-ForegroundColorYellow$i=0foreach($tin$targets){$i++Write-Host(" [{0}] {1} render:{2} / capture:{3}"-f$i,$t.Name,(Get-StateText$t.RenderState),$(if($t.CapState-eq$null){'no capture endpoint'}else{Get-StateText$t.CapState}))-ForegroundColorGray}Write-Host''if($Force){Write-Host'(-Force: rebuild all)'-ForegroundColorGray}else{$sel=$nulltry{$sel=Read-Host'Enter numbers to fix only some (comma separated, e.g. 1,3), Enter = all, N = cancel'}catch{$sel='N'}if("$sel".Trim()-eq''){}elseif("$sel".Trim()-match'^[Nn]'){Write-Host'Cancelled, nothing changed.'-ForegroundColorGray;return}else{$picked=@()foreach($xin("$sel".Trim()-split',')){$n=0if([int]::TryParse($x.Trim(),[ref]$n)){if($n-ge1-and$n-le$targets.Count){$picked+=$targets[$n-1]}}}if($picked.Count-gt0){$targets=@($picked)}else{Write-Host'Invalid selection, processing all.'-ForegroundColorYellow}}}}# ---------------- 3) Elevation ----------------$isAdmin=(New-ObjectSecurity.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)if(-not$isAdmin){Write-Host''Write-Host'Rebuild needs administrator rights, asking for elevation (click Yes in UAC)...'-ForegroundColorYellow$argList=@('-NoProfile','-ExecutionPolicy','Bypass','-File',"`"$PSCommandPath`"",'-Force')if($Device){$argList+=@('-Device',$Device)}try{Start-Process-FilePath'powershell.exe'-VerbRunAs-ArgumentList$argList-ErrorActionStop}catch{Write-Host('Elevation failed: '+$_.Exception.Message)-ForegroundColorRed}return}# ---------------- 4) Rebuild ----------------Write-Host''Write-Host'=== Step 2: rebuild ==='-ForegroundColorCyan$hfpGroups=$targets|Where-Object{$_.HfpId}|Group-ObjectHfpIdforeach($gin$hfpGroups){$who=($g.Group |Select-Object-First1).NameWrite-Host" [HFP] $who"-ForegroundColorGray[void](Reset-Pnp$g.Name' restart the Bluetooth call device')}Start-Sleep-Seconds10$targetKeys=@($targets|ForEach-Object{$_.Key})$still=@(Get-PairedList|Where-Object{($targetKeys-contains$_.Key)-and(($_.CapState-ne1)-or($_.RenderState-ne1))})if($still.Count-gt0){$audioIds=@()foreach($ein$targets){$dev=$nullif($e.AudioDev){$dev=Get-PnpDevice-ClassMEDIA-ErrorActionSilentlyContinue|Where-Object{$_.FriendlyName-eq$e.AudioDev}|Select-Object-First1}if(-not$dev){$dev=Get-PnpDevice-ClassMEDIA-ErrorActionSilentlyContinue|Where-Object{$_.FriendlyName-match'Bluetooth.*Audio'}|Select-Object-First1}if($dev){$audioIds+=$dev.InstanceId}}$audioIds=@($audioIds|Select-Object-Unique)if($audioIds.Count-gt0){Write-Host''Write-Host' endpoints still inactive, deep repair: restart the parent audio device'-ForegroundColorYellowforeach($idin$audioIds){[void](Reset-Pnp$id' restart the parent audio device')}Start-Sleep-Seconds12}}# ---------------- 5) Verify ----------------$list2=Show-Table'Step 3: verify after rebuild'$online2=@($list2|Where-Object{$_.Connected})if($Device){$online2=@($online2|Where-Object{$_.Name-like"*$Device*"})}$bad2=@($online2|Where-Object{($_.CapState-ne1)-or($_.RenderState-ne1)})Write-Host''if($bad2.Count-eq0){Write-Host'[result] success: every connected headset has both render and capture endpoints ready'-ForegroundColorGreenWrite-Host' next: fully quit the browser/app -> reopen it -> pick the headset microphone in its settings'-ForegroundColorGray}else{Write-Host('[result] still abnormal: {0} headset(s): {1}'-f$bad2.Count,(($bad2|ForEach-Object{$_.Name})-join', '))-ForegroundColorRedWrite-Host' 1) is the headset also connected to a phone? Multipoint takes the call channel; disconnect the phone first'-ForegroundColorGrayWrite-Host' 2) Settings -> Bluetooth & devices -> the headset -> Remove device, then pair again'-ForegroundColorGrayWrite-Host' 3) reboot, then run this script again'-ForegroundColorGray}Write-Host''Write-Host'Press any key to close this window...'-ForegroundColorGraytry{$null=$Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')}catch{}
Multipoint with a phone - the phone owns the call channel, so Windows sees no usable capture endpoint. Disconnect the phone first.
No capture endpoint at all - remove the pairing and pair the headset again.
LE Audio - a headset paired over LE Audio may not expose an HFP endpoint, so the "no capture endpoint" verdict is expected.
Scope - the A2DP/HFP nodes and the endpoint layout come from the Windows Bluetooth stack, not from the headset vendor, so nothing in the script is brand-specific. It was checked on Windows 11 build 26300 (Intel Bluetooth and audio stack) with Baseus, Huawei and Poly headsets; other audio drivers and LE Audio are untested.