Add audio encoding parameters check

bug - 3345296

Change-Id: If3f33955f5473b0c5ad9c9b85f8b5cb21ddd7e65
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index db308c7..11900d4 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -453,8 +453,9 @@
      * the specified audio sampling rate is applicable. The sampling rate really depends
      * on the format for the audio recording, as well as the capabilities of the platform.
      * For instance, the sampling rate supported by AAC audio coding standard ranges
-     * from 8 to 96 kHz. Please consult with the related audio coding standard for the
-     * supported audio sampling rate.
+     * from 8 to 96 kHz, the sampling rate supported by AMRNB is 8kHz, and the sampling
+     * rate supported by AMRWB is 16kHz. Please consult with the related audio coding
+     * standard for the supported audio sampling rate.
      *
      * @param samplingRate the sampling rate for audio in samples per second.
      */
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index d372ee6..992abd7 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -846,27 +846,12 @@
                     mAudioEncoder);
             return BAD_VALUE;
         }
-        if (mSampleRate != 8000) {
-            LOGE("Invalid sampling rate %d used for AMRNB recording",
-                    mSampleRate);
-            return BAD_VALUE;
-        }
     } else {  // mOutputFormat must be OUTPUT_FORMAT_AMR_WB
         if (mAudioEncoder != AUDIO_ENCODER_AMR_WB) {
             LOGE("Invlaid encoder %d used for AMRWB recording",
                     mAudioEncoder);
             return BAD_VALUE;
         }
-        if (mSampleRate != 16000) {
-            LOGE("Invalid sample rate %d used for AMRWB recording",
-                    mSampleRate);
-            return BAD_VALUE;
-        }
-    }
-    if (mAudioChannels != 1) {
-        LOGE("Invalid number of audio channels %d used for amr recording",
-                mAudioChannels);
-        return BAD_VALUE;
     }
 
     if (mAudioSource >= AUDIO_SOURCE_LIST_END) {
@@ -874,8 +859,12 @@
         return BAD_VALUE;
     }
 
-    sp<MediaSource> audioEncoder = createAudioSource();
+    status_t status = BAD_VALUE;
+    if (OK != (status = checkAudioEncoderCapabilities())) {
+        return status;
+    }
 
+    sp<MediaSource> audioEncoder = createAudioSource();
     if (audioEncoder == NULL) {
         return UNKNOWN_ERROR;
     }
@@ -1050,6 +1039,79 @@
     return OK;
 }
 
+status_t StagefrightRecorder::checkAudioEncoderCapabilities() {
+    clipAudioBitRate();
+    clipAudioSampleRate();
+    clipNumberOfAudioChannels();
+    return OK;
+}
+
+void StagefrightRecorder::clipAudioBitRate() {
+    LOGV("clipAudioBitRate: encoder %d", mAudioEncoder);
+
+    int minAudioBitRate =
+            mEncoderProfiles->getAudioEncoderParamByName(
+                "enc.aud.bps.min", mAudioEncoder);
+    if (mAudioBitRate < minAudioBitRate) {
+        LOGW("Intended audio encoding bit rate (%d) is too small"
+            " and will be set to (%d)", mAudioBitRate, minAudioBitRate);
+        mAudioBitRate = minAudioBitRate;
+    }
+
+    int maxAudioBitRate =
+            mEncoderProfiles->getAudioEncoderParamByName(
+                "enc.aud.bps.max", mAudioEncoder);
+    if (mAudioBitRate > maxAudioBitRate) {
+        LOGW("Intended audio encoding bit rate (%d) is too large"
+            " and will be set to (%d)", mAudioBitRate, maxAudioBitRate);
+        mAudioBitRate = maxAudioBitRate;
+    }
+}
+
+void StagefrightRecorder::clipAudioSampleRate() {
+    LOGV("clipAudioSampleRate: encoder %d", mAudioEncoder);
+
+    int minSampleRate =
+            mEncoderProfiles->getAudioEncoderParamByName(
+                "enc.aud.hz.min", mAudioEncoder);
+    if (mSampleRate < minSampleRate) {
+        LOGW("Intended audio sample rate (%d) is too small"
+            " and will be set to (%d)", mSampleRate, minSampleRate);
+        mSampleRate = minSampleRate;
+    }
+
+    int maxSampleRate =
+            mEncoderProfiles->getAudioEncoderParamByName(
+                "enc.aud.hz.max", mAudioEncoder);
+    if (mSampleRate > maxSampleRate) {
+        LOGW("Intended audio sample rate (%d) is too large"
+            " and will be set to (%d)", mSampleRate, maxSampleRate);
+        mSampleRate = maxSampleRate;
+    }
+}
+
+void StagefrightRecorder::clipNumberOfAudioChannels() {
+    LOGV("clipNumberOfAudioChannels: encoder %d", mAudioEncoder);
+
+    int minChannels =
+            mEncoderProfiles->getAudioEncoderParamByName(
+                "enc.aud.ch.min", mAudioEncoder);
+    if (mAudioChannels < minChannels) {
+        LOGW("Intended number of audio channels (%d) is too small"
+            " and will be set to (%d)", mAudioChannels, minChannels);
+        mAudioChannels = minChannels;
+    }
+
+    int maxChannels =
+            mEncoderProfiles->getAudioEncoderParamByName(
+                "enc.aud.ch.max", mAudioEncoder);
+    if (mAudioChannels > maxChannels) {
+        LOGW("Intended number of audio channels (%d) is too large"
+            " and will be set to (%d)", mAudioChannels, maxChannels);
+        mAudioChannels = maxChannels;
+    }
+}
+
 void StagefrightRecorder::clipVideoFrameHeight() {
     LOGV("clipVideoFrameHeight: encoder %d", mVideoEncoder);
     int minFrameHeight = mEncoderProfiles->getVideoEncoderParamByName(
@@ -1206,18 +1268,23 @@
 }
 
 status_t StagefrightRecorder::setupAudioEncoder(const sp<MediaWriter>& writer) {
-    sp<MediaSource> audioEncoder;
+    status_t status = BAD_VALUE;
+    if (OK != (status = checkAudioEncoderCapabilities())) {
+        return status;
+    }
+
     switch(mAudioEncoder) {
         case AUDIO_ENCODER_AMR_NB:
         case AUDIO_ENCODER_AMR_WB:
         case AUDIO_ENCODER_AAC:
-            audioEncoder = createAudioSource();
             break;
+
         default:
             LOGE("Unsupported audio encoder: %d", mAudioEncoder);
             return UNKNOWN_ERROR;
     }
 
+    sp<MediaSource> audioEncoder = createAudioSource();
     if (audioEncoder == NULL) {
         return UNKNOWN_ERROR;
     }
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index 36a15a8..72225db 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -123,6 +123,7 @@
     status_t startMPEG2TSRecording();
     sp<MediaSource> createAudioSource();
     status_t checkVideoEncoderCapabilities();
+    status_t checkAudioEncoderCapabilities();
     status_t setupCameraSource(sp<CameraSource> *cameraSource);
     status_t setupAudioEncoder(const sp<MediaWriter>& writer);
     status_t setupVideoEncoder(
@@ -158,6 +159,9 @@
     void clipVideoFrameRate();
     void clipVideoFrameWidth();
     void clipVideoFrameHeight();
+    void clipAudioBitRate();
+    void clipAudioSampleRate();
+    void clipNumberOfAudioChannels();
 
     StagefrightRecorder(const StagefrightRecorder &);
     StagefrightRecorder &operator=(const StagefrightRecorder &);