我有一个android活动,它连接到一个java类,并以套接字的形式向它发送数据包。该课程接收声音包并将其扔给PC扬声器。代码运行良好,但在PC扬声器中播放声音时,会出现持续的抖动/中断。
android活动:
public class SendActivity extends Activity {
private Button startButton, stopButton;
public byte[] buffer;
public static DatagramSocket socket;
private int port = 50005;
AudioRecord recorder;
private int sampleRate = 8000;
@SuppressWarnings("deprecation")
private int channelConfig = AudioFormat.CHANNEL_IN_MONO;
private int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
int minBufSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig,
audioFormat);
private boolean status = true;
int bufferSizeInBytes;
int bufferSizeInShorts;
int shortsRead;
short audioBuffer[];
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_send);
startButton = (Button) findViewById(R.id.start_button);
stopButton = (Button) findViewById(R.id.stop_button);
startButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
status = true;
startStreaming();
}
});
stopButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
status = false;
recorder.release();
Log.d("VS", "Recorder released");
}
});
minBufSize += 5120;
System.out.println("minBufSize: " + minBufSize);
}
public void startStreaming() {
Thread streamThread = new Thread(new Runnable() {
@Override
public void run() {
try {
DatagramSocket socket = new DatagramSocket();
Log.d("VS", "Socket Created");
byte[] buffer = new byte[minBufSize];
Log.d("VS", "Buffer created of size " + minBufSize);
DatagramPacket packet;
//machine's IP
final InetAddress destination = InetAddress
.getByName("192.168.1.20");
Log.d("VS", "Address retrieved");
recorder = new AudioRecord(MediaRecorder.AudioSource.VOICE_RECOGNITION,
sampleRate, channelConfig, audioFormat,
minBufSize * 10);
Log.d("VS", "Recorder initialized");
recorder.startRecording();
while (status == true) {
// reading data from MIC into buffer
minBufSize = recorder.read(buffer, 0, buffer.length);
// putting buffer in the packet
packet = new DatagramPacket(buffer, buffer.length,
destination, port);
socket.send(packet);
System.out.println("MinBufferSize: " + minBufSize);
}
} catch (UnknownHostException e) {
Log.e("VS", "UnknownHostException");
} catch (IOException e) {
e.printStackTrace();
Log.e("VS", "IOException");
}
}
});
streamThread.start();
}
}
android布局:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".SendActivity" >
<Button
android:id="@+id/stop_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@+id/start_button"
android:layout_alignBottom="@+id/start_button"
android:layout_toRightOf="@+id/start_button"
android:text="Stop" />
<Button
android:id="@+id/start_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="79dp"
android:layout_marginTop="163dp"
android:text="Start" />
</RelativeLayout>
Android清单:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.audiostreamsample"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" >
</uses-permission>
<uses-permission android:name="android.permission.INTERNET" >
</uses-permission>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" >
</uses-permission>
<uses-permission android:name="android.permission.READ_PHONE_STATE" >
</uses-permission>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.audiostreamsample.SendActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
要接收数据包并将其发送到PC扬声器的类:
class Server {
AudioInputStream audioInputStream;
static AudioInputStream ais;
static AudioFormat format;
static boolean status = true;
static int port = 50005;
static int sampleRate = 8000;
public static void main(String args[]) throws Exception {
DatagramSocket serverSocket = new DatagramSocket(50005);
/**
* Formula for lag = (byte_size/sample_rate)*2
* Byte size 9728 will produce ~ 0.45 seconds of lag. Voice slightly broken.
* Byte size 1400 will produce ~ 0.06 seconds of lag. Voice extremely broken.
* Byte size 4000 will produce ~ 0.18 seconds of lag. Voice slightly more broken then 9728.
*/
byte[] receiveData = new byte[5000];
format = new AudioFormat(sampleRate, 16, 1, true, false);
while (status == true) {
DatagramPacket receivePacket = new DatagramPacket(receiveData,
receiveData.length);
serverSocket.receive(receivePacket);
ByteArrayInputStream baiss = new ByteArrayInputStream(
receivePacket.getData());
ais = new AudioInputStream(baiss, format, receivePacket.getLength());
toSpeaker(receivePacket.getData());
}
}
public static void toSpeaker(byte soundbytes[]) {
try {
DataLine.Info dataLineInfo = new DataLine.Info(SourceDataLine.class, format);
SourceDataLine sourceDataLine = (SourceDataLine) AudioSystem.getLine(dataLineInfo);
sourceDataLine.open(format);
FloatControl volumeControl = (FloatControl) sourceDataLine.getControl(FloatControl.Type.MASTER_GAIN);
volumeControl.setValue(6.0206f);
sourceDataLine.start();
sourceDataLine.open(format);
sourceDataLine.start();
System.out.println("format? :" + sourceDataLine.getFormat());
sourceDataLine.write(soundbytes, 0, soundbytes.length);
System.out.println(soundbytes.toString());
sourceDataLine.drain();
sourceDataLine.close();
} catch (Exception e) {
System.out.println("Not working in speakers...");
e.printStackTrace();
}
}
}
如果你想在IDE中测试应用程序,那么只需创建两个不同的项目,一个用于android应用程序,另一个用于服务器类。
在android应用程序中,只需添加机器的IP并在设备上运行该应用程序,手机和计算机应该属于同一网络。请将服务器类作为java应用程序执行。
抖动将是突出和恼人的,但声音将或多或少清晰。请建议我怎么做才能得到更清晰的输出。
对于实际的流媒体,您需要一些编码支持。除了发送数据报和希望最好的东西外,还有更多的事情要考虑。
真正的网络并不完美。
您应该阅读简单的媒体流协议,如RTP,也许可以使用一个向两端提供RTP的库。RTP通常位于UDP之上。
用于音频的TCP流可能不如UDP/RTP有用,因为您必须关闭Nagling。
您至少需要在接收器端设置一个小的缓冲区,以防止缓冲区变空导致声音丢失。
我对同一主题进行了研究,发现android设备是a2dp源,音频只能从a2dp源流式传输到a2dp接收器。A2dp接收器可以是蓝牙耳机或蓝牙扬声器。 但我的问题是,Android应用程序“蓝牙音乐播放器”是如何工作的? 它允许从一部手机到另一部手机进行流媒体传输。因此,在这种情况下,收听移动设备必须充当接收器。这怎么可能?他们是否使用其他配置文件而不是a2dp? 好吧,这可能是他们使用的不同配置文
嗨,我正在学习Selenium&我不太清楚上面两个函数是如何工作的:问题陈述: 我有一个练习作业:转到http://the-internet.herokuapp.com/ 单击链接>多个窗口一个窗口打开>单击>>单击此处另一个窗口打开>>从该窗口获取文本并打印,然后返回http://the-internet.herokuapp.com/Windows并打印文本。 流程:http://the-int
我面临的问题,使用MediaPlayer以及原生Android音频播放器播放音频网址。这是我的网址http://live.politiafm.com:8500/politiafm.mp3 这是我的代码使用本机音频播放器Intent意图=new Intent(android.content.Intent。ACTION_VIEW);intent.setDataAndType(Uri.parse(STR
问题内容: 我正在另一台PC上实现从MIC到Java服务器的实时流传输。但是我只听到白噪声。 我已经附上了客户端程序和服务器程序 并且服务器端没有问题。它与android客户端AudioRecord完美运行。 问题答案: 因此,我用正弦波(或某种在某种意义上类似正弦波的东西)填充了麦克风,并且您的程序运行正常。 因此,我的具体更改是: 显然,我将其误解为一个512字节长的片段,并破坏了正弦波,但事
我正在使用核心音频(与swift包装)播放一些音频样本(一个简短的刺激,其中记录一个冲动)。我坚持使用核心音频,而不是更新的AVFoundation,因为我需要一些严格的定时和多设备输入,更新的框架还没有涵盖(我通过苹果代码请求他们告诉我必须使用核心音频)。 我现在创建了一个非常简单的正弦波,使用: 如果我把它写到一个wav文件并回放,音调就会按预期的方式创建。 然而,我实际上想在应用程序中触发这
我有一个badtokenexception的报告,尽管我尝试了任何事情,但我无法复制它,对我来说也不清楚它是如何发生的。 BadTokenException(@Android.view.viewrootimpl:setView:575)通过(@Android.view.WindowmanagerGlobal:AddView:272)完整跟踪:Android.view.Windowmanager$B