Browse Source

[WallPadCall]
1. 방문객 원격 통화
- 기존 월패드와 동일하게 수정한 부분(DataSend부분, DataSender 변경에 따른 수정 부분)
- moip 통화 부분에서 기존 월패드와 다르게 영상데이터를 UDP로 처리하는 부분에 따라 따로 수정 -> 2024.09.30 일자로 찾으면 됨 (현장 시험)
- 현관 통화 부분에서 인코딩 시, RTPManager 초기화 화도록 수정 -> 2024.09.30 일자로 찾으면 됨 (현장 시험)
2. 버전업
- 2022.11.11.01 -> 2024.09.30.01

jglee 6 tháng trước cách đây
mục cha
commit
5dd207b1be

+ 1 - 1
WallPadCall/src/main/AndroidManifest.xml

@@ -1,7 +1,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="kr.co.icontrols.wallpadcall"
     android:versionCode="17"
-    android:versionName="2022.11.11.01">
+    android:versionName="2024.09.30.01">
 
     <!--android:sharedUserId="android.uid.system"-->
     <!--<uses-sdk-->

+ 5 - 3
WallPadCall/src/main/java/kr/co/icontrols/callengine/engine/AudioRecordController.java

@@ -344,9 +344,11 @@ public class AudioRecordController {
                 avp.frameType = 1; // 0: G711, 1: PCM 데이터 전송
 
                 try {
-//                    Log.d(TAG, "[sendDoorAudioToMobile] mDataSender.que.put()");
-                    MainActivity.mDataSender.blockingQueue.put(avp);
-                } catch (InterruptedException e) {
+                    Log.d(TAG, "[sendDoorAudioToMobile] mDataSender.que.put()");
+                    //MainActivity.mDataSender.blockingQueue.put(avp);
+                    //jglee - 2024.06.20 모바일 원격통화(오리지날에 있는것 적용)
+                    if(MainActivity.mDataSender!=null )MainActivity.mDataSender.InputData(avp);
+                } catch (Exception e) {
                     Log.e(TAG, "[InterruptedException] sendDoorAudioToMobile()");
                     //e.printStackTrace();
             LogUtil.errorLogInfo("", TAG, e);

+ 40 - 6
WallPadCall/src/main/java/kr/co/icontrols/callengine/engine/CallController.java

@@ -582,7 +582,12 @@ public class CallController extends CallManager implements SIPEventListener {
                             mCallInfo.setCallStatus(eCallType, CALLSTATUS.CALLING);
                             if (eCallOwner == CALLOWNER.MOBILE) {
                                 LOG("[CallScenarioManager] CALLOWNER [" + eCallOwner + "]");
-                                if (MainActivity.mDataSender != null) MainActivity.mDataSender.start();
+                                //jglee - 2023.02.02 데이터 초기화 후, 시작하는 것으로 수정
+                              if(MainActivity.mDataSender !=null)
+                                {
+                                    MainActivity.mDataSender.Init();
+                                    MainActivity.mDataSender.start();
+                                }
                             }
                             mCallEventListener.onCallEvent(eCallOwner, CALLSTATUS.CALLING, eCallType, strRemoteIP, strRemoteSIPID, strMessage);
                             MainActivity.mSubPhoneController.sendACKFrontMonitoring(eCallOwner, eCallType);
@@ -596,7 +601,12 @@ public class CallController extends CallManager implements SIPEventListener {
                     else if (eCallType == CALLTYPE.RESIDENCE) {
                         if (eCallOwner == CALLOWNER.MOBILE) {
                             ((MainActivity) mContext).changeMenuNScreen(ID.MENU.MENU_TALKRESIDENCE);
-                            if (MainActivity.mDataSender != null) MainActivity.mDataSender.start(); // 모바일에서 홈뷰어 요청하였을 때
+                            //jglee - 2023.02.02 데이터 초기화 후, 시작하는 것으로 수정
+                            if(MainActivity.mDataSender !=null)
+                            {
+                                MainActivity.mDataSender.Init();
+                                MainActivity.mDataSender.start();
+                            }// 모바일에서 홈뷰어 요청하였을 때
 
                             if (mCallEventListener != null) {
                                 mCallInfo.setCallStatus(eCallType, CALLSTATUS.HOMEVIEW);
@@ -693,8 +703,14 @@ public class CallController extends CallManager implements SIPEventListener {
                         if (ConfigValues.bRemoteCall) {
                             RemoteCallMSG.REMOTE_CALLTYPE = eCallType;
                             RemoteCallMSG.REMOTE_CALLSTATUS = CALLSTATUS.CALLED;
+                            Log.d(TAG, "CallController - CallType : " + eCallType + ", Status : " +  RemoteCallMSG.REMOTE_CALLSTATUS);
                             MainActivity.mRemoteCallController.sendOpenRemoteCall(RemoteCallMSG.REMOTE_CALLTYPE, RemoteCallMSG.REMOTE_CALLSTATUS);
-                            if (MainActivity.mDataSender != null) MainActivity.mDataSender.start();
+                            //jglee - 2023.02.02 데이터 초기화 후, 시작하는 것으로 수정
+                            if(MainActivity.mDataSender !=null)
+                            {
+                                MainActivity.mDataSender.Init();
+                                MainActivity.mDataSender.start();
+                            }
                         }
                     }
                     else if (eCallType == CALLTYPE.LOBBY) {
@@ -703,7 +719,12 @@ public class CallController extends CallManager implements SIPEventListener {
                             RemoteCallMSG.REMOTE_CALLTYPE = eCallType;
                             RemoteCallMSG.REMOTE_CALLSTATUS = CALLSTATUS.CALLED;
                             MainActivity.mRemoteCallController.sendOpenRemoteCall(RemoteCallMSG.REMOTE_CALLTYPE, RemoteCallMSG.REMOTE_CALLSTATUS);
-                            if (MainActivity.mDataSender != null) MainActivity.mDataSender.start();
+                            //jglee - 2023.02.02 데이터 초기화 후, 시작하는 것으로 수정
+                            if(MainActivity.mDataSender !=null)
+                            {
+                                MainActivity.mDataSender.Init();
+                                MainActivity.mDataSender.start();
+                            }
                         }
                     }
                     else if (eCallType == CALLTYPE.GUARD) {
@@ -711,7 +732,12 @@ public class CallController extends CallManager implements SIPEventListener {
                         if (ConfigValues.bRemoteCall) {
                             RemoteCallMSG.REMOTE_CALLTYPE = eCallType;
                             MainActivity.mRemoteCallController.sendOpenRemoteCall(RemoteCallMSG.REMOTE_CALLTYPE, strRemoteSIPID, strRemoteIP);
-                            if (MainActivity.mDataSender != null) MainActivity.mDataSender.start();
+                            //jglee - 2023.02.02 데이터 초기화 후, 시작하는 것으로 수정
+                            if (MainActivity.mDataSender != null)
+                            {
+                                MainActivity.mDataSender.Init();
+                                MainActivity.mDataSender.start();
+                            }
                         }
                     }
                     else if (eCallType == CALLTYPE.RESIDENCE) {
@@ -856,7 +882,11 @@ public class CallController extends CallManager implements SIPEventListener {
                         if (RemoteCallMSG.REMOTE_CALLTYPE == CALLTYPE.LOBBY) {
                             if (mSIPInterface != null) mSIPInterface.videoSet(false, false, false); // 모바일에서 로비통화 종료시 영상 먼저 종료
                         }
-                        if (MainActivity.mDataSender != null) MainActivity.mDataSender.interrupt();
+                        //jglee - 2023.02.02 데이터 초기화 후, 시작하는 것으로 수정
+                        if (MainActivity.mDataSender != null) {
+                            MainActivity.mDataSender.onClose();
+                            MainActivity.mDataSender.interrupt();
+                        }
                         RemoteCallMSG.REMOTE_CALLTYPE = CALLTYPE.NONE;
                         RemoteCallMSG.REMOTE_CALLSTATUS = CALLSTATUS.IDLE;
                         RemoteCallMSG.REMOTE_CALLOWNER = CALLOWNER.NONE;
@@ -2702,6 +2732,10 @@ public class CallController extends CallManager implements SIPEventListener {
         } finally {
             try {
                 mFileOutputStream.close();
+                //여기서 비트맵 리소스 해제
+                //2023.04.21 jglee 메모리 해제
+                if(bitmap!=null) bitmap.recycle();
+                bitmap = null;
             } catch (IOException e) {
                 Log.e(TAG, "[IOException] saveBMPtoJPG(Bitmap bitmap, String strFilePath)");
                 //e.printStackTrace();

+ 14 - 0
WallPadCall/src/main/java/kr/co/icontrols/callengine/engine/RemoteCallController.java

@@ -22,6 +22,7 @@ import kr.co.icontrols.callengine.remotecall.RemoteCallMSG.REMOTECALLHANDELKEY;
 import kr.co.icontrols.callengine.remotecall.RemoteCallMSG.REMOTECALLMSG;
 import kr.co.icontrols.callengine.remotecall.RemoteCallManager;
 import kr.co.icontrols.wallpadcall.MainActivity;
+import kr.co.icontrols.wallpadcall.declare.DataClasses;
 
 public class RemoteCallController {
 
@@ -153,6 +154,7 @@ public class RemoteCallController {
                     break;
 
                 case REMOTECALLMSG.RECEIVE_EVENT_START_CALL:
+                    //여기서 실제로 모바일 통화 이면
                     receiveStartCalling(msg.getData());
                     break;
 
@@ -213,10 +215,17 @@ public class RemoteCallController {
                 }
             } else if (eCallType == CALLTYPE.LOBBY) {
                 if (eCallOwner == CALLOWNER.NONE) {
+                    //jglee - 2024.09.30 로비가 통화를 받는 경우
+                    //여기세 실제로 TryCall하는것을 해야 한다.
+                    //로비에서 통화 trycall을 해야 함으로 해당 내용 필요
+                    //기존 로비 moip 통화 시, 통화 방식이 변경됨에 따라서 추가 함(jglee - 2024.09.30)
+                    MainActivity.ScreenTalkLobby.send_start_talking_request(DataClasses.RemoteIDInfo.strIP);
                     MainActivity.mCallController.CallScenarioManager(CALLOWNER.MOBILE, CALLEVENTTYPE.CONNECT_CALL, eCallType, null, null, null);
                 }
             } else if (eCallType == CALLTYPE.GUARD) {
                 if (eCallOwner == CALLOWNER.NONE) {
+                    //기존 로비 moip 통화 시, 통화 방식이 변경됨에 따라서 추가 함(jglee - 2024.09.30)
+                    MainActivity.ScreenTalkGuard.TryCall();
                     MainActivity.mCallController.CallScenarioManager(CALLOWNER.MOBILE, CALLEVENTTYPE.CONNECT_CALL, eCallType, null, null, null);
                 }
             }
@@ -276,6 +285,11 @@ public class RemoteCallController {
 
     private void receiveCloseSession(Bundle mBundle) {
         try {
+            if (MainActivity.mCallController.mCallInfo == null) {
+                Log.w(TAG, "[receiveCloseSession] MainActivity.mCallController.mCallInfo is null!!");
+                return;
+            }
+
             CALLTYPE eCallType = CALLTYPE.getCALLTYPE(mBundle.getString(REMOTECALLHANDELKEY.CALLTYPE));
             CALLOWNER eCallOwner = MainActivity.mCallController.mCallInfo.getCallOwner();
             Log.d(TAG, "[receiveCloseSession] eCallType [" + eCallType + "], eCallOwner [" + eCallOwner + "]");

+ 5 - 4
WallPadCall/src/main/java/kr/co/icontrols/callengine/engine/SIPInterface.java

@@ -3017,10 +3017,11 @@ public class SIPInterface {
                 avp.length = size;
                 avp.frameType = IFrame;
                 try {
-//                    Log.d(TAG, "[sendVideoToMobile] mDataSender.que.put()");
-//                    Log.d(TAG, "[sendVideoToMobile] avp.length [" + avp.length + "]");
-                    if (avp != null) MainActivity.mDataSender.blockingQueue.put(avp);
-                } catch (InterruptedException e) {
+                    Log.d(TAG, "[sendVideoToMobile] mDataSender.que.put()");
+                    Log.d(TAG, "[sendVideoToMobile] avp.length [" + avp.length + "]");
+                    //jglee - 2023.02.02 모바일 원격통화로 데이터를 넣는 경우 함수를 이용하여 현재 쓰레드가 종료가 됬는지 확인하기 위해 함수 형태로 변경
+                    if (avp != null) MainActivity.mDataSender.InputData(avp); 
+                } catch (Exception e) {
                     Log.e(TAG, "[InterruptedException] sendVideoToMobile(byte[] data, int size)");
                     //e.printStackTrace();
                     LogUtil.errorLogInfo("", TAG, e);

+ 12 - 6
WallPadCall/src/main/java/kr/co/icontrols/callengine/engine/VideoController.java

@@ -200,6 +200,10 @@ public class VideoController {
 
                             if (bEncoding) {
                                 if (!bEncoderStarted) {
+                                    //2024.09.30 jglee - 현관 통화 추가 부분(기존 월패드랑 다르게 처리)
+                                    videoRTPManager = new VideoRTPManager();
+                                    videoRTPManager.start();
+
                                     bEncoderStarted = true;
                                     MainActivity.mCallController.mVideoJNI.setCheckIFrame(true);
 
@@ -217,9 +221,9 @@ public class VideoController {
                             if (bDecoding) {
                                 if (!bDecoderStarted) {
                                     bDecoderStarted = true;
-                                    //videoRTPManager = new VideoRTPManager();
-                                    //videoRTPManager.start();
-//                                MainActivity.mCallController.mVideoJNI.setComposite(false);
+                                    videoRTPManager = new VideoRTPManager();
+                                    videoRTPManager.start();
+                               // MainActivity.mCallController.mVideoJNI.setComposite(false);
                                     MainActivity.mCallController.mVideoJNI.decoderStartOperation();
                                 }
                             }
@@ -331,11 +335,13 @@ public class VideoController {
                 avp.length = size;
                 avp.frameType = iFrame; // pictype (I-Frame: 0)
                 try {
-//                    Log.d(TAG, "[sendFrontVideoToMobile] mDataSender.que.put()");
-                    MainActivity.mDataSender.blockingQueue.put(avp);
+                    Log.d(TAG, "[sendFrontVideoToMobile] mDataSender.que.put()");
+                    //MainActivity.mDataSender.blockingQueue.put(avp);
+                    //jglee - 2023.02.02 모바일 원격통화로 데이터를 넣는 경우 함수를 이용하여 현재 쓰레드가 종료가 됬는지 확인하기 위해 함수 형태로 변경
+                    if(MainActivity.mDataSender.blockingQueue!=null ) MainActivity.mDataSender.InputData(avp);
                 } catch (RuntimeException re) {
                     LogUtil.errorLogInfo("", TAG, re);
-                } catch (InterruptedException e) {
+                } catch (Exception e) {
                     Log.e(TAG, "[InterruptedException] sendFrontVideoToMobile()");
                     //e.printStackTrace();
                     LogUtil.errorLogInfo("", TAG, e);

+ 145 - 12
WallPadCall/src/main/java/kr/co/icontrols/callengine/remotecall/DataSender.java

@@ -7,6 +7,7 @@ import com.util.LogUtil;
 
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
 
 import kr.co.icontrols.wallpadcall.MainActivity;
 
@@ -16,40 +17,172 @@ public class DataSender extends Thread {
 
     public BlockingQueue<AVPacket> blockingQueue = new LinkedBlockingQueue<AVPacket>();
 
+    // jglee - 2023.02.02 상태종료 flag
+    private boolean mbisClose  = false;
+
+    // jglee - 2023.02.02  거동수상자 녹화 중 호출된 곳이 moip 통화와 front인지를 확인하기 위한 flag
+    /**
+     * 거동수상자 도중, 현관콜이 불렸는지 확인하기 위한 변수(이중 종료를 방지하기 위해 필요)
+     */
+    private boolean isCallFront = false;
+
+    // jglee - 2023.02.02  거동수상자 녹화 중, Front가 호출됬는지 확인하기 위한 함수
+    /**
+     * 거동수상자 도중, 현관콜이 불렸는지 확인하기 위한 변수(이중 종료를 방지하기 위해 필요)
+     * @return
+     */
+    public boolean isCalledFront(){
+        return isCallFront;
+    }
+
+    // jglee - 2023.02.02
+    /**
+     * 거동수상자 도중, 로비콜이 불렸는지 확인하기 위한 변수(이중 종료를 방지하기 위해 필요)
+     */
+    public boolean mbLoobyCalled = false;
+
+    // jglee - 2023.02.02 큐를 이용하여 직접 넣는것이 아닌 함수 이용(데이터를 넣는 경우, 현재 쓰레드가 종료가 됬는지 여부를 확인하기 위해 추가)
+    /**
+     * AVPacket 입력
+     * @param packet 입력 패킷
+     */
+    public void InputData(AVPacket packet)
+    {
+        try
+        {
+            if(blockingQueue!=null && !mbisClose)
+            {
+                blockingQueue.put(packet);
+            }
+        }
+        catch (Exception e)
+        {
+
+        }
+    }
+
+
+
+    // 종료
+    /**
+     * 쓰레드 종료
+     */
+    public void onClose(){
+        mbisClose = true;
+    };
+
+    // jglee - 2023.02.02 거동수상자 녹화 중, 현관이 호출되면 불러야 하는 함수(원격통화 라이브러리가 이중으로 중지되는것을 방지하기 위함)
+    /**
+     * 거동수상자 도중, 현관콜이 불렸는지 확인하기 위한 변수(이중 종료를 방지하기 위해 필요)
+     */
+    public void onCalledFront(){
+        Log.d(TAG, "jglee Remote onCalledFront()");
+        isCallFront = true;
+    }
+
+    // jglee - 2023.02.02 종료 여부 확이하기
+    /**
+     * 쓰레드 종료
+     * @return
+     */
+    public boolean isClose() {
+        Log.d(TAG, "jglee Remote isClose()");
+        boolean temp = mbisClose;
+        return temp;
+    };
+
+
+    /**
+     * 변수 초기화
+     */
+    public void Init()
+    {
+        mbisClose  = false;
+        if(blockingQueue == null)
+            blockingQueue = new LinkedBlockingQueue<AVPacket>();
+    }
+
+    /**
+     * 모바일 전송 종료
+     */
+    protected void Release()
+    {
+        Log.d(TAG, "jglee Remote Release()");
+        //2022.10.27 큐 null 처리
+        if(blockingQueue!=null)
+            blockingQueue.clear();
+        blockingQueue = null;
+
+        //jglee - 2022.10.27 사용한 라이브러리 닫기
+        MainActivity.mRemoteCallController.sendCloseRemoteCall();
+    }
+
     public void run() {
+
         try {
-//            Log.e(TAG, "DataSender =============== [1] ===============");
+            //String currentDate = new SimpleDateFormat("HH:mm:ss z yyyy", Locale.getDefault()).format(new Date());
+            //Log.d(TAG, "CallDataSender : Instance Start Time : " + currentDate);
             VisitorCallLib mVisitorCallLib = VisitorCallLib.getInstance();
+            //currentDate = new SimpleDateFormat("HH:mm:ss z yyyy", Locale.getDefault()).format(new Date());
+            //Log.d(TAG, "CallDataSender : Instance Start Send Packet TIme : " + currentDate);
+//            i= 0;
+//            long Thread_ID = Thread.currentThread().getId();
+//            int ThreadCount = Thread.activeCount();
             for (;;) {
                 try {
-//                    Log.e(TAG, "DataSender =============== [2] ===============");
-                    AVPacket avPacket = blockingQueue.take();
-                    if (mVisitorCallLib != null) {
-//                        Log.e(TAG, "DataSender =============== [3] ===============");
+                    //jglee - 2022.10.27 추가 정상적으로 쓰레드 종료를 위해
+                    //jglee - 2023.01.16 종료되는 시점에 다른 함수들도 실행하지 않기 위해 위치 수정(take이후에서 take 이전으로)
+                    if(mbisClose)
+                    {
+                        break;
+                    }
+
+
+                    AVPacket avPacket = null;
+
+                    if (blockingQueue != null) {
+                        if (!blockingQueue.isEmpty() ) avPacket = blockingQueue.poll(10, TimeUnit.MILLISECONDS);;//blockingQueue.take();
+                    }
+
+//                    if (blockingQueue != null) {
+//                        if ( blockingQueue.size() > 0 ) avPacket = blockingQueue.poll(10, TimeUnit.MILLISECONDS);
+//                    }
+
+
+                    if (avPacket != null && mVisitorCallLib != null) {
+//                        Log.d(TAG, "Count : " + ThreadCount + "ID : " + Thread_ID + ", jglee - CallDataSender********************************************************" + i++);
 //                        Log.d(TAG, "[DataSender.run()] ndkHandle [" + mVisitorCallLib.ndkHandle + "], avType [" + avPacket.avType + "], length [" + avPacket.length + "], frameType [" + avPacket.frameType + "]");
                         int sendMediaResult = mVisitorCallLib.SendMedia(mVisitorCallLib.ndkHandle, avPacket.avType, avPacket.data, avPacket.length, avPacket.frameType);
-//                        Log.d(TAG, "[DataSender.run()] EVENT_sendMediaResult [" + sendMediaResult + "]");
-                        if (sendMediaResult == -2) { // define.SendMediaFail
+                        Log.d(TAG, "[DataSender.run()] EVENT_sendMediaResult [" + sendMediaResult + "]");
+                        if (sendMediaResult == -2) {
+                            // define.SendMediaFail
                             Log.w(TAG, "[DataSender.run()] RemoteCall SendMedia FAIL!!!");
                             MainActivity.mRemoteCallController.sendCloseRemoteCall();
                             break;
                         }
-//                        Log.e(TAG, "DataSender =============== [3-1] ===============");
                     }
+                } catch (RuntimeException re) {
+                    Log.e(TAG, "[RuntimeException] DataSender.run()");
+                    LogUtil.errorLogInfo("", TAG, re);
                 } catch (InterruptedException e) {
-//                    Log.e(TAG, "DataSender =============== [5] ===============");
                     Log.e(TAG, "[InterruptedException] DataSender.run()");
-                    //e.printStackTrace();
                     LogUtil.errorLogInfo("", TAG, e);
                 }
             }
+
+            //2022.10.27 큐 null 처리
+            Release();
+
         } catch (RuntimeException re) {
+            Log.e(TAG, "[RuntimeException] DataSender.run()");
             LogUtil.errorLogInfo("", TAG, re);
+            //jglee - 2023.01.18 예외처리 발생 시, 해당 쓰레드 정상처리를 위해 추가
+            Release();
         } catch (Exception e) {
-//            Log.e(TAG, "DataSender =============== [6] ===============");
             Log.e(TAG, "[Exception] DataSender.run()");
-            //e.printStackTrace();
             LogUtil.errorLogInfo("", TAG, e);
+            //jglee - 2023.01.18 예외처리 발생 시, 해당 쓰레드 정상처리를 위해 추가
+            Release();
         }
     }
 }

+ 49 - 2
WallPadCall/src/main/java/kr/co/icontrols/callengine/remotecall/RemoteCallManager.java

@@ -47,6 +47,7 @@ import kr.co.icontrols.callengine.remotecall.RemoteCallMSG.REMOTECALL_CALLER;
 import kr.co.icontrols.callengine.remotecall.RemoteCallMSG.REMOTECALL_CALLOWNER;
 import kr.co.icontrols.callengine.remotecall.RemoteCallMSG.REMOTECALL_CALLTYPE;
 import kr.co.icontrols.callengine.sip.SIPStun;
+import kr.co.icontrols.wallpadcall.MainActivity;
 import kr.co.icontrols.wallpadcall.declare.DataClasses.GuardListTable;
 import kr.co.icontrols.wallpadcall.declare.DataClasses.RemoteIDInfo;
 import kr.co.icontrols.wallpadcall.declare.Declare;
@@ -69,6 +70,8 @@ public class RemoteCallManager extends Service implements VisitorCallLib.Callbac
 
     GuardListTable mGuardListTable = null; // 경비실기 목록
 
+    boolean bBLOCK_REQUEST_CALL = false;   // 원격통화 요청 거절 flag, 원격통화가 종료된 후에 백그라운드 리소스 정리중 요청이 오면 꼬임 (true: 거절, false: 수락)
+
     @Override
     public IBinder onBind(Intent intent) {
         return mMessenger.getBinder();
@@ -270,6 +273,20 @@ public class RemoteCallManager extends Service implements VisitorCallLib.Callbac
         }
     }
 
+    private void setBlockRemoteCall() {
+        try {
+            bBLOCK_REQUEST_CALL = true;
+            VisitorCallEventHandler.removeMessages(VisitorCallEvent.RELEASE_BLOCK_REQUEST_CALL);
+            sendHandlerMsgDelayed(VisitorCallEvent.RELEASE_BLOCK_REQUEST_CALL, 0, 0, 5000);
+        } catch (RuntimeException re) {
+            Log.e(TAG, "[RuntimeException] setBlockRemoteCall()");
+            LogUtil.errorLogInfo("", TAG, re);
+        } catch (Exception e) {
+            Log.e(TAG, "[Exception] setBlockRemoteCall()");
+            LogUtil.errorLogInfo("", TAG, e);
+        }
+    }
+
 
     /************************************************************
      *
@@ -353,6 +370,17 @@ public class RemoteCallManager extends Service implements VisitorCallLib.Callbac
         try {
             Log.d(TAG, "[EVENT_RequestMonitor] handle [" + handle + "], device [" + device + "], caller [" + caller + "]");
             Log.d(TAG, "[EVENT_RequestMonitor] bWallPadCallLive [" + SIPStun.bWallPadCallLive + "]");
+
+            //jglee - 2024.06.20 남창우 차장님이 작업한 모바일 통화 종료 코드 가져오기(2022.08.26 작업 내용)
+            if (bBLOCK_REQUEST_CALL) {
+                // 모바일 통화 종료후, 후처리 진행중
+                Log.w(TAG, "[EVENT_RequestMonitor] Blocked remotecall!! bBLOCK_REQUEST_CALL [" + bBLOCK_REQUEST_CALL +"]");
+                Object obj = handle;
+                Message message = VisitorCallEventHandler.obtainMessage(VisitorCallEvent.EVENT_REQUEST_MONITOR_ERR, obj);
+                VisitorCallEventHandler.sendMessage(message);
+                return -1;
+            }
+
             if (!SIPStun.bWallPadCallLive && mHandle == -1) {
                 // 모바일 요청 성공
                 mVisitorCallLib.ndkHandle = mHandle = handle;
@@ -607,6 +635,7 @@ public class RemoteCallManager extends Service implements VisitorCallLib.Callbac
         public final int EVENT_OTHEREVENT = 8;
         public final int EVENT_REQUEST_MONITOR_ERR = 9;
         public final int EVENT_CLOSED_SESSION = 10;
+        public final int RELEASE_BLOCK_REQUEST_CALL = 1000;
     }
 
     int mHandle = -1;
@@ -616,7 +645,7 @@ public class RemoteCallManager extends Service implements VisitorCallLib.Callbac
         public void handleMessage(Message msg) {
             super.handleMessage(msg);
             try {
-//                Log.d(TAG, "[VisitorCallEventHandler] msg.what [" + msg.what + "]");
+                Log.d(TAG, "[VisitorCallEventHandler] msg.what [" + msg.what + "]");
                 if (msg.what == VisitorCallEvent.EVENT_REQUEST_MONITOR) {
                     String device = (String) msg.obj;
                     if (device.equals(REMOTECALL_CALLTYPE.CALLTYPE_DOOR)) {
@@ -630,6 +659,18 @@ public class RemoteCallManager extends Service implements VisitorCallLib.Callbac
                     }
                 } else if (msg.what == VisitorCallEvent.EVENT_START_CALLING) {
                     Log.d(TAG, "[VisitorCallEventHandler] REMOTE_CALLTYPE [" + RemoteCallMSG.REMOTE_CALLTYPE + "]");
+                    //jglee - 2023.02.02 여기서 해당 Sender가 종료되면 정지
+                    if(MainActivity.mDataSender!=null && MainActivity.mDataSender.isClose())
+                    {
+                        Log.d(TAG, "[VisitorCallEventHandler] Sender Close");
+                        return;
+                    }
+                    //jglee - 2023.02.02 여기서 통화가 걸려오는 경우나, 거동수상자 녹화중일 경우만 사용할 수 있도록 체크
+                    if(MainActivity.mCallController.mCallInfo.getCalledCnt() == 0  && !Global.getRecordingStatus() && MainActivity.mCallController.mCallInfo.getFRONT() != CALLSTATUS.CALLING)
+                    {
+                        Log.d(TAG, "[VisitorCallEventHandler] CheckCalled and StrangeRecord");
+                        return;
+                    }
                     if (RemoteCallMSG.REMOTE_CALLTYPE != CALLTYPE.NONE) sendMsgToRemoteMsns(REMOTECALLMSG.RECEIVE_EVENT_START_CALL, RemoteCallMSG.REMOTE_CALLTYPE);
                 } else if (msg.what == VisitorCallEvent.EVENT_AUDIO_DATA) {
                     AVPacket avp = (AVPacket) msg.obj;
@@ -649,6 +690,7 @@ public class RemoteCallManager extends Service implements VisitorCallLib.Callbac
                         sendHandlerMsg(HANDLERMSG.GET_USERLIST, 0, 0, phoneKey);
                     }
                 } else if (msg.what == VisitorCallEvent.EVENT_CLOSED_SESSION || msg.what == VisitorCallEvent.EVENT_REQUEST_MONITOR_ERR) {
+                    if (msg.what == VisitorCallEvent.EVENT_CLOSED_SESSION) setBlockRemoteCall();
                     int handle = (int) msg.obj;
                     if (mVisitorCallLib != null) {
                         Log.d(TAG, "[VisitorCallEventHandler] EVENT_CLOSED_SESSION handle [" + handle + "]");
@@ -671,6 +713,10 @@ public class RemoteCallManager extends Service implements VisitorCallLib.Callbac
                             }
                         }
                     }
+                    bBLOCK_REQUEST_CALL = false;
+                }
+                else if (msg.what == VisitorCallEvent.RELEASE_BLOCK_REQUEST_CALL) {
+                    bBLOCK_REQUEST_CALL = false;
                 }
             } catch (RuntimeException re) {
                 LogUtil.errorLogInfo("", TAG, re);
@@ -958,6 +1004,8 @@ public class RemoteCallManager extends Service implements VisitorCallLib.Callbac
             List<String[]> GuardList = null;
             WallpadDeviceSet deviceSet = new WallpadDeviceSet(getApplicationContext());
             GuardList = deviceSet.GetGuardList();
+            deviceSet.closeDB();
+
             mGuardListTable = new GuardListTable();
             mGuardListTable.clearTable();
             Log.d(TAG, "[getGuardList] GuardList.size [" + GuardList.size() + "]");
@@ -966,7 +1014,6 @@ public class RemoteCallManager extends Service implements VisitorCallLib.Callbac
                 Log.d(TAG, "[getGuardList] GuardList [" + i + "] = " + GuardList.get(i)[0]);
                 mGuardListTable.addGuardTable(GuardList.get(i)[0], Global.makeGuardIP(GuardList.get(i)[1]), null);
             }
-            deviceSet.closeDB();
 
             int nGuardCnt = mGuardListTable.getCnt();
             if (nGuardCnt > 0) {

+ 57 - 2
WallPadCall/src/main/java/kr/co/icontrols/wallpadcall/MainActivity.java

@@ -100,6 +100,7 @@ import kr.co.icontrols.callengine.history.CallHistoryManager;
 import kr.co.icontrols.callengine.history.VisitorPictureHistoryManager;
 import kr.co.icontrols.callengine.pstn.ATCmds.PSTNHANDLERMSG;
 import kr.co.icontrols.callengine.pstn.PSTNController;
+import kr.co.icontrols.callengine.remotecall.AVPacket;
 import kr.co.icontrols.callengine.remotecall.DataSender;
 import kr.co.icontrols.callengine.sip.SIPController;
 import kr.co.icontrols.callengine.sip.SIPStun;
@@ -313,8 +314,8 @@ public class MainActivity extends WpadActivity {
 
     // Screen
     private TalkFront ScreenTalkFront = null;   // 현관통화
-    private TalkLobby ScreenTalkLobby = null;   // 로비통화
-    private TalkGuard ScreenTalkGuard = null;   // 경비실통화
+    public static TalkLobby ScreenTalkLobby = null;   // 로비통화
+    public static TalkGuard ScreenTalkGuard = null;   // 경비실통화
     private TalkResidence ScreenTalkResidence = null;   // 세대통화
     private TalkPSTN ScreenTalkPSTN = null;   // 국선통화
     private InquiryCallHistory ScreenInquiryCallHistory = null;   // 통화내역
@@ -2444,6 +2445,8 @@ public class MainActivity extends WpadActivity {
                 if (ConfigValues.bSubPhoneEnable) mSubPhoneController.releaseSubPhoneController();
                 if (ConfigValues.bRemoteCall) {
                     mRemoteCallController.releaseRemoteCallController();
+                    //2022.10.27 jglee - 해당 쓰레드 정상 종료를 위해 코드 추가
+                    mDataSender.onClose();
                     mDataSender.interrupt();
                     mDataSender = null;
                 }
@@ -6826,7 +6829,9 @@ public class MainActivity extends WpadActivity {
 
                     m_bUDPRECV = true;
                     //m_MediaDecoder.decodeSample(buf1, 0, buf1.length, 0, 0);
+                    //jglee - 2024.09.27
                     MainActivity.mCallController.mVideoJNI.sendDataToDecoder(buf1,0,buf1.length,0);
+                    if (ConfigValues.bRemoteCall)sendVideoToMobile(buf1, buf1.length, isH264iFrame(buf1, buf1.length));
                     //buf[12] = 0x00;
                     //buf[13] = 0x00;
 
@@ -6880,6 +6885,56 @@ public class MainActivity extends WpadActivity {
         }
     }
 
+    public int isH264iFrame(byte[] data, int size) {
+//            Log.d(TAG, "[isH264iFrame] data [" + Global.HexToString(data) + "], size [" + size + "]");
+        int index = 0;
+        for (; index + 3 < size; index++) {
+            // This should always succeed in the first iteration.
+            if (data[index] == 0 && data[index + 1] == 0 && data[index + 2] == 1)
+                break;
+        }
+
+        if (index + 3 >= size) return 0;
+        index += 3;
+
+        int nalType = data[index] & 0x1F;
+        if (nalType == 0x05 || nalType == 0x07 || nalType == 0x08)
+            return 1;
+
+        return 2;
+    }
+    
+    public void sendVideoToMobile(byte[] data, int size, int IFrame) {
+        try {
+//            Log.d(TAG, "[sendVideoToMobile] data.length [" + data.length + "], size [" + size + "], IFrame [" + IFrame + "]");
+            if (MainActivity.mDataSender != null) {
+                AVPacket avp = new AVPacket();
+                avp.avType = 0; // 0:video, 1:audio
+                avp.data = data;
+                avp.length = size;
+                avp.frameType = IFrame;
+                try {
+                    Log.d(TAG, "[sendVideoToMobile] mDataSender.que.put()");
+                    Log.d(TAG, "[sendVideoToMobile] avp.length [" + avp.length + "]");
+                    //jglee - 2023.02.02 모바일 원격통화로 데이터를 넣는 경우 함수를 이용하여 현재 쓰레드가 종료가 됬는지 확인하기 위해 함수 형태로 변경
+                    if (avp != null) MainActivity.mDataSender.InputData(avp);
+                } catch (Exception e) {
+                    Log.e(TAG, "[InterruptedException] sendVideoToMobile(byte[] data, int size)");
+                    //e.printStackTrace();
+                    LogUtil.errorLogInfo("", TAG, e);
+                }
+            } else {
+                Log.w(TAG, "[sendVideoToMobile] mDataSender is null!!");
+            }
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+        } catch (Exception e) {
+            Log.e(TAG, "[Exception] sendVideoToMobile(byte[] data)");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+        }
+    }
+
 
 
 }

+ 9 - 0
WallPadCall/src/main/java/kr/co/icontrols/wallpadcall/screen/TalkGuard.java

@@ -1247,6 +1247,15 @@ public class TalkGuard extends WpadScreen implements CallEventListener, MainEven
         }
     }
 
+    /**
+     * 2024.09.30 통화 시작
+     */
+    public void TryCall()
+    {
+        mySocket s = new mySocket(RemoteIDInfo.strIP, "I_AM_TALKING");
+        s.start();
+    }
+
     private void doEnd() {
         try {
             if (MainActivity.mCallController.mCallInfo.getIDLECnt() != MainActivity.mCallController.mCallInfo.IDLECNT_MAX) {

+ 2 - 1
WallPadCall/src/main/java/kr/co/icontrols/wallpadcall/screen/TalkLobby.java

@@ -1972,7 +1972,8 @@ public class TalkLobby extends WpadScreen implements CallEventListener, MainEven
         }
     }
 
-	private boolean send_start_talking_request(String strTargetIP) {
+    //2024.09.30 jglee - 외부에서 호출 할 수 있도록 변경
+	public boolean send_start_talking_request(String strTargetIP) {
 
         LOG_INFO("[send_start_talking_request] strTargetIP() "+ RemoteIDInfo.strDong + " " + RemoteIDInfo.strHo);
         mySocket s = new mySocket(RemoteIDInfo.strIP, "I_AM_TALKING");