diff options
Diffstat (limited to 'media')
151 files changed, 5316 insertions, 2018 deletions
diff --git a/media/java/android/media/AmrInputStream.java b/media/java/android/media/AmrInputStream.java index bc68472..8b7eee2 100644 --- a/media/java/android/media/AmrInputStream.java +++ b/media/java/android/media/AmrInputStream.java @@ -44,7 +44,7 @@ public final class AmrInputStream extends InputStream private int mGae; // result amr stream - private byte[] mBuf = new byte[SAMPLES_PER_FRAME * 2]; + private final byte[] mBuf = new byte[SAMPLES_PER_FRAME * 2]; private int mBufIn = 0; private int mBufOut = 0; diff --git a/media/java/android/media/AsyncPlayer.java b/media/java/android/media/AsyncPlayer.java index 09aec2e..804528e 100644 --- a/media/java/android/media/AsyncPlayer.java +++ b/media/java/android/media/AsyncPlayer.java @@ -49,7 +49,7 @@ public class AsyncPlayer { } } - private LinkedList<Command> mCmdQueue = new LinkedList(); + private final LinkedList<Command> mCmdQueue = new LinkedList(); private void startSound(Command cmd) { // Preparing can be slow, so if there is something else diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java index 8990fe5..49f498e 100644 --- a/media/java/android/media/AudioFormat.java +++ b/media/java/android/media/AudioFormat.java @@ -31,10 +31,11 @@ public class AudioFormat { public static final int ENCODING_INVALID = 0; /** Default audio data format */ public static final int ENCODING_DEFAULT = 1; + // These two values must be kept in sync with JNI code for AudioTrack, AudioRecord /** Audio data format: PCM 16 bit per sample. Guaranteed to be supported by devices. */ - public static final int ENCODING_PCM_16BIT = 2; // accessed by native code + public static final int ENCODING_PCM_16BIT = 2; /** Audio data format: PCM 8 bit per sample. Not guaranteed to be supported by devices. */ - public static final int ENCODING_PCM_8BIT = 3; // accessed by native code + public static final int ENCODING_PCM_8BIT = 3; /** Invalid audio channel configuration */ /** @deprecated use CHANNEL_INVALID instead */ diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index a0881a7..78eb89f 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -22,8 +22,6 @@ import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; import android.content.Intent; -import android.database.ContentObserver; -import android.graphics.Bitmap; import android.os.Binder; import android.os.Handler; import android.os.IBinder; @@ -37,7 +35,6 @@ import android.util.Log; import android.view.KeyEvent; import android.view.VolumePanel; -import java.util.Iterator; import java.util.HashMap; /** @@ -49,11 +46,9 @@ import java.util.HashMap; public class AudioManager { private final Context mContext; - private final Handler mHandler; private long mVolumeKeyUpTime; private int mVolumeControlStream = -1; private static String TAG = "AudioManager"; - private static boolean localLOGV = false; /** * Broadcast intent, a hint for applications that audio is about to become @@ -359,7 +354,6 @@ public class AudioManager { */ public AudioManager(Context context) { mContext = context; - mHandler = new Handler(context.getMainLooper()); } private static IAudioService getService() @@ -1515,7 +1509,7 @@ public class AudioManager { * Map to convert focus event listener IDs, as used in the AudioService audio focus stack, * to actual listener objects. */ - private HashMap<String, OnAudioFocusChangeListener> mAudioFocusIdListenerMap = + private final HashMap<String, OnAudioFocusChangeListener> mAudioFocusIdListenerMap = new HashMap<String, OnAudioFocusChangeListener>(); /** * Lock to prevent concurrent changes to the list of focus listeners for this AudioManager @@ -1530,7 +1524,7 @@ public class AudioManager { /** * Handler for audio focus events coming from the audio service. */ - private FocusEventHandlerDelegate mAudioFocusEventHandlerDelegate = + private final FocusEventHandlerDelegate mAudioFocusEventHandlerDelegate = new FocusEventHandlerDelegate(); /** @@ -1569,7 +1563,7 @@ public class AudioManager { } } - private IAudioFocusDispatcher mAudioFocusDispatcher = new IAudioFocusDispatcher.Stub() { + private final IAudioFocusDispatcher mAudioFocusDispatcher = new IAudioFocusDispatcher.Stub() { public void dispatchAudioFocusChange(int focusChange, String id) { Message m = mAudioFocusEventHandlerDelegate.getHandler().obtainMessage(focusChange, id); @@ -1655,11 +1649,46 @@ public class AudioManager { mAudioFocusDispatcher, getIdForAudioFocusListener(l), mContext.getPackageName() /* package name */); } catch (RemoteException e) { - Log.e(TAG, "Can't call requestAudioFocus() from AudioService due to "+e); + Log.e(TAG, "Can't call requestAudioFocus() on AudioService due to "+e); } return status; } + /** + * @hide + * Used internally by telephony package to request audio focus. Will cause the focus request + * to be associated with the "voice communication" identifier only used in AudioService + * to identify this use case. + * @param streamType use STREAM_RING for focus requests when ringing, VOICE_CALL for + * the establishment of the call + * @param durationHint the type of focus request. AUDIOFOCUS_GAIN_TRANSIENT is recommended so + * media applications resume after a call + */ + public void requestAudioFocusForCall(int streamType, int durationHint) { + IAudioService service = getService(); + try { + service.requestAudioFocus(streamType, durationHint, mICallBack, null, + AudioService.IN_VOICE_COMM_FOCUS_ID, + "system" /* dump-friendly package name */); + } catch (RemoteException e) { + Log.e(TAG, "Can't call requestAudioFocusForCall() on AudioService due to "+e); + } + } + + /** + * @hide + * Used internally by telephony package to abandon audio focus, typically after a call or + * when ringing ends and the call is rejected or not answered. + * Should match one or more calls to {@link #requestAudioFocusForCall(int, int)}. + */ + public void abandonAudioFocusForCall() { + IAudioService service = getService(); + try { + service.abandonAudioFocus(null, AudioService.IN_VOICE_COMM_FOCUS_ID); + } catch (RemoteException e) { + Log.e(TAG, "Can't call abandonAudioFocusForCall() on AudioService due to "+e); + } + } /** * Abandon audio focus. Causes the previous focus owner, if any, to receive focus. @@ -1674,7 +1703,7 @@ public class AudioManager { status = service.abandonAudioFocus(mAudioFocusDispatcher, getIdForAudioFocusListener(l)); } catch (RemoteException e) { - Log.e(TAG, "Can't call abandonAudioFocus() from AudioService due to "+e); + Log.e(TAG, "Can't call abandonAudioFocus() on AudioService due to "+e); } return status; } @@ -1926,7 +1955,7 @@ public class AudioManager { /** * {@hide} */ - private IBinder mICallBack = new Binder(); + private final IBinder mICallBack = new Binder(); /** * Checks whether the phone is in silent mode, with or without vibrate. diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java index 855e831..5cc24c0 100644 --- a/media/java/android/media/AudioRecord.java +++ b/media/java/android/media/AudioRecord.java @@ -161,7 +161,7 @@ public class AudioRecord /** * Lock to make sure mRecordingState updates are reflecting the actual state of the object. */ - private Object mRecordingStateLock = new Object(); + private final Object mRecordingStateLock = new Object(); /** * The listener the AudioRecord notifies when the record position reaches a marker * or for periodic updates during the progression of the record head. diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java index 37aacab..13e3982 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -102,8 +102,6 @@ public class AudioService extends IAudioService.Stub { private VolumePanel mVolumePanel; // sendMsg() flags - /** Used when a message should be shared across all stream types. */ - private static final int SHARED_MSG = -1; /** If the msg is already queued, replace it with this one. */ private static final int SENDMSG_REPLACE = 0; /** If the msg is already queued, ignore this one and leave the old. */ @@ -112,7 +110,7 @@ public class AudioService extends IAudioService.Stub { private static final int SENDMSG_QUEUE = 2; // AudioHandler message.whats - private static final int MSG_SET_SYSTEM_VOLUME = 0; + private static final int MSG_SET_DEVICE_VOLUME = 0; private static final int MSG_PERSIST_VOLUME = 1; private static final int MSG_PERSIST_RINGER_MODE = 3; private static final int MSG_PERSIST_VIBRATE_SETTING = 4; @@ -126,6 +124,13 @@ public class AudioService extends IAudioService.Stub { private static final int MSG_BT_HEADSET_CNCT_FAILED = 12; private static final int MSG_RCDISPLAY_CLEAR = 13; private static final int MSG_RCDISPLAY_UPDATE = 14; + private static final int MSG_SET_ALL_VOLUMES = 15; + + + // flags for MSG_PERSIST_VOLUME indicating if current and/or last audible volume should be + // persisted + private static final int PERSIST_CURRENT = 0x1; + private static final int PERSIST_LAST_AUDIBLE = 0x2; private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000; // Timeout for connection to bluetooth headset service @@ -141,11 +146,12 @@ public class AudioService extends IAudioService.Stub { private SettingsObserver mSettingsObserver; private int mMode; - private Object mSettingsLock = new Object(); + // protects mRingerMode + private final Object mSettingsLock = new Object(); private boolean mMediaServerOk; private SoundPool mSoundPool; - private Object mSoundEffectsLock = new Object(); + private final Object mSoundEffectsLock = new Object(); private static final int NUM_SOUNDPOOL_CHANNELS = 4; private static final int SOUND_EFFECT_VOLUME = 1000; @@ -162,7 +168,7 @@ public class AudioService extends IAudioService.Stub { /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect * uses soundpool (second column) */ - private int[][] SOUND_EFFECT_FILES_MAP = new int[][] { + private final int[][] SOUND_EFFECT_FILES_MAP = new int[][] { {0, -1}, // FX_KEY_CLICK {0, -1}, // FX_FOCUS_NAVIGATION_UP {0, -1}, // FX_FOCUS_NAVIGATION_DOWN @@ -175,7 +181,7 @@ public class AudioService extends IAudioService.Stub { }; /** @hide Maximum volume index values for audio streams */ - private int[] MAX_STREAM_VOLUME = new int[] { + private final int[] MAX_STREAM_VOLUME = new int[] { 5, // STREAM_VOICE_CALL 7, // STREAM_SYSTEM 7, // STREAM_RING @@ -191,7 +197,7 @@ public class AudioService extends IAudioService.Stub { * of another stream: This avoids multiplying the volume settings for hidden * stream types that follow other stream behavior for volume settings * NOTE: do not create loops in aliases! */ - private int[] STREAM_VOLUME_ALIAS = new int[] { + private final int[] STREAM_VOLUME_ALIAS = new int[] { AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL AudioSystem.STREAM_SYSTEM, // STREAM_SYSTEM AudioSystem.STREAM_RING, // STREAM_RING @@ -204,19 +210,19 @@ public class AudioService extends IAudioService.Stub { AudioSystem.STREAM_MUSIC // STREAM_TTS }; - private AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() { + private final AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() { public void onError(int error) { switch (error) { case AudioSystem.AUDIO_STATUS_SERVER_DIED: if (mMediaServerOk) { - sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SHARED_MSG, SENDMSG_NOOP, 0, 0, + sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SENDMSG_NOOP, 0, 0, null, 1500); mMediaServerOk = false; } break; case AudioSystem.AUDIO_STATUS_OK: if (!mMediaServerOk) { - sendMsg(mAudioHandler, MSG_MEDIA_SERVER_STARTED, SHARED_MSG, SENDMSG_NOOP, 0, 0, + sendMsg(mAudioHandler, MSG_MEDIA_SERVER_STARTED, SENDMSG_NOOP, 0, 0, null, 0); mMediaServerOk = true; } @@ -232,6 +238,7 @@ public class AudioService extends IAudioService.Stub { * {@link AudioManager#RINGER_MODE_SILENT}, or * {@link AudioManager#RINGER_MODE_VIBRATE}. */ + // protected by mSettingsLock private int mRingerMode; /** @see System#MODE_RINGER_STREAMS_AFFECTED */ @@ -263,17 +270,17 @@ public class AudioService extends IAudioService.Stub { private boolean mIsRinging = false; // Devices currently connected - private HashMap <Integer, String> mConnectedDevices = new HashMap <Integer, String>(); + private final HashMap <Integer, String> mConnectedDevices = new HashMap <Integer, String>(); // Forced device usage for communications private int mForcedUseForComm; // List of binder death handlers for setMode() client processes. // The last process to have called setMode() is at the top of the list. - private ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>(); + private final ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>(); // List of clients having issued a SCO start request - private ArrayList <ScoClient> mScoClients = new ArrayList <ScoClient>(); + private final ArrayList <ScoClient> mScoClients = new ArrayList <ScoClient>(); // BluetoothHeadset API to control SCO connection private BluetoothHeadset mBluetoothHeadset; @@ -323,6 +330,7 @@ public class AudioService extends IAudioService.Stub { // Keyguard manager proxy private KeyguardManager mKeyguardManager; + /////////////////////////////////////////////////////////////////////////// // Construction /////////////////////////////////////////////////////////////////////////// @@ -425,12 +433,17 @@ public class AudioService extends IAudioService.Stub { // Correct stream index values for streams with aliases for (int i = 0; i < numStreamTypes; i++) { + int device = getDeviceForStream(i); if (STREAM_VOLUME_ALIAS[i] != i) { - int index = rescaleIndex(streams[i].mIndex, STREAM_VOLUME_ALIAS[i], i); - streams[i].mIndex = streams[i].getValidIndex(index); - setStreamVolumeIndex(i, index); - index = rescaleIndex(streams[i].mLastAudibleIndex, STREAM_VOLUME_ALIAS[i], i); - streams[i].mLastAudibleIndex = streams[i].getValidIndex(index); + int index = rescaleIndex(streams[i].getIndex(device, false /* lastAudible */), + STREAM_VOLUME_ALIAS[i], + i); + streams[i].mIndex.put(device, streams[i].getValidIndex(index)); + streams[i].applyDeviceVolume(device); + index = rescaleIndex(streams[i].getIndex(device, true /* lastAudible */), + STREAM_VOLUME_ALIAS[i], + i); + streams[i].mLastAudibleIndex.put(device, streams[i].getValidIndex(index)); } } } @@ -438,12 +451,15 @@ public class AudioService extends IAudioService.Stub { private void readPersistedSettings() { final ContentResolver cr = mContentResolver; - mRingerMode = System.getInt(cr, System.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL); + int ringerMode = System.getInt(cr, System.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL); // sanity check in case the settings are restored from a device with incompatible // ringer modes - if (!AudioManager.isValidRingerMode(mRingerMode)) { - mRingerMode = AudioManager.RINGER_MODE_NORMAL; - System.putInt(cr, System.MODE_RINGER, mRingerMode); + if (!AudioManager.isValidRingerMode(ringerMode)) { + ringerMode = AudioManager.RINGER_MODE_NORMAL; + System.putInt(cr, System.MODE_RINGER, ringerMode); + } + synchronized(mSettingsLock) { + mRingerMode = ringerMode; } mVibrateSetting = System.getInt(cr, System.VIBRATE_ON, 0); @@ -469,7 +485,7 @@ public class AudioService extends IAudioService.Stub { // Each stream will read its own persisted settings // Broadcast the sticky intent - broadcastRingerMode(); + broadcastRingerMode(ringerMode); // Broadcast vibrate settings broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER); @@ -479,10 +495,6 @@ public class AudioService extends IAudioService.Stub { restoreMediaButtonReceiver(); } - private void setStreamVolumeIndex(int stream, int index) { - AudioSystem.setStreamVolumeIndex(stream, (index + 5)/10); - } - private int rescaleIndex(int index, int srcStream, int dstStream) { return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex(); } @@ -526,7 +538,11 @@ public class AudioService extends IAudioService.Stub { // checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION) int streamTypeAlias = STREAM_VOLUME_ALIAS[streamType]; VolumeStreamState streamState = mStreamStates[streamTypeAlias]; - final int oldIndex = (streamState.muteCount() != 0) ? streamState.mLastAudibleIndex : streamState.mIndex; + + final int device = getDeviceForStream(streamTypeAlias); + // get last audible index if stream is muted, current index otherwise + final int oldIndex = streamState.getIndex(device, + (streamState.muteCount() != 0) /* lastAudible */); boolean adjustVolume = true; // If either the client forces allowing ringer modes for this adjustment, @@ -534,8 +550,9 @@ public class AudioService extends IAudioService.Stub { if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) || streamTypeAlias == AudioSystem.STREAM_RING || (!mVoiceCapable && streamTypeAlias == AudioSystem.STREAM_MUSIC)) { + int ringerMode = getRingerMode(); // do not vibrate if already in vibrate mode - if (mRingerMode == AudioManager.RINGER_MODE_VIBRATE) { + if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) { flags &= ~AudioManager.FLAG_VIBRATE; } // Check if the ringer mode changes with this volume adjustment. If @@ -554,22 +571,32 @@ public class AudioService extends IAudioService.Stub { if (STREAM_VOLUME_ALIAS[i] == streamTypeAlias) { VolumeStreamState s = mStreamStates[i]; - s.adjustLastAudibleIndex(direction); + s.adjustLastAudibleIndex(direction, device); // Post a persist volume msg - sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, i, - SENDMSG_REPLACE, 0, 1, s, PERSIST_DELAY); + sendMsg(mAudioHandler, + MSG_PERSIST_VOLUME, + SENDMSG_REPLACE, + PERSIST_LAST_AUDIBLE, + device, + s, + PERSIST_DELAY); } } } - index = streamState.mLastAudibleIndex; + index = streamState.getIndex(device, true /* lastAudible */); } else { - if (adjustVolume && streamState.adjustIndex(direction)) { + if (adjustVolume && streamState.adjustIndex(direction, device)) { // Post message to set system volume (it in turn will post a message // to persist). Do not change volume if stream is muted. - sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, streamTypeAlias, SENDMSG_NOOP, 0, 0, - streamState, 0); + sendMsg(mAudioHandler, + MSG_SET_DEVICE_VOLUME, + SENDMSG_NOOP, + device, + 0, + streamState, + 0); } - index = streamState.mIndex; + index = streamState.getIndex(device, false /* lastAudible */); } sendVolumeUpdate(streamType, oldIndex, index, flags); @@ -580,29 +607,35 @@ public class AudioService extends IAudioService.Stub { ensureValidStreamType(streamType); VolumeStreamState streamState = mStreamStates[STREAM_VOLUME_ALIAS[streamType]]; - final int oldIndex = (streamState.muteCount() != 0) ? streamState.mLastAudibleIndex : streamState.mIndex; + final int device = getDeviceForStream(streamType); + // get last audible index if stream is muted, current index otherwise + final int oldIndex = streamState.getIndex(device, + (streamState.muteCount() != 0) /* lastAudible */); // setting ring or notifications volume to 0 on voice capable devices enters silent mode if (mVoiceCapable && (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) || (STREAM_VOLUME_ALIAS[streamType] == AudioSystem.STREAM_RING))) { - int newRingerMode = mRingerMode; + int newRingerMode; if (index == 0) { newRingerMode = System.getInt(mContentResolver, System.VIBRATE_IN_SILENT, 1) == 1 ? AudioManager.RINGER_MODE_VIBRATE : AudioManager.RINGER_MODE_SILENT; - setStreamVolumeInt(STREAM_VOLUME_ALIAS[streamType], index, false, true); + setStreamVolumeInt(STREAM_VOLUME_ALIAS[streamType], + index, + device, + false, + true); } else { newRingerMode = AudioManager.RINGER_MODE_NORMAL; } - if (newRingerMode != mRingerMode) { - setRingerMode(newRingerMode); - } + setRingerMode(newRingerMode); } index = rescaleIndex(index * 10, streamType, STREAM_VOLUME_ALIAS[streamType]); - setStreamVolumeInt(STREAM_VOLUME_ALIAS[streamType], index, false, true); - - index = (streamState.muteCount() != 0) ? streamState.mLastAudibleIndex : streamState.mIndex; + setStreamVolumeInt(STREAM_VOLUME_ALIAS[streamType], index, device, false, true); + // get last audible index if stream is muted, current index otherwise + index = streamState.getIndex(device, + (streamState.muteCount() != 0) /* lastAudible */); sendVolumeUpdate(streamType, oldIndex, index, flags); } @@ -630,28 +663,43 @@ public class AudioService extends IAudioService.Stub { * * @param streamType Type of the stream * @param index Desired volume index of the stream + * @param device the device whose volume must be changed * @param force If true, set the volume even if the desired volume is same * as the current volume. * @param lastAudible If true, stores new index as last audible one */ - private void setStreamVolumeInt(int streamType, int index, boolean force, boolean lastAudible) { + private void setStreamVolumeInt(int streamType, + int index, + int device, + boolean force, + boolean lastAudible) { VolumeStreamState streamState = mStreamStates[streamType]; // If stream is muted, set last audible index only if (streamState.muteCount() != 0) { // Do not allow last audible index to be 0 if (index != 0) { - streamState.setLastAudibleIndex(index); + streamState.setLastAudibleIndex(index, device); // Post a persist volume msg - sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, streamType, - SENDMSG_REPLACE, 0, 1, streamState, PERSIST_DELAY); + sendMsg(mAudioHandler, + MSG_PERSIST_VOLUME, + SENDMSG_REPLACE, + PERSIST_LAST_AUDIBLE, + device, + streamState, + PERSIST_DELAY); } } else { - if (streamState.setIndex(index, lastAudible) || force) { + if (streamState.setIndex(index, device, lastAudible) || force) { // Post message to set system volume (it in turn will post a message // to persist). - sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, streamType, SENDMSG_NOOP, 0, 0, - streamState, 0); + sendMsg(mAudioHandler, + MSG_SET_DEVICE_VOLUME, + SENDMSG_NOOP, + device, + 0, + streamState, + 0); } } } @@ -680,7 +728,8 @@ public class AudioService extends IAudioService.Stub { /** @see AudioManager#getStreamVolume(int) */ public int getStreamVolume(int streamType) { ensureValidStreamType(streamType); - return (mStreamStates[streamType].mIndex + 5) / 10; + int device = getDeviceForStream(streamType); + return (mStreamStates[streamType].getIndex(device, false /* lastAudible */) + 5) / 10; } /** @see AudioManager#getStreamMaxVolume(int) */ @@ -693,27 +742,37 @@ public class AudioService extends IAudioService.Stub { /** Get last audible volume before stream was muted. */ public int getLastAudibleStreamVolume(int streamType) { ensureValidStreamType(streamType); - return (mStreamStates[streamType].mLastAudibleIndex + 5) / 10; + int device = getDeviceForStream(streamType); + return (mStreamStates[streamType].getIndex(device, true /* lastAudible */) + 5) / 10; } /** @see AudioManager#getRingerMode() */ public int getRingerMode() { - return mRingerMode; + synchronized(mSettingsLock) { + return mRingerMode; + } + } + + private void ensureValidRingerMode(int ringerMode) { + if (!AudioManager.isValidRingerMode(ringerMode)) { + throw new IllegalArgumentException("Bad ringer mode " + ringerMode); + } } /** @see AudioManager#setRingerMode(int) */ public void setRingerMode(int ringerMode) { - synchronized (mSettingsLock) { - if (ringerMode != mRingerMode) { - setRingerModeInt(ringerMode, true); - // Send sticky broadcast - broadcastRingerMode(); - } + ensureValidRingerMode(ringerMode); + if (ringerMode != getRingerMode()) { + setRingerModeInt(ringerMode, true); + // Send sticky broadcast + broadcastRingerMode(ringerMode); } } private void setRingerModeInt(int ringerMode, boolean persist) { - mRingerMode = ringerMode; + synchronized(mSettingsLock) { + mRingerMode = ringerMode; + } // Mute stream if not previously muted by ringer mode and ringer mode // is not RINGER_MODE_NORMAL and stream is affected by ringer mode. @@ -723,20 +782,27 @@ public class AudioService extends IAudioService.Stub { for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { if (isStreamMutedByRingerMode(streamType)) { if (!isStreamAffectedByRingerMode(streamType) || - mRingerMode == AudioManager.RINGER_MODE_NORMAL) { + ringerMode == AudioManager.RINGER_MODE_NORMAL) { // ring and notifications volume should never be 0 when not silenced // on voice capable devices if (mVoiceCapable && - STREAM_VOLUME_ALIAS[streamType] == AudioSystem.STREAM_RING && - mStreamStates[streamType].mLastAudibleIndex == 0) { - mStreamStates[streamType].mLastAudibleIndex = 10; + STREAM_VOLUME_ALIAS[streamType] == AudioSystem.STREAM_RING) { + + Set set = mStreamStates[streamType].mLastAudibleIndex.entrySet(); + Iterator i = set.iterator(); + while (i.hasNext()) { + Map.Entry entry = (Map.Entry)i.next(); + if ((Integer)entry.getValue() == 0) { + entry.setValue(10); + } + } } mStreamStates[streamType].mute(null, false); mRingerModeMutedStreams &= ~(1 << streamType); } } else { if (isStreamAffectedByRingerMode(streamType) && - mRingerMode != AudioManager.RINGER_MODE_NORMAL) { + ringerMode != AudioManager.RINGER_MODE_NORMAL) { mStreamStates[streamType].mute(null, true); mRingerModeMutedStreams |= (1 << streamType); } @@ -745,7 +811,7 @@ public class AudioService extends IAudioService.Stub { // Post a persist ringer mode msg if (persist) { - sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE, SHARED_MSG, + sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE, SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY); } } @@ -756,10 +822,10 @@ public class AudioService extends IAudioService.Stub { switch (getVibrateSetting(vibrateType)) { case AudioManager.VIBRATE_SETTING_ON: - return mRingerMode != AudioManager.RINGER_MODE_SILENT; + return getRingerMode() != AudioManager.RINGER_MODE_SILENT; case AudioManager.VIBRATE_SETTING_ONLY_SILENT: - return mRingerMode == AudioManager.RINGER_MODE_VIBRATE; + return getRingerMode() == AudioManager.RINGER_MODE_VIBRATE; case AudioManager.VIBRATE_SETTING_OFF: // return false, even for incoming calls @@ -785,7 +851,7 @@ public class AudioService extends IAudioService.Stub { // Post message to set ringer mode (it in turn will post a message // to persist) - sendMsg(mAudioHandler, MSG_PERSIST_VIBRATE_SETTING, SHARED_MSG, SENDMSG_NOOP, 0, 0, + sendMsg(mAudioHandler, MSG_PERSIST_VIBRATE_SETTING, SENDMSG_NOOP, 0, 0, null, 0); } @@ -926,8 +992,6 @@ public class AudioService extends IAudioService.Stub { if (mode != mMode) { status = AudioSystem.setPhoneState(mode); if (status == AudioSystem.AUDIO_STATUS_OK) { - // automatically handle audio focus for mode changes - handleFocusForCalls(mMode, mode, cb); mMode = mode; } else { if (hdlr != null) { @@ -951,46 +1015,13 @@ public class AudioService extends IAudioService.Stub { } } int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE); - int index = mStreamStates[STREAM_VOLUME_ALIAS[streamType]].mIndex; - setStreamVolumeInt(STREAM_VOLUME_ALIAS[streamType], index, true, false); + int device = getDeviceForStream(streamType); + int index = mStreamStates[STREAM_VOLUME_ALIAS[streamType]].getIndex(device, false); + setStreamVolumeInt(STREAM_VOLUME_ALIAS[streamType], index, device, true, false); } return newModeOwnerPid; } - /** pre-condition: oldMode != newMode */ - private void handleFocusForCalls(int oldMode, int newMode, IBinder cb) { - // if ringing - if (newMode == AudioSystem.MODE_RINGTONE) { - // if not ringing silently - int ringVolume = AudioService.this.getStreamVolume(AudioManager.STREAM_RING); - if (ringVolume > 0) { - // request audio focus for the communication focus entry - requestAudioFocus(AudioManager.STREAM_RING, - AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, cb, - null /* IAudioFocusDispatcher allowed to be null only for this clientId */, - IN_VOICE_COMM_FOCUS_ID /*clientId*/, - "system"); - - } - } - // if entering call - else if ((newMode == AudioSystem.MODE_IN_CALL) - || (newMode == AudioSystem.MODE_IN_COMMUNICATION)) { - // request audio focus for the communication focus entry - // (it's ok if focus was already requested during ringing) - requestAudioFocus(AudioManager.STREAM_RING, - AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, cb, - null /* IAudioFocusDispatcher allowed to be null only for this clientId */, - IN_VOICE_COMM_FOCUS_ID /*clientId*/, - "system"); - } - // if exiting call - else if (newMode == AudioSystem.MODE_NORMAL) { - // abandon audio focus for communication focus entry - abandonAudioFocus(null, IN_VOICE_COMM_FOCUS_ID); - } - } - /** @see AudioManager#getMode() */ public int getMode() { return mMode; @@ -998,20 +1029,20 @@ public class AudioService extends IAudioService.Stub { /** @see AudioManager#playSoundEffect(int) */ public void playSoundEffect(int effectType) { - sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SHARED_MSG, SENDMSG_NOOP, + sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_NOOP, effectType, -1, null, 0); } /** @see AudioManager#playSoundEffect(int, float) */ public void playSoundEffectVolume(int effectType, float volume) { loadSoundEffects(); - sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SHARED_MSG, SENDMSG_NOOP, + sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_NOOP, effectType, (int) (volume * 1000), null, 0); } /** * Loads samples into the soundpool. - * This method must be called at when sound effects are enabled + * This method must be called at first when sound effects are enabled */ public boolean loadSoundEffects() { int status; @@ -1026,10 +1057,6 @@ public class AudioService extends IAudioService.Stub { return true; } mSoundPool = new SoundPool(NUM_SOUNDPOOL_CHANNELS, AudioSystem.STREAM_SYSTEM, 0); - if (mSoundPool == null) { - Log.w(TAG, "loadSoundEffects() could not allocate sound pool"); - return false; - } try { mSoundPoolCallBack = null; @@ -1220,28 +1247,7 @@ public class AudioService extends IAudioService.Stub { for (int streamType = 0; streamType < numStreamTypes; streamType++) { VolumeStreamState streamState = mStreamStates[streamType]; - String settingName = System.VOLUME_SETTINGS[STREAM_VOLUME_ALIAS[streamType]]; - String lastAudibleSettingName = settingName + System.APPEND_FOR_LAST_AUDIBLE; - int index = Settings.System.getInt(mContentResolver, - settingName, - AudioManager.DEFAULT_STREAM_VOLUME[streamType]); - if (STREAM_VOLUME_ALIAS[streamType] != streamType) { - index = rescaleIndex(index * 10, STREAM_VOLUME_ALIAS[streamType], streamType); - } else { - index *= 10; - } - streamState.mIndex = streamState.getValidIndex(index); - - index = (index + 5) / 10; - index = Settings.System.getInt(mContentResolver, - lastAudibleSettingName, - (index > 0) ? index : AudioManager.DEFAULT_STREAM_VOLUME[streamType]); - if (STREAM_VOLUME_ALIAS[streamType] != streamType) { - index = rescaleIndex(index * 10, STREAM_VOLUME_ALIAS[streamType], streamType); - } else { - index *= 10; - } - streamState.mLastAudibleIndex = streamState.getValidIndex(index); + streamState.readSettings(); // unmute stream that was muted but is not affect by mute anymore if (streamState.muteCount() != 0 && !isStreamAffectedByMute(streamType)) { @@ -1253,7 +1259,7 @@ public class AudioService extends IAudioService.Stub { } // apply stream volume if (streamState.muteCount() == 0) { - setStreamVolumeIndex(streamType, streamState.mIndex); + streamState.applyAllVolumes(); } } @@ -1268,7 +1274,7 @@ public class AudioService extends IAudioService.Stub { } mForcedUseForComm = on ? AudioSystem.FORCE_SPEAKER : AudioSystem.FORCE_NONE; - sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SHARED_MSG, SENDMSG_QUEUE, + sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE, AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0); } @@ -1284,9 +1290,9 @@ public class AudioService extends IAudioService.Stub { } mForcedUseForComm = on ? AudioSystem.FORCE_BT_SCO : AudioSystem.FORCE_NONE; - sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SHARED_MSG, SENDMSG_QUEUE, + sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE, AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0); - sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SHARED_MSG, SENDMSG_QUEUE, + sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE, AudioSystem.FOR_RECORD, mForcedUseForComm, null, 0); } @@ -1526,7 +1532,7 @@ public class AudioService extends IAudioService.Stub { // without delay to reset the SCO audio state and clear SCO clients. // If we could get a proxy, send a delayed failure message that will reset our state // in case we don't receive onServiceConnected(). - sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED, 0, + sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED, SENDMSG_REPLACE, 0, 0, null, result ? BT_HEADSET_CNCT_TIMEOUT_MS : 0); return result; } @@ -1540,7 +1546,7 @@ public class AudioService extends IAudioService.Stub { if (mBluetoothHeadset != null) { if (!mBluetoothHeadset.stopVoiceRecognition( mBluetoothHeadsetDevice)) { - sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED, 0, + sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED, SENDMSG_REPLACE, 0, 0, null, 0); } } else if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL && @@ -1623,7 +1629,7 @@ public class AudioService extends IAudioService.Stub { } } if (!status) { - sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED, 0, + sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED, SENDMSG_REPLACE, 0, 0, null, 0); } } @@ -1668,11 +1674,12 @@ public class AudioService extends IAudioService.Stub { */ private boolean checkForRingerModeChange(int oldIndex, int direction, int streamType) { boolean adjustVolumeIndex = true; - int newRingerMode = mRingerMode; + int ringerMode = getRingerMode(); + int newRingerMode = ringerMode; int uiIndex = (oldIndex + 5) / 10; boolean vibeInSilent = System.getInt(mContentResolver, System.VIBRATE_IN_SILENT, 1) == 1; - if (mRingerMode == RINGER_MODE_NORMAL) { + if (ringerMode == RINGER_MODE_NORMAL) { if ((direction == AudioManager.ADJUST_LOWER) && (uiIndex <= 1)) { // enter silent mode if current index is the last audible one and not repeating a // volume key down @@ -1687,7 +1694,7 @@ public class AudioService extends IAudioService.Stub { adjustVolumeIndex = false; } } - } else if (mRingerMode == RINGER_MODE_VIBRATE) { + } else if (ringerMode == RINGER_MODE_VIBRATE) { if ((direction == AudioManager.ADJUST_LOWER)) { // Set it to silent, if it wasn't a long-press if (mPrevVolDirection != AudioManager.ADJUST_LOWER) { @@ -1706,9 +1713,7 @@ public class AudioService extends IAudioService.Stub { adjustVolumeIndex = false; } - if (newRingerMode != mRingerMode) { - setRingerMode(newRingerMode); - } + setRingerMode(newRingerMode); mPrevVolDirection = direction; @@ -1798,10 +1803,10 @@ public class AudioService extends IAudioService.Stub { } } - private void broadcastRingerMode() { + private void broadcastRingerMode(int ringerMode) { // Send sticky broadcast Intent broadcast = new Intent(AudioManager.RINGER_MODE_CHANGED_ACTION); - broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, mRingerMode); + broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, ringerMode); broadcast.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT | Intent.FLAG_RECEIVER_REPLACE_PENDING); long origCallerIdentityToken = Binder.clearCallingIdentity(); @@ -1820,17 +1825,9 @@ public class AudioService extends IAudioService.Stub { } // Message helper methods - private static int getMsg(int baseMsg, int streamType) { - return (baseMsg & 0xffff) | streamType << 16; - } - private static int getMsgBase(int msg) { - return msg & 0xffff; - } - - private static void sendMsg(Handler handler, int baseMsg, int streamType, + private static void sendMsg(Handler handler, int msg, int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) { - int msg = (streamType == SHARED_MSG) ? baseMsg : getMsg(baseMsg, streamType); if (existingMsgPolicy == SENDMSG_REPLACE) { handler.removeMessages(msg); @@ -1838,8 +1835,7 @@ public class AudioService extends IAudioService.Stub { return; } - handler - .sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delay); + handler.sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delay); } boolean checkAudioSettingsPermission(String method) { @@ -1854,6 +1850,22 @@ public class AudioService extends IAudioService.Stub { return false; } + private int getDeviceForStream(int stream) { + int device = AudioSystem.getDevicesForStream(stream); + if ((device & (device - 1)) != 0) { + // Multiple device selection is either: + // - speaker + one other device: give priority to speaker in this case. + // - one A2DP device + another device: happens with duplicated output. In this case + // retain the device on the A2DP output as the other must not correspond to an active + // selection if not the speaker. + if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) { + device = AudioSystem.DEVICE_OUT_SPEAKER; + } else { + device &= AudioSystem.DEVICE_OUT_ALL_A2DP; + } + } + return device; + } /////////////////////////////////////////////////////////////////////////// // Inner classes @@ -1865,54 +1877,127 @@ public class AudioService extends IAudioService.Stub { private String mVolumeIndexSettingName; private String mLastAudibleVolumeIndexSettingName; private int mIndexMax; - private int mIndex; - private int mLastAudibleIndex; - private ArrayList<VolumeDeathHandler> mDeathHandlers; //handles mute/solo requests client death + private final HashMap <Integer, Integer> mIndex = new HashMap <Integer, Integer>(); + private final HashMap <Integer, Integer> mLastAudibleIndex = + new HashMap <Integer, Integer>(); + private ArrayList<VolumeDeathHandler> mDeathHandlers; //handles mute/solo clients death private VolumeStreamState(String settingName, int streamType) { - setVolumeIndexSettingName(settingName); + mVolumeIndexSettingName = settingName; + mLastAudibleVolumeIndexSettingName = settingName + System.APPEND_FOR_LAST_AUDIBLE; mStreamType = streamType; - - final ContentResolver cr = mContentResolver; mIndexMax = MAX_STREAM_VOLUME[streamType]; - mIndex = Settings.System.getInt(cr, - mVolumeIndexSettingName, - AudioManager.DEFAULT_STREAM_VOLUME[streamType]); - mLastAudibleIndex = Settings.System.getInt(cr, - mLastAudibleVolumeIndexSettingName, - (mIndex > 0) ? mIndex : AudioManager.DEFAULT_STREAM_VOLUME[streamType]); AudioSystem.initStreamVolume(streamType, 0, mIndexMax); mIndexMax *= 10; - mIndex = getValidIndex(10 * mIndex); - mLastAudibleIndex = getValidIndex(10 * mLastAudibleIndex); - setStreamVolumeIndex(streamType, mIndex); + + readSettings(); + + applyAllVolumes(); + mDeathHandlers = new ArrayList<VolumeDeathHandler>(); } - public void setVolumeIndexSettingName(String settingName) { - mVolumeIndexSettingName = settingName; - mLastAudibleVolumeIndexSettingName = settingName + System.APPEND_FOR_LAST_AUDIBLE; + public String getSettingNameForDevice(boolean lastAudible, int device) { + String name = lastAudible ? + mLastAudibleVolumeIndexSettingName : + mVolumeIndexSettingName; + String suffix = AudioSystem.getDeviceName(device); + if (suffix.isEmpty()) { + return name; + } + return name + "_" + suffix; + } + + public void readSettings() { + int index = Settings.System.getInt(mContentResolver, + mVolumeIndexSettingName, + AudioManager.DEFAULT_STREAM_VOLUME[mStreamType]); + + mIndex.clear(); + mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, index); + + index = Settings.System.getInt(mContentResolver, + mLastAudibleVolumeIndexSettingName, + (index > 0) ? index : AudioManager.DEFAULT_STREAM_VOLUME[mStreamType]); + mLastAudibleIndex.clear(); + mLastAudibleIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, index); + + int remainingDevices = AudioSystem.DEVICE_OUT_ALL; + for (int i = 0; remainingDevices != 0; i++) { + int device = (1 << i); + if ((device & remainingDevices) == 0) { + continue; + } + remainingDevices &= ~device; + + // retrieve current volume for device + String name = getSettingNameForDevice(false, device); + index = Settings.System.getInt(mContentResolver, name, -1); + if (index == -1) { + continue; + } + mIndex.put(device, getValidIndex(10 * index)); + + // retrieve last audible volume for device + name = getSettingNameForDevice(true, device); + index = Settings.System.getInt(mContentResolver, name, -1); + mLastAudibleIndex.put(device, getValidIndex(10 * index)); + } } - public boolean adjustIndex(int deltaIndex) { - return setIndex(mIndex + deltaIndex * 10, true); + public void applyDeviceVolume(int device) { + AudioSystem.setStreamVolumeIndex(mStreamType, + (getIndex(device, false /* lastAudible */) + 5)/10, + device); } - public boolean setIndex(int index, boolean lastAudible) { - int oldIndex = mIndex; - mIndex = getValidIndex(index); + public void applyAllVolumes() { + // apply default volume first: by convention this will reset all + // devices volumes in audio policy manager to the supplied value + AudioSystem.setStreamVolumeIndex(mStreamType, + (getIndex(AudioSystem.DEVICE_OUT_DEFAULT, false /* lastAudible */) + 5)/10, + AudioSystem.DEVICE_OUT_DEFAULT); + // then apply device specific volumes + Set set = mIndex.entrySet(); + Iterator i = set.iterator(); + while (i.hasNext()) { + Map.Entry entry = (Map.Entry)i.next(); + int device = ((Integer)entry.getKey()).intValue(); + if (device != AudioSystem.DEVICE_OUT_DEFAULT) { + AudioSystem.setStreamVolumeIndex(mStreamType, + ((Integer)entry.getValue() + 5)/10, + device); + } + } + } + + public boolean adjustIndex(int deltaIndex, int device) { + return setIndex(getIndex(device, + false /* lastAudible */) + deltaIndex * 10, + device, + true /* lastAudible */); + } - if (oldIndex != mIndex) { + public boolean setIndex(int index, int device, boolean lastAudible) { + int oldIndex = getIndex(device, false /* lastAudible */); + index = getValidIndex(index); + mIndex.put(device, getValidIndex(index)); + + if (oldIndex != index) { if (lastAudible) { - mLastAudibleIndex = mIndex; + mLastAudibleIndex.put(device, index); } // Apply change to all streams using this one as alias int numStreamTypes = AudioSystem.getNumStreamTypes(); for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { if (streamType != mStreamType && STREAM_VOLUME_ALIAS[streamType] == mStreamType) { - mStreamStates[streamType].setIndex(rescaleIndex(mIndex, mStreamType, streamType), lastAudible); + mStreamStates[streamType].setIndex(rescaleIndex(index, + mStreamType, + streamType), + device, + lastAudible); } } return true; @@ -1921,12 +2006,29 @@ public class AudioService extends IAudioService.Stub { } } - public void setLastAudibleIndex(int index) { - mLastAudibleIndex = getValidIndex(index); + public int getIndex(int device, boolean lastAudible) { + HashMap <Integer, Integer> indexes; + if (lastAudible) { + indexes = mLastAudibleIndex; + } else { + indexes = mIndex; + } + Integer index = indexes.get(device); + if (index == null) { + // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT + index = indexes.get(AudioSystem.DEVICE_OUT_DEFAULT); + } + return index.intValue(); + } + + public void setLastAudibleIndex(int index, int device) { + mLastAudibleIndex.put(device, getValidIndex(index)); } - public void adjustLastAudibleIndex(int deltaIndex) { - setLastAudibleIndex(mLastAudibleIndex + deltaIndex * 10); + public void adjustLastAudibleIndex(int deltaIndex, int device) { + setLastAudibleIndex(getIndex(device, + true /* lastAudible */) + deltaIndex * 10, + device); } public int getMaxIndex() { @@ -1971,10 +2073,20 @@ public class AudioService extends IAudioService.Stub { mICallback.linkToDeath(this, 0); } mDeathHandlers.add(this); - // If the stream is not yet muted by any client, set lvel to 0 + // If the stream is not yet muted by any client, set level to 0 if (muteCount() == 0) { - setIndex(0, false); - sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, mStreamType, SENDMSG_NOOP, 0, 0, + Set set = mIndex.entrySet(); + Iterator i = set.iterator(); + while (i.hasNext()) { + Map.Entry entry = (Map.Entry)i.next(); + int device = ((Integer)entry.getKey()).intValue(); + setIndex(0, device, false /* lastAudible */); + } + sendMsg(mAudioHandler, + MSG_SET_ALL_VOLUMES, + SENDMSG_NOOP, + 0, + 0, VolumeStreamState.this, 0); } } catch (RemoteException e) { @@ -2002,9 +2114,23 @@ public class AudioService extends IAudioService.Stub { if (muteCount() == 0) { // If the stream is not muted any more, restore it's volume if // ringer mode allows it - if (!isStreamAffectedByRingerMode(mStreamType) || mRingerMode == AudioManager.RINGER_MODE_NORMAL) { - setIndex(mLastAudibleIndex, false); - sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, mStreamType, SENDMSG_NOOP, 0, 0, + if (!isStreamAffectedByRingerMode(mStreamType) || + mRingerMode == AudioManager.RINGER_MODE_NORMAL) { + Set set = mIndex.entrySet(); + Iterator i = set.iterator(); + while (i.hasNext()) { + Map.Entry entry = (Map.Entry)i.next(); + int device = ((Integer)entry.getKey()).intValue(); + setIndex(getIndex(device, + true /* lastAudible */), + device, + false /* lastAudible */); + } + sendMsg(mAudioHandler, + MSG_SET_ALL_VOLUMES, + SENDMSG_NOOP, + 0, + 0, VolumeStreamState.this, 0); } } @@ -2083,38 +2209,63 @@ public class AudioService extends IAudioService.Stub { /** Handles internal volume messages in separate volume thread. */ private class AudioHandler extends Handler { - private void setSystemVolume(VolumeStreamState streamState) { + private void setDeviceVolume(VolumeStreamState streamState, int device) { - // Adjust volume - setStreamVolumeIndex(streamState.mStreamType, streamState.mIndex); + // Apply volume + streamState.applyDeviceVolume(device); // Apply change to all streams using this one as alias int numStreamTypes = AudioSystem.getNumStreamTypes(); for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { if (streamType != streamState.mStreamType && - STREAM_VOLUME_ALIAS[streamType] == streamState.mStreamType) { - setStreamVolumeIndex(streamType, mStreamStates[streamType].mIndex); + STREAM_VOLUME_ALIAS[streamType] == streamState.mStreamType) { + mStreamStates[streamType].applyDeviceVolume(device); } } // Post a persist volume msg - sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, streamState.mStreamType, - SENDMSG_REPLACE, 1, 1, streamState, PERSIST_DELAY); + sendMsg(mAudioHandler, + MSG_PERSIST_VOLUME, + SENDMSG_REPLACE, + PERSIST_CURRENT|PERSIST_LAST_AUDIBLE, + device, + streamState, + PERSIST_DELAY); + } - private void persistVolume(VolumeStreamState streamState, boolean current, boolean lastAudible) { - if (current) { - System.putInt(mContentResolver, streamState.mVolumeIndexSettingName, - (streamState.mIndex + 5)/ 10); + private void setAllVolumes(VolumeStreamState streamState) { + + // Apply volume + streamState.applyAllVolumes(); + + // Apply change to all streams using this one as alias + int numStreamTypes = AudioSystem.getNumStreamTypes(); + for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { + if (streamType != streamState.mStreamType && + STREAM_VOLUME_ALIAS[streamType] == streamState.mStreamType) { + mStreamStates[streamType].applyAllVolumes(); + } } - if (lastAudible) { - System.putInt(mContentResolver, streamState.mLastAudibleVolumeIndexSettingName, - (streamState.mLastAudibleIndex + 5) / 10); + } + + private void persistVolume(VolumeStreamState streamState, + int persistType, + int device) { + if ((persistType & PERSIST_CURRENT) != 0) { + System.putInt(mContentResolver, + streamState.getSettingNameForDevice(false /* lastAudible */, device), + (streamState.getIndex(device, false /* lastAudible */) + 5)/ 10); + } + if ((persistType & PERSIST_LAST_AUDIBLE) != 0) { + System.putInt(mContentResolver, + streamState.getSettingNameForDevice(true /* lastAudible */, device), + (streamState.getIndex(device, true /* lastAudible */) + 5) / 10); } } - private void persistRingerMode() { - System.putInt(mContentResolver, System.MODE_RINGER, mRingerMode); + private void persistRingerMode(int ringerMode) { + System.putInt(mContentResolver, System.MODE_RINGER, ringerMode); } private void persistVibrateSetting() { @@ -2138,32 +2289,30 @@ public class AudioService extends IAudioService.Stub { mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1], volFloat, volFloat, 0, 0, 1.0f); } else { MediaPlayer mediaPlayer = new MediaPlayer(); - if (mediaPlayer != null) { - try { - String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH + SOUND_EFFECT_FILES[SOUND_EFFECT_FILES_MAP[effectType][0]]; - mediaPlayer.setDataSource(filePath); - mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM); - mediaPlayer.prepare(); - mediaPlayer.setVolume(volFloat, volFloat); - mediaPlayer.setOnCompletionListener(new OnCompletionListener() { - public void onCompletion(MediaPlayer mp) { - cleanupPlayer(mp); - } - }); - mediaPlayer.setOnErrorListener(new OnErrorListener() { - public boolean onError(MediaPlayer mp, int what, int extra) { - cleanupPlayer(mp); - return true; - } - }); - mediaPlayer.start(); - } catch (IOException ex) { - Log.w(TAG, "MediaPlayer IOException: "+ex); - } catch (IllegalArgumentException ex) { - Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex); - } catch (IllegalStateException ex) { - Log.w(TAG, "MediaPlayer IllegalStateException: "+ex); - } + try { + String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH + SOUND_EFFECT_FILES[SOUND_EFFECT_FILES_MAP[effectType][0]]; + mediaPlayer.setDataSource(filePath); + mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM); + mediaPlayer.prepare(); + mediaPlayer.setVolume(volFloat, volFloat); + mediaPlayer.setOnCompletionListener(new OnCompletionListener() { + public void onCompletion(MediaPlayer mp) { + cleanupPlayer(mp); + } + }); + mediaPlayer.setOnErrorListener(new OnErrorListener() { + public boolean onError(MediaPlayer mp, int what, int extra) { + cleanupPlayer(mp); + return true; + } + }); + mediaPlayer.start(); + } catch (IOException ex) { + Log.w(TAG, "MediaPlayer IOException: "+ex); + } catch (IllegalArgumentException ex) { + Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex); + } catch (IllegalStateException ex) { + Log.w(TAG, "MediaPlayer IllegalStateException: "+ex); } } } @@ -2191,20 +2340,25 @@ public class AudioService extends IAudioService.Stub { @Override public void handleMessage(Message msg) { - int baseMsgWhat = getMsgBase(msg.what); - switch (baseMsgWhat) { + switch (msg.what) { + + case MSG_SET_DEVICE_VOLUME: + setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1); + break; - case MSG_SET_SYSTEM_VOLUME: - setSystemVolume((VolumeStreamState) msg.obj); + case MSG_SET_ALL_VOLUMES: + setAllVolumes((VolumeStreamState) msg.obj); break; case MSG_PERSIST_VOLUME: - persistVolume((VolumeStreamState) msg.obj, (msg.arg1 != 0), (msg.arg2 != 0)); + persistVolume((VolumeStreamState) msg.obj, msg.arg1, msg.arg2); break; case MSG_PERSIST_RINGER_MODE: - persistRingerMode(); + // note that the value persisted is the current ringer mode, not the + // value of ringer mode as of the time the request was made to persist + persistRingerMode(getRingerMode()); break; case MSG_PERSIST_VIBRATE_SETTING: @@ -2217,7 +2371,7 @@ public class AudioService extends IAudioService.Stub { // Force creation of new IAudioFlinger interface so that we are notified // when new media_server process is back to life. AudioSystem.setErrorCallback(mAudioSystemCallback); - sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SHARED_MSG, SENDMSG_NOOP, 0, 0, + sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SENDMSG_NOOP, 0, 0, null, 500); } break; @@ -2234,7 +2388,7 @@ public class AudioService extends IAudioService.Stub { synchronized (mConnectedDevices) { Set set = mConnectedDevices.entrySet(); Iterator i = set.iterator(); - while(i.hasNext()){ + while (i.hasNext()) { Map.Entry device = (Map.Entry)i.next(); AudioSystem.setDeviceConnectionState( ((Integer)device.getKey()).intValue(), @@ -2252,15 +2406,10 @@ public class AudioService extends IAudioService.Stub { // Restore stream volumes int numStreamTypes = AudioSystem.getNumStreamTypes(); for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { - int index; VolumeStreamState streamState = mStreamStates[streamType]; AudioSystem.initStreamVolume(streamType, 0, (streamState.mIndexMax + 5) / 10); - if (streamState.muteCount() == 0) { - index = streamState.mIndex; - } else { - index = 0; - } - setStreamVolumeIndex(streamType, index); + + streamState.applyAllVolumes(); } // Restore ringer mode @@ -2320,6 +2469,10 @@ public class AudioService extends IAudioService.Stub { @Override public void onChange(boolean selfChange) { super.onChange(selfChange); + // FIXME This synchronized is not necessary if mSettingsLock only protects mRingerMode. + // However there appear to be some missing locks around mRingerModeMutedStreams + // and mRingerModeAffectedStreams, so will leave this synchronized for now. + // mRingerModeMutedStreams and mMuteAffectedStreams are safe (only accessed once). synchronized (mSettingsLock) { int ringerModeAffectedStreams = Settings.System.getInt(mContentResolver, Settings.System.MODE_RINGER_STREAMS_AFFECTED, @@ -2666,7 +2819,7 @@ public class AudioService extends IAudioService.Stub { } } else if (action.equals(Intent.ACTION_BOOT_COMPLETED)) { mBootCompleted = true; - sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SHARED_MSG, SENDMSG_NOOP, + sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_NOOP, 0, 0, null, 0); mKeyguardManager = @@ -2707,9 +2860,10 @@ public class AudioService extends IAudioService.Stub { //========================================================================================== /* constant to identify focus stack entry that is used to hold the focus while the phone - * is ringing or during a call + * is ringing or during a call. Used by com.android.internal.telephony.CallManager when + * entering and exiting calls. */ - private final static String IN_VOICE_COMM_FOCUS_ID = "AudioFocus_For_Phone_Ring_And_Calls"; + public final static String IN_VOICE_COMM_FOCUS_ID = "AudioFocus_For_Phone_Ring_And_Calls"; private final static Object mAudioFocusLock = new Object(); @@ -2791,7 +2945,7 @@ public class AudioService extends IAudioService.Stub { } } - private Stack<FocusStackEntry> mFocusStack = new Stack<FocusStackEntry>(); + private final Stack<FocusStackEntry> mFocusStack = new Stack<FocusStackEntry>(); /** * Helper function: @@ -3168,7 +3322,7 @@ public class AudioService extends IAudioService.Stub { * synchronized on mRCStack, but also BEFORE on mFocusLock as any change in either * stack, audio focus or RC, can lead to a change in the remote control display */ - private Stack<RemoteControlStackEntry> mRCStack = new Stack<RemoteControlStackEntry>(); + private final Stack<RemoteControlStackEntry> mRCStack = new Stack<RemoteControlStackEntry>(); /** * Helper function: diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index 95d93b2..3080497 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -27,7 +27,7 @@ package android.media; */ public class AudioSystem { - /* FIXME: Need to finalize this and correlate with native layer */ + /* These values must be kept in sync with AudioSystem.h */ /* * If these are modified, please also update Settings.System.VOLUME_SETTINGS * and attrs.xml and AudioManager.java. @@ -183,6 +183,7 @@ public class AudioSystem } } + /* * AudioPolicyService methods */ @@ -202,6 +203,23 @@ public class AudioSystem public static final int DEVICE_OUT_ANLG_DOCK_HEADSET = 0x800; public static final int DEVICE_OUT_DGTL_DOCK_HEADSET = 0x1000; public static final int DEVICE_OUT_DEFAULT = 0x8000; + public static final int DEVICE_OUT_ALL = (DEVICE_OUT_EARPIECE | + DEVICE_OUT_SPEAKER | + DEVICE_OUT_WIRED_HEADSET | + DEVICE_OUT_WIRED_HEADPHONE | + DEVICE_OUT_BLUETOOTH_SCO | + DEVICE_OUT_BLUETOOTH_SCO_HEADSET | + DEVICE_OUT_BLUETOOTH_SCO_CARKIT | + DEVICE_OUT_BLUETOOTH_A2DP | + DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES | + DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER | + DEVICE_OUT_AUX_DIGITAL | + DEVICE_OUT_ANLG_DOCK_HEADSET | + DEVICE_OUT_DGTL_DOCK_HEADSET | + DEVICE_OUT_DEFAULT); + public static final int DEVICE_OUT_ALL_A2DP = (DEVICE_OUT_BLUETOOTH_A2DP | + DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES | + DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER); // input devices public static final int DEVICE_IN_COMMUNICATION = 0x10000; public static final int DEVICE_IN_AMBIENT = 0x20000; @@ -218,6 +236,54 @@ public class AudioSystem public static final int DEVICE_STATE_AVAILABLE = 1; private static final int NUM_DEVICE_STATES = 1; + public static final String DEVICE_OUT_EARPIECE_NAME = "earpiece"; + public static final String DEVICE_OUT_SPEAKER_NAME = "speaker"; + public static final String DEVICE_OUT_WIRED_HEADSET_NAME = "headset"; + public static final String DEVICE_OUT_WIRED_HEADPHONE_NAME = "headphone"; + public static final String DEVICE_OUT_BLUETOOTH_SCO_NAME = "bt_sco"; + public static final String DEVICE_OUT_BLUETOOTH_SCO_HEADSET_NAME = "bt_sco_hs"; + public static final String DEVICE_OUT_BLUETOOTH_SCO_CARKIT_NAME = "bt_sco_carkit"; + public static final String DEVICE_OUT_BLUETOOTH_A2DP_NAME = "bt_a2dp"; + public static final String DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES_NAME = "bt_a2dp_hp"; + public static final String DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER_NAME = "bt_a2dp_spk"; + public static final String DEVICE_OUT_AUX_DIGITAL_NAME = "aux_digital"; + public static final String DEVICE_OUT_ANLG_DOCK_HEADSET_NAME = "analog_dock"; + public static final String DEVICE_OUT_DGTL_DOCK_HEADSET_NAME = "digital_dock"; + + public static String getDeviceName(int device) + { + switch(device) { + case DEVICE_OUT_EARPIECE: + return DEVICE_OUT_EARPIECE_NAME; + case DEVICE_OUT_SPEAKER: + return DEVICE_OUT_SPEAKER_NAME; + case DEVICE_OUT_WIRED_HEADSET: + return DEVICE_OUT_WIRED_HEADSET_NAME; + case DEVICE_OUT_WIRED_HEADPHONE: + return DEVICE_OUT_WIRED_HEADPHONE_NAME; + case DEVICE_OUT_BLUETOOTH_SCO: + return DEVICE_OUT_BLUETOOTH_SCO_NAME; + case DEVICE_OUT_BLUETOOTH_SCO_HEADSET: + return DEVICE_OUT_BLUETOOTH_SCO_HEADSET_NAME; + case DEVICE_OUT_BLUETOOTH_SCO_CARKIT: + return DEVICE_OUT_BLUETOOTH_SCO_CARKIT_NAME; + case DEVICE_OUT_BLUETOOTH_A2DP: + return DEVICE_OUT_BLUETOOTH_A2DP_NAME; + case DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES: + return DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES_NAME; + case DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER: + return DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER_NAME; + case DEVICE_OUT_AUX_DIGITAL: + return DEVICE_OUT_AUX_DIGITAL_NAME; + case DEVICE_OUT_ANLG_DOCK_HEADSET: + return DEVICE_OUT_ANLG_DOCK_HEADSET_NAME; + case DEVICE_OUT_DGTL_DOCK_HEADSET: + return DEVICE_OUT_DGTL_DOCK_HEADSET_NAME; + default: + return ""; + } + } + // phone state, match audio_mode??? public static final int PHONE_STATE_OFFCALL = 0; public static final int PHONE_STATE_RINGING = 1; @@ -247,11 +313,10 @@ public class AudioSystem public static native int setDeviceConnectionState(int device, int state, String device_address); public static native int getDeviceConnectionState(int device, String device_address); public static native int setPhoneState(int state); - public static native int setRingerMode(int mode, int mask); public static native int setForceUse(int usage, int config); public static native int getForceUse(int usage); public static native int initStreamVolume(int stream, int indexMin, int indexMax); - public static native int setStreamVolumeIndex(int stream, int index); - public static native int getStreamVolumeIndex(int stream); + public static native int setStreamVolumeIndex(int stream, int index, int device); + public static native int getStreamVolumeIndex(int stream, int device); public static native int getDevicesForStream(int stream); } diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java index 4f9eb2b..7d4c282 100644 --- a/media/java/android/media/AudioTrack.java +++ b/media/java/android/media/AudioTrack.java @@ -29,7 +29,7 @@ import android.util.Log; /** * The AudioTrack class manages and plays a single audio resource for Java applications. - * It allows to stream PCM audio buffers to the audio hardware for playback. This is + * It allows streaming PCM audio buffers to the audio hardware for playback. This is * achieved by "pushing" the data to the AudioTrack object using one of the * {@link #write(byte[], int, int)} and {@link #write(short[], int, int)} methods. * @@ -46,7 +46,7 @@ import android.util.Log; * <li>received or generated while previously queued audio is playing.</li> * </ul> * - * The static mode is to be chosen when dealing with short sounds that fit in memory and + * The static mode should be chosen when dealing with short sounds that fit in memory and * that need to be played with the smallest latency possible. The static mode will * therefore be preferred for UI and game sounds that are played often, and with the * smallest overhead possible. @@ -57,7 +57,7 @@ import android.util.Log; * For an AudioTrack using the static mode, this size is the maximum size of the sound that can * be played from it.<br> * For the streaming mode, data will be written to the hardware in chunks of - * sizes inferior to the total buffer size. + * sizes less than or equal to the total buffer size. */ public class AudioTrack { @@ -76,6 +76,7 @@ public class AudioTrack /** indicates AudioTrack state is playing */ public static final int PLAYSTATE_PLAYING = 3; // matches SL_PLAYSTATE_PLAYING + // keep these values in sync with android_media_AudioTrack.cpp /** * Creation mode where audio data is transferred from Java to the native layer * only once before the audio starts playing. @@ -180,7 +181,7 @@ public class AudioTrack /** * The audio data sampling rate in Hz. */ - private int mSampleRate = 22050; + private int mSampleRate; // initialized by all constructors /** * The number of audio output channels (1 is mono, 2 is stereo). */ @@ -193,8 +194,9 @@ public class AudioTrack /** * The type of the audio stream to play. See * {@link AudioManager#STREAM_VOICE_CALL}, {@link AudioManager#STREAM_SYSTEM}, - * {@link AudioManager#STREAM_RING}, {@link AudioManager#STREAM_MUSIC} and - * {@link AudioManager#STREAM_ALARM} + * {@link AudioManager#STREAM_RING}, {@link AudioManager#STREAM_MUSIC}, + * {@link AudioManager#STREAM_ALARM}, {@link AudioManager#STREAM_NOTIFICATION}, and + * {@link AudioManager#STREAM_DTMF}. */ private int mStreamType = AudioManager.STREAM_MUSIC; /** @@ -240,10 +242,9 @@ public class AudioTrack * Class constructor. * @param streamType the type of the audio stream. See * {@link AudioManager#STREAM_VOICE_CALL}, {@link AudioManager#STREAM_SYSTEM}, - * {@link AudioManager#STREAM_RING}, {@link AudioManager#STREAM_MUSIC} and - * {@link AudioManager#STREAM_ALARM} - * @param sampleRateInHz the sample rate expressed in Hertz. Examples of rates are (but - * not limited to) 44100, 22050 and 11025. + * {@link AudioManager#STREAM_RING}, {@link AudioManager#STREAM_MUSIC}, + * {@link AudioManager#STREAM_ALARM}, and {@link AudioManager#STREAM_NOTIFICATION}. + * @param sampleRateInHz the sample rate expressed in Hertz. * @param channelConfig describes the configuration of the audio channels. * See {@link AudioFormat#CHANNEL_OUT_MONO} and * {@link AudioFormat#CHANNEL_OUT_STEREO} @@ -275,14 +276,15 @@ public class AudioTrack * and media players in the same session and not to the output mix. * When an AudioTrack is created without specifying a session, it will create its own session * which can be retreived by calling the {@link #getAudioSessionId()} method. - * If a session ID is provided, this AudioTrack will share effects attached to this session - * with all other media players or audio tracks in the same session. + * If a non-zero session ID is provided, this AudioTrack will share effects attached to this + * session + * with all other media players or audio tracks in the same session, otherwise a new session + * will be created for this track if none is supplied. * @param streamType the type of the audio stream. See * {@link AudioManager#STREAM_VOICE_CALL}, {@link AudioManager#STREAM_SYSTEM}, - * {@link AudioManager#STREAM_RING}, {@link AudioManager#STREAM_MUSIC} and - * {@link AudioManager#STREAM_ALARM} - * @param sampleRateInHz the sample rate expressed in Hertz. Examples of rates are (but - * not limited to) 44100, 22050 and 11025. + * {@link AudioManager#STREAM_RING}, {@link AudioManager#STREAM_MUSIC}, + * {@link AudioManager#STREAM_ALARM}, and {@link AudioManager#STREAM_NOTIFICATION}. + * @param sampleRateInHz the sample rate expressed in Hertz. * @param channelConfig describes the configuration of the audio channels. * See {@link AudioFormat#CHANNEL_OUT_MONO} and * {@link AudioFormat#CHANNEL_OUT_STEREO} @@ -304,8 +306,8 @@ public class AudioTrack int bufferSizeInBytes, int mode, int sessionId) throws IllegalArgumentException { mState = STATE_UNINITIALIZED; - - // remember which looper is associated with the AudioTrack instanciation + + // remember which looper is associated with the AudioTrack instantiation if ((mInitializationLooper = Looper.myLooper()) == null) { mInitializationLooper = Looper.getMainLooper(); } @@ -365,7 +367,7 @@ public class AudioTrack } //-------------- - // sample rate + // sample rate, note these values are subject to change if ( (sampleRateInHz < 4000) || (sampleRateInHz > 48000) ) { throw (new IllegalArgumentException(sampleRateInHz + "Hz is not a supported sample rate.")); @@ -449,7 +451,7 @@ public class AudioTrack // AudioTrack subclasses too. try { stop(); - } catch(IllegalStateException ise) { + } catch(IllegalStateException ise) { // don't raise an exception, we're releasing the resources. } native_release(); @@ -488,7 +490,7 @@ public class AudioTrack public int getSampleRate() { return mSampleRate; } - + /** * Returns the current playback rate in Hz. */ @@ -508,7 +510,8 @@ public class AudioTrack * Returns the type of audio stream this AudioTrack is configured for. * Compare the result against {@link AudioManager#STREAM_VOICE_CALL}, * {@link AudioManager#STREAM_SYSTEM}, {@link AudioManager#STREAM_RING}, - * {@link AudioManager#STREAM_MUSIC} or {@link AudioManager#STREAM_ALARM} + * {@link AudioManager#STREAM_MUSIC}, {@link AudioManager#STREAM_ALARM}, + * {@link AudioManager#STREAM_NOTIFICATION}, or {@link AudioManager#STREAM_DTMF}. */ public int getStreamType() { return mStreamType; @@ -590,22 +593,22 @@ public class AudioTrack static public int getNativeOutputSampleRate(int streamType) { return native_get_output_sample_rate(streamType); } - + /** * Returns the minimum buffer size required for the successful creation of an AudioTrack * object to be created in the {@link #MODE_STREAM} mode. Note that this size doesn't * guarantee a smooth playback under load, and higher values should be chosen according to - * the expected frequency at which the buffer will be refilled with additional data to play. + * the expected frequency at which the buffer will be refilled with additional data to play. * @param sampleRateInHz the sample rate expressed in Hertz. - * @param channelConfig describes the configuration of the audio channels. + * @param channelConfig describes the configuration of the audio channels. * See {@link AudioFormat#CHANNEL_OUT_MONO} and * {@link AudioFormat#CHANNEL_OUT_STEREO} - * @param audioFormat the format in which the audio data is represented. - * See {@link AudioFormat#ENCODING_PCM_16BIT} and + * @param audioFormat the format in which the audio data is represented. + * See {@link AudioFormat#ENCODING_PCM_16BIT} and * {@link AudioFormat#ENCODING_PCM_8BIT} * @return {@link #ERROR_BAD_VALUE} if an invalid parameter was passed, - * or {@link #ERROR} if the implementation was unable to query the hardware for its output - * properties, + * or {@link #ERROR} if the implementation was unable to query the hardware for its output + * properties, * or the minimum buffer size expressed in bytes. */ static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) { @@ -623,18 +626,19 @@ public class AudioTrack loge("getMinBufferSize(): Invalid channel configuration."); return AudioTrack.ERROR_BAD_VALUE; } - - if ((audioFormat != AudioFormat.ENCODING_PCM_16BIT) + + if ((audioFormat != AudioFormat.ENCODING_PCM_16BIT) && (audioFormat != AudioFormat.ENCODING_PCM_8BIT)) { loge("getMinBufferSize(): Invalid audio format."); return AudioTrack.ERROR_BAD_VALUE; } - + + // sample rate, note these values are subject to change if ( (sampleRateInHz < 4000) || (sampleRateInHz > 48000) ) { loge("getMinBufferSize(): " + sampleRateInHz +"Hz is not a supported sample rate."); return AudioTrack.ERROR_BAD_VALUE; } - + int size = native_get_min_buff_size(sampleRateInHz, channelCount, audioFormat); if ((size == -1) || (size == 0)) { loge("getMinBufferSize(): error querying hardware"); @@ -667,7 +671,7 @@ public class AudioTrack public void setPlaybackPositionUpdateListener(OnPlaybackPositionUpdateListener listener) { setPlaybackPositionUpdateListener(listener, null); } - + /** * Sets the listener the AudioTrack notifies when a previously set marker is reached or * for each periodic playback head position update. @@ -676,7 +680,7 @@ public class AudioTrack * @param listener * @param handler the Handler that will receive the event notification messages. */ - public void setPlaybackPositionUpdateListener(OnPlaybackPositionUpdateListener listener, + public void setPlaybackPositionUpdateListener(OnPlaybackPositionUpdateListener listener, Handler handler) { synchronized (mPositionListenerLock) { mPositionListener = listener; @@ -684,7 +688,7 @@ public class AudioTrack if (listener != null) { mEventHandlerDelegate = new NativeEventHandlerDelegate(this, handler); } - + } @@ -728,7 +732,7 @@ public class AudioTrack * the audio data will be consumed and played back, not the original sampling rate of the * content. Setting it to half the sample rate of the content will cause the playback to * last twice as long, but will also result in a negative pitch shift. - * The valid sample rate range if from 1Hz to twice the value returned by + * The valid sample rate range is from 1Hz to twice the value returned by * {@link #getNativeOutputSampleRate(int)}. * @param sampleRateInHz the sample rate expressed in Hz * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE}, @@ -836,7 +840,10 @@ public class AudioTrack /** * Stops playing the audio data. - * + * When used on an instance created in {@link #MODE_STREAM} mode, audio will stop playing + * after the last buffer that was written has been played. For an immediate stop, use + * {@link #pause()}, followed by {@link #flush()} to discard audio data that hasn't been played + * back yet. * @throws IllegalStateException */ public void stop() @@ -855,7 +862,7 @@ public class AudioTrack /** * Pauses the playback of the audio data. Data that has not been played * back will not be discarded. Subsequent calls to {@link #play} will play - * this data back. + * this data back. See {@link #flush()} to discard this data. * * @throws IllegalStateException */ @@ -906,7 +913,7 @@ public class AudioTrack * the parameters don't resolve to valid data and indexes. */ - public int write(byte[] audioData,int offsetInBytes, int sizeInBytes) { + public int write(byte[] audioData, int offsetInBytes, int sizeInBytes) { if ((mDataLoadMode == MODE_STATIC) && (mState == STATE_NO_STATIC_DATA) && (sizeInBytes > 0)) { @@ -917,7 +924,7 @@ public class AudioTrack return ERROR_INVALID_OPERATION; } - if ( (audioData == null) || (offsetInBytes < 0 ) || (sizeInBytes < 0) + if ( (audioData == null) || (offsetInBytes < 0 ) || (sizeInBytes < 0) || (offsetInBytes + sizeInBytes > audioData.length)) { return ERROR_BAD_VALUE; } @@ -948,12 +955,12 @@ public class AudioTrack && (sizeInShorts > 0)) { mState = STATE_INITIALIZED; } - + if (mState != STATE_INITIALIZED) { return ERROR_INVALID_OPERATION; } - if ( (audioData == null) || (offsetInShorts < 0 ) || (sizeInShorts < 0) + if ( (audioData == null) || (offsetInShorts < 0 ) || (sizeInShorts < 0) || (offsetInShorts + sizeInShorts > audioData.length)) { return ERROR_BAD_VALUE; } @@ -1012,8 +1019,8 @@ public class AudioTrack * <p>Note that the passed level value is a raw scalar. UI controls should be scaled * logarithmically: the gain applied by audio framework ranges from -72dB to 0dB, * so an appropriate conversion from linear UI input x to level is: - * x == 0 -> level = 0 - * 0 < x <= R -> level = 10^(72*(x-R)/20/R) + * x == 0 -> level = 0 + * 0 < x <= R -> level = 10^(72*(x-R)/20/R) * * @param level send level scalar * @return error code or success, see {@link #SUCCESS}, @@ -1047,7 +1054,7 @@ public class AudioTrack * by the playback head. */ void onMarkerReached(AudioTrack track); - + /** * Called on the listener to periodically notify it that the playback head has reached * a multiple of the notification period. @@ -1062,11 +1069,11 @@ public class AudioTrack /** * Helper class to handle the forwarding of native events to the appropriate listener * (potentially) handled in a different thread - */ + */ private class NativeEventHandlerDelegate { private final AudioTrack mAudioTrack; private final Handler mHandler; - + NativeEventHandlerDelegate(AudioTrack track, Handler handler) { mAudioTrack = track; // find the looper for our new event handler @@ -1077,7 +1084,7 @@ public class AudioTrack // no given handler, use the looper the AudioTrack was created in looper = mInitializationLooper; } - + // construct the event handler with this looper if (looper != null) { // implement the event handler delegate @@ -1111,9 +1118,9 @@ public class AudioTrack }; } else { mHandler = null; - } + } } - + Handler getHandler() { return mHandler; } @@ -1133,7 +1140,7 @@ public class AudioTrack } if (track.mEventHandlerDelegate != null) { - Message m = + Message m = track.mEventHandlerDelegate.getHandler().obtainMessage(what, arg1, arg2, obj); track.mEventHandlerDelegate.getHandler().sendMessage(m); } diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java index 925f965..9d6c9f6 100644 --- a/media/java/android/media/ExifInterface.java +++ b/media/java/android/media/ExifInterface.java @@ -111,7 +111,7 @@ public class ExifInterface { // there can only be one user at a time for the native functions (and // they cannot keep state in the native code across function calls). We // use sLock to serialize the accesses. - private static Object sLock = new Object(); + private static final Object sLock = new Object(); /** * Reads Exif tags from the specified JPEG file. diff --git a/media/java/android/media/MediaFile.java b/media/java/android/media/MediaFile.java index e275aa6..7f7e284 100644 --- a/media/java/android/media/MediaFile.java +++ b/media/java/android/media/MediaFile.java @@ -120,18 +120,18 @@ public class MediaFile { } } - private static HashMap<String, MediaFileType> sFileTypeMap + private static final HashMap<String, MediaFileType> sFileTypeMap = new HashMap<String, MediaFileType>(); - private static HashMap<String, Integer> sMimeTypeMap + private static final HashMap<String, Integer> sMimeTypeMap = new HashMap<String, Integer>(); // maps file extension to MTP format code - private static HashMap<String, Integer> sFileTypeToFormatMap + private static final HashMap<String, Integer> sFileTypeToFormatMap = new HashMap<String, Integer>(); // maps mime type to MTP format code - private static HashMap<String, Integer> sMimeTypeToFormatMap + private static final HashMap<String, Integer> sMimeTypeToFormatMap = new HashMap<String, Integer>(); // maps MTP format code to mime type - private static HashMap<Integer, String> sFormatToMimeTypeMap + private static final HashMap<Integer, String> sFormatToMimeTypeMap = new HashMap<Integer, String>(); static void addFileType(String extension, int fileType, String mimeType) { diff --git a/media/java/android/media/MediaInserter.java b/media/java/android/media/MediaInserter.java index a998407..e92c710 100644 --- a/media/java/android/media/MediaInserter.java +++ b/media/java/android/media/MediaInserter.java @@ -32,7 +32,7 @@ import java.util.List; * {@hide} */ public class MediaInserter { - private HashMap<Uri, List<ContentValues>> mRowMap = + private final HashMap<Uri, List<ContentValues>> mRowMap = new HashMap<Uri, List<ContentValues>>(); private IContentProvider mProvider; diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index 8d71dcf..4c70e9d 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -1735,6 +1735,9 @@ public class MediaPlayer /** * Called to indicate the video size * + * The video size (width and height) could be 0 if there was no video, + * no display surface was set, or the value was not determined yet. + * * @param mp the MediaPlayer associated with this callback * @param width the width of the video * @param height the height of the video diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java index 08e6032..85d99c1 100644 --- a/media/java/android/media/MediaRecorder.java +++ b/media/java/android/media/MediaRecorder.java @@ -138,10 +138,13 @@ public class MediaRecorder */ public final class AudioSource { /* Do not change these values without updating their counterparts - * in include/media/mediarecorder.h! + * in system/core/include/system/audio.h! */ private AudioSource() {} + + /** Default audio source **/ public static final int DEFAULT = 0; + /** Microphone audio source */ public static final int MIC = 1; @@ -201,18 +204,24 @@ public class MediaRecorder /** MPEG4 media file format*/ public static final int MPEG_4 = 2; - /** The following formats are audio only .aac or .amr formats **/ - /** @deprecated Deprecated in favor of AMR_NB */ - /** Deprecated in favor of MediaRecorder.OutputFormat.AMR_NB */ - /** AMR NB file format */ + /** The following formats are audio only .aac or .amr formats */ + + /** + * AMR NB file format + * @deprecated Deprecated in favor of MediaRecorder.OutputFormat.AMR_NB + */ public static final int RAW_AMR = 3; + /** AMR NB file format */ public static final int AMR_NB = 3; + /** AMR WB file format */ public static final int AMR_WB = 4; + /** @hide AAC ADIF file format */ public static final int AAC_ADIF = 5; - /** @hide AAC ADTS file format */ + + /** AAC ADTS file format */ public static final int AAC_ADTS = 6; /** @hide Stream over a socket, limited to a single stream */ diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java index 386986e..1c13fff 100644 --- a/media/java/android/media/MediaScanner.java +++ b/media/java/android/media/MediaScanner.java @@ -35,6 +35,7 @@ import android.os.Process; import android.os.RemoteException; import android.os.SystemProperties; import android.provider.MediaStore; +import android.provider.MediaStore.Files.FileColumns; import android.provider.Settings; import android.provider.MediaStore.Audio; import android.provider.MediaStore.Files; @@ -58,6 +59,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.Locale; /** * Internal service helper that no-one should use directly. @@ -312,17 +314,8 @@ public class MediaScanner private final String mExternalStoragePath; - // WARNING: Bulk inserts sounded like a great idea and gave us a good performance improvement, - // but unfortunately it also introduced a number of bugs. Many of those bugs were fixed, - // but (at least) one problem is still outstanding: - // - // - Bulk inserts broke the code that sets the default ringtones, notifications, and alarms - // on first boot - // - // This problem might be solvable by moving the logic to the media provider or disabling bulk - // inserts only for those cases. For now, we are disabling bulk inserts until we have a solid - // fix for this problem. - private static final boolean ENABLE_BULK_INSERTS = false; + /** whether to use bulk inserts or individual inserts for each item */ + private static final boolean ENABLE_BULK_INSERTS = true; // used when scanning the image database so we know whether we have to prune // old thumbnail files @@ -352,7 +345,7 @@ public class MediaScanner // this should be set when scanning files on a case insensitive file system. private boolean mCaseInsensitivePaths; - private BitmapFactory.Options mBitmapOptions = new BitmapFactory.Options(); + private final BitmapFactory.Options mBitmapOptions = new BitmapFactory.Options(); private static class FileCacheEntry { long mRowId; @@ -396,6 +389,7 @@ public class MediaScanner setDefaultRingtoneFileNames(); mExternalStoragePath = Environment.getExternalStorageDirectory().getAbsolutePath(); + //mClient.testGenreNameConverter(); } private void setDefaultRingtoneFileNames() { @@ -407,7 +401,7 @@ public class MediaScanner + Settings.System.ALARM_ALERT); } - private MyMediaScannerClient mClient = new MyMediaScannerClient(); + private final MyMediaScannerClient mClient = new MyMediaScannerClient(); private boolean isDrmEnabled() { String prop = SystemProperties.get("drm.service.enabled"); @@ -623,8 +617,36 @@ public class MediaScanner mCompilation = parseSubstring(value, 0, 0); } else if (name.equalsIgnoreCase("isdrm")) { mIsDrm = (parseSubstring(value, 0, 0) == 1); + } else { + //Log.v(TAG, "unknown tag: " + name + " (" + mProcessGenres + ")"); + } + } + + private boolean convertGenreCode(String input, String expected) { + String output = getGenreName(input); + if (output.equals(expected)) { + return true; + } else { + Log.d(TAG, "'" + input + "' -> '" + output + "', expected '" + expected + "'"); + return false; } } + private void testGenreNameConverter() { + convertGenreCode("2", "Country"); + convertGenreCode("(2)", "Country"); + convertGenreCode("(2", "(2"); + convertGenreCode("2 Foo", "Country"); + convertGenreCode("(2) Foo", "Country"); + convertGenreCode("(2 Foo", "(2 Foo"); + convertGenreCode("2Foo", "2Foo"); + convertGenreCode("(2)Foo", "Country"); + convertGenreCode("200 Foo", "Foo"); + convertGenreCode("(200) Foo", "Foo"); + convertGenreCode("200Foo", "200Foo"); + convertGenreCode("(200)Foo", "Foo"); + convertGenreCode("200)Foo", "200)Foo"); + convertGenreCode("200) Foo", "200) Foo"); + } public String getGenreName(String genreTagValue) { @@ -633,18 +655,23 @@ public class MediaScanner } final int length = genreTagValue.length(); - if (length > 0 && genreTagValue.charAt(0) == '(') { + if (length > 0) { + boolean parenthesized = false; StringBuffer number = new StringBuffer(); - int i = 1; - for (; i < length - 1; ++i) { + int i = 0; + for (; i < length; ++i) { char c = genreTagValue.charAt(i); - if (Character.isDigit(c)) { + if (i == 0 && c == '(') { + parenthesized = true; + } else if (Character.isDigit(c)) { number.append(c); } else { break; } } - if (genreTagValue.charAt(i) == ')') { + char charAfterNumber = i < length ? genreTagValue.charAt(i) : ' '; + if ((parenthesized && charAfterNumber == ')') + || !parenthesized && Character.isWhitespace(charAfterNumber)) { try { short genreIndex = Short.parseShort(number.toString()); if (genreIndex >= 0) { @@ -655,7 +682,13 @@ public class MediaScanner } else if (genreIndex < 0xFF && (i + 1) < length) { // genre is valid but unknown, // if there is a string after the value we take it - return genreTagValue.substring(i + 1); + if (parenthesized && charAfterNumber == ')') { + i++; + } + String ret = genreTagValue.substring(i).trim(); + if (ret.length() != 0) { + return ret; + } } else { // else return the number, without parentheses return number.toString(); @@ -855,6 +888,7 @@ public class MediaScanner } } Uri result = null; + boolean needToSetSettings = false; if (rowId == 0) { if (mMtpObjectHandle != 0) { values.put(MediaStore.MediaColumns.MEDIA_SCANNER_NEW_OBJECT_ID, mMtpObjectHandle); @@ -866,12 +900,37 @@ public class MediaScanner } values.put(Files.FileColumns.FORMAT, format); } + // Setting a flag in order not to use bulk insert for the file related with + // notifications, ringtones, and alarms, because the rowId of the inserted file is + // needed. + if (mWasEmptyPriorToScan) { + if (notifications && !mDefaultNotificationSet) { + if (TextUtils.isEmpty(mDefaultNotificationFilename) || + doesPathHaveFilename(entry.mPath, mDefaultNotificationFilename)) { + needToSetSettings = true; + } + } else if (ringtones && !mDefaultRingtoneSet) { + if (TextUtils.isEmpty(mDefaultRingtoneFilename) || + doesPathHaveFilename(entry.mPath, mDefaultRingtoneFilename)) { + needToSetSettings = true; + } + } else if (alarms && !mDefaultAlarmSet) { + if (TextUtils.isEmpty(mDefaultAlarmAlertFilename) || + doesPathHaveFilename(entry.mPath, mDefaultAlarmAlertFilename)) { + needToSetSettings = true; + } + } + } + // new file, insert it // We insert directories immediately to ensure they are in the database // before the files they contain. // Otherwise we can get duplicate directory entries in the database // if one of the media FileInserters is flushed before the files table FileInserter - if (inserter == null || entry.mFormat == MtpConstants.FORMAT_ASSOCIATION) { + // Also, we immediately insert the file if the rowId of the inserted file is + // needed. + if (inserter == null || needToSetSettings || + entry.mFormat == MtpConstants.FORMAT_ASSOCIATION) { result = mMediaProvider.insert(tableUri, values); } else { inserter.insert(tableUri, values); @@ -887,24 +946,33 @@ public class MediaScanner // path should never change, and we want to avoid replacing mixed cased paths // with squashed lower case paths values.remove(MediaStore.MediaColumns.DATA); + + int mediaType = 0; + if (!MediaScanner.isNoMediaPath(entry.mPath)) { + int fileType = MediaFile.getFileTypeForMimeType(mMimeType); + if (MediaFile.isAudioFileType(fileType)) { + mediaType = FileColumns.MEDIA_TYPE_AUDIO; + } else if (MediaFile.isVideoFileType(fileType)) { + mediaType = FileColumns.MEDIA_TYPE_VIDEO; + } else if (MediaFile.isImageFileType(fileType)) { + mediaType = FileColumns.MEDIA_TYPE_IMAGE; + } else if (MediaFile.isPlayListFileType(fileType)) { + mediaType = FileColumns.MEDIA_TYPE_PLAYLIST; + } + values.put(FileColumns.MEDIA_TYPE, mediaType); + } + mMediaProvider.update(result, values, null, null); } - if (notifications && mWasEmptyPriorToScan && !mDefaultNotificationSet) { - if (TextUtils.isEmpty(mDefaultNotificationFilename) || - doesPathHaveFilename(entry.mPath, mDefaultNotificationFilename)) { + if(needToSetSettings) { + if (notifications) { setSettingIfNotSet(Settings.System.NOTIFICATION_SOUND, tableUri, rowId); mDefaultNotificationSet = true; - } - } else if (ringtones && mWasEmptyPriorToScan && !mDefaultRingtoneSet) { - if (TextUtils.isEmpty(mDefaultRingtoneFilename) || - doesPathHaveFilename(entry.mPath, mDefaultRingtoneFilename)) { + } else if (ringtones) { setSettingIfNotSet(Settings.System.RINGTONE, tableUri, rowId); mDefaultRingtoneSet = true; - } - } else if (alarms && mWasEmptyPriorToScan && !mDefaultAlarmSet) { - if (TextUtils.isEmpty(mDefaultAlarmAlertFilename) || - doesPathHaveFilename(entry.mPath, mDefaultAlarmAlertFilename)) { + } else if (alarms) { setSettingIfNotSet(Settings.System.ALARM_ALERT, tableUri, rowId); mDefaultAlarmSet = true; } @@ -983,7 +1051,7 @@ public class MediaScanner // First read existing files from the files table c = mMediaProvider.query(mFilesUri, FILES_PRESCAN_PROJECTION, - where, selectionArgs, null); + where, selectionArgs, null, null); if (c != null) { mWasEmptyPriorToScan = c.getCount() == 0; @@ -1020,7 +1088,7 @@ public class MediaScanner // compute original size of images mOriginalCount = 0; - c = mMediaProvider.query(mImagesUri, ID_PROJECTION, null, null, null); + c = mMediaProvider.query(mImagesUri, ID_PROJECTION, null, null, null, null); if (c != null) { mOriginalCount = c.getCount(); c.close(); @@ -1055,7 +1123,7 @@ public class MediaScanner new String [] { "_data" }, null, null, - null); + null, null); Log.v(TAG, "pruneDeadThumbnailFiles... " + c); if (c != null && c.moveToFirst()) { do { @@ -1128,6 +1196,10 @@ public class MediaScanner mMediaProvider.delete(ContentUris.withAppendedId(mFilesUri, entry.mRowId), null, null); iterator.remove(); + if (entry.mPath.toLowerCase(Locale.US).endsWith("/.nomedia")) { + File f = new File(path); + mMediaProvider.call(MediaStore.UNHIDE_CALL, f.getParent(), null); + } } } } @@ -1420,7 +1492,7 @@ public class MediaScanner if (bestMatch.mRowId == 0) { Cursor c = mMediaProvider.query(mAudioUri, ID_PROJECTION, MediaStore.Files.FileColumns.DATA + "=?", - new String[] { bestMatch.mPath }, null); + new String[] { bestMatch.mPath }, null, null); if (c != null) { if (c.moveToNext()) { bestMatch.mRowId = c.getLong(0); diff --git a/media/java/android/media/MediaScannerConnection.java b/media/java/android/media/MediaScannerConnection.java index 969da39..21b6e14 100644 --- a/media/java/android/media/MediaScannerConnection.java +++ b/media/java/android/media/MediaScannerConnection.java @@ -46,7 +46,7 @@ public class MediaScannerConnection implements ServiceConnection { private IMediaScannerService mService; private boolean mConnected; // true if connect() has been called since last disconnect() - private IMediaScannerListener.Stub mListener = new IMediaScannerListener.Stub() { + private final IMediaScannerListener.Stub mListener = new IMediaScannerListener.Stub() { public void scanCompleted(String path, Uri uri) { MediaScannerConnectionClient client = mClient; if (client != null) { diff --git a/media/java/android/media/MiniThumbFile.java b/media/java/android/media/MiniThumbFile.java index df141c1..63b149c 100644 --- a/media/java/android/media/MiniThumbFile.java +++ b/media/java/android/media/MiniThumbFile.java @@ -52,7 +52,7 @@ public class MiniThumbFile { private RandomAccessFile mMiniThumbFile; private FileChannel mChannel; private ByteBuffer mBuffer; - private static Hashtable<String, MiniThumbFile> sThumbFiles = + private static final Hashtable<String, MiniThumbFile> sThumbFiles = new Hashtable<String, MiniThumbFile>(); /** diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java index 77acfe6..18b4ee6 100644 --- a/media/java/android/media/RemoteControlClient.java +++ b/media/java/android/media/RemoteControlClient.java @@ -576,6 +576,7 @@ public class RemoteControlClient /** * Cache for the metadata strings. * Access synchronized on mCacheLock + * This is re-initialized in apply() and so cannot be final. */ private Bundle mMetadata = new Bundle(); @@ -621,7 +622,7 @@ public class RemoteControlClient /** * The IRemoteControlClient implementation */ - private IRemoteControlClient mIRCC = new IRemoteControlClient.Stub() { + private final IRemoteControlClient mIRCC = new IRemoteControlClient.Stub() { public void onInformationRequested(int clientGeneration, int infoFlags, int artWidth, int artHeight) { diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java index 9c0819f..7aaf4aa 100644 --- a/media/java/android/media/RingtoneManager.java +++ b/media/java/android/media/RingtoneManager.java @@ -224,7 +224,7 @@ public class RingtoneManager { * If a column (item from this list) exists in the Cursor, its value must * be true (value of 1) for the row to be returned. */ - private List<String> mFilterColumns = new ArrayList<String>(); + private final List<String> mFilterColumns = new ArrayList<String>(); private boolean mStopPreviousRingtone = true; private Ringtone mPreviousRingtone; diff --git a/media/java/android/media/SoundPool.java b/media/java/android/media/SoundPool.java index 5e9c018..0f68e98 100644 --- a/media/java/android/media/SoundPool.java +++ b/media/java/android/media/SoundPool.java @@ -161,12 +161,10 @@ public class SoundPool int id = 0; try { File f = new File(path); - if (f != null) { - ParcelFileDescriptor fd = ParcelFileDescriptor.open(f, ParcelFileDescriptor.MODE_READ_ONLY); - if (fd != null) { - id = _load(fd.getFileDescriptor(), 0, f.length(), priority); - fd.close(); - } + ParcelFileDescriptor fd = ParcelFileDescriptor.open(f, ParcelFileDescriptor.MODE_READ_ONLY); + if (fd != null) { + id = _load(fd.getFileDescriptor(), 0, f.length(), priority); + fd.close(); } } catch (java.io.IOException e) { Log.e(TAG, "error loading " + path); diff --git a/media/java/android/media/ThumbnailUtils.java b/media/java/android/media/ThumbnailUtils.java index 078d4af..8eb9332 100644 --- a/media/java/android/media/ThumbnailUtils.java +++ b/media/java/android/media/ThumbnailUtils.java @@ -104,8 +104,10 @@ public class ThumbnailUtils { } if (bitmap == null) { + FileInputStream stream = null; try { - FileDescriptor fd = new FileInputStream(filePath).getFD(); + stream = new FileInputStream(filePath); + FileDescriptor fd = stream.getFD(); BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = 1; options.inJustDecodeBounds = true; @@ -125,7 +127,16 @@ public class ThumbnailUtils { Log.e(TAG, "", ex); } catch (OutOfMemoryError oom) { Log.e(TAG, "Unable to decode file " + filePath + ". OutOfMemoryError.", oom); + } finally { + try { + if (stream != null) { + stream.close(); + } + } catch (IOException ex) { + Log.e(TAG, "", ex); + } } + } if (kind == Images.Thumbnails.MICRO_KIND) { @@ -472,9 +483,7 @@ public class ThumbnailUtils { byte [] thumbData = null; try { exif = new ExifInterface(filePath); - if (exif != null) { - thumbData = exif.getThumbnail(); - } + thumbData = exif.getThumbnail(); } catch (IOException ex) { Log.w(TAG, ex); } diff --git a/media/java/android/media/audiofx/AudioEffect.java b/media/java/android/media/audiofx/AudioEffect.java index 673f9f4..85be267 100644 --- a/media/java/android/media/audiofx/AudioEffect.java +++ b/media/java/android/media/audiofx/AudioEffect.java @@ -386,7 +386,7 @@ public class AudioEffect { default: throw (new RuntimeException( "Cannot initialize effect engine for type: " + type - + "Error: " + initResult)); + + " Error: " + initResult)); } } mId = id[0]; diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java index 19db1c0..18aa4b3 100755 --- a/media/java/android/mtp/MtpDatabase.java +++ b/media/java/android/mtp/MtpDatabase.java @@ -266,7 +266,7 @@ public class MtpDatabase { Cursor c = null; try { c = mMediaProvider.query(mObjectsUri, ID_PROJECTION, PATH_WHERE, - new String[] { path }, null); + new String[] { path }, null, null); if (c != null && c.getCount() > 0) { Log.w(TAG, "file already exists in beginSendObject: " + path); return -1; @@ -433,7 +433,7 @@ public class MtpDatabase { } } - return mMediaProvider.query(mObjectsUri, ID_PROJECTION, where, whereArgs, null); + return mMediaProvider.query(mObjectsUri, ID_PROJECTION, where, whereArgs, null, null); } private int[] getObjectList(int storageID, int format, int parent) { @@ -699,7 +699,7 @@ public class MtpDatabase { String path = null; String[] whereArgs = new String[] { Integer.toString(handle) }; try { - c = mMediaProvider.query(mObjectsUri, PATH_PROJECTION, ID_WHERE, whereArgs, null); + c = mMediaProvider.query(mObjectsUri, PATH_PROJECTION, ID_WHERE, whereArgs, null, null); if (c != null && c.moveToNext()) { path = c.getString(1); } @@ -752,6 +752,29 @@ public class MtpDatabase { return MtpConstants.RESPONSE_GENERAL_ERROR; } + // check if nomedia status changed + if (newFile.isDirectory()) { + // for directories, check if renamed from something hidden to something non-hidden + if (oldFile.getName().startsWith(".") && !newPath.startsWith(".")) { + // directory was unhidden + try { + mMediaProvider.call(MediaStore.UNHIDE_CALL, newPath, null); + } catch (RemoteException e) { + Log.e(TAG, "failed to unhide/rescan for " + newPath); + } + } + } else { + // for files, check if renamed from .nomedia to something else + if (oldFile.getName().toLowerCase(Locale.US).equals(".nomedia") + && !newPath.toLowerCase(Locale.US).equals(".nomedia")) { + try { + mMediaProvider.call(MediaStore.UNHIDE_CALL, oldFile.getParent(), null); + } catch (RemoteException e) { + Log.e(TAG, "failed to unhide/rescan for " + newPath); + } + } + } + return MtpConstants.RESPONSE_OK; } @@ -815,7 +838,7 @@ public class MtpDatabase { Cursor c = null; try { c = mMediaProvider.query(mObjectsUri, OBJECT_INFO_PROJECTION, - ID_WHERE, new String[] { Integer.toString(handle) }, null); + ID_WHERE, new String[] { Integer.toString(handle) }, null, null); if (c != null && c.moveToNext()) { outStorageFormatParent[0] = c.getInt(1); outStorageFormatParent[1] = c.getInt(2); @@ -858,7 +881,7 @@ public class MtpDatabase { Cursor c = null; try { c = mMediaProvider.query(mObjectsUri, PATH_SIZE_FORMAT_PROJECTION, - ID_WHERE, new String[] { Integer.toString(handle) }, null); + ID_WHERE, new String[] { Integer.toString(handle) }, null, null); if (c != null && c.moveToNext()) { String path = c.getString(1); path.getChars(0, path.length(), outFilePath, 0); @@ -887,7 +910,7 @@ public class MtpDatabase { Cursor c = null; try { c = mMediaProvider.query(mObjectsUri, PATH_SIZE_FORMAT_PROJECTION, - ID_WHERE, new String[] { Integer.toString(handle) }, null); + ID_WHERE, new String[] { Integer.toString(handle) }, null, null); if (c != null && c.moveToNext()) { // don't convert to media path here, since we will be matching // against paths in the database matching /data/media @@ -915,6 +938,15 @@ public class MtpDatabase { Uri uri = Files.getMtpObjectsUri(mVolumeName, handle); if (mMediaProvider.delete(uri, null, null) > 0) { + if (format != MtpConstants.FORMAT_ASSOCIATION + && path.toLowerCase(Locale.US).endsWith("/.nomedia")) { + try { + String parentPath = path.substring(0, path.lastIndexOf("/")); + mMediaProvider.call(MediaStore.UNHIDE_CALL, parentPath, null); + } catch (RemoteException e) { + Log.e(TAG, "failed to unhide/rescan for " + path); + } + } return MtpConstants.RESPONSE_OK; } else { return MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE; @@ -933,7 +965,7 @@ public class MtpDatabase { Uri uri = Files.getMtpReferencesUri(mVolumeName, handle); Cursor c = null; try { - c = mMediaProvider.query(uri, ID_PROJECTION, null, null, null); + c = mMediaProvider.query(uri, ID_PROJECTION, null, null, null, null); if (c == null) { return null; } diff --git a/media/java/android/mtp/MtpPropertyGroup.java b/media/java/android/mtp/MtpPropertyGroup.java index 76c8569..dab5454 100644 --- a/media/java/android/mtp/MtpPropertyGroup.java +++ b/media/java/android/mtp/MtpPropertyGroup.java @@ -191,7 +191,7 @@ class MtpPropertyGroup { // for now we are only reading properties from the "objects" table c = mProvider.query(mUri, new String [] { Files.FileColumns._ID, column }, - ID_WHERE, new String[] { Integer.toString(id) }, null); + ID_WHERE, new String[] { Integer.toString(id) }, null, null); if (c != null && c.moveToNext()) { return c.getString(1); } else { @@ -211,7 +211,7 @@ class MtpPropertyGroup { try { c = mProvider.query(Audio.Media.getContentUri(mVolumeName), new String [] { Files.FileColumns._ID, column }, - ID_WHERE, new String[] { Integer.toString(id) }, null); + ID_WHERE, new String[] { Integer.toString(id) }, null, null); if (c != null && c.moveToNext()) { return c.getString(1); } else { @@ -232,7 +232,7 @@ class MtpPropertyGroup { Uri uri = Audio.Genres.getContentUriForAudioId(mVolumeName, id); c = mProvider.query(uri, new String [] { Files.FileColumns._ID, Audio.GenresColumns.NAME }, - null, null, null); + null, null, null, null); if (c != null && c.moveToNext()) { return c.getString(1); } else { @@ -254,7 +254,7 @@ class MtpPropertyGroup { // for now we are only reading properties from the "objects" table c = mProvider.query(mUri, new String [] { Files.FileColumns._ID, column }, - ID_WHERE, new String[] { Integer.toString(id) }, null); + ID_WHERE, new String[] { Integer.toString(id) }, null, null); if (c != null && c.moveToNext()) { return new Long(c.getLong(1)); } @@ -323,7 +323,7 @@ class MtpPropertyGroup { try { // don't query if not necessary if (depth > 0 || handle == 0xFFFFFFFF || mColumns.length > 1) { - c = mProvider.query(mUri, mColumns, where, whereArgs, null); + c = mProvider.query(mUri, mColumns, where, whereArgs, null, null); if (c == null) { return new MtpPropertyList(0, MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE); } diff --git a/media/jni/Android.mk b/media/jni/Android.mk index d4b326c..23cc0e2 100644 --- a/media/jni/Android.mk +++ b/media/jni/Android.mk @@ -26,10 +26,13 @@ LOCAL_SHARED_LIBRARIES := \ libgui \ libstagefright \ libcamera_client \ - libsqlite \ libmtp \ libusbhost \ - libexif + libexif \ + libstagefright_amrnb_common \ + +LOCAL_STATIC_LIBRARIES := \ + libstagefright_amrnbenc LOCAL_C_INCLUDES += \ external/jhead \ diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp index 39fd9a9..8ff9dd3 100644 --- a/media/jni/android_media_MediaPlayer.cpp +++ b/media/jni/android_media_MediaPlayer.cpp @@ -479,7 +479,7 @@ android_media_MediaPlayer_setAudioStreamType(JNIEnv *env, jobject thiz, int stre jniThrowException(env, "java/lang/IllegalStateException", NULL); return; } - process_media_player_call( env, thiz, mp->setAudioStreamType(streamtype) , NULL, NULL ); + process_media_player_call( env, thiz, mp->setAudioStreamType((audio_stream_type_t) streamtype) , NULL, NULL ); } static void diff --git a/media/jni/mediaeditor/Android.mk b/media/jni/mediaeditor/Android.mk index 1af78e3..e44dc7c 100755 --- a/media/jni/mediaeditor/Android.mk +++ b/media/jni/mediaeditor/Android.mk @@ -47,6 +47,7 @@ LOCAL_C_INCLUDES += \ $(TOP)/frameworks/media/libvideoeditor/osal/inc LOCAL_SHARED_LIBRARIES := \ + libaudioutils \ libcutils \ libdl \ libutils \ diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp index 14a5309..0d51def 100644 --- a/media/jni/soundpool/SoundPool.cpp +++ b/media/jni/soundpool/SoundPool.cpp @@ -39,7 +39,7 @@ uint32_t kMaxSampleRate = 48000; uint32_t kDefaultSampleRate = 44100; uint32_t kDefaultFrameCount = 1200; -SoundPool::SoundPool(int maxChannels, int streamType, int srcQuality) +SoundPool::SoundPool(int maxChannels, audio_stream_type_t streamType, int srcQuality) { ALOGV("SoundPool constructor: maxChannels=%d, streamType=%d, srcQuality=%d", maxChannels, streamType, srcQuality); @@ -496,7 +496,7 @@ status_t Sample::doLoad() { uint32_t sampleRate; int numChannels; - int format; + audio_format_t format; sp<IMemory> p; ALOGV("Start decode"); if (mUrl) { @@ -570,7 +570,7 @@ void SoundChannel::play(const sp<Sample>& sample, int nextChannelID, float leftV // initialize track int afFrameCount; int afSampleRate; - int streamType = mSoundPool->streamType(); + audio_stream_type_t streamType = mSoundPool->streamType(); if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) { afFrameCount = kDefaultFrameCount; } diff --git a/media/jni/soundpool/SoundPool.h b/media/jni/soundpool/SoundPool.h index 6010aac..6b11c28 100644 --- a/media/jni/soundpool/SoundPool.h +++ b/media/jni/soundpool/SoundPool.h @@ -56,7 +56,7 @@ public: int sampleID() { return mSampleID; } int numChannels() { return mNumChannels; } int sampleRate() { return mSampleRate; } - int format() { return mFormat; } + audio_format_t format() { return mFormat; } size_t size() { return mSize; } int state() { return mState; } uint8_t* data() { return static_cast<uint8_t*>(mData->pointer()); } @@ -65,7 +65,7 @@ public: sp<IMemory> getIMemory() { return mData; } // hack - void init(int numChannels, int sampleRate, int format, size_t size, sp<IMemory> data ) { + void init(int numChannels, int sampleRate, audio_format_t format, size_t size, sp<IMemory> data ) { mNumChannels = numChannels; mSampleRate = sampleRate; mFormat = format; mSize = size; mData = data; } private: @@ -77,7 +77,7 @@ private: uint16_t mSampleRate; uint8_t mState : 3; uint8_t mNumChannels : 2; - uint8_t mFormat : 2; + audio_format_t mFormat; int mFd; int64_t mOffset; int64_t mLength; @@ -162,7 +162,7 @@ class SoundPool { friend class SoundPoolThread; friend class SoundChannel; public: - SoundPool(int maxChannels, int streamType, int srcQuality); + SoundPool(int maxChannels, audio_stream_type_t streamType, int srcQuality); ~SoundPool(); int load(const char* url, int priority); int load(int fd, int64_t offset, int64_t length, int priority); @@ -178,7 +178,7 @@ public: void setPriority(int channelID, int priority); void setLoop(int channelID, int loop); void setRate(int channelID, float rate); - int streamType() const { return mStreamType; } + audio_stream_type_t streamType() const { return mStreamType; } int srcQuality() const { return mSrcQuality; } // called from SoundPoolThread @@ -220,7 +220,7 @@ private: List<SoundChannel*> mStop; DefaultKeyedVector< int, sp<Sample> > mSamples; int mMaxChannels; - int mStreamType; + audio_stream_type_t mStreamType; int mSrcQuality; int mAllocated; int mNextSampleID; diff --git a/media/jni/soundpool/android_media_SoundPool.cpp b/media/jni/soundpool/android_media_SoundPool.cpp index fe1c20a..da3af9d 100644 --- a/media/jni/soundpool/android_media_SoundPool.cpp +++ b/media/jni/soundpool/android_media_SoundPool.cpp @@ -179,7 +179,7 @@ static jint android_media_SoundPool_native_setup(JNIEnv *env, jobject thiz, jobject weakRef, jint maxChannels, jint streamType, jint srcQuality) { ALOGV("android_media_SoundPool_native_setup"); - SoundPool *ap = new SoundPool(maxChannels, streamType, srcQuality); + SoundPool *ap = new SoundPool(maxChannels, (audio_stream_type_t) streamType, srcQuality); if (ap == NULL) { return -1; } diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp index 62be78c..108d36a 100644 --- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp +++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp @@ -133,7 +133,8 @@ int LvmBundle_init (EffectContext *pContext); int LvmEffect_enable (EffectContext *pContext); int LvmEffect_disable (EffectContext *pContext); void LvmEffect_free (EffectContext *pContext); -int Effect_configure (EffectContext *pContext, effect_config_t *pConfig); +int Effect_setConfig (EffectContext *pContext, effect_config_t *pConfig); +void Effect_getConfig (EffectContext *pContext, effect_config_t *pConfig); int BassBoost_setParameter (EffectContext *pContext, void *pParam, void *pValue); int BassBoost_getParameter (EffectContext *pContext, void *pParam, @@ -936,7 +937,7 @@ void LvmEffect_free(EffectContext *pContext){ } /* end LvmEffect_free */ //---------------------------------------------------------------------------- -// Effect_configure() +// Effect_setConfig() //---------------------------------------------------------------------------- // Purpose: Set input and output audio configuration. // @@ -949,9 +950,9 @@ void LvmEffect_free(EffectContext *pContext){ // //---------------------------------------------------------------------------- -int Effect_configure(EffectContext *pContext, effect_config_t *pConfig){ +int Effect_setConfig(EffectContext *pContext, effect_config_t *pConfig){ LVM_Fs_en SampleRate; - //ALOGV("\tEffect_configure start"); + //ALOGV("\tEffect_setConfig start"); CHECK_ARG(pContext != NULL); CHECK_ARG(pConfig != NULL); @@ -992,7 +993,7 @@ int Effect_configure(EffectContext *pContext, effect_config_t *pConfig){ pContext->pBundledContext->SamplesPerSecond = 48000*2; // 2 secs Stereo break; default: - ALOGV("\tEffect_Configure invalid sampling rate %d", pConfig->inputCfg.samplingRate); + ALOGV("\tEffect_setConfig invalid sampling rate %d", pConfig->inputCfg.samplingRate); return -EINVAL; } @@ -1001,28 +1002,47 @@ int Effect_configure(EffectContext *pContext, effect_config_t *pConfig){ LVM_ControlParams_t ActiveParams; LVM_ReturnStatus_en LvmStatus = LVM_SUCCESS; - ALOGV("\tEffect_configure change sampling rate to %d", SampleRate); + ALOGV("\tEffect_setConfig change sampling rate to %d", SampleRate); /* Get the current settings */ LvmStatus = LVM_GetControlParameters(pContext->pBundledContext->hInstance, &ActiveParams); - LVM_ERROR_CHECK(LvmStatus, "LVM_GetControlParameters", "Effect_configure") + LVM_ERROR_CHECK(LvmStatus, "LVM_GetControlParameters", "Effect_setConfig") if(LvmStatus != LVM_SUCCESS) return -EINVAL; LvmStatus = LVM_SetControlParameters(pContext->pBundledContext->hInstance, &ActiveParams); - LVM_ERROR_CHECK(LvmStatus, "LVM_SetControlParameters", "Effect_configure") - ALOGV("\tEffect_configure Succesfully called LVM_SetControlParameters\n"); + LVM_ERROR_CHECK(LvmStatus, "LVM_SetControlParameters", "Effect_setConfig") + ALOGV("\tEffect_setConfig Succesfully called LVM_SetControlParameters\n"); pContext->pBundledContext->SampleRate = SampleRate; }else{ - //ALOGV("\tEffect_configure keep sampling rate at %d", SampleRate); + //ALOGV("\tEffect_setConfig keep sampling rate at %d", SampleRate); } - //ALOGV("\tEffect_configure End...."); + //ALOGV("\tEffect_setConfig End...."); return 0; -} /* end Effect_configure */ +} /* end Effect_setConfig */ + +//---------------------------------------------------------------------------- +// Effect_getConfig() +//---------------------------------------------------------------------------- +// Purpose: Get input and output audio configuration. +// +// Inputs: +// pContext: effect engine context +// pConfig: pointer to effect_config_t structure holding input and output +// configuration parameters +// +// Outputs: +// +//---------------------------------------------------------------------------- + +void Effect_getConfig(EffectContext *pContext, effect_config_t *pConfig) +{ + memcpy(pConfig, &pContext->config, sizeof(effect_config_t)); +} /* end Effect_getConfig */ //---------------------------------------------------------------------------- // BassGetStrength() @@ -2778,23 +2798,34 @@ int Effect_command(effect_handle_t self, } break; - case EFFECT_CMD_CONFIGURE: - //ALOGV("\tEffect_command cmdCode Case: EFFECT_CMD_CONFIGURE start"); + case EFFECT_CMD_SET_CONFIG: + //ALOGV("\tEffect_command cmdCode Case: EFFECT_CMD_SET_CONFIG start"); if (pCmdData == NULL|| cmdSize != sizeof(effect_config_t)|| pReplyData == NULL|| *replySize != sizeof(int)){ ALOGV("\tLVM_ERROR : Effect_command cmdCode Case: " - "EFFECT_CMD_CONFIGURE: ERROR"); + "EFFECT_CMD_SET_CONFIG: ERROR"); return -EINVAL; } - *(int *) pReplyData = android::Effect_configure(pContext, (effect_config_t *) pCmdData); - //ALOGV("\tEffect_command cmdCode Case: EFFECT_CMD_CONFIGURE end"); + *(int *) pReplyData = android::Effect_setConfig(pContext, (effect_config_t *) pCmdData); + //ALOGV("\tEffect_command cmdCode Case: EFFECT_CMD_SET_CONFIG end"); + break; + + case EFFECT_CMD_GET_CONFIG: + if (pReplyData == NULL || + *replySize != sizeof(effect_config_t)) { + ALOGV("\tLVM_ERROR : Effect_command cmdCode Case: " + "EFFECT_CMD_GET_CONFIG: ERROR"); + return -EINVAL; + } + + android::Effect_getConfig(pContext, (effect_config_t *)pReplyData); break; case EFFECT_CMD_RESET: //ALOGV("\tEffect_command cmdCode Case: EFFECT_CMD_RESET start"); - android::Effect_configure(pContext, &pContext->config); + android::Effect_setConfig(pContext, &pContext->config); //ALOGV("\tEffect_command cmdCode Case: EFFECT_CMD_RESET end"); break; @@ -3078,20 +3109,20 @@ int Effect_command(effect_handle_t self, if (pContext->pBundledContext->bBassEnabled == LVM_TRUE) { ALOGV("\tEFFECT_CMD_SET_DEVICE disable LVM_BASS_BOOST %d", - *(int32_t *)pCmdData); + *(int32_t *)pCmdData); android::LvmEffect_disable(pContext); } pContext->pBundledContext->bBassTempDisabled = LVM_TRUE; } else { ALOGV("\tEFFECT_CMD_SET_DEVICE device is valid for LVM_BASS_BOOST %d", - *(int32_t *)pCmdData); + *(int32_t *)pCmdData); // If a device supports bassboost and the effect has been temporarily disabled // previously then re-enable it if (pContext->pBundledContext->bBassEnabled == LVM_TRUE) { ALOGV("\tEFFECT_CMD_SET_DEVICE re-enable LVM_BASS_BOOST %d", - *(int32_t *)pCmdData); + *(int32_t *)pCmdData); android::LvmEffect_enable(pContext); } pContext->pBundledContext->bBassTempDisabled = LVM_FALSE; diff --git a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp index 1825aab..09cd5cc 100755 --- a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp +++ b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp @@ -175,7 +175,8 @@ enum { //--- local function prototypes int Reverb_init (ReverbContext *pContext); void Reverb_free (ReverbContext *pContext); -int Reverb_configure (ReverbContext *pContext, effect_config_t *pConfig); +int Reverb_setConfig (ReverbContext *pContext, effect_config_t *pConfig); +void Reverb_getConfig (ReverbContext *pContext, effect_config_t *pConfig); int Reverb_setParameter (ReverbContext *pContext, void *pParam, void *pValue); int Reverb_getParameter (ReverbContext *pContext, void *pParam, @@ -609,7 +610,7 @@ void Reverb_free(ReverbContext *pContext){ } /* end Reverb_free */ //---------------------------------------------------------------------------- -// Reverb_configure() +// Reverb_setConfig() //---------------------------------------------------------------------------- // Purpose: Set input and output audio configuration. // @@ -622,9 +623,9 @@ void Reverb_free(ReverbContext *pContext){ // //---------------------------------------------------------------------------- -int Reverb_configure(ReverbContext *pContext, effect_config_t *pConfig){ +int Reverb_setConfig(ReverbContext *pContext, effect_config_t *pConfig){ LVM_Fs_en SampleRate; - //ALOGV("\tReverb_configure start"); + //ALOGV("\tReverb_setConfig start"); CHECK_ARG(pContext != NULL); CHECK_ARG(pConfig != NULL); @@ -642,7 +643,7 @@ int Reverb_configure(ReverbContext *pContext, effect_config_t *pConfig){ return -EINVAL; } - //ALOGV("\tReverb_configure calling memcpy"); + //ALOGV("\tReverb_setConfig calling memcpy"); memcpy(&pContext->config, pConfig, sizeof(effect_config_t)); @@ -666,7 +667,7 @@ int Reverb_configure(ReverbContext *pContext, effect_config_t *pConfig){ SampleRate = LVM_FS_48000; break; default: - ALOGV("\rReverb_Configure invalid sampling rate %d", pConfig->inputCfg.samplingRate); + ALOGV("\rReverb_setConfig invalid sampling rate %d", pConfig->inputCfg.samplingRate); return -EINVAL; } @@ -675,28 +676,46 @@ int Reverb_configure(ReverbContext *pContext, effect_config_t *pConfig){ LVREV_ControlParams_st ActiveParams; LVREV_ReturnStatus_en LvmStatus = LVREV_SUCCESS; - //ALOGV("\tReverb_configure change sampling rate to %d", SampleRate); + //ALOGV("\tReverb_setConfig change sampling rate to %d", SampleRate); /* Get the current settings */ LvmStatus = LVREV_GetControlParameters(pContext->hInstance, &ActiveParams); - LVM_ERROR_CHECK(LvmStatus, "LVREV_GetControlParameters", "Reverb_configure") + LVM_ERROR_CHECK(LvmStatus, "LVREV_GetControlParameters", "Reverb_setConfig") if(LvmStatus != LVREV_SUCCESS) return -EINVAL; LvmStatus = LVREV_SetControlParameters(pContext->hInstance, &ActiveParams); - LVM_ERROR_CHECK(LvmStatus, "LVREV_SetControlParameters", "Reverb_configure") - //ALOGV("\tReverb_configure Succesfully called LVREV_SetControlParameters\n"); + LVM_ERROR_CHECK(LvmStatus, "LVREV_SetControlParameters", "Reverb_setConfig") + //ALOGV("\tReverb_setConfig Succesfully called LVREV_SetControlParameters\n"); }else{ - //ALOGV("\tReverb_configure keep sampling rate at %d", SampleRate); + //ALOGV("\tReverb_setConfig keep sampling rate at %d", SampleRate); } - //ALOGV("\tReverb_configure End"); + //ALOGV("\tReverb_setConfig End"); return 0; -} /* end Reverb_configure */ +} /* end Reverb_setConfig */ +//---------------------------------------------------------------------------- +// Reverb_getConfig() +//---------------------------------------------------------------------------- +// Purpose: Get input and output audio configuration. +// +// Inputs: +// pContext: effect engine context +// pConfig: pointer to effect_config_t structure holding input and output +// configuration parameters +// +// Outputs: +// +//---------------------------------------------------------------------------- + +void Reverb_getConfig(ReverbContext *pContext, effect_config_t *pConfig) +{ + memcpy(pConfig, &pContext->config, sizeof(effect_config_t)); +} /* end Reverb_getConfig */ //---------------------------------------------------------------------------- // Reverb_init() @@ -1924,24 +1943,36 @@ int Reverb_command(effect_handle_t self, *(int *) pReplyData = 0; break; - case EFFECT_CMD_CONFIGURE: + case EFFECT_CMD_SET_CONFIG: //ALOGV("\tReverb_command cmdCode Case: " - // "EFFECT_CMD_CONFIGURE start"); - if (pCmdData == NULL|| - cmdSize != sizeof(effect_config_t)|| - pReplyData == NULL|| - *replySize != sizeof(int)){ + // "EFFECT_CMD_SET_CONFIG start"); + if (pCmdData == NULL || + cmdSize != sizeof(effect_config_t) || + pReplyData == NULL || + *replySize != sizeof(int)) { + ALOGV("\tLVM_ERROR : Reverb_command cmdCode Case: " + "EFFECT_CMD_SET_CONFIG: ERROR"); + return -EINVAL; + } + *(int *) pReplyData = android::Reverb_setConfig(pContext, + (effect_config_t *) pCmdData); + break; + + case EFFECT_CMD_GET_CONFIG: + if (pReplyData == NULL || + *replySize != sizeof(effect_config_t)) { ALOGV("\tLVM_ERROR : Reverb_command cmdCode Case: " - "EFFECT_CMD_CONFIGURE: ERROR"); + "EFFECT_CMD_GET_CONFIG: ERROR"); return -EINVAL; } - *(int *) pReplyData = Reverb_configure(pContext, (effect_config_t *) pCmdData); + + android::Reverb_getConfig(pContext, (effect_config_t *)pReplyData); break; case EFFECT_CMD_RESET: //ALOGV("\tReverb_command cmdCode Case: " // "EFFECT_CMD_RESET start"); - Reverb_configure(pContext, &pContext->config); + Reverb_setConfig(pContext, &pContext->config); break; case EFFECT_CMD_GET_PARAM:{ diff --git a/media/libeffects/preprocessing/Android.mk b/media/libeffects/preprocessing/Android.mk index 77d40b6..7f7c7e1 100755 --- a/media/libeffects/preprocessing/Android.mk +++ b/media/libeffects/preprocessing/Android.mk @@ -13,7 +13,7 @@ LOCAL_SRC_FILES:= \ LOCAL_C_INCLUDES += \ external/webrtc/src \ external/webrtc/src/modules/interface \ - external/webrtc/src/modules/audio_processing/main/interface \ + external/webrtc/src/modules/audio_processing/interface \ system/media/audio_effects/include LOCAL_C_INCLUDES += $(call include-path-for, speex) diff --git a/media/libeffects/preprocessing/PreProcessing.cpp b/media/libeffects/preprocessing/PreProcessing.cpp index 6267d1d..9fd6764 100755 --- a/media/libeffects/preprocessing/PreProcessing.cpp +++ b/media/libeffects/preprocessing/PreProcessing.cpp @@ -24,8 +24,8 @@ #include <audio_effects/effect_aec.h> #include <audio_effects/effect_agc.h> #include <audio_effects/effect_ns.h> -#include "modules/interface/module_common_types.h" -#include "modules/audio_processing/main/interface/audio_processing.h" +#include <module_common_types.h> +#include <audio_processing.h> #include "speex/speex_resampler.h" @@ -220,8 +220,8 @@ bool HasReverseStream(uint32_t procId) // Automatic Gain Control (AGC) //------------------------------------------------------------------------------ -static const int kAgcDefaultTargetLevel = 0; -static const int kAgcDefaultCompGain = 90; +static const int kAgcDefaultTargetLevel = 3; +static const int kAgcDefaultCompGain = 9; static const bool kAgcDefaultLimiter = true; int AgcInit (preproc_effect_t *effect) @@ -940,6 +940,19 @@ int Session_SetConfig(preproc_session_t *session, effect_config_t *config) return 0; } +void Session_GetConfig(preproc_session_t *session, effect_config_t *config) +{ + memset(config, 0, sizeof(effect_config_t)); + config->inputCfg.samplingRate = config->outputCfg.samplingRate = session->samplingRate; + config->inputCfg.format = config->outputCfg.format = AUDIO_FORMAT_PCM_16_BIT; + config->inputCfg.channels = session->inChannelCount == 1 ? + AUDIO_CHANNEL_IN_MONO : AUDIO_CHANNEL_IN_STEREO; + config->outputCfg.channels = session->outChannelCount == 1 ? + AUDIO_CHANNEL_IN_MONO : AUDIO_CHANNEL_IN_STEREO; + config->inputCfg.mask = config->outputCfg.mask = + (EFFECT_CONFIG_SMP_RATE | EFFECT_CONFIG_CHANNELS | EFFECT_CONFIG_FORMAT); +} + int Session_SetReverseConfig(preproc_session_t *session, effect_config_t *config) { if (config->inputCfg.samplingRate != config->outputCfg.samplingRate || @@ -969,6 +982,17 @@ int Session_SetReverseConfig(preproc_session_t *session, effect_config_t *config return 0; } +void Session_GetReverseConfig(preproc_session_t *session, effect_config_t *config) +{ + memset(config, 0, sizeof(effect_config_t)); + config->inputCfg.samplingRate = config->outputCfg.samplingRate = session->samplingRate; + config->inputCfg.format = config->outputCfg.format = AUDIO_FORMAT_PCM_16_BIT; + config->inputCfg.channels = config->outputCfg.channels = + session->revChannelCount == 1 ? AUDIO_CHANNEL_IN_MONO : AUDIO_CHANNEL_IN_STEREO; + config->inputCfg.mask = config->outputCfg.mask = + (EFFECT_CONFIG_SMP_RATE | EFFECT_CONFIG_CHANNELS | EFFECT_CONFIG_FORMAT); +} + void Session_SetProcEnabled(preproc_session_t *session, uint32_t procId, bool enabled) { if (enabled) { @@ -1250,13 +1274,13 @@ int PreProcessingFx_Command(effect_handle_t self, *(int *)pReplyData = 0; break; - case EFFECT_CMD_CONFIGURE: + case EFFECT_CMD_SET_CONFIG: if (pCmdData == NULL|| cmdSize != sizeof(effect_config_t)|| pReplyData == NULL|| *replySize != sizeof(int)){ ALOGV("PreProcessingFx_Command cmdCode Case: " - "EFFECT_CMD_CONFIGURE: ERROR"); + "EFFECT_CMD_SET_CONFIG: ERROR"); return -EINVAL; } *(int *)pReplyData = Session_SetConfig(effect->session, (effect_config_t *)pCmdData); @@ -1266,13 +1290,24 @@ int PreProcessingFx_Command(effect_handle_t self, *(int *)pReplyData = Effect_SetState(effect, PREPROC_EFFECT_STATE_CONFIG); break; - case EFFECT_CMD_CONFIGURE_REVERSE: - if (pCmdData == NULL|| - cmdSize != sizeof(effect_config_t)|| - pReplyData == NULL|| - *replySize != sizeof(int)){ + case EFFECT_CMD_GET_CONFIG: + if (pReplyData == NULL || + *replySize != sizeof(effect_config_t)) { + ALOGV("\tLVM_ERROR : PreProcessingFx_Command cmdCode Case: " + "EFFECT_CMD_GET_CONFIG: ERROR"); + return -EINVAL; + } + + Session_GetConfig(effect->session, (effect_config_t *)pCmdData); + break; + + case EFFECT_CMD_SET_CONFIG_REVERSE: + if (pCmdData == NULL || + cmdSize != sizeof(effect_config_t) || + pReplyData == NULL || + *replySize != sizeof(int)) { ALOGV("PreProcessingFx_Command cmdCode Case: " - "EFFECT_CMD_CONFIGURE_REVERSE: ERROR"); + "EFFECT_CMD_SET_CONFIG_REVERSE: ERROR"); return -EINVAL; } *(int *)pReplyData = Session_SetReverseConfig(effect->session, @@ -1282,6 +1317,16 @@ int PreProcessingFx_Command(effect_handle_t self, } break; + case EFFECT_CMD_GET_CONFIG_REVERSE: + if (pReplyData == NULL || + *replySize != sizeof(effect_config_t)){ + ALOGV("PreProcessingFx_Command cmdCode Case: " + "EFFECT_CMD_GET_CONFIG_REVERSE: ERROR"); + return -EINVAL; + } + Session_GetReverseConfig(effect->session, (effect_config_t *)pCmdData); + break; + case EFFECT_CMD_RESET: if (effect->ops->reset) { effect->ops->reset(effect); diff --git a/media/libeffects/testlibs/AudioBiquadFilter.cpp b/media/libeffects/testlibs/AudioBiquadFilter.cpp index 72917a3..16dd1c5 100644 --- a/media/libeffects/testlibs/AudioBiquadFilter.cpp +++ b/media/libeffects/testlibs/AudioBiquadFilter.cpp @@ -17,12 +17,10 @@ #include <string.h> #include <assert.h> +#include <cutils/compiler.h> #include "AudioBiquadFilter.h" -#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) -#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) - namespace android { const audio_coef_t AudioBiquadFilter::IDENTITY_COEFS[AudioBiquadFilter::NUM_COEFS] = { AUDIO_COEF_ONE, 0, 0, 0, 0 }; @@ -55,7 +53,7 @@ void AudioBiquadFilter::clear() { void AudioBiquadFilter::setCoefs(const audio_coef_t coefs[NUM_COEFS], bool immediate) { memcpy(mTargetCoefs, coefs, sizeof(mTargetCoefs)); if (mState & STATE_ENABLED_MASK) { - if (UNLIKELY(immediate)) { + if (CC_UNLIKELY(immediate)) { memcpy(mCoefs, coefs, sizeof(mCoefs)); setState(STATE_NORMAL); } else { @@ -70,7 +68,7 @@ void AudioBiquadFilter::process(const audio_sample_t in[], audio_sample_t out[], } void AudioBiquadFilter::enable(bool immediate) { - if (UNLIKELY(immediate)) { + if (CC_UNLIKELY(immediate)) { memcpy(mCoefs, mTargetCoefs, sizeof(mCoefs)); setState(STATE_NORMAL); } else { @@ -79,7 +77,7 @@ void AudioBiquadFilter::enable(bool immediate) { } void AudioBiquadFilter::disable(bool immediate) { - if (UNLIKELY(immediate)) { + if (CC_UNLIKELY(immediate)) { memcpy(mCoefs, IDENTITY_COEFS, sizeof(mCoefs)); setState(STATE_BYPASS); } else { @@ -142,7 +140,7 @@ void AudioBiquadFilter::process_bypass(const audio_sample_t * in, audio_sample_t * out, int frameCount) { // The common case is in-place processing, because this is what the EQ does. - if (UNLIKELY(in != out)) { + if (CC_UNLIKELY(in != out)) { memcpy(out, in, frameCount * mNumChannels * sizeof(audio_sample_t)); } } diff --git a/media/libeffects/testlibs/AudioCoefInterpolator.cpp b/media/libeffects/testlibs/AudioCoefInterpolator.cpp index 039ab9f..6b56922 100644 --- a/media/libeffects/testlibs/AudioCoefInterpolator.cpp +++ b/media/libeffects/testlibs/AudioCoefInterpolator.cpp @@ -16,10 +16,10 @@ */ #include <string.h> -#include "AudioCoefInterpolator.h" -#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) -#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) +#include <cutils/compiler.h> + +#include "AudioCoefInterpolator.h" namespace android { @@ -44,9 +44,9 @@ void AudioCoefInterpolator::getCoef(const int intCoord[], uint32_t fracCoord[], size_t index = 0; size_t dim = mNumInDims; while (dim-- > 0) { - if (UNLIKELY(intCoord[dim] < 0)) { + if (CC_UNLIKELY(intCoord[dim] < 0)) { fracCoord[dim] = 0; - } else if (UNLIKELY(intCoord[dim] >= (int)mInDims[dim] - 1)) { + } else if (CC_UNLIKELY(intCoord[dim] >= (int)mInDims[dim] - 1)) { fracCoord[dim] = 0; index += mInDimOffsets[dim] * (mInDims[dim] - 1); } else { @@ -63,7 +63,7 @@ void AudioCoefInterpolator::getCoefRecurse(size_t index, memcpy(out, mTable + index, mNumOutDims * sizeof(audio_coef_t)); } else { getCoefRecurse(index, fracCoord, out, dim + 1); - if (LIKELY(fracCoord != 0)) { + if (CC_LIKELY(fracCoord != 0)) { audio_coef_t tempCoef[MAX_OUT_DIMS]; getCoefRecurse(index + mInDimOffsets[dim], fracCoord, tempCoef, dim + 1); diff --git a/media/libeffects/testlibs/AudioCommon.h b/media/libeffects/testlibs/AudioCommon.h index 444f93a..e8080dc 100644 --- a/media/libeffects/testlibs/AudioCommon.h +++ b/media/libeffects/testlibs/AudioCommon.h @@ -20,6 +20,7 @@ #include <stdint.h> #include <stddef.h> +#include <cutils/compiler.h> namespace android { @@ -76,9 +77,9 @@ inline int16_t audio_sample_t_to_s15(audio_sample_t sample) { // Convert a audio_sample_t sample to S15 (with clipping) inline int16_t audio_sample_t_to_s15_clip(audio_sample_t sample) { // TODO: optimize for targets supporting this as an atomic operation. - if (__builtin_expect(sample >= (0x7FFF << 9), 0)) { + if (CC_UNLIKELY(sample >= (0x7FFF << 9))) { return 0x7FFF; - } else if (__builtin_expect(sample <= -(0x8000 << 9), 0)) { + } else if (CC_UNLIKELY(sample <= -(0x8000 << 9))) { return 0x8000; } else { return audio_sample_t_to_s15(sample); diff --git a/media/libeffects/testlibs/AudioPeakingFilter.cpp b/media/libeffects/testlibs/AudioPeakingFilter.cpp index 60fefe6..99323ac 100644 --- a/media/libeffects/testlibs/AudioPeakingFilter.cpp +++ b/media/libeffects/testlibs/AudioPeakingFilter.cpp @@ -21,9 +21,7 @@ #include <new> #include <assert.h> - -#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) -#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) +#include <cutils/compiler.h> namespace android { // Format of the coefficient table: @@ -66,12 +64,12 @@ void AudioPeakingFilter::reset() { void AudioPeakingFilter::setFrequency(uint32_t millihertz) { mNominalFrequency = millihertz; - if (UNLIKELY(millihertz > mNiquistFreq / 2)) { + if (CC_UNLIKELY(millihertz > mNiquistFreq / 2)) { millihertz = mNiquistFreq / 2; } uint32_t normFreq = static_cast<uint32_t>( (static_cast<uint64_t>(millihertz) * mFrequencyFactor) >> 10); - if (LIKELY(normFreq > (1 << 23))) { + if (CC_LIKELY(normFreq > (1 << 23))) { mFrequency = (Effects_log2(normFreq) - ((32-9) << 15)) << (FREQ_PRECISION_BITS - 15); } else { mFrequency = 0; @@ -107,11 +105,11 @@ void AudioPeakingFilter::getBandRange(uint32_t & low, uint32_t & high) const { int32_t halfBW = (((mBandwidth + 1) / 2) << 15) / 1200; low = static_cast<uint32_t>((static_cast<uint64_t>(mNominalFrequency) * Effects_exp2(-halfBW + (16 << 15))) >> 16); - if (UNLIKELY(halfBW >= (16 << 15))) { + if (CC_UNLIKELY(halfBW >= (16 << 15))) { high = mNiquistFreq; } else { high = static_cast<uint32_t>((static_cast<uint64_t>(mNominalFrequency) * Effects_exp2(halfBW + (16 << 15))) >> 16); - if (UNLIKELY(high > mNiquistFreq)) { + if (CC_UNLIKELY(high > mNiquistFreq)) { high = mNiquistFreq; } } diff --git a/media/libeffects/testlibs/AudioShelvingFilter.cpp b/media/libeffects/testlibs/AudioShelvingFilter.cpp index b8650ba..e031287 100644 --- a/media/libeffects/testlibs/AudioShelvingFilter.cpp +++ b/media/libeffects/testlibs/AudioShelvingFilter.cpp @@ -21,9 +21,7 @@ #include <new> #include <assert.h> - -#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) -#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) +#include <cutils/compiler.h> namespace android { // Format of the coefficient tables: @@ -71,13 +69,13 @@ void AudioShelvingFilter::reset() { void AudioShelvingFilter::setFrequency(uint32_t millihertz) { mNominalFrequency = millihertz; - if (UNLIKELY(millihertz > mNiquistFreq / 2)) { + if (CC_UNLIKELY(millihertz > mNiquistFreq / 2)) { millihertz = mNiquistFreq / 2; } uint32_t normFreq = static_cast<uint32_t>( (static_cast<uint64_t>(millihertz) * mFrequencyFactor) >> 10); uint32_t log2minFreq = (mType == kLowShelf ? (32-10) : (32-2)); - if (LIKELY(normFreq > (1U << log2minFreq))) { + if (CC_LIKELY(normFreq > (1U << log2minFreq))) { mFrequency = (Effects_log2(normFreq) - (log2minFreq << 15)) << (FREQ_PRECISION_BITS - 15); } else { mFrequency = 0; diff --git a/media/libeffects/testlibs/EffectEqualizer.cpp b/media/libeffects/testlibs/EffectEqualizer.cpp index 43f34de..5241660 100644 --- a/media/libeffects/testlibs/EffectEqualizer.cpp +++ b/media/libeffects/testlibs/EffectEqualizer.cpp @@ -114,7 +114,7 @@ struct EqualizerContext { //--- local function prototypes int Equalizer_init(EqualizerContext *pContext); -int Equalizer_configure(EqualizerContext *pContext, effect_config_t *pConfig); +int Equalizer_setConfig(EqualizerContext *pContext, effect_config_t *pConfig); int Equalizer_getParameter(AudioEqualizer * pEqualizer, int32_t *pParam, size_t *pValueSize, void *pValue); int Equalizer_setParameter(AudioEqualizer * pEqualizer, int32_t *pParam, void *pValue); @@ -224,7 +224,7 @@ extern "C" int EffectGetDescriptor(effect_uuid_t *uuid, } //---------------------------------------------------------------------------- -// Equalizer_configure() +// Equalizer_setConfig() //---------------------------------------------------------------------------- // Purpose: Set input and output audio configuration. // @@ -237,9 +237,9 @@ extern "C" int EffectGetDescriptor(effect_uuid_t *uuid, // //---------------------------------------------------------------------------- -int Equalizer_configure(EqualizerContext *pContext, effect_config_t *pConfig) +int Equalizer_setConfig(EqualizerContext *pContext, effect_config_t *pConfig) { - ALOGV("Equalizer_configure start"); + ALOGV("Equalizer_setConfig start"); CHECK_ARG(pContext != NULL); CHECK_ARG(pConfig != NULL); @@ -272,7 +272,26 @@ int Equalizer_configure(EqualizerContext *pContext, effect_config_t *pConfig) pConfig->outputCfg.accessMode); return 0; -} // end Equalizer_configure +} // end Equalizer_setConfig + +//---------------------------------------------------------------------------- +// Equalizer_getConfig() +//---------------------------------------------------------------------------- +// Purpose: Get input and output audio configuration. +// +// Inputs: +// pContext: effect engine context +// pConfig: pointer to effect_config_t structure holding input and output +// configuration parameters +// +// Outputs: +// +//---------------------------------------------------------------------------- + +void Equalizer_getConfig(EqualizerContext *pContext, effect_config_t *pConfig) +{ + memcpy(pConfig, &pContext->config, sizeof(effect_config_t)); +} // end Equalizer_getConfig //---------------------------------------------------------------------------- @@ -332,7 +351,7 @@ int Equalizer_init(EqualizerContext *pContext) pContext->pEqualizer->enable(true); - Equalizer_configure(pContext, &pContext->config); + Equalizer_setConfig(pContext, &pContext->config); return 0; } // end Equalizer_init @@ -643,16 +662,22 @@ extern "C" int Equalizer_command(effect_handle_t self, uint32_t cmdCode, uint32_ } *(int *) pReplyData = Equalizer_init(pContext); break; - case EFFECT_CMD_CONFIGURE: + case EFFECT_CMD_SET_CONFIG: if (pCmdData == NULL || cmdSize != sizeof(effect_config_t) || pReplyData == NULL || *replySize != sizeof(int)) { return -EINVAL; } - *(int *) pReplyData = Equalizer_configure(pContext, + *(int *) pReplyData = Equalizer_setConfig(pContext, (effect_config_t *) pCmdData); break; + case EFFECT_CMD_GET_CONFIG: + if (pReplyData == NULL || *replySize != sizeof(effect_config_t)) { + return -EINVAL; + } + Equalizer_getConfig(pContext, (effect_config_t *) pCmdData); + break; case EFFECT_CMD_RESET: - Equalizer_configure(pContext, &pContext->config); + Equalizer_setConfig(pContext, &pContext->config); break; case EFFECT_CMD_GET_PARAM: { if (pCmdData == NULL || cmdSize < (int)(sizeof(effect_param_t) + sizeof(int32_t)) || diff --git a/media/libeffects/testlibs/EffectReverb.c b/media/libeffects/testlibs/EffectReverb.c index d22868a..ebb72c1 100644 --- a/media/libeffects/testlibs/EffectReverb.c +++ b/media/libeffects/testlibs/EffectReverb.c @@ -318,14 +318,20 @@ static int Reverb_Command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSi pRvbModule->context.mState = REVERB_STATE_INITIALIZED; } break; - case EFFECT_CMD_CONFIGURE: + case EFFECT_CMD_SET_CONFIG: if (pCmdData == NULL || cmdSize != sizeof(effect_config_t) || pReplyData == NULL || *replySize != sizeof(int)) { return -EINVAL; } - *(int *) pReplyData = Reverb_Configure(pRvbModule, + *(int *) pReplyData = Reverb_setConfig(pRvbModule, (effect_config_t *)pCmdData, false); break; + case EFFECT_CMD_GET_CONFIG: + if (pReplyData == NULL || *replySize != sizeof(effect_config_t)) { + return -EINVAL; + } + Reverb_getConfig(pRvbModule, (effect_config_t *) pCmdData); + break; case EFFECT_CMD_RESET: Reverb_Reset(pReverb, false); break; @@ -492,7 +498,7 @@ int Reverb_Init(reverb_module_t *pRvbModule, int aux, int preset) { pRvbModule->config.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE; pRvbModule->config.outputCfg.mask = EFFECT_CONFIG_ALL; - ret = Reverb_Configure(pRvbModule, &pRvbModule->config, true); + ret = Reverb_setConfig(pRvbModule, &pRvbModule->config, true); if (ret < 0) { ALOGV("Reverb_Init error %d on module %p", ret, pRvbModule); } @@ -501,7 +507,7 @@ int Reverb_Init(reverb_module_t *pRvbModule, int aux, int preset) { } /*---------------------------------------------------------------------------- - * Reverb_Init() + * Reverb_setConfig() *---------------------------------------------------------------------------- * Purpose: * Set input and output audio configuration. @@ -518,7 +524,7 @@ int Reverb_Init(reverb_module_t *pRvbModule, int aux, int preset) { *---------------------------------------------------------------------------- */ -int Reverb_Configure(reverb_module_t *pRvbModule, effect_config_t *pConfig, +int Reverb_setConfig(reverb_module_t *pRvbModule, effect_config_t *pConfig, bool init) { reverb_object_t *pReverb = &pRvbModule->context; int bufferSizeInSamples; @@ -531,12 +537,12 @@ int Reverb_Configure(reverb_module_t *pRvbModule, effect_config_t *pConfig, || pConfig->outputCfg.channels != OUTPUT_CHANNELS || pConfig->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT || pConfig->outputCfg.format != AUDIO_FORMAT_PCM_16_BIT) { - ALOGV("Reverb_Configure invalid config"); + ALOGV("Reverb_setConfig invalid config"); return -EINVAL; } if ((pReverb->m_Aux && (pConfig->inputCfg.channels != AUDIO_CHANNEL_OUT_MONO)) || (!pReverb->m_Aux && (pConfig->inputCfg.channels != AUDIO_CHANNEL_OUT_STEREO))) { - ALOGV("Reverb_Configure invalid config"); + ALOGV("Reverb_setConfig invalid config"); return -EINVAL; } @@ -576,7 +582,7 @@ int Reverb_Configure(reverb_module_t *pRvbModule, effect_config_t *pConfig, pReverb->m_nCosWT_5KHz = 25997; break; default: - ALOGV("Reverb_Configure invalid sampling rate %d", pReverb->m_nSamplingRate); + ALOGV("Reverb_setConfig invalid sampling rate %d", pReverb->m_nSamplingRate); return -EINVAL; } @@ -620,6 +626,28 @@ int Reverb_Configure(reverb_module_t *pRvbModule, effect_config_t *pConfig, } /*---------------------------------------------------------------------------- + * Reverb_getConfig() + *---------------------------------------------------------------------------- + * Purpose: + * Get input and output audio configuration. + * + * Inputs: + * pRvbModule - pointer to reverb effect module + * pConfig - pointer to effect_config_t structure containing input + * and output audio parameters configuration + * Outputs: + * + * Side Effects: + * + *---------------------------------------------------------------------------- + */ + +void Reverb_getConfig(reverb_module_t *pRvbModule, effect_config_t *pConfig) +{ + memcpy(pConfig, &pRvbModule->config, sizeof(effect_config_t)); +} + +/*---------------------------------------------------------------------------- * Reverb_Reset() *---------------------------------------------------------------------------- * Purpose: @@ -844,7 +872,7 @@ int Reverb_getParameter(reverb_object_t *pReverb, int32_t param, size_t *pSize, if (param == REVERB_PARAM_ROOM_HF_LEVEL) { break; } - pValue32 = &pProperties->decayTime; + pValue32 = (int32_t *)&pProperties->decayTime; /* FALL THROUGH */ case REVERB_PARAM_DECAY_TIME: @@ -916,7 +944,7 @@ int Reverb_getParameter(reverb_object_t *pReverb, int32_t param, size_t *pSize, if (param == REVERB_PARAM_REFLECTIONS_LEVEL) { break; } - pValue32 = &pProperties->reflectionsDelay; + pValue32 = (int32_t *)&pProperties->reflectionsDelay; /* FALL THROUGH */ case REVERB_PARAM_REFLECTIONS_DELAY: @@ -940,7 +968,7 @@ int Reverb_getParameter(reverb_object_t *pReverb, int32_t param, size_t *pSize, if (param == REVERB_PARAM_REVERB_LEVEL) { break; } - pValue32 = &pProperties->reverbDelay; + pValue32 = (int32_t *)&pProperties->reverbDelay; /* FALL THROUGH */ case REVERB_PARAM_REVERB_DELAY: diff --git a/media/libeffects/testlibs/EffectReverb.h b/media/libeffects/testlibs/EffectReverb.h index 8e2cc31..5137074 100644 --- a/media/libeffects/testlibs/EffectReverb.h +++ b/media/libeffects/testlibs/EffectReverb.h @@ -329,7 +329,8 @@ static int Reverb_GetDescriptor(effect_handle_t self, */ int Reverb_Init(reverb_module_t *pRvbModule, int aux, int preset); -int Reverb_Configure(reverb_module_t *pRvbModule, effect_config_t *pConfig, bool init); +int Reverb_setConfig(reverb_module_t *pRvbModule, effect_config_t *pConfig, bool init); +void Reverb_getConfig(reverb_module_t *pRvbModule, effect_config_t *pConfig); void Reverb_Reset(reverb_object_t *pReverb, bool init); int Reverb_setParameter (reverb_object_t *pReverb, int32_t param, size_t size, void *pValue); diff --git a/media/libeffects/visualizer/EffectVisualizer.cpp b/media/libeffects/visualizer/EffectVisualizer.cpp index c441710..5d70a9b 100644 --- a/media/libeffects/visualizer/EffectVisualizer.cpp +++ b/media/libeffects/visualizer/EffectVisualizer.cpp @@ -78,7 +78,7 @@ void Visualizer_reset(VisualizerContext *pContext) } //---------------------------------------------------------------------------- -// Visualizer_configure() +// Visualizer_setConfig() //---------------------------------------------------------------------------- // Purpose: Set input and output audio configuration. // @@ -91,9 +91,9 @@ void Visualizer_reset(VisualizerContext *pContext) // //---------------------------------------------------------------------------- -int Visualizer_configure(VisualizerContext *pContext, effect_config_t *pConfig) +int Visualizer_setConfig(VisualizerContext *pContext, effect_config_t *pConfig) { - ALOGV("Visualizer_configure start"); + ALOGV("Visualizer_setConfig start"); if (pConfig->inputCfg.samplingRate != pConfig->outputCfg.samplingRate) return -EINVAL; if (pConfig->inputCfg.channels != pConfig->outputCfg.channels) return -EINVAL; @@ -112,6 +112,26 @@ int Visualizer_configure(VisualizerContext *pContext, effect_config_t *pConfig) //---------------------------------------------------------------------------- +// Visualizer_getConfig() +//---------------------------------------------------------------------------- +// Purpose: Get input and output audio configuration. +// +// Inputs: +// pContext: effect engine context +// pConfig: pointer to effect_config_t structure holding input and output +// configuration parameters +// +// Outputs: +// +//---------------------------------------------------------------------------- + +void Visualizer_getConfig(VisualizerContext *pContext, effect_config_t *pConfig) +{ + memcpy(pConfig, &pContext->mConfig, sizeof(effect_config_t)); +} + + +//---------------------------------------------------------------------------- // Visualizer_init() //---------------------------------------------------------------------------- // Purpose: Initialize engine with default configuration. @@ -144,7 +164,7 @@ int Visualizer_init(VisualizerContext *pContext) pContext->mCaptureSize = VISUALIZER_CAPTURE_SIZE_MAX; - Visualizer_configure(pContext, &pContext->mConfig); + Visualizer_setConfig(pContext, &pContext->mConfig); return 0; } @@ -337,14 +357,21 @@ int Visualizer_command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize, } *(int *) pReplyData = Visualizer_init(pContext); break; - case EFFECT_CMD_CONFIGURE: + case EFFECT_CMD_SET_CONFIG: if (pCmdData == NULL || cmdSize != sizeof(effect_config_t) || pReplyData == NULL || *replySize != sizeof(int)) { return -EINVAL; } - *(int *) pReplyData = Visualizer_configure(pContext, + *(int *) pReplyData = Visualizer_setConfig(pContext, (effect_config_t *) pCmdData); break; + case EFFECT_CMD_GET_CONFIG: + if (pReplyData == NULL || + *replySize != sizeof(effect_config_t)) { + return -EINVAL; + } + Visualizer_getConfig(pContext, (effect_config_t *)pReplyData); + break; case EFFECT_CMD_RESET: Visualizer_reset(pContext); break; diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk index 7af4a87..23670df 100644 --- a/media/libmedia/Android.mk +++ b/media/libmedia/Android.mk @@ -43,13 +43,12 @@ LOCAL_SRC_FILES:= \ IEffectClient.cpp \ AudioEffect.cpp \ Visualizer.cpp \ - MemoryLeakTrackUtil.cpp \ - fixedfft.cpp.arm + MemoryLeakTrackUtil.cpp LOCAL_SHARED_LIBRARIES := \ libui libcutils libutils libbinder libsonivox libicuuc libexpat \ libcamera_client libstagefright_foundation \ - libgui libdl + libgui libdl libaudioutils LOCAL_WHOLE_STATIC_LIBRARY := libmedia_helper @@ -61,6 +60,7 @@ LOCAL_C_INCLUDES := \ $(TOP)/frameworks/base/include/media/stagefright/openmax \ external/icu4c/common \ external/expat/lib \ - system/media/audio_effects/include + system/media/audio_effects/include \ + system/media/audio_utils/include include $(BUILD_SHARED_LIBRARY) diff --git a/media/libmedia/AudioEffect.cpp b/media/libmedia/AudioEffect.cpp index 6639d06..a242846 100644 --- a/media/libmedia/AudioEffect.cpp +++ b/media/libmedia/AudioEffect.cpp @@ -342,7 +342,7 @@ void AudioEffect::binderDied() { ALOGW("IEffect died"); mStatus = NO_INIT; - if (mCbf) { + if (mCbf != NULL) { status_t status = DEAD_OBJECT; mCbf(EVENT_ERROR, mUserData, &status); } @@ -363,7 +363,7 @@ void AudioEffect::controlStatusChanged(bool controlGranted) mStatus = ALREADY_EXISTS; } } - if (mCbf) { + if (mCbf != NULL) { mCbf(EVENT_CONTROL_STATUS_CHANGED, mUserData, &controlGranted); } } @@ -373,7 +373,7 @@ void AudioEffect::enableStatusChanged(bool enabled) ALOGV("enableStatusChanged %p enabled %d mCbf %p", this, enabled, mCbf); if (mStatus == ALREADY_EXISTS) { mEnabled = enabled; - if (mCbf) { + if (mCbf != NULL) { mCbf(EVENT_ENABLE_STATUS_CHANGED, mUserData, &enabled); } } @@ -389,7 +389,7 @@ void AudioEffect::commandExecuted(uint32_t cmdCode, return; } - if (mCbf && cmdCode == EFFECT_CMD_SET_PARAM) { + if (mCbf != NULL && cmdCode == EFFECT_CMD_SET_PARAM) { effect_param_t *cmd = (effect_param_t *)cmdData; cmd->status = *(int32_t *)replyData; mCbf(EVENT_PARAMETER_CHANGED, mUserData, cmd); diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index 34a5eb7..c96bc76 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -39,9 +39,7 @@ #include <system/audio.h> #include <cutils/bitops.h> - -#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) -#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) +#include <cutils/compiler.h> namespace android { // --------------------------------------------------------------------------- @@ -50,7 +48,7 @@ namespace android { status_t AudioRecord::getMinFrameCount( int* frameCount, uint32_t sampleRate, - int format, + audio_format_t format, int channelCount) { size_t size = 0; @@ -80,14 +78,15 @@ status_t AudioRecord::getMinFrameCount( // --------------------------------------------------------------------------- AudioRecord::AudioRecord() - : mStatus(NO_INIT), mSessionId(0) + : mStatus(NO_INIT), mSessionId(0), + mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(ANDROID_TGROUP_DEFAULT) { } AudioRecord::AudioRecord( - int inputSource, + audio_source_t inputSource, uint32_t sampleRate, - int format, + audio_format_t format, uint32_t channelMask, int frameCount, uint32_t flags, @@ -95,7 +94,8 @@ AudioRecord::AudioRecord( void* user, int notificationFrames, int sessionId) - : mStatus(NO_INIT), mSessionId(0) + : mStatus(NO_INIT), mSessionId(0), + mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(ANDROID_TGROUP_DEFAULT) { mStatus = set(inputSource, sampleRate, format, channelMask, frameCount, flags, cbf, user, notificationFrames, sessionId); @@ -119,9 +119,9 @@ AudioRecord::~AudioRecord() } status_t AudioRecord::set( - int inputSource, + audio_source_t inputSource, uint32_t sampleRate, - int format, + audio_format_t format, uint32_t channelMask, int frameCount, uint32_t flags, @@ -148,7 +148,7 @@ status_t AudioRecord::set( sampleRate = DEFAULT_SAMPLE_RATE; } // these below should probably come from the audioFlinger too... - if (format == 0) { + if (format == AUDIO_FORMAT_DEFAULT) { format = AUDIO_FORMAT_PCM_16_BIT; } // validate parameters @@ -206,11 +206,8 @@ status_t AudioRecord::set( return status; } - if (cbf != 0) { + if (cbf != NULL) { mClientRecordThread = new ClientRecordThread(*this, threadCanCallJava); - if (mClientRecordThread == 0) { - return NO_INIT; - } } mStatus = NO_ERROR; @@ -231,7 +228,7 @@ status_t AudioRecord::set( mMarkerReached = false; mNewPosition = 0; mUpdatePeriod = 0; - mInputSource = (uint8_t)inputSource; + mInputSource = inputSource; mFlags = flags; mInput = input; AudioSystem::acquireAudioSessionId(mSessionId); @@ -251,7 +248,7 @@ uint32_t AudioRecord::latency() const return mLatency; } -int AudioRecord::format() const +audio_format_t AudioRecord::format() const { return mFormat; } @@ -266,7 +263,7 @@ uint32_t AudioRecord::frameCount() const return mFrameCount; } -int AudioRecord::frameSize() const +size_t AudioRecord::frameSize() const { if (audio_is_linear_pcm(mFormat)) { return channelCount()*audio_bytes_per_sample(mFormat); @@ -275,9 +272,9 @@ int AudioRecord::frameSize() const } } -int AudioRecord::inputSource() const +audio_source_t AudioRecord::inputSource() const { - return (int)mInputSource; + return mInputSource; } // ------------------------------------------------------------------------- @@ -326,9 +323,11 @@ status_t AudioRecord::start() cblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS; cblk->waitTimeMs = 0; if (t != 0) { - t->run("ClientRecordThread", ANDROID_PRIORITY_AUDIO); + t->run("ClientRecordThread", ANDROID_PRIORITY_AUDIO); } else { - setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO); + mPreviousPriority = getpriority(PRIO_PROCESS, 0); + mPreviousSchedulingGroup = androidGetThreadSchedulingGroup(0); + androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO); } } else { mActive = 0; @@ -363,7 +362,8 @@ status_t AudioRecord::stop() if (t != 0) { t->requestExit(); } else { - setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL); + setpriority(PRIO_PROCESS, 0, mPreviousPriority); + androidSetThreadSchedulingGroup(0, mPreviousSchedulingGroup); } } @@ -387,7 +387,7 @@ uint32_t AudioRecord::getSampleRate() status_t AudioRecord::setMarkerPosition(uint32_t marker) { - if (mCbf == 0) return INVALID_OPERATION; + if (mCbf == NULL) return INVALID_OPERATION; mMarkerPosition = marker; mMarkerReached = false; @@ -397,7 +397,7 @@ status_t AudioRecord::setMarkerPosition(uint32_t marker) status_t AudioRecord::getMarkerPosition(uint32_t *marker) { - if (marker == 0) return BAD_VALUE; + if (marker == NULL) return BAD_VALUE; *marker = mMarkerPosition; @@ -406,7 +406,7 @@ status_t AudioRecord::getMarkerPosition(uint32_t *marker) status_t AudioRecord::setPositionUpdatePeriod(uint32_t updatePeriod) { - if (mCbf == 0) return INVALID_OPERATION; + if (mCbf == NULL) return INVALID_OPERATION; uint32_t curPosition; getPosition(&curPosition); @@ -418,7 +418,7 @@ status_t AudioRecord::setPositionUpdatePeriod(uint32_t updatePeriod) status_t AudioRecord::getPositionUpdatePeriod(uint32_t *updatePeriod) { - if (updatePeriod == 0) return BAD_VALUE; + if (updatePeriod == NULL) return BAD_VALUE; *updatePeriod = mUpdatePeriod; @@ -427,7 +427,7 @@ status_t AudioRecord::getPositionUpdatePeriod(uint32_t *updatePeriod) status_t AudioRecord::getPosition(uint32_t *position) { - if (position == 0) return BAD_VALUE; + if (position == NULL) return BAD_VALUE; AutoMutex lock(mLock); *position = mCblk->user; @@ -448,7 +448,7 @@ unsigned int AudioRecord::getInputFramesLost() // must be called with mLock held status_t AudioRecord::openRecord_l( uint32_t sampleRate, - uint32_t format, + audio_format_t format, uint32_t channelMask, int frameCount, uint32_t flags, @@ -508,11 +508,11 @@ status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) goto start_loop_here; while (framesReady == 0) { active = mActive; - if (UNLIKELY(!active)) { + if (CC_UNLIKELY(!active)) { cblk->lock.unlock(); return NO_MORE_BUFFERS; } - if (UNLIKELY(!waitCount)) { + if (CC_UNLIKELY(!waitCount)) { cblk->lock.unlock(); return WOULD_BLOCK; } @@ -529,7 +529,7 @@ status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) if (cblk->flags & CBLK_INVALID_MSK) { goto create_new_record; } - if (__builtin_expect(result!=NO_ERROR, false)) { + if (CC_UNLIKELY(result != NO_ERROR)) { cblk->waitTimeMs += waitTimeMs; if (cblk->waitTimeMs >= cblk->bufferTimeoutMs) { ALOGW( "obtainBuffer timed out (is the CPU pegged?) " diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index f7f129c..110a294 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -35,12 +35,13 @@ sp<IAudioFlinger> AudioSystem::gAudioFlinger; sp<AudioSystem::AudioFlingerClient> AudioSystem::gAudioFlingerClient; audio_error_callback AudioSystem::gAudioErrorCallback = NULL; // Cached values -DefaultKeyedVector<int, audio_io_handle_t> AudioSystem::gStreamOutputMap(0); + +DefaultKeyedVector<audio_stream_type_t, audio_io_handle_t> AudioSystem::gStreamOutputMap(0); DefaultKeyedVector<audio_io_handle_t, AudioSystem::OutputDescriptor *> AudioSystem::gOutputs(0); -// Cached values for recording queries +// Cached values for recording queries, all protected by gLock uint32_t AudioSystem::gPrevInSamplingRate = 16000; -int AudioSystem::gPrevInFormat = AUDIO_FORMAT_PCM_16_BIT; +audio_format_t AudioSystem::gPrevInFormat = AUDIO_FORMAT_PCM_16_BIT; int AudioSystem::gPrevInChannelCount = 1; size_t AudioSystem::gInBuffSize = 0; @@ -49,7 +50,7 @@ size_t AudioSystem::gInBuffSize = 0; const sp<IAudioFlinger>& AudioSystem::get_audio_flinger() { Mutex::Autolock _l(gLock); - if (gAudioFlinger.get() == 0) { + if (gAudioFlinger == 0) { sp<IServiceManager> sm = defaultServiceManager(); sp<IBinder> binder; do { @@ -120,7 +121,7 @@ status_t AudioSystem::getMasterMute(bool* mute) return NO_ERROR; } -status_t AudioSystem::setStreamVolume(int stream, float value, int output) +status_t AudioSystem::setStreamVolume(audio_stream_type_t stream, float value, int output) { if (uint32_t(stream) >= AUDIO_STREAM_CNT) return BAD_VALUE; const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); @@ -129,7 +130,7 @@ status_t AudioSystem::setStreamVolume(int stream, float value, int output) return NO_ERROR; } -status_t AudioSystem::setStreamMute(int stream, bool mute) +status_t AudioSystem::setStreamMute(audio_stream_type_t stream, bool mute) { if (uint32_t(stream) >= AUDIO_STREAM_CNT) return BAD_VALUE; const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); @@ -138,7 +139,7 @@ status_t AudioSystem::setStreamMute(int stream, bool mute) return NO_ERROR; } -status_t AudioSystem::getStreamVolume(int stream, float* volume, int output) +status_t AudioSystem::getStreamVolume(audio_stream_type_t stream, float* volume, int output) { if (uint32_t(stream) >= AUDIO_STREAM_CNT) return BAD_VALUE; const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); @@ -147,7 +148,7 @@ status_t AudioSystem::getStreamVolume(int stream, float* volume, int output) return NO_ERROR; } -status_t AudioSystem::getStreamMute(int stream, bool* mute) +status_t AudioSystem::getStreamMute(audio_stream_type_t stream, bool* mute) { if (uint32_t(stream) >= AUDIO_STREAM_CNT) return BAD_VALUE; const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); @@ -156,9 +157,9 @@ status_t AudioSystem::getStreamMute(int stream, bool* mute) return NO_ERROR; } -status_t AudioSystem::setMode(int mode) +status_t AudioSystem::setMode(audio_mode_t mode) { - if (mode >= AUDIO_MODE_CNT) return BAD_VALUE; + if (uint32_t(mode) >= AUDIO_MODE_CNT) return BAD_VALUE; const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); if (af == 0) return PERMISSION_DENIED; return af->setMode(mode); @@ -203,7 +204,12 @@ int AudioSystem::logToLinear(float volume) return volume ? 100 - int(dBConvertInverse * log(volume) + 0.5) : 0; } -status_t AudioSystem::getOutputSamplingRate(int* samplingRate, int streamType) +// DEPRECATED +status_t AudioSystem::getOutputSamplingRate(int* samplingRate, int streamType) { + return getOutputSamplingRate(samplingRate, (audio_stream_type_t)streamType); +} + +status_t AudioSystem::getOutputSamplingRate(int* samplingRate, audio_stream_type_t streamType) { OutputDescriptor *outputDesc; audio_io_handle_t output; @@ -212,14 +218,14 @@ status_t AudioSystem::getOutputSamplingRate(int* samplingRate, int streamType) streamType = AUDIO_STREAM_MUSIC; } - output = getOutput((audio_stream_type_t)streamType); + output = getOutput(streamType); if (output == 0) { return PERMISSION_DENIED; } gLock.lock(); outputDesc = AudioSystem::gOutputs.valueFor(output); - if (outputDesc == 0) { + if (outputDesc == NULL) { ALOGV("getOutputSamplingRate() no output descriptor for output %d in gOutputs", output); gLock.unlock(); const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); @@ -236,7 +242,12 @@ status_t AudioSystem::getOutputSamplingRate(int* samplingRate, int streamType) return NO_ERROR; } -status_t AudioSystem::getOutputFrameCount(int* frameCount, int streamType) +// DEPRECATED +status_t AudioSystem::getOutputFrameCount(int* frameCount, int streamType) { + return getOutputFrameCount(frameCount, (audio_stream_type_t)streamType); +} + +status_t AudioSystem::getOutputFrameCount(int* frameCount, audio_stream_type_t streamType) { OutputDescriptor *outputDesc; audio_io_handle_t output; @@ -245,14 +256,14 @@ status_t AudioSystem::getOutputFrameCount(int* frameCount, int streamType) streamType = AUDIO_STREAM_MUSIC; } - output = getOutput((audio_stream_type_t)streamType); + output = getOutput(streamType); if (output == 0) { return PERMISSION_DENIED; } gLock.lock(); outputDesc = AudioSystem::gOutputs.valueFor(output); - if (outputDesc == 0) { + if (outputDesc == NULL) { gLock.unlock(); const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); if (af == 0) return PERMISSION_DENIED; @@ -267,7 +278,7 @@ status_t AudioSystem::getOutputFrameCount(int* frameCount, int streamType) return NO_ERROR; } -status_t AudioSystem::getOutputLatency(uint32_t* latency, int streamType) +status_t AudioSystem::getOutputLatency(uint32_t* latency, audio_stream_type_t streamType) { OutputDescriptor *outputDesc; audio_io_handle_t output; @@ -276,14 +287,14 @@ status_t AudioSystem::getOutputLatency(uint32_t* latency, int streamType) streamType = AUDIO_STREAM_MUSIC; } - output = getOutput((audio_stream_type_t)streamType); + output = getOutput(streamType); if (output == 0) { return PERMISSION_DENIED; } gLock.lock(); outputDesc = AudioSystem::gOutputs.valueFor(output); - if (outputDesc == 0) { + if (outputDesc == NULL) { gLock.unlock(); const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); if (af == 0) return PERMISSION_DENIED; @@ -298,25 +309,30 @@ status_t AudioSystem::getOutputLatency(uint32_t* latency, int streamType) return NO_ERROR; } -status_t AudioSystem::getInputBufferSize(uint32_t sampleRate, int format, int channelCount, +status_t AudioSystem::getInputBufferSize(uint32_t sampleRate, audio_format_t format, int channelCount, size_t* buffSize) { + gLock.lock(); // Do we have a stale gInBufferSize or are we requesting the input buffer size for new values - if ((gInBuffSize == 0) || (sampleRate != gPrevInSamplingRate) || (format != gPrevInFormat) + size_t inBuffSize = gInBuffSize; + if ((inBuffSize == 0) || (sampleRate != gPrevInSamplingRate) || (format != gPrevInFormat) || (channelCount != gPrevInChannelCount)) { + gLock.unlock(); + const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); + if (af == 0) { + return PERMISSION_DENIED; + } + inBuffSize = af->getInputBufferSize(sampleRate, format, channelCount); + gLock.lock(); // save the request params gPrevInSamplingRate = sampleRate; gPrevInFormat = format; gPrevInChannelCount = channelCount; - gInBuffSize = 0; - const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); - if (af == 0) { - return PERMISSION_DENIED; - } - gInBuffSize = af->getInputBufferSize(sampleRate, format, channelCount); + gInBuffSize = inBuffSize; } - *buffSize = gInBuffSize; + gLock.unlock(); + *buffSize = inBuffSize; return NO_ERROR; } @@ -328,7 +344,7 @@ status_t AudioSystem::setVoiceVolume(float value) return af->setVoiceVolume(value); } -status_t AudioSystem::getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames, int stream) +status_t AudioSystem::getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames, audio_stream_type_t stream) { const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); if (af == 0) return PERMISSION_DENIED; @@ -337,7 +353,7 @@ status_t AudioSystem::getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames stream = AUDIO_STREAM_MUSIC; } - return af->getRenderPosition(halFrames, dspFrames, getOutput((audio_stream_type_t)stream)); + return af->getRenderPosition(halFrames, dspFrames, getOutput(stream)); } unsigned int AudioSystem::getInputFramesLost(audio_io_handle_t ioHandle) { @@ -389,7 +405,7 @@ void AudioSystem::AudioFlingerClient::binderDied(const wp<IBinder>& who) { void AudioSystem::AudioFlingerClient::ioConfigChanged(int event, int ioHandle, void *param2) { ALOGV("ioConfigChanged() event %d", event); OutputDescriptor *desc; - uint32_t stream; + audio_stream_type_t stream; if (ioHandle == 0) return; @@ -397,8 +413,8 @@ void AudioSystem::AudioFlingerClient::ioConfigChanged(int event, int ioHandle, v switch (event) { case STREAM_CONFIG_CHANGED: - if (param2 == 0) break; - stream = *(uint32_t *)param2; + if (param2 == NULL) break; + stream = *(audio_stream_type_t *)param2; ALOGV("ioConfigChanged() STREAM_CONFIG_CHANGED stream %d, output %d", stream, ioHandle); if (gStreamOutputMap.indexOfKey(stream) >= 0) { gStreamOutputMap.replaceValueFor(stream, ioHandle); @@ -409,7 +425,7 @@ void AudioSystem::AudioFlingerClient::ioConfigChanged(int event, int ioHandle, v ALOGV("ioConfigChanged() opening already existing output! %d", ioHandle); break; } - if (param2 == 0) break; + if (param2 == NULL) break; desc = (OutputDescriptor *)param2; OutputDescriptor *outputDesc = new OutputDescriptor(*desc); @@ -438,7 +454,7 @@ void AudioSystem::AudioFlingerClient::ioConfigChanged(int event, int ioHandle, v ALOGW("ioConfigChanged() modifying unknow output! %d", ioHandle); break; } - if (param2 == 0) break; + if (param2 == NULL) break; desc = (OutputDescriptor *)param2; ALOGV("ioConfigChanged() new config for output %d samplingRate %d, format %d channels %d frameCount %d latency %d", @@ -462,7 +478,7 @@ void AudioSystem::setErrorCallback(audio_error_callback cb) { gAudioErrorCallback = cb; } -bool AudioSystem::routedToA2dpOutput(int streamType) { +bool AudioSystem::routedToA2dpOutput(audio_stream_type_t streamType) { switch(streamType) { case AUDIO_STREAM_MUSIC: case AUDIO_STREAM_VOICE_CALL: @@ -484,7 +500,7 @@ sp<AudioSystem::AudioPolicyServiceClient> AudioSystem::gAudioPolicyServiceClient const sp<IAudioPolicyService>& AudioSystem::get_audio_policy_service() { gLock.lock(); - if (gAudioPolicyService.get() == 0) { + if (gAudioPolicyService == 0) { sp<IServiceManager> sm = defaultServiceManager(); sp<IBinder> binder; do { @@ -531,21 +547,15 @@ audio_policy_dev_state_t AudioSystem::getDeviceConnectionState(audio_devices_t d return aps->getDeviceConnectionState(device, device_address); } -status_t AudioSystem::setPhoneState(int state) +status_t AudioSystem::setPhoneState(audio_mode_t state) { + if (uint32_t(state) >= AUDIO_MODE_CNT) return BAD_VALUE; const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); if (aps == 0) return PERMISSION_DENIED; return aps->setPhoneState(state); } -status_t AudioSystem::setRingerMode(uint32_t mode, uint32_t mask) -{ - const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); - if (aps == 0) return PERMISSION_DENIED; - return aps->setRingerMode(mode, mask); -} - status_t AudioSystem::setForceUse(audio_policy_force_use_t usage, audio_policy_forced_cfg_t config) { const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); @@ -563,7 +573,7 @@ audio_policy_forced_cfg_t AudioSystem::getForceUse(audio_policy_force_use_t usag audio_io_handle_t AudioSystem::getOutput(audio_stream_type_t stream, uint32_t samplingRate, - uint32_t format, + audio_format_t format, uint32_t channels, audio_policy_output_flags_t flags) { @@ -621,9 +631,9 @@ void AudioSystem::releaseOutput(audio_io_handle_t output) aps->releaseOutput(output); } -audio_io_handle_t AudioSystem::getInput(int inputSource, +audio_io_handle_t AudioSystem::getInput(audio_source_t inputSource, uint32_t samplingRate, - uint32_t format, + audio_format_t format, uint32_t channels, audio_in_acoustics_t acoustics, int sessionId) @@ -663,18 +673,22 @@ status_t AudioSystem::initStreamVolume(audio_stream_type_t stream, return aps->initStreamVolume(stream, indexMin, indexMax); } -status_t AudioSystem::setStreamVolumeIndex(audio_stream_type_t stream, int index) +status_t AudioSystem::setStreamVolumeIndex(audio_stream_type_t stream, + int index, + audio_devices_t device) { const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); if (aps == 0) return PERMISSION_DENIED; - return aps->setStreamVolumeIndex(stream, index); + return aps->setStreamVolumeIndex(stream, index, device); } -status_t AudioSystem::getStreamVolumeIndex(audio_stream_type_t stream, int *index) +status_t AudioSystem::getStreamVolumeIndex(audio_stream_type_t stream, + int *index, + audio_devices_t device) { const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); if (aps == 0) return PERMISSION_DENIED; - return aps->getStreamVolumeIndex(stream, index); + return aps->getStreamVolumeIndex(stream, index, device); } uint32_t AudioSystem::getStrategyForStream(audio_stream_type_t stream) @@ -723,7 +737,7 @@ status_t AudioSystem::setEffectEnabled(int id, bool enabled) return aps->setEffectEnabled(id, enabled); } -status_t AudioSystem::isStreamActive(int stream, bool* state, uint32_t inPastMs) +status_t AudioSystem::isStreamActive(audio_stream_type_t stream, bool* state, uint32_t inPastMs) { const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); if (aps == 0) return PERMISSION_DENIED; diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index d51cd69..8c33f41 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -1,4 +1,4 @@ -/* //device/extlibs/pv/android/AudioTrack.cpp +/* frameworks/base/media/libmedia/AudioTrack.cpp ** ** Copyright 2007, The Android Open Source Project ** @@ -38,12 +38,12 @@ #include <utils/Atomic.h> #include <cutils/bitops.h> +#include <cutils/compiler.h> #include <system/audio.h> #include <system/audio_policy.h> -#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) -#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) +#include <audio_utils/primitives.h> namespace android { // --------------------------------------------------------------------------- @@ -51,7 +51,7 @@ namespace android { // static status_t AudioTrack::getMinFrameCount( int* frameCount, - int streamType, + audio_stream_type_t streamType, uint32_t sampleRate) { int afSampleRate; @@ -79,14 +79,15 @@ status_t AudioTrack::getMinFrameCount( // --------------------------------------------------------------------------- AudioTrack::AudioTrack() - : mStatus(NO_INIT) + : mStatus(NO_INIT), + mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(ANDROID_TGROUP_DEFAULT) { } AudioTrack::AudioTrack( - int streamType, + audio_stream_type_t streamType, uint32_t sampleRate, - int format, + audio_format_t format, int channelMask, int frameCount, uint32_t flags, @@ -94,7 +95,8 @@ AudioTrack::AudioTrack( void* user, int notificationFrames, int sessionId) - : mStatus(NO_INIT) + : mStatus(NO_INIT), + mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(ANDROID_TGROUP_DEFAULT) { mStatus = set(streamType, sampleRate, format, channelMask, frameCount, flags, cbf, user, notificationFrames, @@ -106,13 +108,33 @@ AudioTrack::AudioTrack( uint32_t sampleRate, int format, int channelMask, + int frameCount, + uint32_t flags, + callback_t cbf, + void* user, + int notificationFrames, + int sessionId) + : mStatus(NO_INIT), + mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(ANDROID_TGROUP_DEFAULT) +{ + mStatus = set((audio_stream_type_t)streamType, sampleRate, (audio_format_t)format, channelMask, + frameCount, flags, cbf, user, notificationFrames, + 0, false, sessionId); +} + +AudioTrack::AudioTrack( + audio_stream_type_t streamType, + uint32_t sampleRate, + audio_format_t format, + int channelMask, const sp<IMemory>& sharedBuffer, uint32_t flags, callback_t cbf, void* user, int notificationFrames, int sessionId) - : mStatus(NO_INIT) + : mStatus(NO_INIT), + mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(ANDROID_TGROUP_DEFAULT) { mStatus = set(streamType, sampleRate, format, channelMask, 0, flags, cbf, user, notificationFrames, @@ -139,9 +161,9 @@ AudioTrack::~AudioTrack() } status_t AudioTrack::set( - int streamType, + audio_stream_type_t streamType, uint32_t sampleRate, - int format, + audio_format_t format, int channelMask, int frameCount, uint32_t flags, @@ -178,7 +200,7 @@ status_t AudioTrack::set( sampleRate = afSampleRate; } // these below should probably come from the audioFlinger too... - if (format == 0) { + if (format == AUDIO_FORMAT_DEFAULT) { format = AUDIO_FORMAT_PCM_16_BIT; } if (channelMask == 0) { @@ -203,8 +225,8 @@ status_t AudioTrack::set( uint32_t channelCount = popcount(channelMask); audio_io_handle_t output = AudioSystem::getOutput( - (audio_stream_type_t)streamType, - sampleRate,format, channelMask, + streamType, + sampleRate, format, channelMask, (audio_policy_output_flags_t)flags); if (output == 0) { @@ -214,7 +236,7 @@ status_t AudioTrack::set( mVolume[LEFT] = 1.0f; mVolume[RIGHT] = 1.0f; - mSendLevel = 0; + mSendLevel = 0.0f; mFrameCount = frameCount; mNotificationFramesReq = notificationFrames; mSessionId = sessionId; @@ -223,7 +245,7 @@ status_t AudioTrack::set( // create the IAudioTrack status_t status = createTrack_l(streamType, sampleRate, - (uint32_t)format, + format, (uint32_t)channelMask, frameCount, flags, @@ -235,23 +257,19 @@ status_t AudioTrack::set( return status; } - if (cbf != 0) { + if (cbf != NULL) { mAudioTrackThread = new AudioTrackThread(*this, threadCanCallJava); - if (mAudioTrackThread == 0) { - ALOGE("Could not create callback thread"); - return NO_INIT; - } } mStatus = NO_ERROR; mStreamType = streamType; - mFormat = (uint32_t)format; + mFormat = format; mChannelMask = (uint32_t)channelMask; mChannelCount = channelCount; mSharedBuffer = sharedBuffer; mMuted = false; - mActive = 0; + mActive = false; mCbf = cbf; mUserData = user; mLoopCount = 0; @@ -278,12 +296,12 @@ uint32_t AudioTrack::latency() const return mLatency; } -int AudioTrack::streamType() const +audio_stream_type_t AudioTrack::streamType() const { return mStreamType; } -int AudioTrack::format() const +audio_format_t AudioTrack::format() const { return mFormat; } @@ -298,7 +316,7 @@ uint32_t AudioTrack::frameCount() const return mCblk->frameCount; } -int AudioTrack::frameSize() const +size_t AudioTrack::frameSize() const { if (audio_is_linear_pcm(mFormat)) { return channelCount()*audio_bytes_per_sample(mFormat); @@ -337,18 +355,20 @@ void AudioTrack::start() sp <IMemory> iMem = mCblkMemory; audio_track_cblk_t* cblk = mCblk; - if (mActive == 0) { + if (!mActive) { mFlushed = false; - mActive = 1; + mActive = true; mNewPosition = cblk->server + mUpdatePeriod; cblk->lock.lock(); cblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS; cblk->waitTimeMs = 0; android_atomic_and(~CBLK_DISABLED_ON, &cblk->flags); if (t != 0) { - t->run("AudioTrackThread", ANDROID_PRIORITY_AUDIO); + t->run("AudioTrackThread", ANDROID_PRIORITY_AUDIO); } else { - setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO); + mPreviousPriority = getpriority(PRIO_PROCESS, 0); + mPreviousSchedulingGroup = androidGetThreadSchedulingGroup(0); + androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO); } ALOGV("start %p before lock cblk %p", this, mCblk); @@ -366,11 +386,12 @@ void AudioTrack::start() cblk->lock.unlock(); if (status != NO_ERROR) { ALOGV("start() failed"); - mActive = 0; + mActive = false; if (t != 0) { t->requestExit(); } else { - setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL); + setpriority(PRIO_PROCESS, 0, mPreviousPriority); + androidSetThreadSchedulingGroup(0, mPreviousSchedulingGroup); } } } @@ -390,8 +411,8 @@ void AudioTrack::stop() } AutoMutex lock(mLock); - if (mActive == 1) { - mActive = 0; + if (mActive) { + mActive = false; mCblk->cv.signal(); mAudioTrack->stop(); // Cancel loops (If we are in the middle of a loop, playback @@ -408,7 +429,8 @@ void AudioTrack::stop() if (t != 0) { t->requestExit(); } else { - setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL); + setpriority(PRIO_PROCESS, 0, mPreviousPriority); + androidSetThreadSchedulingGroup(0, mPreviousSchedulingGroup); } } @@ -419,7 +441,8 @@ void AudioTrack::stop() bool AudioTrack::stopped() const { - return !mActive; + AutoMutex lock(mLock); + return stopped_l(); } void AudioTrack::flush() @@ -451,8 +474,8 @@ void AudioTrack::pause() { ALOGV("pause"); AutoMutex lock(mLock); - if (mActive == 1) { - mActive = 0; + if (mActive) { + mActive = false; mAudioTrack->pause(); } } @@ -470,7 +493,7 @@ bool AudioTrack::muted() const status_t AudioTrack::setVolume(float left, float right) { - if (left > 1.0f || right > 1.0f) { + if (left < 0.0f || left > 1.0f || right < 0.0f || right > 1.0f) { return BAD_VALUE; } @@ -478,8 +501,7 @@ status_t AudioTrack::setVolume(float left, float right) mVolume[LEFT] = left; mVolume[RIGHT] = right; - // write must be atomic - mCblk->volumeLR = (uint32_t(uint16_t(right * 0x1000)) << 16) | uint16_t(left * 0x1000); + mCblk->setVolumeLR((uint32_t(uint16_t(right * 0x1000)) << 16) | uint16_t(left * 0x1000)); return NO_ERROR; } @@ -497,14 +519,14 @@ void AudioTrack::getVolume(float* left, float* right) status_t AudioTrack::setAuxEffectSendLevel(float level) { ALOGV("setAuxEffectSendLevel(%f)", level); - if (level > 1.0f) { + if (level < 0.0f || level > 1.0f) { return BAD_VALUE; } AutoMutex lock(mLock); mSendLevel = level; - mCblk->sendLevel = uint16_t(level * 0x1000); + mCblk->setSendLevel(level); return NO_ERROR; } @@ -582,13 +604,13 @@ status_t AudioTrack::setLoop_l(uint32_t loopStart, uint32_t loopEnd, int loopCou status_t AudioTrack::getLoop(uint32_t *loopStart, uint32_t *loopEnd, int *loopCount) { AutoMutex lock(mLock); - if (loopStart != 0) { + if (loopStart != NULL) { *loopStart = mCblk->loopStart; } - if (loopEnd != 0) { + if (loopEnd != NULL) { *loopEnd = mCblk->loopEnd; } - if (loopCount != 0) { + if (loopCount != NULL) { if (mCblk->loopCount < 0) { *loopCount = -1; } else { @@ -601,7 +623,7 @@ status_t AudioTrack::getLoop(uint32_t *loopStart, uint32_t *loopEnd, int *loopCo status_t AudioTrack::setMarkerPosition(uint32_t marker) { - if (mCbf == 0) return INVALID_OPERATION; + if (mCbf == NULL) return INVALID_OPERATION; mMarkerPosition = marker; mMarkerReached = false; @@ -611,7 +633,7 @@ status_t AudioTrack::setMarkerPosition(uint32_t marker) status_t AudioTrack::getMarkerPosition(uint32_t *marker) { - if (marker == 0) return BAD_VALUE; + if (marker == NULL) return BAD_VALUE; *marker = mMarkerPosition; @@ -620,7 +642,7 @@ status_t AudioTrack::getMarkerPosition(uint32_t *marker) status_t AudioTrack::setPositionUpdatePeriod(uint32_t updatePeriod) { - if (mCbf == 0) return INVALID_OPERATION; + if (mCbf == NULL) return INVALID_OPERATION; uint32_t curPosition; getPosition(&curPosition); @@ -632,7 +654,7 @@ status_t AudioTrack::setPositionUpdatePeriod(uint32_t updatePeriod) status_t AudioTrack::getPositionUpdatePeriod(uint32_t *updatePeriod) { - if (updatePeriod == 0) return BAD_VALUE; + if (updatePeriod == NULL) return BAD_VALUE; *updatePeriod = mUpdatePeriod; @@ -642,9 +664,10 @@ status_t AudioTrack::getPositionUpdatePeriod(uint32_t *updatePeriod) status_t AudioTrack::setPosition(uint32_t position) { AutoMutex lock(mLock); - Mutex::Autolock _l(mCblk->lock); - if (!stopped()) return INVALID_OPERATION; + if (!stopped_l()) return INVALID_OPERATION; + + Mutex::Autolock _l(mCblk->lock); if (position > mCblk->user) return BAD_VALUE; @@ -656,7 +679,7 @@ status_t AudioTrack::setPosition(uint32_t position) status_t AudioTrack::getPosition(uint32_t *position) { - if (position == 0) return BAD_VALUE; + if (position == NULL) return BAD_VALUE; AutoMutex lock(mLock); *position = mFlushed ? 0 : mCblk->server; @@ -667,7 +690,7 @@ status_t AudioTrack::reload() { AutoMutex lock(mLock); - if (!stopped()) return INVALID_OPERATION; + if (!stopped_l()) return INVALID_OPERATION; flush_l(); @@ -685,7 +708,7 @@ audio_io_handle_t AudioTrack::getOutput() // must be called with mLock held audio_io_handle_t AudioTrack::getOutput_l() { - return AudioSystem::getOutput((audio_stream_type_t)mStreamType, + return AudioSystem::getOutput(mStreamType, mCblk->sampleRate, mFormat, mChannelMask, (audio_policy_output_flags_t)mFlags); } @@ -708,9 +731,9 @@ status_t AudioTrack::attachAuxEffect(int effectId) // must be called with mLock held status_t AudioTrack::createTrack_l( - int streamType, + audio_stream_type_t streamType, uint32_t sampleRate, - uint32_t format, + audio_format_t format, uint32_t channelMask, int frameCount, uint32_t flags, @@ -802,9 +825,7 @@ status_t AudioTrack::createTrack_l( ALOGE("Could not get control block"); return NO_INIT; } - mAudioTrack.clear(); mAudioTrack = track; - mCblkMemory.clear(); mCblkMemory = cblk; mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer()); android_atomic_or(CBLK_DIRECTION_OUT, &mCblk->flags); @@ -816,8 +837,8 @@ status_t AudioTrack::createTrack_l( mCblk->stepUser(mCblk->frameCount); } - mCblk->volumeLR = (uint32_t(uint16_t(mVolume[RIGHT] * 0x1000)) << 16) | uint16_t(mVolume[LEFT] * 0x1000); - mCblk->sendLevel = uint16_t(mSendLevel * 0x1000); + mCblk->setVolumeLR((uint32_t(uint16_t(mVolume[RIGHT] * 0x1000)) << 16) | uint16_t(mVolume[LEFT] * 0x1000)); + mCblk->setSendLevel(mSendLevel); mAudioTrack->attachAuxEffect(mAuxEffectId); mCblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS; mCblk->waitTimeMs = 0; @@ -829,7 +850,7 @@ status_t AudioTrack::createTrack_l( status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) { AutoMutex lock(mLock); - int active; + bool active; status_t result = NO_ERROR; audio_track_cblk_t* cblk = mCblk; uint32_t framesReq = audioBuffer->frameCount; @@ -851,12 +872,12 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) goto start_loop_here; while (framesAvail == 0) { active = mActive; - if (UNLIKELY(!active)) { + if (CC_UNLIKELY(!active)) { ALOGV("Not active and NO_MORE_BUFFERS"); cblk->lock.unlock(); return NO_MORE_BUFFERS; } - if (UNLIKELY(!waitCount)) { + if (CC_UNLIKELY(!waitCount)) { cblk->lock.unlock(); return WOULD_BLOCK; } @@ -865,7 +886,7 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs)); cblk->lock.unlock(); mLock.lock(); - if (mActive == 0) { + if (!mActive) { return status_t(STOPPED); } cblk->lock.lock(); @@ -874,7 +895,7 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) if (cblk->flags & CBLK_INVALID_MSK) { goto create_new_track; } - if (__builtin_expect(result!=NO_ERROR, false)) { + if (CC_UNLIKELY(result != NO_ERROR)) { cblk->waitTimeMs += waitTimeMs; if (cblk->waitTimeMs >= cblk->bufferTimeoutMs) { // timing out when a loop has been set and we have already written upto loop end @@ -978,7 +999,7 @@ ssize_t AudioTrack::write(const void* buffer, size_t userSize) ssize_t written = 0; const int8_t *src = (const int8_t *)buffer; Buffer audioBuffer; - size_t frameSz = (size_t)frameSize(); + size_t frameSz = frameSize(); do { audioBuffer.frameCount = userSize/frameSz; @@ -998,12 +1019,7 @@ ssize_t AudioTrack::write(const void* buffer, size_t userSize) if (mFormat == AUDIO_FORMAT_PCM_8_BIT && !(mFlags & AUDIO_POLICY_OUTPUT_FLAG_DIRECT)) { // Divide capacity by 2 to take expansion into account toWrite = audioBuffer.size>>1; - // 8 to 16 bit conversion - int count = toWrite; - int16_t *dst = (int16_t *)(audioBuffer.i8); - while(count--) { - *dst++ = (int16_t)(*src++^0x80) << 8; - } + memcpy_to_i16_from_u8(audioBuffer.i16, (const uint8_t *) src, toWrite); } else { toWrite = audioBuffer.size; memcpy(audioBuffer.i8, src, toWrite); @@ -1032,10 +1048,11 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread) sp <IAudioTrack> audioTrack = mAudioTrack; sp <IMemory> iMem = mCblkMemory; audio_track_cblk_t* cblk = mCblk; + bool active = mActive; mLock.unlock(); // Manage underrun callback - if (mActive && (cblk->framesAvailable() == cblk->frameCount)) { + if (active && (cblk->framesAvailable() == cblk->frameCount)) { ALOGV("Underrun user: %x, server: %x, flags %04x", cblk->user, cblk->server, cblk->flags); if (!(android_atomic_or(CBLK_UNDERRUN_ON, &cblk->flags) & CBLK_UNDERRUN_MSK)) { mCbf(EVENT_UNDERRUN, mUserData, 0); @@ -1123,19 +1140,14 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread) if (writtenSize > reqSize) writtenSize = reqSize; if (mFormat == AUDIO_FORMAT_PCM_8_BIT && !(mFlags & AUDIO_POLICY_OUTPUT_FLAG_DIRECT)) { - // 8 to 16 bit conversion - const int8_t *src = audioBuffer.i8 + writtenSize-1; - int count = writtenSize; - int16_t *dst = audioBuffer.i16 + writtenSize-1; - while(count--) { - *dst-- = (int16_t)(*src--^0x80) << 8; - } + // 8 to 16 bit conversion, note that source and destination are the same address + memcpy_to_i16_from_u8(audioBuffer.i16, (const uint8_t *) audioBuffer.i8, writtenSize); writtenSize <<= 1; } audioBuffer.size = writtenSize; // NOTE: mCblk->frameSize is not equal to AudioTrack::frameSize() for - // 8 bit PCM data: in this case, mCblk->frameSize is based on a sampel size of + // 8 bit PCM data: in this case, mCblk->frameSize is based on a sample size of // 16 bit. audioBuffer.frameCount = writtenSize/mCblk->frameSize; @@ -1307,15 +1319,15 @@ void AudioTrack::AudioTrackThread::onFirstRef() audio_track_cblk_t::audio_track_cblk_t() : lock(Mutex::SHARED), cv(Condition::SHARED), user(0), server(0), - userBase(0), serverBase(0), buffers(0), frameCount(0), - loopStart(UINT_MAX), loopEnd(UINT_MAX), loopCount(0), volumeLR(0), - sendLevel(0), flags(0) + userBase(0), serverBase(0), buffers(NULL), frameCount(0), + loopStart(UINT_MAX), loopEnd(UINT_MAX), loopCount(0), mVolumeLR(0x10001000), + mSendLevel(0), flags(0) { } uint32_t audio_track_cblk_t::stepUser(uint32_t frameCount) { - uint32_t u = this->user; + uint32_t u = user; u += frameCount; // Ensure that user is never ahead of server for AudioRecord @@ -1324,16 +1336,16 @@ uint32_t audio_track_cblk_t::stepUser(uint32_t frameCount) if (bufferTimeoutMs == MAX_STARTUP_TIMEOUT_MS-1) { bufferTimeoutMs = MAX_RUN_TIMEOUT_MS; } - } else if (u > this->server) { - ALOGW("stepServer occured after track reset"); - u = this->server; + } else if (u > server) { + ALOGW("stepServer occurred after track reset"); + u = server; } if (u >= userBase + this->frameCount) { userBase += this->frameCount; } - this->user = u; + user = u; // Clear flow control error condition as new data has been written/read to/from buffer. if (flags & CBLK_UNDERRUN_MSK) { @@ -1350,7 +1362,7 @@ bool audio_track_cblk_t::stepServer(uint32_t frameCount) return false; } - uint32_t s = this->server; + uint32_t s = server; s += frameCount; if (flags & CBLK_DIRECTION_MSK) { @@ -1363,9 +1375,9 @@ bool audio_track_cblk_t::stepServer(uint32_t frameCount) // while the mixer is processing a block: in this case, // stepServer() is called After the flush() has reset u & s and // we have s > u - if (s > this->user) { - ALOGW("stepServer occured after track reset"); - s = this->user; + if (s > user) { + ALOGW("stepServer occurred after track reset"); + s = user; } } @@ -1381,7 +1393,7 @@ bool audio_track_cblk_t::stepServer(uint32_t frameCount) serverBase += this->frameCount; } - this->server = s; + server = s; if (!(flags & CBLK_INVALID_MSK)) { cv.signal(); @@ -1392,7 +1404,7 @@ bool audio_track_cblk_t::stepServer(uint32_t frameCount) void* audio_track_cblk_t::buffer(uint32_t offset) const { - return (int8_t *)this->buffers + (offset - userBase) * this->frameSize; + return (int8_t *)buffers + (offset - userBase) * frameSize; } uint32_t audio_track_cblk_t::framesAvailable() @@ -1403,8 +1415,8 @@ uint32_t audio_track_cblk_t::framesAvailable() uint32_t audio_track_cblk_t::framesAvailable_l() { - uint32_t u = this->user; - uint32_t s = this->server; + uint32_t u = user; + uint32_t s = server; if (flags & CBLK_DIRECTION_MSK) { uint32_t limit = (s < loopStart) ? s : loopStart; @@ -1416,8 +1428,8 @@ uint32_t audio_track_cblk_t::framesAvailable_l() uint32_t audio_track_cblk_t::framesReady() { - uint32_t u = this->user; - uint32_t s = this->server; + uint32_t u = user; + uint32_t s = server; if (flags & CBLK_DIRECTION_MSK) { if (u < loopEnd) { @@ -1462,4 +1474,3 @@ bool audio_track_cblk_t::tryLock() // ------------------------------------------------------------------------- }; // namespace android - diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp index abd491f..fc5520f 100644 --- a/media/libmedia/IAudioFlinger.cpp +++ b/media/libmedia/IAudioFlinger.cpp @@ -82,9 +82,9 @@ public: virtual sp<IAudioTrack> createTrack( pid_t pid, - int streamType, + audio_stream_type_t streamType, uint32_t sampleRate, - uint32_t format, + audio_format_t format, uint32_t channelMask, int frameCount, uint32_t flags, @@ -97,7 +97,7 @@ public: sp<IAudioTrack> track; data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); data.writeInt32(pid); - data.writeInt32(streamType); + data.writeInt32((int32_t) streamType); data.writeInt32(sampleRate); data.writeInt32(format); data.writeInt32(channelMask); @@ -131,7 +131,7 @@ public: pid_t pid, int input, uint32_t sampleRate, - uint32_t format, + audio_format_t format, uint32_t channelMask, int frameCount, uint32_t flags, @@ -188,13 +188,13 @@ public: return reply.readInt32(); } - virtual uint32_t format(int output) const + virtual audio_format_t format(int output) const { Parcel data, reply; data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); data.writeInt32(output); remote()->transact(FORMAT, data, &reply); - return reply.readInt32(); + return (audio_format_t) reply.readInt32(); } virtual size_t frameCount(int output) const @@ -249,47 +249,47 @@ public: return reply.readInt32(); } - virtual status_t setStreamVolume(int stream, float value, int output) + virtual status_t setStreamVolume(audio_stream_type_t stream, float value, int output) { Parcel data, reply; data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); - data.writeInt32(stream); + data.writeInt32((int32_t) stream); data.writeFloat(value); data.writeInt32(output); remote()->transact(SET_STREAM_VOLUME, data, &reply); return reply.readInt32(); } - virtual status_t setStreamMute(int stream, bool muted) + virtual status_t setStreamMute(audio_stream_type_t stream, bool muted) { Parcel data, reply; data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); - data.writeInt32(stream); + data.writeInt32((int32_t) stream); data.writeInt32(muted); remote()->transact(SET_STREAM_MUTE, data, &reply); return reply.readInt32(); } - virtual float streamVolume(int stream, int output) const + virtual float streamVolume(audio_stream_type_t stream, int output) const { Parcel data, reply; data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); - data.writeInt32(stream); + data.writeInt32((int32_t) stream); data.writeInt32(output); remote()->transact(STREAM_VOLUME, data, &reply); return reply.readFloat(); } - virtual bool streamMute(int stream) const + virtual bool streamMute(audio_stream_type_t stream) const { Parcel data, reply; data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); - data.writeInt32(stream); + data.writeInt32((int32_t) stream); remote()->transact(STREAM_MUTE, data, &reply); return reply.readInt32(); } - virtual status_t setMode(int mode) + virtual status_t setMode(audio_mode_t mode) { Parcel data, reply; data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); @@ -343,7 +343,7 @@ public: remote()->transact(REGISTER_CLIENT, data, &reply); } - virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount) + virtual size_t getInputBufferSize(uint32_t sampleRate, audio_format_t format, int channelCount) { Parcel data, reply; data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); @@ -356,7 +356,7 @@ public: virtual int openOutput(uint32_t *pDevices, uint32_t *pSamplingRate, - uint32_t *pFormat, + audio_format_t *pFormat, uint32_t *pChannels, uint32_t *pLatencyMs, uint32_t flags) @@ -364,7 +364,7 @@ public: Parcel data, reply; uint32_t devices = pDevices ? *pDevices : 0; uint32_t samplingRate = pSamplingRate ? *pSamplingRate : 0; - uint32_t format = pFormat ? *pFormat : 0; + audio_format_t format = pFormat ? *pFormat : AUDIO_FORMAT_DEFAULT; uint32_t channels = pChannels ? *pChannels : 0; uint32_t latency = pLatencyMs ? *pLatencyMs : 0; @@ -382,7 +382,7 @@ public: if (pDevices) *pDevices = devices; samplingRate = reply.readInt32(); if (pSamplingRate) *pSamplingRate = samplingRate; - format = reply.readInt32(); + format = (audio_format_t) reply.readInt32(); if (pFormat) *pFormat = format; channels = reply.readInt32(); if (pChannels) *pChannels = channels; @@ -430,14 +430,14 @@ public: virtual int openInput(uint32_t *pDevices, uint32_t *pSamplingRate, - uint32_t *pFormat, + audio_format_t *pFormat, uint32_t *pChannels, - uint32_t acoustics) + audio_in_acoustics_t acoustics) { Parcel data, reply; uint32_t devices = pDevices ? *pDevices : 0; uint32_t samplingRate = pSamplingRate ? *pSamplingRate : 0; - uint32_t format = pFormat ? *pFormat : 0; + audio_format_t format = pFormat ? *pFormat : AUDIO_FORMAT_DEFAULT; uint32_t channels = pChannels ? *pChannels : 0; data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); @@ -445,14 +445,14 @@ public: data.writeInt32(samplingRate); data.writeInt32(format); data.writeInt32(channels); - data.writeInt32(acoustics); + data.writeInt32((int32_t) acoustics); remote()->transact(OPEN_INPUT, data, &reply); int input = reply.readInt32(); devices = reply.readInt32(); if (pDevices) *pDevices = devices; samplingRate = reply.readInt32(); if (pSamplingRate) *pSamplingRate = samplingRate; - format = reply.readInt32(); + format = (audio_format_t) reply.readInt32(); if (pFormat) *pFormat = format; channels = reply.readInt32(); if (pChannels) *pChannels = channels; @@ -468,11 +468,11 @@ public: return reply.readInt32(); } - virtual status_t setStreamOutput(uint32_t stream, int output) + virtual status_t setStreamOutput(audio_stream_type_t stream, int output) { Parcel data, reply; data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); - data.writeInt32(stream); + data.writeInt32((int32_t) stream); data.writeInt32(output); remote()->transact(SET_STREAM_OUTPUT, data, &reply); return reply.readInt32(); @@ -640,7 +640,7 @@ public: *id = tmp; } tmp = reply.readInt32(); - if (enabled) { + if (enabled != NULL) { *enabled = tmp; } effect = interface_cast<IEffect>(reply.readStrongBinder()); @@ -678,7 +678,7 @@ status_t BnAudioFlinger::onTransact( pid_t pid = data.readInt32(); int streamType = data.readInt32(); uint32_t sampleRate = data.readInt32(); - int format = data.readInt32(); + audio_format_t format = (audio_format_t) data.readInt32(); int channelCount = data.readInt32(); size_t bufferCount = data.readInt32(); uint32_t flags = data.readInt32(); @@ -687,7 +687,7 @@ status_t BnAudioFlinger::onTransact( int sessionId = data.readInt32(); status_t status; sp<IAudioTrack> track = createTrack(pid, - streamType, sampleRate, format, + (audio_stream_type_t) streamType, sampleRate, format, channelCount, bufferCount, flags, buffer, output, &sessionId, &status); reply->writeInt32(sessionId); reply->writeInt32(status); @@ -699,7 +699,7 @@ status_t BnAudioFlinger::onTransact( pid_t pid = data.readInt32(); int input = data.readInt32(); uint32_t sampleRate = data.readInt32(); - int format = data.readInt32(); + audio_format_t format = (audio_format_t) data.readInt32(); int channelCount = data.readInt32(); size_t bufferCount = data.readInt32(); uint32_t flags = data.readInt32(); @@ -762,31 +762,31 @@ status_t BnAudioFlinger::onTransact( int stream = data.readInt32(); float volume = data.readFloat(); int output = data.readInt32(); - reply->writeInt32( setStreamVolume(stream, volume, output) ); + reply->writeInt32( setStreamVolume((audio_stream_type_t) stream, volume, output) ); return NO_ERROR; } break; case SET_STREAM_MUTE: { CHECK_INTERFACE(IAudioFlinger, data, reply); int stream = data.readInt32(); - reply->writeInt32( setStreamMute(stream, data.readInt32()) ); + reply->writeInt32( setStreamMute((audio_stream_type_t) stream, data.readInt32()) ); return NO_ERROR; } break; case STREAM_VOLUME: { CHECK_INTERFACE(IAudioFlinger, data, reply); int stream = data.readInt32(); int output = data.readInt32(); - reply->writeFloat( streamVolume(stream, output) ); + reply->writeFloat( streamVolume((audio_stream_type_t) stream, output) ); return NO_ERROR; } break; case STREAM_MUTE: { CHECK_INTERFACE(IAudioFlinger, data, reply); int stream = data.readInt32(); - reply->writeInt32( streamMute(stream) ); + reply->writeInt32( streamMute((audio_stream_type_t) stream) ); return NO_ERROR; } break; case SET_MODE: { CHECK_INTERFACE(IAudioFlinger, data, reply); - int mode = data.readInt32(); + audio_mode_t mode = (audio_mode_t) data.readInt32(); reply->writeInt32( setMode(mode) ); return NO_ERROR; } break; @@ -825,7 +825,7 @@ status_t BnAudioFlinger::onTransact( case GET_INPUTBUFFERSIZE: { CHECK_INTERFACE(IAudioFlinger, data, reply); uint32_t sampleRate = data.readInt32(); - int format = data.readInt32(); + audio_format_t format = (audio_format_t) data.readInt32(); int channelCount = data.readInt32(); reply->writeInt32( getInputBufferSize(sampleRate, format, channelCount) ); return NO_ERROR; @@ -834,7 +834,7 @@ status_t BnAudioFlinger::onTransact( CHECK_INTERFACE(IAudioFlinger, data, reply); uint32_t devices = data.readInt32(); uint32_t samplingRate = data.readInt32(); - uint32_t format = data.readInt32(); + audio_format_t format = (audio_format_t) data.readInt32(); uint32_t channels = data.readInt32(); uint32_t latency = data.readInt32(); uint32_t flags = data.readInt32(); @@ -879,15 +879,15 @@ status_t BnAudioFlinger::onTransact( CHECK_INTERFACE(IAudioFlinger, data, reply); uint32_t devices = data.readInt32(); uint32_t samplingRate = data.readInt32(); - uint32_t format = data.readInt32(); + audio_format_t format = (audio_format_t) data.readInt32(); uint32_t channels = data.readInt32(); - uint32_t acoutics = data.readInt32(); + audio_in_acoustics_t acoustics = (audio_in_acoustics_t) data.readInt32(); int input = openInput(&devices, &samplingRate, &format, &channels, - acoutics); + acoustics); reply->writeInt32(input); reply->writeInt32(devices); reply->writeInt32(samplingRate); @@ -904,7 +904,7 @@ status_t BnAudioFlinger::onTransact( CHECK_INTERFACE(IAudioFlinger, data, reply); uint32_t stream = data.readInt32(); int output = data.readInt32(); - reply->writeInt32(setStreamOutput(stream, output)); + reply->writeInt32(setStreamOutput((audio_stream_type_t) stream, output)); return NO_ERROR; } break; case SET_VOICE_VOLUME: { diff --git a/media/libmedia/IAudioFlingerClient.cpp b/media/libmedia/IAudioFlingerClient.cpp index 5a3f250..9458bc0 100644 --- a/media/libmedia/IAudioFlingerClient.cpp +++ b/media/libmedia/IAudioFlingerClient.cpp @@ -73,7 +73,7 @@ status_t BnAudioFlingerClient::onTransact( CHECK_INTERFACE(IAudioFlingerClient, data, reply); int event = data.readInt32(); int ioHandle = data.readInt32(); - void *param2 = 0; + void *param2 = NULL; AudioSystem::OutputDescriptor desc; uint32_t stream; if (event == AudioSystem::STREAM_CONFIG_CHANGED) { diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp index 50b4855..99385aa4 100644 --- a/media/libmedia/IAudioPolicyService.cpp +++ b/media/libmedia/IAudioPolicyService.cpp @@ -33,7 +33,7 @@ enum { SET_DEVICE_CONNECTION_STATE = IBinder::FIRST_CALL_TRANSACTION, GET_DEVICE_CONNECTION_STATE, SET_PHONE_STATE, - SET_RINGER_MODE, + SET_RINGER_MODE, // reserved, no longer used SET_FORCE_USE, GET_FORCE_USE, GET_OUTPUT, @@ -91,7 +91,7 @@ public: return static_cast <audio_policy_dev_state_t>(reply.readInt32()); } - virtual status_t setPhoneState(int state) + virtual status_t setPhoneState(audio_mode_t state) { Parcel data, reply; data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); @@ -100,16 +100,6 @@ public: return static_cast <status_t> (reply.readInt32()); } - virtual status_t setRingerMode(uint32_t mode, uint32_t mask) - { - Parcel data, reply; - data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); - data.writeInt32(mode); - data.writeInt32(mask); - remote()->transact(SET_RINGER_MODE, data, &reply); - return static_cast <status_t> (reply.readInt32()); - } - virtual status_t setForceUse(audio_policy_force_use_t usage, audio_policy_forced_cfg_t config) { Parcel data, reply; @@ -132,7 +122,7 @@ public: virtual audio_io_handle_t getOutput( audio_stream_type_t stream, uint32_t samplingRate, - uint32_t format, + audio_format_t format, uint32_t channels, audio_policy_output_flags_t flags) { @@ -154,7 +144,7 @@ public: Parcel data, reply; data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); data.writeInt32(output); - data.writeInt32(stream); + data.writeInt32((int32_t) stream); data.writeInt32(session); remote()->transact(START_OUTPUT, data, &reply); return static_cast <status_t> (reply.readInt32()); @@ -167,7 +157,7 @@ public: Parcel data, reply; data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); data.writeInt32(output); - data.writeInt32(stream); + data.writeInt32((int32_t) stream); data.writeInt32(session); remote()->transact(STOP_OUTPUT, data, &reply); return static_cast <status_t> (reply.readInt32()); @@ -182,16 +172,16 @@ public: } virtual audio_io_handle_t getInput( - int inputSource, + audio_source_t inputSource, uint32_t samplingRate, - uint32_t format, + audio_format_t format, uint32_t channels, audio_in_acoustics_t acoustics, int audioSession) { Parcel data, reply; data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); - data.writeInt32(inputSource); + data.writeInt32((int32_t) inputSource); data.writeInt32(samplingRate); data.writeInt32(static_cast <uint32_t>(format)); data.writeInt32(channels); @@ -240,21 +230,28 @@ public: return static_cast <status_t> (reply.readInt32()); } - virtual status_t setStreamVolumeIndex(audio_stream_type_t stream, int index) + virtual status_t setStreamVolumeIndex(audio_stream_type_t stream, + int index, + audio_devices_t device) { Parcel data, reply; data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); data.writeInt32(static_cast <uint32_t>(stream)); data.writeInt32(index); + data.writeInt32(static_cast <uint32_t>(device)); remote()->transact(SET_STREAM_VOLUME, data, &reply); return static_cast <status_t> (reply.readInt32()); } - virtual status_t getStreamVolumeIndex(audio_stream_type_t stream, int *index) + virtual status_t getStreamVolumeIndex(audio_stream_type_t stream, + int *index, + audio_devices_t device) { Parcel data, reply; data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); data.writeInt32(static_cast <uint32_t>(stream)); + data.writeInt32(static_cast <uint32_t>(device)); + remote()->transact(GET_STREAM_VOLUME, data, &reply); int lIndex = reply.readInt32(); if (index) *index = lIndex; @@ -324,11 +321,11 @@ public: return static_cast <status_t> (reply.readInt32()); } - virtual bool isStreamActive(int stream, uint32_t inPastMs) const + virtual bool isStreamActive(audio_stream_type_t stream, uint32_t inPastMs) const { Parcel data, reply; data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); - data.writeInt32(stream); + data.writeInt32((int32_t) stream); data.writeInt32(inPastMs); remote()->transact(IS_STREAM_ACTIVE, data, &reply); return reply.readInt32(); @@ -394,15 +391,7 @@ status_t BnAudioPolicyService::onTransact( case SET_PHONE_STATE: { CHECK_INTERFACE(IAudioPolicyService, data, reply); - reply->writeInt32(static_cast <uint32_t>(setPhoneState(data.readInt32()))); - return NO_ERROR; - } break; - - case SET_RINGER_MODE: { - CHECK_INTERFACE(IAudioPolicyService, data, reply); - uint32_t mode = data.readInt32(); - uint32_t mask = data.readInt32(); - reply->writeInt32(static_cast <uint32_t>(setRingerMode(mode, mask))); + reply->writeInt32(static_cast <uint32_t>(setPhoneState((audio_mode_t) data.readInt32()))); return NO_ERROR; } break; @@ -427,7 +416,7 @@ status_t BnAudioPolicyService::onTransact( audio_stream_type_t stream = static_cast <audio_stream_type_t>(data.readInt32()); uint32_t samplingRate = data.readInt32(); - uint32_t format = data.readInt32(); + audio_format_t format = (audio_format_t) data.readInt32(); uint32_t channels = data.readInt32(); audio_policy_output_flags_t flags = static_cast <audio_policy_output_flags_t>(data.readInt32()); @@ -472,9 +461,9 @@ status_t BnAudioPolicyService::onTransact( case GET_INPUT: { CHECK_INTERFACE(IAudioPolicyService, data, reply); - int inputSource = data.readInt32(); + audio_source_t inputSource = (audio_source_t) data.readInt32(); uint32_t samplingRate = data.readInt32(); - uint32_t format = data.readInt32(); + audio_format_t format = (audio_format_t) data.readInt32(); uint32_t channels = data.readInt32(); audio_in_acoustics_t acoustics = static_cast <audio_in_acoustics_t>(data.readInt32()); @@ -525,7 +514,10 @@ status_t BnAudioPolicyService::onTransact( audio_stream_type_t stream = static_cast <audio_stream_type_t>(data.readInt32()); int index = data.readInt32(); - reply->writeInt32(static_cast <uint32_t>(setStreamVolumeIndex(stream, index))); + audio_devices_t device = static_cast <audio_devices_t>(data.readInt32()); + reply->writeInt32(static_cast <uint32_t>(setStreamVolumeIndex(stream, + index, + device))); return NO_ERROR; } break; @@ -533,8 +525,9 @@ status_t BnAudioPolicyService::onTransact( CHECK_INTERFACE(IAudioPolicyService, data, reply); audio_stream_type_t stream = static_cast <audio_stream_type_t>(data.readInt32()); + audio_devices_t device = static_cast <audio_devices_t>(data.readInt32()); int index; - status_t status = getStreamVolumeIndex(stream, &index); + status_t status = getStreamVolumeIndex(stream, &index, device); reply->writeInt32(index); reply->writeInt32(static_cast <uint32_t>(status)); return NO_ERROR; @@ -598,9 +591,9 @@ status_t BnAudioPolicyService::onTransact( case IS_STREAM_ACTIVE: { CHECK_INTERFACE(IAudioPolicyService, data, reply); - int stream = data.readInt32(); + audio_stream_type_t stream = (audio_stream_type_t) data.readInt32(); uint32_t inPastMs = (uint32_t)data.readInt32(); - reply->writeInt32( isStreamActive(stream, inPastMs) ); + reply->writeInt32( isStreamActive((audio_stream_type_t) stream, inPastMs) ); return NO_ERROR; } break; diff --git a/media/libmedia/IAudioTrack.cpp b/media/libmedia/IAudioTrack.cpp index 0b372f3..e618619 100644 --- a/media/libmedia/IAudioTrack.cpp +++ b/media/libmedia/IAudioTrack.cpp @@ -46,6 +46,18 @@ public: { } + virtual sp<IMemory> getCblk() const + { + Parcel data, reply; + sp<IMemory> cblk; + data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor()); + status_t status = remote()->transact(GET_CBLK, data, &reply); + if (status == NO_ERROR) { + cblk = interface_cast<IMemory>(reply.readStrongBinder()); + } + return cblk; + } + virtual status_t start() { Parcel data, reply; @@ -88,18 +100,6 @@ public: remote()->transact(PAUSE, data, &reply); } - virtual sp<IMemory> getCblk() const - { - Parcel data, reply; - sp<IMemory> cblk; - data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor()); - status_t status = remote()->transact(GET_CBLK, data, &reply); - if (status == NO_ERROR) { - cblk = interface_cast<IMemory>(reply.readStrongBinder()); - } - return cblk; - } - virtual status_t attachAuxEffect(int effectId) { Parcel data, reply; diff --git a/media/libmedia/IMediaDeathNotifier.cpp b/media/libmedia/IMediaDeathNotifier.cpp index 8525482..aeb35a5 100644 --- a/media/libmedia/IMediaDeathNotifier.cpp +++ b/media/libmedia/IMediaDeathNotifier.cpp @@ -36,7 +36,7 @@ IMediaDeathNotifier::getMediaPlayerService() { ALOGV("getMediaPlayerService"); Mutex::Autolock _l(sServiceLock); - if (sMediaPlayerService.get() == 0) { + if (sMediaPlayerService == 0) { sp<IServiceManager> sm = defaultServiceManager(); sp<IBinder> binder; do { diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp index 9c1e6b7..64cc919 100644 --- a/media/libmedia/IMediaPlayer.cpp +++ b/media/libmedia/IMediaPlayer.cpp @@ -198,11 +198,11 @@ public: return reply.readInt32(); } - status_t setAudioStreamType(int type) + status_t setAudioStreamType(audio_stream_type_t stream) { Parcel data, reply; data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); - data.writeInt32(type); + data.writeInt32((int32_t) stream); remote()->transact(SET_AUDIO_STREAM_TYPE, data, &reply); return reply.readInt32(); } @@ -397,7 +397,7 @@ status_t BnMediaPlayer::onTransact( } break; case SET_AUDIO_STREAM_TYPE: { CHECK_INTERFACE(IMediaPlayer, data, reply); - reply->writeInt32(setAudioStreamType(data.readInt32())); + reply->writeInt32(setAudioStreamType((audio_stream_type_t) data.readInt32())); return NO_ERROR; } break; case SET_LOOPING: { diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp index 8e4dd04..f5b5cbd 100644 --- a/media/libmedia/IMediaPlayerService.cpp +++ b/media/libmedia/IMediaPlayerService.cpp @@ -78,7 +78,7 @@ public: return interface_cast<IMediaRecorder>(reply.readStrongBinder()); } - virtual sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) + virtual sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, audio_format_t* pFormat) { Parcel data, reply; data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor()); @@ -86,11 +86,11 @@ public: remote()->transact(DECODE_URL, data, &reply); *pSampleRate = uint32_t(reply.readInt32()); *pNumChannels = reply.readInt32(); - *pFormat = reply.readInt32(); + *pFormat = (audio_format_t) reply.readInt32(); return interface_cast<IMemory>(reply.readStrongBinder()); } - virtual sp<IMemory> decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) + virtual sp<IMemory> decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, audio_format_t* pFormat) { Parcel data, reply; data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor()); @@ -100,7 +100,7 @@ public: remote()->transact(DECODE_FD, data, &reply); *pSampleRate = uint32_t(reply.readInt32()); *pNumChannels = reply.readInt32(); - *pFormat = reply.readInt32(); + *pFormat = (audio_format_t) reply.readInt32(); return interface_cast<IMemory>(reply.readStrongBinder()); } @@ -148,11 +148,11 @@ status_t BnMediaPlayerService::onTransact( const char* url = data.readCString(); uint32_t sampleRate; int numChannels; - int format; + audio_format_t format; sp<IMemory> player = decode(url, &sampleRate, &numChannels, &format); reply->writeInt32(sampleRate); reply->writeInt32(numChannels); - reply->writeInt32(format); + reply->writeInt32((int32_t) format); reply->writeStrongBinder(player->asBinder()); return NO_ERROR; } break; @@ -163,11 +163,11 @@ status_t BnMediaPlayerService::onTransact( int64_t length = data.readInt64(); uint32_t sampleRate; int numChannels; - int format; + audio_format_t format; sp<IMemory> player = decode(fd, offset, length, &sampleRate, &numChannels, &format); reply->writeInt32(sampleRate); reply->writeInt32(numChannels); - reply->writeInt32(format); + reply->writeInt32((int32_t) format); reply->writeStrongBinder(player->asBinder()); return NO_ERROR; } break; diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp index d2f5f71..27c7e03 100644 --- a/media/libmedia/IOMX.cpp +++ b/media/libmedia/IOMX.cpp @@ -59,9 +59,10 @@ public: : BpInterface<IOMX>(impl) { } - virtual bool livesLocally(pid_t pid) { + virtual bool livesLocally(node_id node, pid_t pid) { Parcel data, reply; data.writeInterfaceToken(IOMX::getInterfaceDescriptor()); + data.writeIntPtr((intptr_t)node); data.writeInt32(pid); remote()->transact(LIVES_LOCALLY, data, &reply); @@ -417,7 +418,9 @@ status_t BnOMX::onTransact( case LIVES_LOCALLY: { CHECK_INTERFACE(IOMX, data, reply); - reply->writeInt32(livesLocally((pid_t)data.readInt32())); + node_id node = (void *)data.readIntPtr(); + pid_t pid = (pid_t)data.readInt32(); + reply->writeInt32(livesLocally(node, pid)); return OK; } diff --git a/media/libmedia/JetPlayer.cpp b/media/libmedia/JetPlayer.cpp index fa5b67a..8456db5 100644 --- a/media/libmedia/JetPlayer.cpp +++ b/media/libmedia/JetPlayer.cpp @@ -91,7 +91,7 @@ int JetPlayer::init() mAudioTrack = new AudioTrack(); mAudioTrack->set(AUDIO_STREAM_MUSIC, //TODO parametrize this pLibConfig->sampleRate, - 1, // format = PCM 16bits per sample, + AUDIO_FORMAT_PCM_16_BIT, (pLibConfig->numChannels == 2) ? AUDIO_CHANNEL_OUT_STEREO : AUDIO_CHANNEL_OUT_MONO, mTrackBufferSize, 0); @@ -100,7 +100,8 @@ int JetPlayer::init() { Mutex::Autolock l(mMutex); ALOGV("JetPlayer::init(): trying to start render thread"); - createThreadEtc(renderThread, this, "jetRenderThread", ANDROID_PRIORITY_AUDIO); + mThread = new JetPlayerThread(this); + mThread->run("jetRenderThread", ANDROID_PRIORITY_AUDIO); mCondition.wait(mMutex); } if (mTid > 0) { @@ -156,12 +157,6 @@ int JetPlayer::release() //------------------------------------------------------------------------------------------------- -int JetPlayer::renderThread(void* p) { - - return ((JetPlayer*)p)->render(); -} - -//------------------------------------------------------------------------------------------------- int JetPlayer::render() { EAS_RESULT result = EAS_FAILURE; EAS_I32 count; @@ -173,10 +168,6 @@ int JetPlayer::render() { // allocate render buffer mAudioBuffer = new EAS_PCM[pLibConfig->mixBufferSize * pLibConfig->numChannels * MIX_NUM_BUFFERS]; - if (!mAudioBuffer) { - ALOGE("JetPlayer::render(): mAudioBuffer allocate failed"); - goto threadExit; - } // signal main thread that we started { @@ -343,8 +334,8 @@ int JetPlayer::loadFromFile(const char* path) Mutex::Autolock lock(mMutex); mEasJetFileLoc = (EAS_FILE_LOCATOR) malloc(sizeof(EAS_FILE)); - memset(mJetFilePath, 0, 256); - strncpy(mJetFilePath, path, strlen(path)); + strncpy(mJetFilePath, path, sizeof(mJetFilePath)); + mJetFilePath[sizeof(mJetFilePath) - 1] = '\0'; mEasJetFileLoc->path = mJetFilePath; mEasJetFileLoc->fd = 0; diff --git a/media/libmedia/MediaScannerClient.cpp b/media/libmedia/MediaScannerClient.cpp index 40b8188..9fe1820 100644 --- a/media/libmedia/MediaScannerClient.cpp +++ b/media/libmedia/MediaScannerClient.cpp @@ -173,6 +173,7 @@ void MediaScannerClient::convertValues(uint32_t encoding) const char* source = mValues->getEntry(i); int targetLength = len * 3 + 1; char* buffer = new char[targetLength]; + // don't normally check for NULL, but in this case targetLength may be large if (!buffer) break; char* target = buffer; diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp index 35dfbb8..e6e989d 100644 --- a/media/libmedia/ToneGenerator.cpp +++ b/media/libmedia/ToneGenerator.cpp @@ -751,7 +751,7 @@ const ToneGenerator::ToneDescriptor ToneGenerator::sToneDescriptors[] = { // Used by ToneGenerator::getToneForRegion() to convert user specified supervisory tone type // to actual tone for current region. -const unsigned char ToneGenerator::sToneMappingTable[NUM_REGIONS-1][NUM_SUP_TONES] = { +const unsigned char /*tone_type*/ ToneGenerator::sToneMappingTable[NUM_REGIONS-1][NUM_SUP_TONES] = { { // ANSI TONE_ANSI_DIAL, // TONE_SUP_DIAL TONE_ANSI_BUSY, // TONE_SUP_BUSY @@ -798,7 +798,7 @@ const unsigned char ToneGenerator::sToneMappingTable[NUM_REGIONS-1][NUM_SUP_TONE // none // //////////////////////////////////////////////////////////////////////////////// -ToneGenerator::ToneGenerator(int streamType, float volume, bool threadCanCallJava) { +ToneGenerator::ToneGenerator(audio_stream_type_t streamType, float volume, bool threadCanCallJava) { ALOGV("ToneGenerator constructor: streamType=%d, volume=%f\n", streamType, volume); @@ -811,9 +811,9 @@ ToneGenerator::ToneGenerator(int streamType, float volume, bool threadCanCallJav mThreadCanCallJava = threadCanCallJava; mStreamType = streamType; mVolume = volume; - mpAudioTrack = 0; - mpToneDesc = 0; - mpNewToneDesc = 0; + mpAudioTrack = NULL; + mpToneDesc = NULL; + mpNewToneDesc = NULL; // Generate tone by chunks of 20 ms to keep cadencing precision mProcessSize = (mSamplingRate * 20) / 1000; @@ -855,7 +855,7 @@ ToneGenerator::ToneGenerator(int streamType, float volume, bool threadCanCallJav ToneGenerator::~ToneGenerator() { ALOGV("ToneGenerator destructor\n"); - if (mpAudioTrack) { + if (mpAudioTrack != NULL) { stopTone(); ALOGV("Delete Track: %p\n", mpAudioTrack); delete mpAudioTrack; @@ -878,7 +878,7 @@ ToneGenerator::~ToneGenerator() { // none // //////////////////////////////////////////////////////////////////////////////// -bool ToneGenerator::startTone(int toneType, int durationMs) { +bool ToneGenerator::startTone(tone_type toneType, int durationMs) { bool lResult = false; status_t lStatus; @@ -1012,15 +1012,11 @@ bool ToneGenerator::initAudioTrack() { if (mpAudioTrack) { delete mpAudioTrack; - mpAudioTrack = 0; + mpAudioTrack = NULL; } // Open audio track in mono, PCM 16bit, default sampling rate, default buffer size mpAudioTrack = new AudioTrack(); - if (mpAudioTrack == 0) { - ALOGE("AudioTrack allocation failed"); - goto initAudioTrack_exit; - } ALOGV("Create Track: %p\n", mpAudioTrack); mpAudioTrack->set(mStreamType, @@ -1052,7 +1048,7 @@ initAudioTrack_exit: if (mpAudioTrack) { ALOGV("Delete Track I: %p\n", mpAudioTrack); delete mpAudioTrack; - mpAudioTrack = 0; + mpAudioTrack = NULL; } return false; @@ -1321,7 +1317,7 @@ audioCallback_EndLoop: bool ToneGenerator::prepareWave() { unsigned int segmentIdx = 0; - if (!mpNewToneDesc) { + if (mpNewToneDesc == NULL) { return false; } @@ -1353,9 +1349,6 @@ bool ToneGenerator::prepareWave() { new ToneGenerator::WaveGenerator((unsigned short)mSamplingRate, frequency, TONEGEN_GAIN/lNumWaves); - if (lpWaveGen == 0) { - goto prepareWave_exit; - } mWaveGens.add(frequency, lpWaveGen); } frequency = mpNewToneDesc->segments[segmentIdx].waveFreq[++freqIdx]; @@ -1375,12 +1368,6 @@ bool ToneGenerator::prepareWave() { } return true; - -prepareWave_exit: - - clearWaveGens(); - - return false; } @@ -1447,13 +1434,13 @@ void ToneGenerator::clearWaveGens() { // none // //////////////////////////////////////////////////////////////////////////////// -int ToneGenerator::getToneForRegion(int toneType) { - int regionTone; +ToneGenerator::tone_type ToneGenerator::getToneForRegion(tone_type toneType) { + tone_type regionTone; if (mRegion == CEPT || toneType < FIRST_SUP_TONE || toneType > LAST_SUP_TONE) { regionTone = toneType; } else { - regionTone = sToneMappingTable[mRegion][toneType - FIRST_SUP_TONE]; + regionTone = (tone_type) sToneMappingTable[mRegion][toneType - FIRST_SUP_TONE]; } ALOGV("getToneForRegion, tone %d, region %d, regionTone %d", toneType, mRegion, regionTone); diff --git a/media/libmedia/Visualizer.cpp b/media/libmedia/Visualizer.cpp index d08ffa5..13b64e9 100644 --- a/media/libmedia/Visualizer.cpp +++ b/media/libmedia/Visualizer.cpp @@ -27,8 +27,7 @@ #include <cutils/bitops.h> #include <media/Visualizer.h> - -extern void fixed_fft_real(int n, int32_t *v); +#include <audio_utils/fixedfft.h> namespace android { @@ -54,7 +53,7 @@ Visualizer::~Visualizer() status_t Visualizer::setEnabled(bool enabled) { - Mutex::Autolock _l(mLock); + Mutex::Autolock _l(mCaptureLock); sp<CaptureThread> t = mCaptureThread; if (t != 0) { @@ -74,7 +73,7 @@ status_t Visualizer::setEnabled(bool enabled) if (status == NO_ERROR) { if (t != 0) { if (enabled) { - t->run("AudioTrackThread"); + t->run("Visualizer"); } else { t->requestExit(); } @@ -93,7 +92,7 @@ status_t Visualizer::setCaptureCallBack(capture_cbk_t cbk, void* user, uint32_t if (rate > CAPTURE_RATE_MAX) { return BAD_VALUE; } - Mutex::Autolock _l(mLock); + Mutex::Autolock _l(mCaptureLock); if (mEnabled) { return INVALID_OPERATION; @@ -115,10 +114,6 @@ status_t Visualizer::setCaptureCallBack(capture_cbk_t cbk, void* user, uint32_t if (cbk != NULL) { mCaptureThread = new CaptureThread(*this, rate, ((flags & CAPTURE_CALL_JAVA) != 0)); - if (mCaptureThread == 0) { - ALOGE("Could not create callback thread"); - return NO_INIT; - } } ALOGV("setCaptureCallBack() rate: %d thread %p flags 0x%08x", rate, mCaptureThread.get(), mCaptureFlags); @@ -133,7 +128,7 @@ status_t Visualizer::setCaptureSize(uint32_t size) return BAD_VALUE; } - Mutex::Autolock _l(mLock); + Mutex::Autolock _l(mCaptureLock); if (mEnabled) { return INVALID_OPERATION; } @@ -235,7 +230,7 @@ status_t Visualizer::doFft(uint8_t *fft, uint8_t *waveform) void Visualizer::periodicCapture() { - Mutex::Autolock _l(mLock); + Mutex::Autolock _l(mCaptureLock); ALOGV("periodicCapture() %p mCaptureCallBack %p mCaptureFlags 0x%08x", this, mCaptureCallBack, mCaptureFlags); if (mCaptureCallBack != NULL && diff --git a/media/libmedia/autodetect.cpp b/media/libmedia/autodetect.cpp index dfcc6a0..be5c3b2 100644 --- a/media/libmedia/autodetect.cpp +++ b/media/libmedia/autodetect.cpp @@ -16,7 +16,7 @@ #include "autodetect.h" -typedef struct CharRange { +struct CharRange { uint16_t first; uint16_t last; }; diff --git a/media/libmedia/fixedfft.cpp b/media/libmedia/fixedfft.cpp deleted file mode 100644 index 2b495e6..0000000 --- a/media/libmedia/fixedfft.cpp +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - -/* A Fixed point implementation of Fast Fourier Transform (FFT). Complex numbers - * are represented by 32-bit integers, where higher 16 bits are real part and - * lower ones are imaginary part. Few compromises are made between efficiency, - * accuracy, and maintainability. To make it fast, arithmetic shifts are used - * instead of divisions, and bitwise inverses are used instead of negates. To - * keep it small, only radix-2 Cooley-Tukey algorithm is implemented, and only - * half of the twiddle factors are stored. Although there are still ways to make - * it even faster or smaller, it costs too much on one of the aspects. - */ - -#include <stdio.h> -#include <stdint.h> -#ifdef __arm__ -#include <machine/cpu-features.h> -#endif - -#define LOG_FFT_SIZE 10 -#define MAX_FFT_SIZE (1 << LOG_FFT_SIZE) - -static const int32_t twiddle[MAX_FFT_SIZE / 4] = { - 0x00008000, 0xff378001, 0xfe6e8002, 0xfda58006, 0xfcdc800a, 0xfc13800f, - 0xfb4a8016, 0xfa81801e, 0xf9b88027, 0xf8ef8032, 0xf827803e, 0xf75e804b, - 0xf6958059, 0xf5cd8068, 0xf5058079, 0xf43c808b, 0xf374809e, 0xf2ac80b2, - 0xf1e480c8, 0xf11c80de, 0xf05580f6, 0xef8d8110, 0xeec6812a, 0xedff8146, - 0xed388163, 0xec718181, 0xebab81a0, 0xeae481c1, 0xea1e81e2, 0xe9588205, - 0xe892822a, 0xe7cd824f, 0xe7078276, 0xe642829d, 0xe57d82c6, 0xe4b982f1, - 0xe3f4831c, 0xe3308349, 0xe26d8377, 0xe1a983a6, 0xe0e683d6, 0xe0238407, - 0xdf61843a, 0xde9e846e, 0xdddc84a3, 0xdd1b84d9, 0xdc598511, 0xdb998549, - 0xdad88583, 0xda1885be, 0xd95885fa, 0xd8988637, 0xd7d98676, 0xd71b86b6, - 0xd65c86f6, 0xd59e8738, 0xd4e1877b, 0xd42487c0, 0xd3678805, 0xd2ab884c, - 0xd1ef8894, 0xd13488dd, 0xd0798927, 0xcfbe8972, 0xcf0489be, 0xce4b8a0c, - 0xcd928a5a, 0xccd98aaa, 0xcc218afb, 0xcb698b4d, 0xcab28ba0, 0xc9fc8bf5, - 0xc9468c4a, 0xc8908ca1, 0xc7db8cf8, 0xc7278d51, 0xc6738dab, 0xc5c08e06, - 0xc50d8e62, 0xc45b8ebf, 0xc3a98f1d, 0xc2f88f7d, 0xc2488fdd, 0xc198903e, - 0xc0e990a1, 0xc03a9105, 0xbf8c9169, 0xbedf91cf, 0xbe329236, 0xbd86929e, - 0xbcda9307, 0xbc2f9371, 0xbb8593dc, 0xbadc9448, 0xba3394b5, 0xb98b9523, - 0xb8e39592, 0xb83c9603, 0xb7969674, 0xb6f196e6, 0xb64c9759, 0xb5a897ce, - 0xb5059843, 0xb46298b9, 0xb3c09930, 0xb31f99a9, 0xb27f9a22, 0xb1df9a9c, - 0xb1409b17, 0xb0a29b94, 0xb0059c11, 0xaf689c8f, 0xaecc9d0e, 0xae319d8e, - 0xad979e0f, 0xacfd9e91, 0xac659f14, 0xabcd9f98, 0xab36a01c, 0xaaa0a0a2, - 0xaa0aa129, 0xa976a1b0, 0xa8e2a238, 0xa84fa2c2, 0xa7bda34c, 0xa72ca3d7, - 0xa69ca463, 0xa60ca4f0, 0xa57ea57e, 0xa4f0a60c, 0xa463a69c, 0xa3d7a72c, - 0xa34ca7bd, 0xa2c2a84f, 0xa238a8e2, 0xa1b0a976, 0xa129aa0a, 0xa0a2aaa0, - 0xa01cab36, 0x9f98abcd, 0x9f14ac65, 0x9e91acfd, 0x9e0fad97, 0x9d8eae31, - 0x9d0eaecc, 0x9c8faf68, 0x9c11b005, 0x9b94b0a2, 0x9b17b140, 0x9a9cb1df, - 0x9a22b27f, 0x99a9b31f, 0x9930b3c0, 0x98b9b462, 0x9843b505, 0x97ceb5a8, - 0x9759b64c, 0x96e6b6f1, 0x9674b796, 0x9603b83c, 0x9592b8e3, 0x9523b98b, - 0x94b5ba33, 0x9448badc, 0x93dcbb85, 0x9371bc2f, 0x9307bcda, 0x929ebd86, - 0x9236be32, 0x91cfbedf, 0x9169bf8c, 0x9105c03a, 0x90a1c0e9, 0x903ec198, - 0x8fddc248, 0x8f7dc2f8, 0x8f1dc3a9, 0x8ebfc45b, 0x8e62c50d, 0x8e06c5c0, - 0x8dabc673, 0x8d51c727, 0x8cf8c7db, 0x8ca1c890, 0x8c4ac946, 0x8bf5c9fc, - 0x8ba0cab2, 0x8b4dcb69, 0x8afbcc21, 0x8aaaccd9, 0x8a5acd92, 0x8a0cce4b, - 0x89becf04, 0x8972cfbe, 0x8927d079, 0x88ddd134, 0x8894d1ef, 0x884cd2ab, - 0x8805d367, 0x87c0d424, 0x877bd4e1, 0x8738d59e, 0x86f6d65c, 0x86b6d71b, - 0x8676d7d9, 0x8637d898, 0x85fad958, 0x85beda18, 0x8583dad8, 0x8549db99, - 0x8511dc59, 0x84d9dd1b, 0x84a3dddc, 0x846ede9e, 0x843adf61, 0x8407e023, - 0x83d6e0e6, 0x83a6e1a9, 0x8377e26d, 0x8349e330, 0x831ce3f4, 0x82f1e4b9, - 0x82c6e57d, 0x829de642, 0x8276e707, 0x824fe7cd, 0x822ae892, 0x8205e958, - 0x81e2ea1e, 0x81c1eae4, 0x81a0ebab, 0x8181ec71, 0x8163ed38, 0x8146edff, - 0x812aeec6, 0x8110ef8d, 0x80f6f055, 0x80def11c, 0x80c8f1e4, 0x80b2f2ac, - 0x809ef374, 0x808bf43c, 0x8079f505, 0x8068f5cd, 0x8059f695, 0x804bf75e, - 0x803ef827, 0x8032f8ef, 0x8027f9b8, 0x801efa81, 0x8016fb4a, 0x800ffc13, - 0x800afcdc, 0x8006fda5, 0x8002fe6e, 0x8001ff37, -}; - -/* Returns the multiplication of \conj{a} and {b}. */ -static inline int32_t mult(int32_t a, int32_t b) -{ -#if __ARM_ARCH__ >= 6 - int32_t t = b; - __asm__("smuad %0, %0, %1" : "+r" (t) : "r" (a)); - __asm__("smusdx %0, %0, %1" : "+r" (b) : "r" (a)); - __asm__("pkhtb %0, %0, %1, ASR #16" : "+r" (t) : "r" (b)); - return t; -#else - return (((a >> 16) * (b >> 16) + (int16_t)a * (int16_t)b) & ~0xFFFF) | - ((((a >> 16) * (int16_t)b - (int16_t)a * (b >> 16)) >> 16) & 0xFFFF); -#endif -} - -static inline int32_t half(int32_t a) -{ -#if __ARM_ARCH__ >= 6 - __asm__("shadd16 %0, %0, %1" : "+r" (a) : "r" (0)); - return a; -#else - return ((a >> 1) & ~0x8000) | (a & 0x8000); -#endif -} - -void fixed_fft(int n, int32_t *v) -{ - int scale = LOG_FFT_SIZE, i, p, r; - - for (r = 0, i = 1; i < n; ++i) { - for (p = n; !(p & r); p >>= 1, r ^= p); - if (i < r) { - int32_t t = v[i]; - v[i] = v[r]; - v[r] = t; - } - } - - for (p = 1; p < n; p <<= 1) { - --scale; - - for (i = 0; i < n; i += p << 1) { - int32_t x = half(v[i]); - int32_t y = half(v[i + p]); - v[i] = x + y; - v[i + p] = x - y; - } - - for (r = 1; r < p; ++r) { - int32_t w = MAX_FFT_SIZE / 4 - (r << scale); - i = w >> 31; - w = twiddle[(w ^ i) - i] ^ (i << 16); - for (i = r; i < n; i += p << 1) { - int32_t x = half(v[i]); - int32_t y = mult(w, v[i + p]); - v[i] = x - y; - v[i + p] = x + y; - } - } - } -} - -void fixed_fft_real(int n, int32_t *v) -{ - int scale = LOG_FFT_SIZE, m = n >> 1, i; - - fixed_fft(n, v); - for (i = 1; i <= n; i <<= 1, --scale); - v[0] = mult(~v[0], 0x80008000); - v[m] = half(v[m]); - - for (i = 1; i < n >> 1; ++i) { - int32_t x = half(v[i]); - int32_t z = half(v[n - i]); - int32_t y = z - (x ^ 0xFFFF); - x = half(x + (z ^ 0xFFFF)); - y = mult(y, twiddle[i << scale]); - v[i] = x - y; - v[n - i] = (x + y) ^ 0xFFFF; - } -} diff --git a/media/libmedia/mediametadataretriever.cpp b/media/libmedia/mediametadataretriever.cpp index 88e269f..8d53357 100644 --- a/media/libmedia/mediametadataretriever.cpp +++ b/media/libmedia/mediametadataretriever.cpp @@ -35,7 +35,7 @@ sp<MediaMetadataRetriever::DeathNotifier> MediaMetadataRetriever::sDeathNotifier const sp<IMediaPlayerService>& MediaMetadataRetriever::getService() { Mutex::Autolock lock(sServiceLock); - if (sService.get() == 0) { + if (sService == 0) { sp<IServiceManager> sm = defaultServiceManager(); sp<IBinder> binder; do { diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp index 2284927..f1c47dd 100644 --- a/media/libmedia/mediaplayer.cpp +++ b/media/libmedia/mediaplayer.cpp @@ -30,7 +30,7 @@ #include <gui/SurfaceTextureClient.h> #include <media/mediaplayer.h> -#include <media/AudioTrack.h> +#include <media/AudioSystem.h> #include <surfaceflinger/Surface.h> @@ -478,7 +478,7 @@ status_t MediaPlayer::reset() return reset_l(); } -status_t MediaPlayer::setAudioStreamType(int type) +status_t MediaPlayer::setAudioStreamType(audio_stream_type_t type) { ALOGV("MediaPlayer::setAudioStreamType"); Mutex::Autolock _l(mLock); @@ -709,7 +709,7 @@ void MediaPlayer::notify(int msg, int ext1, int ext2, const Parcel *obj) } } -/*static*/ sp<IMemory> MediaPlayer::decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) +/*static*/ sp<IMemory> MediaPlayer::decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, audio_format_t* pFormat) { ALOGV("decode(%s)", url); sp<IMemory> p; @@ -729,7 +729,7 @@ void MediaPlayer::died() notify(MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED, 0); } -/*static*/ sp<IMemory> MediaPlayer::decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) +/*static*/ sp<IMemory> MediaPlayer::decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, audio_format_t* pFormat) { ALOGV("decode(%d, %lld, %lld)", fd, offset, length); sp<IMemory> p; diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index f5cb019..a0c20ae 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -1010,7 +1010,7 @@ status_t MediaPlayerService::Client::reset() return p->reset(); } -status_t MediaPlayerService::Client::setAudioStreamType(int type) +status_t MediaPlayerService::Client::setAudioStreamType(audio_stream_type_t type) { ALOGV("[%d] setAudioStreamType(%d)", mConnId, type); // TODO: for hardware output, call player instead @@ -1149,7 +1149,7 @@ int Antagonizer::callbackThread(void* user) static size_t kDefaultHeapSize = 1024 * 1024; // 1MB -sp<IMemory> MediaPlayerService::decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) +sp<IMemory> MediaPlayerService::decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, audio_format_t* pFormat) { ALOGV("decode(%s)", url); sp<MemoryBase> mem; @@ -1197,7 +1197,7 @@ sp<IMemory> MediaPlayerService::decode(const char* url, uint32_t *pSampleRate, i mem = new MemoryBase(cache->getHeap(), 0, cache->size()); *pSampleRate = cache->sampleRate(); *pNumChannels = cache->channelCount(); - *pFormat = (int)cache->format(); + *pFormat = cache->format(); ALOGV("return memory @ %p, sampleRate=%u, channelCount = %d, format = %d", mem->pointer(), *pSampleRate, *pNumChannels, *pFormat); Exit: @@ -1205,7 +1205,7 @@ Exit: return mem; } -sp<IMemory> MediaPlayerService::decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) +sp<IMemory> MediaPlayerService::decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, audio_format_t* pFormat) { ALOGV("decode(%d, %lld, %lld)", fd, offset, length); sp<MemoryBase> mem; @@ -1339,7 +1339,7 @@ status_t MediaPlayerService::AudioOutput::getPosition(uint32_t *position) } status_t MediaPlayerService::AudioOutput::open( - uint32_t sampleRate, int channelCount, int format, int bufferCount, + uint32_t sampleRate, int channelCount, audio_format_t format, int bufferCount, AudioCallback cb, void *cookie) { mCallback = cb; @@ -1611,7 +1611,7 @@ bool CallbackThread::threadLoop() { //////////////////////////////////////////////////////////////////////////////// status_t MediaPlayerService::AudioCache::open( - uint32_t sampleRate, int channelCount, int format, int bufferCount, + uint32_t sampleRate, int channelCount, audio_format_t format, int bufferCount, AudioCallback cb, void *cookie) { ALOGV("open(%u, %d, %d, %d)", sampleRate, channelCount, format, bufferCount); @@ -1621,7 +1621,7 @@ status_t MediaPlayerService::AudioCache::open( mSampleRate = sampleRate; mChannelCount = (uint16_t)channelCount; - mFormat = (uint16_t)format; + mFormat = format; mMsecsPerFrame = 1.e3 / (float) sampleRate; if (cb != NULL) { diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h index 04d9e28..fa71d11 100644 --- a/media/libmediaplayerservice/MediaPlayerService.h +++ b/media/libmediaplayerservice/MediaPlayerService.h @@ -34,6 +34,7 @@ namespace android { +class AudioTrack; class IMediaRecorder; class IMediaMetadataRetriever; class IOMX; @@ -83,7 +84,7 @@ class MediaPlayerService : public BnMediaPlayerService virtual status_t open( uint32_t sampleRate, int channelCount, - int format, int bufferCount, + audio_format_t format, int bufferCount, AudioCallback cb, void *cookie); virtual void start(); @@ -92,7 +93,7 @@ class MediaPlayerService : public BnMediaPlayerService virtual void flush(); virtual void pause(); virtual void close(); - void setAudioStreamType(int streamType) { mStreamType = streamType; } + void setAudioStreamType(audio_stream_type_t streamType) { mStreamType = streamType; } void setVolume(float left, float right); status_t setAuxEffectSendLevel(float level); status_t attachAuxEffect(int effectId); @@ -108,7 +109,7 @@ class MediaPlayerService : public BnMediaPlayerService AudioTrack* mTrack; AudioCallback mCallback; void * mCallbackCookie; - int mStreamType; + audio_stream_type_t mStreamType; float mLeftVolume; float mRightVolume; float mMsecsPerFrame; @@ -139,7 +140,7 @@ class MediaPlayerService : public BnMediaPlayerService virtual int getSessionId(); virtual status_t open( - uint32_t sampleRate, int channelCount, int format, + uint32_t sampleRate, int channelCount, audio_format_t format, int bufferCount = 1, AudioCallback cb = NULL, void *cookie = NULL); @@ -149,10 +150,10 @@ class MediaPlayerService : public BnMediaPlayerService virtual void flush() {} virtual void pause() {} virtual void close() {} - void setAudioStreamType(int streamType) {} + void setAudioStreamType(audio_stream_type_t streamType) {} void setVolume(float left, float right) {} uint32_t sampleRate() const { return mSampleRate; } - uint32_t format() const { return (uint32_t)mFormat; } + audio_format_t format() const { return mFormat; } size_t size() const { return mSize; } status_t wait(); @@ -170,7 +171,7 @@ class MediaPlayerService : public BnMediaPlayerService sp<MemoryHeapBase> mHeap; float mMsecsPerFrame; uint16_t mChannelCount; - uint16_t mFormat; + audio_format_t mFormat; ssize_t mFrameCount; uint32_t mSampleRate; uint32_t mSize; @@ -190,8 +191,8 @@ public: virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, int audioSessionId); - virtual sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat); - virtual sp<IMemory> decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat); + virtual sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, audio_format_t* pFormat); + virtual sp<IMemory> decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, audio_format_t* pFormat); virtual sp<IOMX> getOMX(); virtual status_t dump(int fd, const Vector<String16>& args); @@ -259,7 +260,7 @@ private: virtual status_t getCurrentPosition(int* msec); virtual status_t getDuration(int* msec); virtual status_t reset(); - virtual status_t setAudioStreamType(int type); + virtual status_t setAudioStreamType(audio_stream_type_t type); virtual status_t setLooping(int loop); virtual status_t setVolume(float leftVolume, float rightVolume); virtual status_t invoke(const Parcel& request, Parcel *reply); diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp index d219fc2..beda945 100644 --- a/media/libmediaplayerservice/MediaRecorderClient.cpp +++ b/media/libmediaplayerservice/MediaRecorderClient.cpp @@ -33,8 +33,6 @@ #include <utils/String16.h> -#include <media/AudioTrack.h> - #include <system/audio.h> #include "MediaRecorderClient.h" diff --git a/media/libmediaplayerservice/MidiFile.cpp b/media/libmediaplayerservice/MidiFile.cpp index d89b5f4..7cb8c29 100644 --- a/media/libmediaplayerservice/MidiFile.cpp +++ b/media/libmediaplayerservice/MidiFile.cpp @@ -86,7 +86,8 @@ MidiFile::MidiFile() : // create playback thread { Mutex::Autolock l(mMutex); - createThreadEtc(renderThread, this, "midithread", ANDROID_PRIORITY_AUDIO); + mThread = new MidiFileThread(this); + mThread->run("midithread", ANDROID_PRIORITY_AUDIO); mCondition.wait(mMutex); ALOGV("thread started"); } @@ -427,11 +428,6 @@ status_t MidiFile::createOutputTrack() { return NO_ERROR; } -int MidiFile::renderThread(void* p) { - - return ((MidiFile*)p)->render(); -} - int MidiFile::render() { EAS_RESULT result = EAS_FAILURE; EAS_I32 count; diff --git a/media/libmediaplayerservice/MidiFile.h b/media/libmediaplayerservice/MidiFile.h index 3469389..f6f8f7b 100644 --- a/media/libmediaplayerservice/MidiFile.h +++ b/media/libmediaplayerservice/MidiFile.h @@ -19,11 +19,11 @@ #define ANDROID_MIDIFILE_H #include <media/MediaPlayerInterface.h> -#include <media/AudioTrack.h> #include <libsonivox/eas.h> namespace android { +// Note that the name MidiFile is misleading; this actually represents a MIDI file player class MidiFile : public MediaPlayerInterface { public: MidiFile(); @@ -65,7 +65,6 @@ public: private: status_t createOutputTrack(); status_t reset_nosync(); - static int renderThread(void*); int render(); void updateState(){ EAS_State(mEasData, mEasHandle, &mState); } @@ -78,12 +77,35 @@ private: EAS_I32 mDuration; EAS_STATE mState; EAS_FILE mFileLocator; - int mStreamType; + audio_stream_type_t mStreamType; bool mLoop; volatile bool mExit; bool mPaused; volatile bool mRender; pid_t mTid; + + class MidiFileThread : public Thread { + public: + MidiFileThread(MidiFile *midiPlayer) : mMidiFile(midiPlayer) { + } + + protected: + virtual ~MidiFileThread() {} + + private: + MidiFile *mMidiFile; + + bool threadLoop() { + int result; + result = mMidiFile->render(); + return false; + } + + MidiFileThread(const MidiFileThread &); + MidiFileThread &operator=(const MidiFileThread &); + }; + + sp<MidiFileThread> mThread; }; }; // namespace android diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index a00aaa5..b731d0f 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -480,7 +480,7 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) { // completed. ALOGV("postponing reset mFlushingAudio=%d, mFlushingVideo=%d", - mFlushingAudio, mFlushingVideo); + mFlushingAudio, mFlushingVideo); mResetPostponed = true; break; @@ -690,7 +690,7 @@ status_t NuPlayer::feedDecoderInputData(bool audio, const sp<AMessage> &msg) { bool timeChange = (type & ATSParser::DISCONTINUITY_TIME) != 0; ALOGI("%s discontinuity (formatChange=%d, time=%d)", - audio ? "audio" : "video", formatChange, timeChange); + audio ? "audio" : "video", formatChange, timeChange); if (audio) { mSkipRenderingAudioUntilMediaTimeUs = -1; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp index 074cb4f..15259cb 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp @@ -376,7 +376,7 @@ void NuPlayer::Renderer::onDrainVideoQueue() { bool tooLate = (mVideoLateByUs > 40000); if (tooLate) { - ALOGV("video late by %lld us (%.2f secs)", lateByUs, lateByUs / 1E6); + ALOGV("video late by %lld us (%.2f secs)", mVideoLateByUs, mVideoLateByUs / 1E6); } else { ALOGV("rendering video at media time %.2f secs", mediaTimeUs / 1E6); } @@ -629,7 +629,7 @@ void NuPlayer::Renderer::onPause() { } ALOGV("now paused audio queue has %d entries, video has %d entries", - mAudioQueue.size(), mVideoQueue.size()); + mAudioQueue.size(), mVideoQueue.size()); mPaused = true; } diff --git a/media/libstagefright/AACExtractor.cpp b/media/libstagefright/AACExtractor.cpp index 52b1200..33f22f2 100644 --- a/media/libstagefright/AACExtractor.cpp +++ b/media/libstagefright/AACExtractor.cpp @@ -22,6 +22,7 @@ #include "include/avc_utils.h" #include <media/stagefright/foundation/ABuffer.h> +#include <media/stagefright/foundation/AMessage.h> #include <media/stagefright/DataSource.h> #include <media/stagefright/MediaBufferGroup.h> #include <media/stagefright/MediaDebug.h> @@ -131,18 +132,28 @@ static size_t getAdtsFrameLength(const sp<DataSource> &source, off64_t offset, s return frameSize; } -AACExtractor::AACExtractor(const sp<DataSource> &source) +AACExtractor::AACExtractor( + const sp<DataSource> &source, const sp<AMessage> &_meta) : mDataSource(source), mInitCheck(NO_INIT), mFrameDurationUs(0) { - String8 mimeType; - float confidence; - if (!SniffAAC(mDataSource, &mimeType, &confidence, NULL)) { - return; + sp<AMessage> meta = _meta; + + if (meta == NULL) { + String8 mimeType; + float confidence; + sp<AMessage> _meta; + + if (!SniffAAC(mDataSource, &mimeType, &confidence, &meta)) { + return; + } } + int64_t offset; + CHECK(meta->findInt64("offset", &offset)); + uint8_t profile, sf_index, channel, header[2]; - if (mDataSource->readAt(2, &header, 2) < 2) { + if (mDataSource->readAt(offset + 2, &header, 2) < 2) { return; } @@ -156,7 +167,6 @@ AACExtractor::AACExtractor(const sp<DataSource> &source) mMeta = MakeAACCodecSpecificData(profile, sf_index, channel); - off64_t offset = 0; off64_t streamSize, numFrames = 0; size_t frameSize = 0; int64_t duration = 0; @@ -245,7 +255,12 @@ AACSource::~AACSource() { status_t AACSource::start(MetaData *params) { CHECK(!mStarted); - mOffset = 0; + if (mOffsetVector.empty()) { + mOffset = 0; + } else { + mOffset = mOffsetVector.itemAt(0); + } + mCurrentTimeUs = 0; mGroup = new MediaBufferGroup; mGroup->add_buffer(new MediaBuffer(kMaxFrameSize)); @@ -318,10 +333,39 @@ status_t AACSource::read( bool SniffAAC( const sp<DataSource> &source, String8 *mimeType, float *confidence, - sp<AMessage> *) { + sp<AMessage> *meta) { + off64_t pos = 0; + + for (;;) { + uint8_t id3header[10]; + if (source->readAt(pos, id3header, sizeof(id3header)) + < (ssize_t)sizeof(id3header)) { + return false; + } + + if (memcmp("ID3", id3header, 3)) { + break; + } + + // Skip the ID3v2 header. + + size_t len = + ((id3header[6] & 0x7f) << 21) + | ((id3header[7] & 0x7f) << 14) + | ((id3header[8] & 0x7f) << 7) + | (id3header[9] & 0x7f); + + len += 10; + + pos += len; + + ALOGV("skipped ID3 tag, new starting offset is %lld (0x%016llx)", + pos, pos); + } + uint8_t header[2]; - if (source->readAt(0, &header, 2) != 2) { + if (source->readAt(pos, &header, 2) != 2) { return false; } @@ -329,6 +373,10 @@ bool SniffAAC( if ((header[0] == 0xff) && ((header[1] & 0xf6) == 0xf0)) { *mimeType = MEDIA_MIMETYPE_AUDIO_AAC_ADTS; *confidence = 0.2; + + *meta = new AMessage; + (*meta)->setInt64("offset", pos); + return true; } diff --git a/media/libstagefright/AACWriter.cpp b/media/libstagefright/AACWriter.cpp index 1673ccd..9cdb463 100644 --- a/media/libstagefright/AACWriter.cpp +++ b/media/libstagefright/AACWriter.cpp @@ -60,7 +60,7 @@ AACWriter::AACWriter(int fd) AACWriter::~AACWriter() { if (mStarted) { - stop(); + reset(); } if (mFd != -1) { @@ -152,7 +152,7 @@ status_t AACWriter::pause() { return OK; } -status_t AACWriter::stop() { +status_t AACWriter::reset() { if (!mStarted) { return OK; } diff --git a/media/libstagefright/AMRWriter.cpp b/media/libstagefright/AMRWriter.cpp index 6c4e307..59b4ca7 100644 --- a/media/libstagefright/AMRWriter.cpp +++ b/media/libstagefright/AMRWriter.cpp @@ -52,7 +52,7 @@ AMRWriter::AMRWriter(int fd) AMRWriter::~AMRWriter() { if (mStarted) { - stop(); + reset(); } if (mFd != -1) { @@ -152,7 +152,7 @@ status_t AMRWriter::pause() { return OK; } -status_t AMRWriter::stop() { +status_t AMRWriter::reset() { if (!mStarted) { return OK; } diff --git a/media/libstagefright/AVIExtractor.cpp b/media/libstagefright/AVIExtractor.cpp index a3187b7..5a6211e 100644 --- a/media/libstagefright/AVIExtractor.cpp +++ b/media/libstagefright/AVIExtractor.cpp @@ -577,6 +577,7 @@ static const char *GetMIMETypeForHandler(uint32_t handler) { case FOURCC('a', 'v', 'c', '1'): case FOURCC('d', 'a', 'v', 'c'): case FOURCC('x', '2', '6', '4'): + case FOURCC('H', '2', '6', '4'): case FOURCC('v', 's', 's', 'h'): return MEDIA_MIMETYPE_VIDEO_AVC; diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk index 690deac..483e5ab 100644 --- a/media/libstagefright/Android.mk +++ b/media/libstagefright/Android.mk @@ -9,6 +9,7 @@ LOCAL_SRC_FILES:= \ AACWriter.cpp \ AMRExtractor.cpp \ AMRWriter.cpp \ + AVIExtractor.cpp \ AudioPlayer.cpp \ AudioSource.cpp \ AwesomePlayer.cpp \ @@ -73,12 +74,11 @@ LOCAL_SHARED_LIBRARIES := \ libcrypto \ libssl \ libgui \ + libstagefright_omx \ LOCAL_STATIC_LIBRARIES := \ libstagefright_color_conversion \ libstagefright_aacenc \ - libstagefright_amrnbenc \ - libstagefright_amrwbenc \ libstagefright_avcenc \ libstagefright_m4vh263enc \ libstagefright_matroska \ @@ -140,7 +140,6 @@ endif # ifeq ($(HTTP_STACK),chrome) ################################################################################ LOCAL_SHARED_LIBRARIES += \ - libstagefright_amrnb_common \ libstagefright_enc_common \ libstagefright_avc_common \ libstagefright_foundation \ diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp index 2172cc0..fef2a00 100644 --- a/media/libstagefright/AudioSource.cpp +++ b/media/libstagefright/AudioSource.cpp @@ -47,7 +47,7 @@ static void AudioRecordCallbackFunction(int event, void *user, void *info) { } AudioSource::AudioSource( - int inputSource, uint32_t sampleRate, uint32_t channels) + audio_source_t inputSource, uint32_t sampleRate, uint32_t channels) : mStarted(false), mSampleRate(sampleRate), mPrevSampleTimeUs(0), @@ -72,7 +72,7 @@ AudioSource::AudioSource( AudioSource::~AudioSource() { if (mStarted) { - stop(); + reset(); } delete mRecord; @@ -130,7 +130,7 @@ void AudioSource::waitOutstandingEncodingFrames_l() { } } -status_t AudioSource::stop() { +status_t AudioSource::reset() { Mutex::Autolock autoLock(mLock); if (!mStarted) { return UNKNOWN_ERROR; diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp index d0cb7ff..8073af8 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -30,7 +30,7 @@ #include "include/MPEG2TSExtractor.h" #include "include/WVMExtractor.h" -#include "timedtext/TimedTextPlayer.h" +#include "timedtext/TimedTextDriver.h" #include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> @@ -192,7 +192,7 @@ AwesomePlayer::AwesomePlayer() mVideoBuffer(NULL), mDecryptHandle(NULL), mLastVideoTimeUs(-1), - mTextPlayer(NULL) { + mTextDriver(NULL) { CHECK_EQ(mClient.connect(), (status_t)OK); DataSource::RegisterDefaultSniffers(); @@ -335,6 +335,14 @@ status_t AwesomePlayer::setDataSource_l( return UNKNOWN_ERROR; } + if (extractor->getDrmFlag()) { + checkDrmStatus(dataSource); + } + + return setDataSource_l(extractor); +} + +void AwesomePlayer::checkDrmStatus(const sp<DataSource>& dataSource) { dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient); if (mDecryptHandle != NULL) { CHECK(mDrmManagerClient); @@ -342,8 +350,6 @@ status_t AwesomePlayer::setDataSource_l( notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_DRM_NO_LICENSE); } } - - return setDataSource_l(extractor); } status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) { @@ -524,9 +530,9 @@ void AwesomePlayer::reset_l() { delete mAudioPlayer; mAudioPlayer = NULL; - if (mTextPlayer != NULL) { - delete mTextPlayer; - mTextPlayer = NULL; + if (mTextDriver != NULL) { + delete mTextDriver; + mTextDriver = NULL; } mVideoRenderer.clear(); @@ -1112,7 +1118,7 @@ status_t AwesomePlayer::pause_l(bool at_eos) { } if (mFlags & TEXTPLAYER_STARTED) { - mTextPlayer->pause(); + mTextDriver->pause(); modifyFlags(TEXT_RUNNING, CLEAR); } @@ -1266,9 +1272,9 @@ status_t AwesomePlayer::seekTo(int64_t timeUs) { } status_t AwesomePlayer::setTimedTextTrackIndex(int32_t index) { - if (mTextPlayer != NULL) { + if (mTextDriver != NULL) { if (index >= 0) { // to turn on a text track - status_t err = mTextPlayer->setTimedTextTrackIndex(index); + status_t err = mTextDriver->setTimedTextTrackIndex(index); if (err != OK) { return err; } @@ -1284,7 +1290,7 @@ status_t AwesomePlayer::setTimedTextTrackIndex(int32_t index) { modifyFlags(TEXTPLAYER_STARTED, CLEAR); } - return mTextPlayer->setTimedTextTrackIndex(index); + return mTextDriver->setTimedTextTrackIndex(index); } } else { return INVALID_OPERATION; @@ -1313,7 +1319,7 @@ status_t AwesomePlayer::seekTo_l(int64_t timeUs) { seekAudioIfNecessary_l(); if (mFlags & TEXTPLAYER_STARTED) { - mTextPlayer->seekTo(mSeekTimeUs); + mTextDriver->seekToAsync(mSeekTimeUs); } if (!(mFlags & PLAYING)) { @@ -1358,11 +1364,11 @@ void AwesomePlayer::addTextSource(sp<MediaSource> source) { Mutex::Autolock autoLock(mTimedTextLock); CHECK(source != NULL); - if (mTextPlayer == NULL) { - mTextPlayer = new TimedTextPlayer(this, mListener, &mQueue); + if (mTextDriver == NULL) { + mTextDriver = new TimedTextDriver(mListener); } - mTextPlayer->addTextSource(source); + mTextDriver->addInBandTextSource(source); } status_t AwesomePlayer::initAudioDecoder() { @@ -1689,7 +1695,7 @@ void AwesomePlayer::onVideoEvent() { } if ((mFlags & TEXTPLAYER_STARTED) && !(mFlags & (TEXT_RUNNING | SEEK_PREVIEW))) { - mTextPlayer->resume(); + mTextDriver->resume(); modifyFlags(TEXT_RUNNING, SET); } @@ -2095,7 +2101,7 @@ status_t AwesomePlayer::finishSetDataSource_l() { String8 mimeType; float confidence; sp<AMessage> dummy; - bool success = SniffDRM(dataSource, &mimeType, &confidence, &dummy); + bool success = SniffWVM(dataSource, &mimeType, &confidence, &dummy); if (!success || strcasecmp( @@ -2115,13 +2121,8 @@ status_t AwesomePlayer::finishSetDataSource_l() { } } - dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient); - - if (mDecryptHandle != NULL) { - CHECK(mDrmManagerClient); - if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) { - notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_DRM_NO_LICENSE); - } + if (extractor->getDrmFlag()) { + checkDrmStatus(dataSource); } status_t err = setDataSource_l(extractor); @@ -2240,11 +2241,11 @@ status_t AwesomePlayer::setParameter(int key, const Parcel &request) { case KEY_PARAMETER_TIMED_TEXT_ADD_OUT_OF_BAND_SOURCE: { Mutex::Autolock autoLock(mTimedTextLock); - if (mTextPlayer == NULL) { - mTextPlayer = new TimedTextPlayer(this, mListener, &mQueue); + if (mTextDriver == NULL) { + mTextDriver = new TimedTextDriver(mListener); } - return mTextPlayer->setParameter(key, request); + return mTextDriver->addOutOfBandTextSource(request); } case KEY_PARAMETER_CACHE_STAT_COLLECT_FREQ_MS: { diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp index 1850c9c..228659c 100755 --- a/media/libstagefright/CameraSource.cpp +++ b/media/libstagefright/CameraSource.cpp @@ -548,7 +548,7 @@ status_t CameraSource::initWithCameraAccess( CameraSource::~CameraSource() { if (mStarted) { - stop(); + reset(); } else if (mInitCheck == OK) { // Camera is initialized but because start() is never called, // the lock on Camera is never released(). This makes sure @@ -632,8 +632,8 @@ void CameraSource::releaseCamera() { mCameraFlags = 0; } -status_t CameraSource::stop() { - ALOGD("stop: E"); +status_t CameraSource::reset() { + ALOGD("reset: E"); Mutex::Autolock autoLock(mLock); mStarted = false; mFrameAvailableCondition.signal(); @@ -670,7 +670,7 @@ status_t CameraSource::stop() { } CHECK_EQ(mNumFramesReceived, mNumFramesEncoded + mNumFramesDropped); - ALOGD("stop: X"); + ALOGD("reset: X"); return OK; } diff --git a/media/libstagefright/CameraSourceTimeLapse.cpp b/media/libstagefright/CameraSourceTimeLapse.cpp index 263ab50..83d67b9 100644 --- a/media/libstagefright/CameraSourceTimeLapse.cpp +++ b/media/libstagefright/CameraSourceTimeLapse.cpp @@ -87,6 +87,10 @@ CameraSourceTimeLapse::CameraSourceTimeLapse( } CameraSourceTimeLapse::~CameraSourceTimeLapse() { + if (mLastReadBufferCopy) { + mLastReadBufferCopy->release(); + mLastReadBufferCopy = NULL; + } } void CameraSourceTimeLapse::startQuickReadReturns() { @@ -204,15 +208,6 @@ status_t CameraSourceTimeLapse::read( } } -void CameraSourceTimeLapse::stopCameraRecording() { - ALOGV("stopCameraRecording"); - CameraSource::stopCameraRecording(); - if (mLastReadBufferCopy) { - mLastReadBufferCopy->release(); - mLastReadBufferCopy = NULL; - } -} - sp<IMemory> CameraSourceTimeLapse::createIMemoryCopy( const sp<IMemory> &source_data) { diff --git a/media/libstagefright/DRMExtractor.cpp b/media/libstagefright/DRMExtractor.cpp index 9452ab1..afc4a80 100644 --- a/media/libstagefright/DRMExtractor.cpp +++ b/media/libstagefright/DRMExtractor.cpp @@ -282,13 +282,13 @@ bool SniffDRM( if (decryptHandle != NULL) { if (decryptHandle->decryptApiType == DecryptApiType::CONTAINER_BASED) { *mimeType = String8("drm+container_based+") + decryptHandle->mimeType; + *confidence = 10.0f; } else if (decryptHandle->decryptApiType == DecryptApiType::ELEMENTARY_STREAM_BASED) { *mimeType = String8("drm+es_based+") + decryptHandle->mimeType; - } else if (decryptHandle->decryptApiType == DecryptApiType::WV_BASED) { - *mimeType = MEDIA_MIMETYPE_CONTAINER_WVM; - ALOGW("SniffWVM: found match\n"); + *confidence = 10.0f; + } else { + return false; } - *confidence = 10.0f; return true; } diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp index 43539bb..d0a7880 100644 --- a/media/libstagefright/DataSource.cpp +++ b/media/libstagefright/DataSource.cpp @@ -15,6 +15,12 @@ */ #include "include/AMRExtractor.h" +#include "include/AVIExtractor.h" + +#if CHROMIUM_AVAILABLE +#include "include/DataUriSource.h" +#endif + #include "include/MP3Extractor.h" #include "include/MPEG4Extractor.h" #include "include/WAVExtractor.h" @@ -26,6 +32,7 @@ #include "include/DRMExtractor.h" #include "include/FLACExtractor.h" #include "include/AACExtractor.h" +#include "include/WVMExtractor.h" #include "matroska/MatroskaExtractor.h" @@ -112,7 +119,9 @@ void DataSource::RegisterDefaultSniffers() { RegisterSniffer(SniffMPEG2TS); RegisterSniffer(SniffMP3); RegisterSniffer(SniffAAC); + RegisterSniffer(SniffAVI); RegisterSniffer(SniffMPEG2PS); + RegisterSniffer(SniffWVM); char value[PROPERTY_VALUE_MAX]; if (property_get("drm.service.enabled", value, NULL) @@ -134,6 +143,10 @@ sp<DataSource> DataSource::CreateFromURI( return NULL; } source = new NuCachedSource2(httpSource); +# if CHROMIUM_AVAILABLE + } else if (!strncasecmp("data:", uri, 5)) { + source = new DataUriSource(uri); +#endif } else { // Assume it's a filename. source = new FileSource(uri); diff --git a/media/libstagefright/FileSource.cpp b/media/libstagefright/FileSource.cpp index 73cb48c..01f53e4 100644 --- a/media/libstagefright/FileSource.cpp +++ b/media/libstagefright/FileSource.cpp @@ -127,7 +127,7 @@ status_t FileSource::getSize(off64_t *size) { return OK; } -sp<DecryptHandle> FileSource::DrmInitialization() { +sp<DecryptHandle> FileSource::DrmInitialization(const char *mime) { if (mDrmManagerClient == NULL) { mDrmManagerClient = new DrmManagerClient(); } @@ -138,7 +138,7 @@ sp<DecryptHandle> FileSource::DrmInitialization() { if (mDecryptHandle == NULL) { mDecryptHandle = mDrmManagerClient->openDecryptSession( - mFd, mOffset, mLength); + mFd, mOffset, mLength, mime); } if (mDecryptHandle == NULL) { diff --git a/media/libstagefright/MPEG2TSWriter.cpp b/media/libstagefright/MPEG2TSWriter.cpp index 36009ab..0b4ecbe 100644 --- a/media/libstagefright/MPEG2TSWriter.cpp +++ b/media/libstagefright/MPEG2TSWriter.cpp @@ -513,7 +513,7 @@ void MPEG2TSWriter::init() { MPEG2TSWriter::~MPEG2TSWriter() { if (mStarted) { - stop(); + reset(); } mLooper->unregisterHandler(mReflector->id()); @@ -564,7 +564,7 @@ status_t MPEG2TSWriter::start(MetaData *param) { return OK; } -status_t MPEG2TSWriter::stop() { +status_t MPEG2TSWriter::reset() { CHECK(mStarted); for (size_t i = 0; i < mSources.size(); ++i) { diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp index 22bdd95..6c95d4e 100644 --- a/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/MPEG4Extractor.cpp @@ -20,7 +20,6 @@ #include "include/MPEG4Extractor.h" #include "include/SampleTable.h" #include "include/ESDS.h" -#include "timedtext/TimedTextPlayer.h" #include <arpa/inet.h> @@ -1372,8 +1371,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { uint32_t type = ntohl(buffer); // For the 3GPP file format, the handler-type within the 'hdlr' box - // shall be 'text' - if (type == FOURCC('t', 'e', 'x', 't')) { + // shall be 'text'. We also want to support 'sbtl' handler type + // for a practical reason as various MPEG4 containers use it. + if (type == FOURCC('t', 'e', 'x', 't') || type == FOURCC('s', 'b', 't', 'l')) { mLastTrack->meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_TEXT_3GPP); } @@ -2429,4 +2429,3 @@ bool SniffMPEG4( } } // namespace android - diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp index 06dd875..068660b 100755 --- a/media/libstagefright/MPEG4Writer.cpp +++ b/media/libstagefright/MPEG4Writer.cpp @@ -282,7 +282,7 @@ MPEG4Writer::MPEG4Writer(int fd) } MPEG4Writer::~MPEG4Writer() { - stop(); + reset(); while (!mTracks.empty()) { List<Track *>::iterator it = mTracks.begin(); @@ -616,7 +616,7 @@ void MPEG4Writer::release() { mStarted = false; } -status_t MPEG4Writer::stop() { +status_t MPEG4Writer::reset() { if (mInitCheck != OK) { return OK; } else { diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp index 7b17d65..2171492 100644 --- a/media/libstagefright/MediaExtractor.cpp +++ b/media/libstagefright/MediaExtractor.cpp @@ -19,6 +19,7 @@ #include <utils/Log.h> #include "include/AMRExtractor.h" +#include "include/AVIExtractor.h" #include "include/MP3Extractor.h" #include "include/MPEG4Extractor.h" #include "include/WAVExtractor.h" @@ -109,10 +110,12 @@ sp<MediaExtractor> MediaExtractor::Create( ret = new MatroskaExtractor(source); } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) { ret = new MPEG2TSExtractor(source); + } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_AVI)) { + ret = new AVIExtractor(source); } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WVM)) { ret = new WVMExtractor(source); } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC_ADTS)) { - ret = new AACExtractor(source); + ret = new AACExtractor(source, meta); } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2PS)) { ret = new MPEG2PSExtractor(source); } diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libstagefright/NuCachedSource2.cpp index 249c298..0957426 100644 --- a/media/libstagefright/NuCachedSource2.cpp +++ b/media/libstagefright/NuCachedSource2.cpp @@ -370,6 +370,7 @@ void NuCachedSource2::onFetch() { && (mSource->flags() & DataSource::kIsHTTPBasedSource)) { ALOGV("Disconnecting at high watermark"); static_cast<HTTPBase *>(mSource.get())->disconnect(); + mFinalStatus = -EAGAIN; } } } else { @@ -549,7 +550,7 @@ ssize_t NuCachedSource2::readInternal(off64_t offset, void *data, size_t size) { size_t delta = offset - mCacheOffset; - if (mFinalStatus != OK) { + if (mFinalStatus != OK && mNumRetriesLeft == 0) { if (delta >= mCache->totalSize()) { return mFinalStatus; } @@ -591,7 +592,7 @@ status_t NuCachedSource2::seekInternal_l(off64_t offset) { size_t totalSize = mCache->totalSize(); CHECK_EQ(mCache->releaseFromStart(totalSize), totalSize); - mFinalStatus = OK; + mNumRetriesLeft = kMaxNumRetries; mFetching = true; return OK; @@ -603,8 +604,8 @@ void NuCachedSource2::resumeFetchingIfNecessary() { restartPrefetcherIfNecessary_l(true /* ignore low water threshold */); } -sp<DecryptHandle> NuCachedSource2::DrmInitialization() { - return mSource->DrmInitialization(); +sp<DecryptHandle> NuCachedSource2::DrmInitialization(const char* mime) { + return mSource->DrmInitialization(mime); } void NuCachedSource2::getDrmInfo(sp<DecryptHandle> &handle, DrmManagerClient **client) { diff --git a/media/libstagefright/OMXClient.cpp b/media/libstagefright/OMXClient.cpp index 9de873e..7a805aa 100644 --- a/media/libstagefright/OMXClient.cpp +++ b/media/libstagefright/OMXClient.cpp @@ -20,11 +20,299 @@ #include <binder/IServiceManager.h> #include <media/IMediaPlayerService.h> -#include <media/stagefright/MediaDebug.h> +#include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/OMXClient.h> +#include <utils/KeyedVector.h> + +#include "include/OMX.h" namespace android { +struct MuxOMX : public IOMX { + MuxOMX(const sp<IOMX> &remoteOMX); + virtual ~MuxOMX(); + + virtual IBinder *onAsBinder() { return NULL; } + + virtual bool livesLocally(node_id node, pid_t pid); + + virtual status_t listNodes(List<ComponentInfo> *list); + + virtual status_t allocateNode( + const char *name, const sp<IOMXObserver> &observer, + node_id *node); + + virtual status_t freeNode(node_id node); + + virtual status_t sendCommand( + node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param); + + virtual status_t getParameter( + node_id node, OMX_INDEXTYPE index, + void *params, size_t size); + + virtual status_t setParameter( + node_id node, OMX_INDEXTYPE index, + const void *params, size_t size); + + virtual status_t getConfig( + node_id node, OMX_INDEXTYPE index, + void *params, size_t size); + + virtual status_t setConfig( + node_id node, OMX_INDEXTYPE index, + const void *params, size_t size); + + virtual status_t getState( + node_id node, OMX_STATETYPE* state); + + virtual status_t storeMetaDataInBuffers( + node_id node, OMX_U32 port_index, OMX_BOOL enable); + + virtual status_t enableGraphicBuffers( + node_id node, OMX_U32 port_index, OMX_BOOL enable); + + virtual status_t getGraphicBufferUsage( + node_id node, OMX_U32 port_index, OMX_U32* usage); + + virtual status_t useBuffer( + node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms, + buffer_id *buffer); + + virtual status_t useGraphicBuffer( + node_id node, OMX_U32 port_index, + const sp<GraphicBuffer> &graphicBuffer, buffer_id *buffer); + + virtual status_t allocateBuffer( + node_id node, OMX_U32 port_index, size_t size, + buffer_id *buffer, void **buffer_data); + + virtual status_t allocateBufferWithBackup( + node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms, + buffer_id *buffer); + + virtual status_t freeBuffer( + node_id node, OMX_U32 port_index, buffer_id buffer); + + virtual status_t fillBuffer(node_id node, buffer_id buffer); + + virtual status_t emptyBuffer( + node_id node, + buffer_id buffer, + OMX_U32 range_offset, OMX_U32 range_length, + OMX_U32 flags, OMX_TICKS timestamp); + + virtual status_t getExtensionIndex( + node_id node, + const char *parameter_name, + OMX_INDEXTYPE *index); + +private: + mutable Mutex mLock; + + sp<IOMX> mRemoteOMX; + sp<IOMX> mLocalOMX; + + KeyedVector<node_id, bool> mIsLocalNode; + + bool isLocalNode(node_id node) const; + bool isLocalNode_l(node_id node) const; + const sp<IOMX> &getOMX(node_id node) const; + const sp<IOMX> &getOMX_l(node_id node) const; + + static bool IsSoftwareComponent(const char *name); + + DISALLOW_EVIL_CONSTRUCTORS(MuxOMX); +}; + +MuxOMX::MuxOMX(const sp<IOMX> &remoteOMX) + : mRemoteOMX(remoteOMX) { +} + +MuxOMX::~MuxOMX() { +} + +bool MuxOMX::isLocalNode(node_id node) const { + Mutex::Autolock autoLock(mLock); + + return isLocalNode_l(node); +} + +bool MuxOMX::isLocalNode_l(node_id node) const { + return mIsLocalNode.indexOfKey(node) >= 0; +} + +// static +bool MuxOMX::IsSoftwareComponent(const char *name) { + return !strncasecmp(name, "OMX.google.", 11); +} + +const sp<IOMX> &MuxOMX::getOMX(node_id node) const { + return isLocalNode(node) ? mLocalOMX : mRemoteOMX; +} + +const sp<IOMX> &MuxOMX::getOMX_l(node_id node) const { + return isLocalNode_l(node) ? mLocalOMX : mRemoteOMX; +} + +bool MuxOMX::livesLocally(node_id node, pid_t pid) { + return getOMX(node)->livesLocally(node, pid); +} + +status_t MuxOMX::listNodes(List<ComponentInfo> *list) { + Mutex::Autolock autoLock(mLock); + + if (mLocalOMX == NULL) { + mLocalOMX = new OMX; + } + + return mLocalOMX->listNodes(list); +} + +status_t MuxOMX::allocateNode( + const char *name, const sp<IOMXObserver> &observer, + node_id *node) { + Mutex::Autolock autoLock(mLock); + + sp<IOMX> omx; + + if (IsSoftwareComponent(name)) { + if (mLocalOMX == NULL) { + mLocalOMX = new OMX; + } + omx = mLocalOMX; + } else { + omx = mRemoteOMX; + } + + status_t err = omx->allocateNode(name, observer, node); + + if (err != OK) { + return err; + } + + if (omx == mLocalOMX) { + mIsLocalNode.add(*node, true); + } + + return OK; +} + +status_t MuxOMX::freeNode(node_id node) { + Mutex::Autolock autoLock(mLock); + + status_t err = getOMX_l(node)->freeNode(node); + + if (err != OK) { + return err; + } + + mIsLocalNode.removeItem(node); + + return OK; +} + +status_t MuxOMX::sendCommand( + node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) { + return getOMX(node)->sendCommand(node, cmd, param); +} + +status_t MuxOMX::getParameter( + node_id node, OMX_INDEXTYPE index, + void *params, size_t size) { + return getOMX(node)->getParameter(node, index, params, size); +} + +status_t MuxOMX::setParameter( + node_id node, OMX_INDEXTYPE index, + const void *params, size_t size) { + return getOMX(node)->setParameter(node, index, params, size); +} + +status_t MuxOMX::getConfig( + node_id node, OMX_INDEXTYPE index, + void *params, size_t size) { + return getOMX(node)->getConfig(node, index, params, size); +} + +status_t MuxOMX::setConfig( + node_id node, OMX_INDEXTYPE index, + const void *params, size_t size) { + return getOMX(node)->setConfig(node, index, params, size); +} + +status_t MuxOMX::getState( + node_id node, OMX_STATETYPE* state) { + return getOMX(node)->getState(node, state); +} + +status_t MuxOMX::storeMetaDataInBuffers( + node_id node, OMX_U32 port_index, OMX_BOOL enable) { + return getOMX(node)->storeMetaDataInBuffers(node, port_index, enable); +} + +status_t MuxOMX::enableGraphicBuffers( + node_id node, OMX_U32 port_index, OMX_BOOL enable) { + return getOMX(node)->enableGraphicBuffers(node, port_index, enable); +} + +status_t MuxOMX::getGraphicBufferUsage( + node_id node, OMX_U32 port_index, OMX_U32* usage) { + return getOMX(node)->getGraphicBufferUsage(node, port_index, usage); +} + +status_t MuxOMX::useBuffer( + node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms, + buffer_id *buffer) { + return getOMX(node)->useBuffer(node, port_index, params, buffer); +} + +status_t MuxOMX::useGraphicBuffer( + node_id node, OMX_U32 port_index, + const sp<GraphicBuffer> &graphicBuffer, buffer_id *buffer) { + return getOMX(node)->useGraphicBuffer( + node, port_index, graphicBuffer, buffer); +} + +status_t MuxOMX::allocateBuffer( + node_id node, OMX_U32 port_index, size_t size, + buffer_id *buffer, void **buffer_data) { + return getOMX(node)->allocateBuffer( + node, port_index, size, buffer, buffer_data); +} + +status_t MuxOMX::allocateBufferWithBackup( + node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms, + buffer_id *buffer) { + return getOMX(node)->allocateBufferWithBackup( + node, port_index, params, buffer); +} + +status_t MuxOMX::freeBuffer( + node_id node, OMX_U32 port_index, buffer_id buffer) { + return getOMX(node)->freeBuffer(node, port_index, buffer); +} + +status_t MuxOMX::fillBuffer(node_id node, buffer_id buffer) { + return getOMX(node)->fillBuffer(node, buffer); +} + +status_t MuxOMX::emptyBuffer( + node_id node, + buffer_id buffer, + OMX_U32 range_offset, OMX_U32 range_length, + OMX_U32 flags, OMX_TICKS timestamp) { + return getOMX(node)->emptyBuffer( + node, buffer, range_offset, range_length, flags, timestamp); +} + +status_t MuxOMX::getExtensionIndex( + node_id node, + const char *parameter_name, + OMX_INDEXTYPE *index) { + return getOMX(node)->getExtensionIndex(node, parameter_name, index); +} + OMXClient::OMXClient() { } @@ -38,6 +326,11 @@ status_t OMXClient::connect() { mOMX = service->getOMX(); CHECK(mOMX.get() != NULL); + if (!mOMX->livesLocally(NULL /* node */, getpid())) { + ALOGI("Using client-side OMX mux."); + mOMX = new MuxOMX(mOMX); + } + return OK; } diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index 60d9bb7..381320b 100755 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -19,8 +19,6 @@ #include <utils/Log.h> #include "include/AACEncoder.h" -#include "include/AMRNBEncoder.h" -#include "include/AMRWBEncoder.h" #include "include/AVCEncoder.h" #include "include/M4vH263Encoder.h" @@ -71,8 +69,6 @@ static sp<MediaSource> Make##name(const sp<MediaSource> &source, const sp<MetaDa #define FACTORY_REF(name) { #name, Make##name }, -FACTORY_CREATE_ENCODER(AMRNBEncoder) -FACTORY_CREATE_ENCODER(AMRWBEncoder) FACTORY_CREATE_ENCODER(AACEncoder) FACTORY_CREATE_ENCODER(AVCEncoder) FACTORY_CREATE_ENCODER(M4vH263Encoder) @@ -86,8 +82,6 @@ static sp<MediaSource> InstantiateSoftwareEncoder( }; static const FactoryInfo kFactoryInfo[] = { - FACTORY_REF(AMRNBEncoder) - FACTORY_REF(AMRWBEncoder) FACTORY_REF(AACEncoder) FACTORY_REF(AVCEncoder) FACTORY_REF(M4vH263Encoder) @@ -149,10 +143,11 @@ static const CodecInfo kDecoderInfo[] = { static const CodecInfo kEncoderInfo[] = { { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.TI.AMR.encode" }, - { MEDIA_MIMETYPE_AUDIO_AMR_NB, "AMRNBEncoder" }, + { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.google.amrnb.encoder" }, { MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.TI.WBAMR.encode" }, - { MEDIA_MIMETYPE_AUDIO_AMR_WB, "AMRWBEncoder" }, + { MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.google.amrwb.encoder" }, { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.TI.AAC.encode" }, + { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.google.aac.encoder" }, { MEDIA_MIMETYPE_AUDIO_AAC, "AACEncoder" }, { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.TI.DUCATI1.VIDEO.MPEG4E" }, { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.7x30.video.encoder.mpeg4" }, @@ -1482,11 +1477,12 @@ OMXCodec::OMXCodec( const sp<MediaSource> &source, const sp<ANativeWindow> &nativeWindow) : mOMX(omx), - mOMXLivesLocally(omx->livesLocally(getpid())), + mOMXLivesLocally(omx->livesLocally(node, getpid())), mNode(node), mQuirks(quirks), mFlags(flags), mIsEncoder(isEncoder), + mIsVideo(!strncasecmp("video/", mime, 6)), mMIME(strdup(mime)), mComponentName(strdup(componentName)), mSource(source), @@ -2192,7 +2188,7 @@ error: } int64_t OMXCodec::retrieveDecodingTimeUs(bool isCodecSpecific) { - CHECK(mIsEncoder); + CHECK(mIsEncoder && mIsVideo); if (mDecodingTimeList.empty()) { CHECK(mSignalledEOS || mNoMoreOutputData); @@ -2387,7 +2383,7 @@ void OMXCodec::on_message(const omx_message &msg) { mNoMoreOutputData = true; } - if (mIsEncoder) { + if (mIsEncoder && mIsVideo) { int64_t decodingTimeUs = retrieveDecodingTimeUs(isCodecSpecific); buffer->meta_data()->setInt64(kKeyDecodingTime, decodingTimeUs); } @@ -3249,7 +3245,7 @@ bool OMXCodec::drainInputBuffer(BufferInfo *info) { int64_t lastBufferTimeUs; CHECK(srcBuffer->meta_data()->findInt64(kKeyTime, &lastBufferTimeUs)); CHECK(lastBufferTimeUs >= 0); - if (mIsEncoder) { + if (mIsEncoder && mIsVideo) { mDecodingTimeList.push_back(lastBufferTimeUs); } diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp index 8d80d63..d9858d7 100644 --- a/media/libstagefright/SampleTable.cpp +++ b/media/libstagefright/SampleTable.cpp @@ -618,26 +618,31 @@ status_t SampleTable::findSyncSampleNear( } uint32_t left = 0; - while (left < mNumSyncSamples) { - uint32_t x = mSyncSamples[left]; + uint32_t right = mNumSyncSamples; + while (left < right) { + uint32_t center = left + (right - left) / 2; + uint32_t x = mSyncSamples[center]; - if (x >= start_sample_index) { + if (start_sample_index < x) { + right = center; + } else if (start_sample_index > x) { + left = center + 1; + } else { + left = center; break; } - - ++left; } - if (left == mNumSyncSamples) { if (flags == kFlagAfter) { ALOGE("tried to find a sync frame after the last one: %d", left); return ERROR_OUT_OF_RANGE; } + left = left - 1; } - if (left > 0) { - --left; - } + // Now ssi[left] is the sync sample index just before (or at) + // start_sample_index. + // Also start_sample_index < ssi[left + 1], if left + 1 < mNumSyncSamples. uint32_t x = mSyncSamples[left]; @@ -682,7 +687,11 @@ status_t SampleTable::findSyncSampleNear( x = mSyncSamples[left - 1]; - CHECK(x <= start_sample_index); + if (x > start_sample_index) { + // The table of sync sample indices was not sorted + // properly. + return ERROR_MALFORMED; + } } break; } @@ -696,7 +705,11 @@ status_t SampleTable::findSyncSampleNear( x = mSyncSamples[left + 1]; - CHECK(x >= start_sample_index); + if (x < start_sample_index) { + // The table of sync sample indices was not sorted + // properly. + return ERROR_MALFORMED; + } } break; diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp index 48df058..2233d1b 100644 --- a/media/libstagefright/SurfaceMediaSource.cpp +++ b/media/libstagefright/SurfaceMediaSource.cpp @@ -32,6 +32,8 @@ #include <utils/Log.h> #include <utils/String8.h> +#include <private/gui/ComposerService.h> + namespace android { SurfaceMediaSource::SurfaceMediaSource(uint32_t bufW, uint32_t bufH) : diff --git a/media/libstagefright/WVMExtractor.cpp b/media/libstagefright/WVMExtractor.cpp index 2092cb6..1e4e049 100644 --- a/media/libstagefright/WVMExtractor.cpp +++ b/media/libstagefright/WVMExtractor.cpp @@ -45,17 +45,12 @@ namespace android { static Mutex gWVMutex; WVMExtractor::WVMExtractor(const sp<DataSource> &source) - : mDataSource(source) { - { - Mutex::Autolock autoLock(gWVMutex); - if (gVendorLibHandle == NULL) { - gVendorLibHandle = dlopen("libwvm.so", RTLD_NOW); - } + : mDataSource(source) +{ + Mutex::Autolock autoLock(gWVMutex); - if (gVendorLibHandle == NULL) { - ALOGE("Failed to open libwvm.so"); - return; - } + if (!getVendorLibHandle()) { + return; } typedef WVMLoadableExtractor *(*GetInstanceFunc)(sp<DataSource>); @@ -64,13 +59,28 @@ WVMExtractor::WVMExtractor(const sp<DataSource> &source) "_ZN7android11GetInstanceENS_2spINS_10DataSourceEEE"); if (getInstanceFunc) { + CHECK(source->DrmInitialization(MEDIA_MIMETYPE_CONTAINER_WVM) != NULL); mImpl = (*getInstanceFunc)(source); CHECK(mImpl != NULL); + setDrmFlag(true); } else { ALOGE("Failed to locate GetInstance in libwvm.so"); } } +bool WVMExtractor::getVendorLibHandle() +{ + if (gVendorLibHandle == NULL) { + gVendorLibHandle = dlopen("libwvm.so", RTLD_NOW); + } + + if (gVendorLibHandle == NULL) { + ALOGE("Failed to open libwvm.so"); + } + + return gVendorLibHandle != NULL; +} + WVMExtractor::~WVMExtractor() { } @@ -113,5 +123,33 @@ void WVMExtractor::setAdaptiveStreamingMode(bool adaptive) { } } +bool SniffWVM( + const sp<DataSource> &source, String8 *mimeType, float *confidence, + sp<AMessage> *) { + + Mutex::Autolock autoLock(gWVMutex); + + if (!WVMExtractor::getVendorLibHandle()) { + return false; + } + + typedef WVMLoadableExtractor *(*SnifferFunc)(const sp<DataSource>&); + SnifferFunc snifferFunc = + (SnifferFunc) dlsym(gVendorLibHandle, + "_ZN7android15IsWidevineMediaERKNS_2spINS_10DataSourceEEE"); + + if (snifferFunc) { + if ((*snifferFunc)(source)) { + *mimeType = MEDIA_MIMETYPE_CONTAINER_WVM; + *confidence = 10.0f; + return true; + } + } else { + ALOGE("IsWidevineMedia not found in libwvm.so"); + } + + return false; +} + } //namespace android diff --git a/media/libstagefright/chromium_http/Android.mk b/media/libstagefright/chromium_http/Android.mk index 6573e3c..63775f1 100644 --- a/media/libstagefright/chromium_http/Android.mk +++ b/media/libstagefright/chromium_http/Android.mk @@ -3,8 +3,9 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ - ChromiumHTTPDataSource.cpp \ - support.cpp \ + DataUriSource.cpp \ + ChromiumHTTPDataSource.cpp \ + support.cpp LOCAL_C_INCLUDES:= \ $(JNI_H_INCLUDE) \ diff --git a/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp b/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp index 180460b..76f7946 100644 --- a/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp +++ b/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp @@ -259,7 +259,7 @@ void ChromiumHTTPDataSource::onDisconnectComplete() { mCondition.broadcast(); } -sp<DecryptHandle> ChromiumHTTPDataSource::DrmInitialization() { +sp<DecryptHandle> ChromiumHTTPDataSource::DrmInitialization(const char* mime) { Mutex::Autolock autoLock(mLock); if (mDrmManagerClient == NULL) { @@ -275,7 +275,7 @@ sp<DecryptHandle> ChromiumHTTPDataSource::DrmInitialization() { * original one */ mDecryptHandle = mDrmManagerClient->openDecryptSession( - String8(mURI.c_str())); + String8(mURI.c_str()), mime); } if (mDecryptHandle == NULL) { diff --git a/media/libstagefright/chromium_http/DataUriSource.cpp b/media/libstagefright/chromium_http/DataUriSource.cpp new file mode 100644 index 0000000..ecf3fa1 --- /dev/null +++ b/media/libstagefright/chromium_http/DataUriSource.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2011 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. + */ + +#include <include/DataUriSource.h> + +#include <net/base/data_url.h> +#include <googleurl/src/gurl.h> + + +namespace android { + +DataUriSource::DataUriSource(const char *uri) : + mDataUri(uri), + mInited(NO_INIT) { + + // Copy1: const char *uri -> String8 mDataUri. + std::string mimeTypeStr, unusedCharsetStr, dataStr; + // Copy2: String8 mDataUri -> std::string + const bool ret = net::DataURL::Parse( + GURL(std::string(mDataUri.string())), + &mimeTypeStr, &unusedCharsetStr, &dataStr); + // Copy3: std::string dataStr -> AString mData + mData.setTo(dataStr.data(), dataStr.length()); + mInited = ret ? OK : UNKNOWN_ERROR; + + // The chromium data url implementation defaults to using "text/plain" + // if no mime type is specified. We prefer to leave this unspecified + // instead, since the mime type is sniffed in most cases. + if (mimeTypeStr != "text/plain") { + mMimeType = mimeTypeStr.c_str(); + } +} + +ssize_t DataUriSource::readAt(off64_t offset, void *out, size_t size) { + if (mInited != OK) { + return mInited; + } + + const off64_t length = mData.size(); + if (offset >= length) { + return UNKNOWN_ERROR; + } + + const char *dataBuf = mData.c_str(); + const size_t bytesToCopy = + offset + size >= length ? (length - offset) : size; + + if (bytesToCopy > 0) { + memcpy(out, dataBuf + offset, bytesToCopy); + } + + return bytesToCopy; +} + +} // namespace android diff --git a/media/libstagefright/codecs/aacdec/SoftAAC.cpp b/media/libstagefright/codecs/aacdec/SoftAAC.cpp index da9d280..ea6c360 100644 --- a/media/libstagefright/codecs/aacdec/SoftAAC.cpp +++ b/media/libstagefright/codecs/aacdec/SoftAAC.cpp @@ -218,6 +218,18 @@ OMX_ERRORTYPE SoftAAC::internalSetParameter( return OMX_ErrorNone; } + case OMX_IndexParamAudioPcm: + { + const OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = + (OMX_AUDIO_PARAM_PCMMODETYPE *)params; + + if (pcmParams->nPortIndex != 1) { + return OMX_ErrorUndefined; + } + + return OMX_ErrorNone; + } + default: return SimpleSoftOMXComponent::internalSetParameter(index, params); } diff --git a/media/libstagefright/codecs/aacenc/Android.mk b/media/libstagefright/codecs/aacenc/Android.mk index 8318ba4..34a2796 100644 --- a/media/libstagefright/codecs/aacenc/Android.mk +++ b/media/libstagefright/codecs/aacenc/Android.mk @@ -85,3 +85,29 @@ LOCAL_C_INCLUDES += $(LOCAL_PATH)/src/asm/ARMV7 endif include $(BUILD_STATIC_LIBRARY) + +################################################################################ + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + SoftAACEncoder.cpp + +LOCAL_C_INCLUDES := \ + frameworks/base/media/libstagefright/include \ + frameworks/base/include/media/stagefright/openmax \ + frameworks/base/media/libstagefright/codecs/common/include \ + +LOCAL_CFLAGS := -DOSCL_IMPORT_REF= + +LOCAL_STATIC_LIBRARIES := \ + libstagefright_aacenc + +LOCAL_SHARED_LIBRARIES := \ + libstagefright_omx libstagefright_foundation libutils \ + libstagefright_enc_common + +LOCAL_MODULE := libstagefright_soft_aacenc +LOCAL_MODULE_TAGS := optional + +include $(BUILD_SHARED_LIBRARY) diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder.cpp b/media/libstagefright/codecs/aacenc/SoftAACEncoder.cpp new file mode 100644 index 0000000..c6724c2 --- /dev/null +++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder.cpp @@ -0,0 +1,560 @@ +/* + * Copyright (C) 2012 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. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "SoftAACEncoder" +#include <utils/Log.h> + +#include "SoftAACEncoder.h" + +#include "voAAC.h" +#include "cmnMemory.h" + +#include <media/stagefright/foundation/ADebug.h> +#include <media/stagefright/foundation/hexdump.h> + +namespace android { + +template<class T> +static void InitOMXParams(T *params) { + params->nSize = sizeof(T); + params->nVersion.s.nVersionMajor = 1; + params->nVersion.s.nVersionMinor = 0; + params->nVersion.s.nRevision = 0; + params->nVersion.s.nStep = 0; +} + +SoftAACEncoder::SoftAACEncoder( + const char *name, + const OMX_CALLBACKTYPE *callbacks, + OMX_PTR appData, + OMX_COMPONENTTYPE **component) + : SimpleSoftOMXComponent(name, callbacks, appData, component), + mEncoderHandle(NULL), + mApiHandle(NULL), + mMemOperator(NULL), + mNumChannels(1), + mSampleRate(44100), + mBitRate(0), + mSentCodecSpecificData(false), + mInputSize(0), + mInputFrame(NULL), + mInputTimeUs(-1ll), + mSawInputEOS(false), + mSignalledError(false) { + initPorts(); + CHECK_EQ(initEncoder(), (status_t)OK); + + setAudioParams(); +} + +SoftAACEncoder::~SoftAACEncoder() { + delete[] mInputFrame; + mInputFrame = NULL; + + if (mEncoderHandle) { + CHECK_EQ(VO_ERR_NONE, mApiHandle->Uninit(mEncoderHandle)); + mEncoderHandle = NULL; + } + + delete mApiHandle; + mApiHandle = NULL; + + delete mMemOperator; + mMemOperator = NULL; +} + +void SoftAACEncoder::initPorts() { + OMX_PARAM_PORTDEFINITIONTYPE def; + InitOMXParams(&def); + + def.nPortIndex = 0; + def.eDir = OMX_DirInput; + def.nBufferCountMin = kNumBuffers; + def.nBufferCountActual = def.nBufferCountMin; + def.nBufferSize = kNumSamplesPerFrame * sizeof(int16_t) * 2; + def.bEnabled = OMX_TRUE; + def.bPopulated = OMX_FALSE; + def.eDomain = OMX_PortDomainAudio; + def.bBuffersContiguous = OMX_FALSE; + def.nBufferAlignment = 1; + + def.format.audio.cMIMEType = const_cast<char *>("audio/raw"); + def.format.audio.pNativeRender = NULL; + def.format.audio.bFlagErrorConcealment = OMX_FALSE; + def.format.audio.eEncoding = OMX_AUDIO_CodingPCM; + + addPort(def); + + def.nPortIndex = 1; + def.eDir = OMX_DirOutput; + def.nBufferCountMin = kNumBuffers; + def.nBufferCountActual = def.nBufferCountMin; + def.nBufferSize = 8192; + def.bEnabled = OMX_TRUE; + def.bPopulated = OMX_FALSE; + def.eDomain = OMX_PortDomainAudio; + def.bBuffersContiguous = OMX_FALSE; + def.nBufferAlignment = 2; + + def.format.audio.cMIMEType = const_cast<char *>("audio/aac"); + def.format.audio.pNativeRender = NULL; + def.format.audio.bFlagErrorConcealment = OMX_FALSE; + def.format.audio.eEncoding = OMX_AUDIO_CodingAAC; + + addPort(def); +} + +status_t SoftAACEncoder::initEncoder() { + mApiHandle = new VO_AUDIO_CODECAPI; + + if (VO_ERR_NONE != voGetAACEncAPI(mApiHandle)) { + ALOGE("Failed to get api handle"); + return UNKNOWN_ERROR; + } + + mMemOperator = new VO_MEM_OPERATOR; + mMemOperator->Alloc = cmnMemAlloc; + mMemOperator->Copy = cmnMemCopy; + mMemOperator->Free = cmnMemFree; + mMemOperator->Set = cmnMemSet; + mMemOperator->Check = cmnMemCheck; + + VO_CODEC_INIT_USERDATA userData; + memset(&userData, 0, sizeof(userData)); + userData.memflag = VO_IMF_USERMEMOPERATOR; + userData.memData = (VO_PTR) mMemOperator; + if (VO_ERR_NONE != + mApiHandle->Init(&mEncoderHandle, VO_AUDIO_CodingAAC, &userData)) { + ALOGE("Failed to init AAC encoder"); + return UNKNOWN_ERROR; + } + + return OK; +} + +OMX_ERRORTYPE SoftAACEncoder::internalGetParameter( + OMX_INDEXTYPE index, OMX_PTR params) { + switch (index) { + case OMX_IndexParamAudioPortFormat: + { + OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams = + (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params; + + if (formatParams->nPortIndex > 1) { + return OMX_ErrorUndefined; + } + + if (formatParams->nIndex > 0) { + return OMX_ErrorNoMore; + } + + formatParams->eEncoding = + (formatParams->nPortIndex == 0) + ? OMX_AUDIO_CodingPCM : OMX_AUDIO_CodingAAC; + + return OMX_ErrorNone; + } + + case OMX_IndexParamAudioAac: + { + OMX_AUDIO_PARAM_AACPROFILETYPE *aacParams = + (OMX_AUDIO_PARAM_AACPROFILETYPE *)params; + + if (aacParams->nPortIndex != 1) { + return OMX_ErrorUndefined; + } + + aacParams->nBitRate = mBitRate; + aacParams->nAudioBandWidth = 0; + aacParams->nAACtools = 0; + aacParams->nAACERtools = 0; + aacParams->eAACProfile = OMX_AUDIO_AACObjectMain; + aacParams->eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4FF; + aacParams->eChannelMode = OMX_AUDIO_ChannelModeStereo; + + aacParams->nChannels = mNumChannels; + aacParams->nSampleRate = mSampleRate; + aacParams->nFrameLength = 0; + + return OMX_ErrorNone; + } + + case OMX_IndexParamAudioPcm: + { + OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = + (OMX_AUDIO_PARAM_PCMMODETYPE *)params; + + if (pcmParams->nPortIndex != 0) { + return OMX_ErrorUndefined; + } + + pcmParams->eNumData = OMX_NumericalDataSigned; + pcmParams->eEndian = OMX_EndianBig; + pcmParams->bInterleaved = OMX_TRUE; + pcmParams->nBitPerSample = 16; + pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear; + pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF; + pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF; + + pcmParams->nChannels = mNumChannels; + pcmParams->nSamplingRate = mSampleRate; + + return OMX_ErrorNone; + } + + default: + return SimpleSoftOMXComponent::internalGetParameter(index, params); + } +} + +OMX_ERRORTYPE SoftAACEncoder::internalSetParameter( + OMX_INDEXTYPE index, const OMX_PTR params) { + switch (index) { + case OMX_IndexParamStandardComponentRole: + { + const OMX_PARAM_COMPONENTROLETYPE *roleParams = + (const OMX_PARAM_COMPONENTROLETYPE *)params; + + if (strncmp((const char *)roleParams->cRole, + "audio_encoder.aac", + OMX_MAX_STRINGNAME_SIZE - 1)) { + return OMX_ErrorUndefined; + } + + return OMX_ErrorNone; + } + + case OMX_IndexParamAudioPortFormat: + { + const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams = + (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params; + + if (formatParams->nPortIndex > 1) { + return OMX_ErrorUndefined; + } + + if (formatParams->nIndex > 0) { + return OMX_ErrorNoMore; + } + + if ((formatParams->nPortIndex == 0 + && formatParams->eEncoding != OMX_AUDIO_CodingPCM) + || (formatParams->nPortIndex == 1 + && formatParams->eEncoding != OMX_AUDIO_CodingAAC)) { + return OMX_ErrorUndefined; + } + + return OMX_ErrorNone; + } + + case OMX_IndexParamAudioAac: + { + OMX_AUDIO_PARAM_AACPROFILETYPE *aacParams = + (OMX_AUDIO_PARAM_AACPROFILETYPE *)params; + + if (aacParams->nPortIndex != 1) { + return OMX_ErrorUndefined; + } + + mBitRate = aacParams->nBitRate; + mNumChannels = aacParams->nChannels; + mSampleRate = aacParams->nSampleRate; + + if (setAudioParams() != OK) { + return OMX_ErrorUndefined; + } + + return OMX_ErrorNone; + } + + case OMX_IndexParamAudioPcm: + { + OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = + (OMX_AUDIO_PARAM_PCMMODETYPE *)params; + + if (pcmParams->nPortIndex != 0) { + return OMX_ErrorUndefined; + } + + mNumChannels = pcmParams->nChannels; + mSampleRate = pcmParams->nSamplingRate; + + if (setAudioParams() != OK) { + return OMX_ErrorUndefined; + } + + return OMX_ErrorNone; + } + + + default: + return SimpleSoftOMXComponent::internalSetParameter(index, params); + } +} + +status_t SoftAACEncoder::setAudioParams() { + // We call this whenever sample rate, number of channels or bitrate change + // in reponse to setParameter calls. + + ALOGV("setAudioParams: %lu Hz, %lu channels, %lu bps", + mSampleRate, mNumChannels, mBitRate); + + status_t err = setAudioSpecificConfigData(); + + if (err != OK) { + return err; + } + + AACENC_PARAM params; + memset(¶ms, 0, sizeof(params)); + params.sampleRate = mSampleRate; + params.bitRate = mBitRate; + params.nChannels = mNumChannels; + params.adtsUsed = 0; // We add adts header in the file writer if needed. + if (VO_ERR_NONE != mApiHandle->SetParam( + mEncoderHandle, VO_PID_AAC_ENCPARAM, ¶ms)) { + ALOGE("Failed to set AAC encoder parameters"); + return UNKNOWN_ERROR; + } + + return OK; +} + +static status_t getSampleRateTableIndex(int32_t sampleRate, int32_t &index) { + static const int32_t kSampleRateTable[] = { + 96000, 88200, 64000, 48000, 44100, 32000, + 24000, 22050, 16000, 12000, 11025, 8000 + }; + const int32_t tableSize = + sizeof(kSampleRateTable) / sizeof(kSampleRateTable[0]); + + for (int32_t i = 0; i < tableSize; ++i) { + if (sampleRate == kSampleRateTable[i]) { + index = i; + return OK; + } + } + + return UNKNOWN_ERROR; +} + +status_t SoftAACEncoder::setAudioSpecificConfigData() { + // The AAC encoder's audio specific config really only encodes + // number of channels and the sample rate (mapped to an index into + // a fixed sample rate table). + + int32_t index; + status_t err = getSampleRateTableIndex(mSampleRate, index); + if (err != OK) { + ALOGE("Unsupported sample rate (%lu Hz)", mSampleRate); + return err; + } + + if (mNumChannels > 2 || mNumChannels <= 0) { + ALOGE("Unsupported number of channels(%lu)", mNumChannels); + return UNKNOWN_ERROR; + } + + // OMX_AUDIO_AACObjectLC + mAudioSpecificConfigData[0] = ((0x02 << 3) | (index >> 1)); + mAudioSpecificConfigData[1] = ((index & 0x01) << 7) | (mNumChannels << 3); + + return OK; +} + +void SoftAACEncoder::onQueueFilled(OMX_U32 portIndex) { + if (mSignalledError) { + return; + } + + List<BufferInfo *> &inQueue = getPortQueue(0); + List<BufferInfo *> &outQueue = getPortQueue(1); + + if (!mSentCodecSpecificData) { + // The very first thing we want to output is the codec specific + // data. It does not require any input data but we will need an + // output buffer to store it in. + + if (outQueue.empty()) { + return; + } + + BufferInfo *outInfo = *outQueue.begin(); + OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; + outHeader->nFilledLen = sizeof(mAudioSpecificConfigData); + outHeader->nFlags = OMX_BUFFERFLAG_CODECCONFIG; + + uint8_t *out = outHeader->pBuffer + outHeader->nOffset; + memcpy(out, mAudioSpecificConfigData, sizeof(mAudioSpecificConfigData)); + +#if 0 + ALOGI("sending codec specific data."); + hexdump(out, sizeof(mAudioSpecificConfigData)); +#endif + + outQueue.erase(outQueue.begin()); + outInfo->mOwnedByUs = false; + notifyFillBufferDone(outHeader); + + mSentCodecSpecificData = true; + } + + size_t numBytesPerInputFrame = + mNumChannels * kNumSamplesPerFrame * sizeof(int16_t); + + for (;;) { + // We do the following until we run out of buffers. + + while (mInputSize < numBytesPerInputFrame) { + // As long as there's still input data to be read we + // will drain "kNumSamplesPerFrame * mNumChannels" samples + // into the "mInputFrame" buffer and then encode those + // as a unit into an output buffer. + + if (mSawInputEOS || inQueue.empty()) { + return; + } + + BufferInfo *inInfo = *inQueue.begin(); + OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; + + const void *inData = inHeader->pBuffer + inHeader->nOffset; + + size_t copy = numBytesPerInputFrame - mInputSize; + if (copy > inHeader->nFilledLen) { + copy = inHeader->nFilledLen; + } + + if (mInputFrame == NULL) { + mInputFrame = new int16_t[kNumSamplesPerFrame * mNumChannels]; + } + + if (mInputSize == 0) { + mInputTimeUs = inHeader->nTimeStamp; + } + + memcpy((uint8_t *)mInputFrame + mInputSize, inData, copy); + mInputSize += copy; + + inHeader->nOffset += copy; + inHeader->nFilledLen -= copy; + + // "Time" on the input buffer has in effect advanced by the + // number of audio frames we just advanced nOffset by. + inHeader->nTimeStamp += + (copy * 1000000ll / mSampleRate) + / (mNumChannels * sizeof(int16_t)); + + if (inHeader->nFilledLen == 0) { + if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { + ALOGV("saw input EOS"); + mSawInputEOS = true; + + // Pad any remaining data with zeroes. + memset((uint8_t *)mInputFrame + mInputSize, + 0, + numBytesPerInputFrame - mInputSize); + + mInputSize = numBytesPerInputFrame; + } + + inQueue.erase(inQueue.begin()); + inInfo->mOwnedByUs = false; + notifyEmptyBufferDone(inHeader); + + inData = NULL; + inHeader = NULL; + inInfo = NULL; + } + } + + // At this point we have all the input data necessary to encode + // a single frame, all we need is an output buffer to store the result + // in. + + if (outQueue.empty()) { + return; + } + + BufferInfo *outInfo = *outQueue.begin(); + OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; + + VO_CODECBUFFER inputData; + memset(&inputData, 0, sizeof(inputData)); + inputData.Buffer = (unsigned char *)mInputFrame; + inputData.Length = numBytesPerInputFrame; + CHECK(VO_ERR_NONE == + mApiHandle->SetInputData(mEncoderHandle, &inputData)); + + VO_CODECBUFFER outputData; + memset(&outputData, 0, sizeof(outputData)); + VO_AUDIO_OUTPUTINFO outputInfo; + memset(&outputInfo, 0, sizeof(outputInfo)); + + uint8_t *outPtr = (uint8_t *)outHeader->pBuffer + outHeader->nOffset; + size_t outAvailable = outHeader->nAllocLen - outHeader->nOffset; + + VO_U32 ret = VO_ERR_NONE; + size_t nOutputBytes = 0; + do { + outputData.Buffer = outPtr; + outputData.Length = outAvailable - nOutputBytes; + ret = mApiHandle->GetOutputData( + mEncoderHandle, &outputData, &outputInfo); + if (ret == VO_ERR_NONE) { + outPtr += outputData.Length; + nOutputBytes += outputData.Length; + } + } while (ret != VO_ERR_INPUT_BUFFER_SMALL); + + outHeader->nFilledLen = nOutputBytes; + + outHeader->nFlags = OMX_BUFFERFLAG_ENDOFFRAME; + + if (mSawInputEOS) { + // We also tag this output buffer with EOS if it corresponds + // to the final input buffer. + outHeader->nFlags = OMX_BUFFERFLAG_EOS; + } + + outHeader->nTimeStamp = mInputTimeUs; + +#if 0 + ALOGI("sending %d bytes of data (time = %lld us, flags = 0x%08lx)", + nOutputBytes, mInputTimeUs, outHeader->nFlags); + + hexdump(outHeader->pBuffer + outHeader->nOffset, outHeader->nFilledLen); +#endif + + outQueue.erase(outQueue.begin()); + outInfo->mOwnedByUs = false; + notifyFillBufferDone(outHeader); + + outHeader = NULL; + outInfo = NULL; + + mInputSize = 0; + } +} + +} // namespace android + +android::SoftOMXComponent *createSoftOMXComponent( + const char *name, const OMX_CALLBACKTYPE *callbacks, + OMX_PTR appData, OMX_COMPONENTTYPE **component) { + return new android::SoftAACEncoder(name, callbacks, appData, component); +} diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder.h b/media/libstagefright/codecs/aacenc/SoftAACEncoder.h new file mode 100644 index 0000000..d148eb7 --- /dev/null +++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2012 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. + */ + +#ifndef SOFT_AAC_ENCODER_H_ + +#define SOFT_AAC_ENCODER_H_ + +#include "SimpleSoftOMXComponent.h" + +struct VO_AUDIO_CODECAPI; +struct VO_MEM_OPERATOR; + +namespace android { + +struct SoftAACEncoder : public SimpleSoftOMXComponent { + SoftAACEncoder( + const char *name, + const OMX_CALLBACKTYPE *callbacks, + OMX_PTR appData, + OMX_COMPONENTTYPE **component); + +protected: + virtual ~SoftAACEncoder(); + + virtual OMX_ERRORTYPE internalGetParameter( + OMX_INDEXTYPE index, OMX_PTR params); + + virtual OMX_ERRORTYPE internalSetParameter( + OMX_INDEXTYPE index, const OMX_PTR params); + + virtual void onQueueFilled(OMX_U32 portIndex); + +private: + enum { + kNumBuffers = 4, + kNumSamplesPerFrame = 1024, + }; + + void *mEncoderHandle; + VO_AUDIO_CODECAPI *mApiHandle; + VO_MEM_OPERATOR *mMemOperator; + + OMX_U32 mNumChannels; + OMX_U32 mSampleRate; + OMX_U32 mBitRate; + + bool mSentCodecSpecificData; + size_t mInputSize; + int16_t *mInputFrame; + int64_t mInputTimeUs; + + bool mSawInputEOS; + + uint8_t mAudioSpecificConfigData[2]; + + bool mSignalledError; + + void initPorts(); + status_t initEncoder(); + + status_t setAudioSpecificConfigData(); + status_t setAudioParams(); + + DISALLOW_EVIL_CONSTRUCTORS(SoftAACEncoder); +}; + +} // namespace android + +#endif // SOFT_AAC_ENCODER_H_ diff --git a/media/libstagefright/codecs/aacenc/src/asm/ARMV7/PrePostMDCT_v7.s b/media/libstagefright/codecs/aacenc/src/asm/ARMV7/PrePostMDCT_v7.s index b2bc9d9..7f6b881 100644 --- a/media/libstagefright/codecs/aacenc/src/asm/ARMV7/PrePostMDCT_v7.s +++ b/media/libstagefright/codecs/aacenc/src/asm/ARMV7/PrePostMDCT_v7.s @@ -23,9 +23,13 @@ .section .text .global PreMDCT + .fnstart PreMDCT: stmdb sp!, {r4 - r11, lr} + .save {r4 - r11, lr} + fstmfdd sp!, {d8 - d15} + .vsave {d8 - d15} add r9, r0, r1, lsl #2 sub r3, r9, #32 @@ -74,14 +78,20 @@ PreMDCT_LOOP: bne PreMDCT_LOOP PreMDCT_END: + fldmfdd sp!, {d8 - d15} ldmia sp!, {r4 - r11, pc} @ENDP @ |PreMDCT| + .fnend .section .text .global PostMDCT + .fnstart PostMDCT: stmdb sp!, {r4 - r11, lr} + .save {r4 - r11, lr} + fstmfdd sp!, {d8 - d15} + .vsave {d8 - d15} add r9, r0, r1, lsl #2 sub r3, r9, #32 @@ -129,7 +139,8 @@ PostMDCT_LOOP: bne PostMDCT_LOOP PostMDCT_END: + fldmfdd sp!, {d8 - d15} ldmia sp!, {r4 - r11, pc} @ENDP @ |PostMDCT| - .end + .fnend diff --git a/media/libstagefright/codecs/aacenc/src/asm/ARMV7/R4R8First_v7.s b/media/libstagefright/codecs/aacenc/src/asm/ARMV7/R4R8First_v7.s index 3033156..03fa6a9 100644 --- a/media/libstagefright/codecs/aacenc/src/asm/ARMV7/R4R8First_v7.s +++ b/media/libstagefright/codecs/aacenc/src/asm/ARMV7/R4R8First_v7.s @@ -23,9 +23,13 @@ .section .text .global Radix8First + .fnstart Radix8First: stmdb sp!, {r4 - r11, lr} + .save {r4 - r11, lr} + fstmfdd sp!, {d8 - d15} + .vsave {d8 - d15} ldr r3, SQRT1_2 cmp r1, #0 @@ -103,17 +107,23 @@ Radix8First_LOOP: bne Radix8First_LOOP Radix8First_END: + fldmfdd sp!, {d8 - d15} ldmia sp!, {r4 - r11, pc} SQRT1_2: .word 0x2d413ccd @ENDP @ |Radix8First| + .fnend .section .text .global Radix4First + .fnstart Radix4First: stmdb sp!, {r4 - r11, lr} + .save {r4 - r11, lr} + fstmfdd sp!, {d8 - d15} + .vsave {d8 - d15} cmp r1, #0 beq Radix4First_END @@ -140,7 +150,8 @@ Radix4First_LOOP: bne Radix4First_LOOP Radix4First_END: + fldmfdd sp!, {d8 - d15} ldmia sp!, {r4 - r11, pc} @ENDP @ |Radix4First| - .end + .fnend diff --git a/media/libstagefright/codecs/aacenc/src/asm/ARMV7/Radix4FFT_v7.s b/media/libstagefright/codecs/aacenc/src/asm/ARMV7/Radix4FFT_v7.s index f874825..431bc30 100644 --- a/media/libstagefright/codecs/aacenc/src/asm/ARMV7/Radix4FFT_v7.s +++ b/media/libstagefright/codecs/aacenc/src/asm/ARMV7/Radix4FFT_v7.s @@ -23,9 +23,13 @@ .section .text .global Radix4FFT + .fnstart Radix4FFT: stmdb sp!, {r4 - r11, lr} + .save {r4 - r11, lr} + fstmfdd sp!, {d8 - d15} + .vsave {d8 - d15} mov r1, r1, asr #2 cmp r1, #0 @@ -137,7 +141,8 @@ Radix4FFT_LOOP1_END: bne Radix4FFT_LOOP1 Radix4FFT_END: + fldmfdd sp!, {d8 - d15} ldmia sp!, {r4 - r11, pc} @ENDP @ |Radix4FFT| - .end + .fnend diff --git a/media/libstagefright/codecs/amrnb/enc/Android.mk b/media/libstagefright/codecs/amrnb/enc/Android.mk index b6aed81..94e8726 100644 --- a/media/libstagefright/codecs/amrnb/enc/Android.mk +++ b/media/libstagefright/codecs/amrnb/enc/Android.mk @@ -74,3 +74,30 @@ LOCAL_CFLAGS := \ LOCAL_MODULE := libstagefright_amrnbenc include $(BUILD_STATIC_LIBRARY) + +################################################################################ + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + SoftAMRNBEncoder.cpp + +LOCAL_C_INCLUDES := \ + frameworks/base/media/libstagefright/include \ + frameworks/base/include/media/stagefright/openmax \ + $(LOCAL_PATH)/src \ + $(LOCAL_PATH)/include \ + $(LOCAL_PATH)/../common/include \ + $(LOCAL_PATH)/../common + +LOCAL_STATIC_LIBRARIES := \ + libstagefright_amrnbenc + +LOCAL_SHARED_LIBRARIES := \ + libstagefright_omx libstagefright_foundation libutils \ + libstagefright_amrnb_common + +LOCAL_MODULE := libstagefright_soft_amrnbenc +LOCAL_MODULE_TAGS := optional + +include $(BUILD_SHARED_LIBRARY) diff --git a/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.cpp b/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.cpp new file mode 100644 index 0000000..07f8b4f --- /dev/null +++ b/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.cpp @@ -0,0 +1,404 @@ +/* + * Copyright (C) 2012 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. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "SoftAMRNBEncoder" +#include <utils/Log.h> + +#include "SoftAMRNBEncoder.h" + +#include "gsmamr_enc.h" + +#include <media/stagefright/foundation/ADebug.h> +#include <media/stagefright/foundation/hexdump.h> + +namespace android { + +static const int32_t kSampleRate = 8000; + +template<class T> +static void InitOMXParams(T *params) { + params->nSize = sizeof(T); + params->nVersion.s.nVersionMajor = 1; + params->nVersion.s.nVersionMinor = 0; + params->nVersion.s.nRevision = 0; + params->nVersion.s.nStep = 0; +} + +SoftAMRNBEncoder::SoftAMRNBEncoder( + const char *name, + const OMX_CALLBACKTYPE *callbacks, + OMX_PTR appData, + OMX_COMPONENTTYPE **component) + : SimpleSoftOMXComponent(name, callbacks, appData, component), + mEncState(NULL), + mSidState(NULL), + mBitRate(0), + mMode(MR475), + mInputSize(0), + mInputTimeUs(-1ll), + mSawInputEOS(false), + mSignalledError(false) { + initPorts(); + CHECK_EQ(initEncoder(), (status_t)OK); +} + +SoftAMRNBEncoder::~SoftAMRNBEncoder() { + if (mEncState != NULL) { + AMREncodeExit(&mEncState, &mSidState); + mEncState = mSidState = NULL; + } +} + +void SoftAMRNBEncoder::initPorts() { + OMX_PARAM_PORTDEFINITIONTYPE def; + InitOMXParams(&def); + + def.nPortIndex = 0; + def.eDir = OMX_DirInput; + def.nBufferCountMin = kNumBuffers; + def.nBufferCountActual = def.nBufferCountMin; + def.nBufferSize = kNumSamplesPerFrame * sizeof(int16_t); + def.bEnabled = OMX_TRUE; + def.bPopulated = OMX_FALSE; + def.eDomain = OMX_PortDomainAudio; + def.bBuffersContiguous = OMX_FALSE; + def.nBufferAlignment = 1; + + def.format.audio.cMIMEType = const_cast<char *>("audio/raw"); + def.format.audio.pNativeRender = NULL; + def.format.audio.bFlagErrorConcealment = OMX_FALSE; + def.format.audio.eEncoding = OMX_AUDIO_CodingPCM; + + addPort(def); + + def.nPortIndex = 1; + def.eDir = OMX_DirOutput; + def.nBufferCountMin = kNumBuffers; + def.nBufferCountActual = def.nBufferCountMin; + def.nBufferSize = 8192; + def.bEnabled = OMX_TRUE; + def.bPopulated = OMX_FALSE; + def.eDomain = OMX_PortDomainAudio; + def.bBuffersContiguous = OMX_FALSE; + def.nBufferAlignment = 2; + + def.format.audio.cMIMEType = const_cast<char *>("audio/3gpp"); + def.format.audio.pNativeRender = NULL; + def.format.audio.bFlagErrorConcealment = OMX_FALSE; + def.format.audio.eEncoding = OMX_AUDIO_CodingAMR; + + addPort(def); +} + +status_t SoftAMRNBEncoder::initEncoder() { + if (AMREncodeInit(&mEncState, &mSidState, false /* dtx_enable */) != 0) { + return UNKNOWN_ERROR; + } + + return OK; +} + +OMX_ERRORTYPE SoftAMRNBEncoder::internalGetParameter( + OMX_INDEXTYPE index, OMX_PTR params) { + switch (index) { + case OMX_IndexParamAudioPortFormat: + { + OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams = + (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params; + + if (formatParams->nPortIndex > 1) { + return OMX_ErrorUndefined; + } + + if (formatParams->nIndex > 0) { + return OMX_ErrorNoMore; + } + + formatParams->eEncoding = + (formatParams->nPortIndex == 0) + ? OMX_AUDIO_CodingPCM : OMX_AUDIO_CodingAMR; + + return OMX_ErrorNone; + } + + case OMX_IndexParamAudioAmr: + { + OMX_AUDIO_PARAM_AMRTYPE *amrParams = + (OMX_AUDIO_PARAM_AMRTYPE *)params; + + if (amrParams->nPortIndex != 1) { + return OMX_ErrorUndefined; + } + + amrParams->nChannels = 1; + amrParams->nBitRate = mBitRate; + amrParams->eAMRBandMode = (OMX_AUDIO_AMRBANDMODETYPE)(mMode + 1); + amrParams->eAMRDTXMode = OMX_AUDIO_AMRDTXModeOff; + amrParams->eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF; + + return OMX_ErrorNone; + } + + case OMX_IndexParamAudioPcm: + { + OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = + (OMX_AUDIO_PARAM_PCMMODETYPE *)params; + + if (pcmParams->nPortIndex != 0) { + return OMX_ErrorUndefined; + } + + pcmParams->eNumData = OMX_NumericalDataSigned; + pcmParams->eEndian = OMX_EndianBig; + pcmParams->bInterleaved = OMX_TRUE; + pcmParams->nBitPerSample = 16; + pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear; + pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelCF; + + pcmParams->nChannels = 1; + pcmParams->nSamplingRate = kSampleRate; + + return OMX_ErrorNone; + } + + default: + return SimpleSoftOMXComponent::internalGetParameter(index, params); + } +} + +OMX_ERRORTYPE SoftAMRNBEncoder::internalSetParameter( + OMX_INDEXTYPE index, const OMX_PTR params) { + switch (index) { + case OMX_IndexParamStandardComponentRole: + { + const OMX_PARAM_COMPONENTROLETYPE *roleParams = + (const OMX_PARAM_COMPONENTROLETYPE *)params; + + if (strncmp((const char *)roleParams->cRole, + "audio_encoder.amrnb", + OMX_MAX_STRINGNAME_SIZE - 1)) { + return OMX_ErrorUndefined; + } + + return OMX_ErrorNone; + } + + case OMX_IndexParamAudioPortFormat: + { + const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams = + (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params; + + if (formatParams->nPortIndex > 1) { + return OMX_ErrorUndefined; + } + + if (formatParams->nIndex > 0) { + return OMX_ErrorNoMore; + } + + if ((formatParams->nPortIndex == 0 + && formatParams->eEncoding != OMX_AUDIO_CodingPCM) + || (formatParams->nPortIndex == 1 + && formatParams->eEncoding != OMX_AUDIO_CodingAMR)) { + return OMX_ErrorUndefined; + } + + return OMX_ErrorNone; + } + + case OMX_IndexParamAudioAmr: + { + OMX_AUDIO_PARAM_AMRTYPE *amrParams = + (OMX_AUDIO_PARAM_AMRTYPE *)params; + + if (amrParams->nPortIndex != 1) { + return OMX_ErrorUndefined; + } + + if (amrParams->nChannels != 1 + || amrParams->eAMRDTXMode != OMX_AUDIO_AMRDTXModeOff + || amrParams->eAMRFrameFormat + != OMX_AUDIO_AMRFrameFormatFSF + || amrParams->eAMRBandMode < OMX_AUDIO_AMRBandModeNB0 + || amrParams->eAMRBandMode > OMX_AUDIO_AMRBandModeNB7) { + return OMX_ErrorUndefined; + } + + mBitRate = amrParams->nBitRate; + mMode = amrParams->eAMRBandMode - 1; + + amrParams->eAMRDTXMode = OMX_AUDIO_AMRDTXModeOff; + amrParams->eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF; + + return OMX_ErrorNone; + } + + case OMX_IndexParamAudioPcm: + { + OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = + (OMX_AUDIO_PARAM_PCMMODETYPE *)params; + + if (pcmParams->nPortIndex != 0) { + return OMX_ErrorUndefined; + } + + if (pcmParams->nChannels != 1 + || pcmParams->nSamplingRate != kSampleRate) { + return OMX_ErrorUndefined; + } + + return OMX_ErrorNone; + } + + + default: + return SimpleSoftOMXComponent::internalSetParameter(index, params); + } +} + +void SoftAMRNBEncoder::onQueueFilled(OMX_U32 portIndex) { + if (mSignalledError) { + return; + } + + List<BufferInfo *> &inQueue = getPortQueue(0); + List<BufferInfo *> &outQueue = getPortQueue(1); + + size_t numBytesPerInputFrame = kNumSamplesPerFrame * sizeof(int16_t); + + for (;;) { + // We do the following until we run out of buffers. + + while (mInputSize < numBytesPerInputFrame) { + // As long as there's still input data to be read we + // will drain "kNumSamplesPerFrame" samples + // into the "mInputFrame" buffer and then encode those + // as a unit into an output buffer. + + if (mSawInputEOS || inQueue.empty()) { + return; + } + + BufferInfo *inInfo = *inQueue.begin(); + OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; + + const void *inData = inHeader->pBuffer + inHeader->nOffset; + + size_t copy = numBytesPerInputFrame - mInputSize; + if (copy > inHeader->nFilledLen) { + copy = inHeader->nFilledLen; + } + + if (mInputSize == 0) { + mInputTimeUs = inHeader->nTimeStamp; + } + + memcpy((uint8_t *)mInputFrame + mInputSize, inData, copy); + mInputSize += copy; + + inHeader->nOffset += copy; + inHeader->nFilledLen -= copy; + + // "Time" on the input buffer has in effect advanced by the + // number of audio frames we just advanced nOffset by. + inHeader->nTimeStamp += + (copy * 1000000ll / kSampleRate) / sizeof(int16_t); + + if (inHeader->nFilledLen == 0) { + if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { + ALOGV("saw input EOS"); + mSawInputEOS = true; + + // Pad any remaining data with zeroes. + memset((uint8_t *)mInputFrame + mInputSize, + 0, + numBytesPerInputFrame - mInputSize); + + mInputSize = numBytesPerInputFrame; + } + + inQueue.erase(inQueue.begin()); + inInfo->mOwnedByUs = false; + notifyEmptyBufferDone(inHeader); + + inData = NULL; + inHeader = NULL; + inInfo = NULL; + } + } + + // At this point we have all the input data necessary to encode + // a single frame, all we need is an output buffer to store the result + // in. + + if (outQueue.empty()) { + return; + } + + BufferInfo *outInfo = *outQueue.begin(); + OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; + + uint8_t *outPtr = outHeader->pBuffer + outHeader->nOffset; + size_t outAvailable = outHeader->nAllocLen - outHeader->nOffset; + + Frame_Type_3GPP frameType; + int res = AMREncode( + mEncState, mSidState, (Mode)mMode, + mInputFrame, outPtr, &frameType, AMR_TX_WMF); + + CHECK_GE(res, 0); + CHECK_LE((size_t)res, outAvailable); + + // Convert header byte from WMF to IETF format. + outPtr[0] = ((outPtr[0] << 3) | 4) & 0x7c; + + outHeader->nFilledLen = res; + outHeader->nFlags = OMX_BUFFERFLAG_ENDOFFRAME; + + if (mSawInputEOS) { + // We also tag this output buffer with EOS if it corresponds + // to the final input buffer. + outHeader->nFlags = OMX_BUFFERFLAG_EOS; + } + + outHeader->nTimeStamp = mInputTimeUs; + +#if 0 + ALOGI("sending %d bytes of data (time = %lld us, flags = 0x%08lx)", + nOutputBytes, mInputTimeUs, outHeader->nFlags); + + hexdump(outHeader->pBuffer + outHeader->nOffset, outHeader->nFilledLen); +#endif + + outQueue.erase(outQueue.begin()); + outInfo->mOwnedByUs = false; + notifyFillBufferDone(outHeader); + + outHeader = NULL; + outInfo = NULL; + + mInputSize = 0; + } +} + +} // namespace android + +android::SoftOMXComponent *createSoftOMXComponent( + const char *name, const OMX_CALLBACKTYPE *callbacks, + OMX_PTR appData, OMX_COMPONENTTYPE **component) { + return new android::SoftAMRNBEncoder(name, callbacks, appData, component); +} diff --git a/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.h b/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.h new file mode 100644 index 0000000..50178c4 --- /dev/null +++ b/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2012 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. + */ + +#ifndef SOFT_AMRNB_ENCODER_H_ + +#define SOFT_AMRNB_ENCODER_H_ + +#include "SimpleSoftOMXComponent.h" + +namespace android { + +struct SoftAMRNBEncoder : public SimpleSoftOMXComponent { + SoftAMRNBEncoder( + const char *name, + const OMX_CALLBACKTYPE *callbacks, + OMX_PTR appData, + OMX_COMPONENTTYPE **component); + +protected: + virtual ~SoftAMRNBEncoder(); + + virtual OMX_ERRORTYPE internalGetParameter( + OMX_INDEXTYPE index, OMX_PTR params); + + virtual OMX_ERRORTYPE internalSetParameter( + OMX_INDEXTYPE index, const OMX_PTR params); + + virtual void onQueueFilled(OMX_U32 portIndex); + +private: + enum { + kNumBuffers = 4, + kNumSamplesPerFrame = 160, + }; + + void *mEncState; + void *mSidState; + + OMX_U32 mBitRate; + int mMode; + + size_t mInputSize; + int16_t mInputFrame[kNumSamplesPerFrame]; + int64_t mInputTimeUs; + + bool mSawInputEOS; + bool mSignalledError; + + void initPorts(); + status_t initEncoder(); + + status_t setAudioParams(); + + DISALLOW_EVIL_CONSTRUCTORS(SoftAMRNBEncoder); +}; + +} // namespace android + +#endif // SOFT_AMRNB_ENCODER_H_ diff --git a/media/libstagefright/codecs/amrwbenc/Android.mk b/media/libstagefright/codecs/amrwbenc/Android.mk index ae43870..6ce6171 100644 --- a/media/libstagefright/codecs/amrwbenc/Android.mk +++ b/media/libstagefright/codecs/amrwbenc/Android.mk @@ -117,4 +117,26 @@ endif include $(BUILD_STATIC_LIBRARY) +################################################################################ +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + SoftAMRWBEncoder.cpp + +LOCAL_C_INCLUDES := \ + frameworks/base/media/libstagefright/include \ + frameworks/base/include/media/stagefright/openmax \ + frameworks/base/media/libstagefright/codecs/common/include \ + +LOCAL_STATIC_LIBRARIES := \ + libstagefright_amrwbenc + +LOCAL_SHARED_LIBRARIES := \ + libstagefright_omx libstagefright_foundation libutils \ + libstagefright_enc_common + +LOCAL_MODULE := libstagefright_soft_amrwbenc +LOCAL_MODULE_TAGS := optional + +include $(BUILD_SHARED_LIBRARY) diff --git a/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.cpp b/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.cpp new file mode 100644 index 0000000..9ccb49c --- /dev/null +++ b/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.cpp @@ -0,0 +1,459 @@ +/* + * Copyright (C) 2012 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. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "SoftAMRWBEncoder" +#include <utils/Log.h> + +#include "SoftAMRWBEncoder.h" + +#include "cmnMemory.h" + +#include <media/stagefright/foundation/ADebug.h> +#include <media/stagefright/foundation/hexdump.h> + +namespace android { + +static const int32_t kSampleRate = 16000; + +template<class T> +static void InitOMXParams(T *params) { + params->nSize = sizeof(T); + params->nVersion.s.nVersionMajor = 1; + params->nVersion.s.nVersionMinor = 0; + params->nVersion.s.nRevision = 0; + params->nVersion.s.nStep = 0; +} + +SoftAMRWBEncoder::SoftAMRWBEncoder( + const char *name, + const OMX_CALLBACKTYPE *callbacks, + OMX_PTR appData, + OMX_COMPONENTTYPE **component) + : SimpleSoftOMXComponent(name, callbacks, appData, component), + mEncoderHandle(NULL), + mApiHandle(NULL), + mMemOperator(NULL), + mBitRate(0), + mMode(VOAMRWB_MD66), + mInputSize(0), + mInputTimeUs(-1ll), + mSawInputEOS(false), + mSignalledError(false) { + initPorts(); + CHECK_EQ(initEncoder(), (status_t)OK); +} + +SoftAMRWBEncoder::~SoftAMRWBEncoder() { + if (mEncoderHandle != NULL) { + CHECK_EQ(VO_ERR_NONE, mApiHandle->Uninit(mEncoderHandle)); + mEncoderHandle = NULL; + } + + delete mApiHandle; + mApiHandle = NULL; + + delete mMemOperator; + mMemOperator = NULL; +} + +void SoftAMRWBEncoder::initPorts() { + OMX_PARAM_PORTDEFINITIONTYPE def; + InitOMXParams(&def); + + def.nPortIndex = 0; + def.eDir = OMX_DirInput; + def.nBufferCountMin = kNumBuffers; + def.nBufferCountActual = def.nBufferCountMin; + def.nBufferSize = kNumSamplesPerFrame * sizeof(int16_t); + def.bEnabled = OMX_TRUE; + def.bPopulated = OMX_FALSE; + def.eDomain = OMX_PortDomainAudio; + def.bBuffersContiguous = OMX_FALSE; + def.nBufferAlignment = 1; + + def.format.audio.cMIMEType = const_cast<char *>("audio/raw"); + def.format.audio.pNativeRender = NULL; + def.format.audio.bFlagErrorConcealment = OMX_FALSE; + def.format.audio.eEncoding = OMX_AUDIO_CodingPCM; + + addPort(def); + + def.nPortIndex = 1; + def.eDir = OMX_DirOutput; + def.nBufferCountMin = kNumBuffers; + def.nBufferCountActual = def.nBufferCountMin; + def.nBufferSize = 8192; + def.bEnabled = OMX_TRUE; + def.bPopulated = OMX_FALSE; + def.eDomain = OMX_PortDomainAudio; + def.bBuffersContiguous = OMX_FALSE; + def.nBufferAlignment = 2; + + def.format.audio.cMIMEType = const_cast<char *>("audio/amr-wb"); + def.format.audio.pNativeRender = NULL; + def.format.audio.bFlagErrorConcealment = OMX_FALSE; + def.format.audio.eEncoding = OMX_AUDIO_CodingAMR; + + addPort(def); +} + +status_t SoftAMRWBEncoder::initEncoder() { + mApiHandle = new VO_AUDIO_CODECAPI; + + if (VO_ERR_NONE != voGetAMRWBEncAPI(mApiHandle)) { + ALOGE("Failed to get api handle"); + return UNKNOWN_ERROR; + } + + mMemOperator = new VO_MEM_OPERATOR; + mMemOperator->Alloc = cmnMemAlloc; + mMemOperator->Copy = cmnMemCopy; + mMemOperator->Free = cmnMemFree; + mMemOperator->Set = cmnMemSet; + mMemOperator->Check = cmnMemCheck; + + VO_CODEC_INIT_USERDATA userData; + memset(&userData, 0, sizeof(userData)); + userData.memflag = VO_IMF_USERMEMOPERATOR; + userData.memData = (VO_PTR) mMemOperator; + + if (VO_ERR_NONE != mApiHandle->Init( + &mEncoderHandle, VO_AUDIO_CodingAMRWB, &userData)) { + ALOGE("Failed to init AMRWB encoder"); + return UNKNOWN_ERROR; + } + + VOAMRWBFRAMETYPE type = VOAMRWB_RFC3267; + if (VO_ERR_NONE != mApiHandle->SetParam( + mEncoderHandle, VO_PID_AMRWB_FRAMETYPE, &type)) { + ALOGE("Failed to set AMRWB encoder frame type to %d", type); + return UNKNOWN_ERROR; + } + + return OK; +} + +OMX_ERRORTYPE SoftAMRWBEncoder::internalGetParameter( + OMX_INDEXTYPE index, OMX_PTR params) { + switch (index) { + case OMX_IndexParamAudioPortFormat: + { + OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams = + (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params; + + if (formatParams->nPortIndex > 1) { + return OMX_ErrorUndefined; + } + + if (formatParams->nIndex > 0) { + return OMX_ErrorNoMore; + } + + formatParams->eEncoding = + (formatParams->nPortIndex == 0) + ? OMX_AUDIO_CodingPCM : OMX_AUDIO_CodingAMR; + + return OMX_ErrorNone; + } + + case OMX_IndexParamAudioAmr: + { + OMX_AUDIO_PARAM_AMRTYPE *amrParams = + (OMX_AUDIO_PARAM_AMRTYPE *)params; + + if (amrParams->nPortIndex != 1) { + return OMX_ErrorUndefined; + } + + amrParams->nChannels = 1; + amrParams->nBitRate = mBitRate; + + amrParams->eAMRBandMode = + (OMX_AUDIO_AMRBANDMODETYPE)(mMode + OMX_AUDIO_AMRBandModeWB0); + + amrParams->eAMRDTXMode = OMX_AUDIO_AMRDTXModeOff; + amrParams->eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF; + + return OMX_ErrorNone; + } + + case OMX_IndexParamAudioPcm: + { + OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = + (OMX_AUDIO_PARAM_PCMMODETYPE *)params; + + if (pcmParams->nPortIndex != 0) { + return OMX_ErrorUndefined; + } + + pcmParams->eNumData = OMX_NumericalDataSigned; + pcmParams->eEndian = OMX_EndianBig; + pcmParams->bInterleaved = OMX_TRUE; + pcmParams->nBitPerSample = 16; + pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear; + pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelCF; + + pcmParams->nChannels = 1; + pcmParams->nSamplingRate = kSampleRate; + + return OMX_ErrorNone; + } + + default: + return SimpleSoftOMXComponent::internalGetParameter(index, params); + } +} + +OMX_ERRORTYPE SoftAMRWBEncoder::internalSetParameter( + OMX_INDEXTYPE index, const OMX_PTR params) { + switch (index) { + case OMX_IndexParamStandardComponentRole: + { + const OMX_PARAM_COMPONENTROLETYPE *roleParams = + (const OMX_PARAM_COMPONENTROLETYPE *)params; + + if (strncmp((const char *)roleParams->cRole, + "audio_encoder.amrwb", + OMX_MAX_STRINGNAME_SIZE - 1)) { + return OMX_ErrorUndefined; + } + + return OMX_ErrorNone; + } + + case OMX_IndexParamAudioPortFormat: + { + const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams = + (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params; + + if (formatParams->nPortIndex > 1) { + return OMX_ErrorUndefined; + } + + if (formatParams->nIndex > 0) { + return OMX_ErrorNoMore; + } + + if ((formatParams->nPortIndex == 0 + && formatParams->eEncoding != OMX_AUDIO_CodingPCM) + || (formatParams->nPortIndex == 1 + && formatParams->eEncoding != OMX_AUDIO_CodingAMR)) { + return OMX_ErrorUndefined; + } + + return OMX_ErrorNone; + } + + case OMX_IndexParamAudioAmr: + { + OMX_AUDIO_PARAM_AMRTYPE *amrParams = + (OMX_AUDIO_PARAM_AMRTYPE *)params; + + if (amrParams->nPortIndex != 1) { + return OMX_ErrorUndefined; + } + + if (amrParams->nChannels != 1 + || amrParams->eAMRDTXMode != OMX_AUDIO_AMRDTXModeOff + || amrParams->eAMRFrameFormat + != OMX_AUDIO_AMRFrameFormatFSF + || amrParams->eAMRBandMode < OMX_AUDIO_AMRBandModeWB0 + || amrParams->eAMRBandMode > OMX_AUDIO_AMRBandModeWB8) { + return OMX_ErrorUndefined; + } + + mBitRate = amrParams->nBitRate; + + mMode = (VOAMRWBMODE)( + amrParams->eAMRBandMode - OMX_AUDIO_AMRBandModeWB0); + + amrParams->eAMRDTXMode = OMX_AUDIO_AMRDTXModeOff; + amrParams->eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF; + + if (VO_ERR_NONE != + mApiHandle->SetParam( + mEncoderHandle, VO_PID_AMRWB_MODE, &mMode)) { + ALOGE("Failed to set AMRWB encoder mode to %d", mMode); + return OMX_ErrorUndefined; + } + + return OMX_ErrorNone; + } + + case OMX_IndexParamAudioPcm: + { + OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = + (OMX_AUDIO_PARAM_PCMMODETYPE *)params; + + if (pcmParams->nPortIndex != 0) { + return OMX_ErrorUndefined; + } + + if (pcmParams->nChannels != 1 + || pcmParams->nSamplingRate != (OMX_U32)kSampleRate) { + return OMX_ErrorUndefined; + } + + return OMX_ErrorNone; + } + + + default: + return SimpleSoftOMXComponent::internalSetParameter(index, params); + } +} + +void SoftAMRWBEncoder::onQueueFilled(OMX_U32 portIndex) { + if (mSignalledError) { + return; + } + + List<BufferInfo *> &inQueue = getPortQueue(0); + List<BufferInfo *> &outQueue = getPortQueue(1); + + size_t numBytesPerInputFrame = kNumSamplesPerFrame * sizeof(int16_t); + + for (;;) { + // We do the following until we run out of buffers. + + while (mInputSize < numBytesPerInputFrame) { + // As long as there's still input data to be read we + // will drain "kNumSamplesPerFrame" samples + // into the "mInputFrame" buffer and then encode those + // as a unit into an output buffer. + + if (mSawInputEOS || inQueue.empty()) { + return; + } + + BufferInfo *inInfo = *inQueue.begin(); + OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; + + const void *inData = inHeader->pBuffer + inHeader->nOffset; + + size_t copy = numBytesPerInputFrame - mInputSize; + if (copy > inHeader->nFilledLen) { + copy = inHeader->nFilledLen; + } + + if (mInputSize == 0) { + mInputTimeUs = inHeader->nTimeStamp; + } + + memcpy((uint8_t *)mInputFrame + mInputSize, inData, copy); + mInputSize += copy; + + inHeader->nOffset += copy; + inHeader->nFilledLen -= copy; + + // "Time" on the input buffer has in effect advanced by the + // number of audio frames we just advanced nOffset by. + inHeader->nTimeStamp += + (copy * 1000000ll / kSampleRate) / sizeof(int16_t); + + if (inHeader->nFilledLen == 0) { + if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { + ALOGV("saw input EOS"); + mSawInputEOS = true; + + // Pad any remaining data with zeroes. + memset((uint8_t *)mInputFrame + mInputSize, + 0, + numBytesPerInputFrame - mInputSize); + + mInputSize = numBytesPerInputFrame; + } + + inQueue.erase(inQueue.begin()); + inInfo->mOwnedByUs = false; + notifyEmptyBufferDone(inHeader); + + inData = NULL; + inHeader = NULL; + inInfo = NULL; + } + } + + // At this point we have all the input data necessary to encode + // a single frame, all we need is an output buffer to store the result + // in. + + if (outQueue.empty()) { + return; + } + + BufferInfo *outInfo = *outQueue.begin(); + OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; + + uint8_t *outPtr = outHeader->pBuffer + outHeader->nOffset; + size_t outAvailable = outHeader->nAllocLen - outHeader->nOffset; + + VO_CODECBUFFER inputData; + memset(&inputData, 0, sizeof(inputData)); + inputData.Buffer = (unsigned char *) mInputFrame; + inputData.Length = mInputSize; + + CHECK_EQ(VO_ERR_NONE, + mApiHandle->SetInputData(mEncoderHandle, &inputData)); + + VO_CODECBUFFER outputData; + memset(&outputData, 0, sizeof(outputData)); + VO_AUDIO_OUTPUTINFO outputInfo; + memset(&outputInfo, 0, sizeof(outputInfo)); + + outputData.Buffer = outPtr; + outputData.Length = outAvailable; + VO_U32 ret = mApiHandle->GetOutputData( + mEncoderHandle, &outputData, &outputInfo); + CHECK(ret == VO_ERR_NONE || ret == VO_ERR_INPUT_BUFFER_SMALL); + + outHeader->nFilledLen = outputData.Length; + outHeader->nFlags = OMX_BUFFERFLAG_ENDOFFRAME; + + if (mSawInputEOS) { + // We also tag this output buffer with EOS if it corresponds + // to the final input buffer. + outHeader->nFlags = OMX_BUFFERFLAG_EOS; + } + + outHeader->nTimeStamp = mInputTimeUs; + +#if 0 + ALOGI("sending %ld bytes of data (time = %lld us, flags = 0x%08lx)", + outHeader->nFilledLen, mInputTimeUs, outHeader->nFlags); + + hexdump(outHeader->pBuffer + outHeader->nOffset, outHeader->nFilledLen); +#endif + + outQueue.erase(outQueue.begin()); + outInfo->mOwnedByUs = false; + notifyFillBufferDone(outHeader); + + outHeader = NULL; + outInfo = NULL; + + mInputSize = 0; + } +} + +} // namespace android + +android::SoftOMXComponent *createSoftOMXComponent( + const char *name, const OMX_CALLBACKTYPE *callbacks, + OMX_PTR appData, OMX_COMPONENTTYPE **component) { + return new android::SoftAMRWBEncoder(name, callbacks, appData, component); +} diff --git a/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.h b/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.h new file mode 100644 index 0000000..d0c1dab --- /dev/null +++ b/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2012 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. + */ + +#ifndef SOFT_AMRWB_ENCODER_H_ + +#define SOFT_AMRWB_ENCODER_H_ + +#include "SimpleSoftOMXComponent.h" + +#include "voAMRWB.h" + +struct VO_AUDIO_CODECAPI; +struct VO_MEM_OPERATOR; + +namespace android { + +struct SoftAMRWBEncoder : public SimpleSoftOMXComponent { + SoftAMRWBEncoder( + const char *name, + const OMX_CALLBACKTYPE *callbacks, + OMX_PTR appData, + OMX_COMPONENTTYPE **component); + +protected: + virtual ~SoftAMRWBEncoder(); + + virtual OMX_ERRORTYPE internalGetParameter( + OMX_INDEXTYPE index, OMX_PTR params); + + virtual OMX_ERRORTYPE internalSetParameter( + OMX_INDEXTYPE index, const OMX_PTR params); + + virtual void onQueueFilled(OMX_U32 portIndex); + +private: + enum { + kNumBuffers = 4, + kNumSamplesPerFrame = 320, + }; + + void *mEncoderHandle; + VO_AUDIO_CODECAPI *mApiHandle; + VO_MEM_OPERATOR *mMemOperator; + + OMX_U32 mBitRate; + VOAMRWBMODE mMode; + + size_t mInputSize; + int16_t mInputFrame[kNumSamplesPerFrame]; + int64_t mInputTimeUs; + + bool mSawInputEOS; + bool mSignalledError; + + void initPorts(); + status_t initEncoder(); + + DISALLOW_EVIL_CONSTRUCTORS(SoftAMRWBEncoder); +}; + +} // namespace android + +#endif // SOFT_AMRWB_ENCODER_H_ diff --git a/media/libstagefright/colorconversion/ColorConverter.cpp b/media/libstagefright/colorconversion/ColorConverter.cpp index 5cc3f78..f3ef3de 100644 --- a/media/libstagefright/colorconversion/ColorConverter.cpp +++ b/media/libstagefright/colorconversion/ColorConverter.cpp @@ -144,8 +144,8 @@ status_t ColorConverter::convertCbYCrY( return ERROR_UNSUPPORTED; } - uint32_t *dst_ptr = (uint32_t *)dst.mBits - + (dst.mCropTop * dst.mWidth + dst.mCropLeft) / 2; + uint16_t *dst_ptr = (uint16_t *)dst.mBits + + dst.mCropTop * dst.mWidth + dst.mCropLeft; const uint8_t *src_ptr = (const uint8_t *)src.mBits + (src.mCropTop * dst.mWidth + src.mCropLeft) * 2; @@ -182,11 +182,15 @@ status_t ColorConverter::convertCbYCrY( | ((kAdjustedClip[g2] >> 2) << 5) | (kAdjustedClip[b2] >> 3); - dst_ptr[x / 2] = (rgb2 << 16) | rgb1; + if (x + 1 < src.cropWidth()) { + *(uint32_t *)(&dst_ptr[x]) = (rgb2 << 16) | rgb1; + } else { + dst_ptr[x] = rgb1; + } } src_ptr += src.mWidth * 2; - dst_ptr += dst.mWidth / 2; + dst_ptr += dst.mWidth; } return OK; @@ -290,15 +294,14 @@ status_t ColorConverter::convertQCOMYUV420SemiPlanar( const BitmapParams &src, const BitmapParams &dst) { uint8_t *kAdjustedClip = initClip(); - if (!((dst.mWidth & 3) == 0 - && (src.mCropLeft & 1) == 0 + if (!((src.mCropLeft & 1) == 0 && src.cropWidth() == dst.cropWidth() && src.cropHeight() == dst.cropHeight())) { return ERROR_UNSUPPORTED; } - uint32_t *dst_ptr = (uint32_t *)dst.mBits - + (dst.mCropTop * dst.mWidth + dst.mCropLeft) / 2; + uint16_t *dst_ptr = (uint16_t *)dst.mBits + + dst.mCropTop * dst.mWidth + dst.mCropLeft; const uint8_t *src_y = (const uint8_t *)src.mBits + src.mCropTop * src.mWidth + src.mCropLeft; @@ -340,7 +343,11 @@ status_t ColorConverter::convertQCOMYUV420SemiPlanar( | ((kAdjustedClip[g2] >> 2) << 5) | (kAdjustedClip[r2] >> 3); - dst_ptr[x / 2] = (rgb2 << 16) | rgb1; + if (x + 1 < src.cropWidth()) { + *(uint32_t *)(&dst_ptr[x]) = (rgb2 << 16) | rgb1; + } else { + dst_ptr[x] = rgb1; + } } src_y += src.mWidth; @@ -349,7 +356,7 @@ status_t ColorConverter::convertQCOMYUV420SemiPlanar( src_u += src.mWidth; } - dst_ptr += dst.mWidth / 2; + dst_ptr += dst.mWidth; } return OK; @@ -361,15 +368,14 @@ status_t ColorConverter::convertYUV420SemiPlanar( uint8_t *kAdjustedClip = initClip(); - if (!((dst.mWidth & 3) == 0 - && (src.mCropLeft & 1) == 0 + if (!((src.mCropLeft & 1) == 0 && src.cropWidth() == dst.cropWidth() && src.cropHeight() == dst.cropHeight())) { return ERROR_UNSUPPORTED; } - uint32_t *dst_ptr = (uint32_t *)dst.mBits - + (dst.mCropTop * dst.mWidth + dst.mCropLeft) / 2; + uint16_t *dst_ptr = (uint16_t *)dst.mBits + + dst.mCropTop * dst.mWidth + dst.mCropLeft; const uint8_t *src_y = (const uint8_t *)src.mBits + src.mCropTop * src.mWidth + src.mCropLeft; @@ -411,7 +417,11 @@ status_t ColorConverter::convertYUV420SemiPlanar( | ((kAdjustedClip[g2] >> 2) << 5) | (kAdjustedClip[r2] >> 3); - dst_ptr[x / 2] = (rgb2 << 16) | rgb1; + if (x + 1 < src.cropWidth()) { + *(uint32_t *)(&dst_ptr[x]) = (rgb2 << 16) | rgb1; + } else { + dst_ptr[x] = rgb1; + } } src_y += src.mWidth; @@ -420,7 +430,7 @@ status_t ColorConverter::convertYUV420SemiPlanar( src_u += src.mWidth; } - dst_ptr += dst.mWidth / 2; + dst_ptr += dst.mWidth; } return OK; @@ -430,15 +440,14 @@ status_t ColorConverter::convertTIYUV420PackedSemiPlanar( const BitmapParams &src, const BitmapParams &dst) { uint8_t *kAdjustedClip = initClip(); - if (!((dst.mWidth & 3) == 0 - && (src.mCropLeft & 1) == 0 + if (!((src.mCropLeft & 1) == 0 && src.cropWidth() == dst.cropWidth() && src.cropHeight() == dst.cropHeight())) { return ERROR_UNSUPPORTED; } - uint32_t *dst_ptr = (uint32_t *)dst.mBits - + (dst.mCropTop * dst.mWidth + dst.mCropLeft) / 2; + uint16_t *dst_ptr = (uint16_t *)dst.mBits + + dst.mCropTop * dst.mWidth + dst.mCropLeft; const uint8_t *src_y = (const uint8_t *)src.mBits; @@ -478,7 +487,11 @@ status_t ColorConverter::convertTIYUV420PackedSemiPlanar( | ((kAdjustedClip[g2] >> 2) << 5) | (kAdjustedClip[b2] >> 3); - dst_ptr[x / 2] = (rgb2 << 16) | rgb1; + if (x + 1 < src.cropWidth()) { + *(uint32_t *)(&dst_ptr[x]) = (rgb2 << 16) | rgb1; + } else { + dst_ptr[x] = rgb1; + } } src_y += src.mWidth; @@ -487,7 +500,7 @@ status_t ColorConverter::convertTIYUV420PackedSemiPlanar( src_u += src.mWidth; } - dst_ptr += dst.mWidth / 2; + dst_ptr += dst.mWidth; } return OK; diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp index 0df66f1..0cddd2e 100644 --- a/media/libstagefright/httplive/LiveSession.cpp +++ b/media/libstagefright/httplive/LiveSession.cpp @@ -215,7 +215,9 @@ void LiveSession::onDisconnect() { mDisconnectPending = false; } -status_t LiveSession::fetchFile(const char *url, sp<ABuffer> *out) { +status_t LiveSession::fetchFile( + const char *url, sp<ABuffer> *out, + int64_t range_offset, int64_t range_length) { *out = NULL; sp<DataSource> source; @@ -234,8 +236,18 @@ status_t LiveSession::fetchFile(const char *url, sp<ABuffer> *out) { } } - status_t err = mHTTPDataSource->connect( - url, mExtraHeaders.isEmpty() ? NULL : &mExtraHeaders); + KeyedVector<String8, String8> headers = mExtraHeaders; + if (range_offset > 0 || range_length >= 0) { + headers.add( + String8("Range"), + String8( + StringPrintf( + "bytes=%lld-%s", + range_offset, + range_length < 0 + ? "" : StringPrintf("%lld", range_offset + range_length - 1).c_str()).c_str())); + } + status_t err = mHTTPDataSource->connect(url, &headers); if (err != OK) { return err; @@ -270,9 +282,21 @@ status_t LiveSession::fetchFile(const char *url, sp<ABuffer> *out) { buffer = copy; } + size_t maxBytesToRead = bufferRemaining; + if (range_length >= 0) { + int64_t bytesLeftInRange = range_length - buffer->size(); + if (bytesLeftInRange < maxBytesToRead) { + maxBytesToRead = bytesLeftInRange; + + if (bytesLeftInRange == 0) { + break; + } + } + } + ssize_t n = source->readAt( buffer->size(), buffer->data() + buffer->size(), - bufferRemaining); + maxBytesToRead); if (n < 0) { return n; @@ -659,8 +683,15 @@ rinse_repeat: explicitDiscontinuity = true; } + int64_t range_offset, range_length; + if (!itemMeta->findInt64("range-offset", &range_offset) + || !itemMeta->findInt64("range-length", &range_length)) { + range_offset = 0; + range_length = -1; + } + sp<ABuffer> buffer; - status_t err = fetchFile(uri.c_str(), &buffer); + status_t err = fetchFile(uri.c_str(), &buffer, range_offset, range_length); if (err != OK) { ALOGE("failed to fetch .ts segment at url '%s'", uri.c_str()); mDataSource->queueEOS(err); diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp index 5e30488..7d3cf05 100644 --- a/media/libstagefright/httplive/M3UParser.cpp +++ b/media/libstagefright/httplive/M3UParser.cpp @@ -152,6 +152,7 @@ status_t M3UParser::parse(const void *_data, size_t size) { const char *data = (const char *)_data; size_t offset = 0; + uint64_t segmentRangeOffset = 0; while (offset < size) { size_t offsetLF = offset; while (offsetLF < size && data[offsetLF] != '\n') { @@ -218,6 +219,24 @@ status_t M3UParser::parse(const void *_data, size_t size) { } mIsVariantPlaylist = true; err = parseStreamInf(line, &itemMeta); + } else if (line.startsWith("#EXT-X-BYTERANGE")) { + if (mIsVariantPlaylist) { + return ERROR_MALFORMED; + } + + uint64_t length, offset; + err = parseByteRange(line, segmentRangeOffset, &length, &offset); + + if (err == OK) { + if (itemMeta == NULL) { + itemMeta = new AMessage; + } + + itemMeta->setInt64("range-offset", offset); + itemMeta->setInt64("range-length", length); + + segmentRangeOffset = offset + length; + } } if (err != OK) { @@ -447,6 +466,52 @@ status_t M3UParser::parseCipherInfo( } // static +status_t M3UParser::parseByteRange( + const AString &line, uint64_t curOffset, + uint64_t *length, uint64_t *offset) { + ssize_t colonPos = line.find(":"); + + if (colonPos < 0) { + return ERROR_MALFORMED; + } + + ssize_t atPos = line.find("@", colonPos + 1); + + AString lenStr; + if (atPos < 0) { + lenStr = AString(line, colonPos + 1, line.size() - colonPos - 1); + } else { + lenStr = AString(line, colonPos + 1, atPos - colonPos - 1); + } + + lenStr.trim(); + + const char *s = lenStr.c_str(); + char *end; + *length = strtoull(s, &end, 10); + + if (s == end || *end != '\0') { + return ERROR_MALFORMED; + } + + if (atPos >= 0) { + AString offStr = AString(line, atPos + 1, line.size() - atPos - 1); + offStr.trim(); + + const char *s = offStr.c_str(); + *offset = strtoull(s, &end, 10); + + if (s == end || *end != '\0') { + return ERROR_MALFORMED; + } + } else { + *offset = curOffset; + } + + return OK; +} + +// static status_t M3UParser::ParseInt32(const char *s, int32_t *x) { char *end; long lval = strtol(s, &end, 10); diff --git a/media/libstagefright/include/AACExtractor.h b/media/libstagefright/include/AACExtractor.h index 8e5657b..e98ca82 100644 --- a/media/libstagefright/include/AACExtractor.h +++ b/media/libstagefright/include/AACExtractor.h @@ -29,7 +29,7 @@ class String8; class AACExtractor : public MediaExtractor { public: - AACExtractor(const sp<DataSource> &source); + AACExtractor(const sp<DataSource> &source, const sp<AMessage> &meta); virtual size_t countTracks(); virtual sp<MediaSource> getTrack(size_t index); diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h index 0985f47..a7a3d47 100644 --- a/media/libstagefright/include/AwesomePlayer.h +++ b/media/libstagefright/include/AwesomePlayer.h @@ -41,7 +41,7 @@ struct ISurfaceTexture; class DrmManagerClinet; class DecryptHandle; -class TimedTextPlayer; +class TimedTextDriver; struct WVMExtractor; struct AwesomeRenderer : public RefBase { @@ -232,7 +232,7 @@ private: sp<DecryptHandle> mDecryptHandle; int64_t mLastVideoTimeUs; - TimedTextPlayer *mTextPlayer; + TimedTextDriver *mTextDriver; mutable Mutex mTimedTextLock; sp<WVMExtractor> mWVMExtractor; @@ -290,6 +290,7 @@ private: bool isStreamingHTTP() const; void sendCacheStats(); + void checkDrmStatus(const sp<DataSource>& dataSource); enum FlagMode { SET, @@ -325,4 +326,3 @@ private: } // namespace android #endif // AWESOME_PLAYER_H_ - diff --git a/media/libstagefright/include/ChromiumHTTPDataSource.h b/media/libstagefright/include/ChromiumHTTPDataSource.h index 18f8913..82e08fd 100644 --- a/media/libstagefright/include/ChromiumHTTPDataSource.h +++ b/media/libstagefright/include/ChromiumHTTPDataSource.h @@ -43,7 +43,7 @@ struct ChromiumHTTPDataSource : public HTTPBase { virtual status_t getSize(off64_t *size); virtual uint32_t flags(); - virtual sp<DecryptHandle> DrmInitialization(); + virtual sp<DecryptHandle> DrmInitialization(const char *mime); virtual void getDrmInfo(sp<DecryptHandle> &handle, DrmManagerClient **client); diff --git a/media/libstagefright/include/DataUriSource.h b/media/libstagefright/include/DataUriSource.h new file mode 100644 index 0000000..d223c06 --- /dev/null +++ b/media/libstagefright/include/DataUriSource.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2011 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. + */ + +#ifndef DATA_URI_SOURCE_H_ + +#define DATA_URI_SOURCE_H_ + +#include <stdio.h> + +#include <media/stagefright/DataSource.h> +#include <media/stagefright/MediaErrors.h> +#include <media/stagefright/foundation/AString.h> + +namespace android { + +class DataUriSource : public DataSource { +public: + DataUriSource(const char *uri); + + virtual status_t initCheck() const { + return mInited; + } + + virtual ssize_t readAt(off64_t offset, void *data, size_t size); + + virtual status_t getSize(off64_t *size) { + if (mInited != OK) { + return mInited; + } + + *size = mData.size(); + return OK; + } + + virtual String8 getUri() { + return mDataUri; + } + + virtual String8 getMIMEType() const { + return mMimeType; + } + +protected: + virtual ~DataUriSource() { + // Nothing to delete. + } + +private: + const String8 mDataUri; + + String8 mMimeType; + // Use AString because individual bytes may not be valid UTF8 chars. + AString mData; + status_t mInited; + + // Disallow copy and assign. + DataUriSource(const DataUriSource &); + DataUriSource &operator=(const DataUriSource &); +}; + +} // namespace android + +#endif // DATA_URI_SOURCE_H_ diff --git a/media/libstagefright/include/LiveSession.h b/media/libstagefright/include/LiveSession.h index 116ed0e..3a11612 100644 --- a/media/libstagefright/include/LiveSession.h +++ b/media/libstagefright/include/LiveSession.h @@ -120,7 +120,10 @@ private: void onMonitorQueue(); void onSeek(const sp<AMessage> &msg); - status_t fetchFile(const char *url, sp<ABuffer> *out); + status_t fetchFile( + const char *url, sp<ABuffer> *out, + int64_t range_offset = 0, int64_t range_length = -1); + sp<M3UParser> fetchPlaylist(const char *url, bool *unchanged); size_t getBandwidthIndex(); diff --git a/media/libstagefright/include/M3UParser.h b/media/libstagefright/include/M3UParser.h index 478582d..e30d6fd 100644 --- a/media/libstagefright/include/M3UParser.h +++ b/media/libstagefright/include/M3UParser.h @@ -72,6 +72,10 @@ private: static status_t parseCipherInfo( const AString &line, sp<AMessage> *meta, const AString &baseURI); + static status_t parseByteRange( + const AString &line, uint64_t curOffset, + uint64_t *length, uint64_t *offset); + static status_t ParseInt32(const char *s, int32_t *x); static status_t ParseDouble(const char *s, double *x); diff --git a/media/libstagefright/include/NuCachedSource2.h b/media/libstagefright/include/NuCachedSource2.h index 7a03e7e..c27a29b 100644 --- a/media/libstagefright/include/NuCachedSource2.h +++ b/media/libstagefright/include/NuCachedSource2.h @@ -40,7 +40,7 @@ struct NuCachedSource2 : public DataSource { virtual status_t getSize(off64_t *size); virtual uint32_t flags(); - virtual sp<DecryptHandle> DrmInitialization(); + virtual sp<DecryptHandle> DrmInitialization(const char* mime); virtual void getDrmInfo(sp<DecryptHandle> &handle, DrmManagerClient **client); virtual String8 getUri(); diff --git a/media/libstagefright/include/OMX.h b/media/libstagefright/include/OMX.h index 53e764f..2c87b34 100644 --- a/media/libstagefright/include/OMX.h +++ b/media/libstagefright/include/OMX.h @@ -31,7 +31,7 @@ class OMX : public BnOMX, public: OMX(); - virtual bool livesLocally(pid_t pid); + virtual bool livesLocally(node_id node, pid_t pid); virtual status_t listNodes(List<ComponentInfo> *list); diff --git a/media/libstagefright/include/ThrottledSource.h b/media/libstagefright/include/ThrottledSource.h index 8928a4a..7fe7c06 100644 --- a/media/libstagefright/include/ThrottledSource.h +++ b/media/libstagefright/include/ThrottledSource.h @@ -35,6 +35,11 @@ struct ThrottledSource : public DataSource { virtual status_t getSize(off64_t *size); virtual uint32_t flags(); + virtual String8 getMIMEType() const { + return mSource->getMIMEType(); + } + + private: Mutex mLock; diff --git a/media/libstagefright/include/WVMExtractor.h b/media/libstagefright/include/WVMExtractor.h index deecd25..9f763f9 100644 --- a/media/libstagefright/include/WVMExtractor.h +++ b/media/libstagefright/include/WVMExtractor.h @@ -23,6 +23,8 @@ namespace android { +struct AMessage; +class String8; class DataSource; class WVMLoadableExtractor : public MediaExtractor { @@ -58,6 +60,8 @@ public: // is used. void setAdaptiveStreamingMode(bool adaptive); + static bool getVendorLibHandle(); + protected: virtual ~WVMExtractor(); @@ -69,6 +73,10 @@ private: WVMExtractor &operator=(const WVMExtractor &); }; +bool SniffWVM( + const sp<DataSource> &source, String8 *mimeType, float *confidence, + sp<AMessage> *); + } // namespace android #endif // DRM_EXTRACTOR_H_ diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp index 694b12d..ace883c 100644 --- a/media/libstagefright/omx/OMX.cpp +++ b/media/libstagefright/omx/OMX.cpp @@ -185,7 +185,7 @@ void OMX::binderDied(const wp<IBinder> &the_late_who) { instance->onObserverDied(mMaster); } -bool OMX::livesLocally(pid_t pid) { +bool OMX::livesLocally(node_id node, pid_t pid) { return pid == getpid(); } diff --git a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp index 0914f32..c79e01f 100644 --- a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp +++ b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp @@ -333,8 +333,9 @@ OMX_ERRORTYPE SimpleSoftOMXComponent::getState(OMX_STATETYPE *state) { void SimpleSoftOMXComponent::onMessageReceived(const sp<AMessage> &msg) { Mutex::Autolock autoLock(mLock); - - switch (msg->what()) { + uint32_t msgType = msg->what(); + ALOGV("msgType = %d", msgType); + switch (msgType) { case kWhatSendCommand: { int32_t cmd, param; @@ -354,27 +355,27 @@ void SimpleSoftOMXComponent::onMessageReceived(const sp<AMessage> &msg) { CHECK(mState == OMX_StateExecuting && mTargetState == mState); bool found = false; - for (size_t i = 0; i < mPorts.size(); ++i) { - PortInfo *port = &mPorts.editItemAt(i); + size_t portIndex = (kWhatEmptyThisBuffer == msgType)? + header->nInputPortIndex: header->nOutputPortIndex; + PortInfo *port = &mPorts.editItemAt(portIndex); - for (size_t j = 0; j < port->mBuffers.size(); ++j) { - BufferInfo *buffer = &port->mBuffers.editItemAt(j); + for (size_t j = 0; j < port->mBuffers.size(); ++j) { + BufferInfo *buffer = &port->mBuffers.editItemAt(j); - if (buffer->mHeader == header) { - CHECK(!buffer->mOwnedByUs); + if (buffer->mHeader == header) { + CHECK(!buffer->mOwnedByUs); - buffer->mOwnedByUs = true; + buffer->mOwnedByUs = true; - CHECK((msg->what() == kWhatEmptyThisBuffer - && port->mDef.eDir == OMX_DirInput) - || (port->mDef.eDir == OMX_DirOutput)); + CHECK((msgType == kWhatEmptyThisBuffer + && port->mDef.eDir == OMX_DirInput) + || (port->mDef.eDir == OMX_DirOutput)); - port->mQueue.push_back(buffer); - onQueueFilled(i); + port->mQueue.push_back(buffer); + onQueueFilled(portIndex); - found = true; - break; - } + found = true; + break; } } diff --git a/media/libstagefright/omx/SoftOMXPlugin.cpp b/media/libstagefright/omx/SoftOMXPlugin.cpp index da3ae42..99ffe7d 100644 --- a/media/libstagefright/omx/SoftOMXPlugin.cpp +++ b/media/libstagefright/omx/SoftOMXPlugin.cpp @@ -35,8 +35,11 @@ static const struct { } kComponents[] = { { "OMX.google.aac.decoder", "aacdec", "audio_decoder.aac" }, + { "OMX.google.aac.encoder", "aacenc", "audio_encoder.aac" }, { "OMX.google.amrnb.decoder", "amrdec", "audio_decoder.amrnb" }, + { "OMX.google.amrnb.encoder", "amrnbenc", "audio_encoder.amrnb" }, { "OMX.google.amrwb.decoder", "amrdec", "audio_decoder.amrwb" }, + { "OMX.google.amrwb.encoder", "amrwbenc", "audio_encoder.amrwb" }, { "OMX.google.h264.decoder", "h264dec", "video_decoder.avc" }, { "OMX.google.g711.alaw.decoder", "g711dec", "audio_decoder.g711alaw" }, { "OMX.google.g711.mlaw.decoder", "g711dec", "audio_decoder.g711mlaw" }, diff --git a/media/libstagefright/omx/tests/Android.mk b/media/libstagefright/omx/tests/Android.mk index bf69428..41c08be 100644 --- a/media/libstagefright/omx/tests/Android.mk +++ b/media/libstagefright/omx/tests/Android.mk @@ -7,11 +7,13 @@ LOCAL_SRC_FILES = \ LOCAL_SHARED_LIBRARIES := \ libstagefright libbinder libmedia libutils -LOCAL_C_INCLUDES:= \ +LOCAL_C_INCLUDES := \ $(JNI_H_INCLUDE) \ frameworks/base/media/libstagefright \ $(TOP)/frameworks/base/include/media/stagefright/openmax -LOCAL_MODULE:= omx_tests +LOCAL_MODULE := omx_tests + +LOCAL_MODULE_TAGS := tests include $(BUILD_EXECUTABLE) diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h index 2391c5c..9a7dd70 100644 --- a/media/libstagefright/rtsp/MyHandler.h +++ b/media/libstagefright/rtsp/MyHandler.h @@ -122,6 +122,7 @@ struct MyHandler : public AHandler { mSetupTracksSuccessful(false), mSeekPending(false), mFirstAccessUnit(true), + mAllTracksHaveTime(false), mNTPAnchorUs(-1), mMediaAnchorUs(-1), mLastMediaTimeUs(0), @@ -723,6 +724,7 @@ struct MyHandler : public AHandler { mSetupTracksSuccessful = false; mSeekPending = false; mFirstAccessUnit = true; + mAllTracksHaveTime = false; mNTPAnchorUs = -1; mMediaAnchorUs = -1; mNumAccessUnitsReceived = 0; @@ -930,6 +932,7 @@ struct MyHandler : public AHandler { info->mNTPAnchorUs = -1; } + mAllTracksHaveTime = false; mNTPAnchorUs = -1; int64_t timeUs; @@ -1037,6 +1040,14 @@ struct MyHandler : public AHandler { ALOGW("Never received any data, disconnecting."); (new AMessage('abor', id()))->post(); } + } else { + if (!mAllTracksHaveTime) { + ALOGW("We received some RTCP packets, but time " + "could not be established on all tracks, now " + "using fake timestamps"); + + fakeTimestamps(); + } } break; } @@ -1211,6 +1222,7 @@ private: bool mSeekPending; bool mFirstAccessUnit; + bool mAllTracksHaveTime; int64_t mNTPAnchorUs; int64_t mMediaAnchorUs; int64_t mLastMediaTimeUs; @@ -1357,6 +1369,7 @@ private: } void fakeTimestamps() { + mNTPAnchorUs = -1ll; for (size_t i = 0; i < mTracks.size(); ++i) { onTimeUpdate(i, 0, 0ll); } @@ -1377,6 +1390,21 @@ private: mNTPAnchorUs = ntpTimeUs; mMediaAnchorUs = mLastMediaTimeUs; } + + if (!mAllTracksHaveTime) { + bool allTracksHaveTime = true; + for (size_t i = 0; i < mTracks.size(); ++i) { + TrackInfo *track = &mTracks.editItemAt(i); + if (track->mNTPAnchorUs < 0) { + allTracksHaveTime = false; + break; + } + } + if (allTracksHaveTime) { + mAllTracksHaveTime = true; + ALOGI("Time now established for all tracks."); + } + } } void onAccessUnitComplete( @@ -1403,7 +1431,7 @@ private: TrackInfo *track = &mTracks.editItemAt(trackIndex); - if (mNTPAnchorUs < 0 || mMediaAnchorUs < 0 || track->mNTPAnchorUs < 0) { + if (!mAllTracksHaveTime) { ALOGV("storing accessUnit, no time established yet"); track->mPackets.push_back(accessUnit); return; diff --git a/media/libstagefright/timedtext/Android.mk b/media/libstagefright/timedtext/Android.mk index 59d0e15..8b23dee 100644 --- a/media/libstagefright/timedtext/Android.mk +++ b/media/libstagefright/timedtext/Android.mk @@ -3,7 +3,10 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ TextDescriptions.cpp \ - TimedTextParser.cpp \ + TimedTextDriver.cpp \ + TimedTextInBandSource.cpp \ + TimedTextSource.cpp \ + TimedTextSRTSource.cpp \ TimedTextPlayer.cpp LOCAL_CFLAGS += -Wno-multichar diff --git a/media/libstagefright/timedtext/TimedTextDriver.cpp b/media/libstagefright/timedtext/TimedTextDriver.cpp new file mode 100644 index 0000000..9ec9415 --- /dev/null +++ b/media/libstagefright/timedtext/TimedTextDriver.cpp @@ -0,0 +1,223 @@ + /* + * Copyright (C) 2012 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. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "TimedTextDriver" +#include <utils/Log.h> + +#include <binder/IPCThreadState.h> + +#include <media/MediaPlayerInterface.h> +#include <media/stagefright/MediaErrors.h> +#include <media/stagefright/MediaSource.h> +#include <media/stagefright/DataSource.h> +#include <media/stagefright/Utils.h> +#include <media/stagefright/foundation/ADebug.h> +#include <media/stagefright/foundation/ALooper.h> + +#include "TimedTextDriver.h" + +#include "TextDescriptions.h" +#include "TimedTextPlayer.h" +#include "TimedTextSource.h" + +namespace android { + +TimedTextDriver::TimedTextDriver( + const wp<MediaPlayerBase> &listener) + : mLooper(new ALooper), + mListener(listener), + mState(UNINITIALIZED) { + mLooper->setName("TimedTextDriver"); + mLooper->start(); + mPlayer = new TimedTextPlayer(listener); + mLooper->registerHandler(mPlayer); +} + +TimedTextDriver::~TimedTextDriver() { + mTextInBandVector.clear(); + mTextOutOfBandVector.clear(); + mLooper->stop(); +} + +status_t TimedTextDriver::setTimedTextTrackIndex_l(int32_t index) { + if (index >= + (int)(mTextInBandVector.size() + mTextOutOfBandVector.size())) { + return BAD_VALUE; + } + + sp<TimedTextSource> source; + if (index < mTextInBandVector.size()) { + source = mTextInBandVector.itemAt(index); + } else { + source = mTextOutOfBandVector.itemAt(index - mTextInBandVector.size()); + } + mPlayer->setDataSource(source); + return OK; +} + +status_t TimedTextDriver::start() { + Mutex::Autolock autoLock(mLock); + switch (mState) { + case UNINITIALIZED: + return INVALID_OPERATION; + case STOPPED: + mPlayer->start(); + break; + case PLAYING: + return OK; + case PAUSED: + mPlayer->resume(); + break; + default: + TRESPASS(); + } + mState = PLAYING; + return OK; +} + +status_t TimedTextDriver::stop() { + return pause(); +} + +// TODO: Test if pause() works properly. +// Scenario 1: start - pause - resume +// Scenario 2: start - seek +// Scenario 3: start - pause - seek - resume +status_t TimedTextDriver::pause() { + Mutex::Autolock autoLock(mLock); + switch (mState) { + case UNINITIALIZED: + return INVALID_OPERATION; + case STOPPED: + return OK; + case PLAYING: + mPlayer->pause(); + break; + case PAUSED: + return OK; + default: + TRESPASS(); + } + mState = PAUSED; + return OK; +} + +status_t TimedTextDriver::resume() { + return start(); +} + +status_t TimedTextDriver::seekToAsync(int64_t timeUs) { + mPlayer->seekToAsync(timeUs); + return OK; +} + +status_t TimedTextDriver::setTimedTextTrackIndex(int32_t index) { + // TODO: This is current implementation for MediaPlayer::disableTimedText(). + // Find better way for readability. + if (index < 0) { + mPlayer->pause(); + return OK; + } + + status_t ret = OK; + Mutex::Autolock autoLock(mLock); + switch (mState) { + case UNINITIALIZED: + ret = INVALID_OPERATION; + break; + case PAUSED: + ret = setTimedTextTrackIndex_l(index); + break; + case PLAYING: + mPlayer->pause(); + ret = setTimedTextTrackIndex_l(index); + if (ret != OK) { + break; + } + mPlayer->start(); + break; + case STOPPED: + // TODO: The only difference between STOPPED and PAUSED is this + // part. Revise the flow from "MediaPlayer::enableTimedText()" and + // remove one of the status, PAUSED and STOPPED, if possible. + ret = setTimedTextTrackIndex_l(index); + if (ret != OK) { + break; + } + mPlayer->start(); + break; + defaut: + TRESPASS(); + } + return ret; +} + +status_t TimedTextDriver::addInBandTextSource( + const sp<MediaSource>& mediaSource) { + sp<TimedTextSource> source = + TimedTextSource::CreateTimedTextSource(mediaSource); + if (source == NULL) { + return ERROR_UNSUPPORTED; + } + Mutex::Autolock autoLock(mLock); + mTextInBandVector.add(source); + if (mState == UNINITIALIZED) { + mState = STOPPED; + } + return OK; +} + +status_t TimedTextDriver::addOutOfBandTextSource( + const Parcel &request) { + // TODO: Define "TimedTextSource::CreateFromURI(uri)" + // and move below lines there..? + + // String values written in Parcel are UTF-16 values. + const String16 uri16 = request.readString16(); + String8 uri = String8(request.readString16()); + + uri.toLower(); + // To support local subtitle file only for now + if (strncasecmp("file://", uri.string(), 7)) { + return ERROR_UNSUPPORTED; + } + sp<DataSource> dataSource = + DataSource::CreateFromURI(uri); + if (dataSource == NULL) { + return ERROR_UNSUPPORTED; + } + + sp<TimedTextSource> source; + if (uri.getPathExtension() == String8(".srt")) { + source = TimedTextSource::CreateTimedTextSource( + dataSource, TimedTextSource::OUT_OF_BAND_FILE_SRT); + } + + if (source == NULL) { + return ERROR_UNSUPPORTED; + } + + Mutex::Autolock autoLock(mLock); + + mTextOutOfBandVector.add(source); + if (mState == UNINITIALIZED) { + mState = STOPPED; + } + return OK; +} + +} // namespace android diff --git a/media/libstagefright/timedtext/TimedTextDriver.h b/media/libstagefright/timedtext/TimedTextDriver.h new file mode 100644 index 0000000..efedb6e --- /dev/null +++ b/media/libstagefright/timedtext/TimedTextDriver.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2012 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. + */ + +#ifndef TIMED_TEXT_DRIVER_H_ +#define TIMED_TEXT_DRIVER_H_ + +#include <media/stagefright/foundation/ABase.h> // for DISALLOW_* macro +#include <utils/Errors.h> // for status_t +#include <utils/RefBase.h> +#include <utils/threads.h> + +namespace android { + +class ALooper; +class MediaPlayerBase; +class MediaSource; +class Parcel; +class TimedTextPlayer; +class TimedTextSource; + +class TimedTextDriver { +public: + TimedTextDriver(const wp<MediaPlayerBase> &listener); + + ~TimedTextDriver(); + + // TODO: pause-resume pair seems equivalent to stop-start pair. + // Check if it is replaceable with stop-start. + status_t start(); + status_t stop(); + status_t pause(); + status_t resume(); + + status_t seekToAsync(int64_t timeUs); + + status_t addInBandTextSource(const sp<MediaSource>& source); + status_t addOutOfBandTextSource(const Parcel &request); + + status_t setTimedTextTrackIndex(int32_t index); + +private: + Mutex mLock; + + enum State { + UNINITIALIZED, + STOPPED, + PLAYING, + PAUSED, + }; + + sp<ALooper> mLooper; + sp<TimedTextPlayer> mPlayer; + wp<MediaPlayerBase> mListener; + + // Variables to be guarded by mLock. + State mState; + Vector<sp<TimedTextSource> > mTextInBandVector; + Vector<sp<TimedTextSource> > mTextOutOfBandVector; + // -- End of variables to be guarded by mLock + + status_t setTimedTextTrackIndex_l(int32_t index); + + DISALLOW_EVIL_CONSTRUCTORS(TimedTextDriver); +}; + +} // namespace android + +#endif // TIMED_TEXT_DRIVER_H_ diff --git a/media/libstagefright/timedtext/TimedTextInBandSource.cpp b/media/libstagefright/timedtext/TimedTextInBandSource.cpp new file mode 100644 index 0000000..f2c4d54 --- /dev/null +++ b/media/libstagefright/timedtext/TimedTextInBandSource.cpp @@ -0,0 +1,118 @@ + /* + * Copyright (C) 2012 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. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "TimedTextInBandSource" +#include <utils/Log.h> + +#include <binder/Parcel.h> +#include <media/stagefright/MediaBuffer.h> +#include <media/stagefright/MediaDebug.h> // CHECK_XX macro +#include <media/stagefright/MediaDefs.h> // for MEDIA_MIMETYPE_xxx +#include <media/stagefright/MediaErrors.h> +#include <media/stagefright/MediaSource.h> +#include <media/stagefright/MetaData.h> + +#include "TimedTextInBandSource.h" +#include "TextDescriptions.h" + +namespace android { + +TimedTextInBandSource::TimedTextInBandSource(const sp<MediaSource>& mediaSource) + : mSource(mediaSource) { +} + +TimedTextInBandSource::~TimedTextInBandSource() { +} + +status_t TimedTextInBandSource::read( + int64_t *timeUs, Parcel *parcel, const MediaSource::ReadOptions *options) { + MediaBuffer *textBuffer = NULL; + status_t err = mSource->read(&textBuffer, options); + if (err != OK) { + return err; + } + CHECK(textBuffer != NULL); + textBuffer->meta_data()->findInt64(kKeyTime, timeUs); + // TODO: this is legacy code. when 'timeUs' can be <= 0? + if (*timeUs > 0) { + extractAndAppendLocalDescriptions(*timeUs, textBuffer, parcel); + } + textBuffer->release(); + return OK; +} + +// Each text sample consists of a string of text, optionally with sample +// modifier description. The modifier description could specify a new +// text style for the string of text. These descriptions are present only +// if they are needed. This method is used to extract the modifier +// description and append it at the end of the text. +status_t TimedTextInBandSource::extractAndAppendLocalDescriptions( + int64_t timeUs, const MediaBuffer *textBuffer, Parcel *parcel) { + const void *data; + size_t size = 0; + int32_t flag = TextDescriptions::LOCAL_DESCRIPTIONS; + + const char *mime; + CHECK(mSource->getFormat()->findCString(kKeyMIMEType, &mime)); + + if (strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP) == 0) { + data = textBuffer->data(); + size = textBuffer->size(); + + if (size > 0) { + parcel->freeData(); + flag |= TextDescriptions::IN_BAND_TEXT_3GPP; + return TextDescriptions::getParcelOfDescriptions( + (const uint8_t *)data, size, flag, timeUs / 1000, parcel); + } + return OK; + } + return ERROR_UNSUPPORTED; +} + +// To extract and send the global text descriptions for all the text samples +// in the text track or text file. +// TODO: send error message to application via notifyListener()...? +status_t TimedTextInBandSource::extractGlobalDescriptions(Parcel *parcel) { + const void *data; + size_t size = 0; + int32_t flag = TextDescriptions::GLOBAL_DESCRIPTIONS; + + const char *mime; + CHECK(mSource->getFormat()->findCString(kKeyMIMEType, &mime)); + + // support 3GPP only for now + if (strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP) == 0) { + uint32_t type; + // get the 'tx3g' box content. This box contains the text descriptions + // used to render the text track + if (!mSource->getFormat()->findData( + kKeyTextFormatData, &type, &data, &size)) { + return ERROR_MALFORMED; + } + + if (size > 0) { + flag |= TextDescriptions::IN_BAND_TEXT_3GPP; + return TextDescriptions::getParcelOfDescriptions( + (const uint8_t *)data, size, flag, 0, parcel); + } + return OK; + } + return ERROR_UNSUPPORTED; +} + +} // namespace android diff --git a/media/libstagefright/timedtext/TimedTextInBandSource.h b/media/libstagefright/timedtext/TimedTextInBandSource.h new file mode 100644 index 0000000..26e5737 --- /dev/null +++ b/media/libstagefright/timedtext/TimedTextInBandSource.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2012 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. + */ + +#ifndef TIMED_TEXT_IN_BAND_SOURCE_H_ +#define TIMED_TEXT_IN_BAND_SOURCE_H_ + +#include <media/stagefright/MediaErrors.h> +#include <media/stagefright/MediaSource.h> + +#include "TimedTextSource.h" + +namespace android { + +class MediaBuffer; +class Parcel; + +class TimedTextInBandSource : public TimedTextSource { + public: + TimedTextInBandSource(const sp<MediaSource>& mediaSource); + virtual status_t start() { return mSource->start(); } + virtual status_t stop() { return mSource->stop(); } + virtual status_t read( + int64_t *timeUs, + Parcel *parcel, + const MediaSource::ReadOptions *options = NULL); + virtual status_t extractGlobalDescriptions(Parcel *parcel); + + protected: + virtual ~TimedTextInBandSource(); + + private: + sp<MediaSource> mSource; + + status_t extractAndAppendLocalDescriptions( + int64_t timeUs, const MediaBuffer *textBuffer, Parcel *parcel); + + DISALLOW_EVIL_CONSTRUCTORS(TimedTextInBandSource); +}; + +} // namespace android + +#endif // TIMED_TEXT_IN_BAND_SOURCE_H_ diff --git a/media/libstagefright/timedtext/TimedTextParser.h b/media/libstagefright/timedtext/TimedTextParser.h deleted file mode 100644 index 44774c2..0000000 --- a/media/libstagefright/timedtext/TimedTextParser.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2011 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. - */ - -#ifndef TIMED_TEXT_PARSER_H_ - -#define TIMED_TEXT_PARSER_H_ - -#include <media/MediaPlayerInterface.h> -#include <media/stagefright/foundation/ABase.h> -#include <media/stagefright/foundation/AString.h> -#include <media/stagefright/MediaSource.h> - -namespace android { - -class DataSource; - -class TimedTextParser : public RefBase { -public: - TimedTextParser(); - virtual ~TimedTextParser(); - - enum FileType { - OUT_OF_BAND_FILE_SRT = 1, - }; - - status_t getText(AString *text, int64_t *startTimeUs, int64_t *endTimeUs, - const MediaSource::ReadOptions *options = NULL); - status_t init(const sp<DataSource> &dataSource, FileType fileType); - void reset(); - -private: - Mutex mLock; - - sp<DataSource> mDataSource; - off64_t mOffset; - - struct TextInfo { - int64_t endTimeUs; - // the offset of the text in the original file - off64_t offset; - int textLen; - }; - - int mIndex; - FileType mFileType; - - // the key indicated the start time of the text - KeyedVector<int64_t, TextInfo> mTextVector; - - status_t getNextInSrtFileFormat( - off64_t *offset, int64_t *startTimeUs, TextInfo *info); - status_t readNextLine(off64_t *offset, AString *data); - - status_t scanFile(); - - DISALLOW_EVIL_CONSTRUCTORS(TimedTextParser); -}; - -} // namespace android - -#endif // TIMED_TEXT_PARSER_H_ - diff --git a/media/libstagefright/timedtext/TimedTextPlayer.cpp b/media/libstagefright/timedtext/TimedTextPlayer.cpp index 3014b0b..8c2df88 100644 --- a/media/libstagefright/timedtext/TimedTextPlayer.cpp +++ b/media/libstagefright/timedtext/TimedTextPlayer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 The Android Open Source Project + * Copyright (C) 2012 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. @@ -18,399 +18,164 @@ #define LOG_TAG "TimedTextPlayer" #include <utils/Log.h> -#include <binder/IPCThreadState.h> - +#include <media/stagefright/foundation/AMessage.h> #include <media/stagefright/MediaDebug.h> -#include <media/stagefright/MediaDefs.h> #include <media/stagefright/MediaErrors.h> -#include <media/stagefright/MediaSource.h> -#include <media/stagefright/MetaData.h> -#include <media/stagefright/MediaBuffer.h> -#include <media/stagefright/FileSource.h> -#include <media/stagefright/Utils.h> +#include <media/MediaPlayerInterface.h> -#include "include/AwesomePlayer.h" #include "TimedTextPlayer.h" -#include "TimedTextParser.h" -#include "TextDescriptions.h" - -namespace android { -struct TimedTextEvent : public TimedEventQueue::Event { - TimedTextEvent( - TimedTextPlayer *player, - void (TimedTextPlayer::*method)()) - : mPlayer(player), - mMethod(method) { - } - -protected: - virtual ~TimedTextEvent() {} - - virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) { - (mPlayer->*mMethod)(); - } +#include "TimedTextDriver.h" +#include "TimedTextSource.h" -private: - TimedTextPlayer *mPlayer; - void (TimedTextPlayer::*mMethod)(); +namespace android { - TimedTextEvent(const TimedTextEvent &); - TimedTextEvent &operator=(const TimedTextEvent &); -}; +static const int64_t kAdjustmentProcessingTimeUs = 100000ll; -TimedTextPlayer::TimedTextPlayer( - AwesomePlayer *observer, - const wp<MediaPlayerBase> &listener, - TimedEventQueue *queue) - : mSource(NULL), - mOutOfBandSource(NULL), - mSeekTimeUs(0), - mStarted(false), - mTextEventPending(false), - mQueue(queue), - mListener(listener), - mObserver(observer), - mTextBuffer(NULL), - mTextParser(NULL), - mTextType(kNoText) { - mTextEvent = new TimedTextEvent(this, &TimedTextPlayer::onTextEvent); +TimedTextPlayer::TimedTextPlayer(const wp<MediaPlayerBase> &listener) + : mListener(listener), + mSource(NULL), + mSendSubtitleGeneration(0) { } TimedTextPlayer::~TimedTextPlayer() { - if (mStarted) { - reset(); + if (mSource != NULL) { + mSource->stop(); + mSource.clear(); + mSource = NULL; } - - mTextTrackVector.clear(); - mTextOutOfBandVector.clear(); } -status_t TimedTextPlayer::start(uint8_t index) { - CHECK(!mStarted); - - if (index >= - mTextTrackVector.size() + mTextOutOfBandVector.size()) { - ALOGE("Incorrect text track index: %d", index); - return BAD_VALUE; - } - - status_t err; - if (index < mTextTrackVector.size()) { // start an in-band text - mSource = mTextTrackVector.itemAt(index); - - err = mSource->start(); - - if (err != OK) { - return err; - } - mTextType = kInBandText; - } else { // start an out-of-band text - OutOfBandText text = - mTextOutOfBandVector.itemAt(index - mTextTrackVector.size()); - - mOutOfBandSource = text.source; - TimedTextParser::FileType fileType = text.type; - - if (mTextParser == NULL) { - mTextParser = new TimedTextParser(); - } - - if ((err = mTextParser->init(mOutOfBandSource, fileType)) != OK) { - return err; - } - mTextType = kOutOfBandText; - } - - // send sample description format - if ((err = extractAndSendGlobalDescriptions()) != OK) { - return err; - } - - int64_t positionUs; - mObserver->getPosition(&positionUs); - seekTo(positionUs); - - postTextEvent(); - - mStarted = true; - - return OK; +void TimedTextPlayer::start() { + sp<AMessage> msg = new AMessage(kWhatSeek, id()); + msg->setInt64("seekTimeUs", -1); + msg->post(); } void TimedTextPlayer::pause() { - CHECK(mStarted); - - cancelTextEvent(); + (new AMessage(kWhatPause, id()))->post(); } void TimedTextPlayer::resume() { - CHECK(mStarted); - - postTextEvent(); -} - -void TimedTextPlayer::reset() { - CHECK(mStarted); - - // send an empty text to clear the screen - notifyListener(MEDIA_TIMED_TEXT); - - cancelTextEvent(); - - mSeeking = false; - mStarted = false; - - if (mTextType == kInBandText) { - if (mTextBuffer != NULL) { - mTextBuffer->release(); - mTextBuffer = NULL; - } - - if (mSource != NULL) { - mSource->stop(); - mSource.clear(); - mSource = NULL; - } - } else { - if (mTextParser != NULL) { - mTextParser.clear(); - mTextParser = NULL; - } - if (mOutOfBandSource != NULL) { - mOutOfBandSource.clear(); - mOutOfBandSource = NULL; - } - } + start(); } -status_t TimedTextPlayer::seekTo(int64_t time_us) { - Mutex::Autolock autoLock(mLock); - - mSeeking = true; - mSeekTimeUs = time_us; - - postTextEvent(); - - return OK; +void TimedTextPlayer::seekToAsync(int64_t timeUs) { + sp<AMessage> msg = new AMessage(kWhatSeek, id()); + msg->setInt64("seekTimeUs", timeUs); + msg->post(); } -status_t TimedTextPlayer::setTimedTextTrackIndex(int32_t index) { - if (index >= - (int)(mTextTrackVector.size() + mTextOutOfBandVector.size())) { - return BAD_VALUE; - } - - if (mStarted) { - reset(); - } - - if (index >= 0) { - return start(index); - } - return OK; +void TimedTextPlayer::setDataSource(sp<TimedTextSource> source) { + sp<AMessage> msg = new AMessage(kWhatSetSource, id()); + msg->setObject("source", source); + msg->post(); } -void TimedTextPlayer::onTextEvent() { - Mutex::Autolock autoLock(mLock); - - if (!mTextEventPending) { - return; - } - mTextEventPending = false; - - if (mData.dataSize() > 0) { - notifyListener(MEDIA_TIMED_TEXT, &mData); - mData.freeData(); - } - - MediaSource::ReadOptions options; - if (mSeeking) { - options.setSeekTo(mSeekTimeUs, - MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC); - mSeeking = false; - - notifyListener(MEDIA_TIMED_TEXT); //empty text to clear the screen - } - - int64_t positionUs, timeUs; - mObserver->getPosition(&positionUs); - - if (mTextType == kInBandText) { - if (mSource->read(&mTextBuffer, &options) != OK) { - return; +void TimedTextPlayer::onMessageReceived(const sp<AMessage> &msg) { + switch (msg->what()) { + case kWhatPause: { + mSendSubtitleGeneration++; + break; } - - mTextBuffer->meta_data()->findInt64(kKeyTime, &timeUs); - } else { - int64_t endTimeUs; - if (mTextParser->getText( - &mText, &timeUs, &endTimeUs, &options) != OK) { - return; - } - } - - if (timeUs > 0) { - extractAndAppendLocalDescriptions(timeUs); - } - - if (mTextType == kInBandText) { - if (mTextBuffer != NULL) { - mTextBuffer->release(); - mTextBuffer = NULL; + case kWhatSeek: { + int64_t seekTimeUs = 0; + msg->findInt64("seekTimeUs", &seekTimeUs); + if (seekTimeUs < 0) { + sp<MediaPlayerBase> listener = mListener.promote(); + if (listener != NULL) { + int32_t positionMs = 0; + listener->getCurrentPosition(&positionMs); + seekTimeUs = positionMs * 1000ll; + } + } + doSeekAndRead(seekTimeUs); + break; + } + case kWhatSendSubtitle: { + int32_t generation; + CHECK(msg->findInt32("generation", &generation)); + if (generation != mSendSubtitleGeneration) { + // Drop obsolete msg. + break; + } + sp<RefBase> obj; + msg->findObject("subtitle", &obj); + if (obj != NULL) { + sp<ParcelEvent> parcelEvent; + parcelEvent = static_cast<ParcelEvent*>(obj.get()); + notifyListener(MEDIA_TIMED_TEXT, &(parcelEvent->parcel)); + } else { + notifyListener(MEDIA_TIMED_TEXT); + } + doRead(); + break; + } + case kWhatSetSource: { + sp<RefBase> obj; + msg->findObject("source", &obj); + if (obj == NULL) break; + if (mSource != NULL) { + mSource->stop(); + } + mSource = static_cast<TimedTextSource*>(obj.get()); + mSource->start(); + Parcel parcel; + if (mSource->extractGlobalDescriptions(&parcel) == OK && + parcel.dataSize() > 0) { + notifyListener(MEDIA_TIMED_TEXT, &parcel); + } else { + notifyListener(MEDIA_TIMED_TEXT); + } + break; } - } else { - mText.clear(); - } - - //send the text now - if (timeUs <= positionUs + 100000ll) { - postTextEvent(); - } else { - postTextEvent(timeUs - positionUs - 100000ll); } } -void TimedTextPlayer::postTextEvent(int64_t delayUs) { - if (mTextEventPending) { - return; - } - - mTextEventPending = true; - mQueue->postEventWithDelay(mTextEvent, delayUs < 0 ? 10000 : delayUs); -} - -void TimedTextPlayer::cancelTextEvent() { - mQueue->cancelEvent(mTextEvent->eventID()); - mTextEventPending = false; +void TimedTextPlayer::doSeekAndRead(int64_t seekTimeUs) { + MediaSource::ReadOptions options; + options.setSeekTo(seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC); + doRead(&options); } -void TimedTextPlayer::addTextSource(sp<MediaSource> source) { - Mutex::Autolock autoLock(mLock); - mTextTrackVector.add(source); +void TimedTextPlayer::doRead(MediaSource::ReadOptions* options) { + int64_t timeUs = 0; + sp<ParcelEvent> parcelEvent = new ParcelEvent(); + mSource->read(&timeUs, &(parcelEvent->parcel), options); + postTextEvent(parcelEvent, timeUs); } -status_t TimedTextPlayer::setParameter(int key, const Parcel &request) { - Mutex::Autolock autoLock(mLock); - - if (key == KEY_PARAMETER_TIMED_TEXT_ADD_OUT_OF_BAND_SOURCE) { - const String16 uri16 = request.readString16(); - String8 uri = String8(uri16); - KeyedVector<String8, String8> headers; - - // To support local subtitle file only for now - if (strncasecmp("file://", uri.string(), 7)) { - return INVALID_OPERATION; - } - sp<DataSource> dataSource = - DataSource::CreateFromURI(uri, &headers); - status_t err = dataSource->initCheck(); +void TimedTextPlayer::postTextEvent(const sp<ParcelEvent>& parcel, int64_t timeUs) { + sp<MediaPlayerBase> listener = mListener.promote(); + if (listener != NULL) { + int64_t positionUs, delayUs; + int32_t positionMs = 0; + listener->getCurrentPosition(&positionMs); + positionUs = positionMs * 1000; - if (err != OK) { - return err; - } - - OutOfBandText text; - text.source = dataSource; - if (uri.getPathExtension() == String8(".srt")) { - text.type = TimedTextParser::OUT_OF_BAND_FILE_SRT; + if (timeUs <= positionUs + kAdjustmentProcessingTimeUs) { + delayUs = 0; } else { - return ERROR_UNSUPPORTED; + delayUs = timeUs - positionUs - kAdjustmentProcessingTimeUs; } - - mTextOutOfBandVector.add(text); - - return OK; - } - return INVALID_OPERATION; -} - -void TimedTextPlayer::notifyListener(int msg, const Parcel *parcel) { - if (mListener != NULL) { - sp<MediaPlayerBase> listener = mListener.promote(); - - if (listener != NULL) { - if (parcel && (parcel->dataSize() > 0)) { - listener->sendEvent(msg, 0, 0, parcel); - } else { // send an empty timed text to clear the screen - listener->sendEvent(msg); - } + sp<AMessage> msg = new AMessage(kWhatSendSubtitle, id()); + msg->setInt32("generation", mSendSubtitleGeneration); + if (parcel != NULL) { + msg->setObject("subtitle", parcel); } + msg->post(delayUs); } } -// Each text sample consists of a string of text, optionally with sample -// modifier description. The modifier description could specify a new -// text style for the string of text. These descriptions are present only -// if they are needed. This method is used to extract the modifier -// description and append it at the end of the text. -status_t TimedTextPlayer::extractAndAppendLocalDescriptions(int64_t timeUs) { - const void *data; - size_t size = 0; - int32_t flag = TextDescriptions::LOCAL_DESCRIPTIONS; - - if (mTextType == kInBandText) { - const char *mime; - CHECK(mSource->getFormat()->findCString(kKeyMIMEType, &mime)); - - if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) { - flag |= TextDescriptions::IN_BAND_TEXT_3GPP; - data = mTextBuffer->data(); - size = mTextBuffer->size(); - } else { - // support 3GPP only for now - return ERROR_UNSUPPORTED; +void TimedTextPlayer::notifyListener(int msg, const Parcel *parcel) { + sp<MediaPlayerBase> listener = mListener.promote(); + if (listener != NULL) { + if (parcel != NULL && (parcel->dataSize() > 0)) { + listener->sendEvent(msg, 0, 0, parcel); + } else { // send an empty timed text to clear the screen + listener->sendEvent(msg); } - } else { - data = mText.c_str(); - size = mText.size(); - flag |= TextDescriptions::OUT_OF_BAND_TEXT_SRT; } - - if ((size > 0) && (flag != TextDescriptions::LOCAL_DESCRIPTIONS)) { - mData.freeData(); - return TextDescriptions::getParcelOfDescriptions( - (const uint8_t *)data, size, flag, timeUs / 1000, &mData); - } - - return OK; } -// To extract and send the global text descriptions for all the text samples -// in the text track or text file. -status_t TimedTextPlayer::extractAndSendGlobalDescriptions() { - const void *data; - size_t size = 0; - int32_t flag = TextDescriptions::GLOBAL_DESCRIPTIONS; - - if (mTextType == kInBandText) { - const char *mime; - CHECK(mSource->getFormat()->findCString(kKeyMIMEType, &mime)); - - // support 3GPP only for now - if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) { - uint32_t type; - // get the 'tx3g' box content. This box contains the text descriptions - // used to render the text track - if (!mSource->getFormat()->findData( - kKeyTextFormatData, &type, &data, &size)) { - return ERROR_MALFORMED; - } - - flag |= TextDescriptions::IN_BAND_TEXT_3GPP; - } - } - - if ((size > 0) && (flag != TextDescriptions::GLOBAL_DESCRIPTIONS)) { - Parcel parcel; - if (TextDescriptions::getParcelOfDescriptions( - (const uint8_t *)data, size, flag, 0, &parcel) == OK) { - if (parcel.dataSize() > 0) { - notifyListener(MEDIA_TIMED_TEXT, &parcel); - } - } - } - - return OK; -} -} +} // namespace android diff --git a/media/libstagefright/timedtext/TimedTextPlayer.h b/media/libstagefright/timedtext/TimedTextPlayer.h index a744db5..837beeb 100644 --- a/media/libstagefright/timedtext/TimedTextPlayer.h +++ b/media/libstagefright/timedtext/TimedTextPlayer.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 The Android Open Source Project + * Copyright (C) 2012 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. @@ -15,99 +15,61 @@ */ #ifndef TIMEDTEXT_PLAYER_H_ - #define TIMEDTEXT_PLAYER_H_ -#include <media/MediaPlayerInterface.h> +#include <binder/Parcel.h> #include <media/stagefright/foundation/ABase.h> -#include <media/stagefright/foundation/AString.h> +#include <media/stagefright/foundation/AHandler.h> +#include <media/stagefright/MediaSource.h> +#include <utils/RefBase.h> -#include "include/TimedEventQueue.h" -#include "TimedTextParser.h" +#include "TimedTextSource.h" namespace android { -class MediaSource; -class AwesomePlayer; -class MediaBuffer; +class AMessage; +class MediaPlayerBase; +class TimedTextDriver; +class TimedTextSource; -class TimedTextPlayer { +class TimedTextPlayer : public AHandler { public: - TimedTextPlayer(AwesomePlayer *observer, - const wp<MediaPlayerBase> &listener, - TimedEventQueue *queue); + TimedTextPlayer(const wp<MediaPlayerBase> &listener); virtual ~TimedTextPlayer(); - // index: the index of the text track which will - // be turned on - status_t start(uint8_t index); - + void start(); void pause(); - void resume(); + void seekToAsync(int64_t timeUs); + void setDataSource(sp<TimedTextSource> source); - status_t seekTo(int64_t time_us); - - void addTextSource(sp<MediaSource> source); - - status_t setTimedTextTrackIndex(int32_t index); - status_t setParameter(int key, const Parcel &request); +protected: + virtual void onMessageReceived(const sp<AMessage> &msg); private: - enum TextType { - kNoText = 0, - kInBandText = 1, - kOutOfBandText = 2, + enum { + kWhatPause = 'paus', + kWhatSeek = 'seek', + kWhatSendSubtitle = 'send', + kWhatSetSource = 'ssrc', }; - Mutex mLock; - - sp<MediaSource> mSource; - sp<DataSource> mOutOfBandSource; - - bool mSeeking; - int64_t mSeekTimeUs; - - bool mStarted; - - sp<TimedEventQueue::Event> mTextEvent; - bool mTextEventPending; - - TimedEventQueue *mQueue; - - wp<MediaPlayerBase> mListener; - AwesomePlayer *mObserver; - - MediaBuffer *mTextBuffer; - Parcel mData; - - // for in-band timed text - Vector<sp<MediaSource> > mTextTrackVector; - - // for out-of-band timed text - struct OutOfBandText { - TimedTextParser::FileType type; - sp<DataSource> source; + // To add Parcel into an AMessage as an object, it should be 'RefBase'. + struct ParcelEvent : public RefBase { + Parcel parcel; }; - Vector<OutOfBandText > mTextOutOfBandVector; - sp<TimedTextParser> mTextParser; - AString mText; - - TextType mTextType; - - void reset(); + wp<MediaPlayerBase> mListener; + sp<TimedTextSource> mSource; + int32_t mSendSubtitleGeneration; + void doSeekAndRead(int64_t seekTimeUs); + void doRead(MediaSource::ReadOptions* options = NULL); void onTextEvent(); - void postTextEvent(int64_t delayUs = -1); - void cancelTextEvent(); - + void postTextEvent(const sp<ParcelEvent>& parcel = NULL, int64_t timeUs = -1); void notifyListener(int msg, const Parcel *parcel = NULL); - status_t extractAndAppendLocalDescriptions(int64_t timeUs); - status_t extractAndSendGlobalDescriptions(); - DISALLOW_EVIL_CONSTRUCTORS(TimedTextPlayer); }; diff --git a/media/libstagefright/timedtext/TimedTextParser.cpp b/media/libstagefright/timedtext/TimedTextSRTSource.cpp index 0bada16..3752d34 100644 --- a/media/libstagefright/timedtext/TimedTextParser.cpp +++ b/media/libstagefright/timedtext/TimedTextSRTSource.cpp @@ -1,5 +1,5 @@ -/* - * Copyright (C) 2011 The Android Open Source Project + /* + * Copyright (C) 2012 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. @@ -14,149 +14,126 @@ * limitations under the License. */ -#include "TimedTextParser.h" +//#define LOG_NDEBUG 0 +#define LOG_TAG "TimedTextSRTSource" +#include <utils/Log.h> + +#include <binder/Parcel.h> +#include <media/stagefright/foundation/AString.h> #include <media/stagefright/DataSource.h> +#include <media/stagefright/MediaErrors.h> +#include <media/stagefright/MediaSource.h> + +#include "TimedTextSRTSource.h" +#include "TextDescriptions.h" namespace android { -TimedTextParser::TimedTextParser() - : mDataSource(NULL), - mOffset(0), - mIndex(0) { +TimedTextSRTSource::TimedTextSRTSource(const sp<DataSource>& dataSource) + : mSource(dataSource), + mIndex(0) { } -TimedTextParser::~TimedTextParser() { - reset(); +TimedTextSRTSource::~TimedTextSRTSource() { } -status_t TimedTextParser::init( - const sp<DataSource> &dataSource, FileType fileType) { - mDataSource = dataSource; - mFileType = fileType; - - status_t err; - if ((err = scanFile()) != OK) { +status_t TimedTextSRTSource::start() { + status_t err = scanFile(); + if (err != OK) { reset(); - return err; } - - return OK; + return err; } -void TimedTextParser::reset() { - mDataSource.clear(); +void TimedTextSRTSource::reset() { mTextVector.clear(); - mOffset = 0; mIndex = 0; } -// scan the text file to get start/stop time and the -// offset of each piece of text content -status_t TimedTextParser::scanFile() { - if (mFileType != OUT_OF_BAND_FILE_SRT) { - return ERROR_UNSUPPORTED; +status_t TimedTextSRTSource::stop() { + reset(); + return OK; +} + +status_t TimedTextSRTSource::read( + int64_t *timeUs, + Parcel *parcel, + const MediaSource::ReadOptions *options) { + int64_t endTimeUs; + AString text; + status_t err = getText(options, &text, timeUs, &endTimeUs); + if (err != OK) { + return err; + } + + if (*timeUs > 0) { + extractAndAppendLocalDescriptions(*timeUs, text, parcel); } + return OK; +} +status_t TimedTextSRTSource::scanFile() { off64_t offset = 0; int64_t startTimeUs; bool endOfFile = false; while (!endOfFile) { TextInfo info; - status_t err = getNextInSrtFileFormat(&offset, &startTimeUs, &info); - - if (err != OK) { - if (err == ERROR_END_OF_STREAM) { + status_t err = getNextSubtitleInfo(&offset, &startTimeUs, &info); + switch (err) { + case OK: + mTextVector.add(startTimeUs, info); + break; + case ERROR_END_OF_STREAM: endOfFile = true; - } else { + break; + default: return err; - } - } else { - mTextVector.add(startTimeUs, info); } } - if (mTextVector.isEmpty()) { return ERROR_MALFORMED; } return OK; } -// read one line started from *offset and store it into data. -status_t TimedTextParser::readNextLine(off64_t *offset, AString *data) { - char character; - - data->clear(); - - while (true) { - ssize_t err; - if ((err = mDataSource->readAt(*offset, &character, 1)) < 1) { - if (err == 0) { - return ERROR_END_OF_STREAM; - } - return ERROR_IO; - } - - (*offset) ++; - - // a line could end with CR, LF or CR + LF - if (character == 10) { - break; - } else if (character == 13) { - if ((err = mDataSource->readAt(*offset, &character, 1)) < 1) { - if (err == 0) { // end of the stream - return OK; - } - return ERROR_IO; - } - - (*offset) ++; - - if (character != 10) { - (*offset) --; - } - break; - } - - data->append(character); - } - - return OK; -} - /* SRT format: - * Subtitle number - * Start time --> End time - * Text of subtitle (one or more lines) - * Blank line + * Subtitle number + * Start time --> End time + * Text of subtitle (one or more lines) + * Blank lines * * .srt file example: - * 1 - * 00:00:20,000 --> 00:00:24,400 - * Altocumulus clouds occur between six thousand + * 1 + * 00:00:20,000 --> 00:00:24,400 + * Altocumulus clouds occr between six thousand * - * 2 - * 00:00:24,600 --> 00:00:27,800 - * and twenty thousand feet above ground level. + * 2 + * 00:00:24,600 --> 00:00:27,800 + * and twenty thousand feet above ground level. */ -status_t TimedTextParser::getNextInSrtFileFormat( - off64_t *offset, int64_t *startTimeUs, TextInfo *info) { +status_t TimedTextSRTSource::getNextSubtitleInfo( + off64_t *offset, int64_t *startTimeUs, TextInfo *info) { AString data; status_t err; - if ((err = readNextLine(offset, &data)) != OK) { - return err; - } - // to skip the first line + // To skip blank lines. + do { + if ((err = readNextLine(offset, &data)) != OK) { + return err; + } + data.trim(); + } while (data.empty()); + + // Just ignore the first non-blank line which is subtitle sequence number. if ((err = readNextLine(offset, &data)) != OK) { return err; } - int hour1, hour2, min1, min2, sec1, sec2, msec1, msec2; // the start time format is: hours:minutes:seconds,milliseconds // 00:00:24,600 --> 00:00:27,800 if (sscanf(data.c_str(), "%02d:%02d:%02d,%03d --> %02d:%02d:%02d,%03d", - &hour1, &min1, &sec1, &msec1, &hour2, &min2, &sec2, &msec2) != 8) { + &hour1, &min1, &sec1, &msec1, &hour2, &min2, &sec2, &msec2) != 8) { return ERROR_MALFORMED; } @@ -167,7 +144,6 @@ status_t TimedTextParser::getNextInSrtFileFormat( } info->offset = *offset; - bool needMoreData = true; while (needMoreData) { if ((err = readNextLine(offset, &data)) != OK) { @@ -186,25 +162,56 @@ status_t TimedTextParser::getNextInSrtFileFormat( } } } - info->textLen = *offset - info->offset; - return OK; } -status_t TimedTextParser::getText( - AString *text, int64_t *startTimeUs, int64_t *endTimeUs, - const MediaSource::ReadOptions *options) { - Mutex::Autolock autoLock(mLock); +status_t TimedTextSRTSource::readNextLine(off64_t *offset, AString *data) { + data->clear(); + while (true) { + ssize_t readSize; + char character; + if ((readSize = mSource->readAt(*offset, &character, 1)) < 1) { + if (readSize == 0) { + return ERROR_END_OF_STREAM; + } + return ERROR_IO; + } - text->clear(); + (*offset)++; + + // a line could end with CR, LF or CR + LF + if (character == 10) { + break; + } else if (character == 13) { + if ((readSize = mSource->readAt(*offset, &character, 1)) < 1) { + if (readSize == 0) { // end of the stream + return OK; + } + return ERROR_IO; + } + (*offset)++; + if (character != 10) { + (*offset)--; + } + break; + } + data->append(character); + } + return OK; +} + +status_t TimedTextSRTSource::getText( + const MediaSource::ReadOptions *options, + AString *text, int64_t *startTimeUs, int64_t *endTimeUs) { + text->clear(); int64_t seekTimeUs; MediaSource::ReadOptions::SeekMode mode; - if (options && options->getSeekTo(&seekTimeUs, &mode)) { - int64_t lastEndTimeUs = mTextVector.valueAt(mTextVector.size() - 1).endTimeUs; + if (options != NULL && options->getSeekTo(&seekTimeUs, &mode)) { + int64_t lastEndTimeUs = + mTextVector.valueAt(mTextVector.size() - 1).endTimeUs; int64_t firstStartTimeUs = mTextVector.keyAt(0); - if (seekTimeUs < 0 || seekTimeUs > lastEndTimeUs) { return ERROR_OUT_OF_RANGE; } else if (seekTimeUs < firstStartTimeUs) { @@ -227,31 +234,42 @@ status_t TimedTextParser::getText( low = mid + 1; } else { if ((high == mid + 1) - && (seekTimeUs < mTextVector.keyAt(high))) { + && (seekTimeUs < mTextVector.keyAt(high))) { break; } high = mid - 1; } } - mIndex = mid; } } - - TextInfo info = mTextVector.valueAt(mIndex); + const TextInfo &info = mTextVector.valueAt(mIndex); *startTimeUs = mTextVector.keyAt(mIndex); *endTimeUs = info.endTimeUs; - mIndex ++; + mIndex++; char *str = new char[info.textLen]; - if (mDataSource->readAt(info.offset, str, info.textLen) < info.textLen) { + if (mSource->readAt(info.offset, str, info.textLen) < info.textLen) { delete[] str; return ERROR_IO; } - text->append(str, info.textLen); delete[] str; return OK; } +status_t TimedTextSRTSource::extractAndAppendLocalDescriptions( + int64_t timeUs, const AString &text, Parcel *parcel) { + const void *data = text.c_str(); + size_t size = text.size(); + int32_t flag = TextDescriptions::LOCAL_DESCRIPTIONS | + TextDescriptions::OUT_OF_BAND_TEXT_SRT; + + if (size > 0) { + return TextDescriptions::getParcelOfDescriptions( + (const uint8_t *)data, size, flag, timeUs / 1000, parcel); + } + return OK; +} + } // namespace android diff --git a/media/libstagefright/timedtext/TimedTextSRTSource.h b/media/libstagefright/timedtext/TimedTextSRTSource.h new file mode 100644 index 0000000..a0734d9 --- /dev/null +++ b/media/libstagefright/timedtext/TimedTextSRTSource.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2012 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. + */ + +#ifndef TIMED_TEXT_SRT_SOURCE_H_ +#define TIMED_TEXT_SRT_SOURCE_H_ + +#include <media/stagefright/MediaErrors.h> +#include <media/stagefright/MediaSource.h> +#include <utils/Compat.h> // off64_t + +#include "TimedTextSource.h" + +namespace android { + +class AString; +class DataSource; +class MediaBuffer; +class Parcel; + +class TimedTextSRTSource : public TimedTextSource { + public: + TimedTextSRTSource(const sp<DataSource>& dataSource); + virtual status_t start(); + virtual status_t stop(); + virtual status_t read( + int64_t *timeUs, + Parcel *parcel, + const MediaSource::ReadOptions *options = NULL); + + protected: + virtual ~TimedTextSRTSource(); + + private: + sp<DataSource> mSource; + + struct TextInfo { + int64_t endTimeUs; + // The offset of the text in the original file. + off64_t offset; + int textLen; + }; + + int mIndex; + KeyedVector<int64_t, TextInfo> mTextVector; + + void reset(); + status_t scanFile(); + status_t getNextSubtitleInfo( + off64_t *offset, int64_t *startTimeUs, TextInfo *info); + status_t readNextLine(off64_t *offset, AString *data); + status_t getText( + const MediaSource::ReadOptions *options, + AString *text, int64_t *startTimeUs, int64_t *endTimeUs); + status_t extractAndAppendLocalDescriptions( + int64_t timeUs, const AString &text, Parcel *parcel); + + DISALLOW_EVIL_CONSTRUCTORS(TimedTextSRTSource); +}; + +} // namespace android + +#endif // TIMED_TEXT_SRT_SOURCE_H_ diff --git a/media/libstagefright/timedtext/TimedTextSource.cpp b/media/libstagefright/timedtext/TimedTextSource.cpp new file mode 100644 index 0000000..9efe67c --- /dev/null +++ b/media/libstagefright/timedtext/TimedTextSource.cpp @@ -0,0 +1,53 @@ + /* + * Copyright (C) 2012 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. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "TimedTextSource" +#include <utils/Log.h> + +#include <media/stagefright/DataSource.h> +#include <media/stagefright/MediaSource.h> + +#include "TimedTextSource.h" + +#include "TimedTextInBandSource.h" +#include "TimedTextSRTSource.h" + +namespace android { + +// static +sp<TimedTextSource> TimedTextSource::CreateTimedTextSource( + const sp<MediaSource>& mediaSource) { + return new TimedTextInBandSource(mediaSource); +} + +// static +sp<TimedTextSource> TimedTextSource::CreateTimedTextSource( + const sp<DataSource>& dataSource, FileType filetype) { + switch(filetype) { + case OUT_OF_BAND_FILE_SRT: + return new TimedTextSRTSource(dataSource); + case OUT_OF_BAND_FILE_SMI: + // TODO: Implement for SMI. + ALOGE("Supporting SMI is not implemented yet"); + break; + default: + ALOGE("Undefined subtitle format. : %d", filetype); + } + return NULL; +} + +} // namespace android diff --git a/media/libstagefright/timedtext/TimedTextSource.h b/media/libstagefright/timedtext/TimedTextSource.h new file mode 100644 index 0000000..06bae71 --- /dev/null +++ b/media/libstagefright/timedtext/TimedTextSource.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2012 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. + */ + +#ifndef TIMED_TEXT_SOURCE_H_ +#define TIMED_TEXT_SOURCE_H_ + +#include <media/stagefright/foundation/ABase.h> // for DISALLOW_XXX macro. +#include <media/stagefright/MediaErrors.h> +#include <media/stagefright/MediaSource.h> // for MediaSource::ReadOptions +#include <utils/RefBase.h> + +namespace android { + +class DataSource; +class Parcel; + +class TimedTextSource : public RefBase { + public: + enum FileType { + OUT_OF_BAND_FILE_SRT = 1, + OUT_OF_BAND_FILE_SMI = 2, + }; + static sp<TimedTextSource> CreateTimedTextSource( + const sp<MediaSource>& source); + static sp<TimedTextSource> CreateTimedTextSource( + const sp<DataSource>& source, FileType filetype); + TimedTextSource() {} + virtual status_t start() = 0; + virtual status_t stop() = 0; + // Returns subtitle parcel and its start time. + virtual status_t read( + int64_t *timeUs, + Parcel *parcel, + const MediaSource::ReadOptions *options = NULL) = 0; + virtual status_t extractGlobalDescriptions(Parcel *parcel) { + return INVALID_OPERATION; + } + + protected: + virtual ~TimedTextSource() { } + + private: + DISALLOW_EVIL_CONSTRUCTORS(TimedTextSource); +}; + +} // namespace android + +#endif // TIMED_TEXT_SOURCE_H_ diff --git a/media/mediaserver/main_mediaserver.cpp b/media/mediaserver/main_mediaserver.cpp index f078192..1520c01 100644 --- a/media/mediaserver/main_mediaserver.cpp +++ b/media/mediaserver/main_mediaserver.cpp @@ -15,10 +15,7 @@ ** limitations under the License. */ -// System headers required for setgroups, etc. -#include <sys/types.h> -#include <unistd.h> -#include <grp.h> +#define LOG_TAG "mediaserver" #include <binder/IPCThreadState.h> #include <binder/ProcessState.h> @@ -29,7 +26,6 @@ #include <CameraService.h> #include <MediaPlayerService.h> #include <AudioPolicyService.h> -#include <private/android_filesystem_config.h> using namespace android; diff --git a/media/mtp/Android.mk b/media/mtp/Android.mk index e590bab..fc7fc4f 100644 --- a/media/mtp/Android.mk +++ b/media/mtp/Android.mk @@ -39,6 +39,9 @@ LOCAL_MODULE:= libmtp LOCAL_CFLAGS := -DMTP_DEVICE -DMTP_HOST +# Needed for <bionic_time.h> +LOCAL_C_INCLUDES := bionic/libc/private + LOCAL_SHARED_LIBRARIES := libutils libcutils libusbhost libbinder include $(BUILD_SHARED_LIBRARY) diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaAudioManagerTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaAudioManagerTest.java index c9087d1..7967ce7 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaAudioManagerTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaAudioManagerTest.java @@ -19,8 +19,13 @@ package com.android.mediaframeworktest.functional.audio; import com.android.mediaframeworktest.MediaFrameworkTest; import android.content.Context; import android.media.AudioManager; +import android.media.MediaPlayer; +import android.media.AudioManager.OnAudioFocusChangeListener; +import android.os.Looper; import android.test.ActivityInstrumentationTestCase2; import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.LargeTest; +import android.util.Log; /** * Junit / Instrumentation test case for the media AudioManager api @@ -28,8 +33,13 @@ import android.test.suitebuilder.annotation.MediumTest; public class MediaAudioManagerTest extends ActivityInstrumentationTestCase2<MediaFrameworkTest> { - private String TAG = "MediaAudioManagerTest"; + private final static String TAG = "MediaAudioManagerTest"; + // the AudioManager used throughout the test private AudioManager mAudioManager; + // keep track of looper for AudioManager so we can terminate it + private Looper mAudioManagerLooper; + private final Object mLooperLock = new Object(); + private final static int WAIT_FOR_LOOPER_TO_INITIALIZE_MS = 60000; // 60s private int[] ringtoneMode = {AudioManager.RINGER_MODE_NORMAL, AudioManager.RINGER_MODE_SILENT, AudioManager.RINGER_MODE_VIBRATE}; @@ -37,17 +47,48 @@ public class MediaAudioManagerTest extends ActivityInstrumentationTestCase2<Medi super("com.android.mediaframeworktest", MediaFrameworkTest.class); } + private void initializeAudioManagerWithLooper() { + new Thread() { + @Override + public void run() { + Looper.prepare(); + mAudioManagerLooper = Looper.myLooper(); + mAudioManager = (AudioManager)getActivity().getSystemService(Context.AUDIO_SERVICE); + synchronized (mLooperLock) { + mLooperLock.notify(); + } + Looper.loop(); + } + }.start(); + } + @Override protected void setUp() throws Exception { super.setUp(); - mAudioManager = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE); + synchronized(mLooperLock) { + initializeAudioManagerWithLooper(); + try { + mLooperLock.wait(WAIT_FOR_LOOPER_TO_INITIALIZE_MS); + } catch (Exception e) { + assertTrue("initializeAudioManagerWithLooper() failed to complete in time", false); + } + } } @Override protected void tearDown() throws Exception { super.tearDown(); + synchronized(mLooperLock) { + if (mAudioManagerLooper != null) { + mAudioManagerLooper.quit(); + } + } } + //----------------------------------------------------------------- + // Ringer Mode + //---------------------------------- + public boolean validateSetRingTone(int i) { int getRingtone = mAudioManager.getRingerMode(); if (i != getRingtone) @@ -67,4 +108,136 @@ public class MediaAudioManagerTest extends ActivityInstrumentationTestCase2<Medi assertTrue("SetRingtoneMode : " + ringtoneMode[i], result); } } + + //----------------------------------------------------------------- + // AudioFocus + //---------------------------------- + + private static AudioFocusListener mAudioFocusListener; + private final static int INVALID_FOCUS = -80; // initialized to magic invalid focus change type + private final static int WAIT_FOR_AUDIOFOCUS_LOSS_MS = 10; + + private static class AudioFocusListener implements OnAudioFocusChangeListener { + public int mLastFocusChange = INVALID_FOCUS; + public int mFocusChangeCounter = 0; + public AudioFocusListener() { + } + public void onAudioFocusChange(int focusChange) { + mLastFocusChange = focusChange; + mFocusChangeCounter++; + } + } + + /** + * Fails the test if expectedFocusLossMode != mAudioFocusListener.mLastFocusChange + */ + private void verifyAudioFocusLoss(int focusGainMode, int expectedFocusLossMode) + throws Exception { + // request AudioFocus so we can test that mAudioFocusListener loses it when another + // request comes in + int result = mAudioManager.requestAudioFocus(mAudioFocusListener, + AudioManager.STREAM_MUSIC, + AudioManager.AUDIOFOCUS_GAIN); + assertTrue("requestAudioFocus returned " + result, + result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED); + // cause mAudioFocusListener to lose AudioFocus + result = mAudioManager.requestAudioFocus(null, AudioManager.STREAM_MUSIC, + focusGainMode); + assertTrue("requestAudioFocus returned " + result, + result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED); + // the audio focus request is async, so wait a bit to verify it had the expected effect + java.lang.Thread.sleep(WAIT_FOR_AUDIOFOCUS_LOSS_MS); + // test successful if the expected focus loss was recorded + assertEquals("listener lost focus", + mAudioFocusListener.mLastFocusChange, expectedFocusLossMode); + } + + private void setupAudioFocusListener() { + mAudioFocusListener = new AudioFocusListener(); + mAudioManager.registerAudioFocusListener(mAudioFocusListener); + } + + private void cleanupAudioFocusListener() { + // clean up + mAudioManager.abandonAudioFocus(mAudioFocusListener); + mAudioManager.unregisterAudioFocusListener(mAudioFocusListener); + } + + //---------------------------------- + + //Test case 1: test audio focus listener loses audio focus: + // AUDIOFOCUS_GAIN causes AUDIOFOCUS_LOSS + @MediumTest + public void testAudioFocusLoss() throws Exception { + setupAudioFocusListener(); + + verifyAudioFocusLoss(AudioManager.AUDIOFOCUS_GAIN, AudioManager.AUDIOFOCUS_LOSS); + + cleanupAudioFocusListener(); + } + + //Test case 2: test audio focus listener loses audio focus: + // AUDIOFOCUS_GAIN_TRANSIENT causes AUDIOFOCUS_LOSS_TRANSIENT + @MediumTest + public void testAudioFocusLossTransient() throws Exception { + setupAudioFocusListener(); + + verifyAudioFocusLoss(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, + AudioManager.AUDIOFOCUS_LOSS_TRANSIENT); + + cleanupAudioFocusListener(); + } + + //Test case 3: test audio focus listener loses audio focus: + // AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK causes AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK + @MediumTest + public void testAudioFocusLossTransientDuck() throws Exception { + setupAudioFocusListener(); + + verifyAudioFocusLoss(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, + AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK); + + cleanupAudioFocusListener(); + } + + //Test case 4: test audio focus registering and use over 3000 iterations + @LargeTest + public void testAudioFocusStressListenerRequestAbandon() throws Exception { + final int ITERATIONS = 3000; + // here we only test the life cycle of a focus listener, and make sure we don't crash + // when doing it many times without waiting + for (int i = 0 ; i < ITERATIONS ; i++) { + setupAudioFocusListener(); + int result = mAudioManager.requestAudioFocus(mAudioFocusListener, + AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN); + assertTrue("audio focus request was not granted", + result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED); + cleanupAudioFocusListener(); + } + assertTrue("testAudioFocusListenerLifeCycle : tested" + ITERATIONS +" iterations", true); + } + + //Test case 5: test audio focus use without listener + @LargeTest + public void testAudioFocusStressNoListenerRequestAbandon() throws Exception { + final int ITERATIONS = 1000; + // make sure we have a listener in the stack + setupAudioFocusListener(); + mAudioManager.requestAudioFocus(mAudioFocusListener, AudioManager.STREAM_MUSIC, + AudioManager.AUDIOFOCUS_GAIN); + // keep making the current owner lose and gain audio focus repeatedly + for (int i = 0 ; i < ITERATIONS ; i++) { + mAudioManager.requestAudioFocus(null, AudioManager.STREAM_MUSIC, + AudioManager.AUDIOFOCUS_GAIN_TRANSIENT); + mAudioManager.abandonAudioFocus(null); + // the audio focus request is async, so wait a bit to verify it had the expected effect + java.lang.Thread.sleep(WAIT_FOR_AUDIOFOCUS_LOSS_MS); + } + // verify there were 2 audio focus changes per iteration (one loss + one gain) + assertTrue("testAudioFocusListenerLifeCycle : observed " + + mAudioFocusListener.mFocusChangeCounter + " AudioFocus changes", + mAudioFocusListener.mFocusChangeCounter == ITERATIONS * 2); + mAudioManager.abandonAudioFocus(mAudioFocusListener); + mAudioManager.unregisterAudioFocusListener(mAudioFocusListener); + } } diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaEnvReverbTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaEnvReverbTest.java index 3c8d05a..e788c17 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaEnvReverbTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaEnvReverbTest.java @@ -353,6 +353,8 @@ public class MediaEnvReverbTest extends ActivityInstrumentationTestCase2<MediaFr AudioEffect vc = null; MediaPlayer mp = null; AudioManager am = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE); + int ringerMode = am.getRingerMode(); + am.setRingerMode(AudioManager.RINGER_MODE_NORMAL); int volume = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC); am.setStreamVolume(AudioManager.STREAM_MUSIC, am.getStreamMaxVolume(AudioManager.STREAM_MUSIC), @@ -411,6 +413,7 @@ public class MediaEnvReverbTest extends ActivityInstrumentationTestCase2<MediaFr probe.release(); } am.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0); + am.setRingerMode(ringerMode); } assertTrue(msg, result); } @@ -425,6 +428,8 @@ public class MediaEnvReverbTest extends ActivityInstrumentationTestCase2<MediaFr MediaPlayer mp = null; AudioEffect rvb = null; AudioManager am = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE); + int ringerMode = am.getRingerMode(); + am.setRingerMode(AudioManager.RINGER_MODE_NORMAL); int volume = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC); am.setStreamVolume(AudioManager.STREAM_MUSIC, am.getStreamMaxVolume(AudioManager.STREAM_MUSIC), @@ -495,6 +500,7 @@ public class MediaEnvReverbTest extends ActivityInstrumentationTestCase2<MediaFr probe.release(); } am.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0); + am.setRingerMode(ringerMode); } assertTrue(msg, result); } diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaPresetReverbTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaPresetReverbTest.java index 757bbc5..bc9c48d 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaPresetReverbTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaPresetReverbTest.java @@ -198,6 +198,8 @@ public class MediaPresetReverbTest extends ActivityInstrumentationTestCase2<Medi AudioEffect vc = null; MediaPlayer mp = null; AudioManager am = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE); + int ringerMode = am.getRingerMode(); + am.setRingerMode(AudioManager.RINGER_MODE_NORMAL); int volume = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC); am.setStreamVolume(AudioManager.STREAM_MUSIC, am.getStreamMaxVolume(AudioManager.STREAM_MUSIC), @@ -254,6 +256,7 @@ public class MediaPresetReverbTest extends ActivityInstrumentationTestCase2<Medi probe.release(); } am.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0); + am.setRingerMode(ringerMode); } assertTrue(msg, result); } @@ -268,6 +271,8 @@ public class MediaPresetReverbTest extends ActivityInstrumentationTestCase2<Medi MediaPlayer mp = null; AudioEffect rvb = null; AudioManager am = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE); + int ringerMode = am.getRingerMode(); + am.setRingerMode(AudioManager.RINGER_MODE_NORMAL); int volume = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC); am.setStreamVolume(AudioManager.STREAM_MUSIC, am.getStreamMaxVolume(AudioManager.STREAM_MUSIC), @@ -336,6 +341,7 @@ public class MediaPresetReverbTest extends ActivityInstrumentationTestCase2<Medi probe.release(); } am.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0); + am.setRingerMode(ringerMode); } assertTrue(msg, result); } diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaVisualizerTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaVisualizerTest.java index e0cf51d..b0bf654 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaVisualizerTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaVisualizerTest.java @@ -200,6 +200,8 @@ public class MediaVisualizerTest extends ActivityInstrumentationTestCase2<MediaF AudioEffect vc = null; MediaPlayer mp = null; AudioManager am = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE); + int ringerMode = am.getRingerMode(); + am.setRingerMode(AudioManager.RINGER_MODE_NORMAL); int volume = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC); am.setStreamVolume(AudioManager.STREAM_MUSIC, am.getStreamMaxVolume(AudioManager.STREAM_MUSIC), @@ -264,6 +266,7 @@ public class MediaVisualizerTest extends ActivityInstrumentationTestCase2<MediaF vc.release(); } am.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0); + am.setRingerMode(ringerMode); } assertTrue(msg, result); } @@ -276,6 +279,8 @@ public class MediaVisualizerTest extends ActivityInstrumentationTestCase2<MediaF AudioEffect vc = null; MediaPlayer mp = null; AudioManager am = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE); + int ringerMode = am.getRingerMode(); + am.setRingerMode(AudioManager.RINGER_MODE_NORMAL); int volume = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC); am.setStreamVolume(AudioManager.STREAM_MUSIC, am.getStreamMaxVolume(AudioManager.STREAM_MUSIC), @@ -393,6 +398,7 @@ public class MediaVisualizerTest extends ActivityInstrumentationTestCase2<MediaF vc.release(); } am.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0); + am.setRingerMode(ringerMode); } assertTrue(msg, result); } diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/videoeditor/MediaItemThumbnailTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/videoeditor/MediaItemThumbnailTest.java index 80a3bcd..7dfab7d 100755 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/videoeditor/MediaItemThumbnailTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/videoeditor/MediaItemThumbnailTest.java @@ -82,7 +82,6 @@ public class MediaItemThumbnailTest extends /** * To test thumbnail / frame extraction on H.263 QCIF. */ - // TODO : TC_TN_001 @LargeTest public void testThumbnailForH263QCIF() throws Exception { final String videoItemFilename = INPUT_FILE_PATH @@ -104,7 +103,6 @@ public class MediaItemThumbnailTest extends /** * To test thumbnail / frame extraction on MPEG4 VGA . */ - // TODO : TC_TN_002 @LargeTest public void testThumbnailForMPEG4VGA() throws Exception { final String videoItemFilename = INPUT_FILE_PATH + @@ -124,7 +122,6 @@ public class MediaItemThumbnailTest extends /** * To test thumbnail / frame extraction on MPEG4 NTSC. */ - // TODO : TC_TN_003 @LargeTest public void testThumbnailForMPEG4NTSC() throws Exception { final String videoItemFilename = INPUT_FILE_PATH @@ -144,7 +141,6 @@ public class MediaItemThumbnailTest extends /** * To test thumbnail / frame extraction on MPEG4 WVGA. */ - // TODO : TC_TN_004 @LargeTest public void testThumbnailForMPEG4WVGA() throws Exception { @@ -165,7 +161,6 @@ public class MediaItemThumbnailTest extends /** * To test thumbnail / frame extraction on MPEG4 QCIF. */ - // TODO : TC_TN_005 @LargeTest public void testThumbnailForMPEG4QCIF() throws Exception { final String videoItemFilename = INPUT_FILE_PATH @@ -186,7 +181,6 @@ public class MediaItemThumbnailTest extends /** * To test thumbnail / frame extraction on H264 QCIF. */ - // TODO : TC_TN_006 @LargeTest public void testThumbnailForH264QCIF() throws Exception { final String videoItemFilename = INPUT_FILE_PATH @@ -207,7 +201,6 @@ public class MediaItemThumbnailTest extends /** * To test thumbnail / frame extraction on H264 VGA. */ - // TODO : TC_TN_007 @LargeTest public void testThumbnailForH264VGA() throws Exception { final String videoItemFilename = INPUT_FILE_PATH + @@ -228,7 +221,6 @@ public class MediaItemThumbnailTest extends /** * To test thumbnail / frame extraction on H264 WVGA. */ - // TODO : TC_TN_008 @LargeTest public void testThumbnailForH264WVGA() throws Exception { final String videoItemFilename = INPUT_FILE_PATH + @@ -248,7 +240,6 @@ public class MediaItemThumbnailTest extends /** * To test thumbnail / frame extraction on H264 854x480. */ - // TODO : TC_TN_009 @LargeTest public void testThumbnailForH264854_480() throws Exception { final String videoItemFilename = INPUT_FILE_PATH @@ -269,7 +260,6 @@ public class MediaItemThumbnailTest extends /** * To test thumbnail / frame extraction on H264 960x720. */ - // TODO : TC_TN_010 @LargeTest public void testThumbnailForH264HD960() throws Exception { final String videoItemFilename = INPUT_FILE_PATH + @@ -290,7 +280,6 @@ public class MediaItemThumbnailTest extends /** * To test thumbnail / frame extraction on H264 1080x720 . */ - // TODO : TC_TN_011 @LargeTest public void testThumbnailForH264HD1080() throws Exception { final String videoItemFilename = INPUT_FILE_PATH + @@ -310,7 +299,6 @@ public class MediaItemThumbnailTest extends /** * Check the thumbnail / frame extraction precision at 0,100 and 200 ms */ - // TODO : TC_TN_012 @LargeTest public void testThumbnailForH264VGADifferentDuration() throws Exception { final String videoItemFilename = INPUT_FILE_PATH + @@ -345,7 +333,6 @@ public class MediaItemThumbnailTest extends *Check the thumbnail / frame extraction precision at * FileDuration,FileDuration/2 + 100 andFileDuration/2 + 200 ms */ - // TODO : TC_TN_013 @LargeTest public void testThumbnailForMP4VGA() throws Exception { final String videoItemFilename = INPUT_FILE_PATH + @@ -379,7 +366,6 @@ public class MediaItemThumbnailTest extends /** * Check the thumbnail / frame extraction on JPEG file */ - // TODO : TC_TN_014 @LargeTest public void testThumbnailForImage() throws Exception { final String imageItemFilename = INPUT_FILE_PATH + "IMG_640x480.jpg"; @@ -402,7 +388,6 @@ public class MediaItemThumbnailTest extends /** *To test ThumbnailList for H263 QCIF */ - // TODO : TC_TN_015 @LargeTest public void testThumbnailListH263QCIF() throws Exception { final String videoItemFilename = INPUT_FILE_PATH @@ -432,7 +417,6 @@ public class MediaItemThumbnailTest extends /** *To test ThumbnailList for MPEG4 QCIF */ - // TODO : TC_TN_016 @LargeTest public void testThumbnailListMPEG4QCIF() throws Exception { final String videoItemFilename = INPUT_FILE_PATH @@ -463,7 +447,6 @@ public class MediaItemThumbnailTest extends /** *To test ThumbnailList for H264 VGA */ - // TODO : TC_TN_017 @LargeTest public void testThumbnailListH264VGA() throws Exception { final String videoItemFilename = INPUT_FILE_PATH + @@ -492,7 +475,6 @@ public class MediaItemThumbnailTest extends /** *To test ThumbnailList for H264 WVGA */ - // TODO : TC_TN_018 @LargeTest public void testThumbnailListH264WVGA() throws Exception { final String videoItemFilename = INPUT_FILE_PATH + @@ -521,7 +503,6 @@ public class MediaItemThumbnailTest extends /** *To test ThumbnailList for H264 VGA ,Time exceeding file duration */ - // TODO : TC_TN_019 @LargeTest public void testThumbnailH264VGAExceedingFileDuration() throws Exception { final String videoItemFilename = INPUT_FILE_PATH + @@ -547,7 +528,6 @@ public class MediaItemThumbnailTest extends /** *To test ThumbnailList for VGA Image */ - // TODO : TC_TN_020 @LargeTest public void testThumbnailListVGAImage() throws Exception { final String imageItemFilename = INPUT_FILE_PATH + "IMG_640x480.jpg"; @@ -576,7 +556,6 @@ public class MediaItemThumbnailTest extends /** *To test ThumbnailList for Invalid file path */ - // TODO : TC_TN_021 @LargeTest public void testThumbnailForInvalidFilePath() throws Exception { final String imageItemFileName = INPUT_FILE_PATH + "/sdcard/abc.jpg"; @@ -596,7 +575,6 @@ public class MediaItemThumbnailTest extends /** * To test thumbnail / frame extraction with setBoundaries */ - // TODO : TC_TN_022 @LargeTest public void testThumbnailForMPEG4WVGAWithSetBoundaries() throws Exception { final String videoItemFilename = INPUT_FILE_PATH + @@ -620,7 +598,6 @@ public class MediaItemThumbnailTest extends /** *To test ThumbnailList for H264 WVGA with setExtractboundaries */ - // TODO : TC_TN_023 @LargeTest public void testThumbnailListForH264WVGAWithSetBoundaries() throws Exception { final String videoItemFilename = INPUT_FILE_PATH + @@ -652,7 +629,6 @@ public class MediaItemThumbnailTest extends /** *To test ThumbnailList for H264 WVGA with count > frame available */ - // TODO : TC_TN_024 @LargeTest public void testThumbnailListForH264WVGAWithCount() throws Exception { final String videoItemFilename = INPUT_FILE_PATH + @@ -684,7 +660,6 @@ public class MediaItemThumbnailTest extends /** *To test ThumbnailList for H264 WVGA with startTime > End Time */ - // TODO : TC_TN_025 @LargeTest public void testThumbnailListH264WVGAWithStartGreaterEnd() throws Exception { final String videoItemFilename = INPUT_FILE_PATH + @@ -710,9 +685,8 @@ public class MediaItemThumbnailTest extends } /** - *To test ThumbnailList TC_TN_026 for H264 WVGA with startTime = End Time + *To test ThumbnailList for H264 WVGA with startTime = End Time */ - // TODO : TC_TN_026 @LargeTest public void testThumbnailListH264WVGAWithStartEqualEnd() throws Exception { final String videoItemFilename = INPUT_FILE_PATH + @@ -738,10 +712,9 @@ public class MediaItemThumbnailTest extends } /** - *To test ThumbnailList TC_TN_027 for file where video duration is less + *To test ThumbnailList for file where video duration is less * than file duration. */ - // TODO : TC_TN_027 @LargeTest public void testThumbnailForVideoDurationLessFileDuration() throws Exception { final String videoItemFilename = INPUT_FILE_PATH @@ -760,9 +733,8 @@ public class MediaItemThumbnailTest extends } /** - *To test ThumbnailList TC_TN_028 for file which has video part corrupted + *To test ThumbnailList for file which has video part corrupted */ - // TODO : TC_TN_028 @LargeTest public void testThumbnailWithCorruptedVideoPart() throws Exception { final String videoItemFilename = INPUT_FILE_PATH + @@ -787,7 +759,6 @@ public class MediaItemThumbnailTest extends /** * Check the thumbnail / frame list extraction for Height as Negative Value */ - // TODO : TC_TN_029 @LargeTest public void testThumbnailWithNegativeHeight() throws Exception { final String videoItemFilename = INPUT_FILE_PATH @@ -815,7 +786,6 @@ public class MediaItemThumbnailTest extends /** * Check the thumbnail for Height as Zero */ - // TODO : TC_TN_030 @LargeTest public void testThumbnailWithHeightAsZero() throws Exception { final String videoItemFilename = INPUT_FILE_PATH @@ -839,7 +809,6 @@ public class MediaItemThumbnailTest extends /** * Check the thumbnail for Height = 10 */ - // TODO : TC_TN_031 @LargeTest public void testThumbnailWithHeight() throws Exception { final String videoItemFilename = INPUT_FILE_PATH @@ -859,7 +828,6 @@ public class MediaItemThumbnailTest extends /** * Check the thumbnail / frame list extraction for Width as Negative Value */ - // TODO : TC_TN_032 @LargeTest public void testThumbnailWithNegativeWidth() throws Exception { final String videoItemFilename = INPUT_FILE_PATH @@ -887,7 +855,6 @@ public class MediaItemThumbnailTest extends /** * Check the thumbnail / frame list extraction for Width zero */ - // TODO : TC_TN_033 @LargeTest public void testThumbnailWithWidthAsZero() throws Exception { final String videoItemFilename = INPUT_FILE_PATH @@ -911,7 +878,6 @@ public class MediaItemThumbnailTest extends /** * Check the thumbnail for Width = 10 */ - // TODO : TC_TN_034 @LargeTest public void testThumbnailWithWidth() throws Exception { final String videoItemFilename = INPUT_FILE_PATH @@ -931,7 +897,6 @@ public class MediaItemThumbnailTest extends /** * To test thumbnail / frame extraction on MPEG4 (time beyond file duration). */ - // TODO : TC_TN_035 @LargeTest public void testThumbnailMPEG4withMorethanFileDuration() throws Exception { final String videoItemFilename = INPUT_FILE_PATH diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/videoeditor/MediaPropertiesTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/videoeditor/MediaPropertiesTest.java index e2f6863..34cf9f0 100755 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/videoeditor/MediaPropertiesTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/videoeditor/MediaPropertiesTest.java @@ -130,7 +130,6 @@ public class MediaPropertiesTest extends /** *To test Media Properties for file MPEG4 854 x 480 */ - // TODO : Remove TC_MP_001 @LargeTest public void testPropertiesMPEG4854_480() throws Exception { final String videoItemFilename = INPUT_FILE_PATH @@ -163,7 +162,6 @@ public class MediaPropertiesTest extends /** *To test Media Properties for file MPEG4 WVGA */ - // TODO : Remove TC_MP_002 @LargeTest public void testPropertiesMPEGWVGA() throws Exception { final String videoItemFilename = INPUT_FILE_PATH @@ -195,7 +193,6 @@ public class MediaPropertiesTest extends /** *To test media properties for MPEG4 720x480 (NTSC) + AAC file. */ - // TODO : Remove TC_MP_003 @LargeTest public void testPropertiesMPEGNTSC() throws Exception { final String videoItemFilename = INPUT_FILE_PATH @@ -227,7 +224,6 @@ public class MediaPropertiesTest extends /** *To test Media Properties for file MPEG4 VGA */ - // TODO : Remove TC_MP_004 @LargeTest public void testPropertiesMPEGVGA() throws Exception { final String videoItemFilename = INPUT_FILE_PATH @@ -259,7 +255,6 @@ public class MediaPropertiesTest extends /** *To test Media Properties for file MPEG4 QCIF */ - // TODO : Remove TC_MP_005 @LargeTest public void testPropertiesMPEGQCIF() throws Exception { final String videoItemFilename = INPUT_FILE_PATH @@ -291,7 +286,6 @@ public class MediaPropertiesTest extends /** *To To test media properties for H263 176x144 (QCIF) + AAC (mono) file. */ - // TODO : Remove TC_MP_006 @LargeTest public void testPropertiesH263QCIF() throws Exception { final String videoItemFilename = INPUT_FILE_PATH @@ -322,7 +316,6 @@ public class MediaPropertiesTest extends /** *To test Media Properties for file H264 VGA */ - // TODO : Remove TC_MP_007 @LargeTest public void testPropertiesH264VGA() throws Exception { final String videoItemFilename = INPUT_FILE_PATH @@ -353,7 +346,6 @@ public class MediaPropertiesTest extends /** *To test Media Properties for file H264 NTSC */ - // TODO : Remove TC_MP_008 @LargeTest public void testPropertiesH264NTSC() throws Exception { final String videoItemFilename = INPUT_FILE_PATH @@ -385,7 +377,6 @@ public class MediaPropertiesTest extends /** *To test media properties for H264 800x480 (WVGA) + AAC file. */ - // TODO : Remove TC_MP_009 @LargeTest public void testPropertiesH264WVGA() throws Exception { final String videoItemFilename = INPUT_FILE_PATH + @@ -417,7 +408,6 @@ public class MediaPropertiesTest extends /** *To test Media Properties for file H264 HD1280 */ - // TODO : Remove TC_MP_010 @LargeTest public void testPropertiesH264HD1280() throws Exception { final String videoItemFilename = INPUT_FILE_PATH @@ -449,7 +439,6 @@ public class MediaPropertiesTest extends /** *To test media properties for H264 1080x720 + AAC file */ - // TODO : Remove TC_MP_011 @LargeTest public void testPropertiesH264HD1080WithAudio() throws Exception { final String videoItemFilename = INPUT_FILE_PATH @@ -481,7 +470,6 @@ public class MediaPropertiesTest extends /** *To test Media Properties for file WMV - Unsupported type */ - // TODO : Remove TC_MP_012 @LargeTest public void testPropertiesWMVFile() throws Exception { final String videoItemFilename = INPUT_FILE_PATH + @@ -506,7 +494,6 @@ public class MediaPropertiesTest extends /** *To test media properties for H.264 Main/Advanced profile. */ - // TODO : Remove TC_MP_013 @LargeTest public void testPropertiesH264MainLineProfile() throws Exception { final String videoItemFilename = INPUT_FILE_PATH @@ -539,7 +526,6 @@ public class MediaPropertiesTest extends /** *To test Media Properties for non existing file. */ - // TODO : Remove TC_MP_014 @LargeTest public void testPropertiesForNonExsitingFile() throws Exception { final String videoItemFilename = INPUT_FILE_PATH + "abc.3gp"; @@ -559,7 +545,6 @@ public class MediaPropertiesTest extends /** *To test Media Properties for file H264 HD1080 */ - // TODO : Remove TC_MP_015 @LargeTest public void testPropertiesH264HD1080WithoutAudio() throws Exception { final String videoItemFilename = INPUT_FILE_PATH + @@ -591,7 +576,6 @@ public class MediaPropertiesTest extends /** *To test Media Properties for Image file of JPEG Type */ - // TODO : Remove TC_MP_016 @LargeTest public void testPropertiesVGAImage() throws Exception { final String imageItemFilename = INPUT_FILE_PATH + "IMG_640x480.jpg"; @@ -611,7 +595,6 @@ public class MediaPropertiesTest extends /** *To test Media Properties for Image file of PNG Type */ - // TODO : Remove TC_MP_017 @LargeTest public void testPropertiesPNG() throws Exception { final String imageItemFilename = INPUT_FILE_PATH + "IMG_640x480.png"; @@ -630,7 +613,6 @@ public class MediaPropertiesTest extends /** *To test Media Properties for file GIF - Unsupported type */ - // TODO : Remove TC_MP_018 @LargeTest public void testPropertiesGIFFile() throws Exception { @@ -651,7 +633,6 @@ public class MediaPropertiesTest extends /** *To test Media Properties for file Text file named as 3GP */ - // TODO : Remove TC_MP_019 @LargeTest public void testPropertiesofDirtyFile() throws Exception { @@ -672,7 +653,6 @@ public class MediaPropertiesTest extends /** *To test Media Properties for file name as NULL */ - // TODO : Remove TC_MP_020 @LargeTest public void testPropertieNULLFile() throws Exception { final String videoItemFilename = null; @@ -691,7 +671,6 @@ public class MediaPropertiesTest extends /** *To test Media Properties for file which is of type MPEG2 */ - // TODO : Remove TC_MP_021 @LargeTest public void testPropertiesMPEG2File() throws Exception { final String videoItemFilename = INPUT_FILE_PATH + @@ -709,9 +688,8 @@ public class MediaPropertiesTest extends } /** - *To test Media Properties TC_MP_023 for file without Video only Audio + *To test Media Properties for file without Video only Audio */ - // TODO : Remove TC_MP_023 @LargeTest public void testProperties3GPWithoutVideoMediaItem() throws Exception { final String audioFilename = INPUT_FILE_PATH + @@ -731,7 +709,6 @@ public class MediaPropertiesTest extends /** *To test media properties for Audio Track file. (No Video, AAC Audio) */ - // TODO : Remove TC_MP_024 @LargeTest public void testProperties3GPWithoutVideoAudioTrack() throws Exception { @@ -753,7 +730,6 @@ public class MediaPropertiesTest extends /** *To test media properties for Audio Track file. MP3 file */ - // TODO : Remove TC_MP_025 @LargeTest public void testPropertiesMP3AudioTrack() throws Exception { diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/videoeditor/VideoEditorAPITest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/videoeditor/VideoEditorAPITest.java index b32d865..6e520c3 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/videoeditor/VideoEditorAPITest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/videoeditor/VideoEditorAPITest.java @@ -88,7 +88,6 @@ public class VideoEditorAPITest extends /** * To Test Creation of Media Video Item. */ - // TODO : remove TC_API_001 @LargeTest public void testMediaVideoItem() throws Exception { final String videoItemFileName = INPUT_FILE_PATH @@ -130,7 +129,6 @@ public class VideoEditorAPITest extends * To test creation of Media Video Item with Set Extract Boundaries With Get * the Begin and End Time. */ - // TODO : remove TC_API_002 @LargeTest public void testMediaVideoItemExtractBoundaries() throws Exception { final String videoItemFileName = INPUT_FILE_PATH @@ -199,7 +197,6 @@ public class VideoEditorAPITest extends /** * To test creation of Media Video Item with Set and Get rendering Mode */ - // TODO : remove TC_API_003 @LargeTest public void testMediaVideoItemRenderingModes() throws Exception { final String videoItemFileName = INPUT_FILE_PATH @@ -238,12 +235,10 @@ public class VideoEditorAPITest extends mediaVideoItem1.getRenderingMode()); } - /** Test Case TC_API_004 is removed */ /** * To Test the Media Video API : Set Audio Volume, Get Audio Volume and Mute */ - // TODO : remove TC_API_005 @LargeTest public void testMediaVideoItemAudioFeatures() throws Exception { final String videoItemFileName = INPUT_FILE_PATH @@ -301,7 +296,6 @@ public class VideoEditorAPITest extends * extractAudioWaveFormData */ - // TODO : remove TC_API_006 @LargeTest public void testMediaVideoItemGetWaveformData() throws Exception { @@ -343,7 +337,6 @@ public class VideoEditorAPITest extends * To Test the Media Video API : Get Effect, GetAllEffects, remove Effect */ - // TODO : remove TC_API_007 @LargeTest public void testMediaVideoItemEffect() throws Exception { final String videoItemFileName = INPUT_FILE_PATH @@ -384,7 +377,6 @@ public class VideoEditorAPITest extends * To Test the Media Video API : Get Before and after transition */ - // TODO : remove TC_API_008 @LargeTest public void testMediaVideoItemTransitions() throws Exception { final String videoItemFileName = INPUT_FILE_PATH @@ -431,7 +423,6 @@ public class VideoEditorAPITest extends * */ - // TODO : remove TC_API_009 @LargeTest public void testMediaVideoItemOverlays() throws Exception { final String videoItemFileName = INPUT_FILE_PATH @@ -474,7 +465,6 @@ public class VideoEditorAPITest extends /** * To Test Creation of Media Image Item. */ - // TODO : remove TC_API_010 @LargeTest public void testMediaImageItem() throws Exception { final String imageItemFileName = INPUT_FILE_PATH + "IMG_1600x1200.jpg"; @@ -511,7 +501,6 @@ public class VideoEditorAPITest extends /** * To Test the Media Image API : Get and Set rendering Mode */ - // TODO : remove TC_API_011 @LargeTest public void testMediaImageItemRenderingModes() throws Exception { final String imageItemFileName = INPUT_FILE_PATH + "IMG_1600x1200.jpg"; @@ -554,7 +543,6 @@ public class VideoEditorAPITest extends /** * To Test the Media Image API : GetHeight and GetWidth */ - // TODO : remove TC_API_012 @LargeTest public void testMediaImageItemHeightWidth() throws Exception { final String imageItemFileName = INPUT_FILE_PATH + "IMG_640x480.jpg"; @@ -576,7 +564,6 @@ public class VideoEditorAPITest extends /** * To Test the Media Image API : Scaled Height and Scaled GetWidth */ - // TODO : remove TC_API_013 @LargeTest public void testMediaImageItemScaledHeightWidth() throws Exception { final String imageItemFileName = INPUT_FILE_PATH + "IMG_1600x1200.jpg"; @@ -597,7 +584,6 @@ public class VideoEditorAPITest extends * To Test the Media Image API : Get Effect, GetAllEffects, remove Effect */ - // TODO : remove TC_API_014 @LargeTest public void testMediaImageItemEffect() throws Exception { final String imageItemFileName = INPUT_FILE_PATH + "IMG_1600x1200.jpg"; @@ -637,7 +623,6 @@ public class VideoEditorAPITest extends * To Test the Media Image API : Get Before and after transition */ - // TODO : remove TC_API_015 @LargeTest public void testMediaImageItemTransitions() throws Exception { final String imageItemFileName = INPUT_FILE_PATH + "IMG_1600x1200.jpg"; @@ -685,7 +670,6 @@ public class VideoEditorAPITest extends * Overlay */ - // TODO : remove TC_API_016 @LargeTest public void testMediaImageItemOverlays() throws Exception { final String imageItemFileName = INPUT_FILE_PATH + "IMG_640x480.jpg"; @@ -729,7 +713,6 @@ public class VideoEditorAPITest extends * To test creation of Audio Track */ - // TODO : remove TC_API_017 @LargeTest public void testAudioTrack() throws Exception { final String audioFileName = INPUT_FILE_PATH + @@ -756,7 +739,6 @@ public class VideoEditorAPITest extends /** * To test creation of Audio Track with set extract boundaries */ - // TODO : remove TC_API_018 @LargeTest public void testAudioTrackExtractBoundaries() throws Exception { final String audioFileName = INPUT_FILE_PATH + @@ -824,7 +806,6 @@ public class VideoEditorAPITest extends /** * To test creation of Audio Track with set Start Time and Get Time */ - // TODO : remove TC_API_019 @LargeTest public void testAudioTrackSetGetTime() throws Exception { final String audioFileName = INPUT_FILE_PATH + @@ -840,7 +821,6 @@ public class VideoEditorAPITest extends /** * To Test the Audio Track API: Enable Ducking */ - // TODO : remove TC_API_020 @LargeTest public void testAudioTrackEnableDucking() throws Exception { final String audioFileName = INPUT_FILE_PATH + @@ -910,7 +890,6 @@ public class VideoEditorAPITest extends /** * To Test the Audio Track API: Looping */ - // TODO : remove TC_API_021 @LargeTest public void testAudioTrackLooping() throws Exception { final String audioFileName = INPUT_FILE_PATH + @@ -928,7 +907,6 @@ public class VideoEditorAPITest extends /** * To Test the Audio Track API:Extract waveform data */ - // TODO : remove TC_API_022 @LargeTest public void testAudioTrackWaveFormData() throws Exception { @@ -984,7 +962,6 @@ public class VideoEditorAPITest extends /** * To Test the Audio Track API: Mute */ - // TODO : remove TC_API_023 @LargeTest public void testAudioTrackMute() throws Exception { final String audioFileName = INPUT_FILE_PATH + @@ -1001,7 +978,6 @@ public class VideoEditorAPITest extends /** * To Test the Audio Track API: Get Volume and Set Volume */ - // TODO : remove TC_API_024 @LargeTest public void testAudioTrackGetSetVolume() throws Exception { final String audioFileName = INPUT_FILE_PATH + @@ -1042,7 +1018,6 @@ public class VideoEditorAPITest extends /** * To test Effect Color. */ - // TODO : remove TC_API_025 @LargeTest public void testAllEffects() throws Exception { final String videoItemFileName = INPUT_FILE_PATH + @@ -1206,7 +1181,6 @@ public class VideoEditorAPITest extends /** * To test Effect Color : Set duration and Get Duration */ - // TODO : remove TC_API_026 @LargeTest public void testEffectSetgetDuration() throws Exception { final String videoItemFileName = INPUT_FILE_PATH + @@ -1246,7 +1220,6 @@ public class VideoEditorAPITest extends /** * To test Effect Color : UNDEFINED color param value */ - // TODO : remove TC_API_027 @LargeTest public void testEffectUndefinedColorParam() throws Exception { final String videoItemFileName = INPUT_FILE_PATH + @@ -1269,7 +1242,6 @@ public class VideoEditorAPITest extends /** * To test Effect Color : with Invalid StartTime and Duration */ - // TODO : remove TC_API_028 @LargeTest public void testEffectInvalidStartTimeAndDuration() throws Exception { final String videoItemFileName = INPUT_FILE_PATH + @@ -1315,7 +1287,6 @@ public class VideoEditorAPITest extends /** * To test Effect : with NULL Media Item */ - // TODO : remove TC_API_034 @LargeTest public void testEffectNullMediaItem() throws Exception { boolean flagForException = false; @@ -1331,7 +1302,6 @@ public class VideoEditorAPITest extends /** * To test Effect : KenBurn Effect */ - // TODO : remove TC_API_035 @LargeTest public void testEffectKenBurn() throws Exception { // Test ken burn effect using a JPEG file. @@ -1375,7 +1345,6 @@ public class VideoEditorAPITest extends * To test KenBurnEffect : Set StartRect and EndRect */ - // TODO : remove TC_API_036 @LargeTest public void testEffectKenBurnSet() throws Exception { final String imageItemFileName = INPUT_FILE_PATH + "IMG_640x480.jpg"; @@ -1443,7 +1412,6 @@ public class VideoEditorAPITest extends * SPEED_UP/SPEED_DOWN/LINEAR/MIDDLE_SLOW/MIDDLE_FAST */ - // TODO : remove TC_API_037 @LargeTest public void testTransitionFadeBlack() throws Exception { @@ -1591,7 +1559,6 @@ public class VideoEditorAPITest extends * SPEED_UP/SPEED_DOWN/LINEAR/MIDDLE_SLOW/MIDDLE_FAST */ - // TODO : remove TC_API_038 @LargeTest public void testTransitionCrossFade() throws Exception { @@ -1742,7 +1709,6 @@ public class VideoEditorAPITest extends * ,DIRECTION_BOTTOM_OUT_TOP_IN */ - // TODO : remove TC_API_039 @LargeTest public void testTransitionSliding() throws Exception { final String videoItemFilename1 = INPUT_FILE_PATH + @@ -1932,7 +1898,6 @@ public class VideoEditorAPITest extends * SPEED_UP/SPEED_DOWN/LINEAR/MIDDLE_SLOW/MIDDLE_FAST */ - // TODO : remove TC_API_040 @LargeTest public void testTransitionAlpha() throws Exception { @@ -2111,7 +2076,6 @@ public class VideoEditorAPITest extends * To test Frame Overlay for Media Video Item */ - // TODO : remove TC_API_041 @LargeTest public void testFrameOverlayVideoItem() throws Exception { final String videoItemFilename1 = INPUT_FILE_PATH + @@ -2147,7 +2111,6 @@ public class VideoEditorAPITest extends * Duration */ - // TODO : remove TC_API_042 @LargeTest public void testFrameOverlaySetAndGet() throws Exception { final String videoItemFilename1 = INPUT_FILE_PATH + @@ -2193,7 +2156,6 @@ public class VideoEditorAPITest extends * Duration */ - // TODO : remove TC_API_043 @LargeTest public void testFrameOverlayInvalidTime() throws Exception { final String videoItemFilename1 = INPUT_FILE_PATH + @@ -2242,7 +2204,6 @@ public class VideoEditorAPITest extends /** * To test Frame Overlay for Media Image Item */ - // TODO : remove TC_API_045 @LargeTest public void testFrameOverlayImageItem() throws Exception { final String imageItemFilename1 = INPUT_FILE_PATH + "IMG_640x480.jpg"; @@ -2278,7 +2239,6 @@ public class VideoEditorAPITest extends * Duration */ - // TODO : remove TC_API_046 @LargeTest public void testFrameOverlaySetAndGetImage() throws Exception { final String videoItemFilename1 = INPUT_FILE_PATH + "IMG_640x480.jpg"; @@ -2321,7 +2281,6 @@ public class VideoEditorAPITest extends * Duration */ - // TODO : remove TC_API_047 @LargeTest public void testFrameOverlayInvalidTimeImage() throws Exception { final String videoItemFilename1 = INPUT_FILE_PATH + "IMG_640x480.jpg"; @@ -2370,7 +2329,6 @@ public class VideoEditorAPITest extends * To Test Frame Overlay Media Image Item :JPG File */ - // TODO : remove TC_API_048 @LargeTest public void testFrameOverlayJPGImage() throws Exception { @@ -2392,7 +2350,6 @@ public class VideoEditorAPITest extends * * @throws Exception */ - // TODO : remove TC_API_049 @LargeTest public void testVideoEditorAPI() throws Exception { @@ -2555,7 +2512,6 @@ public class VideoEditorAPITest extends * * @throws Exception */ - // TODO : remove TC_API_050 @LargeTest public void testVideoLessThanAudio() throws Exception { final String videoItemFileName1 = INPUT_FILE_PATH @@ -2583,7 +2539,6 @@ public class VideoEditorAPITest extends * * @throws Exception */ - // TODO : remove TC_API_051 @LargeTest public void testVideoContentHD() throws Exception { final String videoItemFileName1 = INPUT_FILE_PATH @@ -2609,7 +2564,6 @@ public class VideoEditorAPITest extends * * @throws Exception */ - // TODO : remove TC_API_052 @LargeTest public void testRemoveAudioTrack() throws Exception { final String audioFileName = INPUT_FILE_PATH + @@ -2638,7 +2592,6 @@ public class VideoEditorAPITest extends * * @throws Exception */ - // TODO : remove TC_API_053 @LargeTest public void testAudioDuckingDisable() throws Exception { final String audioFileName = INPUT_FILE_PATH + @@ -2653,8 +2606,6 @@ public class VideoEditorAPITest extends } - // TODO : remove TC_API_054 - /** This test case is added with Test case ID TC_API_010 */ /** * To test: Need a basic test case for the get value for TransitionAlpha @@ -2662,7 +2613,6 @@ public class VideoEditorAPITest extends * * @throws Exception */ - // TODO : remove TC_API_055 @LargeTest public void testTransitionAlphaBasic() throws Exception { @@ -2700,7 +2650,6 @@ public class VideoEditorAPITest extends * * @throws Exception */ - // TODO : remove TC_API_056 @LargeTest public void testNullAPIs() throws Exception { diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/videoeditor/VideoEditorExportTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/videoeditor/VideoEditorExportTest.java index 57a1c75..69ecf0d 100755 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/videoeditor/VideoEditorExportTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/videoeditor/VideoEditorExportTest.java @@ -91,7 +91,6 @@ public class VideoEditorExportTest extends /** * To Test export : Merge and Trim different types of Video and Image files */ - // TODO :remove TC_EXP_001 @LargeTest public void testExportMergeTrim() throws Exception { final String videoItemFilename1 = INPUT_FILE_PATH @@ -173,7 +172,6 @@ public class VideoEditorExportTest extends /** *To Test export : With Effect and Overlays on Different Media Items */ - // TODO :remove TC_EXP_002 @LargeTest public void testExportEffectOverlay() throws Exception { final String videoItemFilename1 = INPUT_FILE_PATH @@ -301,7 +299,6 @@ public class VideoEditorExportTest extends /** * To test export : with Image with KenBurnEffect */ - // TODO : remove TC_EXP_003 @LargeTest public void testExportEffectKenBurn() throws Exception { final String imageItemFileName = INPUT_FILE_PATH + "IMG_640x480.jpg"; @@ -359,7 +356,6 @@ public class VideoEditorExportTest extends /** * To Test Export : With Video and Image and An Audio BackGround Track */ - // TODO : remove TC_EXP_004 @LargeTest public void testExportAudio() throws Exception { final String videoItemFileName = INPUT_FILE_PATH @@ -420,7 +416,6 @@ public class VideoEditorExportTest extends /** *To Test export : With Transition on Different Media Items */ - // TODO :remove TC_EXP_005 @LargeTest public void testExportTransition() throws Exception { final String videoItemFilename1 = INPUT_FILE_PATH @@ -540,7 +535,6 @@ public class VideoEditorExportTest extends * * @throws Exception */ - // TODO :remove TC_EXP_006 @LargeTest public void testExportWithoutMediaItems() throws Exception { boolean flagForException = false; @@ -566,7 +560,6 @@ public class VideoEditorExportTest extends * * @throws Exception */ - // TODO :remove TC_EXP_007 @LargeTest public void testExportWithoutMediaItemsAddRemove() throws Exception { final String videoItemFilename1 = INPUT_FILE_PATH + @@ -621,7 +614,6 @@ public class VideoEditorExportTest extends * * @throws Exception */ - // TODO :remove TC_EXP_008 @LargeTest public void testExportMMS() throws Exception { final String videoItemFilename1 = INPUT_FILE_PATH diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/videoeditor/VideoEditorPreviewTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/videoeditor/VideoEditorPreviewTest.java index 4181903..7965b0a 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/videoeditor/VideoEditorPreviewTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/videoeditor/VideoEditorPreviewTest.java @@ -216,7 +216,6 @@ public class VideoEditorPreviewTest extends /** *To test Preview : FULL Preview of current work (beginning till end) */ - // TODO : remove TC_PRV_001 @LargeTest public void testPreviewTheStoryBoard() throws Exception { final String videoItemFileName1 = INPUT_FILE_PATH @@ -275,7 +274,6 @@ public class VideoEditorPreviewTest extends /** * To test Preview : Preview of start + 10 sec till end of story board */ - // TODO : remove TC_PRV_002 @LargeTest public void testPreviewTheStoryBoardFromDuration() throws Exception { final String videoItemFileName1 = INPUT_FILE_PATH @@ -336,7 +334,6 @@ public class VideoEditorPreviewTest extends /** * To test Preview : Preview of current Effects applied */ - // TODO : remove TC_PRV_003 @LargeTest public void testPreviewOfEffects() throws Exception { final String videoItemFileName1 = INPUT_FILE_PATH + @@ -394,7 +391,6 @@ public class VideoEditorPreviewTest extends *To test Preview : Preview of current Transitions applied (with multiple * generatePreview) */ - // TODO : remove TC_PRV_004 @LargeTest public void testPreviewWithTransition() throws Exception { @@ -547,7 +543,6 @@ public class VideoEditorPreviewTest extends /** * To test Preview : Preview of current Overlay applied */ - // TODO : remove TC_PRV_005 @LargeTest public void testPreviewWithOverlay() throws Exception { final String videoItemFileName = INPUT_FILE_PATH @@ -601,7 +596,6 @@ public class VideoEditorPreviewTest extends * To test Preview : Preview of current Trim applied (with default aspect * ratio) */ - // TODO : remove TC_PRV_006 @LargeTest public void testPreviewWithTrim() throws Exception { final String videoItemFileName = INPUT_FILE_PATH + @@ -625,7 +619,6 @@ public class VideoEditorPreviewTest extends * applied */ - // TODO : remove TC_PRV_007 @LargeTest public void testPreviewWithOverlayEffectKenBurn() throws Exception { @@ -684,7 +677,6 @@ public class VideoEditorPreviewTest extends /** *To test Preview : Export during preview */ - // TODO : remove TC_PRV_008 @LargeTest public void testPreviewDuringExport() throws Exception { final String videoItemFileName = INPUT_FILE_PATH + @@ -765,7 +757,6 @@ public class VideoEditorPreviewTest extends * To test Preview : Preview of current Effects applied (with from time > * total duration) */ - // TODO : remove TC_PRV_009 @LargeTest public void testPreviewWithDurationGreaterThanMediaDuration() throws Exception { @@ -826,7 +817,6 @@ public class VideoEditorPreviewTest extends * To test Preview : Preview of current Effects applied (with Render Preview * Frame) */ - // TODO : remove TC_PRV_010 @LargeTest public void testPreviewWithRenderPreviewFrame() throws Exception { final String videoItemFileName = INPUT_FILE_PATH + @@ -873,7 +863,6 @@ public class VideoEditorPreviewTest extends * To test Preview : Preview of current work from selected jump location * till end with Audio Track */ - // TODO : remove TC_PRV_011 @LargeTest public void testPreviewWithEndAudioTrack() throws Exception { final String imageItemFilename1 = INPUT_FILE_PATH + "IMG_1600x1200.jpg"; @@ -917,7 +906,6 @@ public class VideoEditorPreviewTest extends /** * To test render Preview Frame */ - // TODO : remove TC_PRV_012 @LargeTest public void testRenderPreviewFrame() throws Exception { final String videoItemFileName1 = INPUT_FILE_PATH @@ -1031,7 +1019,6 @@ public class VideoEditorPreviewTest extends /** * To Test Preview : Without any Media Items in the story Board */ - // TODO : remove TC_PRV_013 @LargeTest public void testStartPreviewWithoutMediaItems() throws Exception { boolean flagForException = false; @@ -1064,7 +1051,6 @@ public class VideoEditorPreviewTest extends * To Test Preview : Add Media and Remove Media Item (Without any Media * Items in the story Board) */ - // TODO : remove TC_PRV_014 @LargeTest public void testStartPreviewAddRemoveMediaItems() throws Exception { final String videoItemFilename1 = INPUT_FILE_PATH @@ -1134,7 +1120,6 @@ public class VideoEditorPreviewTest extends * To test Preview : Preview of current Effects applied (with Render Preview * Frame) */ - // TODO : remove TC_PRV_015 @LargeTest public void testPreviewWithRenderPreviewFrameWithoutGenerate() throws Exception { final String videoItemFileName = INPUT_FILE_PATH + diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/VideoEditorPerformance.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/VideoEditorPerformance.java index 3d0be4f..6f1959c 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/VideoEditorPerformance.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/VideoEditorPerformance.java @@ -931,7 +931,6 @@ public class VideoEditorPerformance extends /** *To test ThumbnailList for H264 */ - // TODO : TC_PRF_12 @LargeTest public void testThumbnailH264NonIFrame() throws Exception { final String videoItemFilename = INPUT_FILE_PATH + @@ -962,7 +961,6 @@ public class VideoEditorPerformance extends /** *To test ThumbnailList for H264 */ - // TODO : TC_PRF_13 @LargeTest public void testThumbnailH264AnIFrame() throws Exception { final String videoItemFilename = INPUT_FILE_PATH + diff --git a/media/tests/README.txt b/media/tests/README.txt new file mode 100644 index 0000000..e3e1639 --- /dev/null +++ b/media/tests/README.txt @@ -0,0 +1,10 @@ +MediaFrameworkTest/ + Uses instrumentation and so can be run with runtest. + It assumes /sdcard/media_api/ has been populated. + +contents/media_api/ + Push to /sdcard/media_api/ for use with MediaFrameworkTest: + adb shell mkdir /sdcard/media_api + adb push contents/media_api/ /sdcard/media_api/ + +All other subdirectories are manual tests or sample apps. |