客户端实现语音的采样并发送,同时接收服务器发来的语音数据并播放

代码如下:

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效验。

多人语言聊天以及多人视频聊天相关推荐

  1. 基于web视频聊天技术归纳

    本文转载于http://zhidao.baidu.com/link?url=brsWhD7CoFno5-Lojb-lpz7Vc8VeD6WPI_4Eh5cWnVdfYRUJoIGCyYCzO_J3tx ...

  2. 视频聊天网站的研究、发展以及趋势时间

    摘要: 此文讲述了视频聊天网站相关的技术.发展过程以及未来的发展趋势.我长时间从事外包业务开发和技术开发的,从客户那里了解到了很多的视频聊天网站相关的需求,经过自己长时间对视频聊天网站运营模式.盈利模 ...

  3. 【转帖】视频聊天网站的研究、发展以及趋势

    摘要: 此文讲述了视频聊天网站相关的技术.发展过程以及未来的发展趋势.我长时间从事外包业务开发和技术开发的,从客户那里了解到了很多的视频聊天网站相关的需求,经过自己长时间对视频聊天网站运营模式.盈利模 ...

  4. 视频聊天网站的技术与发展

    视频聊天网站的技术与发展 摘要: 此文讲述了视频聊天网站相关的技术.发展过程.从客户那里了解到了很多的视频聊天相关的需求,经过自己长时间对视频聊天网站运营模式.盈利模式.系统架构以及相关技术的研究,写 ...

  5. 视频聊天网站的研究、发展以及趋势

    摘要: 此文讲述了视频聊天网站相关的技术.发展过程以及未来的发展趋势.我长时间从事外包业务开发和技术开发的,从客户那里了解到了很多的视频聊天网站相关的需求,经过自己长时间对视频聊天网站运营模式.盈利模 ...

  6. 视频聊天网站的研究、发展以及趋势(转)

    此文讲述了视频聊天网站相关的技术.发展过程以及未来的发展趋势.我长时间从事外包业务开发和技术开发的,从客户那里了解到了很多的视频聊天网站相关的需求,经过自己长时间对视频聊天网站运营模式.盈利模式.系统 ...

  7. 类似51vv视频聊天室方案建设

    一.前言 1.类似新浪视频聊天室和呱呱视频聊天室,99CU等体现方式,聊天大厅和聊天房间能够自主切换. 2. 数据库最好运用MS SQL,代码模块化开拓,有充足的扩大性以及接口,二次开拓更简单. 3. ...

  8. 视频聊天软件的技术实现

    社会经济的发展使得人民生活水平不断提高,越来月注重精神享受.而科技的发展新媒体和自媒体的突飞猛进,给人们的生活带来了便利.网络视频聊天娱乐就是在这种蓬勃发展的互联网市场经济下的产物,也是现代更多草根通 ...

  9. 视频聊天开发参考资料

    本文阐述视频聊天网站相关的技术.发展过程以及未来的发展趋势.我长时间从事外包业务开发和技术开发的,从客户那里了解到了很多的视频聊天网站相关的需求,经过自己长时间对视频聊天网站运营模式.盈利模式.系统架 ...

  10. 【教程】使用腾讯云轻量应用服务器搭建Mirotalk,让自己拥有一个视频聊天、屏幕共享平台!

    前言 现在这个时代,个人不论小白还是大佬,搭建网站都有许多方法与平台,但是在服务器的选择上,当然是本文的主角:腾讯云轻量应用服务器更具性价比,为什么?下面准备工作一一为你介绍,所以今天,小俊继续给大家 ...

最新文章

  1. 【每日一算法】独特的电子邮件地址
  2. 配置 Spring.NET
  3. QT的QAccessibleEvent类的使用
  4. 大型分布式存储方案MinIO介绍,看完你就懂了!
  5. OpenCV3学习(4.3)——图像形态学(膨胀,腐蚀)
  6. 冰冰讲数学鸿蒙团队4年级,冰冰也曾是水肿星人?3分钟急救方案教你甩掉晨间浮肿脸!...
  7. Centos安装Kafka集群
  8. php 显示外链图片,php绘图之加载外部图片的方法
  9. PAT-A1025 PAT Ranking
  10. C语言笔记(谭浩强)
  11. 安卓 实现一个简单的计算器
  12. Linux基础命令之cd返回上级目录/返回根目录/进目录/返回上一次目录/返回指定目录
  13. Terraria泰拉瑞亚服务器搭建
  14. SpringBoot中通过接口下载resources下的文件
  15. Web全栈~26.IO
  16. 大一微积分笔记整理_如何学好高等数学,尤其是大一的极限、微积分?
  17. SSD学习系列(二)LMDB概念以及将VOC数据集转换成LMDB格式
  18. Docker常用命令和实战演练
  19. FreeRTOS-ARM架构深入理解
  20. Oracle 11g安装使用、备份恢复并与SpringBoot集成

热门文章

  1. matlab carcasonne,米迪运河.ppt
  2. Goroutine 并发调度模型深度解析之手撸一个高性能 goroutine 池
  3. 70+个NLP语料库数据集
  4. 斐讯智能电视盒子P1刷Armbian系统的简单教程
  5. 作为程序猿要多注意身体(华佗教你睡觉)
  6. 最近,帮一个学生做了一个毕业设计
  7. 诡异的Connection reset
  8. NestedTensor(DETR)
  9. 01、NRF52832介绍功耗、射频参数、芯片处理能力、内存和支持协议详解
  10. ITK 数据表达(图像)