public async Task <RadioCall> PostOneAsync([FromBody] RadioCall radioCall)
        {
            var tgIdent = radioCall.TalkGroupIdentifier;

            if (radioCall.TalkGroupId <= 0)
            {
                var talkGroup = await DbContext
                                .TalkGroups
                                .FirstOrDefaultAsync(t => t.Identifier == tgIdent);

                if (talkGroup == null)
                {
                    talkGroup = new TalkGroup()
                    {
                        Identifier = tgIdent
                    };

                    var tgEntity = await DbContext
                                   .TalkGroups
                                   .AddAsync(talkGroup);

                    await DbContext.SaveChangesAsync();

                    talkGroup = tgEntity.Entity;
                }

                radioCall.TalkGroupId = talkGroup.Id;
            }

            var radioCallEntity = await DbContext.RadioCalls.AddAsync(radioCall);

            await DbContext.SaveChangesAsync();

            return(radioCallEntity.Entity);
        }
示例#2
0
        public async Task SignalRadioClient_CanPostCall()
        {
            var radioCall = new RadioCall()
            {
                TalkGroupIdentifier = 123,
                CallState           = 123,
                CallRecordState     = 123,
                CallIdentifier      = "call",
                TalkGroupTag        = "abc",
                Elapsed             = 123,
                Length           = 123,
                IsPhase2         = true,
                IsConventional   = false,
                IsEncrypted      = false,
                IsAnalog         = false,
                StartTime        = 123,
                StopTime         = 123,
                FrequencyHz      = 1233123123,
                Frequency        = 123,
                CallSerialNumber = 123,
                CallWavPath      = "thisisthewave",
                SigmfFileName    = "sigmf",
                DebugFilename    = "debug",
                Filename         = "filename",
                StatusFilename   = "filename"
            };

            var result = await _signalRadioClient.PostCallAsync(radioCall);
        }
示例#3
0
        public void PublishVoiceCall(RadioCall call)
        {
            string message = JsonSerializer.Serialize(call);

            byte[] body = Encoding.UTF8.GetBytes(message);
            evtchannel.BasicPublish("radio_events", "", basicProperties: null, body: body);
        }
示例#4
0
        protected virtual bool GetMetadata(RadioCall radioCall, out string title, out string artist, out string comment)
        {
            var talkGroup = radioCall.TalkGroup;

            if (radioCall.TalkGroup is null)
            {
                throw new Exception("Unable to determine TalkGroup");
            }

            title   = null;
            artist  = null;
            comment = null;

            try
            {
                title   = string.Format("[{0}][{1}]", radioCall.CallSerialNumber, talkGroup.AlphaTag);
                artist  = string.Format("{0} ({1})", talkGroup.Identifier, talkGroup.Name);
                comment = talkGroup.Description;
                return(true);
            }
            catch (System.Exception)
            {
                return(false);
            }
        }
示例#5
0
        protected async Task <bool> PushCallToStreamAsync(RadioCall radioCall, CancellationToken cancellationToken = default(CancellationToken))
        {
            var tgStreams = await _client.GetStreamsByTalkGroupIdAsync(radioCall.TalkGroupId, cancellationToken);

            if (tgStreams is null)
            {
                return(false);
            }

            var queueCallMessage = string.Format("queue.push {0}{1}", radioCall.Filename, Environment.NewLine);

            foreach (var stream in tgStreams)
            {
                using (var mutex = new Mutex(true, $"SR_{stream.Id}"))
                {
                    bool streamQueueResult = false;
                    try
                    {
                        mutex.WaitOne();
                        var socketPath = Path.Join(_liquidBridgeConfig.LiquidsoapSocketsPath, string.Format("{0}.sock", stream.StreamIdentifier));

                        if (!File.Exists(socketPath))
                        {
                            System.Console.WriteLine("Stream Socket missing, starting new stream...");
                            var streamConfigPath = _liquidBridgeConfig.BuildLiquidsoapConfig(stream.StreamIdentifier, stream.StreamIdentifier, radioCall?.TalkGroup?.Description, "Radio");
                            if (!await StartStreamAsync(streamConfigPath, () => File.Exists(socketPath), cancellationToken))
                            {
                                continue;
                            }
                        }

                        streamQueueResult = SendMessageToSocket(queueCallMessage, socketPath, cancellationToken) > 0;
                    }
                    catch (OperationCanceledException)
                    {
                        return(true);
                    }
                    catch (Exception e)
                    {
                        System.Console.WriteLine(e);
                    }
                    finally
                    {
                        if (streamQueueResult)
                        {
                            System.Console.WriteLine("{0} >> {1}", stream.StreamIdentifier, queueCallMessage);
                        }
                        else
                        {
                            System.Console.WriteLine("{0} XX Failed", stream.StreamIdentifier);
                        }
                    }
                }
            }
            return(true);
        }
示例#6
0
        public async Task <RadioCall> PostCallAsync(RadioCall radioCall, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (radioCall is null)
            {
                throw new ArgumentNullException(nameof(radioCall));
            }

            var response = await _httpClient.PostAsJsonAsync("RadioCalls", radioCall, cancellationToken);

            response.EnsureSuccessStatusCode();

            return(await response.Content.ReadAsAsync <RadioCall>(cancellationToken));
        }
        private async Task HandleCallsActiveAsync(IEnumerable <Call> calls, CancellationToken cancellationToken = default(CancellationToken))
        {
            foreach (var call in calls)
            {
                var radioCall = await DbContext.RadioCalls.FirstOrDefaultAsync(c => c.CallIdentifier == call.Id);

                if (radioCall == null)
                {
                    radioCall = RadioCall.FromCall(call);

                    await DbContext
                    .RadioCalls.AddAsync(radioCall, cancellationToken);
                }
                else
                {
                    radioCall.UpdateFromCall(call);
                }
            }
        }
示例#8
0
        protected virtual void ConvertCallWavToMp3(RadioCall radioCall, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (radioCall is null)
            {
                throw new ArgumentNullException(nameof(radioCall));
            }

            var inputFile = new FileInfo(radioCall.CallWavPath);

            if (!inputFile.Exists)
            {
                throw new Exception("Missing input file");
            }


            var tempDir    = Path.GetTempPath();
            var outputPath = Path.Join(tempDir, string.Format("{0}.mp3", inputFile.Name.TrimEnd(inputFile.Extension.ToArray())));

            string title   = string.Empty;
            string artist  = string.Empty;
            string comment = string.Empty;

            if (!GetMetadata(radioCall, out title, out artist, out comment))
            {
                throw new Exception("Could not GetMetadata");
            }

            var lamePath = "/usr/bin/lame";
            var lameArgs = string.Format("--quiet --preset voice --tt \"{0}\" --ta \"{1}\", --tc \"{2}\" {3} {4}", title, artist, comment, inputFile.FullName, outputPath);

            //Execute Lame to convert, timeout after 20 seconds, success on result code 0
            if (ExecuteProcess(lamePath, lameArgs, true, 20 * 1000) == 0)
            {
                radioCall.Filename = outputPath;
                System.Console.WriteLine("Converted call to mp3: {0}", radioCall.Filename);
            }
        }
示例#9
0
        static void HandleUserCall(object sender, CallEventArgs e)
        {
            RadioCall call    = e.Call;
            string    rssiStr = "";

            if (!double.IsNaN(call.RSSI))
            {
                rssiStr = " RSSI " + call.RSSI;
                DBRadio r = db.ReadRadio(call.From);
                if (r == null)
                {
                    r = new DBRadio(call.From.Int, call.RSSI);
                }
                else
                {
                    r.AddReading(call.RSSI);
                }
                db.UpdateRadio(r);
            }
            if (call.IsAudio)
            {
                Console.WriteLine("Audio Call : {0} => {1} " + rssiStr, call.From, call.To);
                AudioCall ac       = (AudioCall)call;
                string    filename = String.Format(@"E:\RadioCalls\{0} - {1} to {2}.mp3", call.Start.ToString("yyyy-MM-ddTHH-mm-ss"), call.From.Int, call.To.Int);
                try
                {
                    ac.SaveToMP3(filename);
                }
                catch (Exception)
                {
                    Console.WriteLine("Unable to decode audio!");
                }
                db.WriteVoiceCall(call.From, call.To, call.Start, call.End, call.RSSI, call.Slot, filename);
                srv.PublishVoiceCall(call);
            }
            else
            {
                DataCall dc = (DataCall)call;
                switch (dc.DataType)
                {
                case CallDataType.TMS:
                    if (dc.TextMessage.Type == MessageType.Ack)
                    {
                        Console.WriteLine("Text Message Ack : {0} => {1}" + rssiStr, call.From, call.To);
                    }
                    else if (dc.TextMessage != null)
                    {
                        Console.WriteLine("Text Message : {0} => {1} \"{2}\"" + rssiStr, call.From, call.To, dc.TextMessage.Message);
                    }
                    else
                    {
                        Console.WriteLine("Text Message : {0} => {1} unable to parse!" + rssiStr, call.From, call.To);
                    }
                    break;

                case CallDataType.LRRP:
                    LRRPPacket pkt = dc.LRRPPacket;
                    if (pkt.Type == LRRPPacketType.ImmediateLocationResponse || pkt.Type == LRRPPacketType.TriggeredLocationData)
                    {
                        Console.WriteLine("Got LRRP Packet from {0} {1} {2}", call.From, pkt, rssiStr);
                    }
                    else
                    {
                        Console.WriteLine("Got LRRP Control Message: {0} => {1}" + rssiStr, call.From, call.To);
                    }
                    break;

                case CallDataType.ICMP:
                    Console.WriteLine("Got ICMP Ping: {0} => {1}" + rssiStr, call.From, call.To);
                    break;

                case CallDataType.RadioCheck:
                    Console.WriteLine("Got Radio Check: {0} => {1}" + rssiStr, call.From, call.To);
                    break;

                case CallDataType.RadioCheckAck:
                    Console.WriteLine("Got Radio Check Ack: {0} => {1}" + rssiStr, call.From, call.To);
                    break;

                case CallDataType.UnknownSmall:
                case CallDataType.IPAck:
                    //Just ignore this
                    break;

                default:
                    Console.WriteLine("Data Call Type is {0}", dc.DataType);
                    Console.WriteLine("Got Unknown radio call: {0} => {1}" + rssiStr, call.From, call.To);
                    Console.WriteLine("    " + BitConverter.ToString(call.Data));
                    break;
                }
            }
        }
示例#10
0
        public async Task Test1()
        {
            var templateResource   = (new FileInfo("Resources/stream.defaults.liq")).FullName;
            var talkgroupsResource = (new FileInfo("Resources/danecom-talkgroups.priorities.csv")).FullName;

            var liquidBridgeConfig = new LiquidBridgeConfig()
            {
                IcecastHost            = "192.168.1.215",
                IcecastPort            = 8000,
                StreamPassword         = "******",
                LiquidsoapSocketsPath  = Path.Join(Directory.GetCurrentDirectory(), "ls-socks"),
                LiquidsoapTemplatePath = templateResource,
                ConnectionString       = "http://127.0.0.1:8001/api/"
            };

            var expectedTalkGroupIdentifier = (ushort)13050;
            var expectedCallIdentifier      = (ulong)1594255860;
            var expectedFrequency           = 172075000;
            var expectedOriginalExtension   = "wav";
            var expectedConvertedExtension  = "mp3";

            if (Directory.Exists(liquidBridgeConfig.LiquidsoapSocketsPath))
            {
                Directory.Delete(liquidBridgeConfig.LiquidsoapSocketsPath);
            }

            Directory.CreateDirectory(liquidBridgeConfig.LiquidsoapSocketsPath);

            var tempDir = Path.GetTempPath();

            var callWavPath = Path.Join(tempDir, string.Format("{0}-{1}_{2}.{3}", expectedTalkGroupIdentifier, expectedCallIdentifier, expectedFrequency, expectedOriginalExtension));

            if (File.Exists(callWavPath))
            {
                File.Delete(callWavPath);
            }

            File.Create(callWavPath).Close();

            var mockStream1 = new Stream()
            {
                Id = 1,
                StreamIdentifier = "stream-1"
            };

            var mockStream2 = new Stream()
            {
                Id = 2,
                StreamIdentifier = "stream-2"
            };

            var mockStream3 = new Stream()
            {
                Id = 3,
                StreamIdentifier = "stream-3"
            };

            var mockTalkGroup = new TalkGroup()
            {
                Id               = 1,
                AlphaTag         = "TGPALPHA",
                Identifier       = expectedTalkGroupIdentifier,
                Name             = "Tag Test Alpha (1)",
                Description      = "This channel is used for testing",
                TalkGroupStreams = new Collection <TalkGroupStream>()
            };

            mockTalkGroup.TalkGroupStreams.Add(new TalkGroupStream()
            {
                TalkGroup = mockTalkGroup, TalkGroupId = mockTalkGroup.Id, Stream = mockStream1, StreamId = mockStream1.Id
            });
            mockTalkGroup.TalkGroupStreams.Add(new TalkGroupStream()
            {
                TalkGroup = mockTalkGroup, TalkGroupId = mockTalkGroup.Id, Stream = mockStream2, StreamId = mockStream2.Id
            });
            mockTalkGroup.TalkGroupStreams.Add(new TalkGroupStream()
            {
                TalkGroup = mockTalkGroup, TalkGroupId = mockTalkGroup.Id, Stream = mockStream3, StreamId = mockStream3.Id
            });

            var mockRadioCall = new RadioCall()
            {
                Id               = 1,
                TalkGroupId      = mockTalkGroup.Id,
                TalkGroup        = mockTalkGroup,
                CallIdentifier   = expectedCallIdentifier.ToString(),
                CallSerialNumber = (long)expectedCallIdentifier,
                CallWavPath      = callWavPath,
                FrequencyHz      = expectedFrequency,
                Frequency        = expectedFrequency
            };

            var clientMock = new Mock <ISignalRadioClient>();

            clientMock
            .Setup(c => c.GetTalkGroupByIdentifierAsync(expectedTalkGroupIdentifier, It.IsAny <CancellationToken>()))
            .ReturnsAsync(mockTalkGroup);

            clientMock
            .Setup(c => c.PostCallAsync(It.IsAny <RadioCall>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(mockRadioCall);

            var talkGroupStreams = new Collection <Stream>(mockTalkGroup.TalkGroupStreams.Select(t => t.Stream).ToList());

            clientMock
            .Setup(c => c.GetStreamsByTalkGroupIdAsync(mockTalkGroup.Id, It.IsAny <CancellationToken>()))
            .ReturnsAsync(talkGroupStreams);

            var handlerMock = new Mock <CallHandler>()
            {
                CallBase = true
            };

            handlerMock
            .Protected()
            .Setup <int>("ExecuteProcess", "/usr/bin/liquidsoap", ItExpr.IsAny <string>(), ItExpr.IsAny <bool>(), ItExpr.IsAny <int>())
            .Returns(0);     //return 0 for success


            var handler = new CallHandler(liquidBridgeConfig, clientMock.Object);

            await handler.HandleCallAsync(callWavPath);
        }