591 lines
24 KiB
Java
591 lines
24 KiB
Java
/*
|
|
* Copyright (C) 2008 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.
|
|
*/
|
|
|
|
package android.media;
|
|
|
|
|
|
import java.io.FileDescriptor;
|
|
import java.lang.ref.WeakReference;
|
|
import java.lang.CloneNotSupportedException;
|
|
|
|
import android.content.res.AssetFileDescriptor;
|
|
import android.os.Looper;
|
|
import android.os.Handler;
|
|
import android.os.Message;
|
|
import android.util.AndroidRuntimeException;
|
|
import android.util.Log;
|
|
|
|
/**
|
|
* JetPlayer provides access to JET content playback and control.
|
|
*
|
|
* <p>Please refer to the JET Creator User Manual for a presentation of the JET interactive
|
|
* music concept and how to use the JetCreator tool to create content to be player by JetPlayer.
|
|
*
|
|
* <p>Use of the JetPlayer class is based around the playback of a number of JET segments
|
|
* sequentially added to a playback FIFO queue. The rendering of the MIDI content stored in each
|
|
* segment can be dynamically affected by two mechanisms:
|
|
* <ul>
|
|
* <li>tracks in a segment can be muted or unmuted at any moment, individually or through
|
|
* a mask (to change the mute state of multiple tracks at once)</li>
|
|
* <li>parts of tracks in a segment can be played at predefined points in the segment, in order
|
|
* to maintain synchronization with the other tracks in the segment. This is achieved through
|
|
* the notion of "clips", which can be triggered at any time, but that will play only at the
|
|
* right time, as authored in the corresponding JET file.</li>
|
|
* </ul>
|
|
* As a result of the rendering and playback of the JET segments, the user of the JetPlayer instance
|
|
* can receive notifications from the JET engine relative to:
|
|
* <ul>
|
|
* <li>the playback state,</li>
|
|
* <li>the number of segments left to play in the queue,</li>
|
|
* <li>application controller events (CC80-83) to mark points in the MIDI segments.</li>
|
|
* </ul>
|
|
* Use {@link #getJetPlayer()} to construct a JetPlayer instance. JetPlayer is a singleton class.
|
|
* </p>
|
|
*
|
|
* <div class="special reference">
|
|
* <h3>Developer Guides</h3>
|
|
* <p>For more information about how to use JetPlayer, read the
|
|
* <a href="{@docRoot}guide/topics/media/jetplayer.html">JetPlayer</a> developer guide.</p></div>
|
|
*/
|
|
public class JetPlayer
|
|
{
|
|
//--------------------------------------------
|
|
// Constants
|
|
//------------------------
|
|
/**
|
|
* The maximum number of simultaneous tracks. Use {@link #getMaxTracks()} to
|
|
* access this value.
|
|
*/
|
|
private static int MAXTRACKS = 32;
|
|
|
|
// to keep in sync with the JetPlayer class constants
|
|
// defined in frameworks/base/include/media/JetPlayer.h
|
|
private static final int JET_EVENT = 1;
|
|
private static final int JET_USERID_UPDATE = 2;
|
|
private static final int JET_NUMQUEUEDSEGMENT_UPDATE = 3;
|
|
private static final int JET_PAUSE_UPDATE = 4;
|
|
|
|
// to keep in sync with external/sonivox/arm-wt-22k/lib_src/jet_data.h
|
|
// Encoding of event information on 32 bits
|
|
private static final int JET_EVENT_VAL_MASK = 0x0000007f; // mask for value
|
|
private static final int JET_EVENT_CTRL_MASK = 0x00003f80; // mask for controller
|
|
private static final int JET_EVENT_CHAN_MASK = 0x0003c000; // mask for channel
|
|
private static final int JET_EVENT_TRACK_MASK = 0x00fc0000; // mask for track number
|
|
private static final int JET_EVENT_SEG_MASK = 0xff000000; // mask for segment ID
|
|
private static final int JET_EVENT_CTRL_SHIFT = 7; // shift to get controller number to bit 0
|
|
private static final int JET_EVENT_CHAN_SHIFT = 14; // shift to get MIDI channel to bit 0
|
|
private static final int JET_EVENT_TRACK_SHIFT = 18; // shift to get track ID to bit 0
|
|
private static final int JET_EVENT_SEG_SHIFT = 24; // shift to get segment ID to bit 0
|
|
|
|
// to keep in sync with values used in external/sonivox/arm-wt-22k/Android.mk
|
|
// Jet rendering audio parameters
|
|
private static final int JET_OUTPUT_RATE = 22050; // _SAMPLE_RATE_22050 in Android.mk
|
|
private static final int JET_OUTPUT_CHANNEL_CONFIG =
|
|
AudioFormat.CHANNEL_OUT_STEREO; // NUM_OUTPUT_CHANNELS=2 in Android.mk
|
|
|
|
|
|
//--------------------------------------------
|
|
// Member variables
|
|
//------------------------
|
|
/**
|
|
* Handler for jet events and status updates coming from the native code
|
|
*/
|
|
private NativeEventHandler mEventHandler = null;
|
|
|
|
/**
|
|
* Looper associated with the thread that creates the AudioTrack instance
|
|
*/
|
|
private Looper mInitializationLooper = null;
|
|
|
|
/**
|
|
* Lock to protect the event listener updates against event notifications
|
|
*/
|
|
private final Object mEventListenerLock = new Object();
|
|
|
|
private OnJetEventListener mJetEventListener = null;
|
|
|
|
private static JetPlayer singletonRef;
|
|
|
|
|
|
//--------------------------------
|
|
// Used exclusively by native code
|
|
//--------------------
|
|
/**
|
|
* Accessed by native methods: provides access to C++ JetPlayer object
|
|
*/
|
|
@SuppressWarnings("unused")
|
|
private long mNativePlayerInJavaObj;
|
|
|
|
|
|
//--------------------------------------------
|
|
// Constructor, finalize
|
|
//------------------------
|
|
/**
|
|
* Factory method for the JetPlayer class.
|
|
* @return the singleton JetPlayer instance
|
|
*/
|
|
public static JetPlayer getJetPlayer() {
|
|
if (singletonRef == null) {
|
|
singletonRef = new JetPlayer();
|
|
}
|
|
return singletonRef;
|
|
}
|
|
|
|
/**
|
|
* Cloning a JetPlayer instance is not supported. Calling clone() will generate an exception.
|
|
*/
|
|
public Object clone() throws CloneNotSupportedException {
|
|
// JetPlayer is a singleton class,
|
|
// so you can't clone a JetPlayer instance
|
|
throw new CloneNotSupportedException();
|
|
}
|
|
|
|
|
|
private JetPlayer() {
|
|
|
|
// remember which looper is associated with the JetPlayer instanciation
|
|
if ((mInitializationLooper = Looper.myLooper()) == null) {
|
|
mInitializationLooper = Looper.getMainLooper();
|
|
}
|
|
|
|
int buffSizeInBytes = AudioTrack.getMinBufferSize(JET_OUTPUT_RATE,
|
|
JET_OUTPUT_CHANNEL_CONFIG, AudioFormat.ENCODING_PCM_16BIT);
|
|
|
|
if ((buffSizeInBytes != AudioTrack.ERROR)
|
|
&& (buffSizeInBytes != AudioTrack.ERROR_BAD_VALUE)) {
|
|
|
|
native_setup(new WeakReference<JetPlayer>(this),
|
|
JetPlayer.getMaxTracks(),
|
|
// bytes to frame conversion:
|
|
// 1200 == minimum buffer size in frames on generation 1 hardware
|
|
Math.max(1200, buffSizeInBytes /
|
|
(AudioFormat.getBytesPerSample(AudioFormat.ENCODING_PCM_16BIT) *
|
|
2 /*channels*/)));
|
|
}
|
|
}
|
|
|
|
|
|
protected void finalize() {
|
|
native_finalize();
|
|
}
|
|
|
|
|
|
/**
|
|
* Stops the current JET playback, and releases all associated native resources.
|
|
* The object can no longer be used and the reference should be set to null
|
|
* after a call to release().
|
|
*/
|
|
public void release() {
|
|
native_release();
|
|
singletonRef = null;
|
|
}
|
|
|
|
|
|
//--------------------------------------------
|
|
// Getters
|
|
//------------------------
|
|
/**
|
|
* Returns the maximum number of simultaneous MIDI tracks supported by JetPlayer
|
|
*/
|
|
public static int getMaxTracks() {
|
|
return JetPlayer.MAXTRACKS;
|
|
}
|
|
|
|
|
|
//--------------------------------------------
|
|
// Jet functionality
|
|
//------------------------
|
|
/**
|
|
* Loads a .jet file from a given path.
|
|
* @param path the path to the .jet file, for instance "/sdcard/mygame/music.jet".
|
|
* @return true if loading the .jet file was successful, false if loading failed.
|
|
*/
|
|
public boolean loadJetFile(String path) {
|
|
return native_loadJetFromFile(path);
|
|
}
|
|
|
|
|
|
/**
|
|
* Loads a .jet file from an asset file descriptor.
|
|
* @param afd the asset file descriptor.
|
|
* @return true if loading the .jet file was successful, false if loading failed.
|
|
*/
|
|
public boolean loadJetFile(AssetFileDescriptor afd) {
|
|
long len = afd.getLength();
|
|
if (len < 0) {
|
|
throw new AndroidRuntimeException("no length for fd");
|
|
}
|
|
return native_loadJetFromFileD(
|
|
afd.getFileDescriptor(), afd.getStartOffset(), len);
|
|
}
|
|
|
|
/**
|
|
* Closes the resource containing the JET content.
|
|
* @return true if successfully closed, false otherwise.
|
|
*/
|
|
public boolean closeJetFile() {
|
|
return native_closeJetFile();
|
|
}
|
|
|
|
|
|
/**
|
|
* Starts playing the JET segment queue.
|
|
* @return true if rendering and playback is successfully started, false otherwise.
|
|
*/
|
|
public boolean play() {
|
|
return native_playJet();
|
|
}
|
|
|
|
|
|
/**
|
|
* Pauses the playback of the JET segment queue.
|
|
* @return true if rendering and playback is successfully paused, false otherwise.
|
|
*/
|
|
public boolean pause() {
|
|
return native_pauseJet();
|
|
}
|
|
|
|
|
|
/**
|
|
* Queues the specified segment in the JET queue.
|
|
* @param segmentNum the identifier of the segment.
|
|
* @param libNum the index of the sound bank associated with the segment. Use -1 to indicate
|
|
* that no sound bank (DLS file) is associated with this segment, in which case JET will use
|
|
* the General MIDI library.
|
|
* @param repeatCount the number of times the segment will be repeated. 0 means the segment will
|
|
* only play once. -1 means the segment will repeat indefinitely.
|
|
* @param transpose the amount of pitch transposition. Set to 0 for normal playback.
|
|
* Range is -12 to +12.
|
|
* @param muteFlags a bitmask to specify which MIDI tracks will be muted during playback. Bit 0
|
|
* affects track 0, bit 1 affects track 1 etc.
|
|
* @param userID a value specified by the application that uniquely identifies the segment.
|
|
* this value is received in the
|
|
* {@link OnJetEventListener#onJetUserIdUpdate(JetPlayer, int, int)} event listener method.
|
|
* Normally, the application will keep a byte value that is incremented each time a new
|
|
* segment is queued up. This can be used to look up any special characteristics of that
|
|
* track including trigger clips and mute flags.
|
|
* @return true if the segment was successfully queued, false if the queue is full or if the
|
|
* parameters are invalid.
|
|
*/
|
|
public boolean queueJetSegment(int segmentNum, int libNum, int repeatCount,
|
|
int transpose, int muteFlags, byte userID) {
|
|
return native_queueJetSegment(segmentNum, libNum, repeatCount,
|
|
transpose, muteFlags, userID);
|
|
}
|
|
|
|
|
|
/**
|
|
* Queues the specified segment in the JET queue.
|
|
* @param segmentNum the identifier of the segment.
|
|
* @param libNum the index of the soundbank associated with the segment. Use -1 to indicate that
|
|
* no sound bank (DLS file) is associated with this segment, in which case JET will use
|
|
* the General MIDI library.
|
|
* @param repeatCount the number of times the segment will be repeated. 0 means the segment will
|
|
* only play once. -1 means the segment will repeat indefinitely.
|
|
* @param transpose the amount of pitch transposition. Set to 0 for normal playback.
|
|
* Range is -12 to +12.
|
|
* @param muteArray an array of booleans to specify which MIDI tracks will be muted during
|
|
* playback. The value at index 0 affects track 0, value at index 1 affects track 1 etc.
|
|
* The length of the array must be {@link #getMaxTracks()} for the call to succeed.
|
|
* @param userID a value specified by the application that uniquely identifies the segment.
|
|
* this value is received in the
|
|
* {@link OnJetEventListener#onJetUserIdUpdate(JetPlayer, int, int)} event listener method.
|
|
* Normally, the application will keep a byte value that is incremented each time a new
|
|
* segment is queued up. This can be used to look up any special characteristics of that
|
|
* track including trigger clips and mute flags.
|
|
* @return true if the segment was successfully queued, false if the queue is full or if the
|
|
* parameters are invalid.
|
|
*/
|
|
public boolean queueJetSegmentMuteArray(int segmentNum, int libNum, int repeatCount,
|
|
int transpose, boolean[] muteArray, byte userID) {
|
|
if (muteArray.length != JetPlayer.getMaxTracks()) {
|
|
return false;
|
|
}
|
|
return native_queueJetSegmentMuteArray(segmentNum, libNum, repeatCount,
|
|
transpose, muteArray, userID);
|
|
}
|
|
|
|
|
|
/**
|
|
* Modifies the mute flags.
|
|
* @param muteFlags a bitmask to specify which MIDI tracks are muted. Bit 0 affects track 0,
|
|
* bit 1 affects track 1 etc.
|
|
* @param sync if false, the new mute flags will be applied as soon as possible by the JET
|
|
* render and playback engine. If true, the mute flags will be updated at the start of the
|
|
* next segment. If the segment is repeated, the flags will take effect the next time
|
|
* segment is repeated.
|
|
* @return true if the mute flags were successfully updated, false otherwise.
|
|
*/
|
|
public boolean setMuteFlags(int muteFlags, boolean sync) {
|
|
return native_setMuteFlags(muteFlags, sync);
|
|
}
|
|
|
|
|
|
/**
|
|
* Modifies the mute flags for the current active segment.
|
|
* @param muteArray an array of booleans to specify which MIDI tracks are muted. The value at
|
|
* index 0 affects track 0, value at index 1 affects track 1 etc.
|
|
* The length of the array must be {@link #getMaxTracks()} for the call to succeed.
|
|
* @param sync if false, the new mute flags will be applied as soon as possible by the JET
|
|
* render and playback engine. If true, the mute flags will be updated at the start of the
|
|
* next segment. If the segment is repeated, the flags will take effect the next time
|
|
* segment is repeated.
|
|
* @return true if the mute flags were successfully updated, false otherwise.
|
|
*/
|
|
public boolean setMuteArray(boolean[] muteArray, boolean sync) {
|
|
if(muteArray.length != JetPlayer.getMaxTracks())
|
|
return false;
|
|
return native_setMuteArray(muteArray, sync);
|
|
}
|
|
|
|
|
|
/**
|
|
* Mutes or unmutes a single track.
|
|
* @param trackId the index of the track to mute.
|
|
* @param muteFlag set to true to mute, false to unmute.
|
|
* @param sync if false, the new mute flags will be applied as soon as possible by the JET
|
|
* render and playback engine. If true, the mute flag will be updated at the start of the
|
|
* next segment. If the segment is repeated, the flag will take effect the next time
|
|
* segment is repeated.
|
|
* @return true if the mute flag was successfully updated, false otherwise.
|
|
*/
|
|
public boolean setMuteFlag(int trackId, boolean muteFlag, boolean sync) {
|
|
return native_setMuteFlag(trackId, muteFlag, sync);
|
|
}
|
|
|
|
|
|
/**
|
|
* Schedules the playback of a clip.
|
|
* This will automatically update the mute flags in sync with the JET Clip Marker (controller
|
|
* 103). The parameter clipID must be in the range of 0-63. After the call to triggerClip, when
|
|
* JET next encounters a controller event 103 with bits 0-5 of the value equal to clipID and
|
|
* bit 6 set to 1, it will automatically unmute the track containing the controller event.
|
|
* When JET encounters the complementary controller event 103 with bits 0-5 of the value equal
|
|
* to clipID and bit 6 set to 0, it will mute the track again.
|
|
* @param clipId the identifier of the clip to trigger.
|
|
* @return true if the clip was successfully triggered, false otherwise.
|
|
*/
|
|
public boolean triggerClip(int clipId) {
|
|
return native_triggerClip(clipId);
|
|
}
|
|
|
|
|
|
/**
|
|
* Empties the segment queue, and clears all clips that are scheduled for playback.
|
|
* @return true if the queue was successfully cleared, false otherwise.
|
|
*/
|
|
public boolean clearQueue() {
|
|
return native_clearQueue();
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------
|
|
// Internal class to handle events posted from native code
|
|
//------------------------
|
|
private class NativeEventHandler extends Handler
|
|
{
|
|
private JetPlayer mJet;
|
|
|
|
public NativeEventHandler(JetPlayer jet, Looper looper) {
|
|
super(looper);
|
|
mJet = jet;
|
|
}
|
|
|
|
@Override
|
|
public void handleMessage(Message msg) {
|
|
OnJetEventListener listener = null;
|
|
synchronized (mEventListenerLock) {
|
|
listener = mJet.mJetEventListener;
|
|
}
|
|
switch(msg.what) {
|
|
case JET_EVENT:
|
|
if (listener != null) {
|
|
// call the appropriate listener after decoding the event parameters
|
|
// encoded in msg.arg1
|
|
mJetEventListener.onJetEvent(
|
|
mJet,
|
|
(short)((msg.arg1 & JET_EVENT_SEG_MASK) >> JET_EVENT_SEG_SHIFT),
|
|
(byte) ((msg.arg1 & JET_EVENT_TRACK_MASK) >> JET_EVENT_TRACK_SHIFT),
|
|
// JETCreator channel numbers start at 1, but the index starts at 0
|
|
// in the .jet files
|
|
(byte)(((msg.arg1 & JET_EVENT_CHAN_MASK) >> JET_EVENT_CHAN_SHIFT) + 1),
|
|
(byte) ((msg.arg1 & JET_EVENT_CTRL_MASK) >> JET_EVENT_CTRL_SHIFT),
|
|
(byte) (msg.arg1 & JET_EVENT_VAL_MASK) );
|
|
}
|
|
return;
|
|
case JET_USERID_UPDATE:
|
|
if (listener != null) {
|
|
listener.onJetUserIdUpdate(mJet, msg.arg1, msg.arg2);
|
|
}
|
|
return;
|
|
case JET_NUMQUEUEDSEGMENT_UPDATE:
|
|
if (listener != null) {
|
|
listener.onJetNumQueuedSegmentUpdate(mJet, msg.arg1);
|
|
}
|
|
return;
|
|
case JET_PAUSE_UPDATE:
|
|
if (listener != null)
|
|
listener.onJetPauseUpdate(mJet, msg.arg1);
|
|
return;
|
|
|
|
default:
|
|
loge("Unknown message type " + msg.what);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//--------------------------------------------
|
|
// Jet event listener
|
|
//------------------------
|
|
/**
|
|
* Sets the listener JetPlayer notifies when a JET event is generated by the rendering and
|
|
* playback engine.
|
|
* Notifications will be received in the same thread as the one in which the JetPlayer
|
|
* instance was created.
|
|
* @param listener
|
|
*/
|
|
public void setEventListener(OnJetEventListener listener) {
|
|
setEventListener(listener, null);
|
|
}
|
|
|
|
/**
|
|
* Sets the listener JetPlayer notifies when a JET event is generated by the rendering and
|
|
* playback engine.
|
|
* Use this method to receive JET events in the Handler associated with another
|
|
* thread than the one in which you created the JetPlayer instance.
|
|
* @param listener
|
|
* @param handler the Handler that will receive the event notification messages.
|
|
*/
|
|
public void setEventListener(OnJetEventListener listener, Handler handler) {
|
|
synchronized(mEventListenerLock) {
|
|
|
|
mJetEventListener = listener;
|
|
|
|
if (listener != null) {
|
|
if (handler != null) {
|
|
mEventHandler = new NativeEventHandler(this, handler.getLooper());
|
|
} else {
|
|
// no given handler, use the looper the AudioTrack was created in
|
|
mEventHandler = new NativeEventHandler(this, mInitializationLooper);
|
|
}
|
|
} else {
|
|
mEventHandler = null;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Handles the notification when the JET engine generates an event.
|
|
*/
|
|
public interface OnJetEventListener {
|
|
/**
|
|
* Callback for when the JET engine generates a new event.
|
|
*
|
|
* @param player the JET player the event is coming from
|
|
* @param segment 8 bit unsigned value
|
|
* @param track 6 bit unsigned value
|
|
* @param channel 4 bit unsigned value
|
|
* @param controller 7 bit unsigned value
|
|
* @param value 7 bit unsigned value
|
|
*/
|
|
void onJetEvent(JetPlayer player,
|
|
short segment, byte track, byte channel, byte controller, byte value);
|
|
/**
|
|
* Callback for when JET's currently playing segment's userID is updated.
|
|
*
|
|
* @param player the JET player the status update is coming from
|
|
* @param userId the ID of the currently playing segment
|
|
* @param repeatCount the repetition count for the segment (0 means it plays once)
|
|
*/
|
|
void onJetUserIdUpdate(JetPlayer player, int userId, int repeatCount);
|
|
|
|
/**
|
|
* Callback for when JET's number of queued segments is updated.
|
|
*
|
|
* @param player the JET player the status update is coming from
|
|
* @param nbSegments the number of segments in the JET queue
|
|
*/
|
|
void onJetNumQueuedSegmentUpdate(JetPlayer player, int nbSegments);
|
|
|
|
/**
|
|
* Callback for when JET pause state is updated.
|
|
*
|
|
* @param player the JET player the status update is coming from
|
|
* @param paused indicates whether JET is paused (1) or not (0)
|
|
*/
|
|
void onJetPauseUpdate(JetPlayer player, int paused);
|
|
}
|
|
|
|
|
|
//--------------------------------------------
|
|
// Native methods
|
|
//------------------------
|
|
private native final boolean native_setup(Object Jet_this,
|
|
int maxTracks, int trackBufferSize);
|
|
private native final void native_finalize();
|
|
private native final void native_release();
|
|
private native final boolean native_loadJetFromFile(String pathToJetFile);
|
|
private native final boolean native_loadJetFromFileD(FileDescriptor fd, long offset, long len);
|
|
private native final boolean native_closeJetFile();
|
|
private native final boolean native_playJet();
|
|
private native final boolean native_pauseJet();
|
|
private native final boolean native_queueJetSegment(int segmentNum, int libNum,
|
|
int repeatCount, int transpose, int muteFlags, byte userID);
|
|
private native final boolean native_queueJetSegmentMuteArray(int segmentNum, int libNum,
|
|
int repeatCount, int transpose, boolean[] muteArray, byte userID);
|
|
private native final boolean native_setMuteFlags(int muteFlags, boolean sync);
|
|
private native final boolean native_setMuteArray(boolean[]muteArray, boolean sync);
|
|
private native final boolean native_setMuteFlag(int trackId, boolean muteFlag, boolean sync);
|
|
private native final boolean native_triggerClip(int clipId);
|
|
private native final boolean native_clearQueue();
|
|
|
|
//---------------------------------------------------------
|
|
// Called exclusively by native code
|
|
//--------------------
|
|
@SuppressWarnings("unused")
|
|
private static void postEventFromNative(Object jetplayer_ref,
|
|
int what, int arg1, int arg2) {
|
|
//logd("Event posted from the native side: event="+ what + " args="+ arg1+" "+arg2);
|
|
JetPlayer jet = (JetPlayer)((WeakReference)jetplayer_ref).get();
|
|
|
|
if ((jet != null) && (jet.mEventHandler != null)) {
|
|
Message m =
|
|
jet.mEventHandler.obtainMessage(what, arg1, arg2, null);
|
|
jet.mEventHandler.sendMessage(m);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------
|
|
// Utils
|
|
//--------------------
|
|
private final static String TAG = "JetPlayer-J";
|
|
|
|
private static void logd(String msg) {
|
|
Log.d(TAG, "[ android.media.JetPlayer ] " + msg);
|
|
}
|
|
|
|
private static void loge(String msg) {
|
|
Log.e(TAG, "[ android.media.JetPlayer ] " + msg);
|
|
}
|
|
|
|
}
|