[sip-comm-dev] Memory leak in sip-communicator


#1

During testing of the sip-communicator, a significant memory leak was
discovered. The leak was verified

by observing the Task manager memory report.

In file Image1.gif a screen capture of the leakage tool used, is
enclosed. Number of calls

was 69, and several objects are not released.

Since the problem seemed to occur in AVReceiver/ AVTransmitter section,
a test was deviced, that

deleted MediaManager , ran System.gc() and set up a new instance og
MediaManager between calls.

The amount memory used, was still increasing proportinally with
number of calls.

In file Image2.gif, a screen dump of objects with two times the number
of calls is shown.

RTPManager objects are increasing with a factor of two, for each call. (
One in each direction receive / transmit)

After scanning the internet, it was discovered that a report submitted
in the JMF interest group, describes

a similar problem trying to release RTPManager objects without success.

The JMF version used is 2.1.1.e.

The AVTransmitter / AVReceiver / MediaManager source code is checked out
and found to be in compliance with Sun's recdmmendations.

At this point it seems to be a problem in JMF. The debugger shows ,
some JMF objects like RTPManager and PlayerBackEngine are not released.

Best regards

Dennis Lazreg

Dolphin Software A.S


#2

Good job Dennis!

Thanks a lot for the profiling!

We will definitely have to spend some time on fine tuning JMF and patching it where possible but it will unfortunately have to wait until we have at least a pre-release of the 1.0 version.

At that point we'll have to discuss the issue you bring out again.

Thanks again
Emil

Dennis Lazreg wrote:

···

During testing of the sip-communicator, a significant memory leak was discovered. The leak was verified

by observing the Task manager memory report.

In file Image1.gif a screen capture of the leakage tool used, is enclosed. Number of calls

was 69, and several objects are not released.

Since the problem seemed to occur in AVReceiver/ AVTransmitter section, a test was deviced, that

deleted MediaManager , ran System.gc() and set up a new instance og MediaManager between calls.

The amount memory used, was still increasing proportinally with number of calls.

In file Image2.gif, a screen dump of objects with two times the number of calls is shown.

RTPManager objects are increasing with a factor of two, for each call. ( One in each direction receive / transmit)

After scanning the internet, it was discovered that a report submitted in the JMF interest group, describes

a similar problem trying to release RTPManager objects without success.

The JMF version used is 2.1.1.e.

The AVTransmitter / AVReceiver / MediaManager source code is checked out and found to be in compliance with Sun's recdmmendations.

At this point it seems to be a problem in JMF. The debugger shows , some JMF objects like RTPManager and PlayerBackEngine are not released.

Best regards

Dennis Lazreg

Dolphin Software A.S

------------------------------------------------------------------------

------------------------------------------------------------------------

------------------------------------------------------------------------

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@sip-communicator.dev.java.net
For additional commands, e-mail: dev-help@sip-communicator.dev.java.net

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@sip-communicator.dev.java.net
For additional commands, e-mail: dev-help@sip-communicator.dev.java.net


#3

Hello All,

I wonder if you tried calling using video between 2 windows machines !! … JMF did not detect my web cam … so I could not try it … !! Instead I tried between Mac and Windows … and could did not work as I hoped … !

Thanks

Amer

···

To unsubscribe, e-mail: dev-unsubscribe@sip-communicator.dev.java.net
For additional commands, e-mail: dev-help@sip-communicator.dev.java.net


#4

Hi Emil
Is it possible to download ( look at source ) og the pre-release of the 1.0 version.
Thanks a lot

Emil Ivov <emil_ivov@yahoo.com> a �crit :
Good job Dennis!

Thanks a lot for the profiling!

We will definitely have to spend some time on fine tuning JMF and
patching it where possible but it will unfortunately have to wait until
we have at least a pre-release of the 1.0 version.

At that point we'll have to discuss the issue you bring out again.

Thanks again
Emil

Dennis Lazreg wrote:

···

During testing of the sip-communicator, a significant memory leak was
discovered. The leak was verified

by observing the Task manager memory report.

In file Image1.gif a screen capture of the leakage tool used, is
enclosed. Number of calls

was 69, and several objects are not released.

Since the problem seemed to occur in AVReceiver/ AVTransmitter section,
a test was deviced, that

deleted MediaManager , ran System.gc() and set up a new instance og
MediaManager between calls.

The amount memory used, was still increasing proportinally with
number of calls.

In file Image2.gif, a screen dump of objects with two times the number
of calls is shown.

RTPManager objects are increasing with a factor of two, for each call. (
One in each direction receive / transmit)

After scanning the internet, it was discovered that a report submitted
in the JMF interest group, describes

a similar problem trying to release RTPManager objects without success.

The JMF version used is 2.1.1.e.

The AVTransmitter / AVReceiver / MediaManager source code is checked out
and found to be in compliance with Sun's recdmmendations.

At this point it seems to be a problem in JMF. The debugger shows ,
some JMF objects like RTPManager and PlayerBackEngine are not released.

Best regards

Dennis Lazreg

Dolphin Software A.S

------------------------------------------------------------------------

------------------------------------------------------------------------

------------------------------------------------------------------------

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@sip-communicator.dev.java.net
For additional commands, e-mail: dev-help@sip-communicator.dev.java.net

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@sip-communicator.dev.java.net
For additional commands, e-mail: dev-help@sip-communicator.dev.java.net

---------------------------------
Appel audio GRATUIT partout dans le monde avec le nouveau Yahoo! Messenger
T�l�chargez le ici !


#5

Not yet but it won't be long before you can. We hope we'll be able to make it for the deadline announced on the web page (i.e. beginning of september). If not a final release we'll do our best to at least bring out a release candidate. We will announce it on the list so stay tuned.

Thank you all for your patience (I guarantee it's worth it!)

Cheers
Emil

D. Lazreg wrote:

···

Hi Emil
Is it possible to download ( look at source ) og the pre-release of the 1.0 version.
Thanks a lot

*/Emil Ivov <emil_ivov@yahoo.com>/* a �crit :

    Good job Dennis!

    Thanks a lot for the profiling!

    We will definitely have to spend some time on fine tuning JMF and
    patching it where possible but it will unfortunately have to wait until
    we have at least a pre-release of the 1.0 version.

    At that point we'll have to discuss the issue you bring out again.

    Thanks again
    Emil

    Dennis Lazreg wrote:
     > During testing of the sip-communicator, a significant memory leak
    was
     > discovered. The leak was verified
     >
     > by observing the Task manager memory report.
     >
     > In file Image1.gif a screen capture of the leakage tool used, is
     > enclosed. Number of calls
     >
     > was 69, and several objects are not released.
     >
     > Since the problem seemed to occur in AVReceiver/ AVTransmitter
    section,
     > a! test was deviced, that
     >
     > deleted MediaManager , ran System.gc() and set up a new instance og
     > MediaManager between calls.
     >
     > The amount memory used, was still increasing proportinally with
     > number of calls.
     >
     > In file Image2.gif, a screen dump of objects with two times the
    number
     > of calls is shown.
     >
     > RTPManager objects are increasing with a factor of two, for each
    call. (
     > One in each direction receive / transmit)
     >
     > After scanning the internet, it was discovered that a report
    submitted
     > in the JMF interest group, describes
     >
     > a similar problem trying to release RTPManager objects without
    success.
     >
     > The JMF version used is 2.1.1.e.
     >
     > The AVTransmitter / AVReceiver / MediaManager source code is
    checked out
     > and found to be in complia! nce with Sun's recdmmendations.
     >
     > At this point it seems to be a problem in JMF. The debugger shows ,
     > some JMF objects like RTPManager and PlayerBackEngine are not
    released.
     >
     > Best regards
     >
     > Dennis Lazreg
     >
     > Dolphin Software A.S
     >
    ------------------------------------------------------------------------
     >
    ------------------------------------------------------------------------
     >
    ------------------------------------------------------------------------
     >
     > ---------------------------------------------------------------------
     > To unsubscribe, e-mail: dev-unsubscribe@sip-communicator.dev.java.net
     > For additional commands, e-mail:
    dev-help@sip-communicator.dev.java.net

    ---------------------------------------------------------------------
    To unsubscribe, e-mail: dev-unsubscribe@sip-communicator.dev.java.net
    For additional commands, e-mail: dev-help@sip-communicator.dev.java.net

------------------------------------------------------------------------
*Appel audio GRATUIT partout dans le monde* avec le nouveau Yahoo! Messenger
T�l�chargez le ici ! <http://us.rd.yahoo.com/messenger/mail_taglines/default/*http://fr.messenger.yahoo.com>

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@sip-communicator.dev.java.net
For additional commands, e-mail: dev-help@sip-communicator.dev.java.net


#6

Hi Amer,

Video capture is not supported by JMF on MAC so no wornder it didn't work.

Incidentally. Does anyone ahve any references concerning capture libs on MAC? We'd like to add a video capture datasource for jmf so if anyone has good lib refs - it will be appreciated.

Cheers
Emil

Amer C wrote:

···

Hello All,

   I wonder if you tried calling using video between 2 windows machines !! .. JMF did not detect my web cam .. so I could not try it .. !! Instead I tried between Mac and Windows .. and could did not work as I hoped .. !

Thanks

Amer

--------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscribe@sip-communicator.dev.java.net For additional commands, e-mail: dev-help@sip-communicator.dev.java.net

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@sip-communicator.dev.java.net
For additional commands, e-mail: dev-help@sip-communicator.dev.java.net


#7

Hi,

I modified the MediaManager , AVTransmitter , AVReceiver to avoid the Memory Leak

Cheers
Dennis

Emil Ivov <emil_ivov@yahoo.com> a �crit : Not yet but it won't be long before you can. We hope we'll be able to
make it for the deadline announced on the web page (i.e. beginning of
september). If not a final release we'll do our best to at least bring
out a release candidate. We will announce it on the list so stay tuned.

Thank you all for your patience (I guarantee it's worth it!)

Cheers
Emil

D. Lazreg wrote:

AVReceiver.java (18 KB)

AVTransmitter.java (22.9 KB)

MediaManager.java (45.7 KB)

···

Hi Emil
Is it possible to download ( look at source ) og the pre-release of the
1.0 version.
Thanks a lot

*/Emil Ivov /* a �crit :

Good job Dennis!

Thanks a lot for the profiling!

We will definitely have to spend some time on fine tuning JMF and
patching it where possible but it will unfortunately have to wait until
we have at least a pre-release of the 1.0 version.

At that point we'll have to discuss the issue you bring out again.

Thanks again
Emil

Dennis Lazreg wrote:
> During testing of the sip-communicator, a significant memory leak
was
> discovered. The leak was verified
>
> by observing the Task manager memory report.
>
>
>
> In file Image1.gif a screen capture of the leakage tool used, is
> enclosed. Number of calls
>
> was 69, and several objects are not released.
>
>
>
> Since the problem seemed to occur in AVReceiver/ AVTransmitter
section,
> a! test was deviced, that
>
> deleted MediaManager , ran System.gc() and set up a new instance og
> MediaManager between calls.
>
>
>
> The amount memory used, was still increasing proportinally with
> number of calls.
>
>
>
> In file Image2.gif, a screen dump of objects with two times the
number
> of calls is shown.
>
> RTPManager objects are increasing with a factor of two, for each
call. (
> One in each direction receive / transmit)
>
>
>
> After scanning the internet, it was discovered that a report
submitted
> in the JMF interest group, describes
>
> a similar problem trying to release RTPManager objects without
success.
>
>
>
> The JMF version used is 2.1.1.e.
>
>
>
> The AVTransmitter / AVReceiver / MediaManager source code is
checked out
> and found to be in complia! nce with Sun's recdmmendations.
>
>
>
> At this point it seems to be a problem in JMF. The debugger shows ,
> some JMF objects like RTPManager and PlayerBackEngine are not
released.
>
>
>
> Best regards
>
>
>
> Dennis Lazreg
>
> Dolphin Software A.S
>
>
>
------------------------------------------------------------------------
>
>
>
------------------------------------------------------------------------
>
>
>
------------------------------------------------------------------------
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@sip-communicator.dev.java.net
> For additional commands, e-mail:
dev-help@sip-communicator.dev.java.net

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@sip-communicator.dev.java.net
For additional commands, e-mail: dev-help@sip-communicator.dev.java.net

------------------------------------------------------------------------
*Appel audio GRATUIT partout dans le monde* avec le nouveau Yahoo! Messenger
T�l�chargez le ici !

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@sip-communicator.dev.java.net
For additional commands, e-mail: dev-help@sip-communicator.dev.java.net

---------------------------------
Appel audio GRATUIT partout dans le monde avec le nouveau Yahoo! Messenger
T�l�chargez le ici !


#8

Hi Emil

I send you all the patches that I have in the sip-communicator

- CallProcessing.processInvite

- CallProcessing.sayOk
The SDP content should be negociated sdp = (Sender SDP & Reciever SDP)

- MediaManager Clean up methods
- AVTransmitter Clean up methods
- AVReceiver Clean up methods

Regards
Dennis

Patches.txt (6.21 KB)

AVReceiver.java (17.3 KB)

AVTransmitter.java (22 KB)

MediaManager.java (44.1 KB)

···

---------------------------------
Appel audio GRATUIT partout dans le monde avec le nouveau Yahoo! Messenger
T�l�chargez le ici !


#9

Thanks Dennis,

This is highly appreciate it. I warn you though that it may take one or two weeks before we get down to inspecting them since we're currently not working on the media service of the new version. Once we get there we'll most surely take them into account and let you know if we have any questions.

Cheers and thanks for your contribution
Emil

D. Lazreg wrote:

···

Hi Emil
I send you all the patches that I have in the sip-communicator
- CallProcessing.processInvite
- CallProcessing.sayOk
The SDP content should be negociated sdp = (Sender SDP & Reciever SDP)
- MediaManager Clean up methods
- AVTransmitter Clean up methods
- AVReceiver Clean up methods
Regards
Dennis

------------------------------------------------------------------------
*Appel audio GRATUIT partout dans le monde* avec le nouveau Yahoo! Messenger
T�l�chargez le ici ! <http://us.rd.yahoo.com/messenger/mail_taglines/default/*http://fr.messenger.yahoo.com>

------------------------------------------------------------------------

CallProcessing.processInvite

  void processInvite(ServerTransaction serverTransaction, Request invite)

old: if (!calleeUser.equals(localUser) && assertUserMatch)

new: if (calleeUser!=null && !calleeUser.equals(localUser) && assertUserMatch)

Moved call.setState(Call.ALERTING) to end of avoid answering an uncompleted call.

  //change status
    call.setState(Call.ALERTING);
    }
  finally
  {

    console.logExit();
  }

CallProcessing.sayOk
  
old:
        try {
                ok.setContent(sdpContent, contentTypeHeader);
            }
            catch (NullPointerException ex) {
                call.setState(Call.DISCONNECTED);
                console.error(
                    "No sdp data was provided for the ok response to an INVITE request!",
                    ex);
                throw new CommunicationsException(
                    "No sdp data was provided for the ok response to an INVITE request!",
                    ex);
            }
      
new:

    try {
  
    String sdp = generateDescription (sdpFactory , sdpContent , call.getRemoteSdpDescription() )
     ok.setContent(sdp , contentTypeHeader);
            }
            catch (NullPointerException ex) {
                call.setState(Call.DISCONNECTED);
                console.error(
                    "No sdp data was provided for the ok response to an INVITE request!",
                    ex);
                throw new CommunicationsException(
                    "No sdp data was provided for the ok response to an INVITE request!",
                    ex);
            }
     
  /**
   * generateDescription
   * @param sdpFactory
   * @param local
   * @param remote
   * @return */
  public String generateDescription (SdpFactory sdpFactory , String local , String remote )
  {
    String sdp ="";
    String txt =" local=" + local + " remote=" + remote ;
    System.out.println("generateDescription-Enter" +txt ); Vector lmedia = null , rmedia=null , audio=null , video=null ;
    SessionDescription sessionDescription = null ;
    try {
       sessionDescription = sdpFactory.createSessionDescription(local);
       lmedia = sessionDescription.getMediaDescriptions(true);
             sessionDescription = sdpFactory.createSessionDescription(remote);
       rmedia = sessionDescription.getMediaDescriptions(true);
              audio = getCommonAudioVideoFormats("audio" , rmedia , lmedia ) ;
       video = getCommonAudioVideoFormats("video" , rmedia , lmedia ); return this.changeMediaDescription(sdpFactory , local , audio , video );
      } catch (Exception ex) {
      ex.printStackTrace();
    }
    return null ; }
  
   * getCommonMediaFormats
   * @param local SDP
   * @param remote SDP
   * @return */
  private Vector getCommonAudioVideoFormats (String audioVideo , Vector remote , Vector local) throws Exception
  {
    Vector result = result = new Vector ();
        for (int i=0 ; i<remote.size() ; ++i)
    {
      javax.sdp.MediaDescription mediadesc = (javax.sdp.MediaDescription)remote.elementAt(i) ;
      Media media =mediadesc.getMedia() ;
      Vector vf = media.getMediaFormats(true) ;
      String mtype = media.getMediaType() ;
      if ( mtype.equalsIgnoreCase(audioVideo) )
      {
        for (int j=0 ; vf!=null && j<vf.size() ; ++j)
        {
          String s = (String)vf.elementAt(j) ;
          if ( this.checkMediaFormatExist(mtype , local , s) )
          {
            result.add(s);
          }
        }
      }
     } return result ;
  }

  /**
   * * @param mtype
   * @param mediaDescriptions
   * @param format
   * @return */
  private boolean checkMediaFormatExist ( String mtype , Vector mediaDescriptions , String format )
  {
    try {
      for (int i=0 ; i<mediaDescriptions.size() ; ++i)
      {
        javax.sdp.MediaDescription mediadesc = (javax.sdp.MediaDescription)mediaDescriptions.elementAt(i) ;
        Media media =mediadesc.getMedia() ;
        if ( media==null ) continue;
        Vector vf = media.getMediaFormats(true) ;
        if ( mtype.equalsIgnoreCase(media.getMediaType()) )
        {
          for (int j=0 ; vf!=null && j<vf.size() ; ++j)
          {
            String tt = (String)vf.elementAt(j) ;
            if ( tt.equals(format) )
            {
              return true ;
            }
          }
        }
      }
    } catch (Exception ex) {
      ex.printStackTrace();
    } return false;
  }

  /**
   * changeMediaDescription
   * @param sdp
   * @param audio
   * @param video
   * @return */
    private String changeMediaDescription ( SdpFactory sdpFactory , String sdpData , Vector audio , Vector video )
  {
    SessionDescription sessionDescription = null ;
    Vector mediaDescriptions = null ;

    String txt =" sdp=" + sdpData + " audio=" + audio + " video=" + video ;
    System.out.println("generateDescription-Enter" +txt );

    try
    {
    
      try
      {
        sessionDescription = sdpFactory.createSessionDescription(sdpData);
      }
      catch (Exception ex)
      {
        throw new Exception("Incorrect SDP data! " + ex);
      }

      try
      {
        mediaDescriptions = sessionDescription.getMediaDescriptions(true);
        for (int i=0 ; i<mediaDescriptions.size() ; ++i)
        {
          javax.sdp.MediaDescription mediadesc = (javax.sdp.MediaDescription)mediaDescriptions.elementAt(i) ;
          Media media =mediadesc.getMedia() ;
          if ( media==null ) continue;
          Vector vf = media.getMediaFormats(true) ;
          if ( media.getMediaType().equalsIgnoreCase("audio") )
          {
            media.setMediaFormats(audio);
            if ( audio==null || audio.size()==0 )
            {
               mediaDescriptions.remove(i) ;
            }
          } else if ( media.getMediaType().equalsIgnoreCase("video") )
          {
             media.setMediaFormats(video);
             if ( video==null || video.size()==0 )
             {
               mediaDescriptions.remove(i) ;
             }
          }
        }
      }
      catch (Exception ex)
      {
        throw new Exception("Failed to extract media descriptions from provided session description!" + ex );
      }
       }
    catch (Exception ex )
    {
       System.out.println("generateSessionDescription fails: " + ex );
    }
    return sessionDescription.toString() ;
  }
}
  
------------------------------------------------------------------------

/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2000 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* Portions of this software are based upon public domain software
* originally written at the National Center for Supercomputing Applications,
* University of Illinois, Urbana-Champaign.
*/
package net.java.sip.communicator.media;

import net.java.sip.communicator.common.*;

import java.net.*;

/**
* <p>Title: SIP COMMUNICATOR</p>
* <p>Description:JAIN-SIP Audio/Video phone application</p>
* <p>Copyright: Copyright (c) 2003</p>
* <p>Organisation: LSIIT laboratory (http://lsiit.u-strasbg.fr) </p>
* <p>Network Research Team (http://www-r2.u-strasbg.fr))</p>
* <p>Louis Pasteur University - Strasbourg - France</p>
* @author Emil Ivov (http://www.emcho.com)
* @author Paulo Pizzarro ( added support for media level connection parameter)
* @version 1.1
*
*/
import java.util.*;

import javax.media.*;
import javax.media.control.*;
import javax.media.protocol.*;
import javax.media.rtp.*;
import javax.media.rtp.event.*;

/**
* AVReceiver to receive RTP transmission using the new RTP API.
*/
class AVReceiver implements ReceiveStreamListener, SessionListener,
  ControllerListener, SendStreamListener
{
  private static Console console = Console.getConsole(AVReceiver.class);
  public static final int DEFAULT_BUFFER_LENGTH = 350;
  private DataSource dataSource = null;
  net.java.sip.communicator.media.MediaManager mediaManager;
  ArrayList sessions = null;
  RTPManager[] mgrs = null;
  boolean dataReceived = false;
  Object dataSync = new Object();
  private int bindRetries = 1;
  
  public AVReceiver(ArrayList sessions)
  {
    this.sessions = sessions;
    players = new Vector () ;

    String retries = null;

    if ((retries = Utils.getProperty(
            "net.java.sip.communicator.media.RECEIVER_BIND_RETRIES")) != null)
    {
      try
      {
        bindRetries = Integer.valueOf(retries).intValue();
      }
      catch (NumberFormatException ex)
      {
        console.error(retries + " is not a valid number. ignoring property", ex);
      }
    }
  }

  void setMediaManager(MediaManager mManager)
  {
    this.mediaManager = mManager;
  }

  protected boolean initialize()
  {
    try
    {
      console.logEntry();

      InetAddress ipAddr;
      SessionAddress localAddr = new SessionAddress();
      SessionAddress destAddr;
      mgrs = new RTPManager[sessions.size()];

      SessionLabel session;

      // Open the RTP sessions.
      for (int i = 0; i < sessions.size(); i++)
      {
        // Parse the session addresses.
        try
        {
          session = new SessionLabel((String) sessions.get(i));
        }
        catch (IllegalArgumentException e)
        {
          console.error("Failed to parse the session address given: " +
            (String) sessions.get(i));
          console.logExit();

          return false;
        }

        if (console.isDebugEnabled())
        {
          console.debug(" Start listening for RTP @ addr: " + session.addr +
            " port: " + session.port + " ttl: " + session.ttl);
        }

        mgrs[i] = mediaManager.getRtpManager(new SessionAddress(
              mediaManager.getLocalHost(), session.port));

        if (mgrs[i] == null)
        {
          mgrs[i] = (RTPManager) RTPManager.newInstance();
          mediaManager.putRtpManager(new SessionAddress(
              mediaManager.getLocalHost(), session.port), mgrs[i]);
        }

        mgrs[i].addSessionListener(this);
        mgrs[i].addReceiveStreamListener(this);
        mgrs[i].addSendStreamListener(this);
        ipAddr = InetAddress.getByName(session.addr);

        int tries = 0;

        while (tries++ < bindRetries)
        {
          if (ipAddr.isMulticastAddress())
          {
            // local and remote address pairs are identical:
            localAddr = new SessionAddress(ipAddr, session.port, session.ttl);
            destAddr = new SessionAddress(ipAddr, session.port, session.ttl);
          }
          else
          {
            localAddr = new SessionAddress(mediaManager.getLocalHost(),
                session.port);
            destAddr = new SessionAddress(ipAddr, session.port);
          }

          try
          {
            mgrs[i].initialize(localAddr);
          }
          catch (Exception exc)
          {
            if (tries < bindRetries)
            {
              continue;
            }

            console.error("Could not initialize rtp manager!", exc);

            return false;
          }

          // You can try out some other buffer size to see
          // if you can get better smoothness.
          BufferControl bc = (BufferControl) mgrs[i].getControl(
              "javax.media.control.BufferControl");

          if (bc != null)
          {
            int bl = DEFAULT_BUFFER_LENGTH;

            try
            {
              bl = Integer.parseInt(Utils.getProperty(
                    "net.java.sip.communicator.media.MEDIA_BUFFER_LENGTH"));
              console.debug("MEDIA_BUFFER_LENGTH length is set to " +
                DEFAULT_BUFFER_LENGTH);
            }
            catch (NumberFormatException ex)
            {
              console.debug(
                "MEDIA_BUFFER_LENGTH length not specified using default " +
                DEFAULT_BUFFER_LENGTH, ex);
            }

            bc.setBufferLength(bl);
          }

          mgrs[i].addTarget(destAddr);

          break; //port retries
        } //port retries
      }
    }
    catch (Exception e)
    {
      console.error("Cannot create the RTP Session: ", e);
      console.logExit();

      return false;
    }

    console.logExit();

    return true;
  }

  public boolean isDone()
  {
    return false;
  }

  /**
   * Close the players and the session managers.
   */
  protected void close()
  {
    try
    {
      console.logEntry();
      console.debug("closeInAVReceiver________ " );

      // close the RTP session.
      for (int i = 0; i < mgrs.length; i++)
      {
        if (mgrs[i] != null)
        {
          if (console.isDebugEnabled())
          {
            console.debug("Stopped mgr " + (int) (i + 1));
          }
          terminateRtpManager(mgrs[i] );
          mgrs[i].removeTargets("Closing session from AVReceiver");
          mgrs[i].dispose();
          mgrs[i] = null;
        }
      }
    }
    finally
    {
      terminateSessions();
      closePlayers();
      console.logExit();
    }
  }

  public void closePlayers()
  {
    if ( players == null ) return ;
    try {
      Iterator iter = players.iterator() ;
      while ( iter.hasNext() )
      {
        Player p = (Player)iter.next() ;
        p.removeControllerListener(this);
        p.close();
        iter.remove();
      }
    } catch (Exception ex) {
      ex.printStackTrace();
    } finally {
    }
      }

/**
   * @dela * terminateRtpManager
   * @param rtpManager
   */
  public synchronized void terminateRtpManager(RTPManager rtpManager)
  {
    try {
      if ( rtpManager != null )
      {
         rtpManager.removeSessionListener(this);
         rtpManager.removeReceiveStreamListener(this);
         rtpManager.removeSendStreamListener(this);

         Vector s = rtpManager.getSendStreams() ;
         if ( s!=null)
         {
           for (int i=0 ; s != null && i <s.size() ; i++)
           {
             SendStream ss = (SendStream)s.elementAt(i) ;
             s.remove(ss) ;
           }
         } Vector r = rtpManager.getReceiveStreams() ;
         if ( r!=null )
         {
           for (int i=0 ; r!=null && i <r.size() ; i++)
           {
             ReceiveStream rr = (ReceiveStream)r.elementAt(i) ;
             r.remove(rr) ;
           }
         } rtpManager.removeTargets("Remove Targets");
         rtpManager.dispose();
         rtpManager = null ; }
    } catch (Exception ex) {
      ex.printStackTrace();
    } finally {
    }

    }

  /**
   * @dela * terminateSessions
   * @param rtpManager
   */
    public synchronized void terminateSessions()
  {
    SessionLabel session = null ;
    if (sessions == null ) return ;
    try {
      for (int i = 0; i < sessions.size(); i++)
      {
        sessions.remove(i) ;
      }
    } catch (Exception ex) {
      ex.printStackTrace();
    } finally {
    }
      }

  /**
   * SessionListener.
   */
  public synchronized void update(SessionEvent evt)
  {
    try
    {
      console.logEntry();

      if (evt instanceof NewParticipantEvent)
      {
        Participant p = ((NewParticipantEvent) evt).getParticipant();

        if (console.isDebugEnabled())
        {
          console.debug("A new participant had just joined: " + p.getCNAME());
        }
      }
      else
      {
        if (console.isDebugEnabled())
        {
          console.debug("Received a the following JMF Session event - " +
            "evt.getClass().getName()");
        }
      }
    }
    finally
    {
      console.logExit();
    }
  }

  /**
   * ReceiveStreamListener
   */
  public synchronized void update(ReceiveStreamEvent evt)
  {
    try
    {
      console.logEntry();

      RTPManager mgr = (RTPManager) evt.getSource();
      Participant participant = evt.getParticipant(); // could be null.
      ReceiveStream stream = evt.getReceiveStream(); // could be null.

      if (evt instanceof NewReceiveStreamEvent)
      {
        try
        {
          stream = ((NewReceiveStreamEvent) evt).getReceiveStream();

          DataSource ds = stream.getDataSource();

          // Find out the formats.
          RTPControl ctl = (RTPControl) ds.getControl("javax.media.rtp.RTPControl");

          if (console.isDebugEnabled())
          {
            if (ctl != null)
            {
              console.debug("Recevied new RTP stream: " + ctl.getFormat());
            }
            else
            {
              console.debug("Recevied new RTP stream");
            }
          }

          Player p = Manager.createPlayer(ds);
          p.addControllerListener(this);
          p.realize();
          players.add(p);
        }
        catch (Exception e)
        {
          console.error("NewReceiveStreamEvent exception ", e);

          return;
        }
      }
      else if (evt instanceof StreamMappedEvent)
      {
        if ((stream != null) && (stream.getDataSource() != null))
        {
          DataSource ds = stream.getDataSource();

          // Find out the formats.
          RTPControl ctl = (RTPControl) ds.getControl(
              "javax.media.rtp.RTPControl");

          if (console.isDebugEnabled())
          {
            String msg = "The previously unidentified stream ";

            if (ctl != null)
            {
              msg += ctl.getFormat();
            }

            msg += (" had now been identified as sent by: " +
            participant.getCNAME());
            console.debug(msg);
          }
        }
      }
      else if (evt instanceof ByeEvent)
      {
        console.debug("Got \"bye\" from: " + participant.getCNAME());
      }
    }
    finally
    {
      console.logExit();
    }
  }

  /**
   * ControllerListener for the Players.
   */
  public synchronized void controllerUpdate(ControllerEvent ce)
  {
    try
    {
      console.logEntry();

      Player p = (Player) ce.getSourceController();

      if (p == null)
      {
        return;
      }

      // Get this when the internal players are realized.
      if (ce instanceof RealizeCompleteEvent)
      {
        console.debug("A player was realized and will be started.");
        p.start();
      }

      if (ce instanceof StartEvent)
      {
        console.debug("Received a StartEvent");
        mediaManager.firePlayerStarting(p);
      }

      if (ce instanceof ControllerErrorEvent)
      {
        console.error(
          "The following error was reported while starting a player" + ce);
      }

      if (ce instanceof ControllerClosedEvent)
      {
        console.debug("Received a ControllerClosedEvent");
        mediaManager.firePlayerStopped();
      }
    }
    finally
    {
      console.logExit();
    }
  }

  public void update(SendStreamEvent event)
  {
      console.debug("received the following JMF Session event - " +
      event.getClass().getName());
  }

  public static void main(String[] argv)
  {
    if (argv.length == 0)
    {
      prUsage();
    }

    ArrayList sessions = new ArrayList();

    for (int i = 0; i < argv.length; i++)
    {
      sessions.add(argv[i]);
    }

    AVReceiver avReceiver = new AVReceiver(sessions);

    if (!avReceiver.initialize())
    {
      System.out.println("[AVReceiver]" + "Failed to initialize the sessions.");
      System.exit(-1);
    }

    // Check to see if AVReceive2 is done.
    try
    {
      while (!avReceiver.isDone())
      {
        Thread.sleep(1000);
      }
    }
    catch (Exception e)
    {
    }

    System.out.println("[AVReceiver]" + "Exiting AVReceive2");
  }

  static void prUsage()
  {
    System.err.println("Usage: AVReceive2 <session> <session> ...");
    System.err.println(" <session>: <address>/<port>/<ttl>");
    System.exit(0);
  }

  /**
   * A utility class to parse the session addresses.
   */
  class SessionLabel
  {
    public String addr = null;
    public int port;
    public int ttl = 1;
    private Console console = Console.getConsole(SessionLabel.class);

    SessionLabel(String session) throws IllegalArgumentException
    {
      try
      {
        console.logEntry();

        int off;
        String portStr = null;
        String ttlStr = null;

        if ((session != null) && (session.length() > 0))
        {
          while ((session.length() > 1) && (session.charAt(0) == '/'))
          {
            session = session.substring(1);

            // Now see if there's a addr specified.
          }

          off = session.indexOf('/');

          if (off == -1)
          {
            if (!session.equals(""))
            {
              addr = session;
            }
          }
          else
          {
            addr = session.substring(0, off);
            session = session.substring(off + 1);

            // Now see if there's a port specified
            off = session.indexOf('/');

            if (off == -1)
            {
              if (!session.equals(""))
              {
                portStr = session;
              }
            }
            else
            {
              portStr = session.substring(0, off);
              session = session.substring(off + 1);

              // Now see if there's a ttl specified
              off = session.indexOf('/');

              if (off == -1)
              {
                if (!session.equals(""))
                {
                  ttlStr = session;
                }
              }
              else
              {
                ttlStr = session.substring(0, off);
              }
            }
          }
        }

        if (addr == null)
        {
          throw new IllegalArgumentException();
        }

        if (portStr != null)
        {
          try
          {
            Integer integer = Integer.valueOf(portStr);

            if (integer != null)
            {
              port = integer.intValue();
            }
          }
          catch (Throwable t)
          {
            throw new IllegalArgumentException();
          }
        }
        else
        {
          throw new IllegalArgumentException();
        }

        if (ttlStr != null)
        {
          try
          {
            Integer integer = Integer.valueOf(ttlStr);

            if (integer != null)
            {
              ttl = integer.intValue();
            }
          }
          catch (Throwable t)
          {
            throw new IllegalArgumentException();
          }
        }
      }
      finally
      {
        console.logExit();
      }
    }
  }

  /*
      private DataSource addDataSource(DataSource newDataSource)
      {
          if (dataSource == null) {
              dataSource = newDataSource;
          }
          else {
              try {
       dataSource = Manager.createMergingDataSource(new DataSource[] {
                      dataSource,
                      newDataSource
                  });
              }
              catch (IncompatibleSourceException ex) {
                  Console.println(
       "[AVReceiver]Failed to create a merging datasource. Old one is ignored!");
                  dataSource = newDataSource;
              }
          }
          return dataSource;
      }
   */
} // end of AVReceive2

------------------------------------------------------------------------

/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2000 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* Portions of this software are based upon public domain software
* originally written at the National Center for Supercomputing Applications,
* University of Illinois, Urbana-Champaign.
*/
package net.java.sip.communicator.media;

import net.java.sip.communicator.common.*;

import java.awt.*;

/**
* <p>Title: SIP COMMUNICATOR</p>
* <p>Description:JAIN-SIP Audio/Video phone application</p>
* <p>Copyright: Copyright (c) 2003</p>
* <p>Organisation: LSIIT laboratory (http://lsiit.u-strasbg.fr) </p>
* <p>Network Research Team (http://www-r2.u-strasbg.fr))</p>
* <p>Louis Pasteur University - Strasbourg - France</p>
* @author Emil Ivov (http://www.emcho.com)
* @author Paulo Pizzarro ( added support for media level connection parameter)
* @version 1.1
*
*/
import java.io.*;

import java.net.*;

import java.util.*;

import javax.media.*;
import javax.media.control.*;
import javax.media.format.*;
import javax.media.protocol.*;
import javax.media.rtp.*;
import javax.media.rtp.rtcp.*;

class AVTransmitter {
  protected static Console console = Console.getConsole(AVTransmitter.class);

  // Input MediaLocator
  // Can be a file or http or capture source
  protected MediaLocator locator;
  protected ArrayList ipAddresses = null;
  protected Processor processor = null;
  protected RTPManager[] rtpMgrs;

  //Used by mobility - keeps rtpMgrs[] corresponding addresses
  protected SessionAddress[] sessionAddresses = null;
  protected DataSource dataOutput = null;
  protected ArrayList ports = null;
  protected ArrayList formatSets = null;
  protected MediaManager mediaManCallback = null;

  /****************************************************************
   * Convenience methods to handle processor's state changes.
   ****************************************************************/
  protected Integer stateLock = new Integer(0);
  protected boolean failed = false;

  public AVTransmitter(Processor processor, ArrayList ipAddresses, ArrayList ports,
    ArrayList formatSets) {
    try {
      console.logEntry();
      this.processor = processor;
      this.ipAddresses = ipAddresses;
      this.ports = ports;
      this.formatSets = formatSets;

      if (console.isDebugEnabled()) {
        console.debug("Created transmitter for: " + ipAddresses.toString() + " at ports: " +
          ports.toString() + " encoded as: " + formatSets.toString());
      }
    } finally {
      console.logExit();
    }
  }

  void setMediaManagerCallback(MediaManager mediaManager) {
    this.mediaManCallback = mediaManager;
  }

  /**
   * Starts the transmission. Returns null if transmission started ok.
   * Otherwise it returns a string with the reason why the setup failed.
   */
  synchronized String start() throws MediaException {
    try {
      console.logEntry();

      String result;
      configureProcessor();

      // Create an RTP session to transmit the output of the
      // processor to the specified IP address and port no.
      try {
        createTransmitter();
      } catch (MediaException ex) {
        console.error("createTransmitter() failed", ex);
        processor.close();
        processor = null;
        throw ex;
      }

      // Start the transmission
      processor.start();

      return null;
    } finally {
      console.logExit();
    }
  }

  /**
   * Stops the transmission if already started
   */
  void stop() {
    try {
      console.logEntry();

      synchronized (this) {
        if (processor != null) {
          processor.stop();
        }
        if (rtpMgrs != null) {
          for (int i = 0; i < rtpMgrs.length; i++) {
             if (rtpMgrs[i] == null) {
               continue;
             }

              //@dela terminateRtpManager(rtpMgrs[i]);
              // }
        }
      }
    } finally {
//@dela
      terminateSessions();
// console.logExit();
    }
  }

  /**
   * @dela
   * terminateRtpManager
   * @param rtpManager
   */
  public synchronized void terminateRtpManager(RTPManager rtpManager) {
    if (rtpManager != null) {
      Vector s = rtpManager.getSendStreams();

      if (s != null) {
        for (int i = 0; (s != null) && (i < s.size()); i++) {
          SendStream ss = (SendStream) s.elementAt(i);
          s.remove(ss);
        }
      }

      Vector r = rtpManager.getReceiveStreams();

      if (r != null) {
        for (int i = 0; (r != null) && (i < r.size()); i++) {
          ReceiveStream rr = (ReceiveStream) r.elementAt(i);
          r.remove(rr);
        }
      }

      rtpManager.dispose();
      rtpManager.removeTargets("Remove Targets");
    }
  }

  /**
   * @dela
   * terminateSessions
   * @param rtpManager
   */
  public synchronized void terminateSessions() {
    if (sessionAddresses == null) {
      return;
    }

    for (int i = 0; i < sessionAddresses.length; i++) {
      sessionAddresses[i] = null;
    }

    sessionAddresses = null;
  }

  protected void configureProcessor() throws MediaException {
    try {
      console.logEntry();

      if (processor == null) {
        console.error("Processor is null.");
        throw new MediaException("Processor is null.");
      }

      // Wait for the processor to configure
      boolean result = true;

      if (processor.getState() < Processor.Configured) {
        result = waitForState(processor, Processor.Configured);
      }

      if (result == false) {
        console.error("Couldn't configure processor");
        throw new MediaException("Couldn't configure processor");
      }

      // Get the tracks from the processor
      TrackControl[] tracks = processor.getTrackControls();

      // Do we have atleast one track?
      if ((tracks == null) || (tracks.length < 1)) {
        console.error("Couldn't find tracks in processor");
        throw new MediaException("Couldn't find tracks in processor");
      }

      // Set the output content descriptor to RAW_RTP
      // This will limit the supported formats reported from
      // Track.getSupportedFormats to only valid RTP formats.
      ContentDescriptor cd = new ContentDescriptor(ContentDescriptor.RAW_RTP);
      processor.setContentDescriptor(cd);

      Format[] supported;
      Format chosenFormat;
      boolean atLeastOneTrack = false;

      // Program the tracks.
      for (int i = 0; i < tracks.length; i++) {
        Format format = tracks[i].getFormat();

        if (tracks[i].isEnabled()) {
          supported = tracks[i].getSupportedFormats();

          if (console.isDebugEnabled()) {
            console.debug("Available encodings are:");

            for (int j = 0; j < supported.length; j++) {
              console.debug("track[" + (i + 1) + "] format[" + (j + 1) + "]=" +
                supported[j].getEncoding());
            }
          }

          // We've set the output content to the RAW_RTP.
          // So all the supported formats should work with RTP.
          // We'll pick one that matches those specified by the constructor.
          if (supported.length > 0) {
            if (supported[0] instanceof VideoFormat) {
              // For video formats, we should double check the
              // sizes since not all formats work in all sizes.
              int index = findFirstMatchingFormat(supported, formatSets);

              if (index != -1) {
                chosenFormat = checkForVideoSizes(tracks[i].getFormat(), supported[index]);
                tracks[i].setFormat(chosenFormat);

                if (console.isDebugEnabled()) {
                  console.debug("Track " + i + " is set to transmit as: " + chosenFormat);
                }

                atLeastOneTrack = true;
              } else {
                tracks[i].setEnabled(false);
              }
            } else {
              int index = findFirstMatchingFormat(supported, formatSets);

              if (index != -1) {
                tracks[i].setFormat(supported[index]);

                if (console.isDebugEnabled()) {
                  console.debug("Track " + i + " is set to transmit as: " + supported[index]);
                }

                atLeastOneTrack = true;
              } else {
                tracks[i].setEnabled(false);
              }
            }
          } else {
            tracks[i].setEnabled(false);
          }
        } else {
          tracks[i].setEnabled(false);
        }
      }

      if (!atLeastOneTrack) {
        console.error("Couldn't set any of the tracks to a valid RTP format");
        throw new MediaException("Couldn't set any of the tracks to a valid RTP format");
      }

      // Realize the processor. This will internally create a flow
      // graph and attempt to create an output datasource
      result = waitForState(processor, Controller.Realized);

      if (result == false) {
        console.error("Couldn't realize processor");
        throw new MediaException("Couldn't realize processor");
      }

      // Set the JPEG quality to .5.
      //TODO set the jpeg quality through a property
      setJPEGQuality(processor, 1f);

      // Get the output data source of the processor
      dataOutput = processor.getDataOutput();
    } finally {
      console.logExit();
    }
  }

  /**
   * Use the RTPManager API to create sessions for each media
   * track of the processor.
   */
  protected void createTransmitter() throws MediaException {
    try {
      console.logEntry();

      PushBufferDataSource pbds = (PushBufferDataSource) dataOutput;
      PushBufferStream[] pbss = pbds.getStreams();
      rtpMgrs = new RTPManager[pbss.length];

      //used by mobility
      sessionAddresses = new SessionAddress[pbss.length];

      SessionAddress localAddr;
      SessionAddress destAddr;
      InetAddress remoteAddress;
      SendStream sendStream;
      SourceDescription[] srcDesList;

      console.debug("data sources - " + pbss.length);

      int port = 0;
      String format = null;
      String ipAddress = null;
for_loop: for (int i = 0; i < pbss.length; i++) {
        try {
          format = pbss[i].getFormat().getEncoding();
          ipAddress = findIPAddressForFormat(format);

          if (ipAddress == null) {
            console.error("failed to find a format's ipAddress");
            throw new MediaException("Internal error! AVTransmitter failed to find a" +
              " format's corresponding ipAddress");
          }

          remoteAddress = InetAddress.getByName(ipAddress);
        } catch (UnknownHostException ex) {
          console.error("Failed to resolve remote address", ex);
          throw new MediaException("Failed to resolve remote address", ex);
        }

        port = findPortForFormat(format);

        if (port == -1) {
          console.error("failed to find a format's port");
          throw new MediaException("Internal error! AVTransmitter failed to find a" +
            " format's corresponding port");
        }

        // first try to bind to same port we're talking to for firewall
        // support if that fails go for a random one
        // which will be randomly changed and retried retryCount times.
        // (erroneous comment reported by Joe.Provino at Sun.COM)
        boolean success = true;
        boolean createdRtpManager = false;
        int retries = 4; // 4 retries

        do {
          success = true;

          int localPort = 0;

          if (retries == 4) {
            localPort = port;
          } else {
            localPort = (int) (63976 * Math.random()) + 1024;
          }

          localAddr = new SessionAddress(mediaManCallback.getLocalHost(), localPort);
          destAddr = new SessionAddress(remoteAddress, port);
          rtpMgrs[i] = mediaManCallback.getRtpManager(localAddr);

          if (rtpMgrs[i] == null) {
            rtpMgrs[i] = RTPManager.newInstance();
            createdRtpManager = true;
          } else {
            success = true;

            break;
          }

          try {
            rtpMgrs[i].initialize(localAddr);
            console.debug("Just bond to port" + localAddr.getDataPort());
            rtpMgrs[i].addTarget(destAddr);
            sessionAddresses[i] = destAddr;
          } catch (InvalidSessionAddressException ex) {
            //port was occupied
            if (console.isDebugEnabled()) {
              console.debug("Couldn't bind to local ports " + localAddr.getDataPort() + ", " +
                localAddr.getControlPort() + " @ " + localAddr.getControlHostAddress() +
                ".\n Exception message was: " + ex.getMessage() + " Will try another pair!");
            }

            success = false;
          } catch (IOException ex) {
            //we should just try to notify user and continue with other tracks
            console.error("Failed to initialize an RTPManager for address pair:\n" +
              "Local address:" + localAddr.toString() + " data port:" + localAddr.getDataPort() +
              " control port:" + localAddr.getControlPort() + "\n" + "Dest address:" + destAddr +
              " data port:" + destAddr.getDataPort() + " control port:" +
              destAddr.getControlPort(), ex);
            mediaManCallback.fireNonFatalMediaError(new MediaException(
                "Failed to initialize an RTPManager for address pair:\n" + "Local address:" +
                localAddr.toString() + " data port:" + localAddr.getDataPort() + " control port:" +
                localAddr.getControlPort() + "\n" + "Dest address:" + destAddr + " data port:" +
                destAddr.getDataPort() + " control port:" + destAddr.getControlPort(), ex));
            success = false;
            retries = 0;
          }
        } while (!success && (--retries > 0));

        //notify user if we could bind at all
        if (!success) {
          if (console.isDebugEnabled()) {
            console.error("Failed to initialise rtp manager for track " + i + " encoded as " +
              pbss[i].getFormat().getEncoding() + " @ [" + ipAddress + "]:" + port + "!");
          }

          mediaManCallback.fireNonFatalMediaError(new MediaException(
              "Failed to initialise rtp manager for track " + i + " encoded as " +
              pbss[i].getFormat().getEncoding() + " @ [" + ipAddress + "]:" + port + "!"));

          continue;
        }

        if (createdRtpManager) {
          mediaManCallback.putRtpManager(localAddr, rtpMgrs[i]);
        }

        try {
          if (console.isDebugEnabled()) {
            console.debug("Creating sendstream with dataOutput" + dataOutput);

            if (dataOutput != null) {
              console.debug("DO content type=" + dataOutput.getContentType());

              Object[] controls = dataOutput.getControls();
              console.debug("Data output controls");

              for (int j = 0; j < controls.length; j++) {
                console.debug("Control[" + j + "]=" + controls[j]);
              }
            }
          }

          sendStream = rtpMgrs[i].createSendStream(dataOutput, i);
          sendStream.start();

          if (console.isDebugEnabled()) {
            console.debug("Started transmitting track " + i + " encoded as " +
              pbss[i].getFormat().getEncoding() + " @ [" + ipAddress + "]:" + port + "!");
          }
        } catch (Exception ex) {
          console.error("Session " + i + " failed to start transmitting.");
          mediaManCallback.fireNonFatalMediaError(new MediaException("Session " + i +
              " failed to start transmitting.", ex));
        }
      }
    } finally {
      console.logExit();
    }
  }

  /**
   * For JPEG and H263, we know that they only work for particular
   * sizes. So we'll perform extra checking here to make sure they
   * are of the right sizes.
   */
  Format checkForVideoSizes(Format original, Format supported) {
    try {
      console.logEntry();

      int width;
      int height;
      Dimension size = ((VideoFormat) original).getSize();
      Format jpegFmt = new Format(VideoFormat.JPEG_RTP);
      Format h263Fmt = new Format(VideoFormat.H263_RTP);

      if (supported.matches(jpegFmt)) {
        // For JPEG, make sure width and height are divisible by 8.
        width = (((size.width % 8) == 0) ? size.width : ((int) (size.width / 8) * 8));
        height = (((size.height % 8) == 0) ? size.height : ((int) (size.height / 8) * 8));
      } else if (supported.matches(h263Fmt)) {
        // For H.263, we only support some specific sizes.
        if (size.width < 128) {
          width = 128;
          height = 96;
        } else if (size.width < 176) {
          width = 176;
          height = 144;
        } else {
          width = 352;
          height = 288;
        }
      } else {
        // We don't know this particular format. We'll just
        // leave it alone then.
        return supported;
      }

      return (new VideoFormat(null, new Dimension(width, height), Format.NOT_SPECIFIED, null,
        Format.NOT_SPECIFIED)).intersects(supported);
    } finally {
      console.logExit();
    }
  }

  protected String findIPAddressForFormat(String format) {
    try {
      console.logEntry();

      for (int i = 0; i < formatSets.size(); i++) {
        ArrayList currentSet = (ArrayList) formatSets.get(i);

        for (int j = 0; j < currentSet.size(); j++) {
          if (((String) currentSet.get(j)).equals(format)) {
            return (String) ipAddresses.get(i);
          }
        }
      }

      return null;
    } finally {
      console.logExit();
    }
  }

  protected int findPortForFormat(String format) {
    try {
      console.logEntry();

      for (int i = 0; i < formatSets.size(); i++) {
        ArrayList currentSet = (ArrayList) formatSets.get(i);

        for (int j = 0; j < currentSet.size(); j++) {
          if (((String) currentSet.get(j)).equals(format)) {
            return ((Integer) ports.get(i)).intValue();
          }
        }
      }

      return -1;
    } finally {
      console.logExit();
    }
  }

  /**
   * Setting the encoding quality to the specified value on the JPEG encoder.
   * 0.5 is a good default.
   */
  void setJPEGQuality(Player p, float val) {
    try {
      console.logEntry();

      Control[] cs = p.getControls();
      QualityControl qc = null;
      VideoFormat jpegFmt = new VideoFormat(VideoFormat.JPEG);

      // Loop through the controls to find the Quality control for
      // the JPEG encoder.
      for (int i = 0; i < cs.length; i++) {
        if (cs[i] instanceof QualityControl && cs[i] instanceof Owned) {
          Object owner = ((Owned) cs[i]).getOwner();

          // Check to see if the owner is a Codec.
          // Then check for the output format.
          if (owner instanceof Codec) {
            Format[] fmts = ((Codec) owner).getSupportedOutputFormats(null);

            for (int j = 0; j < fmts.length; j++) {
              if (fmts[j].matches(jpegFmt)) {
                qc = (QualityControl) cs[i];
                qc.setQuality(val);

                if (console.isDebugEnabled()) {
                  console.debug("Setting quality to " + val + " on " + qc);
                }

                break;
              }
            }
          }

          if (qc != null) {
            break;
          }
        }
      }
    } finally {
      console.logExit();
    }
  }

  protected int findFirstMatchingFormat(Format[] hayStack, ArrayList needles) {
    try {
      console.logEntry();

      if ((hayStack == null) || (needles == null)) {
        return -1;
      }

      for (int j = 0; j < needles.size(); j++) {
        ArrayList currentSet = (ArrayList) needles.get(j);

        for (int k = 0; k < currentSet.size(); k++) {
          for (int i = 0; i < hayStack.length; i++) {
            if (hayStack[i].getEncoding().equals((String) currentSet.get(k))) {
              return i;
            }
          }
        }
      }

      return -1;
    } finally {
      console.logExit();
    }
  }

  Integer getStateLock() {
    return stateLock;
  }

  void setFailed() {
    failed = true;
  }

  protected synchronized boolean waitForState(Processor p, int state) {
    p.addControllerListener(new StateListener());
    failed = false;

    // Call the required method on the processor
    if (state == Processor.Configured) {
      p.configure();
    } else if (state == Processor.Realized) {
      p.realize();
    }

    // Wait until we get an event that confirms the
    // success of the method, or a failure event.
    // See StateListener inner class
    while ((p.getState() < state) && !failed) {
      synchronized (getStateLock()) {
        try {
          getStateLock().wait();
        } catch (InterruptedException ie) {
          return false;
        }
      }
    }

    if (failed) {
      return false;
    } else {
      return true;
    }
  }

  /****************************************************************
   * Inner Classes
   ****************************************************************/
  class StateListener implements ControllerListener {
    public void controllerUpdate(ControllerEvent ce) {
      try {
        console.logEntry();

        // If there was an error during configure or
        // realize, the processor will be closed
        if (ce instanceof ControllerClosedEvent) {
          setFailed();

          // All controller events, send a notification
          // to the waiting thread in waitForState method.
        }

        if (ce instanceof ControllerEvent) {
          synchronized (getStateLock()) {
            getStateLock().notifyAll();
          }
        }

        //Loop media files
        if (ce instanceof EndOfMediaEvent) {
          processor.setMediaTime(new Time(0));
          processor.start();
        }
      } finally {
        console.logExit();
      }
    }
  }
}

------------------------------------------------------------------------

/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2000 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* Portions of this software are based upon public domain software
* originally written at the National Center for Supercomputing Applications,
* University of Illinois, Urbana-Champaign.
*/
package net.java.sip.communicator.media;

import javax.media.rtp.ReceiveStream;
import javax.media.rtp.SendStream;
import net.java.sip.communicator.common.*;
import net.java.sip.communicator.common.NetworkAddressManager;
import net.java.sip.communicator.media.event.*;
import net.java.sip.communicator.media.event.MediaEvent;

import java.io.*;
import java.io.InputStreamReader;

import java.net.*;

import java.util.*;

import javax.media.*;
import javax.media.control.*;
import javax.media.format.*;
import javax.media.protocol.*;
import javax.media.rtp.RTPManager;
import javax.media.rtp.SessionAddress;

import javax.sdp.*;

/**
* <p>Title: SIP COMMUNICATOR</p>
* <p>Description:JAIN-SIP Audio/Video phone application</p>
* <p>Copyright: Copyright (c) 2003</p>
* <p>Organisation: LSIIT laboratory (http://lsiit.u-strasbg.fr) </p>
* <p>Network Research Team (http://www-r2.u-strasbg.fr))</p>
* <p>Louis Pasteur University - Strasbourg - France</p>
* <p>Division Chief: Thomas Noel </p>
* @author Emil Ivov (http://www.emcho.com)
* @author Paulo Pizzarro ( added support for media level connection parameter)
* @version 1.1
*
*/
public class MediaManager implements Serializable
{
  protected static Console console = Console.getConsole(MediaManager.class);
  protected ArrayList listeners = new ArrayList();

  protected MediaEvent mediaEvent = null ;

  protected Vector avTransmitters = new Vector();
  protected AVReceiver avReceiver;
  
  public SdpFactory sdpFactory;
  protected ProcessorUtility procUtility = new ProcessorUtility();

  //media devices
  protected CaptureDeviceInfo audioDevice = null;
  protected CaptureDeviceInfo videoDevice = null;

  //Sdp Codes of all formats supported for
  //transmission by the selected datasource
  protected ArrayList transmittableVideoFormats = new ArrayList();
  protected ArrayList transmittableAudioFormats = new ArrayList();

  //Sdp Codes of all formats that we can receive
  //i.e. all formats supported by JMF
  protected String[] receivableVideoFormats = new String[]
    {
      
      //sdp format // corresponding JMF Format
      Integer.toString(SdpConstants.H263), // javax.media.format.VideoFormat.H263_RTP
      Integer.toString(SdpConstants.JPEG), // javax.media.format.VideoFormat.JPEG_RTP
      Integer.toString(SdpConstants.H261) // javax.media.format.VideoFormat.H261_RTP
    };
  protected String[] receivableAudioFormats = new String[]
    {
      
      //sdp format // corresponding JMF Format
      Integer.toString(SdpConstants.G723), // javax.media.format.AudioFormat.G723_RTP
      Integer.toString(SdpConstants.GSM), // javax.media.format.AudioFormat.GSM_RTP;
      Integer.toString(SdpConstants.PCMU), // javax.media.format.AudioFormat.ULAW_RTP;
      Integer.toString(SdpConstants.DVI4_8000), // javax.media.format.AudioFormat.DVI_RTP;
      Integer.toString(SdpConstants.DVI4_16000), // javax.media.format.AudioFormat.DVI_RTP;
      Integer.toString(SdpConstants.PCMA), // javax.media.format.AudioFormat.ALAW;
      Integer.toString(SdpConstants.G728), // javax.media.format.AudioFormat.G728_RTP;
    //g729 is not suppported by JMF
    // Integer.toString(SdpConstants.G729) // javax.media.format.AudioFormat.G729_RTP
    };

  /**
   * A list of currently active RTPManagers mapped against Local session addresses.
   * The list is used by transmitters and receivers so that receiving and transmitting
   * from the same port simultaneousl is possible
   */
  Hashtable activeRtpManagers = new Hashtable();
  protected String mediaSource = null;

  //only use these for initialisation and for
  // protected DataSource audioDataSource = null;
  // protected DataSource videoDataSource = null;
  protected DataSource avDataSource = null;
  protected Processor processor = null;
  protected boolean isStarted = false;

  public MediaManager()
  {
  }

  public void start() throws MediaException
  {
    try
    {
      console.logEntry();

      try
      {
        sdpFactory = SdpFactory.getInstance();
      }
      catch (SdpException exc)
      {
        console.error("Failed to create sdpFactory", exc);
        throw new MediaException("Failed to create sdpFactory", exc);
      }

      //init jmf capture devices
      setupJMF();

      mediaSource = Utils.getProperty(
          "net.java.sip.communicator.media.MEDIA_SOURCE");

      //Init Capture devices
      DataSource audioDataSource = null;
      DataSource videoDataSource = null;

      if (mediaSource == null)
      {
        console.debug("Scanning available capture devices.");

        //audio device
        Vector audioDevices = CaptureDeviceManager.getDeviceList(new AudioFormat(
              AudioFormat.LINEAR, 44100, 16, 2));

        if (audioDevices.size() > 0)
        {
          audioDevice = (CaptureDeviceInfo) audioDevices.get(0);
          audioDataSource = createDataSource(audioDevice.getLocator());
          console.debug("An Audio Device was found.");
        }
        else
        {
          console.debug("No Audio Device was found.");
        }

        //video device
        Vector videoDevices = CaptureDeviceManager.getDeviceList(new VideoFormat(
              VideoFormat.RGB));

        if (videoDevices.size() > 0)
        {
          videoDevice = (CaptureDeviceInfo) videoDevices.get(0);
          videoDataSource = createDataSource(videoDevice.getLocator());
          console.debug("An RGB Video Device was found.");
        }

        // no RGB camera found. And what about YUV ?
        else
        {
          videoDevices = CaptureDeviceManager.getDeviceList(new VideoFormat(
                VideoFormat.YUV));

          if (videoDevices.size() > 0)
          {
            videoDevice = (CaptureDeviceInfo) videoDevices.get(0);
            videoDataSource = createDataSource(videoDevice.getLocator());
            console.debug("An YUV Video Device was found.");
          }
          else
          {
            console.debug("No Video Device was found.");
          }
        }

        //Create the av data source
        if ((audioDataSource != null) && (videoDataSource != null))
        {
          DataSource[] allDS = new DataSource[] { audioDataSource, videoDataSource };

          try
          {
            avDataSource = Manager.createMergingDataSource(allDS);
          }
          catch (IncompatibleSourceException exc)
          {
            console.error("Failed to create a media data source!" +
              "Media transmission won't be enabled!", exc);

            //Shouldn't happen
            throw new MediaException("Failed to create a media data source!" +
              "Media transmission won't be enabled!", exc);
          }
        }
        else
        {
          if (audioDataSource != null)
          {
            avDataSource = audioDataSource;
          }

          if (videoDataSource != null)
          {
            avDataSource = videoDataSource;
          }
        }

        //avDataSource may be null (Bug report Vince Fourcade)
        if (avDataSource != null)
        {
          initProcessor(avDataSource);
        }
      }

      //A custom media source
      else
      {
        if (console.isDebugEnabled())
        {
          console.debug("Specified Media Source is: " + mediaSource);
        }

        MediaLocator locator = new MediaLocator(mediaSource);
        avDataSource = createDataSource(locator);

        if (avDataSource != null)
        {
          initProcessor(avDataSource);
        }
      }

      isStarted = true;
    }
    finally
    {
      console.logExit();
    }
  }

  protected DataSource createDataSource(MediaLocator locator)
  {
    try
    {
      console.logEntry();

      try
      {
        if (console.isDebugEnabled())
        {
          console.debug((("Creating datasource for:" + locator) != null)
            ? locator.toExternalForm() : "null");
        }

        return Manager.createDataSource(locator);
      }
      catch (NoDataSourceException ex)
      {
        //The failure only concens us
        if (console.isDebugEnabled())
        {
          console.debug("Coud not create data source for " +
            locator.toExternalForm(), ex);
        }

        return null;
      }
      catch (IOException ex)
      {
        //The failure only concens us
        if (console.isDebugEnabled())
        {
          console.debug("Coud not create data source for " +
            locator.toExternalForm(), ex);
        }

        return null;
      }
    }
    finally
    {
      console.logExit();
    }
  }

  public void openMediaStreams(String sdpData) throws MediaException
  {
    try
    {
      console.logEntry();

      if (console.isDebugEnabled())
      {
        console.debug("sdpData arg - " + sdpData);
      }

      checkIfStarted();

      SessionDescription sessionDescription = null;

      if (sdpData == null)
      {
        console.error("The SDP data was null! Cannot open " +
          "a stream withour an SDP Description!");
        throw new MediaException("The SDP data was null! Cannot open " +
          "a stream withour an SDP Description!");
      }

      try
      {
        sessionDescription = sdpFactory.createSessionDescription(sdpData);
      }
      catch (SdpParseException ex)
      {
        console.error("Incorrect SDP data!", ex);
        throw new MediaException("Incorrect SDP data!", ex);
      }

      Vector mediaDescriptions;

      try
      {
        mediaDescriptions = sessionDescription.getMediaDescriptions(true);
      }
      catch (SdpException ex)
      {
        console.error("Failed to extract media descriptions from provided session description!",
          ex);
        throw new MediaException("Failed to extract media descriptions from provided session description!",
          ex);
      }

      Connection sessionConnection = sessionDescription.getConnection();
      String sessionRemoteAddress = null;

      if (sessionConnection != null)
      {
        try
        {
          sessionRemoteAddress = sessionConnection.getAddress();
        }
        catch (SdpParseException ex)
        {
          console.error("Failed to extract the connection address parameter" +
            "from privided session description", ex);
          throw new MediaException(
            "Failed to extract the connection address parameter" +
            "from privided session description", ex);
        }
      }

      int mediaPort = -1;
      boolean atLeastOneTransmitterStarted = false;
      ArrayList mediaTypes = new ArrayList();
      ArrayList remoteAddresses = new ArrayList();
      ArrayList ports = new ArrayList();
      ArrayList formatSets = new ArrayList();
            console.debug("mediaDescriptions size=" + mediaDescriptions.size());
          for (int i = 0; i < mediaDescriptions.size(); i++)
      {
                MediaDescription mediaDescription = (MediaDescription) mediaDescriptions.get(i);
        Media media = mediaDescription.getMedia();

        //Media Type
        String mediaType = null;

        try
        {
          mediaType = media.getMediaType();
        }
        catch (SdpParseException ex)
        {
          console.error(
            "Failed to extract the media type for one of the provided media descriptions!\n" +
            "Ignoring description!", ex);
          fireNonFatalMediaError(new MediaException(
              "Failed to extract the media type for one of the provided media descriptions!\n" +
              "Ignoring description!", ex));

          continue;
        }

        //Find ports
        try
        {
          mediaPort = media.getMediaPort();
        }
        catch (SdpParseException ex)
        {
          console.error("Failed to extract port for media type [" + mediaType +
            "]. Ignoring description!", ex);
          fireNonFatalMediaError(new MediaException(
              "Failed to extract port for media type [" + mediaType +
              "]. Ignoring description!", ex));

          continue;
        }

        //Find formats
        Vector sdpFormats = null;

        try
        {
          sdpFormats = media.getMediaFormats(true);
        }
        catch (SdpParseException ex)
        {
          console.error("Failed to extract media formats for media type [" +
            mediaType + "]. Ignoring description!", ex);
          fireNonFatalMediaError(new MediaException(
              "Failed to extract media formats for media type [" + mediaType +
              "]. Ignoring description!", ex));

          continue;
        }

        Connection mediaConnection = mediaDescription.getConnection();
        String mediaRemoteAddress = null;

        if (mediaConnection == null)
        {
          if (sessionConnection == null)
          {
            console.error(
              "A connection parameter was not present in provided session/media description");
            throw new MediaException(
              "A connection parameter was not present in provided session/media description");
          }
          else
          {
            mediaRemoteAddress = sessionRemoteAddress;
          }
        }
        else
        {
          try
          {
            mediaRemoteAddress = mediaConnection.getAddress();
          }
          catch (SdpParseException ex)
          {
            console.error("Failed to extract the connection address parameter" +
              "from privided media description", ex);
            throw new MediaException(
              "Failed to extract the connection address parameter" +
              "from privided media description", ex);
          }
        }

        //START TRANSMISSION
        try
        {
          if (isMediaTransmittable(mediaType))
          {
            mediaTypes.add(mediaType);
            remoteAddresses.add(mediaRemoteAddress);
            ports.add(new Integer(mediaPort));
            formatSets.add(extractTransmittableJmfFormats(sdpFormats));
          }
          else
          {
            //nothing to transmit here so skip setting the flag
            //bug report and fix - Gary M. Levin - Telecordia
            continue;
          }
        }
        catch (MediaException ex)
        {
          console.error("Could not start a transmitter for media type [" +
            mediaType + "]\nIgnoring media [" + mediaType + "]!", ex);
          fireNonFatalMediaError(new MediaException(
              "Could not start a transmitter for media type [" + mediaType +
              "]\nIgnoring media [" + mediaType + "]!", ex));

          continue;
        }

        atLeastOneTransmitterStarted = true;
      }

      if (!atLeastOneTransmitterStarted)
      {
        console.error(
          "Apparently all media descriptions failed to initialise!\n" +
          "SIP COMMUNICATOR won't be able to open a media stream!");
        throw new MediaException(
          "Apparently all media descriptions failed to initialise!\n" +
          "SIP COMMUNICATOR won't be able to open a media stream!");
      }
      else
      {
  
  //@dela
        this.initProcessor(this.avDataSource);
  //@
        startReceiver(mediaTypes, remoteAddresses);
        startTransmitter(remoteAddresses, ports, formatSets);
      }
    }
    finally
    {
      console.logExit();
    }
  }

  protected void closeProcessor() throws MediaException
  {
    try
    {
      console.logEntry();
       if (processor != null)
      {
        processor.stop();
        processor.close();
//@dela
        processor.deallocate();
// }

      if (avDataSource != null)
      {
        avDataSource.disconnect();
      }
      processor = null ;
    }
    finally
    {
      console.logExit();
    }
  }

  {
  
    try
    {
      console.logEntry();
      closeStreams();
      closeProcessor();
//@dela
      terminateListeners();
// }
    finally
    {
      console.logExit();
    }
  }

   /**
   * terminateListeners * @author dela
   */
  public void terminateListeners()
  {
    if (listeners == null ) return ;
    for (int i = listeners.size() - 1; i >= 0; i--)
    {
      MediaListener listener = (MediaListener) listeners.get(i) ;
      this.removeMediaListener(listener);
    }
      }

  public void closeStreams()
  {
         try
    {
      console.logEntry();
      removeAllRtpManagers();
      stopTransmitters();
      stopReceiver();
      firePlayerStopped();
   //@dela
         closeProcessor();
       terminateListeners();
//@
     } catch (Exception ex)
    {
      ex.printStackTrace();
    }
    finally
    {
      console.logExit();
    }
  }

  protected void startTransmitter(ArrayList destHosts, ArrayList ports,
    ArrayList formatSets) throws MediaException
  {
    try
    {
      console.logEntry();
      console.debug("startTransmitter-Enter destHosts=" + destHosts + " ports=" + ports + " formatSets=" + formatSets);

      if (avDataSource != null)
      {
        if ( processor==null )
        {
          this.initProcessor(avDataSource);
        }
        AVTransmitter avTransmitter = new AVTransmitter(processor, destHosts, ports, formatSets);
        avTransmitter.setMediaManagerCallback(this);
        avTransmitters.add(avTransmitter);
        console.debug("startTransmitter avTransmitters=" + avTransmitters.size() );
        avTransmitter.start();
      }
    }
    finally
    {
      console.logExit();
      console.debug("startTransmitter-Leave" );
    }
  }

  protected void stopTransmitters()
  {
      try {
          console.logEntry();
          for (int i = avTransmitters.size() - 1; i >= 0; i--) {
              try {
                  ( (AVTransmitter) avTransmitters.elementAt(i)).stop();
              } //Catch everything that comes out as we wouldn't want
              //Some null pointer prevent us from closing a device and thus
              //render it unusable
              catch (Exception exc) {
                  console.error("Could not close transmitter " + i, exc);
              }
              avTransmitters.removeElementAt(i);
          }
      }
      finally {
//@dela avTransmitters = new Vector();
// console.logExit();
      }
  }

    protected void startReceiver(ArrayList mediaTypes, ArrayList remoteAddresses)
  {
    try
    {
      console.logEntry();
      console.debug("startReceiver mediaTypes=" + mediaTypes +
        " remoteAddresses=" + remoteAddresses);

      ArrayList sessions = new ArrayList();
      String mediaType = null;

      for (int i = 0; i < mediaTypes.size(); i++)
      {
        mediaType = (String) mediaTypes.get(i);

        if ("audio".equals(mediaType))
        {
          sessions.add((String) remoteAddresses.get(i) + "/" + getAudioPort() +
            "/1");
        }
        else if ("video".equals(mediaType))
        {
          sessions.add((String) remoteAddresses.get(i) + "/" + getVideoPort() +
            "/1");
        }
      }

      avReceiver = new AVReceiver(sessions);
      avReceiver.setMediaManager(this);
      avReceiver.initialize();
    }
    finally
    {
      console.logExit();
    }
  }

  protected void stopReceiver()
  {
    try
    {
      console.logEntry();
      console.debug("stopReceiver-Enter " + avReceiver );
      if (avReceiver != null)
      {
        avReceiver.setMediaManager(null);
// avReceiver.terminateSessions();
        avReceiver.close();
         avReceiver = null;
      }
    }
    finally
    {
      console.logExit();
      console.debug("stopReceiver-Leave " + avReceiver );
    }
  }

  /**
   * Only stops the receiver without deleting it. After calling this method
   * one can call softStartReceiver to relauch reception.
   */
  public void softStopReceiver()
  {
    try
    {
      console.logEntry();
      console.debug("softStopReceiver-Enter" + avReceiver );
      if (avReceiver != null)
      {
        avReceiver.close();
        this.firePlayerStopped();
      }
      else
      {
        console.debug("Attempt to soft stop reception for a null avReceiver");
      }
    }
    finally
    {
      console.debug("softStopReceiver-Leave" + avReceiver );
      console.logExit();
    }
  }

  /**
   * Starts a receiver that has been stopped using softStopReceiver().
   */
  public void softStartReceiver()
  {
    try
    {
      console.logEntry();

      if (avReceiver != null)
      {
        avReceiver.initialize();
      }
      else
      {
        console.error(
          "acReceiver is null. Use softStartReceiver only for receivers " +
          "that had been stopped using softStopReceiver()");
      }
    }
    finally
    {
      console.logExit();
    }
  }

  void firePlayerStarting(Player player)
  {
    try
    {
      console.logEntry();

      mediaEvent = new MediaEvent(player);

      for (int i = listeners.size() - 1; i >= 0; i--)
      {
        ((MediaListener) listeners.get(i)).playerStarting(mediaEvent);
      }
    }
    finally
    {
      console.logExit();
    }
  }

  void firePlayerStopped()
  {
    try
    {
      console.logEntry();

      for (int i = listeners.size() - 1; i >= 0; i--)
      {
        ((MediaListener) listeners.get(i)).playerStopped();
  //@dela listeners.remove(i);
       }
    }
    finally
    {
      console.logExit();
    }
  }

  void fireNonFatalMediaError(Throwable cause)
  {
    try
    {
      console.logEntry();

      MediaErrorEvent evt = new MediaErrorEvent(cause);

      for (int i = listeners.size() - 1; i >= 0; i--)
      {
        ((MediaListener) listeners.get(i)).nonFatalMediaErrorOccurred(evt);
      }
    }
    finally
    {
      console.logExit();
    }
  }

  public void addMediaListener(MediaListener listener)
  {
    try
    {
      console.logEntry();
      listeners.add(listener);
    }
    finally
    {
      console.logExit();
    }
  }

  public void removeMediaListener(MediaListener listener)
  {
    try
    {
      console.logEntry();
      if ( listeners.contains(listener) )
      listeners.remove(listener);
    }
    finally
    {
      console.logExit();
    }
  }

  InetAddress getLocalHost() throws MediaException
  {
    try
    {
      console.logEntry();

      String hostAddress = Utils.getProperty(
          "net.java.sip.communicator.media.IP_ADDRESS");
      InetAddress localhost = null;

      if (hostAddress == null)
      {
        localhost = NetworkAddressManager.getLocalHost(false);
      }
      else
      {
        try
        {
          localhost = InetAddress.getByName(hostAddress);
        }
        catch (UnknownHostException ex)
        {
          throw new MediaException("Failed to create localhost!", ex);
        }
      }

      if (console.isDebugEnabled())
      {
        console.debug("returning - " + localhost.getHostAddress());
      }

      return localhost;
    }
    finally
    {
      console.logExit();
    }
  }

  public String generateSdpDescription() throws MediaException
  {
    try
    {
      console.logEntry();
      checkIfStarted();

      try
      {
        SessionDescription sessDescr = sdpFactory.createSessionDescription();

        //"v=0"
        Version v = sdpFactory.createVersion(0);
        InetSocketAddress publicVideoAddress = NetworkAddressManager.getPublicAddressFor(Integer.parseInt(
              getVideoPort()));
        InetSocketAddress publicAudioAddress = NetworkAddressManager.getPublicAddressFor(Integer.parseInt(
              getAudioPort()));
        InetAddress publicIpAddress = publicAudioAddress.getAddress();
        String addrType = (publicIpAddress instanceof Inet6Address)
          ? "IP6" : "IP4";

        //spaces in the user name mess everything up.
        //bug report - Alessandro Melzi
        Origin o = sdpFactory.createOrigin(Utils.getProperty("user.name")
                                                .replace(' ', '_'), 0, 0, "IN",
            addrType, publicIpAddress.getHostAddress());

        //"s=-"
        SessionName s = sdpFactory.createSessionName("-");

        //c=
        Connection c = sdpFactory.createConnection("IN", addrType,
            publicIpAddress.getHostAddress());

        //"t=0 0"
        TimeDescription t = sdpFactory.createTimeDescription();
        Vector timeDescs = new Vector();
        timeDescs.add(t);

        //--------Audio media description
        //make sure preferred formats come first
        surfacePreferredEncodings(getReceivableAudioFormats());

        String[] formats = getReceivableAudioFormats();
        MediaDescription am = sdpFactory.createMediaDescription("audio",
            publicAudioAddress.getPort(), 1, "RTP/AVP", formats);

        if (!isAudioTransmissionSupported())
        {
          am.setAttribute("recvonly", null);

          //--------Video media description
        }

        surfacePreferredEncodings(getReceivableVideoFormats());

        //"m=video 22222 RTP/AVP 34";
        String[] vformats = getReceivableVideoFormats();
        MediaDescription vm = sdpFactory.createMediaDescription("video",
            publicVideoAddress.getPort(), 1, "RTP/AVP", vformats);

        if (!isVideoTransmissionSupported())
        {
          vm.setAttribute("recvonly", null);
        }

        Vector mediaDescs = new Vector();

        //Add Video and media descriptions if the user has not requested
        //otherwise (feature request by Pradeep Cheetal)
        if ((Utils.getProperty(
              "net.java.sip.communicator.media.NO_AUDIO_DESCRIPTION_IN_SDP") == null) ||
            !Utils.getProperty(
              "net.java.sip.communicator.media.NO_AUDIO_DESCRIPTION_IN_SDP")
                    .equalsIgnoreCase("true"))
        {
          mediaDescs.add(am);
        }

        if ((Utils.getProperty(
              "net.java.sip.communicator.media.NO_VIDEO_DESCRIPTION_IN_SDP") == null) ||
            !Utils.getProperty(
              "net.java.sip.communicator.media.NO_VIDEO_DESCRIPTION_IN_SDP")
                    .equalsIgnoreCase("true"))
        {
          mediaDescs.add(vm);
        }

        sessDescr.setVersion(v);
        sessDescr.setOrigin(o);
        sessDescr.setConnection(c);
        sessDescr.setSessionName(s);
        sessDescr.setTimeDescriptions(timeDescs);

        if (mediaDescs.size() > 0)
        {
          sessDescr.setMediaDescriptions(mediaDescs);
        }

        if (console.isDebugEnabled())
        {
          console.debug("Generated SDP - " + sessDescr.toString());
        }

        return sessDescr.toString();
      }
      catch (SdpException exc)
      {
        console.error("An SDP exception occurred while generating local sdp description",
          exc);
        throw new MediaException("An SDP exception occurred while generating local sdp description",
          exc);
      }
    }
    finally
    {
      console.logExit();
    }
  }

  String getAudioPort()
  {
    try
    {
      console.logEntry();

      String audioPort = Utils.getProperty(
          "net.java.sip.communicator.media.AUDIO_PORT");

      return (audioPort == null) ? "22224" : audioPort;
    }
    finally
    {
      console.logExit();
    }
  }

  String getVideoPort()
  {
    try
    {
      console.logEntry();

      String videoPort = Utils.getProperty(
          "net.java.sip.communicator.media.VIDEO_PORT");

      return (videoPort == null) ? "22222" : videoPort;
    }
    finally
    {
      console.logExit();
    }
  }

  protected void finalize()
  {
    try
    {
      console.logEntry();

      try
      {
        if (avDataSource != null)
        {
          avDataSource.disconnect();
        }
      }
      catch (Exception exc)
      {
        console.error("Failed to disconnect data source:" + exc.getMessage());
      }
    }
    finally
    {
      console.logExit();
    }
  }

  public boolean isStarted()
  {
    return isStarted;
  }

  protected void checkIfStarted() throws MediaException
  {
    if (!isStarted())
    {
      console.error("The MediaManager had not been properly started! " +
        "Impossible to continue");
      throw new MediaException(
        "The MediaManager had not been properly started! " +
        "Impossible to continue");
    }
  }

  protected boolean isAudioTransmissionSupported()
  {
    return transmittableAudioFormats.size() > 0;
  }

  protected boolean isVideoTransmissionSupported()
  {
    return transmittableVideoFormats.size() > 0;
  }

  protected boolean isMediaTransmittable(String media)
  {
    if (media.equalsIgnoreCase("video") && isVideoTransmissionSupported())
    {
      return true;
    }
    else if (media.equalsIgnoreCase("audio") && isAudioTransmissionSupported())
    {
      return true;
    }
    else
    {
      return false;
    }
  }

  protected String[] getReceivableAudioFormats()
  {
    return receivableAudioFormats;
  }

  protected String[] getReceivableVideoFormats()
  {
    return receivableVideoFormats;
  }

  protected String findCorrespondingJmfFormat(String sdpFormatStr)
  {
    int sdpFormat = -1;

    try
    {
      sdpFormat = Integer.parseInt(sdpFormatStr);
    }
    catch (NumberFormatException ex)
    {
      return null;
    }

    switch (sdpFormat)
    {
    case SdpConstants.PCMU:
      return AudioFormat.ULAW_RTP;

    case SdpConstants.GSM:
      return AudioFormat.GSM_RTP;

    case SdpConstants.G723:
      return AudioFormat.G723_RTP;

    case SdpConstants.DVI4_8000:
      return AudioFormat.DVI_RTP;

    case SdpConstants.DVI4_16000:
      return AudioFormat.DVI_RTP;

    case SdpConstants.PCMA:
      return AudioFormat.ALAW;

    case SdpConstants.G728:
      return AudioFormat.G728_RTP;

    case SdpConstants.G729:
      return AudioFormat.G729_RTP;

    case SdpConstants.H263:
      return VideoFormat.H263_RTP;

    case SdpConstants.JPEG:
      return VideoFormat.JPEG_RTP;

    case SdpConstants.H261:
      return VideoFormat.H261_RTP;

    default:
      return null;
    }
  }

  protected String findCorrespondingSdpFormat(String jmfFormat)
  {
    if (jmfFormat == null)
    {
      return null;
    }
    else if (jmfFormat.equals(AudioFormat.ULAW_RTP))
    {
      return Integer.toString(SdpConstants.PCMU);
    }
    else if (jmfFormat.equals(AudioFormat.GSM_RTP))
    {
      return Integer.toString(SdpConstants.GSM);
    }
    else if (jmfFormat.equals(AudioFormat.G723_RTP))
    {
      return Integer.toString(SdpConstants.G723);
    }
    else if (jmfFormat.equals(AudioFormat.DVI_RTP))
    {
      return Integer.toString(SdpConstants.DVI4_8000);
    }
    else if (jmfFormat.equals(AudioFormat.DVI_RTP))
    {
      return Integer.toString(SdpConstants.DVI4_16000);
    }
    else if (jmfFormat.equals(AudioFormat.ALAW))
    {
      return Integer.toString(SdpConstants.PCMA);
    }
    else if (jmfFormat.equals(AudioFormat.G728_RTP))
    {
      return Integer.toString(SdpConstants.G728);
    }
    else if (jmfFormat.equals(AudioFormat.G729_RTP))
    {
      return Integer.toString(SdpConstants.G729);
    }
    else if (jmfFormat.equals(VideoFormat.H263_RTP))
    {
      return Integer.toString(SdpConstants.H263);
    }
    else if (jmfFormat.equals(VideoFormat.JPEG_RTP))
    {
      return Integer.toString(SdpConstants.JPEG);
    }
    else if (jmfFormat.equals(VideoFormat.H261_RTP))
    {
      return Integer.toString(SdpConstants.H261);
    }
    else
    {
      return null;
    }
  }

  /**
   * @param sdpFormats
   * @return
   * @throws MediaException
   */
  protected ArrayList extractTransmittableJmfFormats(Vector sdpFormats)
    throws MediaException
  {
    try
    {
      console.logEntry();

      ArrayList jmfFormats = new ArrayList();

      for (int i = 0; i < sdpFormats.size(); i++)
      {
        int sdpFormat = -1;
        String jmfFormat = findCorrespondingJmfFormat(sdpFormats.elementAt(i)
                                                                .toString());

        if (jmfFormat != null)
        {
          jmfFormats.add(jmfFormat);
        }
      }

      if (jmfFormats.size() == 0)
      {
        throw new MediaException(
          "None of the supplied sdp formats for is supported by SIP COMMUNICATOR");
      }

      return jmfFormats;
    }
    finally
    {
      console.logExit();
    }
  }

  //This is the data source that we'll be using to transmit
  //let's see what can it do
  protected void initProcessor(DataSource dataSource) throws MediaException
  {
    try
    {
      console.logEntry();

      try
      {
        try
        {
          dataSource.connect();
        }

        //Thrown when operation is not supported by the OS
        catch (NullPointerException ex)
        {
          console.error("An internal error occurred while" +
            " trying to connec to to datasource!", ex);
          throw new MediaException("An internal error occurred while" +
            " trying to connec to to datasource!", ex);
        }

        processor = Manager.createProcessor(dataSource);
        procUtility.waitForState(processor, Processor.Configured);
      }
      catch (NoProcessorException ex)
      {
        console.error("Media manager could not create a processor\n" +
          "for the specified data source", ex);
        throw new MediaException("Media manager could not create a processor\n" +
          "for the specified data source", ex);
      }
      catch (IOException ex)
      {
        console.error("Media manager could not connect " +
          "to the specified data source", ex);
        throw new MediaException("Media manager could not connect " +
          "to the specified data source", ex);
      }

      processor.setContentDescriptor(new ContentDescriptor(
          ContentDescriptor.RAW_RTP));

      TrackControl[] trackControls = processor.getTrackControls();
      console.debug("We will be able to transmit in:");

      for (int i = 0; i < trackControls.length; i++)
      {
        Format[] formats = trackControls[i].getSupportedFormats();

        for (int j = 0; j < formats.length; j++)
        {
          Format format = formats[j];
          String encoding = format.getEncoding();

          if (format instanceof AudioFormat)
          {
            String sdp = findCorrespondingSdpFormat(encoding);

            if ((sdp != null) && !transmittableAudioFormats.contains(sdp))
            {
              if (console.isDebugEnabled())
              {
                console.debug("Audio=[" + (j + 1) + "]=" + encoding + "; sdp=" +
                  sdp);
              }

              transmittableAudioFormats.add(sdp);
            }
          }

          if (format instanceof VideoFormat)
          {
            String sdp = findCorrespondingSdpFormat(encoding);

            if ((sdp != null) && !transmittableVideoFormats.contains(sdp))
            if ((sdp != null) )

            {
              if (console.isDebugEnabled())
              {
                console.debug("Video=[" + (j + 1) + "]=" + encoding + "; sdp=" +
                  sdp);
              }

              transmittableVideoFormats.add(sdp);
            }
          }
        }
      }
    }
    finally
    {
      console.logExit();
    }
  }

  /*
   protected static MediaManager mman;
      public static void main(String[] args)
          throws Throwable
      {
          mman = new MediaManager();
          System.setProperty("net.java.sip.communicator.media.MEDIA_SOURCE","file://home/emcho/lostinspace.mov");
       System.setProperty("net.java.sip.communicator.media.VIDEO_PORT","44444");
       System.setProperty("net.java.sip.communicator.media.AUDIO_PORT","44446");
          System.setProperty("net.java.sip.communicator.media.IP_ADDRESS","2001:660:220:102:230:5ff:fe1a:805f");
          mman.start();
          String sdp =
                    "v=0" + "\r\n" +
                    "o=Emcho 0 0 IN IP4 130.79.90.142" + "\r\n" +
                    "s=-" + "\r\n" +
                    "c=IN IP4 2001:660:220:102:230:5ff:fe2a:77c1" + "\r\n" +
                    "t=2208988800 2208988800" + "\r\n" +
                    "m=video 22222 RTP/AVP 20 26 31" + "\r\n" +
                    "m=audio 22224 RTP/AVP 3 0 4 5 6 8 15 18" + "\r\n"
                    ;
          mman.openMediaStreams(sdp);
          javax.swing.JFrame frame = new javax.swing.JFrame("Close & Exit");
          frame.addWindowListener(new java.awt.event.WindowAdapter(){
     public void windowClosing(java.awt.event.WindowEvent evt)
              {
                  try {
                      mman.stop();
                  }
                  catch (MediaException ex) {
                      ex.printStackTrace();
                  }
               System.exit(0);
              }
          });
          frame.show();
      }
      protected void writeObject(ObjectOutputStream oos) throws IOException
      {
          oos.defaultWriteObject();
      }
      protected void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException
      {
          ois.defaultReadObject();
      }
   */

  /**
   * Returns a cached instance of an RtpManager bound on the specified local
   * address. If no such instance exists null is returned.
   * @param localAddress the address where the rtp manager must be bound locally.
   * @return an rtp manager bound on the specified address or null if such an
   * instance was not found.
   */
  synchronized RTPManager getRtpManager(SessionAddress localAddress)
  {
    return (RTPManager) activeRtpManagers.get(localAddress);
  }

  /**
   * Maps the specified rtp manager against the specified local address so
   * that it may be later retrieved in case someone wants to operate
   * (transmit/receive) on the same port.
   * @param localAddress the address where the rtp manager is bound
   * @param rtpManager the rtp manager itself
   */
  synchronized void putRtpManager(SessionAddress localAddress,
    RTPManager rtpManager)
  {
    activeRtpManagers.put(localAddress, rtpManager);
  }

  /**
   * Removes all rtp managers from the rtp manager cache.
   */
  public synchronized void removeAllRtpManagers()
  {
    try {
      Enumeration rtpManages = activeRtpManagers.keys();
        while (rtpManages.hasMoreElements())
      {
        SessionAddress item = (SessionAddress) rtpManages.nextElement();
        RTPManager rtpManager = (RTPManager) activeRtpManagers.get(item) ;
        if ( rtpManager != null )
        {
           Vector s = rtpManager.getSendStreams() ;
           if ( s!=null)
           {
             for (int i=0 ; s != null && i <s.size() ; i++)
             {
               SendStream ss = (SendStream)s.elementAt(i) ;
               s.remove(ss) ;
             }
           } Vector r = rtpManager.getReceiveStreams() ;
           if ( r !=null )
           {
             for (int i=0 ; i <r.size() ; i++)
             {
               ReceiveStream rr = (ReceiveStream)r.elementAt(i) ;
               r.remove(rr) ;
             }
           }
                 }
        rtpManager.dispose();
        rtpManager.removeTargets("Remove Targets");
        activeRtpManagers.remove(item);
      }
    }
    catch ( Exception ex )
    {
      ex.printStackTrace();
    }

  }

  /**
   * Moves formats with the specified encoding to the top of the array list
   * so that they are the ones chosen for transmission (if supported by the
   * remote party) (feature request by Vince Fourcade)
   */
  protected void surfacePreferredEncodings(String[] formats)
  {
    try
    {
      console.logEntry();

      String preferredAudioEncoding = Utils.getProperty(
          "net.java.sip.communicator.media.PREFERRED_AUDIO_ENCODING");
      String preferredVideoEncoding = Utils.getProperty(
          "net.java.sip.communicator.media.PREFERRED_VIDEO_ENCODING");

      if ((preferredAudioEncoding == null) && (preferredVideoEncoding == null))
      {
        return;
      }

      for (int i = 0; i < formats.length; i++)
      {
        String encoding = formats[i];

        if (((preferredAudioEncoding != null) &&
            encoding.equalsIgnoreCase(preferredAudioEncoding)) ||
            ((preferredVideoEncoding != null) &&
            encoding.equalsIgnoreCase(preferredVideoEncoding)))
        {
          formats[i] = formats[0];
          formats[0] = encoding;

          if (console.isDebugEnabled())
          {
            console.debug("Encoding [" + findCorrespondingJmfFormat(encoding) +
              "] is set as preferred.");
          }

          break;
        }
      }
    }
    finally
    {
      console.logExit();
    }
  }

  /**
   * Runs JMFInit the first time the application is started so that capture
   * devices are properly detected and initialized by JMF.
   * @throws MediaException if an exception occurs during the detection.
   */
  public static void setupJMF() throws MediaException
  {
    try
    {
      console.logExit();

      //.jmf is the place where we store the jmf.properties file used
      //by JMF. if the directory does not exist or it does not contain
      //a jmf.properties file. or if the jmf.properties file has 0 length
      //then this is the first time we're running and should continue to
      //with JMFInit
      String homeDir = System.getProperty("user.home");
      File jmfDir = new File(homeDir, ".jmf");
      String classpath = System.getProperty("java.class.path");
      classpath += (System.getProperty("path.separator") +
      jmfDir.getAbsolutePath());
      System.setProperty("java.class.path", classpath);

      if (!jmfDir.exists())
      {
        jmfDir.mkdir();
      }

      File jmfProperties = new File(jmfDir, "jmf.properties");

      if (!jmfProperties.exists())
      {
        try
        {
          jmfProperties.createNewFile();
        }
        catch (IOException ex)
        {
          throw new MediaException("Failed to create jmf.properties - " +
            jmfProperties.getAbsolutePath());
        }
      }

      //if we're running on linux checkout that libjmutil.so is where it
      //should be and put it there.
      runLinuxPreInstall();

      if (jmfProperties.length() == 0)
      {
        JMFInit.start();
      }
    }
    finally
    {
      console.logExit();
    }
  }

  private static void runLinuxPreInstall()
  {
    try
    {
      console.logEntry();

      if ((Utils.getProperty("os.name") == null) ||
          !Utils.getProperty("os.name").equalsIgnoreCase("Linux"))
      {
        return;
      }

      try
      {
        System.loadLibrary("jmv4l");
        console.debug("Successfully loaded libjmv4l.so");
      }
      catch (UnsatisfiedLinkError err)
      {
        console.debug("Failed to load libjmv4l.so. Will try and copy libjmutil.so",
          err);

        String destinationPathStr = Utils.getProperty("java.home") +
          File.separator + "lib" + File.separator + "i386";
        String libjmutilFileStr = "libjmutil.so";

        try
        {
          InputStream libIS = MediaManager.class.getClassLoader()
                                                .getResourceAsStream(libjmutilFileStr);
          File outFile = new File(destinationPathStr + File.separator +
              libjmutilFileStr);

          //Check if file is already there - Ben Asselstine
          if (outFile.exists())
          {
            //if we're here then libjmutil is already where it should be
            // but yet we failed to load libjmv4l.
            //so notify log and bail out
            console.error("An error occurred while trying to load JMF. This " +
              "error is probably due to a JMF installation problem. " +
              "Please copy libjmutil.so to a location contained by " +
              "$LD_LIBRARY_PATH and try again!", err);

            return;
          }

          outFile.createNewFile();

          console.debug("jmutil");

          FileOutputStream fileOS = new FileOutputStream(outFile);
          int available = libIS.available();
          byte[] bytes = new byte[libIS.available()];
          int read = 0;
          int i = 0;

          for (i = 0; i < available; i++)
          {
            bytes[i] = (byte) libIS.read();
          }

          console.debug("Read " + i + " bytes out of " + available);

          fileOS.write(bytes, 0, bytes.length);
          console.debug("Wrote " + available + " bytes.");
          bytes = null;
          libIS.close();
          fileOS.close();
        }
        catch (IOException exc)
        {
          if ((exc.getMessage() != null) &&
              (exc.getMessage().toLowerCase().indexOf("permission denied") != -1))
          {
            console.showError("Permission denied!",
              "Because of insufficient permissions SIP Communicator has failed " +
              "to copy a required library to\n\n\t" + destinationPathStr +
              "!\n\nPlease run the application as root or " +
              "manually copy the " + libjmutilFileStr +
              " file to the above location!\n");
          }

          exc.printStackTrace();
        }
      }

      /** @todo check whether we have a permissions problem and alert the
      * user that they should be running as root */
      catch (Throwable t)
      {
        console.debug("Error while loading");
      }
    }
    finally
    {
      console.logExit();
    }
  }
}

/*
   v=0
   o=Emcho 0 0 IN IP4 130.79.90.142
   s=-
   c=IN IP4 130.79.90.142
   t=2208988800 2208988800
   m=video 22222 RTP/AVP 20 26 31
   m=audio 22224 RTP/AVP 0 3 4 5 6 8 15 18
*/
/*
    PCMU javax.media.format.AudioFormat.ULAW_RTP;
    1016
    G721
    GSM javax.media.format.AudioFormat.GSM_RTP;
    G723 javax.media.format.AudioFormat.G723_RTP
    DVI4_8000 javax.media.format.AudioFormat.DVI_RTP;
    DVI4_16000 javax.media.format.AudioFormat.DVI_RTP;
    LPC
    PCMA javax.media.format.AudioFormat.ALAW;
    G722 javax.media.format.AudioFormat.ALAW;
    L16_2CH
    L16_1CH
    QCELP
    CN
    MPA
    G728 javax.media.format.AudioFormat.G728_RTP;
    DVI4_11025
    DVI4_22050
    G729 javax.media.format.AudioFormat.G729_RTP
    CN_DEPRECATED
    H263 javax.media.format.VideoFormat.H263_RTP
    CelB
    JPEG javax.media.format.VideoFormat.JPEG_RTP
    nv
    H261 javax.media.format.VideoFormat.H261_RTP
       MPV*/

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@sip-communicator.dev.java.net
For additional commands, e-mail: dev-help@sip-communicator.dev.java.net