"Thousand-mile Pronunciation" of Fangka Mahjong Analysis Series

Posted by Coco on Thu, 18 Jul 2019 04:15:00 +0200

From: http://blog.csdn.net/honghaier/article/details/62494089


” Fangka "Mahjong R&D skills, in the"Red Boy's Game Development Road". Welcome to pay attention to the public number!



Fangka Mahjong Analysis Series of "Thousand-mile Pronunciation"


In the room card game, it is necessary to watch and play cards frequently. In order to communicate in real time, typing and chatting are often troublesome. Through voice communication, reminders can help players express their emotions in time and enhance the atmosphere of the game.

                                       



So how does this work?

           

First, the process is divided into three steps:

           

1. Recording sound and compressing it into data packets: This process is usually when the player clicks the button, starts recording, loosens the button, stops recording and generates WAV files, and then compresses them into WAV files by encoding conversion.

Here is the basis Android Make a distinction between the two platforms.


  1.         void startSoundRecord()  
  2.     {  
  3.         std::string kFileName = utility::toString(time(NULL),".wav");  
  4.         s_kRecordFileName = cocos2d::FileUtils::getInstance()->getWritablePath()+kFileName;  
  5. #if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID  
  6.         JniMethodInfo minfo;    
  7.         bool isHave = JniHelper::getStaticMethodInfo(minfo,JAVA_CLASSNAME, "startSoundRecord""(Ljava/lang/String;)V");  
  8.         if (isHave)    
  9.         {    
  10.             jstring jurl = minfo.env->NewStringUTF(kFileName.c_str());  
  11.             minfo.env->CallStaticVoidMethod(minfo.classID, minfo.methodID,jurl);   
  12.             cocos2d::log("JniFun call startSoundRecord over!");  
  13.   
  14.             minfo.env->DeleteLocalRef(minfo.classID);    
  15.         }    
  16.         else  
  17.         {  
  18.             cocos2d::log("JniFun call startSoundRecord error!");  
  19.         }  
  20. #endif  
  21. #if CC_TARGET_PLATFORM == CC_PLATFORM_IOS  
  22.         IosHelper::beginRecord(s_kRecordFileName.c_str());  
  23. #endif  
  24.     }  
  25.   
  26.   
  27.     const char* stopSoundRecord()  
  28.     {  
  29. #if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID  
  30.         std::string str;  
  31.         JniMethodInfo minfo;    
  32.         bool isHave = JniHelper::getStaticMethodInfo(minfo,JAVA_CLASSNAME, "stopSoundRecord""()Ljava/lang/String;");  
  33.         if (isHave)    
  34.         {    
  35.             jstring jFileName = (jstring)minfo.env->CallStaticObjectMethod(minfo.classID, minfo.methodID);   
  36.             const char *newStr = minfo.env->GetStringUTFChars(jFileName, 0);  
  37.             str = newStr;  
  38.             cocos2d::log("JniFun call stopSoundRecord over :");  
  39.             cocos2d::log("%s",str.c_str());  
  40.             minfo.env->ReleaseStringUTFChars(jFileName, newStr);  
  41.             minfo.env->DeleteLocalRef(minfo.classID);   
  42.         }    
  43.         else  
  44.         {  
  45.             cocos2d::log("JniFun call stopSoundRecord error!");  
  46.         }  
  47.         return str.c_str();  
  48. #endif  
  49. #if CC_TARGET_PLATFORM == CC_PLATFORM_IOS  
  50.         IosHelper::endRecord();  
  51.         return s_kRecordFileName.c_str();  
  52. #endif  
  53.         return "";  
  54.     }  




At Native. Java Achieve recording and end:


     

  1.   //Start recording  
  2.        public static void startSoundRecord( String SoundFileName)  
  3. {  
  4.  String SoundFilePath= Environment.getExternalStorageDirectory().getAbsolutePath();    
  5.   
  6. if (filePath != null)  
  7. {  
  8.     File file = new File(filePath);  
  9.     if (file!= null && file.exists())  
  10.     {  
  11.         file.delete();  
  12.     }  
  13.  }  
  14. filePath = SoundFilePath+"/"+SoundFileName;  
  15. recorder = new MediaRecorder();  
  16.               //Recording from a microphone  
  17. recorder.setAudioSource(MediaRecorder.AudioSource.MIC);    
  18.               //Set the encoding format to AMR  
  19. recorder.setOutputFormat(MediaRecorder.OutputFormat.RAW_AMR);    
  20. recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);    
  21. recorder.setOutputFile(SoundFilePath+"/"+SoundFileName);    
  22. try {    
  23.     recorder.prepare();//  
  24.     recorder.start();//  
  25. catch (IllegalStateException e) {    
  26.     e.printStackTrace();    
  27. catch (IOException e) {    
  28.     e.printStackTrace();    
  29. }    
  30. }  
  31.   
  32.       //End recording  
  33. public static String stopSoundRecord()  
  34. {  
  35. recorder.stop();//   
  36.               recorder.release(); //   
  37.               recorder = null;    
  38. return filePath;  
  39. }  


In addition, in AndroidMainfest.xml, be aware of opening recording permissions:


 

  1. <uses-permission android:name="android.permission.RECORD_AUDIO" />    


iOS Version Processing: You need to complete the corresponding functions in the mm file


  1.  AVAudioRecorder *recorder = NULL;  
  2. void IosHelper::beginRecord(const charchar *_fileName)  
  3. {  
  4.       if (recorder == nil)  
  5.       {  
  6.         //Setting File Name and Recording Path  
  7.         NSString *recordFilePath = [NSString stringWithCString:_fileName encoding:NSUTF8StringEncoding];  
  8.           
  9.         NSDictionary *recordSetting = [[NSDictionary alloc] initWithObjectsAndKeys:  
  10.                                        [NSNumber numberWithFloat8000.0],AVSampleRateKey, //sampling rate  
  11.                                        [NSNumber numberWithInt: kAudioFormatLinearPCM],AVFormatIDKey,  
  12.                                        [NSNumber numberWithInt:16],AVLinearPCMBitDepthKey,//Sampling digit default 16  
  13.                                        [NSNumber numberWithInt: 1], AVNumberOfChannelsKey,//Number of channels  
  14.                                        nil nil];  
  15.         //Initial recording  
  16.         NSError *error = nil;  
  17.         recorder = [[ AVAudioRecorder alloc] initWithURL:[NSURL URLWithString:recordFilePath] settings:recordSetting error:&error];  
  18.       }  
  19.       recorder.meteringEnabled = YES;  
  20.       [recorder prepareToRecord];  
  21.       //Start recording  
  22.       UInt32 sessionCategory = kAudioSessionCategory_PlayAndRecord;  
  23.       AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(sessionCategory), &sessionCategory);  
  24.       
  25.       //Speaker playback  
  26.       UInt32 audioRouteOverride = kAudioSessionOverrideAudioRoute_Speaker;  
  27.       AudioSessionSetProperty (kAudioSessionProperty_OverrideAudioRoute, sizeof(audioRouteOverride), &audioRouteOverride);  
  28.       [[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayAndRecord error:nil];  
  29.       [[AVAudioSession sharedInstance] setActive:YES error:nil];  
  30.       [recorder record];  
  31. }  
  32.   
  33. const charchar * IosHelper::endRecord()  
  34. {  
  35.         if (recorder == nil)  
  36.         return "";  
  37.         if (recorder.isRecording)  
  38.         [recorder stop];  
  39.     return "";  
  40. }  


                                           
            


Second. Send voice data to server: After recording voice and generating file, send the file out.


  1. std::string kFileName = JniFun::stopSoundRecord();  
  2. sendTalkFile(m_pLocal->GetChairID(),kFileName);  



This is to send the file in the form of data packets without elaborating.

        

Third. Receive the data and decompress, play: After receiving the message, write the data to the file and play it.

          

  1. bool GameBase::RevTalk_File(CMD_GR_C_TableTalk* pNetInfo)  
  2. {  
  3.     if (pNetInfo->strTalkSize == 0)  
  4.     {  
  5.         return true;  
  6.     }  
  7.     static int iIdex = 0;  
  8.     iIdex ++;  
  9.     std::string kFile = utility::toString(cocos2d::CCFileUtils::sharedFileUtils()->getWritablePath(),"TableTalk",iIdex,".arm");  
  10.     FILE *fp = fopen(kFile.c_str(), "wb");  
  11.   
  12.     fseek(fp,0,SEEK_END);  
  13.     fseek(fp,0,SEEK_SET);  
  14.     fwrite(&pNetInfo->strTalkData,sizeof(unsigned char), pNetInfo->strTalkSize,fp);  
  15.     fclose(fp);  
  16.     int iAddTime = pNetInfo->strTalkSize/1200+2.0f;  
  17.     if (iAddTime > 10)  
  18.     {  
  19.         iAddTime = 10;  
  20.     }  
  21.     std::string kDestFile = kFile;  
  22.     utility::StringReplace(kDestFile,"arm","wav");  
  23.         //Here we need to do a decompression conversion to convert ARM into WAV.  
  24.     ArmFun::ArmToWav(kFile.c_str(),kDestFile.c_str());  
  25.         //In order to prevent the interference of game music, first silence game music  
  26.     SoundFun::Instance().PaseBackMusic();  
  27.     SoundFun::Instance().ResumeBackMusic(iAddTime);  
  28.     SoundFun::Instance().PaseEffectMusic();  
  29.     SoundFun::Instance().ResumeEffectMusic(iAddTime);  
  30.         //Play the received sound file  
  31.     SoundFun::Instance().playEffectDirect(kDestFile);  
  32.         //Designated player displays animated icons for playing voice  
  33.     GamePlayer* pPlayer = getBasePlayerByChairID(pNetInfo->cbChairID);  
  34.     if (pPlayer)  
  35.     {  
  36.         pPlayer->showTalkState(pNetInfo);  
  37.     }  
  38.           
  39.     return true;  
  40. }  


          

In the end, voice chat in room card chess and cards is completely realized. Of course, this method is not perfect, and it would be better if real-time voice conversation in P2P could be opened. In addition, this set of code will continue to produce sound files, which is a problem, small partners can send sound and play sound after deleting the generated sound files, so as not to cause space growth BUG.~


” Fangka "Mahjong R&D skills, in the"Red Boy's Game Development Road". Welcome to pay attention to the public number!

                             

Topics: encoding Android Java xml