在 Android/iOS 中使用 Adob​​e AIR 播放 AAC 流

Posted

技术标签:

【中文标题】在 Android/iOS 中使用 Adob​​e AIR 播放 AAC 流【英文标题】:Playing AAC streams with Adobe AIR in Android/iOS 【发布时间】:2014-11-08 08:19:05 【问题描述】:

看起来这是一个很常见的问题,但我仍然看不到任何解决方案。

目标是在 Adob​​e AIR 移动应用程序中播放一些 AAC 流。

我使用了来自https://code.google.com/p/project-thunder-snow/ 的转码器。一个将 FLV 标头添加到 AAC 数据中,因此可以通过标准的 AS3 NetStream 对象(据我了解)播放流。它适用于 Win 和 Mac,但在 androidios 上启动的同一个应用程序既不会产生声音,也不会产生任何错误。我发现转码器工作正常,原因是不同的 NetStreams 的特点。

那么,是否有任何解决方案,或者至少有描述 PC 和移动平台上的 NetStreams 之间差异的文档?

【问题讨论】:

您好,请问您能回答这个问题吗? ***.com/questions/25819826/…。如果你能给他们提供他们显示的网址的快速示例以及如何/在哪里使用 Thunder-Snow。 FLV 在 iOS 上不受支持。在 Android 上,您可以播放存储卡中保存的 FLV 文件,但我不知道流媒体。因此,当您在移动设备上获取此 AAC 数据时,您不应使用 FLV 包装,而是使用 [Native Extensions] 缓冲并发送到另一个本机应用程序(即:内置 OS 解码器?),另请参阅 [Google results]。只需要考虑一件事,但我自己没有尝试过。 看起来有些人能够以某种方式在 Android 上玩它 - ***.com/questions/20714135/…。我们已经尝试为 Android 构建合适的原生扩展,但是使用可用的 C/Java 解决方案很难制作 ANE。((( 不幸的是,我不知道如何向***.com/users/1282424/rolf-kaiser询问他在Android上的做法。((( 感谢您回答其他链接。不是我的问题只是我也有联系然后找到你并希望你能帮助他。既然@Rolf-Kaiser 已链接,他可能会在这里注意到并提出建议,也许?无论如何,我可能会为您提供解决方案.. 【参考方案1】:

好吧...我可能对你有一个线索。我尝试从 Flash CS5 内部运行您在 other question 上发布的 NBAAC 代码链接并收到此错误:

onChannelReady : MetaData Error: Error #2067: The ExternalInterface is not available in this container. ExternalInterface requires Internet Explorer ActiveX, Firefox, Mozilla 1.7.5 and greater, or other browsers that support NPRuntime.

因此,播放器似乎设计为仅在 html 页面内使用并使用 ExternalInterface (javascript) 将元数据从浏览器获取到 SWF

我删除了 ExternalInterface 的东西,它在没有浏览器/HTML 的 Flash Player 和 Device Central 中可以正常播放。在您的 AIR 应用程序中尝试此代码(我没有再安装 AIR 来确认..)

package

        import com.thebitstream.flv.CodecFactory;
        import com.thebitstream.flv.Transcoder;
        import com.thebitstream.flv.codec.*;
        import com.thebitstream.ice.*;
        import com.thebitstream.nsv.*;

        import flash.display.Sprite;
        import flash.events.Event;
        import flash.events.IOErrorEvent;
        import flash.events.ProgressEvent;
        import flash.events.SecurityErrorEvent;
        //import flash.external.externalInterface;
        import flash.media.SoundTransform;
        import flash.net.NetConnection;
        import flash.net.NetStream;
        import flash.net.NetStreamAppendBytesAction;
        import flash.net.URLRequest;
        import flash.net.URLRequestMethod;
        import flash.net.URLStream;
        import flash.utils.ByteArray;
        import flash.utils.setTimeout;

        [SWF (,)]

        public dynamic class NBAAC_AIR_v2 extends Sprite
        
            public var request:URLRequest;
            public var transcoder :Transcoder
            public var transport :NetConnection;
            public var transportStream :NetStream;
            public var serverConnection:URLStream;

            //public var host:String=" "; //now not used in line... request=new URLRequest(resource);
            public var resource:String="http://aacplus-ac-64.timlradio.co.uk/;"; //test station

            public function NBAAC_AIR_v2 ()
            
                super();

                /*
                if(loaderInfo.parameters.host)
                        host=loaderInfo.parameters.host;
                if(loaderInfo.parameters.resource)
                        resource=loaderInfo.parameters.resource;
                 */       

                //CodecFactory.ImportCodec(MetaData);

                CodecFactory.ImportCodec(AAC);
                CodecFactory.ImportCodec(AACP);         

                transcoder = new Transcoder();
                transcoder.addEventListener(CodecEvent.STREAM_READY,onChannelReady);
                transcoder.addEventListener(StreamDataEvent.DATA, onTag);
                transcoder.initiate();

                transcoder.loadCodec("AAC");

                transport = new NetConnection();
                transport.connect(null);

                flash.utils.setTimeout(boot,500);
            

            public function boot():void
            
                //externalInterface.addCallback('nbaac.setVolume', onVolume);
                //externalInterface.addCallback('nbaac.togglePause', onTogglePause);
                //externalInterface.addCallback('nbaac.setBuffer', setBufferLength);
                //externalInterface.addCallback('nbaac.getBuffer', getBufferLength);
                //externalInterface.addCallback('nbaac.getTime', getTime);

                /*
                var meta:Object=;
                meta.uri="";
                meta.StreamTitle=""; 
                */

                //externalInterface.call('logit','start up');

                transportStream = new NetStream(transport);
                transportStream.bufferTime=2;
                transportStream.client = this;
                transportStream.soundTransform=new SoundTransform(.5,0);
                transportStream.play(null);                             
                transportStream.appendBytesAction(NetStreamAppendBytesAction.RESET_BEGIN);

                var headerTag:ByteArray=transcoder.createHeader(false,true);
                transportStream.appendBytes(headerTag);                         
                headerTag.clear();

                //transcoder.readMetaObject(meta,0);

                serverConnection=new URLStream();
                serverConnection.addEventListener(ProgressEvent.PROGRESS,loaded);
                serverConnection.addEventListener(IOErrorEvent.IO_ERROR, onIo);                                 
                serverConnection.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onNoPolicy);
                serverConnection.addEventListener(Event.CLOSE, onClose);

                request=new URLRequest(resource); //removed "host" from url

                //request.requestHeaders=[new URLRequestHeader("GET",resource+" HTTP/1.0")];
                //request.requestHeaders=[new URLRequestHeader("Icy-MetaData","1")];

                request.method=URLRequestMethod.GET;
                serverConnection.load(request);
            

            private function getTime() :Number
               return transportStream.time;  

            private function getBufferLength() :Number
              return transportStream.bufferLength; 

            private function setBufferLength (val:Number) :void
               transportStream.bufferTime = val;  

            private function onTogglePause():void
               transportStream.togglePause(); 

            private function onVolume (val:Number) :void
               transportStream.soundTransform = new SoundTransform(val, 0); 

            private function onIo(pe:IOErrorEvent) :void
              /* externalInterface.call('logit','IOErrorEvent') */  

            private function onTag(sde:StreamDataEvent) :void
            
                    sde.tag.position=0;
                    transportStream.appendBytes(sde.tag);
            

            private function onChannelReady(ce:CodecEvent) :void
              trace('onChannelReady :',ce.codec.type); 

            private function onClose(e:Event):void
               /* externalInterface.call('logit','onClose') */ 

            public function onMetaData(e:Object):void
              /* externalInterface.call('logit','onMetaData') */ 

            private function loaded(e:ProgressEvent):void
                                   
                var chunk:ByteArray=new ByteArray();

                while(serverConnection.bytesAvailable)
                   chunk.writeByte( serverConnection.readByte() ); 

                chunk.position=0;   
                transcoder.addRawData( chunk, 0, "AAC" );                                                        
            

            private function onNoPolicy(se:SecurityErrorEvent):void
             /* externalInterface.call('logit','SecurityErrorEvent'+host+resource+'<br />'+se.text); */ 

    


【讨论】:

嗯...关于示例的基本版本,您绝对正确,它针对 HTML 或任何其他实现外部接口的应用程序容器。您的更新版本似乎只是删除了对容器的调用。在独立播放器中启动应用很有用,但在移动平台上无济于事。( 我们需要 Kaiser 在这个..??你的测试链接是什么?我注意到一些流在 Chrome 中不起作用,但在 I.Explorer 和 Firefox 中是可以的,即使使用这个更新的代码。是否对 Shoutcast 或 Icecast 系统感到挑剔?也可以尝试不使用 ...;.../;的网址,因为这是 Flash 中与浏览器相关的技巧 String="http://aacplus-ac-64.timlradio.co.uk/;"; 变为 String="http://aacplus-ac-64.timlradio.co.uk"; 但无论如何我发现我的链接可能不像非英国连接.. 是的,Kiser 肯定想介绍一下他的转码算法。我的测试链接是listen.classicrocklounge.com:8000/aac64。 在 Device Central 调试器中,我现在注意到 D.C 设置是“嵌入在 HTML 中的”,因此它只能在 HTML 文件 (FP 10.3?) 内的移动设备上运行。无论如何,这条线索的唯一解决方案是尝试在您的 AIR 应用程序中嵌入 HTML 和 SWF。这个想法是让您的 AIR 应用程序成为浏览器。我自己无法尝试,所以请告诉我:看看这个 [Embed SWF+HTML in AIR] 还有这个 [HTML-based AIR App]。

以上是关于在 Android/iOS 中使用 Adob​​e AIR 播放 AAC 流的主要内容,如果未能解决你的问题,请参考以下文章

在 Adob​​e AxAcroPDFLib 中启用注释

在 Adob​​e Phonegap Build 中,Deviceready 未触发

使用 Adob​​e AIR 在 iOS 上保存位图

如何在 Adob​​e Animate CC 中使用舞台宽度和高度(Canvas doc)

在 Adob​​e Flex/AIR 中使用 HTTPService 对象进行 HTTP 基本身份验证

Android SDK 到 Adob​​e Air