Как программно определить аудиовыход в Windows 10? - PullRequest
2 голосов
/ 09 мая 2019

Я занимаюсь разработкой приложения на C ++, которое реализует Microsoft Speech API (SAPI). Я разработал множество функций, связанных с Text-To-Speech. Среди них функция, которая позволяет выводить список аудиовыходов, и функция, которая позволяет определять аудиовыход.

Я начал разработку этой программы для Windows 7, но теперь перешел на Windows 10. Однако функция, определяющая вывод звука, больше не работает. Я ничего не редактировал в своем коде, и в Windows 7 он работал отлично.

Вот код, который перечисляет доступные аудиовыходы

int getAudioOut( int auOut ) //get audio outputs function
{
    if( SUCCEEDED( hr ) )
    {
       //Enumerate Audio Outputs
       hr = SpEnumTokens( SPCAT_AUDIOOUT, NULL, NULL, &cpEnum );
       cpEnum->GetCount( &vCount );
       cpEnum->Item( saveAudio, &cpAudioOutToken );
       SpGetDescription( cpAudioOutToken, &dynStr );
       printf( "Defined audio output is: %ls\n\n", dynStr );
       dynStr.Clear();

       //Loop through the audio output list and enumerate them all
       for( audioOut = 0; audioOut <= vCount - 1; audioOut++ )
       {
          cpAudioOutToken.Release();
          cpEnum->Item( audioOut, &cpAudioOutToken );
          SpGetDescription( cpAudioOutToken, &dynStr );
          printf( "Defined Audio Output %i - %ls\n", audioOut, dynStr );
          dynStr.Clear();
       }
       printf( "\n" );
       audioOut = saveAudio;

       cpEnum.Release();
       cpAudioOutToken.Release();
    }
    else
    {
       printf( "Could not enumerate available audio outputs\n" );
    }

    return true;
}

Вот код, который позволяет определять аудиовыход

int setAudioOut( int auOut ) //define audio output function
{
   if( SUCCEEDED( hr ) )
   {
      hr = SpEnumTokens( SPCAT_AUDIOOUT, NULL, NULL, &cpEnum );
      cpEnum->GetCount( &vCount );
      size_t nOut = auOut;

      if( nOut >= vCount )
      {
         cout << "Not so many audio outputs available! Try again\n" << endl;
      }
      else
      {
         cout << "Success" << endl;
      }

       ULONG audioOut = static_cast<ULONG>( nOut ); //convert nOut to ULONG audioOut

       cpEnum->Item( audioOut, &cpAudioOutToken );
       SpGetDescription( cpAudioOutToken, &dynStr );
       printf( "You chose %ls\n\n", dynStr );
       cpVoice->SetOutput( cpAudioOutToken, TRUE ); //Initialization of the Audio Output
       dynStr.Clear();

       cpEnum.Release();
       cpAudioOutToken.Release();

       saveAudio = audioOut; //define saveAudio to audioOut value
    }
    else
    {
       printf( "Could not set audio output\n" );
    }

    return true;
}

Когда я запускаю свою программу и вызываю функцию getAudioOut, я получаю следующий список:

getAudioOut function listing

Первая строка показывает аудиовыход по умолчанию, а две ниже - доступные выходы. В Windows 7, когда я устанавливаю второй аудиовыход (Lautsprecher / Kopfhörer) по умолчанию, звук из первого (Digitalaudio) не выходит, что имеет смысл. Тем не менее, в Windows 10 я воспроизвел ту же процедуру, но она не работает. Выходной аудиосигнал всегда определяется в соответствии с аудио меню.

Audio Menu

Мой вопрос: Кто-нибудь сталкивался с этой проблемой? Есть ли альтернатива программному определению аудиовыхода?

1 Ответ

1 голос
/ 10 мая 2019

Я отредактировал код, как предложил @NikolayShmyrev, но он ничего не изменил. Однако я продолжил копаться в проблеме и обнаружил, что проблема возникла из-за другой функции. Действительно, когда я переключился с Windows 7 на Windows 10, у меня возникли другие проблемы с функцией синтеза речи и функцией речи в файл WAV. Когда я запустил программу и вызвал функцию Text-To-Speech, все работало отлично. Когда я вызвал функцию Speech2Wav, она тоже сработала. Однако, когда я вспомнил функцию Text-To-Speech, переменная HRESULT hr = S_OK; изменила свое значение, и звук не воспроизводился. Значение hr было установлено на -2147200968 , что соответствует Ошибка 0x80045038: SPERR_STREAM_CLOSED ( источник / список кодов ошибок )

Чтобы решить эту проблему, я должен был определить аудиовыход, подобный этому cpVoice->SetOutput( cpAudioOutToken, TRUE ); в функции Text-To-Speech.

Это возвращает нас к проблеме, о которой я говорил выше. Когда я устанавливаю аудиовыход в функции setAudioOut, я освобождаю его значение в конце cpAudioOutToken.Release(); Однако я снова использую ту же переменную в функции Text-To-Speech. Его значение было установлено равным нулю, потому что я выпустил его, когда определил вывод звука. Вот почему аудио выход всегда был установлен по умолчанию. Чтобы решить эту проблему, я присвоил значение cpAudioOutToken другой переменной с именем cpSpeechOutToken.

Вот код для функции setAudioOut

int setAudioOut( int auOut ) //define audio output function
{
   if( SUCCEEDED( hr ) )
   {
      hr = SpEnumTokens( SPCAT_AUDIOOUT, NULL, NULL, &cpEnum );
      cpEnum->GetCount( &vCount );
      size_t nOut = auOut;

      if( nOut >= vCount )
      {
         cout << "Not so many audio outputs available! Try again\n" << endl;
         return 0;
      }
      else
      {
         cout << "Success" << endl;
      }

      ULONG audioOut = static_cast<ULONG>( nOut ); //convert nOut to ULONG audioOut

      cpEnum->Item( audioOut, &cpAudioOutToken );
      SpGetDescription( cpAudioOutToken, &dynStr );
      printf( "You chose %ls\n\n", dynStr );
      cpVoice->SetOutput( cpAudioOutToken, TRUE ); //Initialization of the Audio Output
      dynStr.Clear();

      cpEnum.Release();
      cpSpeechOutToken = cpAudioOutToken;
      cpAudioOutToken.Release();
      saveAudio = audioOut; //define saveAudio to audioOut value
   }
   else
   {
      printf( "Could not set audio output\n" );
   }
   return true;
}

Вот код из Text-To-Speech функции

int ttsSpeak( const char* text ) //Text to Speech speaking function
{
   if( SUCCEEDED( hr ) )
   {
      string xmlSentence( text );
      hr = SpEnumTokens( SPCAT_VOICES_WIN10, NULL, NULL, &cpEnum );
      //Replace SPCAT_VOICES_WIN10 with SPCAT_VOICES if you want to use it on Windows 7

      cpEnum->Item( saveVoice, &cpVoiceToken ); //get saveVoice token defined at line 175
      cpVoice->SetVoice( cpVoiceToken ); //Initialization of the voice

      //string strText( text );

      int wchars_num = MultiByteToWideChar( CP_ACP, 0, xmlSentence.c_str(), -1, NULL, 0 );
      wchar_t* wstr = new wchar_t[ wchars_num ];
      MultiByteToWideChar( CP_ACP, 0, xmlSentence.c_str(), -1, wstr, wchars_num );

      printf( "Text To Speech processing\n" );
      cpVoice->SetOutput( cpSpeechOutToken, TRUE );
      hr = cpVoice->Speak( wstr, SVSFIsXML, NULL );

      saveText = xmlSentence.c_str();

      cpEnum.Release();
      cpVoiceToken.Release();
      delete new wchar_t[ wchars_num ];
  }
  else
  {
     printf( "Could not speak entered text\n" );
  }
  return true;
}
...