- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
目标:我有一个正在运行的小型 Android 应用程序,它通过麦克风接受输入并实时将其流式传输回 - 我正在尝试对其进行修改,以便它通过流式传输数据到我电脑上的 Java 服务器。
问题:
我得到的只是一遍又一遍的“滴答”声,或者连续的“哔”声(这两种声音会根据我阅读文章的方式而变化)数据服务器端)。
PC 没有声音。我意识到这很可能与我播放声音的方式有关,因为在 Android 设备上它能够准确地播放自己的声音。
代码:在客户端和服务器端都只有一个类。
服务器如何接收和尝试播放数据:
public static void main(String[] args) {
try {
ServerSocket x = new ServerSocket(6790);
try {
while (true) {
System.out.println("started");
Socket clientSocket = x.accept();
System.out.println("Connected" + clientSocket.getInetAddress());
InputStream y = clientSocket.getInputStream();
// ObjectInputStream in = new ObjectInputStream(y);
AudioFormat format = new AudioFormat(8000, 16, 1, true, true);
AudioInputStream audIn = new AudioInputStream(y, format, 1);
SourceDataLine speakers;
try {
byte[] data = new byte[32];
int numBytesRead;
int CHUNK_SIZE = 1024;
int bytesRead = 0;
DataLine.Info dataLineInfo = new DataLine.Info(SourceDataLine.class, format);
speakers = (SourceDataLine) AudioSystem.getLine(dataLineInfo);
speakers.open(format);
speakers.start();
while (bytesRead < 100000) {
numBytesRead = audIn.read(data, 0, 16); //y.read(data, 0, 16);
bytesRead += numBytesRead;
System.out.println(numBytesRead);
//for immediate playback
if (numBytesRead > 0) {
speakers.write(data, 0, 16);
System.out.println("writing data");
}
}
speakers.drain();
speakers.close();
} catch (LineUnavailableException e) {
e.printStackTrace();
}
}
} catch (Exception e1) {
e1.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
}
我如何从客户端记录和发送:
public void run() {
try {
Log.i("Audio", "Running Audio Thread");
AudioRecord recorder = null;
AudioTrack track = null;
ObjectOutputStream out = new ObjectOutputStream(x.getOutputStream());
short[][] buffers = new short[256][160];
int ix = 0;
/*
* Initialize buffer to hold continuously recorded audio data, start recording, and start
* playback.
*/
int N = AudioRecord.getMinBufferSize(8000, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT);
recorder = new AudioRecord(AudioSource.MIC, 8000, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, N * 1);
track = new AudioTrack(AudioManager.STREAM_MUSIC, 8000, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, N * 1,
AudioTrack.MODE_STREAM);
recorder.startRecording();
track.play();
/*
* Loops until something outside of this thread stops it.
* Reads the data from the recorder and writes it to the audio track for playback.
*/
while (!stopped) {
Log.i("Map", "Writing new data to buffer");
short[] buffer = buffers[ix++ % buffers.length];
N = recorder.read(buffer, 0, buffer.length);
// ensure endianess
ByteBuffer bb = ByteBuffer.allocate(buffer.length * 2);
bb.order(ByteOrder.LITTLE_ENDIAN);
bb.asShortBuffer().put(buffer);
byte[] byteBuffer = bb.array();
track.write(buffer, 0, buffer.length);
out.write(byteBuffer);
}
/*
* Frees the thread's resources after the loop completes so that it can be run again
*/
recorder.stop();
recorder.release();
track.stop();
track.release();
Log.d("Exit", "Exiting thread");
} catch (Throwable x) {
Log.w("Audio", "Error reading voice audio", x);
}
}
我非常清楚 UDP 通常用于语音流,但这是唯一接近工作的代码集。在以前的版本中,我尝试过使用诸如 RTP 和 WebRTC 之类的东西,以及多个库,这是我能够获得“实时”回放的唯一版本。
我已经尝试了很多不同的方法,例如使用 Clip 和 ObjectInputStream,但似乎没有任何效果。在这个版本中,我通过 ObjectOutputStream 发送
short[]
byte[]
通过 OutputStream,并通过 AudioInputStream 读取,但我愿意只要它有效,就可以发送和读取任何类型的数据。我已经尝试将 short[]
转换为 byte[]
并播放它,但它似乎没有帮助。
错误:
不会报告任何实际错误(因为没有抛出异常)。 LogCat 也没有任何问题。
(这不再正确;有关更多详细信息,请参阅编辑)
请注意,格式的唯一工作配置是:
AudioFormat format = new AudioFormat(8000, 16, 1, true, true); //louder
AudioFormat format = new AudioFormat(8000, 16, 1, true, false); //quieter
其他 2 种有符号/无符号 + 字节序的组合抛出异常。
我还可以确认数据实际上是通过连接发送的——我使用 wireshark 进入它,我可以清楚地看到源和目的地,以及正在发送的数据。我肯定会发送到正确的端口。
如果需要更多代码,请询问,我会编辑并发布。
TLDR;如何播放从 Android 设备发送到运行 Java 服务器的计算机的声音?
编辑:经过进一步调查和一些代码修改,声音仍然没有播放,但我发现了一些新问题。 Logcat 现在抛出异常,服务器不断读取流结束信号 (-1)。我通过将其打印到屏幕上来确认它。
LogCat 错误:
03-04 10:28:47.496: W/Audio(794): Error reading voice audio
03-04 10:28:47.496: W/Audio(794): java.net.SocketException: Socket closed
03-04 10:28:47.496: W/Audio(794): at libcore.io.Posix.sendtoBytes(Native Method)
03-04 10:28:47.496: W/Audio(794): at libcore.io.Posix.sendto(Posix.java:156)
03-04 10:28:47.496: W/Audio(794): at libcore.io.BlockGuardOs.sendto(BlockGuardOs.java:177)
03-04 10:28:47.496: W/Audio(794): at libcore.io.IoBridge.sendto(IoBridge.java:466)
03-04 10:28:47.496: W/Audio(794): at java.net.PlainSocketImpl.write(PlainSocketImpl.java:508)
03-04 10:28:47.496: W/Audio(794): at java.net.PlainSocketImpl.access$100(PlainSocketImpl.java:46)
03-04 10:28:47.496: W/Audio(794): at java.net.PlainSocketImpl$PlainSocketOutputStream.write(PlainSocketImpl.java:270)
03-04 10:28:47.496: W/Audio(794): at java.io.OutputStream.write(OutputStream.java:82)
03-04 10:28:47.496: W/Audio(794): at com.javaorigin.rtpsender.MainActivity$Audio.run(MainActivity.java:126)
据我所知,我没有关闭与套接字或套接字本身(服务器端和客户端)相关的任何流。那么是什么导致了这个异常呢?只有当我“停止”录制时才会抛出此异常 - 在从 android 设备录制期间,回放工作正常。如果我删除 out.write()
,我将返回接收完整的循环功能(例如,我可以对着设备说话,DEVICE 将播放它)。它还允许我在同一 session 中多次“开始”或“停止”。不会抛出任何异常。将 out.write()
放回代码时,我无法启动/停止多个 session 。相反,在初始 session 之后,异常被抛出,下次我尝试“开始”录制时,应用程序崩溃了。
最佳答案
乍一看,虽然我没有仔细检查您的代码或亲自尝试过您的代码,但我可以看到您正在使用 ObjectOutputStream.writeObject()
编写数组,但将其作为原始字节读取.
这肯定会引起问题。 ObjectOutputStream.writeObject()
用于序列化 Java 对象;它写入的不仅仅是原始数据,甚至是数组。它写入对象类、签名和一些其他内容,以便它可以被另一端的 ObjectInputStream
反序列化(如果您好奇,请指定此格式 here)。
您有多种选择。我能想到的是:
不要使用 ObjectOutputStream.writeObject()
。而是将原始数据直接写入套接字(具有正确的字节顺序等以匹配您的帧格式)。例如,您可以通过 ByteBuffer#asShortBuffer()
在 ByteBuffer
中缓冲您的数据(确保设置匹配的字节顺序),然后写入相应的字节数组到套接字的输出流。这将是开销最低的方法。
创建一些 Serializable
类,将您的短缓冲区作为成员保存。用 ObjectOutputStream
编写它并在另一端用 ObjectInputStream
读取它(您需要在客户端和服务器中使用相同的类)。不过,它不会像前面的选项那样直接通过 AudioInputStream
读取。
您可能还会想到其他选项。如果 ByteBuffer
很难在您的代码中工作,那么您可以将每个 short 单独编写为一对字节;相同的最终效果(请注意,ShortBuffer.array()
将允许您将缓冲区作为 short[]
访问,这可能有助于简化集成)。
关于java - 将从安卓设备接收到的数据输出为声音,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28842962/
初学者 android 问题。好的,我已经成功写入文件。例如。 //获取文件名 String filename = getResources().getString(R.string.filename
我已经将相同的图像保存到/data/data/mypackage/img/中,现在我想显示这个全屏,我曾尝试使用 ACTION_VIEW 来显示 android 标准程序,但它不是从/data/dat
我正在使用Xcode 9,Swift 4。 我正在尝试使用以下代码从URL在ImageView中显示图像: func getImageFromUrl(sourceUrl: String) -> UII
我的 Ubuntu 安装 genymotion 有问题。主要是我无法调试我的数据库,因为通过 eclipse 中的 DBMS 和 shell 中的 adb 我无法查看/data/文件夹的内容。没有显示
我正在尝试用 PHP 发布一些 JSON 数据。但是出了点问题。 这是我的 html -- {% for x in sets %}
我观察到两种方法的结果不同。为什么是这样?我知道 lm 上发生了什么,但无法弄清楚 tslm 上发生了什么。 > library(forecast) > set.seed(2) > tts lm(t
我不确定为什么会这样!我有一个由 spring data elasticsearch 和 spring data jpa 使用的类,但是当我尝试运行我的应用程序时出现错误。 Error creatin
在 this vega 图表,如果我下载并转换 flare-dependencies.json使用以下 jq 到 csv命令, jq -r '(map(keys) | add | unique) as
我正在提交一个项目,我必须在其中创建一个带有表的 mysql 数据库。一切都在我这边进行,所以我只想检查如何将我所有的压缩文件发送给使用不同计算机的人。基本上,我如何为另一台计算机创建我的数据库文件,
我有一个应用程序可以将文本文件写入内部存储。我想仔细看看我的电脑。 我运行了 Toast.makeText 来显示路径,它说:/数据/数据/我的包 但是当我转到 Android Studio 的 An
我喜欢使用 Genymotion 模拟器以如此出色的速度加载 Android。它有非常好的速度,但仍然有一些不稳定的性能。 如何从 Eclipse 中的文件资源管理器访问 Genymotion 模拟器
我需要更改 Silverlight 中文本框的格式。数据通过 MVVM 绑定(bind)。 例如,有一个 int 属性,我将 1 添加到 setter 中的值并调用 OnPropertyChanged
我想向 Youtube Data API 提出请求,但我不需要访问任何用户信息。我只想浏览公共(public)视频并根据搜索词显示视频。 我可以在未经授权的情况下这样做吗? 最佳答案 YouTube
我已经设置了一个 Twilio 应用程序,我想向人们发送更新,但我不想回复单个文本。我只是想让他们在有问题时打电话。我一切正常,但我想在发送文本时显示传入文本,以确保我不会错过任何问题。我正在使用 p
我有一个带有表单的网站(目前它是纯 HTML,但我们正在切换到 JQuery)。流程是这样的: 接受用户的输入 --- 5 个整数 通过 REST 调用网络服务 在服务器端运行一些计算...并生成一个
假设我们有一个名为 configuration.js 的文件,当我们查看内部时,我们会看到: 'use strict'; var profile = { "project": "%Projec
这部分是对 Previous Question 的扩展我的: 我现在可以从我的 CI Controller 成功返回 JSON 数据,它返回: {"results":[{"id":"1","Sourc
有什么有效的方法可以删除 ios 中 CBL 的所有文档存储?我对此有疑问,或者,如果有人知道如何从本质上使该应用程序像刚刚安装一样,那也会非常有帮助。我们正在努力确保我们的注销实际上将应用程序设置为
我有一个 Rails 应用程序,它与其他 Rails 应用程序通信以进行数据插入。我使用 jQuery $.post 方法进行数据插入。对于插入,我的其他 Rails 应用程序显示 200 OK。但在
我正在为服务于发布请求的 API 调用运行单元测试。我正在传递请求正文,并且必须将响应作为帐户数据返回。但我只收到断言错误 注意:数据是从 Azure 中获取的 spec.js const accou
我是一名优秀的程序员,十分优秀!