Visual Studio 2019
C#
SDR# plug-in (for non NET 5 versions)
.NET Framework 4.6
RDS data from SDR# to RdsSpy with TCP without virtual audio cable
Asynchronous TCP socket
Source code and dll (updated 2021-03-02 - many fixes for more stable operation): https://github.com/OH1GIU-P/sdrsharp-rds2rdsspy
Copy SDRSharp.RdsiPlugin.dll from ...SDRSharp.RdsiPlugin\bin\Release to SDR# folder and add magic line to Plugins.xml
<add key="Rdsi" value="SDRSharp.RdsiPlugin.RdsiPlugin,SDRSharp.RdsiPlugin"/>
Connect from RdsSpy to SDR# seems to require to do 2 times: file -> play stream operation
Needs some tuning, buffering in plug-in needed because it seems that RdsSpy cannot receive/process data from TCP stream as fast as SDR# provides RDS group data.
https://i.ibb.co/sH7Qfjw/scrrds.jpg
using System.Windows.Forms;
using SDRSharp.Common;
using SDRSharp.Radio;
namespace SDRSharp.RdsiPlugin
{
public class RdsiPlugin : ISharpPlugin
{
private const string _displayName = "SDR#2RdsSpy";
private ISharpControl _control;
private RdsiPluginPanel _guiControl;
public UserControl Gui
{
get { return _guiControl; }
}
public string DisplayName
{
get { return _displayName; }
}
public void Close()
{
_guiControl.Close();
}
public void Initialize(ISharpControl control)
{
_control = control;
_guiControl = new RdsiPluginPanel(_control);
control.RegisterStreamHook((object)new RdsHwnd(_guiControl), ProcessorType.RDSBitStream);
}
}
}
using System;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using SDRSharp.Common;
namespace SDRSharp.RdsiPlugin
{
public partial class RdsiPluginPanel : UserControl
{
private bool _socketSend = false;
private int _clientConnect = 0;
private readonly ISharpControl _control;
private int _cnt = 0;
private IPHostEntry _host = null;
private IPAddress _ipAddress = null;
private IPEndPoint _localEndPoint = null;
private Socket _listener = null;
private Socket _handler = null;
public RdsiPluginPanel(ISharpControl control)
{
InitializeComponent();
_control = control;
labelCount.Text = "0";
labelConn.Text = "Not connected";
numPort.Value = 3122;
IPHostEntry _host = Dns.GetHostEntry("localhost");
int i;
for (i = 0; i < _host.AddressList.Length; i++)
{
if (_host.AddressList[i].AddressFamily == AddressFamily.InterNetwork)
{
break;
}
}
_ipAddress = _host.AddressList[i];
_localEndPoint = new IPEndPoint(_ipAddress, Convert.ToInt32(numPort.Value));
}
public void socketSend(String groups)
{
if (_socketSend)
{
byte[] msg = Encoding.ASCII.GetBytes(groups);
try
{
_handler.Send(msg);
_cnt++;
}
catch (SocketException ex)
{
_socketSend = false;
labelConn.Text = "Connection forcibly closed";
}
labelCount.Text = _cnt.ToString();
}
}
private void buttonStart_Click(object sender, EventArgs e)
{
_cnt = 0;
_socketSend = false;
_clientConnect = 0;
labelCount.Text = "0";
labelConn.Text = "Not connected";
_localEndPoint.Port = Convert.ToInt32(numPort.Value);
_localEndPoint.Address = _ipAddress;
try
{
_listener = new Socket(_ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
_listener.Bind(_localEndPoint);
_listener.Listen(1);
}
catch (Exception ex)
{
MessageBox.Show("Listen: " + ex.Message);
closeListener();
return;
}
labelConn.Text = "Connecting ...";
buttonStart.Enabled = false;
buttonStop.Enabled = true;
try
{
_listener.BeginAccept(ClientConnected, null);
}
catch (Exception ex)
{
MessageBox.Show("BeginAccept: " + ex.Message);
buttonStart.Enabled = true;
buttonStop.Enabled = false;
labelConn.Text = "Not connected";
closeListener();
return;
}
while (true)
{
if (_clientConnect != 0)
{
break;
}
Application.DoEvents();
}
if (_clientConnect == 2)
{
return;
}
labelConn.Text = "Connected";
buttonStart.Enabled = false;
buttonStop.Enabled = true;
numPort.Enabled = false;
_socketSend = true;
}
void ClientConnected(IAsyncResult ar)
{
if (_clientConnect == 2)
{
return;
}
_handler = _listener.Accept();
_clientConnect = 1;
}
private void buttonStop_Click(object sender, EventArgs e)
{
_socketSend = false;
_clientConnect = 2;
closeListener();
closeHandler();
labelConn.Text = "Not connected";
labelCount.Text = "0";
numPort.Enabled = true;
buttonStart.Enabled = true;
buttonStop.Enabled = false;
}
public void closeListener()
{
if (_listener != null)
{
_listener.Close();
_listener.Dispose();
_listener = null;
}
}
public void closeHandler()
{
if (_handler != null)
{
_handler.Shutdown(SocketShutdown.Both);
_handler.Close();
_handler = null;
}
}
public void Close()
{
_socketSend = false;
_clientConnect = 2;
closeHandler();
closeListener();
}
}
}
using System.Text;
using SDRSharp.Radio;
namespace SDRSharp.RdsiPlugin
{
public unsafe class RdsHwnd : IRdsBitStreamProcessor, IBaseProcessor
{
private bool _enabled = true;
private readonly RdsiPluginPanel _rdsiPluginPanel;
public RdsHwnd(RdsiPluginPanel _rdsPanelRef)
{
_rdsiPluginPanel = _rdsPanelRef;
}
public bool Enabled
{
get
{
return _enabled;
}
set
{
_enabled = value;
}
}
public void Process(ref RdsFrame _rdsFrame)
{
_rdsFrame.Filter = false;
string pic = string.Format("{0:X}", _rdsFrame.GroupA).Trim();
if (pic.Length != 4)
return;
StringBuilder _sb = new StringBuilder();
_sb.Append(pic);
_sb.Append(string.Format("{0:X}", _rdsFrame.GroupB));
_sb.Append(string.Format("{0:X}", _rdsFrame.GroupC));
_sb.AppendLine(string.Format("{0:X}", _rdsFrame.GroupD));
_rdsiPluginPanel.socketSend(_sb.ToString());
}
}
}
Kommentit
Tämän blogin kommentit tarkistetaan ennen julkaisua.