程序写了两个线程,一个用于录制AudioRecordThread,一个用于播放AudioTrackThread.
(一)录制与发送
@Override
public void run() {
if (mSocket == null)
return
try {
mStartTime = System.currentTimeMillis()
audioRec.startRecording()
while (flag) {
try {
byte[] bytes_pkg = buffer.clone()
if (mRecordQueue.size() >= 2) {
int length = audioRec.read(buffer, 0, minBufferSize)
//获取音量大小
mVolume = getAudioColum(buffer)
System.out.println(TAG + "= " + mVolume)
Message message = mHandler.obtainMessage()
message.arg1 = (int) mVolume
mHandler.sendMessage(message)
DatagramPacket writePacket
InetAddress inet = InetAddress.getByName(inetAddressName)
writePacket = new DatagramPacket(buffer, length, inet, PORT)
writePacket.setLength(length)
System.out.println("AudioRTwritePacket = " + writePacket.getData().toString())
mSocket.send(writePacket)
}
mRecordQueue.add(bytes_pkg)
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace()
}
}
audioRec.stop()
} catch (Exception e) {
e.printStackTrace()
}
}
里面包含了获取音量大小,便于在页面上面展示,方法参考了 点击打开链接
private double getAudioColum(byte[] buffer) {
double sumVolume = 0.0
double avgVolume = 0.0
double volume = 0.0
for (int i = 0i <buffer.lengthi += 2) {
int v1 = buffer[i] &0xFF
int v2 = buffer[i + 1] &0xFF
int temp = v1 + (v2 <<8)// 小端
if (temp >= 0x8000) {
temp = 0xffff - temp
}
sumVolume += Math.abs(temp)
}
avgVolume = sumVolume / buffer.length / 2
volume = Math.log10(1 + avgVolume) * 10
return volume
}
(二)接收与播放
@Override
public void run() {
if (mSocket == null)
return
audioTrk.play()
while (flag) {
DatagramPacket recevPacket
try {
recevPacket = new DatagramPacket(buffer, 0, buffer.length)
mSocket.receive(recevPacket)
audioTrk.write(recevPacket.getData(), 0, recevPacket.getLength())
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace()
}
}
audioTrk.stop()
}
(三)主页面 接收按钮事件
@OnClick({R.id.btn_receive})
public void onViewClicked(View view) {
switch (view.getId()) {
case R.id.btn_receive:
if (btnReceive.getText().toString().equals("开始接收")) {
btnReceive.setText("停止接收")
try {
if (audioTrackThread == null) {
audioTrackThread = new AudioTrackThread()
}
new Thread(audioTrackThread).start()
} catch (SocketException e) {
e.printStackTrace()
}
} else {
btnReceive.setText("开始接收")
audioTrackThread.setFlag(false)
}
break
}
}
(四)发送按钮事件
ivSpeak.setOnTouchListener(new View.OnTouchListener() {
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//按下按钮开始录制
ivSpeak.setText("正在说话")
//显示录音提示
relativeLayout.setVisibility(View.VISIBLE)
try {
if (audioRecordThread == null) {
audioRecordThread = new AudioRecordThread(handler)
}
audioRecordThread.setInetAddressName(tvReceiveIp.getText().toString())
audioRecordThread.setFlag(true)
new Thread(audioRecordThread).start()
} catch (SocketException e) {
e.printStackTrace()
}
break
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
//松开按钮结束录制
ivSpeak.setText("按住说话")
relativeLayout.setVisibility(View.GONE)
audioRecordThread.setFlag(false)
mStopTime = audioRecordThread.getmStopTime()
mStartTime = audioRecordThread.getmStartTime()
creatMessageBean((mStopTime - mStartTime) / 1000, true)
break
}
return true
}
})
能语音聊天的软件有:1、《YY》语音聊天软件的鼻祖,上线以来一直深受用户的喜爱。在软件里面有很多的聊天室,用户可以随机加入别人的聊天室,抢麦序唱歌聊天,玩法丰富。
2、《IS语音》视频互动软件,可以看视频也可以聊语音,帮助用户释放自己的激情。聊天室多种玩法,唱歌PK还是打视频PK都可以,PK主题由用户自己决定。
3、《久久语音》在平台上有很多的语音怪,她们声音好听个性十足,有萝莉音也有御姐音,你喜欢的声音里面都有,即时语音传输让大家用声音交友,用真情互动。
4、《耳旁语音》真人在线聊天,平台保证用户的资料都是真实的,语音聊天让用户处CP更加简单,支持多人同步语音,点唱功能还可以指定喜欢的声音来唱歌。
5、《以陌语音》不想打字的用户可以试一试这款聊天软件,在平台上大家都有机会找到一起聊天伙伴,甚至是心仪的对象,多人聊天让用户不在尴尬,不担心没有话题可以聊。
6、《小恩爱》非常适合情侣用户的专属聊天软件,两个人一起在软件上建立爱的小屋,通过连麦来玩游戏,越玩感情越深,异地情侣也可以因为即时的语音聊天感觉近在咫尺。
7、《探探》更加新潮的交友方式,滑动卡片就能匹配到心仪的聊天对象,如果匹配不成功的话是不能开展聊天的,所以大家可以放心自己会被陌生人打扰的问题。
传输语音和文件都可以通过Mswinsock 实现,只是速度方面我没有试过,我正巧最近也弄了点Mswinsock 相关的东西,代码发给你看看,希望有帮助传送文件对于网络编程来说是基本的功能,比如远程控制软件。在编制一个软件时,我从网上下了很多传文件的程序,这些程序提供的传文件功能根本就不能用。传文本还可以,传二进制文件根本就不行。因此,作为一个基本的功能模块,有必要单独介绍一下。
首先,在VB中要传送字符串,你可以这样写:
Dim strData As String
strData = "Test"
Winsock1.SendData strData
但是如果你传送的二进制文件,你还能用String变量来存放吗?从理论上分析是不行的,我也做了实验,确实是不行的。文件虽然可以传,但是接受的文件和发送的不一样,原因可能是二进制文件里可以有任何"字符",但是不是所有的字符都可以放在String变量里。
除了String类型的变量,VB中其他类型的变量都只有几个字节长,难道一次只能发几个字节吗?那样岂不是要累死机器了!其实,情况没有那么悲观,我们完全可以使用数组来解决这个问题,就是使用byte数组。把要传送的文件都读到数组里,然后发送出去。程序如下:
FileName 为要传送的文件名,WinS为发送文件的WinSock控件。这是一个发送端的程序。
Public Sub SendFile(FileName As String, WinS As Winsock)
Dim FreeF As Integer ''空闲的文件号
Dim LenFile As Long ''文件的长度
Dim bytData() As Byte ''存放数据的数组
FreeF = FreeFile ''获得空闲的文件号
Open FileName For Binary As #FreeFile ''打开文件
DoEvents
LenFile = LOF(FreeFile) ''获得文件长度
ReDim bytData(1 To LenFile) ''根据文件长度重新定义数组大小
Get #FreeFile, , bytData ''把文件读入到数组里
Close #FreeFile ''关闭文件
WinS.SendData bytData ''发送数据
End Sub
接受端的程序如下:
Private Sub Winsock1_DataArrival(ByVal bytesTotal As Long)
Dim bytData() As Byte
Dim f
f = FreeFile
Open strFileName For Binary As #f
ReDim bytData(1 To bytesTotal)
Winsock1.GetData bytData
Put #f, i, bytData
i = i + bytesTotal ''保证每次写都是在文件的末尾, i是个全局变量
Close #f
End Sub
这里有两个需要注意的地方,ReDim Preserve bytData(1 To LenFile),下标是从1开始的,如果你写成ReDim bytData( LenFile),下标就是从0开始了,数组就有LenFile+1长了。LenFile = LOF(FreeFile)中的LOF是获得文件长度的函数,是VB里带的,我见过很多例子用API,或者循环的读直到末尾来获取文件长度,这样都是很麻烦的,使用LOF函数就可以了。
这样的程序,即可以传送文本文件,也可以传送二进制文件。但是你有没有发现这个程序的问题呢?如果我要传送一个50M的文件呢?系统可以为bytData分配50M的内存空间吗?
于是笔者拿一个50M的文件做实验吧,接收到的文件和原来的文件不一样,比原来的大。问题出在那呢?
首先,根据文件大小重新定义bytData数组的大小本身就有问题,系统是不可能无限制的给数组分配空间的,即使可以,也会造成系统响应变慢。在传50M文件的时候,系统就跟死机了一样。那么怎么解决这个问题呢,一个自然的想法就是把数据分段传送。程序如下:
发送程序, iPos是个全局变量,初始值为0。这个变量保存着当前数据的位置。Const iMax = 65535是每个数据块的大小。
Dim FreeF As Integer ''空闲的文件号
Dim LenFile As Long ''文件的长度
Dim bytData() As Byte ''存放数据的数组
FreeF = FreeFile ''获得空闲的文件号
Open FileName For Binary As #FreeF ''打开文件
DoEvents
LenFile = LOF(FreeF) ''获得文件长度
If LenFile <= iMax Then ''如果要发送的文件小于数据块大小,直接发送
ReDim bytData(1 To LenFile) ''根据文件长度重新定义数组大小
Get #FreeF, , bytData ''把文件读入到数组里
Close #FreeF ''关闭文件
WinS.SendData bytData ''发送数据
Exit Sub
End If
''文件大于数据块大小,进行分块发送
Do Until (iPos >= (LenFile - iMax)) ''发送整块数据的循环
ReDim bytData(1 To iMax)
Get #FreeF, iPos + 1, bytData
WinS.SendData bytData
iPos = iPos + iMax ''移动iPos,使它指向下来要读的数据
Loop
''这里要注意的是,必须检查文件有没有剩下的数据,如果文件大小正好等于数据块大小的
'' 整数倍,那么就没有剩下的数据了
ReDim bytData(1 To LenFile - iPos) ''发送剩下的不够一个数据块的数据
Get #FreeF, iPos + 1, bytData
WinS.SendData bytData
Close #FreeF
下面是接收端的程序:
Private Sub Winsock1_DataArrival(ByVal bytesTotal As Long)
Dim bytData() As Byte
Dim lLenFile As Long
Dim f
f = FreeFile
Open strFileName For Binary As #f ''strFileName是文件名
lLenFile = LOF(f)
ReDim bytData(1 To bytesTotal)
Winsock1.GetData bytData
If lLenFile = 0 Then ''lLenFile=0表示是第一次打开文件,这里有个问题,就是''如果如果该文件存在的话,就会出错,应该在打开前检查文件是否存在。(这里我省略了)
Put #f, 1, bytData
Else
Put #f, lLenFile + 1, bytData
End If
Close #f
End Sub
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)