/*
 *
 * SOUND DEVICE CONTROL FRAME
 * Copyright 2011-2012 KWANGHAESOFT LTD.
 * Creator: JGK
 * PUBLISH DATE: Dec. 2011
 *
 *............................................
 * Compact Type :Checked - not related.
 * Date:2012 04 27
 * ............................................
 *
 */
package cm.sip.hns;

import android.annotation.SuppressLint;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioRecord;
import android.media.AudioTrack;
import android.media.MediaRecorder;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

import java.util.Date;

import milsip.stack.sip.SIPG711;
import milsip.stack.sip.SIPStack;
import kr.co.icontrols.ilp300_700.MainActivity;
import kr.co.icontrols.ilp300_700.call.CallManager.REMOTECALLOWNER;

public class SIPSound {

    static String TAG = "SIPSound";

    public static AudioManager amAudioManager = null;
    public static boolean bSpeaker = false;
    public static boolean bSpeakerLock = false;
    public static boolean playStarted = false;
    public static int BULK_SIZE = 384;
    protected static short[] dmaShortBuffer = null;

    static int BUFFER_COUNT = 3;
    static int BUFFER_SIZE = 8000;
    static int DMA_SIZE = 800;
    static int BUFFER_PLAY_INDEX = 0;
    static int BUFFER_BUFFERREDSIZE = 0;
    static byte[] captureBuffer = null;
    static byte[] dmaBuffer = null;
    static byte[] comportableNoise = null;
    static int PTIME = 20;
    static boolean recorderStarted = false;
    static AudioRecord recorder = null; //2012 09 28  ->static
    static AudioTrack track = null; //2012 09 28  ->static
    static int SOUND_TYPE_DEFAULT = 0;
    static int SOUND_TYPE_TELEPHONE = 1;
    static int SOUND_TYPE_MUSIC = 2;
    static boolean bActive = false;
    static boolean CAPTURE_DATA_TYPE_IS_BYTE = false;   //false:short true:byte
    static int remotePayloadType = SIPStack.SIP_CODEC_G711U;

    boolean running = false;
    Thread captureThread = null;
    int databufferredSize = 0;
    boolean bCaptureBufferLock = false;
    int flowIndicator = SIPStack.SIP_MEDIAFLOW_SENDRECV;
    byte[] lineardata = new byte[1024];   //320
    byte[] bulkdata = new byte[1024];

    private final static int AUDIO_MODE_NORMAL = AudioManager.MODE_NORMAL;              // Normal: 0(초기화)

    private final static int AUDIO_MODE_MOIP_GUARD = 12;                                // 경비통화: 12
    private final static int AUDIO_MODE_MOIP_RESIDENCE = AudioManager.MODE_RINGTONE;    // 세대통화: 1

    public SIPSound() {
        // throws LineUnavailableException
        BUFFER_PLAY_INDEX = 0;
        BUFFER_BUFFERREDSIZE = 0;
        bActive = false;

        DMA_SIZE = AudioRecord.getMinBufferSize(8000, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT);

        dmaBuffer = new byte[DMA_SIZE];
        dmaShortBuffer = new short[DMA_SIZE / 2];
        // dma729Buffer        = new short[DMA_SIZE/2];

        BUFFER_SIZE = DMA_SIZE;
        captureBuffer = new byte[BUFFER_SIZE];
        comportableNoise = new byte[BUFFER_SIZE];
        Log.i(TAG, "BUFFER_SIZE : " + BUFFER_SIZE);

        SIPG711.getPCMLinearComportableNoise(comportableNoise, BUFFER_SIZE);

        recorder = null;
        track = null;
        recorderStarted = false;
        playStarted = false;
        bSpeaker = false;
        bSpeakerLock = false;
    }

    public static void initRoute() {
        if (SIPSound.amAudioManager != null) {
            SIPSound.amAudioManager.setRouting(AudioManager.MODE_CURRENT, AudioManager.ROUTE_EARPIECE, AudioManager.ROUTE_ALL);
            SIPSound.amAudioManager.setRouting(AudioManager.MODE_NORMAL, AudioManager.ROUTE_EARPIECE, AudioManager.ROUTE_ALL);

            SIPSound.amAudioManager.setRouting(AudioManager.MODE_RINGTONE, AudioManager.ROUTE_EARPIECE, AudioManager.ROUTE_ALL);
            SIPSound.amAudioManager.setRouting(AudioManager.MODE_IN_CALL, AudioManager.ROUTE_EARPIECE, AudioManager.ROUTE_ALL);

            if (amAudioManager != null) {
                amAudioManager.setMicrophoneMute(false);
                amAudioManager.setSpeakerphoneOn(false); // 초기화
                if (MainActivity.mCallController.mCallInfo != null) {
                    if (MainActivity.mCallController.mCallInfo.geteRemoteCallOwner() == REMOTECALLOWNER.GUARD) {
                        Log.w(TAG, "[initRoute] setMode(AUDIO_MODE_MOIP_GUARD) [" + AUDIO_MODE_MOIP_GUARD + "]");
                        amAudioManager.setMode(AUDIO_MODE_MOIP_GUARD);
                    } else if (MainActivity.mCallController.mCallInfo.geteRemoteCallOwner() == REMOTECALLOWNER.RESIDENCE) {
                        Log.w(TAG, "[initRoute] setMode(AUDIO_MODE_MOIP_RESIDENCE) [" + AUDIO_MODE_MOIP_RESIDENCE + "]");
                        amAudioManager.setMode(AUDIO_MODE_MOIP_RESIDENCE);
                    } else {
                        Log.w(TAG, "[initRoute] Invalid RemoteCallOwner [" + MainActivity.mCallController.mCallInfo.geteRemoteCallOwner() + "]");
//                        mHandler.sendEmptyMessage(0);
                    }
                } else {
                    Log.w(TAG, "[initRoute] MainActivity.mCallController.mCallInfo is null!!");
                }

                // 초기화시 setMode(0)
                Log.w(TAG, "[initRoute] setMode(AUDIO_MODE_NORMAL) [" + AUDIO_MODE_NORMAL + "]");
                amAudioManager.setMode(AUDIO_MODE_NORMAL);
                amAudioManager.setSpeakerphoneOn(false);
            }
            // SIPSound.setSpeakerRoute(false);
        }
    }

    public static void resetDevice() {
        if (track != null) {
            playStarted = false;
            track.pause();
            track = null;
        }

        if (recorder != null) {
            recorderStarted = false;
            recorder.stop();
            //recorder.release();
            recorder = null;
        }
    }

    protected static void resetAudioTrack() {
        // Log.i(TAG, ">>>>>>>>>>>>>>>>>>>>>RESETAUDIOTRACK ++++++++++");

        if (playStarted) return;
        if (track != null) {
            track.pause();
            track.release();
            track = null;
        }
        playStarted = false;
        bActive = false;

        if (MainActivity.mCallController.mCallInfo != null) {
            if (MainActivity.mCallController.mCallInfo.geteRemoteCallOwner() == REMOTECALLOWNER.GUARD) {
                if (amAudioManager != null) {
                    Log.w(TAG, "[resetAudioTrack] setMode(AUDIO_MODE_MOIP_GUARD) [" + AUDIO_MODE_MOIP_GUARD + "]");
                    amAudioManager.setMode(AUDIO_MODE_MOIP_GUARD);
                }
            }
            else if (MainActivity.mCallController.mCallInfo.geteRemoteCallOwner() == REMOTECALLOWNER.RESIDENCE) {
                if (amAudioManager != null) {
                    Log.w(TAG, "[resetAudioTrack] setMode(AUDIO_MODE_MOIP_RESIDENCE) [" + AUDIO_MODE_MOIP_RESIDENCE + "]");
                    amAudioManager.setMode(AUDIO_MODE_MOIP_RESIDENCE);
                }
            } else {
                Log.w(TAG, "[resetAudioTrack] Invalid RemoteCallOwner [" + MainActivity.mCallController.mCallInfo.geteRemoteCallOwner() + "]");
                mHandler.sendEmptyMessage(0);
            }
        } else {
            Log.w(TAG, "[resetAudioTrack] MainActivity.mCallController.mCallInfo is null");
        }

        if (track == null) {   // bulk case
            int minSize = AudioTrack.getMinBufferSize(8000, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT);
            int playbufferSize = minSize * 2;

            track = new AudioTrack(AudioManager.STREAM_VOICE_CALL, 8000, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, playbufferSize, AudioTrack.MODE_STREAM);   // original
        }
        if (track != null) {
            playStarted = true;
        }
        bSpeakerLock = false;
        // Log.i(TAG, ">>>>>>>>>>>>>>>>>>>>>RESETAUDIOTRACK ++++++++++END");
        return;
    }

    public static void resetBufferInfo() {
        try {
            Log.i(TAG, "[resetBufferInfo] SIPSound::  resetBufferInfo");
            BUFFER_PLAY_INDEX = 0;
            BUFFER_BUFFERREDSIZE = 0;
            if (track != null) track.flush();
        } catch (Exception e) {
            Log.e(TAG, "[Exception] resetBufferInfo()");
        }
        return;
    }

    public static void setSpeakerRoute(boolean out) {
        bSpeakerLock = true;
        try {
            if (out) {
                amAudioManager.setSpeakerphoneOn(true);
                bSpeaker = true;
            } else {
                amAudioManager.setSpeakerphoneOn(false);
                bSpeaker = false;
            }

            if (track != null && track.getPlayState() == AudioTrack.PLAYSTATE_PLAYING) {
                resetAudioTrack();
            }
        } catch (Exception e) {
            Log.e(TAG, "[Exception] setSpeakerRoute(boolean out)");
        }
        bSpeakerLock = false;
    }

    public void captureAudio() {
        // throws LineUnavailableException
        // Log.i(TAG, ">>>>>>>>>>>>>>>>>>>>>CAPTUREAUDIO ++++++++++");
        if (!recorderStarted) {
            captureThread = new Thread() {
                //@Override
                public void run() {
                    if (recorder == null) {
                        // work normal
                        recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, 8000, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, DMA_SIZE);
                    }

                    if (recorder != null) {
                        try {
                            int frames = DMA_SIZE / 2;
                            // int frames = 160;
                            recorder.setPositionNotificationPeriod(frames);   // duration(��)*samplerate(8000)
                            recorder.setRecordPositionUpdateListener(new AudioRecord.OnRecordPositionUpdateListener() {
                                //@Override
                                public void onPeriodicNotification(AudioRecord recorder) {

                                    try {
                                        if (recorderStarted == false) {
                                            if (track != null && playStarted) {
                                                playStarted = false;
                                            }

                                            if (recorder != null && recorderStarted) {
                                                recorderStarted = false;
                                            }
                                            bActive = false;
                                            return;
                                        }

                                        int frames = DMA_SIZE / 2;
                                        int count = recorder.read(dmaShortBuffer, 0, frames);
                                        bufferring(dmaShortBuffer, count);

                                    } catch (Exception e) {
                                        Log.e(TAG, "[Exception] captureAudio().run().onPeriodicNotification  ===== 1 =====");
                                    }
                                }

                                // @Override
                                public void onMarkerReached(AudioRecord recorder) {

                                }
                            });

                            recorderStarted = true;
                            recorder.startRecording();
                            recorder.read(dmaShortBuffer, 0, frames);

                        } catch (IllegalStateException e) {
                            Log.e(TAG, "[IllegalStateException] captureAudio().run() ===== 2 =====");
                            if (track != null && playStarted) {
                                playStarted = false;
                            }

                            if (recorder != null && recorderStarted) {
                                recorderStarted = false;
                            }

                            bActive = false;
                            return;
                        } catch (Exception e1) {
                            Log.e(TAG, "[Exception] captureAudio().run() ===== 3 =====");
                            if (track != null && playStarted) {
                                playStarted = false;
                            }

                            if (recorder != null && recorderStarted) {
                                recorderStarted = false;
                            }

                            bActive = false;
                            return;
                        }

                        try {
                            while (recorderStarted) {
                                if (isInterrupted()) {
                                    if (track != null && playStarted) {
                                        playStarted = false;
                                    }

                                    if (recorder != null && recorderStarted) {
                                        recorderStarted = false;
                                    }

                                    bActive = false;
                                    break;
                                }
                                Thread.sleep(1000);
                            }
                        } catch (Exception e) {
                            SIPStack.exceptionCountAtCurrentCall++;
                            Log.e(TAG, "[Exception] captureAudio().run() ===== 4 =====");
                        }

                        if (track != null && playStarted) {
                            playStarted = false;
                        }

                        if (recorder != null && recorderStarted) {
                            recorderStarted = false;
                        }
                        bActive = false;
                    }
                }
            };
            // captureThread.setPriority(1);
            captureThread.start();
            recorderStarted = true;
            // Log.e(TAG, ">>>>>>>>>>>>>>>>>>>>>CAPTUREAUDIO ++++++++++END");
        }
    }

    public void closeAudioDevice() {
        try {
            // Log.i(TAG, "[closeAudioDevice]  CLOSEAUDIODEVICE CAPTURE++++++++++");
            // setSpeakerRoute(false);
            if (recorder != null) {   // && recorderStarted)
                recorderStarted = false;
                recorder.stop();
                if (captureThread == null) Log.w(TAG, "[closeAudioDevice] captureThread is null!!");
                Log.w(TAG, "[closeAudioDevice] captureThread.isAlive() = " + captureThread.isAlive());
                Log.w(TAG, "[closeAudioDevice] captureThread.isInterrupted() = " + captureThread.isInterrupted());
                if (captureThread != null && captureThread.isAlive() && !captureThread.isInterrupted()) {
                    captureThread.interrupt();
                }

                if (recorder != null) {
                    recorder.release();
                }
                recorder = null;
            }

            // Log.i(TAG, ">>>>>>>>>>>>>>>>>>>>>CLOSEAUDIODEVICE CAPTURE++++++++++END");

            if (amAudioManager != null) {
                boolean bSpeakOn = amAudioManager.isSpeakerphoneOn();
                Log.d(TAG, "[closeAudiDevice] before *** bSpeakOn = " + bSpeakOn);
                Log.w(TAG, "[closeAudioDevice] setMode(AUDIO_MODE_NORMAL) [" + AUDIO_MODE_NORMAL + "]");
                amAudioManager.setMode(AUDIO_MODE_NORMAL);
                amAudioManager.setSpeakerphoneOn(false); // 통화 종료시 초기화
                bSpeakOn = amAudioManager.isSpeakerphoneOn();
                Log.d(TAG, "[closeAudiDevice] after ***  bSpeakOn = " + bSpeakOn);
            }
        } catch (Exception e) {
//		     Log.e(TAG, "[Exception] closeAudioDevice() --> CLOSEAUDIODEVICE CAPTURE++++++++++EXCEPTION");
            Log.e(TAG, "[Exception] closeAudioDevice() -> CLOSEAUDIODEVICE CAPTURE");
            e.printStackTrace();
        }

        try {
            // Log.i(TAG, ">>>>>>>>>>>>>>>>>>>>>CLOSEAUDIODEVICE TRACK++++++++++");
            if (track != null) {   // && playStarted)
                playStarted = false;
                track.pause();
            } else if (track != null) {   // && track.getState()==AudioTrack.PLAYSTATE_PLAYING)
                track.pause();
            }

            if (track != null) {
                track.release();
            }
            track = null;
            // Log.i(TAG, ">>>>>>>>>>>>>>>>>>>>>CLOSEAUDIODEVICE TRACK++++++++++END");

            // if (amAudioManager != null) amAudioManager.setMode(AudioManager.MODE_NORMAL);
        } catch (Exception e) {
//		     Log.e(TAG, "[Exception] closeAudioDevice() --> CLOSEAUDIODEVICE TRACK++++++++++EXCEPTION");
            Log.e(TAG, "[Exception] closeAudioDevice() -> CLOSEAUDIODEVICE TRACK");
            e.printStackTrace();
        }
        return;
    }

    public void closeCaptureDevice() {
        try {
            Log.w(TAG, "[closeAudioDevice] ===== START =====");
            // Log.i(TAG, ">>>>>>>>>>>>>>>>>>>>>CLOSEAUDIODEVICE CAPTURE++++++++++");
            // setSpeakerRoute(false);

            if (recorder != null) {   // && recorderStarted)
                recorderStarted = false;
                recorder.stop();
                if (captureThread != null && captureThread.isAlive() && !captureThread.isInterrupted()) {
                    captureThread.interrupt();
                }

                if (recorder != null) {
                    recorder.release();
                }
                recorder = null;
            }

            if (amAudioManager != null) {
//                Log.d(TAG, "[setMode] ========== MODE_NORMAL ==========");
                Log.w(TAG, "[closeCaptureDevice] setMode(AUDIO_MODE_NORMAL) [" + AUDIO_MODE_NORMAL + "]");
                amAudioManager.setMode(AUDIO_MODE_NORMAL);
                amAudioManager.setSpeakerphoneOn(false);
            }
        } catch (Exception e) {
            Log.e(TAG, "[Exception] closeCaptureDevice() --> CLOSEAUDIODEVICE CAPTURE");
            e.printStackTrace();
        }
        return;
    }

    @SuppressLint("InlinedApi")
    public void prepareAudioTrack() {
        try {
            // Log.i(TAG", ">>>>>>>>>>>>>>>>>>>>>PREPAREAUDIOTRACK ++++++++++");
            if (playStarted) return;
            if (MainActivity.mCallController.mCallInfo != null) {
                if (MainActivity.mCallController.mCallInfo.geteRemoteCallOwner() == REMOTECALLOWNER.GUARD) {
                    if (amAudioManager != null) {
                        Log.w(TAG, "[prepareAudioTrack] setMode(AUDIO_MODE_MOIP_GUARD) [" + AUDIO_MODE_MOIP_GUARD + "]");
                        amAudioManager.setMode(AUDIO_MODE_MOIP_GUARD);
                    }
                } else if (MainActivity.mCallController.mCallInfo.geteRemoteCallOwner() == REMOTECALLOWNER.RESIDENCE) {
                    if (amAudioManager != null) {
                        Log.w(TAG, "[prepareAudioTrack] setMode(AUDIO_MODE_MOIP_RESIDENCE) [" + AUDIO_MODE_MOIP_RESIDENCE + "]");
                        amAudioManager.setMode(AUDIO_MODE_MOIP_RESIDENCE);
                    }
                } else {
                    Log.w(TAG, "[prepareAudioTrack] Invalid RemoteCallOwner [" + MainActivity.mCallController.mCallInfo.geteRemoteCallOwner() + "]");
                    mHandler.sendEmptyMessage(0);
                }
            } else {
                Log.w(TAG, "[prepareAudioTrack] MainActivity.mCallController.mCallInfo is null!!");
            }

            // bulk case
            int minSize = AudioTrack.getMinBufferSize(8000, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT);
            int playbufferSize = minSize * 2;

            track = new AudioTrack(AudioManager.STREAM_VOICE_CALL, 8000, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, playbufferSize, AudioTrack.MODE_STREAM);   // original

            if (track != null) {
                playStarted = true;
                bActive = true;
            }
            bSpeakerLock = false;
            // Log.i(TAG, ">>>>>>>>>>>>>>>>>>>>>PREPAREAUDIOTRACK ++++++++++END");
        } catch (Exception e) {
            Log.e(TAG, "[Exception] prepareAudioTrack() --> PREPAREAUDIOTRACK ++++++++++EXCEPTION");
        }
        return;
    }

    public void playAudio(byte[] data, int dataSize) {
        if (bSpeakerLock) return;
        if (track != null && playStarted) {
            if (bActive == false) {
                return;
            }

            try {
                track.write(data, 0, dataSize);
                if (track != null) {
                    track.play();
                } else {
                    // bulk case
                    int minSize = AudioTrack.getMinBufferSize(8000, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT);
                    int playbufferSize = minSize * 2;

                    track = new AudioTrack(AudioManager.STREAM_VOICE_CALL, 8000, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, playbufferSize, AudioTrack.MODE_STREAM);
                    if (track != null) {
                        playStarted = true;
                        bActive = true;
                    }
                }
            } catch (Exception e) {
                Log.e(TAG, "[Exception] playAudio(byte[] data, int dataSize) --> BSS DEBUG: TRACK PLAY ERROR");
                e.printStackTrace();
            }
        }
        return;
    }

    public void playAudio(short[] data, int dataSize) {
        if (bSpeakerLock) return;
        if (track != null && playStarted) {
            if (bActive == false) {
                return;
            }

            try {
                track.write(data, 0, dataSize);
                if (track != null) {
                    track.play();
                } else {
                    // bulk case
                    int minSize = AudioTrack.getMinBufferSize(8000, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT);
                    int playbufferSize = minSize * 2;

                    track = new AudioTrack(AudioManager.STREAM_VOICE_CALL, 8000, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, playbufferSize, AudioTrack.MODE_STREAM);   // original
                    if (track != null) {
                        playStarted = true;
                        bActive = true;
                    }
                }
            } catch (Exception e) {
                Log.e(TAG, "[Exception] playAudio(short[] data, int dataSize) --> BSS DEBUG: TRACK PLAY ERROR");
                System.err.println(e);
            }
        }
        return;
    }

    public void bufferring(byte[] data, int datasize) {
        bCaptureBufferLock = true;
        if (data == null || datasize <= 0) {
            bCaptureBufferLock = false;
            return;
        }

        if (BUFFER_BUFFERREDSIZE + datasize > BUFFER_SIZE) {
            BUFFER_PLAY_INDEX = 0;
            BUFFER_BUFFERREDSIZE = 0;
        }

        int savePos = (BUFFER_PLAY_INDEX + BUFFER_BUFFERREDSIZE) % BUFFER_SIZE;
        int bufferTrail = BUFFER_SIZE - savePos;

        if (bufferTrail < datasize) {
            System.arraycopy(data, 0, captureBuffer, savePos, bufferTrail);
            System.arraycopy(data, bufferTrail, captureBuffer, 0, datasize - bufferTrail);
        } else {
            System.arraycopy(data, 0, captureBuffer, savePos, datasize);
        }
        BUFFER_BUFFERREDSIZE += datasize;
        bCaptureBufferLock = false;

        if (flowIndicator == SIPStack.SIP_MEDIAFLOW_SENDONLY) {
            playAudio(comportableNoise, datasize);
        }
        return;
    }

    public void bufferring(short[] data, int datasize) {
        bCaptureBufferLock = true;
        if (data == null || datasize <= 0) {
            bCaptureBufferLock = false;
            return;
        }

        int packetsize = 0;

        //if (remotePayloadType == SIPStack.SIP_CODEC_G711U) {
            packetsize = SIPG711.encode2ULaw(data, datasize, lineardata, 0);
        //} else if (remotePayloadType == SIPStack.SIP_CODEC_G711A) {
         //   packetsize = SIPG711.encode2ALaw(data, datasize, lineardata, 0);
        //}

        if (BUFFER_BUFFERREDSIZE + packetsize > BUFFER_SIZE) {
            BUFFER_PLAY_INDEX = 0;
            BUFFER_BUFFERREDSIZE = 0;
        }

        int savePos = (BUFFER_PLAY_INDEX + BUFFER_BUFFERREDSIZE) % BUFFER_SIZE;
        int bufferTrail = BUFFER_SIZE - savePos;
        if (bufferTrail < packetsize) {
            System.arraycopy(lineardata, 0, captureBuffer, savePos, bufferTrail);
            System.arraycopy(lineardata, bufferTrail, captureBuffer, 0, packetsize - bufferTrail);
        } else {
            System.arraycopy(lineardata, 0, captureBuffer, savePos, packetsize);
        }
        BUFFER_BUFFERREDSIZE += packetsize;
        bCaptureBufferLock = false;

        if (flowIndicator == SIPStack.SIP_MEDIAFLOW_SENDONLY) {
            playAudio(comportableNoise, datasize);
        }
        return;
    }

    public boolean getLineardata(byte[] data, int datasize) {
        if (bCaptureBufferLock) {
            try {
                Date lockTime = null;
                Date currentTime = null;
                boolean bOverTime = false;
                int durationMilli = 0;
                lockTime = new Date();

                while (bCaptureBufferLock) {
                    Thread.sleep(1, 1);
                    currentTime = new Date();
                    durationMilli = (int) (currentTime.getTime() - lockTime.getTime());
                    if (durationMilli > 2) {
                        bOverTime = true;
                        break;
                    }
                }

                if (bOverTime) {
                    return false;
                }
            } catch (Exception e) {
                Log.e(TAG, "[Exception] getLineardata(byte[] data, int datasize)");
                return false;
            }
        }

        if (data == null || datasize <= 0) return false;

        if (datasize > BUFFER_BUFFERREDSIZE) {
            System.arraycopy(comportableNoise, 0, data, 0, datasize);
            return true;
        }

        int bufferTrail = BUFFER_SIZE - BUFFER_PLAY_INDEX;
        if (bufferTrail < datasize) {
            System.arraycopy(captureBuffer, BUFFER_PLAY_INDEX, data, 0, bufferTrail);
            System.arraycopy(captureBuffer, 0, data, bufferTrail, datasize - bufferTrail);
        } else {
            System.arraycopy(captureBuffer, BUFFER_PLAY_INDEX, data, 0, datasize);
        }
        BUFFER_PLAY_INDEX = (BUFFER_PLAY_INDEX + datasize) % BUFFER_SIZE;
        BUFFER_BUFFERREDSIZE -= datasize;
        return true;
    }

    public boolean getEncodeddata(byte[] data, int datasize, int pos) {
        if (bCaptureBufferLock) {
            try {
                Date lockTime = null;
                Date currentTime = null;
                boolean bOverTime = false;
                int durationMilli = 0;
                lockTime = new Date();

                while (bCaptureBufferLock) {
                    Thread.sleep(1, 1);
                    currentTime = new Date();
                    durationMilli = (int) (currentTime.getTime() - lockTime.getTime());
                    if (durationMilli > 2) {
                        bOverTime = true;
                        break;
                    }
                }

                if (bOverTime) {
                    return false;
                }
            } catch (Exception e) {
                Log.e(TAG, "[Exception] getEncodeddata(byte[] data,int datasize,int pos)");
                return false;
            }
        }

        if (data == null || datasize <= 0) return false;

        if (datasize > BUFFER_BUFFERREDSIZE) {
            return false;
        }

        int bufferTrail = BUFFER_SIZE - BUFFER_PLAY_INDEX;

        if (bufferTrail < datasize) {
            System.arraycopy(captureBuffer, BUFFER_PLAY_INDEX, data, pos, bufferTrail);
            System.arraycopy(captureBuffer, 0, data, pos + bufferTrail, datasize - bufferTrail);
        } else {
            System.arraycopy(captureBuffer, BUFFER_PLAY_INDEX, data, pos, datasize);
        }
        BUFFER_PLAY_INDEX = (BUFFER_PLAY_INDEX + datasize) % BUFFER_SIZE;
        BUFFER_BUFFERREDSIZE -= datasize;
        return true;
    }

    public boolean getBulkdata(byte[] data, int datasize, int pos) {
        if (bCaptureBufferLock) {
            return false;
        }

        if (data == null || datasize <= 0) return false;

        if (datasize > BUFFER_BUFFERREDSIZE) {
            return false;
        }

        int bufferTrail = BUFFER_SIZE - BUFFER_PLAY_INDEX;
        if (bufferTrail < datasize) {
            System.arraycopy(captureBuffer, BUFFER_PLAY_INDEX, data, pos, bufferTrail);
            System.arraycopy(captureBuffer, 0, data, pos + bufferTrail, datasize - bufferTrail);
        } else {
            System.arraycopy(captureBuffer, BUFFER_PLAY_INDEX, data, pos, datasize);
        }
        BUFFER_PLAY_INDEX = (BUFFER_PLAY_INDEX + datasize) % BUFFER_SIZE;
        BUFFER_BUFFERREDSIZE -= datasize;
        return true;
    }

    public static Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
//            Log.d(TAG, "[mPathCheckHandler.handleMessage]");
            if (msg.what == 0) {
                if (MainActivity.mCallController.mCallInfo.geteRemoteCallOwner() != REMOTECALLOWNER.NONE)
                    mHandler.sendEmptyMessageDelayed(1, 10);
                else mHandler.sendEmptyMessageDelayed(0, 10);
            } else if (msg.what == 1) {
                Log.d(TAG, "[mHandler.handleMessage] Handler finish!! REMOTECALLOWNER [" + MainActivity.mCallController.mCallInfo.geteRemoteCallOwner() + "]");
                mHandler.removeMessages(0);
                if (MainActivity.mCallController.mCallInfo.geteRemoteCallOwner() == REMOTECALLOWNER.GUARD) {
                    boolean bSpeakOn = amAudioManager.isSpeakerphoneOn();
                    Log.d(TAG, "[mHandler] guard before *** bSpeakOn = " + bSpeakOn);
                    Log.w(TAG, "[mHandler] setMode(AUDIO_MODE_MOIP_GUARD) [" + AUDIO_MODE_MOIP_GUARD + "]");
                    amAudioManager.setMode(AUDIO_MODE_MOIP_GUARD);
                    bSpeakOn = amAudioManager.isSpeakerphoneOn();
                    Log.d(TAG, "[mHandler] guard after *** bSpeakOn = " + bSpeakOn);
                } else if (MainActivity.mCallController.mCallInfo.geteRemoteCallOwner() == REMOTECALLOWNER.RESIDENCE) {
                    boolean bSpeakOn = amAudioManager.isSpeakerphoneOn();
                    Log.d(TAG, "[mHandler] resi before *** bSpeakOn = " + bSpeakOn);
                    Log.w(TAG, "[mHandler] setMode(AUDIO_MODE_MOIP_RESIDENCE) [" + AUDIO_MODE_MOIP_RESIDENCE + "]");
                    amAudioManager.setMode(AUDIO_MODE_MOIP_RESIDENCE);
                    bSpeakOn = amAudioManager.isSpeakerphoneOn();
                    Log.d(TAG, "[mHandler] resi after *** bSpeakOn = " + bSpeakOn);
                }
            }
        }
    };
}







