I have inherited a chunk of code that is using ALSA to capture an audio input at 8KHz, 8 bits, 1 channel. The code looks rather simple, it sets channels to 1, rate to 8000, and period size to 8000. The goal of this program to gather audio data in 30+ min chunks at a time.
The main loop looks like
int retval;
snd_pcm_uframes_t numFrames = 8000;
while (!exit)
{
// Gather data
while( (unsigned int)(retval = snd_pcm_readi ( handle, buffer, numFrames ) ) != numFrames )
{
if( retval == -EPIPE )
{
cerr << "overrun " << endl;
snd_pcm_prepare( handle );
}
else if ( reval < 0 )
{
cerr << "Error : " << snd_strerror( retval ) << endl;
break;
}
}
// buffer processing logic here
}
We have been having behavioral issue (not getting the full 8K samples per second, and weird timing), so I added gettimeofday timestamps around the snd_pcm_readi loop to see how time was being used and I got the following :
loop 1 : 1.017 sec
loop 2 : 2.019 sec
loop 3 : 0 (less than 1ms)
loop 4 : 2.016 sec
loop 5 : .001 sec
.. the 2 loop pattern continues (even run 2.01x sec, odd run 0-1 ms) for the rest of the run. This means I am acutally getting on average less that 8000 samples per second (loss appears to be about 3 seconds per 10 minutes of running). This does not sync well with the other gathered data. Also we would have expected to process the data at about 1 second intervals, not have 2 back to back processes every 2 seconds or so.
As an additional check, I printed out the buffer values are setting the hardware parameters and I got the following :
Buffer Size : 43690
Periods : 5
Period Size : 8000
Period Time : 1000000
Rate : 8000
So in the end I have 2 questions :
1) Why do I get actual data at less than 8 Khz ? (Possible theory, actual hardware is not quite at 8KHz, even if ALSA thinks it can do it).
2) Why the 2 secs/0 secs cycle on the reads which should be 1 second each ? And what can be done to get it to a real 1 second cycle ?
Thanks for the help.
Dale Pennington
snd_pcm_readi() returns as many samples as are available. And it will not wait for more if the device is in non-blocking mode.
You have only retval samples. If you want to handle 8000 samples at once, call snd_pcm_readi() in a loop with the remaining buffer.
Related
I'm using a RedBearLabs Blend V2 to communicate with a SPI peripheral. Everything is functioning correctly at this point and I am receiving the expected data using SPI.write() and catching the return value. The SPI bus is running at 1 MHz in mode 0.
The image below shows the SPI bus connected to a scope. Trace 1 is SCLK, 2 is MISO, 3 is MOSI and 4 is CS. As you can see, I have 4 bursts of SCLK whilst CS is low, each 8 bits in length with a delay of approximately 20 µs in between each burst. Ideally, I need to completely alleviate this 20 µs delay and have 1 SCLK burst of 32 cycles.
The below code is how I am currently achieving what is seen in the scope grab.
int16_t MAX1300::sampleChannel(uint8_t channel, uint8_t inputMode, uint8_t adcMode)
{
int16_t sample;
int8_t hi = 0;
int8_t lo = 0;
MAX1300::InputWord_u word;
word.bits.start = 0b1;
if (inputMode == MAX1300::SINGLE_ENDED) {
word.bits.select = (Channels_se_e)channel;
} else {
word.bits.select = (Channels_dif_e)channel;
}
word.bits.payload = 0b0000;
if (adcMode == MAX1300::EXT_CLK) {
m_cs = 0;
m_spiBus.write(word.all);
m_spiBus.write(7);
hi = m_spiBus.write(0);
lo = m_spiBus.write(0);
m_cs = 1;
}
sample = ((int16_t)hi << 8) | lo;
return sample;
}
So far I have tried setting SPI.format(16, 0) with the intention of having 2 SCLK bursts of 16 cycles, however the SPI bus no longer functions if I do this. The same happens if I use SPI.transfer() with 32-bit buffers - no SPI bus.
I am able to increase the frequency of the bus, thus reducing the delay between each SCLK burst, however this is not really a suitable solution due to the end-application for this device.
What am I doing wrong here, or is what I am attempting to do just not possible with this hardware/firmware combination?
Thanks, Adam
This Question is from Edx-UCSanDiegoX: ALGS201x Data Structure
Fundamentals Programming Challenge 1-3: Network packet processing
simulation
Hi Everyone, I have a very long question, I sincerely appreciate anyone who spend his/her precious time. Only Response Process(const Request &request) implementation is asked in the question, rest is given.
I having difficulty why Failing Test Case, I found the same answer with trying paper and pen :), maybe I made a silly mistake. Thank You.
Problem Description Task:
You are given a series of incoming network packets and your task is to simulate their processing. Packets arrive in some order. For each packet i , you know when it arrived Ai and the time it takes the processor to process it Pi (both in milliseconds). There is only one processor, and it processes the incoming packets in the order of their arrival. Of the processor started to process some packet, it doesn’t interrupt or stop until it finishes the processing of this packet, and the processing of packet I takes exactly Pi milliseconds.
The computer processing the packets has a network buffer of fixed size S. When packets arrive, they are stored in the buffer before being processed. However, if the buffer is full when a packet arrives (there are S packets which are arrived before this packet, and the computer hasn’t finished processing any of them), it is dropped and won’t be processed at all. If several packets arrive at the same time, they are all stored in the buffer (some of them may dropped because of their arrival, and it starts processing the next available packet from the buffer as soon as it finishes processing the previous one. If at some point the computer is not busy, and there are no packets in the buffer, the computer just waits for the next packet to arrive. Note that a packet leaves the buffer and free the space in the buffer as soon as computer finishes processing it.
Input Format:
The First line of input contains the size S of the buffer and the number n of incoming network packets. Each of the next n lines contains two numbers I-th line contains the time of arrival Ai and processing tine Pi (both in ms) of the the I-th packet. It is guaranteed that the sequence of arrival times is non-decreasing. (However, it can contain the exact same times of arrival in milliseconds in this case the packet which is earlier in the input is considered to have arrived earlier.
Output Format: For each packet output either the moment of the time when the processor began processing it or -1 if the packet was dropped. (output is same order as input packets are given)
Sample Runs
Sample 1
Input:
1 0
Output:
If there are no packets, you should not output anything
Sample 2
Input:
1 1
0 0
Output:
0
The only packet arrived at time 0. And computer started processing it.
Sample 3
Input:
1 2
0 1
0 1
Output:
0
1
The first packet arrived at time 0. the second packet also arrived at time 0 , but was dropped. Because the network buffer has size 1 and it was full with first packet already. The first packet started processing at time 0 , second was not processed at all.
Sample 4
Input :
1 2
0 1
1 1
Output:
0
1
The first packet arrived at time 0 , the computer started processing it immediately and finished at time 1 .The second packet arrived at time 1 and the computer started processing it immediately.
Failing Test Case:
Inputs:
3 6
0 2
1 2
2 2
3 2
4 2
5 2
My Output:
0
2
4
-1
6
-1
Correct Output:
0
2
4
6
8
-1
The Code
#include <iostream>
#include <queue>
#include <vector>
struct Request {
Request(int arrival_time, int process_time) :
arrival_time(arrival_time),
process_time(process_time)
{}
int arrival_time;
int process_time;
};
struct Response {
Response(bool dropped, int start_time) :
dropped(dropped),
start_time(start_time)
{}
bool dropped;
int start_time;
};
class Buffer {
public:
Buffer(int size) :
size_(size),
finish_time_()
{}
Response Process(const Request &request)
{
while (!finish_time_.empty() && finish_time_.front() <= request.arrival_time)
finish_time_.pop();
if (finish_time_.empty())
{
finish_time_.push(request.arrival_time + request.process_time);
return Response(false, request.arrival_time);
}
else
{
if (size_> (finish_time_.back() - request.arrival_time))
{
int before = finish_time_.back();
finish_time_.push(before + request.process_time);
return Response(false, before);
}
else
{
return Response(true, 5);
}
}
}
private:
int size_;
std::queue <int> finish_time_;
};
std::vector <Request> ReadRequests()
{
std::vector <Request> requests;
int count;
std::cin >> count;
for (int i = 0; i < count; ++i) {
int arrival_time, process_time;
std::cin >> arrival_time >> process_time;
requests.push_back(Request(arrival_time, process_time));
}
return requests;
}
std::vector <Response> ProcessRequests(const std::vector <Request> &requests, Buffer *buffer)
{
std::vector <Response> responses;
for (int i = 0; i < requests.size(); ++i)
responses.push_back(buffer->Process(requests[i]));
return responses;
}
void PrintResponses(const std::vector <Response> &responses)
{
for (int i = 0; i < responses.size(); ++i)
std::cout << (responses[i].dropped ? -1 : responses[i].start_time) << std::endl;
}
int main() {
int size;
std::cin >> size;
std::vector <Request> requests = ReadRequests();
Buffer buffer(size);
std::vector <Response> responses = ProcessRequests(requests, &buffer);
PrintResponses(responses);
return 0;
}
After a lot of testing with this thing, I still can't figure out why there are extra milliseconds appended to the millisecond limit.
In this case, the whole running loop should last 4000ms, and then print 4000 followed by some other data, however it is always around 4013ms.
I currently know that the problem isn't the stress testing, since without it, it's still at around 4013ms. Besides, there's is a limit for how long the stress testing can take, and the time is justified by how much rendering is able to be done in the remaining time. I also know that it isn't "SDL_GetTicks" including the time I'm initialising variables, since it only starts timing when it is first called. It's not the time it takes to call the function either, because I tested this with a very lightweight nanosecond timer as well, and the result is the same.
Here's some of my results, that are printed at the end:
4013 100 993 40
4013 100 1000 40
4014 100 1000 40
4012 100 992 40
4015 100 985 40
4013 100 1000 40
4022 100 986 40
4014 100 1000 40
4017 100 993 40
Unlike the third column (the amount of frames rendered), the first column shouldn't vary by much more than the few nanoseconds it took to exit the loops and such. Meaning it shouldn't even show a difference since the scope of the timer is milliseconds in this case.
I recompiled between all of them, and the list is pretty much continues the same.
Here's the code:
#include <iostream>
#include <SDL/SDL.h>
void stress(int n) {
n = n + n - n * n + n * n;
}
int main(int argc, char **argv) {
int running = 100,
timestart = 0, timestep = 0,
rendering = 0, logic = 0,
SDL_Init(SDL_INIT_EVERYTHING);
while(running--) { // - Running loop
timestart = SDL_GetTicks();
std::cout << "logic " << logic++ << std::endl;
for(int i = 0; i < 9779998; i++) { // - Stress testing
if(SDL_GetTicks() - timestart >= 30) { // - Maximum of 30 milliseconds spent running logic
break;
}
stress(i);
}
while(SDL_GetTicks() - timestart < 1) { // - Minimum of one millisecond to run through logic
;
}
timestep = SDL_GetTicks() - timestart;
while(40 > timestep) {
timestart = SDL_GetTicks();
std::cout << "rendering " << rendering++ << std::endl;
while(SDL_GetTicks() - timestart < 1) { // - Maximum of one rendering frame per millisecond
;
}
timestep += SDL_GetTicks() - timestart;
}
}
std::cout << SDL_GetTicks() << " " << logic << " " << rendering << " " << timestep << std::endl;
SDL_Quit();
return 0;
}
Elaborating on crowders comment - if your OS decides to switch tasks you will end up with a random error between 0 and 1 ms(or -.5 and .5 if SDL_GetTicks would be rounding it's internal timer, but your results always greater than expected suggest it is actually truncating). These will 'even out' within your next busy wait, but not near the end of the loop - since there is none 'next busy wait' there. To counteract it you need a reference point from before you start your game loop and compare it with GetTicks to measure how much time have "leaked". Also your approach of X miliseconds per frame and busy waits/breaks in the middle of computation isn't the cleanest i've seen. You should probably google about game loops and read a bit.
I'm trying to play raw-pcm data with xaudio and i have huge delays in playing (>=5ms). I'm doing this with next code:
bool Play(uint8_t *data, size_t size)
{
_xaudio_buffer.AudioBytes = size;
_xaudio_buffer.pAudioData = data;
Time t1;
if (_g_source->SubmitSourceBuffer(&_xaudio_buffer) != S_OK)
return false;
if(WaitForSingleObjectEx(_voice_callback.hBufferEndEvent,INFINITE,true) != WAIT_OBJECT_0)
return false;
Time t2;
printf("%d\n",t2-t1);
}
Time class is just a wrapper under GetTickCount, the resulting t2-t1 will return difference in milliseconds. I've checked that my Time class doesn't produce any additional delay.
It is not so hard to calculate play time in milliseconds:
play_time = size*1000 / (channels*(bits_per_sample/8) * frequency)
So for data with size 4608 bytes, 48 khz, 2 channels, 16 bit per sample it should take nearly 24ms for playing such chunk. Instead, code that i showed above needs about >= 31 ms for playing such chunk. What is producing such delay? How to deal with it, if i'm writing a video-player and i obtaining data from real-time stream (i already have synchronization function, but 5ms delay for such small sample produces not ideal sound)?
Also, I've tested this code on 2 computers with Windows 7 with different hardware. Both producing same delay.
Have a 1MB pipe:
if (0 == CreatePipe(&hRead,&hWrite,0,1024*1024))
{
printf("CreatePipe failed\n");
return success;
}
Sending 4000 bytes at a time (bytesReq = 4000)
while ((bytesReq = (FileSize - offset)) != 0)
{
//Send data to Decoder.cpp thread, converting to human readable CSV
if ( (0 == WriteFile(hWrite,
readBuff,
bytesReq,
&bytesWritten,
0) ) ||
(bytesWritten != bytesReq) )
{
printf("WriteFile failed error = %d\n",GetLastError());
break;
}
}
Only 4 bytes at a time being read in at another thread, on other end of pipe.
When I made the pipe smaller, the total time of sending and reading got a lot smaller.
Changed the Pipe Size to –
1024*1024 = 2 minutes (original size)
1024*512 = 1min 47 sec
10,000 = 1min 33 sec
Anything below 10k, 1min 33 sec
How can this be?
Less waiting.
If the pipe buffer is too big, then one process writes all the data and closes it's end of the pipe before the second process even begins.
When the pipe is too big, the processes are executed serially.