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