summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYoann Lopes <yoann.lopes@qt.io>2017-05-31 00:51:56 +0200
committerChristian Stromme <christian.stromme@qt.io>2018-09-26 10:50:18 +0000
commit4b8414b51dac70d949c0f516e1a7d8e723b97c29 (patch)
treedb19e65a90b98c10a9eea39569e47c60518f3d4d
parent3f8962e984969881b057fd294f9f3f3e812f7c4c (diff)
Android: implement QMediaPlayer::setPlaybackRate()
Only possible on Android API level 23 or higher. Task-number: QTBUG-61115 Change-Id: I147575ed0a48f84d4208978a67e0856918e65b3d Reviewed-by: Alex Blasche <alexander.blasche@qt.io>
-rw-r--r--src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtAndroidMediaPlayer.java5
-rw-r--r--src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.cpp43
-rw-r--r--src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.h2
-rw-r--r--src/plugins/android/src/wrappers/jni/androidmediaplayer.cpp61
-rw-r--r--src/plugins/android/src/wrappers/jni/androidmediaplayer.h2
5 files changed, 110 insertions, 3 deletions
diff --git a/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtAndroidMediaPlayer.java b/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtAndroidMediaPlayer.java
index 7fb4a8690..b1da2f1fa 100644
--- a/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtAndroidMediaPlayer.java
+++ b/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtAndroidMediaPlayer.java
@@ -212,6 +212,11 @@ public class QtAndroidMediaPlayer
mContext = context;
}
+ public MediaPlayer getMediaPlayerHandle()
+ {
+ return mMediaPlayer;
+ }
+
private void setState(int state)
{
if (mState == state)
diff --git a/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.cpp b/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.cpp
index 7aa7b97b8..df1463a87 100644
--- a/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.cpp
+++ b/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.cpp
@@ -93,7 +93,9 @@ QAndroidMediaPlayerControl::QAndroidMediaPlayerControl(QObject *parent)
mPendingVolume(-1),
mPendingMute(-1),
mReloadingMedia(false),
- mActiveStateChangeNotifiers(0)
+ mActiveStateChangeNotifiers(0),
+ mPendingPlaybackRate(1.0),
+ mHasPendingPlaybackRate(false)
{
connect(mMediaPlayer,SIGNAL(bufferingChanged(qint32)),
this,SLOT(onBufferingChanged(qint32)));
@@ -290,12 +292,45 @@ void QAndroidMediaPlayerControl::updateAvailablePlaybackRanges()
qreal QAndroidMediaPlayerControl::playbackRate() const
{
- return 1.0f;
+ if (mHasPendingPlaybackRate ||
+ (mState & (AndroidMediaPlayer::Initialized
+ | AndroidMediaPlayer::Prepared
+ | AndroidMediaPlayer::Started
+ | AndroidMediaPlayer::Paused
+ | AndroidMediaPlayer::PlaybackCompleted
+ | AndroidMediaPlayer::Error)) == 0) {
+ return mPendingPlaybackRate;
+ }
+
+ return mMediaPlayer->playbackRate();
}
void QAndroidMediaPlayerControl::setPlaybackRate(qreal rate)
{
- Q_UNUSED(rate);
+ if ((mState & (AndroidMediaPlayer::Initialized
+ | AndroidMediaPlayer::Prepared
+ | AndroidMediaPlayer::Started
+ | AndroidMediaPlayer::Paused
+ | AndroidMediaPlayer::PlaybackCompleted
+ | AndroidMediaPlayer::Error)) == 0) {
+ if (mPendingPlaybackRate != rate) {
+ mPendingPlaybackRate = rate;
+ mHasPendingPlaybackRate = true;
+ Q_EMIT playbackRateChanged(rate);
+ }
+ return;
+ }
+
+ bool succeeded = mMediaPlayer->setPlaybackRate(rate);
+
+ if (mHasPendingPlaybackRate) {
+ mHasPendingPlaybackRate = false;
+ mPendingPlaybackRate = qreal(1.0);
+ if (!succeeded)
+ Q_EMIT playbackRateChanged(playbackRate());
+ } else if (succeeded) {
+ Q_EMIT playbackRateChanged(rate);
+ }
}
QMediaContent QAndroidMediaPlayerControl::media() const
@@ -720,6 +755,8 @@ void QAndroidMediaPlayerControl::flushPendingStates()
setVolume(mPendingVolume);
if (mPendingMute != -1)
setMuted((mPendingMute == 1));
+ if (mHasPendingPlaybackRate)
+ setPlaybackRate(mPendingPlaybackRate);
switch (newState) {
case QMediaPlayer::PlayingState:
diff --git a/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.h b/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.h
index 04f728a59..119add7f8 100644
--- a/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.h
+++ b/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.h
@@ -117,6 +117,8 @@ private:
int mPendingMute;
bool mReloadingMedia;
int mActiveStateChangeNotifiers;
+ qreal mPendingPlaybackRate;
+ bool mHasPendingPlaybackRate; // we need this because the rate can theoretically be negative
void setState(QMediaPlayer::State state);
void setMediaStatus(QMediaPlayer::MediaStatus status);
diff --git a/src/plugins/android/src/wrappers/jni/androidmediaplayer.cpp b/src/plugins/android/src/wrappers/jni/androidmediaplayer.cpp
index 582d8aa9d..b81f98cbd 100644
--- a/src/plugins/android/src/wrappers/jni/androidmediaplayer.cpp
+++ b/src/plugins/android/src/wrappers/jni/androidmediaplayer.cpp
@@ -109,6 +109,33 @@ bool AndroidMediaPlayer::isMuted()
return mMediaPlayer.callMethod<jboolean>("isMuted");
}
+qreal AndroidMediaPlayer::playbackRate()
+{
+ qreal rate(1.0);
+
+ if (QtAndroidPrivate::androidSdkVersion() < 23)
+ return rate;
+
+ QJNIObjectPrivate player = mMediaPlayer.callObjectMethod("getMediaPlayerHandle", "()Landroid/media/MediaPlayer;");
+ if (player.isValid()) {
+ QJNIObjectPrivate playbackParams = player.callObjectMethod("getPlaybackParams", "()Landroid/media/PlaybackParams;");
+ if (playbackParams.isValid()) {
+ const qreal speed = playbackParams.callMethod<jfloat>("getSpeed", "()F");
+ QJNIEnvironmentPrivate env;
+ if (env->ExceptionCheck()) {
+#ifdef QT_DEBUG
+ env->ExceptionDescribe();
+#endif // QT_DEBUG
+ env->ExceptionClear();
+ } else {
+ rate = speed;
+ }
+ }
+ }
+
+ return rate;
+}
+
jobject AndroidMediaPlayer::display()
{
return mMediaPlayer.callObjectMethod("display", "()Landroid/view/SurfaceHolder;").object();
@@ -155,6 +182,40 @@ void AndroidMediaPlayer::setVolume(int volume)
mMediaPlayer.callMethod<void>("setVolume", "(I)V", jint(volume));
}
+bool AndroidMediaPlayer::setPlaybackRate(qreal rate)
+{
+ if (QtAndroidPrivate::androidSdkVersion() < 23) {
+ qWarning("Setting the playback rate on a media player requires Android 6.0 (API level 23) or later");
+ return false;
+ }
+
+ QJNIEnvironmentPrivate env;
+
+ QJNIObjectPrivate player = mMediaPlayer.callObjectMethod("getMediaPlayerHandle", "()Landroid/media/MediaPlayer;");
+ if (player.isValid()) {
+ QJNIObjectPrivate playbackParams = player.callObjectMethod("getPlaybackParams", "()Landroid/media/PlaybackParams;");
+ if (playbackParams.isValid()) {
+ playbackParams.callObjectMethod("setSpeed", "(F)Landroid/media/PlaybackParams;", jfloat(rate));
+ // pitch can only be > 0
+ if (!qFuzzyIsNull(rate))
+ playbackParams.callObjectMethod("setPitch", "(F)Landroid/media/PlaybackParams;", jfloat(qAbs(rate)));
+ player.callMethod<void>("setPlaybackParams", "(Landroid/media/PlaybackParams;)V", playbackParams.object());
+ if (Q_UNLIKELY(env->ExceptionCheck())) {
+#ifdef QT_DEBUG
+ env->ExceptionDescribe();
+#endif // QT_DEBUG
+ env->ExceptionClear();
+ qWarning() << "Invalid playback rate" << rate;
+ return false;
+ } else {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
void AndroidMediaPlayer::setDisplay(AndroidSurfaceTexture *surfaceTexture)
{
mMediaPlayer.callMethod<void>("setDisplay",
diff --git a/src/plugins/android/src/wrappers/jni/androidmediaplayer.h b/src/plugins/android/src/wrappers/jni/androidmediaplayer.h
index 28bfa3662..a7284bb0c 100644
--- a/src/plugins/android/src/wrappers/jni/androidmediaplayer.h
+++ b/src/plugins/android/src/wrappers/jni/androidmediaplayer.h
@@ -103,6 +103,7 @@ public:
bool isPlaying();
int volume();
bool isMuted();
+ qreal playbackRate();
jobject display();
void play();
@@ -113,6 +114,7 @@ public:
void setDataSource(const QString &path);
void prepareAsync();
void setVolume(int volume);
+ bool setPlaybackRate(qreal rate);
void setDisplay(AndroidSurfaceTexture *surfaceTexture);
static bool initJNI(JNIEnv *env);