Support for audio recording into AMR NB/WB files as well as audio tracks in MPEG4 files.

related-to-bug: 2295449
diff --git a/include/media/stagefright/AMRWriter.h b/include/media/stagefright/AMRWriter.h
index 6ee9869..372909a 100644
--- a/include/media/stagefright/AMRWriter.h
+++ b/include/media/stagefright/AMRWriter.h
@@ -20,23 +20,23 @@
 
 #include <stdio.h>
 
-#include <utils/RefBase.h>
+#include <media/stagefright/MediaWriter.h>
 #include <utils/threads.h>
 
 namespace android {
 
 struct MediaSource;
 
-struct AMRWriter : public RefBase {
+struct AMRWriter : public MediaWriter {
     AMRWriter(const char *filename);
     AMRWriter(int fd);
 
     status_t initCheck() const;
 
-    status_t addSource(const sp<MediaSource> &source);
-
-    status_t start();
-    void stop();
+    virtual status_t addSource(const sp<MediaSource> &source);
+    virtual bool reachedEOS();
+    virtual status_t start();
+    virtual void stop();
 
 protected:
     virtual ~AMRWriter();
@@ -49,6 +49,7 @@
     sp<MediaSource> mSource;
     bool mStarted;
     volatile bool mDone;
+    bool mReachedEOS;
     pthread_t mThread;
 
     static void *ThreadWrapper(void *);
diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h
index 2ca04fa..6b93f19 100644
--- a/include/media/stagefright/MPEG4Writer.h
+++ b/include/media/stagefright/MPEG4Writer.h
@@ -20,8 +20,8 @@
 
 #include <stdio.h>
 
+#include <media/stagefright/MediaWriter.h>
 #include <utils/List.h>
-#include <utils/RefBase.h>
 #include <utils/threads.h>
 
 namespace android {
@@ -30,15 +30,15 @@
 class MediaSource;
 class MetaData;
 
-class MPEG4Writer : public RefBase {
+class MPEG4Writer : public MediaWriter {
 public:
     MPEG4Writer(const char *filename);
     MPEG4Writer(int fd);
 
-    void addSource(const sp<MediaSource> &source);
-    status_t start();
-    bool reachedEOS();
-    void stop();
+    virtual status_t addSource(const sp<MediaSource> &source);
+    virtual status_t start();
+    virtual bool reachedEOS();
+    virtual void stop();
 
     void beginBox(const char *fourcc);
     void writeInt8(int8_t x);
diff --git a/include/media/stagefright/MediaWriter.h b/include/media/stagefright/MediaWriter.h
new file mode 100644
index 0000000..b8232c6
--- /dev/null
+++ b/include/media/stagefright/MediaWriter.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2010 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 MEDIA_WRITER_H_
+
+#define MEDIA_WRITER_H_
+
+#include <utils/RefBase.h>
+
+namespace android {
+
+struct MediaSource;
+
+struct MediaWriter : public RefBase {
+    MediaWriter() {}
+
+    virtual status_t addSource(const sp<MediaSource> &source) = 0;
+    virtual bool reachedEOS() = 0;
+    virtual status_t start() = 0;
+    virtual void stop() = 0;
+
+protected:
+    virtual ~MediaWriter() {}
+
+private:
+    MediaWriter(const MediaWriter &);
+    MediaWriter &operator=(const MediaWriter &);
+};
+
+}  // namespace android
+
+#endif  // MEDIA_WRITER_H_
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index a55273d..6383f0c 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -20,6 +20,8 @@
 
 #include "StagefrightRecorder.h"
 
+#include <media/stagefright/AudioSource.h>
+#include <media/stagefright/AMRWriter.h>
 #include <media/stagefright/CameraSource.h>
 #include <media/stagefright/MPEG4Writer.h>
 #include <media/stagefright/MediaDebug.h>
@@ -146,7 +148,90 @@
         return UNKNOWN_ERROR;
     }
 
-    if (mVideoSource == VIDEO_SOURCE_CAMERA) {
+    switch (mOutputFormat) {
+        case OUTPUT_FORMAT_DEFAULT:
+        case OUTPUT_FORMAT_THREE_GPP:
+        case OUTPUT_FORMAT_MPEG_4:
+            return startMPEG4Recording();
+
+        case OUTPUT_FORMAT_AMR_NB:
+        case OUTPUT_FORMAT_AMR_WB:
+            return startAMRRecording();
+
+        default:
+            return UNKNOWN_ERROR;
+    }
+}
+
+sp<MediaSource> StagefrightRecorder::createAMRAudioSource() {
+    uint32_t sampleRate =
+        mAudioEncoder == AUDIO_ENCODER_AMR_NB ? 8000 : 16000;
+
+    sp<AudioSource> audioSource =
+        new AudioSource(
+                mAudioSource,
+                sampleRate,
+                AudioSystem::CHANNEL_IN_MONO);
+
+    status_t err = audioSource->initCheck();
+
+    if (err != OK) {
+        return NULL;
+    }
+
+    sp<MetaData> encMeta = new MetaData;
+    encMeta->setCString(
+            kKeyMIMEType,
+            mAudioEncoder == AUDIO_ENCODER_AMR_NB
+                ? MEDIA_MIMETYPE_AUDIO_AMR_NB : MEDIA_MIMETYPE_AUDIO_AMR_WB);
+
+    encMeta->setInt32(kKeyChannelCount, 1);
+    encMeta->setInt32(kKeySampleRate, sampleRate);
+
+    OMXClient client;
+    CHECK_EQ(client.connect(), OK);
+
+    sp<MediaSource> audioEncoder =
+        OMXCodec::Create(client.interface(), encMeta,
+                         true /* createEncoder */, audioSource);
+
+    return audioEncoder;
+}
+
+status_t StagefrightRecorder::startAMRRecording() {
+    if (mAudioSource == AUDIO_SOURCE_LIST_END
+        || mVideoSource != VIDEO_SOURCE_LIST_END) {
+        return UNKNOWN_ERROR;
+    }
+
+    if (mOutputFormat == OUTPUT_FORMAT_AMR_NB
+            && mAudioEncoder != AUDIO_ENCODER_DEFAULT
+            && mAudioEncoder != AUDIO_ENCODER_AMR_NB) {
+        return UNKNOWN_ERROR;
+    } else if (mOutputFormat == OUTPUT_FORMAT_AMR_WB
+            && mAudioEncoder != AUDIO_ENCODER_AMR_WB) {
+        return UNKNOWN_ERROR;
+    }
+
+    sp<MediaSource> audioEncoder = createAMRAudioSource();
+
+    if (audioEncoder == NULL) {
+        return UNKNOWN_ERROR;
+    }
+
+    CHECK(mOutputFd >= 0);
+    mWriter = new AMRWriter(dup(mOutputFd));
+    mWriter->addSource(audioEncoder);
+    mWriter->start();
+
+    return OK;
+}
+
+status_t StagefrightRecorder::startMPEG4Recording() {
+    mWriter = new MPEG4Writer(dup(mOutputFd));
+
+    if (mVideoSource == VIDEO_SOURCE_DEFAULT
+            || mVideoSource == VIDEO_SOURCE_CAMERA) {
         CHECK(mCamera != NULL);
 
         sp<CameraSource> cameraSource =
@@ -193,11 +278,20 @@
                     true /* createEncoder */, cameraSource);
 
         CHECK(mOutputFd >= 0);
-        mWriter = new MPEG4Writer(dup(mOutputFd));
         mWriter->addSource(encoder);
-        mWriter->start();
     }
 
+    if (mAudioSource != AUDIO_SOURCE_LIST_END) {
+        sp<MediaSource> audioEncoder = createAMRAudioSource();
+
+        if (audioEncoder == NULL) {
+            return UNKNOWN_ERROR;
+        }
+
+        mWriter->addSource(audioEncoder);
+    }
+
+    mWriter->start();
     return OK;
 }
 
@@ -235,7 +329,9 @@
 }
 
 status_t StagefrightRecorder::getMaxAmplitude(int *max) {
-    return UNKNOWN_ERROR;
+    *max = 0;
+
+    return OK;
 }
 
 }  // namespace android
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index 56c4e0e..7ec412d 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -23,7 +23,8 @@
 
 namespace android {
 
-class MPEG4Writer;
+struct MediaSource;
+struct MediaWriter;
 
 struct StagefrightRecorder : public MediaRecorderBase {
     StagefrightRecorder();
@@ -54,7 +55,7 @@
     sp<ICamera> mCamera;
     sp<ISurface> mPreviewSurface;
     sp<IMediaPlayerClient> mListener;
-    sp<MPEG4Writer> mWriter;
+    sp<MediaWriter> mWriter;
 
     audio_source mAudioSource;
     video_source mVideoSource;
@@ -66,6 +67,10 @@
     String8 mParams;
     int mOutputFd;
 
+    status_t startMPEG4Recording();
+    status_t startAMRRecording();
+    sp<MediaSource> createAMRAudioSource();
+
     StagefrightRecorder(const StagefrightRecorder &);
     StagefrightRecorder &operator=(const StagefrightRecorder &);
 };
diff --git a/media/libstagefright/AMRWriter.cpp b/media/libstagefright/AMRWriter.cpp
index 7b681f12..caff452 100644
--- a/media/libstagefright/AMRWriter.cpp
+++ b/media/libstagefright/AMRWriter.cpp
@@ -115,6 +115,7 @@
     pthread_attr_init(&attr);
     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
 
+    mReachedEOS = false;
     mDone = false;
 
     pthread_create(&mThread, &attr, ThreadWrapper, this);
@@ -179,6 +180,14 @@
             break;
         }
     }
+
+    Mutex::Autolock autoLock(mLock);
+    mReachedEOS = true;
+}
+
+bool AMRWriter::reachedEOS() {
+    Mutex::Autolock autoLock(mLock);
+    return mReachedEOS;
 }
 
 }  // namespace android
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 367459f..aee4d15 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -92,9 +92,11 @@
     mTracks.clear();
 }
 
-void MPEG4Writer::addSource(const sp<MediaSource> &source) {
+status_t MPEG4Writer::addSource(const sp<MediaSource> &source) {
     Track *track = new Track(this, source);
     mTracks.push_back(track);
+
+    return OK;
 }
 
 status_t MPEG4Writer::start() {