根据环信3.0集成的视频通话

本项目中我用到的第三方框架:evenbus,和ButterKnife

 ButterKnife:
@BindView(R.id.tv_call_state)
  TextView callStateTextView;
这句就相当于findViewById

@OnClick(R.id.register)
相当于给这个id设置了点击监听


eventbus:

其实很简单,前面有介绍 ,这里就不多说了


第一步就是当环信官网下载jar包并放入自己的项目里面


整个项目需要那几包类和包如图


在Manifest的要声明的权限和service,activity

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.yangzhelin.myvideo30">
    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.GET_TASKS" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

    <application
        android:name=".app.App"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".activities.MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <!-- 设置环信应用的AppKey -->
        <meta-data android:name="EASEMOB_APPKEY"  android:value="9i#110" />
        <!-- 声明SDK所需的service SDK核心功能-->
        <service android:name="com.hyphenate.chat.EMChatService" android:exported="true"/>
        <!-- 声明SDK所需的receiver -->
        <receiver android:name="com.hyphenate.chat.EMMonitorReceiver">
            <intent-filter>
                <action android:name="android.intent.action.PACKAGE_REMOVED"/>
                <data android:scheme="package"/>
            </intent-filter>
            <!-- 可选filter -->
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
                <action android:name="android.intent.action.USER_PRESENT" />
            </intent-filter>
        </receiver>
        <!-- 视频通话 -->
        <activity
            android:name=".activities.VideoCallActivity"
            android:configChanges="orientation|keyboardHidden|screenSize"
            android:screenOrientation="portrait"
            android:launchMode="singleTask"
            android:theme="@style/horizontal_slide" >
        </activity>
    </application>

</manifest>

下面是整个项目的的代码:

package com.example.yangzhelin.myvideo30.app;

import android.app.Application;
import android.content.Context;
import android.content.IntentFilter;


import com.example.yangzhelin.myvideo30.receiver.CallReceiver;
import com.hyphenate.chat.EMClient;
import com.hyphenate.chat.EMOptions;


/**
 * User:yangzhelin
 * Date:2015-09-18
 * Time: 11:31
 */
public class App extends Application{
    public static Context applicationContext;
    private CallReceiver callReceiver;
    @Override
    public void onCreate() {
        super.onCreate();
        applicationContext = this;
        EMOptions options = new EMOptions();
// 默认添加好友时,是不需要验证的,改成需要验证
        options.setAcceptInvitationAlways(false);
        EMClient.getInstance().init(applicationContext, options);
//在做打包混淆时,关闭debug模式,避免消耗不必要的资源
        EMClient.getInstance().setDebugMode(true);

        //注册通话广播接收者
        registerReceiver(new CallReceiver(), new IntentFilter(EMClient.getInstance().callManager().getIncomingCallBroadcastAction()));
    }

}
/**
 * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *     http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.example.yangzhelin.myvideo30.receiver;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

import com.example.yangzhelin.myvideo30.activities.VideoCallActivity;
import com.example.yangzhelin.myvideo30.DemoHelper;
import com.hyphenate.util.EMLog;

/**
 * Created by yangzhelin on 2016/7/28.
 */
public class CallReceiver extends BroadcastReceiver{

   @Override
   public void onReceive(Context context, Intent intent) {
      if(!DemoHelper.getInstance().isLoggedIn())
         return;
      //username
      String from = intent.getStringExtra("from");
      //call type
      String type = intent.getStringExtra("type");
      if("video".equals(type)){ //video call
         context.startActivity(new Intent(context, VideoCallActivity.class).
               putExtra("username", from).putExtra("isComingCall", true).
               addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
      }else{ //voice call
//       context.startActivity(new Intent(context, VoiceCallActivity.class).
//             putExtra("username", from).putExtra("isComingCall", true).
//             addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
      }
      EMLog.d("CallReceiver", "app received a incoming call");
   }

}
package com.example.yangzhelin.myvideo30;


import com.hyphenate.chat.EMClient;

public class DemoHelper {

    private static DemoHelper instance = null;
    public boolean isVoiceCalling;
    public boolean isVideoCalling;
    private DemoHelper() {
    }

    public synchronized static DemoHelper getInstance() {
        if (instance == null) {
            instance = new DemoHelper();
        }
        return instance;
    }
    /**
     * if ever logged in
     *
     * @return
     */
    public boolean isLoggedIn() {
        return EMClient.getInstance().isLoggedInBefore();
    }
}
package com.example.yangzhelin.myvideo30;


import com.halove.android.framework.event.BaseEvent;

/**
 * Copyright (2012-2016) by 杭州九爱科技有限公司. All rights reserved
 * Comments:
 *
 * @author yining
 *         Created on 2016/7/4
 */

public class ToastEvent extends BaseEvent {
    public String text;

    public ToastEvent(String text) {
        this.text = text;
    }

}
package com.example.yangzhelin.myvideo30.util;

import android.content.Context;

/**
 * Created by yangzhelin on 2016/7/28.
 */
public interface IVideoManager {
    /**注册
     * 用户名字
     * @param username*
     * 用户密码
     * @param password
     * @return
     */
    void register(String username, String password);

    /**
     * 登入服务器
     * @param username
     * @param password
     */
    void login(String username, String password);

    /**
     * 登出服务器
     */
    void logout();

    /**
     * 视频聊天
     * @param username
     */
    void video(String username);

    /**
     * 语音聊天
     * @param username
     */
    void voice(String username);



}
package com.example.yangzhelin.myvideo30.util;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;

import com.example.yangzhelin.myvideo30.ToastEvent;
import com.example.yangzhelin.myvideo30.activities.VideoCallActivity;
import com.hyphenate.EMCallBack;
import com.hyphenate.chat.EMClient;
import com.hyphenate.exceptions.HyphenateException;

/**
 * Created by yangzhelin on 2016/7/28.
 */
public class VideoManager implements IVideoManager {
    private static IVideoManager instance = null;
    private Context context;

    private VideoManager(Context context){
        this.context=context;
    }

    public  synchronized static IVideoManager getInstance(Context context){
        if (instance == null) {
            instance = new VideoManager(context);
        }
        return instance;
    }
    @Override
    public void register(final String username, final String password) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                //注册失败会抛出HyphenateException
                try {
                    EMClient.getInstance().createAccount(username, password);//同步方法
                } catch (final HyphenateException e) {
                    toast("注册失败"+ e.getMessage());
                }
            }
        }).start();
    }

    @Override
    public void login(String username, String password) {
        if(TextUtils.isEmpty(username)){
            toast("请输入用户");
            return;
        }else if(TextUtils.isEmpty(password)){
            toast("请输入密码");
            return;
        }

        EMClient.getInstance().login(username,password,new EMCallBack() {//回调
            @Override
            public void onSuccess() {
                EMClient.getInstance().groupManager().loadAllGroups();
                EMClient.getInstance().chatManager().loadAllConversations();
                Log.d("main", "登录聊天服务器成功!");
                toast("登入成功");
            }
            @Override
            public void onProgress(int progress, String status) {

            }
            @Override
            public void onError(int code, String message) {
//                Log.d("main", "登录聊天服务器失败!");
                toast("登入失败");
            }
        });
    }

    @Override
    public void logout() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                EMClient.getInstance().logout(true, new EMCallBack() {

                    @Override
                    public void onSuccess() {
                        toast("退出成功");
                    }
                    @Override
                    public void onProgress(int progress, String status) {
                    }
                    @Override
                    public void onError(int code, String message) {

                        toast("退出失败");
                    }
                });
            }
        }).start();

    }

    @Override
    public void video(String toUser) {
        if (! EMClient.getInstance().isConnected()) {
            toast("未连接到服务器");
            return;
        }else{
            if (TextUtils.isEmpty(toUser)){
                toast("请填写接受方账号");
                return ;
            }
            Intent intent = new Intent(context, VideoCallActivity.class);
            intent.putExtra("username", toUser);
            intent.putExtra("isComingCall", false);
            context.startActivity(intent);
        }
    }

    @Override
    public void voice(String username) {

    }
    public void toast(final String text){
        new ToastEvent(text).fire();

    }
}


/**
 * Copyright (C) 2016 Hyphenate Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *     http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.example.yangzhelin.myvideo30.activities;

import java.util.UUID;

import com.example.yangzhelin.myvideo30.DemoHelper;
import com.example.yangzhelin.myvideo30.R;
import com.hyphenate.chat.EMCallManager.EMCameraDataProcessor;
import com.hyphenate.chat.EMCallManager.EMVideoCallHelper;
import com.hyphenate.chat.EMCallStateChangeListener;
import com.hyphenate.chat.EMClient;

import com.hyphenate.media.EMLocalSurfaceView;
import com.hyphenate.media.EMOppositeSurfaceView;

import com.hyphenate.util.PathUtil;

import android.hardware.Camera;
import android.media.AudioManager;
import android.media.RingtoneManager;
import android.media.SoundPool;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.WindowManager;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.widget.Button;
import android.widget.Chronometer;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;

import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;

public class VideoCallActivity extends CallActivity  {


    @BindView(R.id.tv_call_state)
    TextView callStateTextView;
    @BindView(R.id.ll_coming_call)
    LinearLayout comingBtnContainer;
    @BindView(R.id.btn_refuse_call)
    Button refuseBtn;
    @BindView(R.id.btn_answer_call)
    Button answerBtn;
    @BindView(R.id.btn_hangup_call)
    Button hangupBtn;
    @BindView(R.id.iv_mute)
    ImageView muteImage;
    @BindView(R.id.iv_handsfree)
    ImageView handsFreeImage;
    @BindView(R.id.tv_nick)
    TextView nickTextView;
    @BindView(R.id.chronometer)
    Chronometer chronometer;
    @BindView(R.id.ll_voice_control)
    LinearLayout voiceContronlLayout;
    @BindView(R.id.root_layout)
    RelativeLayout rootContainer;
    @BindView(R.id.ll_btns)
    RelativeLayout btnsContainer;
    @BindView(R.id.rl_Video_function)
    RelativeLayout videoFunction;
    @BindView(R.id.ll_top_container)
    LinearLayout topContainer;
    @BindView(R.id.ll_bottom_container)
    LinearLayout bottomContainer;
    @BindView(R.id.tv_call_monitor)
    TextView monitorTextView;
    @BindView(R.id.tv_network_status)
    TextView netwrokStatusVeiw;
    @BindView(R.id.btn_record_video)
    Button recordBtn;
    @BindView(R.id.btn_switch_camera)
    Button switchCameraBtn;
    @BindView(R.id.seekbar_y_detal)
    SeekBar YDeltaSeekBar;

    private boolean isMuteState;
    private boolean isHandsfreeState;
    private boolean isAnswered;
    private boolean endCallTriggerByMe = false;
    private boolean monitor = true;
    private boolean isInCalling;
    private boolean isRecording = false;
    private Handler uiHandler;
    private EMVideoCallHelper callHelper;
    private BrightnessDataProcess dataProcessor = new BrightnessDataProcess();
    // dynamic adjust brightness
    class BrightnessDataProcess implements EMCameraDataProcessor {
        byte yDelta = 0;
        synchronized void setYDelta(byte yDelta) {
            Log.d("VideoCallActivity", "brigntness uDelta:" + yDelta);
            this.yDelta = yDelta;
        }
        // data size is width*height*2
        // the first width*height is Y, second part is UV
        // the storage layout detailed please refer 2.x demo CameraHelper.onPreviewFrame
        @Override
        public synchronized void onProcessData(byte[] data, Camera camera, int width, int height) {
            int wh = width * height;
            for (int i = 0; i < wh; i++) {
                int d = (data[i] & 0xFF) + yDelta;
                d = d < 16 ? 16 : d;
                d = d > 235 ? 235 : d;
                data[i] = (byte)d;
            }
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if(savedInstanceState != null){
            finish();
            return;
        }
        setContentView(R.layout.em_activity_video_call);
        ButterKnife.bind(this);
        DemoHelper.getInstance().isVideoCalling = true;
        callType = 1;

        getWindow().addFlags(
                WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
                        | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
                        | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);

        uiHandler = new Handler();

        YDeltaSeekBar.setOnSeekBarChangeListener(new YDeltaSeekBarListener());

        msgid = UUID.randomUUID().toString();
        isInComingCall = getIntent().getBooleanExtra("isComingCall", false);
        username = getIntent().getStringExtra("username");

        nickTextView.setText(username);


        localSurface.setZOrderMediaOverlay(true);
        localSurface.setZOrderOnTop(true);

        // remote surfaceview


        // set call state listener
        addCallStateListener();
        if (!isInComingCall) {// outgoing call
            soundPool = new SoundPool(1, AudioManager.STREAM_RING, 0);
            outgoing = soundPool.load(this, R.raw.em_outgoing, 1);

            comingBtnContainer.setVisibility(View.INVISIBLE);
            hangupBtn.setVisibility(View.VISIBLE);
            String st = getResources().getString(R.string.Are_connected_to_each_other);
            callStateTextView.setText(st);
            EMClient.getInstance().callManager().setSurfaceView(localSurface, oppositeSurface);
            handler.sendEmptyMessage(MSG_CALL_MAKE_VIDEO);
        } else { // incoming call
            voiceContronlLayout.setVisibility(View.INVISIBLE);
            localSurface.setVisibility(View.INVISIBLE);
            Uri ringUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE);
            audioManager.setMode(AudioManager.MODE_RINGTONE);
            audioManager.setSpeakerphoneOn(true);
            ringtone = RingtoneManager.getRingtone(this, ringUri);
            ringtone.play();
            EMClient.getInstance().callManager().setSurfaceView(localSurface, oppositeSurface);
        }

        // get instance of call helper, should be called after setSurfaceView was called
        callHelper = EMClient.getInstance().callManager().getVideoCallHelper();

        EMClient.getInstance().callManager().setCameraDataProcessor(dataProcessor);
    }

    class YDeltaSeekBarListener implements SeekBar.OnSeekBarChangeListener {

        @Override
        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
            dataProcessor.setYDelta((byte)(20.0f * (progress - 50) / 50.0f));
        }

        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {
        }

        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {
        }

    }

    /**
     * set call state listener
     */
    void addCallStateListener() {
        callStateListener = new EMCallStateChangeListener() {

            @Override
            public void onCallStateChanged(CallState callState, final CallError error) {
                switch (callState) {

                    case CONNECTING: // is connecting
                        runOnUiThread(new Runnable() {

                            @Override
                            public void run() {
                                callStateTextView.setText(R.string.Are_connected_to_each_other);
                            }

                        });
                        break;
                    case CONNECTED: // connected
                        runOnUiThread(new Runnable() {

                            @Override
                            public void run() {
                                callStateTextView.setText(R.string.have_connected_with);
                            }

                        });
                        break;

                    case ACCEPTED: // call is accepted
                        handler.removeCallbacks(timeoutHangup);
                        runOnUiThread(new Runnable() {

                            @Override
                            public void run() {
                                try {
                                    if (soundPool != null)
                                        soundPool.stop(streamID);
                                } catch (Exception e) {
                                }
                                openSpeakerOn();
                                ((TextView)findViewById(R.id.tv_is_p2p)).setText(EMClient.getInstance().callManager().isDirectCall()
                                        ? R.string.direct_call : R.string.relay_call);
                                handsFreeImage.setImageResource(R.drawable.em_icon_speaker_on);
                                isHandsfreeState = true;
                                isInCalling = true;
                                chronometer.setVisibility(View.VISIBLE);
                                chronometer.setBase(SystemClock.elapsedRealtime());
                                // call durations start
                                chronometer.start();
                                nickTextView.setVisibility(View.INVISIBLE);
                                callStateTextView.setText(R.string.In_the_call);
                                recordBtn.setVisibility(View.VISIBLE);
                                callingState = CallingState.NORMAL;
//                                startMonitor();
                            }

                        });
                        break;
                    case NETWORK_UNSTABLE:
                        runOnUiThread(new Runnable() {
                            public void run() {
                                netwrokStatusVeiw.setVisibility(View.VISIBLE);
                                if(error == CallError.ERROR_NO_DATA){
                                    netwrokStatusVeiw.setText(R.string.no_call_data);
                                }else{
                                    netwrokStatusVeiw.setText(R.string.network_unstable);
                                }
                            }
                        });
                        break;
                    case NETWORK_NORMAL:

                        runOnUiThread(new Runnable() {
                            public void run() {
                                netwrokStatusVeiw.setVisibility(View.INVISIBLE);
                            }
                        });
                        break;
                    case VIDEO_PAUSE:
                        toastByUi("VIDEO_PAUSE");
                        break;
                    case VIDEO_RESUME:
                        toastByUi("VIDEO_RESUME");
                        break;
                    case VOICE_PAUSE:
                        toastByUi("VOICE_PAUSE");
                        break;
                    case VOICE_RESUME:
                        toastByUi("VOICE_RESUME");
                        break;
                    case DISCONNNECTED: // call is disconnected
                        handler.removeCallbacks(timeoutHangup);
                        final CallError fError = error;
                        runOnUiThread(new Runnable() {
                            private void postDelayedCloseMsg() {
                                uiHandler.postDelayed(new Runnable() {

                                    @Override
                                    public void run() {
                                        saveCallRecord();
                                        Animation animation = new AlphaAnimation(1.0f, 0.0f);
                                        animation.setDuration(800);
                                        rootContainer.startAnimation(animation);
                                        finish();
                                    }

                                }, 200);
                            }

                            @Override
                            public void run() {
                                chronometer.stop();
                                callDruationText = chronometer.getText().toString();
                                String s1 = getResources().getString(R.string.The_other_party_refused_to_accept);
                                String s2 = getResources().getString(R.string.Connection_failure);
                                String s3 = getResources().getString(R.string.The_other_party_is_not_online);
                                String s4 = getResources().getString(R.string.The_other_is_on_the_phone_please);
                                String s5 = getResources().getString(R.string.The_other_party_did_not_answer);

                                String s6 = getResources().getString(R.string.hang_up);
                                String s7 = getResources().getString(R.string.The_other_is_hang_up);
                                String s8 = getResources().getString(R.string.did_not_answer);
                                String s9 = getResources().getString(R.string.Has_been_cancelled);

                                if (fError == CallError.REJECTED) {
                                    callingState = CallingState.BEREFUESD;
                                    callStateTextView.setText(s1);
                                } else if (fError == CallError.ERROR_TRANSPORT) {
                                    callStateTextView.setText(s2);
                                } else if (fError == CallError.ERROR_INAVAILABLE) {
                                    callingState = CallingState.OFFLINE;
                                    callStateTextView.setText(s3);
                                } else if (fError == CallError.ERROR_BUSY) {
                                    callingState = CallingState.BUSY;
                                    callStateTextView.setText(s4);
                                } else if (fError == CallError.ERROR_NORESPONSE) {
                                    callingState = CallingState.NORESPONSE;
                                    callStateTextView.setText(s5);
                                }else if (fError == CallError.ERROR_LOCAL_VERSION_SMALLER || fError == CallError.ERROR_PEER_VERSION_SMALLER){
                                    callingState = CallingState.VERSION_NOT_SAME;
                                    callStateTextView.setText(R.string.call_version_inconsistent);
                                }  else {
                                    if (isAnswered) {
                                        callingState = CallingState.NORMAL;
                                        if (endCallTriggerByMe) {
//                                        callStateTextView.setText(s6);
                                        } else {
                                            callStateTextView.setText(s7);
                                        }
                                    } else {
                                        if (isInComingCall) {
                                            callingState = CallingState.UNANSWERED;
                                            callStateTextView.setText(s8);
                                        } else {
                                            if (callingState != CallingState.NORMAL) {
                                                callingState = CallingState.CANCED;
                                                callStateTextView.setText(s9);
                                            } else {
                                                callStateTextView.setText(s6);
                                            }
                                        }
                                    }
                                }
                                postDelayedCloseMsg();
                            }

                        });

                        break;

                    default:
                        break;
                }

            }
        };
        EMClient.getInstance().callManager().addCallStateChangeListener(callStateListener);
    }
    public void toastByUi(final String text){
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(VideoCallActivity.this, text, Toast.LENGTH_SHORT).show();
            }
        });
    }

    @OnClick(R.id.btn_refuse_call)
    public void btn_refuse_call(){
        refuseBtn.setEnabled(false);
        handler.sendEmptyMessage(MSG_CALL_REJECT);
    }
    @OnClick(R.id.btn_answer_call)
    public void btn_answer_call(){
        answerBtn.setEnabled(false);
        openSpeakerOn();
        if (ringtone != null)
            ringtone.stop();

        callStateTextView.setText("answering...");
        handler.sendEmptyMessage(MSG_CALL_ANSWER);
        handsFreeImage.setImageResource(R.drawable.em_icon_speaker_on);
        isAnswered = true;
        isHandsfreeState = true;
        comingBtnContainer.setVisibility(View.INVISIBLE);
        hangupBtn.setVisibility(View.VISIBLE);
        voiceContronlLayout.setVisibility(View.VISIBLE);
        localSurface.setVisibility(View.VISIBLE);
    }
    @OnClick(R.id.btn_hangup_call)
    public void btn_hangup_call(){
        hangupBtn.setEnabled(false);
        chronometer.stop();
        endCallTriggerByMe = true;
        callStateTextView.setText(getResources().getString(R.string.hanging_up));
        if(isRecording){
            callHelper.stopVideoRecord();
        }
        handler.sendEmptyMessage(MSG_CALL_END);
    }
    @OnClick(R.id.iv_mute)
    public void iv_mute(){
        if (isMuteState) {
            // resume voice transfer
            muteImage.setImageResource(R.drawable.em_icon_mute_normal);
            EMClient.getInstance().callManager().resumeVoiceTransfer();
            isMuteState = false;
        } else {
            // pause voice transfer
            muteImage.setImageResource(R.drawable.em_icon_mute_on);
            EMClient.getInstance().callManager().pauseVoiceTransfer();
            isMuteState = true;
        }
    }
    @OnClick(R.id.iv_handsfree)
    public void iv_handsfree(){
        if (isHandsfreeState) {
            // turn off speaker
            handsFreeImage.setImageResource(R.drawable.em_icon_speaker_normal);
            closeSpeakerOn();
            isHandsfreeState = false;
        } else {
            handsFreeImage.setImageResource(R.drawable.em_icon_speaker_on);
            openSpeakerOn();
            isHandsfreeState = true;
        }
    }
    @OnClick(R.id.btn_record_video)
    public void btn_record_video(){
        if(!isRecording){
            callHelper.startVideoRecord(PathUtil.getInstance().getVideoPath().getAbsolutePath());
            isRecording = true;
            recordBtn.setText(R.string.stop_record);
        }else{
            String filepath = callHelper.stopVideoRecord();
            isRecording = false;
            recordBtn.setText(R.string.recording_video);
            Toast.makeText(getApplicationContext(), String.format(getString(R.string.record_finish_toast), filepath), Toast.LENGTH_LONG).show();
        }
    }
    @OnClick(R.id.root_layout)
    public void root_layout(){
        if (callingState == CallingState.NORMAL) {
            if (bottomContainer.getVisibility() == View.VISIBLE) {
                bottomContainer.setVisibility(View.GONE);
                topContainer.setVisibility(View.GONE);
                videoFunction.setVisibility(View.GONE);

            } else {
                bottomContainer.setVisibility(View.VISIBLE);
                topContainer.setVisibility(View.VISIBLE);
                videoFunction.setVisibility(View.VISIBLE);
            }
        }
    }
    @OnClick(R.id.btn_switch_camera)
    public void btn_switch_camera(){
        handler.sendEmptyMessage(MSG_CALL_SWITCH_CAMERA);
    }


    @Override
    protected void onDestroy() {
        DemoHelper.getInstance().isVideoCalling = false;
        stopMonitor();
        if(isRecording){
            callHelper.stopVideoRecord();
            isRecording = false;
        }
        localSurface = null;
        oppositeSurface = null;
        super.onDestroy();
    }

    @Override
    public void onBackPressed() {
        callDruationText = chronometer.getText().toString();
        super.onBackPressed();
    }

    /**
     * for debug & testing, you can remove this when release
     */
    void startMonitor(){
        new Thread(new Runnable() {
            public void run() {
                while(monitor){
                    runOnUiThread(new Runnable() {
                        public void run() {
                            monitorTextView.setText("WidthxHeight"+callHelper.getVideoWidth()+"x"+callHelper.getVideoHeight()
                                    + "\nDelay" + callHelper.getVideoTimedelay()
                                    + "\nFramerate" + callHelper.getVideoFramerate()
                                    + "\nLost" + callHelper.getVideoLostcnt()
                                    + "\nLocalBitrate" + callHelper.getLocalBitrate()
                                    + "\nRemoteBitrate" + callHelper.getRemoteBitrate());

                        }
                    });
                    try {
                        Thread.sleep(1500);
                    } catch (InterruptedException e) {
                    }
                }
            }
        }).start();
    }

    void stopMonitor(){
        monitor = false;
    }

    @Override
    protected void onUserLeaveHint() {
        super.onUserLeaveHint();
        if(isInCalling){
            EMClient.getInstance().callManager().pauseVideoTransfer();
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        if(isInCalling){
            EMClient.getInstance().callManager().resumeVideoTransfer();
        }
    }

}
package com.example.yangzhelin.myvideo30.activities;

import com.example.yangzhelin.myvideo30.R;
import com.hyphenate.chat.EMCallStateChangeListener;
import com.hyphenate.chat.EMClient;
import com.hyphenate.chat.EMMessage;
import com.hyphenate.chat.EMMessage.Status;
import com.hyphenate.chat.EMTextMessageBody;

import com.hyphenate.exceptions.EMServiceNotReadyException;
import com.hyphenate.media.EMLocalSurfaceView;
import com.hyphenate.media.EMOppositeSurfaceView;
import com.hyphenate.util.EMLog;
import com.hyphenate.util.NetUtils;

import android.app.Activity;
import android.content.Context;
import android.media.AudioManager;
import android.media.Ringtone;
import android.media.SoundPool;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.widget.Toast;

import butterknife.BindView;

public class CallActivity extends Activity {
    protected final int MSG_CALL_MAKE_VIDEO = 0;
    protected final int MSG_CALL_MAKE_VOICE = 1;
    protected final int MSG_CALL_ANSWER = 2;
    protected final int MSG_CALL_REJECT = 3;
    protected final int MSG_CALL_END = 4;
    protected final int MSG_CALL_RLEASE_HANDLER = 5;
    protected final int MSG_CALL_SWITCH_CAMERA = 6;

    protected boolean isInComingCall;
    protected String username;
    protected CallingState callingState = CallingState.CANCED;
    protected String callDruationText;
    protected String msgid;
    protected AudioManager audioManager;
    protected SoundPool soundPool;
    protected Ringtone ringtone;
    protected int outgoing;
    protected EMCallStateChangeListener callStateListener;
    @BindView(R.id.local_surface)
    protected EMLocalSurfaceView localSurface;
    @BindView(R.id.opposite_surface)
    protected EMOppositeSurfaceView oppositeSurface;
    protected boolean isAnswered = false;
    protected int streamID = -1;

    /**
     * 0voice call1video call
     */
    protected int callType = 0;

    @Override
    protected void onCreate(Bundle arg0) {
        super.onCreate(arg0);
        audioManager = (AudioManager) this.getSystemService(Context.AUDIO_SERVICE);
    }

    @Override
    protected void onDestroy() {
        if (soundPool != null)
            soundPool.release();
        if (ringtone != null && ringtone.isPlaying())
            ringtone.stop();
        audioManager.setMode(AudioManager.MODE_NORMAL);
        audioManager.setMicrophoneMute(false);

        if(callStateListener != null)
            EMClient.getInstance().callManager().removeCallStateChangeListener(callStateListener);
        releaseHandler();
        super.onDestroy();
    }

    @Override
    public void onBackPressed() {
        handler.sendEmptyMessage(MSG_CALL_END);
        saveCallRecord();
        finish();
        super.onBackPressed();
    }

    Runnable timeoutHangup = new Runnable() {

        @Override
        public void run() {
            handler.sendEmptyMessage(MSG_CALL_END);
        }
    };

    HandlerThread callHandlerThread = new HandlerThread("callHandlerThread");
    { callHandlerThread.start(); }
    protected Handler handler = new Handler(callHandlerThread.getLooper()) {
        @Override
        public void handleMessage(Message msg) {
            EMLog.d("EMCallManager CallActivity", "handleMessage ---enter--- msg.what:" + msg.what);
            switch (msg.what) {
                case MSG_CALL_MAKE_VIDEO:
                case MSG_CALL_MAKE_VOICE:
                    try {
                        streamID = playMakeCallSounds();
                        if (msg.what == MSG_CALL_MAKE_VIDEO) {
                            EMClient.getInstance().callManager().makeVideoCall(username);
                        } else {
                            EMClient.getInstance().callManager().makeVoiceCall(username);
                        }

                        final int MAKE_CALL_TIMEOUT = 50 * 1000;
                        handler.removeCallbacks(timeoutHangup);
                        handler.postDelayed(timeoutHangup, MAKE_CALL_TIMEOUT);
                    } catch (EMServiceNotReadyException e) {
                        e.printStackTrace();
                        runOnUiThread(new Runnable() {
                            public void run() {
                                final String st2 = getResources().getString(R.string.Is_not_yet_connected_to_the_server);
                                Toast.makeText(CallActivity.this, st2, Toast.LENGTH_SHORT).show();
                            }
                        });
                    }
                    break;
                case MSG_CALL_ANSWER:
                    if (ringtone != null)
                        ringtone.stop();
                    if (isInComingCall) {
                        try {
                            if (NetUtils.hasDataConnection(CallActivity.this)) {
                                EMClient.getInstance().callManager().answerCall();
                                isAnswered = true;
                            } else {
                                runOnUiThread(new Runnable() {
                                    public void run() {
                                        final String st2 = getResources().getString(R.string.Is_not_yet_connected_to_the_server);
                                        Toast.makeText(CallActivity.this, st2, Toast.LENGTH_SHORT).show();
                                    }
                                });
                                throw new Exception();
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                            saveCallRecord();
                            finish();
                            return;
                        }
                    }
                    break;
                case MSG_CALL_REJECT:
                    if (ringtone != null)
                        ringtone.stop();
                    try {
                        EMClient.getInstance().callManager().rejectCall();
                    } catch (Exception e1) {
                        e1.printStackTrace();
                        saveCallRecord();
                        finish();
                    }
                    callingState = CallingState.REFUESD;
                    break;
                case MSG_CALL_END:
                    if (soundPool != null)
                        soundPool.stop(streamID);
                    try {
                        EMClient.getInstance().callManager().endCall();
                    } catch (Exception e) {
                        saveCallRecord();
                        finish();
                    }

                    break;
                case MSG_CALL_RLEASE_HANDLER:
                    try {
                        EMClient.getInstance().callManager().endCall();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    handler.removeCallbacks(timeoutHangup);
                    handler.removeMessages(MSG_CALL_MAKE_VIDEO);
                    handler.removeMessages(MSG_CALL_MAKE_VOICE);
                    handler.removeMessages(MSG_CALL_ANSWER);
                    handler.removeMessages(MSG_CALL_REJECT);
                    handler.removeMessages(MSG_CALL_END);
                    callHandlerThread.quit();
                    break;
                case MSG_CALL_SWITCH_CAMERA:
                    EMClient.getInstance().callManager().switchCamera();
                    break;
                default:
                    break;
            }
            EMLog.d("EMCallManager CallActivity", "handleMessage ---exit--- msg.what:" + msg.what);
        }
    };

    void releaseHandler() {
        handler.sendEmptyMessage(MSG_CALL_RLEASE_HANDLER);
    }

    /**
     * play the incoming call ringtone
     *
     */
    protected int playMakeCallSounds() {
        try {
            // max volume
            float audioMaxVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_RING);
            // current volume
            float audioCurrentVolume = audioManager.getStreamVolume(AudioManager.STREAM_RING);
            float volumeRatio = audioCurrentVolume / audioMaxVolume;

            audioManager.setMode(AudioManager.MODE_RINGTONE);
            audioManager.setSpeakerphoneOn(false);

            // play
            int id = soundPool.play(outgoing, // sound resource
                    0.3f, // left volume
                    0.3f, // right volume
                    1,    // priority
                    -1,   // loop0 is no loop-1 is loop forever
                    1);   // playback rate (1.0 = normal playback, range 0.5 to 2.0)
            return id;
        } catch (Exception e) {
            return -1;
        }
    }

    protected void openSpeakerOn() {
        try {
            if (!audioManager.isSpeakerphoneOn())
                audioManager.setSpeakerphoneOn(true);
            audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    protected void closeSpeakerOn() {

        try {
            if (audioManager != null) {
                // int curVolume =
                // audioManager.getStreamVolume(AudioManager.STREAM_VOICE_CALL);
                if (audioManager.isSpeakerphoneOn())
                    audioManager.setSpeakerphoneOn(false);
                audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
                // audioManager.setStreamVolume(AudioManager.STREAM_VOICE_CALL,
                // curVolume, AudioManager.STREAM_VOICE_CALL);

            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * save call record
     */
    protected void saveCallRecord() {
        EMMessage message = null;
        EMTextMessageBody txtBody = null;
        if (!isInComingCall) { // outgoing call
            message = EMMessage.createSendMessage(EMMessage.Type.TXT);
            message.setReceipt(username);
        } else {
            message = EMMessage.createReceiveMessage(EMMessage.Type.TXT);
            message.setFrom(username);
        }

        String st1 = getResources().getString(R.string.call_duration);
        String st2 = getResources().getString(R.string.Refused);
        String st3 = getResources().getString(R.string.The_other_party_has_refused_to);
        String st4 = getResources().getString(R.string.The_other_is_not_online);
        String st5 = getResources().getString(R.string.The_other_is_on_the_phone);
        String st6 = getResources().getString(R.string.The_other_party_did_not_answer);
        String st7 = getResources().getString(R.string.did_not_answer);
        String st8 = getResources().getString(R.string.Has_been_cancelled);
        switch (callingState) {
            case NORMAL:
                txtBody = new EMTextMessageBody(st1 + callDruationText);
                break;
            case REFUESD:
                txtBody = new EMTextMessageBody(st2);
                break;
            case BEREFUESD:
                txtBody = new EMTextMessageBody(st3);
                break;
            case OFFLINE:
                txtBody = new EMTextMessageBody(st4);
                break;
            case BUSY:
                txtBody = new EMTextMessageBody(st5);
                break;
            case NORESPONSE:
                txtBody = new EMTextMessageBody(st6);
                break;
            case UNANSWERED:
                txtBody = new EMTextMessageBody(st7);
                break;
            case VERSION_NOT_SAME:
                txtBody = new EMTextMessageBody(getString(R.string.call_version_inconsistent));
            default:
                txtBody = new EMTextMessageBody(st8);
                break;
        }
        // set message extension
        if(callType == 0){
            message.setAttribute(MESSAGE_ATTR_IS_VOICE_CALL, true);
        }
        else {
            message.setAttribute(MESSAGE_ATTR_IS_VIDEO_CALL, true);
        }
        // set message body
        message.addBody(txtBody);
        message.setMsgId(msgid);
        message.setStatus(Status.SUCCESS);

        // save
        EMClient.getInstance().chatManager().saveMessage(message);
    }

    enum CallingState {
        CANCED, NORMAL, REFUESD, BEREFUESD, UNANSWERED, OFFLINE, NORESPONSE, BUSY, VERSION_NOT_SAME
    }
    public static final String MESSAGE_ATTR_IS_VOICE_CALL = "is_voice_call";
    public static final String MESSAGE_ATTR_IS_VIDEO_CALL = "is_video_call";
}
package com.example.yangzhelin.myvideo30.activities;


import android.os.Bundle;
import android.widget.EditText;
import android.widget.Toast;
import com.example.yangzhelin.myvideo30.R;
import com.example.yangzhelin.myvideo30.ToastEvent;
import com.example.yangzhelin.myvideo30.util.IVideoManager;
import com.example.yangzhelin.myvideo30.util.VideoManager;
import com.halove.android.framework.base.BaseActivity;
import org.greenrobot.eventbus.Subscribe;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
public class MainActivity extends BaseActivity  {
    @BindView(R.id.username)
    EditText username;
    @BindView(R.id.password)
    EditText password;
    @BindView(R.id.to)
    EditText to;
    private IVideoManager videoManger;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
        videoManger = VideoManager.getInstance(this);
    }
    @OnClick(R.id.register)
    void register() {
        String u = username.getText().toString().trim();
        String p = password.getText().toString().trim();
        videoManger.register(u, p);
    }
    @OnClick(R.id.login)
    void login() {
        String u = username.getText().toString().trim();
        String p = password.getText().toString().trim();
        videoManger.login(u, p);
    }
    @OnClick(R.id.logout)
    public void logout() {
        videoManger.logout();
    }
    @OnClick(R.id.voice)
    public void voice() {
        toast("未开通此功能");
    }
    @OnClick(R.id.video)
    public void video() {
        String toUser = to.getText().toString();
        videoManger.video(toUser);
    }
    @Override
    protected void onDestroy() {
        logout();
        super.onDestroy();
    }
    @Subscribe
    public void showMessageToUser(ToastEvent event) {
        final String msg=event.text;
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
            }
        });
    }

}


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
要在Android应用程序中集成环信的EaseIMKit来发送语音,需要遵循以下步骤: 1. 在项目的build.gradle文件中添加环信库的依赖: ``` dependencies { // 环信IM SDK implementation 'com.hyphenate:chat-sdk:3.5.2' // 环信UI库 implementation 'com.hyphenate:chat-ui-sdk:3.5.2' } ``` 2. 在AndroidManifest.xml文件中声明必要的权限: ``` <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.VIBRATE" /> ``` 3. 在你的Activity中创建EaseChatFragment实例,并将其添加到布局中: ``` <fragment android:id="@+id/chat_fragment" android:name="com.hyphenate.easeui.ui.EaseChatFragment" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@+id/top_bar" android:background="@color/white" app:layout_behavior="@string/appbar_scrolling_view_behavior" app:layout_scrollFlags="scroll|exitUntilCollapsed" app:layout_anchor="@id/top_bar" app:layout_anchorGravity="bottom|center_horizontal" /> ``` 4. 在Activity中初始化EaseChatFragment,并设置相关属性: ``` private void initChatFragment() { // 获取EaseChatFragment实例 EaseChatFragment chatFragment = (EaseChatFragment) getSupportFragmentManager().findFragmentById(R.id.chat_fragment); // 设置聊天界面的标题 chatFragment.setTitle("Chat with xxx"); // 设置聊天对象的ID chatFragment.setArguments(getIntent().getExtras()); // 设置是否开启语音消息发送功能 chatFragment.setShowRecord(true); } ``` 5. 在EaseChatFragment中实现发送语音消息的逻辑: ``` // 在EaseChatFragment中重写onSendVoice方法 @Override public void onSendVoice(String filePath, int length) { // 创建语音消息 EMVoiceMessageBody messageBody = new EMVoiceMessageBody(new File(filePath), length); EMMessage message = EMMessage.createVoiceSendMessage(filePath, length, toChatUsername); // 发送语音消息 sendMessage(message); } ``` 以上就是使用环信的EaseIMKit实现Android发送语音消息的步骤。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值