# Probleme mit Thread beim Streaming



## Spacerat (19. Mrz 2009)

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.
	
	
	
	





```
// 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);
}
```


```
// 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;
}
```


```
// 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;
  }
}
```


```
// 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;
}
```
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...


----------



## Spacerat (20. Mrz 2009)

... gibt's irgend einen Grund für diese Ignoranz? Seid ih überfordert? (wie ich grad') PUSH...


----------

