Полученные имена устройств захвата звука различаются при запросе в потоке JavaFX по сравнению с обычным потоком Java - PullRequest
2 голосов
/ 08 мая 2020

Я столкнулся со странным поведением при запросе имен устройств захвата звука в потоке JavaFX по сравнению с «простым» потоком Java.

Обычно я, вероятно, не заметил бы, кроме есть некоторые приложения, не относящиеся к JavaFX, которые используют общий пул конфигурации с приложением JavaFX, и это вызвало некоторые проблемы при программной настройке используемого аудиоустройства захвата.

В двух словах, тот же самый запрос main в простой Поток 1045 * возвращает имена устройств захвата, усеченные до 31 символа, тогда как в потоке JavaFX имена устройств захвата являются «полными».

Например, усеченные результаты ...

Primary Sound Capture Driver
Microphone (HD Pro Webcam C910)
Microphone (Realtek(R) Audio)
Headset (Bose QuietComfort 35 H
Headset Microphone (Oculus Virt

. ..vs 'полные' результаты:

Primary Sound Capture Driver
Microphone (HD Pro Webcam C910)
Microphone (Realtek(R) Audio)
Headset (Bose QuietComfort 35 Hands-Free)
Headset Microphone (Oculus Virtual Audio Device)

Минимальный код приложения JavaFX ниже демонстрирует проблему, и в моем тестировании это происходит как в 32-битной, так и в 64-битной версиях Java8 JDK на Windows 10 . Я не тестировал платформы, отличные от Windows, поэтому я не уверен, происходит ли такое поведение за пределами этой среды.

Метод showCaptureDeviceNames() делает то Электронный запрос и распечатка названий устройств. При вызове из метода main отображаются усеченные имена устройств. Если закомментировано из main и вызвано нажатием кнопки в потоке JavaFX, отображаются «полные» имена устройств.

Интересно, что при вызове в main сначала , а затем в потоке JavaFX показаны усеченные имена, указывающие на то, что происходит какое-то кеширование (которое, к счастью, обеспечивает обходной путь для моей проблемы). Простого вызова AudioSystem.getMixerInfo(); самого по себе достаточно, чтобы вызвать эффект «кэширования»

Кроме того, это происходит только для устройств захвата ; если TargetDataLine.class переключен на SourceDataLine.class для фильтрации устройств воспроизведения , имя устройства всегда будет «полным».

Может ли кто-нибудь подсказать, почему это может происходить ?

Мой текущий обходной путь - убедиться, что приложение JavaFX запрашивает все аудиоустройства до , поток JavaFX запускается с вызова AudioSystem.getMixerInfo(); в main(...). Это работает, но ... в качестве "исправления" это больше похоже на ошибку, которая возникает сама по себе без видимой причины (хотя адекватные комментарии помогут будущим разработчикам, которые столкнутся с этим).

Я бы люблю, когда кто-то говорит мне, что я делаю что-то не так, и есть способ получше.

import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Line;
import javax.sound.sampled.Mixer;
import javax.sound.sampled.Mixer.Info;
import javax.sound.sampled.TargetDataLine;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class CaptureDeviceListTest extends Application
{
    @Override
    public void start( Stage primaryStage )
        throws Exception
    {
        primaryStage.setTitle( "Test Capture Device Queries" );

        Button btn = new Button( "Get capture device names" );
        btn.setOnAction( event -> showCaptureDeviceNames() );

        StackPane root = new StackPane();
        root.getChildren().add( btn );
        primaryStage.setScene( new Scene( root, 200, 200 ) );
        primaryStage.show();
    }

    private static void showCaptureDeviceNames()
    {
        // filter for capture devices - change to `SourceTargetData.class` for playback devices
        Line.Info captureLine = new Line.Info( TargetDataLine.class );
        for( Info mixerInfo : AudioSystem.getMixerInfo() )
        {
            Mixer mixer = AudioSystem.getMixer( mixerInfo );
            if( mixer.isLineSupported( captureLine ) )
                System.out.println( mixerInfo.getName() );
        }
    }

    public static void main( String[] args )
    {
        // COMMENT / UNCOMMENT THE NEXT LINE
        // showCaptureDeviceNames();
        launch( args );
    }
}
...