Zero, preface,

As the post-90s generation, MP3 format music is the soul friend.

When I was a child with headphones, lying on the table to listen to music to see the moon mood. When a melody is remembered, will not emerge a scenery, someone…… Today’s full single – Leong Jingru – Courage (Presents spectrum)

Main Tasks:SD card music, network audio stream playback and control


The introduction of MP3

0.-- Say something

When I was in junior high school, I still had a mobile phone with a physical keyboard. At that time, the memory card felt very precious. 2G was huge

It started with a 256MB memory card. Who didn’t like listening to music and reading e-books? At that time there was no Internet, can only let my sister to help me download, I asked: Under the kind of memory the smallest song Because I found all 4 M, 0.4 M, and can listen, just at that time, a song to listen to, the sound quality is completely don’t care At the time of memory, I pick the maximum memory songs, write down the song, very reluctantly Which the biggest which now, but to collect the feeling of music, and play, listen to calculate


1. Information analysis of courage songs

Stereo: channel number 2 sampling rate: 44.1KHz bit depth: 32bit in PCM Bitrate: 44100*32*2=2822400bps=2756.25Kbps /8= 344.53125KB (4*60+1.162)s* 344.5312kb /s= 83087.8453125b about 81.1m PCM almost close to perfect sound quality (losslessCopy the code

2.MP3 is an audio lossy compression technology(Source of knowledge,Baidu encyclopedia)
MP3(Moving Picture Experts Group Audio Layer III) refers to the mPEG-1 standard in the Audio part of MPEG Audio file compression is a lossy compression, MP3 Audio with 10:1 ~12: The high compression ratio of 1 shows that The bit rate of Courage is compressed from 2756.25Kbps to 320Kbps, and the compression ratio is 8.61:1Copy the code

3. The part of MP3 compression:

The psychoacoustics mentioned in the last part, according to the model of the human ear, there is a lot of redundancy in the lossless data

Compression is the filtering of redundant data, or the deliberate elimination of unimportant information

Taking advantage of the insensitivity of human ear to high frequency sound signals, the time domain waveform signal is converted into frequency domain signal, and divided into multiple frequency bands. Different compression rates are used for different frequency bands, and the compression ratio of high frequency is increased (or even ignored) and the compression ratio of low frequency signal is used to ensure that the signal is not distorted. It's the equivalent of swapping out high frequency sounds that are barely audible to the human ear for the size of the file and storing it in *.mp3 formatCopy the code

4. Compression and sound quality

If you think about it, the same file, the same compression technology: the higher the compression rate, the more information is filtered, the smaller the file, the worse the sound quality and vice versa, 320Kbps can count as very good sound qualityCopy the code

With that, let’s move on to the highlight of the day, MediaPlayer


2. Brief introduction of MediaPlayer

Parent class/interface: PlayerBase/SubtitleController Listener/VolumeAutomation source line number: 5618 - read can not hold the inner class: 27 - the interface class 13, 11 ordinary class constructor: 1, no-parameter construct Indirect construct (method returns an instance of this class) : 5 number of methods: visual 120+ Number of fields: visual 90+Copy the code

Android as a mobile device, there are only a few classes of audio player, MediaPlayer as a mainstay

MediaPlayer is a pretty big class, and it’s close to native, so there’s no reason not to check it out


1. Take a look at this terrifying life cycle

Don’t be afraid. We’ll see


2. The interface

I don’t want to do it with a few buttons, so I want it to look good, because the layout doesn’t have to work

This is the player I wrote out of a play bar put here with two custom controls written before: the top of the play progress, and button click to shallow and then restore how to customize and today is not relevant, but also relatively simple (also see their own source code), can also use buttons and progress bar instead


3. Look at the construction method first
/** * Default constructor. Consider using one of the create() methods for * synchronously instantiating a MediaPlayer from a Uri or resource. * <p>When done with the MediaPlayer, you should call {@link #release()}, To free the resources. If not released, too many MediaPlayer instances may * result in an exception.</p> Consider using one of the create() methods to instantiate MediaPlayer synchronously from a Uri or resource. When using MediaPlayer, you should call Release () to free the resource. If I don't release it, */ public MediaPlayer() {super(new AudioAttribute.builder ().build(),// Superclass construct AudioPlaybackConfiguration.PLAYER_TYPE_JAM_MEDIAPLAYER); Looper looper; if ((looper = Looper.myLooper()) ! = null) { mEventHandler = new EventHandler(this, looper); } else if ((looper = Looper.getMainLooper()) ! = null) { mEventHandler = new EventHandler(this, looper); } else { mEventHandler = null; } mTimeProvider = new TimeProvider(this); mOpenSubtitleSources = new Vector<InputStream>(); /* Native setup requires a weak reference to our object. * It's easier to create it here than in C++. Native_setup requires a weak reference to the object. */ native_setup(new WeakReference<MediaPlayer>(this)); baseRegisterPlayer(); } ---->[native setup] private native final void native_setup(Object mediaplayer_this);Copy the code

4. Five overloading methods for create() :

When you say five, there are two cores: the Uri that locates the resource, and the RES ID that defines the resource

* @param context * @param URI Resource path identifier * @param Holder SurfaceHolder used to display video, Can be empty (audio ignored). * @param audioAttributes class object * @param audioSessionId audioSessionId to be used by the media player, See {AudioManager#generateAudioSessionId()} to get new session * @return a MediaPlayer object, or null if creation failed public static MediaPlayer create(Context context, Uri uri, SurfaceHolder holder, AudioAttributes audioAttributes, int audioSessionId) { try { MediaPlayer mp = new MediaPlayer(); // Create MediaPlayer instance final AudioAttributes aa = AudioAttributes! = null ? audioAttributes : new AudioAttributes.Builder().build(); // If the audio attributes are empty, new one mp.setauDioAttributes (aa); Mp.setaudiosessionid (audioSessionId); // Set audio properties mp.setaudiosessionID (audioSessionId); Mp.setdatasource (context, URI); // Set session ID mp.setdatasource (context, URI); // Set resource if (holder! = null) {//SurfaceHolder is not null mp.setdisplay (holder); // Play SurfaceHolder video} mp.prepare(); // Prepare return mp; // Return MediaPlayer instance} catch (IOException ex) {log.d (TAG, "create failed:", ex); // fall through } catch (IllegalArgumentException ex) { Log.d(TAG, "create failed:", ex); // fall through } catch (SecurityException ex) { Log.d(TAG, "create failed:", ex); // fall through } return null; } ----> Public static MediaPlayer create(Context Context, Uri Uri, SurfaceHolder holder) { int s = AudioSystem.newAudioSessionId(); return create(context, uri, holder, null, s > 0 ? s : 0); } ----> Public static MediaPlayer create(Context Context, Uri Uri) {return create(Context, Uri, null); }Copy the code

Similar to retrieving resources from res, see for yourself (resources under res/ RAW)

There are very few songs that are put directly into the RES, it’s ok to put on some sound effects, but there are better choices for sound effects


3. Simple use of MediaPlayer

The two parameters of the read Uri reload are perfect for playing an audio file

1. Use Uri to play a network song

There’s a couple of songs playing on the server, just play – the simplest version plays

Remember the permissions (I drop pit) < USES – permission android: name = “android. Permission. INTERNET” / >

1.1 – MusicPlayer wrapper class
public class MusicPlayer { private MediaPlayer mPlayer; private Context mContext; public MusicPlayer(Context context) { mContext = context; init(); } / / initializes the private void init () {Uri Uri = Uri. Parse (" in accordance with the http://www.toly1994.com:8089/file/ los day. Mp3 "); mPlayer = MediaPlayer.create(mContext, uri); Public void start() {mplayer.start (); }}Copy the code

1.2 – the Activity
MusicPlayer musicPlayer = new MusicPlayer(this); // instantiate // musicPlayer.start(); / / playCopy the code

It plays fine, but it takes a long time to initialize MusicPlayer from a network resource

Since initialization takes place in the main thread, the screen is white for quite a while. How can I tolerate this


1.3 Initialization in another thread

Do not play until initialization is complete. Return off

public class MusicPlayer { private MediaPlayer mPlayer; private Context mContext; private boolean isInitialized = false; Private Thread initThread; Public MusicPlayer(Context Context) {mContext = Context; initThread = new Thread(this::init); initThread.start(); } private void init () {Uri Uri = Uri. Parse (" in accordance with the http://www.toly1994.com:8089/file/ los day. Mp3 "); mPlayer = MediaPlayer.create(mContext, uri); isInitialized = true; Public void start() {if (! isInitialized) { return; } mPlayer.start(); Public void onDestroyed() {if (mPlayer! = null) { mPlayer.release(); MPlayer = null; } isInitialized = false; }}Copy the code

2. Play music on the local SD card

Remember to add permissions: read and write together, to avoid adding later

Uri Uri = Uri. FromFile (new File (Environment) external.getexternalstoragedirectory () getPath (), "toly/courage - fish leong - 1772728608-1. Mp3"));Copy the code

Life cycle and pause control of MediaPlayer

1. Visualize the following life cycles
Idle Initialized: If I found a job, I was Prepared to bring something for tomorrow. Paused: I wanted to Stop and have a cup of tea. Prepare () : prepare() : prepare() : prepare() : prepare() : prepare() : prepare() : prepare() : prepare() : prepare() : prepare() : prepare(); Always feel the stop method is a little chicken...Copy the code


2.MusicPlayer pause

It can be seen that MediaPlayer. Create already spent Idle, the Initialized, Prepared state

public class MusicPlayer { private MediaPlayer mPlayer; private Context mContext; private boolean isInitialized = false; Private Thread initThread; public MusicPlayer(Context context) { mContext = context; initThread = new Thread(this::init); initThread.start(); } private void init() { Uri uri = Uri.fromFile(new File(Environment.getExternalStorageDirectory().getPath(), "Toly/Courage - Jingru Leong -1772728608-1.mp3")); mPlayer = MediaPlayer.create(mContext, uri); isInitialized = true; MPlayer. SetOnErrorListener ((mp, credit, extra) - > {/ / processing error return false. }); } /** * play */ public void start() {return if (! isInitialized && mPlayer.isPlaying()) { return; } mPlayer.start(); Public Boolean isPlaying() {// return if (! isInitialized) { return false; } return mPlayer.isPlaying(); Public void onDestroyed() {if (mPlayer! = null) { mPlayer.stop(); mPlayer.release(); MPlayer = null; } isInitialized = false; / / private void stop() {if (mPlayer! = null && mPlayer.isPlaying()) { mPlayer.stop(); Public void pause() {if (mPlayer! = null && mPlayer.isPlaying()) { mPlayer.pause(); }}}Copy the code

3. Modifications in the Activity

Change ICONS and play or pause based on musicPlayer’s state

mIdIvCtrl.setOnClickListener(v->{ if (musicPlayer.isPlaying()) { musicPlayer.pause(); mIdIvCtrl.setImageResource(R.drawable.icon_stop_2); // set icon pause} else {musicplayer.start (); mIdIvCtrl.setImageResource(R.drawable.icon_start_2); // Set icon play}});Copy the code

Four, increase the monitoring of the progress

Use Timer, refresh every second when playing, callback progress, do not play, do not refresh the TimeTask in the Timer is not the main thread, simply use Handler to push back to the main thread refresh view


1. The MusicPlayer modification
MTimer = new Timer(); // Create Timer mHandler = new Handler(); Mtimer.schedule (new TimerTask() {@override public void run() {if (isPlaying()) {int pos = mPlayer.getCurrentPosition(); int duration = mPlayer.getDuration(); mHandler.post(() -> { if (mOnSeekListener ! = null) { mOnSeekListener.OnSeek((int) (pos * 1.f / duration * 100)); }}); }, 0, 1000); / / -- -- -- -- -- -- -- -- -- -- -- -- set the schedule to monitor -- -- -- -- -- -- -- -- -- -- - public interface OnSeekListener {void OnSeek (int per_100); } private OnSeekListener mOnSeekListener; public void setOnSeekListener(OnSeekListener onSeekListener) { mOnSeekListener = onSeekListener; }Copy the code

2. Call the listener in the Activity
musicPlayer.setOnSeekListener(per_100 -> { mIdPvPre.setProgress(per_100); // Set progress for the progress bar});Copy the code

Ok, how simple is the progress bar


5. Listening by MediaPlayer

1. Jump method:MusicPlayer
/** * Jump to * @param pre_100 0~100 */ public void seekTo(int pre_100) {pause(); mPlayer.seekTo((int) (pre_100/100.f*mPlayer.getDuration())); start(); }Copy the code

2. Use jump :Activity
mIdPvPre.setOnDragListener(pre_100 -> {
    musicPlayer.seekTo(pre_100);
});
Copy the code

Drag is that simple…


Six, some other listening methods + network audio streams

1. Common monitoring:
/ / callback when loading finished streaming mPlayer. SetOnPreparedListener (mp - > {L.d (" OnPreparedListener "+ L.l ()); }); / / play complete monitoring mPlayer. SetOnCompletionListener (mp - > {L.d (" CompletionListene "+ L.l ()); start(); // Finish playing and play again -- make the single loop}); / / seekTo method complete callback mPlayer. SetOnSeekCompleteListener (mp - > {L.d (" SeekCompleteListener "+ L.l ()); }); / / network streaming media buffer change callback mPlayer. SetOnBufferingUpdateListener ((mp, percent) -> { L.d("BufferingUpdateListener" + percent + L.l()); });Copy the code

2. Network audio stream

Preparing is the state of the prepareAsync() function after it is called

And OnPreparedListener onPrepared () callback to cooperate, is suitable for the broadcast network flow Just now is through the create () to create the MediaPlayer, source of the create () call the prepare () and want to asynchronous preparation, You need to define your own MediaPlayer, because it’s asynchronously prepared and has callbacks, so you don’t have to start threads

private void init() { mPlayer = new MediaPlayer(); / / 1. Unemployed Uri Uri = Uri. Parse (" in accordance with the http://www.toly1994.com:8089/file/ los day. Mp3 "); try { mPlayer.setDataSource(mContext, uri); Mplayer.prepareasync (); //2. } catch (IOException e) {e.printStackTrace(); } / / callback when loading finished streaming mPlayer. SetOnPreparedListener (mp - > {/ / 4. Prepare OK L.d("OnPreparedListener" + L.l()); isInitialized = true; });Copy the code
After Preparing status: to find a job is ready to take tomorrow Mainly and prepareAsync (), will trigger OnPreparedListener asynchronous is Prepared to do. The onPrepared (), and then into the Prepared state. PlaybackCompleted state: The work has been completed. This state is entered if the file has played normally and no loop has been set, triggering the onCompletion() method of the OnCompletionListener.Copy the code

4. Cache progress monitoring

This cache monitor isn’t very useful when you’re reading files in the first place, but the network is different, right

The cache can be heard while the network cache is in use

/ / network streaming media buffer change callback mPlayer. SetOnBufferingUpdateListener ((mp, percent) - > {L.d (" BufferingUpdateListener "+ percent + L.l ()); });Copy the code


5. Dual progress implementation

Cache progress (light blue), play progress (orange), cache progress to see where the cache, also easy to drag


5.1 – NetMusicPlayer processing
/ / network streaming media buffer change callback mPlayer. SetOnBufferingUpdateListener ((mp, percent) - > {the if (mOnBufferListener! = null) { mOnBufferListener.OnSeek(percent); }}); / / -- -- -- -- -- -- -- -- -- -- -- -- set cache monitor progress -- -- -- -- -- -- -- -- -- -- - public interface OnBufferListener {void OnSeek (int per_100); } private MusicPlayer.OnBufferListener mOnBufferListener; public void setOnBufferListener(MusicPlayer.OnBufferListener onBufferListener) { mOnBufferListener = onBufferListener; }Copy the code
5.2– Callback listener in an Activity
musicPlayer.setOnBufferListener(per_100 -> {
    mIdPvPre.setProgress2(per_100);
});
Copy the code

Well, that’s it: leave a picture of the town building


Postscript: Jie wen standard

1. Growth record and Errata of this paper
Program source code The date of note
V0.1 – making The 2018-1-4 MP3 and built-in MediaPlayer
2. More about me
Pen name QQ WeChat hobby
Zhang Feng Jie te Li 1981462002 zdl1994328 language
My lot My Jane books I’m the nuggets Personal website
3. The statement

1—- This article is originally written by Zhang Fengjie, please note if reproduced

2—- welcome the majority of programming enthusiasts to communicate with each other 3—- personal ability is limited, if there is something wrong welcome to criticize and testify, must be humble to correct 4—- see here, I thank you here for your love and support