am 2c2ce8e5
: Merge "Added support for audio sessions in MediaPlayer and AudioTrack." into gingerbread
Merge commit '2c2ce8e53f5eb94916a5d0f40b2877cc7551870d' into gingerbread-plus-aosp * commit '2c2ce8e53f5eb94916a5d0f40b2877cc7551870d': Added support for audio sessions in MediaPlayer and AudioTrack.
This commit is contained in:
@ -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},
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -292,7 +292,7 @@ static void setVideoSurface(const sp<MediaPlayer>& mp, JNIEnv *env, jobject thiz
|
||||
if (surface != NULL) {
|
||||
const sp<Surface> native_surface = get_surface(env, surface);
|
||||
LOGV("prepare: surface=%p (id=%d)",
|
||||
native_surface.get(), native_surface->ID());
|
||||
native_surface.get(), native_surface->getIdentity());
|
||||
mp->setVideoSurface(native_surface);
|
||||
}
|
||||
}
|
||||
@ -332,7 +332,7 @@ android_media_MediaPlayer_prepareAsync(JNIEnv *env, jobject thiz)
|
||||
if (surface != NULL) {
|
||||
const sp<Surface> native_surface = get_surface(env, surface);
|
||||
LOGV("prepareAsync: surface=%p (id=%d)",
|
||||
native_surface.get(), native_surface->ID());
|
||||
native_surface.get(), native_surface->getIdentity());
|
||||
mp->setVideoSurface(native_surface);
|
||||
}
|
||||
process_media_player_call( env, thiz, mp->prepareAsync(), "java/io/IOException", "Prepare Async failed." );
|
||||
@ -705,6 +705,27 @@ android_media_MediaPlayer_native_suspend_resume(
|
||||
return isSuspend ? mp->suspend() : mp->resume();
|
||||
}
|
||||
|
||||
static void android_media_MediaPlayer_set_audio_session_id(JNIEnv *env, jobject thiz, jint sessionId) {
|
||||
LOGV("set_session_id(): %d", sessionId);
|
||||
sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
|
||||
if (mp == NULL ) {
|
||||
jniThrowException(env, "java/lang/IllegalStateException", NULL);
|
||||
return;
|
||||
}
|
||||
process_media_player_call( env, thiz, mp->setAudioSessionId(sessionId), NULL, NULL );
|
||||
}
|
||||
|
||||
static jint android_media_MediaPlayer_get_audio_session_id(JNIEnv *env, jobject thiz) {
|
||||
LOGV("get_session_id()");
|
||||
sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
|
||||
if (mp == NULL ) {
|
||||
jniThrowException(env, "java/lang/IllegalStateException", NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return mp->getAudioSessionId();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
static JNINativeMethod gMethods[] = {
|
||||
@ -738,6 +759,8 @@ static JNINativeMethod gMethods[] = {
|
||||
{"native_finalize", "()V", (void *)android_media_MediaPlayer_native_finalize},
|
||||
{"snoop", "([SI)I", (void *)android_media_MediaPlayer_snoop},
|
||||
{"native_suspend_resume", "(Z)I", (void *)android_media_MediaPlayer_native_suspend_resume},
|
||||
{"getAudioSessionId", "()I", (void *)android_media_MediaPlayer_get_audio_session_id},
|
||||
{"setAudioSessionId", "(I)V", (void *)android_media_MediaPlayer_set_audio_session_id},
|
||||
};
|
||||
|
||||
static const char* const kClassPathName = "android/media/MediaPlayer";
|
||||
|
@ -92,7 +92,8 @@ AudioTrack::AudioTrack(
|
||||
: mStatus(NO_INIT)
|
||||
{
|
||||
mStatus = set(streamType, sampleRate, format, channels,
|
||||
frameCount, flags, cbf, user, notificationFrames, 0);
|
||||
frameCount, flags, cbf, user, notificationFrames,
|
||||
0, false, sessionId);
|
||||
}
|
||||
|
||||
AudioTrack::AudioTrack(
|
||||
@ -109,7 +110,8 @@ AudioTrack::AudioTrack(
|
||||
: mStatus(NO_INIT)
|
||||
{
|
||||
mStatus = set(streamType, sampleRate, format, channels,
|
||||
0, flags, cbf, user, notificationFrames, sharedBuffer);
|
||||
0, flags, cbf, user, notificationFrames,
|
||||
sharedBuffer, false, sessionId);
|
||||
}
|
||||
|
||||
AudioTrack::~AudioTrack()
|
||||
|
@ -58,7 +58,7 @@ public:
|
||||
|
||||
virtual sp<IMediaPlayer> create(
|
||||
pid_t pid, const sp<IMediaPlayerClient>& client,
|
||||
const char* url, const KeyedVector<String8, String8> *headers) {
|
||||
const char* url, const KeyedVector<String8, String8> *headers, int audioSessionId) {
|
||||
Parcel data, reply;
|
||||
data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
|
||||
data.writeInt32(pid);
|
||||
@ -75,8 +75,10 @@ public:
|
||||
data.writeString8(headers->valueAt(i));
|
||||
}
|
||||
}
|
||||
data.writeInt32(audioSessionId);
|
||||
|
||||
remote()->transact(CREATE_URL, data, &reply);
|
||||
|
||||
return interface_cast<IMediaPlayer>(reply.readStrongBinder());
|
||||
}
|
||||
|
||||
@ -89,7 +91,8 @@ public:
|
||||
return interface_cast<IMediaRecorder>(reply.readStrongBinder());
|
||||
}
|
||||
|
||||
virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, int fd, int64_t offset, int64_t length)
|
||||
virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, int fd,
|
||||
int64_t offset, int64_t length, int audioSessionId)
|
||||
{
|
||||
Parcel data, reply;
|
||||
data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
|
||||
@ -98,8 +101,11 @@ public:
|
||||
data.writeFileDescriptor(fd);
|
||||
data.writeInt64(offset);
|
||||
data.writeInt64(length);
|
||||
data.writeInt32(audioSessionId);
|
||||
|
||||
remote()->transact(CREATE_FD, data, &reply);
|
||||
return interface_cast<IMediaPlayer>(reply.readStrongBinder());
|
||||
|
||||
return interface_cast<IMediaPlayer>(reply.readStrongBinder());;
|
||||
}
|
||||
|
||||
virtual sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
|
||||
@ -166,9 +172,10 @@ status_t BnMediaPlayerService::onTransact(
|
||||
String8 value = data.readString8();
|
||||
headers.add(key, value);
|
||||
}
|
||||
int audioSessionId = data.readInt32();
|
||||
|
||||
sp<IMediaPlayer> player = create(
|
||||
pid, client, url, numHeaders > 0 ? &headers : NULL);
|
||||
pid, client, url, numHeaders > 0 ? &headers : NULL, audioSessionId);
|
||||
|
||||
reply->writeStrongBinder(player->asBinder());
|
||||
return NO_ERROR;
|
||||
@ -180,7 +187,9 @@ status_t BnMediaPlayerService::onTransact(
|
||||
int fd = dup(data.readFileDescriptor());
|
||||
int64_t offset = data.readInt64();
|
||||
int64_t length = data.readInt64();
|
||||
sp<IMediaPlayer> player = create(pid, client, fd, offset, length);
|
||||
int audioSessionId = data.readInt32();
|
||||
|
||||
sp<IMediaPlayer> player = create(pid, client, fd, offset, length, audioSessionId);
|
||||
reply->writeStrongBinder(player->asBinder());
|
||||
return NO_ERROR;
|
||||
} break;
|
||||
|
@ -55,6 +55,7 @@ MediaPlayer::MediaPlayer()
|
||||
mLeftVolume = mRightVolume = 1.0;
|
||||
mVideoWidth = mVideoHeight = 0;
|
||||
mLockThreadId = 0;
|
||||
mAudioSessionId = AudioSystem::newAudioSessionId();
|
||||
}
|
||||
|
||||
MediaPlayer::~MediaPlayer()
|
||||
@ -137,7 +138,7 @@ status_t MediaPlayer::setDataSource(
|
||||
const sp<IMediaPlayerService>& service(getMediaPlayerService());
|
||||
if (service != 0) {
|
||||
sp<IMediaPlayer> player(
|
||||
service->create(getpid(), this, url, headers));
|
||||
service->create(getpid(), this, url, headers, mAudioSessionId));
|
||||
err = setDataSource(player);
|
||||
}
|
||||
}
|
||||
@ -150,7 +151,7 @@ status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length)
|
||||
status_t err = UNKNOWN_ERROR;
|
||||
const sp<IMediaPlayerService>& service(getMediaPlayerService());
|
||||
if (service != 0) {
|
||||
sp<IMediaPlayer> player(service->create(getpid(), this, fd, offset, length));
|
||||
sp<IMediaPlayer> player(service->create(getpid(), this, fd, offset, length, mAudioSessionId));
|
||||
err = setDataSource(player);
|
||||
}
|
||||
return err;
|
||||
@ -501,6 +502,27 @@ status_t MediaPlayer::setVolume(float leftVolume, float rightVolume)
|
||||
return OK;
|
||||
}
|
||||
|
||||
status_t MediaPlayer::setAudioSessionId(int sessionId)
|
||||
{
|
||||
LOGV("MediaPlayer::setAudioSessionId(%d)", sessionId);
|
||||
Mutex::Autolock _l(mLock);
|
||||
if (!(mCurrentState & MEDIA_PLAYER_IDLE)) {
|
||||
LOGE("setAudioSessionId called in state %d", mCurrentState);
|
||||
return INVALID_OPERATION;
|
||||
}
|
||||
if (sessionId < 0) {
|
||||
return BAD_VALUE;
|
||||
}
|
||||
mAudioSessionId = sessionId;
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
int MediaPlayer::getAudioSessionId()
|
||||
{
|
||||
Mutex::Autolock _l(mLock);
|
||||
return mAudioSessionId;
|
||||
}
|
||||
|
||||
void MediaPlayer::notify(int msg, int ext1, int ext2)
|
||||
{
|
||||
LOGV("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2);
|
||||
|
@ -252,11 +252,12 @@ sp<IMediaMetadataRetriever> MediaPlayerService::createMetadataRetriever(pid_t pi
|
||||
|
||||
sp<IMediaPlayer> MediaPlayerService::create(
|
||||
pid_t pid, const sp<IMediaPlayerClient>& client, const char* url,
|
||||
const KeyedVector<String8, String8> *headers)
|
||||
const KeyedVector<String8, String8> *headers, int audioSessionId)
|
||||
{
|
||||
int32_t connId = android_atomic_inc(&mNextConnId);
|
||||
sp<Client> c = new Client(this, pid, connId, client);
|
||||
LOGV("Create new client(%d) from pid %d, url=%s, connId=%d", connId, pid, url, connId);
|
||||
sp<Client> c = new Client(this, pid, connId, client, audioSessionId);
|
||||
LOGV("Create new client(%d) from pid %d, url=%s, connId=%d, audioSessionId=%d",
|
||||
connId, pid, url, connId, audioSessionId);
|
||||
if (NO_ERROR != c->setDataSource(url, headers))
|
||||
{
|
||||
c.clear();
|
||||
@ -269,12 +270,12 @@ sp<IMediaPlayer> MediaPlayerService::create(
|
||||
}
|
||||
|
||||
sp<IMediaPlayer> MediaPlayerService::create(pid_t pid, const sp<IMediaPlayerClient>& client,
|
||||
int fd, int64_t offset, int64_t length)
|
||||
int fd, int64_t offset, int64_t length, int audioSessionId)
|
||||
{
|
||||
int32_t connId = android_atomic_inc(&mNextConnId);
|
||||
sp<Client> c = new Client(this, pid, connId, client);
|
||||
LOGV("Create new client(%d) from pid %d, fd=%d, offset=%lld, length=%lld",
|
||||
connId, pid, fd, offset, length);
|
||||
sp<Client> c = new Client(this, pid, connId, client, audioSessionId);
|
||||
LOGV("Create new client(%d) from pid %d, fd=%d, offset=%lld, length=%lld, audioSessionId=%d",
|
||||
connId, pid, fd, offset, length, audioSessionId);
|
||||
if (NO_ERROR != c->setDataSource(fd, offset, length)) {
|
||||
c.clear();
|
||||
} else {
|
||||
@ -609,7 +610,7 @@ void MediaPlayerService::removeClient(wp<Client> client)
|
||||
}
|
||||
|
||||
MediaPlayerService::Client::Client(const sp<MediaPlayerService>& service, pid_t pid,
|
||||
int32_t connId, const sp<IMediaPlayerClient>& client)
|
||||
int32_t connId, const sp<IMediaPlayerClient>& client, int audioSessionId)
|
||||
{
|
||||
LOGV("Client(%d) constructor", connId);
|
||||
mPid = pid;
|
||||
@ -618,6 +619,8 @@ MediaPlayerService::Client::Client(const sp<MediaPlayerService>& service, pid_t
|
||||
mClient = client;
|
||||
mLoop = false;
|
||||
mStatus = NO_INIT;
|
||||
mAudioSessionId = audioSessionId;
|
||||
|
||||
#if CALLBACK_ANTAGONIZER
|
||||
LOGD("create Antagonizer");
|
||||
mAntagonizer = new Antagonizer(notify, this);
|
||||
@ -871,7 +874,7 @@ status_t MediaPlayerService::Client::setDataSource(
|
||||
if (p == NULL) return NO_INIT;
|
||||
|
||||
if (!p->hardwareOutput()) {
|
||||
mAudioOutput = new AudioOutput();
|
||||
mAudioOutput = new AudioOutput(mAudioSessionId);
|
||||
static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);
|
||||
}
|
||||
|
||||
@ -921,7 +924,7 @@ status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64
|
||||
if (p == NULL) return NO_INIT;
|
||||
|
||||
if (!p->hardwareOutput()) {
|
||||
mAudioOutput = new AudioOutput();
|
||||
mAudioOutput = new AudioOutput(mAudioSessionId);
|
||||
static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);
|
||||
}
|
||||
|
||||
@ -1412,9 +1415,11 @@ sp<IMemory> MediaPlayerService::snoop()
|
||||
|
||||
#undef LOG_TAG
|
||||
#define LOG_TAG "AudioSink"
|
||||
MediaPlayerService::AudioOutput::AudioOutput()
|
||||
MediaPlayerService::AudioOutput::AudioOutput(int sessionId)
|
||||
: mCallback(NULL),
|
||||
mCallbackCookie(NULL) {
|
||||
mCallbackCookie(NULL),
|
||||
mSessionId(sessionId) {
|
||||
LOGV("AudioOutput(%d)", sessionId);
|
||||
mTrack = 0;
|
||||
mStreamType = AudioSystem::MUSIC;
|
||||
mLeftVolume = 1.0;
|
||||
@ -1504,7 +1509,7 @@ status_t MediaPlayerService::AudioOutput::open(
|
||||
bufferCount = mMinBufferCount;
|
||||
|
||||
}
|
||||
LOGV("open(%u, %d, %d, %d)", sampleRate, channelCount, format, bufferCount);
|
||||
LOGV("open(%u, %d, %d, %d, %d)", sampleRate, channelCount, format, bufferCount,mSessionId);
|
||||
if (mTrack) close();
|
||||
int afSampleRate;
|
||||
int afFrameCount;
|
||||
@ -1529,14 +1534,21 @@ status_t MediaPlayerService::AudioOutput::open(
|
||||
frameCount,
|
||||
0 /* flags */,
|
||||
CallbackWrapper,
|
||||
this);
|
||||
this,
|
||||
0,
|
||||
mSessionId);
|
||||
} else {
|
||||
t = new AudioTrack(
|
||||
mStreamType,
|
||||
sampleRate,
|
||||
format,
|
||||
(channelCount == 2) ? AudioSystem::CHANNEL_OUT_STEREO : AudioSystem::CHANNEL_OUT_MONO,
|
||||
frameCount);
|
||||
frameCount,
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
0,
|
||||
mSessionId);
|
||||
}
|
||||
|
||||
if ((t == 0) || (t->initCheck() != NO_ERROR)) {
|
||||
|
@ -65,7 +65,7 @@ class MediaPlayerService : public BnMediaPlayerService
|
||||
class AudioOutput : public MediaPlayerBase::AudioSink
|
||||
{
|
||||
public:
|
||||
AudioOutput();
|
||||
AudioOutput(int sessionId);
|
||||
virtual ~AudioOutput();
|
||||
|
||||
virtual bool ready() const { return mTrack != NULL; }
|
||||
@ -108,6 +108,7 @@ class MediaPlayerService : public BnMediaPlayerService
|
||||
float mRightVolume;
|
||||
float mMsecsPerFrame;
|
||||
uint32_t mLatency;
|
||||
int mSessionId;
|
||||
|
||||
static bool mIsOnEmulator;
|
||||
static int mMinBufferCount; // 12 for emulator; otherwise 4
|
||||
@ -185,9 +186,9 @@ public:
|
||||
// House keeping for media player clients
|
||||
virtual sp<IMediaPlayer> create(
|
||||
pid_t pid, const sp<IMediaPlayerClient>& client, const char* url,
|
||||
const KeyedVector<String8, String8> *headers);
|
||||
const KeyedVector<String8, String8> *headers, int audioSessionId);
|
||||
|
||||
virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, int fd, int64_t offset, int64_t length);
|
||||
virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, int fd, int64_t offset, int64_t length, int audioSessionId);
|
||||
virtual sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
|
||||
virtual sp<IMemory> decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
|
||||
virtual sp<IMemory> snoop();
|
||||
@ -237,12 +238,15 @@ private:
|
||||
pid_t pid() const { return mPid; }
|
||||
virtual status_t dump(int fd, const Vector<String16>& args) const;
|
||||
|
||||
int getAudioSessionId() { return mAudioSessionId; }
|
||||
|
||||
private:
|
||||
friend class MediaPlayerService;
|
||||
Client( const sp<MediaPlayerService>& service,
|
||||
pid_t pid,
|
||||
int32_t connId,
|
||||
const sp<IMediaPlayerClient>& client);
|
||||
const sp<IMediaPlayerClient>& client,
|
||||
int audioSessionId);
|
||||
Client();
|
||||
virtual ~Client();
|
||||
|
||||
@ -271,6 +275,7 @@ private:
|
||||
status_t mStatus;
|
||||
bool mLoop;
|
||||
int32_t mConnId;
|
||||
int mAudioSessionId;
|
||||
|
||||
// Metadata filters.
|
||||
media::Metadata::Filter mMetadataAllow; // protected by mLock
|
||||
|
Reference in New Issue
Block a user