我有一个设置窗口,其中包含两个选择框。一个用于选择音频接口,另一个用于选择该接口上的输入通道。
当选择第二个选项框中的项目时,将启动两个后台线程,一个打开targetdataline,另一个线程显示一个仪表以查看音频信号的电平。
这工作正常,但是当我在选择框上选择另一个音频接口时,我想要中断两个线程,保存设备更改,然后再次启动线程。目前,执行此操作会导致应用挂起,但不会报告任何错误。任何帮助表示赞赏。
我有一个对象'audio1Monitor',用于同步音频线程。音频线程在初始化时启动,并在调用此方法之前处于等待状态。我认为发生了两三种不同的错误。方法'captureAudio1()'是要在线程中运行的任务。这取决于两个选择框中每一个的对象。我使用Preferences API'systemPrefs'保存了这些 只有在线程运行时更改选项框对象时才会发生错误。我本质上想要停止captureAudio1()任务并让线程等待,同时selectbox事件监听器执行,然后在结束时通知线程恢复并启动captureAudio1()。有时我得到一个firevaluechangedevent错误,我读过这个错误通常是在选择一个对象时更改选项框的对象,所以尝试取消选择并清除第一个选择框监听器中的列表。我很清楚我在这里,并且已经把头发拉了好几天了。
第一个选择框的代码:
chan1interface.getSelectionModel().selectedIndexProperty().addListener(new ChangeListener<Number>(){
@Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
synchronized(capture.audio1Monitor){
if (capture.audioInput1.getState().equals(RUNNING)){
capture.running = false;
try {
capture.audio1Monitor.wait();
} catch (InterruptedException ex) {
Logger.getLogger(ConfigController.class.getName()).log(Level.SEVERE, null, ex);
}
} else {
}
Mixer.Info[] mixers = AudioSystem.getMixerInfo();
Mixer m = AudioSystem.getMixer(mixers[chan1interface.getSelectionModel().getSelectedIndex()]);
System.out.println(chan1interface.getSelectionModel().getSelectedItem());
Line.Info[] lines = m.getTargetLineInfo();
for (Line.Info info : lines){
ArrayList channels = showSupportedChannels(info);
System.out.println(channels);
int maxValue = getMax(channels);
ArrayList channelList = new ArrayList();
for (int i=0; i<maxValue; i++){
channelList.add(i+1);
}
chan1channel.getSelectionModel().clearSelection();
chan1channel.getItems().removeAll();
ObservableList channelListOL = FXCollections.observableArrayList(channelList);
chan1channel.setItems((ObservableList) channelListOL);
}
String chan1Interface = m.getMixerInfo().getName();
System.out.println(chan1Interface +" - chan1 interface");
final String Interface1 = "interface1";
systemPrefs.put(Interface1, chan1Interface);
}
}
});
第二个选择框的代码:
chan1channel.getSelectionModel().selectedIndexProperty().addListener(new ChangeListener<Number>() {
@Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue){
synchronized(capture.audio1Monitor){
capture.running = false;
if (capture.audioInput1.isAlive()){
try {
capture.audioInput1.wait();
} catch (InterruptedException ex) {
Logger.getLogger(ConfigController.class.getName()).log(Level.SEVERE, null, ex);
}
}
chan1selectedchannel = (int) (chan1channel.getSelectionModel().getSelectedIndex()) + 1;
Mixer.Info[] mixers = AudioSystem.getMixerInfo();
Mixer m = AudioSystem.getMixer(mixers[chan1interface.getSelectionModel().getSelectedIndex()]);
Line.Info[] lines = m.getTargetLineInfo();
for (Line.Info info : lines){
ArrayList channels = showSupportedChannels(info);
System.out.println(channels);
chan1totalchannels = getMax(channels);
}
final String channel1selectedchannel = "chan1selectedchannel";
final String chan1total = "chan1totalchannels";
systemPrefs.put(channel1selectedchannel, String.valueOf(chan1selectedchannel));
systemPrefs.put(chan1total, String.valueOf(chan1totalchannels));
capture.running = true;
System.out.println("4 is called");
capture.audio1Monitor.notify();
if (meterUpdate.isAlive() == false){
try {
Thread.sleep(1000);
meterUpdate.start();
} catch (InterruptedException ex) {
Logger.getLogger(ConfigController.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
});
这是音频线程的代码:
Thread audioInput1 = new Thread(){
public void run(){
synchronized(audio1Monitor){
System.out.println("audioInput1 thread started");
while (constantLoop == true){
try {
System.out.println("audioInput1 'try' thread started");
captureAudio1();
System.out.println("audioInput1 Thread is waiting");
audio1Monitor.wait();
System.out.println("after waiting in thread");
} catch (ParseException ex) {
Logger.getLogger(audioIO.class.getName()).log(Level.SEVERE, null, ex);
} catch (LineUnavailableException ex) {
Logger.getLogger(audioIO.class.getName()).log(Level.SEVERE, null, ex);
} catch (InterruptedException ex) {
try {
audio1Monitor.wait();
} catch (InterruptedException ex1) {
Logger.getLogger(audioIO.class.getName()).log(Level.SEVERE, null, ex1);
}
System.out.println("after waiting in thread");
Logger.getLogger(audioIO.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
};
仪表线程:
Thread meterUpdate = new Thread(new Runnable() {
public void run(){
System.out.println("meter updating");
try {
Thread.sleep(2000);
} catch (InterruptedException ex) {
Logger.getLogger(ConfigController.class.getName()).log(Level.SEVERE, null, ex);
}
while (capture.running == true){
int chunkDivision = 5; //How much to divide each chunk into (total array / chunk division = SPL ms
double[] localSPLArray = capture.chan1double;
double sum1 = 0;
for (int h=1; h<(chunkDivision+1); h++){
long meterStart = System.currentTimeMillis();
System.out.println("Start meter = " + System.currentTimeMillis());
for (int i=0; i<(localSPLArray.length/chunkDivision); i++){
sum1 += (Math.pow(Math.abs(localSPLArray[i + (chunkDivision*h)]), 2));
}
double RMS1sqrt = Math.sqrt(sum1/(localSPLArray.length/10));
double RMS1;
if (RMS1sqrt<5){
RMS1 = 0.1;
} else {
RMS1 = 20*Math.log10(RMS1sqrt/(20*Math.pow(Math.E,-6)));
}
long meterStop = System.currentTimeMillis();
try {
double waitTime = (500/chunkDivision) - (meterStop-meterStart);
System.out.println("WaitTime = " + waitTime);
Thread.sleep((500/chunkDivision) - (meterStop-meterStart));
} catch (InterruptedException ex) {
Logger.getLogger(ConfigController.class.getName()).log(Level.SEVERE, null, ex);
}
Platform.runLater(() -> {
chan1progressbar.setProgress(RMS1/90);
});
}
}
});