问题:
java.lang.IllegalStateException: play() called on uninitialized AudioTrack.
具体报错如下:
E/AudioTrack-Java(10211): [ android.media.AudioTrack ] Error code -20 when initializing AudioTrack.
W/dalvikvm(10211): threadid=11: thread exiting with uncaught exception (group=0x400259f8)
E/AndroidRuntime(10211): FATAL EXCEPTION: Thread-19
E/AndroidRuntime(10211): java.lang.IllegalStateException: play() called on uninitialized AudioTrack.
E/AndroidRuntime(10211): at android.media.AudioTrack.play(AudioTrack.java:764)
E/AndroidRuntime(10211): at com.IPCamera.AudioPlayer.run(AudioPlayer.java:34)
E/AndroidRuntime(10211): at java.lang.Thread.run(Thread.java:1102)
问题发生的背景:
使用AudioTrack 类来播放获取到的音频数据,在中兴和华为手机上面都可以正常播放,但HTC手机和金立手机一播放,程序就奔溃了,调试信息,定位在初始化AudioTrack 时出现上述错误。
问题原因:
如报错提示,初始化AudioTrack 出错,网上搜了下,重新配置了下,具体如下:
第一步:
初始化最小buffersize,就是用来装音频数据的最小的值(暂这样理解)
buffint bufferSize = AudioTrack.getMinBufferSize(8000,
AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT);
第二步:
new 一播放音频的AudioTrack对象。
AudioTrack track = new AudioTrack(AudioManager.STREAM_MUSIC, 8000,
AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT,
bufferSize, AudioTrack.MODE_STREAM);
第三步:准备工作:
track.play();
第四步:播放音频数据(这可以循环播放数据)
将送进去的数据转化为声音播放出来;
track.write(byte[] audioData, int offsetInBytes, int sizeInBytes);
第五步:
停止,同时释放资源。
track.stop();
track.release();
小结:android中用到三个类管理Audio音频操作。
AudioManager用来管理Audio系统;
AudioRecord用来管理录音;
AudioTrack用来管理播放音频。
其中AudiaRecord和AudioTrack这两个类贯穿了Java层,jni层和c代码层,这里面还好很多东西值得深入学习,
这次记录下这些较为肤浅的东东。
参考网址:
http://www.2cto.com/kf/201110/106978.html
http://www.cnblogs.com/innost/archive/2011/01/09/1931457.html
一个星期志之前,由于需要,我开始学习SenchaTouch 2(以下简称ST2)。
笔者只有一点java面向对象的基础,并没有js或者js框架的基础,听说过jQuery,但ST2是个什么东西都不懂。怎么学习呢?第一天只是找了一些资料了解了什么是ST。现在看来一句话概括ST是最准确的:ST是基于HTML5的移动应用框架。读者应该注意到这些定语:
- HTML5:新一代的html标准,它允许在本地大量存储数据(这一点很重要)。且支持非flash的多媒体(这也是苹果不支持flash的原因,HTML5时代是不需要Flash的,详见乔帮主文章http://www.apple.com/hotnews/thoughts-on-flash/ )
- 移动应用:众所周知sencha是Ext的进化,sencha包含很多产品,如下图:ST只是sencha 的其中一个产品,并且专注于移动设备上引用的开发
对ST有了一些了解之后,便开始hello world。在这个阶段很重要的是环境的搭建。我会告诉你:ST的环境搭建只是包括对ST skd的引用,对IDE并没有什么要求。我之所以说这个系列的教程好的原因是这个教程有很好的架构ST应用的知识。你会看到一个好的ST应用目录结构会是这样(上图):
可能需要解释的是app目录。这是ST程序的主要组件:ST程序是基于MVC的。Model,View,Controller。Store是数据集,它像是一张表,一个Store对应一个model。Profile是什么,暂时还不清楚。
学习ST2可能还需要知道以下信息:
1.ST的最新版本是2.0 ,网上很多资料都是1.0版本的,所以运行会报错。
2.ST2基于HTML5,所以调试最好使用Chrome,或者safari。(浏览器对HTML5的支持见维基百科“HTML5”词条)
3.在chorme中调试js程序,F12。
4.在开发阶段请引用ST的debug版本,这样在F12调试的时候会提示错误所在行。
了解这些之后,就开始ST2之旅吧!
本系列翻译文章集合
http://blog.csdn.net/yanwushu/article/category/1235170
感谢文章作者提供精彩的教程!
再次声明:笔者英语能力有限,有些地方可能会误导读者,还请见谅并且提出错误以便笔者尽快改正!
信号和信号槽
在QT中,我们有一个callback技术的替代方案: 我们使用信号(signal)和信号槽(slot)。当一个特定的事件触发时一个对应的信号就会被发射。QT的控件(widget)拥有许多的预定义信号,当然我们也可以通过在widget的继承子类中添加自己的信号给它们。在一个特定的信号响应里一个被称之为信号槽(slot)的方法被调用。同样的,QT的控件也拥有许多的预定义信号槽,你知道的,我们也可以增加自己的信号槽来处理(handle)那些我们关注的信号。
信号和信号槽机制是类型安全的(type-safe):一个信号签名(signature)必需匹配一个接收信号槽的签名。(事实上,一个信号槽可能有一个比它接收到的信号短的签名,因为它可以过忽略掉额外的参数)因为签名是兼容的,那么编译器就可以帮我们找到类型不匹配。信号和信号槽是松耦合的:一个类发射一个信号不用知道也不想知道是哪个信号槽会接收它。Qt的信号和信号槽机制可保证的是当你连接(connect)一个信号到信号槽,在正确时间里信号槽肯定会被调用,带上信号的参数。信号和信号槽可以搞定任何类型的任意数量参数。它们全部都是类型安全的。
所有继承自QObject或它的其中一个子类(如QWidget)都自动的包含了信号和信号槽。当对象改变它们的状态时会向关注它的对象发射信号。这是所有的类都会做的通信。它不知道也不关心是谁接收了它发射的信号。真实的情况就是如此,并且被用来保障对象以软件组件的方式来使用。
信号槽被用来接收信号,但也可以是一般的成员方法。就像一个对象不知道谁接收信号,一个信号槽也不知道它会被连接到哪个信号上。它是保证一个真正的独立组件可以被用在Qt中。你可以尽可能的把多个信号连接到单个的信号槽上,也可以把一个信号连接到多个信号槽上,如果你需要的话。甚至你可以将一个信号直接连接到另一个信号上。(这将会导致第二个信号在第一个信号发射出后立即发射)。
总而言之,信号和信号槽成全了强大的组件式编程机制。
一个简短的例子
一个短小的C++类声明可能是这样的:
class Counter
{
public:
Counter() { m_value = 0; }
int value() const { return m_value; }
void setValue(int value);
private:
int m_value;
};
一个小的基于QObject的类看起来是这样的:
#include <QObject>
class Counter : public QObject
{
Q_OBJECT
public:
Counter() { m_value = 0; }
int value() const { return m_value; }
public slots:
void setValue(int value);
signals:
void valueChanged(int newValue);
private:
int m_value;
};
基于QObject版本的类有着同样的内部状态(state),也提供了public方法来访问状态,只是增加了信号和信号槽以便为组件式编程提供支持。这个类可以通过发射一个信号 valueChanged()来告诉外面的世界它的状态已经改变,并且它还有一个其它对象可以向它发送信号的信号槽。
所有的类要想包含信号和信号槽必需在它们的声明头部加上Q_OBJECT。也必需得继承自(直接或间接)QObject。
信号槽需要程序开发者来实现。这有一个Counter::setValue信号槽的大概实现:
void Counter::setValue(int value)
{
if (value != m_value) {
m_value = value;
emit valueChanged(value);
}
}
“发射行(emit line)”从对象中发射一个valueChanged信号,以新的值作为参数。在下面的代码片断里,我们创建两个Counter对象然后用QObject::connect方法将第一个对象的valueChanged信号连接(connect)到第二对象的setValue()信号槽上:
Counter a, b;
QObject::connect(&a, SIGNAL(valueChanged(int)),
&b, SLOT(setValue(int)));
a.setValue(12); // a.value() == 12, b.value() == 12
b.setValue(48); // a.value() == 12, b.value() == 48
Calling a.setValue(12) makes a emit a valueChanged(12) signal, which b will receive in its setValue() slot, i.e. b.setValue(12) is called. Then b emits the same valueChanged() signal, but since no slot has been connected to b's valueChanged() signal, the signal is ignored.
Note that the setValue() function sets the value and emits the signal only if value != m_value. This prevents infinite looping in the case of cyclic connections (e.g., if b.valueChanged() were connected to a.setValue()).
By default, for every connection you make, a signal is emitted; two signals are emitted for duplicate connections. You can break all of these connections with a single disconnect() call. If you pass the Qt::UniqueConnection type, the connection will only be made if it is not a duplicate. If there is already a duplicate (exact same signal to the exact same slot on the same objects), the connection will fail and connect will return false
This example illustrates that objects can work together without needing to know any information about each other. To enable this, the objects only need to be connected together, and this can be achieved with some simple QObject::connect() function calls, or with uic's automatic connections feature.