1 /* 2 * Copyright 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package org.hyphonate.megaaudio.duplex; 17 18 import android.media.AudioDeviceInfo; 19 import android.util.Log; 20 21 import org.hyphonate.megaaudio.common.BuilderBase; 22 import org.hyphonate.megaaudio.common.StreamBase; 23 import org.hyphonate.megaaudio.player.AudioSource; 24 import org.hyphonate.megaaudio.player.AudioSourceProvider; 25 import org.hyphonate.megaaudio.player.Player; 26 import org.hyphonate.megaaudio.player.PlayerBuilder; 27 import org.hyphonate.megaaudio.recorder.AudioSinkProvider; 28 import org.hyphonate.megaaudio.recorder.Recorder; 29 import org.hyphonate.megaaudio.recorder.RecorderBuilder; 30 31 public class DuplexAudioManager { 32 private static final String TAG = DuplexAudioManager.class.getSimpleName(); 33 34 // Player 35 //TODO - explain these constants 36 private int mNumPlayerChannels = 2; 37 private int mPlayerSampleRate = 48000; 38 private int mNumPlayerBufferFrames; 39 40 private Player mPlayer; 41 private AudioSourceProvider mSourceProvider; 42 private AudioDeviceInfo mPlayerSelectedDevice; 43 44 // Recorder 45 private int mNumRecorderChannels = 2; 46 private int mRecorderSampleRate = 48000; 47 private int mNumRecorderBufferFrames; 48 49 private Recorder mRecorder; 50 private AudioSinkProvider mSinkProvider; 51 private AudioDeviceInfo mRecorderSelectedDevice; 52 private int mInputPreset = Recorder.INPUT_PRESET_NONE; 53 DuplexAudioManager(AudioSourceProvider sourceProvider, AudioSinkProvider sinkProvider)54 public DuplexAudioManager(AudioSourceProvider sourceProvider, AudioSinkProvider sinkProvider) { 55 mSourceProvider = sourceProvider; 56 mSinkProvider = sinkProvider; 57 } 58 getPlayer()59 public Player getPlayer() { 60 return mPlayer; 61 } 62 getRecorder()63 public Recorder getRecorder() { 64 return mRecorder; 65 } 66 setNumRecorderChannels(int numChannels)67 public void setNumRecorderChannels(int numChannels) { 68 mNumRecorderChannels = numChannels; 69 } 70 setInputPreset(int preset)71 public void setInputPreset(int preset) { mInputPreset = preset; } 72 setupStreams(int playerType, int recorderType)73 public int setupStreams(int playerType, int recorderType) { 74 // Recorder 75 if ((recorderType & BuilderBase.TYPE_MASK) != BuilderBase.TYPE_NONE) { 76 try { 77 mRecorder = new RecorderBuilder() 78 .setRecorderType(recorderType) 79 .setAudioSinkProvider(mSinkProvider) 80 .build(); 81 if (mInputPreset != Recorder.INPUT_PRESET_NONE) { 82 mRecorder.setInputPreset(mInputPreset); 83 } 84 mRecorder.setRouteDevice(mRecorderSelectedDevice); 85 int errorCode = mRecorder.setupStream( 86 mNumRecorderChannels, mRecorderSampleRate, mNumRecorderBufferFrames); 87 if (errorCode != StreamBase.OK) { 88 Log.e(TAG, "Recorder setupStream() failed code: " + errorCode); 89 return errorCode; 90 } 91 mNumRecorderBufferFrames = mRecorder.getNumBufferFrames(); 92 } catch (RecorderBuilder.BadStateException ex) { 93 Log.e(TAG, "Recorder - BadStateException" + ex); 94 return StreamBase.ERROR_UNSUPPORTED; 95 } 96 } 97 98 // Player 99 if ((playerType & BuilderBase.TYPE_MASK) != BuilderBase.TYPE_NONE) { 100 try { 101 mNumPlayerBufferFrames = 102 Player.calcMinBufferFrames(mNumPlayerChannels, mPlayerSampleRate); 103 mPlayer = new PlayerBuilder() 104 .setPlayerType(playerType) 105 .setSourceProvider(mSourceProvider) 106 .build(); 107 mPlayer.setRouteDevice(mPlayerSelectedDevice); 108 int errorCode = mPlayer.setupStream( 109 mNumPlayerChannels, mPlayerSampleRate, mNumPlayerBufferFrames); 110 if (errorCode != StreamBase.OK) { 111 Log.e(TAG, "Player - setupStream() failed code: " + errorCode); 112 return errorCode; 113 } 114 } catch (PlayerBuilder.BadStateException ex) { 115 Log.e(TAG, "Player - BadStateException" + ex); 116 return StreamBase.ERROR_UNSUPPORTED; 117 } 118 } 119 120 return StreamBase.OK; 121 } 122 start()123 public int start() { 124 int result = StreamBase.OK; 125 if (mRecorder != null && (result = mRecorder.startStream()) != StreamBase.OK) { 126 return result; 127 } 128 129 if (mPlayer != null && (result = mPlayer.startStream()) != StreamBase.OK) { 130 return result; 131 } 132 133 return result; 134 } 135 stop()136 public int stop() { 137 int playerResult = StreamBase.OK; 138 if (mPlayer != null) { 139 int result1 = mPlayer.stopStream(); 140 int result2 = mPlayer.teardownStream(); 141 playerResult = result1 != StreamBase.OK ? result1 : result2; 142 } 143 144 int recorderResult = StreamBase.OK; 145 if (mRecorder != null) { 146 int result1 = mRecorder.stopStream(); 147 int result2 = mRecorder.teardownStream(); 148 recorderResult = result1 != StreamBase.OK ? result1 : result2; 149 } 150 151 return playerResult != StreamBase.OK ? playerResult: recorderResult; 152 } 153 getNumPlayerBufferFrames()154 public int getNumPlayerBufferFrames() { 155 return mPlayer != null ? mPlayer.getNumBufferFrames() : 0; 156 } 157 getNumRecorderBufferFrames()158 public int getNumRecorderBufferFrames() { 159 return mRecorder != null ? mRecorder.getNumBufferFrames() : 0; 160 } 161 getAudioSource()162 public AudioSource getAudioSource() { 163 return mPlayer != null ? mPlayer.getAudioSource() : null; 164 } 165 } 166