注册 登录
主题 : iPhone microphone输入事件捕获
级别: 新手上路
UID: 16006
精华: 0
发帖: 33
可可豆: 330 CB
威望: 330 点
在线时间: 67(时)
注册时间: 2010-03-23
最后登录: 2016-03-23
0 楼:  发表于: 2010-05-20 23:01    发自: Web Page
来源于 iPhone类代码 分类

iPhone microphone输入事件捕获    (在iOS代码库中浏览本帖)

管理提醒: 本帖被 lvyile 从 iPhone开发 / iPad开发 一般讨论区 移动到本区(2010-05-20)
目的:
利用麦克风做为一种事件的输入方式
核心:
通过AudioSession与AudioQueue实现麦克风输入的数据捕捉.

开启AudioSession:
1.    AudioSessionInitialize
2.    AudioSessionSetProperty(kAudioSessionProperty_AudioCategory)
3.    AudioSessionSetActive

建立声音格式:
1.    声音格式的数据结构AudioStreamBasicDescription
2.    使用kAudioFormatLinearPCM来做为声音格式

建立AudioQueue:
1.    AudioQueueNewInput
2.    AudioQueueStart
3.    AudioQueueSetProperty(kAudioQueueProperty_EnableLevelMetering)

获取声音峰值数据:
1.    记录峰值的数据结构AudioQueueLevelMeterState
2.    AudioQueueGetProperty(kAudioQueueProperty_CurrentLevelMeterDB)

关闭AudioQueue:
1.    AudioQueueStop
2.    AudioQueueDispose

代码:

#import 
#include 

@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)
{
    // 如果要记录声音,可以在这里做记录处理.
    // 如果要分析声音数据,可以在这里做记录处理.
}

static void interruptionListener(void *    inClientData,
                                 UInt32    inInterruptionState)
{
    // 声音中断通知(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, NULL, 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;
        }
    }
    
    // 失败
    mQueue = NULL;
    NSLog(@"startMicrophone:失败.");
    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)
        {
            // 这里没有去处理多个通道的数据显示,直接就显示最后一个通道的结果了
            // 这里的值就是我们打算用来做为一些触发机制的值了,需要用到的时候直接访问_chan_lvls这个数组
            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
[ 此帖被lvyile在2010-05-20 11:32 PM重新编辑 ]

清空我的评分动态本帖最近评分记录: 共可可豆条评分记录
gagaga 贡献值 +5 2008-09-19
隐藏评分记录
级别: 骑士

UID: 1285
精华: 0
发帖: 78
可可豆: 4784 CB
威望: 4784 点
在线时间: 1003(时)
注册时间: 2008-11-10
最后登录: 2018-10-05
1 楼:  发表于: 2010-05-20 23:02    发自: Web Page
嚯嚯。多谢分享。
级别: 版主

状态: 连续签到 - [144天]
UID: 491
精华: 6
发帖: 1763
可可豆: 112160 CB
威望: 112807 点
在线时间: 8537(时)
注册时间: 2008-08-19
最后登录: 2019-05-19
2 楼:  发表于: 2010-05-20 23:32    发自: Web Page
好例子,转移到代码区
 Developer
------------------------------------------------------------
Η αγάπη ποτέ δεν αποτυγχάνει.
愛是永不止息。
Love never fails.

    --《圣经.新约》哥林多前书第13章
级别: 新手上路
UID: 16006
精华: 0
发帖: 33
可可豆: 330 CB
威望: 330 点
在线时间: 67(时)
注册时间: 2010-03-23
最后登录: 2016-03-23
3 楼:  发表于: 2010-05-21 10:48    发自: Web Page
额,这个移过来的话,蓝牙的那个帖子更应该移过来哦.那个才是真的麻烦,两台机器在那里使用做测试,调试才将东西给测试通过了.
级别: 侠客
状态: 连续签到 - [1天]
UID: 15619
精华: 0
发帖: 85
可可豆: 828 CB
威望: 828 点
在线时间: 510(时)
注册时间: 2010-03-17
最后登录: 2015-10-19
4 楼:  发表于: 2010-08-05 10:48    发自: Web Page
好东西,谢谢楼主分享
世界是我们的
级别: 骑士
UID: 14149
精华: 1
发帖: 197
可可豆: 2000 CB
威望: 2000 点
在线时间: 356(时)
注册时间: 2010-02-16
最后登录: 2014-01-06
5 楼:  发表于: 2011-04-16 20:22    发自: Web Page
非常棒!!Mark一下~
级别: 新手上路
UID: 155455
精华: 0
发帖: 40
可可豆: 134 CB
威望: 135 点
在线时间: 93(时)
注册时间: 2012-07-18
最后登录: 2015-04-14
6 楼:  发表于: 2013-05-05 20:52    发自: Web Page
mark一下,话说这个能检测吹气?
级别: 新手上路
UID: 83342
精华: 0
发帖: 34
可可豆: 295 CB
威望: 295 点
在线时间: 54(时)
注册时间: 2011-07-25
最后登录: 2015-12-03
7 楼:  发表于: 2015-10-28 18:28    发自: Web Page
回 1楼(caolei999) 的帖子
楼主 有没有碰到 蓝牙耳机录音时不走耳机的麦克风,走手机自带的麦克风的问题呀
走了这条路,不回头

CocoaChina社区转载内容已尽可能注明出处,如未能核实来源或转发内容图片有权利瑕疵的,请及时联系社区进行修改或删除【联系方式QQ : 3442093904 邮箱:support@cocoachina.com】文章内容为作者独立观点,不代表CocoaChina社区立场。版权归原作者所有,如申请授权请联系作者,因文章侵权CocoaChina社区不承担任何法律及连带责任。

描述
快速回复

关注本帖(如果有新回复会站内信通知您)

发帖、回帖都会得到可观的积分奖励。查看论坛积分规则

按"Ctrl+Enter"直接提交
    顶部