房卡麻将分析系列之"千里传音"
来源:互联网 发布:淘宝中差评处理 编辑:程序博客网 时间:2024/04/29 22:47
”房卡“麻将研发技巧,尽在”红孩儿的游戏开发之路“,欢迎关注公众号!
房卡麻将分析系列之"千里传音"
在房卡棋牌游戏中,因为要频繁的看牌,出牌。为了实时沟通打字聊天往往比较麻烦,通过语音交流,催牌可以很好的帮助玩家及时的表达情绪,增强游戏的气氛。
那么这是怎么做到的呢?
首先这个过程分为三步:
一。录制声音并压缩成数据包:这个过程一般是当玩家点击按钮,开始录音,松开按钮,停止录音并生成WAV文件,之后通过编码转换压缩为
在这里要根据安卓和苹果两个平台来做区分。
void startSoundRecord(){std::string kFileName = utility::toString(time(NULL),".wav");s_kRecordFileName = cocos2d::FileUtils::getInstance()->getWritablePath()+kFileName;#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROIDJniMethodInfo minfo; bool isHave = JniHelper::getStaticMethodInfo(minfo,JAVA_CLASSNAME, "startSoundRecord", "(Ljava/lang/String;)V");if (isHave) { jstring jurl = minfo.env->NewStringUTF(kFileName.c_str());minfo.env->CallStaticVoidMethod(minfo.classID, minfo.methodID,jurl); cocos2d::log("JniFun call startSoundRecord over!");minfo.env->DeleteLocalRef(minfo.classID); } else{cocos2d::log("JniFun call startSoundRecord error!");}#endif#if CC_TARGET_PLATFORM == CC_PLATFORM_IOSIosHelper::beginRecord(s_kRecordFileName.c_str());#endif}const char* stopSoundRecord(){#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROIDstd::string str;JniMethodInfo minfo; bool isHave = JniHelper::getStaticMethodInfo(minfo,JAVA_CLASSNAME, "stopSoundRecord", "()Ljava/lang/String;");if (isHave) { jstring jFileName = (jstring)minfo.env->CallStaticObjectMethod(minfo.classID, minfo.methodID); const char *newStr = minfo.env->GetStringUTFChars(jFileName, 0);str = newStr;cocos2d::log("JniFun call stopSoundRecord over :");cocos2d::log("%s",str.c_str());minfo.env->ReleaseStringUTFChars(jFileName, newStr);minfo.env->DeleteLocalRef(minfo.classID); } else{cocos2d::log("JniFun call stopSoundRecord error!");}return str.c_str();#endif#if CC_TARGET_PLATFORM == CC_PLATFORM_IOSIosHelper::endRecord();return s_kRecordFileName.c_str();#endifreturn "";}
在Native.java中实现录音和结束:
//开始录音 public static void startSoundRecord( String SoundFileName) { String SoundFilePath= Environment.getExternalStorageDirectory().getAbsolutePath(); if (filePath != null){File file = new File(filePath);if (file!= null && file.exists()){file.delete();} }filePath = SoundFilePath+"/"+SoundFileName;recorder = new MediaRecorder(); //从麦克风中录音recorder.setAudioSource(MediaRecorder.AudioSource.MIC); //设置编码格式为AMRrecorder.setOutputFormat(MediaRecorder.OutputFormat.RAW_AMR); recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); recorder.setOutputFile(SoundFilePath+"/"+SoundFileName); try { recorder.prepare();//recorder.start();//} catch (IllegalStateException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } //结束录音 public static String stopSoundRecord() {recorder.stop();// recorder.release(); // recorder = null; return filePath; }
另外,要在AndroidMainfest.xml中注意开启录音权限:
<uses-permission android:name="android.permission.RECORD_AUDIO" />
IOS版本处理:需要在mm文件中完成相应函数
AVAudioRecorder *recorder = NULL;void IosHelper::beginRecord(const char *_fileName){ if (recorder == nil) { //设置文件名和录音路径 NSString *recordFilePath = [NSString stringWithCString:_fileName encoding:NSUTF8StringEncoding]; NSDictionary *recordSetting = [[NSDictionary alloc] initWithObjectsAndKeys: [NSNumber numberWithFloat: 8000.0],AVSampleRateKey, //采样率 [NSNumber numberWithInt: kAudioFormatLinearPCM],AVFormatIDKey, [NSNumber numberWithInt:16],AVLinearPCMBitDepthKey,//采样位数 默认 16 [NSNumber numberWithInt: 1], AVNumberOfChannelsKey,//通道的数目 nil]; //初始化录音 NSError *error = nil; recorder = [[ AVAudioRecorder alloc] initWithURL:[NSURL URLWithString:recordFilePath] settings:recordSetting error:&error]; } recorder.meteringEnabled = YES; [recorder prepareToRecord]; //开始录音 UInt32 sessionCategory = kAudioSessionCategory_PlayAndRecord; AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(sessionCategory), &sessionCategory); // 扬声器播放 UInt32 audioRouteOverride = kAudioSessionOverrideAudioRoute_Speaker; AudioSessionSetProperty (kAudioSessionProperty_OverrideAudioRoute, sizeof(audioRouteOverride), &audioRouteOverride); [[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayAndRecord error:nil]; [[AVAudioSession sharedInstance] setActive:YES error:nil]; [recorder record];}const char * IosHelper::endRecord(){ if (recorder == nil) return ""; if (recorder.isRecording) [recorder stop];return "";}
二。发送声音数据到服务器:在结束录制声音并生成文件后,将文件发送出去。
std::string kFileName = JniFun::stopSoundRecord();sendTalkFile(m_pLocal->GetChairID(),kFileName);
这里就是将文件以数据包形式发送出去,不做详细表述。
三。接收数据并解压,播放: 在接收到消息后,将数据写入文件并播放即可。
bool GameBase::RevTalk_File(CMD_GR_C_TableTalk* pNetInfo){if (pNetInfo->strTalkSize == 0){return true;}static int iIdex = 0;iIdex ++;std::string kFile = utility::toString(cocos2d::CCFileUtils::sharedFileUtils()->getWritablePath(),"TableTalk",iIdex,".arm");FILE *fp = fopen(kFile.c_str(), "wb");fseek(fp,0,SEEK_END);fseek(fp,0,SEEK_SET);fwrite(&pNetInfo->strTalkData,sizeof(unsigned char), pNetInfo->strTalkSize,fp);fclose(fp);int iAddTime = pNetInfo->strTalkSize/1200+2.0f;if (iAddTime > 10){iAddTime = 10;}std::string kDestFile = kFile;utility::StringReplace(kDestFile,"arm","wav"); //这里需要做一个解压转换,将ARM转换成WAVArmFun::ArmToWav(kFile.c_str(),kDestFile.c_str()); //为了防止游戏音乐干扰,先静音游戏音乐SoundFun::Instance().PaseBackMusic();SoundFun::Instance().ResumeBackMusic(iAddTime);SoundFun::Instance().PaseEffectMusic();SoundFun::Instance().ResumeEffectMusic(iAddTime); //播放接收到的声音文件SoundFun::Instance().playEffectDirect(kDestFile); //指定玩家显示播放语音的动画图标GamePlayer* pPlayer = getBasePlayerByChairID(pNetInfo->cbChairID);if (pPlayer){pPlayer->showTalkState(pNetInfo);} return true;}
最终,房卡棋牌中的语音聊天就完整的实现出来了,当然,这种方式并不完美,如果能开启P2P的实时语音对话就更好了。另外,这套代码中会不断的产生声音文件,这是个问题,小伙伴们可以在发送完声音和播放完声音后删除生成的声音文件,以免造成空间增长的BUG~
”房卡“麻将研发技巧,尽在”红孩儿的游戏开发之路“,欢迎关注公众号!
- 房卡麻将分析系列之"千里传音"
- 房卡麻将分析系列之"千里传音"
- 房卡麻将分析系列 "牌局回放" 之 数据设计
- 房卡麻将分析系列 "牌局回放" 之 播放处理
- 房卡麻将分析系列之"发牌器"算法设计
- 房卡麻将分析系列之"架构选型"
- 房卡麻将分析系列之"断线重连"
- 房卡麻将分析之“缺人玩法”
- 房卡麻将分析之”IPV6″改造
- 房卡麻将开发之”代开房间”
- 房卡麻将源码湖南麻将商业源码
- 贵州房卡麻将 房卡贵阳三丁拐 遵义麻将 安顺麻将商业源码
- 网狐房卡麻将教程闲来麻将6603教你修改房卡麻将论坛货
- 麻将网络模块分析
- 麻将代码分析
- 房卡十三水源码下载搭建之红中房卡麻将架设教程
- 麻将洗牌算法系列(1)
- 为什么要写房卡麻将系列文章
- SELinux策略语言--类型强制(编写TE规则)
- 程序员在囧途之垃圾创业团队 .
- 一个节目 如果这样你要怎么做
- love.window
- 汇编输出文字
- 房卡麻将分析系列之"千里传音"
- java用Cors方式让Ajax可以跨域访问
- Myeclipse2016jsp中文乱码问题的解决方法
- 思考专注力
- 151. Reverse Words in a String
- Android Studio 新建或者导入项目出现"building gradle project info"一直卡住的解决方法
- 教育人们通过什么方法保护自己,通过什么方法制裁对方。
- C# -- delegate 与 event 解析
- love