web-dev-qa-db-ja.com

Android WiFi over Phones間の音声のストリーミング

私はマイクから1 AndroidからWiFi経由で別のマイクに音声をストリーミングしようとしています。受け取るもう一方。

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アドレスであり、宛先も物理アドレスのようなものです。しかし、これが関連するかどうかはわかりません。

では、何の問題がありますか?

30
Alabhya

ねえ、WIFIを使用してネットワーク経由で音声/ビデオをストリーミングするために使用される「Libstreaming」と呼ばれるオープンソースライブラリがあります。ご覧ください:

https://github.com/fyhertz/libstreaming

いくつかの例もありますので、ご覧ください。

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

ライブラリを使用してネットワーク経由でRTSPオーディオをストリーミングしました。

7
user3482497

問題を3つの部分に分けてみます。

パート1

オーディオに関連するすべてをコメントすることにより、ソケット接続が正常に機能していることを確認します

パート2

送信者から任意のテキストメッセージ[Hello WiFi]を送信し、受信者側のアプリケーションで受信して印刷します。

パート3

レコーダーが実際に機能しているかどうか別のプロジェクトで録音方法をテストして、正しく機能するかどうかを確認してください。

this コードを使用して、マイクをキャプチャして再生します。

私の経験

私はかつて同様のプロジェクトに取り組み、それをテストするために、録音後に録音した音声データをSDカード上のファイルとして書きました

(生のオーディオになるため、ほとんどの音楽プレーヤーは再生できません... mPlayerは再生するはずです)

3
Atul Goyal

ネットワークプロトコルとしてUDP(DatagramSocketクラス)の使用を慎重に検討する必要があります。

UDPは、受信パケットの順序を維持することを保証しない軽量プロトコルです。これは、オーディオが文字化けする理由の一部である可能性があります。順不同で受信されたパケットは、パケットに相当する音声が順不同で再生されることになります。これらのアウトオブシーケンスパケットの境界では、オーディオサンプルが事実上破損しているクリック/ポップが聞こえます。これに加えて、UDPパケットが正常に配信されることは保証されていません。ドロップされたパケットは明らかに聞こえる文字化けや歪みに追加されます。

最適なオーディオ品質を得るには、TCP(ソケットクラス)が適しています。 TCPは、パケットを受信する順序を維持する、より堅牢なプロトコルです。また、組み込みのエラーチェック機能があり、ドロップされたパケットを再送信します。ただし、この注意機能のため、TCPのネットワークオーバーヘッドは大きくなります。

使用するプロトコルを慎重に検討する必要があると言って、この応答を開始しました。これは、あなたにとって重要なものに応じてどちらかを使用する場合があるためです。

超低レイテンシーの再生が必要な場合でも、オーディオ品質を犠牲にしない場合は、UDPが機能します。ただし、最適なバッファーとサンプルサイズを見つけるには、ある程度の実験が必要です。

歪みのない可能な限り最高のオーディオ再生が必要であるが、少し長いレイテンシーを導入したい場合は、TCPが最適です。

遅延TCPがどれだけ追加されるかは言えません。ただし、ユーザーエクスペリエンスに影響を与えることなく実装できる可能性があります。見つける唯一の方法は、試してみることです。

2
Martyn