/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtMultimedia module 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 Digia. For licensing terms and ** conditions see http://qt.digia.com/licensing. For further information ** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Digia gives you certain additional ** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ package org.qtproject.qt5.android.multimedia; import java.io.IOException; import java.lang.String; // API is level is < 9 unless marked otherwise. import android.app.Activity; import android.content.Context; import android.media.MediaPlayer; import android.net.Uri; import android.util.Log; public class QtAndroidMediaPlayer extends MediaPlayer { // 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 onInfoNative(int what, int extra, long id); native public void onMediaPlayerInfoNative(int what, int extra, long id); native public void onVideoSizeChangedNative(int width, int height, long id); private Uri mUri = null; private final long mID; private boolean mMuted = false; private boolean mPreparing = false; private boolean mInitialized = false; private int mVolume = 100; private static final String TAG = "Qt MediaPlayer"; private static Context mApplicationContext = null; final int MEDIA_PLAYER_INVALID_STATE = 1; final int MEDIA_PLAYER_PREPARING = 2; final int MEDIA_PLAYER_READY = 3; final int MEDIA_PLAYER_DURATION = 4; final int MEDIA_PLAYER_PROGRESS = 5; final int MEDIA_PLAYER_FINISHED = 6; // Activity set by Qt on load. static public void setActivity(final Activity activity) { try { mApplicationContext = activity.getApplicationContext(); } catch(final Exception e) { Log.d(TAG, "" + e.getMessage()); } } private class ProgressWatcher implements Runnable { @Override public void run() { final int duratation = getDuration(); int currentPosition = getCurrentPosition(); try { while (duratation >= currentPosition && isPlaying()) { onMediaPlayerInfoNative(MEDIA_PLAYER_PROGRESS, currentPosition, mID); Thread.sleep(1000); currentPosition = getCurrentPosition(); } } catch (final InterruptedException e) { Log.d(TAG, "" + e.getMessage()); return; } } } /** * MediaPlayer OnErrorListener */ private class MediaPlayerErrorListener implements MediaPlayer.OnErrorListener { @Override public boolean onError(final MediaPlayer mp, final int what, final int extra) { reset(); 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) { onMediaPlayerInfoNative(MEDIA_PLAYER_FINISHED, 0, mID); reset(); } } /** * 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) { onMediaPlayerInfoNative(MEDIA_PLAYER_DURATION, getDuration(), mID); onMediaPlayerInfoNative(MEDIA_PLAYER_READY, 0, mID); mPreparing = false; } } /** * MediaPlayer OnSeekCompleteListener */ private class MediaPlayerSeekCompleteListener implements MediaPlayer.OnSeekCompleteListener { @Override public void onSeekComplete(final MediaPlayer mp) { onMediaPlayerInfoNative(MEDIA_PLAYER_PROGRESS, 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 long id) { super(); mID = id; setOnBufferingUpdateListener(new MediaPlayerBufferingListener()); setOnCompletionListener(new MediaPlayerCompletionListener()); setOnInfoListener(new MediaPlayerInfoListener()); setOnSeekCompleteListener(new MediaPlayerSeekCompleteListener()); setOnVideoSizeChangedListener(new MediaPlayerVideoSizeChangedListener()); setOnErrorListener(new MediaPlayerErrorListener()); } @Override public void start() { if (!mInitialized) { onMediaPlayerInfoNative(MEDIA_PLAYER_INVALID_STATE, 0, mID); return; } if (mApplicationContext == null) return; if (mPreparing) return; if (isPlaying()) return; try { super.start(); Thread progressThread = new Thread(new ProgressWatcher()); progressThread.start(); } catch (final IllegalStateException e) { reset(); Log.d(TAG, "" + e.getMessage()); } } @Override public void pause() { if (!isPlaying()) return; try { super.pause(); } catch (final IllegalStateException e) { reset(); Log.d(TAG, "" + e.getMessage()); } } @Override public void stop() { if (!mInitialized) return; try { super.stop(); } catch (final IllegalStateException e) { Log.d(TAG, "" + e.getMessage()); } finally { reset(); } } @Override public void seekTo(final int msec) { if (!mInitialized) return; try { super.seekTo(msec); onMediaPlayerInfoNative(MEDIA_PLAYER_PROGRESS, msec, mID); } catch (final IllegalStateException e) { Log.d(TAG, "" + e.getMessage()); } } @Override public boolean isPlaying() { boolean playing = false; if (!mInitialized) return playing; try { playing = super.isPlaying(); } catch (final IllegalStateException e) { Log.d(TAG, "" + e.getMessage()); } return playing; } public void setMediaPath(final String path) { if (mInitialized) reset(); try { mPreparing = true; onMediaPlayerInfoNative(MEDIA_PLAYER_PREPARING, 0, mID); mUri = Uri.parse(path); setDataSource(mApplicationContext, mUri); mInitialized = true; setOnPreparedListener(new MediaPlayerPreparedListener()); prepareAsync(); } catch (final IOException e) { mPreparing = false; onErrorNative(MEDIA_ERROR_UNKNOWN, /* MEDIA_ERROR_UNSUPPORTED= */ -1010, mID); } 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()); } } @Override public int getCurrentPosition() { int currentPosition = 0; if (!mInitialized) return currentPosition; try { currentPosition = super.getCurrentPosition(); } catch (final IllegalStateException e) { Log.d(TAG, "" + e.getMessage()); } return currentPosition; } @Override public int getDuration() { int duration = 0; if (!mInitialized) return duration; try { duration = super.getDuration(); } catch (final IllegalStateException e) { Log.d(TAG, "" + e.getMessage()); } return duration; } private float adjustVolume(final int volume) { if (volume < 1) return 0.0f; if (volume > 98) return 1.0f; return (float) (1-(Math.log(100-volume)/Math.log(100))); } public void setVolume(int volume) { if (volume < 0) volume = 0; if (volume > 100) volume = 100; float newVolume = adjustVolume(volume); try { super.setVolume(newVolume, newVolume); if (!mMuted) mVolume = volume; } catch (final IllegalStateException e) { Log.d(TAG, "" + e.getMessage()); } } public int getVolume() { return mVolume; } public void mute(final boolean mute) { mMuted = mute; setVolume(mute ? 0 : mVolume); } public boolean isMuted() { return mMuted; } @Override public void reset() { mInitialized = false; super.reset(); } }