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

📄 datatransmit.java

📁 简易聊天工具
💻 JAVA
字号:

import java.io.*;
import java.awt.Dimension;
import java.net.InetAddress;
import javax.media.*;
import javax.media.protocol.*;
import javax.media.protocol.DataSource;
import javax.media.format.*;
import javax.media.control.TrackControl;
import javax.media.rtp.*;

// 用RTP协议传输数据的类
public class DataTransmit 
{
  	private String ipAddress;         			// 发送目的地(接收端)的IP地址
  	private int portBase;             			// 传输端口号
  	private Processor processor = null;          // 处理器
  	private RTPManager rtpMgrs[];                // RTP管理器
  	private DataSource dataOutput = null;        // 输出的数据源
  	private AudioFormat audioFormat;
  	private VideoFormat videoFormat;

  	// 构造函数
  	public DataTransmit(DataSource ds, String ipAddress, String pb, AudioFormat aformat , VideoFormat vformat) 
  	{
 		this.dataOutput = ds;
    	this.ipAddress = ipAddress;
    	Integer integer = Integer.valueOf(pb);
    	audioFormat = aformat;
    	videoFormat = vformat;
    	if (integer != null)
    	{
      		this.portBase = integer.intValue();
      	}
  	}

  	// 开始传输
  	// 如果一切正常,就返回 null,否则返回出错原因
  	public synchronized String start() 
  	{
    	String result;
    	result = createProcessor();           		// 产生一个处理器
    	if (result != null)
    	{
      		return result;
      	}
   	 	result = createTransmitter();        		// 产生RTP会话,将处理器输出的数据传给指定的IP地址的指定的端口号
    	if (result != null) 
    	{
      		processor.close();
      		processor = null;
      		return result;
    	}
    	processor.start();         					// 让处理器开始传输
    	return null;
  	}

  	// 为指定的媒体定位器产生一个处理器
  	private String createProcessor() 
  	{
    	try 
    	{
      		processor = javax.media.Manager.createProcessor(dataOutput);    // 通过数据源来产生一个处理器
    	}
    	catch (NoProcessorException npe) 
    	{
      		return "Couldn't create processor";
    	}
    	catch (IOException ioe) 
    	{
      		return "IOException creating processor";
    	}
    	boolean result = waitForState(processor, Processor.Configured);     // 等待处理器配置好
    	if (result == false) return "Couldn't configure processor";

    	TrackControl[] tracks = processor.getTrackControls();        		// 为媒体流中的每一个磁道得到一个控制器

    	if (tracks == null || tracks.length < 1)              				// 确保至少有一个可用的磁道
    	{
      		return "Couldn't find tracks in processor";
      	}

    	ContentDescriptor cd = new ContentDescriptor(ContentDescriptor.RAW_RTP);
    	processor.setContentDescriptor(cd);                // 设置输出的内容描述为RAW_RTP
                                                       		// 从而限定每个磁道支持的格式仅为合法的RTP格式,即它影响后面的 Track.getSupportedFormats()
    	Format supported[];
    	Format chosen = null;
    	boolean atLeastOneTrack = false;

    	for (int i = 0; i < tracks.length; i++) 
    	{          											// 对每一个磁道,选择一种RTP支持的传输格式
      		Format format = tracks[i].getFormat();
      		if (tracks[i].isEnabled()) 
      		{                     							// 如果该磁道可用
        		supported = tracks[i].getSupportedFormats();

        		if (supported.length > 0) 
        		{
          			for(int j = 0; j < supported.length; j++)
          			{
            			if (supported[j] instanceof AudioFormat) 
            			{     													// 如果某被支持的格式为音频,则检查其是否符合要求
              				AudioFormat temp = (AudioFormat)supported[j];    	// 强制转换为音频格式
              				if(audioFormat.matches(temp)) 
              				{                  									// 检查该格式是否与用户选定的音频格式相匹配
                				chosen = supported[j];                         	// 匹配则选中
                				break;
              				}
            			}
            			else if(supported[j] instanceof VideoFormat)
            			{
            				VideoFormat temp = (VideoFormat)supported[j];
            				if(videoFormat.matches(temp)) 
              				{      
              													     			// 检查该格式是否与用户选定的视频格式相匹配
              													     			// 检查视频格式的尺寸,以确保正常工作
                				chosen = checkForVideoSizes(tracks[i].getFormat(),supported[j]);
                				break;                         
              				}	
            			}
          			}
          			chosen = supported[0];  
          			tracks[i].setFormat(chosen);
          			System.err.println("Track " + i + " is set to transmit as:");
          			System.err.println("  " + chosen);
          			atLeastOneTrack = true;
        		}
        		else
        		{
          			tracks[i].setEnabled(false);
          		}
      		}
      		else
      		{
        		tracks[i].setEnabled(false);
        	}
    	}
    	if (!atLeastOneTrack)
    	{
      		return "Couldn't set any of the tracks to a valid RTP format";
      	}
    	result = waitForState(processor, Controller.Realized);       		// 等待处理器实现
    	if (result == false)
    	{
      		return "Couldn't realize processor";
      	}
    	dataOutput = processor.getDataOutput();   							// 从处理器得到输出的数据源
    	return null;
  	}

  	// 为处理器的每一个媒体磁道产生一个RTP会话
	private String createTransmitter() 
	{
    	PushBufferDataSource pbds = (PushBufferDataSource)dataOutput;     	// 将数据源转化为“Push”(推)数据源
    	PushBufferStream pbss[] = pbds.getStreams();   						// 得到“Push”数据流
    	rtpMgrs = new RTPManager[pbss.length];       						// 为每个磁道产生一个RTP会话管理器

    	for (int i = 0; i < pbss.length; i++) 
    	{
      		try 
      		{
        		rtpMgrs[i] = RTPManager.newInstance();

        		int port = portBase + 2 * i;                         				// 每增加一个磁道,端口号加2
        		InetAddress ipAddr = InetAddress.getByName(ipAddress);     			// 得到发送目的地的IP地址

        		SessionAddress localAddr = new SessionAddress( InetAddress.getLocalHost(),port);    // 得到本机的会话地址
                                                                					// 这里传输端使用和接收目的端相同的端口号(实际上也可以不同)
        		SessionAddress destAddr = new SessionAddress( ipAddr, port);      	// 得到目的机器(接收端)的会话地址

        		rtpMgrs[i].initialize( localAddr);                  				// 将本机会话地址传给RTP管理器

        		rtpMgrs[i].addTarget( destAddr);                    				// 加入目的会话地址

        		System.err.println( "Created RTP session: " + ipAddress + " " + port);

        		SendStream sendStream = rtpMgrs[i].createSendStream(dataOutput, i); // 产生数据源的RTP传输流

        		sendStream.start();                                					// 开始RTP数据流发送
      		}
      		catch (Exception  e) 
      		{
        		return e.getMessage();
      		}
    	}

    	return null;
  	}

  // 由于JPEG和H.263编码标准,只支持一些特定的图像大小,所以这里进行必要的检查,以确保其可以正确编码
  	Format checkForVideoSizes(Format original, Format supported) 
  	{
		int width, height;
    	Dimension size = ((VideoFormat)original).getSize();         // 得到视频图像的尺寸
    	Format jpegFmt = new Format(VideoFormat.JPEG_RTP);
    	Format h263Fmt = new Format(VideoFormat.H263_RTP);

    	if (supported.matches(jpegFmt)) 							// 对JPEG格式,视频图像的宽和高必须是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)) 						// H.263格式仅支持三种特定的图像尺寸
    	{     						
      		if (size.width <= 128) 
      		{
          		width = 128;
          		height = 96;
      		}
      		else if (size.width <= 176) 
      		{
          		width = 176;
          		height = 144;
      		}
      		else 
      		{
          		width = 352;
          		height = 288;
     		}
    	}
    	else 
    	{         												// 对其他格式不予处理
      		return supported;
    	}

    	return (new VideoFormat(null,new Dimension(width, height),Format.NOT_SPECIFIED,
                            null,Format.NOT_SPECIFIED)).intersects(supported);        // 返回经过处理后的视频格式
  	}

  	// 停止传输
  	public void stop() 
  	{
    	synchronized (this) 
    	{
      		if (processor != null) 
      		{
        		processor.stop();
        		processor.close();                          // 停止处理器
        		processor = null;                           // 关闭处理器
        		for (int i = 0; i < rtpMgrs.length; i++) 
        		{  											// 删除所有RTP管理器
          			rtpMgrs[i].removeTargets( "Session ended.");
          			rtpMgrs[i].dispose();
        		}
      		}
    	}
  	}

  	// 以下两个变量为对处理器状态改变的处理服务
  	private Integer stateLock = new Integer(0);        		// 状态锁变量
  	private boolean failed = false;                    		// 是否失败的状态标志

  	// 得到状态锁
  	Integer getStateLock() 
  	{
    	return stateLock;
  	}

  	// 设置失败标志
  	void setFailed() 
  	{
    	failed = true;
  	}

  	// 等待处理器达到相应的状态
  	private synchronized boolean waitForState(Processor p, int state) 
  	{
    	p.addControllerListener(new StateListener());          // 为处理器加上状态监听
    	failed = false;

    	if (state == Processor.Configured) 
    	{         												// 配置处理器
      		p.configure();
    	}
    	else if (state == Processor.Realized) 
    	{    													// 实现处理器
      		p.realize();
    	}

    	// 一直等待,直到成功达到所需状态,或失败
    	while (p.getState() < state && !failed) 
    	{
      		synchronized (getStateLock()) 
      		{
        		try 
        		{
          			getStateLock().wait();
        		}	
        		catch (InterruptedException ie) 
        		{
          			return false;
        		}
      		}
    	}
    	if (failed) return false;
    	else return true;
  	}

  	// 内部类:处理器的状态监听器
  	class StateListener implements ControllerListener 
  	{
    	public void controllerUpdate(ControllerEvent ce) 
    	{
      		// 如果在处理器配置或实现过程中出现错误,它将关闭
      		if (ce instanceof ControllerClosedEvent)   			// 控制器关闭
      		{
        		setFailed();
			}
      		// 对于所有的控制器事件,通知在waitForState方法中等待的线程
      		if (ce instanceof ControllerEvent) 
      		{
        		synchronized (getStateLock()) 
        		{
          			getStateLock().notifyAll();
        		}
      		}
    	}
  	}

}



⌨️ 快捷键说明

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