S
Spacerat
Gast
Hallo
Ich hab' da mal wieder ein Problem mit meinem "AudioDevice". Beim Streaming in eine Line ("line.write()") bekomme ich ständig eine extrem hohe Prozessorauslastung (teilweise sogar 100%). Also: Das Device definiert einen Clip, welcher zunächst den gesammten Stream in einem ByteArray speichert (wie es eben beim Clip vorgesehen ist). Beim starten wird ein Thread gestartet, welcher das ByteArray paketweise in eine SourceDataLine, welche ebenfalls vom Device definiert wird, schreibt.
Hab' das auch schon mit 12,5FPS und sleeptime 79 versucht. Hab' sogar schon das halbe "com.sun.media.sound"-Paket decompiliert um zu schauen wie die es machen. Wie es ausschaut arbeiten die OpenAL-Methoden so wie sie sollen, aber irgend etwas blockiert halt. Ich verzweifle schon dran... (deswegen poste ich es ja auch hier). Hoffe mir kann jemand helfen.
edit: Zu allem übel zeigt ein jüngstes Experiment, das der Thread auch beim Schreiben in eine "normale" Line stottert oder den Prozessor auslastet. Hmmm.
edit2: grad' von einer Lösung geträumt ... Hab' bei bufferSize wohl vergessen, das audiodaten auch aus mehreren bytes (bis zu 4) bestehen können. also noch mal mit framesize multipliziert. Lösts aber auch nicht wirklich...
Ich hab' da mal wieder ein Problem mit meinem "AudioDevice". Beim Streaming in eine Line ("line.write()") bekomme ich ständig eine extrem hohe Prozessorauslastung (teilweise sogar 100%). Also: Das Device definiert einen Clip, welcher zunächst den gesammten Stream in einem ByteArray speichert (wie es eben beim Clip vorgesehen ist). Beim starten wird ein Thread gestartet, welcher das ByteArray paketweise in eine SourceDataLine, welche ebenfalls vom Device definiert wird, schreibt.
Code:
// die open Methoden der Klasse Clip
public synchronized void open(AudioInputStream stream)
throws LineUnavailableException
{
if(isOpen()) throw LINE_UNAVAILABLE;
try {
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buf = new byte[stream.available()];
while(stream.read(buf) != -1) {
out.write(buf);
}
out.close();
buf = out.toByteArray();
open(stream.getFormat(), buf, 0, buf.length);
} catch(Throwable e) {
throw DBSDataLine.LINE_UNAVAILABLE;
}
}
public synchronized void open(AudioFormat format, byte[] data, int offset, int bufferSize)
throws LineUnavailableException
{
if(isOpen()) throw LINE_UNAVAILABLE;
this.data = new byte[bufferSize];
System.arraycopy(data, offset, this.data, 0, bufferSize);
framesize = ((format.getSampleSizeInBits() + 7) / 8) * format.getChannels();
if(bufferSize % framesize != 0) throw new IllegalArgumentException("bufferSize is not a multiplier of the resulting framesize");
fpos = 0;
bufferSize = (int) (format.getSampleRate() / 25.0F) * framesize;
buffer = new byte[Math.min(bufferSize, this.data.length)];
line.open(format, buffer.length);
}
Code:
// die run Methode des Clip-Threads
public void run()
{
int bpos = 0, dpos = 0;
while(!isInterrupted()) {
while(dpos < data.length) {
bpos = dpos % buffer.length;
fpos = dpos / framesize;
buffer[bpos] = data[dpos];
if(loop[0] != 0) {
if(fpos == loop[2]) {
dpos = (loop[1]) * framesize;
loop[0]--;
if(loop[0] < 0) loop[0] = -1;
}
}
if(dpos != 0 && bpos == 0) {
line.write(buffer, 0, buffer.length);
Arrays.fill(buffer, (byte) 0);
try {
Thread.sleep(30L);
} catch(InterruptedException e) {
interrupt();
}
}
dpos++;
}
if(bpos != 0) {
line.write(buffer, 0, bpos + 1);
line.drain();
interrupt();
}
}
line.flush();
line.stop();
renderer = null;
}
Code:
// die open Methode der SourceDataLine
public synchronized void open(javax.sound.sampled.AudioFormat format, int bufferSize)
throws LineUnavailableException
{
if(isOpen() || (this.format = dev.getALFormat(format)) == null) throw LINE_UNAVAILABLE;
if((bufferSize % this.format.minFrameSize) != 0 || bufferSize <= 0) throw INVALID_BUFFERSIZE;
try {
this.bufferSize = bufferSize;
buffers = new ByteBuffer[BUFFERS]; // z.Zt werden 64 Puffer erstellt
for(bufferSize = 0; bufferSize < BUFFERS; bufferSize++) buffers[bufferSize] = ByteBuffer.allocate(this.bufferSize);
al.alGenSources(1, source, 0);
al.alSourcei(source[0], AL_SOURCE_TYPE, AL_STREAMING);
al.alGenBuffers(BUFFERS, qbuffer, 0);
al.alSourcef(source[0], AL_ROLLOFF_FACTOR, 0.0f);
al.alSourcei(source[0], AL_SOURCE_RELATIVE, AL_TRUE);
dispatch(new LineEvent(this, LineEvent.Type.OPEN, getFramePosition()));
} catch(Throwable e) {
throw LINE_UNAVAILABLE;
}
}
Code:
// die für write relevanten Methoden
public synchronized int write(byte[] b, int off, int len)
{
if(b == null || b.length < off + len || (len % this.format.minFrameSize) != 0) throw INVALID_BUFFERSIZE;
if(!isOpen() || b == null || b.length - off < len) return 0;
active = true;
written = 0;
do {
al.alGetSourcei(source[0], AL_BUFFERS_QUEUED, state, 3);
if(state[3] < BUFFERS) {
written += fillBuffer(b, written + off, len - written);
}
unQueueProcessed();
active = written != len;
} while(active);
return written;
}
private void unQueueProcessed()
{
al.alGetSourcei(source[0], AL_SOURCE_STATE, state, 0);
if(started && state[0] != AL_PLAYING) {
al.alSourcePlay(source[0]);
}
al.alGetSourcei(source[0], AL_BUFFERS_PROCESSED, state, 2);
if(state[2] != 0) {
al.alSourceUnqueueBuffers(source[0], state[2], ubuffer, ubuf);
ubuf += state[2];
ubuf %= BUFFERS;
}
}
private int fillBuffer(byte[] b, int offset, int length)
{
int n, m, s;
for(n = 0; n < length; n += format.sampleSizeInBytes) {
s = 0;
for(m = 0; m < format.sampleSizeInBytes; m++) {
s <<= 8;
s |= b[((!format.isBigEndian())? n + format.sampleSizeInBytes - 1 - m : n + m) + offset] & 0xFF;
}
s += format.bias;
s &= format.mask;
for(m = 0; m < format.sampleSizeInBytes; m++) {
buffers[qbuf].put(n + m, (byte) s);
s >>= 8;
}
}
buffers[qbuf].position(0);
al.alBufferData(qbuffer[qbuf], format.alenum, buffers[qbuf], length, format.sampleRateInt);
al.alSourceQueueBuffers(source[0], 1, qbuffer, qbuf);
qbuf++;
qbuf %= BUFFERS;
return length;
}
edit: Zu allem übel zeigt ein jüngstes Experiment, das der Thread auch beim Schreiben in eine "normale" Line stottert oder den Prozessor auslastet. Hmmm.
edit2: grad' von einer Lösung geträumt ... Hab' bei bufferSize wohl vergessen, das audiodaten auch aus mehreren bytes (bis zu 4) bestehen können. also noch mal mit framesize multipliziert. Lösts aber auch nicht wirklich...
Zuletzt bearbeitet von einem Moderator: