summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLajos Molnar <lajos@google.com>2015-04-24 17:10:07 -0700
committerLajos Molnar <lajos@google.com>2015-04-30 16:56:10 -0700
commit3a474aa67fc31505740526dd249d96204c08bf79 (patch)
tree4db784ee57ffad037fa2ded86d0fd8b3a40173d5
parenta8df0b716bdfda1e10790e6f7297eeff83d2e52a (diff)
downloadframeworks_av-3a474aa67fc31505740526dd249d96204c08bf79.zip
frameworks_av-3a474aa67fc31505740526dd249d96204c08bf79.tar.gz
frameworks_av-3a474aa67fc31505740526dd249d96204c08bf79.tar.bz2
stagefright: support setting/getting playback/sync config in MediaSync
Bug: 18249558 Bug: 19666434 Bug: 20057497 Change-Id: I5868b17423d7c20cfaf4a399f3eb67bfba440605
-rw-r--r--include/media/AVSyncSettings.h61
-rw-r--r--include/media/AudioTrack.h6
-rw-r--r--include/media/IMediaPlayer.h8
-rw-r--r--include/media/MediaPlayerInterface.h31
-rw-r--r--include/media/mediaplayer.h13
-rw-r--r--include/media/stagefright/AudioPlayer.h6
-rw-r--r--include/media/stagefright/MediaSync.h56
-rw-r--r--include/media/stagefright/Utils.h9
-rw-r--r--media/libmedia/AudioTrack.cpp11
-rw-r--r--media/libmedia/IMediaPlayer.cpp108
-rw-r--r--media/libmedia/mediaplayer.cpp54
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.cpp86
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.h14
-rw-r--r--media/libmediaplayerservice/StagefrightPlayer.cpp8
-rw-r--r--media/libmediaplayerservice/StagefrightPlayer.h2
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayer.cpp176
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayer.h18
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp29
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerDriver.h5
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp197
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h27
-rw-r--r--media/libstagefright/AudioPlayer.cpp17
-rw-r--r--media/libstagefright/AwesomePlayer.cpp70
-rw-r--r--media/libstagefright/MediaSync.cpp151
-rw-r--r--media/libstagefright/Utils.cpp34
-rw-r--r--media/libstagefright/include/AwesomePlayer.h4
26 files changed, 1075 insertions, 126 deletions
diff --git a/include/media/AVSyncSettings.h b/include/media/AVSyncSettings.h
new file mode 100644
index 0000000..10e3bcc
--- /dev/null
+++ b/include/media/AVSyncSettings.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2015 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 ANDROID_AV_SYNC_SETTINGS_H
+#define ANDROID_AV_SYNC_SETTINGS_H
+
+namespace android {
+
+enum AVSyncSource : unsigned {
+ // let the system decide the best sync source
+ AVSYNC_SOURCE_DEFAULT = 0,
+ // sync to the system clock
+ AVSYNC_SOURCE_SYSTEM_CLOCK = 1,
+ // sync to the audio track
+ AVSYNC_SOURCE_AUDIO = 2,
+ // sync to the display vsync
+ AVSYNC_SOURCE_VSYNC = 3,
+ AVSYNC_SOURCE_MAX,
+};
+
+enum AVSyncAudioAdjustMode : unsigned {
+ // let the system decide the best audio adjust mode
+ AVSYNC_AUDIO_ADJUST_MODE_DEFAULT = 0,
+ // adjust audio by time stretching
+ AVSYNC_AUDIO_ADJUST_MODE_STRETCH = 1,
+ // adjust audio by resampling
+ AVSYNC_AUDIO_ADJUST_MODE_RESAMPLE = 2,
+ AVSYNC_AUDIO_ADJUST_MODE_MAX,
+};
+
+// max tolerance when adjusting playback speed to desired playback speed
+#define AVSYNC_TOLERANCE_MAX 1.0f
+
+struct AVSyncSettings {
+ AVSyncSource mSource;
+ AVSyncAudioAdjustMode mAudioAdjustMode;
+ float mTolerance;
+ AVSyncSettings()
+ : mSource(AVSYNC_SOURCE_DEFAULT),
+ mAudioAdjustMode(AVSYNC_AUDIO_ADJUST_MODE_DEFAULT),
+ mTolerance(.044f) { }
+};
+
+} // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_AV_SYNC_SETTINGS_H
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index d361901..51d40bb 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -360,6 +360,11 @@ public:
/* Return current source sample rate in Hz */
uint32_t getSampleRate() const;
+ /* Return the original source sample rate in Hz. This corresponds to the sample rate
+ * if playback rate had normal speed and pitch.
+ */
+ uint32_t getOriginalSampleRate() const;
+
/* Set source playback rate for timestretch
* 1.0 is normal speed: < 1.0 is slower, > 1.0 is faster
* 1.0 is normal pitch: < 1.0 is lower pitch, > 1.0 is higher pitch
@@ -749,6 +754,7 @@ protected:
float mVolume[2];
float mSendLevel;
mutable uint32_t mSampleRate; // mutable because getSampleRate() can update it
+ uint32_t mOriginalSampleRate;
AudioPlaybackRate mPlaybackRate;
size_t mFrameCount; // corresponds to current IAudioTrack, value is
// reported back by AudioFlinger to the client
diff --git a/include/media/IMediaPlayer.h b/include/media/IMediaPlayer.h
index df6130d..0fd8933 100644
--- a/include/media/IMediaPlayer.h
+++ b/include/media/IMediaPlayer.h
@@ -35,6 +35,8 @@ class IDataSource;
struct IStreamSource;
class IGraphicBufferProducer;
struct IMediaHTTPService;
+struct AudioPlaybackRate;
+struct AVSyncSettings;
class IMediaPlayer: public IInterface
{
@@ -58,7 +60,11 @@ public:
virtual status_t stop() = 0;
virtual status_t pause() = 0;
virtual status_t isPlaying(bool* state) = 0;
- virtual status_t setPlaybackRate(float rate) = 0;
+ virtual status_t setPlaybackSettings(const AudioPlaybackRate& rate) = 0;
+ virtual status_t getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */) = 0;
+ virtual status_t setSyncSettings(const AVSyncSettings& sync, float videoFpsHint) = 0;
+ virtual status_t getSyncSettings(AVSyncSettings* sync /* nonnull */,
+ float* videoFps /* nonnull */) = 0;
virtual status_t seekTo(int msec) = 0;
virtual status_t getCurrentPosition(int* msec) = 0;
virtual status_t getDuration(int* msec) = 0;
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index 824762a..fa917f9 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -26,8 +26,10 @@
#include <utils/RefBase.h>
#include <media/mediaplayer.h>
+#include <media/AudioResamplerPublic.h>
#include <media/AudioSystem.h>
#include <media/AudioTimestamp.h>
+#include <media/AVSyncSettings.h>
#include <media/Metadata.h>
// Fwd decl to make sure everyone agrees that the scope of struct sockaddr_in is
@@ -132,7 +134,8 @@ public:
virtual void pause() = 0;
virtual void close() = 0;
- virtual status_t setPlaybackRatePermille(int32_t /* rate */) { return INVALID_OPERATION;}
+ virtual status_t setPlaybackRate(const AudioPlaybackRate& rate) = 0;
+ virtual status_t getPlaybackRate(AudioPlaybackRate* rate /* nonnull */) = 0;
virtual bool needsTrailingPadding() { return true; }
virtual status_t setParameters(const String8& /* keyValuePairs */) { return NO_ERROR; }
@@ -173,7 +176,31 @@ public:
virtual status_t stop() = 0;
virtual status_t pause() = 0;
virtual bool isPlaying() = 0;
- virtual status_t setPlaybackRate(float /* rate */) { return INVALID_OPERATION; }
+ virtual status_t setPlaybackSettings(const AudioPlaybackRate& rate) {
+ // by default, players only support setting rate to the default
+ if (!isAudioPlaybackRateEqual(rate, AUDIO_PLAYBACK_RATE_DEFAULT)) {
+ return BAD_VALUE;
+ }
+ return OK;
+ }
+ virtual status_t getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */) {
+ *rate = AUDIO_PLAYBACK_RATE_DEFAULT;
+ return OK;
+ }
+ virtual status_t setSyncSettings(const AVSyncSettings& sync, float /* videoFps */) {
+ // By default, players only support setting sync source to default; all other sync
+ // settings are ignored. There is no requirement for getters to return set values.
+ if (sync.mSource != AVSYNC_SOURCE_DEFAULT) {
+ return BAD_VALUE;
+ }
+ return OK;
+ }
+ virtual status_t getSyncSettings(
+ AVSyncSettings* sync /* nonnull */, float* videoFps /* nonnull */) {
+ *sync = AVSyncSettings();
+ *videoFps = -1.f;
+ return OK;
+ }
virtual status_t seekTo(int msec) = 0;
virtual status_t getCurrentPosition(int *msec) = 0;
virtual status_t getDuration(int *msec) = 0;
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index 256fa9a..3fe749c 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -20,6 +20,8 @@
#include <arpa/inet.h>
#include <binder/IMemory.h>
+
+#include <media/AudioResamplerPublic.h>
#include <media/IMediaPlayerClient.h>
#include <media/IMediaPlayer.h>
#include <media/IMediaDeathNotifier.h>
@@ -32,8 +34,9 @@ class ANativeWindow;
namespace android {
-class Surface;
+struct AVSyncSettings;
class IGraphicBufferProducer;
+class Surface;
enum media_event_type {
MEDIA_NOP = 0, // interface test message
@@ -223,7 +226,12 @@ public:
status_t stop();
status_t pause();
bool isPlaying();
- status_t setPlaybackRate(float rate);
+ status_t setPlaybackSettings(const AudioPlaybackRate& rate);
+ status_t getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */);
+ status_t setSyncSettings(const AVSyncSettings& sync, float videoFpsHint);
+ status_t getSyncSettings(
+ AVSyncSettings* sync /* nonnull */,
+ float* videoFps /* nonnull */);
status_t getVideoWidth(int *w);
status_t getVideoHeight(int *h);
status_t seekTo(int msec);
@@ -278,7 +286,6 @@ private:
int mVideoWidth;
int mVideoHeight;
int mAudioSessionId;
- float mPlaybackRate;
float mSendLevel;
struct sockaddr_in mRetransmitEndpoint;
bool mRetransmitEndpointValid;
diff --git a/include/media/stagefright/AudioPlayer.h b/include/media/stagefright/AudioPlayer.h
index 98c4fa7..e0cd965 100644
--- a/include/media/stagefright/AudioPlayer.h
+++ b/include/media/stagefright/AudioPlayer.h
@@ -25,9 +25,10 @@
namespace android {
-class MediaSource;
+struct AudioPlaybackRate;
class AudioTrack;
struct AwesomePlayer;
+class MediaSource;
class AudioPlayer : public TimeSource {
public:
@@ -73,7 +74,8 @@ public:
bool isSeeking();
bool reachedEOS(status_t *finalStatus);
- status_t setPlaybackRatePermille(int32_t ratePermille);
+ status_t setPlaybackRate(const AudioPlaybackRate &rate);
+ status_t getPlaybackRate(AudioPlaybackRate *rate /* nonnull */);
void notifyAudioEOS();
diff --git a/include/media/stagefright/MediaSync.h b/include/media/stagefright/MediaSync.h
index e071b65..a349986 100644
--- a/include/media/stagefright/MediaSync.h
+++ b/include/media/stagefright/MediaSync.h
@@ -20,6 +20,8 @@
#include <gui/IConsumerListener.h>
#include <gui/IProducerListener.h>
+#include <media/AudioResamplerPublic.h>
+#include <media/AVSyncSettings.h>
#include <media/stagefright/foundation/AHandler.h>
#include <utils/Condition.h>
@@ -77,10 +79,7 @@ public:
// Called when audio track is used as media clock source. It should be
// called before updateQueuedAudioData().
- // |nativeSampleRateInHz| is the sample rate of audio data fed into audio
- // track. It's the same number used to create AudioTrack.
- status_t configureAudioTrack(
- const sp<AudioTrack> &audioTrack, uint32_t nativeSampleRateInHz);
+ status_t configureAudioTrack(const sp<AudioTrack> &audioTrack);
// Create a surface for client to render video frames. This is the surface
// on which the client should render video frames. Those video frames will
@@ -99,21 +98,31 @@ public:
// Set the consumer name of the input queue.
void setName(const AString &name);
- // Set the playback in a desired speed.
- // This method can be called any time.
- // |rate| is the ratio between desired speed and the normal one, and should
- // be non-negative. The meaning of rate values:
- // 1.0 -- normal playback
- // 0.0 -- stop or pause
- // larger than 1.0 -- faster than normal speed
- // between 0.0 and 1.0 -- slower than normal speed
- status_t setPlaybackRate(float rate);
-
// Get the media clock used by the MediaSync so that the client can obtain
// corresponding media time or real time via
// MediaClock::getMediaTime() and MediaClock::getRealTimeFor().
sp<const MediaClock> getMediaClock();
+ // Set the video frame rate hint - this is used by the video FrameScheduler
+ status_t setVideoFrameRateHint(float rate);
+
+ // Get the video frame rate measurement from the FrameScheduler
+ // returns -1 if there is no measurement
+ float getVideoFrameRate();
+
+ // Set the sync settings parameters.
+ status_t setSyncSettings(const AVSyncSettings &syncSettings);
+
+ // Gets the sync settings parameters.
+ void getSyncSettings(AVSyncSettings *syncSettings /* nonnull */);
+
+ // Sets the playback rate using playback settings.
+ // This method can be called any time.
+ status_t setPlaybackSettings(const AudioPlaybackRate &rate);
+
+ // Gets the playback rate (playback settings parameters).
+ void getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */);
+
// Get the play time for pending audio frames in audio sink.
status_t getPlayTimeForPendingAudioFrames(int64_t *outTimeUs);
@@ -201,6 +210,9 @@ private:
sp<ALooper> mLooper;
float mPlaybackRate;
+ AudioPlaybackRate mPlaybackSettings;
+ AVSyncSettings mSyncSettings;
+
sp<MediaClock> mMediaClock;
MediaSync();
@@ -239,6 +251,22 @@ private:
// up. This must be called with mMutex locked.
void onAbandoned_l(bool isInput);
+ // Set the playback in a desired speed.
+ // This method can be called any time.
+ // |rate| is the ratio between desired speed and the normal one, and should
+ // be non-negative. The meaning of rate values:
+ // 1.0 -- normal playback
+ // 0.0 -- stop or pause
+ // larger than 1.0 -- faster than normal speed
+ // between 0.0 and 1.0 -- slower than normal speed
+ void updatePlaybackRate_l(float rate);
+
+ // apply new sync settings
+ void resync_l();
+
+ // apply playback settings only - without resyncing or updating playback rate
+ status_t setPlaybackSettings_l(const AudioPlaybackRate &rate);
+
// helper.
bool isPlaying() { return mPlaybackRate != 0.0; }
diff --git a/include/media/stagefright/Utils.h b/include/media/stagefright/Utils.h
index 0ce1603..5e9d7d4 100644
--- a/include/media/stagefright/Utils.h
+++ b/include/media/stagefright/Utils.h
@@ -76,6 +76,15 @@ struct HLSTime {
bool operator <(const HLSTime &t0, const HLSTime &t1);
+// read and write various object to/from AMessage
+
+void writeToAMessage(sp<AMessage> msg, const AudioPlaybackRate &rate);
+void readFromAMessage(const sp<AMessage> &msg, AudioPlaybackRate *rate /* nonnull */);
+
+void writeToAMessage(sp<AMessage> msg, const AVSyncSettings &sync, float videoFpsHint);
+void readFromAMessage(
+ const sp<AMessage> &msg, AVSyncSettings *sync /* nonnull */, float *videoFps /* nonnull */);
+
} // namespace android
#endif // UTILS_H_
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 36281c4..76d9169 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -393,6 +393,7 @@ status_t AudioTrack::set(
return BAD_VALUE;
}
mSampleRate = sampleRate;
+ mOriginalSampleRate = sampleRate;
mPlaybackRate = AUDIO_PLAYBACK_RATE_DEFAULT;
// Make copy of input parameter offloadInfo so that in the future:
@@ -759,6 +760,15 @@ uint32_t AudioTrack::getSampleRate() const
return mSampleRate;
}
+uint32_t AudioTrack::getOriginalSampleRate() const
+{
+ if (mIsTimed) {
+ return 0;
+ }
+
+ return mOriginalSampleRate;
+}
+
status_t AudioTrack::setPlaybackRate(const AudioPlaybackRate &playbackRate)
{
AutoMutex lock(mLock);
@@ -1106,6 +1116,7 @@ status_t AudioTrack::createTrack_l()
}
if (mSampleRate == 0) {
mSampleRate = afSampleRate;
+ mOriginalSampleRate = afSampleRate;
}
// Client decides whether the track is TIMED (see below), but can only express a preference
// for FAST. Server will perform additional tests.
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
index 0091078..bde35f2 100644
--- a/media/libmedia/IMediaPlayer.cpp
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -21,6 +21,9 @@
#include <binder/Parcel.h>
+#include <media/AudioResamplerPublic.h>
+#include <media/AVSyncSettings.h>
+
#include <media/IDataSource.h>
#include <media/IMediaHTTPService.h>
#include <media/IMediaPlayer.h>
@@ -41,7 +44,10 @@ enum {
START,
STOP,
IS_PLAYING,
- SET_PLAYBACK_RATE,
+ SET_PLAYBACK_SETTINGS,
+ GET_PLAYBACK_SETTINGS,
+ SET_SYNC_SETTINGS,
+ GET_SYNC_SETTINGS,
PAUSE,
SEEK_TO,
GET_CURRENT_POSITION,
@@ -175,15 +181,63 @@ public:
return reply.readInt32();
}
- status_t setPlaybackRate(float rate)
+ status_t setPlaybackSettings(const AudioPlaybackRate& rate)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+ data.writeFloat(rate.mSpeed);
+ data.writeFloat(rate.mPitch);
+ data.writeInt32((int32_t)rate.mFallbackMode);
+ data.writeInt32((int32_t)rate.mStretchMode);
+ remote()->transact(SET_PLAYBACK_SETTINGS, data, &reply);
+ return reply.readInt32();
+ }
+
+ status_t getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+ remote()->transact(GET_PLAYBACK_SETTINGS, data, &reply);
+ status_t err = reply.readInt32();
+ if (err == OK) {
+ *rate = AUDIO_PLAYBACK_RATE_DEFAULT;
+ rate->mSpeed = reply.readFloat();
+ rate->mPitch = reply.readFloat();
+ rate->mFallbackMode = (AudioTimestretchFallbackMode)reply.readInt32();
+ rate->mStretchMode = (AudioTimestretchStretchMode)reply.readInt32();
+ }
+ return err;
+ }
+
+ status_t setSyncSettings(const AVSyncSettings& sync, float videoFpsHint)
{
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
- data.writeFloat(rate);
- remote()->transact(SET_PLAYBACK_RATE, data, &reply);
+ data.writeInt32((int32_t)sync.mSource);
+ data.writeInt32((int32_t)sync.mAudioAdjustMode);
+ data.writeFloat(sync.mTolerance);
+ data.writeFloat(videoFpsHint);
+ remote()->transact(SET_SYNC_SETTINGS, data, &reply);
return reply.readInt32();
}
+ status_t getSyncSettings(AVSyncSettings* sync /* nonnull */, float* videoFps /* nonnull */)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+ remote()->transact(GET_SYNC_SETTINGS, data, &reply);
+ status_t err = reply.readInt32();
+ if (err == OK) {
+ AVSyncSettings settings;
+ settings.mSource = (AVSyncSource)reply.readInt32();
+ settings.mAudioAdjustMode = (AVSyncAudioAdjustMode)reply.readInt32();
+ settings.mTolerance = reply.readFloat();
+ *sync = settings;
+ *videoFps = reply.readFloat();
+ }
+ return err;
+ }
+
status_t pause()
{
Parcel data, reply;
@@ -453,9 +507,51 @@ status_t BnMediaPlayer::onTransact(
reply->writeInt32(ret);
return NO_ERROR;
} break;
- case SET_PLAYBACK_RATE: {
+ case SET_PLAYBACK_SETTINGS: {
+ CHECK_INTERFACE(IMediaPlayer, data, reply);
+ AudioPlaybackRate rate = AUDIO_PLAYBACK_RATE_DEFAULT;
+ rate.mSpeed = data.readFloat();
+ rate.mPitch = data.readFloat();
+ rate.mFallbackMode = (AudioTimestretchFallbackMode)data.readInt32();
+ rate.mStretchMode = (AudioTimestretchStretchMode)data.readInt32();
+ reply->writeInt32(setPlaybackSettings(rate));
+ return NO_ERROR;
+ } break;
+ case GET_PLAYBACK_SETTINGS: {
CHECK_INTERFACE(IMediaPlayer, data, reply);
- reply->writeInt32(setPlaybackRate(data.readFloat()));
+ AudioPlaybackRate rate = AUDIO_PLAYBACK_RATE_DEFAULT;
+ status_t err = getPlaybackSettings(&rate);
+ reply->writeInt32(err);
+ if (err == OK) {
+ reply->writeFloat(rate.mSpeed);
+ reply->writeFloat(rate.mPitch);
+ reply->writeInt32((int32_t)rate.mFallbackMode);
+ reply->writeInt32((int32_t)rate.mStretchMode);
+ }
+ return NO_ERROR;
+ } break;
+ case SET_SYNC_SETTINGS: {
+ CHECK_INTERFACE(IMediaPlayer, data, reply);
+ AVSyncSettings sync;
+ sync.mSource = (AVSyncSource)data.readInt32();
+ sync.mAudioAdjustMode = (AVSyncAudioAdjustMode)data.readInt32();
+ sync.mTolerance = data.readFloat();
+ float videoFpsHint = data.readFloat();
+ reply->writeInt32(setSyncSettings(sync, videoFpsHint));
+ return NO_ERROR;
+ } break;
+ case GET_SYNC_SETTINGS: {
+ CHECK_INTERFACE(IMediaPlayer, data, reply);
+ AVSyncSettings sync;
+ float videoFps;
+ status_t err = getSyncSettings(&sync, &videoFps);
+ reply->writeInt32(err);
+ if (err == OK) {
+ reply->writeInt32((int32_t)sync.mSource);
+ reply->writeInt32((int32_t)sync.mAudioAdjustMode);
+ reply->writeFloat(sync.mTolerance);
+ reply->writeFloat(videoFps);
+ }
return NO_ERROR;
} break;
case PAUSE: {
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 9a276ae..81a5e8c 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -32,7 +32,9 @@
#include <gui/Surface.h>
#include <media/mediaplayer.h>
+#include <media/AudioResamplerPublic.h>
#include <media/AudioSystem.h>
+#include <media/AVSyncSettings.h>
#include <media/IDataSource.h>
#include <binder/MemoryBase.h>
@@ -60,7 +62,6 @@ MediaPlayer::MediaPlayer()
mLoop = false;
mLeftVolume = mRightVolume = 1.0;
mVideoWidth = mVideoHeight = 0;
- mPlaybackRate = 1.0;
mLockThreadId = 0;
mAudioSessionId = AudioSystem::newAudioUniqueId();
AudioSystem::acquireAudioSessionId(mAudioSessionId, -1);
@@ -389,6 +390,9 @@ bool MediaPlayer::isPlaying()
if ((mCurrentState & MEDIA_PLAYER_STARTED) && ! temp) {
ALOGE("internal/external state mismatch corrected");
mCurrentState = MEDIA_PLAYER_PAUSED;
+ } else if ((mCurrentState & MEDIA_PLAYER_PAUSED) && temp) {
+ ALOGE("internal/external state mismatch corrected");
+ mCurrentState = MEDIA_PLAYER_STARTED;
}
return temp;
}
@@ -396,22 +400,50 @@ bool MediaPlayer::isPlaying()
return false;
}
-status_t MediaPlayer::setPlaybackRate(float rate)
+status_t MediaPlayer::setPlaybackSettings(const AudioPlaybackRate& rate)
{
- ALOGV("setPlaybackRate: %f", rate);
- if (rate <= 0.0) {
+ ALOGV("setPlaybackSettings: %f %f %d %d",
+ rate.mSpeed, rate.mPitch, rate.mFallbackMode, rate.mStretchMode);
+ // Negative speed and pitch does not make sense. Further validation will
+ // be done by the respective mediaplayers.
+ if (rate.mSpeed < 0.f || rate.mPitch < 0.f) {
return BAD_VALUE;
}
Mutex::Autolock _l(mLock);
- if (mPlayer != 0) {
- if (mPlaybackRate == rate) {
- return NO_ERROR;
+ if (mPlayer == 0) return INVALID_OPERATION;
+ status_t err = mPlayer->setPlaybackSettings(rate);
+ if (err == OK) {
+ if (rate.mSpeed == 0.f && mCurrentState == MEDIA_PLAYER_STARTED) {
+ mCurrentState = MEDIA_PLAYER_PAUSED;
+ } else if (rate.mSpeed != 0.f && mCurrentState == MEDIA_PLAYER_PAUSED) {
+ mCurrentState = MEDIA_PLAYER_STARTED;
}
- mPlaybackRate = rate;
- return mPlayer->setPlaybackRate(rate);
}
- ALOGV("setPlaybackRate: no active player");
- return INVALID_OPERATION;
+ return err;
+}
+
+status_t MediaPlayer::getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */)
+{
+ Mutex::Autolock _l(mLock);
+ if (mPlayer == 0) return INVALID_OPERATION;
+ return mPlayer->getPlaybackSettings(rate);
+}
+
+status_t MediaPlayer::setSyncSettings(const AVSyncSettings& sync, float videoFpsHint)
+{
+ ALOGV("setSyncSettings: %u %u %f %f",
+ sync.mSource, sync.mAudioAdjustMode, sync.mTolerance, videoFpsHint);
+ Mutex::Autolock _l(mLock);
+ if (mPlayer == 0) return INVALID_OPERATION;
+ return mPlayer->setSyncSettings(sync, videoFpsHint);
+}
+
+status_t MediaPlayer::getSyncSettings(
+ AVSyncSettings* sync /* nonnull */, float* videoFps /* nonnull */)
+{
+ Mutex::Autolock _l(mLock);
+ if (mPlayer == 0) return INVALID_OPERATION;
+ return mPlayer->getSyncSettings(sync, videoFps);
}
status_t MediaPlayer::getVideoWidth(int *w)
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 9567eff..891a9e9 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -981,12 +981,52 @@ status_t MediaPlayerService::Client::isPlaying(bool* state)
return NO_ERROR;
}
-status_t MediaPlayerService::Client::setPlaybackRate(float rate)
+status_t MediaPlayerService::Client::setPlaybackSettings(const AudioPlaybackRate& rate)
{
- ALOGV("[%d] setPlaybackRate(%f)", mConnId, rate);
+ ALOGV("[%d] setPlaybackSettings(%f, %f, %d, %d)",
+ mConnId, rate.mSpeed, rate.mPitch, rate.mFallbackMode, rate.mStretchMode);
sp<MediaPlayerBase> p = getPlayer();
if (p == 0) return UNKNOWN_ERROR;
- return p->setPlaybackRate(rate);
+ return p->setPlaybackSettings(rate);
+}
+
+status_t MediaPlayerService::Client::getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */)
+{
+ sp<MediaPlayerBase> p = getPlayer();
+ if (p == 0) return UNKNOWN_ERROR;
+ status_t ret = p->getPlaybackSettings(rate);
+ if (ret == NO_ERROR) {
+ ALOGV("[%d] getPlaybackSettings(%f, %f, %d, %d)",
+ mConnId, rate->mSpeed, rate->mPitch, rate->mFallbackMode, rate->mStretchMode);
+ } else {
+ ALOGV("[%d] getPlaybackSettings returned %d", mConnId, ret);
+ }
+ return ret;
+}
+
+status_t MediaPlayerService::Client::setSyncSettings(
+ const AVSyncSettings& sync, float videoFpsHint)
+{
+ ALOGV("[%d] setSyncSettings(%u, %u, %f, %f)",
+ mConnId, sync.mSource, sync.mAudioAdjustMode, sync.mTolerance, videoFpsHint);
+ sp<MediaPlayerBase> p = getPlayer();
+ if (p == 0) return UNKNOWN_ERROR;
+ return p->setSyncSettings(sync, videoFpsHint);
+}
+
+status_t MediaPlayerService::Client::getSyncSettings(
+ AVSyncSettings* sync /* nonnull */, float* videoFps /* nonnull */)
+{
+ sp<MediaPlayerBase> p = getPlayer();
+ if (p == 0) return UNKNOWN_ERROR;
+ status_t ret = p->getSyncSettings(sync, videoFps);
+ if (ret == NO_ERROR) {
+ ALOGV("[%d] getSyncSettings(%u, %u, %f, %f)",
+ mConnId, sync->mSource, sync->mAudioAdjustMode, sync->mTolerance, *videoFps);
+ } else {
+ ALOGV("[%d] getSyncSettings returned %d", mConnId, ret);
+ }
+ return ret;
}
status_t MediaPlayerService::Client::getCurrentPosition(int *msec)
@@ -1311,7 +1351,7 @@ MediaPlayerService::AudioOutput::AudioOutput(int sessionId, int uid, int pid,
mStreamType = AUDIO_STREAM_MUSIC;
mLeftVolume = 1.0;
mRightVolume = 1.0;
- mPlaybackRatePermille = 1000;
+ mPlaybackRate = AUDIO_PLAYBACK_RATE_DEFAULT;
mSampleRateHz = 0;
mMsecsPerFrame = 0;
mAuxEffectId = 0;
@@ -1634,7 +1674,7 @@ status_t MediaPlayerService::AudioOutput::open(
mSampleRateHz = sampleRate;
mFlags = flags;
- mMsecsPerFrame = mPlaybackRatePermille / (float) sampleRate;
+ mMsecsPerFrame = 1E3f / (mPlaybackRate.mSpeed * sampleRate);
uint32_t pos;
if (t->getPosition(&pos) == OK) {
mBytesWritten = uint64_t(pos) * t->frameSize();
@@ -1643,7 +1683,7 @@ status_t MediaPlayerService::AudioOutput::open(
status_t res = NO_ERROR;
if ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0) {
- res = t->setSampleRate(mPlaybackRatePermille * mSampleRateHz / 1000);
+ res = t->setPlaybackRate(mPlaybackRate);
if (res == NO_ERROR) {
t->setAuxEffectSendLevel(mSendLevel);
res = t->attachAuxEffect(mAuxEffectId);
@@ -1739,22 +1779,38 @@ void MediaPlayerService::AudioOutput::setVolume(float left, float right)
}
}
-status_t MediaPlayerService::AudioOutput::setPlaybackRatePermille(int32_t ratePermille)
+status_t MediaPlayerService::AudioOutput::setPlaybackRate(const AudioPlaybackRate &rate)
{
- ALOGV("setPlaybackRatePermille(%d)", ratePermille);
- status_t res = NO_ERROR;
- if (mTrack != 0) {
- res = mTrack->setSampleRate(ratePermille * mSampleRateHz / 1000);
- } else {
- res = NO_INIT;
+ ALOGV("setPlaybackRate(%f %f %d %d)",
+ rate.mSpeed, rate.mPitch, rate.mFallbackMode, rate.mStretchMode);
+ if (mTrack == 0) {
+ // remember rate so that we can set it when the track is opened
+ mPlaybackRate = rate;
+ return OK;
+ }
+ status_t res = mTrack->setPlaybackRate(rate);
+ if (res != NO_ERROR) {
+ return res;
}
- mPlaybackRatePermille = ratePermille;
+ // rate.mSpeed is always greater than 0 if setPlaybackRate succeeded
+ CHECK_GT(rate.mSpeed, 0.f);
+ mPlaybackRate = rate;
if (mSampleRateHz != 0) {
- mMsecsPerFrame = mPlaybackRatePermille / (float) mSampleRateHz;
+ mMsecsPerFrame = 1E3f / (rate.mSpeed * mSampleRateHz);
}
return res;
}
+status_t MediaPlayerService::AudioOutput::getPlaybackRate(AudioPlaybackRate *rate)
+{
+ ALOGV("setPlaybackRate");
+ if (mTrack == 0) {
+ return NO_INIT;
+ }
+ *rate = mTrack->getPlaybackRate();
+ return NO_ERROR;
+}
+
status_t MediaPlayerService::AudioOutput::setAuxEffectSendLevel(float level)
{
ALOGV("setAuxEffectSendLevel(%f)", level);
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 1a3ce92..5103841 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -34,7 +34,9 @@
namespace android {
+struct AudioPlaybackRate;
class AudioTrack;
+struct AVSyncSettings;
class IDataSource;
class IMediaRecorder;
class IMediaMetadataRetriever;
@@ -109,7 +111,9 @@ class MediaPlayerService : public BnMediaPlayerService
void setAudioAttributes(const audio_attributes_t * attributes);
void setVolume(float left, float right);
- virtual status_t setPlaybackRatePermille(int32_t ratePermille);
+ virtual status_t setPlaybackRate(const AudioPlaybackRate& rate);
+ virtual status_t getPlaybackRate(AudioPlaybackRate* rate /* nonnull */);
+
status_t setAuxEffectSendLevel(float level);
status_t attachAuxEffect(int effectId);
virtual status_t dump(int fd, const Vector<String16>& args) const;
@@ -139,7 +143,7 @@ class MediaPlayerService : public BnMediaPlayerService
const audio_attributes_t *mAttributes;
float mLeftVolume;
float mRightVolume;
- int32_t mPlaybackRatePermille;
+ AudioPlaybackRate mPlaybackRate;
uint32_t mSampleRateHz; // sample rate of the content, as set in open()
float mMsecsPerFrame;
int mSessionId;
@@ -262,7 +266,11 @@ private:
virtual status_t stop();
virtual status_t pause();
virtual status_t isPlaying(bool* state);
- virtual status_t setPlaybackRate(float rate);
+ virtual status_t setPlaybackSettings(const AudioPlaybackRate& rate);
+ virtual status_t getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */);
+ virtual status_t setSyncSettings(const AVSyncSettings& rate, float videoFpsHint);
+ virtual status_t getSyncSettings(AVSyncSettings* rate /* nonnull */,
+ float* videoFps /* nonnull */);
virtual status_t seekTo(int msec);
virtual status_t getCurrentPosition(int* msec);
virtual status_t getDuration(int* msec);
diff --git a/media/libmediaplayerservice/StagefrightPlayer.cpp b/media/libmediaplayerservice/StagefrightPlayer.cpp
index b37aee3..3fedd9b 100644
--- a/media/libmediaplayerservice/StagefrightPlayer.cpp
+++ b/media/libmediaplayerservice/StagefrightPlayer.cpp
@@ -188,6 +188,14 @@ status_t StagefrightPlayer::getParameter(int key, Parcel *reply) {
return mPlayer->getParameter(key, reply);
}
+status_t StagefrightPlayer::setPlaybackSettings(const AudioPlaybackRate &rate) {
+ return mPlayer->setPlaybackSettings(rate);
+}
+
+status_t StagefrightPlayer::getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */) {
+ return mPlayer->getPlaybackSettings(rate);
+}
+
status_t StagefrightPlayer::getMetadata(
const media::Metadata::Filter& /* ids */, Parcel *records) {
using media::Metadata;
diff --git a/media/libmediaplayerservice/StagefrightPlayer.h b/media/libmediaplayerservice/StagefrightPlayer.h
index e6c30ff..96013df 100644
--- a/media/libmediaplayerservice/StagefrightPlayer.h
+++ b/media/libmediaplayerservice/StagefrightPlayer.h
@@ -60,6 +60,8 @@ public:
virtual void setAudioSink(const sp<AudioSink> &audioSink);
virtual status_t setParameter(int key, const Parcel &request);
virtual status_t getParameter(int key, Parcel *reply);
+ virtual status_t setPlaybackSettings(const AudioPlaybackRate &rate);
+ virtual status_t getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */);
virtual status_t getMetadata(
const media::Metadata::Filter& ids, Parcel *records);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index b670d68..cb8579b 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -37,6 +37,9 @@
#include <cutils/properties.h>
+#include <media/AudioResamplerPublic.h>
+#include <media/AVSyncSettings.h>
+
#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
@@ -180,7 +183,8 @@ NuPlayer::NuPlayer()
mFlushingVideo(NONE),
mResumePending(false),
mVideoScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW),
- mPlaybackRate(1.0),
+ mPlaybackSettings(AUDIO_PLAYBACK_RATE_DEFAULT),
+ mVideoFpsHint(-1.f),
mStarted(false),
mPaused(false),
mPausedByClient(false) {
@@ -331,10 +335,61 @@ void NuPlayer::start() {
(new AMessage(kWhatStart, this))->post();
}
-void NuPlayer::setPlaybackRate(float rate) {
- sp<AMessage> msg = new AMessage(kWhatSetRate, this);
- msg->setFloat("rate", rate);
- msg->post();
+status_t NuPlayer::setPlaybackSettings(const AudioPlaybackRate &rate) {
+ // do some cursory validation of the settings here. audio modes are
+ // only validated when set on the audiosink.
+ if ((rate.mSpeed != 0.f && rate.mSpeed < AUDIO_TIMESTRETCH_SPEED_MIN)
+ || rate.mSpeed > AUDIO_TIMESTRETCH_SPEED_MAX
+ || rate.mPitch < AUDIO_TIMESTRETCH_SPEED_MIN
+ || rate.mPitch > AUDIO_TIMESTRETCH_SPEED_MAX) {
+ return BAD_VALUE;
+ }
+ sp<AMessage> msg = new AMessage(kWhatConfigPlayback, this);
+ writeToAMessage(msg, rate);
+ sp<AMessage> response;
+ status_t err = msg->postAndAwaitResponse(&response);
+ if (err == OK && response != NULL) {
+ CHECK(response->findInt32("err", &err));
+ }
+ return err;
+}
+
+status_t NuPlayer::getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */) {
+ sp<AMessage> msg = new AMessage(kWhatGetPlaybackSettings, this);
+ sp<AMessage> response;
+ status_t err = msg->postAndAwaitResponse(&response);
+ if (err == OK && response != NULL) {
+ CHECK(response->findInt32("err", &err));
+ if (err == OK) {
+ readFromAMessage(response, rate);
+ }
+ }
+ return err;
+}
+
+status_t NuPlayer::setSyncSettings(const AVSyncSettings &sync, float videoFpsHint) {
+ sp<AMessage> msg = new AMessage(kWhatConfigSync, this);
+ writeToAMessage(msg, sync, videoFpsHint);
+ sp<AMessage> response;
+ status_t err = msg->postAndAwaitResponse(&response);
+ if (err == OK && response != NULL) {
+ CHECK(response->findInt32("err", &err));
+ }
+ return err;
+}
+
+status_t NuPlayer::getSyncSettings(
+ AVSyncSettings *sync /* nonnull */, float *videoFps /* nonnull */) {
+ sp<AMessage> msg = new AMessage(kWhatGetSyncSettings, this);
+ sp<AMessage> response;
+ status_t err = msg->postAndAwaitResponse(&response);
+ if (err == OK && response != NULL) {
+ CHECK(response->findInt32("err", &err));
+ if (err == OK) {
+ readFromAMessage(response, sync, videoFps);
+ }
+ }
+ return err;
}
void NuPlayer::pause() {
@@ -627,12 +682,28 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
break;
}
- case kWhatSetRate:
+ case kWhatConfigPlayback:
{
- ALOGV("kWhatSetRate");
- CHECK(msg->findFloat("rate", &mPlaybackRate));
+ sp<AReplyToken> replyID;
+ CHECK(msg->senderAwaitsResponse(&replyID));
+ AudioPlaybackRate rate /* sanitized */;
+ readFromAMessage(msg, &rate);
+ status_t err = OK;
if (mRenderer != NULL) {
- mRenderer->setPlaybackRate(mPlaybackRate);
+ err = mRenderer->setPlaybackSettings(rate);
+ }
+ if (err == OK) {
+ if (rate.mSpeed == 0.f) {
+ onPause();
+ // save all other settings (using non-paused speed)
+ // so we can restore them on start
+ AudioPlaybackRate newRate = rate;
+ newRate.mSpeed = mPlaybackSettings.mSpeed;
+ mPlaybackSettings = newRate;
+ } else { /* rate.mSpeed != 0.f */
+ onResume();
+ mPlaybackSettings = rate;
+ }
}
if (mVideoDecoder != NULL) {
@@ -640,11 +711,86 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
int32_t rate;
if (meta != NULL && meta->findInt32(kKeyFrameRate, &rate) && rate > 0) {
sp<AMessage> params = new AMessage();
- params->setFloat("operating-rate", rate * mPlaybackRate);
+ params->setFloat("operating-rate", rate * mPlaybackSettings.mSpeed);
mVideoDecoder->setParameters(params);
}
}
+ sp<AMessage> response = new AMessage;
+ response->setInt32("err", err);
+ response->postReply(replyID);
+ break;
+ }
+
+ case kWhatGetPlaybackSettings:
+ {
+ sp<AReplyToken> replyID;
+ CHECK(msg->senderAwaitsResponse(&replyID));
+ AudioPlaybackRate rate = mPlaybackSettings;
+ status_t err = OK;
+ if (mRenderer != NULL) {
+ err = mRenderer->getPlaybackSettings(&rate);
+ }
+ if (err == OK) {
+ // get playback settings used by renderer, as it may be
+ // slightly off due to audiosink not taking small changes.
+ mPlaybackSettings = rate;
+ if (mPaused) {
+ rate.mSpeed = 0.f;
+ }
+ }
+ sp<AMessage> response = new AMessage;
+ if (err == OK) {
+ writeToAMessage(response, rate);
+ }
+ response->setInt32("err", err);
+ response->postReply(replyID);
+ break;
+ }
+
+ case kWhatConfigSync:
+ {
+ sp<AReplyToken> replyID;
+ CHECK(msg->senderAwaitsResponse(&replyID));
+
+ ALOGV("kWhatConfigSync");
+ AVSyncSettings sync;
+ float videoFpsHint;
+ readFromAMessage(msg, &sync, &videoFpsHint);
+ status_t err = OK;
+ if (mRenderer != NULL) {
+ err = mRenderer->setSyncSettings(sync, videoFpsHint);
+ }
+ if (err == OK) {
+ mSyncSettings = sync;
+ mVideoFpsHint = videoFpsHint;
+ }
+ sp<AMessage> response = new AMessage;
+ response->setInt32("err", err);
+ response->postReply(replyID);
+ break;
+ }
+
+ case kWhatGetSyncSettings:
+ {
+ sp<AReplyToken> replyID;
+ CHECK(msg->senderAwaitsResponse(&replyID));
+ AVSyncSettings sync = mSyncSettings;
+ float videoFps = mVideoFpsHint;
+ status_t err = OK;
+ if (mRenderer != NULL) {
+ err = mRenderer->getSyncSettings(&sync, &videoFps);
+ if (err == OK) {
+ mSyncSettings = sync;
+ mVideoFpsHint = videoFps;
+ }
+ }
+ sp<AMessage> response = new AMessage;
+ if (err == OK) {
+ writeToAMessage(response, sync, videoFps);
+ }
+ response->setInt32("err", err);
+ response->postReply(replyID);
break;
}
@@ -1114,8 +1260,12 @@ void NuPlayer::onStart() {
mRendererLooper->setName("NuPlayerRenderer");
mRendererLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
mRendererLooper->registerHandler(mRenderer);
- if (mPlaybackRate != 1.0) {
- mRenderer->setPlaybackRate(mPlaybackRate);
+
+ status_t err = mRenderer->setPlaybackSettings(mPlaybackSettings);
+ if (err != OK) {
+ mSource->stop();
+ notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
+ return;
}
sp<MetaData> meta = getFileMeta();
@@ -1282,7 +1432,7 @@ status_t NuPlayer::instantiateDecoder(bool audio, sp<DecoderBase> *decoder) {
sp<MetaData> meta = getFileMeta();
int32_t rate;
if (meta != NULL && meta->findInt32(kKeyFrameRate, &rate) && rate > 0) {
- format->setFloat("operating-rate", rate * mPlaybackRate);
+ format->setFloat("operating-rate", rate * mPlaybackSettings.mSpeed);
}
}
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index 14bdb01..88e929d 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -18,6 +18,7 @@
#define NU_PLAYER_H_
+#include <media/AudioResamplerPublic.h>
#include <media/MediaPlayerInterface.h>
#include <media/stagefright/foundation/AHandler.h>
#include <media/stagefright/NativeWindowWrapper.h>
@@ -26,6 +27,8 @@ namespace android {
struct ABuffer;
struct AMessage;
+struct AudioPlaybackRate;
+struct AVSyncSettings;
class IDataSource;
class MetaData;
struct NuPlayerDriver;
@@ -54,7 +57,11 @@ struct NuPlayer : public AHandler {
const sp<IGraphicBufferProducer> &bufferProducer);
void setAudioSink(const sp<MediaPlayerBase::AudioSink> &sink);
- void setPlaybackRate(float rate);
+ status_t setPlaybackSettings(const AudioPlaybackRate &rate);
+ status_t getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */);
+ status_t setSyncSettings(const AVSyncSettings &sync, float videoFpsHint);
+ status_t getSyncSettings(AVSyncSettings *sync /* nonnull */, float *videoFps /* nonnull */);
+
void start();
void pause();
@@ -108,7 +115,10 @@ private:
kWhatSetVideoNativeWindow = '=NaW',
kWhatSetAudioSink = '=AuS',
kWhatMoreDataQueued = 'more',
- kWhatSetRate = 'setR',
+ kWhatConfigPlayback = 'cfPB',
+ kWhatConfigSync = 'cfSy',
+ kWhatGetPlaybackSettings = 'gPbS',
+ kWhatGetSyncSettings = 'gSyS',
kWhatStart = 'strt',
kWhatScanSources = 'scan',
kWhatVideoNotify = 'vidN',
@@ -180,7 +190,9 @@ private:
int32_t mVideoScalingMode;
- float mPlaybackRate;
+ AudioPlaybackRate mPlaybackSettings;
+ AVSyncSettings mSyncSettings;
+ float mVideoFpsHint;
bool mStarted;
// Actual pause state, either as requested by client or due to buffering.
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index 04a324c..231f2e1 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -360,9 +360,32 @@ bool NuPlayerDriver::isPlaying() {
return mState == STATE_RUNNING && !mAtEOS;
}
-status_t NuPlayerDriver::setPlaybackRate(float rate) {
- mPlayer->setPlaybackRate(rate);
- return OK;
+status_t NuPlayerDriver::setPlaybackSettings(const AudioPlaybackRate &rate) {
+ Mutex::Autolock autoLock(mLock);
+ status_t err = mPlayer->setPlaybackSettings(rate);
+ if (err == OK) {
+ if (rate.mSpeed == 0.f && mState == STATE_RUNNING) {
+ mState = STATE_PAUSED;
+ // try to update position
+ (void)mPlayer->getCurrentPosition(&mPositionUs);
+ notifyListener_l(MEDIA_PAUSED);
+ } else if (rate.mSpeed != 0.f && mState == STATE_PAUSED) {
+ mState = STATE_RUNNING;
+ }
+ }
+ return err;
+}
+
+status_t NuPlayerDriver::getPlaybackSettings(AudioPlaybackRate *rate) {
+ return mPlayer->getPlaybackSettings(rate);
+}
+
+status_t NuPlayerDriver::setSyncSettings(const AVSyncSettings &sync, float videoFpsHint) {
+ return mPlayer->setSyncSettings(sync, videoFpsHint);
+}
+
+status_t NuPlayerDriver::getSyncSettings(AVSyncSettings *sync, float *videoFps) {
+ return mPlayer->getSyncSettings(sync, videoFps);
}
status_t NuPlayerDriver::seekTo(int msec) {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
index 65f170e..9da7fc1 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
@@ -49,7 +49,10 @@ struct NuPlayerDriver : public MediaPlayerInterface {
virtual status_t stop();
virtual status_t pause();
virtual bool isPlaying();
- virtual status_t setPlaybackRate(float rate);
+ virtual status_t setPlaybackSettings(const AudioPlaybackRate &rate);
+ virtual status_t getPlaybackSettings(AudioPlaybackRate *rate);
+ virtual status_t setSyncSettings(const AVSyncSettings &sync, float videoFpsHint);
+ virtual status_t getSyncSettings(AVSyncSettings *sync, float *videoFps);
virtual status_t seekTo(int msec);
virtual status_t getCurrentPosition(int *msec);
virtual status_t getDuration(int *msec);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index f229452..ae01cfc 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -66,7 +66,7 @@ NuPlayer::Renderer::Renderer(
mVideoQueueGeneration(0),
mAudioDrainGeneration(0),
mVideoDrainGeneration(0),
- mPlaybackRate(1.0),
+ mPlaybackSettings(AUDIO_PLAYBACK_RATE_DEFAULT),
mAudioFirstAnchorTimeMediaUs(-1),
mAnchorTimeMediaUs(-1),
mAnchorNumFramesWritten(-1),
@@ -89,6 +89,8 @@ NuPlayer::Renderer::Renderer(
mLastAudioBufferDrained(0),
mWakeLock(new AWakeLock()) {
mMediaClock = new MediaClock;
+ mPlaybackRate = mPlaybackSettings.mSpeed;
+ mMediaClock->setPlaybackRate(mPlaybackRate);
}
NuPlayer::Renderer::~Renderer() {
@@ -121,10 +123,111 @@ void NuPlayer::Renderer::queueEOS(bool audio, status_t finalResult) {
msg->post();
}
-void NuPlayer::Renderer::setPlaybackRate(float rate) {
- sp<AMessage> msg = new AMessage(kWhatSetRate, this);
- msg->setFloat("rate", rate);
- msg->post();
+status_t NuPlayer::Renderer::setPlaybackSettings(const AudioPlaybackRate &rate) {
+ sp<AMessage> msg = new AMessage(kWhatConfigPlayback, this);
+ writeToAMessage(msg, rate);
+ sp<AMessage> response;
+ status_t err = msg->postAndAwaitResponse(&response);
+ if (err == OK && response != NULL) {
+ CHECK(response->findInt32("err", &err));
+ }
+ return err;
+}
+
+status_t NuPlayer::Renderer::onConfigPlayback(const AudioPlaybackRate &rate /* sanitized */) {
+ if (rate.mSpeed == 0.f) {
+ onPause();
+ // don't call audiosink's setPlaybackRate if pausing, as pitch does not
+ // have to correspond to the any non-0 speed (e.g old speed). Keep
+ // settings nonetheless, using the old speed, in case audiosink changes.
+ AudioPlaybackRate newRate = rate;
+ newRate.mSpeed = mPlaybackSettings.mSpeed;
+ mPlaybackSettings = newRate;
+ return OK;
+ }
+
+ if (mAudioSink != NULL) {
+ status_t err = mAudioSink->setPlaybackRate(rate);
+ if (err != OK) {
+ return err;
+ }
+ }
+ mPlaybackSettings = rate;
+ mPlaybackRate = rate.mSpeed;
+ mMediaClock->setPlaybackRate(mPlaybackRate);
+ return OK;
+}
+
+status_t NuPlayer::Renderer::getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */) {
+ sp<AMessage> msg = new AMessage(kWhatGetPlaybackSettings, this);
+ sp<AMessage> response;
+ status_t err = msg->postAndAwaitResponse(&response);
+ if (err == OK && response != NULL) {
+ CHECK(response->findInt32("err", &err));
+ if (err == OK) {
+ readFromAMessage(response, rate);
+ }
+ }
+ return err;
+}
+
+status_t NuPlayer::Renderer::onGetPlaybackSettings(AudioPlaybackRate *rate /* nonnull */) {
+ if (mAudioSink != NULL) {
+ status_t err = mAudioSink->getPlaybackRate(rate);
+ if (err == OK) {
+ if (!isAudioPlaybackRateEqual(*rate, mPlaybackSettings)) {
+ ALOGW("correcting mismatch in internal/external playback rate");
+ }
+ // get playback settings used by audiosink, as it may be
+ // slightly off due to audiosink not taking small changes.
+ mPlaybackSettings = *rate;
+ if (mPaused) {
+ rate->mSpeed = 0.f;
+ }
+ }
+ return err;
+ }
+ *rate = mPlaybackSettings;
+ return OK;
+}
+
+status_t NuPlayer::Renderer::setSyncSettings(const AVSyncSettings &sync, float videoFpsHint) {
+ sp<AMessage> msg = new AMessage(kWhatConfigSync, this);
+ writeToAMessage(msg, sync, videoFpsHint);
+ sp<AMessage> response;
+ status_t err = msg->postAndAwaitResponse(&response);
+ if (err == OK && response != NULL) {
+ CHECK(response->findInt32("err", &err));
+ }
+ return err;
+}
+
+status_t NuPlayer::Renderer::onConfigSync(const AVSyncSettings &sync, float videoFpsHint __unused) {
+ if (sync.mSource != AVSYNC_SOURCE_DEFAULT) {
+ return BAD_VALUE;
+ }
+ // TODO: support sync sources
+ return INVALID_OPERATION;
+}
+
+status_t NuPlayer::Renderer::getSyncSettings(AVSyncSettings *sync, float *videoFps) {
+ sp<AMessage> msg = new AMessage(kWhatGetSyncSettings, this);
+ sp<AMessage> response;
+ status_t err = msg->postAndAwaitResponse(&response);
+ if (err == OK && response != NULL) {
+ CHECK(response->findInt32("err", &err));
+ if (err == OK) {
+ readFromAMessage(response, sync, videoFps);
+ }
+ }
+ return err;
+}
+
+status_t NuPlayer::Renderer::onGetSyncSettings(
+ AVSyncSettings *sync /* nonnull */, float *videoFps /* nonnull */) {
+ *sync = mSyncSettings;
+ *videoFps = -1.f;
+ return OK;
}
void NuPlayer::Renderer::flush(bool audio, bool notifyComplete) {
@@ -365,13 +468,63 @@ void NuPlayer::Renderer::onMessageReceived(const sp<AMessage> &msg) {
break;
}
- case kWhatSetRate:
+ case kWhatConfigPlayback:
{
- CHECK(msg->findFloat("rate", &mPlaybackRate));
- int32_t ratePermille = (int32_t)(0.5f + 1000 * mPlaybackRate);
- mPlaybackRate = ratePermille / 1000.0f;
- mMediaClock->setPlaybackRate(mPlaybackRate);
- mAudioSink->setPlaybackRatePermille(ratePermille);
+ sp<AReplyToken> replyID;
+ CHECK(msg->senderAwaitsResponse(&replyID));
+ AudioPlaybackRate rate;
+ readFromAMessage(msg, &rate);
+ status_t err = onConfigPlayback(rate);
+ sp<AMessage> response = new AMessage;
+ response->setInt32("err", err);
+ response->postReply(replyID);
+ break;
+ }
+
+ case kWhatGetPlaybackSettings:
+ {
+ sp<AReplyToken> replyID;
+ CHECK(msg->senderAwaitsResponse(&replyID));
+ AudioPlaybackRate rate = AUDIO_PLAYBACK_RATE_DEFAULT;
+ status_t err = onGetPlaybackSettings(&rate);
+ sp<AMessage> response = new AMessage;
+ if (err == OK) {
+ writeToAMessage(response, rate);
+ }
+ response->setInt32("err", err);
+ response->postReply(replyID);
+ break;
+ }
+
+ case kWhatConfigSync:
+ {
+ sp<AReplyToken> replyID;
+ CHECK(msg->senderAwaitsResponse(&replyID));
+ AVSyncSettings sync;
+ float videoFpsHint;
+ readFromAMessage(msg, &sync, &videoFpsHint);
+ status_t err = onConfigSync(sync, videoFpsHint);
+ sp<AMessage> response = new AMessage;
+ response->setInt32("err", err);
+ response->postReply(replyID);
+ break;
+ }
+
+ case kWhatGetSyncSettings:
+ {
+ sp<AReplyToken> replyID;
+ CHECK(msg->senderAwaitsResponse(&replyID));
+
+ ALOGV("kWhatGetSyncSettings");
+ AVSyncSettings sync;
+ float videoFps = -1.f;
+ status_t err = onGetSyncSettings(&sync, &videoFps);
+ sp<AMessage> response = new AMessage;
+ if (err == OK) {
+ writeToAMessage(response, sync, videoFps);
+ }
+ response->setInt32("err", err);
+ response->postReply(replyID);
break;
}
@@ -1176,7 +1329,6 @@ void NuPlayer::Renderer::onEnableOffloadAudio() {
void NuPlayer::Renderer::onPause() {
if (mPaused) {
- ALOGW("Renderer::onPause() called while already paused!");
return;
}
@@ -1214,6 +1366,12 @@ void NuPlayer::Renderer::onResume() {
{
Mutex::Autolock autoLock(mLock);
mPaused = false;
+
+ // configure audiosink as we did not do it when pausing
+ if (mAudioSink != NULL) {
+ mAudioSink->setPlaybackRate(mPlaybackSettings);
+ }
+
mMediaClock->setPlaybackRate(mPlaybackRate);
if (!mAudioQueue.empty()) {
@@ -1433,10 +1591,10 @@ status_t NuPlayer::Renderer::onOpenAudioSink(
&offloadInfo);
if (err == OK) {
- if (mPlaybackRate != 1.0) {
- mAudioSink->setPlaybackRatePermille(
- (int32_t)(mPlaybackRate * 1000 + 0.5f));
- }
+ err = mAudioSink->setPlaybackRate(mPlaybackSettings);
+ }
+
+ if (err == OK) {
// If the playback is offloaded to h/w, we pass
// the HAL some metadata information.
// We don't want to do this for PCM because it
@@ -1486,16 +1644,15 @@ status_t NuPlayer::Renderer::onOpenAudioSink(
NULL,
NULL,
(audio_output_flags_t)pcmFlags);
+ if (err == OK) {
+ err = mAudioSink->setPlaybackRate(mPlaybackSettings);
+ }
if (err != OK) {
ALOGW("openAudioSink: non offloaded open failed status: %d", err);
mCurrentPcmInfo = AUDIO_PCMINFO_INITIALIZER;
return err;
}
mCurrentPcmInfo = info;
- if (mPlaybackRate != 1.0) {
- mAudioSink->setPlaybackRatePermille(
- (int32_t)(mPlaybackRate * 1000 + 0.5f));
- }
mAudioSink->start();
}
if (audioSinkChanged) {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
index 38843d5..928b71b 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
@@ -18,6 +18,9 @@
#define NUPLAYER_RENDERER_H_
+#include <media/AudioResamplerPublic.h>
+#include <media/AVSyncSettings.h>
+
#include "NuPlayer.h"
namespace android {
@@ -48,7 +51,10 @@ struct NuPlayer::Renderer : public AHandler {
void queueEOS(bool audio, status_t finalResult);
- void setPlaybackRate(float rate);
+ status_t setPlaybackSettings(const AudioPlaybackRate &rate /* sanitized */);
+ status_t getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */);
+ status_t setSyncSettings(const AVSyncSettings &sync, float videoFpsHint);
+ status_t getSyncSettings(AVSyncSettings *sync /* nonnull */, float *videoFps /* nonnull */);
void flush(bool audio, bool notifyComplete);
@@ -102,7 +108,10 @@ private:
kWhatPostDrainVideoQueue = 'pDVQ',
kWhatQueueBuffer = 'queB',
kWhatQueueEOS = 'qEOS',
- kWhatSetRate = 'setR',
+ kWhatConfigPlayback = 'cfPB',
+ kWhatConfigSync = 'cfSy',
+ kWhatGetPlaybackSettings = 'gPbS',
+ kWhatGetSyncSettings = 'gSyS',
kWhatFlush = 'flus',
kWhatPause = 'paus',
kWhatResume = 'resm',
@@ -141,7 +150,12 @@ private:
int32_t mVideoDrainGeneration;
sp<MediaClock> mMediaClock;
- float mPlaybackRate;
+ float mPlaybackRate; // audio track rate
+
+ AudioPlaybackRate mPlaybackSettings;
+ AVSyncSettings mSyncSettings;
+ float mVideoFpsHint;
+
int64_t mAudioFirstAnchorTimeMediaUs;
int64_t mAnchorTimeMediaUs;
int64_t mAnchorNumFramesWritten;
@@ -217,6 +231,11 @@ private:
void onAudioSinkChanged();
void onDisableOffloadAudio();
void onEnableOffloadAudio();
+ status_t onConfigPlayback(const AudioPlaybackRate &rate /* sanitized */);
+ status_t onGetPlaybackSettings(AudioPlaybackRate *rate /* nonnull */);
+ status_t onConfigSync(const AVSyncSettings &sync, float videoFpsHint);
+ status_t onGetSyncSettings(AVSyncSettings *sync /* nonnull */, float *videoFps /* nonnull */);
+
void onPause();
void onResume();
void onSetVideoFrameRate(float fps);
@@ -252,6 +271,6 @@ private:
DISALLOW_EVIL_CONSTRUCTORS(Renderer);
};
-} // namespace android
+} // namespace android
#endif // NUPLAYER_RENDERER_H_
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index e24824b..dd9d393 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -408,11 +408,22 @@ void AudioPlayer::notifyAudioEOS() {
}
}
-status_t AudioPlayer::setPlaybackRatePermille(int32_t ratePermille) {
+status_t AudioPlayer::setPlaybackRate(const AudioPlaybackRate &rate) {
if (mAudioSink.get() != NULL) {
- return mAudioSink->setPlaybackRatePermille(ratePermille);
+ return mAudioSink->setPlaybackRate(rate);
} else if (mAudioTrack != 0){
- return mAudioTrack->setSampleRate(ratePermille * mSampleRate / 1000);
+ return mAudioTrack->setPlaybackRate(rate);
+ } else {
+ return NO_INIT;
+ }
+}
+
+status_t AudioPlayer::getPlaybackRate(AudioPlaybackRate *rate /* nonnull */) {
+ if (mAudioSink.get() != NULL) {
+ return mAudioSink->getPlaybackRate(rate);
+ } else if (mAudioTrack != 0) {
+ *rate = mAudioTrack->getPlaybackRate();
+ return OK;
} else {
return NO_INIT;
}
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index c14625d..df01e7c 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -241,6 +241,8 @@ AwesomePlayer::AwesomePlayer()
mClockEstimator = new WindowedLinearFitEstimator();
+ mPlaybackSettings = AUDIO_PLAYBACK_RATE_DEFAULT;
+
reset();
}
@@ -1009,6 +1011,10 @@ status_t AwesomePlayer::play_l() {
return err;
}
}
+
+ if (mAudioPlayer != NULL) {
+ mAudioPlayer->setPlaybackRate(mPlaybackSettings);
+ }
}
if (mTimeSource == NULL && mAudioPlayer == NULL) {
@@ -1131,6 +1137,10 @@ status_t AwesomePlayer::startAudioPlayer_l(bool sendErrorNotification) {
}
if (err == OK) {
+ err = mAudioPlayer->setPlaybackRate(mPlaybackSettings);
+ }
+
+ if (err == OK) {
modifyFlags(AUDIO_RUNNING, SET);
mWatchForAudioEOS = true;
@@ -2553,14 +2563,6 @@ status_t AwesomePlayer::setParameter(int key, const Parcel &request) {
{
return setCacheStatCollectFreq(request);
}
- case KEY_PARAMETER_PLAYBACK_RATE_PERMILLE:
- {
- if (mAudioPlayer != NULL) {
- return mAudioPlayer->setPlaybackRatePermille(request.readInt32());
- } else {
- return NO_INIT;
- }
- }
default:
{
return ERROR_UNSUPPORTED;
@@ -2597,6 +2599,58 @@ status_t AwesomePlayer::getParameter(int key, Parcel *reply) {
}
}
+status_t AwesomePlayer::setPlaybackSettings(const AudioPlaybackRate &rate) {
+ Mutex::Autolock autoLock(mLock);
+ // cursory sanity check for non-audio and paused cases
+ if ((rate.mSpeed != 0.f && rate.mSpeed < AUDIO_TIMESTRETCH_SPEED_MIN)
+ || rate.mSpeed > AUDIO_TIMESTRETCH_SPEED_MAX
+ || rate.mPitch < AUDIO_TIMESTRETCH_SPEED_MIN
+ || rate.mPitch > AUDIO_TIMESTRETCH_SPEED_MAX) {
+ return BAD_VALUE;
+ }
+
+ status_t err = OK;
+ if (rate.mSpeed == 0.f) {
+ if (mFlags & PLAYING) {
+ modifyFlags(CACHE_UNDERRUN, CLEAR); // same as pause
+ err = pause_l();
+ }
+ if (err == OK) {
+ // save settings (using old speed) in case player is resumed
+ AudioPlaybackRate newRate = rate;
+ newRate.mSpeed = mPlaybackSettings.mSpeed;
+ mPlaybackSettings = newRate;
+ }
+ return err;
+ }
+ if (mAudioPlayer != NULL) {
+ err = mAudioPlayer->setPlaybackRate(rate);
+ }
+ if (err == OK) {
+ mPlaybackSettings = rate;
+ if (!(mFlags & PLAYING)) {
+ play_l();
+ }
+ }
+ return err;
+}
+
+status_t AwesomePlayer::getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */) {
+ if (mAudioPlayer != NULL) {
+ status_t err = mAudioPlayer->getPlaybackRate(rate);
+ if (err == OK) {
+ mPlaybackSettings = *rate;
+ Mutex::Autolock autoLock(mLock);
+ if (!(mFlags & PLAYING)) {
+ rate->mSpeed = 0.f;
+ }
+ }
+ return err;
+ }
+ *rate = mPlaybackSettings;
+ return OK;
+}
+
status_t AwesomePlayer::getTrackInfo(Parcel *reply) const {
Mutex::Autolock autoLock(mLock);
size_t trackCount = mExtractor->countTracks();
diff --git a/media/libstagefright/MediaSync.cpp b/media/libstagefright/MediaSync.cpp
index 4350b59..85027ce 100644
--- a/media/libstagefright/MediaSync.cpp
+++ b/media/libstagefright/MediaSync.cpp
@@ -56,6 +56,10 @@ MediaSync::MediaSync()
mPlaybackRate(0.0) {
mMediaClock = new MediaClock;
+ // initialize settings
+ mPlaybackSettings = AUDIO_PLAYBACK_RATE_DEFAULT;
+ mPlaybackSettings.mSpeed = mPlaybackRate;
+
mLooper = new ALooper;
mLooper->setName("MediaSync");
mLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
@@ -84,6 +88,11 @@ status_t MediaSync::configureSurface(const sp<IGraphicBufferProducer> &output) {
return INVALID_OPERATION;
}
+ if (output == NULL && mSyncSettings.mSource == AVSYNC_SOURCE_VSYNC) {
+ ALOGE("configureSurface: output surface is used as sync source and cannot be removed.");
+ return INVALID_OPERATION;
+ }
+
if (output != NULL) {
IGraphicBufferProducer::QueueBufferOutput queueBufferOutput;
sp<OutputListener> listener(new OutputListener(this));
@@ -105,8 +114,7 @@ status_t MediaSync::configureSurface(const sp<IGraphicBufferProducer> &output) {
}
// |audioTrack| is used only for querying information.
-status_t MediaSync::configureAudioTrack(
- const sp<AudioTrack> &audioTrack, uint32_t nativeSampleRateInHz) {
+status_t MediaSync::configureAudioTrack(const sp<AudioTrack> &audioTrack) {
Mutex::Autolock lock(mMutex);
// TODO: support audio track change.
@@ -115,15 +123,35 @@ status_t MediaSync::configureAudioTrack(
return INVALID_OPERATION;
}
- if (audioTrack != NULL && nativeSampleRateInHz <= 0) {
- ALOGE("configureAudioTrack: native sample rate should be positive.");
- return BAD_VALUE;
+ if (audioTrack == NULL && mSyncSettings.mSource == AVSYNC_SOURCE_AUDIO) {
+ ALOGE("configureAudioTrack: audioTrack is used as sync source and cannot be removed.");
+ return INVALID_OPERATION;
}
- mAudioTrack = audioTrack;
- mNativeSampleRateInHz = nativeSampleRateInHz;
+ if (audioTrack != NULL) {
+ // check if audio track supports the playback settings
+ if (mPlaybackSettings.mSpeed != 0.f
+ && audioTrack->setPlaybackRate(mPlaybackSettings) != OK) {
+ ALOGE("playback settings are not supported by the audio track");
+ return INVALID_OPERATION;
+ }
+ uint32_t nativeSampleRateInHz = audioTrack->getOriginalSampleRate();
+ if (nativeSampleRateInHz <= 0) {
+ ALOGE("configureAudioTrack: native sample rate should be positive.");
+ return BAD_VALUE;
+ }
+ mAudioTrack = audioTrack;
+ mNativeSampleRateInHz = nativeSampleRateInHz;
+ (void)setPlaybackSettings_l(mPlaybackSettings);
+ }
+ else {
+ mAudioTrack = NULL;
+ mNativeSampleRateInHz = 0;
+ }
- return NO_ERROR;
+ // potentially resync to new source
+ resync_l();
+ return OK;
}
status_t MediaSync::createInputSurface(
@@ -158,21 +186,27 @@ status_t MediaSync::createInputSurface(
return status;
}
-status_t MediaSync::setPlaybackRate(float rate) {
- if (rate < 0.0) {
- return BAD_VALUE;
+void MediaSync::resync_l() {
+ AVSyncSource src = mSyncSettings.mSource;
+ if (src == AVSYNC_SOURCE_DEFAULT) {
+ if (mAudioTrack != NULL) {
+ src = AVSYNC_SOURCE_AUDIO;
+ } else {
+ src = AVSYNC_SOURCE_SYSTEM_CLOCK;
+ }
}
- Mutex::Autolock lock(mMutex);
+ // TODO: resync ourselves to the current clock (e.g. on sync source change)
+ updatePlaybackRate_l(mPlaybackRate);
+}
+void MediaSync::updatePlaybackRate_l(float rate) {
if (rate > mPlaybackRate) {
mNextBufferItemMediaUs = -1;
}
mPlaybackRate = rate;
mMediaClock->setPlaybackRate(rate);
onDrainVideo_l();
-
- return OK;
}
sp<const MediaClock> MediaSync::getMediaClock() {
@@ -264,6 +298,95 @@ void MediaSync::setName(const AString &name) {
mInput->setConsumerName(String8(name.c_str()));
}
+status_t MediaSync::setVideoFrameRateHint(float rate) {
+ // ignored until we add the FrameScheduler
+ return rate >= 0.f ? OK : BAD_VALUE;
+}
+
+float MediaSync::getVideoFrameRate() {
+ // we don't know the frame rate
+ return -1.f;
+}
+
+status_t MediaSync::setSyncSettings(const AVSyncSettings &syncSettings) {
+ // validate settings
+ if (syncSettings.mSource >= AVSYNC_SOURCE_MAX
+ || syncSettings.mAudioAdjustMode >= AVSYNC_AUDIO_ADJUST_MODE_MAX
+ || syncSettings.mTolerance < 0.f
+ || syncSettings.mTolerance >= AVSYNC_TOLERANCE_MAX) {
+ return BAD_VALUE;
+ }
+
+ Mutex::Autolock lock(mMutex);
+
+ // verify that we have the sync source
+ switch (syncSettings.mSource) {
+ case AVSYNC_SOURCE_AUDIO:
+ if (mAudioTrack == NULL) {
+ ALOGE("setSyncSettings: audio sync source requires an audio track");
+ return BAD_VALUE;
+ }
+ break;
+ case AVSYNC_SOURCE_VSYNC:
+ if (mOutput == NULL) {
+ ALOGE("setSyncSettings: vsync sync source requires an output surface");
+ return BAD_VALUE;
+ }
+ break;
+ default:
+ break;
+ }
+
+ mSyncSettings = syncSettings;
+ resync_l();
+ return OK;
+}
+
+void MediaSync::getSyncSettings(AVSyncSettings *syncSettings) {
+ Mutex::Autolock lock(mMutex);
+ *syncSettings = mSyncSettings;
+}
+
+status_t MediaSync::setPlaybackSettings(const AudioPlaybackRate &rate) {
+ Mutex::Autolock lock(mMutex);
+
+ status_t err = setPlaybackSettings_l(rate);
+ if (err == OK) {
+ // TODO: adjust rate if using VSYNC as source
+ updatePlaybackRate_l(rate.mSpeed);
+ }
+ return err;
+}
+
+status_t MediaSync::setPlaybackSettings_l(const AudioPlaybackRate &rate) {
+ if (rate.mSpeed < 0.f || rate.mPitch < 0.f) {
+ // We don't validate other audio settings.
+ // They will be validated when/if audiotrack is set.
+ return BAD_VALUE;
+ }
+
+ if (mAudioTrack != NULL) {
+ if (rate.mSpeed == 0.f) {
+ mAudioTrack->pause();
+ } else {
+ status_t err = mAudioTrack->setPlaybackRate(rate);
+ if (err != OK) {
+ return BAD_VALUE;
+ }
+
+ // ignore errors
+ (void)mAudioTrack->start();
+ }
+ }
+ mPlaybackSettings = rate;
+ return OK;
+}
+
+void MediaSync::getPlaybackSettings(AudioPlaybackRate *rate) {
+ Mutex::Autolock lock(mMutex);
+ *rate = mPlaybackSettings;
+}
+
int64_t MediaSync::getRealTime(int64_t mediaTimeUs, int64_t nowUs) {
int64_t realUs;
if (mMediaClock->getRealTimeFor(mediaTimeUs, &realUs) != OK) {
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index 7b089b0..413628d 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -901,5 +901,39 @@ bool operator <(const HLSTime &t0, const HLSTime &t1) {
|| (t0.mSeq == t1.mSeq && t0.mTimeUs < t1.mTimeUs);
}
+void writeToAMessage(sp<AMessage> msg, const AudioPlaybackRate &rate) {
+ msg->setFloat("speed", rate.mSpeed);
+ msg->setFloat("pitch", rate.mPitch);
+ msg->setInt32("audio-fallback-mode", rate.mFallbackMode);
+ msg->setInt32("audio-stretch-mode", rate.mStretchMode);
+}
+
+void readFromAMessage(const sp<AMessage> &msg, AudioPlaybackRate *rate /* nonnull */) {
+ *rate = AUDIO_PLAYBACK_RATE_DEFAULT;
+ CHECK(msg->findFloat("speed", &rate->mSpeed));
+ CHECK(msg->findFloat("pitch", &rate->mPitch));
+ CHECK(msg->findInt32("audio-fallback-mode", (int32_t *)&rate->mFallbackMode));
+ CHECK(msg->findInt32("audio-stretch-mode", (int32_t *)&rate->mStretchMode));
+}
+
+void writeToAMessage(sp<AMessage> msg, const AVSyncSettings &sync, float videoFpsHint) {
+ msg->setInt32("sync-source", sync.mSource);
+ msg->setInt32("audio-adjust-mode", sync.mAudioAdjustMode);
+ msg->setFloat("tolerance", sync.mTolerance);
+ msg->setFloat("video-fps", videoFpsHint);
+}
+
+void readFromAMessage(
+ const sp<AMessage> &msg,
+ AVSyncSettings *sync /* nonnull */,
+ float *videoFps /* nonnull */) {
+ AVSyncSettings settings;
+ CHECK(msg->findInt32("sync-source", (int32_t *)&settings.mSource));
+ CHECK(msg->findInt32("audio-adjust-mode", (int32_t *)&settings.mAudioAdjustMode));
+ CHECK(msg->findFloat("tolerance", &settings.mTolerance));
+ CHECK(msg->findFloat("video-fps", videoFps));
+ *sync = settings;
+}
+
} // namespace android
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 8bba804..758b2c9 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -21,6 +21,7 @@
#include "HTTPBase.h"
#include "TimedEventQueue.h"
+#include <media/AudioResamplerPublic.h>
#include <media/MediaPlayerInterface.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/OMXClient.h>
@@ -93,6 +94,8 @@ struct AwesomePlayer {
status_t setParameter(int key, const Parcel &request);
status_t getParameter(int key, Parcel *reply);
+ status_t setPlaybackSettings(const AudioPlaybackRate &rate);
+ status_t getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */);
status_t invoke(const Parcel &request, Parcel *reply);
status_t setCacheStatCollectFreq(const Parcel &request);
@@ -180,6 +183,7 @@ private:
sp<MediaSource> mOmxSource;
sp<MediaSource> mAudioSource;
AudioPlayer *mAudioPlayer;
+ AudioPlaybackRate mPlaybackSettings;
int64_t mDurationUs;
int32_t mDisplayWidth;