Reputation: 1561
I am a newbie writing code for sound playback via "alsa api".
I have to repeatedly call a function send_output()
10 times in a sec as:
while(true)
{
send_output();
usleep(100000);
}
but this is a bad way of programming since within the usleep()
function processor is still busy executing the code.
I want to know the way (for I know it exists) to put the function send_output()
into a periodic callback function so that in between the calls, the processor can be kept free for other heavy tasks. Can you help me?
P.S. I am programming on 'Beagleboard' which has a very low clock rate and need to do other tasks too.
Thanks.
Upvotes: 1
Views: 3517
Reputation: 29586
A typical mainloop in an application that needs to coordinate multiple things is centered around the select
function, which waits for events on a set of file descriptors or a timeout.
Your ALSA loop then becomes
// This will keep the time when ALSA expects the next packet
struct timeval alsa_timeout;
// Initialize timeout with current time
gettimeofday(&alsa_timeout, 0);
for(;;) {
// Get current time
struct timeval now;
gettimeofday(&now, 0);
// Whether to re-check the current time before going to sleep
bool restart = false;
if(now.tv_sec > alsa_timeout.tv_sec ||
(now.tv_sec == alsa_timeout.tv_sec && now.tv_usec >= alsa_timeout.tv_usec)) {
send_output();
alsa_timeout.tv_usec += 100000;
if(alsa_timeout.tv_usec > 1000000) {
alsa_timeout.tv_sec += alsa_timeout.tv_usec / 1000000;
alsa_timeout.tv_usec %= 1000000;
}
restart = true;
}
// If we performed some action, this would have taken time, so we need
// to re-fetch the current time
if(restart)
continue;
// Determine when the next action is due
struct timeval next_timeout;
// We only have one action at the moment, which is ALSA. Otherwise, this is the place
// where you look for the earliest time you need to wake up.
next_timeout.tv_sec = alsa_timeout.tv_sec;
next_timeout.tv_usec = alsa_timeout.tv_usec;
struct timeval relative_time;
if(next_timeout.tv_usec >= now.tv_usec) {
relative_time.tv_usec = next_timeout.tv_usec - now.tv_usec;
relative_time.tv_sec = next_timeout.tv_sec - now.tv_sec;
} else {
relative_time.tv_usec = 1000000 - now.tv_usec + next_timeout.tv_usec;
relative_time.tv_sec = next_timeout.tv_sec + 1 - now.tv_usec;
}
// Other parameters become important when you do other work
int rc = select(0, 0, 0, 0, &relative_time);
if(rc == 0)
continue;
if(rc == -1)
break;
// Handle file descriptor based work here
}
Note that I use the absolute time in my calculation and increment that for every packet of samples I send -- this keeps the data rate constant regardless of how long the ALSA subsystem takes to transfer the data to the soundcard, and when I miss a timeout (because some other function took more than 100ms to complete) the output function will be called twice to re-fill the ALSA buffers.
You may need to add some extra code:
gettimeofday()
gettimeofday()
returns UTC, but if you run an NTP client or allow setting the date and time somewhere, that needs to be handled).Upvotes: 0
Reputation: 4164
It is simple you should avoid using synchronization like that. Use event system implementation instead. Define an interface and register it to your class as listener. Each time your class perform some action you will be informed with event. You can take a look on Java listeners implementation also read about ( Bridge, Strategy, Observer ) design patterns. Interface implementation in c++ will looks like:
class IActionListener
{
public:
virtual void actionPerformed( ... some arguments ... )=0;
};
implement this interaface like:
class ConcreteActionListener: public IActionListener
{
public:
void actionPerformed( ... some arguments ... )
{
// do your staff here.
}
};
Check this: http://en.wikipedia.org/wiki/Observer_pattern
Upvotes: 0
Reputation: 4487
You have to do that in the frame of multi-threads
.
According to your tag, let's say you are programming on Linux, so:
void thread_funtion()
{
while(true)
{
send_output();
usleep(100000);
}
}
invoke this function in main thread by:
pthread_t pid;
pthread_create(&pid, NULL, thread_function, NULL);
Please note that:
#include <pthread.h>
gcc
command, then try gcc -pthread
command.Upvotes: 1
Reputation: 16597
man usleep
usleep - suspend execution for microsecond intervals
Upvotes: 1