app语音聊天方案

来源:互联网 发布:java遍历json 编辑:程序博客网 时间:2024/06/10 02:31

目前,市面上的语音聊天方案很多,但是大多按日活跃收费,算下来很不划算。如果自己做,带宽的压力又大,花费更多。
可以使用oss来做,目前提供这种服务的有阿里云,七牛云,腾讯云等。即将语音在本地app录好后进行压缩,再上传到oss,然后app服务端将存有语音的oss地址发到同一个房间,或者同一个工会的人,然后其他人就根据这个地址到oss去下载语音进行播放。
这个方案既可以android平台,也可以在ios平台使用,唯一不同的是android平台是把wav压缩成mp3,ios是把aac压缩成mp3,但是都是使用lame库进行压缩

以ios/七牛为例,将这些功能封装成了一个sdk,另外,因为没有将全部代码拿出来,所以单纯看下面的代码,里面可能有一些变量没有声明,或者一些函数没有实现等等,但是大部分逻辑都包含了。

    • 初始化
    • 开始录音
    • 停止录音并压缩成mp3
    • 播放
    • 上传七牛oss
    • 下载

初始化:

- (int)initSdk{    if ([[[UIDevice currentDevice] systemVersion] compare:@"7.0"] != NSOrderedAscending)    {        //7.0第一次运行会提示,是否允许使用麦克风        AVAudioSession *session = [AVAudioSession sharedInstance];        NSError *sessionError;        //AVAudioSessionCategoryPlayAndRecord用于录音和播放        [session setCategory:AVAudioSessionCategoryPlayAndRecord error:&sessionError];        if(session == nil)        NSLog(@"Error creating session: %@", [sessionError description]);        else        [session setActive:YES error:nil];    }    return 0;}

开始录音

-(void)startRecord:(NSString*)name{//配置录音参数    NSDictionary* recorderSettingsDict =[[NSDictionary alloc] initWithObjectsAndKeys:                           [NSNumber numberWithInt:AVAudioQualityMin],AVEncoderAudioQualityKey,                           [NSNumber numberWithInt:44100],AVSampleRateKey,                           [NSNumber numberWithInt:2],AVNumberOfChannelsKey,                           [NSNumber numberWithInt:16],AVEncoderBitRateKey,                           nil];    if ([self canRecord]) {  //用canRecord判断麦克风是否打开等等        NSError *error = nil;        NSString *documentPath =[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,  NSUserDomainMask,YES) objectAtIndex:0];        //设置录音文件的路径        NSString *FileName=[documentPath stringByAppendingPathComponent:TEMP_RECORD_FILE];        _mRecorder = [[AVAudioRecorder alloc] initWithURL:[NSURL URLWithString:FileName] settings:recorderSettingsDict error:&error];        if (_mRecorder) {            _mFileName = [[NSString alloc] initWithString:name];            _mRecorder.meteringEnabled = YES;            [_mRecorder prepareToRecord];            [_mRecorder record];        } else        {            int errorCode = CFSwapInt32HostToBig ([error code]);            NSLog(@"Error: %@ [%4.4s])" , [error localizedDescription], (char*)&errorCode);        }    }}-(BOOL)canRecord{    __block BOOL bCanRecord = YES;    if ([[[UIDevice currentDevice] systemVersion] compare:@"7.0"] != NSOrderedAscending)    {        AVAudioSession *audioSession = [AVAudioSession sharedInstance];        if ([audioSession respondsToSelector:@selector(requestRecordPermission:)]) {            [audioSession performSelector:@selector(requestRecordPermission:) withObject:^(BOOL granted) {                if (granted) {                    bCanRecord = YES;                }                else {                    bCanRecord = NO;                    dispatch_async(dispatch_get_main_queue(), ^{                        [[[UIAlertView alloc] initWithTitle:nil                                                    message:@"app需要访问您的麦克风。\n请启用麦克风-设置/隐私/麦克风"                                                   delegate:nil                                          cancelButtonTitle:@"关闭"                                          otherButtonTitles:nil] show];                    });                }            }];        }    }    return bCanRecord;}

停止录音,并压缩成mp3

-(void)stopRecord{    [_mRecorder stop];    _mRecorder = nil;    if([self PCMtoMp3:_mFileName]){       // success, you can do something, eg.  upload the .mp3 to qiniu oss    }else{       // failed    }}-(bool)PCMtoMp3:(NSString*)name{    NSString *documentPath =[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,  NSUserDomainMask,YES) objectAtIndex:0];    NSString *cafFilePath = [documentPath stringByAppendingPathComponent:TEMP_RECORD_FILE];//    NSString *mp3FilePath=[documentPath stringByAppendingPathComponent:name];//存储mp3文件的路径    NSFileManager* fileManager=[NSFileManager defaultManager];    if([fileManager removeItemAtPath:mp3FilePath error:nil])    {        NSLog(@"删除");    }    @try {        int read, write;        FILE *pcm = fopen([cafFilePath cStringUsingEncoding:1], "rb");  //source 被转换的音频文件位置        if(pcm == NULL)        {            NSLog(@"file not found");        }        else        {            fseek(pcm, 4*1024, SEEK_CUR);                                   //skip file header            FILE *mp3 = fopen([mp3FilePath cStringUsingEncoding:1], "wb");  //output 输出生成的Mp3文件位置            const int PCM_SIZE = 8192;            const int MP3_SIZE = 8192;            short int pcm_buffer[PCM_SIZE*2];            unsigned char mp3_buffer[MP3_SIZE];                       lame_t lame = lame_init();            //设置压缩参数            lame_set_num_channels(lame,1);//设置1为单通道,默认为2双通道            lame_set_in_samplerate(lame, 44100.0);//11025.0            lame_set_VBR(lame, vbr_default);            lame_set_brate(lame,8);            //lame_set_mode(lame,3);            lame_set_quality(lame,2); /* 2=high 5 = medium 7=low 音质*/            lame_init_params(lame);            do {                read = fread(pcm_buffer, 2*sizeof(short int), PCM_SIZE, pcm);                if (read == 0){                    write = lame_encode_flush(lame, mp3_buffer, MP3_SIZE);                }                else{                    write = lame_encode_buffer_interleaved(lame, pcm_buffer, read, mp3_buffer, MP3_SIZE);                }                fwrite(mp3_buffer, write, 1, mp3);            } while (read != 0);            lame_close(lame);            fclose(mp3);            fclose(pcm);            return YES;        }               return NO;    } @catch (NSException *exception) {         NSLog(@"%@",[exception description]);        return NO;    }@finally {        NSLog(@"执行完成");    }}

播放

-(void)playRecord:(NSString*)name{    NSString *documentPath =[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,  NSUserDomainMask,YES) objectAtIndex:0];    NSString *filePath = [documentPath stringByAppendingPathComponent:name];    NSURL* url = [NSURL URLWithString:filePath];    _mPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];    [_mPlayer play];}

上传七牛oss

这个里面用到了七牛的sdk,具体可以参考七牛官网

-(NSString*) storeOnCloud:(NSString*)filePath withCloudPath:(NSString*)cloudPath withToken:(NSString*)token{    _mUrlUploadId=[[NSString alloc] initWithString:StringUtil::getTimestamp()];    //根据文件名生成路径    NSString *documentPath =[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,  NSUserDomainMask,YES) objectAtIndex:0];    NSString *FileName=[documentPath stringByAppendingPathComponent:filePath];    //上传文件    QNUploadManager *upManager = [[QNUploadManager alloc] init];    [upManager putFile:FileName key:cloudPath token:token              complete: ^(QNResponseInfo *info, NSString *key, NSDictionary *resp) {                  if(info.ok){                      // upload success                  }                  else{                      // upload failed                  }                  NSLog(@"%@", info);                  NSLog(@"%@", resp);                  [_mUrlUploadId release];                  _mUrlUploadId = nil;              } option:nil];    return _mUrlUploadId;}

下载

就是普通的url下载,使用NSURLRequest NSURLConnection ,并实现NSURLConnectionDataDelegate 即可,需要注意的是下载的文件应该存在

 NSString *documentPath =[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,  NSUserDomainMask,YES) objectAtIndex:0];    NSString *FileName=[documentPath stringByAppendingPathComponent:_mUrlDownloadFilePath];

其实在上面的很多函数中都用到过,这个documentPath就是ios为每个app准备的空间,专门用于存放app的一些数据/配置文件等等

0 0
原创粉丝点击