Looking for a SIP client that can use an h.264 RTSP stream as a video source - sip

We are looking to integrate an IP camera (h.264 RTSP stream) with an asterisk PBX system for use in a school for distributed education (so a remote teacher can "dial in and teach").
Ideally we would like to be able to create a SIP client as an autoanswer pbx extension.
We are considering running a *nix box that can use a network video stream as a source for video, mix a separate audio source and present a SIP endpoint.
I understand that SIP express router may be able to:
"call an external C script, which could parse and change the SDP info within the SIP headers of clients it porxy's with, and change address of where it expects to recieve media from."
but I'm thinking it may be easier to look for a way to present an h.264 rtsp stream as /dev/videoX and use a standard SIP client.
If anyone has any pointers or any ideas for research I'd be really appreciative :-)
Thanks for reading!
W
p.s. there are IP cameras out there that claim to have SIP clients, but all I have seen only offer SIP for establishing a bi-directional audio session.

I don't know whether you found the correct answer to this question or not after all this time, but maybe I can give you some advice with VoIP and IP camera management and it would help anybody who has the same problem.
Your goal (if I understand your problem correctly) is basically creating a conference call solution which answers all the incoming calls and attach the IP camera video to all of these calls. I currently work at a company called Ozeki and - I don't know if there's an open-source solution for your problem or not - I'm going to show you an example code with SIP account registration, IP camera connection and answer all the incoming calls with the camera video.
So here is the source code:
public partial class Form1 : Form
{
private IIPCamera _camera;
private DrawingImageProvider _imageProvider;
private MediaConnector _connector;
private VideoViewerWF _videoViewerWf;
private ISoftPhone _softphone;
private IPhoneLine _phoneLine;
private IPhoneCall _call;
private PhoneCallAudioSender _audioSender;
private PhoneCallVideoSender _videoSender;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
_softphone = SoftPhoneFactory.CreateSoftPhone(5000, 10000);
_softphone.IncomingCall += softphone_IncomingCall;
_connector = new MediaConnector();
_videoSender = new PhoneCallVideoSender();
_audioSender = new PhoneCallAudioSender();
_imageProvider = new DrawingImageProvider();
_videoViewerWf = new VideoViewerWF();
SetVideoViewer();
}
private void SetVideoViewer()
{
CameraBox.Controls.Add(_videoViewerWf);
_videoViewerWf.Size = new Size(260, 180);
_videoViewerWf.BackColor = Color.Black;
_videoViewerWf.TabStop = false;
_videoViewerWf.FlipMode = FlipMode.None;
_videoViewerWf.Location = new Point(35, 30);
_videoViewerWf.Name = "_videoViewerWf";
}
private void Register(bool registrationRequired, string displayName, string userName, string authenticationId, string registerPassword, string domainHost)
{
try
{
var account = new SIPAccount(registrationRequired, displayName, userName, authenticationId, registerPassword, domainHost);
_phoneLine = _softphone.CreatePhoneLine(account);
_phoneLine.RegistrationStateChanged += phoneLine_RegistrationStateChanged;
_softphone.RegisterPhoneLine(_phoneLine);
}
catch (Exception ex)
{
label_Phoneline.Text = ex.Message;
}
}
private void phoneLine_RegistrationStateChanged(object sender, RegistrationStateChangedArgs e)
{
InvokeGuiThread(() => label_Phoneline.Text = e.State.ToString());
}
private void softphone_IncomingCall(object sender, VoIPEventArgs<iphonecall> e)
{
if (_camera != null)
{
_call = e.Item;
_call.CallStateChanged += call_CallStateChanged;
ConnectToCall();
_call.Answer();
}
}
private void ConnectToCall()
{
_videoSender.AttachToCall(_call);
_audioSender.AttachToCall(_call);
_connector.Connect(_camera.VideoChannel, _videoSender);
_connector.Connect(_camera.AudioChannel, _audioSender);
}
private void call_CallStateChanged(object sender, CallStateChangedArgs e)
{
InvokeGuiThread(() => label_Call.Text = e.State.ToString());
if (e.State == CallState.Completed)
if (_call != null)
{
_call.CallStateChanged -= call_CallStateChanged;
_connector.Disconnect(_camera.VideoChannel, _videoSender);
_connector.Disconnect(_camera.AudioChannel, _audioSender);
}
}
private void button_Connect_Click(object sender, EventArgs e)
{
_camera = IPCameraFactory.GetCamera("cameraIPAddress:8080", "admin", "admin");
_connector.Connect(_camera.VideoChannel, _imageProvider);
_videoViewerWf.SetImageProvider(_imageProvider);
_videoViewerWf.Start();
_camera.Start();
}
private void button_SIPRegister_Click(object sender, EventArgs e)
{
Register(true, "100", "100", "100", "100", "PBXAddress");
}
private void InvokeGuiThread(Action action)
{
BeginInvoke(action);
}
}
And the (example) GUI:
If you click on Connect button then the IPCameraFactory.GetCamera() will be called which is for connecting to the specified camera using the arguments (RTSP/RTP/HTTP messages in the background).
The Register button calls the Register() method to register your SIP account to the PBX. You can check the registration status at the Status label.
If there is an incoming call then the answer will occur automatically and the camera video and audio channel will attach to the call. So the caller will see and hear you.
Note:
Most of the IP camera microphones have really bad quality so you may connect your own microphone to the call. It's really simple too.
Create a Microphone object:
Microphone microphone = Microphone.GetDefaultDevice();
if (microphone != null)
microphone.Start();
And if there's an incoming call then connect this microphone to the call:
_connector.Connect(microphone, _audioSender);
And that's it. I hope I could help you!

live555 has some open-source implementations like openRTSP and playSIP which could help with your requirements.

Related

Connection not working from Android to UWP on desktop - ZeroMq (NetMq)

I tried some examples of ZMQ on C++,C# and Python. I am trying to have Request-Reply pattern to connect Android device to PC running UWP with Xamarin forms.
Below is the Requestor code:
public void HelloWorld()
{
var timer = new Timer(60000);
timer.Start();
timer.Elapsed += (sender, args) =>
{
this.Cancel = true;
timer.Stop();
};
// Create
const string endpoint = "tcp://PC_ip:3245";
using (var request = new RequestSocket())
{
request.Bind(endpoint);
Thread.Sleep(2000);
while (!Cancel)
{
request.SendFrame("Requester says hello");
var reply = request.ReceiveFrameString();
Debug.WriteLine("Gets reply {0}",reply);
}
}
}
Reply socket code:
public void HelloWorld()
{
var timer = new Timer(60000);
const string endpoint = "tcp://PC_ip:3245";
timer.Start();
timer.Elapsed += (sender, args) =>
{
timer.Stop();
Cancel = true;
};
using (var replierSocket = new ResponseSocket())
{
replierSocket.Connect(endpoint);
Thread.Sleep(2000);
while (!Cancel)
{
var replyFromRequester = replierSocket.ReceiveFrameString();
Debug.WriteLine("Got reply {0}", replyFromRequester);
replierSocket.SendFrame("Response socket say hello");
}
}
}
Cancel is boolean
I went through some questions posted on this and added delay and these connection code blocks only trigger after button clicks on app.
While debugging , request.ReceiveFrameString() replierSocket.ReceiveFrameString(); are not even hit.
I am new to network programming , I understand that for REQ/REP pattern the code has to be in particular order which I traced and fixed I believe and turned off firewall on my PC so that firewall wont block my incoming connections from Android device.
PC_ip stands for IPv4 address I got from ipconfig /all for my wifi. I also tried external ip of my machine from sites like whatsmyip.org at ResponseSocket but I still dont get response between devices.
Please let me know what am I doing wrong.
Issue replication repository : GitHub/me/XamZeroMq

How to know who received a message in a MUC room

For my thesis, I am using Smack to log a XMPP network that uses the MUC module.
Another software is currently sending IoT sensor data into different MUC rooms.
I'd like to know for every message sent into a MUC room, which users were in that room at the time of the message. Is this possible? I could use a messageListener to every muc room, however the listener only receives a message as an argument. Therefore I could not know who is logged into the room inside the listener method.
you can get all muc message in StanzaListener in xmpp. Please follow few steps to done this
Step 1. Declare as a global variables
ChatManagerListener chatListener;
Chat chat;
StanzaListener packetListener;
Step 2. Use this code in oncreate or in fragment
Note: Make sure you have connected with chat server.
packetListener = new StanzaListener() {
#Override
public void processPacket(Stanza packet) throws SmackException.NotConnectedException, InterruptedException {
if (packet instanceof Message) {
final Message message = (Message) packet;
}
}
};
XMPP.getInstance().getConnection(acitiviy)).addAsyncStanzaListener(stanzaListener, null);
ServiceDiscoveryManager sdm = ServiceDiscoveryManager
.getInstanceFor(XMPP.getInstance().getConnection(acitiviy)));
sdm.addFeature("jabber.org/protocol/si");
sdm.addFeature("http://jabber.org/protocol/si");
sdm.addFeature("http://jabber.org/protocol/disco#info");
sdm.addFeature("jabber:iq:privacy");
Step 3. Methods for one to one chat purposer
void sendMessage(String message) {
if (chat != null) {
try {
chat.sendMessage(message);
Message msg = new Message();
msg.setTo(JidCreate.bareFrom(jid));
msg.setFrom(XMPP.getInstance().getConnection(acitiviy)
.getUser());
ChatStateExtension ext = new ChatStateExtension(
ChatState.paused);
msg.addExtension(ext);
lastComposing = System.currentTimeMillis();
chat.sendMessage(msg);
} catch (SmackException.NotConnectedException e) {
} catch (Exception e) {
}
}
}
Step 4. On destroy
XMPP.getInstance().getConnection(acitiviy)).removeAsyncStanzaListener(stanzaListener);
Hope this will help you and if you want more information take a look from here. Thankyou
Nothing prervents you from calling Multi UserCaht.getParticipants() from within the listener. But be warned: If your goal is to determine the other receivers of receivers, then this approach is fragile. I also suggest to think about using PubSub instead of MUC for your IoT use case.

I cannot make UDP Ports work on a Windows Azure Virtual Machine

I cannot receive a UDP packet on a Windows Azure Virtual Machine. I have done the following:
On the Virtual Machine, via Windows Firewall, I opened up Port 1234* both Inbound and Outbound for both UDP and TCP protocols. I did not add any IP exclusions. The rule should apply to Domain, Private and Public profiles. I am allowing Block Edge Traversal.
In the Azure Management Portal, I added Endpoints for my Virtual Machine instance. I added both UDP and TCP protocol endpoints. Public and Private port numbers are both 1234.
I have two test programs that I wrote: UDPSender and UDPReceiver. Using two computers on my local network, the test programs successfully sent a packet between them. (Edit: I also used UDPTester Android App to successfully send a 'trans-ISP' message to my PC running the UDPReceiver.)
Moving UDPReceiver to my Virtual Machine, I cannot successfully receive a message.
Did I miss anything in my Azure Endpoint configuration? Please Help!
* Port Number changed to protect the innocent.
Test Program Code Below...
UDPSender:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
textMessage.Text = "Knock, knock";
textIP.Text = "xxx.xxx.xxx.xxx";
textPort.Text = "1234";
}
private void buttonSend_Click(object sender, EventArgs e)
{
UdpClient udpClient = new UdpClient(textIP.Text, Convert.ToInt32(textPort.Text));
Byte[] sendBytes = Encoding.ASCII.GetBytes(textMessage.Text);
try
{
udpClient.Send(sendBytes, sendBytes.Length);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
}
UDPReceiver:
private static void Main(string[] args)
{
//Creates a UdpClient for reading incoming data.
UdpClient receivingUdpClient = new UdpClient(1234);
while (true)
{
//Creates an IPEndPoint to record the IP Address and port number of the sender.
// The IPEndPoint will allow you to read datagrams sent from any source.
System.Net.IPEndPoint RemoteIpEndPoint = new System.Net.IPEndPoint(System.Net.IPAddress.Any, 0);
try
{
// Blocks until a message returns on this socket from a remote host.
Byte[] receiveBytes = receivingUdpClient.Receive(ref RemoteIpEndPoint);
string returnData = Encoding.ASCII.GetString(receiveBytes);
string messageOut = String.Format("[{0},{1}]#[{2}]: {3}",
RemoteIpEndPoint.Address.ToString(),
RemoteIpEndPoint.Port.ToString(),
DateTime.Now,
returnData.ToString());
Console.WriteLine(messageOut);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
}
The code looks correct. I compared it against my implementation. Here are the key sections for reference:
Your csdef should have the correct port protocol. You said you did this through the portal, but confirm the settings saved:
<Endpoints>
<InputEndpoint name="UdpEndpoint" protocol="udp" port="8080" localPort="8080" />
</Endpoints>
(from https://github.com/ytechie/LogHub/blob/master/Microsoft.LogHub.Cloud/ServiceDefinition.csdef)
And listening on the correct port was as easy as:
var endPoint = new IPEndPoint(IPAddress.Any, 0);
var udp = new UdpClient(8080);
(from https://github.com/ytechie/LogHub/blob/master/Microsoft.LogHub/Global.asax.cs)
Feel free to take a look at my implementation and look for differences. I did notice that you're using the synchronous version of "Receive", but that shouldn't matter.
I'm also curious if this is PaaS or IaaS. In either case, you'll need to hit against the load balanced endpoint, and not an internal endpoint which would be inaccessible from the internet.

cometd bayeux can't send message to a specific client

//StockPriceEmitter is a "dead loop" thread which generate data, and invoke StockPriceService.onUpdates() to send data.
#Service
public class StockPriceService implements StockPriceEmitter.Listener
{
#Inject
private BayeuxServer bayeuxServer;
#Session
private LocalSession sender;
public void onUpdates(List<StockPriceEmitter.Update> updates)
{
for (StockPriceEmitter.Update update : updates)
{
// Create the channel name using the stock symbol
String channelName = "/stock/" + update.getSymbol().toLowerCase(Locale.ENGLISH);
// Initialize the channel, making it persistent and lazy
bayeuxServer.createIfAbsent(channelName, new ConfigurableServerChannel.Initializer()
{
public void configureChannel(ConfigurableServerChannel channel)
{
channel.setPersistent(true);
channel.setLazy(true);
}
});
// Convert the Update business object to a CometD-friendly format
Map<String, Object> data = new HashMap<String, Object>(4);
data.put("symbol", update.getSymbol());
data.put("oldValue", update.getOldValue());
data.put("newValue", update.getNewValue());
// Publish to all subscribers
ServerChannel channel = bayeuxServer.getChannel(channelName);
channel.publish(sender, data, null); // this code works fine
//this.sender.getServerSession().deliver(sender, channel.getId(), data, null); // this code does not work
}
}
}
this line channel.publish(sender, data, null); // this code works fine works fine, now I don't want channel to publish message to all clients subscirbed with it, I want to send to a specific client, so I write this this.sender.getServerSession().deliver(sender, channel.getId(), data, null);, but it does not work, browser can't get message.
thx in advance.
I strongly recommend that you spend some time reading the CometD concepts page, in particular the section about sessions.
Your code does not work because you are sending the message to the sender, not to the recipient.
You need to pick which remote ServerSession you want to send the message to among the many that may be connected to your server, and call serverSession.deliver(...) on that remote ServerSession.
How to pick the remote ServerSession depends on your application.
For example:
for (ServerSession session : bayeuxServer.getSessions())
{
if (isAdminUser(session))
session.deliver(sender, channel.getId(), data, null);
}
You have to provide an implementation of isAdmin(ServerSession) with your logic, of course.
Note that you don't need to iterate over the sessions: if you happen to know the session id to deliver to, you can do:
bayeuxServer.getSession(sessionId).deliver(sender, channel.getId(), data, null);
Also refer to the CometD chat demo shipped with the CometD distribution, that contain a full fledged example of how to send a message to particular session.

sending and receiving broadcast messages

Guys I need some help here..
I am doing a project in c# where the data needs to be sent as a datagram and receive data too which is broadcast.
The following is the code:
public void StartUdpListener(Object state)
{
receivedNotification = udpServer.Receive(ref remoteEndPoint);
notificationReceived = Encoding.ASCII.GetString(receivedNotification);
listBox = new StringBuilder(this.listBox1.Text);
listBox.AppendLine(notificationReceived);
if (listBox1.InvokeRequired)
{
this.Invoke((MethodInvoker)delegate { this.listBox1.Items.Add(listBox.ToString()); });
}
}
public void StartNotification()
{
ThreadPool.QueueUserWorkItem(new WaitCallback(StartUdpListener));
hostName = Dns.GetHostName();
hostBuffer = Encoding.ASCII.GetBytes(hostName);
UdpClient newUdpClient = new UdpClient();
newUdpClient.Send(hostBuffer, hostBuffer.Length, notifyIP);
}
Could you guys please tell me if the code is fine because there is no one around with whom i can test the code on lan
Thanks a ton guys.
Why don't you set up your own broadcaster and listener in separate instances.
This is a great article on socket programming in c#