11package io .agora .api .example .examples .advanced ;
22
33import android .content .Context ;
4- import android .media .AudioFormat ;
5- import android .media .AudioManager ;
64import android .os .Bundle ;
75import android .os .Handler ;
86import android .text .TextUtils ;
2119import com .yanzhenjie .permission .AndPermission ;
2220import com .yanzhenjie .permission .runtime .Permission ;
2321
22+ import java .io .IOException ;
23+ import java .io .InputStream ;
24+ import java .nio .ByteBuffer ;
25+
2426import io .agora .api .example .R ;
2527import io .agora .api .example .annotation .Example ;
2628import io .agora .api .example .common .BaseFragment ;
27- import io .agora .api .example .examples .advanced .customaudio .AudioPlayer ;
2829import io .agora .api .example .utils .CommonUtil ;
2930import io .agora .rtc .AudioFrame ;
3031import io .agora .rtc .Constants ;
@@ -53,15 +54,17 @@ public class ProcessAudioRawData extends BaseFragment implements View.OnClickLis
5354 private static final String TAG = ProcessAudioRawData .class .getSimpleName ();
5455 private EditText et_channel ;
5556 private Button mute , join , speaker ;
56- private Switch loopback ;
57+ private Switch writeBackAudio ;
5758 private RtcEngine engine ;
5859 private int myUid ;
5960 private boolean joined = false ;
60- private boolean isEnableLoopBack = false ;
61- private AudioPlayer mAudioPlayer ;
61+ private boolean isWriteBackAudio = false ;
6262 private static final Integer SAMPLE_RATE = 44100 ;
63+ private static final Integer SAMPLE_NUM_OF_CHANNEL = 2 ;
64+ private static final Integer BIT_PER_SAMPLE = 16 ;
6365 private static final Integer SAMPLES_PER_CALL = 4410 ;
64- private static final Integer SAMPLE_NUM_OF_CHANNEL = 1 ;
66+ private static final String AUDIO_FILE = "output.raw" ;
67+ private InputStream inputStream ;
6568
6669 @ Override
6770 public void onCreate (@ Nullable Bundle savedInstanceState ) {
@@ -86,8 +89,8 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat
8689 mute .setOnClickListener (this );
8790 speaker = view .findViewById (R .id .btn_speaker );
8891 speaker .setOnClickListener (this );
89- loopback = view .findViewById (R .id .loopback );
90- loopback .setOnCheckedChangeListener (this );
92+ writeBackAudio = view .findViewById (R .id .audioWriteBack );
93+ writeBackAudio .setOnCheckedChangeListener (this );
9194 }
9295
9396 @ Override
@@ -107,18 +110,7 @@ public void onActivityCreated(@Nullable Bundle savedInstanceState) {
107110 * The SDK uses this class to report to the app on SDK runtime events.*/
108111 String appId = getString (R .string .agora_app_id );
109112 engine = RtcEngine .create (getContext ().getApplicationContext (), appId , iRtcEngineEventHandler );
110- /** Registers the audio observer object.
111- *
112- * @param observer Audio observer object to be registered. See {@link IAudioFrameObserver IAudioFrameObserver}. Set the value as @p null to cancel registering, if necessary.
113- * @return
114- * - 0: Success.
115- * - < 0: Failure.
116- */
117- engine .registerAudioFrameObserver (audioFrameObserver );
118- engine .setRecordingAudioFrameParameters (SAMPLE_RATE , SAMPLE_NUM_OF_CHANNEL , Constants .RAW_AUDIO_FRAME_OP_MODE_READ_ONLY , SAMPLES_PER_CALL );
119- engine .setMixedAudioFrameParameters (SAMPLE_RATE , SAMPLES_PER_CALL );
120- engine .setPlaybackAudioFrameParameters (SAMPLE_RATE , SAMPLE_NUM_OF_CHANNEL , Constants .RAW_AUDIO_FRAME_OP_MODE_READ_ONLY , SAMPLES_PER_CALL );
121- mAudioPlayer = new AudioPlayer (AudioManager .STREAM_VOICE_CALL , SAMPLE_RATE , SAMPLE_NUM_OF_CHANNEL , AudioFormat .CHANNEL_OUT_MONO );
113+ openAudioFile ();
122114 }
123115 catch (Exception e ) {
124116 e .printStackTrace ();
@@ -135,7 +127,45 @@ public void onDestroy() {
135127 }
136128 handler .post (RtcEngine ::destroy );
137129 engine = null ;
138- mAudioPlayer .stopPlayer ();
130+ closeAudioFile ();
131+ }
132+
133+ private void openAudioFile (){
134+ try {
135+ inputStream = this .getResources ().getAssets ().open (AUDIO_FILE );
136+ } catch (IOException e ) {
137+ e .printStackTrace ();
138+ }
139+ }
140+
141+ private void closeAudioFile (){
142+ try {
143+ inputStream .close ();
144+ } catch (IOException e ) {
145+ e .printStackTrace ();
146+ }
147+ }
148+
149+ private byte [] readBuffer (){
150+ int byteSize = SAMPLES_PER_CALL * BIT_PER_SAMPLE / 8 ;
151+ byte [] buffer = new byte [byteSize ];
152+ try {
153+ if (inputStream .read (buffer ) < 0 ){
154+ inputStream .reset ();
155+ return readBuffer ();
156+ }
157+ } catch (IOException e ) {
158+ e .printStackTrace ();
159+ }
160+ return buffer ;
161+ }
162+
163+ private byte [] audioAggregate (byte [] origin , byte [] buffer ) {
164+ byte [] output = new byte [origin .length ];
165+ for (int i = 0 ; i < origin .length ; i ++) {
166+ output [i ] = (byte ) ((int ) origin [i ] + (int ) buffer [i ] / 2 );
167+ }
168+ return output ;
139169 }
140170
141171 @ Override
@@ -240,8 +270,14 @@ private void joinChannel(String channelId) {
240270 }
241271 // Prevent repeated entry
242272 join .setEnabled (false );
243-
244-
273+ /** Registers the audio observer object.
274+ *
275+ * @param observer Audio observer object to be registered. See {@link IAudioFrameObserver IAudioFrameObserver}. Set the value as @p null to cancel registering, if necessary.
276+ * @return
277+ * - 0: Success.
278+ * - < 0: Failure.
279+ */
280+ engine .registerAudioFrameObserver (audioFrameObserver );
245281 }
246282
247283 /**
@@ -285,7 +321,6 @@ public void onLeaveChannel(RtcStats stats) {
285321 public void onJoinChannelSuccess (String channel , int uid , int elapsed ) {
286322 Log .i (TAG , String .format ("onJoinChannelSuccess channel %s uid %d" , channel , uid ));
287323 showLongToast (String .format ("onJoinChannelSuccess channel %s uid %d" , channel , uid ));
288- mAudioPlayer .startPlayer ();
289324 myUid = uid ;
290325 joined = true ;
291326 handler .post (new Runnable () {
@@ -295,7 +330,7 @@ public void run() {
295330 mute .setEnabled (true );
296331 join .setEnabled (true );
297332 join .setText (getString (R .string .leave ));
298- loopback .setEnabled (true );
333+ writeBackAudio .setEnabled (true );
299334 }
300335 });
301336 }
@@ -375,7 +410,16 @@ public void onActiveSpeaker(int uid) {
375410 private final IAudioFrameObserver audioFrameObserver = new IAudioFrameObserver () {
376411 @ Override
377412 public boolean onRecordFrame (AudioFrame audioFrame ) {
378- return false ;
413+ Log .i (TAG , "onRecordAudioFrame " + isWriteBackAudio );
414+ if (isWriteBackAudio ){
415+ ByteBuffer byteBuffer = audioFrame .samples ;
416+ byte [] buffer = readBuffer ();
417+ byte [] origin = new byte [byteBuffer .remaining ()];
418+ byteBuffer .get (origin );
419+ byteBuffer .flip ();
420+ byteBuffer .put (audioAggregate (origin , buffer ), 0 , byteBuffer .remaining ());
421+ }
422+ return true ;
379423 }
380424
381425 @ Override
@@ -405,27 +449,27 @@ public boolean onPlaybackFrameBeforeMixingEx(AudioFrame audioFrame, int uid, Str
405449
406450 @ Override
407451 public int getObservedAudioFramePosition () {
408- return 0 ;
452+ return IAudioFrameObserver . POSITION_RECORD | IAudioFrameObserver . POSITION_MIXED ;
409453 }
410454
411455 @ Override
412456 public AudioParams getRecordAudioParams () {
413- return null ;
457+ return new AudioParams ( SAMPLE_RATE , SAMPLE_NUM_OF_CHANNEL , Constants . RAW_AUDIO_FRAME_OP_MODE_READ_WRITE , SAMPLES_PER_CALL ) ;
414458 }
415459
416460 @ Override
417461 public AudioParams getPlaybackAudioParams () {
418- return null ;
462+ return new AudioParams ( SAMPLE_RATE , SAMPLE_NUM_OF_CHANNEL , Constants . RAW_AUDIO_FRAME_OP_MODE_READ_ONLY , SAMPLES_PER_CALL ) ;
419463 }
420464
421465 @ Override
422466 public AudioParams getMixedAudioParams () {
423- return null ;
467+ return new AudioParams ( SAMPLE_RATE , SAMPLE_NUM_OF_CHANNEL , Constants . RAW_AUDIO_FRAME_OP_MODE_READ_ONLY , SAMPLES_PER_CALL ) ;
424468 }
425469 };
426470
427471 @ Override
428472 public void onCheckedChanged (CompoundButton compoundButton , boolean b ) {
429- isEnableLoopBack = b ;
473+ isWriteBackAudio = b ;
430474 }
431475}
0 commit comments