Android Open Source - speech_trainer Record Play Task Manager






From Project

Back to project page speech_trainer.

License

The source code is released under:

GNU General Public License

If you think the Android project speech_trainer 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

/**
 * This file is part of Speech Trainer.//  w  w w  .  jav  a2  s .  c  o  m
 * Copyright (C) 2011 Jan Wrobel <wrr@mixedbit.org>
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package mixedbit.speechtrainer.controller;

import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;

import mixedbit.speechtrainer.Assertions;

/**
 * Strategy passed to the RecordPlayTask. Allows to customize how recording and
 * playing are performed. The strategy is responsible for storing and discarding
 * recorded audio data.
 */
interface RecordPlayStrategy {

    /**
     * Blocking method that is invoked repetitively by RecordPlayTask in the
     * RECORD state. Records audio data using a given recorder. The amount of
     * data recorded in a single call should not be large to make RecordPlayTask
     * responsive to cancellation.
     * 
     * @param recorder
     *            Started recorder. Strategy can use only
     *            Recorder.recordAudioData method. RecordPlayTask is responsible
     *            for executing Recorder.StartRecording and
     *            Recorder.StopRecording.
     * 
     * @return State to which RecordPlayTask should switch. RECORD - stay in the
     *         RECORD state and call handleRecord again (unless RecordPlayTask
     *         was terminated asynchronously). PLAY - switch to the PLAY state
     *         and call handlePlay (unless RecordPlayTask was terminated
     *         asynchronously). TERMINATE - terminate RecordPlayTask.
     */
    public RecordPlayTaskManager.RecordPlayTaskState handleRecord(Recorder recorder);

    /**
     * Blocking method that is invoked repetitively by RecordPlayTask in the
     * PLAY state. Plays recorded audio data using a given player. The amount of
     * data played in a single call should not be large to make RecordPlayTask
     * responsive to cancellation.
     * 
     * @param player
     *            Started player. Strategy can use only Player.playAudioData
     *            method. RecordPlayTask is responsible for executing
     *            Player.StartPlaying and Player.StopPlaying.
     * 
     * @return State to which RecordPlayTask should switch. PLAY - stay in the
     *         PLAY state and call handlePlay again (unless RecordPlayTask was
     *         terminated asynchronously). RECORD - switch to the RECORD state
     *         and call handleRecord (unless RecordPlayTask was terminated
     *         asynchronously). TERMINATE - terminate RecordPlayTask.
     */
    public RecordPlayTaskManager.RecordPlayTaskState handlePlay(Player player);
}

/**
 * Starts and terminates RecordPlayTask using a provided executor service. Every
 * started task needs to be terminated before another task can be started.
 */
class RecordPlayTaskManager {

    /**
     * State in which RecordPlayTask is. RECORD - the task is recording audio
     * data, PLAY - the task is playing audio data, TERMINATE - the task is
     * terminating.
     */
    enum RecordPlayTaskState {
        RECORD, PLAY, TERMINATE
    }

    /**
     * Should RecordPlayTask priority be increased. In production setup HIGH
     * priority should be always used. Increasing the priority fails in the
     * standard JUnit environment (it works only when JUnit tests are executed
     * on an Android device or emulator which is slow and doesn't support
     * mocking with EasyMock).
     */
    enum RecordPlayTaskPriority {
        HIGH, TEST,
    }

    private class RecordPlayTask implements Runnable {
        private RecordPlayTaskState recordPlayTaskState;
        private final RecordPlayStrategy recordPlayStrategy;
        private volatile boolean terminateRequested = false;

        /**
         * @param initialState
         *            Initial state in which the task is started.
         * @param recordPlayStrategy
         *            Strategy to which the task delegates recording and
         *            playing.
         */
        public RecordPlayTask(RecordPlayTaskState initialState,
                RecordPlayStrategy recordPlayStrategy) {
            this.recordPlayTaskState = initialState;
            this.recordPlayStrategy = recordPlayStrategy;
        }

        /**
         * Asynchronous request to terminate the task. The task terminates after
         * it finishes processing currently executed action (recording or
         * playing). Can be called if the task already terminated.
         */
        public void requestTerminate() {
            terminateRequested = true;
        }

        public boolean terminateRequested() {
            return terminateRequested;
        }

        @Override
        public void run() {
            if (recordPlayTaskPriority == RecordPlayTaskPriority.HIGH) {
                android.os.Process.setThreadPriority(
                        android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
            }
            startServiceNeededInState(recordPlayTaskState);
            while (!terminateRequested()) {
                RecordPlayTaskState nextState = null;
                switch (recordPlayTaskState) {
                    case RECORD:
                        nextState = recordPlayStrategy.handleRecord(recorder);
                        break;
                    case PLAY:
                        nextState = recordPlayStrategy.handlePlay(player);
                        break;
                    case TERMINATE:
                        Assertions.check(false);
                }
                if (recordPlayTaskState != nextState) {
                    switchState(nextState);
                }
            }
            stopServiceNeededInState(recordPlayTaskState);
        }

        /**
         * Switches the task to the new state. Request the task to terminate if
         * the new state is TERMINATE. Stops a service used in the old state
         * (recorder or player) and starts a service needed in the new state.
         */
        private void switchState(RecordPlayTaskState newState) {
            stopServiceNeededInState(recordPlayTaskState);
            startServiceNeededInState(newState);
            if (newState == RecordPlayTaskState.TERMINATE) {
                requestTerminate();
            }
            recordPlayTaskState = newState;
        }

        private void startServiceNeededInState(RecordPlayTaskState state) {
            switch (state) {
                case PLAY:
                    player.startPlaying();
                    break;
                case RECORD:
                    recorder.startRecording();
                    break;
                case TERMINATE:
                    break;
            }
        }

        private void stopServiceNeededInState(RecordPlayTaskState state) {
            switch (state) {
                case PLAY:
                    player.stopPlaying();
                    break;
                case RECORD:
                    recorder.stopRecording();
                    break;
                case TERMINATE:
                    break;
            }
        }
    }

    private final Recorder recorder;
    private final Player player;
    // Currently running task or null if the task is not running.
    private RecordPlayTask recordPlayTask;
    // Future associated with the currently running task.
    private Future<?> recordPlayTaskFuture;
    private final ExecutorService executor;
    private final RecordPlayTaskPriority recordPlayTaskPriority;

    /**
     * @param executor
     *            Executor service for executing RecordPlay tasks.
     * @param recordPlayTaskPriority
     *            HIGH for production code, LOW_USE_ONLY_FOR_TESTS for unit
     *            tests.
     */
    public RecordPlayTaskManager(Recorder recorder, Player player, ExecutorService executor,
            RecordPlayTaskPriority recordPlayTaskPriority) {
        this.recorder = recorder;
        this.player = player;
        this.executor = executor;
        this.recordPlayTaskPriority = recordPlayTaskPriority;
    }

    /**
     * Starts a new task to play and record audio. If another task has been
     * already started, terminateRecordPlayTask must be called before
     * startRecordPlayTask can be called again.
     * 
     * @param initialState
     *            Defines if the task should start recording or playing.
     * @param recordPlayStrategy
     *            Strategy to be used by the task.
     */
    public void startTask(RecordPlayTaskState initialState, RecordPlayStrategy recordPlayStrategy) {
        Assertions.check(recordPlayTask == null);
        recordPlayTask = new RecordPlayTask(initialState, recordPlayStrategy);
        recordPlayTaskFuture = this.executor.submit(recordPlayTask);
    }

    /**
     * Request a running task to terminate and waits until the task exits. Can
     * be called if the task already terminated or wasn't started.
     */
    public void terminateTaskIfRunning() {
        if (recordPlayTask == null) {
            return;
        }
        recordPlayTask.requestTerminate();

        boolean waitInterrupted = false;
        do {
            try {
                waitInterrupted = false;
                this.recordPlayTaskFuture.get();
            } catch (final InterruptedException e) {
                waitInterrupted = true;
            } catch (final ExecutionException e) {
            } catch (final CancellationException e) {
            }
        } while (waitInterrupted);

        recordPlayTask = null;
        recordPlayTaskFuture = null;
    }
}




Java Source Code List

mixedbit.speechtrainer.AssertionsTest.java
mixedbit.speechtrainer.Assertions.java
mixedbit.speechtrainer.SpeechTrainerConfig.java
mixedbit.speechtrainer.TrainingApplication.java
mixedbit.speechtrainer.controller.AudioBufferAllocatorTest.java
mixedbit.speechtrainer.controller.AudioBufferAllocator.java
mixedbit.speechtrainer.controller.AudioEventListener.java
mixedbit.speechtrainer.controller.AutomaticTrainingControllerTest.java
mixedbit.speechtrainer.controller.AutomaticTrainingController.java
mixedbit.speechtrainer.controller.ControllerFactory.java
mixedbit.speechtrainer.controller.InteractiveTrainingControllerTest.java
mixedbit.speechtrainer.controller.InteractiveTrainingController.java
mixedbit.speechtrainer.controller.Player.java
mixedbit.speechtrainer.controller.RecordPlayTaskManagerTest.java
mixedbit.speechtrainer.controller.RecordPlayTaskManager.java
mixedbit.speechtrainer.controller.Recorder.java
mixedbit.speechtrainer.controller.SilenceFilterTest.java
mixedbit.speechtrainer.controller.SilenceFilter.java
mixedbit.speechtrainer.controller.SilenceLevelDetectorTest.java
mixedbit.speechtrainer.controller.SilenceLevelDetector.java
mixedbit.speechtrainer.controller.TrainingControllerTest.java
mixedbit.speechtrainer.controller.TrainingController.java
mixedbit.speechtrainer.model.AudioBufferInfo.java
mixedbit.speechtrainer.model.AudioEventCollectorTest.java
mixedbit.speechtrainer.model.AudioEventCollector.java
mixedbit.speechtrainer.model.AudioEventHistory.java
mixedbit.speechtrainer.view.AudioEventView.java
mixedbit.speechtrainer.view.FileViewerActivity.java
mixedbit.speechtrainer.view.TrainingActivity.java
mixedbit.speechtrainer.view.TrainingPreferenceActivity.java