private void prefetchAllHeaders(
     final Info firstInfo, final Comment firstComment, final int dataoffset) {
   final Page page = new Page();
   this.m_info = new Info[this.m_links];
   this.m_comments = new Comment[this.m_links];
   this.m_dataOffsets = new long[this.m_links];
   this.m_pcmLengths = new long[this.m_links];
   this.m_serialnos = new int[this.m_links];
   for (int i = 0; i < this.m_links; ++i) {
     if (firstInfo != null && firstComment != null && i == 0) {
       this.m_info[i] = firstInfo;
       this.m_comments[i] = firstComment;
       this.m_dataOffsets[i] = dataoffset;
     } else {
       this.seekHelper(this.m_offsets[i]);
       this.m_info[i] = new Info();
       this.m_comments[i] = new Comment();
       if (this.fetchHeaders(this.m_info[i], this.m_comments[i], null, null) == -1) {
         this.m_dataOffsets[i] = -1L;
       } else {
         this.m_dataOffsets[i] = this.m_offset;
         this.m_oggStreamState.clear();
       }
     }
     final long end = this.m_offsets[i + 1];
     this.seekHelper(end);
     while (true) {
       final int ret = this.getPreviousPage(page);
       if (ret == -1) {
         this.m_info[i].clear();
         break;
       }
       if (page.granulepos() != -1L) {
         this.m_serialnos[i] = page.serialno();
         this.m_pcmLengths[i] = page.granulepos();
         break;
       }
     }
   }
 }
 @Override
 public int pcmSeek(final long pos) {
   if (!this.m_vorbisStream.isSeekable()) {
     return -1;
   }
   long total = this.pcmTotal(-1);
   if (pos < 0L || pos > total) {
     this.m_pcmOffset = -1L;
     this.decodeClear();
     return -1;
   }
   int link;
   for (link = this.m_links - 1; link >= 0; --link) {
     total -= this.m_pcmLengths[link];
     if (pos >= total) {
       break;
     }
   }
   final long target = pos - total;
   long end = this.m_offsets[link + 1];
   long begin = this.m_offsets[link];
   int best = (int) begin;
   final Page page = new Page();
   while (begin < end) {
     long bisect;
     if (end - begin < this.m_chunkSize) {
       bisect = begin;
     } else {
       bisect = (end + begin) / 2L;
     }
     this.seekHelper(bisect);
     final int ret = this.getNextPage(page, end - bisect);
     if (ret == -1) {
       end = bisect;
     } else {
       final long granulepos = page.granulepos();
       if (granulepos < target) {
         best = ret;
         begin = this.m_offset;
       } else {
         end = bisect;
       }
     }
   }
   if (this.rawSeek(best) != 0) {
     this.m_pcmOffset = -1L;
     this.decodeClear();
     return -1;
   }
   if (this.m_pcmOffset >= pos) {
     this.m_pcmOffset = -1L;
     this.decodeClear();
     return -1;
   }
   if (pos > this.pcmTotal(-1)) {
     this.m_pcmOffset = -1L;
     this.decodeClear();
     return -1;
   }
   while (this.m_pcmOffset < pos) {
     final int target2 = (int) (pos - this.m_pcmOffset);
     final int[] _index = new int[this.m_info[this.m_currentLink].channelsCount];
     int samples = this.m_dspState.synthesis_pcmout(this.m_pcmf_buffer, _index);
     if (samples > target2) {
       samples = target2;
     }
     this.m_dspState.synthesis_read(samples);
     this.m_pcmOffset += samples;
     if (samples < target2 && this.processPacket(true) == 0) {
       this.m_pcmOffset = this.pcmTotal(-1);
     }
   }
   return 0;
 }