protected override void OnStop() { // TODO: Add code here to perform any tear-down necessary to stop your service. m_Server.Stop(); CommonLog.Info("=== Stream Recorder stopped ==="); }
protected override void OnStart(string[] args) { // TODO: Add code here to start your service. CommonLog.Info("=== Stream Recorder is starting ==="); m_Server.Start(); }
public void Start() { Stop(); ConfigurationManager.RefreshSection("appSettings"); ConfigurationManager.RefreshSection("channels"); var appSettings = ConfigurationManager.AppSettings; if (appSettings.AllKeys.Contains("Converter")) { m_Config.Converter = appSettings["Converter"]; } if (appSettings.AllKeys.Contains("RemoteCallbackURL")) { m_Config.Callback = appSettings["RemoteCallbackURL"]; } if (appSettings.AllKeys.Contains("StreamDataFolder")) { m_Config.StreamDataFolder = appSettings["StreamDataFolder"]; } if (appSettings.AllKeys.Contains("RecordFileFolder")) { m_Config.RecordFileFolder = appSettings["RecordFileFolder"]; } if (appSettings.AllKeys.Contains("RecordContentType")) { m_Config.RecordContentType = appSettings["RecordContentType"]; } if (appSettings.AllKeys.Contains("MustCreateOutputFile")) { m_Config.MustCreateOutputFile = Convert.ToInt32(appSettings["MustCreateOutputFile"].ToString()); } if (appSettings.AllKeys.Contains("VideoStartOffset")) { m_Config.VideoStartOffset = Convert.ToDecimal(appSettings["VideoStartOffset"].ToString()); } if (appSettings.AllKeys.Contains("AudioStartOffset")) { m_Config.AudioStartOffset = Convert.ToDecimal(appSettings["AudioStartOffset"].ToString()); } m_Config.VideoStartOffset = Decimal.Round(m_Config.VideoStartOffset, 2); m_Config.AudioStartOffset = Decimal.Round(m_Config.AudioStartOffset, 2); if (appSettings.AllKeys.Contains("MaxCacheSize")) { var cacheSize = appSettings["MaxCacheSize"].ToString().ToLower(); if (cacheSize.Last() == 'k') { m_Config.MaxCacheSize = Convert.ToInt32(cacheSize.Substring(0, cacheSize.Length - 1)) * 1024; } else if (cacheSize.Last() == 'm') { m_Config.MaxCacheSize = Convert.ToInt32(cacheSize.Substring(0, cacheSize.Length - 1)) * 1024 * 1024; } else { m_Config.MaxCacheSize = Convert.ToInt32(cacheSize); } } if (appSettings.AllKeys.Contains("MaxRecordSize")) { var recordSize = appSettings["MaxRecordSize"].ToString().ToLower(); if (recordSize.Last() == 'k') { m_Config.MaxRecordSize = Convert.ToInt32(recordSize.Substring(0, recordSize.Length - 1)) * 1024; } else if (recordSize.Last() == 'm') { m_Config.MaxRecordSize = Convert.ToInt32(recordSize.Substring(0, recordSize.Length - 1)) * 1024 * 1024; } else { m_Config.MaxRecordSize = Convert.ToInt32(recordSize); } } string streamDataFolder = Path.GetFullPath(m_Config.StreamDataFolder); string recordFileFolder = Path.GetFullPath(m_Config.RecordFileFolder); List <string> whitelist = new List <string>(); if (appSettings.AllKeys.Contains("Whitelist")) { var list = appSettings["Whitelist"].ToString().Split(','); foreach (var item in list) { whitelist.Add(item.Trim()); } } string allowOrigin = ""; if (appSettings.AllKeys.Contains("AllowOrigin")) { allowOrigin = appSettings["AllowOrigin"].ToString(); } int httpPort = 9009; if (appSettings.AllKeys.Contains("ServerPort")) { httpPort = Convert.ToInt32(appSettings["ServerPort"].ToString()); } if (httpPort > 0) { try { m_CommandServer = new CommandServer(this, httpPort, whitelist, allowOrigin); if (!m_CommandServer.Start()) { CommonLog.Error("Failed to start command server on port: " + httpPort); try { m_CommandServer.Stop(); } catch { } m_CommandServer = null; } else { for (int i = 0; i < 20; i++) { if (!m_CommandServer.IsWorking()) { Thread.Sleep(50); } else { break; } } if (m_CommandServer.IsWorking()) { CommonLog.Info("Started command server on port: " + httpPort); } } } catch { } } try { if (!Directory.Exists(streamDataFolder)) { Directory.CreateDirectory(streamDataFolder); } } catch (Exception ex) { CommonLog.Error("Failed to create StreamDataFolder: " + streamDataFolder); CommonLog.Error(ex.Message); m_Config.StreamDataFolder = ""; } try { if (!Directory.Exists(recordFileFolder)) { Directory.CreateDirectory(recordFileFolder); } } catch (Exception ex) { CommonLog.Error("Failed to create RecordFileFolder: " + recordFileFolder); CommonLog.Error(ex.Message); m_Config.RecordFileFolder = ""; } var channelSettings = (NameValueCollection)ConfigurationManager.GetSection("channels"); var allKeys = channelSettings.AllKeys; lock (m_Clients) { m_Clients.Clear(); foreach (var key in allKeys) { if (key.Trim().Length <= 0) { continue; } string url = channelSettings[key]; m_Clients.Add(new MediaClient(key, url, m_Config)); } } m_AutoKeepOnlineTimer = new Timer(TryToKeepClientsOnline, m_Clients, 500, 1000 * 15); }
private void ProcessRequest(Dictionary <string, string> reqestParams) { if (m_RecordServer == null) { return; } if (!reqestParams.ContainsKey("command")) { return; } CommonLog.Info("Request: " + JsonConvert.SerializeObject(reqestParams)); if (reqestParams["command"] == "record") { if (!reqestParams.ContainsKey("channel")) { return; } if (!reqestParams.ContainsKey("filename")) { return; } var client = m_RecordServer.GetClient(reqestParams["channel"]); if (client != null) { if (client.IsRecording && client.StreamDataFileName.Length > 0) { bool needToEndCurrentRecord = true; if (client.StreamDataFileName == reqestParams["filename"]) { needToEndCurrentRecord = false; } else if (reqestParams.ContainsKey("mainpart")) { string mainPart = reqestParams["mainpart"]; if (mainPart.Length >= 4 && client.StreamDataFileName.Contains(mainPart)) { needToEndCurrentRecord = false; } } if (needToEndCurrentRecord) { client.Export(); Thread.Sleep(500); } } client.Record(reqestParams["filename"]); } else { CommonLog.Error("Failed to record stream: channel [" + reqestParams["channel"] + "] is not found."); } } else if (reqestParams["command"] == "stop") { if (!reqestParams.ContainsKey("channel")) { return; } var client = m_RecordServer.GetClient(reqestParams["channel"]); if (client != null) { client.Export(); } } }
public static int Main(string[] args) { AppDomain.CurrentDomain.UnhandledException += CurrentDomainUnhandledException; // start the program ... if (Environment.UserInteractive) { string parameter = ""; bool needDetails = false; if (args != null && args.Length >= 1) { parameter = args[0]; parameter = parameter.Trim(); if (parameter == "install" || parameter == "uninstall" || parameter == "silent-install" || parameter == "silent-uninstall") { if (parameter == "silent-install" || parameter == "silent-uninstall") { if (parameter == "silent-install") { parameter = "install"; } else if (parameter == "silent-uninstall") { parameter = "uninstall"; } } else { // redirect console output to parent process, normally it should be "cmd" AttachConsole(ATTACH_PARENT_PROCESS); needDetails = true; } string svcName = ""; if (args.Length >= 2) { string[] svcNameArgs = new string[args.Length - 1]; for (int i = 1; i < args.Length; i++) { svcNameArgs[i - 1] = args[i]; } for (int i = 0; i < svcNameArgs.Length; i++) { if (svcName.Length == 0) { svcName = svcNameArgs[i]; } else { svcName = svcName + " " + svcNameArgs[i]; } } svcName = svcName.Trim(); } if (svcName.Length > 0) { SVC_NAME = svcName; } } else { parameter = ""; } } parameter = parameter.Trim(); if (parameter == "install" && SVC_NAME.Length > 0) { Console.WriteLine("Start to install service with name [" + SVC_NAME + "]"); CommonLog.Info("Installing service..."); try { ManagedInstallerClass.InstallHelper(new string[] { Assembly.GetExecutingAssembly().Location }); CommonLog.Info("OK"); Console.WriteLine("Installed service [" + SVC_NAME + "] successfully"); if (needDetails) { Console.WriteLine("You might need to press enter to end the process"); } } catch (Exception ex) { CommonLog.Error("Error: " + ex.Message); Console.WriteLine("Failed to install service [" + SVC_NAME + "]"); if (needDetails) { Console.WriteLine("You might need to press enter to end the process"); } return(-1); } } else if (parameter == "uninstall" && SVC_NAME.Length > 0) { Console.WriteLine("Start to uninstall service [" + SVC_NAME + "]"); CommonLog.Info("Uninstalling service..."); try { ManagedInstallerClass.InstallHelper(new string[] { "/u", Assembly.GetExecutingAssembly().Location }); CommonLog.Info("OK"); Console.WriteLine("Uninstalled service [" + SVC_NAME + "] successfully"); if (needDetails) { Console.WriteLine("You might need to press enter to end the process"); } } catch (Exception ex) { CommonLog.Error("Error: " + ex.Message); //Console.WriteLine("Failed to uninstall service [" + SVC_NAME + "]"); if (needDetails) { Console.WriteLine("You might need to press enter to end the process"); } return(-1); } } else // Run as a console app normally ... { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new MainForm()); Environment.Exit(0); } } else { ServiceBase[] ServicesToRun; ServicesToRun = new ServiceBase[] { new RecorderService() }; ServiceBase.Run(ServicesToRun); } return(0); }
private void WhenDataReceived(object sender, WebSocket4Net.DataReceivedEventArgs e) { if (Info.Status == "closed") { return; } IsReceiving = true; Info.LastDataTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); string overloadFileName = ""; lock (StreamDataFileName) { Info.Status = IsRecording ? "recording" : "receiving"; if (!IsRecording || StreamDataFileName.Length <= 0) { return; } m_CurrentRecordSize += e.Data.Length; if (m_CurrentRecordSize > MaxRecordSize) { overloadFileName = String.Copy(StreamDataFileName); CommonLog.Info("Exceeded max size limit of " + MaxRecordSize + " - " + overloadFileName); } else { if (e.Data.Length > 4 && (e.Data[0] == 0 && e.Data[1] == 0 && e.Data[2] == 0 && e.Data[3] == 1) && m_RawVideoFilePath.Length > 0) { m_VideoCache.Write(e.Data, 0, e.Data.Length); m_VideoCacheSize += e.Data.Length; if (m_VideoCacheSize >= MaxCacheSize) { if (m_RawVideoFilePath.Length > 0 && File.Exists(m_RawVideoFilePath)) { try { using (var fs = new FileStream(m_RawVideoFilePath, FileMode.Append, FileAccess.Write)) { var writer = new BinaryWriter(fs); writer.Write(m_VideoCache.ToArray()); writer.Close(); } } catch (Exception ex) { CommonLog.Error(ex.ToString()); } } else { CommonLog.Error("Video stream data file not found: " + m_RawVideoFilePath); } m_VideoCacheSize = 0; if (m_VideoCache != null) { m_VideoCache.Dispose(); } m_VideoCache = new MemoryStream(); } } else if (e.Data.Length > 0 && m_RawAudioFilePath.Length > 0) { m_AudioCache.Write(e.Data, 0, e.Data.Length); m_AudioCacheSize += e.Data.Length; if (m_AudioCacheSize >= MaxCacheSize) { if (m_RawAudioFilePath.Length > 0 && File.Exists(m_RawAudioFilePath)) { try { using (var fs = new FileStream(m_RawAudioFilePath, FileMode.Append, FileAccess.Write)) { var writer = new BinaryWriter(fs); writer.Write(m_AudioCache.ToArray()); writer.Close(); } } catch (Exception ex) { CommonLog.Error(ex.ToString()); } } else { CommonLog.Error("Audio stream data file not found: " + m_RawAudioFilePath); } m_AudioCacheSize = 0; if (m_AudioCache != null) { m_AudioCache.Dispose(); } m_AudioCache = new MemoryStream(); } } } // end if filesize ok } // end of lock if (overloadFileName.Length > 0) { Task.Factory.StartNew(() => Export(overloadFileName)); } }
private void CallConvertProcess(object rawfile) { var inputParts = rawfile.ToString().Trim().Split(','); if (inputParts.Length < 4) { return; } string converterCmd = inputParts[0].Trim(); string channelName = ""; if (inputParts.Length > 6) { channelName = inputParts[6].Trim(); } if (channelName.Length <= 0) { channelName = "?"; } string callbackUrl = ""; if (inputParts.Length > 7) { callbackUrl = inputParts[7].Trim(); } if (callbackUrl.Length < 2) { callbackUrl = ""; } string outputFolder = inputParts[1].Trim(); string inputVideoFile = inputParts[2].Trim(); string inputAudioFile = inputParts[3].Trim(); string outputFileName = ""; if (inputVideoFile.Length > 1) { outputFileName = Path.GetFileNameWithoutExtension(inputVideoFile); } else if (inputAudioFile.Length > 1) { outputFileName = Path.GetFileNameWithoutExtension(inputAudioFile); } if (outputFileName.Length <= 0) { return; } string outputTempFile = ""; string outputFile = outputFolder + "/" + outputFileName + ".mp4"; try { if (outputFile.Length > 0 && File.Exists(outputFile)) { File.Delete(outputFile); } } catch (Exception ex) { CommonLog.Error(ex.ToString()); } CommonLog.Info("Going to convert file: [" + inputVideoFile + "] + [" + inputAudioFile + "] => [" + outputFile + "]"); List <string> convertParamList = new List <string>(); if (inputVideoFile.Length > 1 && inputAudioFile.Length > 1) { string videoStartOffset = "0"; string audioStartOffset = "0"; if (inputParts.Length > 4) { videoStartOffset = inputParts[4].Trim(); } if (inputParts.Length > 5) { audioStartOffset = inputParts[5].Trim(); } if (videoStartOffset.Length > 0 && videoStartOffset != "0") { audioStartOffset = "0"; // should not enable both } string videoStartOffsetOption = ""; string audioStartOffsetOption = ""; if (videoStartOffset != "0") { videoStartOffsetOption = " -ss " + videoStartOffset; } if (audioStartOffset != "0") { audioStartOffsetOption = " -ss " + audioStartOffset; } if (videoStartOffsetOption.Length <= 0 && audioStartOffsetOption.Length <= 0) { string convertParamLine = ""; convertParamLine = "-y -i \"" + inputVideoFile + "\" "; if (inputAudioFile.Contains(".pcm")) { convertParamLine += "-f u8 -ac 1 "; } convertParamLine += "-i \"" + inputAudioFile + "\" "; convertParamLine += "-c:v copy "; if (!inputAudioFile.Contains(".aac")) { convertParamLine += "-c:a aac "; } else { convertParamLine += "-c:a copy -bsf:a aac_adtstoasc "; } convertParamLine += "-f mp4 \"" + outputFile + "\""; convertParamList.Add(convertParamLine); } else { outputTempFile = outputFolder + "/" + outputFileName + ".tmp.mp4"; string convertParamLine1 = ""; convertParamLine1 = "-y -i \"" + inputVideoFile + "\" "; if (inputAudioFile.Contains(".pcm")) { convertParamLine1 += "-f u8 -ac 1 "; } convertParamLine1 += "-i \"" + inputAudioFile + "\" "; convertParamLine1 += "-c:v copy -c:a copy "; if (!inputAudioFile.Contains(".aac")) { convertParamLine1 += "-c:a aac "; } else { convertParamLine1 += "-c:a copy -bsf:a aac_adtstoasc "; } convertParamLine1 += "-f mp4 \"" + outputTempFile + "\""; convertParamList.Add(convertParamLine1); string convertParamLine2 = ""; convertParamLine2 = "-y " + videoStartOffsetOption + " -i \"" + outputTempFile + "\" "; convertParamLine2 += audioStartOffsetOption + " -i \"" + outputTempFile + "\" "; convertParamLine2 += "-map 0:v -map 1:a -c:v copy -c:a copy "; convertParamLine2 += "-f mp4 \"" + outputFile + "\""; convertParamList.Add(convertParamLine2); } } else if (inputVideoFile.Length > 1) { string convertParamLine = ""; convertParamLine = "-y -i \"" + inputVideoFile + "\" "; convertParamLine += "-c:v copy -an "; convertParamLine += "-f mp4 \"" + outputFile + "\""; convertParamList.Add(convertParamLine); } else if (inputAudioFile.Length > 1) { string convertParamLine = ""; convertParamLine = "-y "; if (inputAudioFile.Contains(".pcm")) { convertParamLine += "-f u8 -ac 1 "; } convertParamLine += "-i \"" + inputAudioFile + "\" "; convertParamLine += "-c:a copy -vn "; if (!inputAudioFile.Contains(".aac")) { convertParamLine += "-c:a aac "; } else { convertParamLine += "-c:a copy -bsf:a aac_adtstoasc "; } convertParamLine += "-f mp4 \"" + outputFile + "\""; convertParamList.Add(convertParamLine); } try { foreach (var paramLine in convertParamList) { //CommonLog.Info(paramLine); ProcessStartInfo pinfo = new ProcessStartInfo(converterCmd, paramLine); pinfo.WorkingDirectory = AppDomain.CurrentDomain.BaseDirectory; pinfo.UseShellExecute = false; pinfo.CreateNoWindow = true; using (Process process = Process.Start(pinfo)) { process.WaitForExit(); } } if (outputTempFile.Length > 0) { try { if (File.Exists(outputTempFile)) { File.Delete(outputTempFile); } } catch (Exception ex) { CommonLog.Error("Failed to delete convertion temp file: " + outputTempFile); CommonLog.Error(ex.Message); } } if (outputFile.Length > 0 && File.Exists(outputFile)) { try { if (inputVideoFile.Length > 1 && File.Exists(inputVideoFile)) { File.Delete(inputVideoFile); } } catch (Exception ex) { CommonLog.Error("Failed to delete video stream data file: " + inputVideoFile); CommonLog.Error(ex.Message); } try { if (inputAudioFile.Length > 1 && File.Exists(inputAudioFile)) { File.Delete(inputAudioFile); } } catch (Exception ex) { CommonLog.Error("Failed to delete video stream data file: " + inputAudioFile); CommonLog.Error(ex.Message); } CommonLog.Info("Finished converting: " + outputFile); if (callbackUrl.Length > 0) { try { HttpWebRequest httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(callbackUrl); httpWebRequest.ContentType = "text/plain"; httpWebRequest.Method = "POST"; using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream())) { streamWriter.Write(channelName + "|" + outputFileName.Trim()); streamWriter.Flush(); streamWriter.Close(); } HttpWebResponse response = (HttpWebResponse)httpWebRequest.GetResponse(); using (StreamReader sr = new StreamReader(response.GetResponseStream())) { string responseResult = sr.ReadToEnd(); if (responseResult == null) { responseResult = ""; } else { responseResult = responseResult.Trim(); } CommonLog.Info("Got remote callback response: " + responseResult); } } catch (Exception ex) { CommonLog.Error("Failed to send request to inform remote server: " + ex.Message); } } } else { CommonLog.Info("Failed to convert live stream to MP4!"); } } catch (Exception ex) { CommonLog.Error("Failed to convert live stream to MP4: " + ex.ToString()); } }
public void Record(string outputFileName = "", bool needOverwrite = true) { lock (StreamDataFileName) { if (Info.Status == "closed") { return; } if (Info.MediaInfo.Length <= 0) { return; } if (IsRecording || StreamDataFileName.Length > 0) { return; } string outputFile = outputFileName; if (outputFile == null || outputFile.Length <= 0) { outputFile = ChannelName + "_" + DateTime.Now.ToString("yyyyMMddHHmmss"); } m_RawVideoFilePath = ""; m_RawAudioFilePath = ""; if (m_RawVideoType.Length > 0) { m_RawVideoFilePath = m_StreamDataFolder + "/" + outputFile + "." + m_RawVideoType; } if (m_RawAudioType.Length > 0) { m_RawAudioFilePath = m_StreamDataFolder + "/" + outputFile + "." + m_RawAudioType; } if (RecordContentType == "video") { m_RawAudioFilePath = ""; } if (RecordContentType == "audio") { m_RawVideoFilePath = ""; } if (needOverwrite) { try { if (m_RawVideoFilePath.Length > 0 && File.Exists(m_RawVideoFilePath)) { File.Delete(m_RawVideoFilePath); } } catch (Exception ex) { CommonLog.Error("Failed to delete old data file: " + m_RawVideoFilePath); CommonLog.Error(ex.ToString()); } try { if (m_RawAudioFilePath.Length > 0 && File.Exists(m_RawAudioFilePath)) { File.Delete(m_RawAudioFilePath); } } catch (Exception ex) { CommonLog.Error("Failed to delete old data file: " + m_RawAudioFilePath); CommonLog.Error(ex.ToString()); } } try { if (m_RawVideoFilePath.Length > 0 && !File.Exists(m_RawVideoFilePath)) { using (var fs = File.Create(m_RawVideoFilePath)) { } } } catch (Exception ex) { string errmsg = "Failed to create/open data file: " + m_RawVideoFilePath; m_RawVideoFilePath = ""; CommonLog.Error(errmsg); CommonLog.Error(ex.ToString()); } try { if (m_RawAudioFilePath.Length > 0 && !File.Exists(m_RawAudioFilePath)) { using (var fs = File.Create(m_RawAudioFilePath)) { } } } catch (Exception ex) { string errmsg = "Failed to create/open data file: " + m_RawAudioFilePath; m_RawAudioFilePath = ""; CommonLog.Error(errmsg); CommonLog.Error(ex.ToString()); } if (m_RawVideoFilePath.Length > 0 && File.Exists(m_RawVideoFilePath)) { m_RawVideoFilePath = Path.GetFullPath(m_RawVideoFilePath); m_VideoCacheSize = 0; if (m_VideoCache != null) { m_VideoCache.Dispose(); } m_VideoCache = new MemoryStream(); CommonLog.Info("Start to record video: " + m_RawVideoFilePath); } else { m_RawVideoFilePath = ""; } if (m_RawAudioFilePath.Length > 0 && File.Exists(m_RawAudioFilePath)) { m_RawAudioFilePath = Path.GetFullPath(m_RawAudioFilePath); m_AudioCacheSize = 0; if (m_AudioCache != null) { m_AudioCache.Dispose(); } m_AudioCache = new MemoryStream(); CommonLog.Info("Start to record audio: " + m_RawAudioFilePath); } else { m_RawAudioFilePath = ""; } if (m_RawVideoFilePath.Length > 0 || m_RawAudioFilePath.Length > 0) { IsRecording = true; StreamDataFileName = outputFile; m_CurrentRecordSize = 0; } else { IsRecording = false; StreamDataFileName = ""; } } }