2012-03-26 9 views
5

Tengo una aplicación de captura/reproducción Swing simple que tiene que detectar si no hay un micrófono apropiado conectado a la computadora y advertir al usuario. Después de una gran cantidad de volverse locos que he encontrado la única solución que me ha permitido detectar el micrófono recién instalado o extraído:Actualización de sonido Java Lista de líneas después de conectar un micrófono

 com.sun.media.sound.JDK13Services.setCachingPeriod(0); 

    private static boolean isMicrophoneAvailable() { 
     try { 
      if (!AudioSystem.isLineSupported(Port.Info.MICROPHONE)) { 
       log.debug("NO MICROPHONE FOUND"); 
       return false; 
      } else { 
       log.debug("MICROPHONE FOUND"); 
       return true; 
      } 
     } catch (IllegalArgumentException e) { 
      log.debug("INCONSISTENT"); 
     } 
     return false; 
    } 

llamada en el subproceso de fondo de esta manera:

new Thread() { 
     public void run() { 
      while(!thisFrame.isClosed()){ 
       if(isMicrophoneAvailable() == true){ 
        //OK 
       }else{ 
        //WARN 
       } 
       try { 
        Thread.sleep(1000); 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 
      } 
     } 
    }).start(); 

El problema es que aunque el dispositivo se detecta correctamente utilizando el método descrito, la lista de Líneas subyacentes no se actualiza. Es decir, cuando se inicia el programa, y ​​el dispositivo se adjunta más adelante, la siguiente excepción se produce cuando se intenta grabar sonido:

java.lang.IllegalArgumentException: No line matching interface TargetDataLine supporting format PCM_SIGNED 44100.0 Hz, 16 bit, stereo, 4 bytes/frame, big-endian is supported. 

¿Hay alguna manera de obtener la lista de líneas de AudioSystem refrescado? ¿Tal vez algo similar a la solución alternativa JDK13Services utilizada al principio para evitar el almacenamiento en caché?

ACTUALIZACIÓN: El código que genera una excepción:

 AudioFormat format = formatControls.getDefaultFormat(); 
     DataLine.Info info = new DataLine.Info(TargetDataLine.class,format); 
     try { 
      line = (TargetDataLine) AudioSystem.getLine(info); 
      line.open(format, line.getBufferSize()); 
     } catch (LineUnavailableException ex) { 
      shutDown("No audio input device available. Please make sure that a microphone is attached to your computer"); 
      return; 
     } catch (Exception ex) { 
      log.error(ex.toString()); 
      shutDown(ex.toString()); 
      return; 
     } 

y la excepción en sí:

java.lang.IllegalArgumentException: No line matching interface TargetDataLine supporting format PCM_SIGNED 44100.0 Hz, 16 bit, stereo, 4 bytes/frame, big-endian is supported. 
+0

Interesante pregunta, +1. Sin embargo, para comprobarlo, te das cuenta de la fragilidad de usar una clase en los paquetes 'com.sun', ¿verdad? Incluso en los JRE donde existe, podría ser eliminado/movido/renombrado en la próxima versión. –

+0

De hecho, me doy cuenta de que esto es al menos una mala práctica, pero fue realmente mi último recurso. Supongo que se puede considerar como un error de implementación de Java Sound. –

+0

Una de muchas. JavaSound es bueno para la gama limitada de cosas que pretende soportar, pero Sun nunca lo desarrolló realmente más. –

Respuesta

0

Publicar el código que produce la excepción podría ayudar.

Estoy asumiendo que sólo se está utilizando el Port.Info para detectar la presencia de un micrófono a continuación, obtener una línea de datos para registrar:

TargetDataLine dataLine = (TargetDataLine) AudioSystem.getLine(new DataLine.Info(TargetDataLine.class, audioFormat));      
dataLine.open(); 
dataLine.start();    
dataLine.read(b, offset, len); 

en cuenta que todavía puede obtener una excepción similar al desconectar el micrófono si el micrófono está físicamente desconectado entre el momento en que comprueba la presencia y la hora en que intenta obtener la Dataline para grabar, pero conectar el microhpone no debería ser un problema.

+0

Parece que estoy haciendo casi lo mismo. De todos modos, he actualizado la pregunta con el código y la excepción. –

+0

Asegúrese de que la línea sea compatible con ese formato de audio. Para listar todos los formatos de audio admitidos por la línea: AudioFormat adfs [] = ((DataLine.Info) dataLine.getLineInfo()). GetFormats(); for (AudioFormat adf: adfs) { System.out.println (adf.toString()); } – msam

+0

No entiendo muy bien tu idea. line = (TargetDataLine) AudioSystem.getLine (información); es donde se lanza la excepción, por lo que no puedo obtener la línea en primer lugar. Tal vez no fui lo suficientemente claro: el micrófono funciona bien, si está conectado a la computadora antes del inicio del programa. La desconexión se detecta correctamente, el botón "Grabar" está desactivado. Cuando se vuelve a enchufar, funciona de nuevo. El problema surge si el micrófono no estaba conectado antes del inicio de jvm. En este caso, incluso si se detecta Port.Info.MICROPHONE, sus líneas aún no son funcionales. –

0

Usando la publicación original como inspiración, se me ocurrió esto como un medio para detectar cuándo se pierde o gana un micrófono. Detecta (en mi sistema) cuando un micrófono USB está enchufado o desenchufado. Lo estoy llamando desde un bucle de hilo de fondo. El método original no funcionó para mí, ya que hay un micrófono incorporado en la computadora portátil, así que necesitaba detectar la adición de un segundo micrófono.

... 
//call this once somewhere to turn the caching period down for faster detection 
    try 
    { 
     //try to set the caching period, defaults to something like 55 seconds 
     com.sun.media.sound.JDK13Services.setCachingPeriod(5); 
    } 
    catch(Exception e) 
    { 
     System.err.println("exception attempting to call com.sun.media.sound.JDK13Services.setCachingPeriod->" + e); 
    } 
... 

private int lastNumMics = -1; 
private synchronized void micCheck() 
{ 
    Line.Info[] lineInfoArray = AudioSystem.getSourceLineInfo(Port.Info.MICROPHONE); 
    int numMics = lineInfoArray == null ? 0 : lineInfoArray.length; 
    if(lastNumMics > -1) 
    { 
     if(numMics < lastNumMics) 
     { 
      //MICROPHONE_LOST 
     } 
     else if(numMics > lastNumMics) 
     { 
      //MICROPHONE_GAINED 
     } 
    } 
    lastNumMics = numMics; 
} 
Cuestiones relacionadas