Ограничение NAudio BufferedWaveProvider BufferDuration, вызывающее остановку чтения через определенное время

У меня есть текстовый речевой движок, который читает экзаменационные вопросы. Читалка вроде работает нормально, но я столкнулся с проблемой, когда есть большой текст для непрерывного чтения.

Через 12 минут (каждый раз) читатель просто перестает читать. Я проследил, что это как-то связано с BufferDuration Naudio BufferedWaveProvider. Вот мой код:

Shared waveOut As WaveOut
    Shared waveFormat As WaveFormat
    Shared provider As BufferedWaveProvider

    Private Shared Function InitializeAudio(Freq As Integer) As Boolean
        Try
            bNoAudioDected = False
            waveOut = New WaveOut()
            waveFormat = New WaveFormat(Freq, 16, 1)


            provider = New BufferedWaveProvider(waveFormat)
            provider.BufferLength = 31457280

           ''this was added for temporary duration fix
             Dim ts = New TimeSpan(0, 30, 0)
             provider.BufferDuration = ts
           '''''''''''''''''''''''''''''''''''''''''''


            provider.DiscardOnBufferOverflow = True
            Try
                waveOut.Init(provider)
            Catch mmEx As NAudio.MmException
                ErrorMessage("Audio device not detected!" & vbNewLine & "Please connect an audio device to use the Text-To-Speech system!")
                bNoAudioDected = True
                bAudioInitialised = True
                Return False
            Catch ex As Exception
                WriteError(ex, "TextToSpeech -> InitializeAudio")
                bNoAudioDected = True
                bAudioInitialised = True
                Return False
            End Try

            Return True
        Catch ex As Exception

        End Try
    End Function

    Private Shared Sub ReleaseAudio()
        Try
            If provider IsNot Nothing Then
                provider.ClearBuffer()
            End If

            If waveOut IsNot Nothing Then
                waveOut.[Stop]()
            End If
        Catch ex As Exception

        End Try
    End Sub

Я заметил, что по умолчанию BufferDuration установлено на: 11:53 мин. Я изменил это в коде на 10 секунд, используя TimeSpan. Через 10 секунд система сделала то же самое, что и 12-минутная проблема.

С тех пор я вручную изменил продолжительность в соответствии с моим кодом выше, сначала на 6 часов (просто для компенсации), это приводит к тому, что система мгновенно выходит из строя. Затем до 2 часов, которые, казалось, работали нормально, но вызывали проблемы с выделением меньшего текста. Затем до 30 минут, как сейчас, и это кажется стабильным, но меня беспокоит надежность, поскольку мои другие две попытки, похоже, вызвали больше проблем.

Мои вопросы в основном заключаются в том, является ли это ограничением dll NAudio, которое может обрабатывать только такое количество непрерывного чтения?

Следует ли изменить BufferDuration, как я это делаю сейчас, или значение по умолчанию должно оставаться прежним?

ИЗМЕНИТЬ

Вот класс-оболочка Text-To-Speech, который я использую. Обратите внимание, что это было предоставлено поставщиком Text-To-Speech, который я использую.

Imports NAudio.Wave
Imports VENET
Imports System.Threading.Thread

Public Class TextToSpeech
#Region "Variables"
#Region "Shared"
    Shared sText As String
    Shared sDir As String()
    Public Shared iSpeechRate As Integer = 100

    Shared hTtsInstance As IntPtr
    Shared hTtsCl As IntPtr
    Public Shared bUploadTypePaper As Boolean = False

#End Region
#Region "Global"
    Dim lstText As List(Of String)
    Dim nErr As NUAN_ERROR
    Dim tts As New VETts
    Dim Lang As VE_LANGUAGE()
    Dim Voice As VE_VOICEINFO()
    Dim thread As Threading.Thread

#End Region
#End Region
#Region "Properties"
    Private _newSpeed As Integer
    Public Property NewSpeed() As Integer
        Get
            Return _newSpeed
        End Get
        Set(ByVal value As Integer)
            _newSpeed = value
        End Set
    End Property

#End Region

    Private SpeechHandler As New VENET.VE_OUTPUTDEVICE(AddressOf StreamSpeech)

    Private Function StreamSpeech(hTtsInst As IntPtr, Msg As VE_MSG, Param As VE_LPARAM, OutData As VE_OUTDATA) As NUAN_ERROR
        Try
            If OutData.pOutPcmBuf IsNot Nothing Then
                provider.AddSamples(OutData.pOutPcmBuf, 0, CInt(OutData.ulPcmBufLen))
            End If
        Catch ex As Exception
            MessageBox.Show("StreamSpeech FAILED: " & nErr)
            MessageBox.Show("StreamSpeech FAILED: " & ex.InnerException.ToString())
        End Try

        Return NUAN_ERROR.NUAN_OK


    End Function



    Private Sub ExecuteTts()
        Try

            NewSpeed = TtsSpeechSpeed

            nErr = tts.ve_ttsGetLanguageList(hTtsCl, Lang)
            If nErr <> NUAN_ERROR.NUAN_OK Then
                MessageBox.Show("ve_ttsGetLanguageList FAILED: " & nErr)
                Exit Sub
            End If

            If Lang.Length = 0 Then
                MessageBox.Show("There are no available languages!")
                Exit Sub
            End If

            nErr = tts.ve_ttsGetVoiceList(hTtsCl, Lang(iLang).szLanguage, 0, Voice)
            If nErr <> NUAN_ERROR.NUAN_OK Then
                MessageBox.Show("ve_ttsGetVoiceList FAILED: " & nErr)
                Exit Sub
            End If

            If Voice.Length = 0 Then
                MessageBox.Show("There are no available voices!")
                Exit Sub
            End If

            Dim paramList() As VE_PARAM

            paramList = New VE_PARAM() {New VE_PARAM(VE_PARAMID.VE_PARAM_LANGUAGE, Lang(iLang).szLanguage), New VE_PARAM(VE_PARAMID.VE_PARAM_SPEECHRATE), New VE_PARAM(VE_PARAMID.VE_PARAM_VOICE, Voice(iVoice).szVoiceName)}

            If NewSpeed <> 0 Then
                iSpeechRate = NewSpeed
            ElseIf NewSpeed = 0 Then
                paramList(1).usValue = iSpeechRate
            End If

            paramList(1).usValue = iSpeechRate

            Try
                nErr = tts.ve_ttsSetParamList(hTtsInstance, paramList)
            Catch ex As Exception
                MsgBox(ex.Message)
            End Try

            If nErr <> NUAN_ERROR.NUAN_OK Then
                MessageBox.Show("ve_ttsSetParamList FAILED: " & nErr)
                Exit Sub
            End If

            Dim FreqParam As VE_PARAM() = {New VE_PARAM(VE_PARAMID.VE_PARAM_FREQUENCY)}

            nErr = tts.ve_ttsGetParamList(hTtsInstance, FreqParam)
            If nErr <> NUAN_ERROR.NUAN_OK Then
                MessageBox.Show("ve_ttsGetParamList FAILED: " & nErr)
                Exit Sub
            End If

            tts.tts_setOutDevice(SpeechHandler)

            ' Start Streaming Audio
            Try
                waveOut.Play()
            Catch ex As Exception

            End Try


            nErr = tts.ve_ttsProcessText2Speech(hTtsInstance, VE_TEXTFORMAT.VE_NORM_TEXT, sText)

            If nErr <> NUAN_ERROR.NUAN_OK And nErr <> NUAN_ERROR.NUAN_E_TTS_USERSTOP Then
                MessageBox.Show("ve_ttsProcessText2Speech FAILED: " & nErr)
                Exit Sub
            End If
        Catch ex As Exception
            MessageBox.Show("ExecuteTts FAILED: " & nErr)
            MessageBox.Show("ExecuteTts FAILED: " & ex.Message.ToString())
            MessageBox.Show("ExecuteTts FAILED: " & ex.InnerException.ToString())
        End Try
    End Sub



    Public Function InitialiseTtsEngine() As Boolean
        Try


            sDir = {sTtsEnginePath}

            nErr = tts.ve_ttsInitialize(sDir, hTtsCl)
            If nErr <> NUAN_ERROR.NUAN_OK Then
                MessageBox.Show("ve_ttsInitialize FAILED: " & nErr)
                Exit Function
            End If

            nErr = tts.ve_ttsOpen(hTtsCl, hTtsInstance)
            If nErr <> NUAN_ERROR.NUAN_OK Then
                MessageBox.Show("ve_ttsOpen FAILED: " & nErr)
                Exit Function
            End If

            If Not InitializeAudio(22050) Then
                MessageBox.Show("Could not initialize audio with sampling frequency")
            End If
        Catch ex As Exception
        End Try
    End Function

    Public Sub CleanUp()
        If hTtsInstance <> 0 Then
            nErr = tts.ve_ttsStop(hTtsInstance)
            Application.DoEvents()
            If nErr <> NUAN_ERROR.NUAN_OK Then
                MessageBox.Show("ve_ttsStop FAILED: " & nErr)
                Exit Sub
            End If

            Sleep(1500)

            nErr = tts.ve_ttsClose(hTtsInstance)
            Application.DoEvents()
            If nErr <> NUAN_ERROR.NUAN_OK Then
                MessageBox.Show("ve_ttsClose FAILED: " & nErr)
                Exit Sub
            End If
        End If

    End Sub

    Public Function UnInitialiseTtsEngineForTest() As Boolean

        Try
            If hTtsInstance <> 0 Then

                nErr = tts.ve_ttsStop(hTtsInstance)
                Application.DoEvents()
                If nErr <> NUAN_ERROR.NUAN_OK Then
                    MessageBox.Show("ve_ttsStop FAILED: " & nErr)

                End If

                Sleep(1500)

                nErr = tts.ve_ttsClose(hTtsInstance)
                Application.DoEvents()
                If nErr <> NUAN_ERROR.NUAN_OK Then
                    MessageBox.Show("ve_ttsClose FAILED: " & nErr)
                    Exit Function
                End If

                nErr = tts.ve_ttsUnInitialize(hTtsCl)
                Application.DoEvents()
                If nErr <> NUAN_ERROR.NUAN_OK Then
                    MessageBox.Show("ve_ttsUnInitialize FAILED: " & nErr)
                    Exit Function
                End If

                ReleaseAudio()

                GC.Collect()
            End If
        Catch ex As Exception
        End Try

    End Function

    Public Function UnInitialiseTtsEngineForQTCTest() As Boolean

        Try
            If hTtsInstance <> 0 Then

                nErr = tts.ve_ttsStop(hTtsInstance)
                Application.DoEvents()
                If nErr <> NUAN_ERROR.NUAN_OK Then
                    MessageBox.Show("ve_ttsStop FAILED: " & nErr)

                End If

                nErr = tts.ve_ttsClose(hTtsInstance)
                Application.DoEvents()
                If nErr <> NUAN_ERROR.NUAN_OK Then
                    MessageBox.Show("ve_ttsClose FAILED: " & nErr)
                    Exit Function
                End If

                nErr = tts.ve_ttsUnInitialize(hTtsCl)
                Application.DoEvents()
                If nErr <> NUAN_ERROR.NUAN_OK Then
                    MessageBox.Show("ve_ttsUnInitialize FAILED: " & nErr)
                    Exit Function
                End If

                ReleaseAudio()

                GC.Collect()
            End If
        Catch ex As Exception
        End Try

    End Function

    Public Function UnInitialiseTtsEngine() As Boolean

        Try
            If hTtsInstance <> 0 Then

                nErr = tts.ve_ttsClose(hTtsInstance)
                Application.DoEvents()
                If nErr <> NUAN_ERROR.NUAN_OK Then
                    MessageBox.Show("ve_ttsClose FAILED: " & nErr)
                    Exit Function
                End If

                nErr = tts.ve_ttsUnInitialize(hTtsCl)
                Application.DoEvents()
                If nErr <> NUAN_ERROR.NUAN_OK Then
                    MessageBox.Show("ve_ttsUnInitialize FAILED: " & nErr)
                    Exit Function
                End If

                ReleaseAudio()

                GC.Collect()
            End If
        Catch ex As Exception
        End Try

    End Function

    Public Sub PlayTts(ByVal text As String)
        Try

            sText = text

            If thread IsNot Nothing Then
                tts.ve_ttsStop(hTtsInstance)
                ReleaseAudio()
                thread.Join()
                thread = Nothing
            End If
            thread = New Threading.Thread(AddressOf ExecuteTts)
            thread.Start()

        Catch ex As Exception


        End Try
    End Sub

    Public Sub PauseResumeTts()
        Try
            If waveOut.PlaybackState = PlaybackState.Playing Then
                waveOut.Pause()
            ElseIf waveOut.PlaybackState = PlaybackState.Paused Then
                waveOut.Resume()
            End If
        Catch ex As Exception
            WriteError(ex, "TextToSpeech -> PlayPauseTts")
        End Try
    End Sub

    Shared waveOut As WaveOut
    Shared waveFormat As WaveFormat
    Shared provider As BufferedWaveProvider

    Private Shared Function InitializeAudio(Freq As Integer) As Boolean

        If bUploadTypePaper = True Then


            Try
                bNoAudioDected = False
                waveOut = New WaveOut()
                waveFormat = New WaveFormat(Freq, 16, 1)


                provider = New BufferedWaveProvider(waveFormat)
                provider.BufferLength = 31457280
                Dim ts = New TimeSpan(0, 30, 0)
                provider.BufferDuration = ts
                provider.DiscardOnBufferOverflow = True
                Try
                    waveOut.Init(provider)
                Catch mmEx As NAudio.MmException
                    ErrorMessage("Audio device not detected!" & vbNewLine & "Please connect an audio device to use the Text-To-Speech system!")
                    bNoAudioDected = True
                    bAudioInitialised = True
                    Return False
                Catch ex As Exception
                    WriteError(ex, "TextToSpeech -> InitializeAudio")
                    bNoAudioDected = True
                    bAudioInitialised = True
                    Return False
                End Try

                Return True
            Catch ex As Exception

            End Try

        End If


        ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
        ''This was provided
        ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
        Try
            bNoAudioDected = False
            waveOut = New WaveOut()
            waveFormat = New WaveFormat(Freq, 16, 1)


            provider = New BufferedWaveProvider(waveFormat)
            provider.BufferLength = 31457280
            provider.DiscardOnBufferOverflow = True
            Try
                waveOut.Init(provider)
            Catch mmEx As NAudio.MmException
                ErrorMessage("Audio device not detected!" & vbNewLine & "Please connect an audio device to use the Text-To-Speech system!")
                bNoAudioDected = True
                bAudioInitialised = True
                Return False
            Catch ex As Exception
                WriteError(ex, "TextToSpeech -> InitializeAudio")
                bNoAudioDected = True
                bAudioInitialised = True
                Return False
            End Try

            Return True
        Catch ex As Exception

        End Try
    End Function

    Private Shared Sub ReleaseAudio()
        Try
            If provider IsNot Nothing Then
                provider.ClearBuffer()
            End If

            If waveOut IsNot Nothing Then
                waveOut.[Stop]()
            End If
        Catch ex As Exception

        End Try
    End Sub
End Class

Это код, который я использую, когда нажимаю кнопку «прочитать текст»:

If CStr(currentSelection.type) <> "None" Then
            Dim range As IHTMLTxtRange = TryCast(currentSelection.createRange(), IHTMLTxtRange)
            If IsNothing(range.text) Then
                MessageBox.Show("There is no available text to be read!", "No Text Available", MessageBoxButtons.OK, MessageBoxIcon.Hand)
                Exit Sub
            End If

            If range IsNot Nothing Then
                CallTts(range.text)
            End If
        ElseIf currentSelection Is Nothing And String.IsNullOrEmpty(browserContents) Then
            MessageBox.Show("There is no available text to be read!", "No Text Available", MessageBoxButtons.OK, MessageBoxIcon.Hand)
            Exit Sub
        Else
            CallTts(browserContents)
        End If

И, наконец, код функции CallTts, который затем переходит к предоставленному классу TextToSpeech:

Try
  If thread IsNot Nothing Then
      tts.ve_ttsStop(hTtsInstance)
      ReleaseAudio()
      thread.Join()
      thread = Nothing
  End If
  thread = New Threading.Thread(AddressOf ExecuteTts)
  thread.Start()
Catch ex As Exception

End Try

person J2H656    schedule 24.07.2017    source источник


Ответы (1)


Вся идея BufferedWaveProvider заключается в том, что один поток заполняет его, а другой поток читает из него. Скорость заполнения и чтения должна быть примерно одинаковой, иначе поток заполнения переполнит буфер или поток чтения будет иметь отсев. Если вы пытаетесь установить размер буфера на несколько часов, похоже, что ваш вариант использования вообще не подходит для BufferedWaveProvider. Как вы добавляете звук в BufferedWaveProvider?

person Mark Heath    schedule 24.07.2017
comment
Привет, Марк, я отредактировал свой вопрос, добавив дополнительную информацию и код, если это поможет. Как видно из редактирования, класс-оболочка Text To Speech, который я использую, был предоставлен провайдером Text To Speech. Они добавили BufferLength = 31457280. Без этого BufferDuration по умолчанию устанавливается примерно на 5 секунд. Как только поток начинается, через 5 секунд он останавливается, как в моем исходном примере 12 минут и 10 секунд соответственно. Единственная причина установки продолжительности — это временное решение, чтобы считыватель не останавливался через 12 минут. Также они говорят, что, поскольку NAudio является третьей стороной, они не могут помочь... - person J2H656; 26.07.2017