编辑:我现在使用的是 Jack(Jack 音频连接套件)。请参阅下面的答案。
我的 Raspberry Pi 上有一个声卡,有 8 个输出 channel (四个立体声 channel ),一个 Octosound 卡。我想要做的是选择其中一个 channel 将声音路由到。 使用此代码,我打印声卡的信息:
mixers = AudioSystem.getMixerInfo();
for (Mixer.Info mixerInfo : mixers) {
logger.debug("\n");
logger.debug("Found Mixer: " + mixerInfo);
Mixer m = AudioSystem.getMixer(mixerInfo);
Line.Info[] sourceLines = m.getSourceLineInfo();
for (Line.Info li : sourceLines) {
logger.debug("Found source line: " + li + " " + li.getClass());
if (li instanceof Port.Info) {
Port.Info portInfo = (Port.Info) li;
logger.debug("port found " + portInfo.getName() + " is source " + portInfo.isSource());
sourceDataLines.add(portInfo);
}
}
Line.Info[] targetLines = m.getTargetLineInfo();
for (Line.Info li : targetLines) {
logger.debug("Found target line: " + li + " " + li.getClass());
outputLines.add(li);
if (li instanceof Port.Info) {
Port.Info portInfo = (Port.Info) li;
logger.debug("port found " + portInfo.getName() + " is source " + portInfo.isSource());
outputPorts.add(portInfo);
}
}
}
private void lineClose(int soundPort) throws LineUnavailableException {
Port.Info lineInfo = outputPorts.get(soundPort);
Line line = (Port) AudioSystem.getLine(lineInfo);
line.close();
}
private void lineOpen(int l) throws LineUnavailableException {
for (int i = 0; i < outputPorts.size(); i++) {
Port.Info lineInfo = outputPorts.get(i);
Line line = (Port) AudioSystem.getLine(lineInfo);
if (l == i) {
line.open();
} else {
line.close();
}
}
}
这是我得到的输出:
Found Mixer: audioinjectoroc [default], version 4.9.41-v7+
Found source line: interface SourceDataLine supporting 84 audio formats, and buffers of at least 32 bytes class com.sun.media.sound.DirectAudioDevice$DirectDLI
Found source line: interface Clip supporting 84 audio formats, and buffers of at least 32 bytes class com.sun.media.sound.DirectAudioDevice$DirectDLI
Found target line: interface TargetDataLine supporting 84 audio formats, and buffers of at least 32 bytes class com.sun.media.sound.DirectAudioDevice$DirectDLI
Found Mixer: audioinjectoroc [plughw:0,0], version 4.9.41-v7+
Found source line: interface SourceDataLine supporting 96 audio formats, and buffers of at least 32 bytes class com.sun.media.sound.DirectAudioDevice$DirectDLI
Found source line: interface Clip supporting 96 audio formats, and buffers of at least 32 bytes class com.sun.media.sound.DirectAudioDevice$DirectDLI
Found target line: interface TargetDataLine supporting 96 audio formats, and buffers of at least 32 bytes class com.sun.media.sound.DirectAudioDevice$DirectDLI
Found Mixer: Port audioinjectoroc [hw:0], version 4.9.41-v7+
Found source line: ADC1 source port class com.sun.media.sound.PortMixer$PortInfo
port found ADC1 is source true
Found source line: ADC2 source port class com.sun.media.sound.PortMixer$PortInfo
port found ADC2 is source true
Found source line: ADC3 source port class com.sun.media.sound.PortMixer$PortInfo
port found ADC3 is source true
Found target line: DAC1 target port class com.sun.media.sound.PortMixer$PortInfo
port found DAC1 is source false
Found target line: DAC2 target port class com.sun.media.sound.PortMixer$PortInfo
port found DAC2 is source false
Found target line: DAC3 target port class com.sun.media.sound.PortMixer$PortInfo
port found DAC3 is source false
Found target line: DAC4 target port class com.sun.media.sound.PortMixer$PortInfo
port found DAC4 is source false
现在这是我用来从 wav 文件输出声音的代码:
String path = soundDirectory + soundUrl;
InputStream is = new FileInputStream(path);
BufferedInputStream bis = new BufferedInputStream(is);
AudioInputStream inputStream = AudioSystem.getAudioInputStream(bis);
AudioFormat format = inputStream.getFormat();
Mixer.Info mi = mixers[0];
SourceDataLine sourceDataLine = (SourceDataLine) AudioSystem.getSourceDataLine(format,mi);
sourceDataLine.open(format);
sourceDataLine.start();
byte[] buf = new byte[1024];
int bytesRead;
while ((bytesRead = inputStream.read(buf)) != -1){
sourceDataLine.write(buf, 0, bytesRead);
}
inputStream.close();
sourceDataLine.drain();
sourceDataLine.stop();
sourceDataLine.close();
lineClose(soundPort);
我已经尝试了很多方法,但在所有情况下,所有输出都会发出声音。
最佳答案
我自己找到了解决方案。我现在使用 Jack(Jack 音频连接套件,请参阅 here。 让 Jack 在 Raspberry Pi 上运行有点麻烦。有好资料here .
我使用 JnaJack with 提供 Java 和 Jack 之间的接口(interface)。
您不能开箱即用地在 Raspbian 上运行 Jack。 Debian Wheezy 有补丁,但 Raspbian Jessie 似乎没有。所以你需要创建一个不使用 DBus 的 Jackd2 版本。 Here它解释了如何在没有 DBus 的情况下构建 Jackd2。有一个障碍:您所要做的就是删除引用 DBus 的两行。他们告诉您要打补丁的所有其他内容现在都默认在 Raspbian 中打了补丁,或者看起来是这样。您需要替换这些行: 下载源代码后,在 debian/rules 中更改
waf-configure-options += $(if $(filter linux,$(DEB_HOST_ARCH_OS)),--alsa --dbus)
became
waf-configure-options += $(if $(filter linux,$(DEB_HOST_ARCH_OS)),--alsa)
dh_install -pjackd2 debian/tmp/usr/share/dbus-1/*
became
#dh_install -pjackd2 debian/tmp/usr/share/dbus-1/*
我修改了在 JnaJack 源代码中找到的 SimpleAudioClient 示例:
public class SimpleAudioClient {
private boolean autoconnect = true;
private JackClient client;
private Processor processor;
private Callback callback;
private ShutDownHook shutDownHook;
private JackPort[] inputPorts;
private JackPort[] outputPorts;
private FloatBuffer[] inputBuffers;
private FloatBuffer[] outputBuffers;
private float samplerate;
private int buffersize;
private volatile boolean active;
private Logger logger = Logger.getLogger(getClass().getSimpleName());
private int channelNumber = 0;
public SimpleAudioClient() throws JackException {
Jack jack = Jack.getInstance();
logger.debug("Jack instance " + jack.toString());
EnumSet<JackOptions> options = EnumSet.of(JackOptions.JackNoStartServer);
EnumSet<JackStatus> status = EnumSet.noneOf(JackStatus.class);
try {
client = jack.openClient("jna_jack", options, status);
} catch (JackException ex) {
System.out.println("ERROR : Status : " + status);
throw ex;
}
String[] inputs = new String[0];
inputPorts = new JackPort[inputs.length];
EnumSet<JackPortFlags> flags = EnumSet.of(JackPortFlags.JackPortIsInput);
for (int i = 0; i < inputs.length; i++) {
//inputPorts[i] = client.registerPort(inputs[i], JackPortType.AUDIO, flags);
}
String[] outputs = new String[]{"playback_1", "playback_2", "playback_3", "playback_4", "playback_5", "playback_6", "playback_7", "playback_8"};
outputPorts = new JackPort[outputs.length];
flags = EnumSet.of(JackPortFlags.JackPortIsOutput);
for (int i = 0; i < outputs.length; i++) {
outputPorts[i] = client.registerPort(outputs[i], JackPortType.AUDIO, flags);
}
processor = new SineAudioSource();
this.inputBuffers = new FloatBuffer[inputPorts.length];
this.outputBuffers = new FloatBuffer[outputPorts.length];
this.callback = new Callback();
this.shutDownHook = new ShutDownHook();
client.onShutdown(shutDownHook);
for (JackPort port : inputPorts) {
logger.debug("input port " + port.getType() + " " + port.getName());
}
for (JackPort port : outputPorts) {
logger.debug("output port " + port.getType() + " " + port.getName());
}
}
public void activate(int channelNr) throws JackException {
this.channelNumber = channelNr;
try {
samplerate = client.getSampleRate();
System.out.println("Sample rate = " + samplerate);
buffersize = client.getBufferSize();
System.out.println("Buffersize = " + buffersize);
processor.setup(samplerate, buffersize);
active = true;
client.setProcessCallback(callback);
client.activate();
if (autoconnect) {
doAutoconnect();
}
} catch (Exception ex) {
active = false;
throw new JackException("Could not activate Jack client");
}
}
private void doAutoconnect() throws JackException {
Jack jack = Jack.getInstance();
String[] physical = jack.getPorts(client, null, JackPortType.AUDIO,
EnumSet.of(JackPortFlags.JackPortIsInput, JackPortFlags.JackPortIsPhysical));
int count = Math.min(outputPorts.length, physical.length);
for (int i = 0; i < count; i++) {
logger.debug("output port " + outputPorts[i].getName());
jack.connect(client, outputPorts[i].getName(), physical[i]);
}
physical = jack.getPorts(client, null, JackPortType.AUDIO,
EnumSet.of(JackPortFlags.JackPortIsOutput, JackPortFlags.JackPortIsPhysical));
count = Math.min(inputPorts.length, physical.length);
for (int i = 0; i < count; i++) {
logger.debug("input port " + inputPorts[i].getName());
//jack.connect(client, physical[i], inputPorts[i].getName());
}
}
public void shutdown() {
active = false;
client.deactivate();
client.close();
}
private void processBuffers(int nframes) {
for (int i = 0; i < inputPorts.length; i++) {
inputBuffers[i] = inputPorts[i].getFloatBuffer();
}
for (int i = 0; i < outputPorts.length; i++) {
outputBuffers[i] = outputPorts[i].getFloatBuffer();
}
processor.process(channelNumber, inputBuffers, outputBuffers);
}
private class Callback implements JackProcessCallback {
public boolean process(JackClient client,final int nframes) {
if (!active) {
return false;
} else {
try {
processBuffers(nframes);
return true;
} catch (Exception ex) {
System.out.println("ERROR : " + ex);
active = false;
return false;
}
}
}
}
private class ShutDownHook implements JackShutdownCallback {
public void clientShutdown(JackClient client) {
active = false;
processor.shutdown();
}
}
public static interface Processor {
public void setup(float samplerate, int buffersize);
public void process(int channelNumber, FloatBuffer[] inputs, FloatBuffer[] outputs);
public void shutdown();
}
/**
* Create a SimpleAudioClient.
*
* @return client
* @throws org.jaudiolibs.jnajack.JackException
*/
public static SimpleAudioClient create(
) throws JackException {
return new SimpleAudioClient();
}
}
我将示例代码中的 SineAudioClient 修改为:
public class SineAudioSource implements SimpleAudioClient.Processor {
private final static int TABLE_SIZE = 200;
private int left_phase = 0;
private int right_phase = 0;
private float[] data;
public void setup(float samplerate, int buffersize) {
data = new float[TABLE_SIZE];
for (int i = 0; i < TABLE_SIZE; i++) {
data[i] = (float) (0.2 * Math.sin(((double) i / (double) TABLE_SIZE) * Math.PI * 2.0));
}
}
public void process(int channelNumber, FloatBuffer[] inputs, FloatBuffer[] outputs) {
FloatBuffer left = outputs[channelNumber];
int size = left.capacity();
for (int i = 0; i < size; i++) {
left.put(i, data[left_phase]);
left_phase += 2;
right_phase += 3;
if (left_phase >= TABLE_SIZE) {
left_phase -= TABLE_SIZE;
}
}
}
public void shutdown() {
System.out.println("Sine Audio Source shutdown");
}
}
因此它在声卡的八个 channel 中的每个 channel 中播放两秒钟的正弦波。我还没有尝试过输入 channel ,我读到当输入和输出都被激活时,很难让 Jack 在 Raspbian 上工作。
我在运行我的应用程序之前启动 Jack,启动命令是
/usr/bin/jackd -dalsa -dhw:audioinjectoroc -r48000 -p1024 -n2 -P &
启动jack时的日志应该显示
creating alsa driver ... hw:audioinjectoroc|-|1024|2|48000|0|0|nomon|swmeter|-|32bit
其中“audioinjector”是声卡的名称。如果显示
...hw:audioinjectoroc|hw:audioinjectoroc|1024 ...
那么您将无法连接到它。
您可以使用 QJackCtl 查看 Jack 设置,您可以在您的 Raspberry Pi 上运行它并从另一台计算机使用 X 服务器进行访问。我没能在 Pi 上运行 X Windows。
如果您想通过 Jack 播放 wav 文件,this是一个很好的例子,说明如何读取 wav 文件并将其提供给 jack。
编辑:该示例是一个很好的起点,但您需要进行一些更改。最好打开您计划使用的所有端口,调用 client.activate(),并在 JackCallback 中将 channel 从您的音频文件路由到声卡中的适当 channel 。您可以使用 qjackctl 查看 Jack 中发生了什么。
关于java - 在java中为八 channel 声卡选择输出行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45821554/
我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/
我正在玩HTML5视频并且在ERB中有以下片段:mp4视频从在我的开发环境中运行的服务器很好地流式传输到chrome。然而firefox显示带有海报图像的视频播放器,但带有一个大X。问题似乎是mongrel不确定ogv扩展的mime类型,并且只返回text/plain,如curl所示:$curl-Ihttp://0.0.0.0:3000/pr6.ogvHTTP/1.1200OKConnection:closeDate:Mon,19Apr201012:33:50GMTLast-Modified:Sun,18Apr201012:46:07GMTContent-Type:text/plain
我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www
状态:我正在构建一个应用程序,其中需要一个可供用户选择颜色的字段,该字段将包含RGB颜色代码字符串。我已经测试了一个看起来很漂亮但效果不佳的。它是“挑剔的颜色”,并托管在此存储库中:https://github.com/Astorsoft/picky-color.在这里我打开一个关于它的一些问题的问题。问题:请建议我在Rails3应用程序中使用一些颜色选择器。 最佳答案 也许页面上的列表jQueryUIDevelopment:ColorPicker为您提供开箱即用的产品。原因是jQuery现在包含在Rails3应用程序中,因此使用基
我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我
什么是ruby的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht
这篇文章是继上一篇文章“Observability:从零开始创建Java微服务并监控它(一)”的续篇。在上一篇文章中,我们讲述了如何创建一个Javaweb应用,并使用Filebeat来收集应用所生成的日志。在今天的文章中,我来详述如何收集应用的指标,使用APM来监控应用并监督web服务的在线情况。源码可以在地址 https://github.com/liu-xiao-guo/java_observability 进行下载。摄入指标指标被视为可以随时更改的时间点值。当前请求的数量可以改变任何毫秒。你可能有1000个请求的峰值,然后一切都回到一个请求。这也意味着这些指标可能不准确,你还想提取最小/
HashMap中为什么引入红黑树,而不是AVL树呢1.概述开始学习这个知识点之前我们需要知道,在JDK1.8以及之前,针对HashMap有什么不同。JDK1.7的时候,HashMap的底层实现是数组+链表JDK1.8的时候,HashMap的底层实现是数组+链表+红黑树我们要思考一个问题,为什么要从链表转为红黑树呢。首先先让我们了解下链表有什么不好???2.链表上述的截图其实就是链表的结构,我们来看下链表的增删改查的时间复杂度增:因为链表不是线性结构,所以每次添加的时候,只需要移动一个节点,所以可以理解为复杂度是N(1)删:算法时间复杂度跟增保持一致查:既然是非线性结构,所以查询某一个节点的时候
遍历文件夹我们通常是使用递归进行操作,这种方式比较简单,也比较容易理解。本文为大家介绍另一种不使用递归的方式,由于没有使用递归,只用到了循环和集合,所以效率更高一些!一、使用递归遍历文件夹整体思路1、使用File封装初始目录,2、打印这个目录3、获取这个目录下所有的子文件和子目录的数组。4、遍历这个数组,取出每个File对象4-1、如果File是否是一个文件,打印4-2、否则就是一个目录,递归调用代码实现publicclassSearchFile{publicstaticvoidmain(String[]args){//初始目录Filedir=newFile("d:/Dev");Datebeg
我基本上来自Java背景并且努力理解Ruby中的模运算。(5%3)(-5%3)(5%-3)(-5%-3)Java中的上述操作产生,2个-22个-2但在Ruby中,相同的表达式会产生21个-1-2.Ruby在逻辑上有多擅长这个?模块操作在Ruby中是如何实现的?如果将同一个操作定义为一个web服务,两个服务如何匹配逻辑。 最佳答案 在Java中,模运算的结果与被除数的符号相同。在Ruby中,它与除数的符号相同。remainder()在Ruby中与被除数的符号相同。您可能还想引用modulooperation.