多人语言聊天以及多人视频聊天
客户端实现语音的采样并发送,同时接收服务器发来的语音数据并播放
代码如下:
public class Audioclient
{@SuppressWarnings({ "unused", "resource", "static-access" })
public static void recordAndRecieveMicrophone(String INET_ADDRESS, int INET_PORT,int FRAME_RATE) throws InterruptedException, LineUnavailableException, UnknownHostException, IOException {Socket socket = new Socket(INET_ADDRESS, INET_PORT);AudioInfo audioInfo=new AudioInfo(new AudioFormat(44100.0F, 16, 2, true, false));audioInfo.writestart();if(socket.isConnected()) {//server端使用readline来获取唯一标识符String uuid = UUID.randomUUID().toString().replaceAll("-", "")+'\n';OutputStream outputstream=socket.getOutputStream();outputstream.write(uuid.getBytes());System.out.println(uuid);}new Thread(new Runnable() {@Overridepublic void run() {ScheduledThreadPoolExecutor exec = new ScheduledThreadPoolExecutor(1);exec.scheduleAtFixedRate(new Runnable() {@Overridepublic void run() {try {audioInfo.write(socket);} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}, 0, (long) 1000 / FRAME_RATE, TimeUnit.MILLISECONDS);}}).start();AudioInfo audioRead=new AudioInfo(new AudioFormat(44100.0F, 16, 2, true, false));audioRead.readstart();new Thread(new Runnable() {@Overridepublic void run() {ScheduledThreadPoolExecutor exec = new ScheduledThreadPoolExecutor(1);exec.scheduleAtFixedRate(new Runnable() {@Overridepublic void run() {byte[] buffer=new byte[1024];InputStream is = null;try {is = socket.getInputStream();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}int size=0;while(true) {int ss1;try {is.read(buffer);audioRead.read(buffer);} catch (IOException e) {// TODO Auto-generated catch blockSystem.out.println("读取错误");}}}}, 0, (long) 1000 / FRAME_RATE, TimeUnit.MILLISECONDS);}}).start();
}
}
为方便后期更改添加编码封装方法,将语音的发送提取出来
public class AudioInfo {AudioFormat audioFormat;SourceDataLine line;ByteBuffer outBuffer;final int AUDIO_DEVICE_INDEX=4;byte[] audioBytes;TargetDataLine recordLine;public int length;public AudioInfo(AudioFormat audioFormat1) {this.audioFormat=audioFormat1;this.length=(int) (audioFormat.getSampleRate()*audioFormat.getChannels());}@SuppressWarnings("unused")public void readstart() throws LineUnavailableException {final DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat);final SourceDataLine soundLine = (SourceDataLine) AudioSystem.getLine(info);soundLine.open(audioFormat);soundLine.start();this.line=soundLine; }public void writestart() throws LineUnavailableException {DataLine.Info dataLineInfo = new DataLine.Info(TargetDataLine.class, audioFormat);TargetDataLine sline = (TargetDataLine) AudioSystem.getLine(dataLineInfo);sline.open(audioFormat);sline.start();this.recordLine=sline;this.audioBytes=new byte[this.length];}public void stop() {if(line!=null)line.close();if(recordLine!=null)recordLine.close();}public void read(byte[] samples) {outBuffer = ByteBuffer.wrap(samples);line.write(outBuffer.array(), 0, outBuffer.capacity());outBuffer.clear();}/** 把缓冲区中的音频数据通过套接字发出去*/public void write(Socket s) throws IOException {int nBytesRead = recordLine.read(audioBytes, 0, recordLine.available());//16位音频格式,需要将byte[]转成short[]int nSamplesRead = nBytesRead / 2;short[] samples = new short[nSamplesRead];ByteBuffer.wrap(audioBytes).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(samples);ShortBuffer sBuff = ShortBuffer.wrap(samples, 0, nSamplesRead);OutputStream outputstream=s.getOutputStream();byte[] simples=new byte[nBytesRead];ByteBuffer.wrap(simples).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().put(sBuff.array());outputstream.write(simples);}
}
同时,要想实现排己性的语音转发,需要服务器拥有套接字的唯一标识
import java.net.Socket;public class OnlySocket{public Socket socket;public String uuid;public OnlySocket(Socket s, String uuid) {this.socket=s;this.uuid=uuid;}public Socket getSocket() {return socket;}public String getUUid() {return uuid;}
}
sever端
public class pushAndpoll {static int i=0;private static Set<OnlySocket> clientList=new HashSet<>();@SuppressWarnings({ "resource", "null" })public static void main(String[] args) throws IOException, LineUnavailableException {ExecutorService es=Executors.newFixedThreadPool(40);ServerSocket ss = null;try {ss=new ServerSocket(5000);} catch (IOException e) {// TODO Auto-generated catch blockSystem.out.println("服务器启动失败");}if(ss!=null) {System.out.println("服务器已启动");System.out.println(ss.getLocalSocketAddress());}while(true) {Socket s=ss.accept();if(s!=null) {System.out.println((++i)+"个客户端链接");InputStream inStream = s.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(inStream));String uuid=reader.readLine();OnlySocket onlysocket=new OnlySocket(s,uuid); clientList.add(onlysocket);System.out.println(onlysocket.uuid);es.execute(receive(onlysocket));}}}@SuppressWarnings("unused")private static Runnable receive(final OnlySocket s) throws LineUnavailableException, UnknownHostException, IOException {AudioInfo audioInfo=new AudioInfo(new AudioFormat(44100.0F, 16, 2, true, false));return new Runnable() {@Overridepublic void run() {BufferedInputStream infile;BufferedOutputStream outfile;try {infile = new BufferedInputStream(s.socket.getInputStream());for(OnlySocket onlysocket:clientList) {if(onlysocket!=null && onlysocket.uuid !=s.uuid) {outfile = new BufferedOutputStream(onlysocket.socket.getOutputStream());byte[] b = new byte[1024];int i;i = infile.read(b);while (i!=-1) {outfile.write(b, 0, i);outfile.flush();i = infile.read(b);}outfile.flush();}}} catch (IOException e) {// TODO Auto-generated catch blocSystem.exit(1);}}};}
}
关于视频的推流编码封装拉流解码 在javacv的仓库上有很多demo,这里不再分享 ,其中有几点浅薄的经验想与大家分享,目前有三种主流流媒体服务协议,分别为rtmp,rtsp以及HLS。其中,我所用过rtmp以及HLS。
nginx加rtmp插件形成的流媒体服务器
支持直播流转HLS,rtmp点播,rtmp直播:其中根据我的多次尝试,如果在虚拟机建构服务器的前提下,通过内网穿透,有一定几率(直播的情况下)直流会直接断开,由于多次调试和查询无果,以至于一度放弃。在成功拉到流的前提下,(rtmp直播 仅开启live选项)延迟为6.7秒,或许是rtmp插件的缓存问题,但nginx的反向代理及负载均衡功能确实很强大。
SRS 简单的rtmp服务器
同样支持上述的功能,不过不存在,由于帧的丢失导致直流的断开情况,很稳定且快速,且为阿里的开源项目,中文文档全面。
RTMP协议下的拉流推流,由本地内网穿透到杭州的服务器,再穿透回来,时间约为3.4秒,与nginx-rtmp约两倍的差距。
尝试通过socket分别传输图像与语音,创建自己的私有协议
语音的编码与传输很快能够通过,然而到图像时,虽然能够拉到流,但是由于javacv的蹩脚,或许是我不够熟练,无法进行更一步的优化,在本地运行服务器,端口转发也会出现闪屏的现象,更别说网络服务器了。
查询调试后发现,原来我发的是一张张图片,也就是i帧,通过javacv的现有的编码器仅能发送推流给rtmp或者本地路径,于是放弃了。。。。后续打算通过c++深入底层,尝试实现私有协议的服务器。
RTMP本质上是将音频封装为flv,这也是flash能够播发rtmp链接的原因,发的是一小段一小段的flv。
HLS本质上是一个目录包含每一个切片,一个切片为一个短小的播放文件,自然播放文件越小,推流就越快,但如果过于小,就会导致解码时间比一个视频播放时间要长,可能会导致缓存区的覆盖,这时就需要设置好缓冲区。
关于文件以及黏包的现象,就可以进行切片,对于文件的中断传输与开始传输可以定义发送关键帧,以及通过MD5效验。
多人语言聊天以及多人视频聊天相关推荐
- 基于web视频聊天技术归纳
本文转载于http://zhidao.baidu.com/link?url=brsWhD7CoFno5-Lojb-lpz7Vc8VeD6WPI_4Eh5cWnVdfYRUJoIGCyYCzO_J3tx ...
- 视频聊天网站的研究、发展以及趋势时间
摘要: 此文讲述了视频聊天网站相关的技术.发展过程以及未来的发展趋势.我长时间从事外包业务开发和技术开发的,从客户那里了解到了很多的视频聊天网站相关的需求,经过自己长时间对视频聊天网站运营模式.盈利模 ...
- 【转帖】视频聊天网站的研究、发展以及趋势
摘要: 此文讲述了视频聊天网站相关的技术.发展过程以及未来的发展趋势.我长时间从事外包业务开发和技术开发的,从客户那里了解到了很多的视频聊天网站相关的需求,经过自己长时间对视频聊天网站运营模式.盈利模 ...
- 视频聊天网站的技术与发展
视频聊天网站的技术与发展 摘要: 此文讲述了视频聊天网站相关的技术.发展过程.从客户那里了解到了很多的视频聊天相关的需求,经过自己长时间对视频聊天网站运营模式.盈利模式.系统架构以及相关技术的研究,写 ...
- 视频聊天网站的研究、发展以及趋势
摘要: 此文讲述了视频聊天网站相关的技术.发展过程以及未来的发展趋势.我长时间从事外包业务开发和技术开发的,从客户那里了解到了很多的视频聊天网站相关的需求,经过自己长时间对视频聊天网站运营模式.盈利模 ...
- 视频聊天网站的研究、发展以及趋势(转)
此文讲述了视频聊天网站相关的技术.发展过程以及未来的发展趋势.我长时间从事外包业务开发和技术开发的,从客户那里了解到了很多的视频聊天网站相关的需求,经过自己长时间对视频聊天网站运营模式.盈利模式.系统 ...
- 类似51vv视频聊天室方案建设
一.前言 1.类似新浪视频聊天室和呱呱视频聊天室,99CU等体现方式,聊天大厅和聊天房间能够自主切换. 2. 数据库最好运用MS SQL,代码模块化开拓,有充足的扩大性以及接口,二次开拓更简单. 3. ...
- 视频聊天软件的技术实现
社会经济的发展使得人民生活水平不断提高,越来月注重精神享受.而科技的发展新媒体和自媒体的突飞猛进,给人们的生活带来了便利.网络视频聊天娱乐就是在这种蓬勃发展的互联网市场经济下的产物,也是现代更多草根通 ...
- 视频聊天开发参考资料
本文阐述视频聊天网站相关的技术.发展过程以及未来的发展趋势.我长时间从事外包业务开发和技术开发的,从客户那里了解到了很多的视频聊天网站相关的需求,经过自己长时间对视频聊天网站运营模式.盈利模式.系统架 ...
- 【教程】使用腾讯云轻量应用服务器搭建Mirotalk,让自己拥有一个视频聊天、屏幕共享平台!
前言 现在这个时代,个人不论小白还是大佬,搭建网站都有许多方法与平台,但是在服务器的选择上,当然是本文的主角:腾讯云轻量应用服务器更具性价比,为什么?下面准备工作一一为你介绍,所以今天,小俊继续给大家 ...
最新文章
- [置顶] 强大的jquery选择器
- C语言回调函数Demo - Win32版
- jQuery validate表单验证demo
- 实验计算机控制器的实验结论,计算机毕业论文控制器实验报告.doc
- 【转载】C#使用is关键字检查对象是否与给定类型兼容
- nginx同一域名下部署多个vue项目
- 拉普拉斯变换学习笔记
- MSDTC报错怎么破
- 计算机鼠标没有安装驱动,鼠标动不了怎么安装驱动_电脑鼠标不能动怎么安装驱动...
- 王阳明:志不立,天下无可成之事
- 1468. 计算税后工资
- 四种常用的ps抠图方法
- diskgenius linux 分区,DiskGenius怎么分区,DiskGenius分区教程
- ICPC 2018 焦作 C题 Supreme Command
- dellr710服务器(DellR710服务器做完raid安装系统找不到磁盘)
- 数字通信中为什么需要时钟线
- pyinstaller打包前后os.path.abspath(__file__)和os.path.realpath(sys.executable)的区别
- mysql is双竖线_MySQL 5.0 新特性教程 存储过程:第二讲
- CSS floats来创建三栏网页布局的方法
- android系统日志如何查看,Android如何查看系统recovery日志,从而找到系统程序、刷机异常…...