Purpose:
Using microphones as an event Input Method
Core:
Use audiosession and audioqueue to capture microphone input data.
Enable audiosession:
1. audiosessioninitialize
2. audiosessionsetproperty (kaudiosessionproperty_audiocategory)
3. audiosessionsetactive
Create sound format:
1. audiostreambasicdescription
2. Use kaudioformatlinearpcm as the sound format
Create audioqueue:
1. audioqueuenewinput
2. audioqueuestart
3. audioqueuesetproperty (kaudioqueueproperty_enablelevelmetering)
Obtain the peak sound data:
1. audioqueuelevelmeterstate
2. audioqueuegetproperty (kaudioqueueproperty_currentlevelmeterdb)
Disable audioqueue:
1. audioqueuestop
2. audioqueuedispose
Code:
# Import <uikit/uikit. h>
# Include <audiotoolbox/audiotoolbox. h>
@ Interface microphonetestviewcontroller: uiviewcontroller {
Iboutlet uilabel * _ averagepower;
Iboutlet uilabel * _ peakpower;
Audioqueueref mqueue;
Audiostreambasicdescription mformat;
Audioqueuelevelmeterstate * _ chan_lvls;
Nsarray * _ channelnumbers;
}
-(Void) setchannelnumbers :( nsarray *) V;
-(Void) initaudiosession;
-(Ibaction) startstop: (ID) sender;
@ End
[/Code]
[Code]
# Import "microphonetestviewcontroller. H"
Static void myinputbufferhandler (void * inuserdata,
Audioqueueref inaq,
Audioqueuebufferref inbuffer,
Const audiotimestamp * instarttime,
Uint32 innumpackets,
Const audiostreampacketdescription * inpacketdesc)
{
// If you want to record the sound, you can record it here.
// If You Want To analyze the sound data, record it here.
}
Static void interruptionlistener (void * inclientdata,
Uint32 ininterruptionstate)
{
// Sound interruption notification (begin, end)
}
@ Implementation microphonetestviewcontroller
// Implement viewdidload to do additional setup after loading the view, typically from a nib.
-(Void) viewdidload {
[Super viewdidload];
_ Averagepower. Text = @ "0 ";
_ Peakpower. Text = @ "0 ";
Mqueue = NULL;
_ Channelnumbers = [[nsarray alloc] initwithobjects: [nsnumber numberwithint: 0], nil];
_ Chan_lvls = (audioqueuelevelmeterstate *) malloc (sizeof (audioqueuelevelmeterstate) * [_ channelnumbers count]);
[Self initaudiosession];
[Nstimer
Scheduledtimerwithtimeinterval: 1.f/ 30.f
Target: Self
Selector: @ selector (_ refresh)
Userinfo: Nil
Repeats: Yes
];
}
-(Void) didreceivememorywarning {
// Releases the view if it doesn't have a superview.
[Super didreceivememorywarning];
// Release any cached data, images, etc that aren't in use.
}
-(Void) viewdidunload {
// Release any retained subviews of the main view.
// E.g. Self. myoutlet = nil;
[_ Channelnumbers release];
Free (_ chan_lvls );
}
-(Void) dealloc {
[Super dealloc];
}
-(Void) initaudiosession
{
Osstatus error = audiosessioninitialize (null, null, interruptionlistener, self );
If (error) printf ("error initializing audio session! % D \ n ", (INT) error );
Else
{
Uint32 Category = kaudiosessioncategory_playandrecord;
Error = audiosessionsetproperty (kaudiosessionproperty_audiocategory, sizeof (category), & category );
If (error) printf ("couldn't set audio category! ");
Error = audiosessionsetactive (true );
If (error) printf ("audiosessionsetactive (true) failed ");
}
}
-(Void) setupaudioformat :( uint32) informatid
{
Memset (& mformat, 0, sizeof (mformat ));
Uint32 size = sizeof (mformat. msamplerate );
Osstatus result = audiosessiongetproperty (kaudiosessionproperty_currenthardwaresamplerate,
& Size,
& Mformat. msamplerate );
Size = sizeof (mformat. mchannelsperframe );
Result = audiosessiongetproperty (kaudiosessionproperty_currenthardwareinputnumberchannels,
& Size,
& Mformat. mchannelsperframe );
Mformat. mformatid = informatid;
If (informatid = kaudioformatlinearpcm)
{
// If we want PCM, default to signed 16-bit little-Endian
Mformat. mformatflags = klinearpcmformatflagissignedinteger | klinearpcmformatflagispacked;
Mformat. mbitsperchannel = 16;
Mformat. mbytesperpacket = mformat. mbytesperframe = (mformat. mbitsperchannel/8) * mformat. mchannelsperframe;
Mformat. mframesperpacket = 1;
}
}
-(Void) startmicrophone
{
[Self setupaudioformat: kaudioformatlinearpcm];
Osstatus result = audioqueuenewinput (& mformat, myinputbufferhandler, null, 0, & mqueue );
If (result = noerr ){
Result = audioqueuestart (mqueue, null );
If (result = noerr ){
Uint32 val = 1;
Audioqueuesetproperty (mqueue, kaudioqueueproperty_enablelevelmetering, & Val, sizeof (uint32 ));
If (mformat. mchannelsperframe! = [_ Channelnumbers count])
{
Nsarray * chan_array;
If (mformat. mchannelsperframe <2)
Chan_array = [[nsarray alloc] initwithobjects: [nsnumber numberwithint: 0], nil];
Else
Chan_array = [[nsarray alloc] initwithobjects: [nsnumber numberwithint: 0], [nsnumber numberwithint: 1], nil];
[Self setchannelnumbers: chan_array];
[Chan_array release];
_ Chan_lvls = (audioqueuelevelmeterstate *) realloc (_ chan_lvls, mformat. mchannelsperframe * sizeof (audioqueuelevelmeterstate ));
}
Return;
}
}
// Failed
Mqueue = NULL;
Nslog (@ "startmicrophone: Failed .");
Return;
}
-(Void) stopmicrophone
{
If (mqueue ){
Audioqueuestop (mqueue, true );
Audioqueuedispose (mqueue, true );
Mqueue = NULL;
}
}
-(Void) _ refresh
{
If (mqueue ){
Uint32 data_sz = sizeof (audioqueuelevelmeterstate) * [_ channelnumbers count];
Oserr status = audioqueuegetproperty (mqueue, kaudioqueueproperty_currentlevelmeterdb, _ chan_lvls, & data_sz );
If (status = noerr)
{
// The data display of multiple channels is not processed here, and the result of the last channel is displayed directly.
// The value here is the value we intend to use as a trigger mechanism. When necessary, access the array _ chan_lvls directly.
For (INT I = 0; I <[_ channelnumbers count]; I ++)
{
Nsinteger channelidx = [(nsnumber *) [_ channelnumbers objectatindex: I] intvalue];
If (channelidx <[_ channelnumbers count] & channelidx <= 127)
{
_ Averagepower. Text = [nsstring stringwithformat: @ "% F", _ chan_lvls [channelidx]. maveragepower];
_ Peakpower. Text = [nsstring stringwithformat: @ "% F", _ chan_lvls [channelidx]. mpeakpower];
}
}
}
}
}
-(Void) setchannelnumbers :( nsarray *) V
{
[V retain];
[_ Channelnumbers release];
_ Channelnumbers = V;
}
-(Ibaction) startstop: (ID) sender
{
If (mqueue ){
[Self stopmicrophone];
} Else {
[Self startmicrophone];
}
}
@ End