Пример #1
0
        /// <summary>
        /// 获取章节语音
        /// </summary>
        /// <param name="chapter">章节</param>
        /// <param name="setCurrentChapter">是否将其设置为当前章节</param>
        /// <param name="synthesizer">语音合成器</param>
        /// <returns></returns>
        public async Task <MediaPlaybackItem> GetChapterVoiceAsync(Chapter chapter, bool setCurrentChapter = false, SpeechSynthesizer synthesizer = null)
        {
            if (Chapters.Count == 0)
            {
                throw new InvalidCastException("Chapter not loaded");
            }
            else if (chapter == null || !Chapters.Contains(chapter))
            {
                throw new ArgumentException("The chapter is not in current book");
            }

            // 将章节转化为语音合成流需要时间和额外的系统资源,不宜生成超量的文本
            string content = GetReadText(chapter);

            if (content.Length > SpeechMaxLength)
            {
                throw new Exception("The chapter detail text length is too large");
            }

            if (CurrentChapter != chapter)
            {
                LoadChapter(chapter);
            }

            // 控件原本是按需加载页面,但考虑到用户会对生成的语音流进行进度调整,所以在生成合成语音时会将当前章节未渲染的部分全部渲染
            _readerView.RenderAllOverflows();
            bool isTempSyn = false;

            if (synthesizer == null)
            {
                synthesizer = new SpeechSynthesizer();
                isTempSyn   = true;
            }
            synthesizer.Options.IncludeSentenceBoundaryMetadata = true;
            synthesizer.Options.IncludeWordBoundaryMetadata     = true;

            var stream = await synthesizer.SynthesizeTextToStreamAsync(content);

            _tempSpeechStream = stream;
            MediaSource source = MediaSource.CreateFromStream(stream, stream.ContentType);

            if (isTempSyn)
            {
                synthesizer.Dispose();
            }
            var playback = new MediaPlaybackItem(source);

            RegisterForWordBoundaryEvents(playback);
            return(playback);
        }