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.recorder; 17 18 import android.media.AudioFormat; 19 import android.media.AudioRecord; 20 21 import org.hyphonate.megaaudio.common.StreamBase; 22 23 public abstract class Recorder extends StreamBase { 24 protected AudioSinkProvider mSinkProvider; 25 26 // This value is to indicate that no explicit call to set an input preset in the builder 27 // will be made. 28 // Constants can be found here: 29 // https://developer.android.com/reference/android/media/MediaRecorder.AudioSource 30 public static final int INPUT_PRESET_NONE = -1; 31 Recorder(AudioSinkProvider sinkProvider)32 public Recorder(AudioSinkProvider sinkProvider) { 33 mSinkProvider = sinkProvider; 34 } setInputPreset(int preset)35 public abstract void setInputPreset(int preset); 36 37 /* 38 * State 39 */ isRecording()40 public abstract boolean isRecording(); 41 42 /* 43 * Utilities 44 */ 45 public static final int AUDIO_CHANNEL_COUNT_MAX = 30; 46 47 public static final int AUDIO_CHANNEL_REPRESENTATION_POSITION = 0x0; 48 public static final int AUDIO_CHANNEL_REPRESENTATION_INDEX = 0x2; 49 50 // 51 // Attributes 52 // 53 // This needs to be static because it is called before creating the Recorder subclass calcMinBufferFrames(int channelCount, int sampleRate)54 public static int calcMinBufferFrames(int channelCount, int sampleRate) { 55 int channelMask = Recorder.channelCountToChannelMask(channelCount); 56 int bufferSizeInBytes = 57 AudioRecord.getMinBufferSize (sampleRate, 58 channelMask, 59 AudioFormat.ENCODING_PCM_FLOAT); 60 return bufferSizeInBytes / sampleSizeInBytes(AudioFormat.ENCODING_PCM_FLOAT); 61 } 62 63 /* 64 * Channel Utils 65 */ 66 // TODO - Consider moving these into a "Utilities" library 67 // /** 68 // * @param chanCount The number of channels for which to generate an index mask. 69 // * @return A channel index mask corresponding to the supplied channel count. 70 // * 71 // * @note The generated index mask has active channels from 0 to chanCount - 1 72 // */ 73 // public static int countToIndexMask(int chanCount) { 74 // return (1 << chanCount) - 1; 75 // } 76 77 /* Not part of public API */ audioChannelMaskFromRepresentationAndBits(int representation, int bits)78 private static int audioChannelMaskFromRepresentationAndBits(int representation, int bits) 79 { 80 return ((representation << AUDIO_CHANNEL_COUNT_MAX) | bits); 81 } 82 83 /* Derive a channel mask for index assignment from a channel count. 84 * Returns the matching channel mask, 85 * or AUDIO_CHANNEL_NONE if the channel count is zero, 86 * or AUDIO_CHANNEL_INVALID if the channel count exceeds AUDIO_CHANNEL_COUNT_MAX. 87 */ audioChannelMaskForIndexAssignmentFromCount(int channel_count)88 private static int audioChannelMaskForIndexAssignmentFromCount(int channel_count) 89 { 90 if (channel_count == 0) { 91 return 0; // AUDIO_CHANNEL_NONE 92 } 93 if (channel_count > AUDIO_CHANNEL_COUNT_MAX) { 94 return AudioFormat.CHANNEL_INVALID; 95 } 96 int bits = (1 << channel_count) - 1; 97 return audioChannelMaskFromRepresentationAndBits(AUDIO_CHANNEL_REPRESENTATION_INDEX, bits); 98 } 99 100 /** 101 * @param channelCount The number of channels for which to generate an input position mask. 102 * @return An input channel-position mask corresponding the supplied number of channels. 103 */ channelCountToChannelMask(int channelCount)104 public static int channelCountToChannelMask(int channelCount) { 105 int bits; 106 switch (channelCount) { 107 case 1: 108 bits = AudioFormat.CHANNEL_IN_MONO; 109 break; 110 111 case 2: 112 bits = AudioFormat.CHANNEL_IN_STEREO; 113 break; 114 115 case 3: 116 case 4: 117 case 5: 118 case 6: 119 case 7: 120 case 8: 121 // FIXME FCC_8 122 return audioChannelMaskForIndexAssignmentFromCount(channelCount); 123 124 default: 125 return AudioFormat.CHANNEL_INVALID; 126 } 127 128 return audioChannelMaskFromRepresentationAndBits(AUDIO_CHANNEL_REPRESENTATION_POSITION, bits); 129 } 130 131 } 132