Re: Audio glitches during playback thru Remote IO unit (iPhone)
Re: Audio glitches during playback thru Remote IO unit (iPhone)
- Subject: Re: Audio glitches during playback thru Remote IO unit (iPhone)
- From: Steven Winston <email@hidden>
- Date: Thu, 13 Aug 2009 14:53:22 -0700
Hi Zhiye,
That's the pesky thing about examples, they often show exactly what
you're looking for but not what you want :). Doing a separate call in
a thread or even a timer will give you the solution you're looking
for. You need to have a large enough buffer already rendered to keep
the hungry beast that is RemoteIO fed. The render function should
almost always be nothing more than something akin to this:
static OSStatis AudioOutputCallback( void * inRefCon,
AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp
*inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames,
AudioBufferList *ioData ) {
if(inBusNumber == 0 ) { //only matters if you also have defined a
render callback for the mic
for(int i = 0; i < inNumberFrames; i++)
(UInt32 *)&ioData->mBuffers[0].mData [i] =
(UInt32*)&((AudioClass*)inRefCon)->playBuffer.mBuffers[0].mData [i];
return noErr;
}
WARNING Above code is untested (just eyeballed it). The other side of
what you're gonna want to do depends on the method you're using to get
the original file read in (for anything of length you have to use a
streaming solution). I'd recommend using AudioQueueServices offline
render to read the file in manageable chunks. Set the buffer size to 3
times the size of you playing buffer. Fill up the play buffer when
the user presses play so you guarantee that it stays full; you'll want
to use a separate thread to instruct AudioQueueServices to do it's
offline render thing. Here's something that I'd use (simple timer
callback again eyeballing as not near my compiler):
void TimerCallback(CFRunLoopTimerRef timer, void *inRefCon) {
AudioClass *THIS = (AudioClass*)inRefCon;
UInt32 reqFrames = (THIS->mBufferByteSize / 2) /
THIS->captureFormat.mBytesPerFrame;
AudioQueueOfflineRender(THIS->mQueue, &THIS->ts,
THIS->captureBuffer, reqFrames);
THIS->playBuffer.mBuffers[0].mData = THIS->captureBuffer->mAudioData;
THIS->playBuffer.mBuffers[0].mDataByteSize =
THIS->captureBuffer->mAudioDataByteSize;
UInt32 writeFrames = THIS->captureABL.mBuffers[0].mDataByteSize /
THIS->captureFormat.mBytesPerFrame;
THIS->ts.mSampleTime += writeFrames;
}
then to setup the timer:
CFRunLoopTimerContext info;
info.version = 0;
info.info = this;
info.retain = NULL;
info.release = NULL;
info.copyDescription = NULL;
RenderTimer = CFRunLoopTimerCreate(NULL, CFAbsoluteTimeGetCurrent(),
(CFTimeInterval)0.25f, 0,0,TimerCallback, &info);
Alright, if you mangle the above enough, you should get the rest of
the way towards what you're trying to do.
Good Luck.
Steve
On Thu, Aug 13, 2009 at 2:28 PM, Zhiye (Sterling)
Li<email@hidden> wrote:
> Hi Bill and Steve,
>
> Thanks a lot for replying. I wish it was not a complicated problem. I guess
> I should study more on the threading chapter. So Bill, do you mean using
> p-thread is the solution to my problem? Sorry, I am new to all theses... So
> the idea is to lock the rendering thread while doing file i/o ?
>
> hi steve, I saw the examples from the link in your reply, however, his code
> only works for short files, because he pre-loads the entire audio file to
> memory before playback, which will not work for long files, especially on
> iPhone. But still thanks a lot!
>
> -Zhiye
>
> On Wed, Aug 12, 2009 at 4:55 PM, William Stewart <email@hidden> wrote:
>>
>> Reading from the file system can take locks, and it does so
>> unconditionally, so you can block and you will miss your deadline, and you
>> hear gaps. So, you don't do this.
>>
>> The render callback from an audio unit that is attached to an audio device
>> (AURIO or AUHAL on the desktop) is running within the context of a deadline
>> driven thread. The deadline is the time represented by a particular request
>> to produce some amount of audio data - say 512 frames at 44.1KHz, means that
>> you have to provide that full amount of data (no more, no less) within that
>> time period (which is approx 11msec)
>>
>> Things that take locks, so you don't do it in the render thread:
>> - reading or writing to the file system
>> - malloc or free (also operator new / delete that would to a
>> "normal" memory allocation pool)
>> - unconditional lock aquisition (in this case you can do a try, and
>> be prepared to NOT obtain the lock - CAMutex has some examples of the
>> difference between Lock and Try using p-thread constructs)
>>
>> Then of course, there's the general problem of just taking too much time
>> (ie, running computations that take more time than you have available)
>>
>> Welcome to core audio :)
>>
>> Bill
>>
>>
>> On Aug 12, 2009, at 12:02 AM, tahome izwah wrote:
>>
>>> I think it is discouraged to do synchronous reads within a render
>>> callback. You should have a separate reader thread and queue up your
>>> audio buffers in memory until they are needed for playback.
>>>
>>> --th
>>> _______________________________________________
>>> Do not post admin requests to the list. They will be ignored.
>>> Coreaudio-api mailing list (email@hidden)
>>> Help/Unsubscribe/Update your Subscription:
>>>
>>> This email sent to email@hidden
>>
>> _______________________________________________
>> Do not post admin requests to the list. They will be ignored.
>> Coreaudio-api mailing list (email@hidden)
>> Help/Unsubscribe/Update your Subscription:
>>
>>
>> This email sent to email@hidden
>
>
> _______________________________________________
> Do not post admin requests to the list. They will be ignored.
> Coreaudio-api mailing list (email@hidden)
> Help/Unsubscribe/Update your Subscription:
>
> This email sent to email@hidden
>
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Coreaudio-api mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden