一个Java类和android活动之间的音频不清晰流而 [英] Audio not clear while streaming between a java class and android activity

查看:117
本文介绍了一个Java类和android活动之间的音频不清晰流而的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个机器人的活动,它连接到一个Java类和将数据包发送给它的插座形式。该类接收声音数据包,并将其罚球PC扬声器。在code是工作出色,但同时播放声音在PC音箱恒定的抖动/中断。

I have an android activity, which connects to a java class and sends data packets to it in form of sockets. The class receives the sound packets and throws them to PC speakers. The code is working excellently, but there is a constant jitter/ interruption while the sound is played in PC speakers.

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应用程序,另一个用于服务器类。

If you want to test the app in your IDE, then simply create two different projects, one for the android app and one for the server class.

在Android应用程序只需添加你的机器的IP,并在设备上运行的应用程序,手机和计算机应该属于同一个网络。请作为一个Java应用程序执行的服务器类。

In the android app just add the IP of your machine and run the app on a device, the mobile and the computer should belong to the same network. Please execute the server class as a java application.

抖动将是突出的和刺激性,但声音会或多或少明确。请建议我该怎么做才能得到更清晰的输出。

The jitter will be prominent and irritating but the voices will be more or less clear. Please suggest me what to do to get a clearer output.

推荐答案

您需要有实际的流约codeD支持。 还有一点要考虑的不仅仅是发送数据包,并希望最好的。

You need to have some coded support for actual streaming. There's a little more to consider than just sending datagrams and hoping for the best.

真正的网络是不完美的。

Real networks are not perfect.

  • 延迟:数据包需要时间
  • 抖动:数据包需要在飞行中的时间不是恒定
  • 丢弃的包:有时候他们不让它
  • 重新排序:有时到达的数据包以不同的顺序来发送

您应该阅读喜欢简单的RTP流媒体协议,并可能使用一个库,它提供了RTP到两端。 RTP通常坐拥UDP。

You should read up on simple media streaming protocols like RTP and perhaps use a library that provides RTP to both ends. RTP commonly sits atop UDP.

TCP流式音频可以比UDP / RTP不太有用,因为你必须关闭Nagling的。

TCP streaming for audio can be less helpful than UDP/RTP , as you'd have to turn off Nagling.

您将至少需要在接收器的小缓冲区结束至prevent缓冲区空导致声音辍学。

You will at a minimum need a small buffer at the receiver end to prevent buffer empty causing sound dropouts.

这篇关于一个Java类和android活动之间的音频不清晰流而的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆