Frames during Audio playback are consumed very fast - linux

My requirement is to play 16 bit, 22KHz linear PCM data to audioout using alsa API. I have added 2 section of code which i have written to configure ALSA and audioout wrapper which writes 2048 frames using write API.
Issue : Getting distorted noise and consuming available frames very quickly
I am configuring ALSA using below api's.
//opening audio handle
if ((err = snd_pcm_open (&rsettings->ppcm_handle, name, SND_PCM_STREAM_PLAYBACK, 0)) < 0)
{
return -1;
}
if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0)
{
return -1;
}
if ((err = snd_pcm_hw_params_any (rsettings->ppcm_handle, hw_params)) < 0)
{
return -1;
}
//setting interleaved mode
if ((err = snd_pcm_hw_params_set_access (rsettings->ppcm_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
{
return -1;
}
//setting bit depth to 2 byte
if ((err = snd_pcm_hw_params_set_format (rsettings->ppcm_handle, hw_params, SND_PCM_FORMAT_S16_LE) ) < 0)
{
return -1;
}
//Setting sample rate to 22050 Hz
if ((err = snd_pcm_hw_params_set_rate(rsettings->ppcm_handle, hw_params, 22050, 0 ) ) < 0 )
{
return -1;
}
//setting number of channels to 1
if ((err = snd_pcm_hw_params_set_channels (rsettings->ppcm_handle, hw_params, 1 ) ) < 0)
{
return -1;
}
snd_pcm_uframes_t frame_size = 1024;
if(( err = snd_pcm_hw_params_set_period_size_near(rsettings->ppcm_handle, hw_params, &frame_size, 0 ) ) < 0 )
{
printf("\n cannot set size");
return -1;
}
// setting number of period to 1
if ((err = snd_pcm_hw_params_set_periods(rsettings->ppcm_handle, hw_params, 1, 1 ) ) < 0)
{
return -1;
}
frame_size = 2048;
//setting buffer size to 2048
if ((err = snd_pcm_hw_params_set_buffer_size_near(rsettings->ppcm_handle, hw_params, &frame_size) ) < 0)
{
return -1;
}
if ((err = snd_pcm_nonblock (rsettings->ppcm_handle, 0 ) ) < 0)
{
return -1;
}
if ( (err = snd_pcm_hw_params (rsettings->ppcm_handle, hw_params)) < 0)
{
return -1;
}
snd_pcm_hw_params_free (hw_params);
if ((err = snd_pcm_prepare (rsettings->ppcm_handle)) < 0)
{
return -1;
}
I have audioout API using POLLING as below
noOfFrames = 2024
while( noOfFrames > 0 )
{
if( 0 > ( poll( descriptors, pollDescriptorCount, 500 ) ) )
{
printf("error polling for data");
}
else
{
printf("\nPoll Unblocked");
if( 0 > ( retVal = snd_pcm_poll_descriptors_revents( rsettings->ppcm_handle, descriptors, pollDescriptorCount, &pollEvent ) ) )
{
printf("\nError getting poll events, return value : %d", retVal);
break;
}
else
{
frames = snd_pcm_avail_update( rsettings->ppcm_handle );
printf("\nAvailable channel frames = %d",frames );
if( frames < 0 )
{
if( frames == -EPIPE )
{
snd_pcm_prepare( rsettings->ppcm_handle );
}
else if( frames == -ESTRPIPE )
{
while (-EAGAIN == snd_pcm_resume( rsettings->ppcm_handle ) )
usleep(2000);
}
else
{
snd_pcm_prepare( rsettings->ppcm_handle);
}
}
else
{
if( frames >= noOfFrames )
{
if ((framesWritten = snd_pcm_writei(rsettings->ppcm_handle, &pBuffer, noOfFrames)) > 0 )
{
printf("\nNo of frames written : %d",framesWritten);
noOfFrames = noOfFrames - framesWritten;
free(descriptors);
}
else if( framesWritten < 0 )
{
if( framesWritten == -EPIPE )
{
snd_pcm_prepare( rsettings->ppcm_handle );
}
else if( framesWritten == -ESTRPIPE )
{
while (-EAGAIN == snd_pcm_resume( rsettings->ppcm_handle ))
usleep(2000);
}
else
{
snd_pcm_prepare( rsettings->ppcm_handle );
}
}
}
else
{
if ( ( framesWritten = snd_pcm_writei(rsettings->ppcm_handle, &pBuffer, frames ) ) > 0 )
{
printf("\nNo of frames written : %d",framesWritten);
noOfFrames = noOfFrames - framesWritten;
free(descriptors);
}
else if( framesWritten < 0 )
{
if( framesWritten == -EPIPE )
{
snd_pcm_prepare( rsettings->ppcm_handle );
}
else if( framesWritten == -ESTRPIPE )
{
while (-EAGAIN == snd_pcm_resume( rsettings->ppcm_handle ))
usleep(2000);
}
else
{
snd_pcm_prepare( rsettings->ppcm_handle );
}
}
}
}
}
}
}
Can some tell where i am going wrong.

Polling to fill Audio Unit buffers with just the requested amount of data will not work. You have to use the Audio Unit callback routines (which the OS calls using a lower latency real-time thread) to fill the audio buffers.
You can poll to pre-fill a lock-free circular fifo with a sufficient amount of audio samples for the Audio Unit callbacks to copy from.

Related

Using RegisterHotKey with number pad values not working?

I have some constants:
constexpr int MonitorDisplay1 = 100;
constexpr int MonitorDisplay2 = 200;
constexpr int MonitorDisplay3 = 400;
constexpr int MonitorDisplay4 = 500;
constexpr int MonitorDisplay1KeyPad = 101;
constexpr int MonitorDisplay2KeyPad = 201;
constexpr int MonitorDisplay3KeyPad = 401;
constexpr int MonitorDisplay4KeyPad = 501;
I have an OnCreate where I setup the hot keys:
int CCenterCursorOnScreenDlg::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (__super::OnCreate(lpCreateStruct) == -1)
return -1;
auto RegisterAppHotkey = [hAppWnd = GetSafeHwnd()](const int nHotKeyID, UINT vk)->bool
{
if (!::RegisterHotKey(hAppWnd, nHotKeyID, MOD_CONTROL | MOD_SHIFT, vk))
{
auto const ec = ::GetLastError();
auto const err_msg = std::format(L"RegisterHotKey failed (error: {})\n",
ec);
AfxMessageBox(err_msg.c_str());
return false;
}
return true;
};
if (m_monitors.rcMonitors.size() > 0)
{
if (!RegisterAppHotkey(MonitorDisplay1, '1'))
{
return -1;
}
if (!RegisterAppHotkey(MonitorDisplay1KeyPad, VK_NUMPAD1))
{
return -1;
}
}
if (m_monitors.rcMonitors.size() > 1)
{
if (!RegisterAppHotkey(MonitorDisplay2, '2'))
{
return -1;
}
if (!RegisterAppHotkey(MonitorDisplay2KeyPad, VK_NUMPAD2))
{
return -1;
}
}
if (m_monitors.rcMonitors.size() > 2)
{
if (!RegisterAppHotkey(MonitorDisplay3, '3'))
{
return -1;
}
if (!RegisterAppHotkey(MonitorDisplay3KeyPad, VK_NUMPAD3))
{
return -1;
}
}
if (m_monitors.rcMonitors.size() > 3)
{
if (!RegisterAppHotkey(MonitorDisplay4, '4'))
{
return -1;
}
if (!RegisterAppHotkey(MonitorDisplay4KeyPad, VK_NUMPAD4))
{
return -1;
}
}
return 0;
}
Previously I just had the 4 hotkeys for 1 / 2 / 3 and 4. They still work. I tried to add new hotkeys for for the number pad on the keyboard, but they are not working.
My OnHotKey handler:
void CCenterCursorOnScreenDlg::OnHotKey(UINT nHotKeyId, UINT nKey1, UINT nKey2)
{
if (nHotKeyId == MonitorDisplay1 || nHotKeyId == MonitorDisplay1KeyPad)
{
CenterCursorOnMonitor(0);
}
else if (nHotKeyId == MonitorDisplay2 || nHotKeyId == MonitorDisplay2KeyPad)
{
CenterCursorOnMonitor(1);
}
else if (nHotKeyId == MonitorDisplay3 || nHotKeyId == MonitorDisplay3KeyPad)
{
CenterCursorOnMonitor(2);
}
else if (nHotKeyId == MonitorDisplay4 || nHotKeyId == MonitorDisplay4KeyPad)
{
CenterCursorOnMonitor(3);
}
__super::OnHotKey(nHotKeyId, nKey1, nKey2);
}
But the number pad versions are not working. Why?
I am unregistering all 8 hotkeys, and num-lock is on. I get no warnings when registering.
This article explains List of Keys (Keyboard, Mouse and Joystick):
Because I was using CTRL + SHIFT, then the meaning of the 4 numeric keys was changing:
End
Down
Page Down
Left
It made sense to change my hotkeys to CTRL + ALT instead to avoid this issue.

How to select multiple items in treewidget and delete those items?

When I am selecting items in treewidget and then clicked on delete button then is is just deleting top most item only from treewidget
Can you correct this code?
This function is calling in connect statement while clicking on button
void TableDockWidget::deleteGroup() {
QTreeWidgetItem *item = treeWidget->currentItem();
QTreeWidgetItem* nextItem = treeWidget->itemBelow(item);
if ( item == NULL ) return;
PeakGroup* group = getSelectedGroup(); //this function is using to //select items from treewidget
if ( group == NULL ) return;
PeakGroup* parentGroup = group->parent;
if ( parentGroup == NULL ) { //top level item
deleteGroup(group); //this is using to delete group
} else if ( parentGroup && parentGroup->childCount() ) { //this a child item
if ( parentGroup->deleteChild(group) ) {
QTreeWidgetItem* parentItem = item->parent();
if ( parentItem ) {
parentItem->removeChild(item);
delete(item);
}
}
}
//show NextItem
if(nextItem) treeWidget->setCurrentItem(nextItem,0);
return;
}
//here, code of function which is selecting items.
PeakGroup* TableDockWidget::getSelectedGroup() {
QTreeWidgetItem *item = treeWidget->currentItem();
if (!item) return NULL;
QVariant v = item->data(0,Qt::UserRole);
PeakGroup* group = v.value<PeakGroup*>();
if ( group != NULL ) { return group; }
return NULL;
}
// code of function which is deleting group
void TableDockWidget::deleteGroup(PeakGroup *groupX) {
qDebug() << "TableDockWidget::deleteGroup()";
if(!groupX) return;
int pos=-1;
for(int i=0; i < allgroups.size(); i++) {
if ( &allgroups[i] == groupX ) {
pos=i; break;
}
}
if (pos == -1) return;
//qDebug() << "Delete pos=" << pos;
QTreeWidgetItemIterator it(treeWidget);
while (*it) {
QTreeWidgetItem* item = (*it);
if (item->isHidden()) { ++it; continue; }
QVariant v = item->data(0,Qt::UserRole);
PeakGroup* group = v.value<PeakGroup*>();
if ( group != NULL and group == groupX) {
item->setHidden(true);
//Deleteing
allgroups.erase(allgroups.begin()+pos);
int posTree = treeWidget->indexOfTopLevelItem(item);
if (posTree != -1) treeWidget->takeTopLevelItem(posTree);
break;
}
++it;
}
for(unsigned int i = 0; i < allgroups.size(); i++) {
allgroups[i].groupId = i + 1;
}
updateTable();
_mainwindow->getEicWidget()->replotForced();
}
PeakGroup* TableDockWidget::getSelectedGroup() {
PeakGroup* group;
QList<QTreeWidgetItem*>selected = treeWidget->selectedItems();
if(selected.size() == 0) return NULL;
Q_FOREACH (QTreeWidgetItem* item, selected) {
QVariant v = item->data(0,Qt::UserRole);
group = v.value<PeakGroup*>();
item->setHidden(true);
}
if ( group != NULL ) { return group; }
else
return NULL;
}

Core Audio Queues Cracking

I get a cracking at the beginning and end of a core audio output queue. The code should simply generate a tone.
Edit: created a sample project
https://github.com/MrMatthias/CoreAudioCrackle
Here is the setup:
-(void) startOutputQueue {
if(userData.outputQueue != NULL) {
if(!checkError(AudioQueuePrime(userData.outputQueue, 0, NULL), "AudioQueuePrime")) {
NSLog(#"Error priming QutputQueue");
}
if(!checkError(AudioQueueStart(userData.outputQueue, NULL), "AudioQueueStart Output")) {
NSLog(#"Error starting OutputQueue");
}
}
}
-(void) setupOutputQueue {
memset(&userData.outputDesc, 0, sizeof(userData.outputDesc));
userData.outputDesc.mFormatID = kAudioFormatLinearPCM;
userData.outputDesc.mFramesPerPacket = 1;
userData.outputDesc.mFormatFlags = kAudioFormatFlagIsBigEndian | kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
userData.outputDesc.mChannelsPerFrame = 1;
userData.outputDesc.mSampleRate = 44100;
userData.outputDesc.mBitsPerChannel = 16;
userData.outputDesc.mBytesPerFrame = userData.outputDesc.mBytesPerPacket = 2;
userData.outputSamplePosition = 0;
if (userData.outputQueue == NULL) {
if(!checkError(AudioQueueNewOutput(&userData.outputDesc, outputCallback, &userData, NULL, NULL, 0, &userData.outputQueue), "AudioQueueNewOutput")) {
return;
}
UInt32 bufferSize = userData.outputDesc.mBytesPerFrame * userData.outputDesc.mSampleRate * DURATION;
for (int i=0; i<3; ++i) {
if(!checkError(AudioQueueAllocateBuffer(userData.outputQueue, bufferSize, &userData.outputBuffers[i]), "AudioQueueAllocateBuffer")) {
return;
}
outputCallback(&userData, userData.outputQueue, userData.outputBuffers[i]);
}
}
}
In the output callback i call a block that fills the buffers:
userData->outputBlock(userData, inAQ, inBuffer);
AudioQueueEnqueueBuffer(userData->outputQueue, inBuffer, 0, NULL);
Filling of the Buffer looks like this:
UInt32 sampleCount = DURATION * userData->outputDesc.mSampleRate;
double f1 = userData->outputDesc.mSampleRate / 10000.0f;
for (int i=0; i<sampleCount; ++i) {
SInt16 sample = CFSwapInt16HostToBig(SHRT_MAX * ( sin((userData->outputSamplePosition + i) * 2 * M_PI / f1) ));
((SInt16*)inBuffer->mAudioData)[i] = sample;
}
userData->outputSamplePosition += sampleCount;
inBuffer->mAudioDataByteSize = sampleCount * 2;
The recording looks like this:
Try adding (SInt16) just before SHRT_MAX ( sin((userData->...
such that your entire code block looks like this
SInt16 sample = CFSwapInt16HostToBig((SInt16)SHRT_MAX * ( sin((userData->outputSamplePosition + i) * 2 * M_PI / f1) ));

ffmpeg-android Extract Audio From Digital Container Format

I make program extracts audio from Digital Container Format (DCF).
I want to obtain an encoded audio file.
so, I think that I can write to file only audio stream packet.
Some DCF file work well, but some files does not work.
Please, can you help me to find a problem?
// src -- is DCF
// dest -- is going to write file
int ExtractAudio(const char src[], const char dest[]) {
av_register_all();
avcodec_register_all();
__android_log_print(ANDROID_LOG_DEBUG, "test", "dest : %s", dest);
__android_log_print(ANDROID_LOG_DEBUG, "test", "src : %s", src);
//파일을 열고 컨텍스트에 파일 형식을 불러온다.
AVFormatContext * pInputFormatContext = NULL;
int err = avformat_open_input(&pInputFormatContext, src, NULL, NULL);
if (err < 0) {
__android_log_print( ANDROID_LOG_DEBUG, "test",
"avformat_open_input Err! %d",err);
return 0;
}
FILE *destFile = fopen(dest, "wb");
FILE *srcFile = fopen(src, "rb");
if (destFile == NULL || srcFile == NULL) {
__android_log_print(ANDROID_LOG_DEBUG, "test", "fopen Err!");
__android_log_print(ANDROID_LOG_DEBUG, "test", "fopen Err!");
return 0;
}
fseek(srcFile, 0, SEEK_END);
DCFSize = ftell(srcFile);
fseek(srcFile, 0, SEEK_SET);
int nAudioStreamIdx = -1;
AVCodec *pAudioCodec = NULL;
err = av_find_stream_info(pInputFormatContext);
if (err < 0) {
__android_log_print(ANDROID_LOG_DEBUG, "test",
"av_find_stream_info Err!");
__android_log_print(ANDROID_LOG_DEBUG, "test",
"av_find_stream_info Err!");
return 0;
}
err = av_find_best_stream(pInputFormatContext, AVMEDIA_TYPE_AUDIO, -1, -1,
&pAudioCodec, NULL);
//에러처리 임시
if (err < 0) {
nAudioStreamIdx = 1;
if (err == AVERROR_STREAM_NOT_FOUND)
__android_log_print(ANDROID_LOG_DEBUG, "test",
"AVERROR_STREAM_NOT_FOUND");
if (err == AVERROR_DECODER_NOT_FOUND)
__android_log_print(ANDROID_LOG_DEBUG, "test",
"AVERROR_DECODER_NOT_FOUND ");
} else
nAudioStreamIdx = err;
AVPacket Packet;
av_init_packet(&Packet);
while (av_read_frame(pInputFormatContext, &Packet) >= 0) {
if (Packet.stream_index == nAudioStreamIdx)
{
fwrite(Packet.data, 1, Packet.size, destFile);
PaketPos = Packet.pos;
//__android_log_print(ANDROID_LOG_DEBUG, "test","Extract Progress : %d",getExtractProgress());
}
}
PaketPos = DCFSize;
return 1;
}

dde callback function does not work

Here's the problem:
I wrote a program to receive data from a StockClient.
When I use DDESpy, I can see s message such as
Time:xxxx hwndTo=0xe00b0 Message(Posted)=Data:<br>
hwndFrom=0x1f06dc, status=2000(fRelease ) fmt=0x1("CF_TEXT")<br>
Data= "value"<br>
Item= "xxxxx"<br>
But my ddecallback function doesn't work (occasionally it can work), why?
DdeInitialize( &_dde_inst, dde_callback, APPCMD_CLIENTONLY/*|CBF_FAIL_ALLSVRXACTIONS*/, 0 );
HSZ _server = DdeCreateStringHandle ( _dde_inst, "DDEServer", CP_WINANSI );
if( !_server )
return -1;
HSZ _topic = DdeCreateStringHandle( _dde_inst, "TOPIC1", CP_WINANSI );
HCONV _conv = DdeConnect( _dde_inst, _server, _topic, NULL );
if( !_conv )
return -1;
for( int i = 0; i < ITEM_NUM; ++i )
{
HSZ _item = DdeCreateStringHandle( _dde_inst, _list[i], CP_WINANSI );
if( _item )
{
DWORD _result;
HDDEDATA _data = DdeClientTransaction( NULL, NULL, _conv, _item, CF_TEXT, XTYP_ADVSTART, TIMEOUT_ASYNC, &_result );
UINT _error = DdeGetLastError(_dde_inst );
DdeFreeStringHandle( _dde_inst, _item );
int _reserve = DMLERR_NO_ERROR;
if( _error != 0 )
{
fprintf( stdout, "dde error = %d\n", _error );
continue;
}
}
}

Resources