/**
   * Checks whether the playback and notification configuration share the same device.
   *
   * @return are audio out and notifications using the same device.
   */
  public boolean audioOutAndNotificationsShareSameDevice() {
    AudioSystem audioSystem = getDeviceConfiguration().getAudioSystem();
    CaptureDeviceInfo notify = audioSystem.getSelectedDevice(AudioSystem.DataFlow.NOTIFY);
    CaptureDeviceInfo playback = audioSystem.getSelectedDevice(AudioSystem.DataFlow.PLAYBACK);

    if (notify == null) return (playback == null);
    else {
      if (playback == null) return false;
      else return notify.getLocator().equals(playback.getLocator());
    }
  }
예제 #2
0
  /**
   * Create preview component.
   *
   * @param type type
   * @param comboBox the options.
   * @param prefSize the preferred size
   * @return the component.
   */
  private static Component createPreview(int type, final JComboBox comboBox, Dimension prefSize) {
    JComponent preview = null;

    if (type == DeviceConfigurationComboBoxModel.AUDIO) {
      Object selectedItem = comboBox.getSelectedItem();

      if (selectedItem instanceof AudioSystem) {
        AudioSystem audioSystem = (AudioSystem) selectedItem;

        if (!NoneAudioSystem.LOCATOR_PROTOCOL.equalsIgnoreCase(audioSystem.getLocatorProtocol())) {
          preview = new TransparentPanel(new GridBagLayout());
          createAudioSystemControls(audioSystem, preview);
        }
      }
    } else if (type == DeviceConfigurationComboBoxModel.VIDEO) {
      JLabel noPreview =
          new JLabel(
              NeomediaActivator.getResources().getI18NString("impl.media.configform.NO_PREVIEW"));

      noPreview.setHorizontalAlignment(SwingConstants.CENTER);
      noPreview.setVerticalAlignment(SwingConstants.CENTER);

      preview = createVideoContainer(noPreview);
      preview.setPreferredSize(prefSize);

      Object selectedItem = comboBox.getSelectedItem();
      CaptureDeviceInfo device = null;
      if (selectedItem instanceof DeviceConfigurationComboBoxModel.CaptureDevice)
        device = ((DeviceConfigurationComboBoxModel.CaptureDevice) selectedItem).info;

      Exception exception;
      try {
        createVideoPreview(device, preview);
        exception = null;
      } catch (IOException ex) {
        exception = ex;
      } catch (MediaException ex) {
        exception = ex;
      }
      if (exception != null) {
        logger.error("Failed to create preview for device " + device, exception);
        device = null;
      }
    }

    return preview;
  }
    /** Configures echo cancellation and noise suppression effects. */
    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    private void configureEffects() {
      if (!AndroidUtils.hasAPI(16)) return;

      AudioSystem audioSystem =
          AudioSystem.getAudioSystem(AudioSystem.LOCATOR_PROTOCOL_AUDIORECORD);

      // Creates echo canceler if available
      if (AcousticEchoCanceler.isAvailable()) {
        AcousticEchoCanceler echoCanceller =
            AcousticEchoCanceler.create(audioRecord.getAudioSessionId());
        if (echoCanceller != null) {
          echoCanceller.setEnableStatusListener(this);
          echoCanceller.setEnabled(audioSystem.isEchoCancel());
          logger.info("Echo cancellation: " + echoCanceller.getEnabled());
        }
      }

      // Automatic gain control
      if (AutomaticGainControl.isAvailable()) {
        AutomaticGainControl agc = AutomaticGainControl.create(audioRecord.getAudioSessionId());
        if (agc != null) {
          agc.setEnableStatusListener(this);
          agc.setEnabled(audioSystem.isAutomaticGainControl());
          logger.info("Auto gain control: " + agc.getEnabled());
        }
      }

      // Creates noise suppressor if available
      if (NoiseSuppressor.isAvailable()) {
        NoiseSuppressor noiseSuppressor = NoiseSuppressor.create(audioRecord.getAudioSessionId());
        if (noiseSuppressor != null) {
          noiseSuppressor.setEnableStatusListener(this);
          noiseSuppressor.setEnabled(audioSystem.isDenoise());
          logger.info("Noise suppressor: " + noiseSuppressor.getEnabled());
        }
      }
    }
예제 #4
0
  /**
   * Creates the UI controls which are to control the details of a specific <tt>AudioSystem</tt>.
   *
   * @param audioSystem the <tt>AudioSystem</tt> for which the UI controls to control its details
   *     are to be created
   * @param container the <tt>JComponent</tt> into which the UI controls which are to control the
   *     details of the specified <tt>audioSystem</tt> are to be added
   */
  public static void createAudioSystemControls(AudioSystem audioSystem, JComponent container) {
    GridBagConstraints constraints = new GridBagConstraints();

    constraints.anchor = GridBagConstraints.NORTHWEST;
    constraints.fill = GridBagConstraints.HORIZONTAL;
    constraints.weighty = 0;

    int audioSystemFeatures = audioSystem.getFeatures();
    boolean featureNotifyAndPlaybackDevices =
        ((audioSystemFeatures & AudioSystem.FEATURE_NOTIFY_AND_PLAYBACK_DEVICES) != 0);

    constraints.gridx = 0;
    constraints.insets = new Insets(3, 0, 3, 3);
    constraints.weightx = 0;

    constraints.gridy = 0;
    container.add(
        new JLabel(getLabelText(DeviceConfigurationComboBoxModel.AUDIO_CAPTURE)), constraints);
    if (featureNotifyAndPlaybackDevices) {
      constraints.gridy = 2;
      container.add(
          new JLabel(getLabelText(DeviceConfigurationComboBoxModel.AUDIO_PLAYBACK)), constraints);
      constraints.gridy = 3;
      container.add(
          new JLabel(getLabelText(DeviceConfigurationComboBoxModel.AUDIO_NOTIFY)), constraints);
    }

    constraints.gridx = 1;
    constraints.insets = new Insets(3, 3, 3, 0);
    constraints.weightx = 1;

    JComboBox captureCombo = null;

    if (featureNotifyAndPlaybackDevices) {
      captureCombo = new JComboBox();
      captureCombo.setEditable(false);
      captureCombo.setModel(
          new DeviceConfigurationComboBoxModel(
              captureCombo,
              mediaService.getDeviceConfiguration(),
              DeviceConfigurationComboBoxModel.AUDIO_CAPTURE));
      constraints.gridy = 0;
      container.add(captureCombo, constraints);
    }

    int anchor = constraints.anchor;
    SoundLevelIndicator capturePreview =
        new SoundLevelIndicator(
            SimpleAudioLevelListener.MIN_LEVEL, SimpleAudioLevelListener.MAX_LEVEL);

    constraints.anchor = GridBagConstraints.CENTER;
    constraints.gridy = (captureCombo == null) ? 0 : 1;
    container.add(capturePreview, constraints);
    constraints.anchor = anchor;

    constraints.gridy = GridBagConstraints.RELATIVE;

    if (featureNotifyAndPlaybackDevices) {
      JComboBox playbackCombo = new JComboBox();

      playbackCombo.setEditable(false);
      playbackCombo.setModel(
          new DeviceConfigurationComboBoxModel(
              captureCombo,
              mediaService.getDeviceConfiguration(),
              DeviceConfigurationComboBoxModel.AUDIO_PLAYBACK));
      container.add(playbackCombo, constraints);

      JComboBox notifyCombo = new JComboBox();

      notifyCombo.setEditable(false);
      notifyCombo.setModel(
          new DeviceConfigurationComboBoxModel(
              captureCombo,
              mediaService.getDeviceConfiguration(),
              DeviceConfigurationComboBoxModel.AUDIO_NOTIFY));
      container.add(notifyCombo, constraints);
    }

    if ((AudioSystem.FEATURE_ECHO_CANCELLATION & audioSystemFeatures) != 0) {
      final SIPCommCheckBox echoCancelCheckBox =
          new SIPCommCheckBox(
              NeomediaActivator.getResources().getI18NString("impl.media.configform.ECHOCANCEL"));

      /*
       * First set the selected one, then add the listener in order to
       * avoid saving the value when using the default one and only
       * showing to user without modification.
       */
      echoCancelCheckBox.setSelected(mediaService.getDeviceConfiguration().isEchoCancel());
      echoCancelCheckBox.addItemListener(
          new ItemListener() {
            public void itemStateChanged(ItemEvent e) {
              mediaService.getDeviceConfiguration().setEchoCancel(echoCancelCheckBox.isSelected());
            }
          });
      container.add(echoCancelCheckBox, constraints);
    }

    if ((AudioSystem.FEATURE_DENOISE & audioSystemFeatures) != 0) {
      final SIPCommCheckBox denoiseCheckBox =
          new SIPCommCheckBox(
              NeomediaActivator.getResources().getI18NString("impl.media.configform.DENOISE"));

      /*
       * First set the selected one, then add the listener in order to
       * avoid saving the value when using the default one and only
       * showing to user without modification.
       */
      denoiseCheckBox.setSelected(mediaService.getDeviceConfiguration().isDenoise());
      denoiseCheckBox.addItemListener(
          new ItemListener() {
            public void itemStateChanged(ItemEvent e) {
              mediaService.getDeviceConfiguration().setDenoise(denoiseCheckBox.isSelected());
            }
          });
      container.add(denoiseCheckBox, constraints);
    }

    createAudioPreview(audioSystem, captureCombo, capturePreview);
  }
  /**
   * Creates an SCAudioClip from the given URI and adds it to the list of available audio-s.
   *
   * @param uri the path where the audio file could be found
   * @param playback use or not the playback device.
   * @return a newly created <tt>SCAudioClip</tt> from <tt>uri</tt>
   */
  public SCAudioClip createAudio(String uri, boolean playback) {
    SCAudioClip audio;

    synchronized (audiosSyncRoot) {
      final AudioKey key = new AudioKey(uri, playback);

      /*
       * While we want to reuse the SCAudioClip instances, they may be
       * used by a single user at a time. That's why we'll forget about
       * them while they are in use and we'll reclaim them when they are
       * no longer in use.
       */
      audio = (audios == null) ? null : audios.remove(key);

      if (audio == null) {
        try {
          AudioSystem audioSystem = getDeviceConfiguration().getAudioSystem();

          if (audioSystem == null) {
            audio = new JavaSoundClipImpl(uri, this);
          } else if (NoneAudioSystem.LOCATOR_PROTOCOL.equalsIgnoreCase(
              audioSystem.getLocatorProtocol())) {
            audio = null;
          } else {
            audio = new AudioSystemClipImpl(uri, this, audioSystem, playback);
          }
        } catch (Throwable t) {
          if (t instanceof ThreadDeath) throw (ThreadDeath) t;
          else {
            /*
             * Could not initialize a new SCAudioClip instance to be
             * played.
             */
            return null;
          }
        }
      }

      /*
       * Make sure that the SCAudioClip will be reclaimed for reuse when
       * it is no longer in use.
       */
      if (audio != null) {
        if (audios == null) audios = new HashMap<AudioKey, SCAudioClip>();

        /*
         * We have to return in the Map which was active at the time the
         * SCAudioClip was initialized because it may have become
         * invalid if the playback or notify audio device changed.
         */
        final Map<AudioKey, SCAudioClip> finalAudios = audios;
        final SCAudioClip finalAudio = audio;

        audio =
            new SCAudioClip() {
              /**
               * Evaluates a specific <tt>loopCondition</tt> as defined by {@link
               * SCAudioClip#play(int,Callable)}.
               *
               * @param loopCondition the <tt>Callable&lt;Boolean&gt;</tt> which represents the
               *     <tt>loopCondition</tt> to be evaluated
               * @return {@link Boolean#FALSE} if <tt>loopCondition</tt> is <tt>null</tt>;
               *     otherwise, the value returned by invoking {@link Callable#call()} on the
               *     specified <tt>loopCondition</tt>
               * @throws Exception if the specified <tt>loopCondition</tt> throws an
               *     <tt>Exception</tt>
               */
              private Boolean evaluateLoopCondition(Callable<Boolean> loopCondition)
                  throws Exception {
                /*
                 * SCAudioClip.play(int,Callable<Boolean>) is
                 * documented to play the SCAudioClip once only if
                 * the loopCondition is null. The same will be
                 * accomplished by returning Boolean.FALSE.
                 */
                return (loopCondition == null) ? Boolean.FALSE : loopCondition.call();
              }

              /**
               * {@inheritDoc}
               *
               * <p>Returns the wrapped <tt>SCAudioClip</tt> into the cache from it has earlier been
               * retrieved in order to allow its reuse.
               */
              @Override
              protected void finalize() throws Throwable {
                try {
                  synchronized (audios) {
                    finalAudios.put(key, finalAudio);
                  }
                } finally {
                  super.finalize();
                }
              }

              public void play() {
                /*
                 * SCAudioClip.play() is documented to behave as if
                 * loopInterval is negative and/or loopCondition is
                 * null. We have to take care that this instance
                 * does not get garbage collected until the
                 * finalAudio finishes playing so we will delegate
                 * to this instance's implementation of
                 * SCAudioClip.play(int,Callable<Boolean>) instead
                 * of to the finalAudio's.
                 */
                play(-1, null);
              }

              public void play(int loopInterval, final Callable<Boolean> finalLoopCondition) {
                /*
                 * We have to make sure that this instance does not
                 * get garbage collected before the finalAudio
                 * finishes playing. The argument loopCondition of
                 * the method
                 * SCAudioClip.play(int,Callable<Boolean>) will
                 * live/be referenced during that time so we will
                 * use it to hold on to this instance.
                 */
                Callable<Boolean> loopCondition =
                    new Callable<Boolean>() {
                      public Boolean call() throws Exception {
                        return evaluateLoopCondition(finalLoopCondition);
                      }
                    };

                finalAudio.play(loopInterval, loopCondition);
              }

              public void stop() {
                finalAudio.stop();
              }

              /**
               * Determines whether this audio is started i.e. a <tt>play</tt> method was invoked
               * and no subsequent <tt>stop</tt> has been invoked yet.
               *
               * @return <tt>true</tt> if this audio is started; otherwise, <tt>false</tt>
               */
              public boolean isStarted() {
                return finalAudio.isStarted();
              }
            };
      }
    }

    return audio;
  }