/**
   * Initializes the basic audio track to be able to playback.
   *
   * @param sampleRate The sample rate of the track
   * @param numChannels The number of channels available in the track.
   */
  private void initDevice(int sampleRate, int numChannels) throws IOException {
    L.d(TAG, "initDevice called in state:" + state);
    lock.lock();
    try {
      final int format = findFormatFromChannels(numChannels);
      final int minSize =
          AudioTrack.getMinBufferSize(sampleRate, format, AudioFormat.ENCODING_PCM_16BIT);

      if (minSize == AudioTrack.ERROR || minSize == AudioTrack.ERROR_BAD_VALUE) {
        L.e(TAG, "minSize=" + minSize);
        throw new IOException("getMinBufferSize returned " + minSize);
      }
      track =
          new AudioTrack(
              AudioManager.STREAM_MUSIC,
              sampleRate,
              format,
              AudioFormat.ENCODING_PCM_16BIT,
              minSize * 4,
              AudioTrack.MODE_STREAM);
      sonic = new Sonic(sampleRate, numChannels);
    } finally {
      lock.unlock();
    }
  }
 @Override
 public void reset() {
   L.v(TAG, "reset called in state: " + state);
   stayAwake(false);
   lock.lock();
   try {
     continuing = false;
     try {
       if (state != State.PLAYBACK_COMPLETED) {
         while (isDecoding) {
           synchronized (decoderLock) {
             decoderLock.notify();
             decoderLock.wait();
           }
         }
       }
     } catch (InterruptedException e) {
       L.e(TAG, "Interrupted in reset while waiting for decoder thread to stop.", e);
     }
     if (codec != null) {
       codec.release();
       L.d(TAG, "releasing codec");
       codec = null;
     }
     if (extractor != null) {
       extractor.release();
       extractor = null;
     }
     if (track != null) {
       track.release();
       track = null;
     }
     state = State.IDLE;
     L.d(TAG, "State changed to: " + state);
   } finally {
     lock.unlock();
   }
 }
 private void error(String methodName) {
   L.e(TAG, "Error in " + methodName + " at state=" + state);
   state = State.ERROR;
   stayAwake(false);
 }