Let arduino ring phones via SIP

I just managed to hack some code which makes my arduino connect to a SIP server (Fritzbox) and send SIP REGISTER/INVITE to let phones ring. Now working on CANCEL to stop the ringing :wink:

That's all I need, I guess audio would be too much for an arduino. If someone is interested in the code, let me know...

-edit-
Latest code version at the end of the thread.

I'm interested. My plan to do the same was to just hack up some worthless SIP phones I have laying around to trigger the redial button using an Arduino output. That's still probably cheaper than adding a network interface to the Arduino, but it's less than elegant.

--Donnie

Here is my current working code. It can now connect with UDP or TCP to the SIP server and let phones ring. But there are still issues:

  • CANCEL to stop the ringing does not work. It is rejected by my SIP server with a leg/transaction does not exist error, however I could not yet spot my faulty parameters.
  • Currently the code uses an incorrectly (to my current knowlegde) formated Via, otherwise the phone will not ring.
  • Using UDP gives lots of unathorized and declined messages from the SIP server, but the phone rings nevertheless.

To stop the ringing you have to reject the call from the called phone or wait for some timeout.

I have a network capture of a UDP session with a working cancel, but this is quite complicated, I will try to implement this on my arduino as soon as I find some time. If I have working code, I could then strip it down to what is really required.

A mega is required because of code size.

These libraries are required:

See the first line of setup() to configure SIP server IP and port, SIP user, SIP pwd and the phone nr. to dial.

sip.zip (3.44 KB)

Hello friends.
About a year ago I had been playing the asterisk and arduino.I haven't looked to your code but it is very simple interface the asterisk with the arduino and a ethernet shield.Imagination is your limit.
Here is all the info very well explained.
http://www.nerdybynature.com/category/asterisk/

Hi HugoPT,

thanks for the link! Unfortunately I have neither astersik not a web server available. The SIP server is the AVM FritzBox (a DSL router with SIP functionality). My goal is to make the arduino talk SIP directly to the SIP server.

Bernd

Got it working now.

Attached is code that can dial a tel. nr., the called phone rings and after 10 secs. the call is canceled.

What is still missing:

  • Error handling
  • Refactoring into some reusable code/lib
  • The SIP Via header needs to be constructed with a syntax error, otherwise it does not work. I have currently no idea what the problem is.

See setup() for configuration.

edit
Latest code version at the end of the thread

sip.zip (3.34 KB)

HugoPT:
Asterisk – nerdybynature

Interesting idea berndq. I think for the sake of being able to reproduce something similar, I actually like HugoPT's idea of a generic Asterisk server. I'm not sure what the AVM FritzBox is, but it seems like a difficult to find piece of kit. However, a normal Asterisk server running on a RPi is something anyone can reproduce (google Incredible PBX).

Hugo, what were you running your Asterisk server on?

The FritzBox is a multi-purpose DSL router made by AVM and is very popular in and around Germany. (http://www.avm.de/en/Produkte/FRITZBox/index.html). It has built in PBX/DECT/SIP functionality. From a SIP point of view, the code should work with any SIP server, not just the FritBox.

Latest code version, refactored to an arduino library.

edit
Latest code version at the end of the thread

sip.zip (6.1 KB)

1 Like

I am very much interested, but I cannot seem to find any code attached to your last post...?

It is the post dated Jun 19, 2014. There is a paperclip and next to it the filename "sip.zip". Klick on the file name to download.

Hi,

I used you SIP Ringer to ring a Phone when a button is pressed. But sadly this only works once.

void loop() {


  // update() must be called regularyly to actively maintain the calls progress.
  sipRinger.update();
  buttonState = digitalRead(buttonPin);
  if (buttonState == LOW) {
      sipRinger.ring();
    
  }
 
}

Edit: It works when the call is not answered
Edit2: never mind, I fixed it myself

Would you mind to share your fix?

Sure,
in the SIPRinger.cpp I added the recognition of an answered call, to stop the tcpClient and set the status to SIP_STATE_DONE:

        else if(m_state==SIP_STATE_TRYING){
          if((strstr(m_recBuf, "SIP/2.0 486 Busy Here")!=NULL)||(strstr(m_recBuf, "SIP/2.0 603 Decline")!=NULL)){
            m_state=SIP_STATE_READ_ENTIRE_REPLY_THEN_DISCONNECT;
#ifdef SIP_LOG_STATUS
            Serial.print(F("Call failed: "));
            Serial.println(m_recBuf);
#endif
          } 
		  if((strstr(m_recBuf, "SIP/2.0 200 OK")!=NULL)){
#ifdef SIP_LOG_STATUS
            Serial.print(F("Call answered?: "));
#endif		  
			if(strstr(m_recBuf, "Content-Length: 0")!=NULL){		  			
#ifdef SIP_LOG_STATUS            
            Serial.println(m_recBuf);
#endif		  				
			}

			if(m_useTcp==true){
				m_tcpClient.stop();
			}
			m_state=SIP_STATE_DONE;
#ifdef SIP_LOG_STATUS            
			Serial.print(F("Done. free RAM="));
			Serial.println(freeRam());
			Serial.flush();
#endif            
		  }          
        }

Thanks teddybt,

I integrated your fix. Attached is the latest code which has also a memory leak fixed.

sipringer.zip (6.06 KB)

Hi berndq,
I saw in your code that you deliberately disable the SD card (link to the further info is a dead one :astonished:
Is there a specific reason why you do this?
I would plan to use the SD card to store numbers to be dialed?
Thanks for ur feedback.

Hi Poej,

just tested the link: The arduino IDE (1.6.1) does not pass the entire link to the web browser -> "The requested topic does not exist.". Copy/pasting the text into the browser shows the discussion.

I experienced unstable arduino operations and the info from user SkullKill from Sun Oct 28, 2012 6:26 am solved my problem: "did some research, and found that if i am not using the SD card, i need to explicitly disable it"

berndq:
Thanks teddybt,

I integrated your fix. Attached is the latest code which has also a memory leak fixed.

Please re-check the source code, it cannot compiled with IDE 1.6.x :-((

Error: "unable to find a register to spill in class 'NO_REGS'"

Hi Bernd,

using the current Arduino IDE 1.8.3 I also get the NO_REGS error. Seems to be a problem with PSTR macro.

I try to use your script for as an additional door bell. If someone rings the door bell, the phones should also ring. Currenty I compile it with the IDE 1.5.8 which does not produce the error.

I also add a public function to SIPRinger.h:
boolean isBusy();

And also to SIPRinger.cpp:
boolean SIPRinger::isBusy()
{
if ((m_state == SIP_STATE_INIT) || (m_state == SIP_STATE_DONE))
{
return false;
}
else
{
return true;
}
}

In the main sktech I call sipRinger.ring() only if the sipRinger.isBusy() returns false. So I do not get in trouble if the phones are still ringing while th next ring() method should be called.

Also I do not find a solution for handling if a call is answered. The method returns after the state has set to SIP_STATE_DONE, but the call is still active from my phone. So I think the method part
else if ((strstr(m_recBuf, "SIP/2.0 200 OK") != NULL))
{
m_state = SIP_STATE_READ_ENTIRE_REPLY_THEN_DISCONNECT;
#ifdef SIP_LOG_STATUS
Serial.print(F("Call answered: "));
Serial.println(m_recBuf);
#endif
}
should be extended to handle the call and send a hang up (BYE command?).

Do you have any hints?

Regards
Nils

If you search the web for the error message, this seems to be a gcc bug and it seems to be fixed in some arduino IDEs. I have know idea what to do to solve this.

I have abandoned to project because for me it does not work reliably, I never found out why. So my plans are to move this to a more powerful platform where there is reliable SIP support.

I also have not looked inside the code for a long time, so regarding your questions: I thought the ring() can be called without the caller having to check for the internal state of the sipringer, but this seems not the case. Why not extend the ring() to check your busy method, so your main sketch does not have to?

In the beginning i did not expect someone to answer the phone so I did not test this scenario. IIRC I added this later, but I am not sure, there a sever versions in the topic thread, have you used the latest one?

edit: Handling of answered calls: see post #11,#12,#13

What I did to learn the SIP sequence is: install a network sniffer and some SIP client (there are free ones) and trace what they do when you place a call and try to mimic what you want the arduino to do and see what the sniffer catches.

hope this helps

br