Android MP3 Recording Implementation

Source: Internet
Author: User

Copyright Notice:

Welcome reprint, but please keep the original source of the article

Gavinct

Source: http://www.cnblogs.com/ct2011/p/4080193.html

The formats supported by Android recordings are AMR, AAC, but these two audio formats do not perform well across platforms.
MP3 is clearly the best cross-platform choice.
Recently due to project needs, the implementation of this demand, code hosting on GitHub, Welcome to shoot Bricks

Project Address

Gavinct/androidmp3recorder

How to use: readme.md

Overview of Implementation Ideas

Before we analyze the code, we need to clarify a few questions

1. How to eventually generate MP3

The best way to implement the MP3 format is through lame, a proven solution.
For Android, you need to use JNI to invoke the C-language code of Lame to achieve the conversion of audio formats.

2. How to get the original audio data

The Audiorecord class can help us get audio data directly.

3. How to Convert

The online code is recorded and converted to MP3, which is less efficient. Because if the recording time is too long, the conversion time will be correspondingly longer, and the user will have to wait longer to store the recording.
Samsung developers first record and then turn to sample code
Obviously, such a scheme is undesirable.
What we need is the realization of the side record, so that when the recording is stopped, it will not take too long to save.

Implementation code Introduction

Since it's a recording, we've also mentioned the need to use the Audiorecord class, and we'll start with the constructor for this class.

Constructors
Public Audiorecord  (int Audiosource, int Samplerateinhz,  Int Channelconfig,  int Audioformat, int Buffersizeinbytes)            

There are a lot of constructor parameters, and we'll look at 1.1:

    • Audiosource: Sound source, general use MediaRecorder.AudioSource.MIC indicates from microphone
    • Samplerateinhz: Officially, only 44100Hz is supported by all devices. Other 22050, 16000, and 11,025 can only be used on certain devices.
    • Channelconfig: There are two types of stereo (Channel_in_stereo) and Mono (Channel_in_mono). But only mono (Channel_in_mono) is supported by all devices.
    • Audioformat: There are two kinds of audio encoding formats for encoding_pcm_16bit and Encoding_pcm_8bit. Similarly, the official statement only Encoding_pcm_16bit is supported by all devices.
    • Buffersizeinbytes: The Write buffer size (in bytes) of sound data during recording.

In fact, from the above explanation can be seen, the parameters of a lot of classes, but in order to ensure that all devices can be used, we really need to fill in only one parameter: Buffersizeinbytes, the other can use common parameters instead of having to bother to choose.
Before we delve into what buffersizeinbytes should be, let's skip through this paragraph, first of all, to read and convert the recording.

Reading and conversion strategies for recording

The recording is actually similar to UDP, and it needs to read the data continuously.
Since it is constant, then of course we need to iterate, which means we need a thread to read the recording individually and avoid blocking the main thread.
Also similar to UDP, if not read in time, the data exceeds the buffer size, will cause this recording data loss.
As mentioned above, what we want to achieve is the recording edge. Then the problem comes, if we read the data and then pass the data to lame for MP3 encoding, lame encoding time is uncertain, is it possible to cause data loss?
The answer is of course possible, so we can't be programmed by coincidence.
We need another thread, the data encoding thread dedicated to MP3 encoding, and the current recording reading thread is only responsible for reading the recorded PCM data.
With two threads, we also need to make sure that when the encoding thread starts processing the data?

Timing of encoding thread processing data

The traditional approach is to start processing when there is data in the thread, which needs to be constantly looping through the thread to see if there is data to be processed, data to start processing, no data we can temporarily rest a few milliseconds (of course, not sleep can, but caused by too much system consumption).
This approach is obviously inefficient, because no matter how long we take the thread to rest, it can be judged to be unreasonable. Because we don't know the exact time.
So is there another way?
Obviously recording this class is knowing when to process the data and when to rest.
Don ' t call me, I'll call you.
Yes, we should go and see if there is a listener, let the recording to inform the coding thread to start working.
Audiorecord provides us with such a method:

public int setPositionNotificationPeriod (int periodInFrames)Added in API level 3Sets the period at which the listener is called, if set with setRecordPositionUpdateListener(OnRecordPositionUpdateListener) or setRecordPositionUpdateListener(OnRecordPositionUpdateListener, Handler). It is possible for notifications to be lost if the period is too small.

Set the notification period. In frames.
Here we can come back to explain the buffersizeinbytes size of the incoming.

Size of the buffer

In fact, the Audiorecord class provides a convenient way to getminbuffersize to get the size of the buffer.

Public static span class= "DT" >int getminbuffersize  (int Samplerateinhz, int Channelconfig, < Span class= "hljs-function" >int Audioformat)                

Here are the 3 parameters, in fact, we can see from the constructor parameters, so the incoming and there is no problem.
But the key is as above we set the period unit, if the obtained buffer size is not an integer multiple of the periodic units?
Not an integer multiples of course will cause data loss as we suspect, so we also need some data corrections to ensure that the buffer size is an integer multiple.

Mbuffersize = Audiorecord.Getminbuffersize (Default_sampling_rate, Default_channel_config, Default_audio_format.getaudioformat ()); int bytesperframe = Default_audio_format./* Get number of samples. Calculate the buffer size  * (Round up to the Factor of given frame size)  * enable to be divisible, Convenient periodic notice below  * */int framesize = mbuffersize/bytesperframe; if (framesize% frame_count! = 0) {framesize + = (FRAME_ Count-framesize% frame_count); Mbuffersize = Framesize * bytesperframe;}            

Having finished the data fetching thread and coding thread, let's take a closer look at the hero who helped us implement MP3 encoding: Lame

Acquisition and compilation of Lame

Lame Online

Steps
  1. Unzip the libmp3lame to the JNI directory.
  2. Copy lame.h (include directory)
  3. Create Android.mk

    Local_path: = $ (Call My-dir)Include $ (clear_vars) Local_module: = mp3lamelocal_src_files: = bitstream.C FFT.c Id3tag. c mpglib_interface. c presets. c quantize. c Reservoir. c tables. C Util.c vbrtag. C Encoder. c gain_analysis. c lame. c newmdct. c Psymodel. c quantize_pvt. c set_get. c Takehiro. c vbrquantize. c version. Cinclude $ (build_shared_library)        
  4. Delete Non .c / .h file: GNU autotools, makefile.am makefile.in libmp3lame_vc8.vcproj logoe.ico depcomp, folders i386 and other useless files.
  5. Edit Jni/utils.h. extern ieee754_float32_t fast_log2(ieee754_float32_t x);Replace with a extern float fast_log2(float x); . If you forget to replace it, the following error is reported at compile time:

    thumb  : mp3lame <= bitstream.cIn file included from jni/bitstream.c:36:0:jni/util.h:574:5: error: unknown type name ‘ieee754_float32_t‘jni/util.h:574:40: error: unknown type name ‘ieee754_float32_t‘make.exe: *** [obj/local/armeabi/objs/mp3lame/bitstream.o] Error 1
  6. Compile the library file. Warnings may be reported and ignored.

Lame need to provide method init initialization for external
    • Insamplerate: Input Sampling frequency Hz
    • Inchannel: Number of input channels
    • Outsamplerate: Output Sampling frequency Hz
    • outbitrate:encoded bit rate. KHz
    • Quality:mp3 audio quality. 0~9. 0 of them are best, very slow, and 9 are the worst.
      Recommended:
      2:near-best quality, not too slow
      5:good Quality, fast
      7:ok Quality, really fast
PrivateStaticFinalint default_lame_mp3_quality =7;/*** Related to Default_channel_config, because it is mono single sound, so it is 1*/PrivateStaticFinalint Default_lame_in_channel =1;/*** Encoded bit rate. MP3 file is encoded with bit rate 32kbps*/PrivateStaticfinal int DEFAULT_LAME_ Mp3_bit_rate = 32; /** Initialize Lame Buffer* MP3 sampling rate is the same as The recorded PCM sampling rate * the bit rate is 32kbps* */lameutil.              
Encode
    • Bufferleft: Left channel data
    • Bufferright: Right channel data
    • Samples: input data size per channel
    • MP3BUF: Used to receive converted data. 7200 + (1.25 * buffer_l.length)
      Here's what you need to explain:
Task task = mTasks.remove(0);short[] buffer = task.getData();int readSize = task.getReadSize();int encodedSize = LameUtil.encode(buffer, buffer, readSize, mMp3Buffer);
    • Left and right channel: The current channel is selected mono, so the two sides pass in the same buffer.
    • Input data size: The data that the recording thread reads into the buffer is not necessarily full, so the Read method returns the current size, that is, the preceding size data is valid audio data, and the subsequent data is the scrap data that was previously left. This size also needs to be passed in to the lame encoder for encoding.
    • Buffer of MP3: The official rule of the formula: 7200 + (1.25 * buffer_l.length). (Can be seen in the lame.h file)
Flush

Writes the MP3 end information to buffer.
Incoming parameter: mp3buf at least 7200 bytes. This is also used to pass in the previously defined mp3buf to avoid creating too many arrays.

Close

Close release Lame

OK, here, the core conversion code is done, and we'll get something icing on the cake.

Volume

Generally when we do the recording, there will be a demand, according to the volume of the size of an animation, so that the recording appears more vivid.
Of course, I have also provided in this library.
So how do you calculate the volume?
I refer to the volume calculation of Samsung.
Summarized as follows:

/*** This calculation method comes from the Samsung development paradigm**@param buffer*@param readsize*/Private void Calculaterealvolume(short [] buffer, int  ReadSize) { int sum = 0; for (int i = 0; i < readsize; i++) {sum + = buffer[i] * buffer[i];} if (readsize > 0) {double amplitude = sum/readsize; Mvolume = (int) math. 
About Maximum Volume

In fact, for the volume, I do not particularly understand.
Maximum volume given in Samsung's code is 4000, but I found in the actual test that the calculated formula is generally within 1500 of the volume.
So in the recording library I provided, I set the maximum volume to 2000.
This piece welcomes everyone to make valuable comments.

MP3 Recording Implementation Reference
      • Yhirano/mp3voicerecordersampleforandroid
        The Japanese wrote, feel his judgment is imperfect, a bit of coincidence programming meaning, also perhaps I did not read.
      • Talzeus/androidmp3recorder
        A more rigorous code. Mainly based on the changes made by this library.
        Problems that exist:
        • Many of the Audiorecord incoming parameters are not passed in as Android rules. If the sampling frequency uses 22050Hz.
        • Using the Ringbuffer of your own construction, look at this a little dizzy. I use list in the library to store the uncompressed audio data, which is easier to understand.
        • No volume size is provided.

Android MP3 Recording Implementation

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.