diff options
Diffstat (limited to 'media')
25 files changed, 568 insertions, 229 deletions
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java index 5a73d2d..fd12e19 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -805,7 +805,7 @@ public class AudioService extends IAudioService.Stub { if (mode != mMode) { // automatically handle audio focus for mode changes - handleFocusForCalls(mMode, mode); + handleFocusForCalls(mMode, mode, cb); if (AudioSystem.setPhoneState(mode) == AudioSystem.AUDIO_STATUS_OK) { mMode = mode; @@ -864,7 +864,7 @@ public class AudioService extends IAudioService.Stub { } /** pre-condition: oldMode != newMode */ - private void handleFocusForCalls(int oldMode, int newMode) { + private void handleFocusForCalls(int oldMode, int newMode, IBinder cb) { // if ringing if (newMode == AudioSystem.MODE_RINGTONE) { // if not ringing silently @@ -872,8 +872,8 @@ public class AudioService extends IAudioService.Stub { if (ringVolume > 0) { // request audio focus for the communication focus entry requestAudioFocus(AudioManager.STREAM_RING, - AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, - null, null /* both allowed to be null only for this clientId */, + AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, cb, + null /* IAudioFocusDispatcher allowed to be null only for this clientId */, IN_VOICE_COMM_FOCUS_ID /*clientId*/); } @@ -884,8 +884,8 @@ public class AudioService extends IAudioService.Stub { // 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, - null, null /* both allowed to be null only for this clientId */, + AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, cb, + null /* IAudioFocusDispatcher allowed to be null only for this clientId */, IN_VOICE_COMM_FOCUS_ID /*clientId*/); } // if exiting call @@ -2547,10 +2547,9 @@ public class AudioService extends IAudioService.Stub { // the main stream type for the audio focus request is currently not used. It may // potentially be used to handle multiple stream type-dependent audio focuses. - // we need a valid binder callback for clients other than the AudioService's phone - // state listener - if (!IN_VOICE_COMM_FOCUS_ID.equals(clientId) && ((cb == null) || !cb.pingBinder())) { - Log.i(TAG, " AudioFocus DOA client for requestAudioFocus(), exiting"); + // we need a valid binder callback for clients + if (!cb.pingBinder()) { + Log.e(TAG, " AudioFocus DOA client for requestAudioFocus(), aborting."); return AudioManager.AUDIOFOCUS_REQUEST_FAILED; } @@ -2591,17 +2590,14 @@ public class AudioService extends IAudioService.Stub { }//synchronized(mAudioFocusLock) // handle the potential premature death of the new holder of the focus - // (premature death == death before abandoning focus) for a client which is not the - // AudioService's phone state listener - if (!IN_VOICE_COMM_FOCUS_ID.equals(clientId)) { - // Register for client death notification - AudioFocusDeathHandler afdh = new AudioFocusDeathHandler(cb); - try { - cb.linkToDeath(afdh, 0); - } catch (RemoteException e) { - // client has already died! - Log.w(TAG, "AudioFocus requestAudioFocus() could not link to "+cb+" binder death"); - } + // (premature death == death before abandoning focus) + // Register for client death notification + AudioFocusDeathHandler afdh = new AudioFocusDeathHandler(cb); + try { + cb.linkToDeath(afdh, 0); + } catch (RemoteException e) { + // client has already died! + Log.w(TAG, "AudioFocus requestAudioFocus() could not link to "+cb+" binder death"); } return AudioManager.AUDIOFOCUS_REQUEST_GRANTED; diff --git a/media/java/android/media/videoeditor/AudioTrack.java b/media/java/android/media/videoeditor/AudioTrack.java index b2f547b..7069b23 100755 --- a/media/java/android/media/videoeditor/AudioTrack.java +++ b/media/java/android/media/videoeditor/AudioTrack.java @@ -140,7 +140,7 @@ public class AudioTrack { try { properties = mMANativeHelper.getMediaProperties(filename); } catch (Exception e) { - throw new IllegalArgumentException("Unsupported file or file not found"); + throw new IllegalArgumentException(e.getMessage() + " : " + filename); } switch (mMANativeHelper.getFileType(properties.fileType)) { case MediaProperties.FILE_3GP: diff --git a/media/java/android/media/videoeditor/MediaVideoItem.java b/media/java/android/media/videoeditor/MediaVideoItem.java index c91d796..4758de6 100755 --- a/media/java/android/media/videoeditor/MediaVideoItem.java +++ b/media/java/android/media/videoeditor/MediaVideoItem.java @@ -115,7 +115,7 @@ public class MediaVideoItem extends MediaItem { try { properties = mMANativeHelper.getMediaProperties(filename); } catch ( Exception e) { - throw new IllegalArgumentException("Unsupported file or file not found: " + filename); + throw new IllegalArgumentException(e.getMessage() + " : " + filename); } switch (mMANativeHelper.getFileType(properties.fileType)) { diff --git a/media/java/android/media/videoeditor/Transition.java b/media/java/android/media/videoeditor/Transition.java index 3e8fe94..fa9d26d 100755 --- a/media/java/android/media/videoeditor/Transition.java +++ b/media/java/android/media/videoeditor/Transition.java @@ -131,6 +131,11 @@ public abstract class Transition { if (durationMs > getMaximumDuration()) { throw new IllegalArgumentException("The duration is too large"); } + if (afterMediaItem != null) { + mNativeHelper = afterMediaItem.getNativeContext(); + }else { + mNativeHelper = beforeMediaItem.getNativeContext(); + } } /** diff --git a/media/java/android/media/videoeditor/TransitionAlpha.java b/media/java/android/media/videoeditor/TransitionAlpha.java index f7d17cb..22788d4 100755 --- a/media/java/android/media/videoeditor/TransitionAlpha.java +++ b/media/java/android/media/videoeditor/TransitionAlpha.java @@ -104,13 +104,6 @@ public class TransitionAlpha extends Transition { mWidth = dbo.outWidth; mHeight = dbo.outHeight; - if (afterMediaItem != null) { - mNativeHelper = afterMediaItem.getNativeContext(); - }else { - mNativeHelper = beforeMediaItem.getNativeContext(); - } - - mRGBMaskFile = String.format(mNativeHelper.getProjectPath() + "/" + "mask" + transitionId+ ".rgb"); diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java index 98de2f7..b4a4689 100644 --- a/media/java/android/mtp/MtpDatabase.java +++ b/media/java/android/mtp/MtpDatabase.java @@ -20,6 +20,7 @@ import android.content.Context; import android.content.ContentValues; import android.content.IContentProvider; import android.content.Intent; +import android.content.SharedPreferences; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.media.MediaScanner; @@ -62,8 +63,8 @@ public class MtpDatabase { // true if the database has been modified in the current MTP session private boolean mDatabaseModified; - // database for writable MTP device properties - private SQLiteDatabase mDevicePropDb; + // SharedPreferences for writable MTP device properties + private SharedPreferences mDeviceProperties; private static final int DEVICE_PROPERTIES_DATABASE_VERSION = 1; // FIXME - this should be passed in via the constructor @@ -96,9 +97,6 @@ public class MtpDatabase { private static final String PARENT_FORMAT_WHERE = PARENT_WHERE + " AND " + Files.FileColumns.FORMAT + "=?"; - private static final String[] DEVICE_PROPERTY_PROJECTION = new String[] { "_id", "value" }; - private static final String DEVICE_PROPERTY_WHERE = "code=?"; - private final MediaScanner mMediaScanner; static { @@ -114,7 +112,7 @@ public class MtpDatabase { mMediaStoragePath = storagePath; mObjectsUri = Files.getMtpObjectsUri(volumeName); mMediaScanner = new MediaScanner(context); - openDevicePropertiesDatabase(context); + initDeviceProperties(context); } @Override @@ -126,19 +124,38 @@ public class MtpDatabase { } } - private void openDevicePropertiesDatabase(Context context) { - mDevicePropDb = context.openOrCreateDatabase("device-properties", Context.MODE_PRIVATE, null); - int version = mDevicePropDb.getVersion(); - - // initialize if necessary - if (version != DEVICE_PROPERTIES_DATABASE_VERSION) { - mDevicePropDb.execSQL("CREATE TABLE properties (" + - "_id INTEGER PRIMARY KEY AUTOINCREMENT," + - "code INTEGER UNIQUE ON CONFLICT REPLACE," + - "value TEXT" + - ");"); - mDevicePropDb.execSQL("CREATE INDEX property_index ON properties (code);"); - mDevicePropDb.setVersion(DEVICE_PROPERTIES_DATABASE_VERSION); + private void initDeviceProperties(Context context) { + final String devicePropertiesName = "device-properties"; + mDeviceProperties = context.getSharedPreferences(devicePropertiesName, Context.MODE_PRIVATE); + File databaseFile = context.getDatabasePath(devicePropertiesName); + + if (databaseFile.exists()) { + // for backward compatibility - read device properties from sqlite database + // and migrate them to shared prefs + SQLiteDatabase db = null; + Cursor c = null; + try { + db = context.openOrCreateDatabase("device-properties", Context.MODE_PRIVATE, null); + if (db != null) { + c = db.query("properties", new String[] { "_id", "code", "value" }, + null, null, null, null, null); + if (c != null) { + SharedPreferences.Editor e = mDeviceProperties.edit(); + while (c.moveToNext()) { + String name = c.getString(1); + String value = c.getString(2); + e.putString(name, value); + } + e.commit(); + } + } + } catch (Exception e) { + Log.e(TAG, "failed to migrate device properties", e); + } finally { + if (c != null) c.close(); + if (db != null) db.close(); + } + databaseFile.delete(); } } @@ -567,30 +584,15 @@ public class MtpDatabase { switch (property) { case MtpConstants.DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER: case MtpConstants.DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME: - // writable string properties kept in our device property database - Cursor c = null; - try { - c = mDevicePropDb.query("properties", DEVICE_PROPERTY_PROJECTION, - DEVICE_PROPERTY_WHERE, new String[] { Integer.toString(property) }, - null, null, null); - - if (c != null && c.moveToNext()) { - String value = c.getString(1); - int length = value.length(); - if (length > 255) { - length = 255; - } - value.getChars(0, length, outStringValue, 0); - outStringValue[length] = 0; - } else { - outStringValue[0] = 0; - } - return MtpConstants.RESPONSE_OK; - } finally { - if (c != null) { - c.close(); - } + // writable string properties kept in shared preferences + String value = mDeviceProperties.getString(Integer.toString(property), ""); + int length = value.length(); + if (length > 255) { + length = 255; } + value.getChars(0, length, outStringValue, 0); + outStringValue[length] = 0; + return MtpConstants.RESPONSE_OK; case MtpConstants.DEVICE_PROPERTY_IMAGE_SIZE: // use screen size as max image size @@ -612,16 +614,11 @@ public class MtpDatabase { switch (property) { case MtpConstants.DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER: case MtpConstants.DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME: - // writable string properties kept in our device property database - try { - ContentValues values = new ContentValues(); - values.put("code", property); - values.put("value", stringValue); - mDevicePropDb.insert("properties", "code", values); - return MtpConstants.RESPONSE_OK; - } catch (Exception e) { - return MtpConstants.RESPONSE_GENERAL_ERROR; - } + // writable string properties kept in shared prefs + SharedPreferences.Editor e = mDeviceProperties.edit(); + e.putString(Integer.toString(property), stringValue); + return (e.commit() ? MtpConstants.RESPONSE_OK + : MtpConstants.RESPONSE_GENERAL_ERROR); } return MtpConstants.RESPONSE_DEVICE_PROP_NOT_SUPPORTED; diff --git a/media/java/android/mtp/MtpDevice.java b/media/java/android/mtp/MtpDevice.java index 22961d7f..db2cebd 100644 --- a/media/java/android/mtp/MtpDevice.java +++ b/media/java/android/mtp/MtpDevice.java @@ -17,7 +17,7 @@ package android.mtp; import android.hardware.usb.UsbDevice; -import android.hardware.usb.UsbManager; +import android.hardware.usb.UsbDeviceConnection; import android.os.ParcelFileDescriptor; import android.util.Log; @@ -44,17 +44,20 @@ public final class MtpDevice { } /** - * Opens the MTP or PTP device and return an {@link android.mtp.MtpDevice} for it. + * Opens the MTP device. Once the device is open it takes ownership of the + * {@link android.hardware.usb.UsbDeviceConnection}. + * The connection will be closed when you call {@link #close()} + * The connection will also be closed if this method fails. * - * @param manager reference to {@link android.hardware.usb.UsbManager} + * @param connection an open {@link android.hardware.usb.UsbDeviceConnection} for the device * @return true if the device was successfully opened. */ - public boolean open(UsbManager manager) { - if (manager.openDevice(mDevice)) { - return native_open(mDevice.getDeviceName(), mDevice.getFileDescriptor()); - } else { - return false; + public boolean open(UsbDeviceConnection connection) { + boolean result = native_open(mDevice.getDeviceName(), connection.getFileDescriptor()); + if (!result) { + connection.close(); } + return result; } /** diff --git a/media/jni/android_mtp_MtpDevice.cpp b/media/jni/android_mtp_MtpDevice.cpp index fd32665..f5fcb4e 100644 --- a/media/jni/android_mtp_MtpDevice.cpp +++ b/media/jni/android_mtp_MtpDevice.cpp @@ -311,9 +311,9 @@ android_mtp_MtpDevice_get_object_info(JNIEnv *env, jobject thiz, jint objectID) if (objectInfo->mName) env->SetObjectField(info, field_objectInfo_name, env->NewStringUTF(objectInfo->mName)); if (objectInfo->mDateCreated) - env->SetLongField(info, field_objectInfo_dateCreated, objectInfo->mDateCreated); + env->SetLongField(info, field_objectInfo_dateCreated, objectInfo->mDateCreated * 1000LL); if (objectInfo->mDateModified) - env->SetLongField(info, field_objectInfo_dateModified, objectInfo->mDateModified); + env->SetLongField(info, field_objectInfo_dateModified, objectInfo->mDateModified * 1000LL); if (objectInfo->mKeywords) env->SetObjectField(info, field_objectInfo_keywords, env->NewStringUTF(objectInfo->mKeywords)); diff --git a/media/jni/mediaeditor/VideoEditorOsal.cpp b/media/jni/mediaeditor/VideoEditorOsal.cpp index 423e93f..035f59a 100755 --- a/media/jni/mediaeditor/VideoEditorOsal.cpp +++ b/media/jni/mediaeditor/VideoEditorOsal.cpp @@ -207,6 +207,7 @@ static const VideoEdit_Osal_Result gkRESULTS[] = VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_AUDIOBITRATE_TOO_HIGH ), VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_OUTPUT_FILE_SIZE_TOO_SMALL ), VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_NOMORE_SPACE ), + VIDEOEDIT_OSAL_RESULT_INIT(M4MCS_ERR_FILE_DRM_PROTECTED ), // M4READER_Common.h VIDEOEDIT_OSAL_RESULT_INIT(M4ERR_READER_UNKNOWN_STREAM_TYPE ), diff --git a/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp b/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp index 73a7c9c..3b795ce 100755 --- a/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp +++ b/media/jni/mediaeditor/VideoEditorPropertiesMain.cpp @@ -204,10 +204,17 @@ jobject videoEditProp_getProperties( result = getClipProperties( pEnv, thiz, pFile, clipType, pClipProperties); - // Check if the creation succeeded. - videoEditJava_checkAndThrowIllegalArgumentException( - &gotten, pEnv,(M4NO_ERROR != result), - "Invalid File or File not found"); + if (M4MCS_ERR_FILE_DRM_PROTECTED == result) { + // Check if the creation succeeded. + videoEditJava_checkAndThrowIllegalArgumentException( + &gotten, pEnv,(M4NO_ERROR != result), + "Invalid File - DRM Protected "); + } else { + // Check if the creation succeeded. + videoEditJava_checkAndThrowIllegalArgumentException( + &gotten, pEnv,(M4NO_ERROR != result), + "Invalid File or File not found "); + } /** * Max resolution supported is 1280 x 720. diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index 1d6ffa0..a18bedb 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -128,6 +128,9 @@ status_t AudioRecord::set( { LOGV("set(): sampleRate %d, channels %d, frameCount %d",sampleRate, channels, frameCount); + + AutoMutex lock(mLock); + if (mAudioRecord != 0) { return INVALID_OPERATION; } @@ -183,7 +186,7 @@ status_t AudioRecord::set( mSessionId = sessionId; // create the IAudioRecord - status = openRecord(sampleRate, format, channelCount, + status = openRecord_l(sampleRate, format, channelCount, frameCount, flags, input); if (status != NO_ERROR) { return status; @@ -282,21 +285,31 @@ status_t AudioRecord::start() } AutoMutex lock(mLock); + // acquire a strong reference on the IAudioRecord and IMemory so that they cannot be destroyed + // while we are accessing the cblk + sp <IAudioRecord> audioRecord = mAudioRecord; + sp <IMemory> iMem = mCblkMemory; + audio_track_cblk_t* cblk = mCblk; if (mActive == 0) { mActive = 1; - ret = mAudioRecord->start(); - if (ret == DEAD_OBJECT) { - LOGV("start() dead IAudioRecord: creating a new one"); - ret = openRecord(mCblk->sampleRate, mFormat, mChannelCount, - mFrameCount, mFlags, getInput()); - if (ret == NO_ERROR) { - ret = mAudioRecord->start(); + + cblk->lock.lock(); + if (!(cblk->flags & CBLK_INVALID_MSK)) { + cblk->lock.unlock(); + ret = mAudioRecord->start(); + cblk->lock.lock(); + if (ret == DEAD_OBJECT) { + cblk->flags |= CBLK_INVALID_MSK; } } + if (cblk->flags & CBLK_INVALID_MSK) { + ret = restoreRecord_l(cblk); + } + cblk->lock.unlock(); if (ret == NO_ERROR) { - mNewPosition = mCblk->user + mUpdatePeriod; - mCblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS; - mCblk->waitTimeMs = 0; + mNewPosition = cblk->user + mUpdatePeriod; + cblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS; + cblk->waitTimeMs = 0; if (t != 0) { t->run("ClientRecordThread", THREAD_PRIORITY_AUDIO_CLIENT); } else { @@ -353,6 +366,7 @@ bool AudioRecord::stopped() const uint32_t AudioRecord::getSampleRate() { + AutoMutex lock(mLock); return mCblk->sampleRate; } @@ -400,6 +414,7 @@ status_t AudioRecord::getPosition(uint32_t *position) { if (position == 0) return BAD_VALUE; + AutoMutex lock(mLock); *position = mCblk->user; return NO_ERROR; @@ -415,7 +430,8 @@ unsigned int AudioRecord::getInputFramesLost() // ------------------------------------------------------------------------- -status_t AudioRecord::openRecord( +// must be called with mLock held +status_t AudioRecord::openRecord_l( uint32_t sampleRate, int format, int channelCount, @@ -459,6 +475,7 @@ status_t AudioRecord::openRecord( status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) { + AutoMutex lock(mLock); int active; status_t result; audio_track_cblk_t* cblk = mCblk; @@ -483,7 +500,19 @@ status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) cblk->lock.unlock(); return WOULD_BLOCK; } - result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs)); + if (!(cblk->flags & CBLK_INVALID_MSK)) { + mLock.unlock(); + result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs)); + cblk->lock.unlock(); + mLock.lock(); + if (mActive == 0) { + return status_t(STOPPED); + } + cblk->lock.lock(); + } + if (cblk->flags & CBLK_INVALID_MSK) { + goto create_new_record; + } if (__builtin_expect(result!=NO_ERROR, false)) { cblk->waitTimeMs += waitTimeMs; if (cblk->waitTimeMs >= cblk->bufferTimeoutMs) { @@ -491,16 +520,17 @@ status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) "user=%08x, server=%08x", cblk->user, cblk->server); cblk->lock.unlock(); result = mAudioRecord->start(); + cblk->lock.lock(); if (result == DEAD_OBJECT) { - LOGW("obtainBuffer() dead IAudioRecord: creating a new one"); - result = openRecord(cblk->sampleRate, mFormat, mChannelCount, - mFrameCount, mFlags, getInput()); - if (result == NO_ERROR) { - cblk = mCblk; - mAudioRecord->start(); - } + cblk->flags |= CBLK_INVALID_MSK; +create_new_record: + result = AudioRecord::restoreRecord_l(cblk); + } + if (result != NO_ERROR) { + LOGW("obtainBuffer create Track error %d", result); + cblk->lock.unlock(); + return result; } - cblk->lock.lock(); cblk->waitTimeMs = 0; } if (--waitCount == 0) { @@ -540,12 +570,19 @@ status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) void AudioRecord::releaseBuffer(Buffer* audioBuffer) { - audio_track_cblk_t* cblk = mCblk; - cblk->stepUser(audioBuffer->frameCount); + AutoMutex lock(mLock); + mCblk->stepUser(audioBuffer->frameCount); } audio_io_handle_t AudioRecord::getInput() { + AutoMutex lock(mLock); + return getInput_l(); +} + +// must be called with mLock held +audio_io_handle_t AudioRecord::getInput_l() +{ mInput = AudioSystem::getInput(mInputSource, mCblk->sampleRate, mFormat, mChannels, @@ -573,6 +610,12 @@ ssize_t AudioRecord::read(void* buffer, size_t userSize) return BAD_VALUE; } + mLock.lock(); + // acquire a strong reference on the IAudioRecord and IMemory so that they cannot be destroyed + // while we are accessing the cblk + sp <IAudioRecord> audioRecord = mAudioRecord; + sp <IMemory> iMem = mCblkMemory; + mLock.unlock(); do { @@ -613,9 +656,17 @@ bool AudioRecord::processAudioBuffer(const sp<ClientRecordThread>& thread) uint32_t frames = mRemainingFrames; size_t readSize; + mLock.lock(); + // acquire a strong reference on the IAudioRecord and IMemory so that they cannot be destroyed + // while we are accessing the cblk + sp <IAudioRecord> audioRecord = mAudioRecord; + sp <IMemory> iMem = mCblkMemory; + audio_track_cblk_t* cblk = mCblk; + mLock.unlock(); + // Manage marker callback if (!mMarkerReached && (mMarkerPosition > 0)) { - if (mCblk->user >= mMarkerPosition) { + if (cblk->user >= mMarkerPosition) { mCbf(EVENT_MARKER, mUserData, (void *)&mMarkerPosition); mMarkerReached = true; } @@ -623,7 +674,7 @@ bool AudioRecord::processAudioBuffer(const sp<ClientRecordThread>& thread) // Manage new position callback if (mUpdatePeriod > 0) { - while (mCblk->user >= mNewPosition) { + while (cblk->user >= mNewPosition) { mCbf(EVENT_NEW_POS, mUserData, (void *)&mNewPosition); mNewPosition += mUpdatePeriod; } @@ -669,11 +720,11 @@ bool AudioRecord::processAudioBuffer(const sp<ClientRecordThread>& thread) // Manage overrun callback - if (mActive && (mCblk->framesAvailable_l() == 0)) { - LOGV("Overrun user: %x, server: %x, flags %04x", mCblk->user, mCblk->server, mCblk->flags); - if ((mCblk->flags & CBLK_UNDERRUN_MSK) == CBLK_UNDERRUN_OFF) { + if (mActive && (cblk->framesAvailable() == 0)) { + LOGV("Overrun user: %x, server: %x, flags %04x", cblk->user, cblk->server, cblk->flags); + if ((cblk->flags & CBLK_UNDERRUN_MSK) == CBLK_UNDERRUN_OFF) { mCbf(EVENT_OVERRUN, mUserData, 0); - mCblk->flags |= CBLK_UNDERRUN_ON; + cblk->flags |= CBLK_UNDERRUN_ON; } } @@ -685,6 +736,69 @@ bool AudioRecord::processAudioBuffer(const sp<ClientRecordThread>& thread) return true; } +// must be called with mLock and cblk.lock held. Callers must also hold strong references on +// the IAudioRecord and IMemory in case they are recreated here. +// If the IAudioRecord is successfully restored, the cblk pointer is updated +status_t AudioRecord::restoreRecord_l(audio_track_cblk_t*& cblk) +{ + status_t result; + + if (!(cblk->flags & CBLK_RESTORING_MSK)) { + LOGW("dead IAudioRecord, creating a new one"); + + cblk->flags |= CBLK_RESTORING_ON; + // signal old cblk condition so that other threads waiting for available buffers stop + // waiting now + cblk->cv.broadcast(); + cblk->lock.unlock(); + + // if the new IAudioRecord is created, openRecord_l() will modify the + // following member variables: mAudioRecord, mCblkMemory and mCblk. + // It will also delete the strong references on previous IAudioRecord and IMemory + result = openRecord_l(cblk->sampleRate, mFormat, mChannelCount, + mFrameCount, mFlags, getInput_l()); + if (result == NO_ERROR) { + result = mAudioRecord->start(); + } + if (result != NO_ERROR) { + mActive = false; + } + + // signal old cblk condition for other threads waiting for restore completion + cblk->lock.lock(); + cblk->flags |= CBLK_RESTORED_MSK; + cblk->cv.broadcast(); + cblk->lock.unlock(); + } else { + if (!(cblk->flags & CBLK_RESTORED_MSK)) { + LOGW("dead IAudioRecord, waiting for a new one to be created"); + mLock.unlock(); + result = cblk->cv.waitRelative(cblk->lock, milliseconds(RESTORE_TIMEOUT_MS)); + cblk->lock.unlock(); + mLock.lock(); + } else { + LOGW("dead IAudioRecord, already restored"); + result = NO_ERROR; + cblk->lock.unlock(); + } + if (result != NO_ERROR || mActive == 0) { + result = status_t(STOPPED); + } + } + LOGV("restoreRecord_l() status %d mActive %d cblk %p, old cblk %p flags %08x old flags %08x", + result, mActive, mCblk, cblk, mCblk->flags, cblk->flags); + + if (result == NO_ERROR) { + // from now on we switch to the newly created cblk + cblk = mCblk; + } + cblk->lock.lock(); + + LOGW_IF(result != NO_ERROR, "restoreRecord_l() error %d", result); + + return result; +} + // ========================================================================= AudioRecord::ClientRecordThread::ClientRecordThread(AudioRecord& receiver, bool bCanCallJava) diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index c1bed59..8d8f67b 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -148,6 +148,7 @@ status_t AudioTrack::set( LOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(), sharedBuffer->size()); + AutoMutex lock(mLock); if (mAudioTrack != 0) { LOGE("Track already in use"); return INVALID_OPERATION; @@ -211,8 +212,15 @@ status_t AudioTrack::set( mAuxEffectId = 0; // create the IAudioTrack - status_t status = createTrack(streamType, sampleRate, format, channelCount, - frameCount, flags, sharedBuffer, output, true); + status_t status = createTrack_l(streamType, + sampleRate, + format, + channelCount, + frameCount, + flags, + sharedBuffer, + output, + true); if (status != NO_ERROR) { return status; @@ -312,37 +320,38 @@ void AudioTrack::start() } AutoMutex lock(mLock); + // acquire a strong reference on the IMemory and IAudioTrack so that they cannot be destroyed + // while we are accessing the cblk + sp <IAudioTrack> audioTrack = mAudioTrack; + sp <IMemory> iMem = mCblkMemory; + audio_track_cblk_t* cblk = mCblk; + if (mActive == 0) { mActive = 1; - mNewPosition = mCblk->server + mUpdatePeriod; - mCblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS; - mCblk->waitTimeMs = 0; - mCblk->flags &= ~CBLK_DISABLED_ON; + mNewPosition = cblk->server + mUpdatePeriod; + cblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS; + cblk->waitTimeMs = 0; + cblk->flags &= ~CBLK_DISABLED_ON; if (t != 0) { t->run("AudioTrackThread", THREAD_PRIORITY_AUDIO_CLIENT); } else { setpriority(PRIO_PROCESS, 0, THREAD_PRIORITY_AUDIO_CLIENT); } - if (mCblk->flags & CBLK_INVALID_MSK) { - LOGW("start() track %p invalidated, creating a new one", this); - // no need to clear the invalid flag as this cblk will not be used anymore - // force new track creation - status = DEAD_OBJECT; - } else { + LOGV("start %p before lock cblk %p", this, mCblk); + cblk->lock.lock(); + if (!(cblk->flags & CBLK_INVALID_MSK)) { + cblk->lock.unlock(); status = mAudioTrack->start(); - } - if (status == DEAD_OBJECT) { - LOGV("start() dead IAudioTrack: creating a new one"); - status = createTrack(mStreamType, mCblk->sampleRate, mFormat, mChannelCount, - mFrameCount, mFlags, mSharedBuffer, getOutput(), false); - if (status == NO_ERROR) { - status = mAudioTrack->start(); - if (status == NO_ERROR) { - mNewPosition = mCblk->server + mUpdatePeriod; - } + cblk->lock.lock(); + if (status == DEAD_OBJECT) { + cblk->flags |= CBLK_INVALID_MSK; } } + if (cblk->flags & CBLK_INVALID_MSK) { + status = restoreTrack_l(cblk, true); + } + cblk->lock.unlock(); if (status != NO_ERROR) { LOGV("start() failed"); mActive = 0; @@ -375,14 +384,14 @@ void AudioTrack::stop() mAudioTrack->stop(); // Cancel loops (If we are in the middle of a loop, playback // would not stop until loopCount reaches 0). - setLoop(0, 0, 0); + setLoop_l(0, 0, 0); // the playback head position will reset to 0, so if a marker is set, we need // to activate it again mMarkerReached = false; // Force flush if a shared buffer is used otherwise audioflinger // will not stop before end of buffer is reached. if (mSharedBuffer != 0) { - flush(); + flush_l(); } if (t != 0) { t->requestExit(); @@ -403,6 +412,13 @@ bool AudioTrack::stopped() const void AudioTrack::flush() { + AutoMutex lock(mLock); + flush_l(); +} + +// must be called with mLock held +void AudioTrack::flush_l() +{ LOGV("flush"); // clear playback marker and periodic update counter @@ -445,6 +461,7 @@ status_t AudioTrack::setVolume(float left, float right) return BAD_VALUE; } + AutoMutex lock(mLock); mVolume[LEFT] = left; mVolume[RIGHT] = right; @@ -470,6 +487,7 @@ status_t AudioTrack::setAuxEffectSendLevel(float level) if (level > 1.0f) { return BAD_VALUE; } + AutoMutex lock(mLock); mSendLevel = level; @@ -495,17 +513,26 @@ status_t AudioTrack::setSampleRate(int rate) // Resampler implementation limits input sampling rate to 2 x output sampling rate. if (rate <= 0 || rate > afSamplingRate*2 ) return BAD_VALUE; + AutoMutex lock(mLock); mCblk->sampleRate = rate; return NO_ERROR; } uint32_t AudioTrack::getSampleRate() { + AutoMutex lock(mLock); return mCblk->sampleRate; } status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount) { + AutoMutex lock(mLock); + return setLoop_l(loopStart, loopEnd, loopCount); +} + +// must be called with mLock held +status_t AudioTrack::setLoop_l(uint32_t loopStart, uint32_t loopEnd, int loopCount) +{ audio_track_cblk_t* cblk = mCblk; Mutex::Autolock _l(cblk->lock); @@ -540,6 +567,7 @@ status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount status_t AudioTrack::getLoop(uint32_t *loopStart, uint32_t *loopEnd, int *loopCount) { + AutoMutex lock(mLock); if (loopStart != 0) { *loopStart = mCblk->loopStart; } @@ -599,6 +627,7 @@ 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; @@ -614,7 +643,7 @@ status_t AudioTrack::setPosition(uint32_t position) status_t AudioTrack::getPosition(uint32_t *position) { if (position == 0) return BAD_VALUE; - + AutoMutex lock(mLock); *position = mCblk->server; return NO_ERROR; @@ -622,9 +651,11 @@ status_t AudioTrack::getPosition(uint32_t *position) status_t AudioTrack::reload() { + AutoMutex lock(mLock); + if (!stopped()) return INVALID_OPERATION; - flush(); + flush_l(); mCblk->stepUser(mCblk->frameCount); @@ -633,6 +664,13 @@ status_t AudioTrack::reload() audio_io_handle_t AudioTrack::getOutput() { + AutoMutex lock(mLock); + return getOutput_l(); +} + +// must be called with mLock held +audio_io_handle_t AudioTrack::getOutput_l() +{ return AudioSystem::getOutput((AudioSystem::stream_type)mStreamType, mCblk->sampleRate, mFormat, mChannels, (AudioSystem::output_flags)mFlags); } @@ -654,7 +692,8 @@ status_t AudioTrack::attachAuxEffect(int effectId) // ------------------------------------------------------------------------- -status_t AudioTrack::createTrack( +// must be called with mLock held +status_t AudioTrack::createTrack_l( int streamType, uint32_t sampleRate, int format, @@ -774,6 +813,7 @@ status_t AudioTrack::createTrack( status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) { + AutoMutex lock(mLock); int active; status_t result; audio_track_cblk_t* cblk = mCblk; @@ -800,12 +840,17 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) return WOULD_BLOCK; } if (!(cblk->flags & CBLK_INVALID_MSK)) { + mLock.unlock(); result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs)); + cblk->lock.unlock(); + mLock.lock(); + if (mActive == 0) { + return status_t(STOPPED); + } + cblk->lock.lock(); } + if (cblk->flags & CBLK_INVALID_MSK) { - LOGW("obtainBuffer() track %p invalidated, creating a new one", this); - // no need to clear the invalid flag as this cblk will not be used anymore - cblk->lock.unlock(); goto create_new_track; } if (__builtin_expect(result!=NO_ERROR, false)) { @@ -819,18 +864,17 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) //unlock cblk mutex before calling mAudioTrack->start() (see issue #1617140) cblk->lock.unlock(); result = mAudioTrack->start(); + cblk->lock.lock(); if (result == DEAD_OBJECT) { - LOGW("obtainBuffer() dead IAudioTrack: creating a new one"); + cblk->flags |= CBLK_INVALID_MSK; create_new_track: - result = createTrack(mStreamType, cblk->sampleRate, mFormat, mChannelCount, - mFrameCount, mFlags, mSharedBuffer, getOutput(), false); - if (result == NO_ERROR) { - cblk = mCblk; - cblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS; - mAudioTrack->start(); - } + result = restoreTrack_l(cblk, false); + } + if (result != NO_ERROR) { + LOGW("obtainBuffer create Track error %d", result); + cblk->lock.unlock(); + return result; } - cblk->lock.lock(); } cblk->waitTimeMs = 0; } @@ -848,7 +892,7 @@ create_new_track: } // restart track if it was disabled by audioflinger due to previous underrun - if (cblk->flags & CBLK_DISABLED_MSK) { + if (mActive && (cblk->flags & CBLK_DISABLED_MSK)) { cblk->flags &= ~CBLK_DISABLED_ON; LOGW("obtainBuffer() track %p disabled, restarting", this); mAudioTrack->start(); @@ -883,8 +927,8 @@ create_new_track: void AudioTrack::releaseBuffer(Buffer* audioBuffer) { - audio_track_cblk_t* cblk = mCblk; - cblk->stepUser(audioBuffer->frameCount); + AutoMutex lock(mLock); + mCblk->stepUser(audioBuffer->frameCount); } // ------------------------------------------------------------------------- @@ -903,6 +947,13 @@ ssize_t AudioTrack::write(const void* buffer, size_t userSize) LOGV("write %p: %d bytes, mActive=%d", this, userSize, mActive); + // acquire a strong reference on the IMemory and IAudioTrack so that they cannot be destroyed + // while we are accessing the cblk + mLock.lock(); + sp <IAudioTrack> audioTrack = mAudioTrack; + sp <IMemory> iMem = mCblkMemory; + mLock.unlock(); + ssize_t written = 0; const int8_t *src = (const int8_t *)buffer; Buffer audioBuffer; @@ -953,21 +1004,29 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread) uint32_t frames; size_t writtenSize; + mLock.lock(); + // acquire a strong reference on the IMemory and IAudioTrack so that they cannot be destroyed + // while we are accessing the cblk + sp <IAudioTrack> audioTrack = mAudioTrack; + sp <IMemory> iMem = mCblkMemory; + audio_track_cblk_t* cblk = mCblk; + mLock.unlock(); + // Manage underrun callback - if (mActive && (mCblk->framesReady() == 0)) { - LOGV("Underrun user: %x, server: %x, flags %04x", mCblk->user, mCblk->server, mCblk->flags); - if ((mCblk->flags & CBLK_UNDERRUN_MSK) == CBLK_UNDERRUN_OFF) { + if (mActive && (cblk->framesReady() == 0)) { + LOGV("Underrun user: %x, server: %x, flags %04x", cblk->user, cblk->server, cblk->flags); + if ((cblk->flags & CBLK_UNDERRUN_MSK) == CBLK_UNDERRUN_OFF) { mCbf(EVENT_UNDERRUN, mUserData, 0); - if (mCblk->server == mCblk->frameCount) { + if (cblk->server == cblk->frameCount) { mCbf(EVENT_BUFFER_END, mUserData, 0); } - mCblk->flags |= CBLK_UNDERRUN_ON; + cblk->flags |= CBLK_UNDERRUN_ON; if (mSharedBuffer != 0) return false; } } // Manage loop end callback - while (mLoopCount > mCblk->loopCount) { + while (mLoopCount > cblk->loopCount) { int loopCount = -1; mLoopCount--; if (mLoopCount >= 0) loopCount = mLoopCount; @@ -977,7 +1036,7 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread) // Manage marker callback if (!mMarkerReached && (mMarkerPosition > 0)) { - if (mCblk->server >= mMarkerPosition) { + if (cblk->server >= mMarkerPosition) { mCbf(EVENT_MARKER, mUserData, (void *)&mMarkerPosition); mMarkerReached = true; } @@ -985,7 +1044,7 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread) // Manage new position callback if (mUpdatePeriod > 0) { - while (mCblk->server >= mNewPosition) { + while (cblk->server >= mNewPosition) { mCbf(EVENT_NEW_POS, mUserData, (void *)&mNewPosition); mNewPosition += mUpdatePeriod; } @@ -1068,6 +1127,84 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread) return true; } +// must be called with mLock and cblk.lock held. Callers must also hold strong references on +// the IAudioTrack and IMemory in case they are recreated here. +// If the IAudioTrack is successfully restored, the cblk pointer is updated +status_t AudioTrack::restoreTrack_l(audio_track_cblk_t*& cblk, bool fromStart) +{ + status_t result; + + if (!(cblk->flags & CBLK_RESTORING_MSK)) { + LOGW("dead IAudioTrack, creating a new one from %s", + fromStart ? "start()" : "obtainBuffer()"); + + cblk->flags |= CBLK_RESTORING_ON; + // signal old cblk condition so that other threads waiting for available buffers stop + // waiting now + cblk->cv.broadcast(); + cblk->lock.unlock(); + + // if the new IAudioTrack is created, createTrack_l() will modify the + // following member variables: mAudioTrack, mCblkMemory and mCblk. + // It will also delete the strong references on previous IAudioTrack and IMemory + result = createTrack_l(mStreamType, + cblk->sampleRate, + mFormat, + mChannelCount, + mFrameCount, + mFlags, + mSharedBuffer, + getOutput_l(), + false); + + if (result == NO_ERROR) { + if (!fromStart) { + mCblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS; + } + result = mAudioTrack->start(); + if (fromStart && result == NO_ERROR) { + mNewPosition = mCblk->server + mUpdatePeriod; + } + } + if (result != NO_ERROR) { + mActive = false; + } + + // signal old cblk condition for other threads waiting for restore completion + cblk->lock.lock(); + cblk->flags |= CBLK_RESTORED_MSK; + cblk->cv.broadcast(); + cblk->lock.unlock(); + } else { + if (!(cblk->flags & CBLK_RESTORED_MSK)) { + LOGW("dead IAudioTrack, waiting for a new one"); + mLock.unlock(); + result = cblk->cv.waitRelative(cblk->lock, milliseconds(RESTORE_TIMEOUT_MS)); + cblk->lock.unlock(); + mLock.lock(); + } else { + LOGW("dead IAudioTrack, already restored"); + result = NO_ERROR; + cblk->lock.unlock(); + } + if (result != NO_ERROR || mActive == 0) { + result = status_t(STOPPED); + } + } + LOGV("restoreTrack_l() status %d mActive %d cblk %p, old cblk %p flags %08x old flags %08x", + result, mActive, mCblk, cblk, mCblk->flags, cblk->flags); + + if (result == NO_ERROR) { + // from now on we switch to the newly created cblk + cblk = mCblk; + } + cblk->lock.lock(); + + LOGW_IF(result != NO_ERROR, "restoreTrack_l() error %d", result); + + return result; +} + status_t AudioTrack::dump(int fd, const Vector<String16>& args) const { @@ -1197,7 +1334,9 @@ bool audio_track_cblk_t::stepServer(uint32_t frameCount) this->server = s; - cv.signal(); + if (!(flags & CBLK_INVALID_MSK)) { + cv.signal(); + } lock.unlock(); return true; } diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp index 4c744bd..5734c7e 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -45,6 +45,7 @@ #include <surfaceflinger/Surface.h> #include <gui/ISurfaceTexture.h> #include <gui/SurfaceTextureClient.h> +#include <surfaceflinger/ISurfaceComposer.h> #include <media/stagefright/foundation/ALooper.h> #include <media/stagefright/foundation/AMessage.h> @@ -1189,6 +1190,19 @@ void AwesomePlayer::setVideoSource(sp<MediaSource> source) { } status_t AwesomePlayer::initVideoDecoder(uint32_t flags) { + + // Either the application or the DRM system can independently say + // that there must be a hardware-protected path to an external video sink. + // For now we always require a hardware-protected path to external video sink + // if content is DRMed, but eventually this could be optional per DRM agent. + // When the application wants protection, then + // (USE_SURFACE_ALLOC && (mSurface != 0) && + // (mSurface->getFlags() & ISurfaceComposer::eProtectedByApp)) + // will be true, but that part is already handled by SurfaceFlinger. + if (mDecryptHandle != NULL) { + flags |= OMXCodec::kEnableGrallocUsageProtected; + } + LOGV("initVideoDecoder flags=0x%x", flags); mVideoSource = OMXCodec::Create( mClient.interface(), mVideoTrack->getFormat(), false, // createEncoder diff --git a/media/libstagefright/MP3Extractor.cpp b/media/libstagefright/MP3Extractor.cpp index eb4c68d..03ce202 100644 --- a/media/libstagefright/MP3Extractor.cpp +++ b/media/libstagefright/MP3Extractor.cpp @@ -39,10 +39,10 @@ namespace android { // Everything must match except for -// protection, bitrate, padding, private bits, mode extension, +// protection, bitrate, padding, private bits, mode, mode extension, // copyright bit, original bit and emphasis. // Yes ... there are things that must indeed match... -static const uint32_t kMask = 0xfffe0cc0; +static const uint32_t kMask = 0xfffe0c00; // static bool MP3Extractor::get_mp3_frame_size( diff --git a/media/libstagefright/NuHTTPDataSource.cpp b/media/libstagefright/NuHTTPDataSource.cpp index dbbf3b4..b24343f 100644 --- a/media/libstagefright/NuHTTPDataSource.cpp +++ b/media/libstagefright/NuHTTPDataSource.cpp @@ -1,3 +1,19 @@ +/* + * 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. + */ + //#define LOG_NDEBUG 0 #define LOG_TAG "NuHTTPDataSource" #include <utils/Log.h> diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index 4a94e0d..3e26a95 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -528,6 +528,12 @@ status_t OMXCodec::configureCodec(const sp<MetaData> &meta, uint32_t flags) { mOnlySubmitOneBufferAtOneTime = true; } + mEnableGrallocUsageProtected = false; + if (flags & kEnableGrallocUsageProtected) { + mEnableGrallocUsageProtected = true; + } + LOGV("configureCodec protected=%d", mEnableGrallocUsageProtected); + if (!(flags & kIgnoreCodecSpecificData)) { uint32_t type; const void *data; @@ -1751,7 +1757,11 @@ status_t OMXCodec::allocateOutputBuffersFromNativeWindow() { // XXX: Currently this error is logged, but not fatal. usage = 0; } + if (mEnableGrallocUsageProtected) { + usage |= GRALLOC_USAGE_PROTECTED; + } + LOGV("native_window_set_usage usage=0x%x", usage); err = native_window_set_usage( mNativeWindow.get(), usage | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP); if (err != 0) { diff --git a/media/libstagefright/codecs/aacenc/AACEncoder.cpp b/media/libstagefright/codecs/aacenc/AACEncoder.cpp index a8b1292..e4ff128 100644 --- a/media/libstagefright/codecs/aacenc/AACEncoder.cpp +++ b/media/libstagefright/codecs/aacenc/AACEncoder.cpp @@ -189,6 +189,9 @@ status_t AACEncoder::stop() { delete mApiHandle; mApiHandle = NULL; + delete mMemOperator; + mMemOperator = NULL; + mStarted = false; return OK; diff --git a/media/libstagefright/include/NuHTTPDataSource.h b/media/libstagefright/include/NuHTTPDataSource.h index 082b589..2569568 100644 --- a/media/libstagefright/include/NuHTTPDataSource.h +++ b/media/libstagefright/include/NuHTTPDataSource.h @@ -1,3 +1,19 @@ +/* + * 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. + */ + #ifndef NU_HTTP_DATA_SOURCE_H_ #define NU_HTTP_DATA_SOURCE_H_ diff --git a/media/tests/CameraBrowser/Android.mk b/media/tests/CameraBrowser/Android.mk index 1d81129..46596a7 100644 --- a/media/tests/CameraBrowser/Android.mk +++ b/media/tests/CameraBrowser/Android.mk @@ -7,4 +7,6 @@ LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := CameraBrowser +LOCAL_SDK_VERSION := current + include $(BUILD_PACKAGE) diff --git a/media/tests/CameraBrowser/src/com/android/camerabrowser/CameraBrowser.java b/media/tests/CameraBrowser/src/com/android/camerabrowser/CameraBrowser.java index f642d93..af17ded 100644 --- a/media/tests/CameraBrowser/src/com/android/camerabrowser/CameraBrowser.java +++ b/media/tests/CameraBrowser/src/com/android/camerabrowser/CameraBrowser.java @@ -20,7 +20,6 @@ import android.app.ListActivity; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; -import android.mtp.MtpClient; import android.mtp.MtpDevice; import android.mtp.MtpDeviceInfo; import android.os.Bundle; @@ -79,8 +78,8 @@ public class CameraBrowser extends ListActivity implements MtpClient.Listener { view = (TwoLineListItem)convertView; } - TextView textView1 = (TextView)view.findViewById(com.android.internal.R.id.text1); - TextView textView2 = (TextView)view.findViewById(com.android.internal.R.id.text2); + TextView textView1 = (TextView)view.findViewById(android.R.id.text1); + TextView textView2 = (TextView)view.findViewById(android.R.id.text2); MtpDevice device = mDeviceList.get(position); MtpDeviceInfo info = device.getDeviceInfo(); if (info != null) { diff --git a/media/tests/CameraBrowser/src/com/android/camerabrowser/CameraBrowserApplication.java b/media/tests/CameraBrowser/src/com/android/camerabrowser/CameraBrowserApplication.java index 6f1edfea..8075862 100644 --- a/media/tests/CameraBrowser/src/com/android/camerabrowser/CameraBrowserApplication.java +++ b/media/tests/CameraBrowser/src/com/android/camerabrowser/CameraBrowserApplication.java @@ -17,8 +17,6 @@ package com.android.camerabrowser; import android.app.Application; -import android.mtp.MtpClient; - public class CameraBrowserApplication extends Application { diff --git a/media/java/android/mtp/MtpClient.java b/media/tests/CameraBrowser/src/com/android/camerabrowser/MtpClient.java index c4ee19e..edb5e37 100644 --- a/media/java/android/mtp/MtpClient.java +++ b/media/tests/CameraBrowser/src/com/android/camerabrowser/MtpClient.java @@ -14,21 +14,28 @@ * limitations under the License. */ -package android.mtp; +package com.android.camerabrowser; +import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.hardware.usb.UsbConstants; import android.hardware.usb.UsbDevice; +import android.hardware.usb.UsbDeviceConnection; import android.hardware.usb.UsbInterface; import android.hardware.usb.UsbManager; +import android.mtp.MtpDevice; +import android.mtp.MtpDeviceInfo; +import android.mtp.MtpObjectInfo; +import android.mtp.MtpStorageInfo; import android.os.ParcelFileDescriptor; import android.util.Log; import java.io.IOException; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; /** @@ -40,34 +47,58 @@ public class MtpClient { private static final String TAG = "MtpClient"; + private static final String ACTION_USB_PERMISSION = + "android.mtp.MtpClient.action.USB_PERMISSION"; + private final Context mContext; private final UsbManager mUsbManager; private final ArrayList<Listener> mListeners = new ArrayList<Listener>(); - private final ArrayList<MtpDevice> mDeviceList = new ArrayList<MtpDevice>(); + // mDevices contains all MtpDevices that have been seen by our client, + // so we can inform when the device has been detached. + // mDevices is also used for synchronization in this class. + private final HashMap<String, MtpDevice> mDevices = new HashMap<String, MtpDevice>(); + + private final PendingIntent mPermissionIntent; private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); UsbDevice usbDevice = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); String deviceName = usbDevice.getDeviceName(); - synchronized (mDeviceList) { - MtpDevice mtpDevice = getDeviceLocked(deviceName); + synchronized (mDevices) { + MtpDevice mtpDevice = mDevices.get(deviceName); - if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(intent.getAction())) { + if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) { if (mtpDevice == null) { - mtpDevice = openDevice(usbDevice); + mtpDevice = openDeviceLocked(usbDevice); } if (mtpDevice != null) { - mDeviceList.add(mtpDevice); for (Listener listener : mListeners) { listener.deviceAdded(mtpDevice); } } - } else if (mtpDevice != null) { - mDeviceList.remove(mtpDevice); - for (Listener listener : mListeners) { - listener.deviceRemoved(mtpDevice); + } else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) { + if (mtpDevice != null) { + mDevices.remove(deviceName); + for (Listener listener : mListeners) { + listener.deviceRemoved(mtpDevice); + } + } + } else if (ACTION_USB_PERMISSION.equals(action)) { + boolean permission = intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, + false); + Log.d(TAG, "ACTION_USB_PERMISSION: " + permission); + if (permission) { + if (mtpDevice == null) { + mtpDevice = openDeviceLocked(usbDevice); + } + if (mtpDevice != null) { + for (Listener listener : mListeners) { + listener.deviceAdded(mtpDevice); + } + } } } } @@ -122,21 +153,12 @@ public class MtpClient { public MtpClient(Context context) { mContext = context; mUsbManager = (UsbManager)context.getSystemService(Context.USB_SERVICE); - + mPermissionIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ACTION_USB_PERMISSION), 0); IntentFilter filter = new IntentFilter(); filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED); filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED); + filter.addAction(ACTION_USB_PERMISSION); context.registerReceiver(mUsbReceiver, filter); - - for (UsbDevice usbDevice : mUsbManager.getDeviceList().values()) { - MtpDevice mtpDevice = getDeviceLocked(usbDevice.getDeviceName()); - if (mtpDevice == null) { - mtpDevice = openDevice(usbDevice); - } - if (mtpDevice != null) { - mDeviceList.add(mtpDevice); - } - } } /** @@ -146,11 +168,19 @@ public class MtpClient { * @param device the device to open * @return an MtpDevice for the device. */ - private MtpDevice openDevice(UsbDevice usbDevice) { + private MtpDevice openDeviceLocked(UsbDevice usbDevice) { if (isCamera(usbDevice)) { - MtpDevice mtpDevice = new MtpDevice(usbDevice); - if (mtpDevice.open(mUsbManager)) { - return mtpDevice; + if (!mUsbManager.hasPermission(usbDevice)) { + mUsbManager.requestPermission(usbDevice, mPermissionIntent); + } else { + UsbDeviceConnection connection = mUsbManager.openDevice(usbDevice); + if (connection != null) { + MtpDevice mtpDevice = new MtpDevice(usbDevice); + if (mtpDevice.open(connection)) { + mDevices.put(usbDevice.getDeviceName(), mtpDevice); + return mtpDevice; + } + } } } return null; @@ -170,7 +200,7 @@ public class MtpClient { * @param listener the listener to register */ public void addListener(Listener listener) { - synchronized (mDeviceList) { + synchronized (mDevices) { if (!mListeners.contains(listener)) { mListeners.add(listener); } @@ -183,7 +213,7 @@ public class MtpClient { * @param listener the listener to unregister */ public void removeListener(Listener listener) { - synchronized (mDeviceList) { + synchronized (mDevices) { mListeners.remove(listener); } } @@ -196,8 +226,8 @@ public class MtpClient { * @return the MtpDevice, or null if it does not exist */ public MtpDevice getDevice(String deviceName) { - synchronized (mDeviceList) { - return getDeviceLocked(deviceName); + synchronized (mDevices) { + return mDevices.get(deviceName); } } @@ -209,18 +239,9 @@ public class MtpClient { * @return the MtpDevice, or null if it does not exist */ public MtpDevice getDevice(int id) { - synchronized (mDeviceList) { - return getDeviceLocked(UsbDevice.getDeviceName(id)); - } - } - - private MtpDevice getDeviceLocked(String deviceName) { - for (MtpDevice device : mDeviceList) { - if (device.getDeviceName().equals(deviceName)) { - return device; - } + synchronized (mDevices) { + return mDevices.get(UsbDevice.getDeviceName(id)); } - return null; } /** @@ -229,8 +250,16 @@ public class MtpClient { * @return the list of MtpDevices */ public List<MtpDevice> getDeviceList() { - synchronized (mDeviceList) { - return new ArrayList<MtpDevice>(mDeviceList); + synchronized (mDevices) { + // Query the USB manager since devices might have attached + // before we added our listener. + for (UsbDevice usbDevice : mUsbManager.getDeviceList().values()) { + if (mDevices.get(usbDevice.getDeviceName()) == null) { + openDeviceLocked(usbDevice); + } + } + + return new ArrayList<MtpDevice>(mDevices.values()); } } diff --git a/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectBrowser.java b/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectBrowser.java index 82251d9..68fed7b 100644 --- a/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectBrowser.java +++ b/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectBrowser.java @@ -22,7 +22,6 @@ import android.content.Intent; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; -import android.mtp.MtpClient; import android.mtp.MtpConstants; import android.mtp.MtpDevice; import android.mtp.MtpObjectInfo; diff --git a/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectViewer.java b/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectViewer.java index e9ea9f3..ef69c44 100644 --- a/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectViewer.java +++ b/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectViewer.java @@ -23,7 +23,6 @@ import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.media.MediaScannerConnection; import android.media.MediaScannerConnection.MediaScannerConnectionClient; -import android.mtp.MtpClient; import android.mtp.MtpConstants; import android.mtp.MtpObjectInfo; import android.net.Uri; diff --git a/media/tests/CameraBrowser/src/com/android/camerabrowser/StorageBrowser.java b/media/tests/CameraBrowser/src/com/android/camerabrowser/StorageBrowser.java index 7d5a5da..64320fe 100644 --- a/media/tests/CameraBrowser/src/com/android/camerabrowser/StorageBrowser.java +++ b/media/tests/CameraBrowser/src/com/android/camerabrowser/StorageBrowser.java @@ -19,7 +19,6 @@ package com.android.camerabrowser; import android.app.ListActivity; import android.content.Context; import android.content.Intent; -import android.mtp.MtpClient; import android.mtp.MtpDevice; import android.mtp.MtpStorageInfo; import android.os.Bundle; |