upgrade
This commit is contained in:
18
tianrunPlugins/.idea/codeStyles/Project.xml
generated
18
tianrunPlugins/.idea/codeStyles/Project.xml
generated
@@ -1,5 +1,23 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<JetCodeStyleSettings>
|
||||
<option name="PACKAGES_TO_USE_STAR_IMPORTS">
|
||||
<value>
|
||||
<package name="java.util" alias="false" withSubpackages="false" />
|
||||
<package name="kotlinx.android.synthetic" alias="false" withSubpackages="true" />
|
||||
<package name="io.ktor" alias="false" withSubpackages="true" />
|
||||
</value>
|
||||
</option>
|
||||
<option name="PACKAGES_IMPORT_LAYOUT">
|
||||
<value>
|
||||
<package name="" alias="false" withSubpackages="true" />
|
||||
<package name="java" alias="false" withSubpackages="true" />
|
||||
<package name="javax" alias="false" withSubpackages="true" />
|
||||
<package name="kotlin" alias="false" withSubpackages="true" />
|
||||
<package name="" alias="true" withSubpackages="true" />
|
||||
</value>
|
||||
</option>
|
||||
</JetCodeStyleSettings>
|
||||
<codeStyleSettings language="XML">
|
||||
<indentOptions>
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||
|
||||
2
tianrunPlugins/.idea/misc.xml
generated
2
tianrunPlugins/.idea/misc.xml
generated
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
|
||||
6
tianrunPlugins/.idea/vcs.xml
generated
Normal file
6
tianrunPlugins/.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
**
|
||||
** Copyright 2007, The Android Open Source Project
|
||||
**
|
||||
** 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 android.content.pm;
|
||||
|
||||
/**
|
||||
* API for package data change related callbacks from the Package Manager.
|
||||
* Some usage scenarios include deletion of cache directory, generate
|
||||
* statistics related to code, data, cache usage(TODO)
|
||||
* {@hide}
|
||||
*/
|
||||
oneway interface IPackageDataObserver {
|
||||
void onRemoveCompleted(in String packageName, boolean succeeded);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
**
|
||||
** Copyright 2007, The Android Open Source Project
|
||||
**
|
||||
** 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 android.content.pm;
|
||||
|
||||
import android.content.pm.PackageStats;
|
||||
/**
|
||||
* API for package data change related callbacks from the Package Manager.
|
||||
* Some usage scenarios include deletion of cache directory, generate
|
||||
* statistics related to code, data, cache usage(TODO)
|
||||
* {@hide}
|
||||
*/
|
||||
oneway interface IPackageStatsObserver {
|
||||
|
||||
void onGetStatsCompleted(in PackageStats pStats, boolean succeeded);
|
||||
}
|
||||
20
tianrunPlugins/app/src/main/aidl/android/content/pm/PackageStats.aidl
Executable file
20
tianrunPlugins/app/src/main/aidl/android/content/pm/PackageStats.aidl
Executable file
@@ -0,0 +1,20 @@
|
||||
/* //device/java/android/android/view/WindowManager.aidl
|
||||
**
|
||||
** Copyright 2007, The Android Open Source Project
|
||||
**
|
||||
** 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 android.content.pm;
|
||||
|
||||
parcelable PackageStats;
|
||||
20
tianrunPlugins/app/src/main/aidl/android/telephony/NeighboringCellInfo.aidl
Executable file
20
tianrunPlugins/app/src/main/aidl/android/telephony/NeighboringCellInfo.aidl
Executable file
@@ -0,0 +1,20 @@
|
||||
/* //device/java/android/android/content/Intent.aidl
|
||||
**
|
||||
** Copyright 2007, The Android Open Source Project
|
||||
**
|
||||
** 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 android.telephony;
|
||||
|
||||
parcelable NeighboringCellInfo;
|
||||
261
tianrunPlugins/app/src/main/aidl/com/android/internal/telephony/ITelephony.aidl
Executable file
261
tianrunPlugins/app/src/main/aidl/com/android/internal/telephony/ITelephony.aidl
Executable file
@@ -0,0 +1,261 @@
|
||||
/*
|
||||
* Copyright (C) 2007 The Android Open Source Project
|
||||
*
|
||||
* 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.android.internal.telephony;
|
||||
|
||||
import android.os.Bundle;
|
||||
import java.util.List;
|
||||
import android.telephony.NeighboringCellInfo;
|
||||
|
||||
/**
|
||||
* Interface used to interact with the phone. Mostly this is used by the
|
||||
* TelephonyManager class. A few places are still using this directly.
|
||||
* Please clean them up if possible and use TelephonyManager insteadl.
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
interface ITelephony {
|
||||
|
||||
/**
|
||||
* Dial a number. This doesn't place the call. It displays
|
||||
* the Dialer screen.
|
||||
* @param number the number to be dialed. If null, this
|
||||
* would display the Dialer screen with no number pre-filled.
|
||||
*/
|
||||
void dial(String number);
|
||||
|
||||
/**
|
||||
* Place a call to the specified number.
|
||||
* @param number the number to be called.
|
||||
*/
|
||||
void call(String number);
|
||||
|
||||
/**
|
||||
* If there is currently a call in progress, show the call screen.
|
||||
* The DTMF dialpad may or may not be visible initially, depending on
|
||||
* whether it was up when the user last exited the InCallScreen.
|
||||
*
|
||||
* @return true if the call screen was shown.
|
||||
*/
|
||||
boolean showCallScreen();
|
||||
|
||||
/**
|
||||
* Variation of showCallScreen() that also specifies whether the
|
||||
* DTMF dialpad should be initially visible when the InCallScreen
|
||||
* comes up.
|
||||
*
|
||||
* @param showDialpad if true, make the dialpad visible initially,
|
||||
* otherwise hide the dialpad initially.
|
||||
* @return true if the call screen was shown.
|
||||
*
|
||||
* @see showCallScreen
|
||||
*/
|
||||
boolean showCallScreenWithDialpad(boolean showDialpad);
|
||||
|
||||
/**
|
||||
* End call or go to the Home screen
|
||||
*
|
||||
* @return whether it hung up
|
||||
*/
|
||||
boolean endCall();
|
||||
|
||||
/**
|
||||
* Answer the currently-ringing call.
|
||||
*
|
||||
* If there's already a current active call, that call will be
|
||||
* automatically put on hold. If both lines are currently in use, the
|
||||
* current active call will be ended.
|
||||
*
|
||||
* TODO: provide a flag to let the caller specify what policy to use
|
||||
* if both lines are in use. (The current behavior is hardwired to
|
||||
* "answer incoming, end ongoing", which is how the CALL button
|
||||
* is specced to behave.)
|
||||
*
|
||||
* TODO: this should be a oneway call (especially since it's called
|
||||
* directly from the key queue thread).
|
||||
*/
|
||||
void answerRingingCall();
|
||||
|
||||
/**
|
||||
* Silence the ringer if an incoming call is currently ringing.
|
||||
* (If vibrating, stop the vibrator also.)
|
||||
*
|
||||
* It's safe to call this if the ringer has already been silenced, or
|
||||
* even if there's no incoming call. (If so, this method will do nothing.)
|
||||
*
|
||||
* TODO: this should be a oneway call too (see above).
|
||||
* (Actually *all* the methods here that return void can
|
||||
* probably be oneway.)
|
||||
*/
|
||||
void silenceRinger();
|
||||
|
||||
/**
|
||||
* Check if we are in either an active or holding call
|
||||
* @return true if the phone state is OFFHOOK.
|
||||
*/
|
||||
boolean isOffhook();
|
||||
|
||||
/**
|
||||
* Check if an incoming phone call is ringing or call waiting.
|
||||
* @return true if the phone state is RINGING.
|
||||
*/
|
||||
boolean isRinging();
|
||||
|
||||
/**
|
||||
* Check if the phone is idle.
|
||||
* @return true if the phone state is IDLE.
|
||||
*/
|
||||
boolean isIdle();
|
||||
|
||||
/**
|
||||
* Check to see if the radio is on or not.
|
||||
* @return returns true if the radio is on.
|
||||
*/
|
||||
boolean isRadioOn();
|
||||
|
||||
/**
|
||||
* Check if the SIM pin lock is enabled.
|
||||
* @return true if the SIM pin lock is enabled.
|
||||
*/
|
||||
boolean isSimPinEnabled();
|
||||
|
||||
/**
|
||||
* Cancels the missed calls notification.
|
||||
*/
|
||||
void cancelMissedCallsNotification();
|
||||
|
||||
/**
|
||||
* Supply a pin to unlock the SIM. Blocks until a result is determined.
|
||||
* @param pin The pin to check.
|
||||
* @return whether the operation was a success.
|
||||
*/
|
||||
boolean supplyPin(String pin);
|
||||
|
||||
/**
|
||||
* Handles PIN MMI commands (PIN/PIN2/PUK/PUK2), which are initiated
|
||||
* without SEND (so <code>dial</code> is not appropriate).
|
||||
*
|
||||
* @param dialString the MMI command to be executed.
|
||||
* @return true if MMI command is executed.
|
||||
*/
|
||||
boolean handlePinMmi(String dialString);
|
||||
|
||||
/**
|
||||
* Toggles the radio on or off.
|
||||
*/
|
||||
void toggleRadioOnOff();
|
||||
|
||||
/**
|
||||
* Set the radio to on or off
|
||||
*/
|
||||
boolean setRadio(boolean turnOn);
|
||||
|
||||
/**
|
||||
* Request to update location information in service state
|
||||
*/
|
||||
void updateServiceLocation();
|
||||
|
||||
/**
|
||||
* Enable location update notifications.
|
||||
*/
|
||||
void enableLocationUpdates();
|
||||
|
||||
/**
|
||||
* Disable location update notifications.
|
||||
*/
|
||||
void disableLocationUpdates();
|
||||
|
||||
/**
|
||||
* Enable a specific APN type.
|
||||
*/
|
||||
int enableApnType(String type);
|
||||
|
||||
/**
|
||||
* Disable a specific APN type.
|
||||
*/
|
||||
int disableApnType(String type);
|
||||
|
||||
/**
|
||||
* Allow mobile data connections.
|
||||
*/
|
||||
boolean enableDataConnectivity();
|
||||
|
||||
/**
|
||||
* Disallow mobile data connections.
|
||||
*/
|
||||
boolean disableDataConnectivity();
|
||||
|
||||
/**
|
||||
* Report whether data connectivity is possible.
|
||||
*/
|
||||
boolean isDataConnectivityPossible();
|
||||
|
||||
Bundle getCellLocation();
|
||||
|
||||
/**
|
||||
* Returns the neighboring cell information of the device.
|
||||
*/
|
||||
List<NeighboringCellInfo> getNeighboringCellInfo();
|
||||
|
||||
int getCallState();
|
||||
int getDataActivity();
|
||||
int getDataState();
|
||||
|
||||
/**
|
||||
* Returns the current active phone type as integer.
|
||||
* Returns TelephonyManager.PHONE_TYPE_CDMA if RILConstants.CDMA_PHONE
|
||||
* and TelephonyManager.PHONE_TYPE_GSM if RILConstants.GSM_PHONE
|
||||
*/
|
||||
int getActivePhoneType();
|
||||
|
||||
/**
|
||||
* Returns the CDMA ERI icon index to display
|
||||
*/
|
||||
int getCdmaEriIconIndex();
|
||||
|
||||
/**
|
||||
* Returns the CDMA ERI icon mode,
|
||||
* 0 - ON
|
||||
* 1 - FLASHING
|
||||
*/
|
||||
int getCdmaEriIconMode();
|
||||
|
||||
/**
|
||||
* Returns the CDMA ERI text,
|
||||
*/
|
||||
String getCdmaEriText();
|
||||
|
||||
/**
|
||||
* Returns true if CDMA provisioning needs to run.
|
||||
*/
|
||||
boolean getCdmaNeedsProvisioning();
|
||||
|
||||
/**
|
||||
* Returns the unread count of voicemails
|
||||
*/
|
||||
int getVoiceMessageCount();
|
||||
|
||||
/**
|
||||
* Returns the network type
|
||||
*/
|
||||
int getNetworkType();
|
||||
|
||||
/**
|
||||
* Return true if an ICC card is present
|
||||
*/
|
||||
boolean hasIccCard();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.coolape.tianrun;
|
||||
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.util.Log;
|
||||
|
||||
public class CLOutgoingCallListener extends BroadcastReceiver {
|
||||
String TAG = "unity";
|
||||
static Boolean isOutgoingCall = false;
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (intent.getAction().equals(Intent.ACTION_NEW_OUTGOING_CALL)) {
|
||||
Log.d(TAG, "开始拨号,但并不知道是否接通电话");
|
||||
if (U3dPlugin.isNeedRecordOutCall) {
|
||||
isOutgoingCall = true;
|
||||
U3dPlugin.onBegainOutgoingCall();
|
||||
}
|
||||
} else if (intent.getAction().equals(
|
||||
TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
|
||||
TelephonyManager telephonyManager = (TelephonyManager) context
|
||||
.getSystemService(Context.TELEPHONY_SERVICE);// 注册监听器
|
||||
if (telephonyManager.getCallState() == TelephonyManager.CALL_STATE_IDLE) {
|
||||
|
||||
if (U3dPlugin.isNeedRecordOutCall && isOutgoingCall) {
|
||||
U3dPlugin.onEndgoingCall();
|
||||
isOutgoingCall = false;
|
||||
}
|
||||
Log.d(TAG, "挂电话");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
package com.coolape.tianrun;
|
||||
|
||||
import java.util.Calendar;
|
||||
|
||||
import com.android.internal.telephony.ITelephony;
|
||||
import com.newland.PhoneUtils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Message;
|
||||
import android.telephony.PhoneStateListener;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JD 功能:打电话,录音,通话时间
|
||||
*
|
||||
*/
|
||||
public class CLTeleInterface {
|
||||
|
||||
private String TAG = "TeleInterface";
|
||||
private Context activity;
|
||||
// private Handler handler;
|
||||
private Calendar calendar;
|
||||
private String teleStartTime;
|
||||
private String teleEndTime;
|
||||
private TelephonyManager telephonyManager;
|
||||
public static int TELE_START_TIME = 5;
|
||||
public static int TELE_END_TIME = 6;
|
||||
|
||||
public String getTeleStartTime() {
|
||||
return teleStartTime;
|
||||
}
|
||||
|
||||
public String getTeleEndTime() {
|
||||
return teleEndTime;
|
||||
}
|
||||
public PhoneListener listener;
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
*
|
||||
* @param activity
|
||||
* @param handler
|
||||
* 自定义handler接收消息 msg.what 5:电话拨通时间 6:电话挂断时间
|
||||
*/
|
||||
// public TeleInterface(Context activity, Handler handler) {
|
||||
public CLTeleInterface(Context activity) {
|
||||
this.activity = activity;
|
||||
// this.handler = handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* 拨打电话
|
||||
*
|
||||
* @param phoneNum
|
||||
* 需要拨打号码
|
||||
*/
|
||||
public void Call(String phoneNum) {
|
||||
if (phoneNum.length() != 0) {
|
||||
Intent phoneIntent = new Intent("android.intent.action.CALL",
|
||||
Uri.parse("tel:" + phoneNum));
|
||||
activity.startActivity(phoneIntent);
|
||||
} else {
|
||||
Toast.makeText(activity, "不能输入为空", Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 来电监听注册
|
||||
*/
|
||||
public void teleListen() {
|
||||
telephonyManager = (TelephonyManager) activity
|
||||
.getSystemService(Context.TELEPHONY_SERVICE);// 注册监听器
|
||||
if(listener == null) {
|
||||
listener = new PhoneListener();
|
||||
}
|
||||
telephonyManager.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);// 监听电话状态
|
||||
}
|
||||
|
||||
/**
|
||||
* 挂断电话
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public void endCall() throws Exception {
|
||||
ITelephony iTelephony = PhoneUtils.getITelephony(telephonyManager);
|
||||
iTelephony.endCall();// 自动挂断电话
|
||||
}
|
||||
|
||||
private final class PhoneListener extends PhoneStateListener {
|
||||
private String incomeNumber=""; // 来电号码
|
||||
private boolean isComingCall = false;
|
||||
// private MediaRecorder mediaRecorder;
|
||||
// private File root_file, file;
|
||||
|
||||
@Override
|
||||
public void onCallStateChanged(int state, String incomingNumber) {
|
||||
try {
|
||||
switch (state) {
|
||||
case TelephonyManager.CALL_STATE_RINGING: // 来电
|
||||
Log.d(TAG, "来电============");
|
||||
this.incomeNumber = incomingNumber;
|
||||
Log.d(TAG, "incomingNumber==" + incomingNumber);
|
||||
isComingCall = true;
|
||||
break;
|
||||
case TelephonyManager.CALL_STATE_OFFHOOK: // 接通电话
|
||||
Log.d(TAG, "接通电话============");
|
||||
calendar = Calendar.getInstance();
|
||||
teleStartTime = calendar.getTime().toString();
|
||||
|
||||
Message msg_start = new Message();
|
||||
msg_start.what = TELE_START_TIME;
|
||||
msg_start.obj = teleStartTime;
|
||||
Log.d(TAG, "StartTime=====" + teleStartTime);
|
||||
|
||||
if (U3dPlugin.isNeedRecordOutCall) {
|
||||
// isOutgoingCall = true;
|
||||
U3dPlugin.onBegainOutgoingCall();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case TelephonyManager.CALL_STATE_IDLE: // 挂掉电话
|
||||
if(isComingCall) {
|
||||
U3dPlugin.onEndincomeCall(incomeNumber);
|
||||
// incomeNumber = "";
|
||||
isComingCall = false;
|
||||
} else {
|
||||
if (U3dPlugin.isNeedRecordOutCall) {
|
||||
U3dPlugin.onEndgoingCall();
|
||||
// isOutgoingCall = false;
|
||||
}
|
||||
}
|
||||
Log.d(TAG, "挂掉电话===================!");
|
||||
break;
|
||||
|
||||
}
|
||||
super.onCallStateChanged(state, incomingNumber);
|
||||
} catch (IllegalStateException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
package com.coolape.tianrun;
|
||||
|
||||
import android.content.Context;
|
||||
import android.media.MediaPlayer;
|
||||
import android.media.MediaPlayer.OnCompletionListener;
|
||||
import android.media.MediaPlayer.OnPreparedListener;
|
||||
import android.media.MediaPlayer.OnErrorListener;
|
||||
import android.media.MediaPlayer.OnSeekCompleteListener;
|
||||
import android.net.Uri;
|
||||
|
||||
public class MyMediaPlayer {
|
||||
public static volatile MediaPlayer player = null;
|
||||
static String onPrepareOrgs = "";
|
||||
|
||||
public void prepare(Context context, String audioSource, String orgs) {
|
||||
onPrepareOrgs = orgs;
|
||||
try {
|
||||
Uri uri = Uri.parse(audioSource);
|
||||
if (player == null) {
|
||||
player = MediaPlayer.create(context, uri);
|
||||
player.setLooping(false);
|
||||
} else {
|
||||
if (player.isPlaying()) {
|
||||
stop();
|
||||
}
|
||||
player.reset();
|
||||
if (audioSource.startsWith("http")) {
|
||||
player.setDataSource(context, uri);
|
||||
} else {
|
||||
player.setDataSource(audioSource);
|
||||
}
|
||||
player.prepareAsync();
|
||||
}
|
||||
player.setOnPreparedListener(new OnPreparedListener() {
|
||||
@Override
|
||||
public void onPrepared(MediaPlayer player) {
|
||||
player.setLooping(false);
|
||||
int len = player.getDuration();
|
||||
U3dPlugin.UnitySendMessage("onMediaPrepared", len + "",
|
||||
onPrepareOrgs);
|
||||
}
|
||||
});
|
||||
player.setOnCompletionListener(new OnCompletionListener() {
|
||||
|
||||
@Override
|
||||
public void onCompletion(MediaPlayer player) {
|
||||
pause();
|
||||
U3dPlugin.UnitySendMessage("onMediaComplet", "true",
|
||||
onPrepareOrgs);
|
||||
}
|
||||
});
|
||||
player.setOnErrorListener(new OnErrorListener() {
|
||||
|
||||
@Override
|
||||
public boolean onError(MediaPlayer arg0, int arg1, int arg2) {
|
||||
U3dPlugin.UnitySendMessage("onMediaError", "false",
|
||||
onPrepareOrgs);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
player.setOnSeekCompleteListener(new OnSeekCompleteListener() {
|
||||
|
||||
@Override
|
||||
public void onSeekComplete(MediaPlayer arg0) {
|
||||
// TODO Auto-generated method stub
|
||||
U3dPlugin.UnitySendMessage("onMediaSeek", "true",
|
||||
onPrepareOrgs);
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public int getProgress() {
|
||||
if (player != null) {
|
||||
return player.getCurrentPosition();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void pause() {
|
||||
if (player != null && player.isPlaying()){
|
||||
player.pause();
|
||||
}
|
||||
}
|
||||
|
||||
public void play() {
|
||||
if (player != null && !player.isPlaying()){
|
||||
player.start();
|
||||
}
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
if (player != null)
|
||||
return;
|
||||
if (player.isPlaying()) {
|
||||
player.stop();
|
||||
}
|
||||
try {
|
||||
// mp.prepareAsync();
|
||||
// player.prepare();
|
||||
player.reset();
|
||||
// player.seekTo(0);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void seek(int progress) {
|
||||
if (player != null)
|
||||
player.seekTo(progress);
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
if (player != null) {
|
||||
player.stop();
|
||||
player.release();
|
||||
}
|
||||
player = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
package com.coolape.tianrun;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import android.media.MediaRecorder;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
|
||||
import com.czt.mp3recorder.MP3Recorder;
|
||||
import com.newland.PhoneUtils;
|
||||
import com.unity3d.player.UnityPlayer;
|
||||
|
||||
public class U3dPlugin {
|
||||
static String TAG = "U3d";
|
||||
public CLTeleInterface teleInterface;
|
||||
public static String u3dListener = "";
|
||||
public static String recordFileName = "";
|
||||
public static Boolean isNeedRecordOutCall = false;
|
||||
public static Boolean isConnectedRecordOutCall = false;
|
||||
public static Boolean isWaiting4IncomeCall = false;
|
||||
public static CLOutgoingCallListener outgoingCallRecver = new CLOutgoingCallListener();
|
||||
public static String onEndIncomeCallOrgs = "";
|
||||
public static String onEndCallOrgs = "";
|
||||
public static U3dPlugin self;
|
||||
// static MediaRecorder mediaRecorder;
|
||||
private static MP3Recorder mRecorder;
|
||||
private static File file;
|
||||
public static MyMediaPlayer mediaPlayer;
|
||||
public static int DefaultAudioSource = -1;
|
||||
|
||||
public void init(String _u3dListener) {
|
||||
self = this;
|
||||
u3dListener = _u3dListener;
|
||||
mediaPlayer = new MyMediaPlayer();
|
||||
Handler handler = new Handler(Looper.getMainLooper());
|
||||
handler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
teleInterface = new CLTeleInterface(UnityPlayer.currentActivity);
|
||||
teleInterface.teleListen();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void onDestroy() {
|
||||
if (mRecorder != null) {
|
||||
mRecorder.stop();
|
||||
mRecorder = null;
|
||||
}
|
||||
file = null;
|
||||
}
|
||||
|
||||
public void waitingIncomeCall(String _onEndIncomeCallOrgs) {
|
||||
onEndIncomeCallOrgs = _onEndIncomeCallOrgs;
|
||||
// isWaiting4IncomeCall = true;
|
||||
}
|
||||
|
||||
public void begainCall(String _recordFileName, String _onEndCallOrgs) {
|
||||
onEndCallOrgs = _onEndCallOrgs;
|
||||
recordFileName = _recordFileName;
|
||||
isNeedRecordOutCall = true;
|
||||
}
|
||||
|
||||
public static void onBegainOutgoingCall() {
|
||||
if (isNeedRecordOutCall) {
|
||||
|
||||
Handler handler = new Handler(Looper.getMainLooper());
|
||||
handler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
recordCall(recordFileName);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static void onEndincomeCall(String incomingPhoneNo) {
|
||||
// if (isWaiting4IncomeCall) {
|
||||
// isWaiting4IncomeCall = false;
|
||||
UnitySendMessage("onEndincomeCall", incomingPhoneNo, onEndIncomeCallOrgs);
|
||||
// }
|
||||
}
|
||||
|
||||
public static void onEndgoingCall() {
|
||||
if (isNeedRecordOutCall) {
|
||||
endRecordCall();
|
||||
UnitySendMessage("onEndOutGoingCall", "0", onEndCallOrgs);
|
||||
recordFileName = "";
|
||||
isNeedRecordOutCall = false;
|
||||
isConnectedRecordOutCall = false;
|
||||
}
|
||||
}
|
||||
|
||||
public static void recordCall(String fileName) {
|
||||
if (fileName == null || fileName.isEmpty())
|
||||
return;
|
||||
try {
|
||||
file = new File(fileName);
|
||||
if (!file.exists()) {
|
||||
file.createNewFile();
|
||||
}
|
||||
if (mRecorder == null) {
|
||||
mRecorder = new MP3Recorder(file);
|
||||
}
|
||||
mRecorder.setRecordFile(file);
|
||||
// int sdkVer = PhoneUtils.getSDKVersionNumber();
|
||||
if (DefaultAudioSource < 0) {
|
||||
// if (sdkVer >= 23) {
|
||||
// DefaultAudioSource = MediaRecorder.AudioSource.MIC;
|
||||
// } else {
|
||||
DefaultAudioSource = MediaRecorder.AudioSource.VOICE_CALL;
|
||||
// }
|
||||
}
|
||||
// 获得声音数据源
|
||||
mRecorder.setAudioSource(DefaultAudioSource);
|
||||
mRecorder.start();
|
||||
|
||||
Log.d(TAG, "开始录音!");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
try {
|
||||
endRecordCall();
|
||||
if (mRecorder == null) {
|
||||
mRecorder = new MP3Recorder(file);
|
||||
}
|
||||
file = new File(fileName);
|
||||
if (!file.exists()) {
|
||||
file.createNewFile();
|
||||
}
|
||||
if (mRecorder == null) {
|
||||
mRecorder = new MP3Recorder(file);
|
||||
}
|
||||
mRecorder.setRecordFile(file);
|
||||
|
||||
DefaultAudioSource = MediaRecorder.AudioSource.MIC;
|
||||
// int sdkVer = PhoneUtils.getSDKVersionNumber();
|
||||
mRecorder.setAudioSource(DefaultAudioSource);
|
||||
mRecorder.start();
|
||||
} catch (Exception e2) {
|
||||
e2.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void endRecordCall() {
|
||||
// if (mediaRecorder != null) {
|
||||
// mediaRecorder.stop();
|
||||
// mediaRecorder.release();
|
||||
// mediaRecorder = null;
|
||||
// }
|
||||
try {
|
||||
if (mRecorder != null) {
|
||||
mRecorder.stop();
|
||||
// mRecorder = null;
|
||||
|
||||
file = null;
|
||||
Log.d(TAG, "结束录音!");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static String audioSource;
|
||||
static String orgs;
|
||||
|
||||
public void prepareMedia(String _audioSource, String _orgs) {
|
||||
audioSource = _audioSource;
|
||||
orgs = _orgs;
|
||||
Handler handler = new Handler(Looper.getMainLooper());
|
||||
handler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mediaPlayer.prepare(UnityPlayer.currentActivity, audioSource,
|
||||
orgs);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void mediaPlay() {
|
||||
mediaPlayer.play();
|
||||
}
|
||||
|
||||
public void mediaStop() {
|
||||
mediaPlayer.stop();
|
||||
}
|
||||
|
||||
public void mediaPause() {
|
||||
mediaPlayer.pause();
|
||||
}
|
||||
|
||||
static int seekPosition = 0;
|
||||
|
||||
public void mediaSeek(int progress) {
|
||||
seekPosition = progress;
|
||||
Handler handler = new Handler(Looper.getMainLooper());
|
||||
handler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mediaPlayer.seek(seekPosition);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void mediaDestroy() {
|
||||
mediaPlayer.destroy();
|
||||
}
|
||||
|
||||
public int getMediaProgress() {
|
||||
return mediaPlayer.getProgress();
|
||||
}
|
||||
|
||||
public static void UnitySendMessage(String CallbackFunc, String retCode,
|
||||
String orgs) {
|
||||
if (u3dListener.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
JSONObject jsonObj = new JSONObject();
|
||||
jsonObj.put("code", retCode);
|
||||
jsonObj.put("orgs", orgs);
|
||||
UnityPlayer.UnitySendMessage(u3dListener, CallbackFunc,
|
||||
jsonObj.toString());
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
package com.czt.mp3recorder;
|
||||
|
||||
import android.media.AudioRecord;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
|
||||
import com.czt.mp3recorder.util.LameUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class DataEncodeThread extends HandlerThread implements AudioRecord.OnRecordPositionUpdateListener {
|
||||
private StopHandler mHandler;
|
||||
private static final int PROCESS_STOP = 1;
|
||||
private byte[] mMp3Buffer;
|
||||
private FileOutputStream mFileOutputStream;
|
||||
|
||||
private static class StopHandler extends Handler {
|
||||
|
||||
private DataEncodeThread encodeThread;
|
||||
|
||||
public StopHandler(Looper looper, DataEncodeThread encodeThread) {
|
||||
super(looper);
|
||||
this.encodeThread = encodeThread;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
if (msg.what == PROCESS_STOP) {
|
||||
//处理缓冲区中的数据
|
||||
while (encodeThread.processData() > 0);
|
||||
// Cancel any event left in the queue
|
||||
removeCallbacksAndMessages(null);
|
||||
encodeThread.flushAndRelease();
|
||||
getLooper().quit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param file file
|
||||
* @param bufferSize bufferSize
|
||||
* @throws FileNotFoundException file not found
|
||||
*/
|
||||
public DataEncodeThread(File file, int bufferSize) throws FileNotFoundException {
|
||||
super("DataEncodeThread");
|
||||
this.mFileOutputStream = new FileOutputStream(file);
|
||||
mMp3Buffer = new byte[(int) (7200 + (bufferSize * 2 * 1.25))];
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void start() {
|
||||
super.start();
|
||||
mHandler = new StopHandler(getLooper(), this);
|
||||
}
|
||||
|
||||
private void check() {
|
||||
if (mHandler == null) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
public void sendStopMessage() {
|
||||
check();
|
||||
mHandler.sendEmptyMessage(PROCESS_STOP);
|
||||
}
|
||||
public Handler getHandler() {
|
||||
check();
|
||||
return mHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMarkerReached(AudioRecord recorder) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPeriodicNotification(AudioRecord recorder) {
|
||||
processData();
|
||||
}
|
||||
/**
|
||||
* 从缓冲区中读取并处理数据,使用lame编码MP3
|
||||
* @return 从缓冲区中读取的数据的长度
|
||||
* 缓冲区中没有数据时返回0
|
||||
*/
|
||||
private int processData() {
|
||||
if (mTasks.size() > 0) {
|
||||
Task task = mTasks.remove(0);
|
||||
short[] buffer = task.getData();
|
||||
int readSize = task.getReadSize();
|
||||
int encodedSize = LameUtil.encode(buffer, buffer, readSize, mMp3Buffer);
|
||||
if (encodedSize > 0){
|
||||
try {
|
||||
mFileOutputStream.write(mMp3Buffer, 0, encodedSize);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return readSize;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush all data left in lame buffer to file
|
||||
*/
|
||||
private void flushAndRelease() {
|
||||
//将MP3结尾信息写入buffer中
|
||||
final int flushResult = LameUtil.flush(mMp3Buffer);
|
||||
if (flushResult > 0) {
|
||||
try {
|
||||
mFileOutputStream.write(mMp3Buffer, 0, flushResult);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}finally{
|
||||
if (mFileOutputStream != null) {
|
||||
try {
|
||||
mFileOutputStream.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
LameUtil.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
private List<Task> mTasks = Collections.synchronizedList(new ArrayList<Task>());
|
||||
public void addTask(short[] rawData, int readSize){
|
||||
mTasks.add(new Task(rawData, readSize));
|
||||
}
|
||||
private class Task{
|
||||
private short[] rawData;
|
||||
private int readSize;
|
||||
public Task(short[] rawData, int readSize){
|
||||
this.rawData = rawData.clone();
|
||||
this.readSize = readSize;
|
||||
}
|
||||
public short[] getData(){
|
||||
return rawData;
|
||||
}
|
||||
public int getReadSize(){
|
||||
return readSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
package com.czt.mp3recorder;
|
||||
|
||||
import android.media.AudioFormat;
|
||||
import android.media.AudioRecord;
|
||||
import android.media.MediaRecorder;
|
||||
import android.util.Log;
|
||||
|
||||
import com.czt.mp3recorder.util.LameUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public class MP3Recorder {
|
||||
//=======================AudioRecord Default Settings=======================
|
||||
private static int DEFAULT_AUDIO_SOURCE = MediaRecorder.AudioSource.MIC;
|
||||
/**
|
||||
* 以下三项为默认配置参数。Google Android文档明确表明只有以下3个参数是可以在所有设备上保证支持的。
|
||||
*/
|
||||
private static final int DEFAULT_SAMPLING_RATE = 44100;//模拟器仅支持从麦克风输入8kHz采样率
|
||||
private static final int DEFAULT_CHANNEL_CONFIG = AudioFormat.CHANNEL_IN_MONO;
|
||||
/**
|
||||
* 下面是对此的封装
|
||||
* private static final int DEFAULT_AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
|
||||
*/
|
||||
private static final PCMFormat DEFAULT_AUDIO_FORMAT = PCMFormat.PCM_16BIT;
|
||||
|
||||
//======================Lame Default Settings=====================
|
||||
private static final int DEFAULT_LAME_MP3_QUALITY = 7;
|
||||
/**
|
||||
* 与DEFAULT_CHANNEL_CONFIG相关,因为是mono单声,所以是1
|
||||
*/
|
||||
private static final int DEFAULT_LAME_IN_CHANNEL = 1;
|
||||
/**
|
||||
* Encoded bit rate. MP3 file will be encoded with bit rate 32kbps
|
||||
*/
|
||||
private static final int DEFAULT_LAME_MP3_BIT_RATE = 32;
|
||||
|
||||
//==================================================================
|
||||
|
||||
/**
|
||||
* 自定义 每160帧作为一个周期,通知一下需要进行编码
|
||||
*/
|
||||
private static final int FRAME_COUNT = 160;
|
||||
private AudioRecord mAudioRecord = null;
|
||||
private int mBufferSize;
|
||||
private short[] mPCMBuffer;
|
||||
private DataEncodeThread mEncodeThread;
|
||||
private boolean mIsRecording = false;
|
||||
private File mRecordFile;
|
||||
/**
|
||||
* Default constructor. Setup recorder with default sampling rate 1 channel,
|
||||
* 16 bits pcm
|
||||
* @param recordFile target file
|
||||
*/
|
||||
public MP3Recorder(File recordFile) {
|
||||
mRecordFile = recordFile;
|
||||
}
|
||||
|
||||
public void setRecordFile(File recordFile) {
|
||||
mRecordFile = recordFile;
|
||||
}
|
||||
|
||||
public void setAudioSource(int audioSource) {
|
||||
DEFAULT_AUDIO_SOURCE = audioSource;
|
||||
}
|
||||
/**
|
||||
* Start recording. Create an encoding thread. Start record from this
|
||||
* thread.
|
||||
*
|
||||
* @throws IOException initAudioRecorder throws
|
||||
*/
|
||||
public void start() throws IOException {
|
||||
if (mIsRecording) {
|
||||
return;
|
||||
}
|
||||
mIsRecording = true; // 提早,防止init或startRecording被多次调用
|
||||
initAudioRecorder();
|
||||
mAudioRecord.startRecording();
|
||||
new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
//设置线程权限
|
||||
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
|
||||
while (mIsRecording) {
|
||||
int readSize = mAudioRecord.read(mPCMBuffer, 0, mBufferSize);
|
||||
if (readSize > 0) {
|
||||
mEncodeThread.addTask(mPCMBuffer, readSize);
|
||||
calculateRealVolume(mPCMBuffer, readSize);
|
||||
}
|
||||
}
|
||||
// release and finalize audioRecord
|
||||
mAudioRecord.stop();
|
||||
mAudioRecord.release();
|
||||
mAudioRecord = null;
|
||||
// stop the encoding thread and try to wait
|
||||
// until the thread finishes its job
|
||||
mEncodeThread.sendStopMessage();
|
||||
}
|
||||
/**
|
||||
* 此计算方法来自samsung开发范例
|
||||
*
|
||||
* @param buffer buffer
|
||||
* @param readSize readSize
|
||||
*/
|
||||
private void calculateRealVolume(short[] buffer, int readSize) {
|
||||
double sum = 0;
|
||||
for (int i = 0; i < readSize; i++) {
|
||||
// 这里没有做运算的优化,为了更加清晰的展示代码
|
||||
sum += buffer[i] * buffer[i];
|
||||
}
|
||||
if (readSize > 0) {
|
||||
double amplitude = sum / readSize;
|
||||
mVolume = (int) Math.sqrt(amplitude);
|
||||
}
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
private int mVolume;
|
||||
|
||||
/**
|
||||
* 获取真实的音量。 [算法来自三星]
|
||||
* @return 真实音量
|
||||
*/
|
||||
public int getRealVolume() {
|
||||
return mVolume;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取相对音量。 超过最大值时取最大值。
|
||||
* @return 音量
|
||||
*/
|
||||
public int getVolume(){
|
||||
if (mVolume >= MAX_VOLUME) {
|
||||
return MAX_VOLUME;
|
||||
}
|
||||
return mVolume;
|
||||
}
|
||||
private static final int MAX_VOLUME = 2000;
|
||||
|
||||
/**
|
||||
* 根据资料假定的最大值。 实测时有时超过此值。
|
||||
* @return 最大音量值。
|
||||
*/
|
||||
public int getMaxVolume(){
|
||||
return MAX_VOLUME;
|
||||
}
|
||||
public void stop(){
|
||||
mIsRecording = false;
|
||||
}
|
||||
public boolean isRecording() {
|
||||
return mIsRecording;
|
||||
}
|
||||
/**
|
||||
* Initialize audio recorder
|
||||
*/
|
||||
private void initAudioRecorder() throws IOException {
|
||||
mBufferSize = AudioRecord.getMinBufferSize(DEFAULT_SAMPLING_RATE,
|
||||
DEFAULT_CHANNEL_CONFIG, DEFAULT_AUDIO_FORMAT.getAudioFormat());
|
||||
|
||||
int bytesPerFrame = DEFAULT_AUDIO_FORMAT.getBytesPerFrame();
|
||||
/* Get number of samples. Calculate the buffer size
|
||||
* (round up to the factor of given frame size)
|
||||
* 使能被整除,方便下面的周期性通知
|
||||
* */
|
||||
int frameSize = mBufferSize / bytesPerFrame;
|
||||
if (frameSize % FRAME_COUNT != 0) {
|
||||
frameSize += (FRAME_COUNT - frameSize % FRAME_COUNT);
|
||||
mBufferSize = frameSize * bytesPerFrame;
|
||||
}
|
||||
|
||||
/* Setup audio recorder */
|
||||
mAudioRecord = new AudioRecord(DEFAULT_AUDIO_SOURCE,
|
||||
DEFAULT_SAMPLING_RATE, DEFAULT_CHANNEL_CONFIG, DEFAULT_AUDIO_FORMAT.getAudioFormat(),
|
||||
mBufferSize);
|
||||
|
||||
mPCMBuffer = new short[mBufferSize];
|
||||
/*
|
||||
* Initialize lame buffer
|
||||
* mp3 sampling rate is the same as the recorded pcm sampling rate
|
||||
* The bit rate is 32kbps
|
||||
*
|
||||
*/
|
||||
LameUtil.init(DEFAULT_SAMPLING_RATE, DEFAULT_LAME_IN_CHANNEL, DEFAULT_SAMPLING_RATE, DEFAULT_LAME_MP3_BIT_RATE, DEFAULT_LAME_MP3_QUALITY);
|
||||
// Create and run thread used to encode data
|
||||
// The thread will
|
||||
mEncodeThread = new DataEncodeThread(mRecordFile, mBufferSize);
|
||||
mEncodeThread.start();
|
||||
mAudioRecord.setRecordPositionUpdateListener(mEncodeThread, mEncodeThread.getHandler());
|
||||
mAudioRecord.setPositionNotificationPeriod(FRAME_COUNT);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.czt.mp3recorder;
|
||||
|
||||
import android.media.AudioFormat;
|
||||
|
||||
public enum PCMFormat {
|
||||
PCM_8BIT (1, AudioFormat.ENCODING_PCM_8BIT),
|
||||
PCM_16BIT (2, AudioFormat.ENCODING_PCM_16BIT);
|
||||
|
||||
private int bytesPerFrame;
|
||||
private int audioFormat;
|
||||
|
||||
PCMFormat(int bytesPerFrame, int audioFormat) {
|
||||
this.bytesPerFrame = bytesPerFrame;
|
||||
this.audioFormat = audioFormat;
|
||||
}
|
||||
public int getBytesPerFrame() {
|
||||
return bytesPerFrame;
|
||||
}
|
||||
public int getAudioFormat() {
|
||||
return audioFormat;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package com.czt.mp3recorder.util;
|
||||
|
||||
public class LameUtil {
|
||||
static{
|
||||
System.loadLibrary("mp3lame");
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize LAME.
|
||||
*
|
||||
* @param inSamplerate
|
||||
* input sample rate in Hz.
|
||||
* @param inChannel
|
||||
* number of channels in input stream.
|
||||
* @param outSamplerate
|
||||
* output sample rate in Hz.
|
||||
* @param outBitrate
|
||||
* brate compression ratio in KHz.
|
||||
* @param quality
|
||||
* <p>quality=0..9. 0=best (very slow). 9=worst.</p>
|
||||
* <p>recommended:</p>
|
||||
* <p>2 near-best quality, not too slow</p>
|
||||
* <p>5 good quality, fast</p>
|
||||
* 7 ok quality, really fast
|
||||
*/
|
||||
public native static void init(int inSamplerate, int inChannel,
|
||||
int outSamplerate, int outBitrate, int quality);
|
||||
|
||||
/**
|
||||
* Encode buffer to mp3.
|
||||
*
|
||||
* @param bufferLeft
|
||||
* PCM data for left channel.
|
||||
* @param bufferRight
|
||||
* PCM data for right channel.
|
||||
* @param samples
|
||||
* number of samples per channel.
|
||||
* @param mp3buf
|
||||
* result encoded MP3 stream. You must specified
|
||||
* "7200 + (1.25 * buffer_l.length)" length array.
|
||||
* @return <p>number of bytes output in mp3buf. Can be 0.</p>
|
||||
* <p>-1: mp3buf was too small</p>
|
||||
* <p>-2: malloc() problem</p>
|
||||
* <p>-3: lame_init_params() not called</p>
|
||||
* -4: psycho acoustic problems
|
||||
*/
|
||||
public native static int encode(short[] bufferLeft, short[] bufferRight,
|
||||
int samples, byte[] mp3buf);
|
||||
|
||||
/**
|
||||
* Flush LAME buffer.
|
||||
*
|
||||
* REQUIRED:
|
||||
* lame_encode_flush will flush the intenal PCM buffers, padding with
|
||||
* 0's to make sure the final frame is complete, and then flush
|
||||
* the internal MP3 buffers, and thus may return a
|
||||
* final few mp3 frames. 'mp3buf' should be at least 7200 bytes long
|
||||
* to hold all possible emitted data.
|
||||
*
|
||||
* will also write id3v1 tags (if any) into the bitstream
|
||||
*
|
||||
* return code = number of bytes output to mp3buf. Can be 0
|
||||
* @param mp3buf
|
||||
* result encoded MP3 stream. You must specified at least 7200
|
||||
* bytes.
|
||||
* @return number of bytes output to mp3buf. Can be 0.
|
||||
*/
|
||||
public native static int flush(byte[] mp3buf);
|
||||
|
||||
/**
|
||||
* Close LAME.
|
||||
*/
|
||||
public native static void close();
|
||||
}
|
||||
93
tianrunPlugins/app/src/main/java/com/newland/PhoneUtils.java
Normal file
93
tianrunPlugins/app/src/main/java/com/newland/PhoneUtils.java
Normal file
@@ -0,0 +1,93 @@
|
||||
package com.newland;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import com.android.internal.telephony.ITelephony;
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.telecom.TelecomManager;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.util.Log;
|
||||
|
||||
public class PhoneUtils {
|
||||
/**
|
||||
* 从TelephonyManager中实例化ITelephony,并返回
|
||||
*/
|
||||
static public ITelephony getITelephony(TelephonyManager telMgr)
|
||||
throws Exception {
|
||||
Method getITelephonyMethod = telMgr.getClass().getDeclaredMethod(
|
||||
"getITelephony");
|
||||
getITelephonyMethod.setAccessible(true);// 私有化函数也能使用
|
||||
return (ITelephony) getITelephonyMethod.invoke(telMgr);
|
||||
}
|
||||
|
||||
public static int getSDKVersionNumber() {
|
||||
int sdkVersion;
|
||||
try {
|
||||
sdkVersion = Integer.valueOf(android.os.Build.VERSION.SDK_INT);
|
||||
} catch (NumberFormatException e) {
|
||||
sdkVersion = 0;
|
||||
}
|
||||
return sdkVersion;
|
||||
}
|
||||
|
||||
//判断手机是否处于正在通话中
|
||||
public static boolean phoneIsInUse(Context context) {
|
||||
int sdkVer = getSDKVersionNumber();
|
||||
if(sdkVer >= 23) {
|
||||
return phoneIsInUse6_0(context);
|
||||
} else {
|
||||
return phoneIsInUse5_0(context);
|
||||
}
|
||||
}
|
||||
//Android如何判断手机是否处于正在通话中,Android 6.0之前(具体版本没追溯)用的方法(在Android 5.1上好用)
|
||||
public static boolean phoneIsInUse5_0(Context context) {
|
||||
boolean phoneInUse = false;
|
||||
TelephonyManager mTelephonyManager = (TelephonyManager)context.getSystemService(Service.TELEPHONY_SERVICE);
|
||||
Class<TelephonyManager> c = TelephonyManager.class;
|
||||
Method getITelephonyMethod = null;
|
||||
try {
|
||||
getITelephonyMethod = c.getDeclaredMethod("getITelephony",
|
||||
(Class[]) null);
|
||||
getITelephonyMethod.setAccessible(true);
|
||||
ITelephony iTelephony = (ITelephony) getITelephonyMethod.invoke(
|
||||
mTelephonyManager, (Object[]) null);
|
||||
phoneInUse = !iTelephony.isIdle();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return phoneInUse;
|
||||
}
|
||||
|
||||
//Android 6.0之后用以上方法不好用了,遍寻源码及网上资料得已下方法(在Android 6.0上好用):
|
||||
public static boolean phoneIsInUse6_0(Context context){
|
||||
TelecomManager tm = (TelecomManager)context.getSystemService(Context.TELECOM_SERVICE);
|
||||
return tm.isInCall();
|
||||
}
|
||||
|
||||
static public void printAllInform(Class clsShow) {
|
||||
try {
|
||||
// 取得所有方法
|
||||
Method[] hideMethod = clsShow.getDeclaredMethods();
|
||||
int i = 0;
|
||||
for (; i < hideMethod.length; i++) {
|
||||
Log.e("method name", hideMethod[i].getName());
|
||||
}
|
||||
// 取得所有常量
|
||||
Field[] allFields = clsShow.getFields();
|
||||
for (i = 0; i < allFields.length; i++) {
|
||||
Log.e("Field name", allFields[i].getName());
|
||||
}
|
||||
} catch (SecurityException e) {
|
||||
// throw new RuntimeException(e.getMessage());
|
||||
e.printStackTrace();
|
||||
} catch (IllegalArgumentException e) {
|
||||
// throw new RuntimeException(e.getMessage());
|
||||
e.printStackTrace();
|
||||
} catch (Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,13 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
|
||||
buildscript {
|
||||
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:4.0.0'
|
||||
classpath 'com.android.tools.build:gradle:4.0.1'
|
||||
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
@@ -16,6 +15,7 @@ buildscript {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
|
||||
Reference in New Issue
Block a user