diff options
Diffstat (limited to 'media/java/android')
-rw-r--r-- | media/java/android/media/AudioDeviceInfo.java | 25 | ||||
-rw-r--r-- | media/java/android/media/AudioManager.java | 26 | ||||
-rwxr-xr-x | media/java/android/media/IAudioService.aidl | 4 | ||||
-rw-r--r-- | media/java/android/media/MediaCodec.java | 31 | ||||
-rw-r--r-- | media/java/android/media/MediaRecorder.java | 7 | ||||
-rw-r--r-- | media/java/android/media/tv/tuner/Lnb.java | 21 | ||||
-rw-r--r-- | media/java/android/media/tv/tuner/Tuner.java | 223 | ||||
-rw-r--r-- | media/java/android/media/tv/tuner/dvr/DvrPlayback.java | 13 | ||||
-rw-r--r-- | media/java/android/media/tv/tuner/dvr/DvrRecorder.java | 13 | ||||
-rw-r--r-- | media/java/android/media/tv/tuner/filter/Filter.java | 23 |
10 files changed, 240 insertions, 146 deletions
diff --git a/media/java/android/media/AudioDeviceInfo.java b/media/java/android/media/AudioDeviceInfo.java index 09b382ee46d0..a186566aec0b 100644 --- a/media/java/android/media/AudioDeviceInfo.java +++ b/media/java/android/media/AudioDeviceInfo.java @@ -25,7 +25,6 @@ import android.util.SparseIntArray; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.TreeSet; @@ -515,29 +514,7 @@ public final class AudioDeviceInfo { * For forward compatibility, applications should ignore entries it does not recognize. */ public @NonNull int[] getEncodings() { - final int[] encodings = AudioFormat.filterPublicFormats(mPort.formats()); - boolean hasFloat = false; - boolean hasExtendedIntegerPrecision = false; - - for (int encoding : encodings) { - if (AudioFormat.isEncodingLinearPcm(encoding)) { - if (encoding == AudioFormat.ENCODING_PCM_FLOAT) { - hasFloat = true; - } else if (AudioFormat.getBytesPerSample(encoding) > 2) { - hasExtendedIntegerPrecision = true; - } - } - } - if (hasExtendedIntegerPrecision && !hasFloat) { - // R and earlier compatibility - add ENCODING_PCM_FLOAT to the end - // (replacing the zero pad). This ensures pre-S apps that look - // for ENCODING_PCM_FLOAT continue to see that encoding if the device supports - // extended precision integers. - int[] encodingsPlusFloat = Arrays.copyOf(encodings, encodings.length + 1); - encodingsPlusFloat[encodings.length] = AudioFormat.ENCODING_PCM_FLOAT; - return encodingsPlusFloat; - } - return encodings; + return AudioFormat.filterPublicFormats(mPort.formats()); } /** diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index cdc1964b7f4f..054a7183e67e 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -7118,14 +7118,11 @@ public class AudioManager { @TestApi @NonNull public Map<Integer, Boolean> getSurroundFormats() { - Map<Integer, Boolean> surroundFormats = new HashMap<>(); - int status = AudioSystem.getSurroundFormats(surroundFormats); - if (status != AudioManager.SUCCESS) { - // fail and bail! - Log.e(TAG, "getSurroundFormats failed:" + status); - return new HashMap<Integer, Boolean>(); // Always return a map. + try { + return getService().getSurroundFormats(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); } - return surroundFormats; } /** @@ -7172,15 +7169,14 @@ public class AudioManager { * * @return a list of surround formats */ - public ArrayList<Integer> getReportedSurroundFormats() { - ArrayList<Integer> reportedSurroundFormats = new ArrayList<>(); - int status = AudioSystem.getReportedSurroundFormats(reportedSurroundFormats); - if (status != AudioManager.SUCCESS) { - // fail and bail! - Log.e(TAG, "getReportedSurroundFormats failed:" + status); - return new ArrayList<Integer>(); // Always return a list. + @TestApi + @NonNull + public List<Integer> getReportedSurroundFormats() { + try { + return getService().getReportedSurroundFormats(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); } - return reportedSurroundFormats; } /** diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index a83b93494e30..268419f8db8f 100755 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -159,6 +159,10 @@ interface IAudioService { oneway void reloadAudioSettings(); + Map getSurroundFormats(); + + List getReportedSurroundFormats(); + boolean setSurroundFormatEnabled(int audioFormat, boolean enabled); boolean isSurroundFormatEnabled(int audioFormat); diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java index cc05ecd3f18e..8b9153621165 100644 --- a/media/java/android/media/MediaCodec.java +++ b/media/java/android/media/MediaCodec.java @@ -72,6 +72,37 @@ import java.util.concurrent.locks.ReentrantLock; Finally, you request (or receive) a filled output buffer, consume its contents and release it back to the codec. + <h3 id=qualityFloor><a name="qualityFloor">Minimum Quality Floor for Video Encoding</h3> + <p> + Beginning with {@link android.os.Build.VERSION_CODES#S}, Android's Video MediaCodecs enforce a + minimum quality floor. The intent is to eliminate poor quality video encodings. This quality + floor is applied when the codec is in Variable Bitrate (VBR) mode; it is not applied when + the codec is in Constant Bitrate (CBR) mode. The quality floor enforcement is also restricted + to a particular size range; this size range is currently for video resolutions + larger than 320x240 up through 1920x1080. + + <p> + When this quality floor is in effect, the codec and supporting framework code will work to + ensure that the generated video is of at least a "fair" or "good" quality. The metric + used to choose these targets is the VMAF (Video Multi-method Assessment Function) with a + target score of 70 for selected test sequences. + + <p> + The typical effect is that + some videos will generate a higher bitrate than originally configured. This will be most + notable for videos which were configured with very low bitrates; the codec will use a bitrate + that is determined to be more likely to generate an "fair" or "good" quality video. Another + situation is where a video includes very complicated content (lots of motion and detail); + in such configurations, the codec will use extra bitrate as needed to avoid losing all of + the content's finer detail. + + <p> + This quality floor will not impact content captured at high bitrates (a high bitrate should + already provide the codec with sufficient capacity to encode all of the detail). + The quality floor does not operate on CBR encodings. + The quality floor currently does not operate on resolutions of 320x240 or lower, nor on + videos with resolution above 1920x1080. + <h3>Data Types</h3> <p> Codecs operate on three kinds of data: compressed data, raw audio data and raw video data. diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java index 5936700ed742..74d55e5eda3f 100644 --- a/media/java/android/media/MediaRecorder.java +++ b/media/java/android/media/MediaRecorder.java @@ -1110,6 +1110,13 @@ public class MediaRecorder implements AudioRouting, * clipped internally to ensure the video recording can proceed smoothly based on * the capabilities of the platform. * + * <p> + * NB: the actual bitrate and other encoding characteristics may be affected by + * the minimum quality floor behavior introduced in + * {@link android.os.Build.VERSION_CODES#S}. More detail on how and where this + * impacts video encoding can be found in the + * {@link MediaCodec} page and looking for "quality floor" (near the top of the page). + * * @param bitRate the video encoding bit rate in bits per second. */ public void setVideoEncodingBitRate(int bitRate) { diff --git a/media/java/android/media/tv/tuner/Lnb.java b/media/java/android/media/tv/tuner/Lnb.java index 59ef4b890320..8b69d33722c5 100644 --- a/media/java/android/media/tv/tuner/Lnb.java +++ b/media/java/android/media/tv/tuner/Lnb.java @@ -148,6 +148,7 @@ public class Lnb implements AutoCloseable { LnbCallback mCallback; Executor mExecutor; Tuner mTuner; + private final Object mCallbackLock = new Object(); private native int nativeSetVoltage(int voltage); @@ -164,20 +165,26 @@ public class Lnb implements AutoCloseable { private Lnb() {} void setCallback(Executor executor, @Nullable LnbCallback callback, Tuner tuner) { - mCallback = callback; - mExecutor = executor; - mTuner = tuner; + synchronized (mCallbackLock) { + mCallback = callback; + mExecutor = executor; + mTuner = tuner; + } } private void onEvent(int eventType) { - if (mExecutor != null && mCallback != null) { - mExecutor.execute(() -> mCallback.onEvent(eventType)); + synchronized (mCallbackLock) { + if (mExecutor != null && mCallback != null) { + mExecutor.execute(() -> mCallback.onEvent(eventType)); + } } } private void onDiseqcMessage(byte[] diseqcMessage) { - if (mExecutor != null && mCallback != null) { - mExecutor.execute(() -> mCallback.onDiseqcMessage(diseqcMessage)); + synchronized (mCallbackLock) { + if (mExecutor != null && mCallback != null) { + mExecutor.execute(() -> mCallback.onDiseqcMessage(diseqcMessage)); + } } } diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java index 2ea745b44288..325436648e63 100644 --- a/media/java/android/media/tv/tuner/Tuner.java +++ b/media/java/android/media/tv/tuner/Tuner.java @@ -291,7 +291,7 @@ public class Tuner implements AutoCloseable { @Nullable private OnTuneEventListener mOnTuneEventListener; @Nullable - private Executor mOnTunerEventExecutor; + private Executor mOnTuneEventExecutor; @Nullable private ScanCallback mScanCallback; @Nullable @@ -301,6 +301,10 @@ public class Tuner implements AutoCloseable { @Nullable private Executor mOnResourceLostListenerExecutor; + private final Object mOnTuneEventLock = new Object(); + private final Object mScanCallbackLock = new Object(); + private final Object mOnResourceLostListenerLock = new Object(); + private Integer mDemuxHandle; private Integer mFrontendCiCamHandle; private Integer mFrontendCiCamId; @@ -398,18 +402,22 @@ public class Tuner implements AutoCloseable { */ public void setResourceLostListener(@NonNull @CallbackExecutor Executor executor, @NonNull OnResourceLostListener listener) { - Objects.requireNonNull(executor, "OnResourceLostListener must not be null"); - Objects.requireNonNull(listener, "executor must not be null"); - mOnResourceLostListener = listener; - mOnResourceLostListenerExecutor = executor; + synchronized (mOnResourceLostListenerLock) { + Objects.requireNonNull(executor, "OnResourceLostListener must not be null"); + Objects.requireNonNull(listener, "executor must not be null"); + mOnResourceLostListener = listener; + mOnResourceLostListenerExecutor = executor; + } } /** * Removes the listener for resource lost. */ public void clearResourceLostListener() { - mOnResourceLostListener = null; - mOnResourceLostListenerExecutor = null; + synchronized (mOnResourceLostListenerLock) { + mOnResourceLostListener = null; + mOnResourceLostListenerExecutor = null; + } } /** @@ -618,10 +626,12 @@ public class Tuner implements AutoCloseable { break; } case MSG_RESOURCE_LOST: { - if (mOnResourceLostListener != null + synchronized (mOnResourceLostListenerLock) { + if (mOnResourceLostListener != null && mOnResourceLostListenerExecutor != null) { - mOnResourceLostListenerExecutor.execute( - () -> mOnResourceLostListener.onResourceLost(Tuner.this)); + mOnResourceLostListenerExecutor.execute( + () -> mOnResourceLostListener.onResourceLost(Tuner.this)); + } } break; } @@ -652,8 +662,10 @@ public class Tuner implements AutoCloseable { */ public void setOnTuneEventListener(@NonNull @CallbackExecutor Executor executor, @NonNull OnTuneEventListener eventListener) { - mOnTuneEventListener = eventListener; - mOnTunerEventExecutor = executor; + synchronized (mOnTuneEventLock) { + mOnTuneEventListener = eventListener; + mOnTuneEventExecutor = executor; + } } /** @@ -663,9 +675,10 @@ public class Tuner implements AutoCloseable { * @see #setOnTuneEventListener(Executor, OnTuneEventListener) */ public void clearOnTuneEventListener() { - mOnTuneEventListener = null; - mOnTunerEventExecutor = null; - + synchronized (mOnTuneEventLock) { + mOnTuneEventListener = null; + mOnTuneEventExecutor = null; + } } /** @@ -747,32 +760,34 @@ public class Tuner implements AutoCloseable { @Result public int scan(@NonNull FrontendSettings settings, @ScanType int scanType, @NonNull @CallbackExecutor Executor executor, @NonNull ScanCallback scanCallback) { - /** - * Scan can be called again for blink scan if scanCallback and executor are same as before. - */ - if (((mScanCallback != null) && (mScanCallback != scanCallback)) + synchronized (mScanCallbackLock) { + // Scan can be called again for blink scan if scanCallback and executor are same as + //before. + if (((mScanCallback != null) && (mScanCallback != scanCallback)) || ((mScanCallbackExecutor != null) && (mScanCallbackExecutor != executor))) { - throw new IllegalStateException( + throw new IllegalStateException( "Different Scan session already in progress. stopScan must be called " + "before a new scan session can be " + "started."); - } - mFrontendType = settings.getType(); - if (mFrontendType == FrontendSettings.TYPE_DTMB) { - if (!TunerVersionChecker.checkHigherOrEqualVersionTo( - TunerVersionChecker.TUNER_VERSION_1_1, "Scan with DTMB Frontend")) { - return RESULT_UNAVAILABLE; } - } - if (checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND)) { - mScanCallback = scanCallback; - mScanCallbackExecutor = executor; - mFrontendInfo = null; - FrameworkStatsLog + mFrontendType = settings.getType(); + if (mFrontendType == FrontendSettings.TYPE_DTMB) { + if (!TunerVersionChecker.checkHigherOrEqualVersionTo( + TunerVersionChecker.TUNER_VERSION_1_1, + "Scan with DTMB Frontend")) { + return RESULT_UNAVAILABLE; + } + } + if (checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND)) { + mScanCallback = scanCallback; + mScanCallbackExecutor = executor; + mFrontendInfo = null; + FrameworkStatsLog .write(FrameworkStatsLog.TV_TUNER_STATE_CHANGED, mUserId, FrameworkStatsLog.TV_TUNER_STATE_CHANGED__STATE__SCANNING); - return nativeScan(settings.getType(), settings, scanType); + return nativeScan(settings.getType(), settings, scanType); + } + return RESULT_UNAVAILABLE; } - return RESULT_UNAVAILABLE; } /** @@ -788,14 +803,15 @@ public class Tuner implements AutoCloseable { */ @Result public int cancelScanning() { - FrameworkStatsLog - .write(FrameworkStatsLog.TV_TUNER_STATE_CHANGED, mUserId, + synchronized (mScanCallbackLock) { + FrameworkStatsLog.write(FrameworkStatsLog.TV_TUNER_STATE_CHANGED, mUserId, FrameworkStatsLog.TV_TUNER_STATE_CHANGED__STATE__SCAN_STOPPED); - int retVal = nativeStopScan(); - mScanCallback = null; - mScanCallbackExecutor = null; - return retVal; + int retVal = nativeStopScan(); + mScanCallback = null; + mScanCallbackExecutor = null; + return retVal; + } } private boolean requestFrontend() { @@ -1050,8 +1066,10 @@ public class Tuner implements AutoCloseable { private void onFrontendEvent(int eventType) { Log.d(TAG, "Got event from tuning. Event type: " + eventType); - if (mOnTunerEventExecutor != null && mOnTuneEventListener != null) { - mOnTunerEventExecutor.execute(() -> mOnTuneEventListener.onTuneEvent(eventType)); + synchronized (mOnTuneEventLock) { + if (mOnTuneEventExecutor != null && mOnTuneEventListener != null) { + mOnTuneEventExecutor.execute(() -> mOnTuneEventListener.onTuneEvent(eventType)); + } } Log.d(TAG, "Wrote Stats Log for the events from tuning."); @@ -1072,114 +1090,149 @@ public class Tuner implements AutoCloseable { private void onLocked() { Log.d(TAG, "Wrote Stats Log for locked event from scanning."); - FrameworkStatsLog - .write(FrameworkStatsLog.TV_TUNER_STATE_CHANGED, mUserId, - FrameworkStatsLog.TV_TUNER_STATE_CHANGED__STATE__LOCKED); + FrameworkStatsLog.write( + FrameworkStatsLog.TV_TUNER_STATE_CHANGED, mUserId, + FrameworkStatsLog.TV_TUNER_STATE_CHANGED__STATE__LOCKED); - if (mScanCallbackExecutor != null && mScanCallback != null) { - mScanCallbackExecutor.execute(() -> mScanCallback.onLocked()); + synchronized (mScanCallbackLock) { + if (mScanCallbackExecutor != null && mScanCallback != null) { + mScanCallbackExecutor.execute(() -> mScanCallback.onLocked()); + } } } private void onScanStopped() { - if (mScanCallbackExecutor != null && mScanCallback != null) { - mScanCallbackExecutor.execute(() -> mScanCallback.onScanStopped()); + synchronized (mScanCallbackLock) { + if (mScanCallbackExecutor != null && mScanCallback != null) { + mScanCallbackExecutor.execute(() -> mScanCallback.onScanStopped()); + } } } private void onProgress(int percent) { - if (mScanCallbackExecutor != null && mScanCallback != null) { - mScanCallbackExecutor.execute(() -> mScanCallback.onProgress(percent)); + synchronized (mScanCallbackLock) { + if (mScanCallbackExecutor != null && mScanCallback != null) { + mScanCallbackExecutor.execute(() -> mScanCallback.onProgress(percent)); + } } } private void onFrequenciesReport(int[] frequency) { - if (mScanCallbackExecutor != null && mScanCallback != null) { - mScanCallbackExecutor.execute(() -> mScanCallback.onFrequenciesReported(frequency)); + synchronized (mScanCallbackLock) { + if (mScanCallbackExecutor != null && mScanCallback != null) { + mScanCallbackExecutor.execute(() -> mScanCallback.onFrequenciesReported(frequency)); + } } } private void onSymbolRates(int[] rate) { - if (mScanCallbackExecutor != null && mScanCallback != null) { - mScanCallbackExecutor.execute(() -> mScanCallback.onSymbolRatesReported(rate)); + synchronized (mScanCallbackLock) { + if (mScanCallbackExecutor != null && mScanCallback != null) { + mScanCallbackExecutor.execute(() -> mScanCallback.onSymbolRatesReported(rate)); + } } } private void onHierarchy(int hierarchy) { - if (mScanCallbackExecutor != null && mScanCallback != null) { - mScanCallbackExecutor.execute(() -> mScanCallback.onHierarchyReported(hierarchy)); + synchronized (mScanCallbackLock) { + if (mScanCallbackExecutor != null && mScanCallback != null) { + mScanCallbackExecutor.execute(() -> mScanCallback.onHierarchyReported(hierarchy)); + } } } private void onSignalType(int signalType) { - if (mScanCallbackExecutor != null && mScanCallback != null) { - mScanCallbackExecutor.execute(() -> mScanCallback.onSignalTypeReported(signalType)); + synchronized (mScanCallbackLock) { + if (mScanCallbackExecutor != null && mScanCallback != null) { + mScanCallbackExecutor.execute(() -> mScanCallback.onSignalTypeReported(signalType)); + } } } private void onPlpIds(int[] plpIds) { - if (mScanCallbackExecutor != null && mScanCallback != null) { - mScanCallbackExecutor.execute(() -> mScanCallback.onPlpIdsReported(plpIds)); + synchronized (mScanCallbackLock) { + if (mScanCallbackExecutor != null && mScanCallback != null) { + mScanCallbackExecutor.execute(() -> mScanCallback.onPlpIdsReported(plpIds)); + } } } private void onGroupIds(int[] groupIds) { - if (mScanCallbackExecutor != null && mScanCallback != null) { - mScanCallbackExecutor.execute(() -> mScanCallback.onGroupIdsReported(groupIds)); + synchronized (mScanCallbackLock) { + if (mScanCallbackExecutor != null && mScanCallback != null) { + mScanCallbackExecutor.execute(() -> mScanCallback.onGroupIdsReported(groupIds)); + } } } private void onInputStreamIds(int[] inputStreamIds) { - if (mScanCallbackExecutor != null && mScanCallback != null) { - mScanCallbackExecutor.execute( - () -> mScanCallback.onInputStreamIdsReported(inputStreamIds)); + synchronized (mScanCallbackLock) { + if (mScanCallbackExecutor != null && mScanCallback != null) { + mScanCallbackExecutor.execute( + () -> mScanCallback.onInputStreamIdsReported(inputStreamIds)); + } } } private void onDvbsStandard(int dvbsStandandard) { - if (mScanCallbackExecutor != null && mScanCallback != null) { - mScanCallbackExecutor.execute( - () -> mScanCallback.onDvbsStandardReported(dvbsStandandard)); + synchronized (mScanCallbackLock) { + if (mScanCallbackExecutor != null && mScanCallback != null) { + mScanCallbackExecutor.execute( + () -> mScanCallback.onDvbsStandardReported(dvbsStandandard)); + } } } private void onDvbtStandard(int dvbtStandard) { - if (mScanCallbackExecutor != null && mScanCallback != null) { - mScanCallbackExecutor.execute(() -> mScanCallback.onDvbtStandardReported(dvbtStandard)); + synchronized (mScanCallbackLock) { + if (mScanCallbackExecutor != null && mScanCallback != null) { + mScanCallbackExecutor.execute( + () -> mScanCallback.onDvbtStandardReported(dvbtStandard)); + } } } private void onAnalogSifStandard(int sif) { - if (mScanCallbackExecutor != null && mScanCallback != null) { - mScanCallbackExecutor.execute(() -> mScanCallback.onAnalogSifStandardReported(sif)); + synchronized (mScanCallbackLock) { + if (mScanCallbackExecutor != null && mScanCallback != null) { + mScanCallbackExecutor.execute(() -> mScanCallback.onAnalogSifStandardReported(sif)); + } } } private void onAtsc3PlpInfos(Atsc3PlpInfo[] atsc3PlpInfos) { - if (mScanCallbackExecutor != null && mScanCallback != null) { - mScanCallbackExecutor.execute( - () -> mScanCallback.onAtsc3PlpInfosReported(atsc3PlpInfos)); + synchronized (mScanCallbackLock) { + if (mScanCallbackExecutor != null && mScanCallback != null) { + mScanCallbackExecutor.execute( + () -> mScanCallback.onAtsc3PlpInfosReported(atsc3PlpInfos)); + } } } private void onModulationReported(int modulation) { - if (mScanCallbackExecutor != null && mScanCallback != null) { - mScanCallbackExecutor.execute( - () -> mScanCallback.onModulationReported(modulation)); + synchronized (mScanCallbackLock) { + if (mScanCallbackExecutor != null && mScanCallback != null) { + mScanCallbackExecutor.execute( + () -> mScanCallback.onModulationReported(modulation)); + } } } private void onPriorityReported(boolean isHighPriority) { - if (mScanCallbackExecutor != null && mScanCallback != null) { - mScanCallbackExecutor.execute( - () -> mScanCallback.onPriorityReported(isHighPriority)); + synchronized (mScanCallbackLock) { + if (mScanCallbackExecutor != null && mScanCallback != null) { + mScanCallbackExecutor.execute( + () -> mScanCallback.onPriorityReported(isHighPriority)); + } } } private void onDvbcAnnexReported(int dvbcAnnex) { - if (mScanCallbackExecutor != null && mScanCallback != null) { - mScanCallbackExecutor.execute( - () -> mScanCallback.onDvbcAnnexReported(dvbcAnnex)); + synchronized (mScanCallbackLock) { + if (mScanCallbackExecutor != null && mScanCallback != null) { + mScanCallbackExecutor.execute( + () -> mScanCallback.onDvbcAnnexReported(dvbcAnnex)); + } } } diff --git a/media/java/android/media/tv/tuner/dvr/DvrPlayback.java b/media/java/android/media/tv/tuner/dvr/DvrPlayback.java index d70b8c29622e..1f805d761d49 100644 --- a/media/java/android/media/tv/tuner/dvr/DvrPlayback.java +++ b/media/java/android/media/tv/tuner/dvr/DvrPlayback.java @@ -85,6 +85,7 @@ public class DvrPlayback implements AutoCloseable { private static int sInstantId = 0; private int mSegmentId = 0; private int mUnderflow; + private final Object mListenerLock = new Object(); private native int nativeAttachFilter(Filter filter); private native int nativeDetachFilter(Filter filter); @@ -106,16 +107,20 @@ public class DvrPlayback implements AutoCloseable { /** @hide */ public void setListener( @NonNull Executor executor, @NonNull OnPlaybackStatusChangedListener listener) { - mExecutor = executor; - mListener = listener; + synchronized (mListenerLock) { + mExecutor = executor; + mListener = listener; + } } private void onPlaybackStatusChanged(int status) { if (status == PLAYBACK_STATUS_EMPTY) { mUnderflow++; } - if (mExecutor != null && mListener != null) { - mExecutor.execute(() -> mListener.onPlaybackStatusChanged(status)); + synchronized (mListenerLock) { + if (mExecutor != null && mListener != null) { + mExecutor.execute(() -> mListener.onPlaybackStatusChanged(status)); + } } } diff --git a/media/java/android/media/tv/tuner/dvr/DvrRecorder.java b/media/java/android/media/tv/tuner/dvr/DvrRecorder.java index 0f9f2e7f89a1..2b694668eb03 100644 --- a/media/java/android/media/tv/tuner/dvr/DvrRecorder.java +++ b/media/java/android/media/tv/tuner/dvr/DvrRecorder.java @@ -48,6 +48,7 @@ public class DvrRecorder implements AutoCloseable { private int mSegmentId = 0; private int mOverflow; private Boolean mIsStopped = true; + private final Object mListenerLock = new Object(); private native int nativeAttachFilter(Filter filter); private native int nativeDetachFilter(Filter filter); @@ -69,16 +70,20 @@ public class DvrRecorder implements AutoCloseable { /** @hide */ public void setListener( @NonNull Executor executor, @NonNull OnRecordStatusChangedListener listener) { - mExecutor = executor; - mListener = listener; + synchronized (mListenerLock) { + mExecutor = executor; + mListener = listener; + } } private void onRecordStatusChanged(int status) { if (status == Filter.STATUS_OVERFLOW) { mOverflow++; } - if (mExecutor != null && mListener != null) { - mExecutor.execute(() -> mListener.onRecordStatusChanged(status)); + synchronized (mListenerLock) { + if (mExecutor != null && mListener != null) { + mExecutor.execute(() -> mListener.onRecordStatusChanged(status)); + } } } diff --git a/media/java/android/media/tv/tuner/filter/Filter.java b/media/java/android/media/tv/tuner/filter/Filter.java index 2f3e2d8d5dd9..33742ffd99bf 100644 --- a/media/java/android/media/tv/tuner/filter/Filter.java +++ b/media/java/android/media/tv/tuner/filter/Filter.java @@ -227,6 +227,7 @@ public class Filter implements AutoCloseable { private long mNativeContext; private FilterCallback mCallback; private Executor mExecutor; + private final Object mCallbackLock = new Object(); private final long mId; private int mMainType; private int mSubtype; @@ -253,14 +254,18 @@ public class Filter implements AutoCloseable { } private void onFilterStatus(int status) { - if (mCallback != null && mExecutor != null) { - mExecutor.execute(() -> mCallback.onFilterStatusChanged(this, status)); + synchronized (mCallbackLock) { + if (mCallback != null && mExecutor != null) { + mExecutor.execute(() -> mCallback.onFilterStatusChanged(this, status)); + } } } private void onFilterEvent(FilterEvent[] events) { - if (mCallback != null && mExecutor != null) { - mExecutor.execute(() -> mCallback.onFilterEvent(this, events)); + synchronized (mCallbackLock) { + if (mCallback != null && mExecutor != null) { + mExecutor.execute(() -> mCallback.onFilterEvent(this, events)); + } } } @@ -272,13 +277,17 @@ public class Filter implements AutoCloseable { /** @hide */ public void setCallback(FilterCallback cb, Executor executor) { - mCallback = cb; - mExecutor = executor; + synchronized (mCallbackLock) { + mCallback = cb; + mExecutor = executor; + } } /** @hide */ public FilterCallback getCallback() { - return mCallback; + synchronized (mCallbackLock) { + return mCallback; + } } /** |