private void OnCallStateChanged(IntPtr lc, IntPtr callPtr, LinphoneCallState cstate, string message)
		{
			if (linphoneCore == IntPtr.Zero) return;

			LOG.Info(string.Format( "OnCallStateChanged: State - {0}, CallPtr - {1}, Message: {2}", cstate, callPtr, message));

			var newstate = VATRPCallState.None;
			var direction = LinphoneCallDir.LinphoneCallIncoming;
			string remoteParty = "";
			IntPtr addressStringPtr;
		    bool removeCall = false;
			// detecting direction, state and source-destination data by state
			switch (cstate)
			{
				case LinphoneCallState.LinphoneCallIncomingReceived:
				case LinphoneCallState.LinphoneCallIncomingEarlyMedia:
					newstate = cstate == LinphoneCallState.LinphoneCallIncomingReceived
						? VATRPCallState.InProgress
						: VATRPCallState.EarlyMedia;
					addressStringPtr = LinphoneAPI.linphone_call_get_remote_address_as_string(callPtr);
			        if (addressStringPtr != IntPtr.Zero)
			        {
			            identity = Marshal.PtrToStringAnsi(addressStringPtr);
                        LinphoneAPI.ortp_free(addressStringPtr);
			        }
					remoteParty = identity;
					break;

                case LinphoneCallState.LinphoneCallOutgoingEarlyMedia:
				case LinphoneCallState.LinphoneCallConnected:
					newstate = VATRPCallState.Connected;
					break;
				case LinphoneCallState.LinphoneCallStreamsRunning:
                    newstate = VATRPCallState.StreamsRunning;
					break;
				case LinphoneCallState.LinphoneCallPausedByRemote:
                    newstate = VATRPCallState.RemotePaused;
			        break;
				case LinphoneCallState.LinphoneCallPausing:
                    newstate = VATRPCallState.LocalPausing;
					break;
                case LinphoneCallState.LinphoneCallPaused:
                    newstate = VATRPCallState.LocalPaused;
                    break;
                case LinphoneCallState.LinphoneCallResuming:
                    newstate = VATRPCallState.LocalResuming;
			        break;
				case LinphoneCallState.LinphoneCallOutgoingInit:
				case LinphoneCallState.LinphoneCallOutgoingProgress:
				case LinphoneCallState.LinphoneCallOutgoingRinging:
                    newstate = cstate != LinphoneCallState.LinphoneCallOutgoingRinging
						? VATRPCallState.Trying
						: VATRPCallState.Ringing;
					direction = LinphoneCallDir.LinphoneCallOutgoing;
					addressStringPtr = LinphoneAPI.linphone_call_get_remote_address_as_string(callPtr);
			        if (addressStringPtr != IntPtr.Zero)
			        {
			            remoteParty = Marshal.PtrToStringAnsi(addressStringPtr);
                        LinphoneAPI.ortp_free(addressStringPtr);
			        }
					break;

				case LinphoneCallState.LinphoneCallError:
                    string linphoneLibraryVersion = VATRP.LinphoneWrapper.LinphoneAPI.linphone_core_get_version_asString();
                    LOG.Info("OnCallStateChanged: CallState=LinphoneCallError .LinphoneLib Version: " + linphoneLibraryVersion);
					newstate = VATRPCallState.Error;
			        removeCall = true;
					break;

				case LinphoneCallState.LinphoneCallEnd:
					newstate = VATRPCallState.Closed;
                    removeCall = true;
					break;
				case LinphoneCallState.LinphoneCallReleased:
			        if ((_declinedCallsList != null) && _declinedCallsList.Contains(callPtr))
			        {
                        LOG.Info("   trying to remove callPtr from declinedCallList");
			            _declinedCallsList.Remove(callPtr);
                    }
                    LOG.Info("   calling linphone_call_unref");
                    try
                    {
                        LinphoneAPI.linphone_call_unref(callPtr);
                        LOG.Info("   passed unref");
                    }
                    catch (Exception ex)
                    {
                        LOG.Error("LinphoneService.OnCallStateChanged: Exception occured while calling linphone_call_unref. Details: " + ex.Message);
                    }
			        return;
			}

		    lock (callLock)
		    {
		        VATRPCall call = FindCall(callPtr);

		        if (call == null)
		        {
		            if (_declinedCallsList.Contains(callPtr))
		                return;

		            if (GetActiveCallsCount > 1)
		            {
                        callPtr = LinphoneAPI.linphone_call_ref(callPtr);
                        var cmd = new DeclineCallCommand(callPtr, LinphoneReason.LinphoneReasonBusy);
		                commandQueue.Enqueue(cmd);
                        _declinedCallsList.Add(callPtr);
		                return;
		            }

		            if (!removeCall)
		            {
		                LOG.Info("Call not found. Adding new call into list. ID - " + callPtr + " Calls count: " +
		                         callsList.Count);
                        callPtr = LinphoneAPI.linphone_call_ref(callPtr);
		                call = new VATRPCall(callPtr) {CallState = newstate, CallDirection = direction};
		                CallParams from = direction == LinphoneCallDir.LinphoneCallIncoming ? call.From : call.To;
		                CallParams to = direction == LinphoneCallDir.LinphoneCallIncoming ? call.To : call.From;

		                if (
		                    !VATRPCall.ParseSipAddressEx(remoteParty, out from.DisplayName, out from.Username,
		                        out from.HostAddress,
		                        out from.HostPort))
		                    from.Username = "******";

		                if (
		                    !VATRPCall.ParseSipAddressEx(remoteParty, out to.DisplayName, out to.Username, out to.HostAddress,
		                        out to.HostPort))
		                    to.Username = "******";

		                IntPtr chatPtr = LinphoneAPI.linphone_call_get_chat_room(callPtr);

		                if (chatPtr != IntPtr.Zero)
		                {
		                    VATRPContact contact;
		                    var contactAddress = string.Empty;
		                    if (direction == LinphoneCallDir.LinphoneCallIncoming)
		                    {
		                        contactAddress = string.Format("{0}@{1}", from.Username, from.HostAddress);
		                        contact = new VATRPContact(new ContactID(contactAddress, chatPtr))
		                        {
		                            DisplayName = from.DisplayName,
		                            Fullname = from.Username,
		                            SipUsername = from.Username
		                        };
		                    }
		                    else
		                    {
		                        contactAddress = string.Format("{0}@{1}", to.Username, to.HostAddress);
		                        contact = new VATRPContact(new ContactID(contactAddress, chatPtr))
		                        {
		                            DisplayName = to.DisplayName,
		                            Fullname = to.Username,
		                            SipUsername = to.Username
		                        };
		                    }
		                    contact.RegistrationName = contactAddress;
                            call.ChatRoom = manager.ChatService.InsertRttChat(contact, chatPtr, callPtr);
		                    var loggedContact = manager.ContactService.FindLoggedInContact();
		                    if (loggedContact != null)
		                        call.ChatRoom.AddContact(loggedContact);
		                }

		                callsList.Add(call);
		            }
		        }

		        if (call != null)
		        {
		            call.LinphoneMessage = message;
		            call.CallState = newstate;

                    if (call.CallState == VATRPCallState.Error || call.CallState == VATRPCallState.Closed)
		            {
		                IntPtr errorReason = LinphoneAPI.linphone_call_get_error_info(callPtr);
		                if (errorReason != IntPtr.Zero)
		                {
                            call.SipErrorCode = LinphoneAPI.linphone_error_info_get_protocol_code(errorReason);
		                }
		            }
                    if (CallStateChangedEvent != null)
                        CallStateChangedEvent(call);
		            if (removeCall)
		            {
		                callsList.Remove(call);
		                LOG.Info(string.Format("Call removed from list. Call - {0}. Total calls in list: {1}", callPtr,
		                    callsList.Count));
		            }
		        }
		    }
		}
        public void DeclineCall(IntPtr callPtr)
        {
            if (linphoneCore == IntPtr.Zero)
            {
                if (ErrorEvent != null)
                    ErrorEvent(null, "Cannot terminate calls when Linphone Core is not working.");
                return;
            }

            lock (callLock)
            {
                VATRPCall call = FindCall(callPtr);

                if (call == null)
                {
                    LOG.Warn("Cannot decline call. Cause - Null call");
                    return;
                }
                call.CallState = VATRPCallState.Closed;

                LOG.Info("Decline Call: " + callPtr);
                LOG.Info(string.Format("Call removed from list. Call - {0}. Total calls in list: {1}", callPtr,
                    callsList.Count));
            }
            var cmd = new DeclineCallCommand(callPtr, LinphoneReason.LinphoneReasonDeclined);

            lock (commandQueue)
            {
                commandQueue.Enqueue(cmd);
            }

        }