diff options
Diffstat (limited to 'media/libmediaplayerservice/MidiFile.cpp')
-rw-r--r-- | media/libmediaplayerservice/MidiFile.cpp | 560 |
1 files changed, 0 insertions, 560 deletions
diff --git a/media/libmediaplayerservice/MidiFile.cpp b/media/libmediaplayerservice/MidiFile.cpp deleted file mode 100644 index 60cbd3c..0000000 --- a/media/libmediaplayerservice/MidiFile.cpp +++ /dev/null @@ -1,560 +0,0 @@ -/* MidiFile.cpp -** -** Copyright 2007, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -//#define LOG_NDEBUG 0 -#define LOG_TAG "MidiFile" -#include "utils/Log.h" - -#include <stdio.h> -#include <assert.h> -#include <limits.h> -#include <unistd.h> -#include <fcntl.h> -#include <sched.h> -#include <utils/threads.h> -#include <libsonivox/eas_reverb.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <unistd.h> - -#include <system/audio.h> - -#include "MidiFile.h" - -// ---------------------------------------------------------------------------- - -namespace android { - -// ---------------------------------------------------------------------------- - -// The midi engine buffers are a bit small (128 frames), so we batch them up -static const int NUM_BUFFERS = 4; - -// TODO: Determine appropriate return codes -static status_t ERROR_NOT_OPEN = -1; -static status_t ERROR_OPEN_FAILED = -2; -static status_t ERROR_EAS_FAILURE = -3; -static status_t ERROR_ALLOCATE_FAILED = -4; - -static const S_EAS_LIB_CONFIG* pLibConfig = NULL; - -MidiFile::MidiFile() : - mEasData(NULL), mEasHandle(NULL), mAudioBuffer(NULL), - mPlayTime(-1), mDuration(-1), mState(EAS_STATE_ERROR), - mStreamType(AUDIO_STREAM_MUSIC), mLoop(false), mExit(false), - mPaused(false), mRender(false), mTid(-1) -{ - ALOGV("constructor"); - - mFileLocator.path = NULL; - mFileLocator.fd = -1; - mFileLocator.offset = 0; - mFileLocator.length = 0; - - // get the library configuration and do sanity check - if (pLibConfig == NULL) - pLibConfig = EAS_Config(); - if ((pLibConfig == NULL) || (LIB_VERSION != pLibConfig->libVersion)) { - ALOGE("EAS library/header mismatch"); - goto Failed; - } - - // initialize EAS library - if (EAS_Init(&mEasData) != EAS_SUCCESS) { - ALOGE("EAS_Init failed"); - goto Failed; - } - - // select reverb preset and enable - EAS_SetParameter(mEasData, EAS_MODULE_REVERB, EAS_PARAM_REVERB_PRESET, EAS_PARAM_REVERB_CHAMBER); - EAS_SetParameter(mEasData, EAS_MODULE_REVERB, EAS_PARAM_REVERB_BYPASS, EAS_FALSE); - - // create playback thread - { - Mutex::Autolock l(mMutex); - mThread = new MidiFileThread(this); - mThread->run("midithread", ANDROID_PRIORITY_AUDIO); - mCondition.wait(mMutex); - ALOGV("thread started"); - } - - // indicate success - if (mTid > 0) { - ALOGV(" render thread(%d) started", mTid); - mState = EAS_STATE_READY; - } - -Failed: - return; -} - -status_t MidiFile::initCheck() -{ - if (mState == EAS_STATE_ERROR) return ERROR_EAS_FAILURE; - return NO_ERROR; -} - -MidiFile::~MidiFile() { - ALOGV("MidiFile destructor"); - release(); -} - -status_t MidiFile::setDataSource( - const sp<IMediaHTTPService> & /*httpService*/, - const char* path, - const KeyedVector<String8, String8> *) { - ALOGV("MidiFile::setDataSource url=%s", path); - Mutex::Autolock lock(mMutex); - - // file still open? - if (mEasHandle) { - reset_nosync(); - } - - // open file and set paused state - mFileLocator.path = strdup(path); - mFileLocator.fd = -1; - mFileLocator.offset = 0; - mFileLocator.length = 0; - EAS_RESULT result = EAS_OpenFile(mEasData, &mFileLocator, &mEasHandle); - if (result == EAS_SUCCESS) { - updateState(); - } - - if (result != EAS_SUCCESS) { - ALOGE("EAS_OpenFile failed: [%d]", (int)result); - mState = EAS_STATE_ERROR; - return ERROR_OPEN_FAILED; - } - - mState = EAS_STATE_OPEN; - mPlayTime = 0; - return NO_ERROR; -} - -status_t MidiFile::setDataSource(int fd, int64_t offset, int64_t length) -{ - ALOGV("MidiFile::setDataSource fd=%d", fd); - Mutex::Autolock lock(mMutex); - - // file still open? - if (mEasHandle) { - reset_nosync(); - } - - // open file and set paused state - mFileLocator.fd = dup(fd); - mFileLocator.offset = offset; - mFileLocator.length = length; - EAS_RESULT result = EAS_OpenFile(mEasData, &mFileLocator, &mEasHandle); - updateState(); - - if (result != EAS_SUCCESS) { - ALOGE("EAS_OpenFile failed: [%d]", (int)result); - mState = EAS_STATE_ERROR; - return ERROR_OPEN_FAILED; - } - - mState = EAS_STATE_OPEN; - mPlayTime = 0; - return NO_ERROR; -} - -status_t MidiFile::prepare() -{ - ALOGV("MidiFile::prepare"); - Mutex::Autolock lock(mMutex); - if (!mEasHandle) { - return ERROR_NOT_OPEN; - } - EAS_RESULT result; - if ((result = EAS_Prepare(mEasData, mEasHandle)) != EAS_SUCCESS) { - ALOGE("EAS_Prepare failed: [%ld]", result); - return ERROR_EAS_FAILURE; - } - updateState(); - return NO_ERROR; -} - -status_t MidiFile::prepareAsync() -{ - ALOGV("MidiFile::prepareAsync"); - status_t ret = prepare(); - - // don't hold lock during callback - if (ret == NO_ERROR) { - sendEvent(MEDIA_PREPARED); - } else { - sendEvent(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ret); - } - return ret; -} - -status_t MidiFile::start() -{ - ALOGV("MidiFile::start"); - Mutex::Autolock lock(mMutex); - if (!mEasHandle) { - return ERROR_NOT_OPEN; - } - - // resuming after pause? - if (mPaused) { - if (EAS_Resume(mEasData, mEasHandle) != EAS_SUCCESS) { - return ERROR_EAS_FAILURE; - } - mPaused = false; - updateState(); - } - - mRender = true; - if (mState == EAS_STATE_PLAY) { - sendEvent(MEDIA_STARTED); - } - - // wake up render thread - ALOGV(" wakeup render thread"); - mCondition.signal(); - return NO_ERROR; -} - -status_t MidiFile::stop() -{ - ALOGV("MidiFile::stop"); - Mutex::Autolock lock(mMutex); - if (!mEasHandle) { - return ERROR_NOT_OPEN; - } - if (!mPaused && (mState != EAS_STATE_STOPPED)) { - EAS_RESULT result = EAS_Pause(mEasData, mEasHandle); - if (result != EAS_SUCCESS) { - ALOGE("EAS_Pause returned error %ld", result); - return ERROR_EAS_FAILURE; - } - } - mPaused = false; - sendEvent(MEDIA_STOPPED); - return NO_ERROR; -} - -status_t MidiFile::seekTo(int position) -{ - ALOGV("MidiFile::seekTo %d", position); - // hold lock during EAS calls - { - Mutex::Autolock lock(mMutex); - if (!mEasHandle) { - return ERROR_NOT_OPEN; - } - EAS_RESULT result; - if ((result = EAS_Locate(mEasData, mEasHandle, position, false)) - != EAS_SUCCESS) - { - ALOGE("EAS_Locate returned %ld", result); - return ERROR_EAS_FAILURE; - } - EAS_GetLocation(mEasData, mEasHandle, &mPlayTime); - } - sendEvent(MEDIA_SEEK_COMPLETE); - return NO_ERROR; -} - -status_t MidiFile::pause() -{ - ALOGV("MidiFile::pause"); - Mutex::Autolock lock(mMutex); - if (!mEasHandle) { - return ERROR_NOT_OPEN; - } - if ((mState == EAS_STATE_PAUSING) || (mState == EAS_STATE_PAUSED)) return NO_ERROR; - if (EAS_Pause(mEasData, mEasHandle) != EAS_SUCCESS) { - return ERROR_EAS_FAILURE; - } - mPaused = true; - sendEvent(MEDIA_PAUSED); - return NO_ERROR; -} - -bool MidiFile::isPlaying() -{ - ALOGV("MidiFile::isPlaying, mState=%d", int(mState)); - if (!mEasHandle || mPaused) return false; - return (mState == EAS_STATE_PLAY || (mState == EAS_STATE_READY && mRender)); -} - -status_t MidiFile::getCurrentPosition(int* position) -{ - ALOGV("MidiFile::getCurrentPosition"); - if (!mEasHandle) { - ALOGE("getCurrentPosition(): file not open"); - return ERROR_NOT_OPEN; - } - if (mPlayTime < 0) { - ALOGE("getCurrentPosition(): mPlayTime = %ld", mPlayTime); - return ERROR_EAS_FAILURE; - } - *position = mPlayTime; - return NO_ERROR; -} - -status_t MidiFile::getDuration(int* duration) -{ - - ALOGV("MidiFile::getDuration"); - { - Mutex::Autolock lock(mMutex); - if (!mEasHandle) return ERROR_NOT_OPEN; - *duration = mDuration; - } - - // if no duration cached, get the duration - // don't need a lock here because we spin up a new engine - if (*duration < 0) { - EAS_I32 temp; - EAS_DATA_HANDLE easData = NULL; - EAS_HANDLE easHandle = NULL; - EAS_RESULT result = EAS_Init(&easData); - if (result == EAS_SUCCESS) { - result = EAS_OpenFile(easData, &mFileLocator, &easHandle); - } - if (result == EAS_SUCCESS) { - result = EAS_Prepare(easData, easHandle); - } - if (result == EAS_SUCCESS) { - result = EAS_ParseMetaData(easData, easHandle, &temp); - } - if (easHandle) { - EAS_CloseFile(easData, easHandle); - } - if (easData) { - EAS_Shutdown(easData); - } - - if (result != EAS_SUCCESS) { - return ERROR_EAS_FAILURE; - } - - // cache successful result - mDuration = *duration = int(temp); - } - - return NO_ERROR; -} - -status_t MidiFile::release() -{ - ALOGV("MidiFile::release"); - Mutex::Autolock l(mMutex); - reset_nosync(); - - // wait for render thread to exit - mExit = true; - mCondition.signal(); - - // wait for thread to exit - if (mAudioBuffer) { - mCondition.wait(mMutex); - } - - // release resources - if (mEasData) { - EAS_Shutdown(mEasData); - mEasData = NULL; - } - return NO_ERROR; -} - -status_t MidiFile::reset() -{ - ALOGV("MidiFile::reset"); - Mutex::Autolock lock(mMutex); - return reset_nosync(); -} - -// call only with mutex held -status_t MidiFile::reset_nosync() -{ - ALOGV("MidiFile::reset_nosync"); - sendEvent(MEDIA_STOPPED); - // close file - if (mEasHandle) { - EAS_CloseFile(mEasData, mEasHandle); - mEasHandle = NULL; - } - if (mFileLocator.path) { - free((void*)mFileLocator.path); - mFileLocator.path = NULL; - } - if (mFileLocator.fd >= 0) { - close(mFileLocator.fd); - } - mFileLocator.fd = -1; - mFileLocator.offset = 0; - mFileLocator.length = 0; - - mPlayTime = -1; - mDuration = -1; - mLoop = false; - mPaused = false; - mRender = false; - return NO_ERROR; -} - -status_t MidiFile::setLooping(int loop) -{ - ALOGV("MidiFile::setLooping"); - Mutex::Autolock lock(mMutex); - if (!mEasHandle) { - return ERROR_NOT_OPEN; - } - loop = loop ? -1 : 0; - if (EAS_SetRepeat(mEasData, mEasHandle, loop) != EAS_SUCCESS) { - return ERROR_EAS_FAILURE; - } - return NO_ERROR; -} - -status_t MidiFile::createOutputTrack() { - if (mAudioSink->open(pLibConfig->sampleRate, pLibConfig->numChannels, - CHANNEL_MASK_USE_CHANNEL_ORDER, AUDIO_FORMAT_PCM_16_BIT, 2 /*bufferCount*/) != NO_ERROR) { - ALOGE("mAudioSink open failed"); - return ERROR_OPEN_FAILED; - } - return NO_ERROR; -} - -int MidiFile::render() { - EAS_RESULT result = EAS_FAILURE; - EAS_I32 count; - int temp; - bool audioStarted = false; - - ALOGV("MidiFile::render"); - - // allocate render buffer - mAudioBuffer = new EAS_PCM[pLibConfig->mixBufferSize * pLibConfig->numChannels * NUM_BUFFERS]; - if (!mAudioBuffer) { - ALOGE("mAudioBuffer allocate failed"); - goto threadExit; - } - - // signal main thread that we started - { - Mutex::Autolock l(mMutex); - mTid = gettid(); - ALOGV("render thread(%d) signal", mTid); - mCondition.signal(); - } - - while (1) { - mMutex.lock(); - - // nothing to render, wait for client thread to wake us up - while (!mRender && !mExit) - { - ALOGV("MidiFile::render - signal wait"); - mCondition.wait(mMutex); - ALOGV("MidiFile::render - signal rx'd"); - } - if (mExit) { - mMutex.unlock(); - break; - } - - // render midi data into the input buffer - //ALOGV("MidiFile::render - rendering audio"); - int num_output = 0; - EAS_PCM* p = mAudioBuffer; - for (int i = 0; i < NUM_BUFFERS; i++) { - result = EAS_Render(mEasData, p, pLibConfig->mixBufferSize, &count); - if (result != EAS_SUCCESS) { - ALOGE("EAS_Render returned %ld", result); - } - p += count * pLibConfig->numChannels; - num_output += count * pLibConfig->numChannels * sizeof(EAS_PCM); - } - - // update playback state and position - // ALOGV("MidiFile::render - updating state"); - EAS_GetLocation(mEasData, mEasHandle, &mPlayTime); - EAS_State(mEasData, mEasHandle, &mState); - mMutex.unlock(); - - // create audio output track if necessary - if (!mAudioSink->ready()) { - ALOGV("MidiFile::render - create output track"); - if (createOutputTrack() != NO_ERROR) - goto threadExit; - } - - // Write data to the audio hardware - // ALOGV("MidiFile::render - writing to audio output"); - if ((temp = mAudioSink->write(mAudioBuffer, num_output)) < 0) { - ALOGE("Error in writing:%d",temp); - return temp; - } - - // start audio output if necessary - if (!audioStarted) { - //ALOGV("MidiFile::render - starting audio"); - mAudioSink->start(); - audioStarted = true; - } - - // still playing? - if ((mState == EAS_STATE_STOPPED) || (mState == EAS_STATE_ERROR) || - (mState == EAS_STATE_PAUSED)) - { - switch(mState) { - case EAS_STATE_STOPPED: - { - ALOGV("MidiFile::render - stopped"); - sendEvent(MEDIA_PLAYBACK_COMPLETE); - break; - } - case EAS_STATE_ERROR: - { - ALOGE("MidiFile::render - error"); - sendEvent(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN); - break; - } - case EAS_STATE_PAUSED: - ALOGV("MidiFile::render - paused"); - break; - default: - break; - } - mAudioSink->stop(); - audioStarted = false; - mRender = false; - } - } - -threadExit: - mAudioSink.clear(); - if (mAudioBuffer) { - delete [] mAudioBuffer; - mAudioBuffer = NULL; - } - mMutex.lock(); - mTid = -1; - mCondition.signal(); - mMutex.unlock(); - return result; -} - -} // end namespace android |