From f4952ad13257506690c5bc783db9dc517d4a1cbe Mon Sep 17 00:00:00 2001 From: Nolan Darilek Date: Wed, 25 Nov 2020 10:07:28 -0600 Subject: [PATCH] UWP tweaks and optimizations. * Initialized TTS `MediaPlayer` in real-time mode. * Set media category to speech. * More aggressively drop locks to prevent deadlocks. * Remove checks of queued items that are no longer necessary. * Made `is_speaking` check both media player state and queued item count. * Return eagerly from `stop` if speech isn't in progress, thus eliminating more locks. --- src/backends/winrt.rs | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/backends/winrt.rs b/src/backends/winrt.rs index a7468a8..512eba4 100644 --- a/src/backends/winrt.rs +++ b/src/backends/winrt.rs @@ -8,7 +8,7 @@ use winrt::*; use tts_winrt_bindings::windows::media::playback::{ CurrentMediaPlaybackItemChangedEventArgs, MediaPlaybackItem, MediaPlaybackList, - MediaPlaybackState, MediaPlayer, + MediaPlaybackState, MediaPlayer, MediaPlayerAudioCategory, }; use tts_winrt_bindings::windows::media::speech_synthesis::SpeechSynthesizer; use tts_winrt_bindings::windows::{foundation::TypedEventHandler, media::core::MediaSource}; @@ -53,12 +53,16 @@ impl WinRT { info!("Initializing WinRT backend"); let playback_list = MediaPlaybackList::new()?; let player = MediaPlayer::new()?; + player.set_real_time_playback(true)?; + player.set_audio_category(MediaPlayerAudioCategory::Speech)?; player.set_source(&playback_list)?; let mut backend_id = NEXT_BACKEND_ID.lock().unwrap(); let bid = BackendId::WinRT(*backend_id); *backend_id += 1; + drop(backend_id); let mut backend_to_media_player = BACKEND_TO_MEDIA_PLAYER.lock().unwrap(); backend_to_media_player.insert(bid, player.clone()); + drop(backend_to_media_player); player.media_ended(TypedEventHandler::new(|sender: &MediaPlayer, _args| { let source = sender.source()?; let source: MediaPlaybackList = source.try_into()?; @@ -80,6 +84,7 @@ impl WinRT { }))?; let mut backend_to_playback_list = BACKEND_TO_PLAYBACK_LIST.lock().unwrap(); backend_to_playback_list.insert(bid, playback_list.clone()); + drop(backend_to_playback_list); playback_list.current_item_changed(TypedEventHandler::new( |sender: &MediaPlaybackList, args: &CurrentMediaPlaybackItemChangedEventArgs| { let backend_to_playback_list = BACKEND_TO_PLAYBACK_LIST.lock().unwrap(); @@ -155,17 +160,11 @@ impl Backend for WinRT { let content_type = stream.content_type()?; let source = MediaSource::create_from_stream(stream, content_type)?; let item = MediaPlaybackItem::create(source)?; - let item_index = self.playback_list.current_item_index()?; - let item_count = self.playback_list.items()?.size()?; - let state = self.player.playback_session()?.playback_state()?; - if interrupt && state != MediaPlaybackState::Paused { + if interrupt && self.is_speaking()? { self.stop()?; } - if state == MediaPlaybackState::Paused && item_index != 0 && item_index < item_count { - self.playback_list.items()?.clear()?; - } self.playback_list.items()?.append(&item)?; - if !self.is_speaking()? { + if self.player.playback_session()?.playback_state()? != MediaPlaybackState::Playing { self.player.play()?; } let mut uid = NEXT_UTTERANCE_ID.lock().unwrap(); @@ -179,10 +178,13 @@ impl Backend for WinRT { fn stop(&mut self) -> std::result::Result<(), Error> { trace!("stop()"); + if !self.is_speaking()? { + return Ok(()); + } self.playback_list.items()?.clear()?; - let mut mappings = UTTERANCE_MAPPINGS.lock().unwrap(); let mut callbacks = CALLBACKS.lock().unwrap(); let callbacks = callbacks.get_mut(&self.id).unwrap(); + let mut mappings = UTTERANCE_MAPPINGS.lock().unwrap(); if let Some(callback) = callbacks.utterance_stop.as_mut() { for mapping in &*mappings { callback(mapping.2); @@ -259,9 +261,10 @@ impl Backend for WinRT { } fn is_speaking(&self) -> std::result::Result { + let item_count = self.playback_list.items()?.size()?; let state = self.player.playback_session()?.playback_state()?; let playing = state == MediaPlaybackState::Playing; - Ok(playing) + Ok(item_count != 0 || playing) } }