房卡麻将分析系列之"千里传音"

栏目: 编程语言 · IOS · 发布时间: 7年前

内容简介:房卡麻将分析系列之"千里传音"

”房卡“麻将研发技巧,尽在 ”红孩儿的游戏开发之路“ ,欢迎关注公众号!

房卡麻将分析系列之"千里传音"

在房卡棋牌游戏中,因为要频繁的看牌,出牌。为了实时沟通打字聊天往往比较麻烦,通过语音交流,催牌可以很好的帮助玩家及时的表达情绪,增强游戏的气氛。

房卡麻将分析系列之

那么这是怎么做到的呢?

首先这个过程分为三步:

 一。录制声音并压缩成数据包: 这个过程一般是当玩家点击按钮,开始录音,松开按钮,停止录音并生成WAV文件,之后通过编码转换压缩为

在这里要根据安卓和苹果两个平台来做区分。

void startSoundRecord()
	{
		std::string kFileName = utility::toString(time(NULL),".wav");
		s_kRecordFileName = cocos2d::FileUtils::getInstance()->getWritablePath()+kFileName;
#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
		JniMethodInfo 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_IOS
		IosHelper::beginRecord(s_kRecordFileName.c_str());
#endif
	}


	const char* stopSoundRecord()
	{
#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
		std::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_IOS
		IosHelper::endRecord();
		return s_kRecordFileName.c_str();
#endif
		return "";
	}

在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);  
                //设置编码格式为AMR
		recorder.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转换成WAV
	ArmFun::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~

”房卡“麻将研发技巧,尽在 ”红孩儿的游戏开发之路“ ,欢迎关注公众号!

房卡麻将分析系列之


以上所述就是小编给大家介绍的《房卡麻将分析系列之"千里传音"》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

算法设计与分析

算法设计与分析

郑宗汉//郑晓明 / 清华大学 / 2011-7 / 45.00元

《算法设计与分析(第2版)》系统地介绍算法设计与分析的概念和方法,共4部分内容。第1部分介绍算法设计与分析的基本概念,结合穷举法、排序问题及其他一些算法,对算法的时间复杂性的概念及复杂性的分析方法作了较为详细的叙述;第2部分以算法设计技术为纲,从合并排序、堆排序、离散集合的union和find操作开始,进而介绍递归技术、分治法、贪婪法、动态规划、回溯法、分支与限界法和随机算法等算法设计技术及其复杂......一起来看看 《算法设计与分析》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具