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,15 +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- mAudioPlayer = new AudioPlayer (AudioManager .STREAM_VOICE_CALL , SAMPLE_RATE , SAMPLE_NUM_OF_CHANNEL , AudioFormat .CHANNEL_OUT_MONO );
113+ openAudioFile ();
119114 }
120115 catch (Exception e ) {
121116 e .printStackTrace ();
@@ -132,7 +127,45 @@ public void onDestroy() {
132127 }
133128 handler .post (RtcEngine ::destroy );
134129 engine = null ;
135- 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 ;
136169 }
137170
138171 @ Override
@@ -237,8 +270,14 @@ private void joinChannel(String channelId) {
237270 }
238271 // Prevent repeated entry
239272 join .setEnabled (false );
240-
241-
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 );
242281 }
243282
244283 /**
@@ -282,7 +321,6 @@ public void onLeaveChannel(RtcStats stats) {
282321 public void onJoinChannelSuccess (String channel , int uid , int elapsed ) {
283322 Log .i (TAG , String .format ("onJoinChannelSuccess channel %s uid %d" , channel , uid ));
284323 showLongToast (String .format ("onJoinChannelSuccess channel %s uid %d" , channel , uid ));
285- mAudioPlayer .startPlayer ();
286324 myUid = uid ;
287325 joined = true ;
288326 handler .post (new Runnable () {
@@ -292,7 +330,7 @@ public void run() {
292330 mute .setEnabled (true );
293331 join .setEnabled (true );
294332 join .setText (getString (R .string .leave ));
295- loopback .setEnabled (true );
333+ writeBackAudio .setEnabled (true );
296334 }
297335 });
298336 }
@@ -372,7 +410,16 @@ public void onActiveSpeaker(int uid) {
372410 private final IAudioFrameObserver audioFrameObserver = new IAudioFrameObserver () {
373411 @ Override
374412 public boolean onRecordFrame (AudioFrame audioFrame ) {
375- 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 ;
376423 }
377424
378425 @ Override
@@ -402,12 +449,12 @@ public boolean onPlaybackFrameBeforeMixingEx(AudioFrame audioFrame, int uid, Str
402449
403450 @ Override
404451 public int getObservedAudioFramePosition () {
405- return 0 ;
452+ return IAudioFrameObserver . POSITION_RECORD | IAudioFrameObserver . POSITION_MIXED ;
406453 }
407454
408455 @ Override
409456 public AudioParams getRecordAudioParams () {
410- return new AudioParams (SAMPLE_RATE , SAMPLE_NUM_OF_CHANNEL , Constants .RAW_AUDIO_FRAME_OP_MODE_READ_ONLY , SAMPLES_PER_CALL );
457+ return new AudioParams (SAMPLE_RATE , SAMPLE_NUM_OF_CHANNEL , Constants .RAW_AUDIO_FRAME_OP_MODE_READ_WRITE , SAMPLES_PER_CALL );
411458 }
412459
413460 @ Override
@@ -423,6 +470,6 @@ public AudioParams getMixedAudioParams() {
423470
424471 @ Override
425472 public void onCheckedChanged (CompoundButton compoundButton , boolean b ) {
426- isEnableLoopBack = b ;
473+ isWriteBackAudio = b ;
427474 }
428475}
0 commit comments