MediaBuffer* MidiEngine::readBuffer() { EAS_STATE state; EAS_State(mEasData, mEasHandle, &state); if ((state == EAS_STATE_STOPPED) || (state == EAS_STATE_ERROR)) { return NULL; } MediaBuffer *buffer; status_t err = mGroup->acquire_buffer(&buffer); if (err != OK) { ALOGE("readBuffer: no buffer"); return NULL; } EAS_I32 timeMs; EAS_GetLocation(mEasData, mEasHandle, &timeMs); int64_t timeUs = 1000ll * timeMs; buffer->meta_data()->setInt64(kKeyTime, timeUs); EAS_PCM* p = (EAS_PCM*) buffer->data(); int numBytesOutput = 0; for (int i = 0; i < NUM_COMBINE_BUFFERS; i++) { EAS_I32 numRendered; EAS_RESULT result = EAS_Render(mEasData, p, mEasConfig->mixBufferSize, &numRendered); if (result != EAS_SUCCESS) { ALOGE("EAS_Render returned %ld", result); break; } p += numRendered * mEasConfig->numChannels; numBytesOutput += numRendered * mEasConfig->numChannels * sizeof(EAS_PCM); } buffer->set_range(0, numBytesOutput); ALOGV("readBuffer: returning %zd in buffer %p", buffer->range_length(), buffer); return buffer; }
status_t MidiFile::start() { ALOGV("MidiFile::start"); Mutex::Autolock lock(mMutex); if (!mEasHandle) { return ERROR_NOT_OPEN; } if (mState == EAS_STATE_STOPPED) { int mStartTime = (mPlayTime >= mDuration) ? 0 : mPlayTime; if (EAS_Locate(mEasData, mEasHandle, mStartTime, false) != EAS_SUCCESS) { ALOGE("EAS_Locate failed"); return ERROR_EAS_FAILURE; } EAS_GetLocation(mEasData, mEasHandle, &mPlayTime); } // resuming after pause? if (mPaused) { if (EAS_Resume(mEasData, mEasHandle) != EAS_SUCCESS) { return ERROR_EAS_FAILURE; } mPaused = false; updateState(); } mRender = true; // Due to the limitation of EAS_XXX interfaces design, there's no way // to restart midi playback again once last track reaches EOS. // Here introduces a hack to enforce start again mState = EAS_STATE_PLAY; if (mState == EAS_STATE_PLAY) { sendEvent(MEDIA_STARTED); } // wake up render thread ALOGV(" wakeup render thread"); mCondition.signal(); 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; }
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"); mPlayTime = mDuration; 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; }
static EAS_RESULT PlayFile (EAS_DATA_HANDLE easData, const char* filename, const char* outputFile, const S_EAS_LIB_CONFIG *pLibConfig, void *buffer, EAS_I32 bufferSize) { EAS_HANDLE handle; EAS_RESULT result, reportResult; EAS_I32 count; EAS_STATE state; EAS_I32 playTime; char waveFilename[256]; WAVE_FILE *wFile; EAS_INT i; EAS_PCM *p; EAS_FILE file; /* determine the name of the output file */ wFile = NULL; if (outputFile == NULL) { StrCopy(waveFilename, filename, sizeof(waveFilename)); if (!ChangeFileExt(waveFilename, "wav", sizeof(waveFilename))) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error in output filename %s\n", waveFilename); */ } return EAS_FAILURE; } outputFile = waveFilename; } /* call EAS library to open file */ file.path = filename; file.fd = 0; if ((reportResult = EAS_OpenFile(easData, &file, &handle)) != EAS_SUCCESS) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_OpenFile returned %ld\n", reportResult); */ } return reportResult; } /* prepare to play the file */ if ((result = EAS_Prepare(easData, handle)) != EAS_SUCCESS) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_Prepare returned %ld\n", result); */ } reportResult = result; } /* get play length */ if ((result = EAS_ParseMetaData(easData, handle, &playTime)) != EAS_SUCCESS) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_ParseMetaData returned %ld\n", result); */ } return result; } EAS_ReportEx(_EAS_SEVERITY_NOFILTER, 0xe624f4d9, 0x00000005 , playTime / 1000, playTime % 1000); if (reportResult == EAS_SUCCESS) { /* create the output file */ wFile = WaveFileCreate(outputFile, pLibConfig->numChannels, pLibConfig->sampleRate, sizeof(EAS_PCM) * 8); if (!wFile) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Unable to create output file %s\n", waveFilename); */ } reportResult = EAS_FAILURE; } } /* rendering loop */ while (reportResult == EAS_SUCCESS) { /* we may render several buffers here to fill one host buffer */ for (i = 0, p = buffer; i < NUM_BUFFERS; i++, p+= pLibConfig->mixBufferSize * pLibConfig->numChannels) { /* get the current time */ if ((result = EAS_GetLocation(easData, handle, &playTime)) != EAS_SUCCESS) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_GetLocation returned %d\n",result); */ } if (reportResult == EAS_SUCCESS) reportResult = result; break; } { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Parser time: %d.%03d\n", playTime / 1000, playTime % 1000); */ } /* render a buffer of audio */ if ((result = EAS_Render(easData, p, pLibConfig->mixBufferSize, &count)) != EAS_SUCCESS) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_Render returned %d\n",result); */ } if (reportResult == EAS_SUCCESS) reportResult = result; } } if (result == EAS_SUCCESS) { /* write it to the wave file */ if (WaveFileWrite(wFile, buffer, bufferSize) != bufferSize) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "WaveFileWrite failed\n"); */ } reportResult = EAS_FAILURE; } } if (reportResult == EAS_SUCCESS) { /* check stream state */ if ((result = EAS_State(easData, handle, &state)) != EAS_SUCCESS) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_State returned %d\n", result); */ } reportResult = result; } /* is playback complete */ if ((state == EAS_STATE_STOPPED) || (state == EAS_STATE_ERROR)) break; } } /* close the output file */ if (wFile) { if (!WaveFileClose(wFile)) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error closing wave file %s\n", waveFilename); */ } if (reportResult == EAS_SUCCESS) result = EAS_FAILURE; } } /* close the input file */ if ((result = EAS_CloseFile(easData,handle)) != EAS_SUCCESS) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_Close returned %ld\n", result); */ } if (reportResult == EAS_SUCCESS) result = EAS_FAILURE; } return reportResult; } /* end PlayFile */