"Android Development experience" Implementation of "Sonic Communication/verification" for mobile devices--sinvoice Open Source project Introduction (ii)

Source: Internet
Author: User

Reprint Please specify source: http://blog.csdn.net/zhaokaiqiang1992

In the previous article, we introduced the principle and basic use of acoustic communication/verification, and we'll talk about some of the details.

One more project structure diagram


The Sinvoiceplayer class is a class that we use directly in contact with, by calling the play () method, we can play out the numbers that need to be transferred, and here is the code implementation of this class

/* Copyright (C) Gujicheng * * Licensed under the GPL License Version 2.0; * You are not a use this file except in compliance with the License. * * If you had any question, please contact me.                                * ************************************************************************* * * Author information * * ************************************************************************* * Email: [EMAIL&NB                                                     sp;protected] * * * * qq:29600731 * * * * weibo:http://weibo.com/gujicheng197 * * *************************************** */package Com.libra.sinvoice;import Java.util.arraylist;import java.util.List; Import Android.media.audioformat;import android.text.textutils;import com.libra.sinvoice.buffer.bufferdata;/** * * @ ClassName:com.libra.sinvoice.SinVoicePlayer * @Description: Sound Playback class * @author ZHAOKAiqiang * @date 2014-11-15 PM 12:56:57 * */public class Sinvoiceplayer implements Encoder.listener, Encoder.callback,pcmpl Ayer. Listener, Pcmplayer.callback {private final static String TAG = "Sinvoiceplayer";p rivate final static int state_start = 1; Private final static int state_stop = 2;private final static int state_pending = 3;//default interval time private final static int DEFA Ult_gen_duration = 100;private String mcodebook;//for storing numbers encoded using Coodbook private list<integer> mcodes = new Arraylist<integer> ();p rivate Encoder mencoder;private pcmplayer mplayer;private Buffer mbuffer;private int Mstate;private Listener mlistener;private thread mplaythread;private thread Mencodethread;public static interface Listener {void Onplaystart (); void Onplayend ();} Public Sinvoiceplayer () {this (common.default_code_book);} Public Sinvoiceplayer (String codeBook) {This (CodeBook, Common.default_sample_rate, Common.default_buffer_size, Common.default_buffer_count);} /** * Constructor * * * @param codeBook * @param samplErate * sample Rate * @param buffersize * Buffer Volume * @param buffcount * Number of buffers */public Sinvoiceplaye R (String codeBook, int samplerate, int buffersize,int buffcount) {mstate = State_stop;mbuffer = new Buffer (Buffcount, Buff ersize); mencoder = new Encoder (this, samplerate, singenerator.bits_16,buffersize); Mencoder.setlistener (this); MPlayer = new Pcmplayer (this, samplerate, Audioformat.channel_out_mono,audioformat.encoding_pcm_16bit, bufferSize); Mplayer.setlistener (this); Setcodebook (CodeBook);} public void Setlistener (Listener Listener) {mlistener = Listener;} public void Setcodebook (String codeBook) {if (! Textutils.isempty (CodeBook) && codebook.length () < Encoder.getmaxcodecount ()-1) {mcodebook = CodeBook;}} /** * The text to be encrypted is encoded according to Codebook * * @param text * @return Whether the encoding succeeds */private boolean converttexttocodes (String text) {Boolean r ET = true;if (! Textutils.isempty (text)) {mcodes.clear (); Mcodes.add (common.start_token); int len = Text.length (); for (int i = 0; I < Len ++i) {Char ch = text.charat (i); int index = MCODEBOOK.INDEXOF (CH), if (Index >-1) {Mcodes.add (index + 1);} else {ret = f Alse; LOGHELPER.D (TAG, "invalidate char:" + ch); break;}} if (ret) {mcodes.add (Common.stop_token);}} else {ret = false;} return ret;} public void Play (final String text) {if (State_stop = = Mstate && null! = mcodebook&& Converttexttocodes (te XT) {mstate = State_pending;mplaythread = new Thread () {@Overridepublic void run () {Mplayer.start ();}}; if (null! = Mplaythread) {Mplaythread.start ();} Mencodethread = new Thread () {@Overridepublic void run () {Mencoder.encode (mcodes, default_gen_duration); Stopplayer (); Mencoder.stop (); Mplayer.stop ();}; if (null! = Mencodethread) {Mencodethread.start ();} Mstate = State_start;}} public void Stop () {if (State_start = = mstate) {mstate = State_pending;mencoder.stop (); if (null! = Mencodethread) {try {ME Ncodethread.join ();} catch (Interruptedexception e) {e.printstacktrace ();} finally {mencodethread = null;}}} private voidStopplayer () {if (mencoder.isstoped ()) {mplayer.stop ();} Put End Buffermbuffer.putfull (Bufferdata.getemptybuffer ()), if (null! = Mplaythread) {try {mplaythread.join ();} catch (Interruptedexception e) {E.printstacktrace ();} finally {mplaythread = null;}} Mbuffer.reset (); mstate = State_stop;} @Overridepublic void Onstartencode () {LOGHELPER.D (TAG, "Onstartgen");} @Overridepublic void Freeencodebuffer (Bufferdata buffer) {if (null! = buffer) {mbuffer.putfull (buffer);}} @Overridepublic bufferdata Getencodebuffer () {return mbuffer.getempty ();} @Overridepublic void Onendencode () {} @Overridepublic bufferdata Getplaybuffer () {return mbuffer.getfull ();} @Overridepublic void Freeplaydata (Bufferdata data) {mbuffer.putempty (data);} @Overridepublic void Onplaystart () {if (null! = Mlistener) {Mlistener.onplaystart ();}} @Overridepublic void Onplaystop () {if (null! = Mlistener) {mlistener.onplayend ();}}}

The following are some of the main things about this class:

1.default_gen_duration refers to the interval between each audio signal, which defaults to 0.1 seconds

The 2.convertTextToCodes () method is to filter the text that needs to be encoded, the filter rule is codebook, if the number to be transferred is not in the Codebook, the program will not continue to execute down

Although the Sinvoiceplayer class is important, it is not him that actually completes the sound playback task, but the Pcmplayer class. Because some of the source code naming is very confusing and unclear, so I modified some of the names, if you want to see the original project students do not feel surprised. Let's take a look at the implementation of this class.

/* Copyright (C) Gujicheng * * Licensed under the GPL License Version 2.0; * You are not a use this file except in compliance with the License. * * If you had any question, please contact me.                                * ************************************************************************* * * Author information * * ************************************************************************* * Email: [EMAIL&NB                                                     sp;protected] * * * * qq:29600731 * * * * weibo:http://weibo.com/gujicheng197 * * *************************************** */package Com.libra.sinvoice;import Android.media.audiomanager;import Android.media.audiotrack;import com.libra.sinvoice.buffer.bufferdata;/** * * @ClassName: Com.libra.sinvoice.PcmPlayer * @Description: PCM player * @author Zhaokaiqiang * @date 2014-11-15 pm 1:10:18 * */public CLass Pcmplayer {Private final static String TAG = "Pcmplayer";p rivate final static int state_start = 1;private final Stati c int state_stop = 2;//playback state, used to control playback or to stop private int mstate;private audiotrack audiotrack;//The length of bytes already played private long Playedl En;private pcmlistener pcmlistener;private pcmcallback playercallback;public static interface Pcmlistener {void Onpcmplaystart (); void Onpcmplaystop ();} public static interface Pcmcallback {Bufferdata getplaybuffer (); void Freeplaydata (Bufferdata data);} Public Pcmplayer (Pcmcallback callback, int samplerate, int channel,int format, int buffersize) {playercallback = callback; Initialize the Audiotrack object (audio stream type, sample rate, channel, format, buffer size, mode) Audiotrack = new Audiotrack (Audiomanager.stream_music, Samplerate, Channel, format, buffersize, audiotrack.mode_stream); mstate = State_stop;} public void Setlistener (Pcmlistener listener) {Pcmlistener = listener;} public void Start () {if (State_stop = = Mstate && null! = audiotrack) {mstate = State_start;playedlen = 0;if (null ! = PLAYercallback) {if (null! = Pcmlistener) {Pcmlistener.onpcmplaystart ();} while (State_start = = mstate) {//Gets the byte data to play Bufferdata-playercallback.getplaybuffer (); if (null! = data) {if (null!). = Data.bytedata) {//Set the Byte data to play int len = Audiotrack.write (Data.bytedata, 0,data.getfilledsize ());//First entry, play sound if (0 = = PLA Yedlen) {audiotrack.play ();} Playedlen + = len;//release data playercallback.freeplaydata;} else {LOGHELPER.D (TAG, "It is the end of input, so need stop"); else {LOGHELPER.D (TAG, "get null Data"); break;}} if (state_stop = = mstate) {audiotrack.pause (); Audiotrack.flush (); Audiotrack.stop ();} if (null! = Pcmlistener) {pcmlistener.onpcmplaystop ();}} else {throw new IllegalArgumentException ("Pcmcallback can ' t be null");}}} public void Stop () {if (State_start = = Mstate && null! = audiotrack) {mstate = State_stop;}}}

with regard to this class, the emphasis is on the following points:

1.PcmPalyer is through the Audiotrack class to achieve single-frequency playback, in the initialization of Audiotrack objects, you need to wear a lot of parameters, I have commented in the code. When initializing the Pcmplayer object in Sinvoiceplayer, the following parameters are used for initialization

MPlayer = new pcmplayer (This, samplerate, Audioformat. Channel_out_mono,

Audioformat. encoding_pcm_16bit, buffersize);

Samplerate is the sample rate, the default 44.1khz,audioformat. Channel_out_mono is the use of mono playback, as well as Stereo is a two-channel mode, in order to ensure consistent frequency, the use of mono is the most reasonable. Audioformat. Encoding_pcm_16bit refers to the use of 16-bit PCM format encoding, PCM is also a sound encoding format.


2. The while loop inside the start () method is used to continuously remove the byte data to be played,Audiotrack. The play () method executes only once and assigns the Mstate value to State_stop in STOP (). The while loop exits, executing the Stop method below Audiotrack to end the playback of the sound.


Now that the burden of the last sound is falling on the Audiotrack class, there is no reason why we should not be aware of this class.


Audiotrack is a class used to play sounds, and the constructors need to pass the following parameters

Public Audiotrack (int streamtype, int samplerateinhz, int channelconfig, int Audioformat ,

int buffersizeinbytes, int mode)


focus on what the first and last parameters mean.

There are two categories of mode_static and Mode_stream in Audiotrack. Stream means that the user writes the data once in the application through write to Audiotrack. This is the same as when we send data in the socket, the application layer obtains data from somewhere, for example by encoding and decoding the PCM data, and then write to Audiotrack. The disadvantage of this way is always in the Java layer and native layer interaction, the efficiency loss is large.
Static means that at the beginning of the creation, the audio data is placed in a fixed buffer, and then directly to the Audiotrack, follow-up will not have to write again. The Audiotrack will play the data in the buffer itself. This method is suitable for low memory usage such as ringtones, and for sounds with higher latency requirements.

Since we need to write different data dynamically, so we need to use the Mode_stream mode, the above code, is the first write data, and then play (), in fact, the formal style is the first play (), The Write method then writes the byte data to the Audiotrack. I was puzzled at first, and later found out that the play method was executed only once, and the Write method executes multiple times, while the input data is output.


The first parameter in constructing the Audiotrack Streamtype is related to the Audiomanager in Android, which involves the audio management strategy on the phone.
Android will divide the system's sound into the following categories of common:
Stream_alarm: Warning Sound
Stream_musci: Musical sounds, such as music, etc.
Stream_ring: Ringtones
Stream_system: System Sound
Stream_vocie_call: Telephone Voice


Why do you divide so much? For example, when listening to music to receive a phone call, this time music playback will definitely stop, at this time you can only hear the phone, if you adjust the volume, this adjustment is definitely only for the telephone function. When the phone is finished, and then back to music, you must not adjust the volume. This allows the system to manage the data of these kinds of sounds separately.


This article first introduces here, the next article will introduce the implementation details of the digital coding.

"Android Development experience" Implementation of "Sonic Communication/verification" for mobile devices--sinvoice Open Source project Introduction (ii)

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.