.
昨天完成了DslamTelnetProtocol类,这个类实现了IResponseListener接口,用于对接收到的输入流进行实时的解析、处理。DslamTelnetProtocol这个类的名称也许改成...ProtocolFilter比较合适。
目前启动了一个线程处理telnet的输出。对telnet的输入还是在主线程中调用telnetConnection.send()实现的。下一步应该把输入也用另一个线程来处理。
TODO: 对设备发送的命令放到一个BlockingQueue commandQueue中。DslamTelnetProtocol解析获得的命令结果放BlockingQueue resultQueue中。BlockingQueue确实为生产者-消费者模式简化了很多代码。否则你自己必须封装一个合适的queue,对这个queue进行适当的同步保证并发性。而且需要很好的设计wait() notify()来进行线程之间的协调。
2009年2月6日星期五
2009年2月4日星期三
Telnet命令执行器----对the end of a stream的理解
现在工作中的软件框架中有一个比较严重的问题是网络命令的执行request-reponse之间没有进行很好的协调而是使用sleep, check这种糟糕的方式。
很自然联想起给Neustar做的IM软件。但telnet协议又不同于IM系统所使用的协议。前者是基于长连接,而后者是短连接。对于短链接,请求与回应很容易进行匹对。而长连接,则需要依靠同一个网络连接顺序地、依次地进行请求-回应的处理。
对于利用像telnet协议基于长连接来执行的命令,同步是其天然特性。所以对于命令的执行是没有必要进行异步处理的。(当然也可以进行异步处理,但是意义基本不大,这里异步/同步的选择应该是基于应用的不同而变化。)
先不考虑接口、抽象。直接用两个类封装逻辑。TelnetConnection利用common-net项目中的TelnetClient建立连接,获得input, output。TelnetCommond封装通过telnet协议发出的命令。
public String receiveText() {
StringBuilder sb = null;
try {
sb = new StringBuilder();
byte ch = (byte) in.read();
while (ch > 0) {
sb.append((char) ch);
ch = (byte) in.read(); // 当读到-1之后再用out发送指令之后再也不能读出response了。
// 而且读取这个-1的值时程序被阻塞!
}
} catch (IOException e) {
Log.warn(e);
}
Log.debug(sb.toString());
return sb.toString();
}
改为使用结束字符串做检查标志后就正常了。
byte ch = (byte) in.read();
while (ch > 0) {
sb.append((char) ch);
if (sb.indexOf(endFlagStr) >=0) {
break;
}
ch = (byte) in.read();
}
很奇怪,难道是apache common-net里的类TelnetInputStream实现得有问题?当inputstream读到末尾后,有新的数据进入后没有进行适当的处理?
呵呵,是我的错误!inputStream.read()返回-1说明已经读到了the end of the stream。对于有限容量的stream(比如来自文件的流)来说就是读尽了,对于未知容量的stream比如网络流,如果 read()返回-1,说明这个流可能已经被对端关闭了。总之就应该对这种情况进行处理。再读下去,也是-1。这篇文章对此有些所描述:http://publib.boulder.ibm.com/infocenter/zos/v1r9/index.jsp?topic=/com.ibm.zos.r9.rexa100/h1981605209.htm
Telnet概述及RFC: http://en.wikipedia.org/wiki/Telnet
common-net 的使用:http://www.informit.com/guides/content.aspx?g=java&seqNum=40
很自然联想起给Neustar做的IM软件。但telnet协议又不同于IM系统所使用的协议。前者是基于长连接,而后者是短连接。对于短链接,请求与回应很容易进行匹对。而长连接,则需要依靠同一个网络连接顺序地、依次地进行请求-回应的处理。
对于利用像telnet协议基于长连接来执行的命令,同步是其天然特性。所以对于命令的执行是没有必要进行异步处理的。(当然也可以进行异步处理,但是意义基本不大,这里异步/同步的选择应该是基于应用的不同而变化。)
先不考虑接口、抽象。直接用两个类封装逻辑。TelnetConnection利用common-net项目中的TelnetClient建立连接,获得input, output。TelnetCommond封装通过telnet协议发出的命令。
public String receiveText() {
StringBuilder sb = null;
try {
sb = new StringBuilder();
byte ch = (byte) in.read();
while (ch > 0) {
sb.append((char) ch);
ch = (byte) in.read(); // 当读到-1之后再用out发送指令之后再也不能读出response了。
// 而且读取这个-1的值时程序被阻塞!
}
} catch (IOException e) {
Log.warn(e);
}
Log.debug(sb.toString());
return sb.toString();
}
改为使用结束字符串做检查标志后就正常了。
byte ch = (byte) in.read();
while (ch > 0) {
sb.append((char) ch);
if (sb.indexOf(endFlagStr) >=0) {
break;
}
ch = (byte) in.read();
}
很奇怪,难道是apache common-net里的类TelnetInputStream实现得有问题?当inputstream读到末尾后,有新的数据进入后没有进行适当的处理?
呵呵,是我的错误!inputStream.read()返回-1说明已经读到了the end of the stream。对于有限容量的stream(比如来自文件的流)来说就是读尽了,对于未知容量的stream比如网络流,如果 read()返回-1,说明这个流可能已经被对端关闭了。总之就应该对这种情况进行处理。再读下去,也是-1。这篇文章对此有些所描述:http://publib.boulder.ibm.com/infocenter/zos/v1r9/index.jsp?topic=/com.ibm.zos.r9.rexa100/h1981605209.htm
Telnet概述及RFC: http://en.wikipedia.org/wiki/Telnet
common-net 的使用:http://www.informit.com/guides/content.aspx?g=java&seqNum=40
2009年2月3日星期二
对synchronized 的又一点理解
java里的synchronized给我的一个强烈印象是“同步资源”,或者说是利用对象的monitor进行序列化访问的手段。
当使用object.wait()而没有事先synchronized object时,问题出现了:IllegalMonitorStateException。
wait() 之前必须先过的这个对象上的锁。这就要依靠synchronized。因为
synchronized的基本作用是“获取对象上的monitor”。所谓的同步、序列化访问都是建立在monitor的作用之上的。也许把synchronized理解成获得锁的语句可能更接近事实。
sleep() yield()并没有释放锁,这是和wait()的巨大区别。
当使用object.wait()而没有事先synchronized object时,问题出现了:IllegalMonitorStateException。
wait() 之前必须先过的这个对象上的锁。这就要依靠synchronized。因为
synchronized的基本作用是“获取对象上的monitor”。所谓的同步、序列化访问都是建立在monitor的作用之上的。也许把synchronized理解成获得锁的语句可能更接近事实。
sleep() yield()并没有释放锁,这是和wait()的巨大区别。
2008年11月21日星期五
IMS SDS4.1 training
19,20号参加了Ericsson的IMS SDS4.1的培训。虽然目前还找不到那个公司需要用到这些技术,但是当听着黎巴嫩帅哥老师讲这以前看过的IMS术语心里还是有些开心。
==== 用一句话总结我还记得的术语吧。=======
UA: user agent。
UAC, UAS,C,S分别代表client, server。UAC UAS是相对的。
IMS Core network: 内部使用SIP协议。RTP...这些视频流走的不是ISM网络通道。
SIP 建立会话时使用SDP。SDP放在SIP的body中。
SIP 很像HTTP,有header, 有body。做练习时把SIP的request类型(message reqeust)小写了,结果发出的消息没有收到。
SIP 很像HTTP,有header, 有body。做练习时把SIP的request类型(message reqeust)小写了,结果发出的消息没有收到。
HSS 存放registered User信息,以及用户可以使用的服务(IP/port ...)。Service profile. 其中ifc决定了用户使用特定服务的特定条件。
ifc: Initial Filter Criteria
C-CSCF 从HSS中获得用户的service profile,然后去寻找service application server,比如PoC, WE-Share, IMS-MSG...
ifc: Initial Filter Criteria
C-CSCF 从HSS中获得用户的service profile,然后去寻找service application server,比如PoC, WE-Share, IMS-MSG...
P-CSCF 用户终端(UA)不是直接与C-CSCF talking的。每个UA都固化了P-CSCF 的地址。P-CSCF是与域相关的。
每个电信运营商有自己的domain。比如,chinamobile, vodafone...
Application Server通过SIP servlet处理SIP请求,进行response。SIP servlet像及了HttpServlet。
很遗憾,其它的IMS节点老师就没有再讲了。(Ericsson内部五天的课程,现在压缩成2天。)
==== SDS =====
SDS非常好用。熟悉eclipse的,学习曲线很平坦。SDS menu item提供了几个perspective。DNS, HSS, CSCF的设置很直观。比较炫的一个功能是可以把来来回回的SIP 请求以sequence图的形式画出来。非常直观,见图。
安装glassfish后,一直不能很好的启动glassfish。后来发现是防火墙的原因。同时,启动glassfish之前最好要把DNS, CSCF Server也启动了。
==== 一些规范 =====
- ICP java API: 用于windows/symbian UIQ3
- ICP C++ API: 用于S-60
- IJCU API: 用于J2me
- JSR 281 : 用于java phone。 IJCU是JSR281的subset. 针对的是IMS core。
- JSR 325: 还没有finalise。定义了OMA规范了的service, 针对的是IMS service那层。 比如IMPS,PoC...
- JSR116, SIP Servlet 1.0 JSR289,SIP Servlet 1.1
有个术语“IMS Client Framework”。这个framwork是手机的功能集。以上的API规范是IMS Client Framework之上的一层。
针 对android, iPhone, windows mobile平台的API现在还没有。移动终端太混乱了。虽然moto不自己玩自己了、Nokia买了Symbian和Qt、索爱不玩UIQ了,但是还是 有micrisoft, google, apple。以后不知道谁会被整合到谁的手里。
2008年9月24日星期三
RICO notes
1, 设置Rico.TabbedPanel某个tab为选中状态。 tabs.openByIndex(); tabs.selectionSet.select($$('div.panelHeader'[2]));
2, 删除Rico.LiveGrid 中的一行。
<script type='text/javascript'>
var gridA;
Rico.loadModule('LiveGrid','LiveGridMenu','greenHdg.css');
Rico.onLoad( function() {
var buffer = new Rico.Buffer.Base($('licenseePayloadDG').tBodies[0]);
var grid_options = {
columnSpecs: [ {width:280},
{width:280},
{width:180},
{width:200}
]
};
gridA = new Rico.LiveGrid('licenseePayloadDG', buffer, grid_options);
});
function deleteCurrentRow(obj){
var cell = obj.parentNode;
gridA.selectCell(cell);
var row = gridA.SelectIdxStart.row; // SelectIdxStart.row 表示了当前选中的行的index。
var col = gridA.SelectIdxStart.column; // SelectIdxStart.column 表示了当前选中的列的index。
var cols = gridA.headerColCnt; // headerColCnt 表示了列的总数,是个常量。
gridA.selectRow(row); // selectRow(row) 高亮某行。row是行的索引。
// buffer 是Rico LiveGrid的数据模型对象。baseRows是数组格式的数据。baseRows.splice(row, count) 就把数据从数据模型中删除了。
gridA.buffer.baseRows.splice(row, 1);
// 删除数据后需要刷新页面才能看出效果。
gridA.refreshContents(0);
}
function removeCellzRow(row) {
for( var c=0; c < gridA.headerColCnt; c++ ) {
// LiveGrid的表格形式并不是由HTML table 表示的由<div> + css表现的。columns[]表示了所有的列。columns[c].cell(row)定位到了一个cell.
var cell=gridA.columns[c].cell(row);
// 选择一个单元格。
gridA.selectCell(cell);
// 清空一个单元格的内容。注意: 设置innerHTML=""只是把表现层的东西清空了。后台的数据模型gridA.buffer.baseRows并没有改变。
cell.innerHTML = "";
}
}
</script>
对应的HTML: <a href="#" onclick='javascript: {if(confirm("deleteRow?")) {deleteCurrentRow(this); }else {}}'>DelRow</a>
2, 删除Rico.LiveGrid 中的一行。
<script type='text/javascript'>
var gridA;
Rico.loadModule('LiveGrid','LiveGridMenu','greenHdg.css');
Rico.onLoad( function() {
var buffer = new Rico.Buffer.Base($('licenseePayloadDG').tBodies[0]);
var grid_options = {
columnSpecs: [ {width:280},
{width:280},
{width:180},
{width:200}
]
};
gridA = new Rico.LiveGrid('licenseePayloadDG', buffer, grid_options);
});
function deleteCurrentRow(obj){
var cell = obj.parentNode;
gridA.selectCell(cell);
var row = gridA.SelectIdxStart.row; // SelectIdxStart.row 表示了当前选中的行的index。
var col = gridA.SelectIdxStart.column; // SelectIdxStart.column 表示了当前选中的列的index。
var cols = gridA.headerColCnt; // headerColCnt 表示了列的总数,是个常量。
gridA.selectRow(row); // selectRow(row) 高亮某行。row是行的索引。
// buffer 是Rico LiveGrid的数据模型对象。baseRows是数组格式的数据。baseRows.splice(row, count) 就把数据从数据模型中删除了。
gridA.buffer.baseRows.splice(row, 1);
// 删除数据后需要刷新页面才能看出效果。
gridA.refreshContents(0);
}
function removeCellzRow(row) {
for( var c=0; c < gridA.headerColCnt; c++ ) {
// LiveGrid的表格形式并不是由HTML table 表示的由<div> + css表现的。columns[]表示了所有的列。columns[c].cell(row)定位到了一个cell.
var cell=gridA.columns[c].cell(row);
// 选择一个单元格。
gridA.selectCell(cell);
// 清空一个单元格的内容。注意: 设置innerHTML=""只是把表现层的东西清空了。后台的数据模型gridA.buffer.baseRows并没有改变。
cell.innerHTML = "";
}
}
</script>
对应的HTML: <a href="#" onclick='javascript: {if(confirm("deleteRow?")) {deleteCurrentRow(this); }else {}}'>DelRow</a>
2008年9月7日星期日
运行时
以前的datamodel过于复杂,而且对于未来的计划是早晚要替换掉旧代码,那么如何隔离旧的接口给新的API呢?
我的方法是:定义一个新接口、新的一些class,用旧的class实现这个新接口。外面的模块使用旧的Class的地方,都用新接口引用。
Willie则直接了当的用了extends。
Willie把FConnector继承Thread的关系掐掉了。Connector确实没必要以thread的方式运行。因为其下的session是个thread。牛人终归是牛人,下手就是地方。
总的说来,脑袋里有个动态的系统运行某型至关重要,静态的类图是不够全面的,从某种意义上来说动态模型才是一个真正的程序模型。
最为一个senior的programmer 每个UseCase的call sequences,一定要能在脑袋里流出来,这都搞不定,别提可靠性。
对于高手,代码就是设计。这句话的含义就是对于高手来说,它的大脑就是一个JVM,他知道一个程序从某点执行下去到某点,这个JVM里有几个class,每个class有几个instance, 有多少个线程。
没这水平,就先用UML画点图,自己琢磨琢磨吧。
Spring这个东西得到了公认。除了其中的IoC、AOP这些概念外,其配置文件的功能--装配,不就是强制让你考虑了系统启动时的个对象、实例的各种关系(静态/动态)么?
2008年6月5日星期四
Qt environment for Marvell board.
用于Marvell的板子。
=============== 安装toolchain 以及 Qt
=============== 安装toolchain 以及 Qt
1, create diretory /CMMB
2, cp PlatformRel_Linux2.6.21_MHLV.tgz into the /CMMB
3, tar xvzf PlatformRel_Linux2.6.21_MHLV.tgz
this step create dir pxalinux.
4, cd /CMMB/pxalinux/toolchain
tar xvzf arm-iwmmxt-linux-gnueabi-4.1.1-gpl-lgpl.tgz
This stup create toolchain files in dir /CMMB/pxalinux/toolchain/arm-linux-4.1.1
5, modify the /root/.bashrc to add the path /CMMB/pxalinux/toolchain/arm-linux-4.1.1/bin
into the env var PATH.
export PATH=/CMMB/pxalinux/toolchain/arm-linux-4.1.1/bin:$PATH
6, cd /CMMB/pxalinux/package/usage-model-7.0.5
tar xvzf qtopia-src-gpl.tgz
After this step, the dir qtopia_2.2.0 is created.
7, cd /CMMB/pxalinux/package/usage-model-7.0.5/qtopia_2.2.0
and run the shell: yes | ./build_qtopia.sh > build.log
8,
// 设定 qmake路径。
export PATH=/CMMB/pxalinux/package/usage-model-7.0.5/qtopia_2.2.0/work/qtopia-free-2.2.0/dqt/bin:$PATH
export QMAKESPEC=/CMMB/pxalinux/package/usage-model-7.0.5/qtopia_2.2.0/work/qtopia-free-2.2.0/qtopia/mkspecs/qws/linux-arm-g++
cd /CMMB/pxalinux/package/usage-model-7.0.5/qtopia_2.2.0/work/qtopia-free-2.2.0
chmod +x setQpeEnv
./setQpeEnv
2, cp PlatformRel_Linux2.6.21_MHLV.tgz into the /CMMB
3, tar xvzf PlatformRel_Linux2.6.21_MHLV.tgz
this step create dir pxalinux.
4, cd /CMMB/pxalinux/toolchain
tar xvzf arm-iwmmxt-linux-gnueabi-4.1.1-gpl-lgpl.tgz
This stup create toolchain files in dir /CMMB/pxalinux/toolchain/arm-linux-4.1.1
5, modify the /root/.bashrc to add the path /CMMB/pxalinux/toolchain/arm-linux-4.1.1/bin
into the env var PATH.
export PATH=/CMMB/pxalinux/toolchain/arm-linux-4.1.1/bin:$PATH
6, cd /CMMB/pxalinux/package/usage-model-7.0.5
tar xvzf qtopia-src-gpl.tgz
After this step, the dir qtopia_2.2.0 is created.
7, cd /CMMB/pxalinux/package/usage-model-7.0.5/qtopia_2.2.0
and run the shell: yes | ./build_qtopia.sh > build.log
8,
// 设定 qmake路径。
export PATH=/CMMB/pxalinux/package/usage-model-7.0.5/qtopia_2.2.0/work/qtopia-free-2.2.0/dqt/bin:$PATH
export QMAKESPEC=/CMMB/pxalinux/package/usage-model-7.0.5/qtopia_2.2.0/work/qtopia-free-2.2.0/qtopia/mkspecs/qws/linux-arm-g++
cd /CMMB/pxalinux/package/usage-model-7.0.5/qtopia_2.2.0/work/qtopia-free-2.2.0
chmod +x setQpeEnv
./setQpeEnv
=============== 配置Qt开发环境
1, Create account for development
groupadd cmmbdev
adduser cmmb -g cmmbdev
adduser cmmb -g cmmbdev
passwd cmmb
2, Create a shell setDevEnv.sh, including:
# 导入Qtopia环境变量
4, chmod -R +r /CMMB/pxalinux
cd /CMMB
mkdir tvp
chown -R cmmb tvp
5, qmake -project
modify tvp.pro to include:
QMAKE_LIBS_QT += -ljpeg -luuid -lts -lqpe
6, qmake
7, make
2, Create a shell setDevEnv.sh, including:
# 导入Qtopia环境变量
source /CMMB/pxalinux/package/usage-model-7.0.5/qtopia_2.2.0/work/qtopia-free-2.2.0/setQpeEnv
# 设置toolchain路径
export PATH=/CMMB/pxalinux/toolchain/arm-linux-4.1.1/bin:$PATH
# 设置qmake路径
export PATH=/CMMB/pxalinux/package/usage-model-7.0.5/qtopia_2.2.0/work/qtopia-free-2.2.0/dqt/bin:$PATH
# 设置qmake环境变量配置路径
export QMAKESPEC=/CMMB/pxalinux/package/usage-model-7.0.5/qtopia_2.2.0/work/qtopia-free-2.2.0/qtopia/mkspecs/qws/linux-arm-g++
3, add . ./setDevEnv.sh into the cmmb user's .bashrc# 设置toolchain路径
export PATH=/CMMB/pxalinux/toolchain/arm-linux-4.1.1/bin:$PATH
# 设置qmake路径
export PATH=/CMMB/pxalinux/package/usage-model-7.0.5/qtopia_2.2.0/work/qtopia-free-2.2.0/dqt/bin:$PATH
# 设置qmake环境变量配置路径
export QMAKESPEC=/CMMB/pxalinux/package/usage-model-7.0.5/qtopia_2.2.0/work/qtopia-free-2.2.0/qtopia/mkspecs/qws/linux-arm-g++
4, chmod -R +r /CMMB/pxalinux
cd /CMMB
mkdir tvp
chown -R cmmb tvp
5, qmake -project
modify tvp.pro to include:
QMAKE_LIBS_QT += -ljpeg -luuid -lts -lqpe
6, qmake
7, make
通用的QT安装
1) 升级Kernel
rpm -ql | grep kern
yum intall kern*
2) 修改grub.conf使console支持FrameBuffer。在引导界面可以看到小企鹅。/dev目录下有设备fb0。 这样从console中就可以直接运行GUI程序了。
试图生成 libqte-mt.so, 用于QThread.
2) qt2
./configure -qt2 '-no-xft -thread -I/usr/include -I/usr/include/freetype2 -I/usr/include/freetype'
ln -sf /pub/qtopia-free-2.2.0/dqt/lib/libqt-mt.so.3.3.5 /pub/qtopia-free-2.2.0/qtopia/lib/libqte-mt.so
3)
./configure -qt2 '-no-xft -thread -I/usr/include -I/usr/include/freetype2 -I/usr/include/freetype'
以上步骤都不能生成libqte-mt.so
通过修改config.cache,可以生成libqte-mt.so了。
QPEDIR=/pub/qtopia-free-2.2.0/qtopia
QTOPIA_DEPOT_PATH=/pub/qtopia-free-2.2.0/qtopia
TMAKEDIR=/pub/qtopia-free-2.2.0/tmake
DQTDIR=/pub/qtopia-free-2.2.0/dqt
QT2DIR=/pub/qtopia-free-2.2.0/qt2
QTEDIR=/pub/qtopia-free-2.2.0/qt2
QPE_CFG="-edition pda -displaysize 240x320 -no-qtopiadesktop -release -platform 'linux-g++' -xplatform 'linux-generic-g++'"
QTE_CFG="-embedded -no-xft -qconfig qpe -qvfb -thread -depths 4,8,16,32 -system-jpeg -gif -D QT_TRANSFORM_VFB -release -platform 'linux-g++' -xplatform 'linux-generic-g++'"
QT2_CFG="-no-opengl -no-xft -no-sm -platform 'linux-g++'"
DQT_CFG="-thread -qt-gif -fast -platform 'linux-g++'"
USE_CACHE="no"
这样,Qt2的线程包没有生成,估计要设置-thread 到QT2_CFG中.
虽然这样做生成了libqte-mt.so, 但是把QThread用于QTopia程序(带GUI)时仍旧发生段错误. 普通的QT程序使用QThread时就没有问题.
后来通过配置qtopia的编译发现了这段警告. 看来在qtopia2.2下使用QThread是不稳定的.
[root@localhost qtopia]# ./configure -debug -thread -I/usr/include:/usr/include/freetype:/usr/include/freetype2 -qvfb -qtopia
QPEDIR = /pub/qtopia-free-2.2.0/qtopia
DEPOT = /pub/qpe2.2/qtopia
The following configuration values have been guessed or autodetected:
-arch generic
-displaysize 240-320
-edition pda
-fontfamilies helvetica fixed micro smallsmooth smoothtimes
-fontsizes all
-fontstyles 50 50i 75 75i
-languages en_US
-platform linux-g++
-xplatform linux-generic-g++
WARNING: Trolltech does not support building Qtopia against a multi-threaded Qt.
While it should work, Trolltech can make no guarantees about the ability
of Qtopia to operate correctly when Qt is multi-threaded. If you wish to
use threads in your own apps, you should consider using pthreads directly.
Symlinking header files to include directory
Creating qmake.......
因为以上Qtopia2.2中QThread的问题,这两天改用qtopia-opensource-4.3.1了. 感觉不错。
Qtopia-opensource-4.3.1的安装。
1)安装。
./configure 过程中有警告和错误提示如下。但是不用管它们,依旧可以编译通过。
Project ERROR: This is a dummy profile to be used for translations ONLY.
WARNING: Failure to find: qvfbhdr.h
在gmake的过程中,提示缺少库libXtst, libXmu,而不能继续。此时需要使用 yum install libXtst*, yum install libXmu*进行安装。
2)gmake install。
这一步会生成image。所有要运行的程序都要放在image/bin目录下。这是完整的Qtopia运行环境。
3)样例程序。
把example的样例程序随便copy到某个目录里。通过qtopiamake生成Makefile. 用make install INSTALL_ROOT="imagePath" 进行编译安装。
gstreamer 库与Qtopia的结合。
把利用gstreamer播放mp3的函数封装到动态库libmyGstLib.so中。Qtopia的GUI程序直接库中的函数。遇到的问题及解决如下:
1)段错误。
写了一个很简单的动态库供qtopia程序适用,一切正常。 排除了qtopia的问题。
int startPlayer (int argc, char *argv[]); 方法中有: gst_init (&argc, &argv); 而在Qtopia对其的调用中传递的是startPlayer(1, NULL);
怀疑gstreamer使用了argc, argv参数。于是就把NULL改为了一个字符串数组。问题解决了。但是又说没有找到"mad"插件。
又写了一个只有main函数,调用动态库的程序,却没有mad插件的错误。播放mp3没有问题。
察看了一下编译main函数使用的gcc参数。
libtool --mode=link gcc `pkg-config --cflags --libs gstreamer-0.10` -o gstTestApp test.c
gcc -pthread -I/usr/local/include/gstreamer-0.10 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2 -pthread -o myprog test.c -L/usr/local/lib -L/lib /usr/local/lib/libgstreamer-0.10.so -lrt -lgobject-2.0 -lgmodule-2.0 -ldl -lgthread-2.0 -lxml2 -lz -lm -lglib-2.0 -Wl,--rpath -Wl,/usr/local/lib -Wl,--rpath -Wl,/usr/local/lib
而libmad安装后也提示:
而libmad安装后也提示:
If you ever happen to want to link against installed libraries
in a given directory, LIBDIR, you must either use libtool, and
specify the full pathname of the library, or use the `-LLIBDIR'
flag during linking and do at least one of the following:
- add LIBDIR to the `LD_LIBRARY_PATH' environment variable
during execution
- add LIBDIR to the `LD_RUN_PATH' environment variable
during linking
- use the `-Wl,--rpath -Wl,LIBDIR' linker flag
- have your system administrator add LIBDIR to `/etc/ld.so.conf'
See any operating system documentation about shared libraries for
more information, such as the ld(1) and ld.so(8) manual pages.
in a given directory, LIBDIR, you must either use libtool, and
specify the full pathname of the library, or use the `-LLIBDIR'
flag during linking and do at least one of the following:
- add LIBDIR to the `LD_LIBRARY_PATH' environment variable
during execution
- add LIBDIR to the `LD_RUN_PATH' environment variable
during linking
- use the `-Wl,--rpath -Wl,LIBDIR' linker flag
- have your system administrator add LIBDIR to `/etc/ld.so.conf'
See any operating system documentation about shared libraries for
more information, such as the ld(1) and ld.so(8) manual pages.
通过把这些库和编译选项加入到了myGstLib的编译文件中后,程序就可以播放mp3了.
2) Qt中的Singal-slot机制是同步的.如果某个signal没有处理完毕,界面就会冻结。所以需要使用线程进行播放。
2) Qt中的Singal-slot机制是同步的.如果某个signal没有处理完毕,界面就会冻结。所以需要使用线程进行播放。
订阅:
博文 (Atom)