0
votes

I am facing some problems in my project.

In my project, I need to implement microphone integration with RED5 server using Actionscript which is used to store the audio stream on server and after that I used ffmpeg in java code to convert the flv file to mp3.

I am facing 2 problems here:

  1. The recorded audio creates .flv file which is currepted.

  2. When I try to convert the .flv to .mp3 using ffmpeg, it gets stuck until I stop the Red5 server.

Here is my code of both places. Please let me know where I am doing wrong.

Actionscipt to record microphone audio and stream on red5:

private function initConnection():Void {

        trace("Connecting...");

        nc = new NetConnection();
        nc.client = this;
        nc.addEventListener(NetStatusEvent.NET_STATUS, onNetConnectionStatus);
        nc.connect("rtmp://127.0.0.1/test");

        this.mic = Microphone.getMicrophone();

        if (this.mic != null) {
            this.mic.rate = 44;
            mic.setSilenceLevel(0);
            mic.gain = 100;
            mic.setUseEchoSuppression(true); 
            mic.setLoopBack(true);              
        }                   
    }

To Send on Red5:

public function startSending( nc: NetConnection, filename:String ) {
        ns = new NetStream(nc);
        ns.addEventListener(NetStatusEvent.NET_STATUS, onNetStreamStatus);
        ns.publish(filename, 'record');
        ns.attachAudio(mic);        
}

To Stop recording/sending:

public function stopSending() {
        mic.setLoopBack(false);
        ns.attachAudio(null);
        ns.close();     
}

The resulting .flv stored on server which is currepted.

Not to convert .flv into .mp3, I have used ffmpeg in my Java code as per following:

String ffmpegArgs[] = {executableDir,"-i",flvFile.getAbsolutePath(), "-vn", mp3File.getAbsolutePath()};
Process process = new ProcessBuilder(Arrays.asList(ffmpegArgs)).start();

This starts the file conversion, but it gets stucked. After some time when I stop the server, it immediately shows the converted file. Please let me know, where I am doing wrong.

2
Does the FLV playback correctly? You may want to ensure that its ok before trying to convert it. I would also suggest that you keep loopback set to false.Paul Gregoire

2 Answers

0
votes

I've never used Red5 so can't help much with that. Are you using the server to store the data or could you save the raw bytes to local storage (or just keep in memory) and then send them to the Java server once recording is over? If so, I solved a similar problem on my project which is used for video production from ActionScript sound files (and other assets). You will have good results if you encode the bytes as WAVE before you send to the server. There's an object here for doing the conversion - thibault source here : https://code.google.com/p/micrecorder/downloads/detail?name=MicRecorder%201.2.zip&can=2&q=

The relevant code from that package is this:

    public class WavEncoder implements ISoundEncoder
{
    private static const RIFF:String = "RIFF";  
    private static const WAVE:String = "WAVE";  
    private static const FMT:String = "fmt ";   
    private static const DATA:String = "data";  

    private var _bytes:ByteArray = new ByteArray();
    private var _buffer:ByteArray = new ByteArray();
    private var _volume:Number;

    /**
     * 
     * @param volume
     * 
     */     
    public function WavEncoder( volume:Number=1 )
    {
        _volume = volume;
    }

    /**
     * 
     * @param samples
     * @param channels
     * @param bits
     * @param rate
     * @return 
     * 
     */     
    public function encode( samples:ByteArray, channels:int=2, bits:int=16, rate:int=22100 ):ByteArray
    {
        //var data:ByteArray = create( samples );
        create(samples);

        _bytes.length = 0;
        _bytes.endian = Endian.LITTLE_ENDIAN;

        //create(samples);

        _bytes.writeUTFBytes( WavEncoder.RIFF );
        //_bytes.writeInt( uint( data.length + 44 ) );
        _bytes.writeInt( uint( _buffer.length + 44 ) );
        _bytes.writeUTFBytes( WavEncoder.WAVE );
        _bytes.writeUTFBytes( WavEncoder.FMT );
        _bytes.writeInt( uint( 16 ) );
        _bytes.writeShort( uint( 1 ) );
        _bytes.writeShort( channels );
        _bytes.writeInt( rate );
        _bytes.writeInt( uint( rate * channels * ( bits >> 3 ) ) );
        _bytes.writeShort( uint( channels * ( bits >> 3 ) ) );
        _bytes.writeShort( bits );
        _bytes.writeUTFBytes( WavEncoder.DATA );
        //_bytes.writeInt( data.length );
        _bytes.writeInt(_buffer.length);
        //_bytes.writeBytes( data );
        _bytes.writeBytes( _buffer);
        _bytes.position = 0;

        //data.clear();
        _buffer.clear();
        return _bytes;
    }

    private function create( bytes:ByteArray ):ByteArray        {

        if(!_buffer)
            _buffer = new ByteArray();

        _buffer.endian = Endian.LITTLE_ENDIAN;
        _buffer.length = 0;
        bytes.position = 0;

        while( bytes.bytesAvailable ) 
            _buffer.writeShort( bytes.readFloat() * (0x7fff * _volume) );
        return _buffer;
    }
}

FFmpeg may not understand your encoding and therefore is trying but failing. Not sure if what I posted will help you or not but I post it just in case. Let me know if you have questions about how I fully implemented this to get good playback of sound using FFmpeg, Java and AS to do something similar to what you're trying to do.

0
votes

Finally I got the answer.

The scenario is like this:

As my source .flv file is currupted, when I execute the ffmpeg command from command line, it shows many warnings.

When I execute the same command from my java code the warnings are buffered in jvm and so it become full and process hangs up. I found solution in another stackoverflow thread that we need to flush the errors and other through reading the stream. Here is the code for that;

final BufferedReader stderr = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String line = "";
for (l = 0; ((line = stderr.readLine()) != null);) {
           System.out.println(line)
           l++;
}

 stderr.close();

It worked for me!