summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/media/JetPlayer.h101
-rw-r--r--include/media/ToneGenerator.h1
-rw-r--r--include/media/mediametadataretriever.h5
-rw-r--r--media/libmedia/Android.mk5
-rw-r--r--media/libmedia/AudioTrack.cpp22
-rw-r--r--media/libmedia/IMediaMetadataRetriever.cpp2
-rw-r--r--media/libmedia/JetPlayer.cpp428
-rw-r--r--media/libmedia/ToneGenerator.cpp264
-rw-r--r--media/libmedia/mediarecorder.cpp2
9 files changed, 685 insertions, 145 deletions
diff --git a/include/media/JetPlayer.h b/include/media/JetPlayer.h
new file mode 100644
index 0000000..4268170
--- /dev/null
+++ b/include/media/JetPlayer.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+
+#ifndef JETPLAYER_H_
+#define JETPLAYER_H_
+
+#include <utils/threads.h>
+#include <nativehelper/jni.h>
+
+#include <libsonivox/jet.h>
+#include <libsonivox/eas_types.h>
+#include "AudioTrack.h"
+
+
+namespace android {
+
+typedef void (*jetevent_callback)(int eventType, int val1, int val2, void *cookie);
+
+class JetPlayer {
+
+public:
+
+ static const int JET_USERID_UPDATE = 1;
+ static const int JET_NUMQUEUEDSEGMENT_UPDATE = 2;
+ static const int JET_PAUSE_UPDATE = 3;
+
+ JetPlayer(jobject javaJetPlayer,
+ int maxTracks = 32,
+ int trackBufferSize = 1200);
+ ~JetPlayer();
+ int init();
+ int release();
+
+ int openFile(const char* url);
+ int closeFile();
+ int play();
+ int pause();
+ int queueSegment(int segmentNum, int libNum, int repeatCount, int transpose,
+ EAS_U32 muteFlags, EAS_U8 userID);
+ int setMuteFlags(EAS_U32 muteFlags, bool sync);
+ int setMuteFlag(int trackNum, bool muteFlag, bool sync);
+ int triggerClip(int clipId);
+
+ void setEventCallback(jetevent_callback callback);
+
+ int getMaxTracks() { return mMaxTracks; };
+
+
+private:
+ static int renderThread(void*);
+ int render();
+ void fireEventOnStatusChange();
+
+ JetPlayer() {} // no default constructor
+ void dump();
+ void dumpJetStatus(S_JET_STATUS* pJetStatus);
+
+ jetevent_callback mEventCallback;
+
+ jobject mJavaJetPlayerRef;
+ Mutex mMutex; // mutex to sync the render and playback thread with the JET calls
+ pid_t mTid;
+ Condition mCondition;
+ volatile bool mRender;
+ bool mPaused;
+
+ EAS_STATE mState;
+ int* mMemFailedVar;
+
+ int mMaxTracks; // max number of MIDI tracks, usually 32
+ EAS_DATA_HANDLE mEasData;
+ EAS_FILE_LOCATOR mEasJetFileLoc;
+ EAS_PCM* mAudioBuffer;// EAS renders the MIDI data into this buffer,
+ AudioTrack* mAudioTrack; // and we play it in this audio track
+ int mTrackBufferSize;
+ S_JET_STATUS mJetStatus;
+ S_JET_STATUS mPreviousJetStatus;
+
+ char mJetFilePath[256];
+
+
+}; // end class JetPlayer
+
+} // end namespace android
+
+
+
+#endif /*JETPLAYER_H_*/
diff --git a/include/media/ToneGenerator.h b/include/media/ToneGenerator.h
index da1489f..0ddfb8e 100644
--- a/include/media/ToneGenerator.h
+++ b/include/media/ToneGenerator.h
@@ -134,6 +134,7 @@ private:
Condition mWaitCbkCond; // condition enabling interface to wait for audio callback completion after a change is requested
float mVolume; // Volume applied to audio track
int mStreamType; // Audio stream used for output
+ int mProcessSize; // Size of audio blocks generated at a time by audioCallback() (in PCM frames).
bool initAudioTrack();
static void audioCallback(int event, void* user, void *info);
diff --git a/include/media/mediametadataretriever.h b/include/media/mediametadataretriever.h
index 05cba30..f2719d3 100644
--- a/include/media/mediametadataretriever.h
+++ b/include/media/mediametadataretriever.h
@@ -47,6 +47,11 @@ enum {
METADATA_KEY_RATING = 13,
METADATA_KEY_COMMENT = 14,
METADATA_KEY_COPYRIGHT = 15,
+ METADATA_KEY_BIT_RATE = 16,
+ METADATA_KEY_FRAME_RATE = 17,
+ METADATA_KEY_VIDEO_FORMAT = 18,
+ METADATA_KEY_VIDEO_HEIGHT = 19,
+ METADATA_KEY_VIDEO_WIDTH = 20,
// Add more here...
};
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index 650684a..2a697b9 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -16,10 +16,11 @@ LOCAL_SRC_FILES:= \
mediarecorder.cpp \
IMediaMetadataRetriever.cpp \
mediametadataretriever.cpp \
- ToneGenerator.cpp
+ ToneGenerator.cpp \
+ JetPlayer.cpp
LOCAL_SHARED_LIBRARIES := \
- libui libcutils libutils
+ libui libcutils libutils libsonivox
LOCAL_MODULE:= libmedia
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index d4f2e5a..ce65312 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -231,20 +231,22 @@ status_t AudioTrack::set(
mAudioTrack = track;
mCblkMemory = cblk;
mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer());
+ mCblk->out = 1;
+ // Update buffer size in case it has been limited by AudioFlinger during track creation
+ mFrameCount = mCblk->frameCount;
if (sharedBuffer == 0) {
mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
} else {
mCblk->buffers = sharedBuffer->pointer();
+ // Force buffer full condition as data is already present in shared memory
+ mCblk->stepUser(mFrameCount);
}
- mCblk->out = 1;
mCblk->volume[0] = mCblk->volume[1] = 0x1000;
mVolume[LEFT] = 1.0f;
mVolume[RIGHT] = 1.0f;
mSampleRate = sampleRate;
mStreamType = streamType;
mFormat = format;
- // Update buffer size in case it has been limited by AudioFlinger during track creation
- mFrameCount = mCblk->frameCount;
mChannelCount = channelCount;
mSharedBuffer = sharedBuffer;
mMuted = false;
@@ -327,11 +329,6 @@ void AudioTrack::start()
}
if (android_atomic_or(1, &mActive) == 0) {
- if (mSharedBuffer != 0) {
- // Force buffer full condition as data is already present in shared memory
- mCblk->user = mFrameCount;
- mCblk->flowControlFlag = 0;
- }
mNewPosition = mCblk->server + mUpdatePeriod;
if (t != 0) {
t->run("AudioTrackThread", THREAD_PRIORITY_AUDIO_CLIENT);
@@ -467,7 +464,6 @@ status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount
}
if (loopStart >= loopEnd ||
- loopStart < cblk->user ||
loopEnd - loopStart > mFrameCount) {
LOGW("setLoop invalid value: loopStart %d, loopEnd %d, loopCount %d, framecount %d, user %d", loopStart, loopEnd, loopCount, mFrameCount, cblk->user);
return BAD_VALUE;
@@ -958,12 +954,8 @@ uint32_t audio_track_cblk_t::framesAvailable_l()
uint32_t s = this->server;
if (out) {
- if (u < loopEnd) {
- return s + frameCount - u;
- } else {
- uint32_t limit = (s < loopStart) ? s : loopStart;
- return limit + frameCount - u;
- }
+ uint32_t limit = (s < loopStart) ? s : loopStart;
+ return limit + frameCount - u;
} else {
return frameCount + u - s;
}
diff --git a/media/libmedia/IMediaMetadataRetriever.cpp b/media/libmedia/IMediaMetadataRetriever.cpp
index 615ae37..85b5944 100644
--- a/media/libmedia/IMediaMetadataRetriever.cpp
+++ b/media/libmedia/IMediaMetadataRetriever.cpp
@@ -18,7 +18,7 @@
#include <stdint.h>
#include <sys/types.h>
#include <utils/Parcel.h>
-#include <graphics/SkBitmap.h>
+#include <SkBitmap.h>
#include <media/IMediaMetadataRetriever.h>
namespace android {
diff --git a/media/libmedia/JetPlayer.cpp b/media/libmedia/JetPlayer.cpp
new file mode 100644
index 0000000..f0edf88
--- /dev/null
+++ b/media/libmedia/JetPlayer.cpp
@@ -0,0 +1,428 @@
+/*
+ * Copyright (C) 2008 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 "JetPlayer-C"
+
+#include <utils/Log.h>
+#include <utils/threads.h>
+
+#include <media/JetPlayer.h>
+
+
+#ifdef HAVE_GETTID
+static pid_t myTid() { return gettid(); }
+#else
+static pid_t myTid() { return getpid(); }
+#endif
+
+
+namespace android
+{
+
+static const int MIX_NUM_BUFFERS = 4;
+static const S_EAS_LIB_CONFIG* pLibConfig = NULL;
+
+//-------------------------------------------------------------------------------------------------
+JetPlayer::JetPlayer(jobject javaJetPlayer, int maxTracks, int trackBufferSize) :
+ mEventCallback(NULL),
+ mJavaJetPlayerRef(javaJetPlayer),
+ mTid(-1),
+ mRender(false),
+ mPaused(false),
+ mMaxTracks(maxTracks),
+ mEasData(NULL),
+ mEasJetFileLoc(NULL),
+ mAudioTrack(NULL),
+ mTrackBufferSize(trackBufferSize)
+{
+ LOGV("JetPlayer constructor");
+ mPreviousJetStatus.currentUserID = -1;
+ mPreviousJetStatus.segmentRepeatCount = -1;
+ mPreviousJetStatus.numQueuedSegments = -1;
+ mPreviousJetStatus.paused = true;
+}
+
+//-------------------------------------------------------------------------------------------------
+JetPlayer::~JetPlayer()
+{
+ LOGV("~JetPlayer");
+ release();
+
+}
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::init()
+{
+ //Mutex::Autolock lock(&mMutex);
+
+ EAS_RESULT result;
+
+ // retrieve the EAS library settings
+ if (pLibConfig == NULL)
+ pLibConfig = EAS_Config();
+ if (pLibConfig == NULL) {
+ LOGE("JetPlayer::init(): EAS library configuration could not be retrieved, aborting.");
+ return EAS_FAILURE;
+ }
+
+ // init the EAS library
+ result = EAS_Init(&mEasData);
+ if( result != EAS_SUCCESS) {
+ LOGE("JetPlayer::init(): Error initializing Sonivox EAS library, aborting.");
+ mState = EAS_STATE_ERROR;
+ return result;
+ }
+ // init the JET library
+ result = JET_Init(mEasData, NULL, 0);
+ if( result != EAS_SUCCESS) {
+ LOGE("JetPlayer::init(): Error initializing JET library, aborting.");
+ mState = EAS_STATE_ERROR;
+ return result;
+ }
+
+ // create the output AudioTrack
+ mAudioTrack = new AudioTrack();
+ mAudioTrack->set(AudioTrack::MUSIC, //TODO parametrize this
+ pLibConfig->sampleRate,
+ 1, // format = PCM 16bits per sample,
+ pLibConfig->numChannels,
+ mTrackBufferSize,
+ 0);
+
+ // create render and playback thread
+ {
+ Mutex::Autolock l(mMutex);
+ LOGV("JetPlayer::init(): trying to start render thread");
+ createThreadEtc(renderThread, this, "jetRenderThread", ANDROID_PRIORITY_AUDIO);
+ mCondition.wait(mMutex);
+ }
+ if (mTid > 0) {
+ // render thread started, we're ready
+ LOGV("JetPlayer::init(): render thread(%d) successfully started.", mTid);
+ mState = EAS_STATE_READY;
+ } else {
+ LOGE("JetPlayer::init(): failed to start render thread.");
+ mState = EAS_STATE_ERROR;
+ return EAS_FAILURE;
+ }
+
+ return EAS_SUCCESS;
+}
+
+void JetPlayer::setEventCallback(jetevent_callback eventCallback)
+{
+ Mutex::Autolock l(mMutex);
+ mEventCallback = eventCallback;
+}
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::release()
+{
+ LOGV("JetPlayer::release()");
+ Mutex::Autolock lock(mMutex);
+ mPaused = true;
+ mRender = false;
+ if (mEasData) {
+ JET_Pause(mEasData);
+ JET_CloseFile(mEasData);
+ JET_Shutdown(mEasData);
+ EAS_Shutdown(mEasData);
+ }
+ if (mEasJetFileLoc) {
+ free(mEasJetFileLoc);
+ mEasJetFileLoc = NULL;
+ }
+ if (mAudioTrack) {
+ mAudioTrack->stop();
+ mAudioTrack->flush();
+ delete mAudioTrack;
+ mAudioTrack = NULL;
+ }
+ if (mAudioBuffer) {
+ delete mAudioBuffer;
+ mAudioBuffer = NULL;
+ }
+ mEasData = NULL;
+
+ return EAS_SUCCESS;
+}
+
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::renderThread(void* p) {
+
+ return ((JetPlayer*)p)->render();
+}
+
+//-------------------------------------------------------------------------------------------------
+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 ---------------------------------------
+
+ // nothing to render, wait for client thread to wake us up
+ while (!mRender)
+ {
+ LOGV("JetPlayer::render(): signal wait");
+ 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);
+ }
+
+ // update playback state
+ //LOGV("JetPlayer::render(): updating state");
+ JET_Status(mEasData, &mJetStatus);
+ fireEventOnStatusChange();
+ 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:
+ mAudioTrack->flush();
+ if (mAudioBuffer) {
+ delete [] mAudioBuffer;
+ mAudioBuffer = NULL;
+ }
+ mMutex.lock();
+ mTid = -1;
+ mCondition.signal();
+ mMutex.unlock();
+ return result;
+}
+
+
+//-------------------------------------------------------------------------------------------------
+// fire up an event if any of the status fields has changed
+// precondition: mMutex locked
+void JetPlayer::fireEventOnStatusChange()
+{
+ if( (mJetStatus.currentUserID != mPreviousJetStatus.currentUserID)
+ ||(mJetStatus.segmentRepeatCount != mPreviousJetStatus.segmentRepeatCount) ) {
+ if(mEventCallback) {
+ mEventCallback(
+ JetPlayer::JET_USERID_UPDATE,
+ mJetStatus.currentUserID,
+ mJetStatus.segmentRepeatCount,
+ mJavaJetPlayerRef);
+ }
+ mPreviousJetStatus.currentUserID = mJetStatus.currentUserID;
+ mPreviousJetStatus.segmentRepeatCount = mJetStatus.segmentRepeatCount;
+ }
+
+ if(mJetStatus.numQueuedSegments != mPreviousJetStatus.numQueuedSegments) {
+ if(mEventCallback) {
+ mEventCallback(
+ JetPlayer::JET_NUMQUEUEDSEGMENT_UPDATE,
+ mJetStatus.numQueuedSegments,
+ -1,
+ mJavaJetPlayerRef);
+ }
+ mPreviousJetStatus.numQueuedSegments = mJetStatus.numQueuedSegments;
+ }
+
+ if(mJetStatus.paused != mPreviousJetStatus.paused) {
+ if(mEventCallback) {
+ mEventCallback(JetPlayer::JET_PAUSE_UPDATE,
+ mJetStatus.paused,
+ -1,
+ mJavaJetPlayerRef);
+ }
+ mPreviousJetStatus.paused = mJetStatus.paused;
+ }
+
+}
+
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::openFile(const char* path)
+{
+ LOGV("JetPlayer::openFile(): path=%s", path);
+
+ Mutex::Autolock lock(mMutex);
+
+ mEasJetFileLoc = (EAS_FILE_LOCATOR) malloc(sizeof(EAS_FILE));
+ memset(mJetFilePath, 0, 256);
+ strncpy(mJetFilePath, path, strlen(path));
+ mEasJetFileLoc->path = mJetFilePath;
+
+ mEasJetFileLoc->fd = 0;
+ mEasJetFileLoc->length = 0;
+ mEasJetFileLoc->offset = 0;
+
+ EAS_RESULT result = JET_OpenFile(mEasData, mEasJetFileLoc);
+ if(result != EAS_SUCCESS)
+ mState = EAS_STATE_ERROR;
+ else
+ mState = EAS_STATE_OPEN;
+ return( result );
+}
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::closeFile()
+{
+ Mutex::Autolock lock(mMutex);
+ return JET_CloseFile(mEasData);
+}
+
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::play()
+{
+ LOGV("JetPlayer::play(): entering");
+ Mutex::Autolock lock(mMutex);
+
+ EAS_RESULT result = JET_Play(mEasData);
+
+ mPaused = false;
+ mRender = true;
+
+ JET_Status(mEasData, &mJetStatus);
+ this->dumpJetStatus(&mJetStatus);
+
+ fireEventOnStatusChange();
+
+ // wake up render thread
+ LOGV("JetPlayer::play(): wakeup render thread");
+ mCondition.signal();
+
+ return result;
+}
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::pause()
+{
+ Mutex::Autolock lock(mMutex);
+ mPaused = true;
+ EAS_RESULT result = JET_Pause(mEasData);
+
+ mRender = false;
+
+ JET_Status(mEasData, &mJetStatus);
+ this->dumpJetStatus(&mJetStatus);
+ fireEventOnStatusChange();
+
+
+ return result;
+}
+
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::queueSegment(int segmentNum, int libNum, int repeatCount, int transpose,
+ EAS_U32 muteFlags, EAS_U8 userID)
+{
+ LOGV("JetPlayer::queueSegment segmentNum=%d, libNum=%d, repeatCount=%d, transpose=%d",
+ segmentNum, libNum, repeatCount, transpose);
+ Mutex::Autolock lock(mMutex);
+ return JET_QueueSegment(mEasData, segmentNum, libNum, repeatCount, transpose, muteFlags, userID);
+}
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::setMuteFlags(EAS_U32 muteFlags, bool sync)
+{
+ Mutex::Autolock lock(mMutex);
+ return JET_SetMuteFlags(mEasData, muteFlags, sync);
+}
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::setMuteFlag(int trackNum, bool muteFlag, bool sync)
+{
+ Mutex::Autolock lock(mMutex);
+ return JET_SetMuteFlag(mEasData, trackNum, muteFlag, sync);
+}
+
+//-------------------------------------------------------------------------------------------------
+int JetPlayer::triggerClip(int clipId)
+{
+ LOGV("JetPlayer::triggerClip clipId=%d", clipId);
+ Mutex::Autolock lock(mMutex);
+ return JET_TriggerClip(mEasData, clipId);
+}
+
+//-------------------------------------------------------------------------------------------------
+void JetPlayer::dump()
+{
+ LOGE("JetPlayer dump: JET file=%s", mEasJetFileLoc->path);
+}
+
+void JetPlayer::dumpJetStatus(S_JET_STATUS* pJetStatus)
+{
+ if(pJetStatus!=NULL)
+ LOGV(">> current JET player status: userID=%d segmentRepeatCount=%d numQueuedSegments=%d paused=%d",
+ pJetStatus->currentUserID, pJetStatus->segmentRepeatCount,
+ pJetStatus->numQueuedSegments, pJetStatus->paused);
+ else
+ LOGE(">> JET player status is NULL");
+}
+
+
+} // end namespace android
+
diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp
index 0dee1f6..584d135 100644
--- a/media/libmedia/ToneGenerator.cpp
+++ b/media/libmedia/ToneGenerator.cpp
@@ -56,11 +56,11 @@ const ToneGenerator::ToneDescriptor
{ { 950, 1400, 1800, 0 }, { 330, 1000, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_SUP_ERROR
{ { 425, 0 }, { 200, 600, 200, 3000, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_SUP_CALL_WAITING
{ { 425, 0 }, { 1000, 4000, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_SUP_RINGTONE
- { { 400, 1200, 0 }, { 35, 0 }, 0 }, // TONE_PROP_BEEP
+ { { 400, 1200, 0 }, { 40, 0 }, 0 }, // TONE_PROP_BEEP
{ { 1200, 0 }, { 100, 100, 0 }, 1 }, // TONE_PROP_ACK
{ { 300, 400, 500, 0 }, { 400, 0 }, 0 }, // TONE_PROP_NACK
{ { 400, 1200, 0 }, { 200, 0 }, 0 }, // TONE_PROP_PROMPT
- { { 400, 1200, 0 }, { 35, 200, 35, 0 }, 0 } // TONE_PROP_BEEP2
+ { { 400, 1200, 0 }, { 40, 200, 40, 0 }, 0 } // TONE_PROP_BEEP2
};
////////////////////////////////////////////////////////////////////////////////
@@ -106,6 +106,8 @@ ToneGenerator::ToneGenerator(int streamType, float volume) {
mpAudioTrack = 0;
mpToneDesc = 0;
mpNewToneDesc = 0;
+ // Generate tone by chunks of 20 ms to keep cadencing precision
+ mProcessSize = (mSamplingRate * 20) / 1000;
if (initAudioTrack()) {
LOGV("ToneGenerator INIT OK, time: %d\n", (unsigned int)(systemTime()/1000000));
@@ -330,150 +332,162 @@ void ToneGenerator::audioCallback(int event, void* user, void *info) {
const AudioTrack::Buffer *buffer = static_cast<const AudioTrack::Buffer *>(info);
ToneGenerator *lpToneGen = static_cast<ToneGenerator *>(user);
short *lpOut = buffer->i16;
- unsigned int lReqSmp = buffer->size/sizeof(short);
- unsigned int lGenSmp;
- unsigned int lWaveCmd = WaveGenerator::WAVEGEN_CONT;
- bool lSignal = false;
+ unsigned int lNumSmp = buffer->size/sizeof(short);
if (buffer->size == 0) return;
- lpToneGen->mLock.lock();
// Clear output buffer: WaveGenerator accumulates into lpOut buffer
memset(lpOut, 0, buffer->size);
- // Update pcm frame count and end time (current time at the end of this process)
- lpToneGen->mTotalSmp += lReqSmp;
-
- // Update tone gen state machine and select wave gen command
- switch (lpToneGen->mState) {
- case TONE_PLAYING:
- lWaveCmd = WaveGenerator::WAVEGEN_CONT;
- break;
- case TONE_STARTING:
- LOGV("Starting Cbk");
-
- lWaveCmd = WaveGenerator::WAVEGEN_START;
- break;
- case TONE_STOPPING:
- case TONE_RESTARTING:
- LOGV("Stop/restart Cbk");
-
- lWaveCmd = WaveGenerator::WAVEGEN_STOP;
- lpToneGen->mNextSegSmp = TONEGEN_INF; // forced to skip state machine management below
- break;
- default:
- LOGV("Extra Cbk");
- goto audioCallback_Exit;
- }
-
- // Exit if tone sequence is over
- if (lpToneGen->mpToneDesc->segments[lpToneGen->mCurSegment] == 0) {
- if (lpToneGen->mState == TONE_PLAYING) {
- lpToneGen->mState = TONE_STOPPING;
- }
- goto audioCallback_Exit;
- }
-
- if (lpToneGen->mTotalSmp > lpToneGen->mNextSegSmp) {
- // Time to go to next sequence segment
+ while (lNumSmp) {
+ unsigned int lReqSmp = lNumSmp < lpToneGen->mProcessSize*2 ? lNumSmp : lpToneGen->mProcessSize;
+ unsigned int lGenSmp;
+ unsigned int lWaveCmd = WaveGenerator::WAVEGEN_CONT;
+ bool lSignal = false;
+
+ lpToneGen->mLock.lock();
- LOGV("End Segment, time: %d\n", (unsigned int)(systemTime()/1000000));
-
- lGenSmp = lReqSmp;
-
- if (lpToneGen->mCurSegment & 0x0001) {
- // If odd segment, OFF -> ON transition : reset wave generator
+ // Update pcm frame count and end time (current time at the end of this process)
+ lpToneGen->mTotalSmp += lReqSmp;
+
+ // Update tone gen state machine and select wave gen command
+ switch (lpToneGen->mState) {
+ case TONE_PLAYING:
+ lWaveCmd = WaveGenerator::WAVEGEN_CONT;
+ break;
+ case TONE_STARTING:
+ LOGV("Starting Cbk");
+
lWaveCmd = WaveGenerator::WAVEGEN_START;
-
- LOGV("OFF->ON, lGenSmp: %d, lReqSmp: %d\n", lGenSmp, lReqSmp);
- } else {
- // If even segment, ON -> OFF transition : ramp volume down
+ break;
+ case TONE_STOPPING:
+ case TONE_RESTARTING:
+ LOGV("Stop/restart Cbk");
+
lWaveCmd = WaveGenerator::WAVEGEN_STOP;
-
- LOGV("ON->OFF, lGenSmp: %d, lReqSmp: %d\n", lGenSmp, lReqSmp);
+ lpToneGen->mNextSegSmp = TONEGEN_INF; // forced to skip state machine management below
+ break;
+ default:
+ LOGV("Extra Cbk");
+ goto audioCallback_EndLoop;
}
-
- // Pre increment segment index and handle loop if last segment reached
- if (lpToneGen->mpToneDesc->segments[++lpToneGen->mCurSegment] == 0) {
- LOGV("Last Seg: %d\n", lpToneGen->mCurSegment);
-
- // Pre increment loop count and restart if total count not reached. Stop sequence otherwise
- if (++lpToneGen->mCurCount <= lpToneGen->mpToneDesc->repeatCnt) {
- LOGV("Repeating Count: %d\n", lpToneGen->mCurCount);
-
- lpToneGen->mCurSegment = 0;
-
- LOGV("New segment %d, Next Time: %d\n", lpToneGen->mCurSegment,
- (lpToneGen->mNextSegSmp*1000)/lpToneGen->mSamplingRate);
-
+
+
+ // Exit if tone sequence is over
+ if (lpToneGen->mpToneDesc->segments[lpToneGen->mCurSegment] == 0) {
+ if (lpToneGen->mState == TONE_PLAYING) {
+ lpToneGen->mState = TONE_STOPPING;
+ }
+ goto audioCallback_EndLoop;
+ }
+
+ if (lpToneGen->mTotalSmp > lpToneGen->mNextSegSmp) {
+ // Time to go to next sequence segment
+
+ LOGV("End Segment, time: %d\n", (unsigned int)(systemTime()/1000000));
+
+ lGenSmp = lReqSmp;
+
+ if (lpToneGen->mCurSegment & 0x0001) {
+ // If odd segment, OFF -> ON transition : reset wave generator
+ lWaveCmd = WaveGenerator::WAVEGEN_START;
+
+ LOGV("OFF->ON, lGenSmp: %d, lReqSmp: %d\n", lGenSmp, lReqSmp);
} else {
- LOGV("End repeat, time: %d\n", (unsigned int)(systemTime()/1000000));
-
- // Cancel OFF->ON transition in case previous segment tone state was OFF
- if (!(lpToneGen->mCurSegment & 0x0001)) {
- lGenSmp = 0;
+ // If even segment, ON -> OFF transition : ramp volume down
+ lWaveCmd = WaveGenerator::WAVEGEN_STOP;
+
+ LOGV("ON->OFF, lGenSmp: %d, lReqSmp: %d\n", lGenSmp, lReqSmp);
+ }
+
+ // Pre increment segment index and handle loop if last segment reached
+ if (lpToneGen->mpToneDesc->segments[++lpToneGen->mCurSegment] == 0) {
+ LOGV("Last Seg: %d\n", lpToneGen->mCurSegment);
+
+ // Pre increment loop count and restart if total count not reached. Stop sequence otherwise
+ if (++lpToneGen->mCurCount <= lpToneGen->mpToneDesc->repeatCnt) {
+ LOGV("Repeating Count: %d\n", lpToneGen->mCurCount);
+
+ lpToneGen->mCurSegment = 0;
+
+ LOGV("New segment %d, Next Time: %d\n", lpToneGen->mCurSegment,
+ (lpToneGen->mNextSegSmp*1000)/lpToneGen->mSamplingRate);
+
+ } else {
+ LOGV("End repeat, time: %d\n", (unsigned int)(systemTime()/1000000));
+
+ // Cancel OFF->ON transition in case previous segment tone state was OFF
+ if (!(lpToneGen->mCurSegment & 0x0001)) {
+ lGenSmp = 0;
+ }
}
+ } else {
+ LOGV("New segment %d, Next Time: %d\n", lpToneGen->mCurSegment,
+ (lpToneGen->mNextSegSmp*1000)/lpToneGen->mSamplingRate);
}
+
+ // Update next segment transition position. No harm to do it also for last segment as lpToneGen->mNextSegSmp won't be used any more
+ lpToneGen->mNextSegSmp
+ += (lpToneGen->mpToneDesc->segments[lpToneGen->mCurSegment] * lpToneGen->mSamplingRate) / 1000;
+
} else {
- LOGV("New segment %d, Next Time: %d\n", lpToneGen->mCurSegment,
- (lpToneGen->mNextSegSmp*1000)/lpToneGen->mSamplingRate);
- }
-
- // Update next segment transition position. No harm to do it also for last segment as lpToneGen->mNextSegSmp won't be used any more
- lpToneGen->mNextSegSmp
- += (lpToneGen->mpToneDesc->segments[lpToneGen->mCurSegment] * lpToneGen->mSamplingRate) / 1000;
-
- } else {
- // Inside a segment keep tone ON or OFF
- if (lpToneGen->mCurSegment & 0x0001) {
- lGenSmp = 0; // If odd segment, tone is currently OFF
- } else {
- lGenSmp = lReqSmp; // If event segment, tone is currently ON
+ // Inside a segment keep tone ON or OFF
+ if (lpToneGen->mCurSegment & 0x0001) {
+ lGenSmp = 0; // If odd segment, tone is currently OFF
+ } else {
+ lGenSmp = lReqSmp; // If event segment, tone is currently ON
+ }
}
- }
-
- if (lGenSmp) {
- // If samples must be generated, call all active wave generators and acumulate waves in lpOut
- unsigned int lWaveIdx;
-
- for (lWaveIdx = 0; lWaveIdx < (unsigned int)lpToneGen->mWaveGens.size(); lWaveIdx++) {
- WaveGenerator *lpWaveGen = lpToneGen->mWaveGens[lWaveIdx];
- lpWaveGen->getSamples(lpOut, lGenSmp, lWaveCmd);
+
+ if (lGenSmp) {
+ // If samples must be generated, call all active wave generators and acumulate waves in lpOut
+ unsigned int lWaveIdx;
+
+ for (lWaveIdx = 0; lWaveIdx < (unsigned int)lpToneGen->mWaveGens.size(); lWaveIdx++) {
+ WaveGenerator *lpWaveGen = lpToneGen->mWaveGens[lWaveIdx];
+ lpWaveGen->getSamples(lpOut, lGenSmp, lWaveCmd);
+ }
}
- }
-
-audioCallback_Exit:
-
- switch (lpToneGen->mState) {
- case TONE_RESTARTING:
- LOGV("Cbk restarting track\n");
- if (lpToneGen->prepareWave()) {
- lpToneGen->mState = TONE_STARTING;
- } else {
+
+ lNumSmp -= lReqSmp;
+ lpOut += lReqSmp;
+
+audioCallback_EndLoop:
+
+ switch (lpToneGen->mState) {
+ case TONE_RESTARTING:
+ LOGV("Cbk restarting track\n");
+ if (lpToneGen->prepareWave()) {
+ lpToneGen->mState = TONE_STARTING;
+ } else {
+ lpToneGen->mState = TONE_INIT;
+ lpToneGen->mpAudioTrack->stop();
+ }
+ lSignal = true;
+ break;
+ case TONE_STOPPING:
lpToneGen->mState = TONE_INIT;
+ LOGV("Cbk Stopping track\n");
+ lSignal = true;
lpToneGen->mpAudioTrack->stop();
+
+ // Force loop exit
+ lNumSmp = 0;
+ break;
+ case TONE_STARTING:
+ LOGV("Cbk starting track\n");
+ lpToneGen->mState = TONE_PLAYING;
+ lSignal = true;
+ break;
+ default:
+ break;
}
- lSignal = true;
- break;
- case TONE_STOPPING:
- lpToneGen->mState = TONE_INIT;
- LOGV("Cbk Stopping track\n");
- lSignal = true;
- lpToneGen->mpAudioTrack->stop();
- break;
- case TONE_STARTING:
- LOGV("Cbk starting track\n");
- lpToneGen->mState = TONE_PLAYING;
- lSignal = true;
- break;
- default:
- break;
- }
- if (lSignal)
- lpToneGen->mWaitCbkCond.signal();
- lpToneGen->mLock.unlock();
+ if (lSignal)
+ lpToneGen->mWaitCbkCond.signal();
+ lpToneGen->mLock.unlock();
+ }
}
diff --git a/media/libmedia/mediarecorder.cpp b/media/libmedia/mediarecorder.cpp
index 825e145..6ee4c0d 100644
--- a/media/libmedia/mediarecorder.cpp
+++ b/media/libmedia/mediarecorder.cpp
@@ -493,8 +493,6 @@ MediaRecorder::MediaRecorder()
if (service != NULL) {
mMediaRecorder = service->createMediaRecorder(getpid());
}
-
- mMediaRecorder = service->createMediaRecorder(getpid());
if (mMediaRecorder != NULL) {
mCurrentState = MEDIA_RECORDER_IDLE;
}