Why so many latencies in BB10 audio playback? Why we always get underrun in audio data feeds?

They are two faces of one same issue.

If you started coding audio playback from reading PlayWav sample in BlackBerry’s github repository, you will find there are long latencies in audio playback, that is, about 5s after you fed data, you can hear the sound. But why? BB10 uses ALSA’s libasound as its audio API but the documentation and description are very little. So after many changes here and there, many trials and inspections, I got what controlled the latency.


In PlayWav sample, this field is set to -1, which returned a large number in it from call of snd_pcm_plugin_params(). So we can set this field to a small number to reduce the latency. Indeed it is said that RIM recommends 5 but I don’t know whether it is true and I cannot remember where I found it.

Anyway, a number like 3 or 5 can exactly reduce latency to some small value so that our ears cannot find it. But another strange behavior occurs then: we got UNDERRUN frequently. At that time, if we set snd_pcm_channel_params_t.stop_mode to SND_PCM_STOP_STOP, the playing back stopped after a short time interval; if we set snd_pcm_channel_params_t.stop_mode to SND_PCM_STOP_ROLLOVER, the playback will repeats data in a few last buffers.

The latter issue is due to thread priority. QNX’s io-audio drivers runs playing back in very high priority so it is very easy to make your data UNDERRUN if you just run your data feed thread in a normal priority. In some discussion somebody recommends set data feed thread to 50 and in some other codes the value was set to 18 or so.

Conclusion: to make audio playback smoothly and easily, 1) set frag_max to 5 or another small value but too small may cause UNDERRUN issue. The field controlled data buffering – yes, it equals to audio latency on other side – in implementation of audio playbacks. 2) raise your data feed thread priority to some higher value. Normal thread runs on 10 and audio playback thread runs on a higher priority. Set to higher to avoid data UNDERRUN.


iOS7: We cannot modify UIAlertView directly now.

From iPhoneOS 1 to 6, each experienced iOS programmer knows how to modify UIAlertView for appearance customization. For example, to add some UI elements like UILabel or a secure UITextField for password input, etc. One of our little tool keyOne used this trick.

But this doesn’t work in recent iOS7 beta. The reason is simple after checking view hierarchy in debugger. This is keyWindow when a UIAlertView popped up:

(lldb) po [[UIApplication sharedApplication] keyWindow]
<_UIModalItemHostingWindow: 0xb2dba70; frame = (0 0; 320 568); gestureRecognizers = <NSArray: 0xb2d5f20>; layer = <UIWindowLayer: 0xb2dbb50>>

and a view for alert exactly

(lldb) po [[[[[UIApplication sharedApplication] keyWindow] subviews] objectAtIndex:1] subviews]
<__NSArrayM 0xc975e80>(
<UIView: 0xb2e83a0; frame = (0 0; 320 568); layer = <CALayer: 0xb2e8770>>,
<_UIModalItemRepresentationView: 0xb2e5de0; frame = (25 184; 270 200); layer = <CALayer: 0xb2e5da0>>

The UIAlertView returned to caller is a stub only

lldb) po alertView
<PasswordPrompt: 0xb2c7f80; baseClass = UIAlertView; frame = (0 0; 0 0); opaque = NO; layer = <CALayer: 0xb2a1cc0>>

The view has zero size so we certainly cannot customize it.


It is just like walking on a steel wire over the deep…

…to play with Apple’s famous Xcode and LLVM compiler sets, especially for ARM instead of x64 series.

So, somebody may ask: What beats you on the face _again_?

This time Apple decided to use clang 4.0 from LLVM 3.1svn in its latest Xcode 4.4, which was just pushed out with Mountain Lion some days ago. That’s OK. Generally most of things still work, most of codes still got compiled. But, suddenly I found an assembling error on my one .S file: invalid instruction ‘ldmltfd’. It is not the exact error message but you know the meaning is it.

The .S file can be compiled/assembled without any problem by previous Xcode version, if my memory is still correct, at least by any version of Xcode 4.x and its toolchains, from apple-gcc-4.2 to clang. And, ‘ldmltfd’ is a valid ARM instruction. So it should be another LLVM/clang’s issue. Indeed I must not feel surprising since I already encountered many before.

But I must have a work around otherwise I must return back to Xcode 4.3.x, which doesn’t have official ML support in it. Though I think it is not a big problem, the uninstall and install still take much time. OK. Let’s see.

After adding ‘-v’ to compiling option the output shows clang called itself with ‘-cc1as’ after executed preprocessing. ‘clang -cc1as –help’ shows this call invokes clang’s integrated assembler to assemble the source instead of invoking external ‘as’ program. Fortunately ‘clang’ in my Lion system is still an old version (3.1 from LLVM3.1svn) so I can check it over the source with ‘-v’ option and found it invokes external assembler.

The issue is clear now. Apple guys or LLVM guys or guys having both roles thought clang’s integrated assembler is stable and complete enough. They released this version of clang with integrated assembler set as default behavior in Xcode 4.4. I am just this unlucky man stepping on the mines.

Solution is always simple as long as clang permitted us disable its integrated assembler. Adding ‘-no-integrated-as‘ to each .S file solved the issue, but it still took me about 1 hour to look for the cause and about half an hour to write this blog.


Updated gas-preprocessor to handle clang’s issue related to -g option

clang included in Xcode 4.3.x (LLVM 3.1) has an odd issue when it is used with gas-preprocessor.

As you may know, gas-preprocessor adds “-S” to compiler’s command line to generate assembler source, does some preprocessing on it, then invokes compiler again. The compiler then invokes assembler to create final objective code. Here, compiler is clang and assembler is apple as.

If  a “-g” is specified in clang’s command line, clang will generate dwarf-2 debug information directives into assembler source. When clang gets invoked again, it will also take “-g” into apple as’s command line options. Unfortunately, as declines those debug information directives, including .file and .loc, if it is iovoked with “-g”.

So, I have to add a hack into gas-preprocessor. If -g is in command line, eliminate it in 2nd compiler invocation.

See latest commit in https://github.com/hollylee/gas-preprocessor


Update gas-preproccessor again

This update fixed issue of .if macro inside .rept or .irp through introducing 3rd pass to delay the if macro processing after others.


用 Instruments 来分析 iPhone 应用程序

注意哦, 这里说的不是你自己的应用, 那个太简单容易了, 没什么挑战, 不值得在这里写一篇 blog.

目标: 用 Instruments 来 profiling 第三方的应用, 没有源码的, 只有 binary 的.

Apple 在系统中对 Instruments 运行有一个限制: 在碰到使用 distributed certificate 做 codesign 的 app, 不予运行, 直接 kill 9.

所以, 我们需要有一个可用的 developer certificate. 然后就很简单了.

codesign -fs "iPhone Developer: Holly Lee" --resource-ruls ResourceRules.plist --entitlements Entitlements.xml AppBinary

好了之后放入 iPhone 里覆盖原来的 binary, 然后运行 Instruments 选择该 app 就行了.

当然, 默认的前提是: iPhone 需要 jailbroken 先.

Objective-C(++) 的一些细节注意点

  • 如果把 objc 类放到一个库中, 然后在主程序里并不直接引用到类本身的构造, 而是通过诸如 .xib 中命名或者类似的  serialization 方式使用这个类的话, 需要在 Linker flags 中加入 -ObjC, 否则该类不会被正确构造. 一个例子是将一个 customized view 放到 .a 中, 然后在 xib 中将一个 view 的 class 设为此 custom view, 在主程序中 load 之后, 会发现其实只产生了一个 UIView 而未产生正确的 CustomView. 解决方法就是将 -ObjC 加入到 linker flag. 如果还不行的话, 还有最后一招 -all_load. 这个 linker flag 的意思是不管三七二十一, 把所有东西都连到最后的 binary 里.
  • 作为 Objc 类的成员定义的 C++ 类, 在默认情况下, 其非默认形式的构造函数和析构函数是不会在 objc 类 init 和 dealloc 时被调用的. 要让 objc 在 init 和 dealloc 时调用作为其成员的 C++ 类的非默认构造函数以及析构函数, 必须加上这个编译器参数:  -fobjc-call-cxx-cdtors. 另外, 如果使用了 NSZombieEnabled, 无论是否有上述编译器参数, 构造和析构函数都不会被调用到.

Build android source on SnowLeopard with xcode4

1) Install 10.5 SDK from xcode 3’s dmg

2) Specify “CC=gcc-4.2 CXX=g++-4.2 CPP=cpp-4.2” before make command line to avoid an issue in default llvmgcc-4.2. Of course you can change the gcc symbolic link to what you want but I think it doesn’t make sense for this exception. llvmgcc works on most cases. I just found two exceptions till now – one is Android source, the other is ffmpeg.