cocos2d实现语音_cocos2dx实现录音功能

本文主要实现两个功能:

(1)通过Android sdk的API得到应用程序的包名(PackageName),然后传递给c++层函数。

(2)通过c++函数调用Android的java层函数,显示一个对话框,点击按钮退出程序。

1. 首先来简单学习一下JNI的相关知识,我这篇文章中简单实现了怎么在Android Java层调用c++函数。要想使用JNI,必须得包含头文件,android是使用ndk编译c/c++的,这里jni.h文件位于:\android-ndk-r8b\platforms\android-14\arch-arm\usr\include\jni.h,该文件定义了所有和JNI相关的数据类型和接口。下面是相关代码片段:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

# include       /* C99 */

typedefuint8_t         jboolean;       /* unsigned 8 bits */

typedefint8_t          jbyte;          /* signed 8 bits */

typedefuint16_t        jchar;          /* unsigned 16 bits */

typedefint16_t         jshort;         /* signed 16 bits */

typedefint32_t         jint;           /* signed 32 bits */

typedefint64_t         jlong;          /* signed 64 bits */

typedeffloat          jfloat;         /* 32-bit IEEE 754 */

typedefdouble         jdouble;        /* 64-bit IEEE 754 */

#else

typedefunsigned char  jboolean;       /* unsigned 8 bits */

typedefsignedchar    jbyte;          /* signed 8 bits */

typedefunsigned short jchar;          /* unsigned 16 bits */

typedefshort          jshort;         /* signed 16 bits */

typedefint            jint;           /* signed 32 bits */

typedeflonglong      jlong;          /* signed 64 bits */

typedeffloat          jfloat;         /* 32-bit IEEE 754 */

typedefdouble         jdouble;        /* 64-bit IEEE 754 */

#endif

/* "cardinal indices and sizes" */

typedefjint            jsize;

#ifdef __cplusplus

/*

* Reference types, in C++

*/

class_jobject {};

class_jclass : public_jobject {};

class_jstring : public_jobject {};

class_jarray : public_jobject {};

class_jobjectArray : public_jarray {};

class_jbooleanArray : public_jarray {};

class_jbyteArray : public_jarray {};

class_jcharArray : public_jarray {};

class_jshortArray : public_jarray {};

class_jintArray : public_jarray {};

class_jlongArray : public_jarray {};

class_jfloatArray : public_jarray {};

class_jdoubleArray : public_jarray {};

class_jthrowable : public_jobject {};

typedef_jobject*       jobject;

typedef_jclass*        jclass;

typedef_jstring*       jstring;

typedef_jarray*        jarray;

typedef_jobjectArray*  jobjectArray;

typedef_jbooleanArray* jbooleanArray;

typedef_jbyteArray*    jbyteArray;

typedef_jcharArray*    jcharArray;

typedef_jshortArray*   jshortArray;

typedef_jintArray*     jintArray;

typedef_jlongArray*    jlongArray;

typedef_jfloatArray*   jfloatArray;

typedef_jdoubleArray*  jdoubleArray;

typedef_jthrowable*    jthrowable;

typedef_jobject*       jweak;

#else /* not __cplusplus */

/*

* Reference types, in C.

*/

typedefvoid*           jobject;

typedefjobject         jclass;

typedefjobject         jstring;

typedefjobject         jarray;

typedefjarray          jobjectArray;

typedefjarray          jbooleanArray;

typedefjarray          jbyteArray;

typedefjarray          jcharArray;

typedefjarray          jshortArray;

typedefjarray          jintArray;

typedefjarray          jlongArray;

typedefjarray          jfloatArray;

typedefjarray          jdoubleArray;

typedefjobject         jthrowable;

typedefjobject         jweak;

#endif /* not __cplusplus */

我们经常用到的是JNIEnv*,它是一个c结构体,封装了许多常用的函数,如:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

struct_JNIEnv {

/* do not rename this; it does not seem to be entirely opaque */

conststructJNINativeInterface* functions;

#if defined(__cplusplus)

jint GetVersion()

{ returnfunctions->GetVersion(this); }

jclass DefineClass(constchar*name, jobject loader, constjbyte* buf,

jsize bufLen)

{ returnfunctions->DefineClass(this, name, loader, buf, bufLen); }

jclass FindClass(constchar* name)

{ returnfunctions->FindClass(this, name); }

// 这里省略其他函数...

}

cocos2d-x引擎对jni的操作进行了封装,提供了一个非常好用的类:JniHelper,定义了一些常用的接口,该文件位于cocos2dx/platform/android/jni目录下。下面看看JniHelper.h源码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

typedefstructJniMethodInfo_

{

JNIEnv *    env;

jclass      classID;

jmethodID   methodID;

} JniMethodInfo;

classCC_DLL JniHelper

{

public:

staticJavaVM* getJavaVM();

staticvoidsetJavaVM(JavaVM *javaVM);

staticconstchar* getExternalAssetPath();

staticvoidsetExternalAssetPath(constchar* externalAssetPath);

staticjclass getClassID(constchar*className, JNIEnv *env=0);

staticboolgetStaticMethodInfo(JniMethodInfo &methodinfo, constchar*className, constchar*methodName, constchar*paramCode);

staticboolgetMethodInfo(JniMethodInfo &methodinfo, constchar*className, constchar*methodName, constchar*paramCode);

staticstd::string jstring2string(jstring str);

private:

staticJavaVM *m_psJavaVM;

staticstd::string m_externalAssetPath;

};

下面来解释JniHelper的两个常用函数:

(1)getStaticMethodInfo

用来判断Java的类静态函数是否存在,并初始化结构体JniMethodInfo,该结构体封装了JNIEnv*和java.lang.Class对象、函数ID。这样就可以使用JNIEnv*调用 CallStaticXXXMethod(jclass clazz, jmethodID methodID, …)和 CallXXXMethod(jobject obj, jmethodID methodID, …)等常用函数(XXX替换为函数返回值类型,如:Void,Int等)。

第一个参数为JniMethodInfo,第二个参数是类的绝对路径,第三个参数是函数名,第四个参数是函数签名(参数和返回类型),示例代码如下:

1

2

3

4

if(JniHelper::getStaticMethodInfo(t, CLASS_NAME, "showTipDialog", "(Ljava/lang/String;Ljava/lang/String;)V"))

{

//...

}

关于类型签名,请对照下图:

(2)getMethodInfo

该函数与getStaticMethodInfo类似,用于Java类的非静态函数。

2. 下面开始实现文章开头所述的两个功能,本文是在cocos2d-x 2.0版本 自适应屏幕分辨率demo的基础上添加的。

(1)利用cocos2d-x创建一个Android工程,名为JniTest,包名为com.alexzhou.jni,此时该包下会自动生成一个JniTest.java文件。

(2)首先来实现把应用程序的包名传递给c++函数,在包下创建JniTestHelper.java,该类封装了给c++调用的函数,添加如下代码:

1

2

3

4

5

6

7

8

privatestaticHandler mHandler;

publicstaticvoidinit(Handler handler)

{

JniTestHelper.mHandler = handler;

}

publicstaticnativevoidsetPackageName(String packageName);

(3)打开JniTest.java,在onCreate函数中添加下面的代码:

1

2

3

4

5

protectedvoidonCreate(Bundle savedInstanceState){

super.onCreate(savedInstanceState);

JniTestHelper.init(mHandler);

JniTestHelper.setPackageName(this.getPackageName());

}

(4)java层的代码已经完成了,下面来编写jni层代码,在/jni/hellocpp/下创建test.h和test.cpp文件,test.h文件暂时不添加任何函数,代码如下:

test.h

1

2

3

4

#ifndef TEST_H

#define TEST_H

#endif

test.cpp

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

#include "cocos2d.h"

#include

#include "platform/android/jni/JniHelper.h"

#include "test.h"

#include "JniTest.h"

#define CLASS_NAME "com/alexzhou/jni/JniTestHelper"

usingnamespacecocos2d;

extern"C"

{

voidJava_com_alexzhou_jni_JniTestHelper_setPackageName(JNIEnv *env, jobject thiz, jstring packageName)

{

constchar*pkgName = env->GetStringUTFChars(packageName, NULL);

setPackageName(pkgName);

env->ReleaseStringUTFChars(packageName, pkgName);

}

}

必须加上extern “C”,声明以c语言的方式进行编译,因为c++和c在编译时生成的函数签名不一样,可以在网上查找相关资料,不然运行的时候会出现链接错误。

(5)现在编写c++函数,在Classes目录下创建JniTest.h,代码如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

#ifndef JNI_TEST_H

#define JNI_TEST_H

#include "cocos2d.h"

usingnamespacecocos2d;

voidsetPackageName(constchar*packageName)

{

CCLog("packageName: %s", packageName);

}

#endif

(6)修改jni/Android.mk文件的LOCAL_SRC_FILES值 ,内容如下:

1

2

LOCAL_SRC_FILES := hellocpp/main.cpp \

hellocpp/test.cpp

(7)编译运行,因为我是使用cygwin编译的,而且Android项目不在cocos2d-x的根目录下,所以需要修改build_native.sh,修改COCOS2DX_ROOT和NDK_MODULE_PATH的值,把当前cocos2d-x项目的路径添加到NDK_MODULE_PATH,修改后的值:

1

2

3

COCOS2DX_ROOT="/cygdrive/e/cocos2d-x/cocos2d-2.0-x-2.0.4"

"NDK_MODULE_PATH=${COCOS2DX_ROOT}:${COCOS2DX_ROOT}/cocos2dx/platform/third_party/android/prebuilt:${APP_ROOT}"

运行结果:

(8)现在来实现通过c++函数调用java层函数,显示一个对话框。在JniTestHelper.java添加如下代码:

1

2

3

4

5

6

7

8

9

10

11

12

publicstaticnativevoidexitApp();

privatestaticvoidshowTipDialog(finalString title, finalString text)

{

Message msg = mHandler.obtainMessage();

msg.what = JniTest.SHOW_DIALOG;

DialogMessage dm = newDialogMessage();

dm.title = title;

dm.msg = text;

msg.obj = dm;

msg.sendToTarget();

}

(9)创建一个DialogMessage.java,封装dialog要显示的数据。

1

2

3

4

5

6

7

8

9

10

11

/**

author:alexzhou

email :zhoujiangbohai@163.com

date  :2012-12-14

**/

publicclassDialogMessage {

publicString title;

publicString msg;

}

(10) 修改JniTest.java,添加显示对话框的函数:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

publicstaticfinalintSHOW_DIALOG = 0x0001;

privateHandler mHandler = newHandler()

{

@Override

publicvoidhandleMessage(Message msg) {

switch(msg.what)

{

caseSHOW_DIALOG:

DialogMessage dm = (DialogMessage)msg.obj;

newAlertDialog.Builder(JniTest.this)

.setTitle(dm.title)

.setMessage(dm.msg).setNegativeButton("cancle", newDialogInterface.OnClickListener() {

@Override

publicvoidonClick(DialogInterface dialog, intwhich) {

dialog.dismiss();

}

})

.setPositiveButton("Ok",

newDialogInterface.OnClickListener() {

@Override

publicvoidonClick(DialogInterface dialog, intwhich) {

dialog.dismiss();

JniTestHelper.exitApp();

}

})

.create().show();

break;

}

}

};

(11)在test.h和test.cpp中添加显示对话框的接口:

test.h

1

2

3

4

extern"C"

{

voidshowTipDialog(constchar*title, constchar*msg);

}

test.cpp

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

extern"C"

{

voidshowTipDialog(constchar*title, constchar*msg)

{

JniMethodInfo t;

if(JniHelper::getStaticMethodInfo(t, CLASS_NAME, "showTipDialog", "(Ljava/lang/String;Ljava/lang/String;)V"))

{

jstring jTitle = t.env->NewStringUTF(title);

jstring jMsg = t.env->NewStringUTF(msg);

t.env->CallStaticVoidMethod(t.classID, t.methodID, jTitle, jMsg);

t.env->DeleteLocalRef(jTitle);

t.env->DeleteLocalRef(jMsg);

}

}

voidJava_com_alexzhou_jni_JniTestHelper_setPackageName(JNIEnv *env, jobject thiz, jstring packageName)

{

constchar*pkgName = env->GetStringUTFChars(packageName, NULL);

setPackageName(pkgName);

env->ReleaseStringUTFChars(packageName, pkgName);

}

voidJava_com_alexzhou_jni_JniTestHelper_exitApp(JNIEnv *env, jobject thiz)

{

exitApp();

}

}

(12) 修改Classes目录下的JniTest.h,添加代码:

1

2

3

4

voidexitApp()

{

CCDirector::sharedDirector()->end();

}

(13)到此为止,所有代码都已经完成了,代码比较简单就不详细解释了,现在编译运行,效果如下:

源码下载地址:http://download.csdn.net/detail/u013388439/9459321

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值