• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
How to setup a finished playing audio callback
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

How to setup a finished playing audio callback


  • Subject: How to setup a finished playing audio callback
  • From: Jim Griffin <email@hidden>
  • Date: Mon, 01 Apr 2013 10:08:41 -0400

Hello everyone,

I am working on a project to playback portions of audio files. I am using an AUGraph to 
achieve this since I want to route the audio signal through another component, ie Apple's 
Time Pitch component, kAudioUnitSubType_TimePitch. I set up the graph, the playback 
region and can get the audio playing correctly.  I just cannot determine how to setup
a callback method to tell me when the audio components have finished playing the audio
clip I've setup.  I have been following the examples from the book "Learning Core Audio: A 
Hands-On Guide to Audio Programming for Mac and iOS" by Chris Adamson and the examples 
are great, except how do I set up a callback to let me know when the audio clip is finished.

Here is some of my code.  I create the graph like this:

+(void) createAUGraph:(AUAudioPlayback*)audio
{

// create a new AUGraph
CheckError(NewAUGraph(&audio->_audioPlaybackAudioFile.graph),
"NewAUGraph failed");

// generate description that will match out output device (speakers)
AudioComponentDescription outputcd = {0};
outputcd.componentType = kAudioUnitType_Output;
outputcd.componentSubType = kAudioUnitSubType_DefaultOutput;
outputcd.componentManufacturer = kAudioUnitManufacturer_Apple;

// adds a node with above description to the graph
AUNode outputNode;
CheckError(AUGraphAddNode(audio->_audioPlaybackAudioFile.graph, &outputcd, &outputNode),
"AUGraphAddNode[kAudioUnitSubType_DefaultOutput] failed");

// generate description that will match a generator AU of type: audio file player
AudioComponentDescription fileplayercd = {0};
fileplayercd.componentType = kAudioUnitType_Generator;
fileplayercd.componentSubType = kAudioUnitSubType_AudioFilePlayer;
fileplayercd.componentManufacturer = kAudioUnitManufacturer_Apple;

// adds a node with above description to the graph
AUNode fileNode;
CheckError(AUGraphAddNode(audio->_audioPlaybackAudioFile.graph, &fileplayercd, &fileNode),
"AUGraphAddNode[kAudioUnitSubType_AudioFilePlayer] failed");

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// generate description that will match a timePitchComponent AU of type: Format Converter
AudioComponentDescription auTimePitchComponent = {0};
auTimePitchComponent.componentType = kAudioUnitType_FormatConverter;
auTimePitchComponent.componentSubType = kAudioUnitSubType_TimePitch;
auTimePitchComponent.componentManufacturer = kAudioUnitManufacturer_Apple;

// adds a node with above description to the graph
AUNode auTimePitchNode;
CheckError(AUGraphAddNode(audio->_audioPlaybackAudioFile.graph, &auTimePitchComponent, &auTimePitchNode),
"AUGraphAddNode[kAudioUnitSubType_auTimePitchNode] failed");


// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// opening the graph opens all contained audio units but does not allocate any resources yet
CheckError(AUGraphOpen(audio->_audioPlaybackAudioFile.graph),
"AUGraphOpen failed");

// get the reference to the AudioUnit object for the file player graph node
CheckError(AUGraphNodeInfo(audio->_audioPlaybackAudioFile.graph,
 auTimePitchNode,
 NULL,
 &audio->_audioPlaybackAudioFile.timePitchAU),
"AUGraphNodeInfo failed");

// get the reference to the outputNode object for the file player graph node
CheckError(AUGraphNodeInfo(audio->_audioPlaybackAudioFile.graph,
 outputNode,
 NULL,
 &audio->_audioPlaybackAudioFile.outputAU),
"AUGraphNodeInfo failed");

// get the reference to the AudioUnit object for the file player graph node
CheckError(AUGraphNodeInfo(audio->_audioPlaybackAudioFile.graph,
 fileNode,
 NULL,
 &audio->_audioPlaybackAudioFile.fileAU),
"AUGraphNodeInfo failed");

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// connect the output source of the file player AU to the input source of the output node
CheckError(AUGraphConnectNodeInput(audio->_audioPlaybackAudioFile.graph,
fileNode,
0,
auTimePitchNode,
0),
"AUGraphConnectNodeInput");
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// connect the output source of the file player AU to the input source of the output node
CheckError(AUGraphConnectNodeInput(audio->_audioPlaybackAudioFile.graph,
auTimePitchNode,
0,
outputNode,
0),
"AUGraphConnectNodeInput");
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// set the output stream format of the timepitch unit
float value = 1.0;
printf("Set rate %f\n", value);

OSStatus result = AudioUnitSetParameter(audio->_audioPlaybackAudioFile.timePitchAU,
kTimePitchParam_Rate,
kAudioUnitScope_Global,
0,
value,
0);
if (result)
{
printf("AudioUnitSetParameter kTimePitchParam_Rate Global result %ld X %4.4s\n",
 (long)result, (unsigned int)result, (char*)&result); return;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// now initialize the graph (causes resources to be allocated)
CheckError(AUGraphInitialize(audio->_audioPlaybackAudioFile.graph),
"AUGraphInitialize failed");
}

and then I setup the playback region like this:


SInt64 AUAudioPlayback::PrepareFileAU(audioFilePlayerDescription *player, long startOffset, long endOffset)
{

// tell the file player unit to load the file we want to play
CheckError(AudioUnitSetProperty(player->fileAU, kAudioUnitProperty_ScheduledFileIDs,
 kAudioUnitScope_Global, 0, &player->inputFile, sizeof(player->inputFile)),
"AudioUnitSetProperty[kAudioUnitProperty_ScheduledFileIDs] failed");

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Float64 audioStartOffset = startOffset / 1000.0;
SInt64  computeStartFrame = audioStartOffset * player->inputFormat.mSampleRate;
Float64 audioStopOffset = endOffset / 1000.0;
SInt64  computeStopFrame = (audioStopOffset * player->inputFormat.mSampleRate);
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// tell the file player AU to play from computeStartFrame for computeStopFrame - computeStartFrame frames.
ScheduledAudioFileRegion rgn;
memset (&rgn.mTimeStamp, 0, sizeof(rgn.mTimeStamp));
rgn.mTimeStamp.mFlags = kAudioTimeStampSampleTimeValid;
rgn.mTimeStamp.mSampleTime = 0;
rgn.mCompletionProc = NULL; //audioCompletionProcess;
rgn.mCompletionProcUserData = _receiver;
rgn.mAudioFile = player->inputFile;
rgn.mLoopCount = 0;
rgn.mStartFrame = computeStartFrame;
rgn.mFramesToPlay = computeStopFrame - computeStartFrame; // * player->inputFormat.mFramesPerPacket;


Boolean graphStatus;
OSStatus testForFailure = AUGraphIsInitialized(player->graph, &graphStatus);

CheckError(AudioUnitSetProperty(player->fileAU,
 kAudioUnitProperty_ScheduledFileRegion,
 kAudioUnitScope_Global,
 0,
 &rgn,
 sizeof(rgn)),
"AudioUnitSetProperty[kAudioUnitProperty_ScheduledFileRegion] failed");

// prime the file player AU with default values
UInt32 defaultVal = 0;
CheckError(AudioUnitSetProperty(player->fileAU,
 kAudioUnitProperty_ScheduledFilePrime,
 kAudioUnitScope_Global,
 0,
 &defaultVal,
 sizeof(defaultVal)),
"AudioUnitSetProperty[kAudioUnitProperty_ScheduledFilePrime] failed");

// tell the file player AU when to start playing (-1 sample time means next render cycle)
AudioTimeStamp startTime;
memset (&startTime, 0, sizeof(startTime));
startTime.mFlags = kAudioTimeStampSampleTimeValid;
startTime.mSampleTime = -1;
CheckError(AudioUnitSetProperty(player->fileAU,
 kAudioUnitProperty_ScheduleStartTimeStamp,
 kAudioUnitScope_Global,
 0,
 &startTime,
 sizeof(startTime)),
"AudioUnitSetProperty[kAudioUnitProperty_ScheduleStartTimeStamp]");

testForFailure =  AudioUnitAddPropertyListener (player->fileAU,
  kAudioUnitOfflineProperty_StartOffset,
  listenForPlaybackComplete,
  _receiver);
testForFailure = AudioUnitInitialize(player->fileAU);
// file duration
// AudioUnit anAU;
// AUGraphGetNodeInfo((AUGraph)player->graph, (AUNode)player->fileAU, NULL, NULL, NULL, &anAU);
return (computeStartFrame);
}


Everything works but how do I setup a finished playing callback??


Thank for any help.


Jim Griffin
www.gh-accessibility.com






 _______________________________________________
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

  • Next by Date: Is the AudioFilePlayer audio unit compatible with sandboxing?
  • Next by thread: Is the AudioFilePlayer audio unit compatible with sandboxing?
  • Index(es):
    • Date
    • Thread