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; }
// render void *render(void *data) { EAS_RESULT result; EAS_I32 numGenerated; EAS_I32 count; snd_pcm_sframes_t frames; snd_pcm_sframes_t size; // start loop while (flag == FALSE) { count = 0; while (count < bufferSize) { // lock pthread_mutex_lock(&mutex); // render if ((result = EAS_Render(pEASData, buffer + count, pLibConfig->mixBufferSize, &numGenerated)) != EAS_SUCCESS) { // unlock pthread_mutex_unlock(&mutex); break; } // unlock pthread_mutex_unlock(&mutex); // calculate count in samples count += numGenerated * pLibConfig->numChannels; } // calculate size in frames size = count / pLibConfig->numChannels; if (result == EAS_SUCCESS) { // write pcm frames = snd_pcm_writei(handle, buffer, size); // try to recover if error if (frames < 0) frames = snd_pcm_recover(handle, frames, 0); // else give up if (frames < 0) break; } } }
// this callback handler is called every time a buffer finishes // playing void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context) { EAS_RESULT result; EAS_I32 numGenerated; EAS_I32 count; assert(bq == bqPlayerBufferQueue); assert(NULL == context); // for streaming playback, replace this test by logic to fill the // next buffer count = 0; while (count < bufferSize) { // lock pthread_mutex_lock(&mutex); result = EAS_Render(pEASData, buffer + count, pLibConfig->mixBufferSize, &numGenerated); // unlock pthread_mutex_unlock(&mutex); assert(result == EAS_SUCCESS); count += numGenerated * pLibConfig->numChannels; } // enqueue another buffer result = (*bqPlayerBufferQueue)->Enqueue(bq, buffer, bufferSize * sizeof(EAS_PCM)); // the most likely other result is SL_RESULT_BUFFER_INSUFFICIENT, // which for this code example would indicate a programming error assert(SL_RESULT_SUCCESS == result); }
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 */
//------------------------------------------------------------------------------------------------- int JetPlayer::render() { EAS_RESULT result = EAS_FAILURE; EAS_I32 count; int temp; bool audioStarted = false; LOGV("JetPlayer::render(): entering"); // allocate render buffer mAudioBuffer = new EAS_PCM[pLibConfig->mixBufferSize * pLibConfig->numChannels * MIX_NUM_BUFFERS]; if (!mAudioBuffer) { LOGE("JetPlayer::render(): mAudioBuffer allocate failed"); goto threadExit; } // signal main thread that we started { Mutex::Autolock l(mMutex); mTid = myTid(); LOGV("JetPlayer::render(): render thread(%d) signal", mTid); mCondition.signal(); } while (1) { mMutex.lock(); // [[[[[[[[ LOCK --------------------------------------- if (mEasData == NULL) { mMutex.unlock(); LOGV("JetPlayer::render(): NULL EAS data, exiting render."); goto threadExit; } // nothing to render, wait for client thread to wake us up while (!mRender) { LOGV("JetPlayer::render(): signal wait"); if (audioStarted) { mAudioTrack->pause(); // we have to restart the playback once we start rendering again audioStarted = false; } mCondition.wait(mMutex); LOGV("JetPlayer::render(): signal rx'd"); } // render midi data into the input buffer int num_output = 0; EAS_PCM* p = mAudioBuffer; for (int i = 0; i < MIX_NUM_BUFFERS; i++) { result = EAS_Render(mEasData, p, pLibConfig->mixBufferSize, &count); if (result != EAS_SUCCESS) { LOGE("JetPlayer::render(): EAS_Render returned error %ld", result); } p += count * pLibConfig->numChannels; num_output += count * pLibConfig->numChannels * sizeof(EAS_PCM); // send events that were generated (if any) to the event callback fireEventsFromJetQueue(); } // update playback state //LOGV("JetPlayer::render(): updating state"); JET_Status(mEasData, &mJetStatus); fireUpdateOnStatusChange(); mPaused = mJetStatus.paused; mMutex.unlock(); // UNLOCK ]]]]]]]] ----------------------------------- // check audio output track if (mAudioTrack == NULL) { LOGE("JetPlayer::render(): output AudioTrack was not created"); goto threadExit; } // Write data to the audio hardware //LOGV("JetPlayer::render(): writing to audio output"); if ((temp = mAudioTrack->write(mAudioBuffer, num_output)) < 0) { LOGE("JetPlayer::render(): Error in writing:%d",temp); return temp; } // start audio output if necessary if (!audioStarted) { LOGV("JetPlayer::render(): starting audio playback"); mAudioTrack->start(); audioStarted = true; } }//while (1) threadExit: if (mAudioTrack) { mAudioTrack->stop(); mAudioTrack->flush(); } if (mAudioBuffer) { delete [] mAudioBuffer; mAudioBuffer = NULL; } mMutex.lock(); mTid = -1; mCondition.signal(); mMutex.unlock(); return result; }