diff options
Diffstat (limited to 'src/plugins/android/jar/src/org/qtproject/qt/android/multimedia/QtAndroidMediaPlayer.java')
-rw-r--r-- | src/plugins/android/jar/src/org/qtproject/qt/android/multimedia/QtAndroidMediaPlayer.java | 590 |
1 files changed, 590 insertions, 0 deletions
diff --git a/src/plugins/android/jar/src/org/qtproject/qt/android/multimedia/QtAndroidMediaPlayer.java b/src/plugins/android/jar/src/org/qtproject/qt/android/multimedia/QtAndroidMediaPlayer.java new file mode 100644 index 000000000..aa706179c --- /dev/null +++ b/src/plugins/android/jar/src/org/qtproject/qt/android/multimedia/QtAndroidMediaPlayer.java @@ -0,0 +1,590 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtMultimedia of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +package org.qtproject.qt.android.multimedia; + +import java.io.IOException; +import java.lang.String; +import java.util.HashMap; +import java.io.FileInputStream; + +// API is level is < 9 unless marked otherwise. +import android.content.Context; +import android.media.MediaPlayer; +import android.media.AudioAttributes; +import android.net.Uri; +import android.util.Log; +import java.io.FileDescriptor; +import android.content.res.AssetFileDescriptor; +import android.content.res.AssetManager; +import android.view.SurfaceHolder; + +public class QtAndroidMediaPlayer +{ + // Native callback functions for MediaPlayer + native public void onErrorNative(int what, int extra, long id); + native public void onBufferingUpdateNative(int percent, long id); + native public void onProgressUpdateNative(int progress, long id); + native public void onDurationChangedNative(int duration, long id); + native public void onInfoNative(int what, int extra, long id); + native public void onVideoSizeChangedNative(int width, int height, long id); + native public void onStateChangedNative(int state, long id); + + private MediaPlayer mMediaPlayer = null; + private AudioAttributes mAudioAttributes = null; + private HashMap<String, String> mHeaders = null; + private Uri mUri = null; + private final long mID; + private final Context mContext; + private boolean mMuted = false; + private int mVolume = 100; + private static final String TAG = "Qt MediaPlayer"; + private SurfaceHolder mSurfaceHolder = null; + + private class State { + final static int Uninitialized = 0x1 /* End */; + final static int Idle = 0x2; + final static int Preparing = 0x4; + final static int Prepared = 0x8; + final static int Initialized = 0x10; + final static int Started = 0x20; + final static int Stopped = 0x40; + final static int Paused = 0x80; + final static int PlaybackCompleted = 0x100; + final static int Error = 0x200; + } + + private volatile int mState = State.Uninitialized; + + /** + * MediaPlayer OnErrorListener + */ + private class MediaPlayerErrorListener + implements MediaPlayer.OnErrorListener + { + @Override + public boolean onError(final MediaPlayer mp, + final int what, + final int extra) + { + setState(State.Error); + onErrorNative(what, extra, mID); + return true; + } + + } + + /** + * MediaPlayer OnBufferingListener + */ + private class MediaPlayerBufferingListener + implements MediaPlayer.OnBufferingUpdateListener + { + private int mBufferPercent = -1; + @Override + public void onBufferingUpdate(final android.media.MediaPlayer mp, + final int percent) + { + // Avoid updates when percent is unchanged. + // E.g., we keep getting updates when percent == 100 + if (mBufferPercent == percent) + return; + + onBufferingUpdateNative((mBufferPercent = percent), mID); + } + + } + + /** + * MediaPlayer OnCompletionListener + */ + private class MediaPlayerCompletionListener + implements MediaPlayer.OnCompletionListener + { + @Override + public void onCompletion(final MediaPlayer mp) + { + setState(State.PlaybackCompleted); + } + + } + + /** + * MediaPlayer OnInfoListener + */ + private class MediaPlayerInfoListener + implements MediaPlayer.OnInfoListener + { + @Override + public boolean onInfo(final MediaPlayer mp, + final int what, + final int extra) + { + onInfoNative(what, extra, mID); + return true; + } + + } + + /** + * MediaPlayer OnPreparedListener + */ + private class MediaPlayerPreparedListener + implements MediaPlayer.OnPreparedListener + { + + @Override + public void onPrepared(final MediaPlayer mp) + { + setState(State.Prepared); + onDurationChangedNative(getDuration(), mID); + } + + } + + /** + * MediaPlayer OnSeekCompleteListener + */ + private class MediaPlayerSeekCompleteListener + implements MediaPlayer.OnSeekCompleteListener + { + + @Override + public void onSeekComplete(final MediaPlayer mp) + { + onProgressUpdateNative(getCurrentPosition(), mID); + } + + } + + /** + * MediaPlayer OnVideoSizeChangedListener + */ + private class MediaPlayerVideoSizeChangedListener + implements MediaPlayer.OnVideoSizeChangedListener + { + + @Override + public void onVideoSizeChanged(final MediaPlayer mp, + final int width, + final int height) + { + onVideoSizeChangedNative(width, height, mID); + } + + } + + public QtAndroidMediaPlayer(final Context context, final long id) + { + mID = id; + mContext = context; + } + + public MediaPlayer getMediaPlayerHandle() + { + return mMediaPlayer; + } + + private void setState(int state) + { + if (mState == state) + return; + + mState = state; + + onStateChangedNative(mState, mID); + } + + + private void init() + { + if (mMediaPlayer == null) { + mMediaPlayer = new MediaPlayer(); + setState(State.Idle); + // Make sure the new media player has the volume that was set on the QMediaPlayer + setVolumeHelper(mMuted ? 0 : mVolume); + setAudioAttributes(mMediaPlayer, mAudioAttributes); + } + } + + public void start() + { + if ((mState & (State.Prepared + | State.Started + | State.Paused + | State.PlaybackCompleted)) == 0) { + return; + } + + try { + mMediaPlayer.start(); + setState(State.Started); + } catch (final IllegalStateException e) { + Log.d(TAG, "" + e.getMessage()); + } + } + + + public void pause() + { + if ((mState & (State.Started | State.Paused | State.PlaybackCompleted)) == 0) + return; + + try { + mMediaPlayer.pause(); + setState(State.Paused); + } catch (final IllegalStateException e) { + Log.d(TAG, "" + e.getMessage()); + } + } + + + public void stop() + { + if ((mState & (State.Prepared + | State.Started + | State.Stopped + | State.Paused + | State.PlaybackCompleted)) == 0) { + return; + } + + try { + mMediaPlayer.stop(); + setState(State.Stopped); + } catch (final IllegalStateException e) { + Log.d(TAG, "" + e.getMessage()); + } + } + + + public void seekTo(final int msec) + { + if ((mState & (State.Prepared + | State.Started + | State.Paused + | State.PlaybackCompleted)) == 0) { + return; + } + + try { + mMediaPlayer.seekTo(msec); + } catch (final IllegalStateException e) { + Log.d(TAG, "" + e.getMessage()); + } + } + + + public boolean isPlaying() + { + boolean playing = false; + if ((mState & (State.Idle + | State.Initialized + | State.Prepared + | State.Started + | State.Paused + | State.Stopped + | State.PlaybackCompleted)) == 0) { + return playing; + } + + try { + playing = mMediaPlayer.isPlaying(); + } catch (final IllegalStateException e) { + Log.d(TAG, "" + e.getMessage()); + } + + return playing; + } + + public void prepareAsync() + { + if ((mState & (State.Initialized | State.Stopped)) == 0) + return; + + try { + mMediaPlayer.prepareAsync(); + setState(State.Preparing); + } catch (final IllegalStateException e) { + Log.d(TAG, "" + e.getMessage()); + } + } + + public void initHeaders() + { + mHeaders = new HashMap<String, String>(); + } + + public void setHeader(final String header, final String value) + { + mHeaders.put(header, value); + } + + public void setDataSource(final String path) + { + if ((mState & State.Uninitialized) != 0) + init(); + + if ((mState & State.Idle) == 0) + return; + + mMediaPlayer.setOnBufferingUpdateListener(new MediaPlayerBufferingListener()); + mMediaPlayer.setOnCompletionListener(new MediaPlayerCompletionListener()); + mMediaPlayer.setOnInfoListener(new MediaPlayerInfoListener()); + mMediaPlayer.setOnSeekCompleteListener(new MediaPlayerSeekCompleteListener()); + mMediaPlayer.setOnVideoSizeChangedListener(new MediaPlayerVideoSizeChangedListener()); + mMediaPlayer.setOnErrorListener(new MediaPlayerErrorListener()); + mMediaPlayer.setOnPreparedListener(new MediaPlayerPreparedListener()); + + if (mSurfaceHolder != null) + mMediaPlayer.setDisplay(mSurfaceHolder); + + AssetFileDescriptor afd = null; + FileInputStream fis = null; + try { + mUri = Uri.parse(path); + final boolean inAssets = (mUri.getScheme().compareTo("assets") == 0); + if (inAssets) { + final String asset = mUri.getPath().substring(1 /* Remove first '/' */); + final AssetManager am = mContext.getAssets(); + afd = am.openFd(asset); + final long offset = afd.getStartOffset(); + final long length = afd.getLength(); + FileDescriptor fd = afd.getFileDescriptor(); + mMediaPlayer.setDataSource(fd, offset, length); + } else if (mUri.getScheme().compareTo("file") == 0) { + fis = new FileInputStream(mUri.getPath()); + FileDescriptor fd = fis.getFD(); + mMediaPlayer.setDataSource(fd); + } else { + if (mHeaders.isEmpty()) + mMediaPlayer.setDataSource(path); + else + mMediaPlayer.setDataSource(mContext, mUri, mHeaders); + } + setState(State.Initialized); + } catch (final IOException e) { + Log.d(TAG, "" + e.getMessage()); + } catch (final IllegalArgumentException e) { + Log.d(TAG, "" + e.getMessage()); + } catch (final SecurityException e) { + Log.d(TAG, "" + e.getMessage()); + } catch (final IllegalStateException e) { + Log.d(TAG, "" + e.getMessage()); + } catch (final NullPointerException e) { + Log.d(TAG, "" + e.getMessage()); + } finally { + try { + if (afd != null) + afd.close(); + if (fis != null) + fis.close(); + } catch (final IOException ioe) { /* Ignore... */ } + + if ((mState & State.Initialized) == 0) { + setState(State.Error); + onErrorNative(MediaPlayer.MEDIA_ERROR_UNKNOWN, + -1004 /*MEDIA_ERROR_IO*/, + mID); + return; + } + } + } + + + public int getCurrentPosition() + { + int currentPosition = 0; + if ((mState & (State.Idle + | State.Initialized + | State.Prepared + | State.Started + | State.Paused + | State.Stopped + | State.PlaybackCompleted)) == 0) { + return currentPosition; + } + + try { + currentPosition = mMediaPlayer.getCurrentPosition(); + } catch (final IllegalStateException e) { + Log.d(TAG, "" + e.getMessage()); + } + + return currentPosition; + } + + + public int getDuration() + { + int duration = 0; + if ((mState & (State.Prepared + | State.Started + | State.Paused + | State.Stopped + | State.PlaybackCompleted)) == 0) { + return duration; + } + + try { + duration = mMediaPlayer.getDuration(); + } catch (final IllegalStateException e) { + Log.d(TAG, "" + e.getMessage()); + } + + return duration; + } + + public void setVolume(int volume) + { + if (volume < 0) + volume = 0; + + if (volume > 100) + volume = 100; + + mVolume = volume; + + if (!mMuted) + setVolumeHelper(mVolume); + } + + private void setVolumeHelper(int volume) + { + if ((mState & (State.Idle + | State.Initialized + | State.Stopped + | State.Prepared + | State.Started + | State.Paused + | State.PlaybackCompleted)) == 0) { + return; + } + + try { + float newVolume = (float)volume / 100; + mMediaPlayer.setVolume(newVolume, newVolume); + } catch (final IllegalStateException e) { + Log.d(TAG, "" + e.getMessage()); + } + } + + public SurfaceHolder display() + { + return mSurfaceHolder; + } + + public void setDisplay(SurfaceHolder sh) + { + mSurfaceHolder = sh; + + if ((mState & State.Uninitialized) != 0) + return; + + mMediaPlayer.setDisplay(mSurfaceHolder); + } + + + public int getVolume() + { + return mVolume; + } + + public void mute(final boolean mute) + { + mMuted = mute; + setVolumeHelper(mute ? 0 : mVolume); + } + + public boolean isMuted() + { + return mMuted; + } + + + public void reset() + { + if ((mState & (State.Idle + | State.Initialized + | State.Prepared + | State.Started + | State.Paused + | State.Stopped + | State.PlaybackCompleted + | State.Error)) == 0) { + return; + } + + mMediaPlayer.reset(); + setState(State.Idle); + } + + public void release() + { + if (mMediaPlayer != null) { + mMediaPlayer.reset(); + mMediaPlayer.release(); + mMediaPlayer = null; + } + + setState(State.Uninitialized); + } + + public void setAudioAttributes(int type, int usage) + { + mAudioAttributes = new AudioAttributes.Builder() + .setUsage(usage) + .setContentType(type) + .build(); + + setAudioAttributes(mMediaPlayer, mAudioAttributes); + } + + static private void setAudioAttributes(MediaPlayer player, AudioAttributes attr) + { + if (player == null || attr == null) + return; + + try { + player.setAudioAttributes(attr); + } catch (final IllegalArgumentException e) { + Log.d(TAG, "" + e.getMessage()); + } + } +} |