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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
| #include <stdio.h>
#include <jni.h>
#include <gst/gst.h>
#include "Jaudio.h"
// gcc -fPIC -shared -static Jaudio.c -o libJaudio.so \
-I /usr/lib/jvm/java-1.7.0-openjdk-i386/include \
$(pkg-config --cflags --libs gstreamer-0.10)
/*
* symbol lookup error: libJaudio.so: undefined symbol: gst_init
* gcc参数顺序相关的问题 http://m.oschina.net/blog/97611
* 对于C/C++编译而言,读取编译选项是按照从左到右的顺序执行的 。当编译器遇到源文件时,
* 开始对源文件中用到的函数进行解析,找到相对应函数实现(Definition of Function)。
* 过程是按照先遇到不能解析的函数(unresolved function),
* 然后在源文件选项后面的一些选项中寻找可能的函数体的信息,是这样的一个顺序进行的。
* 包含函数体或者函数定义信息的编译选项出现在源文件之前,当编译器遇到不能解析的函数时,
* 在源文件之后的选项中寻找相关的信息,也就是无法找到相关的函数定义。
*/
// java -Djava.library.path=. Jaudio
//定义消息处理函数
static gboolean bus_call(GstBus *bus,GstMessage *msg,gpointer data){
GMainLoop *loop = (GMainLoop *) data;
//这个是主循环的指针,在接受EOS消息时退出循环
gchar *debug;
GError *error;
switch (GST_MESSAGE_TYPE(msg)){
case GST_MESSAGE_EOS:
g_print("播放结束\n");
g_main_loop_quit(loop);
//退出循环
break;
case GST_MESSAGE_ERROR:
gst_message_parse_error(msg,&error,&debug);
g_free(debug);
g_printerr("错误:%s\n",error->message);
g_error_free(error);
g_main_loop_quit(loop);
break;
default:
break;
}
return TRUE;
}
JNIEXPORT void JNICALL Java_Jaudio_playMP3(JNIEnv *env, jobject this,
jstring jstr){
/*
* 所有的 JNI 调用都使用了 JNIEnv * 类型的指针,
* 习惯上在 CPP 文件中将这个变量定义为 evn,它是任意一个本地方法的第一个参数。
* env 指针指向一个函数指针表,在 VC 中可以直接用"->"操作符访问其中的函数。
* object指向在此Java中实例化的对象 LocalFunction 的句柄,相当于this指针。
*/
const char* str;
str = (*env)->GetStringUTFChars(env,jstr, JNI_FALSE);
// 从 jstr 字符串取得指向字符串 UTF 编码的指针
printf("播放地址:%s\n",str);
jclass cls = (*env)->FindClass(env, "Jaudio");
if(cls != 0){
//printf("FindClass:%p\n",cls);
jmethodID mid =
(*env)->GetStaticMethodID(env, cls, "nanoTime", "()J");
if(mid != 0){
//printf("GetMethodID:%p\n",mid);
jlong jl = (*env)->CallStaticLongMethod(env,cls,mid);
long long l = jl;
printf("Java nanoTime:%lld\n",l);//long jlong signed 64bits
}else{
printf("GetMethodID err\n");
}
}else{
printf("FindClass err\n");
}
GMainLoop *loop;
GstElement *pipeline,*source,*decoder,*sink;//定义组件
GstBus *bus;
const gchar *nano_str;
guint major, minor, micro, nano;
gst_init(NULL,NULL); //初始化
loop = g_main_loop_new(NULL,FALSE);
//创建主循环,在执行 g_main_loop_run后正式开始循环
gst_version (&major, &minor, µ, &nano);
if (nano == 1) nano_str = "(CVS)";
else if (nano == 2) nano_str = "(Prerelease)";
else nano_str = "";
printf("Power By\n\tJava Native Interface & GStreamer%d.%d.%d %s\n",
major, minor, micro, nano_str);
printf("\tJaudio.c v0.0.1 20150211\n");
//创建管道和组件
//创建用来容纳元件的新管道,管道是一个特殊的组件,可以更好的让数据流动
pipeline = gst_pipeline_new("audio-player");
//生成用于读取硬盘数据的元件
source = gst_element_factory_make("filesrc","file-source");
//创建解码器元件
decoder = gst_element_factory_make("mad","mad-decoder");
//创建音频回放元件
sink = gst_element_factory_make("autoaudiosink","audio-output");
/*if(!pipeline||!source||!decoder||!sink){
g_printerr("One element could not be created.Exiting.\n");
return -1;
}*/
if(!pipeline){
g_printerr("GST管道不能创建!\n");
exit(-1);
}
if(!source){
g_printerr("GST播放文件不能创建!\n");
exit(-1);
}
if(!decoder){
g_printerr("GST解码元件不能创建\n");
exit(-1);
}
if(!decoder){
g_printerr("GST音频输出不能创建\n");
exit(-1);
}
//设置 source的location 参数 文件地址.
g_object_set(G_OBJECT(source),"location",str,NULL);
//把组件添加到管道中
gst_bin_add_many(GST_BIN(pipeline),source,decoder,sink,NULL);
//依次连接组件
gst_element_link_many(source,decoder,sink,NULL);
//得到 管道的消息总线
bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline));
//添加消息监视器
gst_bus_add_watch(bus,bus_call,loop);
gst_object_unref(bus);
//开始播放
gst_element_set_state(pipeline,GST_STATE_PLAYING);
g_print("开始播放 -> %s\n",str);
//开始循环
g_main_loop_run(loop);
//停止管道处理流程
gst_element_set_state(pipeline,GST_STATE_NULL);
//释放占用的资源
gst_object_unref(GST_OBJECT(pipeline));
g_print("拜拜,退出\n");
//return 0;
(*env)->ReleaseStringUTFChars(env,jstr, (const char *)str );
// 通知虚拟机本地代码不再需要通过 str 访问 Java 字符串。
}
|