summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-04-21 19:56:55 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-04-21 19:56:55 +0000
commitddd0cff3eb5acdc581c8f6f5b36b1bf8b90c8bed (patch)
tree77daebc4c4c41dae651a3425504a52dd1ccc21b1
parentcad0938b23a933110df171fb7c9f96721f606cd2 (diff)
parent1879ee137ede0d62b88cd16da3d46138ca540dfa (diff)
downloadImsMedia-ddd0cff3eb5acdc581c8f6f5b36b1bf8b90c8bed.tar.gz
Snap for 9989322 from 1879ee137ede0d62b88cd16da3d46138ca540dfa to mainline-rkpd-release
Change-Id: I35046c7ba53f650c5d42314f226f1df5b7cd8dc1
-rw-r--r--framework/src/android/telephony/imsmedia/AudioSessionCallback.java13
-rw-r--r--framework/src/android/telephony/imsmedia/IImsVideoSessionCallback.aidl2
-rw-r--r--framework/src/android/telephony/imsmedia/MediaQualityThreshold.java26
-rw-r--r--framework/src/android/telephony/imsmedia/VideoSessionCallback.java11
-rw-r--r--service/src/com/android/telephony/imsmedia/AudioSession.java11
-rw-r--r--service/src/com/android/telephony/imsmedia/TextSession.java4
-rw-r--r--service/src/com/android/telephony/imsmedia/Utils.java1
-rw-r--r--service/src/com/android/telephony/imsmedia/VideoListener.java2
-rw-r--r--service/src/com/android/telephony/imsmedia/VideoSession.java14
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/Android.bp5
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/include/MediaQualityThreshold.h9
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/include/RtcpConfig.h2
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/src/MediaQualityThreshold.cpp22
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/BaseJitterBuffer.cpp9
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/JitterNetworkAnalyser.cpp8
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/StreamScheduler.cpp60
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioJitterBuffer.cpp130
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioManager.cpp116
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioSession.cpp8
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtcp.cpp20
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtpRx.cpp2
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtpTx.cpp2
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/MediaQualityAnalyzer.cpp145
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/android/ImsMediaAudioPlayer.cpp25
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/android/ImsMediaAudioSource.cpp12
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/android/include/ImsMediaAudioPlayer.h19
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/android/include/ImsMediaAudioSource.h17
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/AudioRtpPayloadDecoderNode.cpp42
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/AudioRtpPayloadEncoderNode.cpp61
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/IAudioPlayerNode.cpp31
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/IAudioSourceNode.cpp13
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/ImsMediaDefine.h4
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/JitterNetworkAnalyser.h2
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/StreamScheduler.h1
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioJitterBuffer.h4
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioManager.h22
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioStreamGraphRtcp.h1
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/MediaQualityAnalyzer.h4
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/nodes/AudioRtpPayloadDecoderNode.h4
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/nodes/AudioRtpPayloadEncoderNode.h2
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/nodes/IAudioPlayerNode.h3
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/nodes/IAudioSourceNode.h2
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/nodes/BaseNode.h20
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/nodes/RtcpEncoderNode.h2
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/nodes/RtpEncoderNode.h1
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/text/TextManager.h8
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/text/TextStreamGraphRtcp.h1
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/text/nodes/TextSourceNode.h5
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/utils/ImsMediaBitWriter.h6
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/utils/ImsMediaEventHandler.h4
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/utils/ImsMediaImageRotate.h38
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/VideoManager.h8
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/VideoStreamGraphRtcp.h1
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/VideoStreamGraphRtpTx.h1
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/android/ImsMediaCamera.h2
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/android/ImsMediaPauseImageSource.h5
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/android/ImsMediaVideoSource.h6
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/nodes/IVideoRendererNode.h35
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/nodes/IVideoSourceNode.h10
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/BaseNode.cpp15
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtcpDecoderNode.cpp25
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtpEncoderNode.cpp42
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextJitterBuffer.cpp14
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextManager.cpp27
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextStreamGraphRtcp.cpp25
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextStreamGraphRtpRx.cpp2
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextStreamGraphRtpTx.cpp2
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/nodes/TextRendererNode.cpp14
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/nodes/TextRtpPayloadDecoderNode.cpp88
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/nodes/TextSourceNode.cpp135
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaBitWriter.cpp35
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaEventHandler.cpp31
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaImageRotate.cpp81
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/ImsMediaVideoUtil.cpp26
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoManager.cpp34
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoSession.cpp6
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoStreamGraphRtcp.cpp29
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoStreamGraphRtpRx.cpp2
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoStreamGraphRtpTx.cpp19
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/android/ImsMediaCamera.cpp56
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/android/ImsMediaPauseImageSource.cpp46
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/android/ImsMediaVideoRenderer.cpp15
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/android/ImsMediaVideoSource.cpp334
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/nodes/IVideoRendererNode.cpp440
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/nodes/IVideoSourceNode.cpp27
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/nodes/VideoRtpPayloadEncoderNode.cpp2
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/protocol/rtp/core/RtcpPacket.cpp38
-rw-r--r--service/src/com/android/telephony/imsmedia/lib/libimsmedia/protocol/rtp/core/RtcpXrPacket.cpp6
-rw-r--r--test/app/ImsMediaTestingApp/app/src/main/java/com/example/imsmediatestingapp/MainActivity.java138
-rw-r--r--test/app/ImsMediaTestingApp/app/src/main/res/layout/settings_video.xml20
-rw-r--r--test/app/ImsMediaTestingApp/app/src/main/res/values/strings.xml1
-rw-r--r--tests/native/Android.bp1
-rw-r--r--tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/MediaQualityThresholdTest.cpp6
-rw-r--r--tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioManagerTest.cpp683
-rw-r--r--tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/MediaQualityAnalyzerTest.cpp190
-rw-r--r--tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/node/AudioRtpPayloadNodeTest.cpp296
-rw-r--r--tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtcpDecoderNodeTests.cpp303
-rw-r--r--tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtcpEncoderNodeTests.cpp349
-rw-r--r--tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextStreamGraphRtcpTest.cpp8
-rw-r--r--tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/nodes/TextSourceNodeTest.cpp133
-rw-r--r--tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaBitReaderTest.cpp75
-rw-r--r--tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaBitWriterTest.cpp77
-rw-r--r--tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaImageRotateTest.cpp98
-rw-r--r--tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoStreamGraphRtcpTest.cpp10
-rw-r--r--tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoStreamGraphRtpTxTest.cpp6
-rw-r--r--tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/include/core/audio/MockAudioManager.h39
-rw-r--r--tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/protocol/rtp/core/RtcpPacketTest.cpp33
-rw-r--r--tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/protocol/rtp/core/RtcpXrPacketTest.cpp4
-rw-r--r--tests/unit/src/com/android/telephony/imsmedia/AudioListenerTest.java29
-rw-r--r--tests/unit/src/com/android/telephony/imsmedia/AudioOffloadTest.java33
-rw-r--r--tests/unit/src/com/android/telephony/imsmedia/AudioSessionTest.java29
-rw-r--r--tests/unit/src/com/android/telephony/imsmedia/ImsMediaTest.java88
-rw-r--r--tests/unit/src/com/android/telephony/imsmedia/MediaQualityThresholdTest.java20
-rw-r--r--tests/unit/src/com/android/telephony/imsmedia/TextListenerTest.java31
-rw-r--r--tests/unit/src/com/android/telephony/imsmedia/TextSessionTest.java30
-rw-r--r--tests/unit/src/com/android/telephony/imsmedia/VideoListenerTest.java37
-rw-r--r--tests/unit/src/com/android/telephony/imsmedia/VideoSessionTest.java34
117 files changed, 3949 insertions, 1512 deletions
diff --git a/framework/src/android/telephony/imsmedia/AudioSessionCallback.java b/framework/src/android/telephony/imsmedia/AudioSessionCallback.java
index 7bf74de3..03863175 100644
--- a/framework/src/android/telephony/imsmedia/AudioSessionCallback.java
+++ b/framework/src/android/telephony/imsmedia/AudioSessionCallback.java
@@ -268,20 +268,11 @@ public class AudioSessionCallback extends ImsMediaManager.SessionCallback {
}
/**
- * Notifies media inactivity observed as per thresholds set by
- * setMediaQualityThreshold() API
- *
- * @param packetType either RTP or RTCP
- */
- public void notifyMediaInactivity(final int packetType) {
- // Base Implementation
- }
-
- /**
* Notifies media quality status observed as per thresholds set by
* setMediaQualityThreshold() API
*
- * @param packetType either RTP or RTCP
+ * @param status The object of MediaQualityStatus with the rtp and
+ * the rtcp statistics.
*/
public void notifyMediaQualityStatus(final MediaQualityStatus status) {
// Base Implementation
diff --git a/framework/src/android/telephony/imsmedia/IImsVideoSessionCallback.aidl b/framework/src/android/telephony/imsmedia/IImsVideoSessionCallback.aidl
index 8de33a39..b48e560d 100644
--- a/framework/src/android/telephony/imsmedia/IImsVideoSessionCallback.aidl
+++ b/framework/src/android/telephony/imsmedia/IImsVideoSessionCallback.aidl
@@ -35,6 +35,6 @@ oneway interface IImsVideoSessionCallback {
void onPeerDimensionChanged(in int width, in int height);
void onHeaderExtensionReceived(in List<RtpHeaderExtension> extensions);
void notifyMediaInactivity(int packetType);
- void notifyPacketLoss(int packetLossPercentage);
+ void notifyBitrate(int bitate);
void notifyVideoDataUsage(long bytes);
}
diff --git a/framework/src/android/telephony/imsmedia/MediaQualityThreshold.java b/framework/src/android/telephony/imsmedia/MediaQualityThreshold.java
index 3f38e89a..42024a87 100644
--- a/framework/src/android/telephony/imsmedia/MediaQualityThreshold.java
+++ b/framework/src/android/telephony/imsmedia/MediaQualityThreshold.java
@@ -38,6 +38,7 @@ public final class MediaQualityThreshold implements Parcelable {
private final int[] mRtpPacketLossRate;
private final int[] mRtpJitterMillis;
private final boolean mNotifyCurrentStatus;
+ private final int mVideoBitrateBps;
/** @hide **/
public MediaQualityThreshold(Parcel in) {
@@ -60,6 +61,7 @@ public final class MediaQualityThreshold implements Parcelable {
mRtpJitterMillis[i] = in.readInt();
}
mNotifyCurrentStatus = in.readBoolean();
+ mVideoBitrateBps = in.readInt();
}
/** @hide **/
@@ -74,6 +76,7 @@ public final class MediaQualityThreshold implements Parcelable {
mRtpJitterMillis = Arrays.copyOf(builder.mRtpJitterMillis,
builder.mRtpJitterMillis.length);
mNotifyCurrentStatus = builder.mNotifyCurrentStatus;
+ mVideoBitrateBps = builder.mVideoBitrateBps;
}
/** @hide **/
@@ -111,6 +114,10 @@ public final class MediaQualityThreshold implements Parcelable {
return mNotifyCurrentStatus;
}
+ public int getVideoBitrateBps() {
+ return mVideoBitrateBps;
+ }
+
@NonNull
@Override
public String toString() {
@@ -122,6 +129,7 @@ public final class MediaQualityThreshold implements Parcelable {
+ ", mRtpPacketLossRate=" + Arrays.toString(mRtpPacketLossRate)
+ ", mRtpJitterMillis=" + Arrays.toString(mRtpJitterMillis)
+ ", mNotifyCurrentStatus=" + mNotifyCurrentStatus
+ + ", mVideoBitrateBps=" + mVideoBitrateBps
+ " }";
}
@@ -130,7 +138,7 @@ public final class MediaQualityThreshold implements Parcelable {
return Objects.hash(Arrays.hashCode(mRtpInactivityTimerMillis), mRtcpInactivityTimerMillis,
mRtpHysteresisTimeInMillis, mRtpPacketLossDurationMillis,
Arrays.hashCode(mRtpPacketLossRate), Arrays.hashCode(mRtpJitterMillis),
- mNotifyCurrentStatus);
+ mNotifyCurrentStatus, mVideoBitrateBps);
}
@Override
@@ -151,7 +159,8 @@ public final class MediaQualityThreshold implements Parcelable {
&& mRtpPacketLossDurationMillis == s.mRtpPacketLossDurationMillis
&& Arrays.equals(mRtpPacketLossRate, s.mRtpPacketLossRate)
&& Arrays.equals(mRtpJitterMillis, s.mRtpJitterMillis)
- && mNotifyCurrentStatus == s.mNotifyCurrentStatus);
+ && mNotifyCurrentStatus == s.mNotifyCurrentStatus
+ && mVideoBitrateBps == s.mVideoBitrateBps);
}
/**
@@ -172,6 +181,7 @@ public final class MediaQualityThreshold implements Parcelable {
dest.writeIntArray(mRtpPacketLossRate);
dest.writeIntArray(mRtpJitterMillis);
dest.writeBoolean(mNotifyCurrentStatus);
+ dest.writeInt(mVideoBitrateBps);
}
public static final @NonNull Parcelable.Creator<MediaQualityThreshold>
@@ -198,6 +208,7 @@ public final class MediaQualityThreshold implements Parcelable {
private int[] mRtpPacketLossRate;
private int[] mRtpJitterMillis;
private boolean mNotifyCurrentStatus;
+ private int mVideoBitrateBps;
/**
* Default constructor for Builder.
@@ -209,6 +220,7 @@ public final class MediaQualityThreshold implements Parcelable {
mRtpPacketLossDurationMillis = 0;
mRtpPacketLossRate = new int[0];
mRtpJitterMillis = new int[0];
+ mVideoBitrateBps = 0;
}
/**
@@ -303,6 +315,16 @@ public final class MediaQualityThreshold implements Parcelable {
}
/**
+ * The receiving bitrate threshold in bps for video call. If it is not zero, bitrate
+ * notification event is triggered when the receiving frame bitrate is less than the
+ * threshold.
+ */
+ public @NonNull Builder setVideoBitrateBps(final int bitrate) {
+ this.mVideoBitrateBps = bitrate;
+ return this;
+ }
+
+ /**
* Build the MediaQualityThreshold.
*
* @return the MediaQualityThreshold object.
diff --git a/framework/src/android/telephony/imsmedia/VideoSessionCallback.java b/framework/src/android/telephony/imsmedia/VideoSessionCallback.java
index cf66ee56..17748bbb 100644
--- a/framework/src/android/telephony/imsmedia/VideoSessionCallback.java
+++ b/framework/src/android/telephony/imsmedia/VideoSessionCallback.java
@@ -151,12 +151,12 @@ public class VideoSessionCallback extends ImsMediaManager.SessionCallback {
}
@Override
- public void notifyPacketLoss(final int packetLossPercentage) {
+ public void notifyBitrate(final int bitrate) {
if (mLocalCallback == null) return;
final long callingIdentity = Binder.clearCallingIdentity();
try {
- mExecutor.execute(() -> mLocalCallback.notifyPacketLoss(packetLossPercentage));
+ mExecutor.execute(() -> mLocalCallback.notifyBitrate(bitrate));
} finally {
restoreCallingIdentity(callingIdentity);
}
@@ -234,13 +234,12 @@ public class VideoSessionCallback extends ImsMediaManager.SessionCallback {
}
/**
- * Notifies RTP packet loss observed as per thresholds set by
+ * Notifies when the video bitrate decreased below the threshold set by
* setMediaQualityThreshold() API
*
- * @param packetLossPercentage percentage of packet loss calculated
- * over the duration
+ * @param bitrate The bitrate of sending video packets in bps unit
*/
- public void notifyPacketLoss(final int packetLossPercentage) {
+ public void notifyBitrate(final int bitrate) {
// Base Implementation
}
diff --git a/service/src/com/android/telephony/imsmedia/AudioSession.java b/service/src/com/android/telephony/imsmedia/AudioSession.java
index 603780c2..dae20c41 100644
--- a/service/src/com/android/telephony/imsmedia/AudioSession.java
+++ b/service/src/com/android/telephony/imsmedia/AudioSession.java
@@ -103,13 +103,14 @@ public final class AudioSession extends IImsAudioSession.Stub implements IMediaS
@VisibleForTesting
AudioSession(final int sessionId,
- final @NonNull IImsAudioSessionCallback callback,
- final @Nullable AudioService audioService,
- final @Nullable AudioLocalSession localSession,
- final @Nullable AudioOffloadService offloadService) {
+ @NonNull final IImsAudioSessionCallback callback,
+ @Nullable final AudioService audioService,
+ @Nullable final AudioLocalSession localSession,
+ @Nullable final AudioOffloadService offloadService,
+ Looper looper) {
mSessionId = sessionId;
mCallback = callback;
- mHandler = new AudioSessionHandler(Looper.getMainLooper());
+ mHandler = new AudioSessionHandler(looper);
mAudioService = audioService;
mLocalSession = localSession;
mAudioListener = new AudioListener(mHandler);
diff --git a/service/src/com/android/telephony/imsmedia/TextSession.java b/service/src/com/android/telephony/imsmedia/TextSession.java
index b0895d8e..dd069a03 100644
--- a/service/src/com/android/telephony/imsmedia/TextSession.java
+++ b/service/src/com/android/telephony/imsmedia/TextSession.java
@@ -73,10 +73,10 @@ public final class TextSession extends IImsTextSession.Stub implements IMediaSes
TextSession(final int sessionId,
final @NonNull IImsTextSessionCallback callback,
final @Nullable TextService textService,
- final @Nullable TextLocalSession localSession) {
+ final @Nullable TextLocalSession localSession, Looper looper) {
mSessionId = sessionId;
mCallback = callback;
- mHandler = new TextSessionHandler(Looper.getMainLooper());
+ mHandler = new TextSessionHandler(looper);
mTextService = textService;
mLocalSession = localSession;
mTextListener = new TextListener(mHandler);
diff --git a/service/src/com/android/telephony/imsmedia/Utils.java b/service/src/com/android/telephony/imsmedia/Utils.java
index 651413b5..5459e6c8 100644
--- a/service/src/com/android/telephony/imsmedia/Utils.java
+++ b/service/src/com/android/telephony/imsmedia/Utils.java
@@ -392,6 +392,7 @@ public final class Utils {
.setRtpPacketLossRate(in.rtpPacketLossRate)
.setRtpJitterMillis(in.rtpJitterMillis)
.setNotifyCurrentStatus(in.notifyCurrentStatus)
+ .setVideoBitrateBps(0)
.build();
}
diff --git a/service/src/com/android/telephony/imsmedia/VideoListener.java b/service/src/com/android/telephony/imsmedia/VideoListener.java
index ce70114b..32122974 100644
--- a/service/src/com/android/telephony/imsmedia/VideoListener.java
+++ b/service/src/com/android/telephony/imsmedia/VideoListener.java
@@ -92,7 +92,7 @@ public class VideoListener implements JNIImsMediaListener {
//TODO: add implementation
break;
case VideoSession.EVENT_MEDIA_INACTIVITY_IND:
- case VideoSession.EVENT_PACKET_LOSS_IND:
+ case VideoSession.EVENT_NOTIFY_BITRATE_IND:
Utils.sendMessage(mHandler, event, parcel.readInt(), Utils.UNUSED);
break;
case VideoSession.EVENT_VIDEO_DATA_USAGE_IND:
diff --git a/service/src/com/android/telephony/imsmedia/VideoSession.java b/service/src/com/android/telephony/imsmedia/VideoSession.java
index a2351df9..02d47ad9 100644
--- a/service/src/com/android/telephony/imsmedia/VideoSession.java
+++ b/service/src/com/android/telephony/imsmedia/VideoSession.java
@@ -59,7 +59,7 @@ public final class VideoSession extends IImsVideoSession.Stub implements IMediaS
public static final int EVENT_PEER_DIMENSION_CHANGED = 205;
public static final int EVENT_RTP_HEADER_EXTENSION_IND = 206;
public static final int EVENT_MEDIA_INACTIVITY_IND = 207;
- public static final int EVENT_PACKET_LOSS_IND = 208;
+ public static final int EVENT_NOTIFY_BITRATE_IND = 208;
public static final int EVENT_VIDEO_DATA_USAGE_IND = 209;
public static final int EVENT_SESSION_CLOSED = 210;
@@ -85,10 +85,10 @@ public final class VideoSession extends IImsVideoSession.Stub implements IMediaS
VideoSession(final int sessionId,
final @NonNull IImsVideoSessionCallback callback,
final @Nullable VideoService videoService,
- final @Nullable VideoLocalSession localSession) {
+ final @Nullable VideoLocalSession localSession, Looper looper) {
mSessionId = sessionId;
mCallback = callback;
- mHandler = new VideoSessionHandler(Looper.getMainLooper());
+ mHandler = new VideoSessionHandler(looper);
mVideoService = videoService;
mLocalSession = localSession;
mVideoListener = new VideoListener(mHandler);
@@ -233,8 +233,8 @@ public final class VideoSession extends IImsVideoSession.Stub implements IMediaS
case EVENT_MEDIA_INACTIVITY_IND:
handleNotifyMediaInactivityInd(msg.arg1);
break;
- case EVENT_PACKET_LOSS_IND:
- handleNotifyPacketLossInd(msg.arg1);
+ case EVENT_NOTIFY_BITRATE_IND:
+ handleNotifyBitrateInd(msg.arg1);
break;
case EVENT_VIDEO_DATA_USAGE_IND:
handleNotifyVideoDataUsage((long) msg.obj);
@@ -344,9 +344,9 @@ public final class VideoSession extends IImsVideoSession.Stub implements IMediaS
}
}
- private void handleNotifyPacketLossInd(int percentage) {
+ private void handleNotifyBitrateInd(int percentage) {
try {
- mCallback.notifyPacketLoss(percentage);
+ mCallback.notifyBitrate(percentage);
} catch (RemoteException e) {
Log.e(TAG, "Failed to notify packet loss: " + e);
}
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/Android.bp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/Android.bp
index de09bc98..c92b7a19 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/Android.bp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/Android.bp
@@ -23,7 +23,7 @@ soong_config_module_type {
module_type: "cc_defaults",
config_namespace: "audio_lib",
variables: ["audio_type"],
- properties: ["static_libs","header_libs"],
+ properties: ["defaults","static_libs","header_libs"],
}
soong_config_string_variable {
@@ -36,6 +36,9 @@ audio_cc_defaults {
soong_config_variables: {
audio_type: {
oem_audio: {
+ defaults: [
+ "libimsmedia_oem_audio_codec_defaults",
+ ],
static_libs: [
"libimsmedia_oem_audio_codec",
],
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/include/MediaQualityThreshold.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/include/MediaQualityThreshold.h
index ecb33980..d7b7ced3 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/include/MediaQualityThreshold.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/include/MediaQualityThreshold.h
@@ -58,6 +58,8 @@ public:
std::vector<int32_t> getRtpJitterMillis() const;
void setNotifyCurrentStatus(bool status);
bool getNotifyCurrentStatus() const;
+ void setVideoBitrateBps(int32_t bitrate);
+ int32_t getVideoBitrateBps() const;
private:
/** The timer in milliseconds for monitoring RTP inactivity */
@@ -85,6 +87,13 @@ private:
* of the current status.
*/
bool mNotifyCurrentStatus;
+
+ /**
+ * The receiving bitrate threshold in bps for video call. If it is not zero, bitrate
+ * notification event is triggered when the receiving frame bitrate is less than the
+ * threshold.
+ */
+ int mVideoBitrateBps;
};
} // namespace imsmedia
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/include/RtcpConfig.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/include/RtcpConfig.h
index c742d883..566497e3 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/include/RtcpConfig.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/include/RtcpConfig.h
@@ -50,7 +50,7 @@ public:
* RTCP XR type Loss RLE Report Block as specified in
* RFC 3611 section 4.1
*/
- FLAG_RTCPXR_LOSS_RLE_REPORT_BLOCK = 1 < 0,
+ FLAG_RTCPXR_LOSS_RLE_REPORT_BLOCK = 1 << 0,
/**
* RTCP XR type Duplicate RLE Report Block as specified in
* RFC 3611 section 4.2
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/src/MediaQualityThreshold.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/src/MediaQualityThreshold.cpp
index f0ca1473..c6ecefdd 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/src/MediaQualityThreshold.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/src/MediaQualityThreshold.cpp
@@ -34,6 +34,7 @@ MediaQualityThreshold::MediaQualityThreshold()
mRtpPacketLossRate.clear();
mRtpJitterMillis.clear();
mNotifyCurrentStatus = false;
+ mVideoBitrateBps = 0;
}
MediaQualityThreshold::MediaQualityThreshold(const MediaQualityThreshold& threshold)
@@ -45,6 +46,7 @@ MediaQualityThreshold::MediaQualityThreshold(const MediaQualityThreshold& thresh
mRtpPacketLossRate = threshold.mRtpPacketLossRate;
mRtpJitterMillis = threshold.mRtpJitterMillis;
mNotifyCurrentStatus = threshold.mNotifyCurrentStatus;
+ mVideoBitrateBps = threshold.mVideoBitrateBps;
}
MediaQualityThreshold::~MediaQualityThreshold() {}
@@ -60,6 +62,7 @@ MediaQualityThreshold& MediaQualityThreshold::operator=(const MediaQualityThresh
mRtpPacketLossRate = threshold.mRtpPacketLossRate;
mRtpJitterMillis = threshold.mRtpJitterMillis;
mNotifyCurrentStatus = threshold.mNotifyCurrentStatus;
+ mVideoBitrateBps = threshold.mVideoBitrateBps;
}
return *this;
}
@@ -72,7 +75,8 @@ bool MediaQualityThreshold::operator==(const MediaQualityThreshold& threshold) c
mRtpPacketLossDurationMillis == threshold.mRtpPacketLossDurationMillis &&
mRtpPacketLossRate == threshold.mRtpPacketLossRate &&
mRtpJitterMillis == threshold.mRtpJitterMillis &&
- mNotifyCurrentStatus == threshold.mNotifyCurrentStatus);
+ mNotifyCurrentStatus == threshold.mNotifyCurrentStatus &&
+ mVideoBitrateBps == threshold.mVideoBitrateBps);
}
bool MediaQualityThreshold::operator!=(const MediaQualityThreshold& threshold) const
@@ -83,7 +87,8 @@ bool MediaQualityThreshold::operator!=(const MediaQualityThreshold& threshold) c
mRtpPacketLossDurationMillis != threshold.mRtpPacketLossDurationMillis ||
mRtpPacketLossRate != threshold.mRtpPacketLossRate ||
mRtpJitterMillis != threshold.mRtpJitterMillis ||
- mNotifyCurrentStatus != threshold.mNotifyCurrentStatus);
+ mNotifyCurrentStatus != threshold.mNotifyCurrentStatus ||
+ mVideoBitrateBps != threshold.mVideoBitrateBps);
}
status_t MediaQualityThreshold::writeToParcel(Parcel* out) const
@@ -113,6 +118,7 @@ status_t MediaQualityThreshold::writeToParcel(Parcel* out) const
}
out->writeInt32(mNotifyCurrentStatus ? 1 : 0);
+ out->writeInt32(mVideoBitrateBps);
return NO_ERROR;
}
@@ -149,7 +155,7 @@ status_t MediaQualityThreshold::readFromParcel(const Parcel* in)
int32_t value;
in->readInt32(&value);
value == 1 ? mNotifyCurrentStatus = true : mNotifyCurrentStatus = false;
-
+ in->readInt32(&mVideoBitrateBps);
return NO_ERROR;
}
@@ -223,6 +229,16 @@ bool MediaQualityThreshold::getNotifyCurrentStatus() const
return mNotifyCurrentStatus;
}
+void MediaQualityThreshold::setVideoBitrateBps(int32_t bitrate)
+{
+ mVideoBitrateBps = bitrate;
+}
+
+int32_t MediaQualityThreshold::getVideoBitrateBps() const
+{
+ return mVideoBitrateBps;
+}
+
} // namespace imsmedia
} // namespace telephony
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/BaseJitterBuffer.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/BaseJitterBuffer.cpp
index c039e690..5242fb34 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/BaseJitterBuffer.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/BaseJitterBuffer.cpp
@@ -44,7 +44,13 @@ void BaseJitterBuffer::SetSessionCallback(BaseSessionCallback* callback)
void BaseJitterBuffer::SetSsrc(uint32_t ssrc)
{
- IMLOGD1("[SetSsrc] ssrc[%x]", ssrc);
+ IMLOGI1("[SetSsrc] ssrc[%x]", ssrc);
+
+ if (mSsrc != 0 && ssrc != mSsrc)
+ {
+ Reset();
+ }
+
mSsrc = ssrc;
}
@@ -76,6 +82,7 @@ uint32_t BaseJitterBuffer::GetCount()
void BaseJitterBuffer::Reset()
{
+ mFirstFrameReceived = false;
mNewInputData = false;
mLastPlayedSeqNum = 0;
mLastPlayedTimestamp = 0;
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/JitterNetworkAnalyser.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/JitterNetworkAnalyser.cpp
index 85757c84..065b013f 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/JitterNetworkAnalyser.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/JitterNetworkAnalyser.cpp
@@ -48,6 +48,8 @@ void JitterNetworkAnalyser::Reset()
mNetworkStatus = NETWORK_STATUS_NORMAL;
mGoodStatusEnteringTime = 0;
mBadStatusChangedTime = 0;
+
+ std::lock_guard<std::mutex> guard(mMutex);
mListJitters.clear();
}
@@ -79,6 +81,8 @@ int32_t JitterNetworkAnalyser::CalculateTransitTimeDifference(
int32_t inputTimestampGap = timestamp - mBasePacketTime;
int32_t inputTimeGap = arrivalTime - mBaseArrivalTime;
int32_t jitter = inputTimeGap - inputTimestampGap;
+
+ std::lock_guard<std::mutex> guard(mMutex);
mListJitters.push_back(jitter);
if (mListJitters.size() > MAX_JITTER_LIST_SIZE)
@@ -91,6 +95,8 @@ int32_t JitterNetworkAnalyser::CalculateTransitTimeDifference(
double JitterNetworkAnalyser::CalculateDeviation(double* pMean)
{
+ std::lock_guard<std::mutex> guard(mMutex);
+
if (mListJitters.empty())
{
*pMean = 0;
@@ -114,6 +120,8 @@ double JitterNetworkAnalyser::CalculateDeviation(double* pMean)
int32_t JitterNetworkAnalyser::GetMaxJitterValue()
{
+ std::lock_guard<std::mutex> guard(mMutex);
+
if (mListJitters.empty())
{
return 0;
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/StreamScheduler.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/StreamScheduler.cpp
index d71707c7..9184212c 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/StreamScheduler.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/StreamScheduler.cpp
@@ -19,11 +19,12 @@
#include <stdint.h>
#include <chrono>
#include <thread>
+#include <algorithm>
using namespace std::chrono;
-#define RUN_WAIT_TIMEOUT 6
-#define STOP_WAIT_TIMEOUT 1000
+#define RUN_WAIT_TIMEOUT_MS 1
+#define STOP_WAIT_TIMEOUT_MS 1000
StreamScheduler::StreamScheduler() {}
@@ -85,7 +86,7 @@ void StreamScheduler::Stop()
{
StopThread();
Awake();
- mConditionExit.wait_timeout(STOP_WAIT_TIMEOUT);
+ mConditionExit.wait_timeout(STOP_WAIT_TIMEOUT_MS);
}
IMLOGD1("[Stop] [%p] exit", this);
@@ -96,53 +97,48 @@ void StreamScheduler::Awake()
mConditionMain.signal();
}
-BaseNode* StreamScheduler::DetermineProcessingNode()
+void StreamScheduler::RunRegisteredNode()
{
- if (IsThreadStopped())
- {
- return nullptr;
- }
-
- BaseNode* pRetNode = nullptr;
- uint32_t nMaxDataInNode = 0;
+ // the list to contain non-source type node
+ std::list<BaseNode*> listNodesToRun;
for (auto& node : mlistRegisteredNode)
{
- if (node != nullptr && !node->IsRunTime())
+ if (node != nullptr && node->GetState() == kNodeStateRunning && !node->IsRunTime())
{
- uint32_t nDataInNode = node->GetDataCount();
-
- if (nDataInNode > 0 && nDataInNode >= nMaxDataInNode)
+ if (node->IsSourceNode()) // process the source node
+ {
+ node->ProcessData();
+ }
+ else if (node->GetDataCount() > 0)
{
- pRetNode = node;
- nMaxDataInNode = nDataInNode;
+ listNodesToRun.push_back(node); // store node to run
}
}
}
- return pRetNode;
-}
-
-void StreamScheduler::RunRegisteredNode()
-{
- for (;;)
+ while (!listNodesToRun.empty())
{
- BaseNode* pNode = DetermineProcessingNode();
-
- if (pNode == nullptr)
+ std::list<BaseNode*>::iterator maxNode =
+ std::max_element(listNodesToRun.begin(), listNodesToRun.end(),
+ [=](BaseNode* a, BaseNode* b)
+ {
+ return a->GetDataCount() < b->GetDataCount();
+ });
+
+ if (maxNode == listNodesToRun.end())
{
break;
}
- if (pNode->GetState() == kNodeStateRunning)
- {
- pNode->ProcessData();
- }
+ (*maxNode)->ProcessData(); // process the non runtime node
if (IsThreadStopped())
{
break;
}
+
+ listNodesToRun.remove(*maxNode);
};
}
@@ -178,10 +174,10 @@ void* StreamScheduler::run()
break;
}
- mConditionMain.wait_timeout(RUN_WAIT_TIMEOUT / 2);
+ mConditionMain.wait_timeout(RUN_WAIT_TIMEOUT_MS);
}
mConditionExit.signal();
IMLOGD1("[run] [%p] exit", this);
return nullptr;
-}
+} \ No newline at end of file
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioJitterBuffer.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioJitterBuffer.cpp
index 7332af54..98bf8014 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioJitterBuffer.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioJitterBuffer.cpp
@@ -45,10 +45,11 @@ AudioJitterBuffer::~AudioJitterBuffer() {}
void AudioJitterBuffer::Reset()
{
- mNextJitterBufferSize = mCurrJitterBufferSize;
+ mFirstFrameReceived = false;
+ mNewInputData = false;
mLastPlayedSeqNum = 0;
mLastPlayedTimestamp = 0;
- mFirstFrameReceived = false;
+ mNextJitterBufferSize = mCurrJitterBufferSize;
mDtxOn = false;
mSIDCount = 0;
mWaiting = true;
@@ -59,10 +60,20 @@ void AudioJitterBuffer::Reset()
mCheckUpdateJitterPacketCnt = 0;
mEnforceUpdate = false;
mNeedToUpdateBasePacket = false;
- BaseJitterBuffer::Reset();
+
+ mMutex.lock();
+ DataEntry* entry = nullptr;
+
+ while (mDataQueue.Get(&entry))
+ {
+ CollectRxRtpStatus(entry->nSeqNum, kRtpStatusDiscarded);
+ mDataQueue.Delete();
+ }
+
+ mMutex.unlock();
+
mJitterAnalyzer.Reset();
mJitterAnalyzer.SetMinMaxJitterBufferSize(mMinJitterBufferSize, mMaxJitterBufferSize);
- mCurrPlayingSeq = 0;
}
void AudioJitterBuffer::SetJitterBufferSize(uint32_t nInit, uint32_t nMin, uint32_t nMax)
@@ -125,15 +136,7 @@ void AudioJitterBuffer::Add(ImsMediaSubType subtype, uint8_t* pbBuffer, uint32_t
if (mCannotGetCount > mMaxJitterBufferSize)
{
- IMLOGD0("[Add] refreshed");
- DataEntry* resetData = nullptr;
-
- while (mDataQueue.Get(&resetData))
- {
- CollectRxRtpStatus(resetData->nSeqNum, kRtpStatusDiscarded);
- Delete();
- }
-
+ IMLOGD0("[Add] reset");
Reset();
}
@@ -145,7 +148,7 @@ void AudioJitterBuffer::Add(ImsMediaSubType subtype, uint8_t* pbBuffer, uint32_t
mJitterAnalyzer.UpdateBaseTimestamp(mBaseTimestamp, mBaseArrivalTime);
}
// TODO: remove mBufferIgnoreSIDPacket logic and the statements
- else if (mBufferIgnoreSIDPacket && !IsSID(currEntry.pbBuffer, currEntry.nBufferSize))
+ else if (mBufferIgnoreSIDPacket && !IsSID(currEntry.nBufferSize))
{
// first packet delay compensation
if ((mBaseTimestamp == 0 && mBaseArrivalTime == 0) || mNeedToUpdateBasePacket)
@@ -194,8 +197,8 @@ void AudioJitterBuffer::Add(ImsMediaSubType subtype, uint8_t* pbBuffer, uint32_t
}
else
{
- IsSID(currEntry.pbBuffer, currEntry.nBufferSize) ? packet->rtpDataType = kRtpDataTypeSid
- : packet->rtpDataType = kRtpDataTypeNormal;
+ IsSID(currEntry.nBufferSize) ? packet->rtpDataType = kRtpDataTypeSid
+ : packet->rtpDataType = kRtpDataTypeNormal;
}
packet->ssrc = mSsrc;
@@ -281,14 +284,20 @@ bool AudioJitterBuffer::Get(ImsMediaSubType* psubtype, uint8_t** ppData, uint32_
if (mDataQueue.GetCount() == 0)
{
- IMLOGD_PACKET0(IM_PACKET_LOG_JITTER, "[Get] wait - empty");
+ IMLOGD_PACKET0(IM_PACKET_LOG_JITTER, "[Get] fail - empty");
+
+ if (!mWaiting)
+ {
+ mCurrPlayingTS += FRAME_INTERVAL;
+ }
+
return false;
}
else if (mDataQueue.Get(&pEntry) && mWaiting)
{
uint32_t jitterDelay = currentTime - pEntry->arrivalTime;
- if (jitterDelay < (mCurrJitterBufferSize - 1) * FRAME_INTERVAL + ALLOWABLE_ERROR)
+ if (jitterDelay <= (mCurrJitterBufferSize - 1) * FRAME_INTERVAL)
{
if (psubtype)
*psubtype = MEDIASUBTYPE_UNDEFINED;
@@ -306,16 +315,22 @@ bool AudioJitterBuffer::Get(ImsMediaSubType* psubtype, uint8_t** ppData, uint32_
IMLOGD_PACKET4(IM_PACKET_LOG_JITTER,
"[Get] Wait - seq[%u], CurrJBSize[%u], delay[%u], QueueCount[%u]",
pEntry->nSeqNum, mCurrJitterBufferSize, jitterDelay, mDataQueue.GetCount());
- mCannotGetCount++;
return false;
}
else
{
- mWaiting = false; // once waiting is reset, it will not set true until resync
-
- // the first frame of voice term
- mCurrPlayingTS = pEntry->nTimestamp;
- mCurrPlayingSeq = pEntry->nSeqNum;
+ // resync until the frame delay is lower than current jitter buffer size
+ if (Resync(currentTime))
+ {
+ mWaiting = false;
+ }
+ else
+ {
+ IMLOGD_PACKET4(IM_PACKET_LOG_JITTER,
+ "[Get] Wait - seq[%u], CurrJBSize[%u], delay[%u], QueueCount[%u]",
+ pEntry->nSeqNum, mCurrJitterBufferSize, jitterDelay, mDataQueue.GetCount());
+ return false;
+ }
}
}
@@ -325,9 +340,8 @@ bool AudioJitterBuffer::Get(ImsMediaSubType* psubtype, uint8_t** ppData, uint32_
(pEntry->nTimestamp < (mCurrPlayingTS + ALLOWABLE_ERROR)))
{
mCurrPlayingTS = pEntry->nTimestamp;
- mCurrPlayingSeq = pEntry->nSeqNum;
IMLOGD_PACKET2(IM_PACKET_LOG_JITTER, "[Get] sync playing TS[%u], seq[%d]", mCurrPlayingTS,
- mCurrPlayingSeq);
+ pEntry->nSeqNum);
}
while (mDataQueue.Get(&pEntry))
@@ -341,13 +355,11 @@ bool AudioJitterBuffer::Get(ImsMediaSubType* psubtype, uint8_t** ppData, uint32_
if (mDataQueue.GetCount() >= nTempBuferSize)
{
mCurrPlayingTS = pEntry->nTimestamp;
- mCurrPlayingSeq = pEntry->nSeqNum;
}
else
{
mCurrPlayingTS = pEntry->nTimestamp -
(nTempBuferSize - mDataQueue.GetCount()) * FRAME_INTERVAL;
- mCurrPlayingSeq = 0;
}
mNeedToUpdateBasePacket = true;
@@ -372,7 +384,7 @@ bool AudioJitterBuffer::Get(ImsMediaSubType* psubtype, uint8_t** ppData, uint32_
}
else // late arrival
{
- if (IsSID(pEntry->pbBuffer, pEntry->nBufferSize))
+ if (IsSID(pEntry->nBufferSize))
{
mSIDCount++;
mDtxOn = true;
@@ -392,7 +404,7 @@ bool AudioJitterBuffer::Get(ImsMediaSubType* psubtype, uint8_t** ppData, uint32_
// decrease jitter buffer
if (mDtxOn && mSIDCount > 4 && mDataQueue.GetCount() > mCurrJitterBufferSize)
{
- if (mDataQueue.Get(&pEntry) && IsSID(pEntry->pbBuffer, pEntry->nBufferSize))
+ if (mDataQueue.Get(&pEntry) && IsSID(pEntry->nBufferSize))
{
IMLOGD_PACKET5(IM_PACKET_LOG_JITTER,
"[Get] delete SID - seq[%d], mark[%d], TS[%u], currTS[%u], queue[%d]",
@@ -429,7 +441,7 @@ bool AudioJitterBuffer::Get(ImsMediaSubType* psubtype, uint8_t** ppData, uint32_
pEntry->nSeqNum, pEntry->bMark, pEntry->nTimestamp, mCurrPlayingTS,
mDataQueue.GetCount());
- if (IsSID(pEntry->pbBuffer, pEntry->nBufferSize))
+ if (IsSID(pEntry->nBufferSize))
{
mSIDCount++;
mDtxOn = true;
@@ -487,7 +499,7 @@ bool AudioJitterBuffer::Get(ImsMediaSubType* psubtype, uint8_t** ppData, uint32_
if (pnSeqNum)
*pnSeqNum = pEntry->nSeqNum;
- if (IsSID(pEntry->pbBuffer, pEntry->nBufferSize))
+ if (IsSID(pEntry->nBufferSize))
{
mSIDCount++;
mDtxOn = true;
@@ -512,12 +524,11 @@ bool AudioJitterBuffer::Get(ImsMediaSubType* psubtype, uint8_t** ppData, uint32_
}
IMLOGD_PACKET7(IM_PACKET_LOG_JITTER,
- "[Get] OK - dtx[%d], curTS[%u], seq[%d], mark[%d], TS[%u], size[%d], queue[%d]",
- mDtxOn, mCurrPlayingTS, pEntry->nSeqNum, pEntry->bMark, pEntry->nTimestamp,
- pEntry->nBufferSize, mDataQueue.GetCount());
+ "[Get] OK - dtx[%d], curTS[%u], seq[%u], TS[%u], size[%u], delay[%u], queue[%u]",
+ mDtxOn, mCurrPlayingTS, pEntry->nSeqNum, pEntry->nTimestamp, pEntry->nBufferSize,
+ currentTime - pEntry->arrivalTime, mDataQueue.GetCount());
mCurrPlayingTS = pEntry->nTimestamp + FRAME_INTERVAL;
- mCurrPlayingSeq = pEntry->nSeqNum + 1;
mFirstFrameReceived = true;
mLastPlayedSeqNum = pEntry->nSeqNum;
mCannotGetCount = 0;
@@ -552,28 +563,24 @@ bool AudioJitterBuffer::Get(ImsMediaSubType* psubtype, uint8_t** ppData, uint32_
mCurrPlayingTS);
mCurrPlayingTS += FRAME_INTERVAL;
- mCurrPlayingSeq++;
return false;
}
return false;
}
-bool AudioJitterBuffer::IsSID(uint8_t* /*pbBuffer*/, uint32_t nBufferSize)
+bool AudioJitterBuffer::IsSID(uint32_t frameSize)
{
switch (mCodecType)
{
case kAudioCodecAmr:
case kAudioCodecAmrWb:
- if (nBufferSize == 5)
- return true;
- else
- return false;
case kAudioCodecEvs:
- if ((nBufferSize == 6) || (nBufferSize == 5))
+ if (frameSize == 6 || frameSize == 5)
+ {
return true;
- else
- return false;
+ }
+ break;
case kAudioCodecPcmu:
case kAudioCodecPcma:
return false;
@@ -581,6 +588,39 @@ bool AudioJitterBuffer::IsSID(uint8_t* /*pbBuffer*/, uint32_t nBufferSize)
IMLOGE1("[IsSID] DTX detect method is not defined for[%u] codec", mCodecType);
return false;
}
+
+ return false;
+}
+
+bool AudioJitterBuffer::Resync(uint32_t currentTime)
+{
+ IMLOGD0("[Resync]");
+ DataEntry* entry = nullptr;
+
+ while (mDataQueue.Get(&entry))
+ {
+ uint32_t timeDiff = currentTime - entry->arrivalTime;
+
+ if (timeDiff > mCurrJitterBufferSize * FRAME_INTERVAL + ALLOWABLE_ERROR)
+ {
+ CollectRxRtpStatus(entry->nSeqNum, kRtpStatusDiscarded);
+ mDataQueue.Delete();
+ }
+ else
+ {
+ if (!IsSID(entry->nBufferSize) ||
+ timeDiff > (mCurrJitterBufferSize - 1) * FRAME_INTERVAL)
+ {
+ mCurrPlayingTS = entry->nTimestamp;
+ IMLOGD2("[Resync] currTs[%d], delay[%d]", mCurrPlayingTS, timeDiff);
+ return true;
+ }
+
+ break;
+ }
+ }
+
+ return false;
}
void AudioJitterBuffer::CollectRxRtpStatus(int32_t seq, kRtpPacketStatus status)
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioManager.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioManager.cpp
index 49efef54..e957cc3b 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioManager.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioManager.cpp
@@ -23,9 +23,18 @@ using namespace android;
AudioManager* AudioManager::sManager = nullptr;
-AudioManager::AudioManager() {}
+AudioManager::AudioManager()
+{
+ mRequestHandler.Init("AUDIO_REQUEST_EVENT");
+ mResponseHandler.Init("AUDIO_RESPONSE_EVENT");
+}
-AudioManager::~AudioManager() {}
+AudioManager::~AudioManager()
+{
+ mRequestHandler.Deinit();
+ mResponseHandler.Deinit();
+ sManager = nullptr;
+}
AudioManager* AudioManager::getInstance()
{
@@ -203,6 +212,22 @@ void AudioManager::setMediaQualityThreshold(int sessionId, MediaQualityThreshold
}
}
+void AudioManager::SendInternalEvent(
+ uint32_t event, uint64_t sessionId, uint64_t paramA, uint64_t paramB)
+{
+ auto session = mSessions.find(sessionId);
+ IMLOGI1("[SendInternalEvent] sessionId[%d]", sessionId);
+
+ if (session != mSessions.end())
+ {
+ (session->second)->SendInternalEvent(event, paramA, paramB);
+ }
+ else
+ {
+ IMLOGE1("[SendInternalEvent] no session id[%d]", sessionId);
+ }
+}
+
void AudioManager::sendMessage(const int sessionId, const android::Parcel& parcel)
{
int nMsg = parcel.readInt32();
@@ -283,35 +308,19 @@ void AudioManager::sendMessage(const int sessionId, const android::Parcel& parce
}
}
-void AudioManager::SendInternalEvent(
- uint32_t event, uint64_t sessionId, uint64_t paramA, uint64_t paramB)
-{
- auto session = mSessions.find(sessionId);
- IMLOGI1("[SendInternalEvent] sessionId[%d]", sessionId);
-
- if (session != mSessions.end())
- {
- (session->second)->SendInternalEvent(event, paramA, paramB);
- }
- else
- {
- IMLOGE1("[SendInternalEvent] no session id[%d]", sessionId);
- }
-}
-
-AudioManager::RequestHandler::RequestHandler() :
- ImsMediaEventHandler("AUDIO_REQUEST_EVENT")
-{
-}
-
-AudioManager::RequestHandler::~RequestHandler() {}
-
void AudioManager::RequestHandler::processEvent(
uint32_t event, uint64_t sessionId, uint64_t paramA, uint64_t paramB)
{
IMLOGI4("[processEvent] event[%d], sessionId[%d], paramA[%d], paramB[%d]", event, sessionId,
paramA, paramB);
ImsMediaResult result = RESULT_SUCCESS;
+
+ if (sManager == nullptr)
+ {
+ IMLOGE0("[processEvent] not ready");
+ return;
+ }
+
switch (event)
{
case kAudioOpenSession:
@@ -320,7 +329,7 @@ void AudioManager::RequestHandler::processEvent(
if (param != nullptr)
{
AudioConfig* pConfig = reinterpret_cast<AudioConfig*>(param->mConfig);
- result = AudioManager::getInstance()->openSession(
+ result = sManager->openSession(
static_cast<int>(sessionId), param->rtpFd, param->rtcpFd, pConfig);
if (result == RESULT_SUCCESS)
@@ -349,8 +358,7 @@ void AudioManager::RequestHandler::processEvent(
}
break;
case kAudioCloseSession:
- if (AudioManager::getInstance()->closeSession(static_cast<int>(sessionId)) ==
- RESULT_SUCCESS)
+ if (sManager->closeSession(static_cast<int>(sessionId)) == RESULT_SUCCESS)
{
ImsMediaEventHandler::SendEvent(
"AUDIO_RESPONSE_EVENT", kAudioSessionClosed, sessionId, 0, 0);
@@ -359,8 +367,7 @@ void AudioManager::RequestHandler::processEvent(
case kAudioModifySession:
{
AudioConfig* config = reinterpret_cast<AudioConfig*>(paramA);
- result =
- AudioManager::getInstance()->modifySession(static_cast<int>(sessionId), config);
+ result = sManager->modifySession(static_cast<int>(sessionId), config);
ImsMediaEventHandler::SendEvent(
"AUDIO_RESPONSE_EVENT", kAudioModifySessionResponse, sessionId, result, paramA);
}
@@ -368,7 +375,7 @@ void AudioManager::RequestHandler::processEvent(
case kAudioAddConfig:
{
AudioConfig* config = reinterpret_cast<AudioConfig*>(paramA);
- result = AudioManager::getInstance()->addConfig(static_cast<int>(sessionId), config);
+ result = sManager->addConfig(static_cast<int>(sessionId), config);
ImsMediaEventHandler::SendEvent(
"AUDIO_RESPONSE_EVENT", kAudioAddConfigResponse, sessionId, result, paramA);
}
@@ -376,8 +383,7 @@ void AudioManager::RequestHandler::processEvent(
case kAudioConfirmConfig:
{
AudioConfig* config = reinterpret_cast<AudioConfig*>(paramA);
- result =
- AudioManager::getInstance()->confirmConfig(static_cast<int>(sessionId), config);
+ result = sManager->confirmConfig(static_cast<int>(sessionId), config);
ImsMediaEventHandler::SendEvent(
"AUDIO_RESPONSE_EVENT", kAudioConfirmConfigResponse, sessionId, result, paramA);
}
@@ -387,7 +393,7 @@ void AudioManager::RequestHandler::processEvent(
AudioConfig* config = reinterpret_cast<AudioConfig*>(paramA);
if (config != nullptr)
{
- AudioManager::getInstance()->deleteConfig(static_cast<int>(sessionId), config);
+ sManager->deleteConfig(static_cast<int>(sessionId), config);
delete config;
}
}
@@ -397,8 +403,7 @@ void AudioManager::RequestHandler::processEvent(
EventParamDtmf* param = reinterpret_cast<EventParamDtmf*>(paramA);
if (param != nullptr)
{
- AudioManager::getInstance()->sendDtmf(
- static_cast<int>(sessionId), param->digit, param->duration);
+ sManager->sendDtmf(static_cast<int>(sessionId), param->digit, param->duration);
delete param;
}
}
@@ -410,8 +415,7 @@ void AudioManager::RequestHandler::processEvent(
if (listExtension != nullptr)
{
- AudioManager::getInstance()->sendRtpHeaderExtension(
- static_cast<int>(sessionId), listExtension);
+ sManager->sendRtpHeaderExtension(static_cast<int>(sessionId), listExtension);
delete listExtension;
}
}
@@ -421,34 +425,32 @@ void AudioManager::RequestHandler::processEvent(
MediaQualityThreshold* threshold = reinterpret_cast<MediaQualityThreshold*>(paramA);
if (threshold != nullptr)
{
- AudioManager::getInstance()->setMediaQualityThreshold(
- static_cast<int>(sessionId), threshold);
+ sManager->setMediaQualityThreshold(static_cast<int>(sessionId), threshold);
delete threshold;
}
}
break;
case kRequestAudioCmr:
case kRequestSendRtcpXrReport:
- AudioManager::getInstance()->SendInternalEvent(
- event, static_cast<int>(sessionId), paramA, paramB);
+ sManager->SendInternalEvent(event, static_cast<int>(sessionId), paramA, paramB);
break;
default:
break;
}
}
-AudioManager::ResponseHandler::ResponseHandler() :
- ImsMediaEventHandler("AUDIO_RESPONSE_EVENT")
-{
-}
-
-AudioManager::ResponseHandler::~ResponseHandler() {}
-
void AudioManager::ResponseHandler::processEvent(
uint32_t event, uint64_t sessionId, uint64_t paramA, uint64_t paramB)
{
IMLOGI4("[processEvent] event[%d], sessionId[%d], paramA[%d], paramB[%d]", event, sessionId,
paramA, paramB);
+
+ if (sManager == nullptr)
+ {
+ IMLOGE0("[processEvent] not ready");
+ return;
+ }
+
android::Parcel parcel;
switch (event)
{
@@ -461,7 +463,7 @@ void AudioManager::ResponseHandler::processEvent(
// fail reason
parcel.writeInt32(static_cast<int>(paramA));
}
- AudioManager::getInstance()->sendResponse(sessionId, parcel);
+ sManager->sendResponse(sessionId, parcel);
break;
case kAudioModifySessionResponse: // fall through
case kAudioAddConfigResponse: // fall through
@@ -473,7 +475,7 @@ void AudioManager::ResponseHandler::processEvent(
if (config != nullptr)
{
config->writeToParcel(&parcel);
- AudioManager::getInstance()->sendResponse(sessionId, parcel);
+ sManager->sendResponse(sessionId, parcel);
delete config;
}
}
@@ -485,7 +487,7 @@ void AudioManager::ResponseHandler::processEvent(
if (config != nullptr)
{
config->writeToParcel(&parcel);
- AudioManager::getInstance()->sendResponse(sessionId, parcel);
+ sManager->sendResponse(sessionId, parcel);
delete config;
}
}
@@ -505,7 +507,7 @@ void AudioManager::ResponseHandler::processEvent(
extension.writeToParcel(&parcel);
}
- AudioManager::getInstance()->sendResponse(sessionId, parcel);
+ sManager->sendResponse(sessionId, parcel);
delete listExtension;
}
}
@@ -517,7 +519,7 @@ void AudioManager::ResponseHandler::processEvent(
if (status != nullptr)
{
status->writeToParcel(&parcel);
- AudioManager::getInstance()->sendResponse(sessionId, parcel);
+ sManager->sendResponse(sessionId, parcel);
delete status;
}
}
@@ -529,7 +531,7 @@ void AudioManager::ResponseHandler::processEvent(
parcel.writeInt32(event);
parcel.writeByte(static_cast<uint8_t>(paramA));
parcel.writeInt32(static_cast<int>(paramB));
- AudioManager::getInstance()->sendResponse(sessionId, parcel);
+ sManager->sendResponse(sessionId, parcel);
break;
case kAudioCallQualityChangedInd:
{
@@ -538,7 +540,7 @@ void AudioManager::ResponseHandler::processEvent(
if (quality != nullptr)
{
quality->writeToParcel(&parcel);
- AudioManager::getInstance()->sendResponse(sessionId, parcel);
+ sManager->sendResponse(sessionId, parcel);
delete quality;
}
}
@@ -546,7 +548,7 @@ void AudioManager::ResponseHandler::processEvent(
case kAudioSessionClosed:
parcel.writeInt32(event);
parcel.writeInt32(static_cast<int>(sessionId));
- AudioManager::getInstance()->sendResponse(sessionId, parcel);
+ sManager->sendResponse(sessionId, parcel);
break;
default:
break;
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioSession.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioSession.cpp
index 13367521..f872d730 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioSession.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioSession.cpp
@@ -33,6 +33,8 @@ AudioSession::~AudioSession()
{
IMLOGD0("[~AudioSession]");
+ mMediaQualityAnalyzer->stop();
+
while (mListGraphRtpTx.size() > 0)
{
AudioStreamGraphRtpTx* graph = mListGraphRtpTx.front();
@@ -71,8 +73,6 @@ AudioSession::~AudioSession()
mListGraphRtcp.pop_front();
delete graph;
}
-
- mMediaQualityAnalyzer->stop();
}
SessionState AudioSession::getState()
@@ -125,10 +125,8 @@ ImsMediaResult AudioSession::startGraph(RtpConfig* config)
IMLOGI1("[startGraph] state[%d]", getState());
- if (mMediaQualityAnalyzer != nullptr &&
- !mMediaQualityAnalyzer->isSameConfig(reinterpret_cast<AudioConfig*>(config)))
+ if (mMediaQualityAnalyzer != nullptr)
{
- mMediaQualityAnalyzer->stop();
mMediaQualityAnalyzer->setConfig(reinterpret_cast<AudioConfig*>(config));
mMediaQualityAnalyzer->start();
}
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtcp.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtcp.cpp
index e238f068..fa42bffd 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtcp.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtcp.cpp
@@ -92,7 +92,7 @@ ImsMediaResult AudioStreamGraphRtcp::update(RtpConfig* config)
if (*reinterpret_cast<AudioConfig*>(mConfig) == *pConfig)
{
- IMLOGD0("[update] no update");
+ IMLOGI0("[update] no update");
return RESULT_SUCCESS;
}
@@ -104,7 +104,7 @@ ImsMediaResult AudioStreamGraphRtcp::update(RtpConfig* config)
if (mConfig->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_NO_FLOW)
{
- IMLOGD0("[update] pause RTCP");
+ IMLOGI0("[update] pause RTCP");
return stop();
}
@@ -138,6 +138,22 @@ ImsMediaResult AudioStreamGraphRtcp::update(RtpConfig* config)
return ret;
}
+ImsMediaResult AudioStreamGraphRtcp::start()
+{
+ if (mConfig == nullptr)
+ {
+ return RESULT_NOT_READY;
+ }
+
+ if (mConfig->getMediaDirection() != RtpConfig::MEDIA_DIRECTION_NO_FLOW)
+ {
+ return BaseStreamGraph::start();
+ }
+
+ // not started
+ return RESULT_SUCCESS;
+}
+
bool AudioStreamGraphRtcp::OnEvent(int32_t type, uint64_t param1, uint64_t param2)
{
IMLOGI3("[onEvent] type[%d], param1[%d], param2[%d]", type, param1, param2);
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtpRx.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtpRx.cpp
index 70963147..233284f5 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtpRx.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtpRx.cpp
@@ -88,7 +88,7 @@ ImsMediaResult AudioStreamGraphRtpRx::update(RtpConfig* config)
if (*mConfig == *pConfig)
{
- IMLOGD0("[update] no update");
+ IMLOGI0("[update] no update");
return RESULT_SUCCESS;
}
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtpTx.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtpTx.cpp
index ae8624a5..f797c117 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtpTx.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioStreamGraphRtpTx.cpp
@@ -95,7 +95,7 @@ ImsMediaResult AudioStreamGraphRtpTx::update(RtpConfig* config)
if (*reinterpret_cast<AudioConfig*>(mConfig) == *pConfig)
{
- IMLOGD0("[update] no update");
+ IMLOGI0("[update] no update");
return RESULT_SUCCESS;
}
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/MediaQualityAnalyzer.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/MediaQualityAnalyzer.cpp
index 55c2568b..4661ee0e 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/MediaQualityAnalyzer.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/MediaQualityAnalyzer.cpp
@@ -24,6 +24,9 @@
#include <AudioConfig.h>
#include <stdlib.h>
#include <algorithm>
+#include <numeric>
+
+using namespace android::telephony::imsmedia;
#define DEFAULT_PARAM (-1)
#define DEFAULT_INACTIVITY_TIME_FOR_CALL_QUALITY (4)
@@ -33,12 +36,17 @@
#define TIMER_INTERVAL (1000) // 1 sec
#define STOP_TIMEOUT (1000) // 1 sec
#define MESSAGE_PROCESSING_INTERVAL (20000) // 20 msec
+#define MEDIA_DIRECTION_CONTAINS_RECEIVE(a) \
+ ((a) == RtpConfig::MEDIA_DIRECTION_SEND_RECEIVE || \
+ (a) == RtpConfig::MEDIA_DIRECTION_RECEIVE_ONLY)
MediaQualityAnalyzer::MediaQualityAnalyzer()
{
mTimeStarted = 0;
mCodecType = 0;
mCodecAttribute = 0;
+ mIsRxRtpEnabled = false;
+ mIsRtcpEnabled = false;
mCallback = nullptr;
std::unique_ptr<RtcpXrEncoder> analyzer(new RtcpXrEncoder());
mRtcpXrEncoder = std::move(analyzer);
@@ -66,10 +74,17 @@ MediaQualityAnalyzer::~MediaQualityAnalyzer()
void MediaQualityAnalyzer::setConfig(AudioConfig* config)
{
+ if (!isSameConfig(config))
+ {
+ reset();
+ }
+
+ mIsRxRtpEnabled = MEDIA_DIRECTION_CONTAINS_RECEIVE(config->getMediaDirection());
mCodecType = config->getCodecType();
mCodecAttribute = config->getEvsParams().getEvsBandwidth();
- IMLOGD2("[setCodecType] type[%d], bandwidth[%d]", mCodecType, mCodecAttribute);
+ mCallQuality.setCodecType(convertAudioCodecType(
+ mCodecType, ImsMediaAudioUtil::FindMaxEvsBandwidthFromRange(mCodecAttribute)));
if (mCodecType == AudioConfig::CODEC_AMR)
{
@@ -79,6 +94,20 @@ void MediaQualityAnalyzer::setConfig(AudioConfig* config)
{
mRtcpXrEncoder->setSamplingRate(16);
}
+
+ // Enable RTCP if both interval and direction is valid
+ bool isRtcpEnabled = (config->getRtcpConfig().getIntervalSec() > 0 &&
+ config->getMediaDirection() != RtpConfig::MEDIA_DIRECTION_NO_FLOW);
+
+ if (mIsRtcpEnabled != isRtcpEnabled)
+ {
+ mIsRtcpEnabled = isRtcpEnabled;
+ mCountRtcpInactivity = 0;
+ mNumRtcpPacketReceived = 0;
+ }
+
+ IMLOGI4("[setConfig] codec type[%d], bandwidth[%d], rxRtp[%d], rtcp[%d]", mCodecType,
+ mCodecAttribute, mIsRxRtpEnabled, mIsRtcpEnabled);
}
void MediaQualityAnalyzer::setCallback(BaseSessionCallback* callback)
@@ -111,16 +140,18 @@ void MediaQualityAnalyzer::setMediaQualityThreshold(const MediaQualityThreshold&
bool MediaQualityAnalyzer::isSameConfig(AudioConfig* config)
{
return (mCodecType == config->getCodecType() &&
- mCodecAttribute == config->getEvsParams().getEvsBandwidth());
+ mCodecAttribute == config->getEvsParams().getEvsBandwidth() &&
+ mIsRxRtpEnabled == MEDIA_DIRECTION_CONTAINS_RECEIVE(config->getMediaDirection()));
}
void MediaQualityAnalyzer::start()
{
- IMLOGD0("[start]");
- mCallQuality.setCodecType(convertAudioCodecType(
- mCodecType, ImsMediaAudioUtil::FindMaxEvsBandwidthFromRange(mCodecAttribute)));
- mTimeStarted = ImsMediaTimer::GetTimeInMilliSeconds();
- StartThread();
+ if (IsThreadStopped())
+ {
+ IMLOGD0("[start]");
+ mTimeStarted = ImsMediaTimer::GetTimeInMilliSeconds();
+ StartThread();
+ }
}
void MediaQualityAnalyzer::stop()
@@ -155,12 +186,7 @@ void MediaQualityAnalyzer::collectInfo(const int32_t streamType, RtpPacket* pack
}
else if (streamType == kStreamRtpRx && packet != nullptr)
{
- if (mSSRC != DEFAULT_PARAM && mSSRC != packet->ssrc)
- {
- IMLOGW0("[collectInfo] ssrc changed");
- }
-
- // for call qualty report
+ // for call quality report
mCallQuality.setNumRtpPacketsReceived(mCallQuality.getNumRtpPacketsReceived() + 1);
mCallQualitySumRelativeJitter += packet->jitter;
@@ -186,8 +212,8 @@ void MediaQualityAnalyzer::collectInfo(const int32_t streamType, RtpPacket* pack
break;
}
- // for loss rate, jitter check
- if (mSSRC == DEFAULT_PARAM) // stream is reset
+ // for jitter check
+ if (mSSRC != packet->ssrc) // stream is reset
{
mJitterRxPacket = std::abs(packet->jitter);
// update rtcp-xr params
@@ -396,7 +422,7 @@ void MediaQualityAnalyzer::processData(const int32_t timeCount)
void MediaQualityAnalyzer::processMediaQuality()
{
// media quality rtp inactivity
- if (mNumRxPacket == 0)
+ if (mNumRxPacket == 0 && mIsRxRtpEnabled)
{
mCountRtpInactivity += 1000;
}
@@ -408,7 +434,7 @@ void MediaQualityAnalyzer::processMediaQuality()
}
// media quality rtcp inactivity
- if (mNumRtcpPacketReceived == 0)
+ if (mNumRtcpPacketReceived == 0 && mIsRtcpEnabled)
{
mCountRtcpInactivity += 1000;
}
@@ -424,7 +450,7 @@ void MediaQualityAnalyzer::processMediaQuality()
if (mPacketLossDuration != 0 && !mListLostPacket.empty())
{
- // calculate loss in duration
+ // counts received packets for the duration
int32_t numReceivedPacketsInDuration =
std::count_if(mListRxPacket.begin(), mListRxPacket.end(),
[=](RtpPacket* packet)
@@ -433,12 +459,21 @@ void MediaQualityAnalyzer::processMediaQuality()
mPacketLossDuration);
});
+ // cumulates the number of lost packets for the duration
+ std::list<LostPacket*> listLostPacketInDuration;
+ std::copy_if(mListLostPacket.begin(), mListLostPacket.end(),
+ std::back_inserter(listLostPacketInDuration),
+ [=](LostPacket* packet)
+ {
+ return (ImsMediaTimer::GetTimeInMilliSeconds() - packet->markedTime <=
+ mPacketLossDuration);
+ });
+
int32_t numLostPacketsInDuration =
- std::count_if(mListLostPacket.begin(), mListLostPacket.end(),
- [=](LostPacket* packet)
+ std::accumulate(begin(listLostPacketInDuration), end(listLostPacketInDuration), 0,
+ [=](int i, const LostPacket* packet)
{
- return (ImsMediaTimer::GetTimeInMilliSeconds() - packet->markedTime <=
- mPacketLossDuration);
+ return packet->numLoss + i;
});
if (numLostPacketsInDuration == 0 || numReceivedPacketsInDuration == 0)
@@ -450,8 +485,8 @@ void MediaQualityAnalyzer::processMediaQuality()
int32_t lossRate = numLostPacketsInDuration * 100 /
(numReceivedPacketsInDuration + numLostPacketsInDuration);
- IMLOGD3("[processData] mediaQualtyStatus lossRate[%d], received[%d], lost[%d]",
- lossRate, numReceivedPacketsInDuration, numLostPacketsInDuration);
+ IMLOGD3("[processMediaQuality] lossRate[%d], received[%d], lost[%d]", lossRate,
+ numReceivedPacketsInDuration, numLostPacketsInDuration);
mQualityStatus.setRtpPacketLossRate(lossRate);
}
}
@@ -460,6 +495,27 @@ void MediaQualityAnalyzer::processMediaQuality()
mQualityStatus.setRtpPacketLossRate(0);
}
+ bool shouldNotify = false;
+
+ // check jitter notification
+ if (!mJitterThreshold.empty() && mIsRxRtpEnabled)
+ {
+ if (mJitterChecker.checkNotifiable(mJitterThreshold, mQualityStatus.getRtpJitterMillis()))
+ {
+ shouldNotify = true;
+ }
+ }
+
+ // check packet loss notification
+ if (!mPacketLossThreshold.empty() && mIsRxRtpEnabled)
+ {
+ if (mPacketLossChecker.checkNotifiable(
+ mPacketLossThreshold, mQualityStatus.getRtpPacketLossRate()))
+ {
+ shouldNotify = true;
+ }
+ }
+
IMLOGD_PACKET4(IM_PACKET_LOG_RTP,
"[processMediaQuality] rtpInactivity[%d], rtcpInactivity[%d], lossRate[%d], "
"jitter[%d]",
@@ -474,7 +530,7 @@ void MediaQualityAnalyzer::processMediaQuality()
return;
}
- if (!mCurrentRtpInactivityTimes.empty())
+ if (!mCurrentRtpInactivityTimes.empty() && mIsRxRtpEnabled)
{
std::vector<int32_t>::iterator rtpIter = std::find_if(mCurrentRtpInactivityTimes.begin(),
mCurrentRtpInactivityTimes.end(),
@@ -492,32 +548,16 @@ void MediaQualityAnalyzer::processMediaQuality()
}
}
- if (mRtcpInactivityTime != 0 && mCountRtcpInactivity == mRtcpInactivityTime)
+ if (mRtcpInactivityTime != 0 && mCountRtcpInactivity == mRtcpInactivityTime && mIsRtcpEnabled)
{
notifyMediaQualityStatus();
mCountRtcpInactivity = 0;
return;
}
- // check jitter notification
- if (!mJitterThreshold.empty())
+ if (shouldNotify)
{
- if (mJitterChecker.checkNotifiable(mJitterThreshold, mQualityStatus.getRtpJitterMillis()))
- {
- notifyMediaQualityStatus();
- return;
- }
- }
-
- // check packet loss notification
- if (!mPacketLossThreshold.empty())
- {
- if (mPacketLossChecker.checkNotifiable(
- mPacketLossThreshold, mQualityStatus.getRtpPacketLossRate()))
- {
- notifyMediaQualityStatus();
- return;
- }
+ notifyMediaQualityStatus();
}
}
@@ -585,7 +625,11 @@ uint32_t MediaQualityAnalyzer::getTxPacketSize()
uint32_t MediaQualityAnalyzer::getLostPacketSize()
{
- return mListLostPacket.size();
+ return std::accumulate(begin(mListLostPacket), end(mListLostPacket), 0,
+ [](int i, const LostPacket* packet)
+ {
+ return packet->numLoss + i;
+ });
}
void MediaQualityAnalyzer::SendEvent(uint32_t event, uint64_t paramA, uint64_t paramB)
@@ -740,6 +784,17 @@ void MediaQualityAnalyzer::reset()
mNumRxPacket = 0;
mNumLostPacket = 0;
mJitterRxPacket = 0.0;
+
+ // rtp and rtcp inactivity
+ mCountRtpInactivity = 0;
+ mCountRtcpInactivity = 0;
+ mNumRtcpPacketReceived = 0;
+
+ // reset the status
+ mQualityStatus = MediaQualityStatus();
+
+ mPacketLossChecker.initialize(mRtpHysteresisTime);
+ mJitterChecker.initialize(mRtpHysteresisTime);
}
void MediaQualityAnalyzer::clearPacketList(std::list<RtpPacket*>& list, const int32_t seq)
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/android/ImsMediaAudioPlayer.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/android/ImsMediaAudioPlayer.cpp
index 2f71f13e..99ba77cc 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/android/ImsMediaAudioPlayer.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/android/ImsMediaAudioPlayer.cpp
@@ -40,10 +40,19 @@ ImsMediaAudioPlayer::ImsMediaAudioPlayer()
{
mAudioStream = nullptr;
mCodec = nullptr;
+ mFormat = nullptr;
+ mCodecType = 0;
+ mCodecMode = 0;
mSamplingRate = DEFAULT_SAMPLING_RATE;
+ mEvsChAwOffset = 0;
+ mEvsBandwidth = kEvsBandwidthNone;
+ memset(mBuffer, 0, sizeof(mBuffer));
+ mEvsBitRate = 0;
mEvsCodecHeaderMode = kRtpPyaloadHeaderModeEvsHeaderFull;
- mFirstFrame = false;
+ mIsFirstFrame = false;
mIsEvsInitialized = false;
+ mIsOctetAligned = false;
+ mIsDtxEnabled = false;
}
ImsMediaAudioPlayer::~ImsMediaAudioPlayer() {}
@@ -85,6 +94,16 @@ void ImsMediaAudioPlayer::SetCodecMode(uint32_t mode)
mCodecMode = mode;
}
+void ImsMediaAudioPlayer::SetDtxEnabled(bool isDtxEnabled)
+{
+ mIsDtxEnabled = isDtxEnabled;
+}
+
+void ImsMediaAudioPlayer::SetOctetAligned(bool isOctetAligned)
+{
+ mIsOctetAligned = isOctetAligned;
+}
+
bool ImsMediaAudioPlayer::Start()
{
char kMimeType[128] = {'\0'};
@@ -368,10 +387,10 @@ bool ImsMediaAudioPlayer::decodeEvs(uint8_t* buffer, uint32_t size)
mIsEvsInitialized = true;
}
- if (!mFirstFrame)
+ if (!mIsFirstFrame)
{
IMLOGD0("[decodeEvs] First frame has been decoded");
- mFirstFrame = true;
+ mIsFirstFrame = true;
}
AAudioStream_write(mAudioStream, output, (decodeSize / 2), 0);
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/android/ImsMediaAudioSource.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/android/ImsMediaAudioSource.cpp
index 9117e0ad..d383cfd1 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/android/ImsMediaAudioSource.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/android/ImsMediaAudioSource.cpp
@@ -50,6 +50,8 @@ ImsMediaAudioSource::ImsMediaAudioSource()
mEvsChAwOffset = 0;
mIsEvsInitialized = false;
mMediaDirection = 0;
+ mIsDtxEnabled = false;
+ mIsOctetAligned = false;
}
ImsMediaAudioSource::~ImsMediaAudioSource() {}
@@ -104,6 +106,16 @@ void ImsMediaAudioSource::SetMediaDirection(int32_t direction)
mMediaDirection = direction;
}
+void ImsMediaAudioSource::SetDtxEnabled(bool isDtxEnabled)
+{
+ mIsDtxEnabled = isDtxEnabled;
+}
+
+void ImsMediaAudioSource::SetOctetAligned(bool isOctetAligned)
+{
+ mIsOctetAligned = isOctetAligned;
+}
+
bool ImsMediaAudioSource::Start()
{
char kMimeType[128] = {'\0'};
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/android/include/ImsMediaAudioPlayer.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/android/include/ImsMediaAudioPlayer.h
index 1b19e342..92c12d9d 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/android/include/ImsMediaAudioPlayer.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/android/include/ImsMediaAudioPlayer.h
@@ -82,6 +82,21 @@ public:
void SetEvsPayloadHeaderMode(int32_t EvsPayloadHeaderMode);
/**
+ * @brief Set Whether discontinuous transmission is enabled or not
+ *
+ * @params isDtxEnabled, if set to true then enable discontinuous transmission
+ */
+ void SetDtxEnabled(bool isDtxEnabled);
+
+ /**
+ * @brief Setting octet-align for AMR/AMR-WB
+ *
+ * @params isOctetAligned, If it's set to true then all fields in the AMR/AMR-WB header
+ * shall be aligned to octet boundaries by adding padding bits.
+ */
+ void SetOctetAligned(bool isOctetAligned);
+
+ /**
* @brief Starts audio player to play the decoded audio frame and ndk audio decoder to decode
* the given data
*
@@ -127,8 +142,10 @@ private:
std::mutex mMutex;
int32_t mEvsBitRate;
kRtpPyaloadHeaderMode mEvsCodecHeaderMode;
- bool mFirstFrame;
+ bool mIsFirstFrame;
bool mIsEvsInitialized;
+ bool mIsDtxEnabled;
+ bool mIsOctetAligned;
};
#endif
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/android/include/ImsMediaAudioSource.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/android/include/ImsMediaAudioSource.h
index 63ed1ad7..d838a8cc 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/android/include/ImsMediaAudioSource.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/android/include/ImsMediaAudioSource.h
@@ -102,6 +102,21 @@ public:
void SetMediaDirection(int32_t direction);
/**
+ * @brief Set Whether discontinuous transmission is enabled or not
+ *
+ * @params isDtxEnabled, if set to true then enable discontinuous transmission
+ */
+ void SetDtxEnabled(bool isDtxEnabled);
+
+ /**
+ * @brief Setting octet-align for AMR/AMR-WB
+ *
+ * @params isOctetAligned, If it's set to true then all fields in the AMR/AMR-WB header
+ * shall be aligned to octet boundaries by adding padding bits.
+ */
+ void SetOctetAligned(bool isOctetAligned);
+
+ /**
* @brief Starts aaudio and ndk audio codec to get the audio frame and encode the audio frames
* with given configuration
*
@@ -149,6 +164,8 @@ private:
ImsMediaCondition mConditionExit;
bool mIsEvsInitialized;
int32_t mMediaDirection;
+ bool mIsDtxEnabled;
+ bool mIsOctetAligned;
};
#endif
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/AudioRtpPayloadDecoderNode.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/AudioRtpPayloadDecoderNode.cpp
index 2525acfd..279557fc 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/AudioRtpPayloadDecoderNode.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/AudioRtpPayloadDecoderNode.cpp
@@ -49,7 +49,7 @@ ImsMediaResult AudioRtpPayloadDecoderNode::Start()
mEvsMode = (kEvsBitrate)ImsMediaAudioUtil::GetMaximumEvsMode(mCoreEvsMode);
mEvsCodecMode = (kEvsCodecMode)ImsMediaAudioUtil::ConvertEvsCodecMode(mEvsMode);
- mPrevCMR = 15;
+ mPrevCMR = mCodecType == kAudioCodecEvs ? 127 : 15;
mListFrameType.clear();
mNodeState = kNodeStateRunning;
return RESULT_SUCCESS;
@@ -133,7 +133,7 @@ void AudioRtpPayloadDecoderNode::OnDataFromFrontNode(ImsMediaSubType subtype, ui
{
case kAudioCodecAmr:
case kAudioCodecAmrWb:
- DecodePayloadAmr(pData, nDataSize, nTimestamp, bMark, nSeqNum, arrivalTime);
+ DecodePayloadAmr(pData, nDataSize, nTimestamp, nSeqNum, arrivalTime);
break;
case kAudioCodecPcmu:
case kAudioCodecPcma:
@@ -152,14 +152,13 @@ void AudioRtpPayloadDecoderNode::OnDataFromFrontNode(ImsMediaSubType subtype, ui
}
void AudioRtpPayloadDecoderNode::DecodePayloadAmr(uint8_t* pData, uint32_t nDataSize,
- uint32_t nTimestamp, bool bMark, uint32_t nSeqNum, uint32_t arrivalTime)
+ uint32_t nTimestamp, uint32_t nSeqNum, uint32_t arrivalTime)
{
if (pData == nullptr || nDataSize == 0)
{
return;
}
- (void)bMark;
uint32_t timestamp = nTimestamp;
uint32_t eRate;
uint32_t f;
@@ -167,9 +166,9 @@ void AudioRtpPayloadDecoderNode::DecodePayloadAmr(uint8_t* pData, uint32_t nData
uint32_t QbitPos; // Q_Speech_Sid_Bad
IMLOGD_PACKET5(IM_PACKET_LOG_PH,
- "[DecodePayloadAmr] GetCodectype[%d], octetAligned[%d], nSeqNum[%d], TS[%u], "
+ "[DecodePayloadAmr] codec type[%d], octetAligned[%d], size[%d], TS[%u], "
"arrivalTime[%u]",
- mCodecType, mOctetAligned, nSeqNum, timestamp, arrivalTime);
+ mCodecType, mOctetAligned, nDataSize, timestamp, arrivalTime);
mBitReader.SetBuffer(pData, nDataSize);
// read cmr
@@ -236,19 +235,20 @@ void AudioRtpPayloadDecoderNode::DecodePayloadAmr(uint8_t* pData, uint32_t nData
mListFrameType.pop_front();
mBitWriter.SetBuffer(mPayload, MAX_AUDIO_PAYLOAD_SIZE);
- // set payload header
+ uint32_t bufferSize = (nDataBitSize + 7) >> 3;
+ // set TOC
mBitWriter.Write(f, 1);
mBitWriter.Write(eRate, 4);
mBitWriter.Write(QbitPos, 1);
mBitWriter.Write(0, 2);
mBitReader.ReadByteBuffer(mPayload + 1, nDataBitSize);
- // add payload header to payload size
- uint32_t nBufferSize = ((nDataBitSize + 7) >> 3) + 1;
+ bufferSize++;
+
IMLOGD_PACKET6(IM_PACKET_LOG_PH,
"[DecodePayloadAmr] result = %02X %02X %02X %02X, len[%d], eRate[%d]", mPayload[0],
- mPayload[1], mPayload[2], mPayload[3], nBufferSize, eRate);
+ mPayload[1], mPayload[2], mPayload[3], bufferSize, eRate);
// send remaining packet number in bundle as bMark value
- SendDataToRearNode(MEDIASUBTYPE_RTPPAYLOAD, mPayload, nBufferSize, timestamp,
+ SendDataToRearNode(MEDIASUBTYPE_RTPPAYLOAD, mPayload, bufferSize, timestamp,
mListFrameType.size(), nSeqNum, MEDIASUBTYPE_UNDEFINED, arrivalTime);
timestamp += 20;
@@ -263,10 +263,9 @@ void AudioRtpPayloadDecoderNode::DecodePayloadEvs(uint8_t* pData, uint32_t nData
return;
}
- IMLOGD_PACKET5(IM_PACKET_LOG_PH,
- "[DecodePayloadEvs] GetCodectype[%d], octetAligned[%d], nSeqNum[%d], TS[%u], "
- "arrivalTime[%u]",
- mCodecType, mOctetAligned, nSeqNum, nTimeStamp, arrivalTime);
+ IMLOGD_PACKET4(IM_PACKET_LOG_PH,
+ "[DecodePayloadEvs] codec type[%d], size[%d], TS[%u], arrivalTime[%u]", mCodecType,
+ nDataSize, nTimeStamp, arrivalTime);
kRtpPyaloadHeaderMode eEVSReceivedPHFormat = kRtpPyaloadHeaderModeEvsCompact;
kEvsCodecMode kEvsCodecMode = kEvsCodecModePrimary;
@@ -321,7 +320,7 @@ void AudioRtpPayloadDecoderNode::DecodePayloadEvs(uint8_t* pData, uint32_t nData
mBitReader.ReadByteBuffer(mPayload, nDataBitSize);
- IMLOGD6("[DecodePayloadEvs] Result =%02X %02X %02X %02X, len=%d,nFrameType=%d",
+ IMLOGD6("[DecodePayloadEvs] Result=%02X %02X %02X %02X, len=%d,nFrameType=%d",
mPayload[0], mPayload[1], mPayload[2], mPayload[3], nDataSize, nFrameType);
SendDataToRearNode(MEDIASUBTYPE_RTPPAYLOAD, mPayload, nDataSize, timestamp, bMark,
@@ -608,7 +607,6 @@ void AudioRtpPayloadDecoderNode::DecodePayloadEvs(uint8_t* pData, uint32_t nData
}
else // ToC byte
{
- IMLOGD0("[DecodePayloadEvs] Decoding TOC header");
toc_f = mBitReader.Read(1);
toc_ft_m = mBitReader.Read(1);
toc_ft_q = mBitReader.Read(1);
@@ -636,14 +634,16 @@ void AudioRtpPayloadDecoderNode::DecodePayloadEvs(uint8_t* pData, uint32_t nData
}
mBitWriter.SetBuffer(mPayload, MAX_AUDIO_PAYLOAD_SIZE);
+ uint32_t bufferSize = (nDataBitSize + 7) >> 3;
+ // set TOC
mBitWriter.Write(h, 1);
mBitWriter.Write(toc_f, 1);
mBitWriter.Write(toc_ft_m, 1);
mBitWriter.Write(toc_ft_q, 1);
mBitWriter.Write(toc_ft_b, 4);
-
mBitReader.ReadByteBuffer(mPayload + 1, nDataBitSize);
+ bufferSize++;
// remove padding bit
{
@@ -653,10 +653,10 @@ void AudioRtpPayloadDecoderNode::DecodePayloadEvs(uint8_t* pData, uint32_t nData
}
IMLOGD6("[DecodePayloadEvs] result = %02X %02X %02X %02X, len=%d, eRate=%d",
- mPayload[0], mPayload[1], mPayload[2], mPayload[3], nDataSize, toc_ft_b);
+ mPayload[0], mPayload[1], mPayload[2], mPayload[3], bufferSize, toc_ft_b);
- SendDataToRearNode(MEDIASUBTYPE_RTPPAYLOAD, mPayload, (((nDataBitSize + 7) >> 3)),
- timestamp, mListFrameType.size(), nSeqNum, MEDIASUBTYPE_UNDEFINED, arrivalTime);
+ SendDataToRearNode(MEDIASUBTYPE_RTPPAYLOAD, mPayload, bufferSize, timestamp,
+ mListFrameType.size(), nSeqNum, MEDIASUBTYPE_UNDEFINED, arrivalTime);
timestamp += 20;
}
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/AudioRtpPayloadEncoderNode.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/AudioRtpPayloadEncoderNode.cpp
index 028eba2d..cffcb2c8 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/AudioRtpPayloadEncoderNode.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/AudioRtpPayloadEncoderNode.cpp
@@ -51,11 +51,13 @@ kBaseNodeId AudioRtpPayloadEncoderNode::GetNodeId()
ImsMediaResult AudioRtpPayloadEncoderNode::Start()
{
- IMLOGD2("[Start] codecType[%d], mode[%d]", mCodecType, mOctetAligned);
mMaxNumOfFrame = mPtime / 20;
mEvsMode = (kEvsBitrate)ImsMediaAudioUtil::GetMaximumEvsMode(mCoreEvsMode);
mEvsCodecMode = (kEvsCodecMode)ImsMediaAudioUtil::ConvertEvsCodecMode(mEvsMode);
+ IMLOGD5("[Start] codecType[%d], mode[%d], num of frames[%d], evs bitrate[%d], evs mode[%d]",
+ mCodecType, mOctetAligned, mMaxNumOfFrame, mEvsMode, mEvsCodecMode);
+
if (mMaxNumOfFrame == 0 || mMaxNumOfFrame > MAX_FRAME_IN_PACKET)
{
IMLOGE1("[Start] Invalid ptime [%d]", mPtime);
@@ -86,16 +88,15 @@ bool AudioRtpPayloadEncoderNode::IsSourceNode()
return false;
}
-void AudioRtpPayloadEncoderNode::OnDataFromFrontNode(ImsMediaSubType subtype, uint8_t* pData,
+void AudioRtpPayloadEncoderNode::OnDataFromFrontNode(ImsMediaSubType /*subtype*/, uint8_t* pData,
uint32_t nDataSize, uint32_t nTimestamp, bool bMark, uint32_t nSeqNum,
ImsMediaSubType nDataType, uint32_t arrivalTime)
{
- (void)subtype;
switch (mCodecType)
{
case kAudioCodecAmr:
case kAudioCodecAmrWb:
- EncodePayloadAmr(pData, nDataSize, nTimestamp, bMark);
+ EncodePayloadAmr(pData, nDataSize, nTimestamp);
break;
case kAudioCodecPcmu:
case kAudioCodecPcma:
@@ -166,16 +167,15 @@ bool AudioRtpPayloadEncoderNode::IsSameConfig(void* config)
}
void AudioRtpPayloadEncoderNode::EncodePayloadAmr(
- uint8_t* pData, uint32_t nDataSize, uint32_t nTimestamp, bool bMark)
+ uint8_t* pData, uint32_t nDataSize, uint32_t nTimestamp)
{
- (void)bMark;
uint32_t nCmr = 15;
uint32_t f, ft, q, nDataBitSize;
-#ifndef LEGACY_AUDIO_ENABLED // for ap audio test
+ // remove TOC from the encoder
pData++;
nDataSize -= 1;
-#endif
+
if (nDataSize > 4)
{
IMLOGD_PACKET5(IM_PACKET_LOG_PH, "[EncodePayloadAmr] src = %02X %02X %02X %02X, len[%d]",
@@ -277,28 +277,18 @@ void AudioRtpPayloadEncoderNode::EncodePayloadAmr(
void AudioRtpPayloadEncoderNode::EncodePayloadEvs(
uint8_t* pData, uint32_t nDataSize, uint32_t nTimeStamp)
{
- kRtpPyaloadHeaderMode eEVSPayloadFormat = kRtpPyaloadHeaderModeEvsHeaderFull;
- kEvsCodecMode kEvsCodecMode;
-
- // 0111 1111 is no request.
- uint32_t nEVSBW = 0x07;
- uint32_t nEVSBR = 0x0f;
- uint32_t nFrameType = 0;
-
if (nDataSize == 0)
{
return;
}
- eEVSPayloadFormat = mEvsPayloadHeaderMode;
+ uint32_t nFrameType = 0;
// compact or header-full format, default is compact formats
- kEvsCodecMode = mEvsCodecMode;
-
// primary or amr-wb io mode, default is primary mode
// primary or amr-wb io mode base on frameSize.
mCurrNumOfFrame++;
- if (eEVSPayloadFormat == kRtpPyaloadHeaderModeEvsCompact)
+ if (mEvsPayloadHeaderMode == kRtpPyaloadHeaderModeEvsCompact)
{
memset(mPayload, 0, MAX_AUDIO_PAYLOAD_SIZE);
mBWHeader.SetBuffer(mPayload, MAX_AUDIO_PAYLOAD_SIZE);
@@ -306,7 +296,7 @@ void AudioRtpPayloadEncoderNode::EncodePayloadEvs(
mTimestamp = nTimeStamp;
// exactly one coded frame without any additional EVS RTP payload header
- if (kEvsCodecMode == kEvsCodecModePrimary)
+ if (mEvsCodecMode == kEvsCodecModePrimary)
{
// calculate nDataBitSize from nDataSize
nFrameType = (uint32_t)ImsMediaAudioUtil::ConvertLenToEVSAudioMode(nDataSize);
@@ -354,9 +344,8 @@ void AudioRtpPayloadEncoderNode::EncodePayloadEvs(
mFirstFrame = false;
}
// one 3-bit CMR field, one coded frame, and zero-padding bits if necessary
- else if (kEvsCodecMode == kEvsCodecModeAmrIo)
+ else if (mEvsCodecMode == kEvsCodecModeAmrIo)
{
- IMLOGE0("[EncodePayloadEvs] COMPACT and AMR_WB_IO");
// calculate nDataBitSize from nDataSize
nFrameType = (uint32_t)ImsMediaAudioUtil::ConvertLenToAmrWbMode(nDataSize);
uint32_t nDataBitSize = ImsMediaAudioUtil::ConvertAmrWbModeToBitLen(nFrameType);
@@ -447,17 +436,23 @@ void AudioRtpPayloadEncoderNode::EncodePayloadEvs(
return;
}
}
- else if (eEVSPayloadFormat == kRtpPyaloadHeaderModeEvsHeaderFull)
+ else if (mEvsPayloadHeaderMode == kRtpPyaloadHeaderModeEvsHeaderFull)
{
+ // 0111 1111 is no request.
+ uint32_t nEVSBW = 0x07;
+ uint32_t nEVSBR = 0x0f;
+
+ // remove 1 byte toc field from the codec
+ pData++;
+ nDataSize--;
+
uint32_t cmr_h, cmr_t, cmr_d = 0; // CMR byte
memset(mPayload, 0, MAX_AUDIO_PAYLOAD_SIZE);
mBWHeader.SetBuffer(mPayload, MAX_AUDIO_PAYLOAD_SIZE);
mBWPayload.SetBuffer(mPayload, MAX_AUDIO_PAYLOAD_SIZE);
- if (kEvsCodecMode == kEvsCodecModePrimary)
+ if (mEvsCodecMode == kEvsCodecModePrimary)
{
- IMLOGE0("[EncodePayloadEvs] HF and PRI");
-
if (nFrameType == kImsAudioEvsPrimaryModeSID || mSendCMR) // CMR value
{
// Header Type identification bit(1bit) - always set to 1
@@ -537,9 +532,8 @@ void AudioRtpPayloadEncoderNode::EncodePayloadEvs(
mFirstFrame = false;
}
}
- else if (kEvsCodecMode == kEvsCodecModeAmrIo)
+ else if (mEvsCodecMode == kEvsCodecModeAmrIo)
{
- IMLOGE0("[EncodePayloadEvs] HF and AMR_WB_IO");
// set CMR byte
// at EVS AMR WB IO Mode, CMR field shall include.
// Header Type identification bit(1bit) - always set to 1
@@ -624,8 +618,7 @@ void AudioRtpPayloadEncoderNode::EncodePayloadEvs(
IMLOGE0("[EncodePayloadEvs] invalid codec mode");
return;
}
-
- } // end of if(eEVSPayloadFormat == kRtpPyaloadHeaderModeEvsHeaderFull)
+ }
else
{
IMLOGE0("[EncodePayloadEvs] invalid payload format");
@@ -637,19 +630,17 @@ void AudioRtpPayloadEncoderNode::EncodePayloadEvs(
uint32_t AudioRtpPayloadEncoderNode::CheckPaddingNecessity(uint32_t nTotalSize)
{
- kEvsCodecMode kEvsCodecMode;
+ kEvsCodecMode evsCodecMode;
uint32_t nEVSCompactId;
uint32_t nSize = nTotalSize;
// check EVS compact size
while (nSize != 0 &&
- ImsMediaAudioUtil::ConvertEVSPayloadMode(nSize, &kEvsCodecMode, &nEVSCompactId) ==
+ ImsMediaAudioUtil::ConvertEVSPayloadMode(nSize, &evsCodecMode, &nEVSCompactId) ==
kRtpPyaloadHeaderModeEvsCompact)
{
mPayload[nSize] = 0;
nSize++;
-
- IMLOGD1("[CheckPaddingNecessity] Add Padding - size[%d]", nSize);
}
return nSize;
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/IAudioPlayerNode.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/IAudioPlayerNode.cpp
index c37fba98..14acf360 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/IAudioPlayerNode.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/IAudioPlayerNode.cpp
@@ -29,6 +29,8 @@ IAudioPlayerNode::IAudioPlayerNode(BaseSessionCallback* callback) :
std::unique_ptr<ImsMediaAudioPlayer> track(new ImsMediaAudioPlayer());
mAudioPlayer = std::move(track);
mConfig = nullptr;
+ mIsOctetAligned = false;
+ mIsDtxEnabled = false;
}
IAudioPlayerNode::~IAudioPlayerNode()
@@ -59,6 +61,8 @@ ImsMediaResult IAudioPlayerNode::ProcessStart()
{
mAudioPlayer->SetCodec(mCodecType);
mAudioPlayer->SetSamplingRate(mSamplingRate * 1000);
+ mAudioPlayer->SetDtxEnabled(mIsDtxEnabled);
+ mAudioPlayer->SetOctetAligned(mIsOctetAligned);
if (mCodecType == kAudioCodecEvs)
{
@@ -76,7 +80,6 @@ ImsMediaResult IAudioPlayerNode::ProcessStart()
IMLOGE0("[IAudioPlayer] Not able to start AudioPlayer");
}
- mFirstFrame = false;
mNodeState = kNodeStateRunning;
StartThread();
return RESULT_SUCCESS;
@@ -130,6 +133,7 @@ void IAudioPlayerNode::SetConfig(void* config)
if (mCodecType == kAudioCodecAmr || mCodecType == kAudioCodecAmrWb)
{
mMode = mConfig->getAmrParams().getAmrMode();
+ mIsOctetAligned = mConfig->getAmrParams().getOctetAligned();
}
else if (mCodecType == kAudioCodecEvs)
{
@@ -141,7 +145,8 @@ void IAudioPlayerNode::SetConfig(void* config)
}
mSamplingRate = mConfig->getSamplingRateKHz();
- SetJitterBufferSize(4, 4, 9);
+ mIsDtxEnabled = mConfig->getDtxEnabled();
+ SetJitterBufferSize(3, 3, 9);
SetJitterOptions(
80, 1, (double)25 / 10, false /** TODO: when enable DTX, set this true on condition*/
);
@@ -161,7 +166,9 @@ bool IAudioPlayerNode::IsSameConfig(void* config)
if (mCodecType == kAudioCodecAmr || mCodecType == kAudioCodecAmrWb)
{
return (mMode == pConfig->getAmrParams().getAmrMode() &&
- mSamplingRate == pConfig->getSamplingRateKHz());
+ mSamplingRate == pConfig->getSamplingRateKHz() &&
+ mIsDtxEnabled == pConfig->getDtxEnabled() &&
+ mIsOctetAligned == pConfig->getAmrParams().getOctetAligned());
}
else if (mCodecType == kAudioCodecEvs)
{
@@ -171,7 +178,8 @@ bool IAudioPlayerNode::IsSameConfig(void* config)
pConfig->getEvsParams().getEvsBandwidth()) &&
mEvsChannelAwOffset == pConfig->getEvsParams().getChannelAwareMode() &&
mSamplingRate == pConfig->getSamplingRateKHz() &&
- mEvsPayloadHeaderMode == pConfig->getEvsParams().getUseHeaderFullOnly());
+ mEvsPayloadHeaderMode == pConfig->getEvsParams().getUseHeaderFullOnly() &&
+ mIsDtxEnabled == pConfig->getDtxEnabled());
}
}
@@ -189,6 +197,7 @@ void* IAudioPlayerNode::run()
bool bMark = false;
uint32_t nSeqNum = 0;
uint64_t nNextTime = ImsMediaTimer::GetTimeInMicroSeconds();
+ bool isFirstFrameReceived = false;
while (true)
{
@@ -201,24 +210,28 @@ void* IAudioPlayerNode::run()
if (GetData(&subtype, &pData, &nDataSize, &nTimestamp, &bMark, &nSeqNum, &datatype) == true)
{
+ IMLOGD_PACKET2(IM_PACKET_LOG_AUDIO, "[run] write buffer size[%d], TS[%u]", nDataSize,
+ nTimestamp);
if (nDataSize != 0)
{
- IMLOGD_PACKET2(IM_PACKET_LOG_AUDIO, "[run] write buffer size[%d], TS[%u]",
- nDataSize, nTimestamp);
if (mAudioPlayer->onDataFrame(pData, nDataSize))
{
// send buffering complete message to client
- if (mFirstFrame == false)
+ if (isFirstFrameReceived == false)
{
mCallback->SendEvent(kImsMediaEventFirstPacketReceived,
reinterpret_cast<uint64_t>(new AudioConfig(*mConfig)));
- mFirstFrame = true;
+ isFirstFrameReceived = true;
}
}
}
-
DeleteData();
}
+ else if (isFirstFrameReceived)
+ {
+ IMLOGE0("[run] GetData returned 0 bytes");
+ mAudioPlayer->onDataFrame(nullptr, 0);
+ }
nNextTime += 20000;
uint64_t nCurrTime = ImsMediaTimer::GetTimeInMicroSeconds();
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/IAudioSourceNode.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/IAudioSourceNode.cpp
index 8bedca46..3eff8305 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/IAudioSourceNode.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/nodes/IAudioSourceNode.cpp
@@ -33,6 +33,8 @@ IAudioSourceNode::IAudioSourceNode(BaseSessionCallback* callback) :
mRunningCodecMode = 0;
mFirstFrame = false;
mMediaDirection = 0;
+ mIsOctetAligned = false;
+ mIsDtxEnabled = false;
}
IAudioSourceNode::~IAudioSourceNode() {}
@@ -54,6 +56,8 @@ ImsMediaResult IAudioSourceNode::ProcessStart()
mAudioSource->SetPtime(mPtime);
mAudioSource->SetSamplingRate(mSamplingRate * 1000);
mAudioSource->SetMediaDirection(mMediaDirection);
+ mAudioSource->SetDtxEnabled(mIsDtxEnabled);
+ mAudioSource->SetOctetAligned(mIsOctetAligned);
if (mCodecType == kAudioCodecEvs)
{
@@ -120,6 +124,7 @@ void IAudioSourceNode::SetConfig(void* config)
if (mCodecType == kAudioCodecAmr || mCodecType == kAudioCodecAmrWb)
{
mCodecMode = pConfig->getAmrParams().getAmrMode();
+ mIsOctetAligned = pConfig->getAmrParams().getOctetAligned();
}
else if (mCodecType == kAudioCodecEvs)
{
@@ -132,6 +137,7 @@ void IAudioSourceNode::SetConfig(void* config)
mMediaDirection = pConfig->getMediaDirection();
mSamplingRate = pConfig->getSamplingRateKHz();
mPtime = pConfig->getPtimeMillis();
+ mIsDtxEnabled = pConfig->getDtxEnabled();
}
bool IAudioSourceNode::IsSameConfig(void* config)
@@ -149,7 +155,9 @@ bool IAudioSourceNode::IsSameConfig(void* config)
{
return (mCodecMode == pConfig->getAmrParams().getAmrMode() &&
mSamplingRate == pConfig->getSamplingRateKHz() &&
- mMediaDirection == pConfig->getMediaDirection());
+ mMediaDirection == pConfig->getMediaDirection() &&
+ mIsDtxEnabled == pConfig->getDtxEnabled() &&
+ mIsOctetAligned == pConfig->getAmrParams().getOctetAligned());
}
else if (mCodecType == kAudioCodecEvs)
{
@@ -159,7 +167,8 @@ bool IAudioSourceNode::IsSameConfig(void* config)
pConfig->getEvsParams().getEvsBandwidth()) &&
mEvsChAwOffset == pConfig->getEvsParams().getChannelAwareMode() &&
mSamplingRate == pConfig->getSamplingRateKHz() &&
- mMediaDirection == pConfig->getMediaDirection());
+ mMediaDirection == pConfig->getMediaDirection() &&
+ mIsDtxEnabled == pConfig->getDtxEnabled());
}
}
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/ImsMediaDefine.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/ImsMediaDefine.h
index 045051c1..75d70238 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/ImsMediaDefine.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/ImsMediaDefine.h
@@ -52,6 +52,7 @@ enum kImsMediaEventType
kImsMediaEventResolutionChanged,
kImsMediaEventNotifyVideoDataUsage,
kImsMediaEventNotifyRttReceived,
+ kImsMediaEventNotifyVideoLowestBitrate,
};
// Internal Request Event
@@ -331,7 +332,7 @@ enum ImsMediaVideoMsgResponse
kVideoPeerDimensionChanged,
kVideoRtpHeaderExtensionInd,
kVideoMediaInactivityInd,
- kVideoPacketLossInd,
+ kVideoBitrateInd,
kVideoDataUsageInd,
kVideoSessionClosed,
};
@@ -360,7 +361,6 @@ enum ImsMediaTextMsgResponse
#define RTT_MAX_CHAR_PER_SEC (30) // ATIS_GTT : 30 characters per second
#define RTT_MAX_UNICODE_UTF8 (4)
#define MAX_RTT_LEN (RTT_MAX_CHAR_PER_SEC * RTT_MAX_UNICODE_UTF8)
-#define T140_MAX_CHUNK (1)
#define PAYLOADENCODER_TEXT_MAX_REDUNDANT_INTERVAL (16383)
struct EventParamOpenSession
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/JitterNetworkAnalyser.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/JitterNetworkAnalyser.h
index 341d4043..e328a21a 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/JitterNetworkAnalyser.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/JitterNetworkAnalyser.h
@@ -19,6 +19,7 @@
#include <stdint.h>
#include <list>
+#include <mutex>
enum NETWORK_STATUS
{
@@ -67,6 +68,7 @@ private:
double CalculateDeviation(double* pMean);
int32_t GetMaxJitterValue();
+ std::mutex mMutex;
uint32_t mMinJitterBufferSize;
uint32_t mMaxJitterBufferSize;
uint32_t mBasePacketTime;
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/StreamScheduler.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/StreamScheduler.h
index b083096a..f9612c5d 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/StreamScheduler.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/StreamScheduler.h
@@ -37,7 +37,6 @@ public:
virtual void* run();
private:
- BaseNode* DetermineProcessingNode();
void RunRegisteredNode();
std::list<BaseNode*> mlistRegisteredNode;
ImsMediaCondition mConditionMain;
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioJitterBuffer.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioJitterBuffer.h
index 001588fc..2c592514 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioJitterBuffer.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioJitterBuffer.h
@@ -36,7 +36,8 @@ public:
uint32_t* pnTimestamp, bool* pbMark, uint32_t* pnSeqNum, uint32_t currentTime);
private:
- bool IsSID(uint8_t* pbBuffer, uint32_t nBufferSize);
+ bool IsSID(uint32_t nBufferSize);
+ bool Resync(uint32_t currentTime);
void CollectRxRtpStatus(int32_t seq, kRtpPacketStatus status);
void CollectJitterBufferStatus(int32_t currSize, int32_t maxSize);
@@ -48,7 +49,6 @@ private:
bool mEnforceUpdate;
uint32_t mCannotGetCount;
uint32_t mCurrPlayingTS;
- uint16_t mCurrPlayingSeq;
uint32_t mBaseTimestamp;
uint32_t mBaseArrivalTime;
uint32_t mCheckUpdateJitterPacketCnt;
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioManager.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioManager.h
index 231b4141..d2a0e441 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioManager.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioManager.h
@@ -37,10 +37,6 @@ public:
*/
class RequestHandler : public ImsMediaEventHandler
{
- public:
- RequestHandler();
- virtual ~RequestHandler();
-
protected:
virtual void processEvent(
uint32_t event, uint64_t sessionId, uint64_t paramA, uint64_t paramB);
@@ -51,10 +47,6 @@ public:
*/
class ResponseHandler : public ImsMediaEventHandler
{
- public:
- ResponseHandler();
- virtual ~ResponseHandler();
-
protected:
virtual void processEvent(
uint32_t event, uint64_t sessionId, uint64_t paramA, uint64_t paramB);
@@ -63,20 +55,22 @@ public:
static AudioManager* getInstance();
virtual int getState(int sessionId);
virtual void sendMessage(const int sessionId, const android::Parcel& parcel);
- void SendInternalEvent(uint32_t event, uint64_t sessionId, uint64_t paramA, uint64_t paramB);
-private:
+protected:
AudioManager();
virtual ~AudioManager();
ImsMediaResult openSession(int sessionId, int rtpFd, int rtcpFd, AudioConfig* config);
ImsMediaResult closeSession(int sessionId);
ImsMediaResult modifySession(int sessionId, AudioConfig* config);
ImsMediaResult addConfig(int sessionId, AudioConfig* config);
- ImsMediaResult deleteConfig(int sessionId, AudioConfig* config);
+ virtual ImsMediaResult deleteConfig(int sessionId, AudioConfig* config);
ImsMediaResult confirmConfig(int sessionId, AudioConfig* config);
- void sendDtmf(int sessionId, char dtmfDigit, int duration);
- void sendRtpHeaderExtension(int sessionId, std::list<RtpHeaderExtension>* listExtension);
- void setMediaQualityThreshold(int sessionId, MediaQualityThreshold* threshold);
+ virtual void sendDtmf(int sessionId, char dtmfDigit, int duration);
+ virtual void sendRtpHeaderExtension(
+ int sessionId, std::list<RtpHeaderExtension>* listExtension);
+ virtual void setMediaQualityThreshold(int sessionId, MediaQualityThreshold* threshold);
+ virtual void SendInternalEvent(
+ uint32_t event, uint64_t sessionId, uint64_t paramA, uint64_t paramB);
static AudioManager* sManager;
std::unordered_map<int, std::unique_ptr<AudioSession>> mSessions;
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioStreamGraphRtcp.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioStreamGraphRtcp.h
index 9691826c..7253b035 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioStreamGraphRtcp.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/AudioStreamGraphRtcp.h
@@ -27,6 +27,7 @@ public:
virtual ~AudioStreamGraphRtcp();
virtual ImsMediaResult create(RtpConfig* config);
virtual ImsMediaResult update(RtpConfig* config);
+ virtual ImsMediaResult start();
virtual bool OnEvent(int32_t type, uint64_t param1, uint64_t param2);
};
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/MediaQualityAnalyzer.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/MediaQualityAnalyzer.h
index f83ea088..feff4892 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/MediaQualityAnalyzer.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/MediaQualityAnalyzer.h
@@ -256,6 +256,10 @@ protected:
int32_t mCodecType;
/** The codec attribute of the audio session, it could be bandwidth in evs codec */
int32_t mCodecAttribute;
+ /** Whether RTP is activated for the receiver or not */
+ bool mIsRxRtpEnabled;
+ /** Whether RTCP is activated for both sender and receiver */
+ bool mIsRtcpEnabled;
/** The begin of the rx rtp packet sequence number for Rtcp-Xr report */
int32_t mBeginSeq;
/** The end of the rx rtp packet sequence number for Rtcp-Xr report */
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/nodes/AudioRtpPayloadDecoderNode.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/nodes/AudioRtpPayloadDecoderNode.h
index 469ea586..c074f0be 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/nodes/AudioRtpPayloadDecoderNode.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/nodes/AudioRtpPayloadDecoderNode.h
@@ -45,8 +45,8 @@ public:
uint32_t arrivalTime = 0);
private:
- void DecodePayloadAmr(uint8_t* pData, uint32_t nDataSize, uint32_t nTimestamp, bool bMark,
- uint32_t nSeqNum, uint32_t arrivalTime);
+ void DecodePayloadAmr(uint8_t* pData, uint32_t nDataSize, uint32_t nTimestamp, uint32_t nSeqNum,
+ uint32_t arrivalTime);
void DecodePayloadEvs(uint8_t* pData, uint32_t nDataSize, uint32_t nTimeStamp, bool bMark,
uint32_t nSeqNum, uint32_t arrivalTime);
bool ProcessCMRForEVS(kRtpPyaloadHeaderMode eEVSPayloadHeaderMode, kEvsCmrCodeType cmr_t,
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/nodes/AudioRtpPayloadEncoderNode.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/nodes/AudioRtpPayloadEncoderNode.h
index 28adc783..cc3be7f3 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/nodes/AudioRtpPayloadEncoderNode.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/nodes/AudioRtpPayloadEncoderNode.h
@@ -38,7 +38,7 @@ public:
virtual bool IsSameConfig(void* config);
private:
- void EncodePayloadAmr(uint8_t* pData, uint32_t nDataSize, uint32_t nTimestamp, bool bMark);
+ void EncodePayloadAmr(uint8_t* pData, uint32_t nDataSize, uint32_t nTimestamp);
void EncodePayloadEvs(uint8_t* pData, uint32_t nDataSize, uint32_t nTimeStamp);
uint32_t CheckPaddingNecessity(uint32_t nTotalSize);
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/nodes/IAudioPlayerNode.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/nodes/IAudioPlayerNode.h
index cb41c0c6..afea1a56 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/nodes/IAudioPlayerNode.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/nodes/IAudioPlayerNode.h
@@ -49,11 +49,12 @@ private:
int32_t mCodecType;
uint32_t mMode;
ImsMediaCondition mCondition;
- bool mFirstFrame;
int8_t mEvsChannelAwOffset;
kEvsBandwidth mEvsBandwidth;
int8_t mSamplingRate;
int32_t mEvsPayloadHeaderMode;
+ bool mIsDtxEnabled;
+ bool mIsOctetAligned;
};
#endif
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/nodes/IAudioSourceNode.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/nodes/IAudioSourceNode.h
index 1f5d8d6e..741556b0 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/nodes/IAudioSourceNode.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/audio/nodes/IAudioSourceNode.h
@@ -68,6 +68,8 @@ public:
int8_t mSamplingRate;
int8_t mEvsChAwOffset;
int32_t mMediaDirection;
+ bool mIsDtxEnabled;
+ bool mIsOctetAligned;
};
#endif
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/nodes/BaseNode.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/nodes/BaseNode.h
index 9ca79518..c7270c6b 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/nodes/BaseNode.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/nodes/BaseNode.h
@@ -237,6 +237,26 @@ public:
uint32_t* arrivalTime = nullptr);
/**
+ * @brief This method is to add data frame to the queue in the node
+ *
+ * @param data The data buffer
+ * @param size The size of data
+ * @param timestamp The timestamp of data, it can be milliseconds unit or rtp timestamp unit
+ * @param mark It is true when the data has marker bit set
+ * @param seq The sequence number of data. it is 0 when there is no valid sequence number set
+ * @param subtype The subtype of data stored in the queue. It can be various subtype according
+ * to the characteristics of the given data
+ * @param dataType The additional data type for the video frames
+ * @param arrivalTime The arrival time of the packet
+ * @param index The index of the queue to add, if it is not set, add the frame to the end of
+ * the queue
+ */
+ virtual void AddData(uint8_t* data, uint32_t size, uint32_t timestamp, bool mark, uint32_t seq,
+ ImsMediaSubType subtype = ImsMediaSubType::MEDIASUBTYPE_UNDEFINED,
+ ImsMediaSubType dataType = ImsMediaSubType::MEDIASUBTYPE_UNDEFINED,
+ uint32_t arrivalTime = 0, int32_t index = -1);
+
+ /**
* @brief Deletes the data stored in the front of the data queue
*
*/
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/nodes/RtcpEncoderNode.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/nodes/RtcpEncoderNode.h
index 5693f2c9..692e1e76 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/nodes/RtcpEncoderNode.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/nodes/RtcpEncoderNode.h
@@ -45,7 +45,7 @@ public:
/**
* @brief The methods operates when the timer is expired
*/
- void ProcessTimer();
+ virtual void ProcessTimer();
/**
* @brief Set the local ip address and port number
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/nodes/RtpEncoderNode.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/nodes/RtpEncoderNode.h
index 54253073..def41205 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/nodes/RtpEncoderNode.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/nodes/RtpEncoderNode.h
@@ -83,6 +83,7 @@ private:
int8_t mRtpTxDtmfPayload;
int8_t mRtpRxDtmfPayload;
int8_t mDtmfSamplingRate;
+ int32_t mDtmfTimestamp;
int32_t mCvoValue;
int8_t mRedundantPayload;
int8_t mRedundantLevel;
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/text/TextManager.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/text/TextManager.h
index 66201daa..67b24ed3 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/text/TextManager.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/text/TextManager.h
@@ -37,10 +37,6 @@ public:
*/
class RequestHandler : public ImsMediaEventHandler
{
- public:
- RequestHandler();
- virtual ~RequestHandler();
-
protected:
virtual void processEvent(
uint32_t event, uint64_t sessionId, uint64_t paramA, uint64_t paramB);
@@ -51,10 +47,6 @@ public:
*/
class ResponseHandler : public ImsMediaEventHandler
{
- public:
- ResponseHandler();
- virtual ~ResponseHandler();
-
protected:
virtual void processEvent(
uint32_t event, uint64_t sessionId, uint64_t paramA, uint64_t paramB);
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/text/TextStreamGraphRtcp.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/text/TextStreamGraphRtcp.h
index 9832f036..2e5155a1 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/text/TextStreamGraphRtcp.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/text/TextStreamGraphRtcp.h
@@ -27,6 +27,7 @@ public:
virtual ~TextStreamGraphRtcp();
virtual ImsMediaResult create(RtpConfig* config);
virtual ImsMediaResult update(RtpConfig* config);
+ virtual ImsMediaResult start();
virtual bool setMediaQualityThreshold(MediaQualityThreshold* threshold);
};
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/text/nodes/TextSourceNode.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/text/nodes/TextSourceNode.h
index 5b61a77e..5b690c90 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/text/nodes/TextSourceNode.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/text/nodes/TextSourceNode.h
@@ -45,7 +45,7 @@ public:
void SendRtt(const android::String8* text);
private:
- void SendBOM();
+ void SendBom();
int32_t mCodecType;
int8_t mRedundantLevel;
@@ -54,9 +54,6 @@ private:
int32_t mBitrate;
bool mBomEnabled;
bool mSentBOM;
- std::list<uint32_t> mListTextSourceSize;
- std::list<uint8_t*> mListTextSource;
- uint8_t mTextToSend[MAX_RTT_LEN];
std::mutex mMutex;
};
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/utils/ImsMediaBitWriter.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/utils/ImsMediaBitWriter.h
index e4aa8ea9..693b2f5c 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/utils/ImsMediaBitWriter.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/utils/ImsMediaBitWriter.h
@@ -25,9 +25,9 @@ public:
ImsMediaBitWriter();
~ImsMediaBitWriter();
void SetBuffer(uint8_t* pbBuffer, uint32_t nBufferSize);
- void Write(uint32_t nValue, uint32_t nSize);
- void WriteByteBuffer(uint8_t* pbSrc, uint32_t nBitSize);
- void WriteByteBuffer(uint32_t value);
+ bool Write(uint32_t nValue, uint32_t nSize);
+ bool WriteByteBuffer(uint8_t* pbSrc, uint32_t nBitSize);
+ bool WriteByteBuffer(uint32_t value);
void Seek(uint32_t nSize);
void AddPadding();
uint32_t GetBufferSize();
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/utils/ImsMediaEventHandler.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/utils/ImsMediaEventHandler.h
index 4e5dc7f0..e01761da 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/utils/ImsMediaEventHandler.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/utils/ImsMediaEventHandler.h
@@ -46,8 +46,10 @@ private:
std::mutex mMutexEvent;
public:
- ImsMediaEventHandler(const char* strName);
+ ImsMediaEventHandler();
virtual ~ImsMediaEventHandler();
+ void Init(const char* strName);
+ void Deinit();
static void SendEvent(const char* strEventHandlerName, uint32_t event, uint64_t paramA,
uint64_t paramB = 0, uint64_t paramC = 0);
char* getName();
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/utils/ImsMediaImageRotate.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/utils/ImsMediaImageRotate.h
index 939cd670..a0d46ddf 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/utils/ImsMediaImageRotate.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/utils/ImsMediaImageRotate.h
@@ -24,7 +24,7 @@ class ImsMediaImageRotate
public:
/**
* @brief Rotates YUVImage_420_Planar Image by 90 degrees and flips.
- * Supports zero pixel and zero row stride.
+ * Supports input row stride equal to width.
*
* Source Image Destination Image
* + - - - - + + - - - - +
@@ -33,17 +33,18 @@ public:
* | 7 8 9 | | 7 4 1 |
* + - - - - + + - - - - +
*
- * @param pbDst Destination buffer with size nDstWidth*nDstHeight*1.5.
+ * @param pOutBuffer Pointer to output buffer with size nDstWidth*nDstHeight*1.5.
* @param pbSrc Source buffer with size nDstWidth*nDstHeight*1.5.
* @param nSrcWidth Source Image width.
* @param nSrcHeight Source Image height.
*/
static void YUV420_Planar_Rotate90_Flip(
- uint8_t* pbDst, uint8_t* pbSrc, uint16_t nSrcWidth, uint16_t nSrcHeight);
+ uint8_t* pOutBuffer, uint8_t* pbSrc, uint16_t nSrcWidth, uint16_t nSrcHeight);
/**
* @brief Rotates YUVImage_420_888 Image by 90 degrees.
- * Supports zero pixel stride and zero row stride.
+ * Supports input row stride equal to width and adds padding when outputStride is not same
+ * as output image width.
*
* Source Image Destination Image
* + - - - - + + - - - - +
@@ -52,18 +53,22 @@ public:
* | 7 8 9 | | 9 6 3 |
* + - - - - + + - - - - +
*
- * @param pbDst Destination buffer with size nDstWidth*nDstHeight*1.5.
+ * @param pOutBuffer Pointer to output buffer with size outputStride*nDstHeight*1.5.
+ * @param nOutBufSize size of output buffer.
+ * @param outputStride Stride of the output image >= nDstWidth.
* @param pYPlane Y-Plane data of size nDstWidth*nDstHeight.
* @param pUVPlane UV-Plane data of size (nDstWidth*nDstHeight)/2.
* @param nSrcWidth Source Image width.
* @param nSrcHeight Source Image height.
+ *
+ * @return -1 on error and 0 on success.
*/
- static void YUV420_SP_Rotate90(uint8_t* pbDst, uint8_t* pYPlane, uint8_t* pUVPlane,
- uint16_t nSrcWidth, uint16_t nSrcHeight);
+ static int YUV420_SP_Rotate90(uint8_t* pOutBuffer, size_t nOutBufSize, uint16_t outputStride,
+ uint8_t* pYPlane, uint8_t* pUVPlane, uint16_t nSrcWidth, uint16_t nSrcHeight);
/**
* @brief Rotates YUVImage_420_888 Image by 90 degrees and flip.
- * Supports zero pixel stride and zero row stride.
+ * Supports input row stride equal to width.
*
* Source Image Destination Image
* + - - - - + + - - - - +
@@ -72,18 +77,19 @@ public:
* | 7 8 9 | | 7 4 1 |
* + - - - - + + - - - - +
*
- * @param pbDst Destination buffer with size nDstWidth*nDstHeight*1.5.
+ * @param pOutBuffer Pointer to output buffer with size nDstWidth*nDstHeight*1.5.
* @param pYPlane Y-Plane data of size nDstWidth*nDstHeight.
* @param pUVPlane UV-Plane data of size (nDstWidth*nDstHeight)/2.
* @param nSrcWidth Source Image width.
* @param nSrcHeight Source Image height.
*/
- static void YUV420_SP_Rotate90_Flip(uint8_t* pbDst, uint8_t* pYPlane, uint8_t* pUVPlane,
+ static void YUV420_SP_Rotate90_Flip(uint8_t* pOutBuffer, uint8_t* pYPlane, uint8_t* pUVPlane,
uint16_t nSrcWidth, uint16_t nSrcHeight);
/**
* @brief Rotates YUVImage_420_888 Image by 270 degrees.
- * Supports zero pixel stride and zero row stride.
+ * Supports input row stride equal to width and adds padding when outputStride is not same
+ * as output image width.
*
* Source Image Destination Image
* + - - - - + + - - - - +
@@ -92,14 +98,18 @@ public:
* | 7 8 9 | | 1 4 7 |
* + - - - - + + - - - - +
*
- * @param pbDst Destination buffer with size nDstWidth*nDstHeight*1.5.
+ * @param pOutBuffer Pointer to output buffer with size nDstWidth*nDstHeight*1.5.
+ * @param nOutBufSize size of output buffer.
+ * @param outputStride Stride of the output image >= nDstWidth.
* @param pYPlane Y-Plane data of size nDstWidth*nDstHeight.
* @param pUVPlane UV-Plane data of size (nDstWidth*nDstHeight)/2.
* @param nSrcWidth Source Image width.
* @param nSrcHeight Source Image height.
+ *
+ * @return -1 on error and 0 on success.
*/
- static void YUV420_SP_Rotate270(uint8_t* pbDst, uint8_t* pYPlane, uint8_t* pUVPlane,
- uint16_t nSrcWidth, uint16_t nSrcHeight);
+ static int YUV420_SP_Rotate270(uint8_t* pOutBuffer, size_t nOutBufSize, uint16_t outputStride,
+ uint8_t* pYPlane, uint8_t* pUVPlane, uint16_t nSrcWidth, uint16_t nSrcHeight);
};
#endif // IMS_MEDIA_IMAGE_ROTATE \ No newline at end of file
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/VideoManager.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/VideoManager.h
index 7c780fd0..91c2747b 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/VideoManager.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/VideoManager.h
@@ -37,10 +37,6 @@ public:
*/
class RequestHandler : public ImsMediaEventHandler
{
- public:
- RequestHandler();
- virtual ~RequestHandler();
-
protected:
virtual void processEvent(
uint32_t event, uint64_t sessionId, uint64_t paramA, uint64_t paramB);
@@ -51,10 +47,6 @@ public:
*/
class ResponseHandler : public ImsMediaEventHandler
{
- public:
- ResponseHandler();
- virtual ~ResponseHandler();
-
protected:
virtual void processEvent(
uint32_t event, uint64_t sessionId, uint64_t paramA, uint64_t paramB);
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/VideoStreamGraphRtcp.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/VideoStreamGraphRtcp.h
index 2ef9a5b6..f1c6d013 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/VideoStreamGraphRtcp.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/VideoStreamGraphRtcp.h
@@ -27,6 +27,7 @@ public:
virtual ~VideoStreamGraphRtcp();
virtual ImsMediaResult create(RtpConfig* config);
virtual ImsMediaResult update(RtpConfig* config);
+ virtual ImsMediaResult start();
virtual bool setMediaQualityThreshold(MediaQualityThreshold* threshold);
virtual bool OnEvent(int32_t type, uint64_t param1, uint64_t param2);
};
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/VideoStreamGraphRtpTx.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/VideoStreamGraphRtpTx.h
index 1255d194..0fd1104a 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/VideoStreamGraphRtpTx.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/VideoStreamGraphRtpTx.h
@@ -29,6 +29,7 @@ public:
virtual ImsMediaResult create(RtpConfig* config);
virtual ImsMediaResult update(RtpConfig* config);
virtual ImsMediaResult start();
+ virtual bool setMediaQualityThreshold(MediaQualityThreshold* threshold);
void setSurface(ANativeWindow* surface);
virtual bool OnEvent(int32_t type, uint64_t param1, uint64_t param2);
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/android/ImsMediaCamera.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/android/ImsMediaCamera.h
index b77bc135..0a7728a1 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/android/ImsMediaCamera.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/android/ImsMediaCamera.h
@@ -101,14 +101,12 @@ public:
sessionOutputs.clear();
targets.clear();
request = nullptr;
- sessionSequenceId = -1;
}
std::vector<ANativeWindow*> outputNativeWindows;
std::vector<ACaptureSessionOutput*> sessionOutputs;
std::vector<ACameraOutputTarget*> targets;
ACaptureRequest* request;
ACameraDevice_request_template requestTemplate;
- int sessionSequenceId;
};
enum kCameraMode
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/android/ImsMediaPauseImageSource.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/android/ImsMediaPauseImageSource.h
index 723499b9..66022fc2 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/android/ImsMediaPauseImageSource.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/android/ImsMediaPauseImageSource.h
@@ -31,10 +31,11 @@ public:
*
* @param width width of the video frames.
* @param height height of the video frames.
+ * @param stride stride of the video frames.
*
* @return returns true if the image is loaded and false in case of failure.
*/
- bool Initialize(int width, int height);
+ bool Initialize(int width, int height, int stride);
/**
* @brief Image YUV buffer loaded in memory is freed.
@@ -58,7 +59,7 @@ private:
AAsset* getImageAsset();
const char* getImageFilePath();
- int8_t* ConvertRgbaToYuv(int8_t* pixels, int width, int height);
+ int8_t* ConvertRgbaToYuv(int8_t* pixels, int width, int height, int stride);
};
#endif // IMSMEDIA_JPEG_SOURCE_H_INCLUDED
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/android/ImsMediaVideoSource.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/android/ImsMediaVideoSource.h
index 3bc63092..b1adce53 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/android/ImsMediaVideoSource.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/android/ImsMediaVideoSource.h
@@ -137,7 +137,7 @@ public:
*
* @param bitrate The bitrate in bps units
*/
- void changeBitrate(const uint32_t bitrate);
+ bool changeBitrate(const uint32_t bitrate);
/**
* @brief Request a new IDR frame to the codec output streaming
@@ -153,11 +153,10 @@ private:
ANativeWindow* mWindow;
AMediaCodec* mCodec;
AMediaFormat* mFormat;
- ANativeWindow* mRecordingSurface;
ANativeWindow* mImageReaderSurface;
AImageReader* mImageReader;
std::mutex mMutex;
- std::mutex mImageReaderMutex;
+ ImsMediaCondition mConditionExit;
IVideoSourceCallback* mListener;
ImsMediaPauseImageSource mPauseImageSource;
int32_t mCodecType;
@@ -168,6 +167,7 @@ private:
uint32_t mCameraZoom;
uint32_t mWidth;
uint32_t mHeight;
+ int32_t mCodecStride;
uint32_t mFramerate;
uint32_t mBitrate;
uint32_t mIntraInterval;
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/nodes/IVideoRendererNode.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/nodes/IVideoRendererNode.h
index caa54322..3e4483e7 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/nodes/IVideoRendererNode.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/nodes/IVideoRendererNode.h
@@ -29,6 +29,16 @@
#define USE_JITTER_BUFFER // off this definition ONLY for test purpose.
#define DEMON_NTP2MSEC 65.55
+enum FrameType
+{
+ UNKNOWN,
+ SPS,
+ PPS,
+ VPS,
+ IDR,
+ NonIDR,
+};
+
/**
* @brief This class describes an interface between depacketization module and audio device
*/
@@ -69,25 +79,25 @@ public:
void SetPacketLossParam(uint32_t time, uint32_t rate);
private:
- bool IsIntraFrame(uint8_t* pbBuffer, uint32_t nBufferSize);
- bool IsConfigFrame(uint8_t* pbBuffer, uint32_t nBufferSize, uint32_t* nBufferOffset = nullptr);
- bool IsSps(uint8_t* pbBuffer, uint32_t nBufferSize, uint32_t* nBufferOffset = nullptr);
- void SaveConfigFrame(uint8_t* pbBuffer, uint32_t nBufferSize, uint32_t type);
+ bool hasStartingCode(uint8_t* buffer, uint32_t bufferSize);
+ FrameType GetFrameType(uint8_t* buffer, uint32_t bufferSize);
+ void SaveConfigFrame(uint8_t* buffer, uint32_t bufferSize, uint32_t type);
+
/**
* @brief Remove Access Uint Delimiter Nal Unit.
*
- * @param pInBuffer
- * @param nInBufferSize
- * @param pOutBuffer
- * @param pOutBufferSize
+ * @param inBuffer
+ * @param ibufferSize
+ * @param outBuffer
+ * @param outBufferSize
* @return true
* @return false
*/
- bool RemoveAUDNalUnit(uint8_t* pInBuffer, uint32_t nInBufferSize, uint8_t** pOutBuffer,
- uint32_t* pOutBufferSize);
+ bool RemoveAUDNalUnit(
+ uint8_t* inBuffer, uint32_t ibufferSize, uint8_t** outBuffer, uint32_t* outBufferSize);
void CheckResolution(uint32_t nWidth, uint32_t nHeight);
- ImsMediaResult ParseAvcSps(uint8_t* pbBuffer, uint32_t nBufferSize, tCodecConfig* pInfo);
- ImsMediaResult ParseHevcSps(uint8_t* pbBuffer, uint32_t nBufferSize, tCodecConfig* pInfo);
+ ImsMediaResult ParseAvcSps(uint8_t* buffer, uint32_t bufferSize, tCodecConfig* config);
+ ImsMediaResult ParseHevcSps(uint8_t* buffer, uint32_t bufferSize, tCodecConfig* config);
void QueueConfigFrame(uint32_t timestamp);
void NotifyPeerDimensionChanged();
@@ -107,7 +117,6 @@ private:
bool mFirstFrame;
ImsMediaSubType mSubtype;
uint32_t mFramerate;
- uint32_t mWaitIntraFrame;
uint32_t mLossDuration;
uint32_t mLossRateThreshold;
};
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/nodes/IVideoSourceNode.h b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/nodes/IVideoSourceNode.h
index bcc43d5b..17acd172 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/nodes/IVideoSourceNode.h
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/include/video/nodes/IVideoSourceNode.h
@@ -46,6 +46,14 @@ public:
* @param window surface buffer to update
*/
void UpdateSurface(ANativeWindow* window);
+
+ /**
+ * @brief Set the bitrate threshold to notify the indication when the encoding video bitrate is
+ * less than the threshold values
+ *
+ * @param bitrate The video encoding bitrate in bps unit
+ */
+ void SetBitrateThreshold(int32_t bitrate);
// callback from ImsMediaVideoSource
virtual void OnUplinkEvent(uint8_t* pBitstream, uint32_t nSize, int64_t pstUsec, uint32_t flag);
virtual void OnEvent(int32_t type, int32_t param1, int32_t param2);
@@ -68,6 +76,8 @@ protected:
android::String8 mImagePath;
uint32_t mDeviceOrientation;
ANativeWindow* mWindow;
+ int32_t mMinBitrateThreshold;
+ bool mBitrateNotified;
};
#endif \ No newline at end of file
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/BaseNode.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/BaseNode.cpp
index 6ee0e6b5..70986fac 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/BaseNode.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/BaseNode.cpp
@@ -268,6 +268,21 @@ bool BaseNode::GetData(ImsMediaSubType* psubtype, uint8_t** ppData, uint32_t* pn
}
}
+void BaseNode::AddData(uint8_t* data, uint32_t size, uint32_t timestamp, bool mark, uint32_t seq,
+ ImsMediaSubType subtype, ImsMediaSubType dataType, uint32_t arrivalTime, int32_t index)
+{
+ DataEntry entry = DataEntry();
+ entry.pbBuffer = data;
+ entry.nBufferSize = size;
+ entry.nTimestamp = timestamp;
+ entry.bMark = mark;
+ entry.nSeqNum = seq;
+ entry.eDataType = dataType;
+ entry.subtype = subtype;
+ entry.arrivalTime = arrivalTime;
+ index == -1 ? mDataQueue.Add(&entry) : mDataQueue.InsertAt(index, &entry);
+}
+
void BaseNode::DeleteData()
{
mDataQueue.Delete();
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtcpDecoderNode.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtcpDecoderNode.cpp
index 7682bfc7..e104c2cb 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtcpDecoderNode.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtcpDecoderNode.cpp
@@ -18,6 +18,10 @@
#include <ImsMediaTrace.h>
#include <ImsMediaVideoUtil.h>
+#ifdef DEBUG_BITRATE_CHANGE_SIMULATION
+static int32_t gTestBitrate = 384000;
+#endif
+
RtcpDecoderNode::RtcpDecoderNode(BaseSessionCallback* callback) :
BaseNode(callback)
{
@@ -84,7 +88,10 @@ void RtcpDecoderNode::OnDataFromFrontNode(ImsMediaSubType subtype, uint8_t* pDat
IMLOGD_PACKET6(IM_PACKET_LOG_RTCP,
"[OnMediaDataInd] media[%d] subtype[%d], Size[%d], TS[%u], Mark[%d], Seq[%d]",
mMediaType, subtype, nDataSize, nTimeStamp, bMark, nSeqNum);
- mRtpSession->ProcRtcpPacket(pData, nDataSize);
+ if (mRtpSession != nullptr)
+ {
+ mRtpSession->ProcRtcpPacket(pData, nDataSize);
+ }
}
bool RtcpDecoderNode::IsRunTime()
@@ -142,6 +149,13 @@ void RtcpDecoderNode::OnRtcpInd(tRtpSvc_IndicationFromStack type, void* data)
{
mCallback->SendEvent(kCollectPacketInfo, kStreamRtcp);
}
+#ifdef DEBUG_BITRATE_CHANGE_SIMULATION
+ else if (mMediaType == IMS_MEDIA_VIDEO)
+ {
+ gTestBitrate *= 0.8;
+ mCallback->SendEvent(kRequestVideoBitrateChange, gTestBitrate);
+ }
+#endif
}
break;
case RTPSVC_RECEIVE_RTCP_RR_IND:
@@ -154,6 +168,13 @@ void RtcpDecoderNode::OnRtcpInd(tRtpSvc_IndicationFromStack type, void* data)
{
mCallback->SendEvent(kCollectPacketInfo, kStreamRtcp);
}
+#ifdef DEBUG_BITRATE_CHANGE_SIMULATION
+ else if (mMediaType == IMS_MEDIA_VIDEO)
+ {
+ gTestBitrate *= 0.8;
+ mCallback->SendEvent(kRequestVideoBitrateChange, gTestBitrate);
+ }
+#endif
}
break;
case RTPSVC_RECEIVE_RTCP_FB_IND:
@@ -274,7 +295,7 @@ void RtcpDecoderNode::ReceiveTmmbr(const tRtpSvcIndSt_ReceiveRtcpFeedbackInd* pa
ImsMediaVideoUtil::ConvertBitrateToPower(bitrate, exp, mantissa);
InternalRequestEventParam* pParam = new InternalRequestEventParam(
- kRtpFbTmmbr, TmmbrParams(receivedSsrc, exp, mantissa, receivedOverhead));
+ kRtpFbTmmbn, TmmbrParams(receivedSsrc, exp, mantissa, receivedOverhead));
mCallback->SendEvent(kRequestVideoSendTmmbn, reinterpret_cast<uint64_t>(pParam));
}
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtpEncoderNode.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtpEncoderNode.cpp
index bcd35a6d..cd4ca421 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtpEncoderNode.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtpEncoderNode.cpp
@@ -36,6 +36,7 @@ RtpEncoderNode::RtpEncoderNode(BaseSessionCallback* callback) :
mRtpTxDtmfPayload = 0;
mRtpRxDtmfPayload = 0;
mDtmfSamplingRate = 0;
+ mDtmfTimestamp = 0;
mCvoValue = CVO_DEFINE_NONE;
mRedundantLevel = 0;
mRedundantPayload = 0;
@@ -289,7 +290,7 @@ bool RtpEncoderNode::SetCvoExtension(const int64_t facing, const int64_t orienta
IMLOGD3("[SetCvoExtension] cvoValue[%d], facing[%ld], orientation[%ld]", mCvoValue, facing,
orientation);
- if (mCvoValue != -1)
+ if (mCvoValue > 0)
{
uint32_t rotation = 0;
uint32_t cameraId = 0;
@@ -337,6 +338,7 @@ bool RtpEncoderNode::SetCvoExtension(const int64_t facing, const int64_t orienta
extensionData[2] = 0; // padding
extensionData[3] = 0; // padding
+ mListRtpExtension.clear();
mListRtpExtension.push_back(RtpHeaderExtensionInfo(
RtpHeaderExtensionInfo::kBitPatternForOneByteHeader, 1, extensionData, 4));
return true;
@@ -445,18 +447,16 @@ bool RtpEncoderNode::ProcessAudioData(ImsMediaSubType subtype, uint8_t* data, ui
return false;
}
+ mMark ? mDtmfTimestamp = currentTimestamp : timeDiff = 0;
mPrevTimestamp = currentTimestamp;
timestampDiff = timeDiff * mSamplingRate;
- IMLOGD_PACKET2(IM_PACKET_LOG_RTP, "[ProcessAudioData] dtmf payload, size[%u], TS[%u]",
- size, currentTimestamp);
+ IMLOGD_PACKET3(IM_PACKET_LOG_RTP,
+ "[ProcessAudioData] dtmf payload, size[%u], TS[%u], diff[%d]", size,
+ mDtmfTimestamp, timestampDiff);
mRtpSession->SendRtpPacket(
- mRtpTxDtmfPayload, data, size, currentTimestamp, mMark, timestampDiff);
-
- if (mMark)
- {
- mMark = false;
- }
+ mRtpTxDtmfPayload, data, size, mDtmfTimestamp, mMark, timestampDiff);
+ mMark = false;
}
}
else // MEDIASUBTYPE_RTPPAYLOAD
@@ -480,8 +480,6 @@ bool RtpEncoderNode::ProcessAudioData(ImsMediaSubType subtype, uint8_t* data, ui
}
else if (timeDiff == 0)
{
- IMLOGD_PACKET2(IM_PACKET_LOG_RTP, "[ProcessAudioData] skip, prev[%u] curr[%u]",
- mPrevTimestamp, currentTimestamp);
return false;
}
else
@@ -496,8 +494,8 @@ bool RtpEncoderNode::ProcessAudioData(ImsMediaSubType subtype, uint8_t* data, ui
kCollectPacketInfo, kStreamRtpTx, reinterpret_cast<uint64_t>(packet));
timestampDiff = timeDiff * mSamplingRate;
- IMLOGD_PACKET3(IM_PACKET_LOG_RTP, "[ProcessAudioData] PayloadTx[%d], Size[%d], TS[%d]",
- mRtpPayloadTx, size, currentTimestamp);
+ IMLOGD_PACKET3(IM_PACKET_LOG_RTP, "[ProcessAudioData] size[%u], TS[%u], diff[%d]", size,
+ currentTimestamp, timestampDiff);
if (!mListRtpExtension.empty())
{
@@ -524,13 +522,23 @@ bool RtpEncoderNode::ProcessAudioData(ImsMediaSubType subtype, uint8_t* data, ui
void RtpEncoderNode::ProcessVideoData(
ImsMediaSubType subtype, uint8_t* data, uint32_t size, uint32_t timestamp, bool mark)
{
- IMLOGD_PACKET2(
- IM_PACKET_LOG_RTP, "[ProcessVideoData] nSize[%d], timestamp[%u]", size, timestamp);
+ IMLOGD_PACKET4(IM_PACKET_LOG_RTP, "[ProcessVideoData] subtype[%d], size[%d], TS[%u], mark[%d]",
+ subtype, size, timestamp, mark);
+
+#ifdef SIMULATE_VIDEO_CVO_UPDATE
+ const int64_t kCameraFacing = kCameraFacingFront;
+ static int64_t sDeviceOrientation = 0;
+ static int64_t sCount = 0;
+ if ((++sCount % 100) == 0)
+ {
+ SetCvoExtension(kCameraFacing, (sDeviceOrientation += 90) % 360);
+ }
+#endif
if (mCvoValue > 0 && mark && subtype == MEDIASUBTYPE_VIDEO_IDR_FRAME)
{
- mRtpSession->SendRtpPacket(
- mRtpPayloadTx, data, size, timestamp, mark, 0, &mListRtpExtension.front());
+ mRtpSession->SendRtpPacket(mRtpPayloadTx, data, size, timestamp, mark, 0,
+ mListRtpExtension.empty() ? nullptr : &mListRtpExtension.front());
}
else
{
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextJitterBuffer.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextJitterBuffer.cpp
index beb1d015..9ed07c0a 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextJitterBuffer.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextJitterBuffer.cpp
@@ -32,11 +32,9 @@ void TextJitterBuffer::Reset()
}
void TextJitterBuffer::Add(ImsMediaSubType subtype, uint8_t* buffer, uint32_t size,
- uint32_t timestamp, bool mark, uint32_t seqNum, ImsMediaSubType dataType,
+ uint32_t timestamp, bool mark, uint32_t seqNum, ImsMediaSubType /*dataType*/,
uint32_t arrivalTime)
{
- (void)dataType;
-
IMLOGD_PACKET6(IM_PACKET_LOG_JITTER,
"[Add] seq[%u], mark[%u], TS[%u], size[%u], lastPlayedSeq[%u], arrivalTime[%u]", seqNum,
mark, timestamp, size, mLastPlayedSeqNum, arrivalTime);
@@ -64,11 +62,6 @@ void TextJitterBuffer::Add(ImsMediaSubType subtype, uint8_t* buffer, uint32_t si
if (mDataQueue.GetCount() == 0) // jitter buffer is empty
{
mDataQueue.Add(&currEntry);
-
- if (!mFirstFrameReceived)
- {
- mFirstFrameReceived = true;
- }
}
else
{
@@ -169,6 +162,11 @@ void TextJitterBuffer::Delete()
return;
}
+ if (!mFirstFrameReceived)
+ {
+ mFirstFrameReceived = true;
+ }
+
mLastPlayedSeqNum = pEntry->nSeqNum;
mLastPlayedTimestamp = pEntry->nTimestamp;
mDataQueue.Delete();
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextManager.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextManager.cpp
index f50a0ba8..33ad7a20 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextManager.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextManager.cpp
@@ -21,9 +21,18 @@
using namespace android;
TextManager* TextManager::manager;
-TextManager::TextManager() {}
+TextManager::TextManager()
+{
+ mRequestHandler.Init("TEXT_REQUEST_EVENT");
+ mResponseHandler.Init("TEXT_RESPONSE_EVENT");
+}
-TextManager::~TextManager() {}
+TextManager::~TextManager()
+{
+ mRequestHandler.Deinit();
+ mResponseHandler.Deinit();
+ manager = nullptr;
+}
TextManager* TextManager::getInstance()
{
@@ -200,13 +209,6 @@ void TextManager::sendMessage(const int sessionId, const android::Parcel& parcel
}
}
-TextManager::RequestHandler::RequestHandler() :
- ImsMediaEventHandler("TEXT_REQUEST_EVENT")
-{
-}
-
-TextManager::RequestHandler::~RequestHandler() {}
-
void TextManager::RequestHandler::processEvent(
uint32_t event, uint64_t sessionId, uint64_t paramA, uint64_t paramB)
{
@@ -294,13 +296,6 @@ void TextManager::RequestHandler::processEvent(
}
}
-TextManager::ResponseHandler::ResponseHandler() :
- ImsMediaEventHandler("TEXT_RESPONSE_EVENT")
-{
-}
-
-TextManager::ResponseHandler::~ResponseHandler() {}
-
void TextManager::ResponseHandler::processEvent(
uint32_t event, uint64_t sessionId, uint64_t paramA, uint64_t paramB)
{
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextStreamGraphRtcp.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextStreamGraphRtcp.cpp
index 922981e6..db36beda 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextStreamGraphRtcp.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextStreamGraphRtcp.cpp
@@ -94,7 +94,7 @@ ImsMediaResult TextStreamGraphRtcp::update(RtpConfig* config)
if (*mConfig == *pConfig)
{
- IMLOGD0("[update] no update");
+ IMLOGI0("[update] no update");
return RESULT_SUCCESS;
}
@@ -105,7 +105,7 @@ ImsMediaResult TextStreamGraphRtcp::update(RtpConfig* config)
mConfig = new TextConfig(pConfig);
- if (mConfig->getRtcpConfig().getIntervalSec() == 0)
+ if (mConfig->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_NO_FLOW)
{
IMLOGI0("[update] pause RTCP");
return stop();
@@ -132,7 +132,8 @@ ImsMediaResult TextStreamGraphRtcp::update(RtpConfig* config)
}
}
- if (mGraphState == kStreamStateCreated && mConfig->getRtcpConfig().getIntervalSec() != 0)
+ if (mGraphState == kStreamStateCreated &&
+ mConfig->getMediaDirection() != RtpConfig::MEDIA_DIRECTION_NO_FLOW)
{
IMLOGI0("[update] resume RTCP");
return start();
@@ -147,6 +148,24 @@ ImsMediaResult TextStreamGraphRtcp::update(RtpConfig* config)
return ret;
}
+ImsMediaResult TextStreamGraphRtcp::start()
+{
+ IMLOGI1("[start] state[%d]", mGraphState);
+
+ if (mConfig == nullptr)
+ {
+ return RESULT_INVALID_PARAM;
+ }
+
+ if (mConfig->getMediaDirection() != RtpConfig::MEDIA_DIRECTION_NO_FLOW)
+ {
+ return BaseStreamGraph::start();
+ }
+
+ // not started
+ return RESULT_SUCCESS;
+}
+
bool TextStreamGraphRtcp::setMediaQualityThreshold(MediaQualityThreshold* threshold)
{
if (threshold != nullptr)
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextStreamGraphRtpRx.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextStreamGraphRtpRx.cpp
index fa7eafa8..a4456320 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextStreamGraphRtpRx.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextStreamGraphRtpRx.cpp
@@ -89,7 +89,7 @@ ImsMediaResult TextStreamGraphRtpRx::update(RtpConfig* config)
if (*mConfig == *pConfig)
{
- IMLOGD0("[update] no update");
+ IMLOGI0("[update] no update");
return RESULT_SUCCESS;
}
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextStreamGraphRtpTx.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextStreamGraphRtpTx.cpp
index 5976bb00..902709b3 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextStreamGraphRtpTx.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextStreamGraphRtpTx.cpp
@@ -98,7 +98,7 @@ ImsMediaResult TextStreamGraphRtpTx::update(RtpConfig* config)
if (*mConfig == *pConfig)
{
- IMLOGD0("[update] no update");
+ IMLOGI0("[update] no update");
return RESULT_SUCCESS;
}
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/nodes/TextRendererNode.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/nodes/TextRendererNode.cpp
index 628248cc..254081d1 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/nodes/TextRendererNode.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/nodes/TextRendererNode.cpp
@@ -114,20 +114,6 @@ void TextRendererNode::ProcessData()
"[ProcessData] size[%u], TS[%u], mark[%u], seq[%u], last seq[%u]", size, timestamp,
mark, seq, mLastPlayedSeq);
- // ignore empty t.140
- if (size == 0)
- {
- mLastPlayedSeq = (uint16_t)seq;
- DeleteData();
- break;
- }
-
- if (data == nullptr)
- {
- IMLOGD0("[ProcessData] invalid data");
- break;
- }
-
if (mFirstFrameReceived)
{
// detect lost packet
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/nodes/TextRtpPayloadDecoderNode.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/nodes/TextRtpPayloadDecoderNode.cpp
index 284311e2..901f88c6 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/nodes/TextRtpPayloadDecoderNode.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/nodes/TextRtpPayloadDecoderNode.cpp
@@ -118,10 +118,10 @@ void TextRtpPayloadDecoderNode::DecodeT140(uint8_t* data, uint32_t size, ImsMedi
if (subtype == MEDIASUBTYPE_BITSTREAM_T140 || subtype == MEDIASUBTYPE_BITSTREAM_T140_RED)
{
- std::list<uint32_t> lstTSOffset;
- std::list<uint32_t> lstLength;
- uint32_t nReadByte = 0;
- uint32_t nRedCount = 0;
+ std::list<uint32_t> listTimestampOffset;
+ std::list<uint32_t> listLength;
+ uint32_t readByte = 0;
+ uint16_t redundantCount = 0;
mBitReader.SetBuffer(data, size);
@@ -136,7 +136,6 @@ void TextRtpPayloadDecoderNode::DecodeT140(uint8_t* data, uint32_t size, ImsMedi
*/
// Primary Data Only
- // Red header + primary header = 5 byte
if (subtype == MEDIASUBTYPE_BITSTREAM_T140)
{
SendDataToRearNode(MEDIASUBTYPE_BITSTREAM_T140, data, size, timestamp, mark, seq);
@@ -144,69 +143,54 @@ void TextRtpPayloadDecoderNode::DecodeT140(uint8_t* data, uint32_t size, ImsMedi
}
// Redundant data included
- while (mBitReader.Read(1) == 1) // Rendundancy bit
+ while (mBitReader.Read(1) == 1) // redundant flag bit
{
- uint32_t nPT = mBitReader.Read(7); // T140 payload type
- uint32_t nTSOffset = mBitReader.Read(14);
- uint32_t nLen = mBitReader.Read(10);
+ uint32_t payloadType = mBitReader.Read(7); // T140 payload type
+ uint32_t timestampOffset = mBitReader.Read(14);
+ uint32_t length = mBitReader.Read(10);
- lstTSOffset.push_back(nTSOffset); // timestamp offset
- lstLength.push_back(nLen); // block length
+ listTimestampOffset.push_back(timestampOffset); // timestamp offset
+ listLength.push_back(length); // block length
- IMLOGD_PACKET3(IM_PACKET_LOG_PH, "[DecodeT140] nPT[%u], nTSOffset[%u], nLen[%u]", nPT,
- nTSOffset, nLen);
- nReadByte += 4;
- nRedCount++;
+ IMLOGD_PACKET3(IM_PACKET_LOG_PH, "[DecodeT140] PT[%u], TSOffset[%u], size[%u]",
+ payloadType, timestampOffset, length);
+ readByte += 4;
+ redundantCount++;
}
mBitReader.Read(7); // T140 payload type (111)
- nReadByte += 1;
+ readByte += 1;
// redundant data
- while (lstTSOffset.size() > 0)
+ while (listTimestampOffset.size() > 0)
{
- uint32_t nRedTimestamp = 0;
- uint32_t nRedLength = 0;
-
- nRedTimestamp = lstTSOffset.front();
- nRedLength = lstLength.front();
-
- if (nRedLength > 0)
- {
- uint32_t nRedSeqNum = 0;
- // here should compare mPayload size red length
- mBitReader.ReadByteBuffer(mPayload, nRedLength * 8);
- nReadByte += nRedLength;
-
- if (seq < nRedCount)
- {
- nRedSeqNum = seq + 0xffff - nRedCount; // round trip
- }
- else
- {
- nRedSeqNum = seq - nRedCount;
- }
-
- IMLOGD_PACKET3(IM_PACKET_LOG_PH,
- "[DecodeT140] nRedTimestamp[%u], nRedLength[%u], nRedSeqNum[%u]",
- timestamp - nRedTimestamp, nRedLength, nRedSeqNum);
- SendDataToRearNode(MEDIASUBTYPE_BITSTREAM_T140, mPayload, nRedLength,
- timestamp - nRedTimestamp, mark, nRedSeqNum);
- }
-
- nRedCount--;
- lstTSOffset.pop_front();
- lstLength.pop_front();
+ uint32_t redundantTimestamp = listTimestampOffset.front();
+ uint32_t redundantLength = listLength.front();
+
+ // read redundant payload
+ mBitReader.ReadByteBuffer(mPayload, redundantLength * 8);
+ readByte += redundantLength;
+
+ uint16_t redundantSeqNum = seq - redundantCount;
+
+ IMLOGD_PACKET3(IM_PACKET_LOG_PH, "[DecodeT140] red TS[%u], size[%u], seq[%u]",
+ timestamp - redundantTimestamp, redundantLength, redundantSeqNum);
+ SendDataToRearNode(MEDIASUBTYPE_BITSTREAM_T140, mPayload, redundantLength,
+ timestamp - redundantTimestamp, mark, redundantSeqNum);
+
+ redundantCount--;
+ listTimestampOffset.pop_front();
+ listLength.pop_front();
}
// primary data
- if (size - nReadByte > 0)
+ if (size - readByte > 0)
{
- mBitReader.ReadByteBuffer(mPayload, (size - nReadByte) * 8);
+ mBitReader.ReadByteBuffer(mPayload, (size - readByte) * 8);
}
SendDataToRearNode(
- MEDIASUBTYPE_BITSTREAM_T140, mPayload, (size - nReadByte), timestamp, mark, seq);
+ MEDIASUBTYPE_BITSTREAM_T140, mPayload, (size - readByte), timestamp, mark, seq);
}
else
{
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/nodes/TextSourceNode.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/nodes/TextSourceNode.cpp
index 82fc1b58..20a01154 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/nodes/TextSourceNode.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/nodes/TextSourceNode.cpp
@@ -30,17 +30,7 @@ TextSourceNode::TextSourceNode(BaseSessionCallback* callback) :
mSentBOM = false;
}
-TextSourceNode::~TextSourceNode()
-{
- while (mListTextSource.size() > 0)
- {
- uint8_t* text = mListTextSource.front();
- delete text;
- mListTextSource.pop_front();
- }
-
- mListTextSourceSize.clear();
-}
+TextSourceNode::~TextSourceNode() {}
kBaseNodeId TextSourceNode::GetNodeId()
{
@@ -49,7 +39,7 @@ kBaseNodeId TextSourceNode::GetNodeId()
ImsMediaResult TextSourceNode::Start()
{
- IMLOGD2("[Start] codec[%d], Redundant Level[%d]", mCodecType, mRedundantLevel);
+ IMLOGD2("[Start] codec[%d], redundant level[%d]", mCodecType, mRedundantLevel);
if (mCodecType == TextConfig::TEXT_CODEC_NONE)
{
@@ -117,52 +107,27 @@ void TextSourceNode::ProcessData()
return;
}
- std::lock_guard<std::mutex> guard(mMutex);
-
- if (mBomEnabled == true && mSentBOM == false)
+ if (mBomEnabled && !mSentBOM)
{
- SendBOM();
+ SendBom();
mSentBOM = true;
}
- uint32_t nLoopCount = 1;
-
- if (mListTextSource.size() >= T140_MAX_CHUNK)
- {
- nLoopCount = T140_MAX_CHUNK;
- }
-
- uint32_t nSendingDataSize = 0;
- memset(mTextToSend, 0, MAX_RTT_LEN);
-
- for (uint32_t i = 0;
- (i < nLoopCount && !mListTextSource.empty() && !mListTextSourceSize.empty()); i++)
- {
- // get first node data
- uint8_t* pData = mListTextSource.front();
- uint32_t nDataSize = mListTextSourceSize.front();
-
- if (pData == nullptr || nDataSize == 0)
- {
- continue;
- }
+ std::lock_guard<std::mutex> guard(mMutex);
- memcpy(mTextToSend + nSendingDataSize, pData, nDataSize);
- nSendingDataSize += nDataSize;
+ ImsMediaSubType subtype = MEDIASUBTYPE_UNDEFINED;
+ ImsMediaSubType datatype = MEDIASUBTYPE_UNDEFINED;
+ uint8_t* data = NULL;
+ uint32_t size = 0;
+ uint32_t timestamp = 0;
+ bool mark = false;
+ uint32_t seq = 0;
- free(pData);
- mListTextSourceSize.pop_front();
- mListTextSource.pop_front();
- }
-
- if (nSendingDataSize > 0)
+ if (GetData(&subtype, &data, &size, &timestamp, &mark, &seq, &datatype))
{
- // send it one char
- IMLOGD_PACKET1(IM_PACKET_LOG_TEXT, "[ProcessData] send[%s]", mTextToSend);
-
mTimeLastSent = ImsMediaTimer::GetTimeInMilliSeconds();
- SendDataToRearNode(MEDIASUBTYPE_BITSTREAM_T140, mTextToSend, nSendingDataSize,
- mTimeLastSent, false, 0);
+ SendDataToRearNode(MEDIASUBTYPE_BITSTREAM_T140, data, size, mTimeLastSent, false, 0);
+ DeleteData();
mRedundantCount = mRedundantLevel;
@@ -178,7 +143,7 @@ void TextSourceNode::ProcessData()
* after the selected buffering time, an empty T140block SHOULD be transmitted. This
* situation is regarded as the beginning of an idle period.
*/
- IMLOGD1("[ProcessData] send empty, nRedCount[%d]", mRedundantCount);
+ IMLOGD1("[ProcessData] send empty, redundant count[%d]", mRedundantCount);
// send default if there is no data to send
SendDataToRearNode(MEDIASUBTYPE_BITSTREAM_T140, nullptr, 0,
ImsMediaTimer::GetTimeInMilliSeconds(), false, 0);
@@ -188,72 +153,26 @@ void TextSourceNode::ProcessData()
void TextSourceNode::SendRtt(const android::String8* text)
{
- if (text == nullptr || text->length() == 0)
+ if (text == NULL || text->length() == 0 || text->length() > MAX_RTT_LEN)
{
IMLOGE0("[SendRtt] invalid data");
return;
}
- IMLOGD2("[SendRtt] size[%u], listSize[%d]", text->length(), mListTextSource.size());
- std::lock_guard<std::mutex> guard(mMutex);
+ IMLOGD2("[SendRtt] size[%u], listSize[%d]", text->length(), mDataQueue.GetCount());
- uint8_t* pData = (uint8_t*)text->string();
- uint32_t nSize = text->length();
- uint32_t nChunkSize = 0;
+ uint8_t tempBuffer[MAX_RTT_LEN] = {'\0'};
+ memcpy(tempBuffer, text->string(), text->length());
- while (nSize > 0)
- {
- // split with UTF-8
- if (pData[0] >= 0xC2 && pData[0] <= 0xDF && nSize >= 2)
- {
- nChunkSize = 2;
- }
- else if (pData[0] >= 0xE0 && pData[0] <= 0xEF && nSize >= 3)
- {
- nChunkSize = 3;
- }
- else if (pData[0] >= 0xF0 && pData[0] <= 0xFF && nSize >= 4)
- {
- nChunkSize = 4;
- }
- else // 1byte
- {
- nChunkSize = 1;
- }
-
- uint8_t* buffer = (uint8_t*)calloc(nChunkSize, sizeof(uint8_t));
-
- if (buffer == nullptr)
- {
- IMLOGE0("[SendRtt] allocated data is null");
- return;
- }
-
- memcpy(buffer, pData, nChunkSize);
- mListTextSource.push_back(buffer);
- mListTextSourceSize.push_back(nChunkSize);
- pData += nChunkSize;
- nSize -= nChunkSize;
- }
+ std::lock_guard<std::mutex> guard(mMutex);
+ AddData(tempBuffer, text->length(), 0, false, 0);
}
-void TextSourceNode::SendBOM()
+void TextSourceNode::SendBom()
{
- const uint32_t sizeofBom = 3;
- uint8_t* buffer = (uint8_t*)calloc(sizeofBom, sizeof(uint8_t));
-
- if (buffer == nullptr)
- {
- IMLOGE0("[SendBOM] allocated data is null");
- return;
- }
-
- // send BOM - The BOM character shall be 0xEFBBBF for UTF-8
- buffer[0] = 0xef;
- buffer[1] = 0xbb;
- buffer[2] = 0xbf;
-
IMLOGD0("[ProcessData] send BOM");
- mListTextSource.push_front(buffer);
- mListTextSourceSize.push_front(sizeofBom);
+ uint8_t bom[3] = {0xEF, 0xBB, 0xBF};
+
+ std::lock_guard<std::mutex> guard(mMutex);
+ AddData(bom, sizeof(bom), 0, false, 0, MEDIASUBTYPE_UNDEFINED, MEDIASUBTYPE_UNDEFINED, 0, 0);
} \ No newline at end of file
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaBitWriter.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaBitWriter.cpp
index cba37f55..91d69581 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaBitWriter.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaBitWriter.cpp
@@ -40,15 +40,17 @@ void ImsMediaBitWriter::SetBuffer(uint8_t* pbBuffer, uint32_t nBufferSize)
mMaxBufferSize = nBufferSize;
}
-void ImsMediaBitWriter::Write(uint32_t nValue, uint32_t nSize)
+bool ImsMediaBitWriter::Write(uint32_t nValue, uint32_t nSize)
{
if (nSize == 0)
- return;
+ {
+ return false;
+ }
if (mBuffer == nullptr || nSize > 24 || mBufferFull)
{
IMLOGE2("[Write] nSize[%d], BufferFull[%d]", nSize, mBufferFull);
- return;
+ return false;
}
// write to bit buffer
@@ -67,9 +69,11 @@ void ImsMediaBitWriter::Write(uint32_t nValue, uint32_t nSize)
{
mBufferFull = true;
}
+
+ return true;
}
-void ImsMediaBitWriter::WriteByteBuffer(uint8_t* pbSrc, uint32_t nBitSize)
+bool ImsMediaBitWriter::WriteByteBuffer(uint8_t* pbSrc, uint32_t nBitSize)
{
uint32_t nByteSize;
uint32_t nRemainBitSize;
@@ -87,7 +91,10 @@ void ImsMediaBitWriter::WriteByteBuffer(uint8_t* pbSrc, uint32_t nBitSize)
for (i = 0; i < nByteSize; i++)
{
- Write(pbSrc[i], 8);
+ if (!Write(pbSrc[i], 8))
+ {
+ return false;
+ }
}
}
@@ -95,11 +102,17 @@ void ImsMediaBitWriter::WriteByteBuffer(uint8_t* pbSrc, uint32_t nBitSize)
{
uint32_t v = pbSrc[nByteSize];
v >>= (8 - nRemainBitSize);
- Write(v, nRemainBitSize);
+
+ if (!Write(v, nRemainBitSize))
+ {
+ return false;
+ }
}
+
+ return true;
}
-void ImsMediaBitWriter::WriteByteBuffer(uint32_t value)
+bool ImsMediaBitWriter::WriteByteBuffer(uint32_t value)
{
uint32_t nRemainBitSize = 32;
@@ -107,8 +120,14 @@ void ImsMediaBitWriter::WriteByteBuffer(uint32_t value)
{
nRemainBitSize -= 8;
uint8_t v = (value >> nRemainBitSize) & 0x00ff;
- Write(v, 8);
+
+ if (!Write(v, 8))
+ {
+ return false;
+ }
}
+
+ return true;
}
void ImsMediaBitWriter::Seek(uint32_t nSize)
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaEventHandler.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaEventHandler.cpp
index b3d165ab..336f2aa5 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaEventHandler.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaEventHandler.cpp
@@ -22,24 +22,29 @@
std::list<ImsMediaEventHandler*> ImsMediaEventHandler::gListEventHandler;
std::mutex ImsMediaEventHandler::mMutex;
-ImsMediaEventHandler::ImsMediaEventHandler(const char* strName)
+ImsMediaEventHandler::ImsMediaEventHandler() {}
+
+ImsMediaEventHandler::~ImsMediaEventHandler() {}
+
+void ImsMediaEventHandler::Init(const char* strName)
{
strncpy(mName, strName, MAX_EVENTHANDLER_NAME);
mbTerminate = false;
gListEventHandler.push_back(this);
- IMLOGD1("[ImsMediaEventHandler] %s", mName);
+ IMLOGD1("[Init] %s", mName);
StartThread();
}
-ImsMediaEventHandler::~ImsMediaEventHandler()
+void ImsMediaEventHandler::Deinit()
{
- IMLOGD1("[~ImsMediaEventHandler] %s", mName);
+ IMLOGD2("[Deinit] %s, queue size[%d]", mName, mListevent.size());
+ std::lock_guard<std::mutex> guard(mMutexEvent);
+ StopThread();
gListEventHandler.remove(this);
mListevent.clear();
mListParamA.clear();
mListParamB.clear();
mListParamC.clear();
- StopThread();
mCondition.signal();
mConditionExit.wait();
}
@@ -73,13 +78,12 @@ char* ImsMediaEventHandler::getName()
void ImsMediaEventHandler::AddEvent(
uint32_t event, uint64_t paramA, uint64_t paramB, uint64_t paramC)
{
+ std::lock_guard<std::mutex> guard(mMutexEvent);
IMLOGD3("[AddEvent] %s, event[%d], size[%d]", mName, event, mListevent.size());
- mMutexEvent.lock();
mListevent.push_back(event);
mListParamA.push_back(paramA);
mListParamB.push_back(paramB);
mListParamC.push_back(paramC);
- mMutexEvent.unlock();
mCondition.signal();
}
@@ -94,17 +98,22 @@ void* ImsMediaEventHandler::run()
for (;;)
{
- // lock
+ if (IsThreadStopped())
+ {
+ break;
+ }
+
mMutexEvent.lock();
- if (IsThreadStopped() || mListevent.size() == 0)
+
+ if (mListevent.size() == 0)
{
mMutexEvent.unlock();
break;
}
- mMutexEvent.unlock();
+
processEvent(mListevent.front(), mListParamA.front(), mListParamB.front(),
mListParamC.front());
- mMutexEvent.lock();
+
mListevent.pop_front();
mListParamA.pop_front();
mListParamB.pop_front();
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaImageRotate.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaImageRotate.cpp
index 90947c19..46d01ceb 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaImageRotate.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaImageRotate.cpp
@@ -15,13 +15,14 @@
*/
#include "ImsMediaImageRotate.h"
+#include <ImsMediaTrace.h>
void ImsMediaImageRotate::YUV420_Planar_Rotate90_Flip(
uint8_t* pbDst, uint8_t* pbSrc, uint16_t nSrcWidth, uint16_t nSrcHeight)
{
uint16_t x, y;
uint64_t srcIdx, dstIdx;
- const uint64_t size = nSrcWidth * nSrcHeight;
+ const size_t size = nSrcWidth * nSrcHeight;
dstIdx = size - 1;
// Rotate Y buffer
@@ -57,41 +58,59 @@ void ImsMediaImageRotate::YUV420_Planar_Rotate90_Flip(
}
}
-void ImsMediaImageRotate::YUV420_SP_Rotate90(uint8_t* pbDst, uint8_t* pYPlane, uint8_t* pUVPlane,
- uint16_t nSrcWidth, uint16_t nSrcHeight)
+int ImsMediaImageRotate::YUV420_SP_Rotate90(uint8_t* pOutBuffer, size_t nOutBufSize,
+ uint16_t outputStride, uint8_t* pYPlane, uint8_t* pUVPlane, uint16_t nSrcWidth,
+ uint16_t nSrcHeight)
{
- uint16_t x, y;
- uint64_t srcIdx, dstIdx;
- const uint64_t size = nSrcWidth * nSrcHeight;
- dstIdx = size - 1;
+ uint16_t x, y, nDstWidth = nSrcHeight, nDstHt = nSrcWidth, nPadWidth = outputStride - nDstWidth;
+ uint64_t srcIdx, dstIdx = (outputStride * nDstHt) - 1;
+ const size_t dstSize = outputStride * nDstHt * 1.5f;
+
+ if (nOutBufSize < (dstSize - nPadWidth))
+ {
+ IMLOGE4("Output buffer size is not sufficient. \
+ Required(outputStride[%d] * outputHeight[%d] * 1.5 = %d) but passed[%d]",
+ outputStride, nDstHt, dstSize, nOutBufSize);
+ return -1;
+ }
+
+ if (nDstWidth > outputStride)
+ {
+ IMLOGE2("Destination width[%d] cannot be bigger than stride[%d]", nDstWidth, outputStride);
+ return -1;
+ }
// Rotate Y buffer
for (y = 0; y < nSrcWidth; y++)
{
+ dstIdx -= nPadWidth;
srcIdx = nSrcWidth - y - 1;
for (x = 0; x < nSrcHeight; x++)
{
- pbDst[dstIdx] = pYPlane[srcIdx]; // Y
+ pOutBuffer[dstIdx] = pYPlane[srcIdx]; // Y
srcIdx += nSrcWidth;
dstIdx--;
}
}
- dstIdx = (size * 1.5f) - 1;
+ dstIdx = dstSize - 1;
nSrcWidth /= 2;
nSrcHeight /= 2;
// Rotate UV buffer
for (y = 0; y < nSrcWidth; y++)
{
+ dstIdx -= nPadWidth;
srcIdx = (nSrcWidth - y - 1) * 2;
for (x = 0; x < nSrcHeight; x++)
{
- pbDst[dstIdx--] = pUVPlane[srcIdx + 1]; // V
- pbDst[dstIdx--] = pUVPlane[srcIdx]; // U
+ pOutBuffer[dstIdx--] = pUVPlane[srcIdx + 1]; // V
+ pOutBuffer[dstIdx--] = pUVPlane[srcIdx]; // U
srcIdx += nSrcWidth * 2;
}
}
+
+ return 0;
}
void ImsMediaImageRotate::YUV420_SP_Rotate90_Flip(uint8_t* pbDst, uint8_t* pYPlane,
@@ -99,7 +118,7 @@ void ImsMediaImageRotate::YUV420_SP_Rotate90_Flip(uint8_t* pbDst, uint8_t* pYPla
{
uint16_t x, y;
uint64_t srcIdx, dstIdx;
- const uint64_t size = nSrcWidth * nSrcHeight;
+ const size_t size = nSrcWidth * nSrcHeight;
dstIdx = size - 1;
@@ -132,40 +151,58 @@ void ImsMediaImageRotate::YUV420_SP_Rotate90_Flip(uint8_t* pbDst, uint8_t* pYPla
}
}
-void ImsMediaImageRotate::YUV420_SP_Rotate270(uint8_t* pbDst, uint8_t* pYPlane, uint8_t* pUVPlane,
- uint16_t nSrcWidth, uint16_t nSrcHeight)
+int ImsMediaImageRotate::YUV420_SP_Rotate270(uint8_t* pOutBuffer, size_t nOutBufSize,
+ uint16_t outputStride, uint8_t* pYPlane, uint8_t* pUVPlane, uint16_t nSrcWidth,
+ uint16_t nSrcHeight)
{
- uint16_t x, y;
- uint64_t srcIdx, dstIdx;
- const uint64_t size = nSrcWidth * nSrcHeight;
+ uint16_t x, y, nDstWth = nSrcHeight, nDstHt = nSrcWidth, nPadWidth = outputStride - nDstWth;
+ uint64_t srcIdx, dstIdx = outputStride * nDstHt - 1;
+ const size_t size = nSrcWidth * nSrcHeight;
+ const size_t dstSize = outputStride * nDstHt * 1.5f;
- dstIdx = size - 1;
+ if (nOutBufSize < (dstSize - nPadWidth))
+ {
+ IMLOGE4("Output buffer size is not sufficient. \
+ Required(outputStride[%d] * outputHeight[%d] * 1.5 = %d) but passed[%d]",
+ outputStride, nDstHt, dstSize, nOutBufSize);
+ return -1;
+ }
+
+ if (nDstWth > outputStride)
+ {
+ IMLOGE2("Destination width[%d] cannot be bigger than stride[%d]", nDstWth, outputStride);
+ return -1;
+ }
// Rotate Y buffer
for (y = 0; y < nSrcWidth; y++)
{
+ dstIdx -= nPadWidth;
srcIdx = size - nSrcWidth + y;
for (x = 0; x < nSrcHeight; x++)
{
- pbDst[dstIdx] = pYPlane[srcIdx]; // Y
+ pOutBuffer[dstIdx] = pYPlane[srcIdx]; // Y
srcIdx -= nSrcWidth;
dstIdx--;
}
}
- dstIdx = (size * 1.5f) - 1;
+ dstIdx = dstSize - 1;
nSrcWidth /= 2;
nSrcHeight /= 2;
// Rotate UV buffer
for (y = 0; y < nSrcWidth; y++)
{
+ dstIdx -= nPadWidth;
srcIdx = (size / 2) - (nSrcWidth - y) * 2;
for (x = 0; x < nSrcHeight; x++)
{
- pbDst[dstIdx--] = pUVPlane[srcIdx + 1]; // V
- pbDst[dstIdx--] = pUVPlane[srcIdx]; // U
+ pOutBuffer[dstIdx--] = pUVPlane[srcIdx + 1]; // V
+ pOutBuffer[dstIdx--] = pUVPlane[srcIdx]; // U
srcIdx -= nSrcWidth * 2;
}
}
+
+ return 0;
} \ No newline at end of file
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/ImsMediaVideoUtil.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/ImsMediaVideoUtil.cpp
index 817a1153..4dea4783 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/ImsMediaVideoUtil.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/ImsMediaVideoUtil.cpp
@@ -590,22 +590,20 @@ bool ImsMediaVideoUtil::ParseHevcSps(uint8_t* pbBuffer, uint32_t nBufferSize, tC
ImsMediaBitReader objBitReader;
objBitReader.SetBuffer(pbBuffer + nOffset, nBufferSize - nOffset);
- objBitReader.Read(4); // sps_video_parameter_set_id;
- uint32_t sps_max_sub_layers_minus1 = objBitReader.Read(3);
- objBitReader.Read(1); // sps_temporal_id_nesting_flag;
+ objBitReader.Read(4); // sps_video_parameter_set_id;
+ uint32_t sps_max_sub_layers_minus1 = objBitReader.Read(3); // 0
+ objBitReader.Read(1); // sps_temporal_id_nesting_flag;
- /*-----------profile_tier_level start-----------------------*/
- objBitReader.Read(3); // general_profile_spac, general_tier_flag
- objBitReader.Read(5); // general_profile_idc
+ objBitReader.Read(3); // general_profile_spac, general_tier_flag
+ pInfo->nProfile = objBitReader.Read(5); // general_profile_idc
- // skip 13byte - flags, not handle
- objBitReader.Read(24);
+ // skip 10byte - flags, not handle
objBitReader.Read(24);
objBitReader.Read(24);
objBitReader.Read(24);
objBitReader.Read(8);
- objBitReader.Read(8); // general_level_idc
+ pInfo->nLevel = objBitReader.Read(8); // general_level_idc
uint8_t sub_layer_profile_present_flag[sps_max_sub_layers_minus1];
uint8_t sub_layer_level_present_flag[sps_max_sub_layers_minus1];
@@ -645,19 +643,15 @@ bool ImsMediaVideoUtil::ParseHevcSps(uint8_t* pbBuffer, uint32_t nBufferSize, tC
objBitReader.ReadByUEMode(); // sps_seq_parameter_set_id
- uint32_t chroma_format_idc;
- chroma_format_idc = objBitReader.ReadByUEMode();
+ uint32_t chroma_format_idc = objBitReader.ReadByUEMode();
if (chroma_format_idc == 3)
{
objBitReader.Read(1); // separate_colour_plane_flag
}
- int32_t pic_width_in_luma_samples = objBitReader.ReadByUEMode();
- int32_t pic_height_in_luma_samples = objBitReader.ReadByUEMode();
-
- pInfo->nWidth = pic_width_in_luma_samples;
- pInfo->nHeight = pic_height_in_luma_samples;
+ pInfo->nWidth = objBitReader.ReadByUEMode();
+ pInfo->nHeight = objBitReader.ReadByUEMode();
uint8_t conformance_window_flag = objBitReader.Read(1);
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoManager.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoManager.cpp
index 9d98be37..4652511a 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoManager.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoManager.cpp
@@ -21,9 +21,18 @@
using namespace android;
VideoManager* VideoManager::manager;
-VideoManager::VideoManager() {}
+VideoManager::VideoManager()
+{
+ mRequestHandler.Init("VIDEO_REQUEST_EVENT");
+ mResponseHandler.Init("VIDEO_RESPONSE_EVENT");
+}
-VideoManager::~VideoManager() {}
+VideoManager::~VideoManager()
+{
+ mRequestHandler.Deinit();
+ mResponseHandler.Deinit();
+ manager = nullptr;
+}
VideoManager* VideoManager::getInstance()
{
@@ -245,13 +254,6 @@ void VideoManager::SendInternalEvent(
}
}
-VideoManager::RequestHandler::RequestHandler() :
- ImsMediaEventHandler("VIDEO_REQUEST_EVENT")
-{
-}
-
-VideoManager::RequestHandler::~RequestHandler() {}
-
void VideoManager::RequestHandler::processEvent(
uint32_t event, uint64_t sessionId, uint64_t paramA, uint64_t paramB)
{
@@ -351,13 +353,6 @@ void VideoManager::RequestHandler::processEvent(
}
}
-VideoManager::ResponseHandler::ResponseHandler() :
- ImsMediaEventHandler("VIDEO_RESPONSE_EVENT")
-{
-}
-
-VideoManager::ResponseHandler::~ResponseHandler() {}
-
void VideoManager::ResponseHandler::processEvent(
uint32_t event, uint64_t sessionId, uint64_t paramA, uint64_t paramB)
{
@@ -407,12 +402,7 @@ void VideoManager::ResponseHandler::processEvent(
// TODO : add implementation
break;
case kVideoMediaInactivityInd:
- parcel.writeInt32(event);
- parcel.writeInt32(static_cast<int>(paramA)); // type
- parcel.writeInt32(static_cast<int>(paramB)); // duration
- VideoManager::getInstance()->sendResponse(sessionId, parcel);
- break;
- case kVideoPacketLossInd:
+ case kVideoBitrateInd:
parcel.writeInt32(event);
parcel.writeInt32(static_cast<int>(paramA));
VideoManager::getInstance()->sendResponse(sessionId, parcel);
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoSession.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoSession.cpp
index 074e37cf..ba43d0a0 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoSession.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoSession.cpp
@@ -106,6 +106,7 @@ ImsMediaResult VideoSession::startGraph(RtpConfig* config)
if (mGraphRtpTx != nullptr)
{
+ mGraphRtpTx->setMediaQualityThreshold(&mThreshold);
ret = mGraphRtpTx->update(config);
if (ret != RESULT_SUCCESS)
@@ -135,6 +136,7 @@ ImsMediaResult VideoSession::startGraph(RtpConfig* config)
if (pConfig->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_SEND_ONLY ||
pConfig->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_SEND_RECEIVE)
{
+ mGraphRtpTx->setMediaQualityThreshold(&mThreshold);
ret = mGraphRtpTx->start();
}
}
@@ -265,6 +267,10 @@ void VideoSession::onEvent(int32_t type, uint64_t param1, uint64_t param2)
ImsMediaEventHandler::SendEvent(
"VIDEO_RESPONSE_EVENT", kVideoDataUsageInd, mSessionId, param1, param2);
break;
+ case kImsMediaEventNotifyVideoLowestBitrate:
+ ImsMediaEventHandler::SendEvent(
+ "VIDEO_RESPONSE_EVENT", kVideoBitrateInd, mSessionId, param1, param2);
+ break;
case kRequestVideoCvoUpdate:
case kRequestVideoBitrateChange:
case kRequestVideoIdrFrame:
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoStreamGraphRtcp.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoStreamGraphRtcp.cpp
index 28ef246a..03a6f728 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoStreamGraphRtcp.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoStreamGraphRtcp.cpp
@@ -94,7 +94,7 @@ ImsMediaResult VideoStreamGraphRtcp::update(RtpConfig* config)
if (*reinterpret_cast<VideoConfig*>(mConfig) == *pConfig)
{
- IMLOGD0("[update] no update");
+ IMLOGI0("[update] no update");
return RESULT_SUCCESS;
}
@@ -105,6 +105,12 @@ ImsMediaResult VideoStreamGraphRtcp::update(RtpConfig* config)
mConfig = new VideoConfig(pConfig);
+ if (mConfig->getMediaDirection() == RtpConfig::MEDIA_DIRECTION_NO_FLOW)
+ {
+ IMLOGI0("[update] pause RTCP");
+ return stop();
+ }
+
ImsMediaResult ret = ImsMediaResult::RESULT_NOT_READY;
// stop scheduler
if (mGraphState == kStreamStateRunning)
@@ -125,7 +131,8 @@ ImsMediaResult VideoStreamGraphRtcp::update(RtpConfig* config)
}
}
- if (mGraphState == kStreamStateCreated && mConfig->getRtcpConfig().getIntervalSec() != 0)
+ if (mGraphState == kStreamStateCreated &&
+ mConfig->getMediaDirection() != RtpConfig::MEDIA_DIRECTION_NO_FLOW)
{
IMLOGI0("[update] resume RTCP");
return start();
@@ -140,6 +147,24 @@ ImsMediaResult VideoStreamGraphRtcp::update(RtpConfig* config)
return ret;
}
+ImsMediaResult VideoStreamGraphRtcp::start()
+{
+ IMLOGI1("[start] state[%d]", mGraphState);
+
+ if (mConfig == nullptr)
+ {
+ return RESULT_INVALID_PARAM;
+ }
+
+ if (mConfig->getMediaDirection() != RtpConfig::MEDIA_DIRECTION_NO_FLOW)
+ {
+ return BaseStreamGraph::start();
+ }
+
+ // not started
+ return RESULT_SUCCESS;
+}
+
bool VideoStreamGraphRtcp::setMediaQualityThreshold(MediaQualityThreshold* threshold)
{
if (threshold != nullptr)
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoStreamGraphRtpRx.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoStreamGraphRtpRx.cpp
index c93bf83a..30912f9e 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoStreamGraphRtpRx.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoStreamGraphRtpRx.cpp
@@ -90,7 +90,7 @@ ImsMediaResult VideoStreamGraphRtpRx::update(RtpConfig* config)
if (*reinterpret_cast<VideoConfig*>(mConfig) == *pConfig)
{
- IMLOGD0("[update] no update");
+ IMLOGI0("[update] no update");
return RESULT_SUCCESS;
}
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoStreamGraphRtpTx.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoStreamGraphRtpTx.cpp
index ea3d4654..bc7c7dd0 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoStreamGraphRtpTx.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoStreamGraphRtpTx.cpp
@@ -106,7 +106,7 @@ ImsMediaResult VideoStreamGraphRtpTx::update(RtpConfig* config)
if (*reinterpret_cast<VideoConfig*>(mConfig) == *pConfig)
{
- IMLOGD0("[update] no update");
+ IMLOGI0("[update] no update");
return RESULT_SUCCESS;
}
@@ -234,6 +234,23 @@ ImsMediaResult VideoStreamGraphRtpTx::start()
return RESULT_SUCCESS;
}
+bool VideoStreamGraphRtpTx::setMediaQualityThreshold(MediaQualityThreshold* threshold)
+{
+ if (threshold != nullptr)
+ {
+ BaseNode* node = findNode(kNodeIdVideoSource);
+
+ if (node != nullptr)
+ {
+ IVideoSourceNode* source = reinterpret_cast<IVideoSourceNode*>(node);
+ source->SetBitrateThreshold(threshold->getVideoBitrateBps());
+ return true;
+ }
+ }
+
+ return false;
+}
+
void VideoStreamGraphRtpTx::setSurface(ANativeWindow* surface)
{
IMLOGI1("[setSurface] state[%d]", mGraphState);
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/android/ImsMediaCamera.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/android/ImsMediaCamera.cpp
index 36a4f1eb..afca7820 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/android/ImsMediaCamera.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/android/ImsMediaCamera.cpp
@@ -191,7 +191,6 @@ bool ImsMediaCamera::OpenCamera()
return false;
}
- // Create back facing camera device
camera_status_t status = ACameraManager_openCamera(mManager, mActiveCameraId.c_str(),
GetDeviceListener(), &gCameraIds[mActiveCameraId].mDevice);
@@ -220,6 +219,7 @@ bool ImsMediaCamera::OpenCamera()
if (status == ACAMERA_OK)
{
mExposureRange.min = val.data.i64[0];
+
if (mExposureRange.min < kMinExposureTime)
{
mExposureRange.min = kMinExposureTime;
@@ -285,7 +285,7 @@ bool ImsMediaCamera::CreateSession(ANativeWindow* preview, ANativeWindow* record
return false;
}
- if (MatchCaptureSizeRequest(preview) == false)
+ if (!MatchCaptureSizeRequest(preview))
{
IMLOGE0("[CreateSession] resolution is not matched");
return false;
@@ -339,7 +339,7 @@ bool ImsMediaCamera::CreateSession(ANativeWindow* preview, ANativeWindow* record
}
}
- if (gCameraIds[mActiveCameraId].mAvailable == false)
+ if (!gCameraIds[mActiveCameraId].mAvailable)
{
gCondition.wait_timeout(MAX_WAIT_CAMERA);
}
@@ -395,39 +395,41 @@ bool ImsMediaCamera::DeleteSession()
mCaptureSession = nullptr;
}
- for (int idxTarget = 0; idxTarget < mCaptureRequest.outputNativeWindows.size(); idxTarget++)
+ if (mCaptureRequest.request != nullptr)
{
- if (mCaptureRequest.outputNativeWindows[idxTarget] == nullptr)
+ for (int idxTarget = 0; idxTarget < mCaptureRequest.outputNativeWindows.size(); idxTarget++)
{
- continue;
- }
+ if (mCaptureRequest.outputNativeWindows[idxTarget] == nullptr)
+ {
+ continue;
+ }
- status = ACaptureRequest_removeTarget(
- mCaptureRequest.request, mCaptureRequest.targets[idxTarget]);
+ status = ACaptureRequest_removeTarget(
+ mCaptureRequest.request, mCaptureRequest.targets[idxTarget]);
- if (status != ACAMERA_OK)
- {
- IMLOGE1("[DeleteSession] error ACaptureRequest_removeTarget[%s]", GetErrorStr(status));
- }
+ if (status != ACAMERA_OK)
+ {
+ IMLOGE1("[DeleteSession] error ACaptureRequest_removeTarget[%s]",
+ GetErrorStr(status));
+ }
- ACameraOutputTarget_free(mCaptureRequest.targets[idxTarget]);
- status = ACaptureSessionOutputContainer_remove(
- mSessionOutputContainer, mCaptureRequest.sessionOutputs[idxTarget]);
+ ACameraOutputTarget_free(mCaptureRequest.targets[idxTarget]);
+ status = ACaptureSessionOutputContainer_remove(
+ mSessionOutputContainer, mCaptureRequest.sessionOutputs[idxTarget]);
- if (status != ACAMERA_OK)
- {
- IMLOGE1("[DeleteSession] error ACaptureSessionOutputContainer_remove[%s]",
- GetErrorStr(status));
- }
+ if (status != ACAMERA_OK)
+ {
+ IMLOGE1("[DeleteSession] error ACaptureSessionOutputContainer_remove[%s]",
+ GetErrorStr(status));
+ }
- ACaptureSessionOutput_free(mCaptureRequest.sessionOutputs[idxTarget]);
- ANativeWindow_release(mCaptureRequest.outputNativeWindows[idxTarget]);
- }
+ ACaptureSessionOutput_free(mCaptureRequest.sessionOutputs[idxTarget]);
+ ANativeWindow_release(mCaptureRequest.outputNativeWindows[idxTarget]);
+ }
- if (mCaptureRequest.request != nullptr)
- {
IMLOGD0("[DeleteSession] free request");
ACaptureRequest_free(mCaptureRequest.request);
+ mCaptureRequest.request = nullptr;
}
mCaptureRequest.outputNativeWindows.resize(0);
@@ -438,6 +440,7 @@ bool ImsMediaCamera::DeleteSession()
{
IMLOGD0("[DeleteSession] free container");
ACaptureSessionOutputContainer_free(mSessionOutputContainer);
+ mSessionOutputContainer = nullptr;
}
return true;
@@ -575,7 +578,6 @@ void ImsMediaCamera::OnDeviceState(ACameraDevice* dev)
IMLOGW1("[OnDeviceState] device %s is disconnected", id.c_str());
gCameraIds[id].mAvailable = false;
ACameraDevice_close(gCameraIds[id].mDevice);
- gCameraIds.erase(id);
}
/*
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/android/ImsMediaPauseImageSource.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/android/ImsMediaPauseImageSource.cpp
index 29a472aa..58c2f9fa 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/android/ImsMediaPauseImageSource.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/android/ImsMediaPauseImageSource.cpp
@@ -63,9 +63,10 @@ void ImsMediaPauseImageSource::Uninitialize()
}
}
-bool ImsMediaPauseImageSource::Initialize(int width, int height)
+bool ImsMediaPauseImageSource::Initialize(int width, int height, int stride)
{
- IMLOGD2("[ImsMediaPauseImageSource] Init(width:%d, height:%d)", width, height);
+ IMLOGD3("[ImsMediaPauseImageSource] Init(width:%d, height:%d, stride:%d)", width, height,
+ stride);
mWidth = width;
mHeight = height;
@@ -105,12 +106,12 @@ bool ImsMediaPauseImageSource::Initialize(int width, int height)
* (AndroidBitmapFormat)AImageDecoderHeaderInfo_getAndroidBitmapFormat(info);
*/
- size_t stride = AImageDecoder_getMinimumStride(decoder); // Image decoder does not
+ size_t decStride = AImageDecoder_getMinimumStride(decoder); // Image decoder does not
// use padding by default
- size_t size = height * stride;
+ size_t size = height * decStride;
int8_t* pixels = reinterpret_cast<int8_t*>(malloc(size));
- result = AImageDecoder_decodeImage(decoder, pixels, stride, size);
+ result = AImageDecoder_decodeImage(decoder, pixels, decStride, size);
if (result != ANDROID_IMAGE_DECODER_SUCCESS)
{
IMLOGE0("[ImsMediaPauseImageSource] error occurred, and the file could not be decoded.");
@@ -119,7 +120,7 @@ bool ImsMediaPauseImageSource::Initialize(int width, int height)
return false;
}
- mYuvImageBuffer = ConvertRgbaToYuv(pixels, width, height);
+ mYuvImageBuffer = ConvertRgbaToYuv(pixels, width, height, stride);
AImageDecoder_delete(decoder);
free(pixels);
@@ -141,7 +142,8 @@ size_t ImsMediaPauseImageSource::GetYuvImage(uint8_t* buffer, size_t len)
return mBufferSize;
}
- IMLOGE0("[ImsMediaPauseImageSource] buffer size is smaller. Cannot copy");
+ IMLOGE2("[ImsMediaPauseImageSource] buffer size is smaller. Expected Bufsize[%d], passed[%d]",
+ mBufferSize, len);
return 0;
}
@@ -200,31 +202,27 @@ const char* ImsMediaPauseImageSource::getImageFilePath()
return nullptr;
}
-int8_t* ImsMediaPauseImageSource::ConvertRgbaToYuv(int8_t* pixels, int width, int height)
+int8_t* ImsMediaPauseImageSource::ConvertRgbaToYuv(
+ int8_t* pixels, int width, int height, int stride)
{
// src array must be integer array, data have no padding alignment
int32_t* pSrcArray = reinterpret_cast<int32_t*>(pixels);
- mBufferSize = width * height * 1.5;
+ mBufferSize = stride * height * 1.5;
int8_t* pDstArray = reinterpret_cast<int8_t*>(malloc(mBufferSize));
int32_t nYIndex = 0;
- int32_t nUVIndex = width * height;
- int32_t r, g, b;
+ int32_t nUVIndex = stride * height;
+ int32_t r, g, b, padLen = stride - width;
double y, u, v;
for (int32_t j = 0; j < height; j++)
{
+ int32_t nIndex = width * j;
for (int32_t i = 0; i < width; i++)
{
- int32_t nIndex = width * j + i;
-
- /*
- * TODO: Decode alpha
- * a = (pSrcArray[nIndex] & 0xff000000) >> 24;
- */
-
r = (pSrcArray[nIndex] & 0xff0000) >> 16;
g = (pSrcArray[nIndex] & 0xff00) >> 8;
b = (pSrcArray[nIndex] & 0xff) >> 0;
+ nIndex++;
// rgb to yuv
y = 0.257 * r + 0.504 * g + 0.098 * b + 16;
@@ -240,7 +238,19 @@ int8_t* ImsMediaPauseImageSource::ConvertRgbaToYuv(int8_t* pixels, int width, in
pDstArray[nUVIndex++] = (uint8_t)((u < 0) ? 0 : ((u > 255) ? 255 : u));
}
}
+
+ // Add padding if stride > width
+ if (padLen > 0)
+ {
+ nYIndex += padLen;
+
+ if (j % 2 == 0)
+ {
+ nUVIndex += padLen;
+ }
+ }
}
+ mBufferSize -= padLen;
return pDstArray;
}
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/android/ImsMediaVideoRenderer.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/android/ImsMediaVideoRenderer.cpp
index a4fe774d..475425be 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/android/ImsMediaVideoRenderer.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/android/ImsMediaVideoRenderer.cpp
@@ -210,10 +210,12 @@ void ImsMediaVideoRenderer::processBuffers()
}
auto index = AMediaCodec_dequeueInputBuffer(mCodec, CODEC_TIMEOUT_NANO);
+
if (index >= 0)
{
size_t bufferSize = 0;
uint8_t* inputBuffer = AMediaCodec_getInputBuffer(mCodec, index, &bufferSize);
+
if (inputBuffer != nullptr)
{
FrameData* frame = mFrameDatas.front();
@@ -223,17 +225,8 @@ void ImsMediaVideoRenderer::processBuffers()
"config[%d]",
index, frame->size, frame->timestamp, frame->isConfig);
- media_status_t err;
- if (frame->isConfig)
- {
- err = AMediaCodec_queueInputBuffer(mCodec, index, 0, frame->size,
- frame->timestamp * 1000, AMEDIACODEC_BUFFER_FLAG_CODEC_CONFIG);
- }
- else
- {
- err = AMediaCodec_queueInputBuffer(
- mCodec, index, 0, frame->size, frame->timestamp * 1000, 0);
- }
+ media_status_t err = AMediaCodec_queueInputBuffer(
+ mCodec, index, 0, frame->size, frame->timestamp * 1000, 0);
if (err != AMEDIA_OK)
{
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/android/ImsMediaVideoSource.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/android/ImsMediaVideoSource.cpp
index c93d99a4..38b71771 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/android/ImsMediaVideoSource.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/android/ImsMediaVideoSource.cpp
@@ -30,7 +30,6 @@ ImsMediaVideoSource::ImsMediaVideoSource()
mWindow = nullptr;
mCodec = nullptr;
mFormat = nullptr;
- mRecordingSurface = nullptr;
mImageReaderSurface = nullptr;
mImageReader = nullptr;
mCodecType = -1;
@@ -164,7 +163,6 @@ void ImsMediaVideoSource::SetDeviceOrientation(const uint32_t degree)
bool ImsMediaVideoSource::Start()
{
IMLOGD1("[Start], VideoMode[%d]", mVideoMode);
- mRecordingSurface = nullptr;
if (mVideoMode == kVideoModeRecording || mVideoMode == kVideoModePauseImage)
{
@@ -214,27 +212,30 @@ bool ImsMediaVideoSource::Start()
return false;
}
- if (mWidth > mHeight) // Is Landscape Mode
- {
- err = AMediaCodec_createInputSurface(mCodec, &mRecordingSurface);
+ mImageReaderSurface = CreateImageReader(mWidth, mHeight);
- if (err != AMEDIA_OK)
- {
- IMLOGE1("[Start] create input surface error[%d]", err);
- AMediaCodec_delete(mCodec);
- mCodec = nullptr;
- AMediaFormat_delete(mFormat);
- mFormat = nullptr;
- return false;
- }
- }
- else
+ if (mImageReaderSurface == nullptr)
{
- mImageReaderSurface = CreateImageReader(mWidth, mHeight);
+ IMLOGE0("[Start] create image reader failed");
+ return false;
+ }
- if (mImageReaderSurface == nullptr)
+ mCodecStride = mWidth;
+ AMediaFormat* encoderInputFormat = AMediaCodec_getInputFormat(mCodec);
+
+ if (encoderInputFormat != nullptr)
+ {
+ // Check if encoder is initialized with the expected configurations.
+ int32_t width = 0, height = 0;
+ AMediaFormat_getInt32(encoderInputFormat, AMEDIAFORMAT_KEY_WIDTH, &width);
+ AMediaFormat_getInt32(encoderInputFormat, AMEDIAFORMAT_KEY_HEIGHT, &height);
+ AMediaFormat_getInt32(encoderInputFormat, AMEDIAFORMAT_KEY_STRIDE, &mCodecStride);
+ AMediaFormat_delete(encoderInputFormat);
+
+ // TODO: More configuration checks should be added
+ if (mWidth != width || mHeight != height || width > mCodecStride)
{
- IMLOGE0("[Start] create image reader failed");
+ IMLOGE0("Encoder doesn't support requested configuration.");
return false;
}
}
@@ -268,9 +269,7 @@ bool ImsMediaVideoSource::Start()
return false;
}
- ANativeWindow* recording = mRecordingSurface ? mRecordingSurface : mImageReaderSurface;
-
- if (mCamera->CreateSession(mWindow, recording) == false)
+ if (mCamera->CreateSession(mWindow, mImageReaderSurface) == false)
{
IMLOGE0("[Start] error create camera session");
AMediaCodec_delete(mCodec);
@@ -294,15 +293,14 @@ bool ImsMediaVideoSource::Start()
}
else if (mVideoMode == kVideoModePauseImage)
{
- mPauseImageSource.Initialize(mWidth, mHeight);
- }
-
- // start encoder output thread
- if (mCodec != nullptr)
- {
- mStopped = false;
- std::thread t1(&ImsMediaVideoSource::processOutputBuffer, this);
- t1.detach();
+ mPauseImageSource.Initialize(mWidth, mHeight, mCodecStride);
+ // start encoder output thread
+ if (mCodec != nullptr)
+ {
+ mStopped = false;
+ std::thread t1(&ImsMediaVideoSource::EncodePauseImage, this);
+ t1.detach();
+ }
}
mDeviceOrientation = -1;
@@ -314,19 +312,19 @@ void ImsMediaVideoSource::Stop()
{
IMLOGD0("[Stop]");
- mMutex.lock();
+ std::lock_guard<std::mutex> guard(mMutex);
mStopped = true;
- mMutex.unlock();
- if (mCamera != nullptr)
+ if (mImageReader != nullptr)
{
- mCamera->StopSession();
+ AImageReader_delete(mImageReader);
+ mImageReader = nullptr;
+ mImageReaderSurface = nullptr;
}
- IMLOGD0("[Stop] deinitialize camera");
-
if (mCamera != nullptr)
{
+ mCamera->StopSession();
mCamera->DeleteSession();
mCamera->DeInitialize();
mCamera = nullptr;
@@ -334,19 +332,12 @@ void ImsMediaVideoSource::Stop()
if (mCodec != nullptr)
{
- if (mRecordingSurface != nullptr)
+ if (mVideoMode == kVideoModePauseImage)
{
- AMediaCodec_signalEndOfInputStream(mCodec);
+ mConditionExit.wait_timeout(mFramerate != 0 ? 1000 / mFramerate : 66);
}
AMediaCodec_stop(mCodec);
-
- if (mRecordingSurface != nullptr)
- {
- ANativeWindow_release(mRecordingSurface);
- mRecordingSurface = nullptr;
- }
-
AMediaCodec_delete(mCodec);
mCodec = nullptr;
}
@@ -357,15 +348,10 @@ void ImsMediaVideoSource::Stop()
mFormat = nullptr;
}
- if (mImageReader != nullptr)
+ if (mVideoMode == kVideoModePauseImage)
{
- std::lock_guard<std::mutex> guard(mImageReaderMutex);
- AImageReader_delete(mImageReader);
- mImageReader = nullptr;
- mImageReaderSurface = nullptr;
+ mPauseImageSource.Uninitialize();
}
-
- mPauseImageSource.Uninitialize();
}
bool ImsMediaVideoSource::IsStopped()
@@ -376,7 +362,7 @@ bool ImsMediaVideoSource::IsStopped()
void ImsMediaVideoSource::onCameraFrame(AImage* pImage)
{
- std::lock_guard<std::mutex> guard(mImageReaderMutex);
+ std::lock_guard<std::mutex> guard(mMutex);
if (mImageReader == nullptr || pImage == nullptr)
{
@@ -389,7 +375,6 @@ void ImsMediaVideoSource::onCameraFrame(AImage* pImage)
{
size_t buffCapacity = 0;
uint8_t* encoderBuf = AMediaCodec_getInputBuffer(mCodec, index, &buffCapacity);
-
if (!encoderBuf || !buffCapacity)
{
IMLOGE1("[onCameraFrame] returned null buffer pointer or buffCapacity[%d]",
@@ -397,69 +382,93 @@ void ImsMediaVideoSource::onCameraFrame(AImage* pImage)
return;
}
- int32_t width, height, ylen, uvlen;
+ int32_t width, height, ylen, uvlen, result = 0;
uint8_t *yPlane, *uvPlane;
AImage_getWidth(pImage, &width);
AImage_getHeight(pImage, &height);
AImage_getPlaneData(pImage, 0, &yPlane, &ylen);
AImage_getPlaneData(pImage, 1, &uvPlane, &uvlen);
- int32_t facing, sensorOrientation;
- mCamera->GetSensorOrientation(mCameraId, &facing, &sensorOrientation);
-
- switch (facing)
+ if (mWidth > mHeight) // landscape mode, copy without rotate
{
- case ACAMERA_LENS_FACING_FRONT:
- {
- ImsMediaImageRotate::YUV420_SP_Rotate270(
- encoderBuf, yPlane, uvPlane, width, height);
- }
- break;
+ memcpy(encoderBuf, yPlane, ylen);
+ memcpy(encoderBuf + ylen, uvPlane, uvlen);
+ }
+ else
+ {
+ int32_t facing, sensorOrientation;
+ mCamera->GetSensorOrientation(mCameraId, &facing, &sensorOrientation);
- case ACAMERA_LENS_FACING_BACK:
+ switch (facing)
{
- ImsMediaImageRotate::YUV420_SP_Rotate90(encoderBuf, yPlane, uvPlane, width, height);
- }
- break;
+ case ACAMERA_LENS_FACING_FRONT:
+ {
+ result = ImsMediaImageRotate::YUV420_SP_Rotate270(
+ encoderBuf, buffCapacity, mCodecStride, yPlane, uvPlane, width, height);
+ }
+ break;
- case ACAMERA_LENS_FACING_EXTERNAL:
- {
- uint32_t size = width * height;
- memcpy(encoderBuf, yPlane, size);
- memcpy(encoderBuf + size, uvPlane, size / 2);
+ case ACAMERA_LENS_FACING_BACK:
+ {
+ result = ImsMediaImageRotate::YUV420_SP_Rotate90(
+ encoderBuf, buffCapacity, mCodecStride, yPlane, uvPlane, width, height);
+ }
+ break;
+
+ case ACAMERA_LENS_FACING_EXTERNAL:
+ {
+ uint32_t size = width * height;
+ memcpy(encoderBuf, yPlane, size);
+ memcpy(encoderBuf + size, uvPlane, size / 2);
+ }
+ break;
}
- break;
}
IMLOGD_PACKET1(IM_PACKET_LOG_VIDEO, "[onCameraFrame] queue buffer size[%d]", ylen + uvlen);
- AMediaCodec_queueInputBuffer(
- mCodec, index, 0, ylen + uvlen, ImsMediaTimer::GetTimeInMicroSeconds(), 0);
+ if (result == 0)
+ {
+ AMediaCodec_queueInputBuffer(
+ mCodec, index, 0, ylen + uvlen, ImsMediaTimer::GetTimeInMicroSeconds(), 0);
+ }
+ else
+ {
+ IMLOGE5("Camera image resolution[%dx%d]. Encoder resolution[%dx%d] buffer size[%d]",
+ width, height, mWidth, mHeight, buffCapacity);
+ AMediaCodec_queueInputBuffer(mCodec, index, 0, 0, 0, 0);
+ return;
+ }
}
else
{
IMLOGE1("[onCameraFrame] dequeueInputBuffer returned index[%d]", index);
}
+
+ processOutputBuffer();
}
-void ImsMediaVideoSource::changeBitrate(const uint32_t bitrate)
+bool ImsMediaVideoSource::changeBitrate(const uint32_t bitrate)
{
IMLOGD1("[changeBitrate] bitrate[%d]", bitrate);
std::lock_guard<std::mutex> guard(mMutex);
if (mStopped)
{
- return;
+ return false;
}
AMediaFormat* params = AMediaFormat_new();
- AMediaFormat_setInt32(params, AMEDIAFORMAT_KEY_BIT_RATE, bitrate);
+ AMediaFormat_setInt32(params, AMEDIACODEC_KEY_VIDEO_BITRATE, bitrate);
media_status_t status = AMediaCodec_setParameters(mCodec, params);
if (status != AMEDIA_OK)
{
IMLOGE1("[changeBitrate] error[%d]", status);
+ return false;
}
+
+ return true;
}
void ImsMediaVideoSource::requestIdrFrame()
@@ -484,29 +493,8 @@ void ImsMediaVideoSource::requestIdrFrame()
void ImsMediaVideoSource::EncodePauseImage()
{
- auto index = AMediaCodec_dequeueInputBuffer(mCodec, CODEC_TIMEOUT_NANO);
- if (index >= 0)
- {
- size_t buffCapacity = 0;
- uint8_t* encoderBuf = AMediaCodec_getInputBuffer(mCodec, index, &buffCapacity);
- if (!encoderBuf || !buffCapacity)
- {
- IMLOGE1("[EncodePauseImage] returned null buffer pointer or buffCapacity[%d]",
- buffCapacity);
- return;
- }
- size_t len = mPauseImageSource.GetYuvImage(encoderBuf, buffCapacity);
- AMediaCodec_queueInputBuffer(
- mCodec, index, 0, len, ImsMediaTimer::GetTimeInMicroSeconds(), 0);
- }
- else
- {
- IMLOGE1("[EncodePauseImage] dequeueInputBuffer returned index[%d]", index);
- }
-}
+ IMLOGD0("[EncodePauseImage] start");
-void ImsMediaVideoSource::processOutputBuffer()
-{
uint32_t nextTime = ImsMediaTimer::GetTimeInMilliSeconds();
uint32_t timeInterval = 66;
@@ -515,74 +503,37 @@ void ImsMediaVideoSource::processOutputBuffer()
timeInterval = 1000 / mFramerate;
}
- IMLOGD2("[processOutputBuffer] interval[%d] CameraId[%d]", timeInterval, mCameraId);
-
- for (;;)
+ while (!IsStopped())
{
- if (IsStopped())
- {
- IMLOGD0("[processOutputBuffer] terminated");
- break;
- }
-
- if (mVideoMode == kVideoModePauseImage)
- {
- EncodePauseImage();
- }
-
- AMediaCodecBufferInfo info;
- auto index = AMediaCodec_dequeueOutputBuffer(mCodec, &info, CODEC_TIMEOUT_NANO);
+ mMutex.lock();
+ auto index = AMediaCodec_dequeueInputBuffer(mCodec, CODEC_TIMEOUT_NANO);
if (index >= 0)
{
- IMLOGD_PACKET5(IM_PACKET_LOG_VIDEO,
- "[processOutputBuffer] index[%d], size[%d], offset[%d], time[%ld], flags[%d]",
- index, info.size, info.offset, info.presentationTimeUs, info.flags);
-
- if (info.size > 0)
- {
- size_t buffCapacity;
- uint8_t* buf = AMediaCodec_getOutputBuffer(mCodec, index, &buffCapacity);
-
- if (IsStopped())
- {
- break;
- }
-
- if (buf != nullptr && buffCapacity > 0)
- {
- if (mListener != nullptr)
- {
- mListener->OnUplinkEvent(
- buf + info.offset, info.size, info.presentationTimeUs, info.flags);
- }
- }
-
- AMediaCodec_releaseOutputBuffer(mCodec, index, false);
- }
- }
- else if (index == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED)
- {
- IMLOGI0("[processOutputBuffer] Encoder output buffer changed");
- }
- else if (index == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED)
- {
- if (mFormat != nullptr)
+ size_t buffCapacity = 0;
+ uint8_t* encoderBuf = AMediaCodec_getInputBuffer(mCodec, index, &buffCapacity);
+ if (!encoderBuf || !buffCapacity)
{
- AMediaFormat_delete(mFormat);
+ IMLOGE1("[EncodePauseImage] returned null buffer pointer or buffCapacity[%d]",
+ buffCapacity);
+ return;
}
- mFormat = AMediaCodec_getOutputFormat(mCodec);
- IMLOGI1("[processOutputBuffer] Encoder format changed, format[%s]",
- AMediaFormat_toString(mFormat));
+ size_t len = mPauseImageSource.GetYuvImage(encoderBuf, buffCapacity);
+ AMediaCodec_queueInputBuffer(
+ mCodec, index, 0, len, ImsMediaTimer::GetTimeInMicroSeconds(), 0);
}
- else if (index == AMEDIACODEC_INFO_TRY_AGAIN_LATER)
+ else
{
- IMLOGD_PACKET0(IM_PACKET_LOG_VIDEO, "[processOutputBuffer] no output buffer");
+ IMLOGE1("[EncodePauseImage] dequeueInputBuffer returned index[%d]", index);
}
- else
+
+ processOutputBuffer();
+ mMutex.unlock();
+
+ if (IsStopped())
{
- IMLOGI1("[processOutputBuffer] unexpected index[%d]", index);
+ break;
}
nextTime += timeInterval;
@@ -591,28 +542,77 @@ void ImsMediaVideoSource::processOutputBuffer()
if (nextTime > nCurrTime)
{
uint32_t timeDiff = nextTime - nCurrTime;
- IMLOGD_PACKET1(IM_PACKET_LOG_VIDEO, "[processOutputBuffer] timeDiff[%u]", timeDiff);
+ IMLOGD_PACKET1(IM_PACKET_LOG_VIDEO, "[EncodePauseImage] timeDiff[%u]", timeDiff);
ImsMediaTimer::Sleep(timeDiff);
}
}
- IMLOGD0("[processOutputBuffer] exit");
+ IMLOGD0("[EncodePauseImage] end");
+ mConditionExit.signal();
}
-static void ImageCallback(void* context, AImageReader* reader)
+void ImsMediaVideoSource::processOutputBuffer()
{
- if (context == nullptr)
+ AMediaCodecBufferInfo info;
+ auto index = AMediaCodec_dequeueOutputBuffer(mCodec, &info, CODEC_TIMEOUT_NANO);
+
+ if (index >= 0)
{
- return;
+ IMLOGD_PACKET5(IM_PACKET_LOG_VIDEO,
+ "[processOutputBuffer] index[%d], size[%d], offset[%d], time[%ld], flags[%d]",
+ index, info.size, info.offset, info.presentationTimeUs, info.flags);
+
+ if (info.size > 0)
+ {
+ size_t buffCapacity;
+ uint8_t* buf = AMediaCodec_getOutputBuffer(mCodec, index, &buffCapacity);
+
+ if (buf != nullptr && buffCapacity > 0)
+ {
+ if (mListener != nullptr)
+ {
+ mListener->OnUplinkEvent(
+ buf + info.offset, info.size, info.presentationTimeUs, info.flags);
+ }
+ }
+
+ AMediaCodec_releaseOutputBuffer(mCodec, index, false);
+ }
+ }
+ else if (index == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED)
+ {
+ IMLOGI0("[processOutputBuffer] Encoder output buffer changed");
}
+ else if (index == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED)
+ {
+ if (mFormat != nullptr)
+ {
+ AMediaFormat_delete(mFormat);
+ }
- ImsMediaVideoSource* pVideoSource = static_cast<ImsMediaVideoSource*>(context);
+ mFormat = AMediaCodec_getOutputFormat(mCodec);
+ IMLOGI1("[processOutputBuffer] Encoder format changed, format[%s]",
+ AMediaFormat_toString(mFormat));
+ }
+ else if (index == AMEDIACODEC_INFO_TRY_AGAIN_LATER)
+ {
+ IMLOGD_PACKET0(IM_PACKET_LOG_VIDEO, "[processOutputBuffer] no output buffer");
+ }
+ else
+ {
+ IMLOGI1("[processOutputBuffer] unexpected index[%d]", index);
+ }
+}
- if (pVideoSource->IsStopped())
+static void ImageCallback(void* context, AImageReader* reader)
+{
+ if (context == nullptr)
{
return;
}
+ ImsMediaVideoSource* pVideoSource = static_cast<ImsMediaVideoSource*>(context);
+
AImage* image = nullptr;
auto status = AImageReader_acquireNextImage(reader, &image);
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/nodes/IVideoRendererNode.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/nodes/IVideoRendererNode.cpp
index 88713fd1..9cff5794 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/nodes/IVideoRendererNode.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/nodes/IVideoRendererNode.cpp
@@ -53,7 +53,6 @@ IVideoRendererNode::IVideoRendererNode(BaseSessionCallback* callback) :
mFirstFrame = false;
mSubtype = MEDIASUBTYPE_UNDEFINED;
mFramerate = 0;
- mWaitIntraFrame = 0;
mLossDuration = 0;
mLossRateThreshold = 0;
}
@@ -87,7 +86,7 @@ ImsMediaResult IVideoRendererNode::Start()
mVideoRenderer->SetDeviceOrientation(mDeviceOrientation);
mVideoRenderer->SetSurface(mWindow);
- if (mVideoRenderer->Start() == false)
+ if (!mVideoRenderer->Start())
{
return RESULT_NOT_READY;
}
@@ -162,134 +161,105 @@ bool IVideoRendererNode::IsSameConfig(void* config)
void IVideoRendererNode::ProcessData()
{
std::lock_guard<std::mutex> guard(mMutex);
- uint8_t* pData = nullptr;
- uint32_t nDataSize = 0;
- uint32_t nTimeStamp = 0;
- bool bMark = false;
- uint32_t nSeqNum = 0;
+ uint8_t* data = nullptr;
+ uint32_t dataSize = 0;
+ uint32_t prevTimestamp = 0;
+ bool mark = false;
+ uint32_t seq = 0;
uint32_t timestamp = 0;
- uint32_t nBitstreamSize = 0;
+ uint32_t frameSize = 0;
ImsMediaSubType subtype = MEDIASUBTYPE_UNDEFINED;
- uint32_t nInitialSeqNum = 0;
- uint32_t nBufferOffset = 0;
+ uint32_t initialSeq = 0;
ImsMediaSubType dataType;
- while (GetData(&subtype, &pData, &nDataSize, &nTimeStamp, &bMark, &nSeqNum, &dataType))
+ while (GetData(&subtype, &data, &dataSize, &timestamp, &mark, &seq, &dataType))
{
IMLOGD_PACKET4(IM_PACKET_LOG_VIDEO,
- "[ProcessData] subtype[%d], Size[%d], TimeStamp[%d] nBitstreamSize[%d]", subtype,
- nDataSize, nTimeStamp, nBitstreamSize);
+ "[ProcessData] subtype[%d], Size[%d], TS[%d] frameSize[%d]", subtype, dataSize,
+ timestamp, frameSize);
- if (timestamp == 0)
+ if (prevTimestamp == 0)
{
- timestamp = nTimeStamp;
+ prevTimestamp = timestamp;
}
- else if (timestamp != nTimeStamp)
+ else if (timestamp != prevTimestamp || (frameSize != 0 && hasStartingCode(data, dataSize)))
{
+ // break when the timestamp is changed or next data has another starting code
break;
}
- if (nDataSize >= MAX_RTP_PAYLOAD_BUFFER_SIZE)
+ if (dataSize >= MAX_RTP_PAYLOAD_BUFFER_SIZE)
{
- IMLOGE1("[ProcessData] exceed buffer size[%d]", nDataSize);
+ IMLOGE1("[ProcessData] exceed buffer size[%d]", dataSize);
return;
}
- memcpy(mBuffer + nBitstreamSize, pData, nDataSize);
- nBitstreamSize += nDataSize;
+ memcpy(mBuffer + frameSize, data, dataSize);
+ frameSize += dataSize;
- if (nInitialSeqNum == 0)
+ if (initialSeq == 0)
{
- nInitialSeqNum = nSeqNum;
+ initialSeq = seq;
}
DeleteData();
- if (bMark)
+ if (mark)
{
break;
}
}
- if (nBitstreamSize == 0)
+ if (frameSize == 0)
{
return;
}
// remove AUD nal unit
- uint32_t nDatabufferSize = nBitstreamSize;
- uint8_t* pDataBuff = mBuffer;
- RemoveAUDNalUnit(mBuffer, nBitstreamSize, &pDataBuff, &nDatabufferSize);
-
- // check Config String for updating config frame
- nBufferOffset = 0;
- if ((mCodecType == kVideoCodecHevc || mCodecType == kVideoCodecAvc) &&
- IsConfigFrame(pDataBuff, nDatabufferSize, &nBufferOffset) == true)
+ uint32_t size = frameSize;
+ uint8_t* buffer = mBuffer;
+ RemoveAUDNalUnit(mBuffer, frameSize, &buffer, &size);
+
+ FrameType frameType = GetFrameType(buffer, size);
+
+ if (frameType == SPS)
{
- SaveConfigFrame(pDataBuff + nBufferOffset, nDatabufferSize - nBufferOffset, kConfigSps);
- SaveConfigFrame(pDataBuff + nBufferOffset, nDatabufferSize - nBufferOffset, kConfigPps);
+ SaveConfigFrame(buffer, size, kConfigSps);
+ tCodecConfig codecConfig;
- if (mCodecType == kVideoCodecHevc)
+ if (mCodecType == kVideoCodecAvc)
{
- SaveConfigFrame(pDataBuff + nBufferOffset, nDatabufferSize - nBufferOffset, kConfigVps);
+ if (ImsMediaVideoUtil::ParseAvcSps(buffer, size, &codecConfig))
+ {
+ CheckResolution(codecConfig.nWidth, codecConfig.nHeight);
+ }
}
-
- if (IsSps(pDataBuff, nDatabufferSize, &nBufferOffset) == true)
+ else if (mCodecType == kVideoCodecHevc)
{
- IMLOGD_PACKET1(
- IM_PACKET_LOG_VIDEO, "[ProcessData] parse SPS - nOffset[%d]", nBufferOffset);
- tCodecConfig codecConfig;
-
- if (mCodecType == kVideoCodecAvc)
+ if (ImsMediaVideoUtil::ParseHevcSps(buffer, size, &codecConfig))
{
- if (ImsMediaVideoUtil::ParseAvcSps(pDataBuff + nBufferOffset,
- nDatabufferSize - nBufferOffset, &codecConfig) == true)
- {
- CheckResolution(codecConfig.nWidth, codecConfig.nHeight);
- }
- }
- else if (mCodecType == kVideoCodecHevc)
- {
- if (ImsMediaVideoUtil::ParseHevcSps(pDataBuff + nBufferOffset,
- nDatabufferSize - nBufferOffset, &codecConfig) == true)
- {
- CheckResolution(codecConfig.nWidth, codecConfig.nHeight);
- }
+ CheckResolution(codecConfig.nWidth, codecConfig.nHeight);
}
}
return;
}
-
- IMLOGD_PACKET2(IM_PACKET_LOG_VIDEO, "[ProcessData] nBitstreamSize[%d] nDatabufferSize[%d]",
- nBitstreamSize, nDatabufferSize);
-
- bool isIntraFrame = IsIntraFrame(pDataBuff, nDatabufferSize);
-
- // drop non-idr frame when idr frame is not received
- if (mWaitIntraFrame > 0 && nDatabufferSize > 0)
+ else if (frameType == PPS)
{
- if (isIntraFrame)
- {
- mWaitIntraFrame = 0;
- }
- else
- {
- // Send FIR when I-frame wasn't received
- if ((mWaitIntraFrame % mFramerate) == 0) // every 1 sec
- {
- // TODO: send PLI event
- IMLOGD0("[ProcessData] request Send PLI");
- }
+ SaveConfigFrame(buffer, size, kConfigPps);
+ return;
+ }
+ else if (frameType == VPS)
+ {
+ SaveConfigFrame(buffer, size, kConfigVps);
+ return;
+ }
- mWaitIntraFrame--;
- nDatabufferSize = 0; // drop non-DIR frame
+ IMLOGD_PACKET2(IM_PACKET_LOG_VIDEO, "[ProcessData] frame type[%d] size[%d]", frameType, size);
- IMLOGD1("[ProcessData] wait intra frame[%d]", mWaitIntraFrame);
- }
- }
+ // TODO: Send PLI or FIR when I-frame wasn't received since beginning.
- if (mFirstFrame == false)
+ if (!mFirstFrame)
{
IMLOGD0("[ProcessData] notify first frame");
mFirstFrame = true;
@@ -297,6 +267,11 @@ void IVideoRendererNode::ProcessData()
if (mCallback != nullptr)
{
mCallback->SendEvent(kImsMediaEventFirstPacketReceived);
+
+ if (mCvoValue <= 0)
+ {
+ mCallback->SendEvent(kImsMediaEventResolutionChanged, mWidth, mHeight);
+ }
}
}
@@ -308,7 +283,8 @@ void IVideoRendererNode::ProcessData()
subtype = MEDIASUBTYPE_ROT0;
}
- if (mSubtype != subtype)
+ // rotation changed
+ if (mSubtype != subtype && (subtype >= MEDIASUBTYPE_ROT0 && subtype <= MEDIASUBTYPE_ROT270))
{
mSubtype = subtype;
int degree = 0;
@@ -335,13 +311,13 @@ void IVideoRendererNode::ProcessData()
}
}
- // send sps/pps before send I frame
- if (isIntraFrame)
+ // send config frames before send I frame
+ if (frameType == IDR)
{
QueueConfigFrame(timestamp);
}
- mVideoRenderer->OnDataFrame(pDataBuff, nDatabufferSize, timestamp, false);
+ mVideoRenderer->OnDataFrame(buffer, size, timestamp, false);
}
void IVideoRendererNode::UpdateSurface(ANativeWindow* window)
@@ -371,214 +347,84 @@ void IVideoRendererNode::SetPacketLossParam(uint32_t time, uint32_t rate)
mLossRateThreshold = rate;
}
-bool IVideoRendererNode::IsIntraFrame(uint8_t* pbBuffer, uint32_t nBufferSize)
+bool IVideoRendererNode::hasStartingCode(uint8_t* buffer, uint32_t bufferSize)
{
- bool bIntraFrame = false;
-
- if (nBufferSize <= 4)
+ if (bufferSize <= 4)
{
return false;
}
- IMLOGD_PACKET2(IM_PACKET_LOG_VIDEO, "[IsIntraFrame] size[%d], data[%s]", nBufferSize,
- ImsMediaTrace::IMTrace_Bin2String(
- reinterpret_cast<const char*>(pbBuffer), nBufferSize > 16 ? 16 : nBufferSize));
-
- switch (mCodecType)
+ // Check for NAL unit delimiter 0x00000001
+ if (buffer[0] == 0x00 && buffer[1] == 0x00 && buffer[2] == 0x00 && buffer[3] == 0x01)
{
- case kVideoCodecAvc:
- {
- uint32_t nCurrSize = nBufferSize;
- uint8_t* nCurrBuff = pbBuffer;
-
- while (nCurrSize >= 5)
- {
- if (nCurrBuff[0] == 0x00 && nCurrBuff[1] == 0x00 && nCurrBuff[2] == 0x00 &&
- nCurrBuff[3] == 0x01 && (nCurrBuff[4] & 0x1F) == 5)
- {
- bIntraFrame = true;
- break;
- }
- nCurrBuff++;
- nCurrSize--;
- }
-
- break;
- }
- case kVideoCodecHevc:
- {
- uint32_t nCurrSize = nBufferSize;
- uint8_t* nCurrBuff = pbBuffer;
- while (nCurrSize >= 5)
- {
- if (nCurrBuff[0] == 0x00 && nCurrBuff[1] == 0x00 && nCurrBuff[2] == 0x00 &&
- nCurrBuff[3] == 0x01 &&
- (((nCurrBuff[4] >> 1) & 0x3F) == 19 || ((nCurrBuff[4] >> 1) & 0x3F) == 20))
- {
- bIntraFrame = true;
- break;
- }
- nCurrBuff++;
- nCurrSize--;
- }
- break;
- }
- default:
- IMLOGE1("[IsIntraFrame] Invalid video codec type %d", mCodecType);
- return true;
+ return true;
}
- return bIntraFrame;
+ return false;
}
-bool IVideoRendererNode::IsConfigFrame(
- uint8_t* pbBuffer, uint32_t nBufferSize, uint32_t* nBufferOffset)
+FrameType IVideoRendererNode::GetFrameType(uint8_t* buffer, uint32_t bufferSize)
{
- bool bConfigFrame = false;
-
- if (nBufferSize <= 4)
- return false;
+ if (!hasStartingCode(buffer, bufferSize))
+ {
+ return UNKNOWN;
+ }
- IMLOGD_PACKET2(IM_PACKET_LOG_VIDEO, "[IsConfigFrame] size[%d], data[%s]", nBufferSize,
- ImsMediaTrace::IMTrace_Bin2String(
- reinterpret_cast<const char*>(pbBuffer), nBufferSize > 16 ? 16 : nBufferSize));
+ uint8_t nalType = buffer[4];
switch (mCodecType)
{
case kVideoCodecAvc:
{
- uint32_t nOffset = 0;
- uint32_t nCurrSize = nBufferSize;
- uint8_t* nCurrBuff = pbBuffer;
-
- while (nCurrSize >= 5)
+ if ((nalType & 0x1F) == 5)
{
- if (nCurrBuff[0] == 0x00 && nCurrBuff[1] == 0x00 && nCurrBuff[2] == 0x00 &&
- nCurrBuff[3] == 0x01 &&
- ((nCurrBuff[4] & 0x1F) == 7 || ((nCurrBuff[4] & 0x1F) == 8)))
- {
- bConfigFrame = true;
-
- if (nBufferOffset)
- {
- *nBufferOffset = nOffset;
- }
- break;
- }
-
- nOffset++;
- nCurrBuff++;
- nCurrSize--;
+ return IDR;
}
- break;
- }
- case kVideoCodecHevc:
- {
- uint32_t nOffset = 0;
- uint32_t nCurrSize = nBufferSize;
- uint8_t* nCurrBuff = pbBuffer;
-
- while (nCurrSize >= 5)
+ else if ((nalType & 0x1F) == 7)
{
- if (nCurrBuff[0] == 0x00 && nCurrBuff[1] == 0x00 && nCurrBuff[2] == 0x00 &&
- nCurrBuff[3] == 0x01 &&
- (((nCurrBuff[4] >> 1) & 0x3F) == 32 || ((nCurrBuff[4] >> 1) & 0x3F) == 33 ||
- ((nCurrBuff[4] >> 1) & 0x3F) == 34))
- {
- bConfigFrame = true;
- if (nBufferOffset)
- {
- *nBufferOffset = nOffset;
- }
- break;
- }
- nOffset++;
- nCurrBuff++;
- nCurrSize--;
+ return SPS;
}
- break;
- }
- default:
- return false;
- }
-
- return bConfigFrame;
-}
-
-bool IVideoRendererNode::IsSps(uint8_t* pbBuffer, uint32_t nBufferSize, uint32_t* nBufferOffset)
-{
- bool bSPS = false;
- if (nBufferSize <= 4)
- {
- return false;
- }
-
- IMLOGD_PACKET2(IM_PACKET_LOG_VIDEO, "[IsSps] size[%d], data[%s]", nBufferSize,
- ImsMediaTrace::IMTrace_Bin2String(
- reinterpret_cast<const char*>(pbBuffer), nBufferSize > 16 ? 16 : nBufferSize));
-
- switch (mCodecType)
- {
- case kVideoCodecAvc:
- {
- uint32_t nOffset = 0;
- uint32_t nCurrSize = nBufferSize;
- uint8_t* nCurrBuff = pbBuffer;
-
- while (nCurrSize >= 5)
+ else if ((nalType & 0x1F) == 8)
{
- if (nCurrBuff[0] == 0x00 && nCurrBuff[1] == 0x00 && nCurrBuff[2] == 0x00 &&
- nCurrBuff[3] == 0x01 && (nCurrBuff[4] & 0x1F) == 7)
- {
- bSPS = true;
-
- if (nBufferOffset)
- {
- *nBufferOffset = nOffset;
- }
-
- break;
- }
-
- nOffset++;
- nCurrBuff++;
- nCurrSize--;
+ return PPS;
+ }
+ else
+ {
+ return NonIDR;
}
break;
}
case kVideoCodecHevc:
{
- uint32_t nOffset = 0;
- uint32_t nCurrSize = nBufferSize;
- uint8_t* nCurrBuff = pbBuffer;
-
- while (nCurrSize >= 5)
+ if (((nalType >> 1) & 0x3F) == 19 || ((nalType >> 1) & 0x3F) == 20)
{
- if (nCurrBuff[0] == 0x00 && nCurrBuff[1] == 0x00 && nCurrBuff[2] == 0x00 &&
- nCurrBuff[3] == 0x01 && ((nCurrBuff[4] >> 1) & 0x3F) == 33)
- {
- bSPS = true;
-
- if (nBufferOffset)
- {
- *nBufferOffset = nOffset;
- }
-
- break;
- }
-
- nOffset++;
- nCurrBuff++;
- nCurrSize--;
+ return IDR;
+ }
+ else if (((nalType >> 1) & 0x3F) == 32)
+ {
+ return VPS;
+ }
+ else if (((nalType >> 1) & 0x3F) == 33)
+ {
+ return SPS;
+ }
+ else if (((nalType >> 1) & 0x3F) == 34)
+ {
+ return PPS;
+ }
+ else
+ {
+ return NonIDR;
}
+
break;
}
default:
- return false;
+ IMLOGE1("[GetFrameType] Invalid video codec type %d", mCodecType);
}
- return bSPS;
+ return UNKNOWN;
}
void IVideoRendererNode::SaveConfigFrame(uint8_t* pbBuffer, uint32_t nBufferSize, uint32_t eMode)
@@ -610,18 +456,17 @@ void IVideoRendererNode::SaveConfigFrame(uint8_t* pbBuffer, uint32_t nBufferSize
if (nCurrBuff[0] == 0x00 && nCurrBuff[1] == 0x00 && nCurrBuff[2] == 0x00 &&
nCurrBuff[3] == 0x01)
{
- if (eMode == kConfigSps && bSPSString == false && ((nCurrBuff[4] & 0x1F) == 7))
+ if (eMode == kConfigSps && !bSPSString && ((nCurrBuff[4] & 0x1F) == 7))
{
nOffset = nCurrSize;
bSPSString = true;
}
- else if (eMode == kConfigPps && bPPSString == false &&
- ((nCurrBuff[4] & 0x1F) == 8))
+ else if (eMode == kConfigPps && !bPPSString && ((nCurrBuff[4] & 0x1F) == 8))
{
nOffset = nCurrSize;
bPPSString = true;
}
- else if (bSPSString == true || bPPSString == true)
+ else if (bSPSString || bPPSString)
{
nConfigSize = nCurrSize - nOffset;
break;
@@ -684,21 +529,20 @@ void IVideoRendererNode::SaveConfigFrame(uint8_t* pbBuffer, uint32_t nBufferSize
if (nCurrBuff[0] == 0x00 && nCurrBuff[1] == 0x00 && nCurrBuff[2] == 0x00 &&
nCurrBuff[3] == 0x01)
{
- if (eMode == kConfigVps && bVPSString == false &&
- (((nCurrBuff[4] >> 1) & 0x3F) == 32))
+ if (eMode == kConfigVps && !bVPSString && (((nCurrBuff[4] >> 1) & 0x3F) == 32))
{
nOffset = nCurrSize;
bVPSString = true;
break;
}
- else if (eMode == kConfigSps && bSPSString == false &&
+ else if (eMode == kConfigSps && !bSPSString &&
(((nCurrBuff[4] >> 1) & 0x3F) == 33))
{
nOffset = nCurrSize;
bSPSString = true;
break;
}
- else if (eMode == kConfigPps && bPPSString == false &&
+ else if (eMode == kConfigPps && !bPPSString &&
(((nCurrBuff[4] >> 1) & 0x3F) == 34))
{
nOffset = nCurrSize;
@@ -711,7 +555,7 @@ void IVideoRendererNode::SaveConfigFrame(uint8_t* pbBuffer, uint32_t nBufferSize
nCurrSize++;
}
- if (bVPSString == true || bSPSString == true || bPPSString == true)
+ if (bVPSString || bSPSString || bPPSString)
{
if ((nBufferSize - nOffset) > 0)
{
@@ -762,13 +606,13 @@ void IVideoRendererNode::SaveConfigFrame(uint8_t* pbBuffer, uint32_t nBufferSize
}
bool IVideoRendererNode::RemoveAUDNalUnit(
- uint8_t* pInBuffer, uint32_t nInBufferSize, uint8_t** ppOutBuffer, uint32_t* pOutBufferSize)
+ uint8_t* inBuffer, uint32_t inBufferSize, uint8_t** outBuffer, uint32_t* outBufferSize)
{
- bool bAUDUnit = false;
- *ppOutBuffer = pInBuffer;
- *pOutBufferSize = nInBufferSize;
+ bool IsAudUnit = false;
+ *outBuffer = inBuffer;
+ *outBufferSize = inBufferSize;
- if (nInBufferSize <= 4)
+ if (inBufferSize <= 4)
{
return false;
}
@@ -777,29 +621,29 @@ bool IVideoRendererNode::RemoveAUDNalUnit(
{
case kVideoCodecAvc:
{
- uint32_t nCurrSize = nInBufferSize;
- uint8_t* nCurrBuff = pInBuffer;
- uint32_t nCnt = 0;
+ uint32_t currSize = inBufferSize;
+ uint8_t* currBuffer = inBuffer;
+ uint32_t count = 0;
- while (nCurrSize >= 5 && nCnt <= 12)
+ while (currSize >= 5 && count <= 12)
{
- if (bAUDUnit == true &&
- (nCurrBuff[0] == 0x00 && nCurrBuff[1] == 0x00 && nCurrBuff[2] == 0x00 &&
- nCurrBuff[3] == 0x01))
+ if (IsAudUnit &&
+ (currBuffer[0] == 0x00 && currBuffer[1] == 0x00 && currBuffer[2] == 0x00 &&
+ currBuffer[3] == 0x01))
{
- *ppOutBuffer = nCurrBuff;
- *pOutBufferSize = nCurrSize;
+ *outBuffer = currBuffer;
+ *outBufferSize = currSize;
break;
}
- if (nCurrBuff[0] == 0x00 && nCurrBuff[1] == 0x00 && nCurrBuff[2] == 0x00 &&
- nCurrBuff[3] == 0x01 && nCurrBuff[4] == 0x09)
+ if (currBuffer[0] == 0x00 && currBuffer[1] == 0x00 && currBuffer[2] == 0x00 &&
+ currBuffer[3] == 0x01 && currBuffer[4] == 0x09)
{
- bAUDUnit = true;
+ IsAudUnit = true;
}
- nCurrBuff++;
- nCurrSize--;
- nCnt++;
+ currBuffer++;
+ currSize--;
+ count++;
}
}
break;
@@ -808,7 +652,7 @@ bool IVideoRendererNode::RemoveAUDNalUnit(
return false;
}
- return bAUDUnit;
+ return IsAudUnit;
}
void IVideoRendererNode::CheckResolution(uint32_t nWidth, uint32_t nHeight)
@@ -838,16 +682,16 @@ void IVideoRendererNode::QueueConfigFrame(uint32_t timestamp)
for (int32_t i = 0; i < nNumOfConfigString; i++)
{
- uint8_t* pConfigData = nullptr;
- uint32_t nConfigLen = mConfigLen[i];
- pConfigData = mConfigBuffer[i];
+ uint8_t* configFrame = nullptr;
+ uint32_t configLen = mConfigLen[i];
+ configFrame = mConfigBuffer[i];
- if (nConfigLen == 0 || mVideoRenderer == nullptr)
+ if (configLen == 0 || mVideoRenderer == nullptr)
{
continue;
}
- mVideoRenderer->OnDataFrame(pConfigData, nConfigLen, timestamp, true);
+ mVideoRenderer->OnDataFrame(configFrame, configLen, timestamp, true);
}
}
@@ -858,6 +702,8 @@ void IVideoRendererNode::NotifyPeerDimensionChanged()
return;
}
+ IMLOGD1("[NotifyPeerDimensionChanged] subtype[%d]", mSubtype);
+
// assume the device is portrait
if (mWidth > mHeight) // landscape
{
@@ -869,7 +715,7 @@ void IVideoRendererNode::NotifyPeerDimensionChanged()
{
mCallback->SendEvent(kImsMediaEventResolutionChanged, mWidth, mHeight);
}
- else
+ else if (mSubtype == MEDIASUBTYPE_ROT90 || mSubtype == MEDIASUBTYPE_ROT270)
{
mCallback->SendEvent(kImsMediaEventResolutionChanged, mHeight, mWidth);
}
@@ -881,7 +727,7 @@ void IVideoRendererNode::NotifyPeerDimensionChanged()
{
mCallback->SendEvent(kImsMediaEventResolutionChanged, mHeight, mWidth);
}
- else
+ else if (mSubtype == MEDIASUBTYPE_ROT90 || mSubtype == MEDIASUBTYPE_ROT270)
{
mCallback->SendEvent(kImsMediaEventResolutionChanged, mWidth, mHeight);
}
@@ -894,7 +740,7 @@ void IVideoRendererNode::NotifyPeerDimensionChanged()
{
mCallback->SendEvent(kImsMediaEventResolutionChanged, mWidth, mHeight);
}
- else
+ else if (mSubtype == MEDIASUBTYPE_ROT90 || mSubtype == MEDIASUBTYPE_ROT270)
{
mCallback->SendEvent(kImsMediaEventResolutionChanged, mHeight, mWidth);
}
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/nodes/IVideoSourceNode.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/nodes/IVideoSourceNode.cpp
index 65b429e2..c95f6240 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/nodes/IVideoSourceNode.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/nodes/IVideoSourceNode.cpp
@@ -45,6 +45,8 @@ IVideoSourceNode::IVideoSourceNode(BaseSessionCallback* callback) :
mImagePath = "";
mDeviceOrientation = 0;
mWindow = nullptr;
+ mMinBitrateThreshold = 0;
+ mBitrateNotified = false;
}
IVideoSourceNode::~IVideoSourceNode() {}
@@ -57,7 +59,6 @@ kBaseNodeId IVideoSourceNode::GetNodeId()
ImsMediaResult IVideoSourceNode::Start()
{
IMLOGD3("[Start] codec[%d], mode[%d], cameraId[%d]", mCodecType, mVideoMode, mCameraId);
- std::lock_guard<std::mutex> guard(mMutex);
if (mVideoSource)
{
@@ -84,12 +85,13 @@ ImsMediaResult IVideoSourceNode::Start()
mVideoSource->SetSurface(mWindow);
- if (mVideoSource->Start() == false)
+ if (!mVideoSource->Start())
{
return RESULT_NOT_READY;
}
mVideoSource->SetDeviceOrientation(mDeviceOrientation);
+ mBitrateNotified = false;
}
mNodeState = kNodeStateRunning;
@@ -99,7 +101,6 @@ ImsMediaResult IVideoSourceNode::Start()
void IVideoSourceNode::Stop()
{
IMLOGD0("[Stop]");
- std::lock_guard<std::mutex> guard(mMutex);
if (mVideoSource)
{
@@ -263,9 +264,9 @@ void IVideoSourceNode::UpdateSurface(ANativeWindow* window)
mWindow = window;
}
-void IVideoSourceNode::OnUplinkEvent(uint8_t* data, uint32_t size, int64_t timestamp, uint32_t flag)
+void IVideoSourceNode::OnUplinkEvent(
+ uint8_t* data, uint32_t size, int64_t timestamp, uint32_t /*flag*/)
{
- (void)flag;
IMLOGD_PACKET2(
IM_PACKET_LOG_VIDEO, "[OnUplinkEvent] size[%zu], timestamp[%ld]", size, timestamp);
std::lock_guard<std::mutex> guard(mMutex);
@@ -277,6 +278,12 @@ void IVideoSourceNode::OnUplinkEvent(uint8_t* data, uint32_t size, int64_t times
}
}
+void IVideoSourceNode::SetBitrateThreshold(int32_t bitrate)
+{
+ IMLOGD1("[SetBitrateThreshold] bitrate[%d]", bitrate);
+ mMinBitrateThreshold = bitrate;
+}
+
void IVideoSourceNode::OnEvent(int32_t type, int32_t param1, int32_t param2)
{
IMLOGD3("[OnEvent] type[%d], param1[%d], param2[%d]", type, param1, param2);
@@ -298,7 +305,15 @@ void IVideoSourceNode::OnEvent(int32_t type, int32_t param1, int32_t param2)
case kRequestVideoBitrateChange:
if (mVideoSource != nullptr)
{
- mVideoSource->changeBitrate(param1);
+ if (mVideoSource->changeBitrate(param1))
+ {
+ if (mMinBitrateThreshold != 0 && param1 <= mMinBitrateThreshold &&
+ mCallback != nullptr && !mBitrateNotified)
+ {
+ mCallback->SendEvent(kImsMediaEventNotifyVideoLowestBitrate, param1);
+ mBitrateNotified = true;
+ }
+ }
}
break;
case kRequestVideoIdrFrame:
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/nodes/VideoRtpPayloadEncoderNode.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/nodes/VideoRtpPayloadEncoderNode.cpp
index 6ec6a3cd..e601c16c 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/nodes/VideoRtpPayloadEncoderNode.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/nodes/VideoRtpPayloadEncoderNode.cpp
@@ -502,7 +502,7 @@ void VideoRtpPayloadEncoderNode::EncodeHevc(
memset(mPPS, 0, MAX_CONFIG_LEN);
memcpy(mPPS, pCurDataPos, nCurDataSize);
mPpsSize = nCurDataSize;
- IMLOGD1("[EncodeHevc] PPS Size [%d]", mSpsSize);
+ IMLOGD1("[EncodeHevc] PPS Size [%d]", mPpsSize);
}
if (nDataSize < nCurDataSize + 4)
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/protocol/rtp/core/RtcpPacket.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/protocol/rtp/core/RtcpPacket.cpp
index b67fde10..2f11d8f1 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/protocol/rtp/core/RtcpPacket.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/protocol/rtp/core/RtcpPacket.cpp
@@ -213,8 +213,8 @@ eRTP_STATUS_CODE RtcpPacket::decodeRtcpPacket(IN RtpBuffer* pobjRtcpPktBuf,
usPktLen -= RTP_WORD_SIZE;
if (usPktLen > iTrackCompLen)
{
- RTP_TRACE_ERROR(
- "[DecodeRtcpPacket] RTCP packet length is Invalid.", usPktLen, iTrackCompLen);
+ RTP_TRACE_ERROR("[DecodeRtcpPacket] Report length is Invalid. ReportLen:%d, RtcpLen:%d",
+ usPktLen, iTrackCompLen);
return RTP_INVALID_MSG;
}
@@ -265,6 +265,9 @@ eRTP_STATUS_CODE RtcpPacket::decodeRtcpPacket(IN RtpBuffer* pobjRtcpPktBuf,
case RTCP_SDES:
{
RTP_TRACE_MESSAGE("[DecodeRtcpPacket] Decoding RTCP_SDES", 0, 0);
+ if (m_pobjSdesPkt != nullptr)
+ delete m_pobjSdesPkt;
+
m_pobjSdesPkt = new RtcpSdesPacket();
if (m_pobjSdesPkt == nullptr)
{
@@ -279,6 +282,9 @@ eRTP_STATUS_CODE RtcpPacket::decodeRtcpPacket(IN RtpBuffer* pobjRtcpPktBuf,
case RTCP_BYE:
{
RTP_TRACE_MESSAGE("[DecodeRtcpPacket] Decoding RTCP_BYE", 0, 0);
+ if (m_pobjByePkt != nullptr)
+ delete m_pobjByePkt;
+
m_pobjByePkt = new RtcpByePacket();
if (m_pobjByePkt == nullptr)
{
@@ -293,6 +299,9 @@ eRTP_STATUS_CODE RtcpPacket::decodeRtcpPacket(IN RtpBuffer* pobjRtcpPktBuf,
case RTCP_APP:
{
RTP_TRACE_MESSAGE("[DecodeRtcpPacket] Decoding RTCP_APP", 0, 0);
+ if (m_pobjAppPkt != nullptr)
+ delete m_pobjAppPkt;
+
m_pobjAppPkt = new RtcpAppPacket();
if (m_pobjAppPkt == nullptr)
{
@@ -321,11 +330,30 @@ eRTP_STATUS_CODE RtcpPacket::decodeRtcpPacket(IN RtpBuffer* pobjRtcpPktBuf,
bFbPkt = eRTP_TRUE;
break;
} // RTCP_RTPFB || RTCP_PSFB
+ case RTCP_XR:
+ {
+ RTP_TRACE_MESSAGE("[DecodeRtcpPacket] Decoding RTCP_XR", 0, 0);
+ if (m_pobjRtcpXrPkt != nullptr)
+ delete m_pobjRtcpXrPkt;
+
+ m_pobjRtcpXrPkt = new RtcpXrPacket();
+ if (m_pobjRtcpXrPkt == nullptr)
+ {
+ RTP_TRACE_ERROR("[Memory Error] new returned NULL.", RTP_ZERO, RTP_ZERO);
+ return RTP_MEMORY_FAIL;
+ }
+ m_pobjRtcpXrPkt->setRtcpHdrInfo(m_objHeader);
+ eDecodeRes = m_pobjRtcpXrPkt->decodeRtcpXrPacket(pucBuffer, usPktLen, uiPktType);
+ bOtherPkt = eRTP_TRUE;
+ break;
+ } // RTCP_XR
default:
{
- RTP_TRACE_WARNING(
- "[DecodeRtcpPacket], Invalid RTCP MSG type received", RTP_ZERO, RTP_ZERO);
- return RTP_INVALID_MSG;
+ RTP_TRACE_WARNING("[DecodeRtcpPacket], Invalid RTCP MSG type[%d] received",
+ uiPktType, RTP_ZERO);
+ // Instead of returning failure, ignore unknown report block and continue to decode
+ // next report block.
+ eDecodeRes = RTP_SUCCESS;
} // default
}; // switch
diff --git a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/protocol/rtp/core/RtcpXrPacket.cpp b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/protocol/rtp/core/RtcpXrPacket.cpp
index 819f13b6..406f04f0 100644
--- a/service/src/com/android/telephony/imsmedia/lib/libimsmedia/protocol/rtp/core/RtcpXrPacket.cpp
+++ b/service/src/com/android/telephony/imsmedia/lib/libimsmedia/protocol/rtp/core/RtcpXrPacket.cpp
@@ -58,9 +58,11 @@ eRTP_STATUS_CODE RtcpXrPacket::decodeRtcpXrPacket(
(RtpDt_Void) pucRtcpXrBuf;
(RtpDt_Void) usRtcpXrLen;
(RtpDt_Void) ucPktType;
- RTP_TRACE_ERROR("decodeRtcpXrPacket not implemented.", RTP_ZERO, RTP_ZERO);
+ RTP_TRACE_WARNING("decodeRtcpXrPacket not implemented.", RTP_ZERO, RTP_ZERO);
- return RTP_FAILURE;
+ /* TODO: Currently, there is no requirement to handle XR packets. Returning success to avoid
+ RTCP decoding issues. */
+ return RTP_SUCCESS;
}
eRTP_STATUS_CODE RtcpXrPacket::formRtcpXrPacket(OUT RtpBuffer* pobjRtcpPktBuf)
diff --git a/test/app/ImsMediaTestingApp/app/src/main/java/com/example/imsmediatestingapp/MainActivity.java b/test/app/ImsMediaTestingApp/app/src/main/java/com/example/imsmediatestingapp/MainActivity.java
index f68076d5..f31d68b3 100644
--- a/test/app/ImsMediaTestingApp/app/src/main/java/com/example/imsmediatestingapp/MainActivity.java
+++ b/test/app/ImsMediaTestingApp/app/src/main/java/com/example/imsmediatestingapp/MainActivity.java
@@ -102,8 +102,8 @@ public class MainActivity extends AppCompatActivity {
private static final int DTMF_SAMPLING_RATE_KHZ = 16;
private static final int DTMF_DURATION = 140;
private static final int IDR_INTERVAL = 1;
- private static final int RESOLUTION_WIDTH = 640;
- private static final int RESOLUTION_HEIGHT = 480;
+ private static final int RESOLUTION_WIDTH = 480;
+ private static final int RESOLUTION_HEIGHT = 640;
private static final String IMAGE = "data/user_de/0/com.android.telephony.imsmedia/test.jpg";
private static final float DISABLED_ALPHA = 0.3f;
private static final float ENABLED_ALPHA = 1.0f;
@@ -119,6 +119,7 @@ public class MainActivity extends AppCompatActivity {
private static final int[] PACKET_LOSS_RATE = { 1, 3 };
private static final int[] JITTER_THRESHOLD = { 100, 200 };
private static final boolean NOTIFY_STATUS = false;
+ private static final int VIDEO_BITRATE_THRESHOLD_BPS = 100000;
private Set<Integer> mSelectedCodecTypes = new HashSet<>();
private Set<Integer> mSelectedAmrModes = new HashSet<>();
@@ -134,6 +135,7 @@ public class MainActivity extends AppCompatActivity {
private int mSelectedCameraZoom = CAMERA_ZOOM;
private int mSelectedDeviceOrientationDegree = 0;
private int mSelectedCvoValue = -1;
+ private String mSelectedVideoResolution = "VGA_PR";
private Set<Integer> mSelectedRtcpFbTypes = new HashSet<>();
// The order of these values determines the priority in which they would be
@@ -569,6 +571,34 @@ public class MainActivity extends AppCompatActivity {
}
}
+ public String[] mVideoResolutionStrings = new String[] {
+ "HD_PR", "HD_LS", "VGA_PR", "VGA_LS", "QVGA_PR", "QVGA_LS", "SIF_PR", "SIF_LS", "CIF_PR",
+ "CIF_LS", "QCIF_PR", "QCIF_LS",
+ };
+
+ public int[][] mVideoResolution = {
+ {720, 1280}, {1280, 720}, {480, 640}, {640, 480}, {240, 320}, {320, 240}, {240, 352},
+ {352, 240}, {288, 352}, {352, 288}, {176, 144}, {144, 176},
+ };
+
+ public int getResolutionWidth(String resolution) {
+ for (int i = 0; i < mVideoResolutionStrings.length; i++) {
+ if (mVideoResolutionStrings[i].equals(resolution)) {
+ return mVideoResolution[i][0];
+ }
+ }
+ return RESOLUTION_WIDTH;
+ }
+
+ public int getResolutionHeight(String resolution) {
+ for (int i = 0; i < mVideoResolutionStrings.length; i++) {
+ if (mVideoResolutionStrings[i].equals(resolution)) {
+ return mVideoResolution[i][1];
+ }
+ }
+ return RESOLUTION_HEIGHT;
+ }
+
/**
* Enum of the different states the application can be in. Mainly used to decide
* how
@@ -790,6 +820,28 @@ public class MainActivity extends AppCompatActivity {
mVideoSession = (ImsVideoSession) session;
Log.d(TAG, "onOpenSessionSuccess: id=" + mVideoSession.getSessionId());
mIsVideoSessionOpened = true;
+
+ MediaQualityThreshold threshold = createMediaQualityThreshold(RTP_TIMEOUT,
+ RTCP_TIMEOUT, RTP_HYSTERESIS_TIME, RTP_PACKET_LOSS_DURATION, PACKET_LOSS_RATE,
+ JITTER_THRESHOLD, NOTIFY_STATUS);
+ mVideoSession.setMediaQualityThreshold(threshold);
+
+ int rtcpfbTypes = 0;
+ for (int types : mSelectedRtcpFbTypes) {
+ rtcpfbTypes |= types;
+ }
+
+ mVideoConfig = createVideoConfig(mSelectedVideoCodec, mSelectedVideoMode,
+ mSelectedFramerate, mSelectedBitrate, mSelectedCodecProfile,
+ mSelectedCodecLevel, mSelectedCameraId, mSelectedCameraZoom,
+ mSelectedDeviceOrientationDegree,
+ mSelectedCvoValue, rtcpfbTypes,
+ getResolutionWidth(mSelectedVideoResolution),
+ getResolutionHeight(mSelectedVideoResolution));
+
+ Log.d(TAG, "VideoConfig: " + mVideoConfig.toString());
+ mVideoSession.modifySession(mVideoConfig);
+
runOnUiThread(() -> {
if (mIsPreviewSurfaceSet) {
mVideoSession.setPreviewSurface(mPreviewSurface);
@@ -799,6 +851,22 @@ public class MainActivity extends AppCompatActivity {
}
});
}
+
+ @Override
+ public void onModifySessionResponse(VideoConfig config,
+ final @ImsMediaSession.SessionOperationResult int result) {
+ Log.d(TAG, "onModifySessionResponse");
+ }
+
+ @Override
+ public void onPeerDimensionChanged(final int width, final int height) {
+ Log.d(TAG, "onPeerDimensionChanged - width=" + width + ", height=" + height);
+ }
+
+ @Override
+ public void notifyBitrate(final int bitrate) {
+ Log.d(TAG, "notifyBitrate - bitrate=" + bitrate);
+ }
}
private class RtpTextSessionCallback extends TextSessionCallback {
@@ -1425,7 +1493,7 @@ public class MainActivity extends AppCompatActivity {
private VideoConfig createVideoConfig(InetSocketAddress remoteRtpAddress,
RtcpConfig rtcpConfig, int codecType, int videoMode, int framerate, int bitrate,
int profile, int level, int cameraId, int cameraZoom, int deviceOrientation, int cvo,
- int rtcpFbTypes) {
+ int rtcpFbTypes, int width, int height) {
VideoConfig config = new VideoConfig.Builder()
.setMediaDirection(RtpConfig.MEDIA_DIRECTION_SEND_RECEIVE)
.setAccessNetwork(AccessNetworkType.EUTRAN)
@@ -1446,8 +1514,8 @@ public class MainActivity extends AppCompatActivity {
.setPacketizationMode(VideoConfig.MODE_NON_INTERLEAVED)
.setCameraId(cameraId)
.setCameraZoom(cameraZoom)
- .setResolutionWidth(RESOLUTION_WIDTH)
- .setResolutionHeight(RESOLUTION_HEIGHT)
+ .setResolutionWidth(width)
+ .setResolutionHeight(height)
.setPauseImagePath(IMAGE)
.setDeviceOrientationDegree(deviceOrientation)
.setCvoValue(cvo)
@@ -1488,6 +1556,7 @@ public class MainActivity extends AppCompatActivity {
.setRtpPacketLossRate(rtpPacketLossRate)
.setRtpJitterMillis(rtpJitterMillis)
.setNotifyCurrentStatus(notifyCurrentStatus)
+ .setVideoBitrateBps(VIDEO_BITRATE_THRESHOLD_BPS)
.build();
}
@@ -1641,7 +1710,7 @@ public class MainActivity extends AppCompatActivity {
*/
private VideoConfig createVideoConfig(int codecType, int videoMode, int framerate, int bitrate,
int profile, int level, int cameraId, int cameraZoom, int deviceOrientation, int cvo,
- int rtcpFbTypes) {
+ int rtcpFbTypes, int width, int height) {
VideoConfig videoConfig = null;
switch (codecType) {
@@ -1649,7 +1718,8 @@ public class MainActivity extends AppCompatActivity {
case VideoConfig.VIDEO_CODEC_HEVC:
videoConfig = createVideoConfig(getRemoteVideoSocketAddress(),
getRemoteVideoRtcpConfig(), codecType, videoMode, framerate, bitrate,
- profile, level, cameraId, cameraZoom, deviceOrientation, cvo, rtcpFbTypes);
+ profile, level, cameraId, cameraZoom, deviceOrientation, cvo, rtcpFbTypes,
+ width, height);
break;
}
@@ -1765,27 +1835,37 @@ public class MainActivity extends AppCompatActivity {
PopupMenu mediaDirectionMenu = new PopupMenu(this, findViewById(R.id.mediaDirectionButton));
mediaDirectionMenu.getMenuInflater()
.inflate(R.menu.media_direction_menu, mediaDirectionMenu.getMenu());
+ int[] direction = { 0 };
mediaDirectionMenu.setOnMenuItemClickListener(item -> {
switch (item.getItemId()) {
case R.id.noFlowDirectionMenuItem:
- mAudioConfig.setMediaDirection(AudioConfig.MEDIA_DIRECTION_NO_FLOW);
+ direction[0] = RtpConfig.MEDIA_DIRECTION_NO_FLOW;
break;
case R.id.sendReceiveDirectionMenuItem:
- mAudioConfig.setMediaDirection(AudioConfig.MEDIA_DIRECTION_SEND_RECEIVE);
+ direction[0] = RtpConfig.MEDIA_DIRECTION_SEND_RECEIVE;
break;
case R.id.receiveOnlyDirectionMenuItem:
- mAudioConfig.setMediaDirection(AudioConfig.MEDIA_DIRECTION_RECEIVE_ONLY);
+ direction[0] = RtpConfig.MEDIA_DIRECTION_RECEIVE_ONLY;
break;
case R.id.sendOnlyDirectionMenuItem:
- mAudioConfig.setMediaDirection(AudioConfig.MEDIA_DIRECTION_SEND_ONLY);
+ direction[0] = RtpConfig.MEDIA_DIRECTION_SEND_ONLY;
break;
case R.id.inactiveDirectionMenuItem:
- mAudioConfig.setMediaDirection(AudioConfig.MEDIA_DIRECTION_INACTIVE);
+ direction[0] = RtpConfig.MEDIA_DIRECTION_INACTIVE;
break;
default:
return false;
}
+ mAudioConfig.setMediaDirection(direction[0]);
mAudioSession.modifySession(mAudioConfig);
+ if (mIsVideoSessionOpened) {
+ mVideoConfig.setMediaDirection(direction[0]);
+ mVideoSession.modifySession(mVideoConfig);
+ }
+ if (mIsTextSessionOpened) {
+ mTextConfig.setMediaDirection(direction[0]);
+ mTextSession.modifySession(mTextConfig);
+ }
return true;
});
mediaDirectionMenu.show();
@@ -1817,11 +1897,6 @@ public class MainActivity extends AppCompatActivity {
mAudioConfig = determineAudioConfig(mLocalDeviceInfo, mRemoteDeviceInfo);
Log.d(TAG, "AudioConfig: " + mAudioConfig.toString());
- int rtcpfbTypes = 0;
- for (int types : mSelectedRtcpFbTypes) {
- rtcpfbTypes |= types;
- }
-
RtpAudioSessionCallback sessionAudioCallback = new RtpAudioSessionCallback();
mImsMediaManager.openSession(mAudioRtp, mAudioRtcp,
ImsMediaSession.SESSION_TYPE_AUDIO,
@@ -1830,17 +1905,10 @@ public class MainActivity extends AppCompatActivity {
+ mRemoteDeviceInfo.getAudioRtpPort());
if (mVideoEnabled) {
- mVideoConfig = createVideoConfig(mSelectedVideoCodec, mSelectedVideoMode,
- mSelectedFramerate, mSelectedBitrate, mSelectedCodecProfile,
- mSelectedCodecLevel, mSelectedCameraId, mSelectedCameraZoom,
- mSelectedDeviceOrientationDegree,
- mSelectedCvoValue, rtcpfbTypes);
- Log.d(TAG, "VideoConfig: " + mVideoConfig.toString());
-
RtpVideoSessionCallback sessionVideoCallback = new RtpVideoSessionCallback();
mImsMediaManager.openSession(mVideoRtp, mVideoRtcp,
ImsMediaSession.SESSION_TYPE_VIDEO,
- mVideoConfig, mExecutor, sessionVideoCallback);
+ null, mExecutor, sessionVideoCallback);
Log.d(TAG, "openSession(): video=" + mRemoteDeviceInfo.getInetAddress() + ":"
+ mRemoteDeviceInfo.getVideoRtpPort());
}
@@ -1896,6 +1964,7 @@ public class MainActivity extends AppCompatActivity {
Spinner videoBitrateSpinner = findViewById(R.id.spinnerVideoBitrates);
Spinner videoDeviceOrientationSpinner = findViewById(R.id.spinnerVideoDeviceOrientations);
Spinner videoCvoValueSpinner = findViewById(R.id.spinnerVideoCvoValues);
+ Spinner videoResolutionSpinner = (Spinner) findViewById(R.id.spinnerVideoResolution);
mSelectedVideoCodec =
((VideoCodecEnum) videoCodecSpinner.getSelectedItem()).getValue();
@@ -1919,6 +1988,7 @@ public class MainActivity extends AppCompatActivity {
.getValue();
mSelectedCvoValue = ((VideoCvoValueEnum) videoCvoValueSpinner.getSelectedItem())
.getValue();
+ mSelectedVideoResolution = (String) videoResolutionSpinner.getSelectedItem();
Toast.makeText(getApplicationContext(), R.string.save_button_action_toast,
Toast.LENGTH_SHORT).show();
}
@@ -2074,7 +2144,7 @@ public class MainActivity extends AppCompatActivity {
setupCodecSelectionOnClickListeners();
}
- private int getSpinnerIndex(Spinner spinner, int value) {
+ private int getSpinnerIndex(Spinner spinner, Object value) {
int index = 0;
for (int i = 0; i < spinner.getCount(); i++) {
if (spinner.getItemAtPosition(i).equals(value)) {
@@ -2097,8 +2167,7 @@ public class MainActivity extends AppCompatActivity {
}
/**
- * Gets the saved user selections for the audio codec settings and updates the
- * UI's lists to
+ * Gets the saved user selections for the audio codec settings and updates the UI's lists to
* match.
*/
private void setupAudioCodecSelectionLists() {
@@ -2226,6 +2295,15 @@ public class MainActivity extends AppCompatActivity {
videoCvoValueSpinner.setAdapter(videoCvoValueAdaptor);
videoCvoValueSpinner.setSelection(getSpinnerIndex(videoCvoValueSpinner,
mSelectedCvoValue));
+
+ Spinner videoResolutionSpinner = (Spinner) findViewById(R.id.spinnerVideoResolution);
+ ArrayAdapter<String> videoResolutionAdapter = new ArrayAdapter<String>(this,
+ android.R.layout.simple_spinner_item, mVideoResolutionStrings);
+ videoResolutionAdapter.setDropDownViewResource(
+ android.R.layout.simple_spinner_dropdown_item);
+ videoResolutionSpinner.setAdapter(videoResolutionAdapter);
+ videoResolutionSpinner.setSelection(getSpinnerIndex(videoResolutionSpinner,
+ mSelectedVideoResolution));
}
/**
@@ -2621,8 +2699,8 @@ public class MainActivity extends AppCompatActivity {
.setFramerate(10)
.setIntraFrameIntervalSec(1)
.setPacketizationMode(VideoConfig.MODE_NON_INTERLEAVED)
- .setResolutionWidth(480)
- .setResolutionHeight(640)
+ .setResolutionWidth(RESOLUTION_WIDTH)
+ .setResolutionHeight(RESOLUTION_HEIGHT)
.setVideoMode(VideoConfig.VIDEO_MODE_RECORDING)
.setMaxMtuBytes(1500);
diff --git a/test/app/ImsMediaTestingApp/app/src/main/res/layout/settings_video.xml b/test/app/ImsMediaTestingApp/app/src/main/res/layout/settings_video.xml
index 89f103ae..ec502bec 100644
--- a/test/app/ImsMediaTestingApp/app/src/main/res/layout/settings_video.xml
+++ b/test/app/ImsMediaTestingApp/app/src/main/res/layout/settings_video.xml
@@ -254,6 +254,26 @@
android:layout_toEndOf="@id/videoCvoValueTitle"
android:layout_below="@id/videoPauseImagePathTitle" />
+ <TextView
+ android:id="@+id/videoResolutionTitle"
+ android:textStyle="bold"
+ android:layout_width="150dp"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="30dp"
+ android:layout_below="@id/videoCvoValueTitle"
+ android:layout_alignStart="@id/videoCodecTitle"
+ android:text="@string/video_resolution"
+ android:textAlignment="textStart" />
+
+ <Spinner
+ android:id="@+id/spinnerVideoResolution"
+ android:layout_width="200dp"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="30dp"
+ android:layout_marginStart="15dp"
+ android:layout_toEndOf="@id/videoResolutionTitle"
+ android:layout_below="@id/videoCvoValueTitle" />
+
<Button
android:id="@+id/saveVideoSettingsButton"
android:layout_width="wrap_content"
diff --git a/test/app/ImsMediaTestingApp/app/src/main/res/values/strings.xml b/test/app/ImsMediaTestingApp/app/src/main/res/values/strings.xml
index 37d6b5a7..7dd2cf86 100644
--- a/test/app/ImsMediaTestingApp/app/src/main/res/values/strings.xml
+++ b/test/app/ImsMediaTestingApp/app/src/main/res/values/strings.xml
@@ -64,6 +64,7 @@
<string name="video_device_orientation">Device Orientation</string>
<string name="video_pause_image_path">Pause Image Path</string>
<string name="video_cvo_value">CVO Value</string>
+ <string name="video_resolution">Resolution</string>
<!-- Save button text -->
<string name="save">SAVE</string>
diff --git a/tests/native/Android.bp b/tests/native/Android.bp
index 5000dee4..4171f753 100644
--- a/tests/native/Android.bp
+++ b/tests/native/Android.bp
@@ -22,6 +22,7 @@ cc_library_headers {
name: "libimsmedia_tests_headers",
export_include_dirs: [
"service/src/com/android/telephony/imsmedia/lib/libimsmedia/include",
+ "service/src/com/android/telephony/imsmedia/lib/libimsmedia/include/core/audio",
],
}
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/MediaQualityThresholdTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/MediaQualityThresholdTest.cpp
index 1ab1ff01..33494468 100644
--- a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/MediaQualityThresholdTest.cpp
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/config/MediaQualityThresholdTest.cpp
@@ -26,6 +26,7 @@ const int32_t kRtpPacketLossDurationMillis = 5000;
const std::vector<int32_t> kRtpPacketLossRate = {3, 5};
const std::vector<int32_t> kRtpJitterMillis = {100, 200};
const bool kNotifyCurrentStatus = false;
+const int32_t kVideoBitrateBps = 100000;
class MediaQualityThresholdTest : public ::testing::Test
{
@@ -42,6 +43,7 @@ protected:
threshold.setRtpPacketLossRate(kRtpPacketLossRate);
threshold.setRtpJitterMillis(kRtpJitterMillis);
threshold.setNotifyCurrentStatus(kNotifyCurrentStatus);
+ threshold.setVideoBitrateBps(kVideoBitrateBps);
}
virtual void TearDown() override {}
@@ -56,6 +58,7 @@ TEST_F(MediaQualityThresholdTest, TestGetterSetter)
EXPECT_EQ(threshold.getRtpPacketLossRate(), kRtpPacketLossRate);
EXPECT_EQ(threshold.getRtpJitterMillis(), kRtpJitterMillis);
EXPECT_EQ(threshold.getNotifyCurrentStatus(), kNotifyCurrentStatus);
+ EXPECT_EQ(threshold.getVideoBitrateBps(), kVideoBitrateBps);
}
TEST_F(MediaQualityThresholdTest, TestParcel)
@@ -85,6 +88,7 @@ TEST_F(MediaQualityThresholdTest, TestEqual)
threshold2.setRtpPacketLossRate(kRtpPacketLossRate);
threshold2.setRtpJitterMillis(kRtpJitterMillis);
threshold2.setNotifyCurrentStatus(kNotifyCurrentStatus);
+ threshold2.setVideoBitrateBps(kVideoBitrateBps);
EXPECT_EQ(threshold, threshold2);
}
@@ -98,6 +102,7 @@ TEST_F(MediaQualityThresholdTest, TestNotEqual)
threshold2.setRtpPacketLossRate(kRtpPacketLossRate);
threshold2.setRtpJitterMillis(kRtpJitterMillis);
threshold2.setNotifyCurrentStatus(kNotifyCurrentStatus);
+ threshold2.setVideoBitrateBps(kVideoBitrateBps);
MediaQualityThreshold threshold3;
threshold3.setRtpInactivityTimerMillis(kRtpInactivityTimerMillis);
@@ -107,6 +112,7 @@ TEST_F(MediaQualityThresholdTest, TestNotEqual)
threshold3.setRtpPacketLossRate(std::vector<int32_t>{5, 10});
threshold3.setRtpJitterMillis(kRtpJitterMillis);
threshold3.setNotifyCurrentStatus(kNotifyCurrentStatus);
+ threshold3.setVideoBitrateBps(kVideoBitrateBps);
EXPECT_NE(threshold, threshold2);
EXPECT_NE(threshold, threshold3);
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioManagerTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioManagerTest.cpp
new file mode 100644
index 00000000..9f8cc4c5
--- /dev/null
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/AudioManagerTest.cpp
@@ -0,0 +1,683 @@
+/**
+ * Copyright (C) 2023 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 <gtest/gtest.h>
+#include <ImsMediaNetworkUtil.h>
+#include <AudioConfig.h>
+#include <MockAudioManager.h>
+#include <ImsMediaCondition.h>
+#include <unordered_map>
+#include <algorithm>
+
+using namespace android::telephony::imsmedia;
+
+using ::testing::_;
+using ::testing::Eq;
+using ::testing::Pointee;
+using ::testing::Ref;
+using ::testing::Return;
+
+// RtpConfig
+const int32_t kMediaDirection = RtpConfig::MEDIA_DIRECTION_SEND_RECEIVE;
+const android::String8 kRemoteAddress("127.0.0.1");
+const int32_t kRemotePort = 10000;
+const int8_t kDscp = 0;
+const int8_t kRxPayload = 96;
+const int8_t kTxPayload = 96;
+const int8_t kSamplingRate = 16;
+
+// RtcpConfig
+const android::String8 kCanonicalName("name");
+const int32_t kTransmitPort = 1001;
+const int32_t kIntervalSec = 5;
+const int32_t kRtcpXrBlockTypes = RtcpConfig::FLAG_RTCPXR_STATISTICS_SUMMARY_REPORT_BLOCK |
+ RtcpConfig::FLAG_RTCPXR_VOIP_METRICS_REPORT_BLOCK;
+
+// AudioConfig
+const int8_t kPTimeMillis = 20;
+const int32_t kMaxPtimeMillis = 100;
+const bool kDtxEnabled = true;
+const int32_t kCodecType = AudioConfig::CODEC_AMR_WB;
+const int8_t kDtmfTxPayloadTypeNumber = 100;
+const int8_t kDtmfRxPayloadTypeNumber = 101;
+const int8_t kDtmfsamplingRateKHz = 16;
+
+// AmrParam
+const int32_t kAmrMode = 8;
+const bool kOctetAligned = false;
+const int32_t kMaxRedundancyMillis = 240;
+
+// EvsParam
+const int32_t kEvsBandwidth = EvsParams::EVS_BAND_NONE;
+const int32_t kEvsMode = 8;
+const int8_t kChannelAwareMode = 3;
+const bool kUseHeaderFullOnly = false;
+const int8_t kcodecModeRequest = 15;
+
+int32_t kSessionId = 0;
+
+static ImsMediaCondition gCondition;
+
+class AudioManagerCallback
+{
+public:
+ int32_t resSessionId;
+ int32_t response;
+ AudioConfig resConfig;
+ ImsMediaResult result;
+ std::list<RtpHeaderExtension> extensions;
+ MediaQualityStatus mediaQualityStatus;
+ char receivedDtmfDigit;
+ int32_t receivedDtmfDuration;
+ CallQuality callQuality;
+
+ void resetRespond()
+ {
+ resSessionId = -1;
+ response = -1;
+ result = RESULT_NOT_READY;
+ }
+
+ void onCallback(const int id, const int event, const ImsMediaResult res)
+ {
+ resSessionId = id;
+ response = event;
+ result = res;
+ }
+
+ void onCallbackConfig(
+ const int id, const int event, const ImsMediaResult res, const AudioConfig& config)
+ {
+ resSessionId = id;
+ response = event;
+ resConfig = config;
+ result = res;
+ }
+
+ void onCallbackHeaderExtension(
+ const int id, const int event, const std::list<RtpHeaderExtension>& list)
+ {
+ extensions.clear();
+ resSessionId = id;
+ response = event;
+ std::copy(list.begin(), list.end(), std::back_inserter(extensions));
+ }
+
+ void onCallbackMediaQualityStatus(
+ const int id, const int event, const MediaQualityStatus& status)
+ {
+ resSessionId = id;
+ response = event;
+ mediaQualityStatus = status;
+ }
+
+ void onCallbackDtmfReceived(const int id, const int event, char digit, int32_t duration)
+ {
+ resSessionId = id;
+ response = event;
+ receivedDtmfDigit = digit;
+ receivedDtmfDuration = duration;
+ }
+
+ void onCallbackCallQuality(const int id, const int event, const CallQuality& status)
+ {
+ resSessionId = id;
+ response = event;
+ callQuality = status;
+ }
+};
+
+static std::unordered_map<int, AudioManagerCallback*> gMapCallback;
+
+class AudioManagerTest : public ::testing::Test
+{
+public:
+ MockAudioManager manager;
+ AudioConfig config;
+ RtcpConfig rtcp;
+ AmrParams amr;
+ EvsParams evs;
+ int socketRtpFd;
+ int socketRtcpFd;
+ AudioManagerCallback callback;
+
+ AudioManagerTest()
+ {
+ socketRtpFd = -1;
+ socketRtcpFd = -1;
+ callback.resetRespond();
+ gCondition.reset();
+ }
+ ~AudioManagerTest() {}
+
+protected:
+ virtual void SetUp() override
+ {
+ rtcp.setCanonicalName(kCanonicalName);
+ rtcp.setTransmitPort(kTransmitPort);
+ rtcp.setIntervalSec(kIntervalSec);
+ rtcp.setRtcpXrBlockTypes(kRtcpXrBlockTypes);
+
+ amr.setAmrMode(kAmrMode);
+ amr.setOctetAligned(kOctetAligned);
+ amr.setMaxRedundancyMillis(kMaxRedundancyMillis);
+
+ evs.setEvsBandwidth(kEvsBandwidth);
+ evs.setEvsMode(kEvsMode);
+ evs.setChannelAwareMode(kChannelAwareMode);
+ evs.setUseHeaderFullOnly(kUseHeaderFullOnly);
+ evs.setCodecModeRequest(kcodecModeRequest);
+
+ config.setMediaDirection(kMediaDirection);
+ config.setRemoteAddress(kRemoteAddress);
+ config.setRemotePort(kRemotePort);
+ config.setRtcpConfig(rtcp);
+ config.setDscp(kDscp);
+ config.setRxPayloadTypeNumber(kRxPayload);
+ config.setTxPayloadTypeNumber(kTxPayload);
+ config.setSamplingRateKHz(kSamplingRate);
+ config.setPtimeMillis(kPTimeMillis);
+ config.setMaxPtimeMillis(kMaxPtimeMillis);
+ config.setDtxEnabled(kDtxEnabled);
+ config.setCodecType(kCodecType);
+ config.setTxDtmfPayloadTypeNumber(kDtmfTxPayloadTypeNumber);
+ config.setRxDtmfPayloadTypeNumber(kDtmfRxPayloadTypeNumber);
+ config.setDtmfsamplingRateKHz(kDtmfsamplingRateKHz);
+ config.setAmrParams(amr);
+ config.setEvsParams(evs);
+
+ manager.setCallback(&audioCallback);
+ gMapCallback.insert(std::make_pair(kSessionId, &callback));
+ const char testIp[] = "127.0.0.1";
+ unsigned int testPortRtp = 30000;
+ socketRtpFd = ImsMediaNetworkUtil::openSocket(testIp, testPortRtp, AF_INET);
+ EXPECT_NE(socketRtpFd, -1);
+ unsigned int testPortRtcp = 30001;
+ socketRtcpFd = ImsMediaNetworkUtil::openSocket(testIp, testPortRtcp, AF_INET);
+ EXPECT_NE(socketRtcpFd, -1);
+ gCondition.reset();
+ }
+
+ virtual void TearDown() override
+ {
+ if (socketRtpFd != -1)
+ {
+ ImsMediaNetworkUtil::closeSocket(socketRtpFd);
+ }
+
+ if (socketRtcpFd != -1)
+ {
+ ImsMediaNetworkUtil::closeSocket(socketRtcpFd);
+ }
+
+ gMapCallback.erase(kSessionId);
+ }
+
+ void openSession(const int32_t sessionId)
+ {
+ callback.resetRespond();
+ android::Parcel parcel;
+ parcel.writeInt32(kAudioOpenSession);
+ parcel.writeInt32(socketRtpFd);
+ parcel.writeInt32(socketRtcpFd);
+ parcel.setDataPosition(0);
+ gCondition.reset();
+ manager.sendMessage(sessionId, parcel);
+ EXPECT_TRUE(!gCondition.wait_timeout(1000));
+ EXPECT_EQ(callback.resSessionId, sessionId);
+ EXPECT_EQ(callback.response, kAudioOpenSessionSuccess);
+ }
+
+ void closeSession(const int32_t sessionId)
+ {
+ callback.resetRespond();
+ android::Parcel parcel;
+ parcel.writeInt32(kAudioCloseSession);
+ parcel.setDataPosition(0);
+ gCondition.reset();
+ manager.sendMessage(sessionId, parcel);
+ EXPECT_TRUE(!gCondition.wait_timeout(1000));
+ EXPECT_EQ(callback.resSessionId, sessionId);
+ EXPECT_EQ(callback.response, kAudioSessionClosed);
+ }
+
+ void testEventResponse(const int32_t sessionId, const int32_t event, AudioConfig* config,
+ const int32_t response, const int32_t result)
+ {
+ callback.resetRespond();
+ android::Parcel parcel;
+ parcel.writeInt32(event);
+
+ if (config != nullptr)
+ {
+ config->writeToParcel(&parcel);
+ }
+
+ parcel.setDataPosition(0);
+ gCondition.reset();
+ manager.sendMessage(sessionId, parcel);
+ EXPECT_TRUE(!gCondition.wait_timeout(1000));
+ EXPECT_EQ(callback.resSessionId, sessionId);
+ EXPECT_EQ(callback.response, response);
+
+ if (callback.response >= kAudioOpenSessionFailure &&
+ callback.response <= kAudioConfirmConfigResponse)
+ {
+ EXPECT_EQ(result, result);
+
+ if (config != nullptr && callback.response >= kAudioModifySessionResponse &&
+ callback.response <= kAudioConfirmConfigResponse)
+ {
+ EXPECT_EQ(callback.resConfig, *config);
+ }
+ }
+ }
+
+ static int32_t audioCallback(int sessionId, const android::Parcel& parcel)
+ {
+ parcel.setDataPosition(0);
+
+ int response = parcel.readInt32();
+ ImsMediaResult result = RESULT_INVALID_PARAM;
+
+ auto callback = gMapCallback.find(sessionId);
+
+ if (callback != gMapCallback.end())
+ {
+ if (response >= kAudioOpenSessionFailure && response <= kAudioConfirmConfigResponse)
+ {
+ result = static_cast<ImsMediaResult>(parcel.readInt32());
+ }
+
+ switch (response)
+ {
+ case kAudioModifySessionResponse:
+ case kAudioAddConfigResponse:
+ case kAudioConfirmConfigResponse:
+ {
+ AudioConfig resConfig;
+ resConfig.readFromParcel(&parcel);
+ (callback->second)->onCallbackConfig(sessionId, response, result, resConfig);
+ }
+ break;
+ case kAudioFirstMediaPacketInd:
+ {
+ AudioConfig resConfig;
+ resConfig.readFromParcel(&parcel);
+ (callback->second)
+ ->onCallbackConfig(sessionId, response, RESULT_SUCCESS, resConfig);
+ }
+ break;
+ case kAudioRtpHeaderExtensionInd:
+ {
+ std::list<RtpHeaderExtension> listExtension;
+ int32_t listSize = parcel.readInt32();
+
+ for (int32_t i = 0; i < listSize; i++)
+ {
+ RtpHeaderExtension extension;
+ extension.readFromParcel(&parcel);
+ listExtension.push_back(extension);
+ }
+
+ (callback->second)
+ ->onCallbackHeaderExtension(sessionId, response, listExtension);
+ }
+ break;
+ case kAudioMediaQualityStatusInd:
+ {
+ MediaQualityStatus status;
+ status.readFromParcel(&parcel);
+ (callback->second)->onCallbackMediaQualityStatus(sessionId, response, status);
+ }
+ break;
+ case kAudioDtmfReceivedInd:
+ (callback->second)
+ ->onCallbackDtmfReceived(
+ sessionId, response, parcel.readByte(), parcel.readInt32());
+ break;
+ case kAudioCallQualityChangedInd:
+ {
+ CallQuality quality;
+ quality.readFromParcel(&parcel);
+ (callback->second)->onCallbackCallQuality(sessionId, response, quality);
+ }
+ break;
+ default:
+ (callback->second)->onCallback(sessionId, response, result);
+ break;
+ }
+ }
+
+ if (response != kAudioCallQualityChangedInd)
+ {
+ gCondition.signal();
+ }
+
+ return 0;
+ }
+};
+
+TEST_F(AudioManagerTest, testOpenCloseSession)
+{
+ EXPECT_EQ(manager.getState(kSessionId), kSessionStateClosed);
+ openSession(kSessionId);
+ closeSession(kSessionId);
+}
+
+TEST_F(AudioManagerTest, testModifySession)
+{
+ testEventResponse(kSessionId, kAudioModifySession, nullptr, kAudioModifySessionResponse,
+ RESULT_INVALID_PARAM);
+
+ openSession(kSessionId);
+
+ testEventResponse(kSessionId, kAudioModifySession, nullptr, kAudioModifySessionResponse,
+ RESULT_INVALID_PARAM);
+
+ testEventResponse(
+ kSessionId, kAudioModifySession, &config, kAudioModifySessionResponse, RESULT_SUCCESS);
+
+ closeSession(kSessionId);
+}
+
+TEST_F(AudioManagerTest, testAddConfig)
+{
+ testEventResponse(
+ kSessionId, kAudioAddConfig, nullptr, kAudioAddConfigResponse, RESULT_INVALID_PARAM);
+
+ openSession(kSessionId);
+
+ testEventResponse(
+ kSessionId, kAudioAddConfig, nullptr, kAudioAddConfigResponse, RESULT_INVALID_PARAM);
+
+ testEventResponse(
+ kSessionId, kAudioAddConfig, &config, kAudioAddConfigResponse, RESULT_SUCCESS);
+
+ closeSession(kSessionId);
+}
+
+TEST_F(AudioManagerTest, testConfirmConfig)
+{
+ testEventResponse(kSessionId, kAudioConfirmConfig, nullptr, kAudioConfirmConfigResponse,
+ RESULT_INVALID_PARAM);
+
+ openSession(kSessionId);
+
+ testEventResponse(kSessionId, kAudioConfirmConfig, nullptr, kAudioConfirmConfigResponse,
+ RESULT_INVALID_PARAM);
+
+ testEventResponse(
+ kSessionId, kAudioConfirmConfig, &config, kAudioConfirmConfigResponse, RESULT_SUCCESS);
+
+ closeSession(kSessionId);
+}
+
+TEST_F(AudioManagerTest, testDeleteConfig)
+{
+ openSession(kSessionId);
+
+ android::Parcel parcel;
+ parcel.writeInt32(kAudioDeleteConfig);
+
+ if (config != nullptr)
+ {
+ config.writeToParcel(&parcel);
+ }
+
+ EXPECT_CALL(manager, deleteConfig(kSessionId, Pointee(Eq(config))))
+ .Times(1)
+ .WillOnce(Return(RESULT_INVALID_PARAM));
+
+ parcel.setDataPosition(0);
+ manager.sendMessage(kSessionId, parcel);
+
+ closeSession(kSessionId);
+}
+
+TEST_F(AudioManagerTest, testSendDtmf)
+{
+ openSession(kSessionId);
+
+ const char kDigit = '1';
+ const int32_t kDuration = 100;
+
+ android::Parcel parcel;
+ parcel.writeInt32(kAudioSendDtmf);
+ parcel.writeByte(kDigit);
+ parcel.writeInt32(kDuration);
+ parcel.setDataPosition(0);
+
+ EXPECT_CALL(manager, sendDtmf(kSessionId, kDigit, kDuration)).Times(1).WillOnce(Return());
+
+ manager.sendMessage(kSessionId, parcel);
+
+ closeSession(kSessionId);
+}
+
+TEST_F(AudioManagerTest, testSendHeaderExtension)
+{
+ openSession(kSessionId);
+
+ std::list<RtpHeaderExtension> extensions;
+ RtpHeaderExtension extension;
+ const uint8_t kExtensionData[] = {0x01, 0x02};
+ const int32_t kExtensionDataSize = 2;
+ extension.setLocalIdentifier(15);
+ extension.setExtensionData(kExtensionData, kExtensionDataSize);
+ extensions.push_back(extension);
+
+ android::Parcel parcel;
+ parcel.writeInt32(kAudioSendRtpHeaderExtension);
+ parcel.writeInt32(extensions.size());
+
+ for (auto& item : extensions)
+ {
+ item.writeToParcel(&parcel);
+ }
+
+ parcel.setDataPosition(0);
+
+ EXPECT_CALL(manager, sendRtpHeaderExtension(kSessionId, Pointee(Eq(extensions))))
+ .Times(1)
+ .WillOnce(Return());
+
+ manager.sendMessage(kSessionId, parcel);
+
+ closeSession(kSessionId);
+}
+
+TEST_F(AudioManagerTest, testSetMediaQualityThreshold)
+{
+ openSession(kSessionId);
+
+ const std::vector<int32_t> kRtpInactivityTimerMillis = {10000, 20000};
+ const int32_t kRtcpInactivityTimerMillis = 20000;
+ const int32_t kRtpHysteresisTimeInMillis = 3000;
+ const int32_t kRtpPacketLossDurationMillis = 5000;
+ const std::vector<int32_t> kRtpPacketLossRate = {3, 5};
+ const std::vector<int32_t> kRtpJitterMillis = {100, 200};
+ const bool kNotifyCurrentStatus = false;
+
+ MediaQualityThreshold threshold;
+ threshold.setRtpInactivityTimerMillis(kRtpInactivityTimerMillis);
+ threshold.setRtcpInactivityTimerMillis(kRtcpInactivityTimerMillis);
+ threshold.setRtpHysteresisTimeInMillis(kRtpHysteresisTimeInMillis);
+ threshold.setRtpPacketLossDurationMillis(kRtpPacketLossDurationMillis);
+ threshold.setRtpPacketLossRate(kRtpPacketLossRate);
+ threshold.setRtpJitterMillis(kRtpJitterMillis);
+ threshold.setNotifyCurrentStatus(kNotifyCurrentStatus);
+
+ android::Parcel parcel;
+ parcel.writeInt32(kAudioSetMediaQualityThreshold);
+ threshold.writeToParcel(&parcel);
+ parcel.setDataPosition(0);
+
+ EXPECT_CALL(manager, setMediaQualityThreshold(kSessionId, Pointee(Eq(threshold))))
+ .Times(1)
+ .WillOnce(Return());
+
+ manager.sendMessage(kSessionId, parcel);
+
+ closeSession(kSessionId);
+}
+
+TEST_F(AudioManagerTest, testSendInternalEventCmr)
+{
+ openSession(kSessionId);
+
+ const int32_t kCmrCode = 1;
+ const int32_t kCmrDefine = 7;
+
+ EXPECT_CALL(manager, SendInternalEvent(kRequestAudioCmr, kSessionId, kCmrCode, kCmrDefine))
+ .Times(1)
+ .WillOnce(Return());
+
+ ImsMediaEventHandler::SendEvent(
+ "AUDIO_REQUEST_EVENT", kRequestAudioCmr, kSessionId, kCmrCode, kCmrDefine);
+
+ closeSession(kSessionId);
+}
+
+TEST_F(AudioManagerTest, testSendInternalEventRtcpXr)
+{
+ openSession(kSessionId);
+
+ const int32_t param1 = 10;
+ const int32_t param2 = 20;
+
+ EXPECT_CALL(manager, SendInternalEvent(kRequestSendRtcpXrReport, kSessionId, param1, param2))
+ .Times(1)
+ .WillOnce(Return());
+
+ ImsMediaEventHandler::SendEvent(
+ "AUDIO_REQUEST_EVENT", kRequestSendRtcpXrReport, kSessionId, param1, param2);
+
+ closeSession(kSessionId);
+}
+
+TEST_F(AudioManagerTest, testFirstMediaPacketInd)
+{
+ AudioConfig* param = new AudioConfig(config);
+
+ ImsMediaEventHandler::SendEvent("AUDIO_RESPONSE_EVENT", kAudioFirstMediaPacketInd, kSessionId,
+ reinterpret_cast<uint64_t>(param), 0);
+
+ gCondition.wait_timeout(20);
+ EXPECT_EQ(callback.resSessionId, kSessionId);
+ EXPECT_EQ(callback.response, kAudioFirstMediaPacketInd);
+ EXPECT_EQ(callback.resConfig, config);
+}
+
+TEST_F(AudioManagerTest, testRtpHeaderExtensionInd)
+{
+ std::list<RtpHeaderExtension> extensions;
+ RtpHeaderExtension extension;
+ const uint8_t kExtensionData[] = {0x01, 0x02};
+ const int32_t kExtensionDataSize = 2;
+ extension.setLocalIdentifier(15);
+ extension.setExtensionData(kExtensionData, kExtensionDataSize);
+ extensions.push_back(extension);
+
+ std::list<RtpHeaderExtension>* param = new std::list<RtpHeaderExtension>();
+ std::copy(extensions.begin(), extensions.end(), std::back_inserter(*param));
+
+ android::Parcel parcel;
+ parcel.writeInt32(param->size());
+
+ for (auto& item : *param)
+ {
+ item.writeToParcel(&parcel);
+ }
+
+ ImsMediaEventHandler::SendEvent("AUDIO_RESPONSE_EVENT", kAudioRtpHeaderExtensionInd, kSessionId,
+ reinterpret_cast<uint64_t>(param), 0);
+
+ gCondition.wait_timeout(20);
+ EXPECT_EQ(callback.resSessionId, kSessionId);
+ EXPECT_EQ(callback.response, kAudioRtpHeaderExtensionInd);
+ EXPECT_EQ(callback.extensions, extensions);
+}
+
+TEST_F(AudioManagerTest, testMediaQualityStatusInd)
+{
+ MediaQualityStatus status;
+ status.setRtpInactivityTimeMillis(10000);
+ status.setRtcpInactivityTimeMillis(10000);
+ status.setRtpPacketLossRate(1);
+ status.setRtpJitterMillis(100);
+
+ MediaQualityStatus* param = new MediaQualityStatus(status);
+
+ ImsMediaEventHandler::SendEvent("AUDIO_RESPONSE_EVENT", kAudioMediaQualityStatusInd, kSessionId,
+ reinterpret_cast<uint64_t>(param), 0);
+
+ gCondition.wait_timeout(20);
+ EXPECT_EQ(callback.resSessionId, kSessionId);
+ EXPECT_EQ(callback.response, kAudioMediaQualityStatusInd);
+ EXPECT_EQ(callback.mediaQualityStatus, status);
+}
+
+TEST_F(AudioManagerTest, testDtmfReceivedInd)
+{
+ const char digit = 1;
+ const int32_t duration = 100;
+
+ ImsMediaEventHandler::SendEvent(
+ "AUDIO_RESPONSE_EVENT", kAudioDtmfReceivedInd, kSessionId, digit, duration);
+
+ gCondition.wait_timeout(20);
+ EXPECT_EQ(callback.resSessionId, kSessionId);
+ EXPECT_EQ(callback.response, kAudioDtmfReceivedInd);
+ EXPECT_EQ(callback.receivedDtmfDigit, digit);
+ EXPECT_EQ(callback.receivedDtmfDuration, duration);
+}
+
+TEST_F(AudioManagerTest, testCallQualityInd)
+{
+ CallQuality quality;
+ quality.setDownlinkCallQualityLevel(0);
+ quality.setUplinkCallQualityLevel(0);
+ quality.setCallDuration(30000);
+ quality.setNumRtpPacketsTransmitted(1500);
+ quality.setNumRtpPacketsReceived(1500);
+ quality.setNumRtpPacketsTransmittedLost(1);
+ quality.setNumRtpPacketsNotReceived(2);
+ quality.setAverageRelativeJitter(50);
+ quality.setMaxRelativeJitter(150);
+ quality.setAverageRoundTripTime(60);
+ quality.setCodecType(AudioConfig::CODEC_AMR_WB);
+ quality.setRtpInactivityDetected(false);
+ quality.setRxSilenceDetected(false);
+ quality.setTxSilenceDetected(false);
+ quality.setNumVoiceFrames(1400);
+ quality.setNumNoDataFrames(0);
+ quality.setNumDroppedRtpPackets(0);
+ quality.setMinPlayoutDelayMillis(100);
+ quality.setMaxPlayoutDelayMillis(180);
+ quality.setNumRtpSidPacketsReceived(100);
+ quality.setNumRtpDuplicatePackets(1);
+
+ CallQuality* param = new CallQuality(quality);
+
+ ImsMediaEventHandler::SendEvent("AUDIO_RESPONSE_EVENT", kAudioCallQualityChangedInd, kSessionId,
+ reinterpret_cast<uint64_t>(param), 0);
+
+ gCondition.wait_timeout(20);
+ EXPECT_EQ(callback.resSessionId, kSessionId);
+ EXPECT_EQ(callback.response, kAudioCallQualityChangedInd);
+ EXPECT_EQ(callback.callQuality, quality);
+} \ No newline at end of file
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/MediaQualityAnalyzerTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/MediaQualityAnalyzerTest.cpp
index a94b6654..ba468406 100644
--- a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/MediaQualityAnalyzerTest.cpp
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/MediaQualityAnalyzerTest.cpp
@@ -19,7 +19,6 @@
#include <AudioConfig.h>
#include <ImsMediaAudioUtil.h>
#include <MediaQualityAnalyzer.h>
-#include <ImsMediaCondition.h>
#include <MockBaseSessionCallback.h>
#include <ImsMediaTimer.h>
@@ -27,7 +26,7 @@ using namespace android::telephony::imsmedia;
using ::testing::_;
// RtpConfig
-const int32_t kMediaDirection = RtpConfig::MEDIA_DIRECTION_INACTIVE;
+const int32_t kMediaDirection = RtpConfig::MEDIA_DIRECTION_SEND_RECEIVE;
const android::String8 kRemoteAddress("127.0.0.1");
const int32_t kRemotePort = 10000;
const int8_t kDscp = 0;
@@ -100,13 +99,7 @@ public:
}
}
- virtual void onEvent(int32_t type, uint64_t param1, uint64_t param2)
- {
- (void)type;
- (void)param1;
- (void)param2;
- }
-
+ virtual void onEvent(int32_t /* type */, uint64_t /* param1 */, uint64_t /* param2 */) {}
CallQuality getCallQuality() { return mCallQuality; }
MediaQualityStatus getMediaQualityStatus() { return mStatus; }
@@ -115,6 +108,49 @@ private:
MediaQualityStatus mStatus;
};
+class FakeMediaQualityAnalyzer : public MediaQualityAnalyzer
+{
+public:
+ FakeMediaQualityAnalyzer() :
+ MediaQualityAnalyzer()
+ {
+ counter = 0;
+ }
+ virtual ~FakeMediaQualityAnalyzer() {}
+
+ virtual void start()
+ {
+ mCallQuality.setCodecType(convertAudioCodecType(
+ mCodecType, ImsMediaAudioUtil::FindMaxEvsBandwidthFromRange(mCodecAttribute)));
+ }
+
+ virtual void stop()
+ {
+ notifyCallQuality();
+ reset();
+ counter = 0;
+ }
+
+ void testProcessCycle(const int32_t numCycle)
+ {
+ for (int i = 0; i < numCycle; i++)
+ {
+ while (!mListevent.empty())
+ {
+ processEvent(mListevent.front(), mListParamA.front(), mListParamB.front());
+ mListevent.pop_front();
+ mListParamA.pop_front();
+ mListParamB.pop_front();
+ }
+
+ processData(++counter);
+ }
+ }
+
+private:
+ int32_t counter;
+};
+
class MediaQualityAnalyzerTest : public ::testing::Test
{
public:
@@ -122,21 +158,20 @@ public:
virtual ~MediaQualityAnalyzerTest() {}
protected:
- MediaQualityAnalyzer* mAnalyzer;
+ FakeMediaQualityAnalyzer* mAnalyzer;
AudioConfig mConfig;
RtcpConfig mRtcpConfig;
AmrParams mAmrParam;
EvsParams mEvsParam;
FakeMediaQualityCallback mFakeCallback;
MockBaseSessionCallback mCallback;
- ImsMediaCondition mCondition;
virtual void SetUp() override
{
mCallback.SetDelegate(&mFakeCallback);
mCallback.DelegateToFake();
- mAnalyzer = new MediaQualityAnalyzer();
+ mAnalyzer = new FakeMediaQualityAnalyzer();
mRtcpConfig.setCanonicalName(kCanonicalName);
mRtcpConfig.setTransmitPort(kTransmitPort);
mRtcpConfig.setIntervalSec(kIntervalSec);
@@ -172,7 +207,6 @@ protected:
mAnalyzer->setCallback(&mCallback);
mAnalyzer->setConfig(&mConfig);
- mCondition.reset();
}
virtual void TearDown() override
@@ -243,7 +277,8 @@ TEST_F(MediaQualityAnalyzerTest, TestCollectTxPackets)
mAnalyzer->SendEvent(kCollectPacketInfo, kStreamRtpTx, reinterpret_cast<uint64_t>(packet));
}
- mCondition.wait_timeout(1100); // 1.1 sec
+ mAnalyzer->testProcessCycle(1);
+
EXPECT_EQ(mAnalyzer->getTxPacketSize(), numPackets);
EXPECT_EQ(mAnalyzer->getRxPacketSize(), 0);
EXPECT_EQ(mAnalyzer->getLostPacketSize(), 0);
@@ -259,17 +294,69 @@ TEST_F(MediaQualityAnalyzerTest, TestCollectTxPackets)
TEST_F(MediaQualityAnalyzerTest, TestRtpInactivityNotRunning)
{
- EXPECT_CALL(mCallback, onEvent(kAudioCallQualityChangedInd, _, _)).Times(1);
+ EXPECT_CALL(mCallback, onEvent(kAudioCallQualityChangedInd, _, _)).Times(2);
EXPECT_CALL(mCallback, onEvent(kImsMediaEventMediaQualityStatus, _, _)).Times(0);
MediaQualityThreshold threshold;
threshold.setRtpInactivityTimerMillis(std::vector<int32_t>{0});
mAnalyzer->setMediaQualityThreshold(threshold);
mAnalyzer->start();
- mCondition.wait_timeout(2100); // 2.1 sec
+ mAnalyzer->testProcessCycle(2);
+ mAnalyzer->stop();
+
+ threshold.setRtpInactivityTimerMillis(std::vector<int32_t>{2000});
+ mConfig.setMediaDirection(RtpConfig::MEDIA_DIRECTION_INACTIVE);
+ mAnalyzer->setConfig(&mConfig);
+ mAnalyzer->setMediaQualityThreshold(threshold);
+ mAnalyzer->start();
+ mAnalyzer->testProcessCycle(2);
+ mAnalyzer->stop();
+}
+
+TEST_F(MediaQualityAnalyzerTest, TestRtpInactivityNoUpdateByDirection)
+{
+ EXPECT_CALL(mCallback, onEvent(kAudioCallQualityChangedInd, _, _)).Times(2);
+ EXPECT_CALL(mCallback, onEvent(kImsMediaEventMediaQualityStatus, _, _)).Times(1);
+ MediaQualityThreshold threshold;
+ threshold.setRtpInactivityTimerMillis(std::vector<int32_t>{4000});
+ mAnalyzer->setMediaQualityThreshold(threshold);
+ mAnalyzer->testProcessCycle(2);
+
+ mConfig.setMediaDirection(RtpConfig::MEDIA_DIRECTION_RECEIVE_ONLY);
+
+ if (!mAnalyzer->isSameConfig(&mConfig))
+ {
+ mAnalyzer->stop();
+ mAnalyzer->start();
+ }
+
+ mAnalyzer->testProcessCycle(2);
mAnalyzer->stop();
+ MediaQualityStatus quality = mFakeCallback.getMediaQualityStatus();
+ EXPECT_EQ(quality.getRtpInactivityTimeMillis(), 4000);
}
-TEST_F(MediaQualityAnalyzerTest, TestRtpInactivityRunning)
+TEST_F(MediaQualityAnalyzerTest, TestRtpInactivityUpdateByDirection)
+{
+ EXPECT_CALL(mCallback, onEvent(kAudioCallQualityChangedInd, _, _)).Times(2);
+ EXPECT_CALL(mCallback, onEvent(kImsMediaEventMediaQualityStatus, _, _)).Times(1);
+ MediaQualityThreshold threshold;
+ threshold.setRtpInactivityTimerMillis(std::vector<int32_t>{2000});
+ mAnalyzer->setMediaQualityThreshold(threshold);
+ mAnalyzer->testProcessCycle(2);
+
+ mConfig.setMediaDirection(RtpConfig::MEDIA_DIRECTION_INACTIVE);
+
+ if (!mAnalyzer->isSameConfig(&mConfig))
+ {
+ mAnalyzer->stop();
+ mAnalyzer->start();
+ }
+
+ mAnalyzer->testProcessCycle(2);
+ mAnalyzer->stop();
+}
+
+TEST_F(MediaQualityAnalyzerTest, TestRtpInactivityUpdate)
{
EXPECT_CALL(mCallback, onEvent(kAudioCallQualityChangedInd, _, _)).Times(2);
EXPECT_CALL(mCallback, onEvent(kImsMediaEventMediaQualityStatus, _, _)).Times(3);
@@ -277,13 +364,13 @@ TEST_F(MediaQualityAnalyzerTest, TestRtpInactivityRunning)
threshold.setRtpInactivityTimerMillis(kRtpInactivityTimerMillis);
mAnalyzer->setMediaQualityThreshold(threshold);
mAnalyzer->start();
- mCondition.wait_timeout(2100); // 2.1 sec
+ mAnalyzer->testProcessCycle(2);
// Check MediaQualityStatus value
MediaQualityStatus quality1 = mFakeCallback.getMediaQualityStatus();
EXPECT_EQ(quality1.getRtpInactivityTimeMillis(), 2000);
- mCondition.wait_timeout(2100); // 2.1 sec
+ mAnalyzer->testProcessCycle(2);
// Check MediaQualityStatus value
MediaQualityStatus quality2 = mFakeCallback.getMediaQualityStatus();
@@ -293,13 +380,43 @@ TEST_F(MediaQualityAnalyzerTest, TestRtpInactivityRunning)
packet->seqNum = 0;
mAnalyzer->SendEvent(kCollectPacketInfo, kStreamRtpRx, reinterpret_cast<uint64_t>(packet));
- mCondition.wait_timeout(3100); // 3.1 sec
+ mAnalyzer->testProcessCycle(3);
MediaQualityStatus quality3 = mFakeCallback.getMediaQualityStatus();
EXPECT_EQ(quality3.getRtpInactivityTimeMillis(), 2000);
mAnalyzer->stop();
}
+TEST_F(MediaQualityAnalyzerTest, TestRtcpInactivityNotRunning)
+{
+ EXPECT_CALL(mCallback, onEvent(kAudioCallQualityChangedInd, _, _)).Times(3);
+ EXPECT_CALL(mCallback, onEvent(kImsMediaEventMediaQualityStatus, _, _)).Times(0);
+ MediaQualityThreshold threshold;
+ threshold.setRtcpInactivityTimerMillis(0);
+ mAnalyzer->setMediaQualityThreshold(threshold);
+ mAnalyzer->start();
+ mAnalyzer->testProcessCycle(2);
+ mAnalyzer->stop();
+
+ threshold.setRtcpInactivityTimerMillis(2000);
+ mConfig.setMediaDirection(RtpConfig::MEDIA_DIRECTION_NO_FLOW);
+ mAnalyzer->setConfig(&mConfig);
+ mAnalyzer->setMediaQualityThreshold(threshold);
+ mAnalyzer->start();
+ mAnalyzer->testProcessCycle(2);
+ mAnalyzer->stop();
+
+ threshold.setRtcpInactivityTimerMillis(2000);
+ mRtcpConfig.setIntervalSec(0);
+ mConfig.setMediaDirection(RtpConfig::MEDIA_DIRECTION_INACTIVE);
+ mConfig.setRtcpConfig(mRtcpConfig);
+ mAnalyzer->setConfig(&mConfig);
+ mAnalyzer->setMediaQualityThreshold(threshold);
+ mAnalyzer->start();
+ mAnalyzer->testProcessCycle(2);
+ mAnalyzer->stop();
+}
+
TEST_F(MediaQualityAnalyzerTest, TestRtcpInactivity)
{
EXPECT_CALL(mCallback, onEvent(kAudioCallQualityChangedInd, _, _)).Times(2);
@@ -308,21 +425,20 @@ TEST_F(MediaQualityAnalyzerTest, TestRtcpInactivity)
threshold.setRtcpInactivityTimerMillis(kRtcpInactivityTimerMillis);
mAnalyzer->setMediaQualityThreshold(threshold);
mAnalyzer->start();
- mCondition.wait_timeout(2100); // 2.1 sec
+ mAnalyzer->testProcessCycle(2);
// Check MediaQualityStatus value
MediaQualityStatus quality1 = mFakeCallback.getMediaQualityStatus();
EXPECT_EQ(quality1.getRtcpInactivityTimeMillis(), 2000);
- mCondition.wait_timeout(2100); // 2.1 sec
+ mAnalyzer->testProcessCycle(2);
// Check MediaQualityStatus value
MediaQualityStatus quality2 = mFakeCallback.getMediaQualityStatus();
EXPECT_EQ(quality2.getRtcpInactivityTimeMillis(), 2000);
mAnalyzer->SendEvent(kCollectPacketInfo, kStreamRtcp);
-
- mCondition.wait_timeout(3100); // 3.1 sec
+ mAnalyzer->testProcessCycle(3);
MediaQualityStatus quality3 = mFakeCallback.getMediaQualityStatus();
EXPECT_EQ(quality3.getRtcpInactivityTimeMillis(), 2000);
@@ -333,7 +449,7 @@ TEST_F(MediaQualityAnalyzerTest, TestCallQualityInactivity)
{
EXPECT_CALL(mCallback, onEvent(kAudioCallQualityChangedInd, _, _)).Times(2);
mAnalyzer->start();
- mCondition.wait_timeout(4100); // 4.1 sec
+ mAnalyzer->testProcessCycle(4);
mAnalyzer->stop();
// Check CallQuality value
@@ -369,7 +485,7 @@ TEST_F(MediaQualityAnalyzerTest, TestCallQualityLevelChanged)
SessionCallbackParameter* param = new SessionCallbackParameter(kReportPacketLossGap, 5, 1);
mAnalyzer->SendEvent(kCollectOptionalInfo, reinterpret_cast<uint64_t>(param), 0);
- mCondition.wait_timeout(5100); // 5.1 sec
+ mAnalyzer->testProcessCycle(5);
EXPECT_EQ(mAnalyzer->getTxPacketSize(), 0);
EXPECT_EQ(mAnalyzer->getRxPacketSize(), numPackets - 1);
@@ -409,7 +525,7 @@ TEST_F(MediaQualityAnalyzerTest, TestJitterInd)
mAnalyzer->SendEvent(kCollectPacketInfo, kStreamRtpRx, reinterpret_cast<uint64_t>(packet));
}
- mCondition.wait_timeout(1100); // 1.1 sec
+ mAnalyzer->testProcessCycle(1);
EXPECT_EQ(mAnalyzer->getTxPacketSize(), 0);
EXPECT_EQ(mAnalyzer->getRxPacketSize(), numPackets);
@@ -452,7 +568,8 @@ TEST_F(MediaQualityAnalyzerTest, TestSsrcChange)
mAnalyzer->SendEvent(kCollectPacketInfo, kStreamRtpRx, reinterpret_cast<uint64_t>(packet));
}
- mCondition.wait_timeout(1100); // 1.1 sec
+ mAnalyzer->testProcessCycle(1);
+
EXPECT_EQ(mAnalyzer->getTxPacketSize(), 0);
EXPECT_EQ(mAnalyzer->getRxPacketSize(), numPackets);
EXPECT_EQ(mAnalyzer->getLostPacketSize(), 0);
@@ -481,7 +598,7 @@ TEST_F(MediaQualityAnalyzerTest, TestPacketLossInd)
{
RtpPacket* packet = new RtpPacket();
- if (i == 5) // make 10% loss rate
+ if (i == 5 || i == 6) // make 20% loss rate
{
continue;
}
@@ -492,14 +609,14 @@ TEST_F(MediaQualityAnalyzerTest, TestPacketLossInd)
mAnalyzer->SendEvent(kCollectPacketInfo, kStreamRtpRx, reinterpret_cast<uint64_t>(packet));
}
- SessionCallbackParameter* param = new SessionCallbackParameter(kReportPacketLossGap, 5, 1);
+ SessionCallbackParameter* param = new SessionCallbackParameter(kReportPacketLossGap, 5, 2);
mAnalyzer->SendEvent(kCollectOptionalInfo, reinterpret_cast<uint64_t>(param), 0);
- mCondition.wait_timeout(1100); // 1.1 sec
+ mAnalyzer->testProcessCycle(1);
EXPECT_EQ(mAnalyzer->getTxPacketSize(), 0);
- EXPECT_EQ(mAnalyzer->getRxPacketSize(), numPackets - 1);
- EXPECT_EQ(mAnalyzer->getLostPacketSize(), 1);
+ EXPECT_EQ(mAnalyzer->getRxPacketSize(), numPackets - 2);
+ EXPECT_EQ(mAnalyzer->getLostPacketSize(), 2);
mAnalyzer->stop();
@@ -507,10 +624,10 @@ TEST_F(MediaQualityAnalyzerTest, TestPacketLossInd)
EXPECT_EQ(mAnalyzer->getRxPacketSize(), 0);
EXPECT_EQ(mAnalyzer->getLostPacketSize(), 0);
- EXPECT_EQ(mFakeCallback.getCallQuality().getNumRtpPacketsNotReceived(), 1);
+ EXPECT_EQ(mFakeCallback.getCallQuality().getNumRtpPacketsNotReceived(), 2);
MediaQualityStatus status = mFakeCallback.getMediaQualityStatus();
- EXPECT_EQ(status.getRtpPacketLossRate(), 10);
+ EXPECT_EQ(status.getRtpPacketLossRate(), 20);
}
TEST_F(MediaQualityAnalyzerTest, TestNotifyMediaQualityStatus)
@@ -521,7 +638,6 @@ TEST_F(MediaQualityAnalyzerTest, TestNotifyMediaQualityStatus)
threshold.setNotifyCurrentStatus(true);
mAnalyzer->setMediaQualityThreshold(threshold);
mAnalyzer->start();
-
- mCondition.wait_timeout(2100); // 2.1 sec
+ mAnalyzer->testProcessCycle(2);
mAnalyzer->stop();
} \ No newline at end of file
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/node/AudioRtpPayloadNodeTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/node/AudioRtpPayloadNodeTest.cpp
new file mode 100644
index 00000000..0221f6fa
--- /dev/null
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/audio/node/AudioRtpPayloadNodeTest.cpp
@@ -0,0 +1,296 @@
+/**
+ * Copyright (C) 2023 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 <gtest/gtest.h>
+#include <AudioConfig.h>
+#include <AudioRtpPayloadEncoderNode.h>
+#include <AudioRtpPayloadDecoderNode.h>
+#include <string.h>
+
+using namespace android::telephony::imsmedia;
+using namespace android;
+
+// RtpConfig
+const int32_t kMediaDirection = RtpConfig::MEDIA_DIRECTION_SEND_RECEIVE;
+const String8 kRemoteAddress("127.0.0.1");
+const int32_t kRemotePort = 10000;
+const int8_t kDscp = 0;
+const int8_t kRxPayload = 96;
+const int8_t kTxPayload = 96;
+const int8_t kSamplingRate = 16;
+
+// RtcpConfig
+const String8 kCanonicalName("name");
+const int32_t kTransmitPort = 10001;
+const int32_t kIntervalSec = 5;
+const int32_t kRtcpXrBlockTypes = 0;
+
+// AudioConfig
+const int8_t kPTimeMillis = 20;
+const int32_t kMaxPtimeMillis = 100;
+const bool kDtxEnabled = true;
+const int8_t kDtmfPayloadTypeNumber = 103;
+const int8_t kDtmfsamplingRateKHz = 16;
+
+// AmrParam
+const int32_t kAmrMode = AmrParams::AMR_MODE_8;
+const bool kOctetAligned = false;
+const int32_t kMaxRedundancyMillis = 240;
+
+// EvsParam
+const int32_t kEvsBandwidth = EvsParams::EVS_SUPER_WIDE_BAND;
+const int32_t kEvsMode = EvsParams::EVS_MODE_13;
+const int8_t kChannelAwareMode = 2;
+
+namespace
+{
+class FakeNode : public BaseNode
+{
+public:
+ explicit FakeNode(BaseSessionCallback* callback = nullptr) :
+ BaseNode(callback)
+ {
+ frameSize = 0;
+ memset(dataFrame, 0, sizeof(dataFrame));
+ }
+ virtual ~FakeNode() {}
+ virtual ImsMediaResult Start() { return RESULT_SUCCESS; }
+ virtual void Stop() {}
+ virtual bool IsRunTime() { return true; }
+ virtual bool IsSourceNode() { return false; }
+ virtual void SetConfig(void* config) { (void)config; }
+ virtual void OnDataFromFrontNode(ImsMediaSubType /*IMS_MEDIA_AUDIO*/, uint8_t* data,
+ uint32_t size, uint32_t /*timestamp*/, bool /*mark*/, uint32_t /*seq*/,
+ ImsMediaSubType /*dataType*/, uint32_t /*arrivalTime*/)
+ {
+ if (data != nullptr && size > 0)
+ {
+ memset(dataFrame, 0, sizeof(dataFrame));
+ memcpy(dataFrame, data, size);
+ frameSize = size;
+ }
+ }
+
+ virtual kBaseNodeState GetState() { return kNodeStateRunning; }
+
+ uint32_t GetFrameSize() { return frameSize; }
+ uint8_t* GetDataFrame() { return dataFrame; }
+
+private:
+ uint32_t frameSize;
+ uint8_t dataFrame[DEFAULT_MTU];
+};
+
+class AudioRtpPayloadNodeTest : public ::testing::Test
+{
+public:
+ AudioRtpPayloadNodeTest()
+ {
+ encoder = nullptr;
+ decoder = nullptr;
+ fakeNode = nullptr;
+ }
+ virtual ~AudioRtpPayloadNodeTest() {}
+
+protected:
+ AmrParams amr;
+ EvsParams evs;
+ RtcpConfig rtcp;
+ AudioConfig audioConfig;
+ AudioRtpPayloadEncoderNode* encoder;
+ AudioRtpPayloadDecoderNode* decoder;
+ FakeNode* fakeNode;
+ std::list<BaseNode*> nodes;
+
+ virtual void SetUp() override
+ {
+ rtcp.setCanonicalName(kCanonicalName);
+ rtcp.setTransmitPort(kTransmitPort);
+ rtcp.setIntervalSec(kIntervalSec);
+ rtcp.setRtcpXrBlockTypes(kRtcpXrBlockTypes);
+
+ setupAudioConfig();
+ setupNodes(&audioConfig);
+ }
+
+ virtual void TearDown() override
+ {
+ while (nodes.size() > 0)
+ {
+ BaseNode* node = nodes.front();
+ node->Stop();
+ delete node;
+ nodes.pop_front();
+ }
+ }
+
+public:
+ void setupNodes(AudioConfig* config)
+ {
+ encoder = new AudioRtpPayloadEncoderNode();
+ encoder->SetMediaType(IMS_MEDIA_AUDIO);
+ encoder->SetConfig(config);
+ nodes.push_back(encoder);
+
+ decoder = new AudioRtpPayloadDecoderNode();
+ decoder->SetMediaType(IMS_MEDIA_AUDIO);
+ decoder->SetConfig(config);
+ nodes.push_back(decoder);
+ encoder->ConnectRearNode(decoder);
+
+ fakeNode = new FakeNode();
+ fakeNode->SetMediaType(IMS_MEDIA_AUDIO);
+ fakeNode->SetConfig(config);
+ nodes.push_back(fakeNode);
+ decoder->ConnectRearNode(fakeNode);
+ }
+
+ void setupAudioConfig()
+ {
+ amr.setAmrMode(kAmrMode);
+ amr.setOctetAligned(kOctetAligned);
+ amr.setMaxRedundancyMillis(kMaxRedundancyMillis);
+
+ audioConfig.setMediaDirection(kMediaDirection);
+ audioConfig.setRemoteAddress(kRemoteAddress);
+ audioConfig.setRemotePort(kRemotePort);
+ audioConfig.setRtcpConfig(rtcp);
+ audioConfig.setDscp(kDscp);
+ audioConfig.setRxPayloadTypeNumber(kRxPayload);
+ audioConfig.setTxPayloadTypeNumber(kTxPayload);
+ audioConfig.setSamplingRateKHz(kSamplingRate);
+ audioConfig.setPtimeMillis(kPTimeMillis);
+ audioConfig.setMaxPtimeMillis(kMaxPtimeMillis);
+ audioConfig.setDtxEnabled(kDtxEnabled);
+ audioConfig.setCodecType(AudioConfig::CODEC_AMR_WB);
+ audioConfig.setTxDtmfPayloadTypeNumber(kDtmfPayloadTypeNumber);
+ audioConfig.setRxDtmfPayloadTypeNumber(kDtmfPayloadTypeNumber);
+ audioConfig.setDtmfsamplingRateKHz(kDtmfsamplingRateKHz);
+ audioConfig.setAmrParams(amr);
+ audioConfig.setEvsParams(evs);
+ }
+};
+
+TEST_F(AudioRtpPayloadNodeTest, startFail)
+{
+ audioConfig.setPtimeMillis(0);
+ encoder->SetConfig(&audioConfig);
+ EXPECT_EQ(encoder->Start(), RESULT_INVALID_PARAM);
+}
+
+TEST_F(AudioRtpPayloadNodeTest, startAndUpdate)
+{
+ EXPECT_EQ(encoder->Start(), RESULT_SUCCESS);
+ EXPECT_EQ(decoder->Start(), RESULT_SUCCESS);
+
+ // no update
+ EXPECT_EQ(encoder->UpdateConfig(&audioConfig), RESULT_SUCCESS);
+ EXPECT_EQ(decoder->UpdateConfig(&audioConfig), RESULT_SUCCESS);
+
+ // update
+ audioConfig.setCodecType(AudioConfig::CODEC_AMR);
+ EXPECT_EQ(encoder->UpdateConfig(&audioConfig), RESULT_SUCCESS);
+ EXPECT_EQ(decoder->UpdateConfig(&audioConfig), RESULT_SUCCESS);
+}
+
+TEST_F(AudioRtpPayloadNodeTest, testAmrBandwidthEfficientDataProcess)
+{
+ EXPECT_EQ(encoder->Start(), RESULT_SUCCESS);
+ EXPECT_EQ(decoder->Start(), RESULT_SUCCESS);
+
+ // AMR-WB mode 8 audio frame with toc field
+ uint8_t testFrame[] = {0x44, 0xe6, 0x6e, 0x84, 0x8a, 0xa4, 0xda, 0xc8, 0xf2, 0x6c, 0xeb, 0x87,
+ 0xe4, 0x56, 0x0f, 0x49, 0x47, 0xfa, 0xdc, 0xa7, 0x9d, 0xbb, 0xcf, 0xda, 0xda, 0x67,
+ 0x80, 0xc2, 0x7f, 0x8d, 0x5b, 0xab, 0xd9, 0xbb, 0xd7, 0x1e, 0x60, 0x96, 0x5d, 0xdd,
+ 0x28, 0x65, 0x5f, 0x43, 0xf4, 0xb9, 0x0d, 0x7d, 0x05, 0x4e, 0x30, 0x50, 0xe1, 0x98,
+ 0x03, 0xed, 0xee, 0x8a, 0xa8, 0x34, 0x40};
+
+ encoder->OnDataFromFrontNode(MEDIASUBTYPE_UNDEFINED, testFrame, sizeof(testFrame), 0, false, 0);
+ EXPECT_EQ(fakeNode->GetFrameSize(), sizeof(testFrame));
+ EXPECT_EQ(memcmp(fakeNode->GetDataFrame(), testFrame, fakeNode->GetFrameSize()), 0);
+}
+
+TEST_F(AudioRtpPayloadNodeTest, testAmrOctetAlignedDataProcess)
+{
+ amr.setOctetAligned(true);
+ audioConfig.setAmrParams(amr);
+ encoder->SetConfig(&audioConfig);
+ decoder->SetConfig(&audioConfig);
+ EXPECT_EQ(encoder->Start(), RESULT_SUCCESS);
+ EXPECT_EQ(decoder->Start(), RESULT_SUCCESS);
+
+ // AMR-WB mode 8 audio frame with toc field
+ uint8_t testFrame[] = {0x44, 0xe6, 0x6e, 0x84, 0x8a, 0xa4, 0xda, 0xc8, 0xf2, 0x6c, 0xeb, 0x87,
+ 0xe4, 0x56, 0x0f, 0x49, 0x47, 0xfa, 0xdc, 0xa7, 0x9d, 0xbb, 0xcf, 0xda, 0xda, 0x67,
+ 0x80, 0xc2, 0x7f, 0x8d, 0x5b, 0xab, 0xd9, 0xbb, 0xd7, 0x1e, 0x60, 0x96, 0x5d, 0xdd,
+ 0x28, 0x65, 0x5f, 0x43, 0xf4, 0xb9, 0x0d, 0x7d, 0x05, 0x4e, 0x30, 0x50, 0xe1, 0x98,
+ 0x03, 0xed, 0xee, 0x8a, 0xa8, 0x34, 0x40};
+
+ encoder->OnDataFromFrontNode(MEDIASUBTYPE_UNDEFINED, testFrame, sizeof(testFrame), 0, false, 0);
+ EXPECT_EQ(fakeNode->GetFrameSize(), sizeof(testFrame));
+ EXPECT_EQ(memcmp(fakeNode->GetDataFrame(), testFrame, fakeNode->GetFrameSize()), 0);
+}
+
+TEST_F(AudioRtpPayloadNodeTest, testEvsCompactModeDataProcess)
+{
+ evs.setEvsBandwidth(kEvsBandwidth);
+ evs.setEvsMode(kEvsMode);
+ evs.setChannelAwareMode(kChannelAwareMode);
+ evs.setUseHeaderFullOnly(false);
+ evs.setCodecModeRequest(-1);
+
+ audioConfig.setEvsParams(evs);
+ audioConfig.setCodecType(AudioConfig::CODEC_EVS);
+ encoder->SetConfig(&audioConfig);
+ decoder->SetConfig(&audioConfig);
+ EXPECT_EQ(encoder->Start(), RESULT_SUCCESS);
+ EXPECT_EQ(decoder->Start(), RESULT_SUCCESS);
+
+ // EVS mode 13.2 kbps frame without toc field
+ uint8_t testFrame[] = {0xce, 0x40, 0xf2, 0xb2, 0xa4, 0xce, 0x4f, 0xd9, 0xfa, 0xe9, 0x77, 0xdc,
+ 0x9b, 0xc0, 0xa8, 0x10, 0xc8, 0xc3, 0x0f, 0xc9, 0x52, 0xc1, 0xda, 0x45, 0x7e, 0x6c,
+ 0x55, 0x47, 0xff, 0xff, 0xff, 0xff, 0xe0};
+
+ encoder->OnDataFromFrontNode(MEDIASUBTYPE_UNDEFINED, testFrame, sizeof(testFrame), 0, false, 0);
+ EXPECT_EQ(fakeNode->GetFrameSize(), sizeof(testFrame));
+ EXPECT_EQ(memcmp(fakeNode->GetDataFrame(), testFrame, fakeNode->GetFrameSize()), 0);
+}
+
+TEST_F(AudioRtpPayloadNodeTest, testEvsHeaderFullModeDataProcess)
+{
+ evs.setEvsBandwidth(kEvsBandwidth);
+ evs.setEvsMode(kEvsMode);
+ evs.setChannelAwareMode(kChannelAwareMode);
+ evs.setUseHeaderFullOnly(true);
+ evs.setCodecModeRequest(-1);
+
+ audioConfig.setEvsParams(evs);
+ audioConfig.setCodecType(AudioConfig::CODEC_EVS);
+ encoder->SetConfig(&audioConfig);
+ decoder->SetConfig(&audioConfig);
+ EXPECT_EQ(encoder->Start(), RESULT_SUCCESS);
+ EXPECT_EQ(decoder->Start(), RESULT_SUCCESS);
+
+ // EVS mode 13.2 kbps frame with toc field
+ uint8_t testFrame[] = {0x04, 0xce, 0x40, 0xf2, 0xb2, 0xa4, 0xce, 0x4f, 0xd9, 0xfa, 0xe9, 0x77,
+ 0xdc, 0x9b, 0xc0, 0xa8, 0x10, 0xc8, 0xc3, 0x0f, 0xc9, 0x52, 0xc1, 0xda, 0x45, 0x7e,
+ 0x6c, 0x55, 0x47, 0xff, 0xff, 0xff, 0xff, 0xe0};
+
+ encoder->OnDataFromFrontNode(MEDIASUBTYPE_UNDEFINED, testFrame, sizeof(testFrame), 0, false, 0);
+ EXPECT_EQ(fakeNode->GetFrameSize(), sizeof(testFrame));
+ EXPECT_EQ(memcmp(fakeNode->GetDataFrame(), testFrame, fakeNode->GetFrameSize()), 0);
+}
+} // namespace
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtcpDecoderNodeTests.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtcpDecoderNodeTests.cpp
new file mode 100644
index 00000000..05687f48
--- /dev/null
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtcpDecoderNodeTests.cpp
@@ -0,0 +1,303 @@
+/**
+ * Copyright (C) 2023 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 <gtest/gtest.h>
+#include <condition_variable>
+#include <mutex>
+#include <RtcpConfig.h>
+#include <AudioConfig.h>
+#include <VideoConfig.h>
+#include <TextConfig.h>
+#include <RtcpDecoderNode.h>
+#include <ImsMediaVideoUtil.h>
+#include <ImsMediaTrace.h>
+
+using namespace android::telephony::imsmedia;
+using namespace android;
+
+namespace
+{
+// RtpConfig
+const int32_t kMediaDirection = RtpConfig::MEDIA_DIRECTION_SEND_RECEIVE;
+const String8 kRemoteAddress("127.0.0.1");
+const int32_t kRemotePort = 10000;
+const int8_t kDscp = 0;
+const int8_t kRxPayload = 96;
+const int8_t kTxPayload = 96;
+const int8_t kSamplingRate = 16;
+
+// RtcpConfig
+const String8 kCanonicalName("name");
+const int32_t kTransmitPort = 10001;
+const int32_t RTCP_INTERVAL = 1;
+const int32_t kIntervalSec = RTCP_INTERVAL;
+int32_t kRtcpXrBlockTypes = 0;
+
+// VideoConfig
+const int32_t kVideoMode = VideoConfig::VIDEO_MODE_PREVIEW;
+const int32_t kMtu = 1500;
+const int32_t kFramerate = DEFAULT_FRAMERATE;
+const int32_t kBitrate = DEFAULT_BITRATE;
+const int32_t kCodecProfile = VideoConfig::AVC_PROFILE_BASELINE;
+const int32_t kCodecLevel = VideoConfig::AVC_LEVEL_12;
+const int32_t kIntraFrameIntervalSec = 1;
+const int32_t kPacketizationMode = VideoConfig::MODE_NON_INTERLEAVED;
+const int32_t kCameraId = 0;
+const int32_t kCameraZoom = 10;
+const int32_t kResolutionWidth = DEFAULT_RESOLUTION_WIDTH;
+const int32_t kResolutionHeight = DEFAULT_RESOLUTION_HEIGHT;
+const int32_t kDeviceOrientationDegree = 0;
+const int32_t kCvoValue = 1;
+const int32_t kRtcpFbTypes = VideoConfig::RTP_FB_NONE;
+
+static std::condition_variable cond;
+static std::mutex timerMutex;
+
+class FakeNode : public BaseNode
+{
+public:
+ bool mOnDataFromFrontNodeCalled = false;
+ virtual ~FakeNode() {}
+ void Stop() {}
+ bool IsRunTime() { return true; }
+ bool IsSourceNode() { return false; }
+ virtual kBaseNodeState GetState() { return kNodeStateRunning; }
+ void SetConfig(void* config) { (void)config; }
+ void OnDataFromFrontNode(ImsMediaSubType, uint8_t*, uint32_t, uint32_t, bool, uint32_t,
+ ImsMediaSubType, uint32_t)
+ {
+ IMLOGI0("FakeNode::OnDataFromFrontNode");
+ mOnDataFromFrontNodeCalled = true;
+ cond.notify_all();
+ }
+
+ ImsMediaResult Start() { return RESULT_SUCCESS; }
+};
+
+class SessionCallback : public BaseSessionCallback
+{
+public:
+ bool mOnEventCalled = false;
+ int32_t mType;
+ uint64_t mParam1, mParam2;
+
+ virtual ~SessionCallback() {}
+ virtual void onEvent(int32_t type, uint64_t param1, uint64_t param2)
+ {
+ IMLOGI0("SessionCallback::onEvent");
+ mOnEventCalled = true;
+ mType = type;
+ mParam1 = param1;
+ mParam2 = param2;
+ cond.notify_all();
+ }
+};
+
+class RtcpDecoderNodeEx : public RtcpDecoderNode
+{
+public:
+ bool mCallBaseClassMethod = false;
+ bool mOnRtcpIndCalled = false;
+
+ RtcpDecoderNodeEx(BaseSessionCallback* callback = nullptr) :
+ RtcpDecoderNode(callback)
+ {
+ }
+ virtual ~RtcpDecoderNodeEx() {}
+};
+
+class RtcpDecoderNodeTests : public ::testing::Test
+{
+public:
+ virtual ~RtcpDecoderNodeTests() {}
+
+protected:
+ RtcpDecoderNodeEx* pRtcpDecNode;
+ VideoConfig videoConfig;
+ FakeNode* pFakeRearNode;
+ SessionCallback* pCallback;
+
+ virtual void SetUp() override
+ {
+ pCallback = new SessionCallback();
+ pRtcpDecNode = new RtcpDecoderNodeEx(pCallback);
+ pRtcpDecNode->SetMediaType(IMS_MEDIA_VIDEO);
+ setupVideoConfig(videoConfig);
+ pRtcpDecNode->SetConfig(&videoConfig);
+ pFakeRearNode = connectNodes(pRtcpDecNode);
+ }
+
+ virtual void TearDown() override
+ {
+ delete pRtcpDecNode;
+ delete pFakeRearNode;
+ delete pCallback;
+ }
+
+ void setupRtcpConfig(RtcpConfig& rtcpConfig)
+ {
+ rtcpConfig.setCanonicalName(kCanonicalName);
+ rtcpConfig.setTransmitPort(kTransmitPort);
+ rtcpConfig.setIntervalSec(kIntervalSec);
+ rtcpConfig.setRtcpXrBlockTypes(kRtcpXrBlockTypes);
+ }
+
+ // using video codec because RTCP has feedback implementation for video media type.
+ void setupVideoConfig(VideoConfig& videoConfig)
+ {
+ videoConfig.setMediaDirection(kMediaDirection);
+ videoConfig.setRemoteAddress(kRemoteAddress);
+ videoConfig.setRemotePort(kRemotePort);
+ RtcpConfig rtcpConfig;
+ setupRtcpConfig(rtcpConfig);
+ videoConfig.setRtcpConfig(rtcpConfig);
+ videoConfig.setMaxMtuBytes(kMtu);
+ videoConfig.setDscp(kDscp);
+ videoConfig.setRxPayloadTypeNumber(kRxPayload);
+ videoConfig.setTxPayloadTypeNumber(kTxPayload);
+ videoConfig.setSamplingRateKHz(kSamplingRate);
+ videoConfig.setVideoMode(kVideoMode);
+ videoConfig.setCodecType(VideoConfig::CODEC_AVC);
+ videoConfig.setFramerate(kFramerate);
+ videoConfig.setBitrate(kBitrate);
+ videoConfig.setCodecProfile(kCodecProfile);
+ videoConfig.setCodecLevel(kCodecLevel);
+ videoConfig.setIntraFrameInterval(kIntraFrameIntervalSec);
+ videoConfig.setPacketizationMode(kPacketizationMode);
+ videoConfig.setCameraId(kCameraId);
+ videoConfig.setCameraZoom(kCameraZoom);
+ videoConfig.setResolutionWidth(kResolutionWidth);
+ videoConfig.setResolutionHeight(kResolutionHeight);
+ videoConfig.setDeviceOrientationDegree(kDeviceOrientationDegree);
+ videoConfig.setCvoValue(kCvoValue);
+ videoConfig.setRtcpFbType(kRtcpFbTypes);
+ }
+
+ FakeNode* connectNodes(RtcpDecoderNode* pRtcpDecNode)
+ {
+ FakeNode* pFakeNode = new FakeNode();
+ pRtcpDecNode->ConnectRearNode(pFakeNode);
+ return pFakeNode;
+ }
+};
+
+TEST_F(RtcpDecoderNodeTests, TestInitState)
+{
+ EXPECT_EQ(pRtcpDecNode->GetNodeId(), kNodeIdRtcpDecoder);
+ EXPECT_EQ(pRtcpDecNode->IsRunTime(), true);
+ EXPECT_EQ(pRtcpDecNode->IsSourceNode(), false);
+}
+
+TEST_F(RtcpDecoderNodeTests, TestConfigChange)
+{
+ VideoConfig videoConfig;
+ setupVideoConfig(videoConfig);
+ EXPECT_EQ(pRtcpDecNode->IsSameConfig(&videoConfig), true);
+}
+
+TEST_F(RtcpDecoderNodeTests, TestStartStopSuccess)
+{
+ EXPECT_EQ(pRtcpDecNode->Start(), RESULT_SUCCESS);
+ EXPECT_EQ(pRtcpDecNode->GetState(), kNodeStateRunning);
+
+ pRtcpDecNode->Stop();
+ EXPECT_EQ(pRtcpDecNode->GetState(), kNodeStateStopped);
+}
+
+TEST_F(RtcpDecoderNodeTests, TestOnRtcpSrInd)
+{
+ pRtcpDecNode->SetMediaType(IMS_MEDIA_AUDIO);
+ tNotifyReceiveRtcpSrInd payload;
+ memset(&payload, 0x00, sizeof(payload));
+ pRtcpDecNode->OnRtcpInd(RTPSVC_RECEIVE_RTCP_SR_IND, &payload);
+ EXPECT_EQ(pCallback->mOnEventCalled, true);
+ EXPECT_EQ(pCallback->mType, kCollectPacketInfo);
+ EXPECT_EQ(pCallback->mParam1, kStreamRtcp);
+}
+
+TEST_F(RtcpDecoderNodeTests, TestOnRtcpRrInd)
+{
+ pRtcpDecNode->SetMediaType(IMS_MEDIA_AUDIO);
+ tNotifyReceiveRtcpRrInd payload;
+ memset(&payload, 0x00, sizeof(payload));
+ pRtcpDecNode->OnRtcpInd(RTPSVC_RECEIVE_RTCP_RR_IND, &payload);
+ EXPECT_EQ(pCallback->mOnEventCalled, true);
+ EXPECT_EQ(pCallback->mType, kCollectPacketInfo);
+ EXPECT_EQ(pCallback->mParam1, kStreamRtcp);
+}
+
+TEST_F(RtcpDecoderNodeTests, TestOnRtcpFbInd)
+{
+ pRtcpDecNode->SetMediaType(IMS_MEDIA_AUDIO);
+ tRtpSvcIndSt_ReceiveRtcpFeedbackInd payload;
+ memset(&payload, 0x00, sizeof(payload));
+ payload.wFmt = kRtpFbTmmbr;
+ uint8_t fbMsgData[64];
+ payload.pMsg = fbMsgData;
+ pRtcpDecNode->OnRtcpInd(RTPSVC_RECEIVE_RTCP_FB_IND, &payload);
+ EXPECT_EQ(pCallback->mOnEventCalled, true);
+ EXPECT_EQ(pCallback->mType, kRequestVideoSendTmmbn);
+}
+
+TEST_F(RtcpDecoderNodeTests, TestOnNumReceivedPacket)
+{
+ pRtcpDecNode->SetMediaType(IMS_MEDIA_AUDIO);
+ pRtcpDecNode->SetInactivityTimerSec(1);
+ pRtcpDecNode->OnNumReceivedPacket(0, 0);
+ EXPECT_EQ(pCallback->mOnEventCalled, true);
+ EXPECT_EQ(pCallback->mType, kImsMediaEventMediaInactivity);
+ EXPECT_EQ(pCallback->mParam1, kProtocolRtcp);
+ EXPECT_EQ(pCallback->mParam2, 1);
+
+ pCallback->mOnEventCalled = false;
+ pRtcpDecNode->OnNumReceivedPacket(1, 0);
+ EXPECT_EQ(pCallback->mOnEventCalled, false);
+
+ pCallback->mOnEventCalled = false;
+ pRtcpDecNode->OnNumReceivedPacket(0, 1);
+ EXPECT_EQ(pCallback->mOnEventCalled, false);
+
+ pCallback->mOnEventCalled = false;
+ pRtcpDecNode->OnNumReceivedPacket(1, 1);
+ EXPECT_EQ(pCallback->mOnEventCalled, false);
+}
+
+TEST_F(RtcpDecoderNodeTests, TestOnEvent)
+{
+ pRtcpDecNode->OnEvent(kRequestRoundTripTimeDelayUpdate, 100);
+ EXPECT_EQ(pCallback->mOnEventCalled, true);
+ EXPECT_EQ(pCallback->mType, kRequestRoundTripTimeDelayUpdate);
+}
+
+TEST_F(RtcpDecoderNodeTests, TestReceiveTmmbr)
+{
+ pRtcpDecNode->SetMediaType(IMS_MEDIA_AUDIO);
+ tRtpSvcIndSt_ReceiveRtcpFeedbackInd payload;
+ memset(&payload, 0x00, sizeof(payload));
+ uint8_t fbMsgData[64];
+ payload.pMsg = fbMsgData;
+ pRtcpDecNode->ReceiveTmmbr(&payload);
+ EXPECT_EQ(pCallback->mOnEventCalled, true);
+ EXPECT_EQ(pCallback->mType, kRequestVideoSendTmmbn);
+}
+
+TEST_F(RtcpDecoderNodeTests, TestRequestIdrFrame)
+{
+ pRtcpDecNode->RequestIdrFrame();
+ EXPECT_EQ(pCallback->mOnEventCalled, true);
+ EXPECT_EQ(pCallback->mType, kRequestVideoIdrFrame);
+}
+} // namespace
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtcpEncoderNodeTests.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtcpEncoderNodeTests.cpp
new file mode 100644
index 00000000..94fd213d
--- /dev/null
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/nodes/RtcpEncoderNodeTests.cpp
@@ -0,0 +1,349 @@
+/**
+ * Copyright (C) 2023 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 <gtest/gtest.h>
+#include <condition_variable>
+#include <mutex>
+#include <RtcpConfig.h>
+#include <AudioConfig.h>
+#include <VideoConfig.h>
+#include <TextConfig.h>
+#include <RtcpEncoderNode.h>
+#include <android/log.h>
+
+using namespace android::telephony::imsmedia;
+using namespace android;
+
+namespace
+{
+// RtpConfig
+const int32_t kMediaDirection = RtpConfig::MEDIA_DIRECTION_SEND_RECEIVE;
+const String8 kRemoteAddress("127.0.0.1");
+const int32_t kRemotePort = 10000;
+const int8_t kDscp = 0;
+const int8_t kRxPayload = 96;
+const int8_t kTxPayload = 96;
+const int8_t kSamplingRate = 16;
+
+// RtcpConfig
+const String8 kCanonicalName("name");
+const int32_t kTransmitPort = 10001;
+const int32_t RTCP_INTERVAL = 1;
+const int32_t kIntervalSec = RTCP_INTERVAL;
+int32_t kRtcpXrBlockTypes = 0;
+
+// VideoConfig
+const int32_t kVideoMode = VideoConfig::VIDEO_MODE_PREVIEW;
+const int32_t kMtu = 1500;
+const int32_t kFramerate = DEFAULT_FRAMERATE;
+const int32_t kBitrate = DEFAULT_BITRATE;
+const int32_t kCodecProfile = VideoConfig::AVC_PROFILE_BASELINE;
+const int32_t kCodecLevel = VideoConfig::AVC_LEVEL_12;
+const int32_t kIntraFrameIntervalSec = 1;
+const int32_t kPacketizationMode = VideoConfig::MODE_NON_INTERLEAVED;
+const int32_t kCameraId = 0;
+const int32_t kCameraZoom = 10;
+const int32_t kResolutionWidth = DEFAULT_RESOLUTION_WIDTH;
+const int32_t kResolutionHeight = DEFAULT_RESOLUTION_HEIGHT;
+const android::String8 kPauseImagePath("data/user_de/0/com.android.telephony.imsmedia/test.jpg");
+const int32_t kDeviceOrientationDegree = 0;
+const int32_t kCvoValue = 1;
+const int32_t kRtcpFbTypes = VideoConfig::RTP_FB_NONE;
+
+static std::condition_variable cond;
+static std::mutex timerMutex;
+
+class FakeNode : public BaseNode
+{
+public:
+ bool mOnDataFromFrontNodeCalled = false;
+ virtual ~FakeNode() {}
+ void Stop() {}
+ bool IsRunTime() { return true; }
+ bool IsSourceNode() { return false; }
+ virtual kBaseNodeState GetState() { return kNodeStateRunning; }
+ void SetConfig(void* config) { (void)config; }
+ void OnDataFromFrontNode(ImsMediaSubType, uint8_t*, uint32_t, uint32_t, bool, uint32_t,
+ ImsMediaSubType, uint32_t)
+ {
+ mOnDataFromFrontNodeCalled = true;
+ cond.notify_all();
+ }
+
+ ImsMediaResult Start() { return RESULT_SUCCESS; }
+};
+
+class SessionCallback : public BaseSessionCallback
+{
+public:
+ bool mOnEventCalled = false;
+ virtual ~SessionCallback() {}
+ virtual void onEvent(int32_t, uint64_t, uint64_t)
+ {
+ mOnEventCalled = true;
+ cond.notify_all();
+ }
+};
+
+class RtcpEncoderNodeEx : public RtcpEncoderNode
+{
+public:
+ bool mCallBaseClassMethod = false;
+ bool mProcessTimerMethodCalled = false;
+
+ RtcpEncoderNodeEx(BaseSessionCallback* callback = nullptr) :
+ RtcpEncoderNode(callback)
+ {
+ }
+ virtual ~RtcpEncoderNodeEx() {}
+
+ void ProcessTimer()
+ {
+ mProcessTimerMethodCalled = true;
+ cond.notify_all();
+
+ if (mCallBaseClassMethod)
+ {
+ RtcpEncoderNode::ProcessTimer();
+ }
+ }
+};
+
+class RtcpEncoderNodeTests : public ::testing::Test
+{
+public:
+ virtual ~RtcpEncoderNodeTests() {}
+
+protected:
+ void setupRtcpConfig(RtcpConfig& rtcpConfig)
+ {
+ rtcpConfig.setCanonicalName(kCanonicalName);
+ rtcpConfig.setTransmitPort(kTransmitPort);
+ rtcpConfig.setIntervalSec(kIntervalSec);
+ rtcpConfig.setRtcpXrBlockTypes(kRtcpXrBlockTypes);
+ }
+
+ // using video codec because RTCP has feedback implementation for video media type.
+ void setupVideoConfig(VideoConfig& videoConfig)
+ {
+ videoConfig.setMediaDirection(kMediaDirection);
+ videoConfig.setRemoteAddress(kRemoteAddress);
+ videoConfig.setRemotePort(kRemotePort);
+ RtcpConfig rtcpConfig;
+ setupRtcpConfig(rtcpConfig);
+ videoConfig.setRtcpConfig(rtcpConfig);
+ videoConfig.setMaxMtuBytes(kMtu);
+ videoConfig.setDscp(kDscp);
+ videoConfig.setRxPayloadTypeNumber(kRxPayload);
+ videoConfig.setTxPayloadTypeNumber(kTxPayload);
+ videoConfig.setSamplingRateKHz(kSamplingRate);
+ videoConfig.setVideoMode(kVideoMode);
+ videoConfig.setCodecType(VideoConfig::CODEC_AVC);
+ videoConfig.setFramerate(kFramerate);
+ videoConfig.setBitrate(kBitrate);
+ videoConfig.setCodecProfile(kCodecProfile);
+ videoConfig.setCodecLevel(kCodecLevel);
+ videoConfig.setIntraFrameInterval(kIntraFrameIntervalSec);
+ videoConfig.setPacketizationMode(kPacketizationMode);
+ videoConfig.setCameraId(kCameraId);
+ videoConfig.setCameraZoom(kCameraZoom);
+ videoConfig.setResolutionWidth(kResolutionWidth);
+ videoConfig.setResolutionHeight(kResolutionHeight);
+ videoConfig.setPauseImagePath(kPauseImagePath);
+ videoConfig.setDeviceOrientationDegree(kDeviceOrientationDegree);
+ videoConfig.setCvoValue(kCvoValue);
+ videoConfig.setRtcpFbType(kRtcpFbTypes);
+ }
+
+ FakeNode* connectNodes(RtcpEncoderNode* pRtcpEncNode)
+ {
+ FakeNode* pFakeNode = new FakeNode();
+ pRtcpEncNode->ConnectRearNode(pFakeNode);
+ return pFakeNode;
+ }
+};
+
+TEST_F(RtcpEncoderNodeTests, TestInitState)
+{
+ RtcpEncoderNode* pRtcpEncNode = new RtcpEncoderNode();
+ EXPECT_EQ(pRtcpEncNode->GetNodeId(), kNodeIdRtcpEncoder);
+ EXPECT_EQ(pRtcpEncNode->IsRunTime(), true);
+ EXPECT_EQ(pRtcpEncNode->IsSourceNode(), true);
+ delete pRtcpEncNode;
+}
+
+TEST_F(RtcpEncoderNodeTests, TestConfigChange)
+{
+ RtcpEncoderNode* pRtcpEncNode = new RtcpEncoderNode();
+ VideoConfig videoConfig;
+ setupVideoConfig(videoConfig);
+ pRtcpEncNode->SetConfig(&videoConfig);
+ EXPECT_EQ(pRtcpEncNode->IsSameConfig(&videoConfig), true);
+ delete pRtcpEncNode;
+}
+
+TEST_F(RtcpEncoderNodeTests, TestStartStopSuccess)
+{
+ SessionCallback callback;
+ RtcpEncoderNodeEx* pRtcpEncNode = new RtcpEncoderNodeEx(&callback);
+ kRtcpXrBlockTypes = RtcpConfig::FLAG_RTCPXR_LOSS_RLE_REPORT_BLOCK;
+ VideoConfig videoConfig;
+ setupVideoConfig(videoConfig);
+ pRtcpEncNode->SetConfig(&videoConfig);
+ EXPECT_EQ(pRtcpEncNode->Start(), RESULT_SUCCESS);
+
+ bool timeout = false;
+ constexpr std::chrono::duration<int> waittime = std::chrono::seconds(RTCP_INTERVAL + 1);
+ // Wait for RTCP timer expiry to confirm start success.
+ {
+ pRtcpEncNode->mCallBaseClassMethod = true;
+ std::unique_lock<std::mutex> lock(timerMutex);
+ if (cond.wait_for(lock, waittime) == std::cv_status::timeout)
+ timeout = true;
+
+ EXPECT_EQ(timeout, false);
+ EXPECT_EQ(pRtcpEncNode->mProcessTimerMethodCalled, true);
+ }
+
+ // Check if SendEvent is called.
+ {
+ timeout = false;
+ std::unique_lock<std::mutex> lock(timerMutex);
+ if (cond.wait_for(lock, waittime) == std::cv_status::timeout)
+ timeout = true;
+
+ EXPECT_EQ(timeout, false);
+ EXPECT_EQ(callback.mOnEventCalled, true);
+ }
+
+ // Call stop and make sure RTCP timer doesn't expire.
+ pRtcpEncNode->Stop();
+ {
+ timeout = false;
+ pRtcpEncNode->mProcessTimerMethodCalled = false;
+ std::unique_lock<std::mutex> lock(timerMutex);
+ if (cond.wait_for(lock, waittime) == std::cv_status::timeout)
+ timeout = true;
+
+ EXPECT_EQ(timeout, true);
+ EXPECT_EQ(pRtcpEncNode->mProcessTimerMethodCalled, false);
+ }
+ delete pRtcpEncNode;
+}
+
+TEST_F(RtcpEncoderNodeTests, TestOnRtcpPacket)
+{
+ RtcpEncoderNode* pRtcpEncNode = new RtcpEncoderNode();
+ FakeNode* pRearNode = connectNodes(pRtcpEncNode);
+
+ unsigned char data[10];
+ pRtcpEncNode->OnRtcpPacket(data, 10);
+ EXPECT_EQ(pRearNode->mOnDataFromFrontNodeCalled, true);
+ delete pRtcpEncNode;
+ delete pRearNode;
+}
+
+TEST_F(RtcpEncoderNodeTests, TestSendNack)
+{
+ RtcpEncoderNode* pRtcpEncNode = new RtcpEncoderNode();
+ pRtcpEncNode->SetMediaType(IMS_MEDIA_VIDEO);
+
+ bool bRet = pRtcpEncNode->SendNack(nullptr);
+ EXPECT_EQ(bRet, false);
+
+ NackParams param;
+ param.PID = 0;
+ param.BLP = 0;
+ param.nSecNackCnt = 0;
+ param.bNackReport = true;
+
+ bRet = pRtcpEncNode->SendNack(&param);
+ EXPECT_EQ(bRet, false);
+
+ VideoConfig videoConfig;
+ setupVideoConfig(videoConfig);
+ videoConfig.setRtcpFbType(VideoConfig::RTP_FB_NACK);
+ pRtcpEncNode->SetConfig(&videoConfig);
+ EXPECT_EQ(pRtcpEncNode->Start(), RESULT_SUCCESS);
+ bRet = pRtcpEncNode->SendNack(&param);
+ EXPECT_EQ(bRet, true);
+ pRtcpEncNode->Stop();
+ delete pRtcpEncNode;
+}
+
+TEST_F(RtcpEncoderNodeTests, TestSendPictureLost)
+{
+ RtcpEncoderNode* pRtcpEncNode = new RtcpEncoderNode();
+ pRtcpEncNode->SetMediaType(IMS_MEDIA_VIDEO);
+ VideoConfig videoConfig;
+ setupVideoConfig(videoConfig);
+ videoConfig.setRtcpFbType(VideoConfig::PSFB_PLI);
+ pRtcpEncNode->SetConfig(&videoConfig);
+ EXPECT_EQ(pRtcpEncNode->Start(), RESULT_SUCCESS);
+
+ bool bRet = pRtcpEncNode->SendPictureLost(kPsfbPli);
+ EXPECT_EQ(bRet, true);
+
+ videoConfig.setRtcpFbType(VideoConfig::PSFB_FIR);
+ pRtcpEncNode->SetConfig(&videoConfig);
+ bRet = pRtcpEncNode->SendPictureLost(kPsfbFir);
+ EXPECT_EQ(bRet, true);
+ pRtcpEncNode->Stop();
+ delete pRtcpEncNode;
+}
+
+TEST_F(RtcpEncoderNodeTests, TestSendTmmbrn)
+{
+ RtcpEncoderNode* pRtcpEncNode = new RtcpEncoderNode();
+ pRtcpEncNode->SetMediaType(IMS_MEDIA_VIDEO);
+ VideoConfig videoConfig;
+ setupVideoConfig(videoConfig);
+ videoConfig.setRtcpFbType(VideoConfig::RTP_FB_TMMBR);
+ pRtcpEncNode->SetConfig(&videoConfig);
+ EXPECT_EQ(pRtcpEncNode->Start(), RESULT_SUCCESS);
+
+ TmmbrParams tmmbr;
+ tmmbr.ssrc = 0x1111;
+ tmmbr.exp = 0x2222;
+ tmmbr.mantissa = 0x3333;
+ tmmbr.overhead = 0x4444;
+ bool bRet = pRtcpEncNode->SendTmmbrn(kRtpFbTmmbr, &tmmbr);
+ EXPECT_EQ(bRet, true);
+
+ videoConfig.setRtcpFbType(VideoConfig::RTP_FB_TMMBR);
+ pRtcpEncNode->SetConfig(&videoConfig);
+ bRet = pRtcpEncNode->SendTmmbrn(kRtpFbTmmbr, &tmmbr);
+ EXPECT_EQ(bRet, true);
+ pRtcpEncNode->Stop();
+ delete pRtcpEncNode;
+}
+
+TEST_F(RtcpEncoderNodeTests, SendRtcpXr)
+{
+ RtcpEncoderNode* pRtcpEncNode = new RtcpEncoderNode();
+ pRtcpEncNode->SetMediaType(IMS_MEDIA_VIDEO);
+ EXPECT_EQ(pRtcpEncNode->Start(), RESULT_SUCCESS);
+
+ bool bRet = pRtcpEncNode->SendRtcpXr(nullptr, 0);
+ EXPECT_EQ(bRet, false);
+
+ uint8_t* pDummyRtcpXrPacket = new uint8_t[10];
+ bRet = pRtcpEncNode->SendRtcpXr(pDummyRtcpXrPacket, 10);
+ EXPECT_EQ(bRet, true);
+ pRtcpEncNode->Stop();
+ delete pRtcpEncNode;
+}
+} // namespace \ No newline at end of file
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextStreamGraphRtcpTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextStreamGraphRtcpTest.cpp
index 4436e429..a292a5f5 100644
--- a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextStreamGraphRtcpTest.cpp
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/TextStreamGraphRtcpTest.cpp
@@ -23,7 +23,7 @@
using namespace android::telephony::imsmedia;
// RtpConfig
-const int32_t kMediaDirection = RtpConfig::MEDIA_DIRECTION_NO_FLOW;
+const int32_t kMediaDirection = RtpConfig::MEDIA_DIRECTION_INACTIVE;
const android::String8 kRemoteAddress("127.0.0.1");
const int32_t kRemotePort = 10000;
const int8_t kDscp = 0;
@@ -130,13 +130,11 @@ TEST_F(TextStreamGraphRtcpTest, TestRtcpStreamAndUpdate)
EXPECT_EQ(graph->update(&config), RESULT_SUCCESS);
EXPECT_EQ(graph->getState(), kStreamStateRunning);
- rtcp.setIntervalSec(0);
- config.setRtcpConfig(rtcp);
+ config.setMediaDirection(RtpConfig::MEDIA_DIRECTION_NO_FLOW);
EXPECT_EQ(graph->update(&config), RESULT_SUCCESS);
EXPECT_EQ(graph->getState(), kStreamStateCreated);
- rtcp.setIntervalSec(5);
- config.setRtcpConfig(rtcp);
+ config.setMediaDirection(RtpConfig::MEDIA_DIRECTION_INACTIVE);
EXPECT_EQ(graph->update(&config), RESULT_SUCCESS);
EXPECT_EQ(graph->getState(), kStreamStateRunning);
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/nodes/TextSourceNodeTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/nodes/TextSourceNodeTest.cpp
index d4ae8902..69a17eb4 100644
--- a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/nodes/TextSourceNodeTest.cpp
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/text/nodes/TextSourceNodeTest.cpp
@@ -15,17 +15,14 @@
*/
#include <gtest/gtest.h>
-#include <gmock/gmock.h>
#include <TextConfig.h>
#include <TextSourceNode.h>
#include <ImsMediaCondition.h>
-#include <MockBaseNode.h>
+#include <string.h>
using namespace android::telephony::imsmedia;
using namespace android;
-using ::testing::Return;
-
// RtpConfig
const int32_t kMediaDirection = RtpConfig::MEDIA_DIRECTION_SEND_ONLY;
const String8 kRemoteAddress("127.0.0.1");
@@ -48,41 +45,40 @@ const int8_t kRedundantPayload = 102;
const int8_t kRedundantLevel = 3;
const bool kKeepRedundantLevel = true;
const int kTextInterval = 300;
-const char* kBom = {"\xEF\xBB\xBF\0"};
+const uint8_t kBom[] = {0xEF, 0xBB, 0xBF};
-class FakeBaseNode : public BaseNode
+class FakeTextNode : public BaseNode
{
public:
- FakeBaseNode() { mEmptyFlag = false; }
- virtual ~FakeBaseNode() {}
+ FakeTextNode()
+ {
+ mEmptyFlag = false;
+ memset(mData, 0, sizeof(mData));
+ }
+ virtual ~FakeTextNode() {}
virtual ImsMediaResult Start() { return RESULT_SUCCESS; }
virtual void Stop() {}
virtual bool IsRunTime() { return true; }
virtual bool IsSourceNode() { return false; }
virtual void SetConfig(void* config) { (void)config; }
- virtual void OnDataFromFrontNode(ImsMediaSubType subtype, uint8_t* data, uint32_t size,
- uint32_t timestamp, bool mark, uint32_t seq, ImsMediaSubType dataType,
- uint32_t arrivalTime)
+ virtual void OnDataFromFrontNode(ImsMediaSubType /*subtype*/, uint8_t* data, uint32_t size,
+ uint32_t /*timestamp*/, bool /*mark*/, uint32_t /*seq*/, ImsMediaSubType /*dataType*/,
+ uint32_t /*arrivalTime*/)
{
- (void)subtype;
- (void)timestamp;
- (void)mark;
- (void)seq;
- (void)dataType;
- (void)arrivalTime;
-
if (size != 0 && size <= MAX_RTT_LEN)
{
memset(mData, 0, sizeof(mData));
memcpy(mData, data, size);
mEmptyFlag = false;
}
- else if (size == 0 && data == nullptr)
+ else if (data == nullptr)
{
mEmptyFlag = true;
}
}
+ virtual kBaseNodeState GetState() { return kNodeStateRunning; }
+
uint8_t* getData() { return mData; }
bool getEmptyFlag() { return mEmptyFlag; }
@@ -94,7 +90,11 @@ private:
class TextSourceNodeTest : public ::testing::Test
{
public:
- TextSourceNodeTest() {}
+ TextSourceNodeTest()
+ {
+ mNode = NULL;
+ mFakeNode = NULL;
+ }
virtual ~TextSourceNodeTest() {}
protected:
@@ -102,8 +102,7 @@ protected:
RtcpConfig mRtcp;
ImsMediaCondition mCondition;
TextSourceNode* mNode;
- MockBaseNode* mMockNode;
- FakeBaseNode mFakeNode;
+ FakeTextNode* mFakeNode;
std::list<BaseNode*> mNodes;
virtual void SetUp() override
@@ -132,18 +131,12 @@ protected:
mNode->SetConfig(&mConfig);
mNodes.push_back(mNode);
- mMockNode = new MockBaseNode();
- mMockNode->SetDelegate(&mFakeNode);
- mMockNode->DelegateToFake();
-
- mMockNode->SetMediaType(IMS_MEDIA_TEXT);
- mMockNode->SetConfig(&mConfig);
- mNodes.push_back(mMockNode);
-
- mNode->ConnectRearNode(mMockNode);
-
- ON_CALL(*mMockNode, GetState()).WillByDefault(Return(kNodeStateRunning));
- ON_CALL(*mMockNode, IsRunTime()).WillByDefault(Return(true));
+ mFakeNode = new FakeTextNode();
+ mFakeNode->SetMediaType(IMS_MEDIA_TEXT);
+ mFakeNode->SetConfig(&mConfig);
+ mNodes.push_back(mFakeNode);
+ mNode->ConnectRearNode(mFakeNode);
+ mCondition.reset();
}
virtual void TearDown() override
@@ -165,26 +158,46 @@ TEST_F(TextSourceNodeTest, startFail)
EXPECT_EQ(mNode->Start(), RESULT_INVALID_PARAM);
}
+TEST_F(TextSourceNodeTest, sendRttDisableBom)
+{
+ mConfig.setKeepRedundantLevel(false);
+ mNode->SetConfig(&mConfig);
+
+ EXPECT_EQ(mNode->Start(), RESULT_SUCCESS);
+ EXPECT_FALSE(mFakeNode->getEmptyFlag());
+
+ String8 testText1 = String8("a");
+ mNode->SendRtt(&testText1);
+
+ mNode->ProcessData();
+ EXPECT_EQ(memcmp(mFakeNode->getData(), testText1.string(), testText1.length()), 0);
+
+ mCondition.wait_timeout(kTextInterval);
+ mNode->ProcessData();
+ // expect empty flag set
+ EXPECT_TRUE(mFakeNode->getEmptyFlag());
+}
+
TEST_F(TextSourceNodeTest, sendRttTestChunkSizeOne)
{
String8 testText1 = String8("a");
EXPECT_EQ(mNode->Start(), RESULT_SUCCESS);
- EXPECT_FALSE(mFakeNode.getEmptyFlag());
+ EXPECT_FALSE(mFakeNode->getEmptyFlag());
mNode->SendRtt(&testText1);
mNode->ProcessData();
// expect BOM
- EXPECT_EQ(String8((char*)mFakeNode.getData()), String8(kBom));
+ EXPECT_EQ(memcmp(mFakeNode->getData(), kBom, sizeof(kBom)), 0);
mCondition.wait_timeout(kTextInterval);
mNode->ProcessData();
- EXPECT_EQ(String8((char*)mFakeNode.getData()), testText1);
+ EXPECT_EQ(memcmp(mFakeNode->getData(), testText1.string(), testText1.length()), 0);
mCondition.wait_timeout(kTextInterval);
mNode->ProcessData();
// expect empty flag set
- EXPECT_TRUE(mFakeNode.getEmptyFlag());
+ EXPECT_TRUE(mFakeNode->getEmptyFlag());
}
TEST_F(TextSourceNodeTest, sendRttTestChunkSizeTwo)
@@ -192,21 +205,21 @@ TEST_F(TextSourceNodeTest, sendRttTestChunkSizeTwo)
String8 testText2 = String8("\xC2\xA9");
EXPECT_EQ(mNode->Start(), RESULT_SUCCESS);
- EXPECT_FALSE(mFakeNode.getEmptyFlag());
+ EXPECT_FALSE(mFakeNode->getEmptyFlag());
mNode->SendRtt(&testText2);
mNode->ProcessData();
// expect BOM
- EXPECT_EQ(String8((char*)mFakeNode.getData()), String8(kBom));
+ EXPECT_EQ(memcmp(mFakeNode->getData(), kBom, sizeof(kBom)), 0);
mCondition.wait_timeout(kTextInterval);
mNode->ProcessData();
- EXPECT_EQ(String8((char*)mFakeNode.getData()), testText2);
+ EXPECT_EQ(memcmp(mFakeNode->getData(), testText2.string(), testText2.length()), 0);
mCondition.wait_timeout(kTextInterval);
mNode->ProcessData();
// expect empty flag set
- EXPECT_TRUE(mFakeNode.getEmptyFlag());
+ EXPECT_TRUE(mFakeNode->getEmptyFlag());
}
TEST_F(TextSourceNodeTest, sendRttTestChunkSizeThree)
@@ -214,21 +227,21 @@ TEST_F(TextSourceNodeTest, sendRttTestChunkSizeThree)
String8 testText3 = String8("\xE2\x9C\x82");
EXPECT_EQ(mNode->Start(), RESULT_SUCCESS);
- EXPECT_FALSE(mFakeNode.getEmptyFlag());
+ EXPECT_FALSE(mFakeNode->getEmptyFlag());
mNode->SendRtt(&testText3);
mNode->ProcessData();
// expect BOM
- EXPECT_EQ(String8((char*)mFakeNode.getData()), String8(kBom));
+ EXPECT_EQ(memcmp(mFakeNode->getData(), kBom, sizeof(kBom)), 0);
mCondition.wait_timeout(kTextInterval);
mNode->ProcessData();
- EXPECT_EQ(String8((char*)mFakeNode.getData()), testText3);
+ EXPECT_EQ(memcmp(mFakeNode->getData(), testText3.string(), testText3.length()), 0);
mCondition.wait_timeout(kTextInterval);
mNode->ProcessData();
// expect empty flag set
- EXPECT_TRUE(mFakeNode.getEmptyFlag());
+ EXPECT_TRUE(mFakeNode->getEmptyFlag());
}
TEST_F(TextSourceNodeTest, sendRttTestChunkSizeFour)
@@ -236,21 +249,21 @@ TEST_F(TextSourceNodeTest, sendRttTestChunkSizeFour)
String8 testText4 = String8("\xF0\x9F\x9A\x80");
EXPECT_EQ(mNode->Start(), RESULT_SUCCESS);
- EXPECT_FALSE(mFakeNode.getEmptyFlag());
+ EXPECT_FALSE(mFakeNode->getEmptyFlag());
mNode->SendRtt(&testText4);
mNode->ProcessData();
// expect BOM
- EXPECT_EQ(String8((char*)mFakeNode.getData()), String8(kBom));
+ EXPECT_EQ(memcmp(mFakeNode->getData(), kBom, sizeof(kBom)), 0);
mCondition.wait_timeout(kTextInterval);
mNode->ProcessData();
- EXPECT_EQ(String8((char*)mFakeNode.getData()), testText4);
+ EXPECT_EQ(memcmp(mFakeNode->getData(), testText4.string(), testText4.length()), 0);
mCondition.wait_timeout(kTextInterval);
mNode->ProcessData();
// expect empty flag set
- EXPECT_TRUE(mFakeNode.getEmptyFlag());
+ EXPECT_TRUE(mFakeNode->getEmptyFlag());
}
TEST_F(TextSourceNodeTest, sendRttTestLongString)
@@ -267,31 +280,19 @@ TEST_F(TextSourceNodeTest, sendRttTestLongString)
testText5.append(testText4);
EXPECT_EQ(mNode->Start(), RESULT_SUCCESS);
- EXPECT_FALSE(mFakeNode.getEmptyFlag());
+ EXPECT_FALSE(mFakeNode->getEmptyFlag());
mNode->SendRtt(&testText5);
mNode->ProcessData();
// expect BOM
- EXPECT_EQ(String8((char*)mFakeNode.getData()), String8(kBom));
-
- mCondition.wait_timeout(kTextInterval);
- mNode->ProcessData();
- EXPECT_EQ(String8((char*)mFakeNode.getData()), testText1);
-
- mCondition.wait_timeout(kTextInterval);
- mNode->ProcessData();
- EXPECT_EQ(String8((char*)mFakeNode.getData()), testText2);
-
- mCondition.wait_timeout(kTextInterval);
- mNode->ProcessData();
- EXPECT_EQ(String8((char*)mFakeNode.getData()), testText3);
+ EXPECT_EQ(memcmp(mFakeNode->getData(), kBom, sizeof(kBom)), 0);
mCondition.wait_timeout(kTextInterval);
mNode->ProcessData();
- EXPECT_EQ(String8((char*)mFakeNode.getData()), testText4);
+ EXPECT_EQ(memcmp(mFakeNode->getData(), testText5.string(), testText5.length()), 0);
mCondition.wait_timeout(kTextInterval);
mNode->ProcessData();
// expect empty flag set
- EXPECT_TRUE(mFakeNode.getEmptyFlag());
+ EXPECT_TRUE(mFakeNode->getEmptyFlag());
}
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaBitReaderTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaBitReaderTest.cpp
new file mode 100644
index 00000000..da66bcf8
--- /dev/null
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaBitReaderTest.cpp
@@ -0,0 +1,75 @@
+/**
+ * Copyright (C) 2023 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 <gtest/gtest.h>
+#include <ImsMediaBitReader.h>
+#include <string.h>
+
+class ImsMediaBitReaderTest : public ::testing::Test
+{
+public:
+protected:
+ virtual void SetUp() override {}
+
+ virtual void TearDown() override {}
+};
+
+TEST_F(ImsMediaBitReaderTest, SetBufferAndReadBitTest)
+{
+ uint8_t testBuffer[] = {1, 2, 4, 8, 16, 32, 64, 128};
+
+ ImsMediaBitReader reader;
+ EXPECT_EQ(reader.Read(24), 0);
+ reader.SetBuffer(testBuffer, sizeof(testBuffer));
+ EXPECT_EQ(reader.Read(32), 0);
+
+ for (int32_t i = 0; i < sizeof(testBuffer); i++)
+ {
+ EXPECT_EQ(reader.Read(8), testBuffer[i]);
+ }
+
+ EXPECT_EQ(reader.Read(8), 0);
+}
+
+TEST_F(ImsMediaBitReaderTest, SetBufferAndReadByteTest)
+{
+ uint8_t testBuffer[] = {1, 2, 4, 8, 16, 32, 64, 128};
+
+ ImsMediaBitReader reader;
+ reader.SetBuffer(testBuffer, sizeof(testBuffer));
+
+ uint8_t dstBuffer[8] = {0};
+
+ for (int32_t i = 0; i < sizeof(testBuffer); i++)
+ {
+ reader.ReadByteBuffer(dstBuffer + i, 8);
+ }
+
+ EXPECT_EQ(memcmp(dstBuffer, testBuffer, sizeof(testBuffer)), 0);
+}
+
+TEST_F(ImsMediaBitReaderTest, SetBufferAndReadUEModeTest)
+{
+ uint8_t testBuffer[] = {0xDA}; // 11011010
+
+ ImsMediaBitReader reader;
+ reader.SetBuffer(testBuffer, sizeof(testBuffer));
+
+ EXPECT_EQ(reader.ReadByUEMode(), 0);
+ EXPECT_EQ(reader.ReadByUEMode(), 0);
+ EXPECT_EQ(reader.ReadByUEMode(), 2);
+ EXPECT_EQ(reader.ReadByUEMode(), 1);
+}
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaBitWriterTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaBitWriterTest.cpp
new file mode 100644
index 00000000..af10eaa2
--- /dev/null
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaBitWriterTest.cpp
@@ -0,0 +1,77 @@
+/**
+ * Copyright (C) 2023 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 <gtest/gtest.h>
+#include <ImsMediaBitWriter.h>
+#include <string.h>
+
+class ImsMediaBitWriterTest : public ::testing::Test
+{
+public:
+protected:
+ virtual void SetUp() override {}
+
+ virtual void TearDown() override {}
+};
+
+TEST_F(ImsMediaBitWriterTest, SetBufferAndWriteBitTest)
+{
+ uint8_t testBuffer[] = {1, 2, 4, 8, 16, 32, 64, 128};
+ uint8_t dstBuffer[8] = {0};
+
+ ImsMediaBitWriter writer;
+
+ EXPECT_EQ(writer.Write(0, 24), false);
+ writer.SetBuffer(dstBuffer, sizeof(dstBuffer));
+ EXPECT_EQ(writer.Write(0, 32), false);
+
+ for (int32_t i = 0; i < sizeof(testBuffer); i++)
+ {
+ EXPECT_EQ(writer.Write(testBuffer[i], 8), true);
+ }
+
+ EXPECT_EQ(writer.Write(0, 8), false);
+ EXPECT_EQ(memcmp(dstBuffer, testBuffer, sizeof(testBuffer)), 0);
+}
+
+TEST_F(ImsMediaBitWriterTest, SetBufferAndWriteByteTest)
+{
+ uint8_t testBuffer[] = {1, 2, 4, 8, 16, 32, 64, 128};
+ uint8_t dstBuffer[8] = {0};
+
+ ImsMediaBitWriter writer;
+ writer.SetBuffer(dstBuffer, sizeof(dstBuffer));
+
+ for (int32_t i = 0; i < sizeof(testBuffer); i++)
+ {
+ EXPECT_EQ(writer.WriteByteBuffer(testBuffer + i, 8), true);
+ }
+
+ EXPECT_EQ(memcmp(dstBuffer, testBuffer, sizeof(testBuffer)), 0);
+}
+
+TEST_F(ImsMediaBitWriterTest, SetBufferAndSeekToWriteTest)
+{
+ uint8_t testBuffer[] = {1, 2, 4, 8, 16, 32, 64, 128};
+ uint8_t dstBuffer[8] = {1, 2, 4, 8};
+
+ ImsMediaBitWriter writer;
+ writer.SetBuffer(dstBuffer, sizeof(dstBuffer));
+ writer.Seek(32);
+ writer.WriteByteBuffer(testBuffer + 4, 32);
+
+ EXPECT_EQ(memcmp(dstBuffer, testBuffer, sizeof(testBuffer)), 0);
+}
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaImageRotateTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaImageRotateTest.cpp
index 60dc69fb..a5cbd157 100644
--- a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaImageRotateTest.cpp
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/utils/ImsMediaImageRotateTest.cpp
@@ -72,6 +72,76 @@ TEST_F(ImsMediaImageRotateTest, Rotate90FlipTest_ZeroImageSize)
EXPECT_EQ(memcmp(output_img, exp_img, 0), 0);
}
+TEST_F(ImsMediaImageRotateTest, Rotate90Test)
+{
+ const uint16_t img_width = 4, img_height = 4;
+ const uint32_t img_buf_size = img_width * img_height * 1.5f;
+
+ // Input image Y buffer
+ uint8_t input_img_y[] = {0, 1, 2, 3, 10, 11, 12, 13, 20, 21, 22, 23, 30, 31, 32, 33};
+
+ // Input image UV buffer
+ uint8_t input_img_uv[] = {80, 90, 81, 91, 82, 92, 83, 93};
+
+ // Expected output Y buffer
+ uint8_t exp_img[img_buf_size] = {30, 20, 10, 0, 31, 21, 11, 1, 32, 22, 12, 2, 33, 23, 13, 3, 82,
+ 92, 80, 90, 83, 93, 81, 91};
+
+ // Output image buffer to be verified
+ uint8_t output_img[img_buf_size] = {0};
+
+ ImsMediaImageRotate::YUV420_SP_Rotate90(
+ output_img, img_buf_size, img_height, input_img_y, input_img_uv, img_width, img_height);
+
+ EXPECT_EQ(memcmp(output_img, exp_img, img_buf_size), 0);
+}
+
+TEST_F(ImsMediaImageRotateTest, Rotate90WithOutputStrideTest)
+{
+ const uint16_t img_width = 4, img_height = 4, outimg_stride = 6;
+ const uint32_t img_buf_size = outimg_stride * img_width * 1.5f;
+
+ // Input image Y buffer
+ uint8_t input_img_y[] = {0, 1, 2, 3, 10, 11, 12, 13, 20, 21, 22, 23, 30, 31, 32, 33};
+
+ // Input image UV buffer
+ uint8_t input_img_uv[] = {80, 90, 81, 91, 82, 92, 83, 93};
+
+ // Expected output Y buffer
+ uint8_t exp_img[img_buf_size] = {30, 20, 10, 0, 0, 0, 31, 21, 11, 1, 0, 0, 32, 22, 12, 2, 0, 0,
+ 33, 23, 13, 3, 0, 0, 82, 92, 80, 90, 0, 0, 83, 93, 81, 91, 0, 0};
+
+ // Output image buffer to be verified
+ uint8_t output_img[img_buf_size] = {0};
+
+ ImsMediaImageRotate::YUV420_SP_Rotate90(output_img, img_buf_size, outimg_stride, input_img_y,
+ input_img_uv, img_width, img_height);
+
+ EXPECT_EQ(memcmp(output_img, exp_img, img_buf_size), 0);
+}
+
+TEST_F(ImsMediaImageRotateTest, Rotate90Flip_ZeroImageSize)
+{
+ const uint16_t img_width = 0, img_height = 0;
+
+ // Input image Y buffer
+ uint8_t input_img_y[0] = {};
+
+ // Input image UV buffer
+ uint8_t input_img_uv[0] = {};
+
+ // Expected output Y buffer
+ uint8_t exp_img[0] = {};
+
+ // Output image buffer to be verified
+ uint8_t output_img[0] = {};
+
+ ImsMediaImageRotate::YUV420_SP_Rotate90(
+ output_img, 0, img_height, input_img_y, input_img_uv, img_width, img_height);
+
+ EXPECT_EQ(memcmp(output_img, exp_img, 0), 0);
+}
+
TEST_F(ImsMediaImageRotateTest, Rotate270Test)
{
const uint16_t img_width = 4, img_height = 4;
@@ -91,7 +161,31 @@ TEST_F(ImsMediaImageRotateTest, Rotate270Test)
uint8_t output_img[img_buf_size] = {0};
ImsMediaImageRotate::YUV420_SP_Rotate270(
- output_img, input_img_y, input_img_uv, img_width, img_height);
+ output_img, img_buf_size, img_height, input_img_y, input_img_uv, img_width, img_height);
+
+ EXPECT_EQ(memcmp(output_img, exp_img, img_buf_size), 0);
+}
+
+TEST_F(ImsMediaImageRotateTest, Rotate270WithOutStrideTest)
+{
+ const uint16_t img_width = 4, img_height = 4, outimg_stride = 6;
+ const uint32_t img_buf_size = outimg_stride * img_width * 1.5f;
+
+ // Input image Y buffer
+ uint8_t input_img_y[] = {0, 1, 2, 3, 10, 11, 12, 13, 20, 21, 22, 23, 30, 31, 32, 33};
+
+ // Input image UV buffer
+ uint8_t input_img_uv[] = {80, 90, 81, 91, 82, 92, 83, 93};
+
+ // Expected output Y buffer
+ uint8_t exp_img[img_buf_size] = {3, 13, 23, 33, 0, 0, 2, 12, 22, 32, 0, 0, 1, 11, 21, 31, 0, 0,
+ 0, 10, 20, 30, 0, 0, 81, 91, 83, 93, 0, 0, 80, 90, 82, 92, 0, 0};
+
+ // Output image buffer to be verified
+ uint8_t output_img[img_buf_size] = {0};
+
+ ImsMediaImageRotate::YUV420_SP_Rotate270(output_img, img_buf_size, outimg_stride, input_img_y,
+ input_img_uv, img_width, img_height);
EXPECT_EQ(memcmp(output_img, exp_img, img_buf_size), 0);
}
@@ -113,7 +207,7 @@ TEST_F(ImsMediaImageRotateTest, Rotate270Test_ZeroImageSize)
uint8_t output_img[0] = {};
ImsMediaImageRotate::YUV420_SP_Rotate270(
- output_img, input_img_y, input_img_uv, img_width, img_height);
+ output_img, 0, img_height, input_img_y, input_img_uv, img_width, img_height);
EXPECT_EQ(memcmp(output_img, exp_img, 0), 0);
}
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoStreamGraphRtcpTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoStreamGraphRtcpTest.cpp
index 327e42fc..0806fe7d 100644
--- a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoStreamGraphRtcpTest.cpp
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoStreamGraphRtcpTest.cpp
@@ -24,7 +24,7 @@
using namespace android::telephony::imsmedia;
// RtpConfig
-const int32_t kMediaDirection = RtpConfig::MEDIA_DIRECTION_SEND_RECEIVE;
+const int32_t kMediaDirection = RtpConfig::MEDIA_DIRECTION_INACTIVE;
const android::String8 kRemoteAddress("127.0.0.1");
const int32_t kRemotePort = 10000;
const int32_t kMtu = 1300;
@@ -163,6 +163,14 @@ TEST_F(VideoStreamGraphRtcpTest, TestRtcpStreamAndUpdate)
EXPECT_EQ(graph->update(&config), RESULT_SUCCESS);
EXPECT_EQ(graph->getState(), kStreamStateRunning);
+ config.setMediaDirection(RtpConfig::MEDIA_DIRECTION_NO_FLOW);
+ EXPECT_EQ(graph->update(&config), RESULT_SUCCESS);
+ EXPECT_EQ(graph->getState(), kStreamStateCreated);
+
+ config.setMediaDirection(RtpConfig::MEDIA_DIRECTION_INACTIVE);
+ EXPECT_EQ(graph->update(&config), RESULT_SUCCESS);
+ EXPECT_EQ(graph->getState(), kStreamStateRunning);
+
EXPECT_EQ(graph->stop(), RESULT_SUCCESS);
EXPECT_EQ(graph->getState(), kStreamStateCreated);
}
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoStreamGraphRtpTxTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoStreamGraphRtpTxTest.cpp
index 332041c4..20f368ba 100644
--- a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoStreamGraphRtpTxTest.cpp
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/core/video/VideoStreamGraphRtpTxTest.cpp
@@ -123,6 +123,12 @@ protected:
1, &previewReader),
AMEDIA_OK);
AImageReader_getWindow(previewReader, &previewSurface);
+
+ /*
+ * TODO: Below line will skip all test under this class, need to remove to include it in
+ * atest
+ */
+ GTEST_SKIP();
}
virtual void TearDown() override
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/include/core/audio/MockAudioManager.h b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/include/core/audio/MockAudioManager.h
new file mode 100644
index 00000000..4a46634b
--- /dev/null
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/include/core/audio/MockAudioManager.h
@@ -0,0 +1,39 @@
+/**
+ * Copyright (C) 2023 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 MOCK_AUDIO_MANAGER_H
+#define MOCK_AUDIO_MANAGER_H
+
+#include <AudioManager.h>
+#include <ImsMediaDefine.h>
+#include <gmock/gmock.h>
+
+class MockAudioManager : public AudioManager
+{
+public:
+ MockAudioManager() { sManager = this; }
+ virtual ~MockAudioManager() { sManager = nullptr; }
+ MOCK_METHOD(ImsMediaResult, deleteConfig, (int sessionId, AudioConfig* config), (override));
+ MOCK_METHOD(void, sendDtmf, (int sessionId, char dtmfDigit, int duration), (override));
+ MOCK_METHOD(void, sendRtpHeaderExtension,
+ (int sessionId, std::list<RtpHeaderExtension>* listExtension), (override));
+ MOCK_METHOD(void, setMediaQualityThreshold, (int sessionId, MediaQualityThreshold* threshold),
+ (override));
+ MOCK_METHOD(void, SendInternalEvent,
+ (uint32_t event, uint64_t sessionId, uint64_t paramA, uint64_t paramB), (override));
+};
+
+#endif \ No newline at end of file
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/protocol/rtp/core/RtcpPacketTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/protocol/rtp/core/RtcpPacketTest.cpp
index 37185728..1c95e03b 100644
--- a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/protocol/rtp/core/RtcpPacketTest.cpp
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/protocol/rtp/core/RtcpPacketTest.cpp
@@ -671,6 +671,39 @@ TEST_F(RtcpPacketTest, DecodeOnlyRtcpSRHeader)
EXPECT_EQ(pRtcpHeader.getLength(), 0 * RTP_WORD_SIZE);
}
+/**
+ * Test RTCP XR packet.
+ */
+TEST_F(RtcpPacketTest, TestDecodeRtcpXrPacket)
+{
+ RtcpPacket rtcpPacket;
+
+ /*
+ * Real-time Transport Control Protocol (Sender Report)
+ * 10.. .... = Version: RFC 1889 Version (2)
+ * ..1. .... = Padding: False
+ * ...0 0001 = Report count: 1
+ * Packet type: XR (207)
+ * Length: 5 (24 bytes)
+ * SSRC : 0xb1c8cb02 (2982726402)
+ * 0x00, 0x00, 0x00, 0x01, // XR block type: VoIP Metrics Report Block (207)
+ * 0x00, 0x0A, // Length of the XR block in 32-bit words: 10
+ * 0x02, 0x01, // Loss rate (packets lost per million packets sent): 2 bytes;
+ * Type-specific: 1 0x00, 0x64, // Loss rate: 100 0x03, 0x01, // Delay
+ * since last report (milliseconds): 2 bytes; Type-specific: 1 0x00, 0x3C, // Delay:
+ * 60 milliseconds
+ */
+ uint8_t bufPacket[] = {0xa1, 0xcf, 0x00, 0x05, 0xb1, 0xc8, 0xcb, 0x02, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x0A, 0x02, 0x01, 0x00, 0x64, 0x03, 0x01, 0x00, 0x3C, 0x00, 0x02};
+
+ RtcpConfigInfo rtcpConfigInfo;
+ RtpBuffer rtpBuffer(24, bufPacket);
+ eRTP_STATUS_CODE res = rtcpPacket.decodeRtcpPacket(&rtpBuffer, 0, &rtcpConfigInfo);
+ EXPECT_EQ(res, RTP_SUCCESS);
+
+ // TODO: After Rtcp-Xr decoder function is implemented, add checks for each files in XR report.
+}
+
TEST_F(RtcpPacketTest, CheckAllGetSets)
{
RtcpPacket rtcpPacket;
diff --git a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/protocol/rtp/core/RtcpXrPacketTest.cpp b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/protocol/rtp/core/RtcpXrPacketTest.cpp
index 1c9a1cb8..45624c71 100644
--- a/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/protocol/rtp/core/RtcpXrPacketTest.cpp
+++ b/tests/native/service/src/com/android/telephony/imsmedia/lib/libimsmedia/protocol/rtp/core/RtcpXrPacketTest.cpp
@@ -47,8 +47,8 @@ TEST(RtcpXrPacketTest, TestDecodeXrPacket)
0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0xc8, 0x53, 0x81, 0xca, 0x00, 0x0a};
eRTP_STATUS_CODE res =
objRtcpXrPacket.decodeRtcpXrPacket(reinterpret_cast<RtpDt_UChar*>(bufXrPacket), 24, 0);
- // Result should be failure because decode XR packet is not supported or implemented.
- EXPECT_EQ(res, RTP_FAILURE);
+
+ EXPECT_EQ(res, RTP_SUCCESS);
}
TEST(RtcpXrPacketTest, TestFormXrPacket)
diff --git a/tests/unit/src/com/android/telephony/imsmedia/AudioListenerTest.java b/tests/unit/src/com/android/telephony/imsmedia/AudioListenerTest.java
index 353b6f7c..5dace993 100644
--- a/tests/unit/src/com/android/telephony/imsmedia/AudioListenerTest.java
+++ b/tests/unit/src/com/android/telephony/imsmedia/AudioListenerTest.java
@@ -22,6 +22,7 @@ import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import android.os.Looper;
import android.os.Parcel;
import android.os.RemoteException;
import android.telephony.CallQuality;
@@ -30,21 +31,22 @@ import android.telephony.imsmedia.AudioConfig;
import android.telephony.imsmedia.IImsAudioSessionCallback;
import android.telephony.imsmedia.ImsMediaSession;
import android.telephony.imsmedia.MediaQualityStatus;
+import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import java.util.List;
-@RunWith(JUnit4.class)
-public class AudioListenerTest {
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class AudioListenerTest extends ImsMediaTest {
private static final int SESSION_ID = 1;
private static final char DTMF_DIGIT = '7';
private static final int DTMF_DURATION = 120;
@@ -58,30 +60,23 @@ public class AudioListenerTest {
@Mock
private IImsAudioSessionCallback mMockIImsAudioSessionCallback;
private AudioConfig mAudioConfig;
- private TestableLooper mLooper;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
AudioSession audioSession = new AudioSession(SESSION_ID, mMockIImsAudioSessionCallback,
- mAudioService, mMockAudioLocalSession, null);
+ mAudioService, mMockAudioLocalSession, null, Looper.myLooper());
AudioSession.AudioSessionHandler handler = audioSession.getAudioSessionHandler();
mAudioListener = new AudioListener(handler);
mAudioListener.setMediaCallback(mMockCallback);
mAudioConfig = AudioConfigTest.createAudioConfig();
- try {
- mLooper = new TestableLooper(handler.getLooper());
- } catch (Exception e) {
- throw new AssertionError("Unable to create TestableLooper", e);
- }
+ mTestClass = AudioListenerTest.this;
+ super.setUp();
}
@After
public void tearDown() throws Exception {
- if (mLooper != null) {
- mLooper.destroy();
- mLooper = null;
- }
+ super.tearDown();
}
private Parcel createParcel(int event, int result, AudioConfig config) {
@@ -238,10 +233,4 @@ public class AudioListenerTest {
doNothing().when(mMockCallback).onSessionClosed(eq(SESSION_ID));
verify(mMockCallback, times(1)).onSessionClosed(eq(SESSION_ID));
}
-
- private void processAllMessages() {
- while (!mLooper.getLooper().getQueue().isIdle()) {
- mLooper.processAllMessages();
- }
- }
}
diff --git a/tests/unit/src/com/android/telephony/imsmedia/AudioOffloadTest.java b/tests/unit/src/com/android/telephony/imsmedia/AudioOffloadTest.java
index 5eb92175..c3013544 100644
--- a/tests/unit/src/com/android/telephony/imsmedia/AudioOffloadTest.java
+++ b/tests/unit/src/com/android/telephony/imsmedia/AudioOffloadTest.java
@@ -30,6 +30,7 @@ import android.hardware.radio.ims.media.IImsMedia;
import android.hardware.radio.ims.media.IImsMediaSession;
import android.hardware.radio.ims.media.RtpConfig;
import android.hardware.radio.ims.media.RtpError;
+import android.os.Looper;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.telephony.CallQuality;
@@ -39,6 +40,7 @@ import android.telephony.imsmedia.IImsAudioSessionCallback;
import android.telephony.imsmedia.ImsMediaSession;
import android.telephony.imsmedia.MediaQualityStatus;
import android.telephony.imsmedia.MediaQualityThreshold;
+import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import com.android.telephony.imsmedia.AudioSession;
@@ -49,7 +51,6 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -60,8 +61,9 @@ import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
-@RunWith(JUnit4.class)
-public class AudioOffloadTest {
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class AudioOffloadTest extends ImsMediaTest {
private static final int SESSION_ID = 1;
private static final int DTMF_DURATION = 120;
private static final int NO_RESOURCES = ImsMediaSession.RESULT_NO_RESOURCES;
@@ -73,7 +75,6 @@ public class AudioOffloadTest {
private AudioSession audioSession;
private AudioOffloadListener offloadListener;
private AudioSession.AudioSessionHandler handler;
- private TestableLooper looper;
@Mock
private IImsAudioSessionCallback callback;
@Mock
@@ -88,24 +89,19 @@ public class AudioOffloadTest {
MockitoAnnotations.initMocks(this);
offloadService = spy(AudioOffloadService.getInstance());
doReturn(imsMedia).when(offloadService).getIImsMedia();
- audioSession = new AudioSession(SESSION_ID, callback, null, null, offloadService);
+ audioSession = new AudioSession(SESSION_ID, callback, null, null, offloadService,
+ Looper.myLooper());
handler = audioSession.getAudioSessionHandler();
audioSession.setAudioOffload(true);
offloadListener = audioSession.getOffloadListener();
audioSession.onOpenSessionSuccess(imsMediaSession);
- try {
- looper = new TestableLooper(handler.getLooper());
- } catch (Exception e) {
- throw new AssertionError("Unable to create TestableLooper", e);
- }
+ mTestClass = AudioOffloadTest.this;
+ super.setUp();
}
@After
public void tearDown() throws Exception {
- if (looper != null) {
- looper.destroy();
- looper = null;
- }
+ super.tearDown();
}
@Test
@@ -263,7 +259,8 @@ public class AudioOffloadTest {
@Test
public void testSetMediaQualityThreshold() {
// Set Media Quality Threshold
- MediaQualityThreshold threshold = MediaQualityThresholdTest.createMediaQualityThreshold();
+ MediaQualityThreshold threshold =
+ MediaQualityThresholdTest.createMediaQualityThresholdForHal();
audioSession.setMediaQualityThreshold(threshold);
processAllMessages();
try {
@@ -397,10 +394,4 @@ public class AudioOffloadTest {
fail("Failed to notify onCallQualityChanged: " + e);
}
}
-
- private void processAllMessages() {
- while (!looper.getLooper().getQueue().isIdle()) {
- looper.processAllMessages();
- }
- }
}
diff --git a/tests/unit/src/com/android/telephony/imsmedia/AudioSessionTest.java b/tests/unit/src/com/android/telephony/imsmedia/AudioSessionTest.java
index 2c9bf484..e51a46fb 100644
--- a/tests/unit/src/com/android/telephony/imsmedia/AudioSessionTest.java
+++ b/tests/unit/src/com/android/telephony/imsmedia/AudioSessionTest.java
@@ -21,6 +21,7 @@ import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import android.os.Looper;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
@@ -31,6 +32,7 @@ import android.telephony.imsmedia.IImsAudioSessionCallback;
import android.telephony.imsmedia.ImsMediaSession;
import android.telephony.imsmedia.MediaQualityStatus;
import android.telephony.imsmedia.MediaQualityThreshold;
+import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import com.android.telephony.imsmedia.AudioService;
@@ -42,7 +44,6 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -50,8 +51,9 @@ import java.net.DatagramSocket;
import java.net.SocketException;
import java.util.ArrayList;
-@RunWith(JUnit4.class)
-public class AudioSessionTest {
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class AudioSessionTest extends ImsMediaTest {
private static final int SESSION_ID = 1;
private static final int DTMF_DURATION = 140;
private static final int UNUSED = -1;
@@ -69,28 +71,21 @@ public class AudioSessionTest {
private AudioLocalSession audioLocalSession;
@Mock
private IImsAudioSessionCallback callback;
- private TestableLooper looper;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
audioSession = new AudioSession(SESSION_ID, callback,
- audioService, audioLocalSession, null);
+ audioService, audioLocalSession, null, Looper.myLooper());
audioListener = audioSession.getAudioListener();
handler = audioSession.getAudioSessionHandler();
- try {
- looper = new TestableLooper(handler.getLooper());
- } catch (Exception e) {
- throw new AssertionError("Unable to create TestableLooper", e);
- }
+ mTestClass = AudioSessionTest.this;
+ super.setUp();
}
@After
public void tearDown() throws Exception {
- if (looper != null) {
- looper.destroy();
- looper = null;
- }
+ super.tearDown();
}
private Parcel createParcel(int message, int result, AudioConfig config) {
@@ -366,10 +361,4 @@ public class AudioSessionTest {
fail("Failed to notify onSessionClosed: " + e);
}
}
-
- private void processAllMessages() {
- while (!looper.getLooper().getQueue().isIdle()) {
- looper.processAllMessages();
- }
- }
}
diff --git a/tests/unit/src/com/android/telephony/imsmedia/ImsMediaTest.java b/tests/unit/src/com/android/telephony/imsmedia/ImsMediaTest.java
new file mode 100644
index 00000000..759e6f32
--- /dev/null
+++ b/tests/unit/src/com/android/telephony/imsmedia/ImsMediaTest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.telephony.imsmedia;
+
+import static org.junit.Assert.fail;
+
+import android.testing.TestableLooper;
+
+import org.junit.After;
+import org.junit.Before;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ImsMediaTest {
+ protected List<TestableLooper> mTestableLoopers = new ArrayList<>();
+ protected TestableLooper mTestableLooper;
+ protected Object mTestClass;
+
+ @Before
+ public void setUp() {
+ mTestableLooper = TestableLooper.get(mTestClass);
+ if (mTestableLooper != null) {
+ monitorTestableLooper(mTestableLooper);
+ }
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ if (!mTestableLoopers.isEmpty()) {
+ for (TestableLooper looper : mTestableLoopers) {
+ looper.getLooper().quit();
+ }
+ }
+ // Unmonitor TestableLooper for ImsMediaTest class
+ if (mTestableLooper != null) {
+ unmonitorTestableLooper(mTestableLooper);
+ }
+ // Destroy all newly created TestableLoopers so they can be reused
+ for (TestableLooper looper : mTestableLoopers) {
+ looper.destroy();
+ }
+ TestableLooper.remove(mTestClass);
+
+ }
+
+ private void monitorTestableLooper(TestableLooper looper) {
+ if (!mTestableLoopers.contains(looper)) {
+ mTestableLoopers.add(looper);
+ }
+ }
+
+ private void unmonitorTestableLooper(TestableLooper looper) {
+ if (mTestableLoopers.contains(looper)) {
+ mTestableLoopers.remove(looper);
+ }
+ }
+
+ private boolean areAllTestableLoopersIdle() {
+ for (TestableLooper looper : mTestableLoopers) {
+ if (!looper.getLooper().getQueue().isIdle()) return false;
+ }
+ return true;
+ }
+
+ public void processAllMessages() {
+ if (mTestableLoopers.isEmpty()) {
+ fail("mTestableLoopers is empty. Please make sure to add @RunWithLooper annotation");
+ }
+ while (!areAllTestableLoopersIdle()) {
+ for (TestableLooper looper : mTestableLoopers) looper.processAllMessages();
+ }
+ }
+}
diff --git a/tests/unit/src/com/android/telephony/imsmedia/MediaQualityThresholdTest.java b/tests/unit/src/com/android/telephony/imsmedia/MediaQualityThresholdTest.java
index 40dfe866..d61e0f33 100644
--- a/tests/unit/src/com/android/telephony/imsmedia/MediaQualityThresholdTest.java
+++ b/tests/unit/src/com/android/telephony/imsmedia/MediaQualityThresholdTest.java
@@ -37,6 +37,7 @@ public class MediaQualityThresholdTest {
private static final int[] PACKET_LOSS_RATE = { 1, 3 };
private static final int[] JITTER_THRESHOLD = { 100, 200 };
private static final boolean NOTIFY_STATUS = false;
+ private static final int VIDEO_BITRATE_BPS = 100000;
@Test
public void testConstructorAndGetters() {
@@ -48,6 +49,7 @@ public class MediaQualityThresholdTest {
assertThat(Arrays.equals(threshold.getRtpPacketLossRate(), PACKET_LOSS_RATE)).isTrue();
assertThat(Arrays.equals(threshold.getRtpJitterMillis(), JITTER_THRESHOLD)).isTrue();
assertThat(threshold.getNotifyCurrentStatus()).isEqualTo(NOTIFY_STATUS);
+ assertThat(threshold.getVideoBitrateBps()).isEqualTo(VIDEO_BITRATE_BPS);
}
@Test
@@ -82,6 +84,7 @@ public class MediaQualityThresholdTest {
.setRtpPacketLossRate(PACKET_LOSS_RATE)
.setRtpJitterMillis(JITTER_THRESHOLD)
.setNotifyCurrentStatus(NOTIFY_STATUS)
+ .setVideoBitrateBps(VIDEO_BITRATE_BPS)
.build();
assertThat(threshold1).isNotEqualTo(threshold2);
@@ -94,6 +97,7 @@ public class MediaQualityThresholdTest {
.setRtpPacketLossRate(PACKET_LOSS_RATE)
.setRtpJitterMillis(JITTER_THRESHOLD)
.setNotifyCurrentStatus(NOTIFY_STATUS)
+ .setVideoBitrateBps(VIDEO_BITRATE_BPS)
.build();
assertThat(threshold1).isNotEqualTo(threshold3);
@@ -106,6 +110,7 @@ public class MediaQualityThresholdTest {
.setRtpPacketLossRate(PACKET_LOSS_RATE)
.setRtpJitterMillis(JITTER_THRESHOLD)
.setNotifyCurrentStatus(NOTIFY_STATUS)
+ .setVideoBitrateBps(VIDEO_BITRATE_BPS)
.build();
assertThat(threshold1).isNotEqualTo(threshold4);
@@ -119,6 +124,7 @@ public class MediaQualityThresholdTest {
.setRtpPacketLossRate(PACKET_LOSS_RATE)
.setRtpJitterMillis(JITTER_THRESHOLD)
.setNotifyCurrentStatus(NOTIFY_STATUS)
+ .setVideoBitrateBps(VIDEO_BITRATE_BPS)
.build();
assertThat(threshold1).isNotEqualTo(threshold5);
@@ -133,6 +139,20 @@ public class MediaQualityThresholdTest {
.setRtpPacketLossRate(PACKET_LOSS_RATE)
.setRtpJitterMillis(JITTER_THRESHOLD)
.setNotifyCurrentStatus(NOTIFY_STATUS)
+ .setVideoBitrateBps(VIDEO_BITRATE_BPS)
+ .build();
+ }
+
+ static MediaQualityThreshold createMediaQualityThresholdForHal() {
+ return new MediaQualityThreshold.Builder()
+ .setRtpInactivityTimerMillis(RTP_TIMEOUT)
+ .setRtcpInactivityTimerMillis(RTCP_TIMEOUT)
+ .setRtpHysteresisTimeInMillis(RTP_HYSTERESIS_TIME)
+ .setRtpPacketLossDurationMillis(RTP_PACKET_LOSS_DURATION)
+ .setRtpPacketLossRate(PACKET_LOSS_RATE)
+ .setRtpJitterMillis(JITTER_THRESHOLD)
+ .setNotifyCurrentStatus(NOTIFY_STATUS)
+ .setVideoBitrateBps(0)
.build();
}
}
diff --git a/tests/unit/src/com/android/telephony/imsmedia/TextListenerTest.java b/tests/unit/src/com/android/telephony/imsmedia/TextListenerTest.java
index ce2520c1..a7f016f5 100644
--- a/tests/unit/src/com/android/telephony/imsmedia/TextListenerTest.java
+++ b/tests/unit/src/com/android/telephony/imsmedia/TextListenerTest.java
@@ -22,23 +22,25 @@ import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import android.os.Looper;
import android.os.Parcel;
import android.os.RemoteException;
import android.telephony.imsmedia.IImsTextSessionCallback;
import android.telephony.imsmedia.ImsMediaSession;
import android.telephony.imsmedia.TextConfig;
+import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-@RunWith(JUnit4.class)
-public class TextListenerTest {
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class TextListenerTest extends ImsMediaTest {
private static final int SESSION_ID = 1;
private static final String TEXT_STREAM = "Hello";
private static final long NATIVE_OBJECT = 1234L;
@@ -52,31 +54,24 @@ public class TextListenerTest {
@Mock
private IImsTextSessionCallback mMockIImsTextSessionCallback;
private TextConfig mTextConfig;
- private TestableLooper mLooper;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
TextSession textSession = new TextSession(SESSION_ID, mMockIImsTextSessionCallback,
- mTextService, mMockTextLocalSession);
+ mTextService, mMockTextLocalSession, Looper.myLooper());
TextSession.TextSessionHandler handler = textSession.getTextSessionHandler();
mTextListener = new TextListener(handler);
mTextListener.setMediaCallback(mMockCallback);
mTextListener.setNativeObject(NATIVE_OBJECT);
mTextConfig = TextConfigTest.createTextConfig();
- try {
- mLooper = new TestableLooper(handler.getLooper());
- } catch (Exception e) {
- throw new AssertionError("Unable to create TestableLooper", e);
- }
+ mTestClass = TextListenerTest.this;
+ super.setUp();
}
@After
- public void tearDown() {
- if (mLooper != null) {
- mLooper.destroy();
- mLooper = null;
- }
+ public void tearDown() throws Exception {
+ super.tearDown();
}
private Parcel createParcel(int event, int result, TextConfig config) {
@@ -166,10 +161,4 @@ public class TextListenerTest {
parcel.recycle();
verify(mMockCallback, times(1)).onSessionClosed(eq(SESSION_ID));
}
-
- private void processAllMessages() {
- while (!mLooper.getLooper().getQueue().isIdle()) {
- mLooper.processAllMessages();
- }
- }
}
diff --git a/tests/unit/src/com/android/telephony/imsmedia/TextSessionTest.java b/tests/unit/src/com/android/telephony/imsmedia/TextSessionTest.java
index 7319711e..0c150026 100644
--- a/tests/unit/src/com/android/telephony/imsmedia/TextSessionTest.java
+++ b/tests/unit/src/com/android/telephony/imsmedia/TextSessionTest.java
@@ -21,6 +21,7 @@ import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import android.os.Looper;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
@@ -28,6 +29,7 @@ import android.telephony.imsmedia.IImsTextSessionCallback;
import android.telephony.imsmedia.ImsMediaSession;
import android.telephony.imsmedia.MediaQualityThreshold;
import android.telephony.imsmedia.TextConfig;
+import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import com.android.telephony.imsmedia.Utils.OpenSessionParams;
@@ -36,15 +38,15 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.net.DatagramSocket;
import java.net.SocketException;
-@RunWith(JUnit4.class)
-public class TextSessionTest {
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class TextSessionTest extends ImsMediaTest {
private static final int SESSION_ID = 1;
private static final int SUCCESS = ImsMediaSession.RESULT_SUCCESS;
private static final int NO_RESOURCES = ImsMediaSession.RESULT_NO_RESOURCES;
@@ -60,27 +62,21 @@ public class TextSessionTest {
private TextLocalSession mTextLocalSession;
@Mock
private IImsTextSessionCallback mCallback;
- private TestableLooper mLooper;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mTextSession = new TextSession(SESSION_ID, mCallback, mTextService, mTextLocalSession);
+ mTextSession = new TextSession(SESSION_ID, mCallback, mTextService, mTextLocalSession,
+ Looper.myLooper());
mTextListener = mTextSession.getTextListener();
mHandler = mTextSession.getTextSessionHandler();
- try {
- mLooper = new TestableLooper(mHandler.getLooper());
- } catch (Exception e) {
- throw new AssertionError("Unable to create TestableLooper", e);
- }
+ mTestClass = TextSessionTest.this;
+ super.setUp();
}
@After
public void tearDown() throws Exception {
- if (mLooper != null) {
- mLooper.destroy();
- mLooper = null;
- }
+ super.tearDown();
}
private Parcel createParcel(int message, int result, TextConfig config) {
@@ -241,10 +237,4 @@ public class TextSessionTest {
fail("Failed to notify onSessionClosed: " + e);
}
}
-
- private void processAllMessages() {
- while (!mLooper.getLooper().getQueue().isIdle()) {
- mLooper.processAllMessages();
- }
- }
}
diff --git a/tests/unit/src/com/android/telephony/imsmedia/VideoListenerTest.java b/tests/unit/src/com/android/telephony/imsmedia/VideoListenerTest.java
index ad90f957..d00ccb1b 100644
--- a/tests/unit/src/com/android/telephony/imsmedia/VideoListenerTest.java
+++ b/tests/unit/src/com/android/telephony/imsmedia/VideoListenerTest.java
@@ -22,23 +22,25 @@ import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import android.os.Looper;
import android.os.Parcel;
import android.os.RemoteException;
import android.telephony.imsmedia.IImsVideoSessionCallback;
import android.telephony.imsmedia.ImsMediaSession;
import android.telephony.imsmedia.VideoConfig;
+import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-@RunWith(JUnit4.class)
-public class VideoListenerTest {
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class VideoListenerTest extends ImsMediaTest {
private static final int SESSION_ID = 1;
private static final long VIDEO_DATA = 1024;
private static final int RESOLUTION_WIDTH = 640;
@@ -54,31 +56,24 @@ public class VideoListenerTest {
@Mock
private IImsVideoSessionCallback mMockIImsVideoSessionCallback;
private VideoConfig mVideoConfig;
- private TestableLooper mLooper;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
VideoSession videoSession = new VideoSession(SESSION_ID, mMockIImsVideoSessionCallback,
- mVideoService, mMockVideoLocalSession);
+ mVideoService, mMockVideoLocalSession, Looper.myLooper());
VideoSession.VideoSessionHandler handler = videoSession.getVideoSessionHandler();
mVideoListener = new VideoListener(handler);
mVideoListener.setMediaCallback(mMockCallback);
mVideoListener.setNativeObject(NATIVE_OBJECT);
mVideoConfig = VideoConfigTest.createVideoConfig();
- try {
- mLooper = new TestableLooper(handler.getLooper());
- } catch (Exception e) {
- throw new AssertionError("Unable to create TestableLooper", e);
- }
+ mTestClass = VideoListenerTest.this;
+ super.setUp();
}
@After
- public void tearDown() {
- if (mLooper != null) {
- mLooper.destroy();
- mLooper = null;
- }
+ public void tearDown() throws Exception {
+ super.tearDown();
}
private Parcel createParcel(int event, int result) {
@@ -170,14 +165,14 @@ public class VideoListenerTest {
}
@Test
- public void testEventPacketLossInd() throws RemoteException {
- Parcel parcel = createParcel(VideoSession.EVENT_PACKET_LOSS_IND,
+ public void testEventNotifyBitrateInd() throws RemoteException {
+ Parcel parcel = createParcel(VideoSession.EVENT_NOTIFY_BITRATE_IND,
ImsMediaSession.PACKET_TYPE_RTCP);
mVideoListener.onMessage(parcel);
processAllMessages();
parcel.recycle();
verify(mMockIImsVideoSessionCallback,
- times(1)).notifyPacketLoss(eq(ImsMediaSession.PACKET_TYPE_RTCP));
+ times(1)).notifyBitrate(eq(ImsMediaSession.PACKET_TYPE_RTCP));
}
@Test
@@ -201,10 +196,4 @@ public class VideoListenerTest {
parcel.recycle();
verify(mMockCallback, times(1)).onSessionClosed(eq(SESSION_ID));
}
-
- private void processAllMessages() {
- while (!mLooper.getLooper().getQueue().isIdle()) {
- mLooper.processAllMessages();
- }
- }
}
diff --git a/tests/unit/src/com/android/telephony/imsmedia/VideoSessionTest.java b/tests/unit/src/com/android/telephony/imsmedia/VideoSessionTest.java
index 3f781886..d9e4b897 100644
--- a/tests/unit/src/com/android/telephony/imsmedia/VideoSessionTest.java
+++ b/tests/unit/src/com/android/telephony/imsmedia/VideoSessionTest.java
@@ -23,6 +23,7 @@ import static org.mockito.Mockito.verify;
import android.graphics.ImageFormat;
import android.media.ImageReader;
+import android.os.Looper;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
@@ -31,6 +32,7 @@ import android.telephony.imsmedia.IImsVideoSessionCallback;
import android.telephony.imsmedia.ImsMediaSession;
import android.telephony.imsmedia.MediaQualityThreshold;
import android.telephony.imsmedia.VideoConfig;
+import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.Surface;
@@ -40,7 +42,6 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -48,8 +49,9 @@ import java.net.DatagramSocket;
import java.net.SocketException;
import java.util.ArrayList;
-@RunWith(JUnit4.class)
-public class VideoSessionTest {
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class VideoSessionTest extends ImsMediaTest {
private static final int SESSION_ID = 1;
private static final int UNUSED = -1;
private static final int SUCCESS = ImsMediaSession.RESULT_SUCCESS;
@@ -79,22 +81,16 @@ public class VideoSessionTest {
public void setUp() {
MockitoAnnotations.initMocks(this);
mVideoSession = new VideoSession(SESSION_ID, mCallback,
- mVideoService, mVideoLocalSession);
+ mVideoService, mVideoLocalSession, Looper.myLooper());
mVideoListener = mVideoSession.getVideoListener();
mHandler = mVideoSession.getVideoSessionHandler();
- try {
- mLooper = new TestableLooper(mHandler.getLooper());
- } catch (Exception e) {
- throw new AssertionError("Unable to create TestableLooper", e);
- }
+ mTestClass = VideoSessionTest.this;
+ super.setUp();
}
@After
public void tearDown() throws Exception {
- if (mLooper != null) {
- mLooper.destroy();
- mLooper = null;
- }
+ super.tearDown();
}
private Parcel createParcel(int message, int result, VideoConfig config) {
@@ -289,12 +285,12 @@ public class VideoSessionTest {
@Test
public void testPacketLossInd() {
// Receive Packet Loss
- Utils.sendMessage(mHandler, VideoSession.EVENT_PACKET_LOSS_IND, PACKET_LOSS, UNUSED);
+ Utils.sendMessage(mHandler, VideoSession.EVENT_NOTIFY_BITRATE_IND, PACKET_LOSS, UNUSED);
processAllMessages();
try {
- verify(mCallback, times(1)).notifyPacketLoss(eq(PACKET_LOSS));
+ verify(mCallback, times(1)).notifyBitrate(eq(PACKET_LOSS));
} catch (RemoteException e) {
- fail("Failed to notify notifyPacketLoss: " + e);
+ fail("Failed to notify notifyBitrate: " + e);
}
}
@@ -330,10 +326,4 @@ public class VideoSessionTest {
fail("Failed to notify onSessionClosed: " + e);
}
}
-
- private void processAllMessages() {
- while (!mLooper.getLooper().getQueue().isIdle()) {
- mLooper.processAllMessages();
- }
- }
}