JetPlayer.java revision 3dec7d563a2f3e1eb967ce2054a00b6620e3558c
1/* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.media; 18 19 20import java.io.FileDescriptor; 21import java.lang.ref.WeakReference; 22import java.lang.CloneNotSupportedException; 23 24import android.content.res.AssetFileDescriptor; 25import android.os.Looper; 26import android.os.Handler; 27import android.os.Message; 28import android.util.AndroidRuntimeException; 29import android.util.Log; 30 31/** 32 * JetPlayer provides access to JET content playback and control. 33 * <p> 34 * Use <code>JetPlayer.getJetPlayer()</code> to get an instance of this class. 35 * 36 */ 37public class JetPlayer 38{ 39 //-------------------------------------------- 40 // Constants 41 //------------------------ 42 /** 43 * The maximum number of simultaneous tracks. Use __link #getMaxTracks()} to 44 * access this value. 45 */ 46 private static int MAXTRACKS = 32; 47 48 // to keep in sync with the JetPlayer class constants 49 // defined in frameworks/base/include/media/JetPlayer.h 50 private static final int JET_EVENT = 1; 51 private static final int JET_USERID_UPDATE = 2; 52 private static final int JET_NUMQUEUEDSEGMENT_UPDATE = 3; 53 private static final int JET_PAUSE_UPDATE = 4; 54 55 // to keep in sync with external/sonivox/arm-wt-22k/lib_src/jet_data.h 56 // Encoding of event information on 32 bits 57 private static final int JET_EVENT_VAL_MASK = 0x0000007f; // mask for value 58 private static final int JET_EVENT_CTRL_MASK = 0x00003f80; // mask for controller 59 private static final int JET_EVENT_CHAN_MASK = 0x0003c000; // mask for channel 60 private static final int JET_EVENT_TRACK_MASK = 0x00fc0000; // mask for track number 61 private static final int JET_EVENT_SEG_MASK = 0xff000000; // mask for segment ID 62 private static final int JET_EVENT_CTRL_SHIFT = 7; // shift to get controller number to bit 0 63 private static final int JET_EVENT_CHAN_SHIFT = 14; // shift to get MIDI channel to bit 0 64 private static final int JET_EVENT_TRACK_SHIFT = 18; // shift to get track ID to bit 0 65 private static final int JET_EVENT_SEG_SHIFT = 24; // shift to get segment ID to bit 0 66 67 68 //-------------------------------------------- 69 // Member variables 70 //------------------------ 71 private EventHandler mNativeEventHandler = null; 72 73 /** 74 * Lock to protect status listener updates against status change notifications 75 */ 76 private final Object mStatusListenerLock = new Object(); 77 78 /** 79 * Lock to protect the event listener updates against event notifications 80 */ 81 private final Object mEventListenerLock = new Object(); 82 83 private JetStatusUpdateListener mJetStatusUpdateListener = null; 84 85 private JetEventListener mJetEventListener = null; 86 87 private static JetPlayer singletonRef; 88 89 90 //-------------------------------- 91 // Used exclusively by native code 92 //-------------------- 93 /** 94 * Accessed by native methods: provides access to C++ JetPlayer object 95 */ 96 @SuppressWarnings("unused") 97 private int mNativePlayerInJavaObj; 98 99 100 //-------------------------------------------- 101 // Constructor, finalize 102 //------------------------ 103 public static JetPlayer getJetPlayer() { 104 if (singletonRef == null) 105 singletonRef = new JetPlayer(); 106 return singletonRef; 107 } 108 109 110 public Object clone() throws CloneNotSupportedException { 111 // JetPlayer is a singleton class, 112 // so you can't clone a JetPlayer instance 113 throw new CloneNotSupportedException(); 114 } 115 116 117 private JetPlayer() { 118 119 native_setup(new WeakReference<JetPlayer>(this), 120 JetPlayer.getMaxTracks(), 121 1200); //TODO parametrize this (?) 122 } 123 124 125 protected void finalize() { 126 native_finalize(); 127 } 128 129 130 public void release() { 131 native_release(); 132 } 133 134 135 private void createNativeEventHandler() { 136 Looper looper; 137 if ((looper = Looper.myLooper()) != null) { 138 mNativeEventHandler = new EventHandler(this, looper); 139 } else if ((looper = Looper.getMainLooper()) != null) { 140 mNativeEventHandler = new EventHandler(this, looper); 141 } else { 142 mNativeEventHandler = null; 143 } 144 } 145 146 147 //-------------------------------------------- 148 // Getters 149 //------------------------ 150 /** 151 * Returns the maximum number of simultaneous MIDI tracks supported by the Jet player 152 */ 153 public static int getMaxTracks() { 154 return JetPlayer.MAXTRACKS; 155 } 156 157 158 //-------------------------------------------- 159 // Jet functionality 160 //------------------------ 161 public boolean loadJetFile(String path) { 162 return native_loadJetFromFile(path); 163 } 164 165 166 public boolean loadJetFile(AssetFileDescriptor afd) { 167 long len = afd.getLength(); 168 if (len < 0) { 169 throw new AndroidRuntimeException("no length for fd"); 170 } 171 return native_loadJetFromFileD( 172 afd.getFileDescriptor(), afd.getStartOffset(), len); 173 } 174 175 176 public boolean closeJetFile() { 177 return native_closeJetFile(); 178 } 179 180 181 public boolean play() { 182 return native_playJet(); 183 } 184 185 186 public boolean pause() { 187 return native_pauseJet(); 188 } 189 190 191 public boolean queueJetSegment(int segmentNum, int libNum, int repeatCount, 192 int transpose, int muteFlags, byte userID) { 193 return native_queueJetSegment(segmentNum, libNum, repeatCount, 194 transpose, muteFlags, userID); 195 } 196 197 198 public boolean queueJetSegmentMuteArray(int segmentNum, int libNum, int repeatCount, 199 int transpose, boolean[] muteArray, byte userID) { 200 if (muteArray.length != JetPlayer.getMaxTracks()) { 201 return false; 202 } 203 return native_queueJetSegmentMuteArray(segmentNum, libNum, repeatCount, 204 transpose, muteArray, userID); 205 } 206 207 208 public boolean setMuteFlags(int muteFlags, boolean sync) { 209 return native_setMuteFlags(muteFlags, sync); 210 } 211 212 213 public boolean setMuteArray(boolean[] muteArray, boolean sync) { 214 if(muteArray.length != JetPlayer.getMaxTracks()) 215 return false; 216 return native_setMuteArray(muteArray, sync); 217 } 218 219 220 public boolean setMuteFlag(int trackId, boolean muteFlag, boolean sync) { 221 return native_setMuteFlag(trackId, muteFlag, sync); 222 } 223 224 225 public boolean triggerClip(int clipId) { 226 return native_triggerClip(clipId); 227 } 228 229 230 public boolean clearQueue() { 231 return native_clearQueue(); 232 } 233 234 235 //--------------------------------------------------------- 236 // Internal class to handle events posted from native code 237 //------------------------ 238 private class EventHandler extends Handler 239 { 240 private JetPlayer mJet; 241 242 public EventHandler(JetPlayer jet, Looper looper) { 243 super(looper); 244 mJet = jet; 245 } 246 247 @Override 248 public void handleMessage(Message msg) { 249 switch(msg.what) { 250 case JET_EVENT: 251 synchronized (mEventListenerLock) { 252 if (mJetEventListener != null) { 253 // call the appropriate listener after decoding the event parameters 254 // encoded in msg.arg1 255 mJetEventListener.onJetEvent( 256 mJet, 257 (short)((msg.arg1 & JET_EVENT_SEG_MASK) >> JET_EVENT_SEG_SHIFT), 258 (byte) ((msg.arg1 & JET_EVENT_TRACK_MASK) >> JET_EVENT_TRACK_SHIFT), 259 // JETCreator channel numbers start at 1, but the index starts at 0 260 // in the .jet files 261 (byte)(((msg.arg1 & JET_EVENT_CHAN_MASK) >> JET_EVENT_CHAN_SHIFT) + 1), 262 (byte) ((msg.arg1 & JET_EVENT_CTRL_MASK) >> JET_EVENT_CTRL_SHIFT), 263 (byte) (msg.arg1 & JET_EVENT_VAL_MASK) ); 264 } 265 } 266 return; 267 case JET_USERID_UPDATE: 268 synchronized (mStatusListenerLock) { 269 if (mJetStatusUpdateListener != null) { 270 mJetStatusUpdateListener.onJetUserIdUpdate(mJet, msg.arg1, msg.arg2); 271 } 272 } 273 return; 274 case JET_NUMQUEUEDSEGMENT_UPDATE: 275 synchronized (mStatusListenerLock) { 276 if (mJetStatusUpdateListener != null) { 277 mJetStatusUpdateListener.onJetNumQueuedSegmentUpdate(mJet, msg.arg1); 278 } 279 } 280 return; 281 case JET_PAUSE_UPDATE: 282 synchronized (mStatusListenerLock) { 283 if (mJetStatusUpdateListener != null) 284 mJetStatusUpdateListener.onJetPauseUpdate(mJet, msg.arg1); 285 } 286 return; 287 288 default: 289 loge("Unknown message type " + msg.what); 290 return; 291 } 292 } 293 } 294 295 296 //-------------------------------------------- 297 // Jet status update listener 298 //------------------------ 299 public void setStatusUpdateListener(JetStatusUpdateListener listener) { 300 synchronized(mStatusListenerLock) { 301 mJetStatusUpdateListener = listener; 302 } 303 304 if ((listener != null) && (mNativeEventHandler == null)) { 305 createNativeEventHandler(); 306 } 307 } 308 309 /** 310 * Handles the notification when the JET status is updated. 311 */ 312 public interface JetStatusUpdateListener { 313 /** 314 * Callback for when JET's currently playing segment userID is updated. 315 * 316 * @param player the JET player the status update is coming from 317 * @param userId the ID of the currently playing segment 318 * @param repeatCount the repetition count for the segment (0 means it plays once) 319 */ 320 void onJetUserIdUpdate(JetPlayer player, int userId, int repeatCount); 321 322 /** 323 * Callback for when JET's number of queued segments is updated. 324 * 325 * @param player the JET player the status update is coming from 326 * @param nbSegments the number of segments in the JET queue 327 */ 328 void onJetNumQueuedSegmentUpdate(JetPlayer player, int nbSegments); 329 330 /** 331 * Callback for when JET pause state is updated. 332 * 333 * @param player the JET player the status update is coming from 334 * @param paused indicates whether JET is paused or not 335 */ 336 void onJetPauseUpdate(JetPlayer player, int paused); 337 } 338 339 340 //-------------------------------------------- 341 // Jet event listener 342 //------------------------ 343 public void setEventListener(JetEventListener listener) { 344 synchronized(mEventListenerLock) { 345 mJetEventListener = listener; 346 } 347 348 if ((listener != null) && (mNativeEventHandler == null)) { 349 createNativeEventHandler(); 350 } 351 } 352 353 /** 354 * Handles the notification when the JET engine generates an event. 355 */ 356 public interface JetEventListener { 357 /** 358 * Callback for when the JET engine generates a new event. 359 * 360 * @param player the JET player the event is coming from 361 * @param segment 8 bit unsigned value 362 * @param track 6 bit unsigned value 363 * @param channel 4 bit unsigned value 364 * @param controller 7 bit unsigned value 365 * @param value 7 bit unsigned value 366 */ 367 void onJetEvent(JetPlayer player, 368 short segment, byte track, byte channel, byte controller, byte value); 369 } 370 371 372 //-------------------------------------------- 373 // Native methods 374 //------------------------ 375 private native final boolean native_setup(Object Jet_this, 376 int maxTracks, int trackBufferSize); 377 private native final void native_finalize(); 378 private native final void native_release(); 379 private native final boolean native_loadJetFromFile(String pathToJetFile); 380 private native final boolean native_loadJetFromFileD(FileDescriptor fd, long offset, long len); 381 private native final boolean native_closeJetFile(); 382 private native final boolean native_playJet(); 383 private native final boolean native_pauseJet(); 384 private native final boolean native_queueJetSegment(int segmentNum, int libNum, 385 int repeatCount, int transpose, int muteFlags, byte userID); 386 private native final boolean native_queueJetSegmentMuteArray(int segmentNum, int libNum, 387 int repeatCount, int transpose, boolean[] muteArray, byte userID); 388 private native final boolean native_setMuteFlags(int muteFlags, boolean sync); 389 private native final boolean native_setMuteArray(boolean[]muteArray, boolean sync); 390 private native final boolean native_setMuteFlag(int trackId, boolean muteFlag, boolean sync); 391 private native final boolean native_triggerClip(int clipId); 392 private native final boolean native_clearQueue(); 393 394 //--------------------------------------------------------- 395 // Called exclusively by native code 396 //-------------------- 397 @SuppressWarnings("unused") 398 private static void postEventFromNative(Object jetplayer_ref, 399 int what, int arg1, int arg2) { 400 401 JetPlayer jet = (JetPlayer)((WeakReference)jetplayer_ref).get(); 402 403 if( (jet!=null) && (jet.mNativeEventHandler!=null) ){ 404 Message m = jet.mNativeEventHandler.obtainMessage(what, arg1, arg2, null); 405 jet.mNativeEventHandler.sendMessage(m); 406 } 407 } 408 409 410 //--------------------------------------------------------- 411 // Utils 412 //-------------------- 413 private final static String TAG = "JetPlayer-J"; 414 415 private static void logd(String msg) { 416 Log.d(TAG, "[ android.media.JetPlayer ] " + msg); 417 } 418 419 private static void loge(String msg) { 420 Log.e(TAG, "[ android.media.JetPlayer ] " + msg); 421 } 422 423} 424