Adobe flex convert ".ogg" file with Ogg Vorbis Encoder for being played with Sound class

248 Views Asked by At

I'm trying to get a ".ogg" file from an URL and play it in my Flex program.

I've make a test with ".mp3" files and it works all fine, with this code:

        public function getFileRemote(url:String, id:String):void{
            var s:Sound = new Sound();
            s.addEventListener(Event.COMPLETE, onSoundLoaded);
            var req:URLRequest = new URLRequest(url);   
            s.load(req);

        }

        private function onSoundLoaded(event:Event):void
        {
            var localSound:Sound = event.target as Sound;
            localSound.play();
        }

But, for ".ogg" format files it doesn't work. So, I've checked some possible solutions and I'm, trying to implement one with the Ogg Vorbis Encoder library.

The code as I have it right now implemented:

        public function getFileRemote(url:String, id:String):void  
        {  
            urlStream = new URLStream();
            var urlReq:URLRequest = new URLRequest(url);  
            urlStream.addEventListener(Event.COMPLETE, loaded);  
            urlStream.load (urlReq);
        }  

        private function handleSoundData(e:SampleDataEvent):void
        {//handleSoundData
            var result:Object;
            var tmpBuffer:ByteArray = new ByteArray();
            result = _oggManager.getSampleData(NUM_SAMPLES, tmpBuffer);

            if (tmpBuffer.length < NUM_SAMPLES * BYTES_PER_SAMPLE)
            {//reset
                trace("Reset");
                //Right now the only way to rewind is reseting the decoder
                _oggManager.initDecoder(_oggBytes);
                result = _oggManager.getSampleData( NUM_SAMPLES, tmpBuffer);
            }//reset

            tmpBuffer.position = 0; 
            while (tmpBuffer.bytesAvailable)
            {//feed
                //feed data
                e.data.writeFloat(tmpBuffer.readFloat());       //Left Channel
                e.data.writeFloat(tmpBuffer.readFloat());       //Right Channel
            }//feed

        }//handleSoundData

        private function loaded(event:Event):void  
        {  
            urlStream.readBytes(_oggBytes, 0, urlStream.bytesAvailable);
            //urlStream.readBytes(_oggBytes);
            _oggManager.decode(_oggBytes);
            //_oggManager.initDecoder(_oggBytes);
            //Make sound
            _sound = new Sound();
            _sound.addEventListener(SampleDataEvent.SAMPLE_DATA, handleSoundData, false, 0, true);
            _soundChannel = _sound.play();
            //trace(urlLoader.data);
        }  */

In the fucntion loaded(), either with both encodings:

  • _oggManager.decode(_oggBytes);
  • _oggManager.initDecoder(_oggBytes);

I get this error:

Main Thread (Suspended: TypeError: Error #1009: Cannot access a property or method of a null object reference.) 
    es.maubic.oxford.portal.views.sessions::ListAudiosView/loaded

So, any tips? any other possible solutions?

UPDATE

Finally, I chose another solution. I rejected transforming ogg audio to mp3. Instead of that, now the ogg audios are in a server and I only need the URL to play them through an audio html tag in my MainApp.html file. Simpler and more efficient.

1

There are 1 best solutions below

1
On BEST ANSWER

I've founded an alternative solution to the problem in the question.

Instead of convert the .ogg file into a .mp3 file, I've modified my code in order to reproduce directly in the application the .ogg file from its url (where it's stored in a server).

Adding this code to main app html file (in my case Admin.html):

    <audio id="audioOgg">
         <source src='' type='audio/ogg'>
    </audio>

    <script language="JavaScript" type="text/javascript">
        var media = document.getElementById("audioOgg");
        var cp=document.getElementById("Admin");
        var audioId;
        function playAudio(audioURL, id) {
            media.src = audioURL;
            audioId = id;
            media.play();
            cp.onStartAudio(audioId);
        }
        function pauseAudio() {
            media.pause();
        }
    </script>

And this code to in the .mxml file:

 <?xml version="1.0" encoding="utf-8"?>
 <mx:TitleWindow xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" title="Audio List" 
                horizontalScrollPolicy="off" verticalScrollPolicy="auto" width="510" height="340" 
                showCloseButton="true" close="closeWindow()">
    <mx:Script>
        <![CDATA[
            import flash.external.ExternalInterface;

            import mx.collections.ArrayCollection;
            import mx.events.FlexEvent;
            import mx.managers.PopUpManager;
            import mx.controls.Alert;

            [Embed(source='../assets/play-btn-small.png')]
            var Play:Class;
            [Embed(source='../assets/stop-btn-small.png')]
            var Stop:Class;

            [Blindable]
            public var dpc:ArrayCollection;

            public function playAudio(audioURL:String, audioId:String){
                ExternalInterface.call("playAudio", audioURL, id);
            }

            public function pauseAudio(){
                ExternalInterface.call("pauseAudio");   
            }
        ]]>
    </mx:Script>
    <mx:Rotate id="rotate" />
    <mx:Zoom id="zoom" />
    <mx:VBox top="0" bottom="0" left="0" right="0" paddingTop="20" paddingLeft="20">
        <mx:Text fontWeight="bold" height="20">
            <mx:text>Click the play/pause button for listening/pause each audio individually:</mx:text>
        </mx:Text>
    </mx:VBox>
    <mx:DataGrid id="gridAudios" top="50" bottom="20" left="20" right="20" width="100%" doubleClickEnabled="false">
        <mx:columns>
            <mx:DataGridColumn headerText="Name" dataField="audioId"/>
            <mx:DataGridColumn id="btnCol" headerText="" textAlign="center">
                <mx:itemRenderer>
                    <mx:Component>
                        <mx:HBox horizontalAlign="center">
                            <mx:Script>
                                <![CDATA[
                                    protected function image1_clickHandler(event:MouseEvent):void
                                    {
                                        if (data.status=='playing'){
                                            outerDocument.pauseAudio(); 
                                            data.status='';
                                        }else{
                                            outerDocument.playAudio(data.url,data.audioId);
                                            data.status='playing';
                                        }
                                    }
                                ]]>
                            </mx:Script>

                            <mx:Image click="image1_clickHandler(event)" 
                                      toolTip="{data.status=='playing' ? 'Stop' : 'Play'}"
                                      useHandCursor="true" source="{data.status=='playing' ? outerDocument.Stop : outerDocument.Play}"/>
                        </mx:HBox>
                    </mx:Component>
                </mx:itemRenderer>
            </mx:DataGridColumn>
        </mx:columns>
    </mx:DataGrid>
</mx:TitleWindow>

Thanks to the ExternalInterface class I'm able to call the Javascript functions declared in my Admin.html file in order to reproduce and stop the audio of the tag element, passing as arguments the audio url & the audio identificator.