Hey,
Ik ben tegen een raar probleem aangelopen tijdens het ontwikkelen van mijn opname tooltje. Ik wil een simpel tooltje maken waarmee ik geluid kan opnemen en de opname kan pauzeren en hervatten. Dit doe ik door tijdens het opstarten TargetDataLine.open(...) aan te roepen. Pas als ik de opname wil starten roep ik TargetDataLine.start() aan. Dit heeft tot gevolg dat de interne buffer van TargetDataLine volstroomt met data die je m.b.v een aparte Capture-Thread uitleest en wegschrijft.
Het vreemde is dat op Ubuntu 10.4, de buffer van TargetDataLine al volloopt na de open(..) call. Ik heb om te debuggen, om de 250ms, de state van de targetDataLine geprint samen met de hoeveelheid data die in de buffer zit. Hier is de opname dus nog niet begonnen. De calls: isRunning(), isActive() en available().
Heb een workaround gevonden, namelijk het starten en stoppen van de TargetDataLine direct na de Open(..) call. Dus:
En mijn volledige source:
[mods] Heb source even opgeschoond. [/mods]
Heb het gevoel dat ik hier een bug in de java-implementatie van linux heb ontdekt. Klopt dat?
Kan iemand hier nog iets zinnigs over zeggen?
En niet onbelangrijk: waar kan ik deze bug het beste reporten?
Bedankt.
Ik ben tegen een raar probleem aangelopen tijdens het ontwikkelen van mijn opname tooltje. Ik wil een simpel tooltje maken waarmee ik geluid kan opnemen en de opname kan pauzeren en hervatten. Dit doe ik door tijdens het opstarten TargetDataLine.open(...) aan te roepen. Pas als ik de opname wil starten roep ik TargetDataLine.start() aan. Dit heeft tot gevolg dat de interne buffer van TargetDataLine volstroomt met data die je m.b.v een aparte Capture-Thread uitleest en wegschrijft.
Het vreemde is dat op Ubuntu 10.4, de buffer van TargetDataLine al volloopt na de open(..) call. Ik heb om te debuggen, om de 250ms, de state van de targetDataLine geprint samen met de hoeveelheid data die in de buffer zit. Hier is de opname dus nog niet begonnen. De calls: isRunning(), isActive() en available().
Je ziet dus dat de buffer al volstroomt terwijl dat nog niet zou moeten gebeuren. In windows 7 krijg ik de volgende uitvoer:sRunning() false isActive() false available: 0
isRunning() false isActive() false available: 0
isRunning() false isActive() false available: 11570
isRunning() false isActive() false available: 11570
isRunning() false isActive() false available: 11570
isRunning() false isActive() false available: 23140
isRunning() false isActive() false available: 23140
isRunning() false isActive() false available: 23140
isRunning() false isActive() false available: 34710
etc..
Zo hoort het natuurlijk.isRunning() false isActive() false available: 0
isRunning() false isActive() false available: 0
isRunning() false isActive() false available: 0
isRunning() false isActive() false available: 0
isRunning() false isActive() false available: 0
isRunning() false isActive() false available: 0
isRunning() false isActive() false available: 0
isRunning() false isActive() false available: 0
isRunning() false isActive() false available: 0
Heb een workaround gevonden, namelijk het starten en stoppen van de TargetDataLine direct na de Open(..) call. Dus:
code:
1
2
3
4
5
6
7
8
9
| //Get everything set up for capture audioFormat = getAudioFormat(); DataLine.Info dataLineInfo = new DataLine.Info(TargetDataLine.class, audioFormat); captureDataLine = (TargetDataLine) AudioSystem.getLine(dataLineInfo); captureDataLine.open(audioFormat); //Workaround! captureDataLine.start(); captureDataLine.stop(); |
En mijn volledige source:
[mods] Heb source even opgeschoond. [/mods]
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
| import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.util.*; import java.io.*; import javax.sound.sampled.*; public class CutFrame extends JFrame { private boolean capturing = false; private boolean finishCapturing = false; //When audio is captured it is written to this stream ByteArrayOutputStream capturedAudioData; //The two data lines to the mixer used for capturing and playback respectively TargetDataLine captureDataLine; //Audio format used for both capture and playback AudioFormat audioFormat; public CutFrame() { //Create buttons and enable some of them final JButton startBtn = new JButton("Start"); //Add event handlers for buttons startBtn.addActionListener( new ActionListener(){ public void actionPerformed( ActionEvent e){ startBtn.setEnabled(false); //Starts capturing audio data System.out.printf("START CAPTURE!!\n"); captureDataLine.start(); capturing = true; } } ); getContentPane().add(startBtn); getContentPane().setLayout( new FlowLayout() ); //Starts the audio capture thread startCaptureThread(); //Set remaining UI attributes setTitle("Recording audio"); setDefaultCloseOperation( EXIT_ON_CLOSE); setSize(400, 70); setVisible(true); } //This method captures audio input // from a microphone and saves it in // a ByteArrayOutputStream object. private void startCaptureThread(){ try{ //Get everything set up for capture audioFormat = getAudioFormat(); DataLine.Info dataLineInfo = new DataLine.Info(TargetDataLine.class, audioFormat); captureDataLine = (TargetDataLine) AudioSystem.getLine(dataLineInfo); captureDataLine.open(audioFormat); //Solution HERE!!! //captureDataLine.start(); //captureDataLine.stop(); //Solution HERE!!! capturing = false; finishCapturing = false; //Create and start capture thread Thread captureThread = new Thread( new CaptureThread()); captureThread.start(); } catch (Exception e) { System.out.println(e); System.exit(0); } } //The audio capturing thread class CaptureThread extends Thread{ public void run(){ //Create new audio data stream to write to capturedAudioData = new ByteArrayOutputStream(); //Create temporary buffer byte tempBuffer[] = new byte[1000]; try { //Read data until capture is stopped while(!finishCapturing) { //Are we capturing audio?? if (capturing) { //Fetch data from captureDataLine and store it into capturedAudioData int cnt = captureDataLine.read( tempBuffer, 0, tempBuffer.length); if(cnt > 0) { capturedAudioData.write(tempBuffer, 0, cnt); } } //Wait some time sleep(250); //Print status System.out.printf("isRunning() %b isActive() %b available: %d \n", captureDataLine.isRunning(), captureDataLine.isActive(), captureDataLine.available()); } //Close capture line captureDataLine.stop(); captureDataLine.flush(); captureDataLine.close(); } catch (Exception e) { System.out.println(e); System.exit(0); } } } //Specify audio format here! private AudioFormat getAudioFormat(){ float sampleRate = 8000.0F; //can be 8000,11025,16000,22050,44100 int sampleSizeInBits = 16; //can be 8 or 16 int channels = 1; //can be 1 or 2 boolean signed = true; boolean bigEndian = false; return new AudioFormat(sampleRate, sampleSizeInBits, channels, signed, bigEndian); } public static void main(String[] argv) { new CutFrame(); } } |
Heb het gevoel dat ik hier een bug in de java-implementatie van linux heb ontdekt. Klopt dat?
Kan iemand hier nog iets zinnigs over zeggen?
En niet onbelangrijk: waar kan ik deze bug het beste reporten?
Bedankt.
[ Voor 218% gewijzigd door chronozphere op 27-02-2011 14:00 ]