Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2c2ce8e5 authored by Eric Laurent's avatar Eric Laurent Committed by Android (Google) Code Review
Browse files

Merge "Added support for audio sessions in MediaPlayer and AudioTrack." into gingerbread

parents 3238302b 619346f9
Loading
Loading
Loading
Loading
+29 −4
Original line number Diff line number Diff line
@@ -166,7 +166,7 @@ static void audioCallback(int event, void* user, void *info) {
static int
android_media_AudioTrack_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
        jint streamType, jint sampleRateInHertz, jint channels,
        jint audioFormat, jint buffSizeInBytes, jint memoryMode)
        jint audioFormat, jint buffSizeInBytes, jint memoryMode, jintArray jSession)
{
    LOGV("sampleRate=%d, audioFormat(from Java)=%d, channels=%x, buffSize=%d",
        sampleRateInHertz, audioFormat, channels, buffSizeInBytes);
@@ -253,6 +253,20 @@ android_media_AudioTrack_native_setup(JNIEnv *env, jobject thiz, jobject weak_th
    
    lpJniStorage->mStreamType = atStreamType;
    
    jint* nSession = NULL;
    if (jSession) {
        nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
        if (nSession == NULL) {
            LOGE("Error creating AudioTrack: Error retrieving session id pointer");
            delete lpJniStorage;
            return AUDIOTRACK_ERROR;
        }
    } else {
        LOGE("Error creating AudioTrack: invalid session ID pointer");
        delete lpJniStorage;
        return AUDIOTRACK_ERROR;
    }

    // create the native AudioTrack object
    AudioTrack* lpTrack = new AudioTrack();
    if (lpTrack == NULL) {
@@ -273,7 +287,8 @@ android_media_AudioTrack_native_setup(JNIEnv *env, jobject thiz, jobject weak_th
            audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user)
            0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack
            0,// shared mem
            true);// thread can call Java
            true,// thread can call Java
            nSession[0]);// audio session ID
            
    } else if (memoryMode == javaAudioTrackFields.MODE_STATIC) {
        // AudioTrack is using shared memory
@@ -293,7 +308,8 @@ android_media_AudioTrack_native_setup(JNIEnv *env, jobject thiz, jobject weak_th
            audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user));
            0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack 
            lpJniStorage->mMemBase,// shared mem
            true);// thread can call Java 
            true,// thread can call Java
            nSession[0]);// audio session ID
    }

    if (lpTrack->initCheck() != NO_ERROR) {
@@ -301,6 +317,12 @@ android_media_AudioTrack_native_setup(JNIEnv *env, jobject thiz, jobject weak_th
        goto native_init_failure;
    }

    // read the audio session ID back from AudioTrack in case we create a new session
    nSession[0] = lpTrack->getSessionId();

    env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
    nSession = NULL;

    // save our newly created C++ AudioTrack in the "nativeTrackInJavaObj" field 
    // of the Java object (in mNativeTrackInJavaObj)
    env->SetIntField(thiz, javaAudioTrackFields.nativeTrackInJavaObj, (int)lpTrack);
@@ -317,6 +339,9 @@ native_init_failure:
    env->SetIntField(thiz, javaAudioTrackFields.nativeTrackInJavaObj, 0);
    
native_track_failure:
    if (nSession != NULL) {
        env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
    }
    env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioTrack_class);
    env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioTrack_ref);
    delete lpJniStorage;
@@ -785,7 +810,7 @@ static JNINativeMethod gMethods[] = {
    {"native_stop",          "()V",      (void *)android_media_AudioTrack_stop},
    {"native_pause",         "()V",      (void *)android_media_AudioTrack_pause},
    {"native_flush",         "()V",      (void *)android_media_AudioTrack_flush},
    {"native_setup",         "(Ljava/lang/Object;IIIIII)I", 
    {"native_setup",         "(Ljava/lang/Object;IIIIII[I)I",
                                         (void *)android_media_AudioTrack_native_setup},
    {"native_finalize",      "()V",      (void *)android_media_AudioTrack_native_finalize},
    {"native_release",       "()V",      (void *)android_media_AudioTrack_native_release},
+5 −2
Original line number Diff line number Diff line
@@ -40,8 +40,11 @@ public:

    virtual sp<IMediaRecorder>  createMediaRecorder(pid_t pid) = 0;
    virtual sp<IMediaMetadataRetriever> createMetadataRetriever(pid_t pid) = 0;
    virtual sp<IMediaPlayer>    create(pid_t pid, const sp<IMediaPlayerClient>& client, const char* url, const KeyedVector<String8, String8> *headers = NULL) = 0;
    virtual sp<IMediaPlayer>    create(pid_t pid, const sp<IMediaPlayerClient>& client, int fd, int64_t offset, int64_t length) = 0;
    virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client,
            const char* url, const KeyedVector<String8, String8> *headers = NULL,
            int audioSessionId = 0) = 0;
    virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client,
            int fd, int64_t offset, int64_t length, int audioSessionId) = 0;
    virtual sp<IMemory>         decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) = 0;
    virtual sp<IMemory>         decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) = 0;
    virtual sp<IOMX>            getOMX() = 0;
+3 −0
Original line number Diff line number Diff line
@@ -172,6 +172,8 @@ public:
            status_t        getMetadata(bool update_only, bool apply_filter, Parcel *metadata);
            status_t        suspend();
            status_t        resume();
            status_t        setAudioSessionId(int sessionId);
            int             getAudioSessionId();
private:
            void            clear_l();
            status_t        seekTo_l(int msec);
@@ -198,6 +200,7 @@ private:
    float                       mRightVolume;
    int                         mVideoWidth;
    int                         mVideoHeight;
    int                         mAudioSessionId;
};

}; // namespace android
+68 −2
Original line number Diff line number Diff line
@@ -210,6 +210,10 @@ public class AudioTrack
     * @see AudioFormat#ENCODING_PCM_16BIT
     */
    private int mAudioFormat = AudioFormat.ENCODING_PCM_16BIT;
    /**
     * Audio session ID
     */
    private int mSessionId = 0;


    //--------------------------------
@@ -257,6 +261,48 @@ public class AudioTrack
     */
    public AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat,
            int bufferSizeInBytes, int mode)
    throws IllegalArgumentException {
        this(streamType, sampleRateInHz, channelConfig, audioFormat,
                bufferSizeInBytes, mode, 0);
    }

    /**
     * Class constructor with audio session. Use this constructor when the AudioTrack must be
     * attached to a particular audio session. The primary use of the audio session ID is to
     * associate audio effects to a particular instance of AudioTrack: if an audio session ID
     * is provided when creating an AudioEffect, this effect will be applied only to audio tracks
     * and media players in the same session and not to the output mix.
     * When an AudioTrack is created without specifying a session, it will create its own session
     * which can be retreived by calling the {@link #getAudioSessionId()} method.
     * If a session ID is provided, this AudioTrack will share effects attached to this session
     * with all other media players or audio tracks in the same session.
     * @param streamType the type of the audio stream. See
     *   {@link AudioManager#STREAM_VOICE_CALL}, {@link AudioManager#STREAM_SYSTEM},
     *   {@link AudioManager#STREAM_RING}, {@link AudioManager#STREAM_MUSIC} and
     *   {@link AudioManager#STREAM_ALARM}
     * @param sampleRateInHz the sample rate expressed in Hertz. Examples of rates are (but
     *   not limited to) 44100, 22050 and 11025.
     * @param channelConfig describes the configuration of the audio channels.
     *   See {@link AudioFormat#CHANNEL_OUT_MONO} and
     *   {@link AudioFormat#CHANNEL_OUT_STEREO}
     * @param audioFormat the format in which the audio data is represented.
     *   See {@link AudioFormat#ENCODING_PCM_16BIT} and
     *   {@link AudioFormat#ENCODING_PCM_8BIT}
     * @param bufferSizeInBytes the total size (in bytes) of the buffer where audio data is read
     *   from for playback. If using the AudioTrack in streaming mode, you can write data into
     *   this buffer in smaller chunks than this size. If using the AudioTrack in static mode,
     *   this is the maximum size of the sound that will be played for this instance.
     *   See {@link #getMinBufferSize(int, int, int)} to determine the minimum required buffer size
     *   for the successful creation of an AudioTrack instance in streaming mode. Using values
     *   smaller than getMinBufferSize() will result in an initialization failure.
     * @param mode streaming or static buffer. See {@link #MODE_STATIC} and {@link #MODE_STREAM}
     * @param sessionId Id of audio session the AudioTrack must be attached to
     * @throws java.lang.IllegalArgumentException
     // FIXME: unhide.
     * @hide
     */
    public AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat,
            int bufferSizeInBytes, int mode, int sessionId)
    throws IllegalArgumentException {
        mState = STATE_UNINITIALIZED;
        
@@ -269,15 +315,23 @@ public class AudioTrack

        audioBuffSizeCheck(bufferSizeInBytes);

        if (sessionId < 0) {
            throw (new IllegalArgumentException("Invalid audio session ID: "+sessionId));
        }

        int[] session = new int[1];
        session[0] = sessionId;
        // native initialization
        int initResult = native_setup(new WeakReference<AudioTrack>(this),
                mStreamType, mSampleRate, mChannels, mAudioFormat,
                mNativeBufferSizeInBytes, mDataLoadMode);
                mNativeBufferSizeInBytes, mDataLoadMode, session);
        if (initResult != SUCCESS) {
            loge("Error code "+initResult+" when initializing AudioTrack.");
            return; // with mState == STATE_UNINITIALIZED
        }

        mSessionId = session[0];

        if (mDataLoadMode == MODE_STATIC) {
            mState = STATE_NO_STATIC_DATA;
        } else {
@@ -590,6 +644,17 @@ public class AudioTrack
        }
    }

    /**
     * Returns the audio session ID.
     *
     * @return the ID of the audio session this AudioTrack belongs to.
     // FIXME: unhide.
     // FIXME: link to AudioEffect class when public.
     * @hide
     */
    public int getAudioSessionId() {
        return mSessionId;
    }

    //--------------------------------------------------------------------------
    // Initialization / configuration
@@ -1012,7 +1077,7 @@ public class AudioTrack

    private native final int native_setup(Object audiotrack_this,
            int streamType, int sampleRate, int nbChannels, int audioFormat,
            int buffSizeInBytes, int mode);
            int buffSizeInBytes, int mode, int[] sessionId);

    private native final void native_finalize();

@@ -1056,6 +1121,7 @@ public class AudioTrack
    static private native final int native_get_min_buff_size(
            int sampleRateInHz, int channelConfig, int audioFormat);

    private native final int native_get_session_id();

    //---------------------------------------------------------
    // Utility methods
+44 −0
Original line number Diff line number Diff line
@@ -423,6 +423,18 @@ import java.lang.ref.WeakReference;
 *     <td>Successful invoke of this method in a valid state transfers the
 *         object to the <em>Stopped</em> state. Calling this method in an
 *         invalid state transfers the object to the <em>Error</em> state.</p></td></tr>
  * <tr><td>setAudioSessionId </p></td>
 *     <td>{Idle} </p></td>
 *     <td>{Initialized, Prepared, Started, Paused, Stopped, PlaybackCompleted,
 *          Error} </p></td>
 *     <td>This method must be called in idle state as the audio session ID must be known before
 *         calling setDataSource. Calling it does not change the object state. </p></td></tr>
 * <tr><td>getAudioSessionId </p></td>
 *     <td>any </p></td>
 *     <td>{} </p></td>
 *     <td>This method can be called in any state and calling it does not change
 *         the object state. </p></td></tr>
 *
 * </table>
 *
 * <a name="Permissions"></a>
@@ -1158,6 +1170,38 @@ public class MediaPlayer
     */
    public native Bitmap getFrameAt(int msec) throws IllegalStateException;

    /**
     * Sets the audio session ID.
     *
     * @param sessionId: the audio session ID.
     * The audio session ID is a system wide unique identifier for the audio stream played by
     * this MediaPlayer instance.
     * The primary use of the audio session ID  is to associate audio effects to a particular
     * instance of MediaPlayer: if an audio session ID is provided when creating an audio effect,
     * this effect will be applied only to the audio content of media players within the same
     * audio session and not to the output mix.
     * When created, a MediaPlayer instance automatically generates its own audio session ID.
     * However, it is possible to force this player to be part of an already existing audio session
     * by calling this method.
     * This method must be called before one of the overloaded <code> setDataSource </code> methods.
     * @throws IllegalStateException if it is called in an invalid state
     *
     // FIXME: unhide.
     // FIXME: link to AudioEffect class when public.
     * @hide
     */
    public native void setAudioSessionId(int sessionId)  throws IllegalArgumentException, IllegalStateException;

    /**
     * Returns the audio session ID.
     *
     * @return the audio session ID. {@see #setAudioSessionId(int)}.
     * Note that the audio session ID is 0 only if a problem occured when the MediaPlayer was contructed.
     // FIXME: unhide.
     * @hide
     */
    public native int getAudioSessionId();

    /**
     * @param request Parcel destinated to the media player. The
     *                Interface token must be set to the IMediaPlayer
Loading