OSDN Git Service

Fix issue 2304669: VoiceIME: starting and canceling voice IME yields persistent ...
authorEric Laurent <elaurent@google.com>
Sat, 5 Dec 2009 13:20:01 +0000 (05:20 -0800)
committerEric Laurent <elaurent@google.com>
Mon, 7 Dec 2009 13:37:47 +0000 (05:37 -0800)
Fixed AudioFlinger::openInput() broken in change ddb78e7753be03937ad57ce7c3c842c52bdad65e
so that an invalid IO handle (0) is returned in case of failure.
Applied the same correction to openOutput().
Modified RecordThread start procedure so that a failure occuring during the first read from audio input stream is detected and causes
the record start to fail.
Modified RecordThread stop procedure to make sure that audio input stream fd is closed before we exit the stop function.

Fixed AudioRecord JAVA and JNI implementation to take status of native AudioRecord::start() into account
and not change mRecordingState to RECORDSTATE_RECORDING if start fails.

core/jni/android_media_AudioRecord.cpp
libs/audioflinger/AudioFlinger.cpp
libs/audioflinger/AudioFlinger.h
media/java/android/media/AudioRecord.java
media/libmedia/AudioRecord.cpp

index 0be996d..d7485ae 100644 (file)
@@ -224,17 +224,17 @@ native_track_failure:
 
 
 // ----------------------------------------------------------------------------
-static void
+static int
 android_media_AudioRecord_start(JNIEnv *env, jobject thiz)
 {
     AudioRecord *lpRecorder = 
             (AudioRecord *)env->GetIntField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
     if (lpRecorder == NULL ) {
         jniThrowException(env, "java/lang/IllegalStateException", NULL);
-        return;
+        return AUDIORECORD_ERROR;
     }
     
-    lpRecorder->start();
+    return android_media_translateRecorderErrorCode(lpRecorder->start());
 }
 
 
@@ -482,7 +482,7 @@ static jint android_media_AudioRecord_get_min_buff_size(JNIEnv *env,  jobject th
 // ----------------------------------------------------------------------------
 static JNINativeMethod gMethods[] = {
     // name,               signature,  funcPtr
-    {"native_start",         "()V",    (void *)android_media_AudioRecord_start},
+    {"native_start",         "()I",    (void *)android_media_AudioRecord_start},
     {"native_stop",          "()V",    (void *)android_media_AudioRecord_stop},
     {"native_setup",         "(Ljava/lang/Object;IIIII)I",
                                        (void *)android_media_AudioRecord_setup},
index 9ec8de5..f3f6e4f 100644 (file)
@@ -3086,23 +3086,34 @@ bool AudioFlinger::RecordThread::threadLoop()
             }
             if (mActiveTrack != 0) {
                 if (mActiveTrack->mState == TrackBase::PAUSING) {
+                    if (!mStandby) {
+                        mInput->standby();
+                        mStandby = true;
+                    }
                     mActiveTrack.clear();
                     mStartStopCond.broadcast();
                 } else if (mActiveTrack->mState == TrackBase::RESUMING) {
-                    mRsmpInIndex = mFrameCount;
                     if (mReqChannelCount != mActiveTrack->channelCount()) {
                         mActiveTrack.clear();
-                    } else {
-                        mActiveTrack->mState = TrackBase::ACTIVE;
+                        mStartStopCond.broadcast();
+                    } else if (mBytesRead != 0) {
+                        // record start succeeds only if first read from audio input
+                        // succeeds
+                        if (mBytesRead > 0) {
+                            mActiveTrack->mState = TrackBase::ACTIVE;
+                        } else {
+                            mActiveTrack.clear();
+                        }
+                        mStartStopCond.broadcast();
                     }
-                    mStartStopCond.broadcast();
+                    mStandby = false;
                 }
-                mStandby = false;
             }
         }
 
         if (mActiveTrack != 0) {
-            if (mActiveTrack->mState != TrackBase::ACTIVE) {
+            if (mActiveTrack->mState != TrackBase::ACTIVE &&
+                mActiveTrack->mState != TrackBase::RESUMING) {
                 usleep(5000);
                 continue;
             }
@@ -3140,18 +3151,19 @@ bool AudioFlinger::RecordThread::threadLoop()
                             }
                         }
                         if (framesOut && mFrameCount == mRsmpInIndex) {
-                            ssize_t bytesRead;
                             if (framesOut == mFrameCount &&
                                 (mChannelCount == mReqChannelCount || mFormat != AudioSystem::PCM_16_BIT)) {
-                                bytesRead = mInput->read(buffer.raw, mInputBytes);
+                                mBytesRead = mInput->read(buffer.raw, mInputBytes);
                                 framesOut = 0;
                             } else {
-                                bytesRead = mInput->read(mRsmpInBuffer, mInputBytes);
+                                mBytesRead = mInput->read(mRsmpInBuffer, mInputBytes);
                                 mRsmpInIndex = 0;
                             }
-                            if (bytesRead < 0) {
+                            if (mBytesRead < 0) {
                                 LOGE("Error reading audio input");
-                                sleep(1);
+                                if (mActiveTrack->mState == TrackBase::ACTIVE) {
+                                    sleep(1);
+                                }
                                 mRsmpInIndex = mFrameCount;
                                 framesOut = 0;
                                 buffer.frameCount = 0;
@@ -3220,7 +3232,7 @@ status_t AudioFlinger::RecordThread::start(RecordThread::RecordTrack* recordTrac
             if (recordTrack != mActiveTrack.get()) {
                 status = -EBUSY;
             } else if (mActiveTrack->mState == TrackBase::PAUSING) {
-                mActiveTrack->mState = TrackBase::RESUMING;
+                mActiveTrack->mState = TrackBase::ACTIVE;
             }
             return status;
         }
@@ -3235,6 +3247,8 @@ status_t AudioFlinger::RecordThread::start(RecordThread::RecordTrack* recordTrac
             return status;
         }
         mActiveTrack->mState = TrackBase::RESUMING;
+        mRsmpInIndex = mFrameCount;
+        mBytesRead = 0;
         // signal thread to start
         LOGV("Signal record thread");
         mWaitWorkCV.signal();
@@ -3275,6 +3289,7 @@ void AudioFlinger::RecordThread::stop(RecordThread::RecordTrack* recordTrack) {
                 mLock.unlock();
                 AudioSystem::stopInput(mId);
                 mLock.lock();
+                LOGV("Record stopped OK");
             }
         }
     }
@@ -3325,10 +3340,12 @@ status_t AudioFlinger::RecordThread::getNextBuffer(AudioBufferProvider::Buffer*
     int channelCount;
 
     if (framesReady == 0) {
-        ssize_t bytesRead = mInput->read(mRsmpInBuffer, mInputBytes);
-        if (bytesRead < 0) {
+        mBytesRead = mInput->read(mRsmpInBuffer, mInputBytes);
+        if (mBytesRead < 0) {
             LOGE("RecordThread::getNextBuffer() Error reading audio input");
-            sleep(1);
+            if (mActiveTrack->mState == TrackBase::ACTIVE) {
+                sleep(1);
+            }
             buffer->raw = 0;
             buffer->frameCount = 0;
             return NOT_ENOUGH_DATA;
@@ -3546,9 +3563,11 @@ int AudioFlinger::openOutput(uint32_t *pDevices,
         if (pFormat) *pFormat = format;
         if (pChannels) *pChannels = channels;
         if (pLatencyMs) *pLatencyMs = thread->latency();
+
+        return mNextThreadId;
     }
 
-    return mNextThreadId;
+    return 0;
 }
 
 int AudioFlinger::openDuplicateOutput(int output1, int output2)
@@ -3694,9 +3713,11 @@ int AudioFlinger::openInput(uint32_t *pDevices,
         if (pChannels) *pChannels = reqChannels;
 
         input->standby();
+
+        return mNextThreadId;
     }
 
-    return mNextThreadId;
+    return 0;
 }
 
 status_t AudioFlinger::closeInput(int input)
index 5a17294..8c29da8 100644 (file)
@@ -744,6 +744,7 @@ private:
                 size_t                              mInputBytes;
                 int                                 mReqChannelCount;
                 uint32_t                            mReqSampleRate;
+                ssize_t                             mBytesRead;
     };
 
     class RecordHandle : public android::BnAudioRecord {
index 7a47157..c48eaad 100644 (file)
@@ -498,8 +498,9 @@ public class AudioRecord
 
         // start recording
         synchronized(mRecordingStateLock) {
-            native_start();
-            mRecordingState = RECORDSTATE_RECORDING;
+            if (native_start() == SUCCESS) {
+                mRecordingState = RECORDSTATE_RECORDING;
+            }
         }
     }
 
@@ -764,7 +765,7 @@ public class AudioRecord
     
     private native final void native_release();
 
-    private native final void native_start();  
+    private native final int native_start();
 
     private native final void native_stop();
 
index c3828f0..f4165ff 100644 (file)
@@ -125,7 +125,7 @@ status_t AudioRecord::set(
     audio_io_handle_t input = AudioSystem::getInput(inputSource,
                                     sampleRate, format, channels, (AudioSystem::audio_in_acoustics)flags);
     if (input == 0) {
-        LOGE("Could not get audio output for stream type %d", inputSource);
+        LOGE("Could not get audio input for record source %d", inputSource);
         return BAD_VALUE;
     }
 
@@ -539,7 +539,6 @@ ssize_t AudioRecord::read(void* buffer, size_t userSize)
         return BAD_VALUE;
     }
 
-    LOGV("read size: %d", userSize);
 
     do {