在CSDN上显示的代码格式不全,在github blog地址显示正确
iOS音频编程之实时语音通信
需求:手机通过Mic采集PCM编码的原始音频数据,将PCM转换为AAC编码格式,通过MultipeerConnectivity框架连接手机并发送AAC数据,在接收端使用Audio Queue播放收到的AAC音频
音频设置
对音频以44.1KHZ的采样率来采样,以64000的比特率对PCM进行AAC转码
1)对AVAudioSession的设置
NSError *error;
self.session = [AVAudioSession sharedInstance];
[self.session setCategory:AVAudioSessionCategoryPlayAndRecord error:&error];
handleError(error);
//route变化监听
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(audioSessionRouteChangeHandle:) name:AVAudioSessionRouteChangeNotification object:self.session];
[self.session setPreferredIOBufferDuration:0.005 error:&error];
handleError(error);
[self.session setPreferredSampleRate:kSmaple error:&error];
handleError(error);
//[self.session overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:&error];
//handleError(error);
[self.session setActive:YES error:&error];
handleError(error);
-(void)audioSessionRouteChangeHandle:(NSNotification *)noti{
// NSError *error;
// [self.session overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:&error];
// handleError(error);
[self.session setActive:YES error:nil];
if (self.startRecord) {
CheckError(AudioOutputUnitStart(_toneUnit), "couldnt start audio unit");
}
}
音频输入输出路径改变会触发audioSessionRouteChangeHandle
,如果想一直让音频从手机的扬声器输出需要在每次Route改变时,把音频输出重定向到AVAudioSessionPortOverrideSpeaker
,否则为手机听筒输出音频;其他设置说明请参照iOS音频编程之变声处理的初始化部分
2)对Audio Unit的设置
AudioComponentDescription acd;
acd.componentType = kAudioUnitType_Output;
acd.componentSubType = kAudioUnitSubType_RemoteIO;
acd.componentFlags = 0;
acd.componentFlagsMask = 0;
acd.componentManufacturer = kAudioUnitManufacturer_Apple;
AudioComponent inputComponent = AudioComponentFindNext(NULL, &acd);
AudioComponentInstanceNew(inputComponent, &_toneUnit);
UInt32 enable = 1;
AudioUnitSetProperty(_toneUnit,
kAudioOutputUnitProperty_EnableIO,
kAudioUnitScope_Input,
kInputBus,
&enable,
sizeof(enable));
mAudioFormat.mSampleRate = kSmaple;//采样率
mAudioFormat.mFormatID = kAudioFormatLinearPCM;//PCM采样
mAudioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
mAudioFormat.mFramesPerPacket = 1;//每个数据包多少帧
mAudioFormat.mChannelsPerFrame = 1;//1单声道,2立体声
mAudioFormat.mBitsPerChannel = 16;//语音每采样点占用位数
mAudioFormat.mBytesPerFrame = mAudioFormat.mBitsPerChannel*mAudioFormat.mChannelsPerFrame/8;//每帧的bytes数
mAudioFormat.mBytesPerPacket = mAudioFormat.mBytesPerFrame*mAudioFormat.mFramesPerPacket;//每个数据包的bytes总数,每帧的bytes数*每个数据包的帧数
mAudioFormat.mReserved