Sunday, December 28, 2008

Some humor, Google's translation from Chinese to English

So, here is how Google reads the talkLock FAQ Chinese version:

talkLock 项目页 talkLock project page

或者,外籍人吃了我的扼要() Or, foreigners eat my brief ()

项目 Item Screenshots Screenshots 工作 Job 博客 Blog

English version English version 汉语版本 Chinese Version

talkLock FAQ (Frequently Asked Questions - 常见问题) talkLock FAQ (Frequently Asked Questions - Frequently Asked Questions)

我为本文的汉语版本的质量差道歉。 I am for this article poor quality of Chinese version of an apology. 我使用一个自动化的工具从英语转换。 I use an automated tool for conversion from the English. 我不读也不写中文。 I do not read nor write Chinese. .我只被问关于talkLock的一个问题,但是我认为它是明显相当常常地回答的乐趣先发制人问题我也许在将来某天被问和。 . I only asked a question on talkLock, but I think it is obviously quite often to answer the question of the fun of pre-emptive one day I might be asked in the future and.

您为什么认为它是写的乐趣FAQ? Why do you think it is fun to write the FAQ?

如果您研究流动Java节目,您会了解。 If you study on the mobile Java programs, you will understand. 我常常地要求分心和从工作的长的休息talkLock,五个或六个星期。 I often ask a distraction from the work of a long rest talkLock, five or six weeks. 我不可能负担工作talkLock今晚,作为I' m如此喜欢与我做几几天前的进展。 I can not afford talkLock work tonight, as I 'm so like me to do a few days ago with the progress. 因此I' 做此的m。 So I 'so here m. Whee! Whee!

那一个问题您被问怎么样? That question was asked how you like?

I被要求什么平台我曾经写和开发talkLock。 I was asked to what I have to write a platform and development talkLock. 这能是一个长的故事,但是I' ll使短通过说我使用与流动性组装的NetBeans。 This is a long story, but I 'll say that I am so short, through the use of assembly and the mobility of the NetBeans. 如果您能跑Netbeans和创造一个新的流动性项目,则大概所有设置您晃动talkLock样式。 If you run Netbeans and create a new mobile project, then probably all of the settings you shaking talkLock style.

什么是talkLock? What is talkLock?

talkLock是打算治疗人认为的一个社会学实验它是整洁的写在他们的手机跑的节目。 talkLock is intended for the treatment of humans as a sociological experiment that it is clean and write in their mobile phones to run programs. 毕业生可以然后连同他们的生活,安全,以他们为条件不,想要做那。 Graduates can then, together with their lives, security, on condition that they do not want to do that. 留下仍然相信的伙计的节目他们想要研究在手机跑然后被投入在观察之下由科学家在我们选择的设施的节目,将被服从到进一步社会学实验。 Continues to believe that the boy left the program they want to study the cell phone and then ran into the observation by scientists in our choice of facilities, programs, will be subject to further sociological experiment.

什么。 什么.

呀,好, talkLock真正地是在手机跑的节目。 Yes, well, talkLock truly run in the cell phone program. 它是未完成作品,但是想法是它将允许任何人在他们的电话的跑的talkLock有与另一人连续talkLock的一次被加密的交谈在他们的手机。 It is the unfinished work, but the idea is that it will allow anyone in their phones running talkLock another person with a straight talkLock to be encrypted in their phone conversation. 想法是伙计能有交谈,不用电子被窃听。 Idea is to have a chat buddy, do not e-tapped. 它当前取决于服务器组分,一个简单的php剧本,作为一mediary在二个电话之间. It now depends on the server component, a simple php script, as a mediary between the two phones.

如果他们的交谈被窃听,人们为什么会关心? If their conversations were tapped, why people care about?

我知道it' 不非常现代的s做价值判断或发表宣示声明,但是我的父母教我那it' 听的s错误people' 没有他们知道的s交谈。 I know it 'not very modern s do value judgments or published a statement declaring, but my parents taught me that it' to listen to the s wrong people 'do not they know s conversation. 也有曾经是普遍的在美国称私密权的另一个老想法。 There was a general right to privacy in the United States, said another old idea. 我真正地不是原教旨主义者,和密码技术总是一个辩论的主题。 I really was not fundamentalists, and cryptographic techniques is always a subject of debate. 某些人民关心,某些人民不。 Some people care about, some people do not. 点是那伙计应该能选择有一次私人会谈,如果他们要对和I' 设法的m帮助与那。 Point is that guys should be able to choose a private talks, if they want to and I 'trying to help and that the m.

伪善言辞坏人民使用此秘密地谈论坏材料? Hypocritical rhetoric bad people use this secret materials about the bad?

这是关于私有化的大辩论隐藏,并且它很多在20世纪90年代初被谈论了。 This is the great debate on the privatization of hide, and it a lot in the 20th century, the early 90s was discussed. 它仍然继续,但是基本上灵魔是在瓶外面。 It is still continuing, but basically the devil is in the bottles of spirits outside. 在伙计享受个人自由的社会,他们自由选择做好事或坏事。 Guys enjoy the freedom of the individual in society, they freely choose to do good or bad thing. 那几乎是与自由的成交。 It is almost closing and freedom. 大家必须与他们的行动的后果居住。 We must be consistent with the consequences of their actions live.

您为什么给talkLock ? Why did you give talkLock?

电话它仁爱一种任意行为。 Call it an arbitrary act of caring. 我喜欢做事和分享与其他人民。 I like doing things and sharing with other people. 给了得我很多,并且我设法退回厚待。 Amazing to me a lot, and I try to return the favor. GNU项目有许多了不起的节目可利用对原始代码,例如Java和操作系统的Linux,伙计给了世界其他地方。 GNU project has many great programs can make use of the original code, such as Java and operating system Linux, a waiter to other parts of the world. 我为为大多他们的节目使用的talkLock使用同一个执照,称GPL的执照, GNU公众执照。 I was for most of their programs talkLock used to use the same license, said the GPL license, GNU public license. 执照的拷贝是分布与talkLock来源。 Licensed copy is the source of distribution and talkLock. 您能闻悉GNU哲学在网。 Can you hear reports that the fainthearted GNU philosophy in the network.

因此我做什么与这种材料? So I do with this material?

谢谢为注册在我们的社会学实验和欢迎! 最初要做的最容易和多数乐趣事大概是指向在您的电话的浏览器http://marmot.dudeabides.net/talkLock/talkLock.jad和安装talkLock。 Thank you for the registration of sociology in our experiments and welcome! Initially to do the easiest and most fun thing is probably the point in your phone's browser http://marmot.dudeabides.net/talkLock/talkLock.jad and install talkLock . 戏耍与它。 Tease with it. 如果您想要尝试一些发展,安装与流动性组装的Netbeans从在计算机上的http://www.netbeans.org。 If you'd like to try some of the development, installation and assembly of Netbeans mobility on the computer from http://www.netbeans.org. 有在的一个讲解开始的流动性项目Netbeans站点。 Explain in the beginning of a mobility project Netbeans site. 您必须命名它" talkLock" ,因为Java对项目名字、程序名、文件名字和事关心。 You must rename it "talkLock", because the Java project name, program name, file name and a matter of concern. 然后下载talkLock.png和talkLock.java从土拨鼠归档,并且复制他们入您NetBeansProjects/talkLock/src目录。 And then download talkLock.java from the woodchuck talkLock.png and archiving, and copy them into your NetBeansProjects / talkLock / src directory. 景气! 您是准备开始编辑talkLock原始代码,做修造,和测试在仿真器。 Boom! You are ready to begin editing talkLock the original code, so built, and tested in the simulator. 您能从也得到一切Sourceforge在tarball的下载区域,但是最新的材料打开土拨鼠。 You can also get all the Sourceforge download the tarball region, but the latest material to open woodchuck.

有没有任何更好的指示? Is there any better instructions?

抱歉,不。 Sorry, no. 在我考虑文字文献时候,我考虑事实talkLock没有基本的功能,并且做有些编制程序。 I consider the text in the literature, I consider the fact that there is no basic talkLock function, and do some programming. 一旦我有1.0,我将尝试充实docco. Once I have a 1.0, I will try to enrich docco.

好弄乱在我的电话的这件事的Im。 Well were in a complete mess in my phone this matter Im. 它是否做任何? Does it do anything?

talkLock是真实地前阿尔法,因此您也许必须尝试某些选择和看发生了什么。 talkLock is true to the former Alpha, so you may need to try some options and see what happened. 这尝试的有些事在这常见问题解答之时文字: 如果您选择" 记录test" 您的电话应该记录一些音频和玩它后面。 This attempt of some things in this FAQ when the text: If you choose to "record test" your phone to record some audio and play it back. 哪修造您尝试和cpu的速度在您的电话的也许变化它录音的长度,通常少于10 秒钟。 Which build you try and cpu speed in your phone may change the length of its recording, usually less than 10 seconds. 如果这运作,则talkLock在您大概将运作当它击中版本1.0,打电话。 If this operation, then you probably will talkLock operation when it hit version 1.0, call. 如果那运作,尝试" 测试whatever"。 If that operation to try to "test whatever". 那将送您刚刚听说对土拨鼠的音频服务器。 That would give you just heard on the audio server woodchuck. 当那做时,尝试" 得到audio" 和您的电话应该下载从土拨鼠的音频,并且玩它。 When it so, try to "get audio" and your phone should download the audio from the woodchuck, and play it. 在之时写,这不运作。 At the time of writing, this does not operate. 音频得到fubared 当它得到http被张贴对服务器。 Fubared audio to be received when it was posted on the http server. **更新10/10/08 **这是没有长期配齐, " 得到audio" 现在工作。 ** Update ** 10/10/08 This is no long-term fully, "get audio" work now. **更新11/05/08 **无这再是真实的。 ** Update ** 11/05/08 without this no longer be true. 检查发行说明在下载区域在Sourceforge射出页,或者我的博客,更新的。 Check the release notes in the region in the Sourceforge download page injection, or my blog, updated.

Hmm,我跑了talkLock,并且我的电话不再现在做声音。 Hmm, I ran talkLock, and now my phone is no longer doing the voice. WTF ? WTF? ! !

呀,这发生。 Yes, this happened. talkLock实验室引起了很多鸭脚板婴孩。 Laboratory talkLock attracted a lot of baby duck feet. 这实际上归结于在不同的电话的儿童车MMAPI 2.0实施。 This is actually attributed to the telephone in different cars children MMAPI 2.0 implementation. 尝试温暖的孕穗或冷的孕穗您的电话或者带电池出去和放回它和运行一个不同的节目除talkLock之外确定音频是愉快的在您的电话。 Try booting warm or cold booting your phone or with the battery out and back into it and running a different program in addition to determine the audio is beyond talkLock happy in your phone. 欢迎到未来的世界。 Welcome to the future world.

我跑了talkLock,并且现在我的女儿怀孕,并且金钱是缺掉的在我的内衣抽屉外面。 I ran talkLock, and my daughter is now pregnant, and the money was missing in my underwear drawer outside.

*耸肩*. * Shrug *.

您测试什么电话talkLock ? What you test telephone talkLock?

主要黑莓珍珠9130。 The main BlackBerry Pearl 9130. 我们有时尝试它在LG CU-500,有在做它工作的音频处理的代码的有些文丐在两个,但是那大概将需要很多工作在许多其他电话运作… Sometimes we try it in the LG CU-500, so it works in the audio processing code, some of the text beggar in two, but that probably will need a lot of work to operate in many other phone ...

什么是当前状态? What is the current status?

观看在Sourceforge页的新闻区域,或者我的博客或者给我发电子邮件。 Views Sourceforge page news in the region, or my blog or send an e-mail to me.

我在我的个人计算机编写了talkLock。 I am in my personal computer to prepare a talkLock. 我现在做什么? I now do?

投入在网络服务器的talkLock.jad和talkLock.jar文件,和指向在您的电话的浏览器.jad文件,并且它将安装,如果您有J2ME,否则流动Java,电话。 Investment in the network server talkLock.jad and talkLock.jar documents, and the point in your phone's browser. Jad files and install it, if you have J2ME, otherwise the flow of Java, Tel. 如果您不安排一台网络服务器得到ahold我,并且不适在您的土拨鼠上把它放。 If you do not arrange a network server, I get ahold, and does not apply in your woodchuck on its release. 或者提供您帐目:) Or provide your accounts:)

我跑talkLock在阳光下或Netbeans仿真器或者MPowerPlayer仿真器。 I ran talkLock in the sun or Netbeans simulator or emulator MPowerPlayer. 它非常不做。 It is not.

两者都不仿真器实施了MMAPI 2.0,是流动Java的部分让您记录音频。 Neither emulator implemented MMAPI 2.0, is part of the mobile Java allows you to record audio. 仿真器不做在我的机器的网络材料。 Emulator not in my machine's network materials. 他们为GUI发展虽则是得心应手的。 GUI development even though they are handy.

因此您是否怎么然后测试? So how then you test?

编辑编码在Netbeans,然后使用" Deploy" 特点。 Edit code in Netbeans, then use the "Deploy" characteristics. 这编写修造和scps它对您的与一点击的网络服务器。 This is the preparation of its scps build and with a click on your web server. 然后我把我的电话指向在网络服务器的.jad,下载并且安装,电话重新起动、然后奔跑talkLock和尝试材料。 Then I put my phone point in the network server. Jad, download and install, phone re-start, and then try to run talkLock and materials. 它慢修造测试调试周期,但是它唯一的方式做它。 It slowly built test debug cycles, but it is the only way to do it.

您怎么心理上应付此? How do you deal with the psychological?

与变化的成功。 And changes of success. 许多饮食焦炭、咖啡和Marlboro光被消耗援助此。 Many diet coke, coffee and Marlboro Light consumed this assistance. 骑自行车或射击枪似乎也是帮助。 Riding a bike or shooting guns also seems to help. 我推荐毕业从做所有流动Java编程的精神疗法*before*. I recommend doing graduation from all mobile Java programming psychotherapy * before *.

您是否有任何人的支持结构? Do you have any support structure?

是,它必要。 Is that it is necessary. 我的女朋友总是令人鼓舞并且谈话我在下,如果必要。 My girlfriend is always encouraging and I talk the next, if necessary. 我也有一位宗师。 I also have a master. 这是什么都不知道关于流动Java代码的人,但是,能看我的代码和说, " 噢,花花公子,… " 并且它运作。 This is nothing to know more about mobile Java code, but can look at my code and said, "Oh, Playboy, ..." and its operation.

更多告诉我关于这位宗师。 Tell me more about this great master.

宗师使我动摇许多次,空的岗位问题最病。 Master makes me shaken many times, the empty posts the most disease. talkLock顺利地被张贴对我的网形式,但是岗位总是0字节。 smooth talkLock was posted on my network forms, but the job is always 0 bytes. 当我从个人计算机浏览器张贴了,它总是运作。 When I put up a personal computer browser, and it is always functioning. 因此宗师劫掠了二个岗位的嗅,并且改变了浏览器倒栽跳水。 Therefore master looting the two olfactory posts and changing the browser header. 我试验此6个星期,但是它未曾发生给我随声附和嗅到telnet加速查明故障。 I test this six weeks, but it never occurred to me smell echo telnet failure to speed up the identification. 他开始随声附和他们到telnet端起80在我的网络服务器,科学地做调节变化,直到他发现了打破岗位的倒栽跳水设置。 He began to echo them to telnet Bao 80 in my web server, scientific regulation of changes to do until he found a broken header set up positions. echod对telnet的talkLock嗅岗位与那变动,和voila, talkLock张贴了Base64编码音频数据对网络服务器。 echod of the talkLock olfactory telnet positions with the changes, and voila, talkLock posted Base64 encoded audio data on the network server.

声音技术。 Sound technology. 因此,当我跑talkLock时,和选择" 显示录音size" 选择,我得到说的屏幕, " 有一例外… " 和在中部它显示录音的字节大小。 So when I run when talkLock, and selecting "Show recording size" options, I get that screen, "with one exception ..." and it shows in the central recording of byte size.

它是不真正地例外。 It is not really an exception. 在流动Java,它容易投入某事在屏幕几秒钟通过使用戒备()。 In mobile Java, it is easy to put something on the screen a few seconds through the use of alert (). 我写戒备()给我调试信息,当代码击中了例外。 I write alert () debugging information to me, when the code hit the exception. 我发现很得心应手我做了它一个方法,以便I 能倾销某事到屏幕真正快使用ExceptionAlert (" 我想要对print"的文本;) 电话。 I found very handy, I do it one way, so I can be dumping something into the use of screen real fast ExceptionAlert ( "I'd like to print" the text;) Tel. 它在它自己的螺纹甚而跑,以便" System" 叶子它在读的太久屏幕。 It has its own thread and even run in order to "System" in the time it leaves the screen for too long.

什么是" System" ? What is the "System"?

在流动Java,您的节目不是独立计画,它MIDlet。 In mobile Java, your program is not an independent program, it MIDlet. 您的节目可能只做什么它的继承作为MIDlet让它。 Your program may be just what it inherited it as a MIDlet. 因为MIDlets是,这为象处理的事件的事是整洁的几乎强迫是事件驱动和事件处理是免费。 Because MIDlets is that this is like dealing with the incident is almost forced to clean is event-driven and event handling is free. 但是您经常也被迫使移动处理器密集的工作在您的主要节目圈外面和到分开的螺纹里。 But you often are forced to make mobile processor-intensive work in your circle outside the main program and to separate thread Lane. 如果您不要做此, " System" 将痛殴在您的主循环采取许多个时间或cpu的工作。 If you do not want to do this, "System" will be severely beaten in your primary cycle to take many months of work time or cpu. 它必须和有关任务开关, IBM纸的尝试Googling在MIDlet生命周期。 And the tasks it must switch, IBM paper try Googling the MIDlet life cycle.

什么做" 摧毁Gremlins" ? What do "destroy the Gremlins"?

如果您必须使用那个选择,您将知道。 If you must use that option, you will know. 对于BBEdit用户,它不做什么您认为. For BBEdit users, it is not what you think.

在哪里圈main()? Where lap main ()?
呀, I 知道,正确? Yes, I know, right? 这和MIDlet生命周期事有关。 MIDlet life cycle of this and related matters. 如果您定义了实施可追捕的类,则做强化中央处理的奔跑()方法充塞,并且定义一个被放弃的()方法或相似,您能搬入您的大工作一条新的螺纹。 If you can hunt for the implementation of the definition of the class, you do to strengthen the central processing run () method peppered, and the definition of an abandoned () method or similar, you can move to your great work of a new thread. 这让您然后开始有一会儿的事()或某一种类主循环和您的MIDlet可能通过叫YourRunnableClass.quit杀害它()。 This gives you a moment and then began to do () or a type of the main circle and your MIDlet might YourRunnableClass.quit called the killing of it (). 它的病残,我知道。 Its invalidity, I know that. 把戏是,您的MIDlet修建实例化您的类,然后修建一条新的螺纹并且哺养您可追捕的类对它。 The trick is that you build the MIDlet instantiate your class, and then build a new thread and feed you can hunt for its class. 象什么? Like what? 象这样: 螺纹MyMainThread =新螺纹(MyRunnableClassInstantiation); 检查我的博客或来源,他们也许帮助。 Like this: Thread MyMainThread = new Thread (MyRunnableClassInstantiation); check my blog or the source, they may help. 需要我大约与MIDlets推测那一个的10个月拧紧。 MIDlets need me to speculate about with one of the 10 months of tightening.

什么做" 大红色Button" 选择? What to do "Big Red Button" choice?

不要按大红色按钮。 Not by big red button.

Chinese translation of talkLock FAQ; push to talk

Well, I decided to make the talkLock project more accessible and ethnically pretty cool. So I translated the FAQ page to Chinese. I was initially very frightened, as Babelfish butchered things completely. Luckily Google was able to do a pretty good translation. So I am content for now. If you want to play with the Chinese version it is here.

So I have decided to agree with everyone who wrote in articles over the last few years saying: "Mobile Java cannot do full-duplex encrypted voice over the data network." Yes, they are right. I know that the devices can do it, but there is not enough low-level control of audio handling in the API to do it.

So talkLock is going push to talk. I have started moving the code this way but have not made a release yet. As always the current code is on marmot.

Happy Holidays and New Year, peace on earth, good will toward men, &c &c

Friday, November 21, 2008

tinkering with the RecordControl and Player

Well I have been seeking better performance. In order to find out where the code is inefficient, I tried the Nokia SDK with it's profiling tools. But that was unsuccessful.

I had the idea of putting some timestamp code in the recording loop. But I had a problem, I wasn't sure how to get the timestamps out of my non-MIDlet class.

A penpal of mine who is a very experienced programmer and lives in Deutscheland (not far from where my car was made) gave me some very helpful tips(Hi Frank). Now I've broken out my non-MIDlet classes into separate source files and made them public. That allowed me to get my timestamp data back into the MIDlet to display.

The other problem that I had was that I was not initializing my array of longs correctly. I was using the array as a sequence of timestamps, longs that are Epoch time.

By looking at these times I was able to find a call that took over 2 seconds. I have moved that code to a place before the recording loop starts in hopes of only having to do it once. However, the RecordControl and Player API aren't responding correctly yet.

The idea is to record for about 200 or 300 ms, then hand off the data to the http POST thread, and loop on this until told to stop.

So far the performance has been great, things are working in terms of tens of milliseconds. But there is still not something right with the RecordControl/Player sequence.

I'm glad to have a couple of gurus now that I can bug when I get stuck! It's a great gift.

Monday, November 10, 2008

looking for performance

I spent some time last Friday trying to find some more performance on the audio recording section of talkLock. That didn't go well, all of my builds were broken. But I was hanging out with some buddies, so it was hard to focus. But I did realize by the end of the night that by moving some declarations out of the while(){} in my Class's run(), I should be able to save quite a bit of memory allocation time when it's time to record. I might have to learn more about Player()s. If I could get the audio recording to drop out between chunks for 100ms-200ms, I would be very happy I think. I realize that that might be really bad, but I'll figure that out when I get there.

I also learned that Knudsen is still really smart. His book says that my trick with "implements Runnable" can be used in your MIDlet. So your MIDlet can have a run() method, and you can do a Thread(this). That is so freakin sick that I love it, and yet it is very perverse. Even more perverse is that it took me like 10 months to discover the Runnable trick, and the whole time it's been in the Knudsen book on my desk in the Man Room.

I took a basic handgun/concealed carry certification over the weekend, and am in the Cisco Certified Network Asskisser class all week this week. I am not very thrilled with my instructor for the CCNA, I think that when I pass the test this time, it will be in spite of that guy. But the shooting and handgun instruction was great. I shot the S&W M&P 9mm very well, I was even asked if I was in military or law enforcement.

I really shouldn't hack any this week with the class going on, but for my sanity I think I probably will at some point.

BTW, talkLock has been ranked as high as 2477th or so on Sourceforge! Anywhere from 1 to 9 downloads a day during the last month or so. The demand for this technology is there. When I hit 1.0 I think that even I will be surprised at the response.

Monday, October 27, 2008

talking and listening

Dear Diary,
Today it finally happened :) Kinda.

So as of last Friday night's hacking, if you choose "test recording", talkLock will record audio and post it (in short chunks) over and over until you choose "Big Red Button". If you choose "get audio", it will get audio from the server and play it over and over until you choose "Big Red Button".

But I was the only one with a java phone to test it!

So I wrote a little shell script on my Mac using a copy of ffplay that I compiled with amr-nb support. I used to curl to fetch audio from the server and feed it to ffplay. Unfortunately ffplay doesn't exit when it finishes playing a sound, so I backgrounded ffplay. This kind of fork-bombed my Mac :o So I had to make my script look for pids for ffplay processes and kill them after playing. This was slow and insane, but I was able to talk into my phone after choosing "test recording", and start my script on the Mac, and see the ffplay visualization of what I said, as well as hear it :) It was choppy, or should I say there were dropouts in the audio of up around a second. But it was doing the thing!

Muahahahahahaha!!!

The horrible and ugly thing I finally figured out from some professor's website, was a trick using a new class that implements Runnable. So I declared a quit() method, and a run() method that did the whole record and POST thing. Then in my main midlet code, I instantiated my Runnable as puttit. The trick is that you pass your Runnable as an argument to a new thread, like "Thread putting = new Thread(puttit);". Then I could call putting.start() to record and POST, and puttit.quit() to make the run() method stop. Whew.

So I didn't have to do anything with mutexes or synchronized or wait or notify. I'm glad of that, especially after reading Roedy Green say to avoid that paradigm.

The most fun though, was saying in a long drawn out monotone, "feeeeeeeddddbbaaaaaacccckkkk" into the phone, which was very close to the Mac. This of course caused a feedback loop as the Mac sound output went back into the phone again, getting more and more distorted and tinny and strange with every iteration :) Wonderful, great fun!

So the performance isn't all there yet, and the code is probably very inefficient, and using "Big Red Button" stops the presses, but the program is unstable afterwards... More hackin'.

Monday, October 20, 2008

more research, synchronized wait and notify

Well, I thought that I understood how to write MIDlets, until I started putting together the pieces of talkLock. Turns out that I have more research to do.

The problem is that in a Mobile Java program, or MIDlet, you don't really have a main(). You get a startApp() method, but it really only gets run once. And your constructor, which in talkLock is named talkLock() (and in a MIDlet called Test it would have to be named test()), of course only gets run to start up your program. So the only part of the code that can get run over and over again, and do things that you would normally do in your main(), are the Commands. But Commands require user input on their menu button or keyboard or touchscreen. So what do you do with code that does something that uses a lot of cpu time, like recording audio and http POSTing it to a server?

The answer is you put that code in a separate thread. But how do you tell that thread to do it's job over and over again, if a condition is met? How do you tell it when it's time to do it's work again? It looks like this is handled by synchronize, wait, notify.

The sample code and articles I have been reading on synchronize, wait, and notify explain how to do this in a MIDlet. But what does it mean to synchronize? What does notify really do? These are java-isms.

So I am having to learn another new paradigm, this synchronize, wait, notify architecture. It's pretty limited really, I will have to write some test code to really analyze the behavior.

Here is what I understand so far: That objects are synchronized. The "synchronized" keyword means that any objects in my code that define as "synchronized" share a spinlock or mutex. Or in MVC terminology (another paradigm that I am learning to apply to this MIDlet model), these objects are Monitored.

So these objects share a spinlock. In the code for these objects, I have them check the state of some global or globals. If they are supposed to be doing something, as defined in this global or globals, then they call wait(). This tells them that they need to hear from the other objects that they share a spinlock with that it is time for them to try to grab the lock and do their work. After the wait() call, they need to check globals again, and do their work.

So if these objects are in separate threads, they can just hang out in memory, and wait for their globals to be set appropriately, and then run off and do some cpu-intensive job. The same behavior as if they were in a main(), but split off into separate threads, and using the synchronized, wait, notify concept.

How do they know it's time for them to do their work? When a notify() is sent (if you have more than two objects on the spinlock, you notifyAll()), then the synchronized objects check their globals. So if you carefully sequence events so that only in certain situations will the objects be triggered to run, then whenever a notifyAll() happens, you know what state the code will be in, and what event will be triggered, by assigning a new value to a global before you notifyAll().

By working this way you can force your code to act like it would in a normal program with a main(). I guess the idea is that your MIDlet will always be responsive to user input, and your mutexed objects will run in separate threads to make sure that main program loop (really just the system listening for user input) will always be available.

At least that's the picture I've painted for myself so far. I think I need some time to absorb these concepts, and maybe depress a little before I write my first test code. I can see a lot of frustrating debugging to get this model right. It's very difficult for me to move away from the 1980s batch programming mindset. As you might have noticed, I still look at this event-driven model from a mindset where I'm trying to make it act like a batch program with a big state machine in it. Old dogs are slow to learn new tricks, if they do.

I can understand why this model of programming is popular, you get a lot of your gui handling stuff for free this way. But I don't think that every problem is best solved with a MVC model.

Actually I think that this will let me come up with a completely new design for talkLock architecturally. Maybe I'll just put all of my code into one synchronized object that runs in a separate thread, and that code will be a big state machine :) It will be my main(), and will just be operated on by the CommandListener setting certain globals and pinging with notify(). Then I can learn this new paradigm and use it without really changing the way I write that much :)

I'll do more research, and read some source code: maybe that's really how people use it anyway :)

Monday, October 13, 2008

mobile java, threads and globals, example source code

So, I started with a clean project in Netbeans, talkLock_beta. The idea is that now that most of my R&D work is done, I should try to design talkLock rather than just hack stuff together.

I have done so, and made a midlet that does a simple test. I increment an integer variable in a thread, a global integer variable for my midlet. The midlet knows that the integer was incremented in the thread. So I don't have to do any crazy message passing things with threads, just use globals. Yay!

I could clean up the code and call it threadsandglobals or something, but for now, here it is.

// includes
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.lcdui.List.*;
import javax.microedition.media.*;
import javax.microedition.media.control.*;
import java.io.*;
import javax.microedition.rms.*;
import javax.microedition.rms.RecordEnumeration.*;
import javax.microedition.io.*;

// our midlet
public class talkLock_beta extends MIDlet implements CommandListener {

// Commands
private Command runthreads;
private Command getvalues;
private Command resetvalues;
private Command exit;

//Forms
Form screenForm;

// Strings

// Ints
int getchunknum;
int postchunknum;

// Displays
Display thescreen;

// our void main
public talkLock_beta(){
// construct our main screen, a Form
screenForm = new Form("talkLock");

// construct our Commands for the CommandListener
exit = new Command("exit", Command.EXIT, 1);
runthreads = new Command("run threads", Command.SCREEN, 0);
getvalues = new Command("get values", Command.SCREEN, 0);
resetvalues = new Command("reset values", Command.SCREEN, 0);

// add our Commands to the Form
screenForm.addCommand(exit);
screenForm.addCommand(runthreads);
screenForm.addCommand(getvalues);
screenForm.addCommand(resetvalues);

// ping the user
screenForm.append("midlet is alive");

// initialize our counters
postchunknum = 1;
getchunknum = 1;

} // end of our void main

// our runthreads method
public void runthreads(){

// the GET thread
Thread getthread = new Thread(){
public void run(){
++getchunknum;
} // end of run
}; // end of getthread

// the POST thread
Thread postthread = new Thread(){
public void run(){
++postchunknum;
} // end of run
}; // end of getthread

// see how they run
postthread.start();
getthread.start();

} // end of runthreads method

// midlet lifecycle destroyApp method
public void destroyApp (boolean unconditional) { }
// midlet lifecycle pauseApp method
public void pauseApp() { }
// midlet lifecycle startApp method
public void startApp() {
// initialize our Display
thescreen = Display.getDisplay(this);
// set our Form as the current Display
thescreen.setCurrent(screenForm);
// flag the CommandListener to listen to our Display object
screenForm.setCommandListener(this);
}
// we have to define our methods for the CommandListener to call
public void commandAction (Command c, Displayable s) {

// our exit command
if(c == exit){
destroyApp(false); notifyDestroyed();
} // end of exit

// our runthreads command
else if (c == runthreads){
runthreads();
} // end of runthreads

// our getvalues command
else if (c == getvalues){
screenForm.append("" + getchunknum);
screenForm.append("" + postchunknum);
} // end of getvalues

// our resetvalues command
else if (c == resetvalues){
getchunknum = 0;
postchunknum = 0;
} // end of resetvalues

} // end of commandAction

} // end of midlet

Wednesday, October 8, 2008

RecordStore works

Well, I figured out the problem with retrieving records from RecordStore. Whatever call I was using to get the byte[] of data was totally wrong. I must have read the wrong API doc or something.

Once I figured that out, I realized that the myrecordstore.getRecord() method returns your data, which I was throwing away. I assigned a variable to collect the data to each call. That helps :)

Then I was returning a StringBuffer from my getrecords() method that did not contain the data from my records, but a reference hash to the object containing my data. I found out that with String, if you run a constructor feeding your byte[] data to it, it will dereference it for you. Like: String stufffromrecordstore = new String(bytearrayreferencefromgetrecord). The "new String()" part runs the constructor and does the dereference magic. Cool huh?

So now in the emulator I get a nice Alert() that prints the stuff from the RecordStore. Yay!

Now how am I going to make all this work together? Hmm... The challenge is to design thigns and *not* prematurely optimize.

Monday, October 6, 2008

pre-alpha_006 - we have gathered most of the pieces

So we have most of the pieces to make talkLock work now. On Blackberry, we can record audio, POST it to the webserver, which then fixes the audio data and base64 decodes it. For some reason the audio data (base64 encoded) loses "+" signs, they are replaced with spaces. Not sure if Apache or PHP does this. But anyway, talk.php (the webserver script side) fixes that. I can then GET the audio and it plays back :)

This is a BIG deal. This means that on Blackberry, I have everything I need to do communication.

I have fixed the code that allowed the audio handling to work on the LG CU500, which I found out is a Qualcomm based phone. However, the Blackberry cannot play audio from the LG, and the LG cannot play audio from the LG.

I think that to troubleshoot this I will take audio from the Blackberry, and audio from the LG, and feed them to ffmpeg to see what the difference is. I hate to make talkLock depend on ffmpeg compiled with amrnb support. That would make things a lot more complicated for folks to install the server side talkLock component. It makes me want to look at perhaps a different programming language for the server side. If Java knows about amrnb for example, then I could just use Java. We'll see.

Also ffmpeg doesn't have a lot of options to convert from amrnb to wav and back, but it has very good ogg support. So I might have to convert from amrnb to ogg to wav, and make all audio that is fetched from the server wav. That is a big hammer for a small nail though.

But we have all of the pieces! Time to hack up a demo option to do two-way communication on Blackberry ;)

Friday, September 26, 2008

constructor issues with http connection

Two posts ago I was talking about how I had to generate the content-length info before I opened the http connection in talkLock.  Actually, the issue was subtler than that, but does make sense :)

Before you feed your OutputStream to your connection object as an argument, you need to set all of your http header information (like content-length, content-type, &c).  This is because passing the stream to the object calls a constructor to run, and build your connection, including the headers.  Trying to assign values after the constructor runs doesn't do anything for the connection that has already been started.

To my surprise the Knudsen book didn't say anything about this!  I wonder if Jonathan knows but never got around to mentioning it in the book.  That's probably the case, he's really freaking smart.

Anyway, turns out that the last release of talkLock does POST, but the data that gets POSTed is zero bytes.  Haven't fixed that yet, and frankly, I'm scratching my noggin on this one.  My tcpdumps on the web server show the data, but it never makes it to http land.  Hruhh?  Dunno.

Also the copy of talk.php that I put on Sourceforge in the last release (talk.php is the server side script) is broken.  It doesn't work at all :(  It's probably safe to get everything from marmot.

Thursday, September 4, 2008

base64 ascii armor and http POST works :)

Well, about a month ago I posted about starting to look at how the network part of talkLock would work. It isn't all finalized yet, but at the moment you can post audio data to marmot from your phone.

The biggest trick was "ascii armor"-ing the audio data, base64 encoding. Trying to send the raw audio data blew things up, because some of the characters in the audio data stream messed with things in http land. Mobile Java does not have any built-in support for base64 encoding or decoding.

First I found Roedy Green's excellent Base64 implementation, which was beautifully written and commented. I jammed it into talkLock and it built straight away. On reading Roedy's software license though, I couldn't decide if it was GPL-friendly or not. It was interesting to think about though, Roedy's software is free for non-military use. I think that that is great. However, part of the risk of the GPL is that software can be used by anyone for anything, as long as sources are provided. A conundrum.

So then I found Stephen Ostermiller's GPL Java Base64 implementation. Once I figured out how his library worked, I was able to incorporate it into talkLock, and it built. So now I had Base64 encoding and it was all GPL. Hooray!

After some testing, and getting stuff back from the encoding routine that looked like normal ASCII gibberish, I went about doing an http POST with the data. I tried setting the Content-Type to "multipart/form-data". But my php script on the web server never acknowledged it as a POST. I started sniffing on marmot and I could see the data come in, but apache never acknowledged a POST. Even though my MIDP code set the Content-Type, in my sniffs I could see that it was being ignored, either by the OS on my phone, or maybe even by Verizon's Squid servers. I tried adding the http header code before the content in the http stream, but Hartley grinned at my naivete, and explained that the headers were built in Java land, and I could not gin up my own fake ones.

Much testing and frustration, and help from my buddy Hartley. We switched to Content-Type text/plain. Added a submit button and tested with Camino on the Mac, which POSTed fine, but no joy from talkLock. Called it a night.

Finally I forced the client code to calculate the length of the data, and did a setConnectionRequest("Content-Length", Integer.toString(dataLength)). Then I pushed all writing to the connection to happen after setting the Content-Length, to avoid the obviously broken automatic Content-Length calculation stuff in Blackberry MIDP-land.

It freaking POSTs Base64-encoded audio data to marmot now :) And there was much rejoicing. Next is getting the audio back and making it play.

I will push out the build and sources, and source for the server side, to SourceForge today.

Wednesday, July 30, 2008

new milestones

Well I pushed a new build of talkLock out to Sourceforge. There are some new event-driven things happening, but mainly I successfully got talkLock to cope with the fact that different phones sometimes use different audio encodings.

It is ugly and hacky, but by using Manager.getCapabilities, I was able to tell whether talkLock was running on a blackberry or an LG CU500. The blackberry just does straight up wav audio, while the LG does amr. With this code audio recording and playback works on the LG as well as the Blackberry :)

This is cool, since in order to have conversations between phones with different encodings, the program will have to know what type of audio it is playing back. I really hope the LG will be able to play back wav that was recorded on the Blackberry. I think that playback is much more mature than recording in MIDP, so I am optimistic.

Now I am starting to work on the networking code. I won't really comment much on it, but after being mocked for a couple of days by Tomcat and trying to do things the servlet way, I have decided not to inflict that on others by writing the talkLockServer component in Java. Instead, I already have a little experience working with HTML forms using PHP, so talkLockServer will have a .php suffix.

Also I think that I will use some kind of database, maybe MySQL, to store and retrieve the hunks of audio data. Since it does some smart caching, I don't think the audio will actually get flushed to disk very often. If everything happens in RAM, it should be pretty quick.

I hope to finish "processing" and mulling soon and get some more code written.

Thursday, July 10, 2008

slow on the uptake

Well, I've been fighting with talkLock, trying to figure out why my records get created in the RecordStore, but they are empty when I read them.

Then I remembered that the "Submit Form" command on the Setup page is what triggers writing the values to the Record Store. Aha.

So I fought with that for a while, trying to get the main program thread to wait for the Command Listener thread so that values are not read before they have a chance to get written by hitting the "Submit Form" command.

Finally I started reading about using threads to handle asynchronous things in MIDlets. It dawned on me that I am trying to do batch programming here. I started programming in the 80's when you had to do all of your event handling yourself.

Light bulb appears over my head.

In MIDlet land, event handling happens for free. But unless you do a lot of thread handling stuff, you are chained to using their event driven model. That is why all of the MIDlets that I have read code for have a basically empty main method. You let the Command Listener fire off events.

My problem was that I wanted to get things going without a Command event. I might look into that eventually, but for now, I am going to let the user kick things off by hitting the "Connect" command :)

Yay! I learnt something. It happens, but it sometimes takes a while. Maybe now I am prepared for an exciting career in javascript or gui programming of somekind.

Wednesday, July 9, 2008

bringing up the ui; using persistent storage; &c

Last evening was cool and rainy. I started the program "from the beginning", in other words, the end user experience that will be the release version of talkLock. So at start time there is the logo, and your server name, user name, and password are fetched from persistent storage, the "RecordStore". If they are not there, I wrote talkLockSetup(). talkLockSetup will give you a form (Form) with TextFields to edit your server name, username, password, and submit the form. On submission, the CommandListener will blow away any existing persistent records, and add your new settings. It's starting to feel like it does stuff and is a real program :)

I did have quite a bit of trouble with the damn RecordStore. It only takes one datatype (byte array), and though it claims to read and write to it, my byte arrays that I get from it are empty. I was assuming that the record IDs for a store that has 3 records would be 1, 2, and 3. That was probably not a good assumption to make. But we'll get there.

Once I get this RecordStore API down, I think it will be time for networking :)