⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 audiochannel.java

📁 开源项目openfire的完整源程序
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
/**
 * $Revision: $
 * $Date: $
 *
 * Copyright (C) 2007 Jive Software. All rights reserved.
 *
 * This software is published under the terms of the GNU Lesser Public License (LGPL),
 * a copy of which is included in this distribution.
 */

package net.java.sipmack.media;

import net.java.sipmack.sip.SIPConfig;

import javax.media.*;
import javax.media.control.TrackControl;
import javax.media.control.BufferControl;
import javax.media.control.PacketSizeControl;
import javax.media.format.AudioFormat;
import javax.media.protocol.ContentDescriptor;
import javax.media.protocol.DataSource;
import javax.media.protocol.PushBufferDataSource;
import javax.media.protocol.PushBufferStream;
import javax.media.rtp.RTPManager;
import javax.media.rtp.SendStream;
import javax.media.rtp.SessionAddress;
import javax.media.rtp.ReceiveStreamListener;
import javax.media.rtp.rtcp.SourceDescription;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;

import org.jivesoftware.sparkimpl.plugin.phone.JMFInit;
import org.jivesoftware.spark.phone.PhoneManager;

/**
 * An Easy to use Audio Channel implemented using JMF.
 * It sends and receives jmf for and from desired IPs and ports.
 * Also has a rport Symetric behavior for better NAT Traversal.
 * It send data from a defined port and receive data in the same port, making NAT binds easier.
 * <p/>
 * Send from portA to portB and receive from portB in portA.
 * <p/>
 * Sending
 * portA ---> portB
 * <p/>
 * Receiving
 * portB ---> portA
 * <p/>
 * <i>Transmit and Receive are interdependents. To receive you MUST trasmit. </i>
 *
 * @author Thiago Camargo
 */
public class AudioChannel {

    private MediaLocator locator;
    private String localIpAddress;
    private String ipAddress;
    private int localPort;
    private int portBase;
    private Format format;

    private Processor processor = null;
    private RTPManager rtpMgrs[];
    private DataSource dataOutput = null;
    private AudioReceiver audioReceiver;

    private List<SendStream> sendStreams = new ArrayList<SendStream>();

    private List<ReceiveStreamListener> receiveListeners = new ArrayList<ReceiveStreamListener>();

    private boolean started = false;

    /**
     * Creates an Audio Channel for a desired jmf locator. For instance: new MediaLocator("dsound://")
     *
     * @param locator
     * @param ipAddress
     * @param localPort
     * @param remotePort
     * @param format
     */
    public AudioChannel(MediaLocator locator,
                        String localIpAddress,
                        String ipAddress,
                        int localPort,
                        int remotePort,
                        Format format) {

        this.locator = locator;
        this.localIpAddress = localIpAddress;
        this.ipAddress = ipAddress;
        this.localPort = localPort;
        this.portBase = remotePort;
        this.format = format;
    }

    /**
     * Starts the transmission. Returns null if transmission started ok.
     * Otherwise it returns a string with the reason why the setup failed.
     * Starts receive also.
     */
    public synchronized String start() {
        if (started) return null;
        started = true;
        String result;

        // Create a processor for the specified jmf locator
        result = createProcessor();
        if (result != null) {
            started = false;
            return result;
        }

        // Create an RTP session to transmit the output of the
        // processor to the specified IP address and port no.
        result = createTransmitter();
        if (result != null) {
            processor.close();
            processor = null;
            started = false;
            return result;
        }

        // Start the transmission
        processor.start();

        return null;
    }

    /**
     * Add Receive Listeners. It monitors RTCP packets and signalling.
     *
     * @param listener listener to add
     */
    public void addReceiverListener(ReceiveStreamListener listener) {
        this.receiveListeners.add(listener);
        for (int i = 0; i < rtpMgrs.length; i++) {
            rtpMgrs[i].addReceiveStreamListener(listener);
        }
    }

    /**
     * Removes Receive Listener.
     *
     * @param listener listener to remove
     */
    public void removeReceiverListener(ReceiveStreamListener listener) {
        this.receiveListeners.remove(listener);
        for (int i = 0; i < rtpMgrs.length; i++) {
            rtpMgrs[i].removeReceiveStreamListener(listener);
        }
    }

    /**
     * Removes All Receive Listeners.
     */
    private void remevoAllReceiverListener() {
        for (ReceiveStreamListener listener : receiveListeners) {
            for (int i = 0; i < rtpMgrs.length; i++) {
                rtpMgrs[i].removeReceiveStreamListener(listener);
            }
        }
        this.receiveListeners.clear();
    }

    /**
     * Stops the transmission if already started.
     * Stops the receiver also.
     */
    public void stop() {
        if (!started) return;
        synchronized (this) {
            try {
                started = false;

                remevoAllReceiverListener();

                if (processor != null) {
                    processor.stop();
                    processor = null;

                    for (int i = 0; i < rtpMgrs.length; i++) {
                        rtpMgrs[i].removeReceiveStreamListener(audioReceiver);
                        rtpMgrs[i].removeSessionListener(audioReceiver);
                        rtpMgrs[i].removeTargets("Session ended.");
                        rtpMgrs[i].dispose();
                    }

                    sendStreams.clear();

                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        System.err.println("RTP Transmission Stopped.");
    }

    /**
     * Creates a JMF media PRocessor
     *
     * @return
     */
    private String createProcessor() {
        if (locator == null)
            return "Locator is null";

        // Try to create a processor to handle the input jmf locator
        try {
            processor = javax.media.Manager.createProcessor(PhoneManager.getDataSource(locator));
        } catch (NoProcessorException npe) {
            npe.printStackTrace();
            return "Couldn't create processor";
        } catch (IOException ioe) {
            ioe.printStackTrace();
            return "IOException creating processor";
        }

        // Wait for it to configure
        boolean result = waitForState(processor, Processor.Configured);
        if (result == false)
            return "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)
            return "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 chosen = null;
        boolean atLeastOneTrack = false;

        // Program the tracks.
        for (int i = 0; i < tracks.length; i++) {
            if (tracks[i].isEnabled()) {

                supported = tracks[i].getSupportedFormats();

                if (supported.length > 0) {
                    for (Format format : supported) {
                        if (format instanceof AudioFormat) {
                            if (this.format.matches(format))
                                chosen = format;
                        }
                    }
                    if (chosen != null) {
                        tracks[i].setFormat(chosen);
                        System.err.println("Track " + i + " is set to transmit as:");
                        System.err.println("  " + chosen);

                        if (tracks[i].getFormat() instanceof AudioFormat) {
                            int packetRate = 20;
                            PacketSizeControl pktCtrl = (PacketSizeControl) processor.getControl(PacketSizeControl.class.getName());
                            if (pktCtrl != null) {
                                try {
                                    pktCtrl.setPacketSize(getPacketSize(tracks[i].getFormat(), packetRate));
                                } catch (IllegalArgumentException e) {
                                    pktCtrl.setPacketSize(160);
                                    // Do nothing

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -