Welcome to the new FlexRadio Community! Please review the new Community Rules and other important new Community information on the Message Board.
Need the latest SmartSDR, Power Genius, Tuner Genius and Antenna Genius Software?
SmartSDR v3.8.19 and the SmartSDR v3.8.19 Release Notes | SmartSDR v2.12.1 and the SmartSDR v2.12.1 Release Notes
SmartSDR v1.12.1 and the SmartSDR v1.12.1 Release Notes
Power Genius XL Utility v3.8.8 and the Power Genius XL Release Notes v3.8.8
Tuner Genius XL Utility v1.2.11 and the Tuner Genius XL Release Notes v1.2.11
Antenna Genius Utility v4.1.8
SmartSDR v3.8.19 and the SmartSDR v3.8.19 Release Notes | SmartSDR v2.12.1 and the SmartSDR v2.12.1 Release Notes
SmartSDR v1.12.1 and the SmartSDR v1.12.1 Release Notes
Power Genius XL Utility v3.8.8 and the Power Genius XL Release Notes v3.8.8
Tuner Genius XL Utility v1.2.11 and the Tuner Genius XL Release Notes v1.2.11
Antenna Genius Utility v4.1.8
If you are having a problem, please refer to the product documentation or check the Help Center for known solutions.
Need technical support from FlexRadio? It's as simple as Creating a HelpDesk ticket.
Need technical support from FlexRadio? It's as simple as Creating a HelpDesk ticket.
DAX Format / How to play DAX samples in C# - FlexAPI
Cliff - G4PZK
Member ✭✭
I'm a competent C# programmer but have little knowledge of playing audio streams. I've written a simple proof of concept app which allows me to discover, connect to and configure my Flex 6300 and 6500 radios.
I have enabled DAX channel 1 for audio output and can see the UDP audio packets with class 0x03e3 on wireshark. I can successful enable/disable them as well as control the radio via my TCP socket. My questions are firstly what is the format of the data after the 0x03e3 classid and secondly does anyone have a simple code example (using NAudio maybe) to play them back? I'm aware that Opus audio is also available but don't want to add the complexity of extra decoding at this time plus the DAX output is lossless and independent of GUI app.
I realise that I could use the FlexLib solution but I'm only using C# as a convenient platform for testing, the final solution may well be in pure C and totally unmanaged.
2
Answers
-
So a progress report as there's been no feedback.
In case anybody else has ever fought this, and with thanks to the various old posts in this community support site, I've managed to dump the incoming data into a file having split the data into left and right channels. I can also dump the data as a stereo or two channel image.
The DAX packets are formatted as below:
Assuming a UdpClient socket is used in C# and the delivered payload in placed in a byte array rxData then the relevant bytes are used thus:
// Note that this is basic code
// get data packet length
int datalen = 4*((rxData[2] * 256) + rxData[3]);
// get packet class
string classID = rxData[14].ToString("X2") + rxData[15].ToString("X2");
// look for DAX channel 1
if (classID=="03E3")
{
// filter out channels into L and R
// declare target arrays for saving
byte[] LChan = new byte[(datalen - 28) / 2];
byte[] RChan = new byte[(datalen - 28) / 2];
int loop;
int pos=0;
// copy over left and right channels
for (loop=0; loop<(datalen-28)/8; loop++)
{
// Left channel
LChan[4*loop] = rxData[28 + (8 * loop)];
LChan[(4 * loop) + 1] = rxData[29 + (8 * loop)];
LChan[(4 * loop) + 2] = rxData[30 + (8 * loop)];
LChan[(4 * loop) + 3] = rxData[31 + (8 * loop)];
// Right channel
RChan[4*loop] = rxData[32 + (8 * loop)];
RChan[(4 * loop) + 1] = rxData[33 + (8 * loop)];
RChan[(4 * loop) + 2] = rxData[34 + (8 * loop)];
RChan[(4 * loop) + 3] = rxData[35 + (8 * loop)];
}
// write byte array to disk file using a BinaryWriter object
// to dump the samples as a two channel stereo file
// just write all bytes from position 28 to the end of the packet
// IE rxData[28] to rxData[datalen-1]
}
If the resulting file is imported into Audacity as a big endian, mono 32 bit float sampled at 24kHz then the audio can be heard!
If the audio isn't deinterleaved but simply dumped as one file from position 28 in the rxData array then it can be imported as a stereo 32 bit float file.
The next stage is to persuade NAudio to play the 'stream'.
1 -
Well done! I have devoted a small amount of time ( over the road truck driver) to this but, have had little success. Just not enough time to dive deeper into it.
Please continue sharing. I know others besides myself are interested in this.
James
WD5GWY0 -
Thanks for the encouragement James! I have wasted far too much time fighting this but now have a trivial solution to play the audio.
Firstly a correction to my earlier post. It turns out that the bytes are little endian rather than big endian so it's necessary to swap them around before trying to play them.
I should have spotted that in the _extensive_ documentation ;-)
The routine receiving the UDP packets is shown below
using System;
using System.Net;
using System.Net.Sockets;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
namespace FlexDebug
{
class FlexUDP
{
private UdpClient _udp = null;
private int _port;
private FlexDebug _parent;
private bool _stopUdp = false;
public bool StopUDP
{
get { return _stopUdp; }
set { _stopUdp = value; }
}
public FlexUDP(FlexDebug parent, int port)
{
int loop;
byte temp1;
byte temp2;
// save parent
_parent = parent;
// save port
_port = port;
// create client
try
{
Task.Run(() =>
{
// create UDP client
_udp = new UdpClient(_port);
IPEndPoint remoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
while (_stopUdp == false)
{
byte[] rxData = _udp.Receive(ref remoteIpEndPoint);
int datalen = 4 * ((rxData[2] * 256) + rxData[3]);
int samples = (datalen - 28) / 4;
string classID = rxData[14].ToString("X2") + rxData[15].ToString("X2");
// check for 03e3 (DAX channel 1)
if (classID == "03E3")
{
// convert from little endian to big endian
for (loop=0; loop<samples; loop++)
{
temp1 = rxData[(loop * 4) + 28];
temp2 = rxData[(loop * 4) + 29];
rxData[(loop * 4) + 28] = rxData[(loop * 4) + 31];
rxData[(loop * 4) + 29] = rxData[(loop * 4) + 30];
rxData[(loop * 4) + 30] = temp2;
rxData[(loop * 4) + 31] = temp1;
}
_parent.ProcessSound(rxData);
}
}
});
}
catch (Exception ex)
{
MessageBox.Show("Error: " + ex.Message);
}
}
}
}
The following code will actually play the samples. Note that it runs in the main window thread. When I create the UDP class I pass the parent to it.
using NAudio.CoreAudioApi;
using NAudio.Wave;
…
private bool _streamActive = false;
private BufferedWaveProvider bufferedWaveProvider = null;
private WaveOut waveOut = null;
private WaveFormat waveFormat=null;
public void ProcessSound(byte[] rxData)
{
// get data length
int datalen = rxData.Length;
// check to activate player
if (_streamActive == true)
{
// add samples to buffer
bufferedWaveProvider.AddSamples(rxData, 28, datalen - 28);
return;
}
// set up format
waveFormat = WaveFormat.CreateIeeeFloatWaveFormat(24000, 2);
// create buffer to allow samples to be added
bufferedWaveProvider = new BufferedWaveProvider(waveFormat);
// add samples to buffer
bufferedWaveProvider.AddSamples(rxData, 28, datalen - 28);
// create waveOut player
waveOut = new WaveOut();
waveOut.Init(bufferedWaveProvider);
waveOut.Volume = 0.25f;
waveOut.Play();
// mark stream is active
_streamActive = true;
}
I've not looked into the latency as yet but it can be tuned to a certain extent in any case. The next problem is to try to figure out how to actually send audio back to the flex for transmission.
I'd be interested to know if anybody uses this code in any projects, more likely it might be useful as a starting point.
Cliff, G4PZK
2 -
Cliff,
I am so sorry for not replying to your post years ago. I got distracted and lost track of my project. I retired at the end of 2020. Other than a few tweaks to my test program, I have not devoted any real time to it. I have finally decided that I need to try and get back into working on my program. I fully intend to try and integrate audio into my project using your example.
Thank you
James
WD5GWY
0
Leave a Comment
Categories
- All Categories
- 289 Community Topics
- 2.1K New Ideas
- 534 The Flea Market
- 7.5K Software
- 6K SmartSDR for Windows
- 146 SmartSDR for Maestro and M models
- 360 SmartSDR for Mac
- 249 SmartSDR for iOS
- 230 SmartSDR CAT
- 172 DAX
- 352 SmartSDR API
- 8.8K Radios and Accessories
- 7K FLEX-6000 Signature Series
- 26 FLEX-8000 Signature Series
- 850 Maestro
- 44 FlexControl
- 847 FLEX Series (Legacy) Radios
- 796 Genius Products
- 416 Power Genius XL Amplifier
- 277 Tuner Genius XL
- 103 Antenna Genius
- 243 Shack Infrastructure
- 166 Networking
- 404 Remote Operation (SmartLink)
- 130 Contesting
- 631 Peripherals & Station Integration
- 125 Amateur Radio Interests
- 870 Third-Party Software