java与面向对象---2.8 捕获音频及输出音频

2.3   捕获音频及输出音频
主要的功能模块在两个程序包中提供:
javax.media.sound.sampled-该程序包明确地说明了捕获、混合以及回播数字采样音频的界面。
javax.media.sound.MIDI-该程序包提供MIDI合成、序列化以及事件传送的界面。
数字音频
音频捕获——从输入源例如麦克风进行数据捕获。 
音频重播——将各种输入源的声音混合并重播。 
制与编码——调整增益、定位、回音处理等等,以及进行格式转换。 
态及其提示——当重播开始和结束、设备打开或关闭以及其他相关事件发生时接收事件。 
对MIDI的支持 
MIDI消息——交换消息(打开音符,关闭音符,诸如此类) 
合成——从MIDI数据装入乐器并产生声音。 
序列化——装入一个MIDI序列,开始和停止播放,以及调整节奏。
数字化音频
通道
Kara Kytle, JAVA声音 API主管工程师和系统设计师说:"Channel是音频管道中的基本功能部件"。实现Channel界面的类代表着该"管道"的一个元素,例如硬件设备,一个声音合成器,或者是一个单音频流。
InputChannel 和 OutputChannel继承了Channel,分别用于读入被捕获的数据和为播放写数据。子界面Clip支持对预装入的音频数据循环播放和重新定位。Device表示任何用于捕获、播放或混和音频的硬件或软件设备。
当一个Channel打开时,它为自己保留了系统资源 ,并且当它结束时,这些资源被释放给其他的应用程序和对象使用。用isOpen()方法可以查询Channel是打开还是关闭的。数据的处理通常由子界面方法比如read()方法来启动,这部分在InputChannel界面说明描述 (请看JAVA声音 API的说明书)。
处理方法使Channel处于负责输入或输出音频数据的状态。用isActive方法可以识别Channel是否处于这种状态。通过调用pause()方法可以使通道处于暂停状态,此状态可以通过isPaused()方法判别。当通道被暂停时,有三种选择:保留数据(缺省),用flush()方法丢弃内部缓冲器中的数据,或用drain()方法使内部缓存中的数据被立即处理。
对象事先可以注册,这样每当通道状态改变时它都可以收到通告信息。该注册对象必须实现Channel.Listener界面,该界面仅包含一个方法update()。当Channel打开、结束、启动、及停止时,该方法都将被调用。当Channel开始或停止活动以及开始或停止捕获数据时,会产生start或stop事件。
输入通道
InputChannel是被捕获的音频数据的源头。该界面提供了方法,可从 InputChannel缓冲器读取被捕获的数据,并判断当前可读的数据量。如果应用程序试图读过多的数据,该读方法阻塞,直到所需读取数据达到为止。 
输出通道
OutputChannel接收用于播放的音频数据。这接口提供方法,将要播放的数据写入OutputChannel的缓冲区,并能判断该通道不间断可接收的数据量。如果应用程序试图写过量的数据,该读方法阻塞,直到有足够数据为止。 
剪贴
Clip接口表示一个特殊的通道,它可以在播放之前先装入音频数据。由于数据是预装入的,而不是流入的,所以clip可以支持持续查询、循环播放、以及重新定位播放。 
设备
Device界面为表示音频设备的类提供方法。音频设备可以是共享的也可是独占的系统资源,它可以是基于硬件的,也可基于软件的,还可是同时基于两者的。它能被重复地打开和关闭,它能时常说明它的内在特性及支持的音频格式。同时,它也提供信息对象来描述设备。
JAVA声音 API进一步描述三种设备子界面:
InputDevice
nputDevice界面提供一个方法getInputChannel来获得一个InputChannel对象,从中捕获可读的音频数据。
OutputDevice
OutputDevice界面提供一个方法getOutputChannel来获得一个OutputChannel对象,音频数据可以写入该输出通道,并予播放。
Mixer
Mixer支持多个InputChannel和/或Clip。 另外,它提供了查询方法,从中可得到它所支持的通道数量,它也提供了支持同步暂停和唤醒多个通道播放的方法。
控件
通道和音频端口 (比如扬声器和麦克风)一般能支持一组控件比如增益和定位。通过将它的类作为参数传给getControl()方法,JAVA声音 API的通道对象和端口对象可以获得一个特别的控件。
编码器
Codecs可以对音频数据编码和解码,允许在不同格式和编码之间转换。JAVA声音 API通过AudioSystem类中的方法为这些转换提供了高级接口。如果给了一个特殊的音频流,应用程序会查询音频系统来找到相应的转换,从而得到指定格式的音频流。
文件和流
音频流是与音频数据格式和数据长度相关的输入流,文件流是与文件类型和数据长度相关的输入流。JAVA声音 API在AudioSystem类中为音频文件和音频流之间的转换提供了接口。
查询和访问安装组件
AudioSystem类充当到采样音频系统资源入口的角色。该类允许程序员查询和访问输入设备、输出设备以及安装好的混音设备。另外,AudioSystem包含许多在不同音频数据格式间转换的方法。它也提供一些方法,使得在不需要对设备直接操作的情况下,直接获得输入通道或输出通道。
系统配置-服务提供者界面(SPI)
对采样音频系统的配置是由javax.media.sound.sampled.spi包来完成的。通过 AudioConfig类的方法,可以在系统中安装或卸载设备,并且可以建立起缺省状态。服务提供者可以希望提供和安装他们自己的编码器和分析器。这个包提供了完成这种功能的机制。
下面是两个综合性说明的例子程序:
程序一:
import java.io.*; 
import javax.sound.sampled.*; 
import java.net.*; 
/** 
* Title:        VoiceChat 
* Description:  输出音频(放音程序)
* Copyright:    Copyright (c) 2001 
* Company: 
* @author       你猜!
* @version 1.0 
*/ 
class Playback implements Runnable 
         { 
                 final int bufSize = 16384; 
                 SourceDataLine line; 
                 Thread thread; 
                 Socket s; 
                 Playback(Socket s){//构造器 取得socket以获得网络输入流
                 this.s=s; 
        } 
       public void start() { 
           thread = new Thread(this); 
           thread.setName("Playback"); 
           thread.start(); 
       } 
       public void stop() { 
           thread = null; 
       } 
       public void run() { 
           AudioFormat format =new AudioFormat(8000,16,2,true,true);//AudioFormat(float sampleRate, int sampleSizeInBits, int channels, boolean signed, boolean bigEndian
           BufferedInputStream playbackInputStream; 
           try { 
             playbackInputStream=new BufferedInputStream(new AudioInputStream(s.getInputStream(),format,2147483647));//封装成音频输出流,如果网络流是经过压缩的需在此加套解压流
           } 
           catch (IOException ex) { 
               return; 
           } 
           DataLine.Info info = new DataLine.Info(SourceDataLine.class,format); 
           try { 
               line = (SourceDataLine) AudioSystem.getLine(info); 
               line.open(format, bufSize); 
           } catch (LineUnavailableException ex) { 
               return; 
           } 
           byte[] data = new byte[1024];//此处数组的大小跟实时性关系不大,可根据情况进行调整
           int numBytesRead = 0; 
           line.start(); 
           while (thread != null) { 
              try{ 
                 numBytesRead = playbackInputStream.read(data); 
                 line.write(data, 0,numBytesRead); 
              } catch (IOException e) { 
                   break; 
               } 
           } 
           if (thread != null) { 
               line.drain(); 
           } 
           line.stop(); 
           line.close(); 
           line = null; 
       } 
} 
程序二:
import java.io.*; 
import javax.sound.sampled.*; 
import java.net.*; 
/** 
* Title:        VoiceChat 
* Description:  音频捕捉(录音程序)
* Copyright:    Copyright (c) 2001 
* Company: 
* @author       你猜!
* @version 1.0 
*/ 
class Capture implements Runnable { 
       TargetDataLine line; 
       Thread thread; 
       Socket s; 
       BufferedOutputStream captrueOutputStream; 
       Capture(Socket s){//构造器 取得socket以获得网络输出流
         this.s=s; 
       }
       public void start() { 
           thread = new Thread(this); 
           thread.setName("Capture"); 
           thread.start(); 
       } 
       public void stop() { 
           thread = null; 
       } 
       public void run() { 
           try { 
             captrueOutputStream=new BufferedOutputStream(s.getOutputStream());//建立输出流 此处可以加套压缩流用来压缩数据
           } 
           catch (IOException ex) { 
               return; 
           } 
           AudioFormat format =new AudioFormat(8000,16,2,true,true);//AudioFormat(float sampleRate, int sampleSizeInBits, int channels, boolean signed, boolean bigEndian
           DataLine.Info info = new DataLine.Info(TargetDataLine.class,format); 
           try { 
               line = (TargetDataLine) AudioSystem.getLine(info); 
               line.open(format, line.getBufferSize()); 
           } catch (Exception ex) { 
               return; 
           } 
           byte[] data = new byte[1024];//此处的1024可以情况进行调整,应跟下面的1024应保持一致
           int numBytesRead=0; 
           line.start(); 
           while (thread != null) { 
               numBytesRead = line.read(data, 0,1024);//取数据(1024)的大小直接关系到传输的速度,一般越小越快,
               try { 
                 captrueOutputStream.write(data, 0, numBytesRead);//写入网络流
               } 
               catch (Exception ex) { 
                   break; 
               } 
           } 
           line.stop(); 
           line.close(); 
           line = null; 
           try { 
               captrueOutputStream.flush(); 
               captrueOutputStream.close(); 
           } catch (IOException ex) { 
               ex.printStackTrace(); 
           } 
       } 
}
 
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值