当前位置: 首页 > 知识库问答 >
问题:

音频不清楚,而流之间的java类和android活动

和选
2023-03-14

我有一个android活动,它连接到一个java类,并以套接字的形式向它发送数据包。该课程接收声音包并将其扔给PC扬声器。代码运行良好,但在PC扬声器中播放声音时,会出现持续的抖动/中断。

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

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

抖动将是突出和恼人的,但声音将或多或少清晰。请建议我怎么做才能得到更清晰的输出。

共有1个答案

魏元白
2023-03-14

对于实际的流媒体,您需要一些编码支持。除了发送数据报和希望最好的东西外,还有更多的事情要考虑。

真正的网络并不完美。

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

您应该阅读简单的媒体流协议,如RTP,也许可以使用一个向两端提供RTP的库。RTP通常位于UDP之上。

用于音频的TCP流可能不如UDP/RTP有用,因为您必须关闭Nagling。

您至少需要在接收器端设置一个小的缓冲区,以防止缓冲区变空导致声音丢失。

 类似资料:
  • 我对同一主题进行了研究,发现android设备是a2dp源,音频只能从a2dp源流式传输到a2dp接收器。A2dp接收器可以是蓝牙耳机或蓝牙扬声器。 但我的问题是,Android应用程序“蓝牙音乐播放器”是如何工作的? 它允许从一部手机到另一部手机进行流媒体传输。因此,在这种情况下,收听移动设备必须充当接收器。这怎么可能?他们是否使用其他配置文件而不是a2dp? 好吧,这可能是他们使用的不同配置文

  • 嗨,我正在学习Selenium&我不太清楚上面两个函数是如何工作的:问题陈述: 我有一个练习作业:转到http://the-internet.herokuapp.com/ 单击链接>多个窗口一个窗口打开>单击>>单击此处另一个窗口打开>>从该窗口获取文本并打印,然后返回http://the-internet.herokuapp.com/Windows并打印文本。 流程:http://the-int

  • 我面临的问题,使用MediaPlayer以及原生Android音频播放器播放音频网址。这是我的网址http://live.politiafm.com:8500/politiafm.mp3 这是我的代码使用本机音频播放器Intent意图=new Intent(android.content.Intent。ACTION_VIEW);intent.setDataAndType(Uri.parse(STR

  • 问题内容: 我正在另一台PC上实现从MIC到Java服务器的实时流传输。但是我只听到白噪声。 我已经附上了客户端程序和服务器程序 并且服务器端没有问题。它与android客户端AudioRecord完美运行。 问题答案: 因此,我用正弦波(或某种在某种意义上类似正弦波的东西)填充了麦克风,并且您的程序运行正常。 因此,我的具体更改是: 显然,我将其误解为一个512字节长的片段,并破坏了正弦波,但事

  • 我正在使用核心音频(与swift包装)播放一些音频样本(一个简短的刺激,其中记录一个冲动)。我坚持使用核心音频,而不是更新的AVFoundation,因为我需要一些严格的定时和多设备输入,更新的框架还没有涵盖(我通过苹果代码请求他们告诉我必须使用核心音频)。 我现在创建了一个非常简单的正弦波,使用: 如果我把它写到一个wav文件并回放,音调就会按预期的方式创建。 然而,我实际上想在应用程序中触发这

  • 我有一个badtokenexception的报告,尽管我尝试了任何事情,但我无法复制它,对我来说也不清楚它是如何发生的。 BadTokenException(@Android.view.viewrootimpl:setView:575)通过(@Android.view.WindowmanagerGlobal:AddView:272)完整跟踪:Android.view.Windowmanager$B