C++ zilib deflate/inflate and ztream parameters - c++

After understood (with some help...) how work the compress and uncompress functions of zlib library, I'm now trying to understand how deflate and inflate work. As far as i understand, compress is used in a single call, whereas deflate can be called several time.
Having a simple program with a Particle struct (coordinate x, y, z), I can deflate my datas without errors (getting a Z_STREAM_END response) and then inflate them with another z_stream object (Z_STREAM_END response too). But when I tried to display back my datas from the inflate response, I can get the x and y coordinate of my struct by not the third one (z).
I think it's due to a wrong parameters i gave to my z_stream object for inflate, but I can't find which one. As far as i understand reading docs and example, that's how I think z_stream works (this is just an example) :
// Here i give a total memory size for the output buffer used by deflate func
#define CHUNK 16384
struct Particle
{
float x;
float y;
float z;
};
...
// An element to get a single particule and give it to deflate func
Bytef *dataOriginal = (Bytef*)malloc( sizeof(Particle) );
// This var will be used to pass compressed data
Bytef *dataCompressed = (Bytef*)malloc( CHUNK );
z_stream strm;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
deflateInit(&strm, Z_DEFAULT_COMPRESSION);
strm.avail_out = CHUNK;
strm.next_out = dataCompressed;
int nbrLoop = 2;
int spaceUsed = 0;
int flush;
Particle p;
for (var i = 0; i<nbrLoop; i++){
// set all values equals to 0
memset( &p, 0, sizeof(Particle) );
// insert some random values
p.x = (i+1) * 1;
p.y = (i+1) * 3;
p.z = (i+1) * 7;
//copy this values in a Bytef* elements
memcpy( dataOriginal, &p, sizeof(Particle) );
strm.avail_in = sizeof(dataOriginal);
strm.next_in = dataOriginal;
// If it's the last particle :
if(i == nbrLoop - 1){
flush = Z_FINISH;
}
else{
flush = Z_NO_FLUSH;
}
int response = deflate(&strm, flush);
// I don't get any errors here
// EDIT : Get Z_OK at first loop, the Z_STREAM_END at second (last)
if( res == Z_STREAM_END ){
spaceUsed = CHUNK - strm.avail_out;
}
}
deflateEnd(&strm);
// Trying to get back my datas
Bytef *decomp = (Bytef*)malloc( sizeof(Particle) );
z_stream strmInflate;
strmInflate.zalloc = Z_NULL;
strmInflate.zfree = Z_NULL;
strmInflate.opaque = Z_NULL;
inflateInit(&strmInflate);
// datas i want to get at the next inflate
strmInflate.avail_in = sizeof(Particle);
strmInflate.next_in = dataCompressed;
// Two particles were compressed, so i need to get back two
strmInflate.avail_out = sizeof(Particle) * 2;
strmInflate.next_out = decomp;
int response = inflate( &strmInflate, Z_NO_FLUSH );
// No error here,
// EDIT : Get Z_OK
inflateEnd( &strmInflate );
Particle testP;
memset( &testP, 0, sizeof(Particle) );
memcpy( &testP, decomp, sizeof(Particle) );
std::cout << testP.x << std::endl; // display 1 OK
std::cout << testP.y << std::endl; // display 3 OK
std::cout << testP.z << std::endl; // display 0 NOT OK
Moreover, i thought that calling inflate a second time will allow me to recover datas of my second particle that was created in my for loop but i can't retrieve it.
Thanks in advance for any help !

strmInflate.avail_in = sizeof(Particle); needs to be strmInflate.avail_in = spaceUsed; You have to provide inflate all of the data produced by deflate.
At the end you want to get Z_STREAM_END from inflate(), not Z_OK. Otherwise you have not decompressed the entire generated stream.
Note that per the documentation in zlib.h, you need to also set next_in and avail_in (to Z_NULL and 0 if you like) before calling inflateInit()
Depending on the size of the input and output buffers you will be using in the final application, you may need more loops to assure that deflate() and inflate() can finish their jobs. Please see the example of how to use zlib.

Related

How save in an array the following 100 received value after a determined received string in Qt

I'm a newbie in C++ and Qt. I want to save in an array the value received in a serialport after I received the string: "Data".
I'm using the terminal example so the serialport works properly.
The read function in the Example is the same:
void MainWindow::readData()
{
QByteArray data = serial->readAll();
console->putData(data);
}
How can I modify it? thanks!!!
If your manual sending the data i recommend you add a start of frame delimiter and an end of frame delimiter and checksum preferably.
QByteArray packet_storage;
just declare it the where you declare serial.
StartOfMessage and EndOfMessage will depend on your device.
I don't know what your transmitting. Hopefully you can figure out from the documentation of your device what your sending out.
as for me i am using
enum Constants
{
StartOfMessage = '\x02', /* Value of byte that marks the start of a message */
EndOfMessage = '\x03', /* Value of byte that marks the end of a message */
CarridgeReturn = '\x0D', /* Carridge return is first byte of end of line */
LineFeed = '\x0A', /* Line feed is second byte of end of line */
NullChar = '\0' /* Null Character */
};
void MainWindow::readData()
{
// read all
QByteArray data = serial->readAll();
// store all read data packet_storage is a QByteArray
packet_storage.append(data);
int start_index = 0;
int end_index = 0;
// process packet if not empty
if(!packet_storage.isEmpty())
{
if( packet_storage.contains(StartOfMessage) && packet_storage.contains(EndOfMessage))
{
start_index = packet_storage.indexOf(StartOfMessage,0);
end_index = packet_storage.indexOf(EndOfMessage,0);
int length = 0;
for (int i=start_index; i <= end_index; i++)
{
length++;
}
// get data
QByteArray dt = packet_storage.mid(start_index,length);
// do your processing here.
// store in vector write to file etc.
processpacket(dt);
packet_storage.remove(start_index,dt.size());
}
}
}

Uncompress Deflate

I'm working on a function that can uncompress the deflate compression, so i can read/draw png files in my c++ program. However, the deflate specification isn't very clear on some things.
So my main question is:
Paragraph 3.2.7. Compression with dynamic Huffman codes (BTYPE=10) of the specification state that
the distance code follows the literal/length
But it does not state how many bits the distance code occupy, is it an entire byte?
And how does the distance code relate?.. whats its use, really?
Any one have a general explanation? since the specification is kinda lacking in clarity.
The specification i found here:
http://www.ietf.org/rfc/rfc1951.txt
Edit (Here is my following code to use with puff inflate code.)
First the header (ConceptApp.h)
#include "resource.h"
#ifdef _WIN64
typedef unsigned long long SIZE_PTR;
#else
typedef unsigned long SIZE_PTR;
#endif
typedef struct _IMAGE {
DWORD Width; //Width in pixels.
DWORD Height; //Height in pixels.
DWORD BitsPerPixel; //24 (RGB), 32 (RGBA).
DWORD Planes; //Count of color planes
PBYTE Pixels; //Pointer to the first pixel of the image.
} IMAGE, *PIMAGE;
typedef DWORD LodePNGColorType;
typedef struct _LodePNGColorMode {
DWORD colortype;
DWORD bitdepth;
} LodePNGColorMode;
typedef struct LodePNGInfo
{
/*header (IHDR), palette (PLTE) and transparency (tRNS) chunks*/
unsigned compression_method;/*compression method of the original file. Always 0.*/
unsigned filter_method; /*filter method of the original file*/
unsigned interlace_method; /*interlace method of the original file*/
LodePNGColorMode color; /*color type and bits, palette and transparency of the PNG file*/
} LodePNGInfo;
typedef struct _ZLIB {
BYTE CMF;
BYTE FLG;
//DWORD DICTID; //if FLG.FDICT (Bit 5) is set, this variable follows.
//Compressed data here...
} ZLIB, *PZLIB;
typedef struct _PNG_IHDR {
DWORD Width;
DWORD Height;
BYTE BitDepth;
BYTE ColourType;
BYTE CompressionMethod;
BYTE FilterMethod;
BYTE InterlaceMethod;
} PNG_IHDR, *PPNG_IHDR;
typedef struct _PNG_CHUNK {
DWORD Length;
CHAR ChuckType[4];
} PNG_CHUNK, *PPNG_CHUNK;
typedef struct _PNG {
BYTE Signature[8];
PNG_CHUNK FirstChunk;
} PNG, *PPNG;
And the code .cpp file:
The main function can be found at the bottom of the file (LoadPng)
BYTE LoadPng(PPNG PngFile, PIMAGE ImageData)
{
PDWORD Pixel = 0;
DWORD ChunkSize = 0;
PPNG_IHDR PngIhdr = (PPNG_IHDR) ((SIZE_PTR) &PngFile->FirstChunk + sizeof(PNG_CHUNK));
DWORD Png_Width = Png_ReadDword((PBYTE)&PngIhdr->Width);
DWORD Png_Height = Png_ReadDword((PBYTE)&PngIhdr->Height);
DWORD BufferSize = (Png_Width*Png_Height) * 8; //This just a guess right now, havent done the math yet. !!!
ChunkSize = Png_ReadDword((PBYTE)&PngFile->FirstChunk.Length);
PPNG_CHUNK ThisChunk = (PPNG_CHUNK) ((SIZE_PTR)&PngFile->FirstChunk + ChunkSize + 12); //12 is the length var itself, Chunktype and CRC.
PPNG_CHUNK NextChunk;
PBYTE UncompressedData = (PBYTE) malloc(BufferSize);
INT RetValue = 0;
do
{
ChunkSize = Png_ReadDword((PBYTE)&ThisChunk->Length);
NextChunk = (PPNG_CHUNK) ((SIZE_PTR)ThisChunk + ChunkSize + 12); //12 is the length var itself, Chunktype and CRC.
if (Png_IsChunk(ThisChunk->ChuckType, "IDAT")) //Is IDAT ?
{
PZLIB iData = (PZLIB) ((SIZE_PTR)ThisChunk + 8); //8 is the length and chunkType.
PBYTE FirstBlock; //ponter to the first 3 bits of the deflate stuff.
if ((iData->CMF & 8) == 8) //deflate compression method.
{
if ((iData->FLG & 0x20) == 0x20)
{
FirstBlock = (PBYTE) ((SIZE_PTR)iData + 6); //DICTID Present.
}
else FirstBlock = (PBYTE) ((SIZE_PTR)iData + 2); //DICTID Not present.
RetValue = puff(UncompressedData, &BufferSize, FirstBlock, &ChunkSize); //I belive chunksize should be fine.
if (RetValue != 0)
{
WCHAR ErrorText[100];
swprintf_s(ErrorText, 100, L"%u", RetValue); //Convert data into string.
MessageBox(NULL, ErrorText, NULL, MB_OK);
}
}
}
ThisChunk = NextChunk;
} while (!Png_IsChunk(ThisChunk->ChuckType, "IEND"));
//LodePNGInfo ImageInfo;
//PBYTE Png_Real_Image = (PBYTE) malloc(BufferSize);
//ImageInfo.compression_method = PngIhdr->CompressionMethod;
//ImageInfo.filter_method = PngIhdr->FilterMethod;
//ImageInfo.interlace_method = PngIhdr->InterlaceMethod;
//ImageInfo.color.bitdepth = PngIhdr->BitDepth;
//ImageInfo.color.colortype = PngIhdr->ColourType;
//Remove Filter/crap blah blah.
//postProcessScanlines(Png_Real_Image, UncompressedData, Png_Width, Png_Height, &ImageInfo);
ImageData->Width = Png_Width;
ImageData->Height = Png_Height;
ImageData->Planes = 0; //Will need changed later.
ImageData->BitsPerPixel = 32; //Will need changed later.
ImageData->Pixels = 0;
//ImageData->Pixels = Png_Real_Image; //image not uncompressed yet.
return TRUE; //ret true for now. fix later.
}
I just hope to make clearer what is stated before--Huffman coding is a method for encoding values using a variable number of bits. In, say, ASCII coding, every letter gets the same number of bits no matter how frequently it is used. In Huffman coding, you could make "e" have fewer bits than an "X".
The trick in huffman coding is how the codes are prefixed. After reading each bit, the decoder knows, unambiguously, whether it has a value or needs to read another bit.
To comprehend the deflate process you need to understand LZ algorithm and Huffman coding.
On their own, both techniques are simple. The complexity comes from how they are put together.
LZ compresses by finding previous occurrences of a string. When a string has occurred previously, it is compressed by referencing the previous occurrence. The Distance is the offset to the previous occurrence. Distance and length specify that occurrence.
The problem is not with puff.
All the IDAT chunks in the png file need to be put together before calling puff.
It should look something like this:
BYTE LoadPng(PPNG PngFile, PIMAGE ImageData)
{
PDWORD Pixel = 0;
DWORD ChunkSize = 0;
PPNG_IHDR PngIhdr = (PPNG_IHDR) ((SIZE_PTR) &PngFile->FirstChunk + sizeof(PNG_CHUNK));
DWORD Png_Width = Png_ReadDword((PBYTE)&PngIhdr->Width);
DWORD Png_Height = Png_ReadDword((PBYTE)&PngIhdr->Height);
DWORD BufferSize = (Png_Width*Png_Height) * 8; //This just a guess right now, havent done the math yet. !!!
ChunkSize = Png_ReadDword((PBYTE)&PngFile->FirstChunk.Length);
PPNG_CHUNK ThisChunk = (PPNG_CHUNK) ((SIZE_PTR)&PngFile->FirstChunk + ChunkSize + 12); //12 is the length var itself, Chunktype and CRC.
PPNG_CHUNK NextChunk;
PBYTE UncompressedData = (PBYTE) malloc(BufferSize);
PBYTE TempBuffer = (PBYTE) malloc(BufferSize); //Put all idat chunks together befor uncompressing.
DWORD DeflateSize = 0; //All IDAT Chunks Added.
PZLIB iData = NULL;
PBYTE FirstBlock = NULL; //ponter to the first 3 bits of the deflate stuff.
INT RetValue = 0;
do
{
ChunkSize = Png_ReadDword((PBYTE)&ThisChunk->Length);
NextChunk = (PPNG_CHUNK) ((SIZE_PTR)ThisChunk + ChunkSize + 12); //12 is the length var itself, Chunktype and CRC.
if (Png_IsChunk(ThisChunk->ChuckType, "IDAT")) //Is IDAT ?
{
CopyMemory(&TempBuffer[DeflateSize], (PBYTE) ((SIZE_PTR)ThisChunk + 8), ChunkSize); //8 is the length and chunkType.
DeflateSize += ChunkSize;
}
ThisChunk = NextChunk;
} while (!Png_IsChunk(ThisChunk->ChuckType, "IEND"));
iData = (PZLIB) TempBuffer;
if ((iData->CMF & 8) == 8) //deflate compression method.
{
if ((iData->FLG & 0x20) == 0x20)
{
FirstBlock = (PBYTE) ((SIZE_PTR)iData + 6); //DICTID Present.
}
else FirstBlock = (PBYTE) ((SIZE_PTR)iData + 2); //DICTID Not present.
}
RetValue = puff(UncompressedData, &BufferSize, FirstBlock, &DeflateSize); //I belive chunksize should be fine.
if (RetValue != 0)
{
WCHAR ErrorText[100];
swprintf_s(ErrorText, 100, L"%u", RetValue);
MessageBox(NULL, ErrorText, NULL, MB_OK);
}
//LodePNGInfo ImageInfo;
//PBYTE Png_Real_Image = (PBYTE) malloc(BufferSize);
//ImageInfo.compression_method = PngIhdr->CompressionMethod;
//ImageInfo.filter_method = PngIhdr->FilterMethod;
//ImageInfo.interlace_method = PngIhdr->InterlaceMethod;
//ImageInfo.color.bitdepth = PngIhdr->BitDepth;
//ImageInfo.color.colortype = PngIhdr->ColourType;
//Remove Filter/crap blah blah.
//postProcessScanlines(Png_Real_Image, UncompressedData, Png_Width, Png_Height, &ImageInfo);
ImageData->Width = Png_Width;
ImageData->Height = Png_Height;
ImageData->Planes = 0; //Will need changed later.
ImageData->BitsPerPixel = 32; //Will need changed later.
ImageData->Pixels = 0;
//ImageData->Pixels = Png_Real_Image; //image not uncompressed yet.
return TRUE; //ret true for now. fix later.
}
You need to first read up on compression, since there is a lot of basic stuff that you're not getting. E.g. The Data Compression Book, by Nelson and Gailly.
Since it's a code, specifically a Huffman code, by definition the number of bits are variable.
If you don't know what the distance is for, then you need to first understand the LZ77 compression approach.
Lastly, aside from curiosity and self-education, there is no need for you to understand the deflate specification or to write your own inflate code. That's what zlib is for.

AudioConverterNew returned -50

I have a little issue regarding the use of the AudioQueue services.
I have followed the guide that is available on Apple's webiste, but when I got to start and run the Audio Queue, I get the message telling me that "AudioConverterNew returned -50".
Now, I know that the -50 error code means that there is a bad parameter. However, what I don't know is which parameter is the bad one (thank you so much Apple...) !
So, here's my code.
Here are the parameters of my class, named cPlayerCocoa
AudioQueueRef mQueue;
AudioQueueBufferRef mBuffers[NUMBER_BUFFERS]; // NUMBER_BUFFERS = 3
uint32 mBufferByteSize;
AudioStreamBasicDescription mDataFormat;
Here's the first function :
static void
BuildBuffer( void* iAQData, AudioQueueRef iAQ, AudioQueueBufferRef iBuffer )
{
cPlayerCocoa* player = (cPlayerCocoa*) iAQData;
player->HandleOutputBuffer( iAQ, iBuffer );
}
It creates a cPlayerCocoa from the structure containing the AudioQueue and calls the HandleOutputBuffer function, which allocates the audio buffers :
void
cPlayerCocoa::HandleOutputBuffer( AudioQueueRef iAQ, AudioQueueBufferRef iBuffer )
{
if( mContinue )
{
xassert( iBuffer->mAudioDataByteSize == 32768 );
int startSample = mPlaySampleCurrent;
int result = 0;
int samplecount = 32768 / ( mSoundData->BytesPerSample() ); // BytesPerSample, in my case, returns 4
tErrorCode error = mSoundData->ReadData( (int16*)(iBuffer->mAudioData), samplecount, &result, startSample );
AudioQueueEnqueueBuffer( mQueue, iBuffer, 0, 0 ); // I'm using CBR data (PCM), hence the 0 passed into the AudioQueueEnqueueBuffer.
if( result != samplecount )
mContinue = false;
startSample += result;
}
else
{
AudioQueueStop( mQueue, false );
}
}
In this next function, the AudioQueue is created then started.
I begin to initialise the parameters of the Data format. Then I create the AudioQueue, and I allocate the 3 buffers.
When the buffers are allocated, I start the AudioQueue and then I run the loop.
void
cPlayerCocoa::ThreadEntry()
{
int samplecount = 32768 / ( mSoundData->BytesPerSample() );
mDataFormat.mSampleRate = mSoundData->SamplingRate(); // Returns 44100
mDataFormat.mFormatID = kAudioFormatLinearPCM;
mDataFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
mDataFormat.mBytesPerPacket = 32768;
mDataFormat.mFramesPerPacket = samplecount;
mDataFormat.mBytesPerFrame = mSoundData->BytesPerSample(); // BytesPerSample returns 4.
mDataFormat.mChannelsPerFrame = 2;
mDataFormat.mBitsPerChannel = uint32(mSoundData->BitsPerChannel());
mDataFormat.mReserved = 0;
AudioQueueNewOutput( &mDataFormat, BuildBuffer, this, CFRunLoopGetCurrent(), kCFRunLoopCommonModes, 0, &mQueue );
for( int i = 0; i < NUMBER_BUFFERS; ++i )
{
AudioQueueAllocateBuffer( mQueue, mBufferByteSize, &mBuffers[i] );
HandleOutputBuffer( mQueue, mBuffers[i] );
}
AudioQueueStart( mQueue, NULL ); // I want the queue to start playing immediately, so I pass NULL
do {
CFRunLoopRunInMode( kCFRunLoopDefaultMode, 0.25, false );
} while ( !NeedStopASAP() );
AudioQueueDispose( mQueue, true );
}
The call to AudioQueueStart returns -50 (bad parameter) and I can't figure what's wrong...
I would really appreciate some help, thanks in advance :-)
I think your ASBD is suspect. PCM formats have predictable values for mBytesPerPacket, mBytesPerFrame, and mFramesPerPacket. For normal 16-bit interleaved signed 44.1 stereo audio the ASBD would look like
AudioStreamBasicDescription asbd = {
.mFormatID = kAudioFormatLinearPCM,
.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked,
.mSampleRate = 44100,
.mChannelsPerFrame = 2,
.mBitsPerChannel = 16,
.mBytesPerPacket = 4,
.mFramesPerPacket = 1,
.mBytesPerFrame = 4,
.mReserved = 0
};
AudioConverterNew returns -50 when one of the ASBDs is unsupported. There is no PCM format where mBytesPerPacket should be 32768, which is why you're getting the error.

Measuring Download Speed in curl and c++. Am I doing it correctly?

I am trying to figure out how to calculate current download speed while downloading Folder of many file(Its not a single file that I am downloading). And I am not able to do it correctly, and now going through it for many hours, its getting too confusing. The download speed sometimes go too high and sometimes its 0.
I am using curl and c++.
In my Download Function the program recursively download each file till all the files are being downloaded.
This is how I setup curl to call TraceProgress function during download:
curl_easy_setopt( curl, CURLOPT_PROGRESSFUNCTION, TraceProgress );
curl_easy_setopt( curl, CURLOPT_PROGRESSDATA, &response );
curl_easy_setopt( curl, CURLOPT_NOPROGRESS, 0 );
Here is the remaining code:
double totalDownloadableSize = 0; // total size of the download, set prior to starting download of the first file
double downloadedSizeTillNow = 0; // total size downloaded till now - keep adding file size that just completed downloading
double currentDownloadingSize = 0; // size that we are downloading - downloadedSizeTillNow + bytes downloaded of the current file (in TraceProgress Function)
double oldDownloadNow = 0; // size of the old download bytes of that particular file
string fileDownloading = "";
string tempFileDownloading = "";
time_t startSeconds;
time_t oldSeconds;
int downloadIterationCounter = 0;
int TraceProgress( void *clientp, double dltotal, double dlnow, double ultotal, double ulnow )
{
// add size downloaded till now of this file to the total size downloaded till now
currentDownloadingSize = downloadedSizeTillNow + dlnow;
double rem = ( ( totalDownloadableSize - currentDownloadingSize ) / 1024 ) / 1024;
// get current time in seconds
time_t currentSeconds = time (NULL);
// get elapsed time since last itiration
time_t secondsElapsedSinceLastItiration = currentSeconds - oldSeconds;
double downloadSinceLastIteration;
if ( oldDownloadNow < dlnow )// so that we don't get wrong data when download file changes
{
downloadSinceLastIteration = dlnow - oldDownloadNow;
}
else
{
downloadSinceLastIteration = dlnow;
}
// calculate current download speed : (dlnow - oldNow) / (current time - oldTime)
double currentDownloadSpeed = downloadSinceLastIteration / (double)secondsElapsedSinceLastItiration;
// if downloading file name is not same as it was in the last call to this function
// change the display text and save the name in the temp. This approach will avoid unnecessory
// text change calls.
if ( fileDownloading.compare( tempFileDownloading ) != 0 )
{
tempFileDownloading = fileDownloading;
string dlfilename = "Downloading: " + fileDownloading;
SetWindowText( hDownloadingSTATIC, dlfilename.c_str() );// set text to static control
}
if ( downloadIterationCounter == 4 )
{
std::ostringstream strs_dn;
strs_dn << (unsigned int)( rem );
std::string downloadNow = strs_dn.str();
string remSize = "Remaining: " + downloadNow + " MB";
SetWindowText( hRemainingDownloadSTATIC, remSize.c_str() );// set text to static control
double idownloadSpeed = currentDownloadSpeed / 1024;
std::ostringstream strs_dnSp;
strs_dnSp << (unsigned int)( idownloadSpeed );
std::string downloadSpeed = strs_dnSp.str();
string downSize = "Download Speed: " + downloadSpeed + " KB/s";
SetWindowText( hDownloadSpeedSTATIC, downSize.c_str() );// set text to static control
oldSeconds = currentSeconds;// save in old
oldDownloadNow = dlnow;// save in old
downloadIterationCounter = 0;
}
else
{
downloadIterationCounter++;
}
return 0;
}
Any help is appreciated. Thanks a lot.
dlnow - oldDownloadNow is probably wrong. You should be just using dlnow instead. You don't need oldDownloadNow at all, unless you want to show the download speed rate of change.
I was confused by the `dltotal` and `dlnow` names. `dltotal` is the *expected* total bytes downloaded, and `dlnow` is bytes downloaded so far. So one does need `oldDownloadNow`, and `dlnow - oldDownloadNow` is the current delta.
This fragment
if ( oldDownloadNow < dlnow )
{
downloadSinceLastIteration = dlnow - oldDownloadNow;
}
else
{
downloadSinceLastIteration = dlnow;
}
has an error: oldDownloadNow == dlnow means that nothing was downloaded since the last time. In this case the current momentary download speed is zero. The fragment should be replaced with
downloadSinceLastIteration = dlnow - oldDownloadNow;
with no check whatsoever. If libcurl suddenly decidess that oldDownloadNow > dlnow, this will duly display negative download speed, which is the right thing to do. Never hide an error intentionally.
In addition, the time() resolution is too coarse. Use some kind of fine-grained timer.

How can I get sample from AudioBufferList

I get the AudioBufferList from a wav file(Which Sample Rate is 44100HZ and the long time is 2second).
But I can't get 44100*2=88200 samples. In actually I got an AudiobufferList which contain 512 nNumberBuffers.
How can I get the sample from the AudioBufferList?
here is my method to get the samples from a wav file
-(float *) GetSoundFile:(NSString *)fileName
{
NSBundle *bundle = [NSBundle mainBundle];
NSString *path = [bundle pathForResource:[fileName stringByDeletingPathExtension]
ofType:[fileName pathExtension]];
NSURL *audioURL = [NSURL fileURLWithPath:path];
if (!audioURL)
{
NSLog(#"file: %# not found.", fileName);
}
OSStatus err = 0;
theFileLengthInFrames = 0; //this is global
AudioStreamBasicDescription theFileFormat;
UInt32 thePropertySize = sizeof(theFileFormat);
ExtAudioFileRef extRef = NULL;
void* theData = NULL;
AudioStreamBasicDescription theOutputFormat;
// Open a file with ExtAudioFileOpen()
err = ExtAudioFileOpenURL((__bridge CFURLRef)(audioURL), &extRef);
// Get the audio data format
err = ExtAudioFileGetProperty(extRef, kExtAudioFileProperty_FileDataFormat, &thePropertySize, &theFileFormat);
theOutputFormat.mSampleRate = samplingRate = theFileFormat.mSampleRate;
theOutputFormat.mChannelsPerFrame = numChannels = 1;
theOutputFormat.mFormatID = kAudioFormatLinearPCM;
theOutputFormat.mBytesPerFrame = sizeof(Float32) * theOutputFormat.mChannelsPerFrame ;
theOutputFormat.mFramesPerPacket = theFileFormat.mFramesPerPacket;
theOutputFormat.mBytesPerPacket = theOutputFormat.mFramesPerPacket * theOutputFormat.mBytesPerFrame;
theOutputFormat.mBitsPerChannel = sizeof(Float32) * 8 ;
theOutputFormat.mFormatFlags = 9 | 12;
//set the output property
err = ExtAudioFileSetProperty(extRef, kExtAudioFileProperty_ClientDataFormat, sizeof(AudioStreamBasicDescription), &theOutputFormat);
// Here I Get the total frame count and write it into gloabal variable
thePropertySize = sizeof(theFileLengthInFrames);
err = ExtAudioFileGetProperty(extRef, kExtAudioFileProperty_FileLengthFrames, &thePropertySize, &theFileLengthInFrames);
UInt32 dataSize = (UInt32)(theFileLengthInFrames * theOutputFormat.mBytesPerFrame);
theData = malloc(dataSize);
AudioBufferList theDataBuffer;
if (theData)
{
theDataBuffer.mNumberBuffers = 1;
theDataBuffer.mBuffers[0].mDataByteSize = dataSize;
theDataBuffer.mBuffers[0].mNumberChannels = theOutputFormat.mChannelsPerFrame;
theDataBuffer.mBuffers[0].mData = theData;
// Read the data into an AudioBufferList
err = ExtAudioFileRead(extRef, (UInt32*)&theFileLengthInFrames, &theDataBuffer);
}
return (float*)theDataBuffer.mBuffers[0].mData;
//here is the data that has thefilelengthInframes amount frames
}
AudioBufferList should not be set to a fixed size because is a temporary buffer, hardware dependent.
The size is unpredictable and you can only set a preferable size, moreover is not granted to be the same size between 2 reading calls.
To get 88200 samples (or what you like) you must incrementally fill a new buffer using,
time by time, the samples in AudioBufferList.
I suggest to use this circular buffer https://github.com/michaeltyson/TPCircularBuffer
made for this purpose.
Hope this help
As I know, AudioBufferList must be configured by you to receive data to it and then it must be filled by some reading function (e.g. ExtAudioFileRead()). So you should prepare it by allocating buffers you need (usually 1 or 2), set nNumberBuffers to that number and read audio data to them. AudioBufferList just stores that buffers and they are will contain frames values.