| 郑昀 @ultrapower 
 
 | 产品名称 
 
 | 产品版本 
 
 | 
| Keyword: JavaME Streaming Audio MMAPI 
 
 | StreamingDemo 
 
 | 1.0.13 
 
 | 
[J2ME]现行环境下 手机
实现网络媒体的流畅实时播放
之简单演示
(StreamingDemo)
说明
我的资源:
http://www.cnblogs.com/Files/zhengyun_ustc/StreamingDemo-src-1.0.13.rar
这个 1.0.13 版本是 j2me 流媒体播放思路的简单演示软件,并不是对现有的RTSP/MMS流媒体服务器的客户端实现,而是自定义算法下载来保证实时播放,可以在 Nokia 7610 手机上真实运行。在手机上使用,请在选择连接点时选择“移动梦网”连接点。
如果修改源代码中 CommandResources.java 中的 m_bCMWAPProxy 标志使之走 CMNET 通道,那么能够在 Nokia S60 的模拟器上运行。
本源代码的大致思路来自于我上次写的三篇讨论稿
J2me 流媒体技术实现讨论 [3] , StreamingDemo 的代码你可以借鉴,但不得用于商业用途,除非得到我的授权。
      
        手机jar安装包下载: 
        
        http://www.cnblogs.com/Files/zhengyun_ustc/StreamingDemo-deployed.rar 
        
        可以将这个包中的StreamingDemo.jar传到您的手机上进行安装。 
        
        使用时,请选择移动梦网连接点。
      
    
如果你想使用劈分好的媒体文件,请从
http://www.cnblogs.com/Files/zhengyun_ustc/changjin.split.rar 下载。
      
        1
      
      
        背景、功能
      
      
        
        
      
    
    摘要 :本章 简单描述 StreamingDemo 的背景、功能。
1.1. 手机上的流媒体
很多人都在 j2medev.com 上讨论过流媒体的实现方式。 国外有一个人提出一种思路,并且号称在 Nokia6260 [ 相关数据:诺基亚 6260 Nokia62602.0 (3.0436.0) SymbianOS7.0s Series602.1 ProfileMIDP-2.0 ConfigurationCLDC-1.0 ] 运行了。
当然我们这里说的不是对 RTSP/MMS 这种主流的流媒体服务器的客户端实现,因为现在中国市场的很多很多手机的 Java 环境都不支持这两个协议,只有新出的某些手机才内置支持这一功能。
我们这次讲的是,在现有 GPRS 环境下,在现有的一两千块钱的手机条件下,如何做到流媒体实时播放呢,而且还能做到较为流畅呢?
2006 年 1 月份,我 恰巧看到了
就此思路和诸位高手讨论了一下,并且写了三篇讨论稿,有了大致的思路。但一直都没有时间去测试这个思路是否可行。
今天索性抽出了一两个小时,把这个思路写出来放在真实手机 /GPRS 网络上测试,不敢独享,遂开放代码,希望借此抛砖引玉。
这里给出 StreamingDemo 的界面,很简单,主要的线程操作和消息处理都在后台:
1.2. 我所谓流媒体的功能
以前我们谈过:
        
          第一步:
        
        
          
        
        
          声明两个
        
        
          Player
        
        
          ,分别由两个独立的线程掌控着;
        
        
          
          
        
        
          第二步:
        
        
          
          HttpConnection
        
        
          开始向服务器请求该
        
        
          audio
        
        
          文件的第一部分字节,我们定这次读取的字节数为
        
        
          18KB
        
        
          ;
        
        
          
          
        
        
          第三步:
        
        
          
        
        
          等第一部分数据到位后,
        
        
          Player A
        
        
          开始
        
        
          realize
        
        
          和
        
        
          prefetch
        
        
          ,并开始播放;
        
        
          
          
        
        
          第四步:
        
        
          
        
        
          在
        
        
          Player A
        
        
          播放同时,
        
        
          (18KB
        
        
          的
        
        
          amr
        
        
          数据可以播放
        
        
          10
        
        
          秒钟
        
        
          )
        
        
          ,
        
        
          HttpConnection
        
        
          继续请求第二部分数据
        
        
          (
        
        
          假设
        
        
          GPRS
        
        
          每秒钟传输
        
        
          3KB
        
        
          ,那么
        
        
          18KB
        
        
          需要传输
        
        
          6
        
        
          秒,算上前后通讯损失的时间,应该不会超过
        
        
          10
        
        
          秒钟
        
        
          )
        
        
          ;
        
        
          
          
        
        
          第五步:
        
        
          
        
        
          第二部分数据到位后,假设
        
        
          Player A
        
        
          还没有播放完
        
        
          (
        
        
          这需要调整你的每一部份数据字节数来使得假设成立
        
        
          )
        
        
          ,那么将数据喂给
        
        
          Player B
        
        
          让它
        
        
          realize
        
        
          和
        
        
          prefetch
        
        
          ;
        
        
          
          
        
        
          第六步:
        
        
          
          Player A
        
        
          播放完后,得到事件通知,于是让
        
        
          Player B
        
        
          开始播放。
        
        
          
          
        
        
          如此往复。
        
        
          
          
        
        
        
      
大致的思路就是这样。
这次,我们起了两个线程,一个叫做“ Main( 主 ) ”,一个叫做“ Secondary( 从属 ) ”,他们都掌握着一个 Player ,同样一个是 Main Player ,一个是 Secondary Player 。这两个 Player 的操作实际上都被 Audio.java 类完全封装好了。线程里面仅仅是调用
Audio.prefetchSound(m_form,
m_isInputMusic,
m_Sequence);
啦,
Audio.playSound(m_Sequence);
啦,这样就可以把媒体资源预先运算以及播放了。
同时,还必须用到 PlayerListener 接口,来得到播放器的各种事件通知,我们需要得知每一个播放器的播放结束消息,以便作出下一步选择:是让从属线程开始播放呢,还是让主线程开始播放呢。
PlayerListener 的播放结束消息 ( PlayerListener.END_OF_MEDIA ) 的处理中,我们还必须用到 MVC 模式中的 Controller ,它是代码中的 GUIController.java ,它负责处理几个消息:
l EventID.EVENT_MAIN_DownloadCompleted
l EventID.EVENT_Main_BeginToPlay
l EventID.EVENT_SECONDARY_BeginToPlay
怎么综合使用这些消息和事件呢?
比如说,当主线程的媒体文件下载完毕后,就应该通知 GUIController 让从属线程也开始下载并加载媒体文件。
当主线程的媒体文件播放完毕了,这时候照理说从属线程的 Player 也已经预先加载好了下一个要播放的媒体文件 ( 如果不行的话就应该调整媒体文件的大小了以使得下载时间和播放时间差不多 ) ,就应该在
public void playerUpdate(Player player, String event, Object data)
的函数处理中,让 Secondary Player 播放了。
这次我们直接将媒体文件用讨论稿中谈及的 ffmpeg 自动切分的办法,已经辟成 11 小段的 AMR 文件了,每一个 AMR 文件都可以独立播放,连起来就是一首完整的《大长今》乐曲。
PlayerA 和 PlayerB 只是周而复始的下载、预运算、播放他们罢了。只不过掌控着 Player 的两个线程和主控制器,会选择时机来让这些操作次第展开。
上面所说的逻辑,可以用下图表示:
        
          2 使用感受
        
        
          
          
        
      
      摘要 :本章 简单描述 StreamingDemo 在真实 GPRS 环境下 的使用感受。
2.1. Nokia7610 手机上的设置
如果你真的要在手机上用到这种功能,那么请申请开通你的 GPRS 包月套餐,那样 20 块钱就可以使用 50MB 流量的 GPRS 了。
如果你的手机是 Nokia 的 S60 系列手机,建议用 Nokia 程序管理器 设置这个应用配置一个参数: 在连接网络时第一次询问 。否则你会屡屡被网络连接警告框打断的。
2.2. Nokia7610 手机上的使用感受
这种流媒体的播放,还是取决于使用时 GPRS 网络的好坏。
我在晚上 19 点使用了一下,感觉比较流畅,甚至超乎我的预期,不认真听,甚至感觉不到在哪里停顿的。
但是在晚上 20 点又用了一下,就有点拖拖拉拉的,延迟较为明显。
可见现行的 GPRS 网络环境还是容易出现拥挤的。
<shapetype id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f"><stroke joinstyle="miter"></stroke><formulas><f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f></formulas><path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect"></path><lock v:ext="edit" aspectratio="t"></lock></shapetype><shape id="_x0000_i1025" style="WIDTH: 414.75pt; HEIGHT: 438pt" type="#_x0000_t75" o:ole=""><imagedata src="file:///C:%5CDOCUME~1%5CZHENGY~1.VIC%5CLOCALS~1%5CTemp%5Cmsohtml1%5C09%5Cclip_image001.emz" o:title=""></imagedata></shape>
      
        3
      
      
        开源版权声明
      
      
        
        
      
    
    由于这个 手机流媒体简单演示 的 思路和代码来自于郑昀以前的讨论稿,今为了促进 J2ME 多媒体应用发展, 决定遵照 GPL 协议的大意开放源代码,您可以自由传播和修改,在遵照下面的约束条件的前提下:
| 条件 1 
 
 | 
| 只要你在 手机流媒体简单演示 的 每一副本上明显和恰当地出版版权声明,保持此许可证的声明和没有担保的声明完整无损,并和程序一起给每个其他的程序接受者一份许可证的副本,你就可以用任何媒体复制和发布你收到的原始的程序的源代码。你可以为转让副本的实际行动收取一定费用,但必须事先得到郑昀的同意。 
 
 | 
| 条件 2 
 
 | 
| 你可以修改 手机流媒体简单演示 程序的一个或几个副本或程序的任何部分,以此形成基于程序的作品。只要你同时满足下面的所有条件,你就可以按前面第一款的要求复制和发布这一经过修改的程序或作品。 
 
 
 
 
 a ) 
 
 你必须在修改的文件中附有明确的说明:你修改了这一文件及具体的修改日期。 
 
 
 
 
 b ) 
 
 你必须使你发布或出版的作品(它包含程序的全部或一部分,或包含由程序的全部或部分衍生的作品)允许第三方作为整体按许可证条款免费使用。 
 
 
 
 
 c ) 
 
 如果修改的程序在运行时以交互方式读取命令,你必须使它在开始进入常规的交互使用方式时打印或显示声明:包括适当的版权声明和没有担保的声明(或者你提供担保的声明);用户可以按此许可证条款重新发布程序的说明;并告诉用户如何看到这一许可证的副本。(例外的情况:如果原始程序以交互方式工作,它并不打印这样的声明,你的基于程序的作品也就不用打印声明)。 
 
 | 
这样,您就可以自由使用并传播本源代码, 当然请您原封不动地保留创建者 zhengyun_ustc( 郑昀 ) 的作者信息 。


 
         
					 
					