Weighted Fair queuing algorithm doing round-robin with just 2 packet flow - algorithm

I tried implementing a simple simulation of the Weighted Fair queuing algorithm.
But I noticed an issue when using only 2 packet flow, the algorithm is not letting twice the amount of T1 packet as it should because they are half the size of T2 packet. Instead it simply do round-robin between the 2 flow.
I understand the problem is that it take some time for T1 to add another packet to the queue and the Weighted Fair queuing have the time to run when T1 queue is empty.
This does not seem to be the expected behavior, am I missing something in the algorithm that would fix this corner case?
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
public class Packet
{
public string name;
public ManualResetEventSlim mres;
public long virFinish;
public long packetSize;
public Packet(string pname, long p_virFinish, long p_packetSize)
{
name = pname;
mres = new ManualResetEventSlim(false);
virFinish = p_virFinish;
packetSize = p_packetSize;
}
}
public class Queue
{
public ConcurrentQueue<Packet> q = new ConcurrentQueue<Packet>();
public long virStart;
public long lastVirFinish;
}
public class FairQueue
{
long VirtualTime; // system virtual time
ConcurrentDictionary<string, Queue> queues = new ConcurrentDictionary<string, Queue>();
public FairQueue() {
VirtualTime = long.MinValue;
queues.GetOrAdd("t1", new Queue());
queues.GetOrAdd("t2", new Queue());
queues.GetOrAdd("t3", new Queue());
}
public ManualResetEventSlim Write(string queueName, long packetSize)
{
var queue = queues[queueName];
Volatile.Write(ref queue.virStart, Math.Max(VirtualTime, queue.lastVirFinish));
var packetFinish = queue.virStart + packetSize;
var packet = new Packet(queueName, packetFinish, packetSize);
queue.q.Enqueue(packet);
Volatile.Write(ref queue.lastVirFinish, packetFinish);
UpdateVirtualClock(queue);
return packet.mres;
}
private void UpdateVirtualClock(Queue queue)
{
long minStart = queue.virStart;
foreach (var item in queues)
{
if (!item.Value.q.IsEmpty)
{
minStart = Math.Min(item.Value.virStart, minStart);
}
}
Volatile.Write(ref VirtualTime, Math.Max(VirtualTime, minStart));
}
// return queue with smallest lastVirFinish
public Queue SelectQueue()
{
long minVirFinish = long.MaxValue; // infinity
Queue selected = null;
foreach (var queue in queues)
{
if (!queue.Value.q.IsEmpty)
{
var lastVirFinish = Volatile.Read(ref queue.Value.lastVirFinish);
if (lastVirFinish < minVirFinish) {
minVirFinish = queue.Value.lastVirFinish;
selected = queue.Value;
}
}
}
return selected;
}
public Packet Send()
{
var selectedQueue = SelectQueue();
if (selectedQueue != null)
{
Packet p;
selectedQueue.q.TryDequeue(out p);
/* Set the start and the finish times of the remaining packets in the queue */
if (!selectedQueue.q.IsEmpty)
{
var next = selectedQueue.q.Take(1).First();
selectedQueue.virStart = selectedQueue.lastVirFinish;
selectedQueue.lastVirFinish = selectedQueue.virStart + next.packetSize;
}
return p;
}
else
{
return null;
}
}
}
class Program
{
static void Main(string[] args)
{
FairQueue fq = new FairQueue();
// Task that enqueue packet
var t1 = Task.Factory.StartNew(
() => {
while (true)
{
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
sw.Start();
var s1 = fq.Write("t1", 100);
s1.Wait();
sw.Stop();
}
}
);
// Task that enqueue packet
var t2 = Task.Factory.StartNew(
() => {
while (true)
{
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
sw.Start();
var s1 = fq.Write("t2", 200);
s1.Wait();
sw.Stop();
}
}
);
// Loop that run the Weighted Fair Queue Algorithm
while (true)
{
var toSend = fq.Send();
if (toSend != null)
{
Console.WriteLine(toSend.name);
Thread.Sleep((int)toSend.packetSize);
toSend.mres.Set();
}
}
}
}
}

Related

Find and update an element in a Java Queue

Trying to work on small use case where i have to add string of websites in a queue. if the site repeats then i have to update the numberofVisits+1. Else i would add that object into the queue. Something wrong with updateCount code. Please let me know
here is the code snippet. I am unable to move forward on this.
public CLassName(String url, int numVisits) {
this.url = url;
this.numVisits = numVisits;
}
public int getNumVisits() {
return this.numVisits;
}
public String getUrl() {
return this.url;
}
public void setNumVisits(int updatedNumVisits) {
this.numVisits = updatedNumVisits;
}
private static Queue<ClassName> sites = new LinkedList<ClassName>();
// Method to find the website in the queue and increment the visited count by 1, adding new node in case website is not found
public static void update(String url) {
//code should go in here. // THis is wrong code
if (sites.isEmpty()) sites.add(new ClassName(url,1));
while(!sites.isEmpty()) {
String tmpUrl = sites.peek().getUrl();
int numVisits = sites.peek().getNumVisits();
if(tmpUrl!=null && tmpUrl.equalsIgnoreCase(url)) {
sites.add(new ClassName(tmpUrl,numVisits+1));
} else if(tmpUrl!=null){
sites.add(new ClassName(tmpUrl,numVisits));
} else {
sites.add(new ClassName(url,1));
}
}
}
public static void main(String[] args) {
String[] visitedSites = { "www.google.co.in", "www.google.co.in", "www.facebook.com", "www.upgrad.com", "www.google.co.in", "www.youtube.com",
"www.facebook.com", "www.facebook.com", "www.google.co.in", "www.microsoft.com", "www.9gag.com", "www.netflix.com",
"www.netflix.com", "www.9gag.com", "www.microsoft.com", "www.amazon.com", "www.amazon.com", "www.uber.com", "www.amazon.com",
"www.microsoft.com" };
for (String url : visitedSites) {
update(url);
}
Thanks for the recommendation. I did a small tweek to address the problem.
I did not add Dummy site
Added a counter and incremented so that it is always < the size of queue
Here is my solution and it works
public static void update(Queue<String> sites,String url,int numberOfVisits)
{
if ( sites.isEmpty()) sites.add(url); // first time
boolean flag = false;
int counter = 0
while (!sites.empty && counter<sites.size()) //go over all the urls in the queue
{
if (sites.head().equalsIgnoreCase(url))
{
flag = true;
break;
}
sites.insert(sites.remove()); //removing the head and inserting it to the end of the queue
counter ++;
}
if (!flag==true) {
numberOfVisits=numberOfVisits+1;
}
else {
sites.insert(url);
}
}
the update method just could be like this;
boolean increased = false;
Iterator<ClassName> statIterator = sites.iterator();
while (statIterator.hasNext()) {
ClassName st = statIterator.next();
if (st.getUrl().equals(url)) {
st.setNumVisits(st.getNumVisits()+1);
increased = true;
break;
}
}
if (!increased) {
sites.add(new ClassName(url,1));
}

how to implement Android In App BillingClient in Xamarin.Android Asynchronously

I am trying to implement below java code in c# referring to Android documentation
List<String> skuList = new ArrayList<> ();
skuList.add("premium_upgrade");
skuList.add("gas");
SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder();
params.setSkusList(skuList).setType(SkuType.INAPP);
billingClient.querySkuDetailsAsync(params.build(),
new SkuDetailsResponseListener() {
#Override
public void onSkuDetailsResponse(BillingResult billingResult,
List<SkuDetails> skuDetailsList) {
// Process the result.
}
});
I have here 2 questions. I thought that i would run this code on a separate thread than UI thread like below to keep my ui responsive while network connection is done. is that the correct approach? QuerySkuDetailsAsync is called async but doesnt implement as async. how should this be working and how to handle in c# because it will fire and forget but Listener to handle the response.
public async Task<List<InAppBillingProduct>> GetProductsAsync(List<string> ProductIds)
{
var getSkuDetailsTask = Task.Factory.StartNew(() =>
{
var prms = SkuDetailsParams.NewBuilder();
var type = BillingClient.SkuType.Inapp;
prms.SetSkusList(ProductIds).SetType(type);
BillingClient.QuerySkuDetailsAsync(prms.Build(), new SkuDetailsResponseListener());
return InAppBillingProducts;
});
return await getSkuDetailsTask;
}
2nd question regarding how to handle with the listener as below. How do I return value from the listener. I need return list of InAppBillingProduct object.
public class SkuDetailsResponseListener : Java.Lang.Object, ISkuDetailsResponseListener
{
public void OnSkuDetailsResponse(BillingResult billingResult, IList<SkuDetails> skus)
{
if (billingResult.ResponseCode == BillingResponseCode.Ok)
{
// get list of Products here and return
}
}
}
FYI. This is how I did it. This is not a complete code but this will give you and idea.
Listener - PCL
============
private async Task EventClicked()
{
var skuList = new List<string>();
skuList.Add("[nameofsubscriptionfoundinyourgoogleplay]");
if (await _billingClientLifecycle.Initialize(skuList, DisconnectedConnection))
{
var firstProduct = _billingClientLifecycle?.ProductsInStore?.FirstOrDefault();
if (firstProduct != null)
{
//purchase here
}
}
}
private void DisconnectedConnection()
{
//Todo.alfon. handle disconnection here...
}
Interface - PCL
===========
public interface IInAppBillingMigratedNew
{
List<InAppBillingPurchase> PurchasedProducts { get; set; }
List<InAppBillingProduct> ProductsInStore { get; set; }
Task<bool> Initialize(List<String> skuList, Action onDisconnected = null);
}
Dependency - Platform Droid
===============
[assembly: XF.Dependency(typeof(InAppBillingMigratedNew))]
public class InAppBillingMigratedNew : Java.Lang.Object, IBillingClientStateListener
, ISkuDetailsResponseListener, IInAppBillingMigratedNew
{
private Activity Context => CrossCurrentActivity.Current.Activity
?? throw new NullReferenceException("Current Context/Activity is null");
private BillingClient _billingClient;
private List<string> _skuList = new List<string>();
private TaskCompletionSource<bool> _tcsInitialized;
private Action _disconnectedAction;
private Dictionary<string, SkuDetails> _skusWithSkuDetails = new Dictionary<string, SkuDetails>();
public List<InAppBillingPurchase> PurchasedProducts { get; set; }
public List<InAppBillingProduct> ProductsInStore { get; set; }
public IntPtr Handle => throw new NotImplementedException();
public Task<bool> Initialize(List<string> skuList, Action disconnectedAction = null)
{
_disconnectedAction = disconnectedAction;
_tcsInitialized = new TaskCompletionSource<bool>();
var taskInit = _tcsInitialized.Task;
_skuList = skuList;
_billingClient = BillingClient.NewBuilder(Context)
.SetListener(this)
.EnablePendingPurchases()
.Build();
if (!_billingClient.IsReady)
{
_billingClient.StartConnection(this);
}
return taskInit;
}
#region IBillingClientStateListener
public void OnBillingServiceDisconnected()
{
Console.WriteLine($"Connection disconnected.");
_tcsInitialized?.TrySetResult(false);
_disconnectedAction?.Invoke();
}
public void OnBillingSetupFinished(BillingResult billingResult)
{
var responseCode = billingResult.ResponseCode;
var debugMessage = billingResult.DebugMessage;
if (responseCode == BillingResponseCode.Ok)
{
QuerySkuDetails();
QueryPurchases();
_tcsInitialized?.TrySetResult(true);
}
else
{
Console.WriteLine($"Failed connection {debugMessage}");
_tcsInitialized?.TrySetResult(false);
}
}
#endregion
#region ISkuDetailsResponseListener
public void OnSkuDetailsResponse(BillingResult billingResult, IList<SkuDetails> skuDetailsList)
{
if (billingResult == null)
{
Console.WriteLine("onSkuDetailsResponse: null BillingResult");
return;
}
var responseCode = billingResult.ResponseCode;
var debugMessage = billingResult.DebugMessage;
switch (responseCode)
{
case BillingResponseCode.Ok:
if (skuDetailsList == null)
{
_skusWithSkuDetails.Clear();
}
else
{
if (skuDetailsList.Count > 0)
{
ProductsInStore = new List<InAppBillingProduct>();
}
foreach (var skuDetails in skuDetailsList)
{
_skusWithSkuDetails.Add(skuDetails.Sku, skuDetails);
//ToDo.alfon. make use mapper here
ProductsInStore.Add(new InAppBillingProduct
{
Name = skuDetails.Title,
Description = skuDetails.Description,
ProductId = skuDetails.Sku,
CurrencyCode = skuDetails.PriceCurrencyCode,
LocalizedIntroductoryPrice = skuDetails.IntroductoryPrice,
LocalizedPrice = skuDetails.Price,
MicrosIntroductoryPrice = skuDetails.IntroductoryPriceAmountMicros,
MicrosPrice = skuDetails.PriceAmountMicros
});
}
}
break;
case BillingResponseCode.ServiceDisconnected:
case BillingResponseCode.ServiceUnavailable:
case BillingResponseCode.BillingUnavailable:
case BillingResponseCode.ItemUnavailable:
case BillingResponseCode.DeveloperError:
case BillingResponseCode.Error:
Console.WriteLine("onSkuDetailsResponse: " + responseCode + " " + debugMessage);
break;
case BillingResponseCode.UserCancelled:
Console.WriteLine("onSkuDetailsResponse: " + responseCode + " " + debugMessage);
break;
// These response codes are not expected.
case BillingResponseCode.FeatureNotSupported:
case BillingResponseCode.ItemAlreadyOwned:
case BillingResponseCode.ItemNotOwned:
default:
Console.WriteLine("onSkuDetailsResponse: " + responseCode + " " + debugMessage);
break;
}
}
#endregion
#region Helper Methods Private
private void ProcessPurchases(List<Purchase> purchasesList)
{
if (purchasesList == null)
{
Console.WriteLine("No purchases done.");
return;
}
if (IsUnchangedPurchaseList(purchasesList))
{
Console.WriteLine("Purchases has not changed.");
return;
}
_purchases.AddRange(purchasesList);
PurchasedProducts = _purchases.Select(sku => new InAppBillingPurchase
{
PurchaseToken = sku.PurchaseToken
})?.ToList();
if (purchasesList != null)
{
LogAcknowledgementStatus(purchasesList);
}
}
private bool IsUnchangedPurchaseList(List<Purchase> purchasesList)
{
// TODO: Optimize to avoid updates with identical data.
return false;
}
private void LogAcknowledgementStatus(List<Purchase> purchasesList)
{
int ack_yes = 0;
int ack_no = 0;
foreach (var purchase in purchasesList)
{
if (purchase.IsAcknowledged)
{
ack_yes++;
}
else
{
ack_no++;
}
}
//Log.d(TAG, "logAcknowledgementStatus: acknowledged=" + ack_yes +
// " unacknowledged=" + ack_no);
}
private void QuerySkuDetails()
{
var parameters = SkuDetailsParams
.NewBuilder()
.SetType(BillingClient.SkuType.Subs)
.SetSkusList(_skuList)
.Build();
_billingClient.QuerySkuDetailsAsync(parameters, this);
}
private void QueryPurchases()
{
if (!_billingClient.IsReady)
{
Console.WriteLine("queryPurchases: BillingClient is not ready");
}
var result = _billingClient.QueryPurchases(BillingClient.SkuType.Subs);
ProcessPurchases(result?.PurchasesList?.ToList());
}
#endregion
}

Running Multiple threads in queue using BlockingCollections

My program has 3 functions. Each function takes a list of Items and fill certain information.
For example
class Item {
String sku,upc,competitorName;
double price;
}
function F1 takes a List and fills upc
function F2 takes List (output of F1) and fills price.
function F3 takes List (output of F2) and fills competitorName
F1 can process 5 items at a time,
F2 can process 20 items at a time,
F3 also 20.
Right now I am running F1 -> F2 -> F3 in serial because F2 needs info(UPC code) from F1. F3 needs price from F2.
I would like to make this process efficient by running F1 run continuously instead of waiting for F2 and F3 to be completed. F1 executes and output into queue then F2 takes 20 items at a time and process them. and then follows F3.
How can i achieve this by using BlockingCollection and Queue?
This is a typical use case of Apache Storm in case you've continuous items coming in to F1. You can implement this in Storm in matter of minutes and you'll have fast and perfectly parallel system in place. Your F1, F2 and F3 will become bolts and your Items producer will become spout.
Since you asked how to do it using BlockingCollections here is an implementation. You'll need 3 threads in total.
ItemsProducer: It is producing 5 items at a time and feeding it to F1.
F2ExecutorThread: It is consuming 20 items at a time and feeding it to F2.
F3ExecutorThread: It is consuming 20 items at a time and feeding it to F3.
You also have 2 blocking queues one is used to transfer data from F1->F2 and one from F2->F3. You can also have a queue to feed data to F1 in similar fashion if required. It depends upon how you are getting the items. I've used Thread.sleep to simulate the time required to execute the function.
Each function will keep looking for items in their assigned queue, irrespective of what other functions are doing and wait until the queue has items. Once they've processed the item they'll put it in another queue for another function. They'll wait until the other queue has space if it is full.
Since all your functions are running in different threads, F1 won't be waiting for F2 or F3 to finish. If your F2 and F3 are significantly faster then F1 you can assign more threads to F1 and keep pushing to same f2Queue.
public class App {
final BlockingQueue<Item> f2Queue = new ArrayBlockingQueue<>(100);
final BlockingQueue<Item> f3Queue = new ArrayBlockingQueue<>(100);
public static void main(String[] args) throws InterruptedException {
App app = new App();
app.start();
}
public void start() throws InterruptedException {
Thread t1 = new ItemsProducer(f2Queue);
Thread t2 = new F2ExecutorThread(f2Queue, f3Queue);
Thread t3 = new F3ExecutorThread(f3Queue);
t1.start();
t2.start();
t3.start();
t1.join();
t2.join();
t3.join();
}
}
/**
* Thread producing 5 items at a time and feeding it to f1()
*/
class ItemsProducer extends Thread {
private BlockingQueue<Item> f2Queue;
private static final int F1_BATCH_SIZE = 5;
public ItemsProducer(BlockingQueue<Item> f2Queue) {
this.f2Queue = f2Queue;
}
public void run() {
Random random = new Random();
while (true) {
try {
List<Item> items = new ArrayList<>();
for (int i = 0; i < F1_BATCH_SIZE; i++) {
Item item = new Item(String.valueOf(random.nextInt(100)));
Thread.sleep(20);
items.add(item);
System.out.println("Item produced: " + item);
}
// Feed items to f1
f1(items);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
void f1(List<Item> items) throws InterruptedException {
Random random = new Random();
for (Item item : items) {
Thread.sleep(100);
item.upc = String.valueOf(random.nextInt(100));
f2Queue.put(item);
}
}
}
/**
* Thread consuming items produced by f1(). It takes 20 items at a time, but if they are not
* available it waits and starts processesing as soon as one gets available
*/
class F2ExecutorThread extends Thread {
static final int F2_BATCH_SIZE = 20;
private BlockingQueue<Item> f2Queue;
private BlockingQueue<Item> f3Queue;
public F2ExecutorThread(BlockingQueue<Item> f2Queue, BlockingQueue<Item> f3Queue) {
this.f2Queue = f2Queue;
this.f3Queue = f3Queue;
}
public void run() {
try {
List<Item> items = new ArrayList<>();
while (true) {
items.clear();
if (f2Queue.drainTo(items, F2_BATCH_SIZE) == 0) {
items.add(f2Queue.take());
}
f2(items);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
void f2(List<Item> items) throws InterruptedException {
Random random = new Random();
for (Item item : items) {
Thread.sleep(100);
item.price = random.nextInt(100);
f3Queue.put(item);
}
}
}
/**
* Thread consuming items produced by f2(). It takes 20 items at a time, but if they are not
* available it waits and starts processesing as soon as one gets available.
*/
class F3ExecutorThread extends Thread {
static final int F3_BATCH_SIZE = 20;
private BlockingQueue<Item> f3Queue;
public F3ExecutorThread(BlockingQueue<Item> f3Queue) {
this.f3Queue = f3Queue;
}
public void run() {
try {
List<Item> items = new ArrayList<>();
while (true) {
items.clear();
if (f3Queue.drainTo(items, F3_BATCH_SIZE) == 0) {
items.add(f3Queue.take());
}
f3(items);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void f3(List<Item> items) throws InterruptedException {
Random random = new Random();
for (Item item : items) {
Thread.sleep(100);
item.competitorName = String.valueOf(random.nextInt(100));
System.out.println("Item done: " + item);
}
}
}
class Item {
String sku, upc, competitorName;
double price;
public Item(String sku) {
this.sku = sku;
}
public String toString() {
return "sku: " + sku + " upc: " + upc + " price: " + price + " compName: " + competitorName;
}
}
I guess you can follow the exact same approach in .Net as well. For better understanding I suggest you to go through basic architecture of http://storm.apache.org/releases/current/Tutorial.html
I tried to do same thing in .NET and i think it is working.
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace BlockingCollectionExample
{
class Program
{
static void Main(string[] args)
{
BlockingCollection<Listing> needUPCJobs = new BlockingCollection<Listing>();
BlockingCollection<Listing> needPricingJobs = new BlockingCollection<Listing>();
// This will have final output
List<Listing> output = new List<Listing>();
// start executor 1 which waits for data until available
var executor1 = Task.Factory.StartNew(() =>
{
int maxSimutenousLimit = 5;
int gg = 0;
while (true)
{
while (needUPCJobs.Count >= maxSimutenousLimit)
{
List<Listing> tempListings = new List<Listing>();
for (int i = 0; i < maxSimutenousLimit; i++)
{
Listing listing = new Listing();
if (needUPCJobs.TryTake(out listing))
tempListings.Add(listing);
}
// Simulating some delay for first executor
Thread.Sleep(1000);
foreach (var eachId in tempListings)
{
eachId.UPC = gg.ToString();
gg++;
needPricingJobs.Add(eachId);
}
}
if (needUPCJobs.IsAddingCompleted)
{
if (needUPCJobs.Count == 0)
break;
else
maxSimutenousLimit = needUPCJobs.Count;
}
}
needPricingJobs.CompleteAdding();
});
// start executor 2 which waits for data until available
var executor2 = Task.Factory.StartNew(() =>
{
int maxSimutenousLimit = 10;
int gg = 10;
while (true)
{
while (needPricingJobs.Count >= maxSimutenousLimit)
{
List<Listing> tempListings = new List<Listing>();
for (int i = 0; i < maxSimutenousLimit; i++)
{
Listing listing = new Listing();
if (needPricingJobs.TryTake(out listing))
tempListings.Add(listing);
}
// Simulating more delay for second executor
Thread.Sleep(10000);
foreach (var eachId in tempListings)
{
eachId.Price = gg;
gg++;
output.Add(eachId);
}
}
if (needPricingJobs.IsAddingCompleted)
{
if(needPricingJobs.Count==0)
break;
else
maxSimutenousLimit = needPricingJobs.Count;
}
}
});
// producer thread
var producer = Task.Factory.StartNew(() =>
{
for (int i = 0; i < 100; i++)
{
needUPCJobs.Add(new Listing() { ID = i });
}
needUPCJobs.CompleteAdding();
});
// wait for producer to finish producing
producer.Wait();
// wait for all executors to finish executing
Task.WaitAll(executor1, executor2);
Console.WriteLine();
Console.WriteLine();
}
}
public class Listing
{
public int ID;
public string UPC;
public double Price;
public Listing() { }
}
}

Algorithm to fire sequential keystrokes

I want to write an algorithm to sequentially press keys F1-F3. My form has these controls:
lblF1
textboxF1
lblF2
textboxF2
lblF3
textboxF3
btnStart
In textboxF1-textboxF3 the time in seconds is entered. This when the program is to press the hotkey. It is important that the program can't press two keys at once, for example F1 and F2. It may not press more than one key in a second. When I click on btnStart it calls Run().
This is how I tried to resolve this:
static int counterF1 = 9999;
static int counterF2 = 9999;
static int counterF3 = 9999;
public void Run()
{
counterF1 = 9999;
counterF2 = 9999;
counterF3 = 9999;
while (true)
{
Loop();
}
}
public void Loop()
{
bool used = false;
if (counterF1 >= (int)textboxF1.text)
{
counterF1 = PressKey(VK_F1);
used = true;
}
if (counterF2 >= (int)textboxF2.text)
{
counterF2 = PressKey(VK_F2);
used = true;
}
if (counterF3 >= (int)textboxF3.text)
{
counterF3 = PressKey(VK_F3);
used = true;
}
if (used == false)
{
IncrementCounters();
Delay(1000);
}
}
public double PressKey(uint key)
{
myPostMessageA(hWindow, WM_KEYDOWN, (uint)key, (uint)key);
IncrementCounters();
return 1; //return 1 because one second
}
public void IncrementCounters()
{
counterF1++;
counterF2++;
counterF3++;
}
But often it doesn't press any key (it is possible it is too late, but can't be an omission). Can you explain how to make an algorithm for this?
We will use a class KeyStroke that stores the necessary data for a special key:
public class KeyStroke
{
public int period { get; set; } // Period in which to hit key
public int next { get; set; } // ticks to the next hit of this key
public int VK { get; set; } //KeyCode
}
public List<KeyStroke> keys = new List<KeyStroke>();
An Initialize() method is needed to read the data from the text boxes and to init the simulation. We utilize a timer with the interval of one second to run the simulation. In my example, I don't read from textboxes, but use constant values. Add the input and error handling. If you use WPF, you can bind the KeyStroke objects to the textboxes.
void Init()
{
//Initialize keys with according periods from input
keys.Clear();
keys.Add(new KeyStroke() { VK = VK_F1, period = 1, next = 1 });
keys.Add(new KeyStroke() { VK = VK_F2, period = 10, next = 10 });
keys.Add(new KeyStroke() { VK = VK_F3, period = 5, next = 5 });
//sort keys by period (descending), in order to handle long period keys, too
keys.Sort((first, second) => second.period.CompareTo(first.period));
//Start the program
var t = new DispatcherTimer();
t.Interval = TimeSpan.FromSeconds(1);
t.Tick += new EventHandler(t_Tick);
t.Start();
}
The tick event is similar to yours:
void t_Tick(object sender, EventArgs e)
{
bool used = false;
foreach (var key in keys)
{
if (key.next <= 0 && !used)
{
PressKey(key.VK);
key.next = key.period;
used = true;
}
key.next--;
}
}

Lossless reading from mic

I'm using NAudio (but it applies to reading directly) to capture microphone wave data. It seems that if my app is busy it drops/skips some input data from the mic.
I've set the reading thread to top priority, but I'm doing heavy calculations in several other thread at the same time.
Is there a way to read data lossless?
(Or is it lossless, and my bug elsewhere?)
When I was making a similar app and had a similar problem, it turned out that I needed a buffer that can hold at least 3 seconds of data. Try to increase the buffer to 10 seconds of data and if it doesn't solve your problem then there are more issues. If it works try decreasing the buffer size until it works properly
EDIT: Here a quick & dirty managed dx recording for you to try.
public class BMSRecordingEventArgs : EventArgs
{
byte[] data;
bool endRec;
public BMSRecordingEventArgs(byte[] data, bool endRec)
{
this.data = data;
this.endRec = endRec;
}
public byte[] Data
{
get { return data; }
}
public bool EndRec
{
get { return endRec; }
}
}
public class AudioRecorder
{
public delegate void DataReceivedHandler(object sender, BMSRecordingEventArgs e);
public event DataReceivedHandler DataReceivedHandle;
public const int CAPTURE_BUFFER_SIZE = 32000;
DXS.Capture dxsCapDev;
DXS.CaptureBuffer dxsCapBuffer;
DXS.CaptureBufferDescription dxsCapBufferDesc;
System.Threading.Thread thrdCapturingThread;
DXS.BufferPositionNotify[] dxsBpna;
private volatile bool StopRec;
System.Threading.ManualResetEvent mreStillRunning = new System.Threading.ManualResetEvent(false);
DXS.BufferPositionNotify dxsBPNHalf;
DXS.BufferPositionNotify dxsBPNFull;
DXS.Notify Notify;
System.Threading.AutoResetEvent ARE;
public AudioRecorder(Guid DeviceGuid,DXS.WaveFormat wfWaveFormat,DXS.CaptureEffectDescription[] dxsCapEffectDesc)
{
dxsCapDev = new Microsoft.DirectX.DirectSound.Capture(DeviceGuid);
dxsCapBufferDesc = new Microsoft.DirectX.DirectSound.CaptureBufferDescription();
dxsCapBufferDesc.BufferBytes = CAPTURE_BUFFER_SIZE;
dxsCapBufferDesc.Format = wfWaveFormat;
dxsCapBufferDesc.WaveMapped = true;
dxsCapBufferDesc.CaptureEffectDescription = dxsCapEffectDesc;
dxsCapBufferDesc.ControlEffects = true;
dxsCapBuffer = new Microsoft.DirectX.DirectSound.CaptureBuffer(dxsCapBufferDesc, dxsCapDev);
ARE = new System.Threading.AutoResetEvent(false);
dxsBPNHalf = new Microsoft.DirectX.DirectSound.BufferPositionNotify();
dxsBPNFull = new Microsoft.DirectX.DirectSound.BufferPositionNotify();
dxsBPNHalf.Offset = CAPTURE_BUFFER_SIZE / 2 - 1;
dxsBPNFull.Offset = CAPTURE_BUFFER_SIZE-1;
dxsBPNFull.EventNotifyHandle = ARE.SafeWaitHandle.DangerousGetHandle();
dxsBPNHalf.EventNotifyHandle = ARE.SafeWaitHandle.DangerousGetHandle();
dxsBpna = new Microsoft.DirectX.DirectSound.BufferPositionNotify[2];
dxsBpna[0] = dxsBPNHalf;
dxsBpna[1] = dxsBPNFull;
Notify = new Microsoft.DirectX.DirectSound.Notify(dxsCapBuffer);
Notify.SetNotificationPositions(dxsBpna);
}
public void StartRecording()
{
if (thrdCapturingThread != null)
throw new Exception("Already Recording !");
StopRec = false;
thrdCapturingThread = new System.Threading.Thread(Record);
thrdCapturingThread.Start();
}
private void Record()
{
DataReceivedHandler drh2 = DataReceivedHandle;
dxsCapBuffer.Start(true);
byte[] TempBaf = new byte[CAPTURE_BUFFER_SIZE / 2];
int StartingOffset = 0;
while (dxsCapBuffer.Capturing && !StopRec)
{
ARE.WaitOne(-1,false);
StartingOffset %= CAPTURE_BUFFER_SIZE;
TempBaf = (byte[])dxsCapBuffer.Read(StartingOffset, typeof(byte), Microsoft.DirectX.DirectSound.LockFlag.FromWriteCursor, CAPTURE_BUFFER_SIZE / 2);
StartingOffset += TempBaf.Length;
if (drh2 != null)
drh2(this, new BMSRecordingEventArgs(TempBaf, false));
}
dxsCapBuffer.Stop();
if (drh2 != null)
drh2(this, new BMSRecordingEventArgs(TempBaf, true));
mreStillRunning.Set();
}
public void StopRecording()
{
StopRec = true;
mreStillRunning.WaitOne(-1,false);
thrdCapturingThread = null;
}
}

Resources