通过WiFi在Android手机之间流式传输语音

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了通过WiFi在Android手机之间流式传输语音相关的知识,希望对你有一定的参考价值。

我正试图通过WiFi将音频从1个android流式传输到另一个Android。在查看一些示例后,我制作了2个应用程序,每个应用程序中只有一个活动,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地址,也就像物理地址。不确定这是否相关。

那有什么问题呢?

答案

嘿,有一个名为“Libstreaming”的开源库,用于通过网络使用WIFI传输语音/视频。看看吧:

https://github.com/fyhertz/libstreaming

还提供了一些示例,请仔细看看:

https://github.com/fyhertz/libstreaming-examples

我已经使用该库通过网络流式传输RTSP音频,希望它可能有用。

另一答案

我试着将问题分成三部分。

第1部分

通过注释与音频相关的所有内容,确保套接字连接正常工作

第2部分

只发送来自发件人的任意文本消息[Hello WiFi],然后在接收方应用程序中接收和打印它。

第3部分

录像机是否实际工作?尝试在单独的项目中测试您的录制方式,看它是否正常工作。

使用this代码捕获麦克风并播放它。

我的经验

我曾经在一个类似的项目上工作并测试它,我做的是在录制之后我将录制的音频数据作为文件写在SD卡上

(这将是原始音频,因此大多数音乐播放器将无法播放它... mPlayer应该播放它我想)

另一答案

您需要仔细考虑使用UDP(DatagramSocket类)作为您的网络协议。

UDP是一种轻量级协议,不保证维护接收数据包的顺序。这可能是音频乱码的部分原因。无序接收的数据包将导致无序播放音频数据包。在这些无序数据包的边界处,您将听到音频样本实际损坏的点击/弹出。除此之外,不保证UDP数据包成功传送。任何丢弃的数据包显然会增加任何听到的乱码或失真。

TCP(套接字类)将是获得最佳音频质量的更好选择。 TCP是一种更强大的协议,可以保持接收数据包的顺序。它还具有内置错误检查功能,并将重新发送任何丢弃的数据包。但是,由于这种注意功能,TCP具有更高的网络开销。

我开始回答说你需要仔细考虑你使用的协议。这是因为有一种情况可以根据对你重要的事情来使用。

如果你想要超低延迟播放,但很高兴牺牲音频质量,那么UDP就能工作。但是,需要进行一些实验才能找到最佳的缓冲液和样品量。

如果你想要最好的音频重新制作,零失真,但很乐意引入稍多的延迟,那么TCP就是可行的路线。

我不能说TCP会增加多少延迟。但它有可能在不影响用户体验的情况下实施。找出答案的唯一方法是尝试并看到。

以上是关于通过WiFi在Android手机之间流式传输语音的主要内容,如果未能解决你的问题,请参考以下文章

通过 wifi 传输视频?

在 Android 上使用 OpenSL ES 通过套接字通信流式传输 MP3 音频

在iOS上通过WiFi和蓝牙流式传输视频

在外部蓝牙设备和 Android 手机之间传输音频

将音频和视频从 Android 手机流式传输到 RTMP 服务器的最佳方式

如何使用套接字编程在两个 android 手机之间创建实时音频流..?