Strange issue in Combining Audio Files and playing

2020-02-28 05:01发布

问题:

All , I am using Media Recorder for Recording Audio.

Case 1: If i use Android Version 2.2 installed devices, my recorded audio combined and playing well.

Case 2: If i use it in Android 1.6 installed devices, i am not able to play the combined audio file.

It is playing only the very first recorded audio and next recorded audio files keep empty no sound.

Also i am not getting any error in Logcat.

I used following code for recording audio :

    mRecorder = new MediaRecorder();
    mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
    mRecorder.setOutputFormat(MediaRecorder.OutputFormat.RAW_AMR);
    mRecorder.setOutputFile(main_record_file);
    mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
    mRecorder.prepare();
    mRecorder.start();

Also i tried for mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);

Code for combining Audio file :

    public void createCombineRecFile(){
    combined_file_stored_path=getFilename_combined_raw(); // File path in String to store recorded audio
    byte fileContent[]=null;
    FileInputStream ins;
    FileOutputStream fos = null;
    try{
        fos = new FileOutputStream(combined_file_stored_path,true);
    }
    catch (FileNotFoundException e1){
        // TODO Auto-generated catch block
        e1.printStackTrace();
    }
    for(int i=0;i<audNames.size();i++){
        try{
            File f=new File(audNames.get(i));
            Log.v("Record Message", "File Length=========>>>"+f.length());
            fileContent = new byte[(int)f.length()];
            ins=new FileInputStream(audNames.get(i));
            int r=ins.read(fileContent);// Reads the file content as byte from the list.
            Log.v("Record Message", "Number Of Bytes Readed=====>>>"+r);
            fos.write(fileContent);//Write the byte into the combine file.

            Log.v("Record Message", "File======="+i+"is Appended");

        }
        catch (FileNotFoundException e){
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        catch (IOException e) 
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    try{
        fos.close();
        Log.v("Record Message", "===== Combine File Closed =====");
    }
    catch (IOException e){
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

Let me know any details need.Thanks.

回答1:

Every audio file has its own header (includes information about length/samples etc.) - by combining the files the way you do the resulting file has multiple headers, one per source file (depending on the exact format with file offsets etc.). Thus the resulting file is NOT correct in terms of file format spec.

The newer Android version are more permissive and work/play with "multiple headers" present... the older versions do not...

To create a correctly combined audio file you must conform to the spec which among other things means creating one new header which describes all included audio...

Use for the the combination of audio files a different approach - for example via ffmpeg (see this for how to make ffmpeg for android).



回答2:

Foreword: Haven't tested this, but I don't see why it shouldn't work.

Provided the headers ARE the cause of this problem, you can solve it really easily. Using the code you've given, the encoding is AMR-NB. According to this document the AMR header is simply the first 6 bytes, which are 0x23, 0x21, 0x41, 0x4D, 0x52, 0x0A. If the headers in subsequent files are causing the issue, simply omit those bytes from subsequent files e.g.

write all bytes of first file
write from byte[6] -> byte[end] of subsequent files

Let me know how it goes.

EDIT: At request, change the try block to:

try{
        File f=new File(audNames.get(i));
        Log.v("Record Message", "File Length=========>>>"+f.length());
        fileContent = new byte[(int)f.length()];

        ///////////////new bit////////

        //same as you had, this opens a byte stream to the file
        ins=new FileInputStream(audNames.get(i));
        //reads fileContent.length bytes
        ins.read(fileContent);
        //now fileContent contains the entire audio file - in bytes.
        if(i>0){
            //we are not writing the first audio recording, but subsequent ones
            //so we don't want the header included in the write

            //copy the entire file, but not the first 6 bytes
            byte[] headerlessFileContent = new byte[fileContent.length()-6];
            for(int j=6; j<fileContent.length();j++){
                headerlessFileContent[j-6] = fileContent[j];
            }
            fileContent = headerlessFileContent;
        }
        ////////////////////////////

        Log.v("Record Message", "Number Of Bytes Readed=====>>>"+r);
        fos.write(fileContent);//Write the byte into the combine file.

        Log.v("Record Message", "File======="+i+"is Appended");

    }