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); }
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); }
public void PublishVoiceCall(RadioCall call) { string message = JsonSerializer.Serialize(call); byte[] body = Encoding.UTF8.GetBytes(message); evtchannel.BasicPublish("radio_events", "", basicProperties: null, body: body); }
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); } }
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); }
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); } } }
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); } }
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; } } }
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); }