| // | 
| //  UniversalSDK.m | 
| //  Unity-iPhone | 
| // | 
| //  Created by 蔡瀚 on 2018/4/24. | 
| // | 
|   | 
| #import "UniversalSDK.h" | 
| #import "JPUSHService.h" | 
| #import "AdSupport/AdSupport.h" | 
| #import "Tracking.h" | 
| #import "opus.h" | 
| #ifdef NSFoundationVersionNumber_iOS_9_x_Max | 
| #import <UserNotifications/UserNotifications.h> | 
| #endif | 
| #import "SystemConfiguration/CaptiveNetwork.h" | 
| #import <TTTracker/TTTracker+Game.h> | 
| #import <AoyouSDK/IVQNAoyouSDK.h> | 
|   | 
| @interface UniversalSDK()<JPUSHRegisterDelegate,UIWebViewDelegate> | 
| @end | 
|   | 
| @implementation UniversalSDK | 
|   | 
| #define CHANNEL_NUM 1 | 
|   | 
| static int s_frequency = 16000; | 
| static int s_bitRate = 20000; | 
| static int s_bandMode = OPUS_BANDWIDTH_WIDEBAND; | 
| static int s_frameSize = 160; | 
| static int sBatteryLevel = -1; | 
| static int sBatteryState = -1; | 
| static NSString* sAppID; | 
| static NSString* sGameID; | 
| static NSString* sUserName; | 
| static NSThread* _thread; | 
|   | 
| -(void) Init | 
| { | 
|     NSString *_bundlePath = [[NSBundle mainBundle] pathForResource:@"The2thWorldRES.bundle" ofType:nil]; | 
|     NSString* _configPath = [[NSBundle bundleWithPath:_bundlePath] pathForResource:@"The2thWorldSDKConfig" ofType:@"plist"]; | 
|     NSMutableDictionary *_configDict = [[NSMutableDictionary alloc] initWithContentsOfFile:_configPath]; | 
|      | 
|     UIDevice *_device = [UIDevice currentDevice]; | 
|     _device.batteryMonitoringEnabled = true; | 
|      | 
|     NSString* _uniqueID = [[NSUserDefaults standardUserDefaults] objectForKey:@"tsw_unique_id"]; | 
|     //获取IDFA | 
|     NSString* _idfa = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString]; | 
|      | 
|     if(_uniqueID == NULL || [_uniqueID length] <= 0) | 
|     { | 
|         //判断IDFA是否为空 | 
|         BOOL isEmpty = [[_idfa stringByReplacingOccurrencesOfString:@"-" withString:@""] stringByReplacingOccurrencesOfString:@"0" withString:@""].length; | 
|         if (isEmpty) { | 
|             //不为空,将IDFA作为唯一标识 | 
|             _uniqueID = _idfa; | 
|         } | 
|         else { | 
|             //为空,获取UUID作为唯一标识 | 
|             _uniqueID = [[[UIDevice currentDevice] identifierForVendor] UUIDString]; | 
|         } | 
|          | 
|         //保存唯一设备标识,如已存在则不进行任何处理 | 
|         [[NSUserDefaults standardUserDefaults] setObject:_uniqueID forKey:@"tsw_unique_id"]; | 
|         [[NSUserDefaults standardUserDefaults] synchronize]; | 
|     } | 
|      | 
|     // 取得UserAgent | 
|     UIWebView* _webView = [[UIWebView alloc] initWithFrame:CGRectZero]; | 
|     NSString* _userAgent = [_webView stringByEvaluatingJavaScriptFromString:@"navigator.userAgent"]; | 
|      | 
|     // 发送设备信息 | 
|     NSMutableDictionary *_dict = [NSMutableDictionary dictionaryWithObjectsAndKeys: | 
|                                   _uniqueID,@"unique_id", | 
|                                   _idfa,@"android_id", | 
|                                   [NSNumber numberWithInt:S2U_DeviceInfo],@"code", | 
|                                   _userAgent,@"userAgent",nil]; | 
|     [self SendMessageToUnity:_dict]; | 
|      | 
|     // 发送个推id | 
|     [_dict removeAllObjects]; | 
|     [_dict setObject:[JPUSHService registrationID] forKey:@"clientID"]; | 
|     [_dict setObject:[NSNumber numberWithInt:S2U_PushClientID] forKey:@"code"]; | 
|     [self SendMessageToUnity:_dict]; | 
|      | 
|     // 热云初始化 | 
|     [Tracking initWithAppKey:_configDict[@"TrackingIO_AppKey"] | 
|                withChannelId:@"_default_"]; | 
|      | 
|     // 今日头条 | 
|     NSDictionary* _infoDictionary = [[NSBundle mainBundle] infoDictionary]; | 
|     [TTTracker startWithAppID:_configDict[@"TTTrack_AppID"] | 
|                       channel:@"ios-xbqy" | 
|                       appName:[_infoDictionary objectForKey:@"CFBundleDisplayName"]]; | 
|      | 
|     // 发送初始化完成 | 
|     [_dict removeAllObjects]; | 
|     [_dict setObject:[NSNumber numberWithInt:S2U_SdkInitComplete] forKey:@"code"]; | 
|     [_dict setObject:@"yl" forKey:@"channelPlatform"]; | 
|     [self SendMessageToUnity:_dict]; | 
| } | 
|   | 
| -(void)SendMessageToUnity:(NSDictionary*)dict | 
| { | 
|     BOOL _result = [NSJSONSerialization isValidJSONObject:dict]; | 
|     if(_result) | 
|     { | 
|         NSData* _jsonData = [NSJSONSerialization dataWithJSONObject:dict options:0 error:NULL]; | 
|         UnitySendMessage(UNITY_OBJ_NAME, UNITY_FUNC_NAME, | 
|                          [[[NSString alloc] initWithData:_jsonData encoding:NSUTF8StringEncoding] UTF8String]); | 
|     } | 
| } | 
|   | 
| -(void) BatteryThread { | 
|     while (TRUE) | 
|     { | 
|         [NSThread sleepForTimeInterval:1]; | 
|          | 
|         UIDevice *_device = [UIDevice currentDevice]; | 
|          | 
|         int _state = [_device batteryState]; | 
|         if(_state != sBatteryState){ | 
|             sBatteryState = _state; | 
|             NSDictionary *_dict = [NSDictionary dictionaryWithObjectsAndKeys: | 
|                                    [NSNumber numberWithInt:sBatteryState], @"status", | 
|                                    [NSNumber numberWithInt:S2U_BatteryCharging], @"code", nil]; | 
|              | 
|             [self SendMessageToUnity:_dict]; | 
|         } | 
|          | 
|         int _level = (int)([_device batteryLevel] * 100); | 
|         if(_level != sBatteryLevel){ | 
|             sBatteryLevel = _level; | 
|             NSDictionary *_dict = [NSDictionary dictionaryWithObjectsAndKeys: | 
|                                    [NSNumber numberWithInt:sBatteryLevel], @"level", | 
|                                    [NSNumber numberWithInt:S2U_BatteryLevel], @"code", nil]; | 
|              | 
|             [self SendMessageToUnity:_dict]; | 
|         } | 
|     } | 
| } | 
|   | 
| -(void) OpenURL:(NSString*) url { | 
|      | 
|     if(m_UIWebView != NULL) { | 
|         [self btnClick:NULL]; | 
|         return; | 
|     } | 
|      | 
|     CGRect _bounds = UnityGetMainWindow().bounds; | 
|      | 
|     float _scale = _bounds.size.width / 1334; | 
|      | 
|     float _width = 982 * _scale; | 
|     float _height = 560 * _scale; | 
|      | 
|     float _offsetX = (_bounds.size.width - _width) * .5f; | 
|     float _offsetY = (_bounds.size.height - _height) * .5f; | 
|      | 
|     m_UIWebView = [[UIWebView alloc] initWithFrame:CGRectMake(_offsetX, _offsetY, _width, _height)]; | 
|     m_UIWebView.delegate = self; | 
|     m_UIWebView.scalesPageToFit = YES ; | 
|     m_UIWebView.scrollView.scrollEnabled = YES; | 
|     m_UIWebView.scrollView.bounces = NO; | 
|     NSURLRequest *request =[NSURLRequest requestWithURL:[NSURL URLWithString:url]]; | 
|     [m_UIWebView loadRequest:request]; | 
| } | 
|   | 
| -(void) btnClick:(UIButton*)sender { | 
|     [m_CloseBtn removeFromSuperview]; | 
|     [m_CloseBtn removeTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside]; | 
|     m_CloseBtn = NULL; | 
|      | 
|     NSURLCache *_cache = [NSURLCache sharedURLCache]; | 
|     [_cache removeAllCachedResponses]; | 
|     [_cache setDiskCapacity:0]; | 
|     [_cache setMemoryCapacity:0]; | 
|      | 
|     [m_UIWebView removeFromSuperview]; | 
|     m_UIWebView = NULL; | 
| } | 
|   | 
| -(void)webViewDidStartLoad:(UIWebView *)webView{ | 
| } | 
|   | 
| -(void)webViewDidFinishLoad:(UIWebView *)webView{ | 
|      | 
|     [UnityGetMainWindow().rootViewController.view addSubview:m_UIWebView]; | 
|     CGRect _bounds = UnityGetMainWindow().bounds; | 
|      | 
|     float _scale = _bounds.size.width / 1334; | 
|      | 
|     float _width = 982 * _scale; | 
|     float _height = 560 * _scale; | 
|      | 
|     m_CloseBtn = [UIButton buttonWithType:UIButtonTypeRoundedRect]; | 
|     [m_CloseBtn setFrame:CGRectMake(_width - 455 * _scale, _height - 86 * _scale, 180 * _scale, 72 * _scale)]; | 
|     [m_CloseBtn setTitle:@"我知道了" forState:UIControlStateNormal]; | 
|      | 
|     NSString *_bundlePath = [[NSBundle mainBundle] pathForResource:@"The2thWorldRES.bundle" ofType:nil]; | 
|     NSBundle *_bundle = [NSBundle bundleWithPath:_bundlePath]; | 
|     NSString *pic1Path = [_bundle pathForResource:@"TY_AN_34.png" ofType:nil]; | 
|      | 
|     [m_CloseBtn setBackgroundImage:[UIImage imageWithContentsOfFile:pic1Path] forState:UIControlStateNormal]; | 
|     [m_CloseBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; | 
|     [m_CloseBtn addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside]; | 
|      | 
|     [m_UIWebView addSubview:m_CloseBtn]; | 
| } | 
|   | 
| -(void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error{ | 
| } | 
|   | 
| -(void)JPushInit:(NSDictionary*)launchOptions { | 
|      | 
|      | 
|     NSString *_bundlePath = [[NSBundle mainBundle] pathForResource:@"The2thWorldRES.bundle" ofType:nil]; | 
|     NSString* _configPath = [[NSBundle bundleWithPath:_bundlePath] pathForResource:@"The2thWorldSDKConfig" ofType:@"plist"]; | 
|     NSMutableDictionary *_configDict = [[NSMutableDictionary alloc] initWithContentsOfFile:_configPath]; | 
|      | 
|     JPUSHRegisterEntity *_entity = [[JPUSHRegisterEntity alloc] init]; | 
|     _entity.types = JPAuthorizationOptionAlert | JPAuthorizationOptionBadge | JPAuthorizationOptionSound; | 
|     if([[UIDevice currentDevice].systemVersion floatValue] > 8.0){ | 
|     } | 
|      | 
|     [JPUSHService registerForRemoteNotificationConfig:_entity | 
|                                              delegate:self]; | 
|     [JPUSHService setupWithOption:launchOptions | 
|                            appKey:_configDict[@"JPush_AppKey"] | 
|                           channel:@"develop" | 
|                  apsForProduction:JPush_IsProduction | 
|             advertisingIdentifier:nil]; | 
| } | 
|   | 
| - (void)jpushNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler { | 
|      | 
|     NSDictionary * userInfo = response.notification.request.content.userInfo; | 
|     if([response.notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) { | 
|         [JPUSHService handleRemoteNotification:userInfo]; | 
|     } | 
|     completionHandler(); | 
| } | 
|   | 
| - (void)jpushNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(NSInteger))completionHandler { | 
|      | 
|     NSDictionary * userInfo = notification.request.content.userInfo; | 
|     if([notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) { | 
|         [JPUSHService handleRemoteNotification:userInfo]; | 
|     } | 
|     completionHandler(UNNotificationPresentationOptionAlert); | 
| } | 
|   | 
| -(id) APNativeJSONObject:(NSData *)data{ | 
|     if (!data) { | 
|         return nil; | 
|     } | 
|      | 
|     NSError *error = nil; | 
|     id retId = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error]; | 
|      | 
|     if (error) { | 
|         NSLog(@"%s trans data to obj with error: %@", __func__, error); | 
|         return nil; | 
|     } | 
|      | 
|     return retId; | 
| } | 
|   | 
| -(NSData *)APNativeJSONData:(id)obj { | 
|     NSError *error = nil; | 
|     NSData *data = [NSJSONSerialization dataWithJSONObject:obj options:0 error:&error]; | 
|     if (error) { | 
|         NSLog(@"%s trans obj to data with error: %@", __func__, error); | 
|         return nil; | 
|     } | 
|     return data; | 
| } | 
|   | 
| -(void) RemoveLocalNotificationWithIdentifierKey:(NSString*) idKey{ | 
|     JPushNotificationIdentifier *identifier = [[JPushNotificationIdentifier alloc] init]; | 
|     identifier.identifiers = @[idKey]; | 
|     identifier.delivered = YES;  //iOS10以上有效,等于YES则在通知中心显示的里面移除,等于NO则为在待推送的里面移除;iOS10以下无效 | 
|     [JPUSHService removeNotification:identifier]; | 
| } | 
|   | 
| -(void)HandleUnityMessage:(NSString *)json { | 
|      | 
|     NSLog(@"收到Unity发来的消息 => %@", json); | 
|      | 
|     NSData *_jsonData = [json dataUsingEncoding:NSUTF8StringEncoding]; | 
|     NSDictionary *_dict = [self APNativeJSONObject:_jsonData]; | 
|      | 
|     switch([[_dict objectForKey:@"code"] intValue]){ | 
|         case U2S_Init: | 
|             [self Init]; | 
|             sAppID = _dict[@"appID"]; | 
|             sGameID = _dict[@"gameID"]; | 
|             break; | 
|         case U2S_CopyContent: | 
|             [UIPasteboard generalPasteboard].string = _dict[@"content"]; | 
|             break; | 
|         case U2S_FreePlatformInit: | 
|             break; | 
|         case U2S_MakeKeyAndVisible: | 
|         { | 
|             UIWindow * _window = [[UIApplication sharedApplication].delegate window]; | 
|             if (_window != nil && _window.rootViewController != nil) { | 
|                 [_window makeKeyAndVisible]; | 
|             } | 
|         } | 
|             break; | 
|         case U2S_OpenWebView: | 
|             [self OpenURL:_dict[@"url"]]; | 
|             break; | 
|         case U2S_FreePlatformLogin: | 
|         { | 
|             [IVQNAoyouSDK ETTTloadLoginingVCResultSuccess:^(NSString * _Nonnull loginTime, NSString * _Nonnull userName, NSString * _Nonnull sign) { | 
|                 NSDictionary *_dict = [NSDictionary dictionaryWithObjectsAndKeys: | 
|                                        [NSDictionary dictionaryWithObjectsAndKeys:sign, @"token", | 
|                                         [NSString stringWithFormat:@"%@",loginTime], @"token_expire", | 
|                                         userName, @"account", nil],@"info", | 
|                                        [NSNumber numberWithInt:S2U_FreePlatformLoginOk], @"code", nil]; | 
|                 sUserName = userName; | 
|                 [self SendMessageToUnity:_dict]; | 
|             } failed:^(NSInteger code, NSString * _Nonnull message) { | 
|                 NSLog(@"登录失败: code=%zd, msg=%@",code,message); | 
|             }]; | 
|         } | 
|             break; | 
|         case U2S_FreePlatformLogout: | 
|         { | 
|             [IVQNAoyouSDK ETTTloadLoginingVCResultSuccess:^(NSString * _Nonnull loginTime, NSString * _Nonnull userName, NSString * _Nonnull sign) { | 
|                 NSDictionary *_dict = [NSDictionary dictionaryWithObjectsAndKeys: | 
|                                        [NSDictionary dictionaryWithObjectsAndKeys:sign, @"token", | 
|                                         [NSString stringWithFormat:@"%@",loginTime], @"token_expire", | 
|                                         userName, @"account", nil],@"info", | 
|                                        [NSNumber numberWithInt:S2U_FreePlatformLoginOk], @"code", nil]; | 
|                 sUserName = userName; | 
|                 [self SendMessageToUnity:_dict]; | 
|             } failed:^(NSInteger code, NSString * _Nonnull message) { | 
|                 NSLog(@"登录失败: code=%zd, msg=%@",code,message); | 
|             }]; | 
|         } | 
|             break; | 
|         case U2S_RoleLogin: | 
|             [IVQNAoyouSDK NFEGSetUserInfoWithRoleId:[NSString stringWithFormat:@"%@",[_dict objectForKey:@"roleID"]] | 
|                                            roleName:[_dict objectForKey:@"roleName"] | 
|                                           roleLevel:[NSString stringWithFormat:@"%@",[_dict objectForKey:@"level"]] | 
|                                              zoneId:[NSString stringWithFormat:@"%@",[_dict objectForKey:@"sid"]] | 
|                                            zoneName:[_dict objectForKey:@"serverName"] | 
|                                              attach:@"" | 
|                                               block:^(NSInteger code) { | 
|                                                   NSLog(@"---- code: %zd",code); | 
|                                               }]; | 
|             break; | 
|         case U2S_FreePlatformPay: | 
|         { | 
|             [IVQNAoyouSDK KPTBloadToFQVCWithRoleid:[_dict objectForKey:@"roleID"] | 
|                                                 mo:[_dict objectForKey:@"mount"] | 
|                                           serverid:[_dict objectForKey:@"sid"] | 
|                                        productName:[_dict objectForKey:@"title"] | 
|                                        productDesc:[_dict objectForKey:@"title"] | 
|                                             attach:[NSString stringWithFormat:@"{\"appid\":\"%@\",\"cpinfo\":\"%@\",\"cporderid\":\"%@\",\"productid\":\"%@\"}", | 
|                                                     sAppID, | 
|                                                     [_dict objectForKey:@"cpInfo"], | 
|                                                     [_dict objectForKey:@"orderId"], | 
|                                                     sGameID] | 
|                                          productId:[_dict objectForKey:@"cpInfo"] | 
|                                            success:^(NSString * _Nonnull message, NSString * _Nonnull money) { | 
|                                                NSDictionary *_dict = [NSDictionary dictionaryWithObjectsAndKeys: | 
|                                                                       [NSNumber numberWithInt:S2U_FreePlatformPayOk], @"code", nil]; | 
|                                                [self SendMessageToUnity:_dict]; | 
|                                            } faild:^(NSString * _Nonnull message, NSInteger code, NSString * _Nonnull money) { | 
|                                                NSDictionary *_dict = [NSDictionary dictionaryWithObjectsAndKeys: | 
|                                                                       [NSNumber numberWithInt:S2U_FreePlatformPayFail], @"code", nil]; | 
|                                                [self SendMessageToUnity:_dict]; | 
|                                            }]; | 
|         } | 
|             break; | 
|         case U2S_PayFinished: | 
|             [Tracking setRyzf:[_dict objectForKey:@"orderID"] | 
|                      ryzfType:[_dict objectForKey:@"payType"] | 
|                        hbType:[_dict objectForKey:@"moneyType"] | 
|                      hbAmount:[_dict[@"money"] floatValue]]; | 
|              | 
|             [TTTracker purchaseEventWithContentType:@"mingwen" | 
|                                         contentName:@"yuanbao" | 
|                                           contentID:[_dict objectForKey:@"orderID"] | 
|                                       contentNumber:1 | 
|                                      paymentChannel:@"_defaul_" | 
|                                            currency:@"rmb" | 
|                                     currency_amount:[_dict[@"money"] intValue] | 
|                                           isSuccess:true]; | 
|             break; | 
|         case U2S_BatteryListenStart: | 
|             if(_thread == NULL) | 
|             { | 
|                 _thread = [[NSThread alloc] initWithTarget:self selector:@selector(BatteryThread) object:nil]; | 
|                 [_thread setName:@"BatteryCheck"]; | 
|             } | 
|             if(![_thread isExecuting]) | 
|             { | 
|                 [_thread start]; | 
|             } | 
|             break; | 
|         case U2S_BatteryListenStop: | 
|             break; | 
|         case U2S_SendRegistEvent: | 
|             [Tracking setRegisterWithAccountID:sUserName]; | 
|             [TTTracker registerEventByMethod:@"_default_" isSuccess:true]; | 
|             break; | 
|         case U2S_SendLoginEvent: | 
|             [Tracking setLoginWithAccountID:sUserName]; | 
|             [TTTracker loginEventByMethod:@"_default_" isSuccess:true]; | 
|             break; | 
|         case U2S_JPushRemoveLocalMessage: | 
|             [self RemoveLocalNotificationWithIdentifierKey:_dict[@"id"]]; | 
|             break; | 
|         case U2S_JPushAddLocalMessage: | 
|         { | 
|             JPushNotificationContent *_content = [[JPushNotificationContent alloc] init]; | 
|             if (_dict[@"title"]) { | 
|                 _content.title = _dict[@"title"]; | 
|             } | 
|             if (_dict[@"subtitle"]) { | 
|                 _content.subtitle = _dict[@"subtitle"]; | 
|             } | 
|             if (_dict[@"content"]) { | 
|                 _content.body = _dict[@"content"]; | 
|             } | 
|             if (_dict[@"badge"]) { | 
|                 _content.badge = @([_dict[@"badge"] intValue]); | 
|             } | 
|             if (_dict[@"action"]) { | 
|                 _content.action = _dict[@"action"]; | 
|             } | 
|             if (_dict[@"extra"]) { | 
|                 _content.userInfo = _dict[@"extra"]; | 
|             } | 
|             if (_dict[@"sound"]) { | 
|                 _content.sound = _dict[@"sound"]; | 
|             } | 
|             JPushNotificationTrigger *_trigger = [[JPushNotificationTrigger alloc] init]; | 
|             if (_dict[@"fireTime"]) { | 
|                 long _time = [_dict[@"fireTime"] longValue]; | 
|                 NSNumber *date = @(_time); | 
|                 if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 10.0) { | 
|                     NSTimeInterval currentInterval = [[NSDate date] timeIntervalSince1970]; | 
|                     NSTimeInterval interval = [date doubleValue] - currentInterval; | 
|                     interval = interval > 0? interval : 0; | 
|                     _trigger.timeInterval = interval; | 
|                 } else { | 
|                     _trigger.fireDate = [NSDate dateWithTimeIntervalSince1970: [date doubleValue]]; | 
|                 } | 
|                 JPushNotificationRequest *_request = [[JPushNotificationRequest alloc] init]; | 
|                 _request.requestIdentifier = [NSString stringWithFormat:@"%@",_dict[@"id"]]; | 
|                 _request.content = _content; | 
|                 _request.trigger = _trigger; | 
|                 _request.completionHandler = ^(id result) { | 
|                     // iOS10以上成功则result为UNNotificationRequest对象,失败则result为nil;iOS10以下成功result为UILocalNotification对象,失败则result为nil | 
|                     NSLog(@"结果返回:%@", result); | 
|                 }; | 
|                 [JPUSHService addNotification:_request]; | 
|                 break; | 
|             } | 
|         } | 
|     } | 
| } | 
| @end | 
|   | 
| extern "C" void native_opus_init(int frequency, int bitRate, int bandMode) | 
| { | 
|     s_frequency = frequency; | 
|     s_bandMode = bandMode; | 
|     s_bitRate = bitRate; | 
|     s_frameSize = frequency / 100; | 
| } | 
|   | 
| extern "C" int native_opus_encode(opus_int16 *pcm, int len, unsigned char *opus) | 
| { | 
|     int errorCode = 0; | 
|     opus_int32 skip = 0; | 
|     OpusEncoder *enc = opus_encoder_create(s_frequency, CHANNEL_NUM, OPUS_APPLICATION_VOIP, &errorCode); | 
|     if (OPUS_OK != errorCode) { | 
|         enc = NULL; | 
|         return -1; | 
|     } | 
|      | 
|     opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(s_bandMode)); | 
|     opus_encoder_ctl(enc, OPUS_SET_BITRATE(s_bitRate)); | 
|     opus_encoder_ctl(enc, OPUS_SET_VBR(1)); | 
|     opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(10)); | 
|     opus_encoder_ctl(enc, OPUS_SET_INBAND_FEC(0)); | 
|     opus_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS(OPUS_SIGNAL_VOICE)); | 
|     opus_encoder_ctl(enc, OPUS_SET_DTX(0)); | 
|     opus_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(0)); | 
|     opus_encoder_ctl(enc, OPUS_GET_LOOKAHEAD(&skip)); | 
|     opus_encoder_ctl(enc, OPUS_SET_LSB_DEPTH(16)); | 
|      | 
|     unsigned char *rbytes = opus; | 
|     opus_int16 *frame = pcm; | 
|     int totalSize = 0; | 
|     while (len >= s_frameSize) | 
|     { | 
|         opus_int32 length = opus_encode(enc, frame, s_frameSize, rbytes + sizeof(char), s_bitRate); | 
|         rbytes[0] = length; | 
|         frame += s_frameSize; | 
|         rbytes += length + sizeof(char); | 
|         len -= s_frameSize; | 
|         totalSize += length; | 
|     } | 
|     opus_encoder_destroy(enc); | 
|     return totalSize; | 
| } | 
|   | 
| extern "C" int native_opus_decode(unsigned char *opus, int len, short *pcm) | 
| { | 
|     int err = 0; | 
|     //opus_int32 skip = 0; | 
|      | 
|     OpusDecoder *dec = opus_decoder_create(s_frequency, CHANNEL_NUM, &err); | 
|     if (err != OPUS_OK) { | 
|         dec = NULL; | 
|         return -1; | 
|     } | 
|      | 
|     while (len > 0) | 
|     { | 
|         int frame_opus_length = opus[0]; | 
|         int length = opus_decode(dec, opus + sizeof(char), frame_opus_length, pcm, s_frameSize, 0); | 
|         opus += sizeof(char) + frame_opus_length; | 
|         pcm += s_frameSize; | 
|         len = len - frame_opus_length - sizeof(char); | 
|     } | 
|     opus_decoder_destroy(dec); | 
|     return 0; | 
| } |