公司项目需要开发一个类似QQ、微信的即时IM聊天功能,做到实时监控消息,需要用的技术是websocket,今天整理下语言聊天这块;其实语言聊天,包含两部分,录音和音乐播放,关于简单语言聊天功能如下图:

录音

在AVFoundation框架中有一个AVAudioRecorder类专门处理录音操作,它同样支持多种音频格式。与AVAudioPlayer类似,你完全可以将它看成是一个录音机控制类,下面是常用的属性和方法:

先来了解下AVAudioRecorder的常用属性:

@property (readonly, getter=isRecording) BOOL recording;//是否正在录音
@property (readonly) NSDictionary<NSString *, id> *settings;//录音配置
@property (readonly) NSURL *url;//录音文件存放URL
@property (readonly) NSTimeInterval currentTime;//录音时长
@property (getter=isMeteringEnabled) BOOL meteringEnabled;//是否监控声波

常用对象方法:

- (BOOL)prepareToRecord;//为录音准备缓冲区
- (BOOL)record;//录音开始,暂停后调用会恢复录音
- (BOOL)recordAtTime:(NSTimeInterval)time;//在指定时间后开始录音
- (BOOL)recordForDuration:(NSTimeInterval) duration;//按指定时长录音
- (BOOL)recordAtTime:(NSTimeInterval)time forDuration:(NSTimeInterval)duration;//上面2个的合体
- (void)pause; //中断录音
- (void)stop; //停止录音
- (BOOL)deleteRecording;//删除录音,必须先停止录音再删除

常用的代理方法:

//录音完成后调用
- (void)audioRecorderDidFinishRecording:(AVAudioRecorder *)recorder successfully:(BOOL)flag;//录音编码发送错误时调用
- (void)audioRecorderEncodeErrorDidOccur:(AVAudioRecorder *)recorder error:(NSError *)error;

音频

如果播放较大的音频或者要对音频有精确的控制则System Sound Service可能就很难满足实际需求了,通常这种情况会选择使用AVFoundation.framework中的AVAudioPlayer来实现。AVAudioPlayer可以看成一个播放器,它支持多种音频格式,而且能够进行进度、音量、播放速度等控制

AVAudioPlayer的使用比较简单:

1.初始化AVAudioPlayer对象,此时通常指定本地文件路径。

2.设置播放器属性,例如重复次数、音量大小等。

3.调用play方法播放。

具体实现代码

#import <AVFoundation/AVFoundation.h>
#define kRecordAudioFile @"myRecord.caf"


@interface ViewController ()<AVAudioRecorderDelegate>
{
  NSString *dateName;

}
@property (weak, nonatomic) IBOutlet UITableView *table;

@property (nonatomic,strong) AVAudioRecorder *audioRecorder;//音频录音机
@property (nonatomic,strong) AVAudioPlayer *audioPlayer;//音频播放器,用于播放录音文件


@property(nonatomic,strong) NSMutableArray *spaceData;


@end

@implementation ViewController
#pragma mark - 私有方法
/**
 * 设置音频会话
 */
-(void)setAudioSession{

  AVAudioSession *audioSession=[AVAudioSession sharedInstance];
  //设置为播放和录音状态,以便可以在录制完之后播放录音
  [audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
  [audioSession setActive:YES error:nil];
}



/**
 * 取得录音文件设置
 *
 * @return 录音设置
 */
-(NSDictionary *)getAudioSetting{
  NSMutableDictionary *dicM=[NSMutableDictionary dictionary];
  //设置录音格式
  [dicM setObject:@(kAudioFormatLinearPCM) forKey:AVFormatIDKey];
  //设置录音采样率,8000是电话采样率,对于一般录音已经够了
  [dicM setObject:@(8000) forKey:AVSampleRateKey];
  //设置通道,这里采用单声道
  [dicM setObject:@(1) forKey:AVNumberOfChannelsKey];
  //每个采样点位数,分为8、16、24、32
  [dicM setObject:@(8) forKey:AVLinearPCMBitDepthKey];
  //是否使用浮点数采样
  [dicM setObject:@(YES) forKey:AVLinearPCMIsFloatKey];
  //....其他设置等
  return dicM;
}
/**
 * 取得录音文件保存路径
 *
 * @return 录音文件路径
 */
-(NSURL *)getPlayPath:(NSString *)title{


  //  static int index = 0;

  NSString *urlStr=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
  urlStr=[urlStr stringByAppendingPathComponent:[NSString stringWithFormat:@"%@%@",title,kRecordAudioFile]];
  NSLog(@"play file path:%@",urlStr);
  NSURL *url=[NSURL fileURLWithPath:urlStr];

  return url;
}

/**
 * 以日期为title,来保存录音
 *
 * @return <#return value description#>
 */
- (NSString *) convertDateFromString
{
  NSDate *date = [NSDate date];
  //  NSLog(@"%@--askl",date);
  //  
  NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; 
  //zzz表示时区,zzz可以删除,这样返回的日期字符将不包含时区信息。

  [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
  NSString *destDateString = [dateFormatter stringFromDate:date];

  return destDateString;

}

长按录音,松开停止

- (void)setClikeSpaceState:(NSString *)aState
{
  NSLog(@"点击语音---");  

  if([aState isEqualToString:@"begin"])
  {
    NSLog(@"begin---");

    dateName = [self convertDateFromString];
    //创建录音文件保存路径
    NSURL *url=[self getPlayPath:dateName];
    //创建录音格式设置
    NSDictionary *setting=[self getAudioSetting];
    //创建录音机
    NSError *error=nil;
    _audioRecorder=[[AVAudioRecorder alloc]initWithURL:url settings:setting error:&error];
    _audioRecorder.delegate=self;
    _audioRecorder.meteringEnabled=YES;//如果要监控声波则必须设置为YES

    if (![self.audioRecorder isRecording]) {
      [self.audioRecorder record];//首次使用应用时如果调用record方法会询问用户是否允许使用麦克风
      //    self.timer.fireDate=[NSDate distantPast];

      NSLog(@"111");
    }


  }else
  {
    NSLog(@"end---");


    /** 停止录音*/
    [self.audioRecorder stop];


    /** 录音地址*/
    NSURL *url = [self getPlayPath:dateName];

    /** 加载数据*/

    AVAudioPlayer  *audioPlayer1 = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];

    Model *model = [[Model alloc]init];
    model.duration = [NSString stringWithFormat:@"%.f",audioPlayer1.duration];
    model.spacePath = dateName;



    /** table 刷新*/
    [self.spaceData addObject:model];
    [self.table reloadData];


    /** table 滚动到当前row*/

    [self.table selectRowAtIndexPath:[NSIndexPath indexPathForRow:(self.spaceData.count - 1) inSection:0] animated:YES scrollPosition:UITableViewScrollPositionTop];






  }
}

点击table 播放

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{


  Model *model = self.spaceData[indexPath.row];  

  /** 播放录音*/
  NSURL *url=[self getPlayPath:model.spacePath];
  NSError *error=nil;
  _audioPlayer=[[AVAudioPlayer alloc]initWithContentsOfURL:url error:&error];
  _audioPlayer.numberOfLoops=0;

  [_audioPlayer prepareToPlay];
  [self.audioPlayer play];

  NSLog(@"%.0f---aaaa",_audioPlayer.duration);

  /** UIImage动画数组*/
  NSMutableArray  *imgData = [NSMutableArray array];
  for(int i=0;i<4;i  )
  {
    UIImage *aImage = [UIImage imageNamed:[NSString stringWithFormat:@"chat_receiver_audio_playing00%d",i]];
    [imgData addObject:aImage];

  }

  TwoTableViewCell *twoCell = [self.table cellForRowAtIndexPath:indexPath];




  /** 点击动画*/

  [twoCell.speak setAnimationImages:imgData];
  //    [twoCell.speak setAnimationRepeatCount:1];
  [twoCell.speak setAnimationDuration:1];
  [twoCell.speak startAnimating];

  dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)([model.duration intValue] * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

    [twoCell.speak stopAnimating];

  });

}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持Devmax。

iOS开发项目- 基于WebSocket的聊天通讯(2)的更多相关文章

  1. 五分钟学会HTML5的WebSocket协议

    这篇文章主要介绍了五分钟学会HTML5的WebSocket协议,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  2. 前端监听websocket消息并实时弹出(实例代码)

    这篇文章主要介绍了前端监听websocket消息并实时弹出,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  3. HTML5 WebSocket实现点对点聊天的示例代码

    这篇文章主要介绍了HTML5 WebSocket实现点对点聊天的示例代码的相关资料,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  4. HTML5在微信内置浏览器下右上角菜单的调整字体导致页面显示错乱的问题

    HTML5在微信内置浏览器下,在右上角菜单的调整字体导致页面显示错乱的问题,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧

  5. iOS实现拖拽View跟随手指浮动效果

    这篇文章主要为大家详细介绍了iOS实现拖拽View跟随手指浮动,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  6. ios – containerURLForSecurityApplicationGroupIdentifier:在iPhone和Watch模拟器上给出不同的结果

    我使用默认的XCode模板创建了一个WatchKit应用程序.我向iOSTarget,WatchkitAppTarget和WatchkitAppExtensionTarget添加了应用程序组权利.(这是应用程序组名称:group.com.lombax.fiveminutes)然后,我尝试使用iOSApp和WatchKitExtension访问共享文件夹URL:延期:iOS应用:但是,测试NSURL

  7. ios – Testflight无法安装应用程序

    我有几个测试人员注册了testflight并连接了他们的设备……他们有不同的ios型号……但是所有这些都有同样的问题.当他们从“safari”或“testflight”应用程序本身单击应用程序的安装按钮时……达到约90%并出现错误消息…

  8. ibm-mobilefirst – 在iOS 7.1上获取“无法安装应用程序,因为证书无效”错误

    当我的客户端将他们的设备更新到iOS7.1,然后尝试从AppCenter更新我们的应用程序时,我收到了上述错误.经过一番搜索,我找到了一个类似问题的帖子here.但是后来因为我在客户端使用AppCenter更新应用程序的环境中,我无法使用USB插件并为他们安装应用程序.在发布支持之前,是否有通过AppCenter进行下载的解决方法?

  9. ios – 视图的简单拖放?

    我正在学习iOS,但我找不到如何向UIView添加拖放行为.我试过了:它说“UIView没有可见的接口声明选择器addTarget”此外,我尝试添加平移手势识别器,但不确定这是否是我需要的它被称为,但不知道如何获得事件的坐标.在iOS中注册移动事件回调/拖放操作的标准简单方法是什么?

  10. ios – 什么控制iTunes中iPhone应用程序支持的语言列表?

    什么控制iPhone应用程序的iTunes页面中支持的语言?

随机推荐

  1. iOS实现拖拽View跟随手指浮动效果

    这篇文章主要为大家详细介绍了iOS实现拖拽View跟随手指浮动,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  2. iOS – genstrings:无法连接到输出目录en.lproj

    使用我桌面上的项目文件夹,我启动终端输入:cd然后将我的项目文件夹拖到终端,它给了我路径.然后我将这行代码粘贴到终端中找.-name*.m|xargsgenstrings-oen.lproj我在终端中收到此错误消息:genstrings:无法连接到输出目录en.lproj它多次打印这行,然后说我的项目是一个目录的路径?没有.strings文件.对我做错了什么的想法?

  3. iOS 7 UIButtonBarItem图像没有色调

    如何确保按钮图标采用全局色调?解决方法只是想将其转换为根注释,以便为“回答”复选标记提供更好的上下文,并提供更好的格式.我能想出这个!

  4. ios – 在自定义相机层的AVFoundation中自动对焦和自动曝光

    为AVFoundation定制图层相机创建精确的自动对焦和曝光的最佳方法是什么?

  5. ios – Xcode找不到Alamofire,错误:没有这样的模块’Alamofire’

    我正在尝试按照github(https://github.com/Alamofire/Alamofire#cocoapods)指令将Alamofire包含在我的Swift项目中.我创建了一个新项目,导航到项目目录并运行此命令sudogeminstallcocoapods.然后我面临以下错误:搜索后我设法通过运行此命令安装cocoapodssudogeminstall-n/usr/local/bin

  6. ios – 在没有iPhone6s或更新的情况下测试ARKit

    我在决定下载Xcode9之前.我想玩新的框架–ARKit.我知道要用ARKit运行app我需要一个带有A9芯片或更新版本的设备.不幸的是我有一个较旧的.我的问题是已经下载了新Xcode的人.在我的情况下有可能运行ARKit应用程序吗?那个或其他任何模拟器?任何想法或我将不得不购买新设备?解决方法任何iOS11设备都可以使用ARKit,但是具有高质量AR体验的全球跟踪功能需要使用A9或更高版本处理器的设备.使用iOS11测试版更新您的设备是必要的.

  7. 将iOS应用移植到Android

    我们制作了一个具有2000个目标c类的退出大型iOS应用程序.我想知道有一个最佳实践指南将其移植到Android?此外,由于我们的应用程序大量使用UINavigation和UIView控制器,我想知道在Android上有类似的模型和实现.谢谢到目前为止,guenter解决方法老实说,我认为你正在计划的只是制作难以维护的糟糕代码.我意识到这听起来像很多工作,但从长远来看它会更容易,我只是将应用程序的概念“移植”到android并从头开始编写.

  8. ios – 在Swift中覆盖Objective C类方法

    我是Swift的初学者,我正在尝试在Swift项目中使用JSONModel.我想从JSONModel覆盖方法keyMapper,但我没有找到如何覆盖模型类中的Objective-C类方法.该方法的签名是:我怎样才能做到这一点?解决方法您可以像覆盖实例方法一样执行此操作,但使用class关键字除外:

  9. ios – 在WKWebView中获取链接URL

    我想在WKWebView中获取tapped链接的url.链接采用自定义格式,可触发应用中的某些操作.例如HTTP://我的网站/帮助#深层链接对讲.我这样使用KVO:这在第一次点击链接时效果很好.但是,如果我连续两次点击相同的链接,它将不报告链接点击.是否有解决方法来解决这个问题,以便我可以检测每个点击并获取链接?任何关于这个的指针都会很棒!解决方法像这样更改addobserver在observeValue函数中,您可以获得两个值

  10. ios – 在Swift的UIView中找到UILabel

    我正在尝试在我的UIViewControllers的超级视图中找到我的UILabels.这是我的代码:这是在Objective-C中推荐的方式,但是在Swift中我只得到UIViews和CALayer.我肯定在提供给这个方法的视图中有UILabel.我错过了什么?我的UIViewController中的调用:解决方法使用函数式编程概念可以更轻松地实现这一目标.

返回
顶部