【发布时间】:2012-03-03 13:08:45
【问题描述】:
我正在尝试通过 WiFi 将麦克风中的音频从 1 个 Android 流式传输到另一个。 在查看了一些示例后,我制作了 2 个应用程序,每个应用程序都有一个 Activity,1 个用于捕获和发送音频,另一个用于接收。
我使用 Audiorecord 和 Audiotrack 类来捕捉和播放。但是,我只是听到了一些噼啪声(虽然我恢复了,但在我做了一些更改后它现在已经停止了)
发送语音的活动。
public class VoiceSenderActivity extends Activity {
private EditText target;
private TextView streamingLabel;
private Button startButton,stopButton;
public byte[] buffer;
public static DatagramSocket socket;
private int port=50005; //which port??
AudioRecord recorder;
//Audio Configuration.
private int sampleRate = 8000; //How much will be ideal?
private int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO;
private int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
private boolean status = true;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
target = (EditText) findViewById (R.id.target_IP);
streamingLabel = (TextView) findViewById(R.id.streaming_label);
startButton = (Button) findViewById (R.id.start_button);
stopButton = (Button) findViewById (R.id.stop_button);
streamingLabel.setText("Press Start! to begin");
startButton.setOnClickListener (startListener);
stopButton.setOnClickListener (stopListener);
}
private final OnClickListener stopListener = new OnClickListener() {
@Override
public void onClick(View arg0) {
status = false;
recorder.release();
Log.d("VS","Recorder released");
}
};
private final OnClickListener startListener = new OnClickListener() {
@Override
public void onClick(View arg0) {
status = true;
startStreaming();
}
};
public void startStreaming() {
Thread streamThread = new Thread(new Runnable() {
@Override
public void run() {
try {
int minBufSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat);
DatagramSocket socket = new DatagramSocket();
Log.d("VS", "Socket Created");
byte[] buffer = new byte[minBufSize];
Log.d("VS","Buffer created of size " + minBufSize);
DatagramPacket packet;
final InetAddress destination = InetAddress.getByName(target.getText().toString());
Log.d("VS", "Address retrieved");
recorder = new AudioRecord(MediaRecorder.AudioSource.MIC,sampleRate,channelConfig,audioFormat,minBufSize);
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);
}
} catch(UnknownHostException e) {
Log.e("VS", "UnknownHostException");
} catch (IOException e) {
Log.e("VS", "IOException");
}
}
});
streamThread.start();
}
}
接收语音的活动
public class VoiceReceiverActivity extends Activity {
private Button receiveButton,stopButton;
public static DatagramSocket socket;
private AudioTrack speaker;
//Audio Configuration.
private int sampleRate = 8000; //How much will be ideal?
private int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO;
private int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
private boolean status = true;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
receiveButton = (Button) findViewById (R.id.receive_button);
stopButton = (Button) findViewById (R.id.stop_button);
findViewById(R.id.receive_label);
receiveButton.setOnClickListener(receiveListener);
stopButton.setOnClickListener(stopListener);
}
private final OnClickListener stopListener = new OnClickListener() {
@Override
public void onClick(View v) {
status = false;
speaker.release();
Log.d("VR","Speaker released");
}
};
private final OnClickListener receiveListener = new OnClickListener() {
@Override
public void onClick(View arg0) {
status = true;
startReceiving();
}
};
public void startReceiving() {
Thread receiveThread = new Thread (new Runnable() {
@Override
public void run() {
try {
DatagramSocket socket = new DatagramSocket(50005);
Log.d("VR", "Socket Created");
byte[] buffer = new byte[256];
//minimum buffer size. need to be careful. might cause problems. try setting manually if any problems faced
int minBufSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat);
speaker = new AudioTrack(AudioManager.STREAM_MUSIC,sampleRate,channelConfig,audioFormat,minBufSize,AudioTrack.MODE_STREAM);
speaker.play();
while(status == true) {
try {
DatagramPacket packet = new DatagramPacket(buffer,buffer.length);
socket.receive(packet);
Log.d("VR", "Packet Received");
//reading content from packet
buffer=packet.getData();
Log.d("VR", "Packet data read into buffer");
//sending data to the Audiotrack obj i.e. speaker
speaker.write(buffer, 0, minBufSize);
Log.d("VR", "Writing buffer content to speaker");
} catch(IOException e) {
Log.e("VR","IOException");
}
}
} catch (SocketException e) {
Log.e("VR", "SocketException");
}
}
});
receiveThread.start();
}
}
我使用wireshark检查数据包是否正在发送,我可以看到数据包。然而,源是发送设备的 MAC 地址,而目标也类似于物理地址。不过不确定这是否相关。
那么有什么问题呢?
【问题讨论】:
-
您至少要处理三个问题:延迟(或丢失)数据、整体数据吞吐量以及采样频率略有不匹配的可能性。实用的 IP 电话必须有处理这三者的方法。不匹配的时钟非常棘手 - 最初您可以引入延迟以提供一些缓冲余量,但如果发送方速度较慢,您将耗尽缓冲区并且接收方将缺乏数据;而如果发送者速度更快,缓冲区最终会溢出未播放的数据。
-
我确实设法让这个工作真正发挥作用。确实没有频率不匹配的问题。数据延迟,是的。有一种我自己的协议来匹配接收器/发送器时钟。最后它确实起作用了,但只是有一些延迟(随着与无线路由器的距离而增加)
-
嘿,我为您上面的代码实现了一个测试应用程序,对下面建议的所有必要更改进行了更改,但我仍然遇到问题。我在两部手机之间进行通信没问题,但我认为麦克风录制不正确,因为我在另一端听不到任何声音。您是否有指向我可以查看的示例解决方案的链接?
-
@chuckliddell0 你在两部手机之间获得通讯是什么意思?你的意思是你能听到一些声音但它是乱码?尝试调整您的采样率和缓冲区大小并获得最佳拟合。
-
@Alabhya 您是否设法减少了延迟?我使用 44100 HZ 和 4096 的缓冲区大小实现了你的代码,它工作正常,但有点滞后。
标签: android audio stream voice