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.common;
17 
18 import android.media.AudioDeviceCallback;
19 import android.media.AudioDeviceInfo;
20 import android.media.AudioFormat;
21 
22 public abstract class StreamBase {
23     //
24     // Error Codes
25     // These values must be kept in sync with the equivalent symbols in
26     // megaaudio/common/Streambase.h
27     //
28     public static final int OK = 0;
29     public static final int ERROR_UNKNOWN = -1;
30     public static final int ERROR_UNSUPPORTED = -2;
31     public static final int ERROR_INVALID_STATE = -3;
32 
33     //
34     // Stream attributes
35     //
36     protected int mChannelCount;
37     protected int mSampleRate;
38 
39     // Routing
40     protected AudioDeviceInfo mRouteDevice;
41 
42     // the thread on which the underlying Android AudioTrack/AudioRecord will run
43     protected Thread mStreamThread = null;
44 
45     //
46     // Attributes
47     //
getChannelCount()48     public int getChannelCount() { return mChannelCount; }
getSampleRate()49     public int getSampleRate() { return mSampleRate; }
50 
getNumBufferFrames()51     public abstract int getNumBufferFrames();
52 
53     // Routing
setRouteDevice(AudioDeviceInfo routeDevice)54     public void setRouteDevice(AudioDeviceInfo routeDevice) {
55         mRouteDevice = routeDevice;
56     }
57 
58     public static final int ROUTED_DEVICE_ID_INVALID = -1;
getRoutedDeviceId()59     public abstract int getRoutedDeviceId();
60 
61     //
62     // Sample Format Utils
63     //
64     /**
65      * @param encoding An Android ENCODING_ constant for audio data.
66      * @return The size in BYTES of samples encoded as specified.
67      */
sampleSizeInBytes(int encoding)68     public static int sampleSizeInBytes(int encoding) {
69         switch (encoding) {
70             case AudioFormat.ENCODING_PCM_16BIT:
71                 return 2;
72 
73             case AudioFormat.ENCODING_PCM_FLOAT:
74                 return 4;
75 
76             default:
77                 return 0;
78         }
79     }
80 
81     /**
82      * @param numChannels   The number of channels in a FRAME of audio data.
83      * @return  The size in BYTES of a FRAME of audio data encoded as specified.
84      */
calcFrameSizeInBytes(int numChannels)85     public static int calcFrameSizeInBytes(int numChannels) {
86         return sampleSizeInBytes(AudioFormat.ENCODING_PCM_FLOAT) * numChannels;
87     }
88 
89     //
90     // State
91     //
92 
93     /**
94      * @param channelCount  The number of channels of audio data to be streamed.
95      * @param sampleRate    The stream sample rate
96      * @param numFrames     The number of frames of audio data in the stream's buffer.
97      * @return              ERROR_NONE if successful, otherwise an error code
98      */
setupStream(int channelCount, int sampleRate, int numFrames)99     public abstract int setupStream(int channelCount, int sampleRate, int numFrames);
100 
teardownStream()101     public abstract int teardownStream();
102 
103     /**
104      * Starts playback on an open stream player. (@see open() method above).
105      * @return              ERROR_NONE if successful, otherwise an error code
106      */
startStream()107     public abstract int startStream();
108 
109     /**
110      * Stops playback.
111      * May not stop the stream immediately. i.e. does not stop until the next audio callback
112      * from the underlying system.
113      * @return              ERROR_NONE if successful, otherwise an error code
114      */
stopStream()115     public abstract int stopStream();
116 
117     //
118     // Thread stuff
119     //
120     /**
121      * Joins the record thread to ensure that the stream is stopped.
122      */
waitForStreamThreadToExit()123     protected void waitForStreamThreadToExit() {
124         try {
125             if (mStreamThread != null) {
126                 mStreamThread.join();
127                 mStreamThread = null;
128             }
129         } catch (InterruptedException e) {
130             e.printStackTrace();
131         }
132     }
133 
134     //
135     // Utility
136     //
137     /**
138      * @param chanCount The number of channels for which to generate an index mask.
139      * @return  A channel index mask corresponding to the supplied channel count.
140      *
141      * @note The generated index mask has active channels from 0 to chanCount - 1
142      */
channelCountToIndexMask(int chanCount)143     public static int channelCountToIndexMask(int chanCount) {
144         return  (1 << chanCount) - 1;
145     }
146 }
147