I am creating a pos app that cannot communicate with my fiscal printer. So I have decided to store a receipt in a text file as Json object and make Windows Service app with FileSystemWatch to check for file updates and forward it to printer. I am using third party library to communicate with the printer. Here is a code of the service:
Program.cs
static void Main(string[] args)
{
var program = new Watcher();
if (Environment.UserInteractive)
{
program.Start();
}
else
{
ServiceBase.Run(new ServiceBase[]
{
program
});
}
//ServiceBase[] ServicesToRun;
//ServicesToRun = new ServiceBase[]
//{
// new Watcher()
//};
//ServiceBase.Run(ServicesToRun);
}
Watcher.cs
public partial class Watcher : ServiceBase
{
[DllImport("advapi32.dll", SetLastError = true)]
private static extern bool SetServiceStatus(IntPtr handle, ref ServiceStatus serviceStatus);
public static OICFiscalPrinter printer { get; set; }
[StructLayout(LayoutKind.Sequential)]
public struct ServiceStatus
{
public long dwServiceType;
public ServiceState dwCurrentState;
public long dwControlsAccepted;
public long dwWin32ExitCode;
public long dwServiceSpecificExitCode;
public long dwCheckPoint;
public long dwWaitHint;
};
public enum ServiceState
{
SERVICE_STOPPED = 0x00000001,
SERVICE_START_PENDING = 0x00000002,
SERVICE_STOP_PENDING = 0x00000003,
SERVICE_RUNNING = 0x00000004,
SERVICE_CONTINUE_PENDING = 0x00000005,
SERVICE_PAUSE_PENDING = 0x00000006,
SERVICE_PAUSED = 0x00000007,
}
public Watcher()
{
InitializeComponent();
}
public void CheckReceipt(object e, FileSystemEventArgs args)
{
printer = new OICFiscalPrinter();
var name = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
string text = null;
try
{
text = System.IO.File.ReadAllText(name + "\\Pictures\\test.txt");
var BasketList = JsonConvert.DeserializeObject<List<ItemsOnFacture>>(text);
printer.PortConfigString = "PortName=COM4;DataBits=8;Speed=9600;" +
"Parity = N; StopBits = 1; FlowControl = X;" +
"ReadTimeout = 6000;" +
"WriteTimeout = 500; UseReadBuffer = 1";
printer.Active = true;
var t = printer.Open();
if (!t) return;
printer.OpenReceipt();
foreach (var item in BasketList)
{
printer.ReceiptItem(item.ItemName, item.VatFee == 5 ? "B" : item.VatFee == 8 ? "A" : "D",
(decimal)item.PriceBrutto,
item.Amount, "unit", (decimal)item.PriceBruttoSum);
}
printer.CloseReceipt((decimal)BasketList.Sum(w => w.PriceBruttoSum),
(decimal)BasketList.Sum(w => w.PriceBruttoSum));
printer.Close();
File.Delete(name + "\\Pictures\\test.txt");
}
catch
{
}
}
public void Start()
{
//Start Logic here
var serviceStatus = new ServiceStatus
{
dwCurrentState = ServiceState.SERVICE_START_PENDING,
dwWaitHint = 100000
};
this.fileSystemWatcher1 = new System.IO.FileSystemWatcher();
((System.ComponentModel.ISupportInitialize)(this.fileSystemWatcher1)).BeginInit();
//
// fileSystemWatcher1
//
this.fileSystemWatcher1.EnableRaisingEvents = true;
var name = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
fileSystemWatcher1 = new FileSystemWatcher(name + "\\Pictures", "test.txt")
{
EnableRaisingEvents = true,
IncludeSubdirectories = false,
NotifyFilter = NotifyFilters.DirectoryName
};
SetServiceStatus(this.ServiceHandle, ref serviceStatus);
this.fileSystemWatcher1.Changed += new System.IO.FileSystemEventHandler(this.CheckReceipt);
((System.ComponentModel.ISupportInitialize)(this.fileSystemWatcher1)).EndInit();
// Update the service state to Running.
serviceStatus.dwCurrentState = ServiceState.SERVICE_RUNNING;
SetServiceStatus(this.ServiceHandle, ref serviceStatus);
}
protected override void OnStart(string[] args)
{
Start();
}
protected override void OnContinue()
{
}
protected override void OnStop()
{
}
private FileSystemWatcher fileSystemWatcher1;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
//
// Watcher
//
components = new System.ComponentModel.Container();
this.ServiceName = "WATTOFP";
}
#endregion
}
ProjectInstaller.cs
[RunInstaller(true)]
public class ProjectInstaller : System.Configuration.Install.Installer
{
public ProjectInstaller()
{
InitializeComponent();
}
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.serviceProcessInstaller1 = new System.ServiceProcess.ServiceProcessInstaller();
this.serviceInstaller1 = new System.ServiceProcess.ServiceInstaller();
//
// serviceProcessInstaller1
//
this.serviceProcessInstaller1.Account = System.ServiceProcess.ServiceAccount.LocalSystem;
this.serviceProcessInstaller1.Password = null;
this.serviceProcessInstaller1.Username = null;
//
// serviceInstaller1
//
this.serviceInstaller1.Description = "WATTO Fiscal Printer";
this.serviceInstaller1.DisplayName = "WATTO Fiscal Printer";
this.serviceInstaller1.ServiceName = "WATTOFP";
this.serviceInstaller1.StartType = System.ServiceProcess.ServiceStartMode.Automatic;
//
// ProjectInstaller
//
this.Installers.AddRange(new System.Configuration.Install.Installer[] {
this.serviceProcessInstaller1,
this.serviceInstaller1});
}
#endregion
private System.ServiceProcess.ServiceProcessInstaller serviceProcessInstaller1;
private System.ServiceProcess.ServiceInstaller serviceInstaller1;
}
The problem is the fact that after installation when I try to run the service it starts and immediately stops as the warning appears. How can I make the service run and the watch the file for the changes?
The problem might be that service by default is running under system account. Thus user folder is not what you're expecting and there is no file there.
Usually when service cannot be started, there should be a error with exception in event log. Please post it here for further assistance.
Related
Based on below answer, I implemented least loaded connection for StackExchange.Redis:
https://stackoverflow.com/a/58106770
public class RedisConnectionWrapper : IRedisConnectionWrapper
{
#region Fields
private readonly Config _config;
private bool _disposed = false;
private readonly Lazy<string> _connectionString;
private static ConcurrentBag<Lazy<ConnectionMultiplexer>> _connections;
#endregion
#region Ctor
public RedisConnectionWrapper(Config config)
{
_config = config;
_connectionString = new Lazy<string>("CONNECTION_STRING");
ConnectionMultiplexer.SetFeatureFlag("preventthreadtheft", _config.RedisPreventThreadTheft);
if (_config.UseLeastLoadedConnection)
InitializeLeastLoadedConnections();
}
#endregion
/// <summary>
/// Initialize lazy connections to Redis servers
/// </summary>
/// <returns></returns>
private void InitializeLeastLoadedConnections()
{
_connections = new ConcurrentBag<Lazy<ConnectionMultiplexer>>();
for (var i = 0; i < _config.PoolSize; i++)
{
var connection = ConnectionMultiplexer.Connect(_connectionString.Value);
connection.IncludePerformanceCountersInExceptions = true;
_connections.Add(new Lazy<ConnectionMultiplexer>(connection));
}
}
/// <summary>
/// Get least loaded connection to Redis servers
/// </summary>
/// <returns></returns>
protected ConnectionMultiplexer GetLeastLoadedConnection()
{
Lazy<ConnectionMultiplexer> connection;
var loadedLazys = _connections.Where(lazy => lazy.IsValueCreated && lazy.Value.IsConnected);
if (loadedLazys.Count() == _connections.Count)
{
var minValue = _connections.Min(lazy => lazy.Value.GetCounters().TotalOutstanding);
connection = _connections.First(lazy => lazy.Value.GetCounters().TotalOutstanding == minValue);
}
else
{
Console.WriteLine("Creating a new connection to Redis");
connection = _connections.First(lazy => !lazy.IsValueCreated);
}
return connection.Value;
}
/// <summary>
/// Release all resources associated with this object
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
// Protected implementation of Dispose pattern.
protected virtual void Dispose(bool disposing)
{
if (_disposed)
return;
if (disposing)
{
if (_config.UseLeastLoadedConnection)
{
var activeConnections = _connections.Where(lazy => lazy.IsValueCreated).ToList();
activeConnections.ForEach(connection => connection.Value.Dispose());
}
}
_disposed = true;
}
But I'm getting this exception on high traffic:
System.InvalidOperationException: Sequence contains no matching element
at System.Linq.ThrowHelper.ThrowNoMatchException()
at System.Linq.Enumerable.First[TSource](IEnumerable1 source, Func2 predicate)
Anybody can help me?
After some traces, I did some changes and it worked:
var loadedLazys = _connections.Where(lazy => lazy.IsValueCreated);
if (loadedLazys.Count() == _connections.Count)
{
connection = _connections.OrderBy(lazy => lazy.Value.GetCounters().TotalOutstanding).First();
}
I changed this part of my code as well:
private void InitializeLeastLoadedConnections()
{
lock (_lock)
{
_connections = new ConcurrentBag<Lazy<ConnectionMultiplexer>>();
for (var i = 0; i < _config.PoolSize; i++)
{
_connections.Add(new Lazy<ConnectionMultiplexer>(() =>
{
var connection = ConnectionMultiplexer.Connect(_connectionString.Value);
connection.IncludePerformanceCountersInExceptions = true;
return connection;
}));
}
}
}
Also I changed the return type of GetLeastLoadedConnection() from ConnectionMultiplexer to IConnectionMultiplexer.
My Windows service runs briefly, and then stops (no err msg).
I have this code in Program.cs of my Windows service:
static class Program
{
[STAThread]
static void Main()
{
#if(!DEBUG)
var ServicesToRun = new ServiceBase[]
{
new RoboRprtrService()
};
ServiceBase.Run(ServicesToRun);
#else
var rrs = new RoboRprtrService();
rrs.ConfigureService();
Console.ReadLine();
#endif
}
}
The breakpoint here:
var rrs = new RoboRprtrService();
...is hit (the DEBUG constant is currently defined), and so is the call to "InitializeComponent()" in my ServiceBase class, which is as follows:
public partial class RoboRprtrService : ServiceBase
{
private Timer timer;
private bool operationIsRunning;
public RoboRprtrService()
{
InitializeComponent(); // <= Breakpoint here; is reached
}
protected override void OnStart(string[] args)
{
ConfigureService(); // <= Breakpoint here, not hit
}
public void ConfigureService()
{
const int ONE_HOUR = 3600000;
timer = new Timer { Interval = 50000 };
timer.Elapsed += timer_Tick;
timer.Enabled = true;
RoboRprtrLib.WriteToLog("RoboRprtrService has started");
}
private void timer_Tick(object sender, ElapsedEventArgs eeargs)
{
if (operationIsRunning) return; // <= Breakpoint here, not hit
operationIsRunning = true;
timer.Elapsed -= timer_Tick;
try
{
RoboRprtrLib.WriteToLog("Timer tick event has occurred");
RoboRprtrLib.GenerateAndSaveDueReports();
operationIsRunning = false;
}
finally
{
timer.Elapsed += timer_Tick;
}
}
protected override void OnStop()
{
timer.Enabled = false;
RoboRprtrLib.WriteToLog("RoboRprtrService has stopped");
}
}
When I step (F11) into the InitializeComponent(); in the constructor, it takes me to this machine-generated code:
namespace RoboReporterService
{
partial class RoboRprtrService
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
this.ServiceName = "Service1";
}
#endregion
}
}
...(into the InitializeComponent() method) and then the Service stops.
Why does my service fail to "stay alive"?
As a side note, this project's properties, on the Application tab, show the output type of this as "Windows Application"; shouldn't it be "Class Library"?
UPDATE
Note: If I call code from the ConfigureService() method in the Service class, like so:
public void ConfigureService()
{
const int ONE_HOUR = 3600000;
timer = new Timer { Interval = 50000 };
timer.Elapsed += timer_Tick;
timer.Enabled = true;
RoboRprtrLib.WriteToLog("RoboRprtrService has started");
operationIsRunning = true;
RoboRprtrLib.GenerateAndSaveDueReports();
operationIsRunning = false;
}
...it runs; but then the service stops, and the timer_Tick() handler is never reached, even though it is hooked up in ConfigureService()
I have SinglaR hub class "MyHub" and a .net client class that connects to it successfully in runtime. however when i'm testing the client with nunit test it doesn't connect, I've debugged the test and find that hub instance doesn't created by SinglaR's hub activator class.
I'm using Resharper nunit runner for running test.
Here is my hub class structure, i've remove method's body for simplicity.
[HubName("myHub")]
public class MyHub : Hub
{
private static readonly ILog Logger = LogManager.GetLogger(typeof(MyHub));
#region MyRegion
#region Connection Methods
public MyHub()
{
}
private static int c;
public override Task OnConnected()
{
}
private string UserNameConnectionId
{
}
public override Task OnReconnected()
{
lock (LockObject)
{
}
}
public override Task OnDisconnected(bool b)
{
lock (LockObject)
{
}
}
private void LogUserActivity(string userName, string activity)
{
}
#endregion
//Live controls invoke this Method to send their required data and also their ConnectionId
/// <summary>
/// </summary>
/// <param name="liveControlsInfo"></param>
public Task UpdateLiveControlsInfo(LiveControlInfo[] liveControlsInfo)
{
lock (LockObject)
{
}
}
public string GetValue()
{
return "SignalR Rox!";
}
public void Acknowledge()
{
lock (LockObject)
{
string connectionId = Context.ConnectionId;
}
}
}
#endregion
}
}
here is HubWinClient class
public class HubWinClient
{
private readonly string _userName;
public int ServerPort { get; set; }
private static readonly ILog logger = LogManager.GetLogger(typeof (HubWinClient));
protected int HubLogCounter = 0;
private HubConnection connection;
private bool moduleStarted;
private IHubProxy myHub;
public HubWinClient(int serverPort, string userName= "Windows Hub Client", bool tryConnect=false)
{
_userName = userName;
ServerPort = serverPort;
}
public void Start()
{
ConnectToHub();
moduleStarted = true;
}
public void Stop()
{
DisconnectFromHub();
moduleStarted = false;
}
public void ConnectToHub()
{
ConnectToHub(false);
}
public event EventHandler<EventArgs> ConnectingToHub = delegate { };
public event EventHandler<EventArgs> ConnectedToHub = delegate { };
/// <summary>
/// callback event called by hubhost
/// </summary>
public event EventHandler<int> LogSentToHub = delegate { };
public event EventHandler<EventArgs> DisonnectedFromHub = delegate { };
public event EventHandler<EventArgs> HubConnectionError = delegate { };
public event EventHandler<EventArgs> HubInvokeError = delegate { };
public event EventHandler<EventArgs> HubInvokeSuccess = delegate { };
public event EventHandler<EventArgs> NotConnectedToSentLog = delegate { };
public event EventHandler<LogMessage> DataRecivedFromHub = delegate { };
/// <summary>
/// connects HunNotifier to Hun in order to ListenerMessage passing can be done
/// </summary>
/// <param name="reconnect"></param>
private void ConnectToHub(bool reconnect)
{
//This url will not point to a specific connection. But will instead point to the root of your site=root of hub server.
string hubAddress = "http://localhost:" + ServerPort;
connection = new HubConnection(hubAddress, new Dictionary<string, string>{{"UserName", _userName } });
ConnectingToHub(this, new EventArgs());
if (reconnect)
logger.InfoFormat("HubWinClient reconnecting to HubHost # {0}...", hubAddress);
else
logger.InfoFormat("HubWinClient connecting to HubHost # {0}...", hubAddress);
myHub = connection.CreateHubProxy("myHub");
myHub.On("joined", joined);
myHub.On("rejoined", rejoined);
myHub.On("leaved", leaved);
myHub.On<LogMessage>("addData", addData);
myHub.On<int>("LogSentToWeb", LogSentToWeb);
connection.StateChanged += change =>
{
var a = change;
var b = 10;
var a1 = connection.LastError;
var b2 = connection.Proxy;
};
try
{
connection.Start();
}
catch (AggregateException aggregateException)
{
Exception exception = aggregateException.InnerException;
logger.Error("HubWinClient connection to HubHost exception...", exception);
HubConnectionError(this, new MyEventArgs {Exception = exception});
}
catch (Exception exception)
{
logger.Error("HubWinClient connection to HubHost exception...", exception);
HubConnectionError(this, new MyEventArgs {Exception = exception});
}
}
public void DisconnectFromHub()
{
connection.Stop();
}
/// <summary>
/// when hub notifier connected to hub, hub invoke this method to inform connection success.
/// </summary>
public void joined()
{
var liveControlInfo = new LiveControlInfo
{
LiveControlType = LiveControlType.mainClient
};
// myHub.Invoke("AddLiveControl", liveControlInfo).Wait();
// logger.Info("HubWinClient joined");
ConnectedToHub(this, new EventArgs());
}
/// <summary>
/// when hub notifier reconnected to hub, hub invoke this method to inform reconnection success.
/// </summary>
public void rejoined()
{
logger.Info("HubWinClient rejoined");
}
/// <summary>
/// when hub notifier disconnect from hub, hub invoke this method to inform disconnection.
/// </summary>
public void leaved()
{
logger.Info("HubWinClient disconnected");
DisonnectedFromHub(this, new EventArgs());
}
public void addData(LogMessage logMessage)
{
DataRecivedFromHub(this, logMessage);
}
public event EventHandler<LogMessage> OnSendingLogToHub = delegate { };
/// <summary>
/// called by HubClientMoudle when it's ApplyLogReceived are invoked by WCF service
/// </summary>
/// <param name="logMessage"></param>
public void SendToHub(LogMessage logMessage)
{
OnSendingLogToHub(this, logMessage);
if (!moduleStarted) return;
if (connection.State != ConnectionState.Connected)
ConnectToHub(true);
if (connection.State == ConnectionState.Connected)
{
if (System.Diagnostics.Debugger.IsAttached ||
Math.Abs((logMessage.Log.ArrivalDateTime - DateTime.Now).Ticks) < TimeSpan.FromMinutes(10).Ticks)
{
try
{
Task task = myHub.Invoke("send", logMessage);
task.Wait(5000);
logger.Debug("Send log success");
HubInvokeSuccess(this, new EventArgs());
}
catch (AggregateException aggregateException)
{
Exception exception = aggregateException.InnerException;
logger.Error("Send log Exceotion!", exception);
HubInvokeError(this, new MyEventArgs {Exception = exception});
}
catch (Exception exception)
{
logger.Error("Send log Exceotion!", exception);
HubInvokeError(this, new MyEventArgs {Exception = exception});
}
}
else
{
logger.Warn("Log arrival date time is not less than DateTime.Now+30 minutues");
}
}
else
{
logger.Warn("HubWinClient not connected to send log");
NotConnectedToSentLog(this, new EventArgs());
}
}
/// <summary>
/// when Hub receives log from HubWinClient, calls this method to inform send success
/// </summary>
/// <param name="log"></param>
public void LogSentToWeb(int logId)
{
logger.Debug("Call back from Hub: send success");
LogSentToHub(this, logId);
}
}
Here is my test:
[Category("Integration")]
public class HubWinClientTests
{
[Test]
public void TestConnection()
{
//arrange
const int port = 4000;
HubHost hubHost = new HubHost(port);
HubWinClient hubWinClient = new HubWinClient(port,"mvc app client");
bool clientConnected = false;
bool clientDisconnected = false;
bool hubInvokeError = false;
hubWinClient.ConnectedToHub += (sender, args) => { clientConnected = true; };
hubWinClient.DisonnectedFromHub += (sender, args) => { clientDisconnected = true; };
hubWinClient.HubInvokeError += (sender, args) => { hubInvokeError = true; };
//act
hubHost.Start();
hubWinClient.Start();
//assert
var constrain = Is.True.After(10000, 100);
Assert.That(() => clientConnected, constrain);
//act
hubWinClient.SendToHub(new LogMessage());
//assert
var constrain2 = Is.True.After(2000, 100);
Assert.That(() => hubInvokeError == false, constrain2);
// act
hubWinClient.DisconnectFromHub();
// assert
var constrain1 = Is.True.After(2000, 100);
Assert.That(() => clientDisconnected, constrain1);
hubHost.Stop();
}
}
For some reason when i run my the test by resharper nunit runner, hub instance does created and my test fails. i think it's related to Resharper's and how it create test environment (i'e process creation and such stuff).
Any ideas.
Thanks.
i'm developing an app, and i need to play music from url.
i'm using this code, and it works fine.
But, while a song is playing, and the screen switches off, then the music stops. I need that the music continues playing until its end, even if the screen switches off.
i suppose i have to change this file, but i don't know how:
using System;
using AudioToolbox;
using System.Threading;
using System.Collections.Generic;
using System.Linq;
namespace SecondoSenso
{
/// <summary>
/// A Class to hold the AudioBuffer with all setting together
/// </summary>
internal class AudioBuffer
{
public IntPtr Buffer { get; set; }
public List<AudioStreamPacketDescription> PacketDescriptions { get; set; }
public int CurrentOffset { get; set; }
public bool IsInUse { get; set; }
}
/// <summary>
/// Wrapper around OutputQueue and AudioFileStream to allow streaming of various filetypes
/// </summary>
public class StreamingPlayback : IDisposable
{
public bool boolDispose = false;
public event EventHandler Finished;
public event Action<OutputAudioQueue> OutputReady;
// the AudioToolbox decoder
AudioFileStream fileStream;
int bufferSize = 128 * 256;
List<AudioBuffer> outputBuffers;
AudioBuffer currentBuffer;
// Maximum buffers
int maxBufferCount = 4;
// Keep track of all queued up buffers, so that we know that the playback finished
int queuedBufferCount = 0;
// Current Filestream Position - if we don't keep track we don't know when to push the last uncompleted buffer
long currentByteCount = 0;
//Used to trigger a dump of the last buffer.
bool lastPacket;
public OutputAudioQueue OutputQueue;
public bool Started { get; private set; }
public float Volume {
get {
return OutputQueue.Volume;
}
set {
OutputQueue.Volume = value;
}
}
/// <summary>
/// Defines the size forearch buffer, when using a slow source use more buffers with lower buffersizes
/// </summary>
public int BufferSize {
get {
return bufferSize;
}
set {
bufferSize = value;
}
}
/// <summary>
/// Defines the maximum Number of Buffers to use, the count can only change after Reset is called or the
/// StreamingPlayback is freshly instantiated
/// </summary>
public int MaxBufferCount {
get {
return maxBufferCount;
}
set {
maxBufferCount = value;
}
}
public StreamingPlayback () : this (AudioFileType.MP3)
{
}
public StreamingPlayback (AudioFileType type)
{
fileStream = new AudioFileStream (type);
fileStream.PacketDecoded += AudioPacketDecoded;
fileStream.PropertyFound += AudioPropertyFound;
}
public void Reset ()
{
if (fileStream != null) {
fileStream.Close ();
fileStream = new AudioFileStream (AudioFileType.MP3);
currentByteCount = 0;
fileStream.PacketDecoded += AudioPacketDecoded;
fileStream.PropertyFound += AudioPropertyFound;
}
}
public void ResetOutputQueue ()
{
if (OutputQueue != null) {
OutputQueue.Stop (true);
OutputQueue.Reset ();
foreach (AudioBuffer buf in outputBuffers) {
buf.PacketDescriptions.Clear ();
OutputQueue.FreeBuffer (buf.Buffer);
}
outputBuffers = null;
OutputQueue.Dispose ();
}
}
/// <summary>
/// Stops the OutputQueue
/// </summary>
public void Pause ()
{
OutputQueue.Pause ();
Started = false;
}
/// <summary>
/// Starts the OutputQueue
/// </summary>
public void Play ()
{
OutputQueue.Start ();
Started = true;
}
/// <summary>
/// Main methode to kick off the streaming, just send the bytes to this method
/// </summary>
public void ParseBytes (byte[] buffer, int count, bool discontinuity, bool lastPacket)
{
this.lastPacket = lastPacket;
fileStream.ParseBytes (buffer, 0, count, discontinuity);
}
public void Dispose ()
{
Dispose (true);
GC.SuppressFinalize (this);
}
public void Dispose(int tt) {
}
/// <summary>
/// Cleaning up all the native Resource
/// </summary>
protected virtual void Dispose (bool disposing)
{
if (disposing) {
if (OutputQueue != null)
OutputQueue.Stop(true);
if (outputBuffers != null) {
foreach (var b in outputBuffers)
OutputQueue.FreeBuffer (b.Buffer);
outputBuffers.Clear ();
outputBuffers = null;
}
if (fileStream != null) {
fileStream.Close ();
fileStream = null;
}
if (OutputQueue != null) {
OutputQueue.Dispose ();
OutputQueue = null;
}
}
}
/// <summary>
/// Saving the decoded Packets to our active Buffer, if the Buffer is full queue it into the OutputQueue
/// and wait until another buffer gets freed up
/// </summary>
void AudioPacketDecoded (object sender, PacketReceivedEventArgs args)
{
foreach (var p in args.PacketDescriptions) {
currentByteCount += p.DataByteSize;
AudioStreamPacketDescription pd = p;
int left = bufferSize - currentBuffer.CurrentOffset;
if (left < pd.DataByteSize) {
EnqueueBuffer ();
WaitForBuffer ();
}
AudioQueue.FillAudioData (currentBuffer.Buffer, currentBuffer.CurrentOffset, args.InputData, (int)pd.StartOffset, pd.DataByteSize);
// Set new offset for this packet
pd.StartOffset = currentBuffer.CurrentOffset;
// Add the packet to our Buffer
currentBuffer.PacketDescriptions.Add (pd);
// Add the Size so that we know how much is in the buffer
currentBuffer.CurrentOffset += pd.DataByteSize;
}
if ((fileStream != null && currentByteCount == fileStream.DataByteCount) || lastPacket)
EnqueueBuffer ();
}
/// <summary>
/// Flush the current buffer and close the whole thing up
/// </summary>
public void FlushAndClose ()
{
if (OutputQueue != null) {
EnqueueBuffer ();
OutputQueue.Flush ();
}
Dispose ();
}
/// <summary>
/// Enqueue the active buffer to the OutputQueue
/// </summary>
void EnqueueBuffer ()
{
currentBuffer.IsInUse = true;
OutputQueue.EnqueueBuffer (currentBuffer.Buffer, currentBuffer.CurrentOffset, currentBuffer.PacketDescriptions.ToArray ());
queuedBufferCount++;
StartQueueIfNeeded ();
}
/// <summary>
/// Wait until a buffer is freed up
/// </summary>
void WaitForBuffer ()
{
int curIndex = outputBuffers.IndexOf (currentBuffer);
currentBuffer = outputBuffers [curIndex < outputBuffers.Count - 1 ? curIndex + 1 : 0];
lock (currentBuffer) {
while (currentBuffer.IsInUse)
Monitor.Wait (currentBuffer);
}
}
void StartQueueIfNeeded ()
{
if (Started)
return;
Play ();
}
/// <summary>
/// When a AudioProperty in the fed packets is found this callback is called
/// </summary>
void AudioPropertyFound (object sender, PropertyFoundEventArgs args)
{
if (args.Property == AudioFileStreamProperty.ReadyToProducePackets) {
Started = false;
if (OutputQueue != null)
OutputQueue.Dispose ();
OutputQueue = new OutputAudioQueue (fileStream.StreamBasicDescription);
if (OutputReady != null)
OutputReady (OutputQueue);
currentByteCount = 0;
OutputQueue.BufferCompleted += HandleBufferCompleted;
outputBuffers = new List<AudioBuffer> ();
for (int i = 0; i < MaxBufferCount; i++) {
IntPtr outBuffer;
OutputQueue.AllocateBuffer (BufferSize, out outBuffer);
outputBuffers.Add (new AudioBuffer () {
Buffer = outBuffer,
PacketDescriptions = new List<AudioStreamPacketDescription> ()
});
}
currentBuffer = outputBuffers.First ();
OutputQueue.MagicCookie = fileStream.MagicCookie;
}
}
/// <summary>
/// Is called when a buffer is completly read and can be freed up
/// </summary>
void HandleBufferCompleted (object sender, BufferCompletedEventArgs e)
{
queuedBufferCount--;
IntPtr buf = e.IntPtrBuffer;
foreach (var buffer in outputBuffers) {
if (buffer.Buffer != buf)
continue;
// free Buffer
buffer.PacketDescriptions.Clear ();
buffer.CurrentOffset = 0;
lock (buffer) {
buffer.IsInUse = false;
Monitor.Pulse (buffer);
}
}
if (queuedBufferCount == 0 && Finished != null)
Finished (this, new EventArgs ());
}
}
}
how can i change the code to allow that?
thanks in advance for helps.
Put this following code in your AppDelegate.csin the FinishedLaunchingmethod.
NSError sessionError = null;
AVAudioSession.SharedInstance().SetCategory(AVAudioSession.CategoryAmbient, out sessionError);
AVAudioSession.SharedInstance().SetActive(true, out sessionError);
Apps get suspended when the phone is put to sleep. If you wan't your app to continue executing, you have to register for background execution.
Here is a nice guide Jonathan Sagorin (if you don't mind putting it over from Swift/obj-c).
Basically the class you are looking for is AVAudioSession and it's SetActive Method to activate a background audio session.
The System.Threading.EventWaitHandle type does not contain a definition for 'dispose'.
How am I supposed to dispose of the EventWaitHandle when I want to kill the object in which it is contained? I've been having a serious memory leak problem and I've tried setting the EventWaitHandle to null and the memory leak persists.
Here's my code (I'm using Bob Craven's library, I added only the dispose() method):
using System;
using System.Threading;
namespace Rlc.Cron
{
public class CronObject
{
public delegate void CronEvent(CronObject cronObject);
public event CronEvent OnCronTrigger;
public event CronEvent OnStarted;
public event CronEvent OnStopped;
public event CronEvent OnThreadAbort;
private CronObjectDataContext _cronObjectDataContext;
private Guid _id = Guid.NewGuid();
private object _startStopLock = new object();
private EventWaitHandle _wh = new AutoResetEvent(false);
private Thread _thread;
public bool _isStarted;
private bool _isStopRequested;
private DateTime _nextCronTrigger;
public Guid Id { get { return _id; } }
public object Object { get { return _cronObjectDataContext.Object; } }
public DateTime LastTigger { get { return _cronObjectDataContext.LastTrigger; } }
/// <summary>
/// Initializes a new instance of the <see cref="CronObject"/> class.
/// </summary>
/// <param name="cronObjectDataContext">The cron object data context.</param>
public CronObject(CronObjectDataContext cronObjectDataContext)
{
if (cronObjectDataContext == null)
{
throw new ArgumentNullException("cronObjectDataContext");
}
if (cronObjectDataContext.Object == null)
{
throw new ArgumentException("cronObjectDataContext.Object");
}
if (cronObjectDataContext.CronSchedules == null || cronObjectDataContext.CronSchedules.Count == 0)
{
throw new ArgumentException("cronObjectDataContext.CronSchedules");
}
_cronObjectDataContext = cronObjectDataContext;
}
/// <summary>
/// Starts this instance.
/// </summary>
/// <returns></returns>
public bool Start()
{
lock (_startStopLock)
{
// Can't start if already started.
//
if (_isStarted)
{
return false;
}
_isStarted = true;
_isStopRequested = false;
// This is a long running process. Need to run on a thread
// outside the thread pool.
//
_thread = new Thread(ThreadRoutine);
_thread.Start();
}
// Raise the started event.
//
if(OnStarted != null)
{
OnStarted(this);
}
return true;
}
/// <summary>
/// Stops this instance.
/// </summary>
/// <returns></returns>
public bool Stop()
{
lock (_startStopLock)
{
// Can't stop if not started.
//
if (!_isStarted)
{
return false;
}
_isStarted = false;
_isStopRequested = true;
// Signal the thread to wake up early
//
_wh.Set();
// Wait for the thread to join.
//
if(!_thread.Join(5000))
{
_thread.Abort();
// Raise the thread abort event.
//
if(OnThreadAbort != null)
{
OnThreadAbort(this);
}
}
}
// Raise the stopped event.
//
if(OnStopped != null)
{
OnStopped(this);
}
return true;
}
public void dispose(){
this.Stop ();
this.OnCronTrigger = null;
this.OnStarted=null;
this.OnStopped=null;
this.OnThreadAbort=null;
this._cronObjectDataContext=null;
this._startStopLock = null;
this._wh = null;
this._thread=null;
}
/// <summary>
/// Cron object thread routine.
/// </summary>
private void ThreadRoutine()
{
// Continue until stop is requested.
//
while(!_isStopRequested)
{
// Determine the next cron trigger
//
DetermineNextCronTrigger(out _nextCronTrigger);
TimeSpan sleepSpan = _nextCronTrigger - DateTime.Now;
if(sleepSpan.TotalMilliseconds < 0)
{
// Next trigger is in the past. Trigger the right away.
//
sleepSpan = new TimeSpan(0, 0, 0, 0, 50);
}
// Wait here for the timespan or until I am triggered
// to wake up.
//
if(!_wh.WaitOne(sleepSpan))
{
// Timespan is up...raise the trigger event
//
if(OnCronTrigger != null)
{
OnCronTrigger(this);
}
// Update the last trigger time.
//
_cronObjectDataContext.LastTrigger = DateTime.Now;
}
}
}
/// <summary>
/// Determines the next cron trigger.
/// </summary>
/// <param name="nextTrigger">The next trigger.</param>
private void DetermineNextCronTrigger(out DateTime nextTrigger)
{
nextTrigger = DateTime.MaxValue;
foreach (CronSchedule cronSchedule in _cronObjectDataContext.CronSchedules)
{
DateTime thisTrigger;
if(cronSchedule.GetNext(LastTigger, out thisTrigger))
{
if (thisTrigger < nextTrigger)
{
nextTrigger = thisTrigger;
}
}
}
}
~CronObject(){
Console.WriteLine ("===================CRONOBJECT DESTROYED!!===============");
}
}
}