Android Open Source - rfcx-guardian-android Block Thread Manager






From Project

Back to project page rfcx-guardian-android.

License

The source code is released under:

Apache License

If you think the Android project rfcx-guardian-android listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
 * Copyright (C) 2010  Preston Lacey http://javaflacencoder.sourceforge.net/
 * All Rights Reserved./* w  w  w  .ja v  a 2s . co m*/
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

package net.sourceforge.javaFlacEncoder;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.Map;
import java.util.HashMap;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
import java.util.Vector;

/**
 * BlockThreadManager is used by FLACEncoder(when encoding with threads), to
 * dispatch BlockEncodeRequests to ThreadFrames which do the actual encode.
 *
 *
 * BlockThreadManager accepts BlockEncodeRequest objects to encode.
 * For each Frame object given to encode with, a Thread is supplied. This thread
 * will take a BlockEncodeRequest, encode it, then give it back to the BlockThreadManager
 * The thread will then take another BlockencodeRequest, and repeat. If no block
 * encode requests are available, it will block till available.
 *
 * 
 * The main thread of the BlockThreadManager will be waiting for additions to
 * the finished queue. If the item is not the next in line to be written to file,
 * it will be saved temporarily. If it is the next item to be written, it will
 * be given back to the FLACEncoder to be written to output, and any saved objects
 * will be searched to see if more can be written. The main thread will then wait
 * for the next frame again.
 *
 *
 *
 *
 * @author Preston Lacey
 */
public class BlockThreadManager implements Runnable{
  /* unassignedEncodeRequests: Requests waiting to be assigned a thread */
  LinkedBlockingQueue<BlockEncodeRequest> unassignedEncodeRequests = null;

  /* requests that have just finished encoding, and are ready for writing.
   * Since run() polls against this for newly finished requests, requests
   * recieved out of order will be temporarily stored in finishedRequestStore
   */
  LinkedBlockingQueue<BlockEncodeRequest> finishedEncodeRequests = null;

  /* pending requests in the order that we must pass them to the FLACEncoder.
   * The top object is moved to nextTarget until it is found in
   * finishedEncodeRequests and passed to the encoder. */
  LinkedBlockingQueue<BlockEncodeRequest> orderedEncodeRequests = null;

  /* frameThreadMap: Keep track of which thread is handling which frame */
  Map<FrameThread, Thread> frameThreadMap = null;

  /* Thread which watches for finished encodes and alerts FLACEncoder of their
   * finished state. This thread will die when there is no data to encode, but
   * should remain valid and unchanged so long as blocks are encoding or
   * queued. It may therefore be used to monitor/interrupt, an encode process.
   */
  volatile Thread managerThread = null;

  /* FLACEncoder object we will send finished requests to */
  volatile FLACEncoder encoder = null;

  /* Must be false if we've been explicitly told to stop. Adding new requests
   * will reset this value to true */
  volatile boolean process = true;

  /* FrameThreads that are not currently assigned to a Thread */
  Vector<FrameThread> inactiveFrameThreads = null;

  /* Lock ensures that only one FrameThread may get a new request at a time */
  private final Object getLock = new Object();

  /* Store finished requests that are not yet passed back to the FLACEncoder*/
  Vector<BlockEncodeRequest> finishedRequestStore = null;

  /* blockWhileQueueExceeds() waits on this lock for changes to queue size */
  private final Object outstandingCountLock = new Object();

  /* Next request which must be found and returned to the FLACEncoder. */
  volatile BlockEncodeRequest nextTarget = null;

  /* Number of requests added but not yet returned to FLACEncoder */
  volatile int outstandingCount = 0;
    
  /**
   * Constructor. Must supply a valid FLACEncoder object which will be alerted
   * when a block is finished encoding.
   * @param encoder FLACEncoder to use in encoding process.
   */
  public BlockThreadManager(FLACEncoder encoder) {
    this.encoder = encoder;
    unassignedEncodeRequests = new LinkedBlockingQueue<BlockEncodeRequest>();
    finishedEncodeRequests = new LinkedBlockingQueue<BlockEncodeRequest>();
    orderedEncodeRequests = new LinkedBlockingQueue<BlockEncodeRequest>();
    frameThreadMap = Collections.synchronizedMap(new HashMap<FrameThread, Thread>());
    inactiveFrameThreads = new Vector<FrameThread>();
    finishedRequestStore  = new Vector<BlockEncodeRequest>();
    managerThread = null;
  }

  /**
   * Get total number of BlockEncodeRequests added to this manager, but not
   * yet passed back to the FLACEncoder object.
   * @return number of BlockEncodeRequests remaining in this manager.
   */
  synchronized public int getTotalManagedCount() {
    return outstandingCount;
  }

  /**
   * This function is used to help control flow of BlockEncodeRequests into
   * this manager. It will block so long as their is at least as many
   * unprocessed blocks waiting to be encoded as the value given.
   *
   * @param count Maximum number of outstanding requests that may exist before
   * this method may return.
   */
  public void blockWhileQueueExceeds(int count) {
    boolean loop = true;
    boolean interrupted = false;
    try {
      do {
      synchronized(outstandingCountLock) {
        if(outstandingCount > count) {
          try {
            outstandingCountLock.wait();
          }catch(InterruptedException e) {
            //ignore interruption, loop again.
            interrupted = true;
          }
        }
        else
        loop = false;
        }
      }while(loop);
    }finally {
      if(interrupted)
      Thread.currentThread().interrupt();
    }
  }

  /**
   * Add a Frame to this manager, which it will use to encode a block. Each
   * Frame added allows one more thread to be used for encoding. At least one
   * Frame must be added for this manager to encode.
   * @param frame Frame to use for encoding.
   * @return boolean false if there was an error adding the frame, true
   * otherwise.
   */
  synchronized public boolean addFrameThread(Frame frame) {
    FrameThread ft = new FrameThread(frame, this);
    inactiveFrameThreads.add(ft);
    boolean r = true;
    startFrameThreads();
    return r;
  }

  /**
   * Start any available FrameThread objects encoding, so long as there are
   * waiting BlockEncodeRequest objects.
   *
   */
  synchronized private void startFrameThreads() {
    if(!process)
      return;
    int requests = unassignedEncodeRequests.size();
    int frames = inactiveFrameThreads.size();
    frames = (requests <= frames) ? requests:frames;
    for(int i = 0; i < frames; i++) {
      FrameThread ft = inactiveFrameThreads.remove(0);
      Thread thread = new Thread(ft);
      frameThreadMap.put(ft, thread);
      thread.start();
    }
  }

  /**
   * Notify this manager that a FrameThread has ended it's run() method,
   * returning the FrameThread object to the manager for use in future Threads.
   *
   * @param ft FrameThread object which is ending.
   */
  synchronized public void notifyFrameThreadExit(FrameThread ft) {
    frameThreadMap.remove(ft);
    inactiveFrameThreads.add(ft);
    startFrameThreads();
  }

  /**
   * Get a BlockEncodeRequest object which is queued for encoding, pausing for
   * up to 0.5 seconds till one is available. It is expected that this object
   * will later(after encoding to a FLAC frame) be returned to this manager
   * through the returnFinishedRequest method. Failure to return the finished
   * object will cause the encoding process to hang.
   *
   * @return BlockEncodingRequest to encode, null if none available.
   */
  public BlockEncodeRequest getWaitingRequest() {
    BlockEncodeRequest result = null;
    synchronized(getLock) {
      boolean loop = true;
      try {
        while(loop) {
          result = unassignedEncodeRequests.poll(500, TimeUnit.MILLISECONDS);
          if(result != null) {
            synchronized(outstandingCountLock) {
            outstandingCountLock.notifyAll();
          }
          orderedEncodeRequests.add(result);
          }
          loop = false;
        }
      } catch(InterruptedException e) {
          Thread.currentThread().interrupt();
      }
    }
    return result;
  }

  /**
   * Notify this manager that it may stop as soon as all currently outstanding
   * requests are completed. Future calls to addRequest() will clear this stop
   * state.
   */
  synchronized public void stop() {
    process = false;
    BlockEncodeRequest temp = new BlockEncodeRequest();
    temp.setAll(null, -1, -1, -1, -1, null);
    int count = frameThreadMap.size();
    for(int i = 0; i < count; i++) {
      unassignedEncodeRequests.add(temp);
    }
  }

  /**
   * Used to return a finished BlockEncodeRequest from a FrameThread. This
   * must only be called with a finished request, which was originally added
   * to this manager through the addRequest() method.
   *
   * @param ber finished BlockEncodeRequest that needs passed back to the
   * FLACEncoder object.
   *
   */
  synchronized public void returnFinishedRequest(BlockEncodeRequest ber) {
    try {
      finishedEncodeRequests.put(ber);
      restartManager();
    }catch(InterruptedException e) {
      returnFinishedRequest(ber);
      Thread.currentThread().interrupt();
    }
  }

/**
 * Waits for the next BlockEncodeRequest that needs to be sent back to the
 * FLACEncoder for finalizing. If no request is finished, or currently
 * assigned to an encoding thread, will timeout after 0.5 seconds and end.
 */
public void run () {
  //wait for finished item
  //send finished item to encoder
  //loop to top
  boolean loop = true;
  boolean interrupted = false;
  try {
    while(loop) {
      try {
        if(nextTarget == null)
          nextTarget = orderedEncodeRequests.poll(500,TimeUnit.MILLISECONDS);
        if(nextTarget == null) {
          loop = false;
        }
        else if(nextTarget.frameNumber < 0) {
          loop = false;
          nextTarget = null;
          orderedEncodeRequests.clear();
        }
        else if(finishedRequestStore.remove(nextTarget)) {
          encoder.blockFinished(nextTarget);
          nextTarget = null;
          synchronized(outstandingCountLock) {
            outstandingCount--;
            outstandingCountLock.notifyAll();
          }
        }
        else {
          BlockEncodeRequest ber = finishedEncodeRequests.poll(500, TimeUnit.MILLISECONDS);
          if(ber == null) {//nothing to process yet, let this thread end.
            loop = false;
          }
          else if(nextTarget == ber) {
            encoder.blockFinished(ber);
            nextTarget = null;
            synchronized(outstandingCountLock) {
              outstandingCount--;
              outstandingCountLock.notifyAll();
            }
          }
          else {
            finishedRequestStore.add(ber);
          }
        }
        }catch(InterruptedException e) {
          interrupted = true;
        }
      }
    }finally {
      if(interrupted)
      Thread.currentThread().interrupt();
    }
    synchronized(this) {
      managerThread = null;
      restartManager();
    }
  }

  /**
   * Attempt to restart the managerThread if possible/needed. This is the only
   * function that should *ever* call managerThread.start(). We should call
   * this at any time a managerThread may be needed but not started. For
   * example, after returning a BlockEncodeRequest from an encoding thread.
   */
  synchronized private void restartManager() {
    if(managerThread == null && orderedEncodeRequests.size() > 0 ) {
      managerThread = new Thread(this);
      managerThread.start();
    }
  }

  /**
   * Add a BlockEncodeRequest to the manager. This will immediately attempt
   * to assign a request to an encoding thread(which may not occur if no
   * threads are currently available). Requests are passed back to the
   * currently set FLACEncoder object when finished and ready to be written
   * to output.
   *
   * @param ber Block request to encode
   * @return boolean true if block added, false if an error occured.
   */
  synchronized public boolean addRequest(BlockEncodeRequest ber) {
    //add request to the manager(requests are automatically removed when complete)
    process = true;
    boolean r = true;
    try {
      unassignedEncodeRequests.put(ber);
      synchronized(outstandingCountLock) {
      outstandingCount++;
    }
    startFrameThreads();
    }catch(InterruptedException e) {
      r = false;
      Thread.currentThread().interrupt();
    }
    return r;
  }
}




Java Source Code List

net.sourceforge.javaFlacEncoder.ArrayRecycler.java
net.sourceforge.javaFlacEncoder.BlockEncodeRequest.java
net.sourceforge.javaFlacEncoder.BlockThreadManager.java
net.sourceforge.javaFlacEncoder.CRC16.java
net.sourceforge.javaFlacEncoder.CRC8.java
net.sourceforge.javaFlacEncoder.ChannelData.java
net.sourceforge.javaFlacEncoder.EncodedElement_32.java
net.sourceforge.javaFlacEncoder.EncodedElement.java
net.sourceforge.javaFlacEncoder.EncodingConfiguration.java
net.sourceforge.javaFlacEncoder.FLACEncoder.java
net.sourceforge.javaFlacEncoder.FLACFileOutputStream.java
net.sourceforge.javaFlacEncoder.FLACOutputStream.java
net.sourceforge.javaFlacEncoder.FLACStreamController.java
net.sourceforge.javaFlacEncoder.FLACStreamIdentifier.java
net.sourceforge.javaFlacEncoder.FLACStreamOutputStream.java
net.sourceforge.javaFlacEncoder.FLAC_ConsoleFileEncoder.java
net.sourceforge.javaFlacEncoder.FLAC_FileEncoder.java
net.sourceforge.javaFlacEncoder.FLAC_MD5.java
net.sourceforge.javaFlacEncoder.FrameHeader.java
net.sourceforge.javaFlacEncoder.FrameThread.java
net.sourceforge.javaFlacEncoder.Frame.java
net.sourceforge.javaFlacEncoder.LPC.java
net.sourceforge.javaFlacEncoder.MetadataBlockHeader.java
net.sourceforge.javaFlacEncoder.MetadataBlockStreamInfo.java
net.sourceforge.javaFlacEncoder.RiceEncoder.java
net.sourceforge.javaFlacEncoder.StreamConfiguration.java
net.sourceforge.javaFlacEncoder.Subframe_Constant.java
net.sourceforge.javaFlacEncoder.Subframe_Fixed.java
net.sourceforge.javaFlacEncoder.Subframe_LPC.java
net.sourceforge.javaFlacEncoder.Subframe_Verbatim.java
net.sourceforge.javaFlacEncoder.Subframe.java
net.sourceforge.javaFlacEncoder.UTF8Modified.java
org.rfcx.guardian.RfcxGuardianPrefs.java
org.rfcx.guardian.RfcxGuardian.java
org.rfcx.guardian.activity.MainActivity.java
org.rfcx.guardian.activity.PrefsActivity.java
org.rfcx.guardian.api.ApiCore.java
org.rfcx.guardian.audio.AudioCore.java
org.rfcx.guardian.database.AlertDb.java
org.rfcx.guardian.database.AudioDb.java
org.rfcx.guardian.database.DeviceStateDb.java
org.rfcx.guardian.database.SmsDb.java
org.rfcx.guardian.device.AirplaneMode.java
org.rfcx.guardian.device.CpuUsage.java
org.rfcx.guardian.device.DeviceState.java
org.rfcx.guardian.intentservice.ApiCheckInTriggerIntentService.java
org.rfcx.guardian.intentservice.AudioEncodeIntentService.java
org.rfcx.guardian.intentservice.ServiceMonitorIntentService.java
org.rfcx.guardian.receiver.AirplaneModeReceiver.java
org.rfcx.guardian.receiver.BootReceiver.java
org.rfcx.guardian.receiver.ConnectivityReceiver.java
org.rfcx.guardian.receiver.SmsReceiver.java
org.rfcx.guardian.service.ApiCheckInService.java
org.rfcx.guardian.service.AudioCaptureService.java
org.rfcx.guardian.service.CarrierCodeService.java
org.rfcx.guardian.service.DeviceStateService.java
org.rfcx.guardian.telecom.CarrierInteraction.java
org.rfcx.guardian.utility.DateTimeUtils.java
org.rfcx.guardian.utility.DeviceGuid.java
org.rfcx.guardian.utility.ExtAudioRecorderModified.java
org.rfcx.guardian.utility.FileUtils.java
org.rfcx.guardian.utility.HttpGet.java
org.rfcx.guardian.utility.HttpPostMultipart.java
org.rfcx.guardian.utility.TimeOfDay.java