Skip to content

Commit 983dfc0

Browse files
committed
Resolve Rollbar# 33034,
SpeechManager:.ctor Unable to initialize System.Speech.Synthesis.SpeechSynthesizer, Microsoft Windows 10.0.19043
1 parent 5741b63 commit 983dfc0

2 files changed

Lines changed: 61 additions & 49 deletions

File tree

SpeechService/SpeechManager.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ public async Task InitializeAsync (CancellationToken ct = default)
6969
// Prep the System.Speech synthesizer
7070
try
7171
{
72-
systemSpeechSynth = new SystemSpeechSynthesizer( ref voiceStore );
72+
systemSpeechSynth = new SystemSpeechSynthesizer();
73+
systemSpeechSynth.Initialize( voiceStore );
7374
}
7475
catch ( ThreadAbortException )
7576
{

SpeechService/SpeechSynthesizers/SystemSpeechSynthesizer.cs

Lines changed: 59 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ internal string currentVoice
2828
}
2929
}
3030

31-
public SystemSpeechSynthesizer ( ref HashSet<VoiceDetails> voiceStore )
31+
public void Initialize ( HashSet<VoiceDetails> voiceStore )
3232
{
3333
bool TrySystemVoice ( VoiceDetails voiceDetails )
3434
{
@@ -57,76 +57,87 @@ bool TrySystemVoice ( VoiceDetails voiceDetails )
5757
systemSpeechVoices = synth
5858
.GetInstalledVoices()
5959
.Where( v => v.Enabled &&
60-
!v.VoiceInfo.Name.Contains( "Microsoft Server Speech Text to Speech Voice" ) &&
60+
!v.VoiceInfo.Name.Contains( "Microsoft Server Speech Text to Speech Voice" ) &&
6161
!v.VoiceInfo.Name.Contains( "eSpeak" ) )
6262
.ToList();
6363
}
6464

65-
foreach ( var voice in systemSpeechVoices )
65+
try
6666
{
67-
try
67+
foreach ( var voice in systemSpeechVoices )
6868
{
69-
Logging.Debug( $"Found voice: {voice.VoiceInfo.Name}", voice.VoiceInfo );
69+
try
70+
{
71+
Logging.Debug( $"Found voice: {voice.VoiceInfo.Name}", voice.VoiceInfo );
7072

71-
var voiceDetails = new VoiceDetails( voice.VoiceInfo.Name, voice.VoiceInfo.Gender.ToString(),
73+
var voiceDetails = new VoiceDetails( voice.VoiceInfo.Name, voice.VoiceInfo.Gender.ToString(),
7274
voice.VoiceInfo.Culture ?? CultureInfo.InvariantCulture, nameof(System) );
7375

74-
// Skip duplicates of voices already added from Windows.Media.SpeechSynthesis
75-
// (for example, if OneCore voices have been added to System.Speech with a registry edit)
76-
if ( voiceStore.Any( v => v.name == voiceDetails.name ) )
77-
{
78-
Logging.Debug(
79-
$"{voice.VoiceInfo.Name} has already been added to the voice list, skipping." );
80-
continue;
81-
}
76+
// Skip duplicates of voices already added from Windows.Media.SpeechSynthesis
77+
// (for example, if OneCore voices have been added to System.Speech with a registry edit)
78+
if ( voiceStore.Any( v => v.name == voiceDetails.name ) )
79+
{
80+
Logging.Debug(
81+
$"{voice.VoiceInfo.Name} has already been added to the voice list, skipping." );
82+
continue;
83+
}
8284

83-
// Skip voices which are not selectable
84-
if ( !TrySystemVoice( voiceDetails ) )
85-
{
86-
Logging.Debug( $"{voice.VoiceInfo.Name} is not selectable, skipping." );
87-
continue;
88-
}
85+
// Suppress voices "Desktop" variant voices from System.Speech.Synthesis
86+
// where we already have a (newer) OneCore version (without disabling manual invocation of those voices)
87+
if ( voiceStore.Any( v => $"{v.name} Desktop" == voiceDetails.name ) )
88+
{
89+
voiceDetails.hideVoice = true;
90+
}
8991

90-
// Suppress voices "Desktop" variant voices from System.Speech.Synthesis
91-
// where we already have a (newer) OneCore version (without disabling manual invocation of those voices)
92-
if ( voiceStore.Any( v => $"{v.name} Desktop" == voiceDetails.name ) )
93-
{
94-
voiceDetails.hideVoice = true;
95-
}
92+
// Skip Amazon Polly voices - these tend to throw various internal errors (cause unknown)
93+
// and are not currently reliable, particularly in VoiceAttack.
94+
if ( !string.IsNullOrEmpty( voiceDetails.name ) &&
95+
voiceDetails.name.StartsWith( "Amazon Polly" ) )
96+
{
97+
continue;
98+
}
99+
100+
// Skip voices which are not selectable
101+
if ( !TrySystemVoice( voiceDetails ) )
102+
{
103+
Logging.Debug( $"{voice.VoiceInfo.Name} is not selectable, skipping." );
104+
continue;
105+
}
96106

97-
// Skip Amazon Polly voices - these tend to throw various internal errors (cause unknown)
98-
// and are not currently reliable, particularly in VoiceAttack.
99-
if ( !string.IsNullOrEmpty( voiceDetails.name ) &&
100-
voiceDetails.name.StartsWith( "Amazon Polly" ) )
107+
voiceStore.Add( voiceDetails );
108+
Logging.Debug( $"Loaded voice: {voice.VoiceInfo.Name}", voiceDetails );
109+
}
110+
catch ( Exception e )
101111
{
112+
if ( voice.VoiceInfo.Culture is null )
113+
{
114+
Logging.Warn( $"Failed to load {voice.VoiceInfo.Name}, voice culture is not set.", e );
115+
}
116+
else
117+
{
118+
Logging.Error( $"Failed to load {voice.VoiceInfo.Name}", e );
119+
}
102120
continue;
103121
}
104-
105-
voiceStore.Add( voiceDetails );
106-
Logging.Debug( $"Loaded voice: {voice.VoiceInfo.Name}", voiceDetails );
107122
}
108-
catch ( Exception e )
123+
}
124+
finally
125+
{
126+
if ( selectedVoice != null )
109127
{
110-
if ( voice.VoiceInfo.Culture is null )
128+
try
111129
{
112-
Logging.Warn( $"Failed to load {voice.VoiceInfo.Name}, voice culture is not set.", e );
130+
lock ( synthLock )
131+
{
132+
synth.SelectVoice( selectedVoice.Name );
133+
}
113134
}
114-
else
135+
catch ( Exception e )
115136
{
116-
Logging.Error( $"Failed to load {voice.VoiceInfo.Name}", e );
137+
Logging.Warn( $"Failed to restore selected voice {selectedVoice.Name} during initialization.", e );
117138
}
118139
}
119140
}
120-
121-
if ( selectedVoice == null )
122-
{
123-
return;
124-
}
125-
126-
lock ( synthLock )
127-
{
128-
synth.SelectVoice( selectedVoice.Name );
129-
}
130141
}
131142

132143
internal Stream Speak(VoiceDetails voiceDetails, string speech, SpeechServiceConfiguration Configuration)

0 commit comments

Comments
 (0)