1

私は現在、音声を送信するためのアプリケーションを開発しています。2 つのサービスを実行しています。1 つは受信用、もう 1 つは送信用です。送信者の重要なものは次のようになります。

            final DatagramSocket dSocket = new DatagramSocket();

            android.os.Process
                    .setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);

            Log.d(TAG, "Thread starting...");
            int buffersize = AudioRecord.getMinBufferSize(11025,
                    AudioFormat.CHANNEL_CONFIGURATION_MONO,
                    AudioFormat.ENCODING_PCM_16BIT);

            AudioRecord arec = new AudioRecord(
                    MediaRecorder.AudioSource.MIC, 11025,
                    AudioFormat.CHANNEL_CONFIGURATION_MONO,
                    AudioFormat.ENCODING_PCM_16BIT, buffersize);

            byte[] buffer = new byte[buffersize];
            Log.d(TAG, "Starting to record, buffersize=" + buffersize);
            arec.startRecording();

            while (isRunning && !isInterrupted()) {

                try {
                    Log.d(TAG, "Recording..");
                    arec.read(buffer, 0, buffersize);
                    DatagramPacket dPacket = new DatagramPacket(buffer,
                            buffersize);

                    for (Peer cur : mPeers) {
                        if(cur.isSelf) continue;

                        dPacket.setAddress(InetAddress
                                .getByName(cur.IP_ADDRESS));
                        dPacket.setPort(Config.UDP_PORT);
                        dSocket.send(dPacket);
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

このコードは動作し、オーディオ パケットを送信します。

レシーバー サービスは次のようになります。

            // DatagramSocket dSocket = new DatagramSocket();
            DatagramChannel dChannel = DatagramChannel.open();
            DatagramSocket dSocket = dChannel.socket();

            dSocket.setReuseAddress(true);
            dSocket.setSoTimeout(2000);
            dSocket.bind(new InetSocketAddress(Config.UDP_PORT));

            Log.d(TAG, "DatagramSocket open.");

            android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);

            int buffersize = AudioRecord.getMinBufferSize(11025,
                    AudioFormat.CHANNEL_CONFIGURATION_MONO,
                    AudioFormat.ENCODING_PCM_16BIT);

            AudioTrack aTrack = new AudioTrack(
                    AudioManager.STREAM_VOICE_CALL, 11025,
                    AudioFormat.CHANNEL_CONFIGURATION_MONO,
                    AudioFormat.ENCODING_PCM_16BIT, buffersize,
                    AudioTrack.MODE_STREAM);

            DatagramPacket dPacket = new DatagramPacket(
                    new byte[buffersize], buffersize);
            Log.d(TAG, "Packet with buffersize=" + buffersize);
            aTrack.play();
            Log.d(TAG, "Playing track..");

            byte[] buffer = new byte[buffersize];

            while (isRunning && !isInterrupted()) {
                try {
                    dSocket.receive(dPacket);
                    buffer = dPacket.getData();

                    aTrack.setPlaybackRate(11025);
                    aTrack.write(buffer, 0, buffer.length);

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            aTrack.stop();

これも機能しますが、数秒以上送信した後、大きな遅延が発生し、パケットはまだ到着しますが遅くなり、オーディオの再生は単に「遅れる」だけです - 品質を改善するにはどうすればよいですか? これは直接のピアツーピア接続であり、サーバーは関与しません。バッファサイズを大きくする必要がありますか? 現在のバッファ サイズは、Android から取得した最小バッファ サイズです。これは、私のデバイス (Galaxy Nexus 2 台) では 1024 です。ところで、優先度が「URGENT」に設定されている別のスレッドを開始するサービス(これが利用可能な最高のものであると私は信じています)。私の目的では、mPeers リストにはピアが 1 つしかないため、「for」ループは実際にはこれを遅らせていないと思います。

4

2 に答える 2

2

送信側ループのネットワーク関連部分を削除するとどうなるか確認しましたか? つまり、マイクからの read() 呼び出しはすぐに返されますか? また、パケットの到着が遅いとおっしゃっていますが、送信するタイミングにも大きな遅延があるかどうかは確認されましたか?

私が尋ねている理由は、バッファがいっぱいであるため、送信ソケットのブロックが原因で説明した現象が発生する可能性があるためです。ソケットがブロックされている場合、send() 呼び出しが完了するまでに長い時間がかかります。トラフィックの帯域幅が非常に広い場合や、CPU が非常に遅い場合を除き、UDP ソケットでは発生しないはずですが (通常は発火して忘れます)、確認する価値があります。

ブロックを回避するには、非ブロック ソケットを作成します。私は Java ネットワーキングにあまり詳しくありませんが、これを行うにはDatagramChannelが必要なようです。

于 2013-04-04T20:27:38.210 に答える