├── .classpath
├── .gitignore
├── .project
├── .settings
└── org.eclipse.jdt.core.prefs
├── LICENSE
├── NOTICE
├── README.md
├── demo
├── .classpath
├── .project
├── .settings
│ └── org.eclipse.jdt.core.prefs
├── AndroidManifest.xml
├── gen
│ └── com
│ │ └── skd
│ │ └── androidrecordingtest
│ │ └── BuildConfig.java
├── libs
│ └── android-support-v4.jar
├── proguard-project.txt
├── project.properties
├── res
│ ├── drawable-hdpi
│ │ ├── ic_launcher.png
│ │ └── ic_switch.jpg
│ ├── drawable-mdpi
│ │ └── ic_launcher.png
│ ├── drawable-xhdpi
│ │ └── ic_launcher.png
│ ├── layout
│ │ ├── audio_play.xml
│ │ ├── audio_rec.xml
│ │ ├── main.xml
│ │ ├── video_play.xml
│ │ └── video_rec.xml
│ ├── values-sw600dp
│ │ └── dimens.xml
│ ├── values-sw720dp-land
│ │ └── dimens.xml
│ ├── values-v11
│ │ └── styles.xml
│ ├── values-v14
│ │ └── styles.xml
│ └── values
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
└── src
│ └── com
│ └── skd
│ └── androidrecordingtest
│ ├── AudioPlaybackActivity.java
│ ├── AudioRecordingActivity.java
│ ├── MainActivity.java
│ ├── SizeAdapter.java
│ ├── VideoPlaybackActivity.java
│ ├── VideoRecordingActivity.java
│ └── utils
│ ├── NotificationUtils.java
│ └── StorageUtils.java
└── lib
├── .classpath
├── .project
├── .settings
└── org.eclipse.jdt.core.prefs
├── AndroidManifest.xml
├── gen
└── com
│ └── skd
│ └── androidrecording
│ └── BuildConfig.java
├── libs
├── android-support-v4.jar
└── simplesound-0.1.jar
├── proguard-project.txt
├── project.properties
├── res
├── drawable-hdpi
│ └── ic_launcher.png
├── drawable-mdpi
│ └── ic_launcher.png
├── drawable-xhdpi
│ └── ic_launcher.png
├── values-v11
│ └── styles.xml
├── values-v14
│ └── styles.xml
└── values
│ ├── strings.xml
│ └── styles.xml
└── src
└── com
└── skd
└── androidrecording
├── audio
├── AudioPlaybackManager.java
├── AudioRecordingHandler.java
└── AudioRecordingThread.java
├── fft
├── Complex.java
└── FFT.java
├── video
├── AdaptiveSurfaceView.java
├── CameraHelper.java
├── CameraManager.java
├── MediaPlayerManager.java
├── MediaRecorderManager.java
├── PlaybackHandler.java
├── VideoPlaybackManager.java
├── VideoRecordingHandler.java
└── VideoRecordingManager.java
└── visualizer
├── AudioData.java
├── FFTData.java
├── VisualizerView.java
└── renderer
├── BarGraphRenderer.java
└── Renderer.java
/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | bin/
2 | Thumbs.db
3 | R.java
4 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | AndroidRecording
4 |
5 |
6 |
7 |
8 |
9 | com.android.ide.eclipse.adt.ResourceManagerBuilder
10 |
11 |
12 |
13 |
14 | com.android.ide.eclipse.adt.PreCompilerBuilder
15 |
16 |
17 |
18 |
19 | org.eclipse.jdt.core.javabuilder
20 |
21 |
22 |
23 |
24 | com.android.ide.eclipse.adt.ApkBuilder
25 |
26 |
27 |
28 |
29 |
30 | com.android.ide.eclipse.adt.AndroidNature
31 | org.eclipse.jdt.core.javanature
32 |
33 |
34 |
--------------------------------------------------------------------------------
/.settings/org.eclipse.jdt.core.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
3 | org.eclipse.jdt.core.compiler.compliance=1.6
4 | org.eclipse.jdt.core.compiler.source=1.6
5 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/NOTICE:
--------------------------------------------------------------------------------
1 | AndroidRecording
2 | Copyright (C) 2013 Steelkiwi Development, Julia Zudikova
3 |
4 | This software contains code derived from Android-Visualizer project licensed under the Mit license http://opensource.org/licenses/mit-license.php and available from https://github.com/felixpalmer/android-visualizer.
5 |
6 | This software contains code from the "Get frequency wav audio using FFT and Complex class" post discussed at http://stackoverflow.com/questions/17429407/get-frequency-wav-audio-using-fft-and-complex-class.
7 |
8 | This software contains code from the "Recording .Wav with Android AudioRecorder" post discussed at http://stackoverflow.com/questions/17192256/recording-wav-with-android-audiorecorder and from Simplesound project available from https://code.google.com/p/simplesound/.
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Android Recording Library
2 | =======================================
3 |
4 | Android Recording library offers convenient tools for audio/video recording and playback.
5 |
6 | For audio it uses:
7 | * AudioRecord to capture and save audio signal from microphone
8 | * MediaPlayer with MediaController to play recorded audio
9 | * custom Visualizer (like bar chart) to represent audio signal on screen while recording and during playback
10 |
11 | For video it uses:
12 | * Camera and MediaRecorder to record a video of specified resolution
13 | * MediaPlayer with MediaController to play recorded video
14 | * custom SurfaceView with adjustable size to properly display Camera preview and recorded video (in portrait and landscape modes)
15 |
16 | Record audio: how to use
17 | ------------------------
18 |
19 | 1. Setup VisualizerView
20 |
21 | ```xml
22 |
26 |
27 | ```
28 |
29 | ```java
30 | visualizerView = (VisualizerView) findViewById(R.id.visualizerView);
31 | setupVisualizer();
32 |
33 | ...
34 |
35 | private void setupVisualizer() {
36 | Paint paint = new Paint();
37 | paint.setStrokeWidth(5f); //set bar width
38 | paint.setAntiAlias(true);
39 | paint.setColor(Color.argb(200, 227, 69, 53)); //set bar color
40 | BarGraphRenderer barGraphRendererBottom = new BarGraphRenderer(2, paint, false);
41 | visualizerView.addRenderer(barGraphRendererBottom);
42 | }
43 | ```
44 |
45 | 2. Start recording thread
46 |
47 | ```java
48 | private void startRecording() {
49 | recordingThread = new AudioRecordingThread(fileName, new AudioRecordingHandler() { //pass file name where to store the recorded audio
50 | @Override
51 | public void onFftDataCapture(final byte[] bytes) {
52 | runOnUiThread(new Runnable() {
53 | public void run() {
54 | if (visualizerView != null) {
55 | visualizerView.updateVisualizerFFT(bytes); //update VisualizerView with new audio portion
56 | }
57 | }
58 | });
59 | }
60 |
61 | @Override
62 | public void onRecordSuccess() {}
63 |
64 | @Override
65 | public void onRecordingError() {}
66 |
67 | @Override
68 | public void onRecordSaveError() {}
69 | });
70 | recordingThread.start();
71 | }
72 | ```
73 |
74 | 3. When done, stop recording
75 |
76 | ```java
77 | private void stopRecording() {
78 | if (recordingThread != null) {
79 | recordingThread.stopRecording();
80 | recordingThread = null;
81 | }
82 | }
83 | ```
84 |
85 | Play audio: how to use
86 | ------------------------
87 |
88 | 1. Setup VisualizerView
89 |
90 | 2. Setup AudioPlaybackManager. It will attach MediaPlayer to a VisualizerView
91 |
92 | ```java
93 | playbackManager = new AudioPlaybackManager(this, visualizerView, playbackHandler);
94 | playbackManager.setupPlayback(fileName); //pass file name of the recorded audio
95 | ```
96 |
97 | 3. Use onscreen MediaController to play/pause/stop/rewind audio
98 |
99 |
100 | Record video: how to use
101 | ------------------------
102 |
103 | 1. Setup custom SurfaceView (AdaptiveSurfaceView)
104 |
105 | ```xml
106 |
110 | ```
111 |
112 | 2. Setup RecordingManager
113 |
114 | ```java
115 | videoView = (AdaptiveSurfaceView) findViewById(R.id.videoView);
116 | recordingManager = new VideoRecordingManager(videoView, recordingHandler); //pass reference to custom SurfaceView
117 | ```
118 |
119 | 3. Choose desired video resolution and pass it to RecordingManager, it will adjust size of AdaptiveSurfaceView to properly display Camera output
120 |
121 | ```java
122 | recordingManager.setPreviewSize(videoSize);
123 | ```
124 |
125 | 4. To start recording use
126 |
127 | ```java
128 | recordingManager.startRecording(fileName, videoSize)
129 | ```
130 |
131 | 5. To stop recording use
132 |
133 | ```java
134 | recordingManager.stopRecording()
135 | ```
136 |
137 | Play video: how to use
138 | ------------------------
139 |
140 | 1. Setup custom SurfaceView (AdaptiveSurfaceView)
141 |
142 | 2. Setup VideoPlaybackManager. It will attach MediaPlayer to a VisualizerView
143 |
144 | ```java
145 | playbackManager = new VideoPlaybackManager(this, videoView, playbackHandler);
146 | playbackManager.setupPlayback(fileName); //pass file name of the recorded video
147 | ```
148 |
149 | 3. Use onscreen MediaController to play/pause/stop/rewind video
150 |
151 |
152 | ====================================
153 |
154 | For more details, please, see the demo project.
155 |
--------------------------------------------------------------------------------
/demo/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/demo/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | AndroidRecording-test
4 |
5 |
6 |
7 |
8 |
9 | com.android.ide.eclipse.adt.ResourceManagerBuilder
10 |
11 |
12 |
13 |
14 | com.android.ide.eclipse.adt.PreCompilerBuilder
15 |
16 |
17 |
18 |
19 | org.eclipse.jdt.core.javabuilder
20 |
21 |
22 |
23 |
24 | com.android.ide.eclipse.adt.ApkBuilder
25 |
26 |
27 |
28 |
29 |
30 | com.android.ide.eclipse.adt.AndroidNature
31 | org.eclipse.jdt.core.javanature
32 |
33 |
34 |
--------------------------------------------------------------------------------
/demo/.settings/org.eclipse.jdt.core.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
3 | org.eclipse.jdt.core.compiler.compliance=1.6
4 | org.eclipse.jdt.core.compiler.source=1.6
5 |
--------------------------------------------------------------------------------
/demo/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
25 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
39 |
40 |
43 |
44 |
48 |
49 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/demo/gen/com/skd/androidrecordingtest/BuildConfig.java:
--------------------------------------------------------------------------------
1 | /** Automatically generated file. DO NOT MODIFY */
2 | package com.skd.androidrecordingtest;
3 |
4 | public final class BuildConfig {
5 | public final static boolean DEBUG = true;
6 | }
--------------------------------------------------------------------------------
/demo/libs/android-support-v4.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steelkiwi/AndroidRecording/4d7956c30dbd6b12e8477a1070773730fa31ed50/demo/libs/android-support-v4.jar
--------------------------------------------------------------------------------
/demo/proguard-project.txt:
--------------------------------------------------------------------------------
1 | # To enable ProGuard in your project, edit project.properties
2 | # to define the proguard.config property as described in that file.
3 | #
4 | # Add project specific ProGuard rules here.
5 | # By default, the flags in this file are appended to flags specified
6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt
7 | # You can edit the include path and order by changing the ProGuard
8 | # include property in project.properties.
9 | #
10 | # For more details, see
11 | # http://developer.android.com/guide/developing/tools/proguard.html
12 |
13 | # Add any project specific keep options here:
14 |
15 | # If your project uses WebView with JS, uncomment the following
16 | # and specify the fully qualified class name to the JavaScript interface
17 | # class:
18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
19 | # public *;
20 | #}
21 |
--------------------------------------------------------------------------------
/demo/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system edit
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 | #
10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
12 |
13 | # Project target.
14 | target=android-18
15 | android.library.reference.1=../lib
16 |
--------------------------------------------------------------------------------
/demo/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steelkiwi/AndroidRecording/4d7956c30dbd6b12e8477a1070773730fa31ed50/demo/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo/res/drawable-hdpi/ic_switch.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steelkiwi/AndroidRecording/4d7956c30dbd6b12e8477a1070773730fa31ed50/demo/res/drawable-hdpi/ic_switch.jpg
--------------------------------------------------------------------------------
/demo/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steelkiwi/AndroidRecording/4d7956c30dbd6b12e8477a1070773730fa31ed50/demo/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steelkiwi/AndroidRecording/4d7956c30dbd6b12e8477a1070773730fa31ed50/demo/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/demo/res/layout/audio_play.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/demo/res/layout/audio_rec.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
14 |
15 |
23 |
24 |
31 |
32 |
33 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/demo/res/layout/main.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
13 |
14 |
--------------------------------------------------------------------------------
/demo/res/layout/video_play.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/demo/res/layout/video_rec.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
14 |
15 |
23 |
24 |
32 |
33 |
40 |
41 |
42 |
51 |
52 |
57 |
58 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/demo/res/values-sw600dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/demo/res/values-sw720dp-land/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 | 128dp
8 |
9 |
10 |
--------------------------------------------------------------------------------
/demo/res/values-v11/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/demo/res/values-v14/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/demo/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 16dp
5 | 16dp
6 |
7 |
8 |
--------------------------------------------------------------------------------
/demo/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Android Recording
5 | Audio Recording
6 | Video Recording
7 | Playback
8 |
9 |
10 | - @string/audioActivity
11 | - @string/videoActivity
12 |
13 |
14 | Record
15 | Stop
16 | Play
17 |
18 | External storage is unavailable
19 | Error recording audio
20 | Error saving audio record
21 | Recording video failed
22 |
23 |
--------------------------------------------------------------------------------
/demo/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
14 |
15 |
16 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/demo/src/com/skd/androidrecordingtest/AudioPlaybackActivity.java:
--------------------------------------------------------------------------------
1 | package com.skd.androidrecordingtest;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.graphics.Color;
6 | import android.graphics.Paint;
7 | import android.os.Bundle;
8 | import android.view.MotionEvent;
9 |
10 | import com.skd.androidrecording.audio.AudioPlaybackManager;
11 | import com.skd.androidrecording.video.PlaybackHandler;
12 | import com.skd.androidrecording.visualizer.VisualizerView;
13 | import com.skd.androidrecording.visualizer.renderer.BarGraphRenderer;
14 |
15 | public class AudioPlaybackActivity extends Activity {
16 | public static String FileNameArg = "arg_filename";
17 |
18 | private static String fileName = null;
19 |
20 | private VisualizerView visualizerView;
21 |
22 | private AudioPlaybackManager playbackManager;
23 |
24 | private PlaybackHandler playbackHandler = new PlaybackHandler() {
25 | @Override
26 | public void onPreparePlayback() {
27 | runOnUiThread (new Runnable() {
28 | public void run() {
29 | playbackManager.showMediaController();
30 | }
31 | });
32 | }
33 | };
34 |
35 | @Override
36 | protected void onCreate(Bundle savedInstanceState) {
37 | super.onCreate(savedInstanceState);
38 | setContentView(R.layout.audio_play);
39 |
40 | Intent i = getIntent();
41 | if ((i != null) && (i.getExtras() != null)) {
42 | fileName = i.getExtras().getString(FileNameArg);
43 | }
44 |
45 | visualizerView = (VisualizerView) findViewById(R.id.visualizerView);
46 | setupVisualizer();
47 |
48 | playbackManager = new AudioPlaybackManager(this, visualizerView, playbackHandler);
49 | playbackManager.setupPlayback(fileName);
50 | }
51 |
52 | @Override
53 | public boolean onTouchEvent(MotionEvent event) {
54 | playbackManager.showMediaController();
55 | return false;
56 | }
57 |
58 | @Override
59 | protected void onPause() {
60 | super.onPause();
61 |
62 | playbackManager.pause();
63 | playbackManager.hideMediaController();
64 | }
65 |
66 | @Override
67 | protected void onDestroy() {
68 | playbackManager.dispose();
69 | playbackHandler = null;
70 |
71 | super.onDestroy();
72 | }
73 |
74 | private void setupVisualizer() {
75 | Paint paint = new Paint();
76 | paint.setStrokeWidth(5f);
77 | paint.setAntiAlias(true);
78 | paint.setColor(Color.argb(200, 227, 69, 53));
79 | BarGraphRenderer barGraphRendererBottom = new BarGraphRenderer(2, paint, false);
80 | visualizerView.addRenderer(barGraphRendererBottom);
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/demo/src/com/skd/androidrecordingtest/AudioRecordingActivity.java:
--------------------------------------------------------------------------------
1 | package com.skd.androidrecordingtest;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.graphics.Color;
6 | import android.graphics.Paint;
7 | import android.os.Bundle;
8 | import android.view.View;
9 | import android.view.View.OnClickListener;
10 | import android.widget.Button;
11 |
12 | import com.skd.androidrecording.audio.AudioRecordingHandler;
13 | import com.skd.androidrecording.audio.AudioRecordingThread;
14 | import com.skd.androidrecording.visualizer.VisualizerView;
15 | import com.skd.androidrecording.visualizer.renderer.BarGraphRenderer;
16 | import com.skd.androidrecordingtest.utils.NotificationUtils;
17 | import com.skd.androidrecordingtest.utils.StorageUtils;
18 |
19 | public class AudioRecordingActivity extends Activity {
20 | private static String fileName = null;
21 |
22 | private Button recordBtn, playBtn;
23 | private VisualizerView visualizerView;
24 |
25 | private AudioRecordingThread recordingThread;
26 | private boolean startRecording = true;
27 |
28 | @Override
29 | protected void onCreate(Bundle savedInstanceState) {
30 | super.onCreate(savedInstanceState);
31 | setContentView(R.layout.audio_rec);
32 |
33 | if (!StorageUtils.checkExternalStorageAvailable()) {
34 | NotificationUtils.showInfoDialog(this, getString(R.string.noExtStorageAvailable));
35 | return;
36 | }
37 | fileName = StorageUtils.getFileName(true);
38 |
39 | recordBtn = (Button) findViewById(R.id.recordBtn);
40 | recordBtn.setOnClickListener(new OnClickListener() {
41 | @Override
42 | public void onClick(View v) {
43 | record();
44 | }
45 | });
46 |
47 | playBtn = (Button) findViewById(R.id.playBtn);
48 | playBtn.setOnClickListener(new OnClickListener() {
49 | @Override
50 | public void onClick(View v) {
51 | play();
52 | }
53 | });
54 |
55 | visualizerView = (VisualizerView) findViewById(R.id.visualizerView);
56 | setupVisualizer();
57 | }
58 |
59 | @Override
60 | protected void onPause() {
61 | super.onPause();
62 |
63 | recordStop();
64 | }
65 |
66 | @Override
67 | protected void onDestroy() {
68 | recordStop();
69 | releaseVisualizer();
70 |
71 | super.onDestroy();
72 | }
73 |
74 | private void setupVisualizer() {
75 | Paint paint = new Paint();
76 | paint.setStrokeWidth(5f);
77 | paint.setAntiAlias(true);
78 | paint.setColor(Color.argb(200, 227, 69, 53));
79 | BarGraphRenderer barGraphRendererBottom = new BarGraphRenderer(2, paint, false);
80 | visualizerView.addRenderer(barGraphRendererBottom);
81 | }
82 |
83 | private void releaseVisualizer() {
84 | visualizerView.release();
85 | visualizerView = null;
86 | }
87 |
88 | private void record() {
89 | if (startRecording) {
90 | recordStart();
91 | }
92 | else {
93 | recordStop();
94 | }
95 | }
96 |
97 | private void recordStart() {
98 | startRecording();
99 | startRecording = false;
100 | recordBtn.setText(R.string.stopRecordBtn);
101 | playBtn.setEnabled(false);
102 | }
103 |
104 | private void recordStop() {
105 | stopRecording();
106 | startRecording = true;
107 | recordBtn.setText(R.string.recordBtn);
108 | playBtn.setEnabled(true);
109 | }
110 |
111 | private void startRecording() {
112 | recordingThread = new AudioRecordingThread(fileName, new AudioRecordingHandler() {
113 | @Override
114 | public void onFftDataCapture(final byte[] bytes) {
115 | runOnUiThread(new Runnable() {
116 | public void run() {
117 | if (visualizerView != null) {
118 | visualizerView.updateVisualizerFFT(bytes);
119 | }
120 | }
121 | });
122 | }
123 |
124 | @Override
125 | public void onRecordSuccess() {}
126 |
127 | @Override
128 | public void onRecordingError() {
129 | runOnUiThread(new Runnable() {
130 | public void run() {
131 | recordStop();
132 | NotificationUtils.showInfoDialog(AudioRecordingActivity.this, getString(R.string.recordingError));
133 | }
134 | });
135 | }
136 |
137 | @Override
138 | public void onRecordSaveError() {
139 | runOnUiThread(new Runnable() {
140 | public void run() {
141 | recordStop();
142 | NotificationUtils.showInfoDialog(AudioRecordingActivity.this, getString(R.string.saveRecordError));
143 | }
144 | });
145 | }
146 | });
147 | recordingThread.start();
148 | }
149 |
150 | private void stopRecording() {
151 | if (recordingThread != null) {
152 | recordingThread.stopRecording();
153 | recordingThread = null;
154 | }
155 | }
156 |
157 | private void play() {
158 | Intent i = new Intent(AudioRecordingActivity.this, AudioPlaybackActivity.class);
159 | i.putExtra(VideoPlaybackActivity.FileNameArg, fileName);
160 | startActivityForResult(i, 0);
161 | }
162 | }
163 |
--------------------------------------------------------------------------------
/demo/src/com/skd/androidrecordingtest/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.skd.androidrecordingtest;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import android.view.View;
7 | import android.widget.AdapterView;
8 | import android.widget.AdapterView.OnItemClickListener;
9 | import android.widget.ArrayAdapter;
10 | import android.widget.ListView;
11 |
12 | public class MainActivity extends Activity {
13 |
14 | @Override
15 | protected void onCreate(Bundle savedInstanceState) {
16 | super.onCreate(savedInstanceState);
17 | setContentView(R.layout.main);
18 |
19 | ListView list = (ListView) findViewById(android.R.id.list);
20 | ArrayAdapter listAdapter = new ArrayAdapter(getApplicationContext(),
21 | android.R.layout.simple_list_item_1,
22 | getResources().getStringArray(R.array.activities));
23 | list.setAdapter(listAdapter);
24 | list.setOnItemClickListener(new OnItemClickListener() {
25 | @Override
26 | public void onItemClick(AdapterView> arg0, View arg1, int arg2, long arg3) {
27 | launchDemo(arg2);
28 | }
29 | });
30 | }
31 |
32 | private void launchDemo(int position) {
33 | switch (position) {
34 | case 0: default: {
35 | Intent i = new Intent(MainActivity.this, AudioRecordingActivity.class);
36 | startActivity(i);
37 | break;
38 | }
39 | case 1: {
40 | Intent i = new Intent(MainActivity.this, VideoRecordingActivity.class);
41 | startActivity(i);
42 | break;
43 | }
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/demo/src/com/skd/androidrecordingtest/SizeAdapter.java:
--------------------------------------------------------------------------------
1 | package com.skd.androidrecordingtest;
2 |
3 | import java.util.List;
4 |
5 | import android.hardware.Camera.Size;
6 | import android.text.TextUtils.TruncateAt;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.widget.BaseAdapter;
10 | import android.widget.TextView;
11 |
12 | public class SizeAdapter extends BaseAdapter {
13 |
14 | private List sizes;
15 |
16 | public SizeAdapter(List sizes) {
17 | this.sizes = sizes;
18 | }
19 |
20 | public void set(List sizes) {
21 | this.sizes.clear();
22 | this.sizes = sizes;
23 | notifyDataSetChanged();
24 | }
25 |
26 | @Override
27 | public int getCount() {
28 | return sizes != null ? sizes.size() : 0;
29 | }
30 |
31 | @Override
32 | public Size getItem(int position) {
33 | return sizes.get(position);
34 | }
35 |
36 | @Override
37 | public long getItemId(int position) {
38 | return position;
39 | }
40 |
41 | @Override
42 | public View getView(int position, View convertView, ViewGroup parent) {
43 | TextView view = new TextView(parent.getContext());
44 | view.setText(String.format("%s: %sx%s", "Video", sizes.get(position).width, sizes.get(position).height));
45 | view.setEllipsize(TruncateAt.END);
46 | view.setPadding(16, 16, 16, 16);
47 | return view;
48 | }
49 |
50 | @Override
51 | public View getDropDownView(int position, View convertView, ViewGroup parent) {
52 | TextView view = new TextView(parent.getContext());
53 | view.setText(String.format("%s: %sx%s", "Video", sizes.get(position).width, sizes.get(position).height));
54 | view.setPadding(16, 16, 16, 16);
55 | return view;
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/demo/src/com/skd/androidrecordingtest/VideoPlaybackActivity.java:
--------------------------------------------------------------------------------
1 | package com.skd.androidrecordingtest;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import android.view.MotionEvent;
7 |
8 | import com.skd.androidrecording.video.AdaptiveSurfaceView;
9 | import com.skd.androidrecording.video.PlaybackHandler;
10 | import com.skd.androidrecording.video.VideoPlaybackManager;
11 |
12 | public class VideoPlaybackActivity extends Activity {
13 | public static String FileNameArg = "arg_filename";
14 |
15 | private static String fileName = null;
16 |
17 | private AdaptiveSurfaceView videoView;
18 |
19 | private VideoPlaybackManager playbackManager;
20 |
21 | private PlaybackHandler playbackHandler = new PlaybackHandler() {
22 | @Override
23 | public void onPreparePlayback() {
24 | runOnUiThread (new Runnable() {
25 | public void run() {
26 | playbackManager.showMediaController();
27 | }
28 | });
29 | }
30 | };
31 |
32 | @Override
33 | protected void onCreate(Bundle savedInstanceState) {
34 | super.onCreate(savedInstanceState);
35 | setContentView(R.layout.video_play);
36 |
37 | Intent i = getIntent();
38 | if ((i != null) && (i.getExtras() != null)) {
39 | fileName = i.getExtras().getString(FileNameArg);
40 | }
41 |
42 | videoView = (AdaptiveSurfaceView) findViewById(R.id.videoView);
43 |
44 | playbackManager = new VideoPlaybackManager(this, videoView, playbackHandler);
45 | playbackManager.setupPlayback(fileName);
46 | }
47 |
48 | @Override
49 | public boolean onTouchEvent(MotionEvent event) {
50 | playbackManager.showMediaController();
51 | return false;
52 | }
53 |
54 | @Override
55 | protected void onPause() {
56 | super.onPause();
57 |
58 | playbackManager.pause();
59 | playbackManager.hideMediaController();
60 | }
61 |
62 | @Override
63 | protected void onDestroy() {
64 | playbackManager.dispose();
65 | playbackHandler = null;
66 |
67 | super.onDestroy();
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/demo/src/com/skd/androidrecordingtest/VideoRecordingActivity.java:
--------------------------------------------------------------------------------
1 | package com.skd.androidrecordingtest;
2 |
3 | import java.util.List;
4 |
5 | import android.annotation.SuppressLint;
6 | import android.app.Activity;
7 | import android.content.Intent;
8 | import android.hardware.Camera.Size;
9 | import android.os.Build;
10 | import android.os.Bundle;
11 | import android.view.View;
12 | import android.view.View.OnClickListener;
13 | import android.widget.AdapterView;
14 | import android.widget.AdapterView.OnItemSelectedListener;
15 | import android.widget.Button;
16 | import android.widget.ImageButton;
17 | import android.widget.Spinner;
18 | import android.widget.Toast;
19 |
20 | import com.skd.androidrecording.video.AdaptiveSurfaceView;
21 | import com.skd.androidrecording.video.CameraHelper;
22 | import com.skd.androidrecording.video.VideoRecordingHandler;
23 | import com.skd.androidrecording.video.VideoRecordingManager;
24 | import com.skd.androidrecordingtest.utils.NotificationUtils;
25 | import com.skd.androidrecordingtest.utils.StorageUtils;
26 |
27 | public class VideoRecordingActivity extends Activity {
28 | private static String fileName = null;
29 |
30 | private Button recordBtn, playBtn;
31 | private ImageButton switchBtn;
32 | private Spinner videoSizeSpinner;
33 |
34 | private Size videoSize = null;
35 | private VideoRecordingManager recordingManager;
36 |
37 | private VideoRecordingHandler recordingHandler = new VideoRecordingHandler() {
38 | @Override
39 | public boolean onPrepareRecording() {
40 | if (videoSizeSpinner == null) {
41 | initVideoSizeSpinner();
42 | return true;
43 | }
44 | return false;
45 | }
46 |
47 | @Override
48 | public Size getVideoSize() {
49 | return videoSize;
50 | }
51 |
52 | @Override
53 | public int getDisplayRotation() {
54 | return VideoRecordingActivity.this.getWindowManager().getDefaultDisplay().getRotation();
55 | }
56 | };
57 |
58 | @Override
59 | protected void onCreate(Bundle savedInstanceState) {
60 | super.onCreate(savedInstanceState);
61 | setContentView(R.layout.video_rec);
62 |
63 | if (!StorageUtils.checkExternalStorageAvailable()) {
64 | NotificationUtils.showInfoDialog(this, getString(R.string.noExtStorageAvailable));
65 | return;
66 | }
67 | fileName = StorageUtils.getFileName(false);
68 |
69 | AdaptiveSurfaceView videoView = (AdaptiveSurfaceView) findViewById(R.id.videoView);
70 | recordingManager = new VideoRecordingManager(videoView, recordingHandler);
71 |
72 | recordBtn = (Button) findViewById(R.id.recordBtn);
73 | recordBtn.setOnClickListener(new OnClickListener() {
74 | @Override
75 | public void onClick(View v) {
76 | record();
77 | }
78 | });
79 |
80 | switchBtn = (ImageButton) findViewById(R.id.switchBtn);
81 | if (recordingManager.getCameraManager().hasMultipleCameras()) {
82 | switchBtn.setOnClickListener(new OnClickListener() {
83 | @Override
84 | public void onClick(View v) {
85 | switchCamera();
86 | }
87 | });
88 | }
89 | else {
90 | switchBtn.setVisibility(View.GONE);
91 | }
92 |
93 | playBtn = (Button) findViewById(R.id.playBtn);
94 | playBtn.setOnClickListener(new OnClickListener() {
95 | @Override
96 | public void onClick(View v) {
97 | play();
98 | }
99 | });
100 | }
101 |
102 | @Override
103 | protected void onDestroy() {
104 | recordingManager.dispose();
105 | recordingHandler = null;
106 |
107 | super.onDestroy();
108 | }
109 |
110 | @SuppressLint("NewApi")
111 | private void initVideoSizeSpinner() {
112 | videoSizeSpinner = (Spinner) findViewById(R.id.videoSizeSpinner);
113 | if (Build.VERSION.SDK_INT >= 11) {
114 | List sizes = CameraHelper.getCameraSupportedVideoSizes(recordingManager.getCameraManager().getCamera());
115 | videoSizeSpinner.setAdapter(new SizeAdapter(sizes));
116 | videoSizeSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
117 | @Override
118 | public void onItemSelected(AdapterView> arg0, View arg1, int arg2, long arg3) {
119 | videoSize = (Size) arg0.getItemAtPosition(arg2);
120 | recordingManager.setPreviewSize(videoSize);
121 | }
122 |
123 | @Override
124 | public void onNothingSelected(AdapterView> arg0) {}
125 | });
126 | videoSize = (Size) videoSizeSpinner.getItemAtPosition(0);
127 | }
128 | else {
129 | videoSizeSpinner.setVisibility(View.GONE);
130 | }
131 | }
132 |
133 | @SuppressLint("NewApi")
134 | private void updateVideoSizes() {
135 | if (Build.VERSION.SDK_INT >= 11) {
136 | ((SizeAdapter) videoSizeSpinner.getAdapter()).set(CameraHelper.getCameraSupportedVideoSizes(recordingManager.getCameraManager().getCamera()));
137 | videoSizeSpinner.setSelection(0);
138 | videoSize = (Size) videoSizeSpinner.getItemAtPosition(0);
139 | recordingManager.setPreviewSize(videoSize);
140 | }
141 | }
142 |
143 | private void switchCamera() {
144 | recordingManager.getCameraManager().switchCamera();
145 | updateVideoSizes();
146 | }
147 |
148 | private void record() {
149 | if (recordingManager.stopRecording()) {
150 | recordBtn.setText(R.string.recordBtn);
151 | switchBtn.setEnabled(true);
152 | playBtn.setEnabled(true);
153 | videoSizeSpinner.setEnabled(true);
154 | }
155 | else {
156 | startRecording();
157 | }
158 | }
159 |
160 | private void startRecording() {
161 | if (recordingManager.startRecording(fileName, videoSize)) {
162 | recordBtn.setText(R.string.stopRecordBtn);
163 | switchBtn.setEnabled(false);
164 | playBtn.setEnabled(false);
165 | videoSizeSpinner.setEnabled(false);
166 | return;
167 | }
168 | Toast.makeText(this, getString(R.string.videoRecordingError), Toast.LENGTH_LONG).show();
169 | }
170 |
171 | private void play() {
172 | Intent i = new Intent(VideoRecordingActivity.this, VideoPlaybackActivity.class);
173 | i.putExtra(VideoPlaybackActivity.FileNameArg, fileName);
174 | startActivityForResult(i, 0);
175 | }
176 | }
177 |
--------------------------------------------------------------------------------
/demo/src/com/skd/androidrecordingtest/utils/NotificationUtils.java:
--------------------------------------------------------------------------------
1 | package com.skd.androidrecordingtest.utils;
2 |
3 | import android.app.AlertDialog;
4 | import android.content.Context;
5 | import android.content.DialogInterface;
6 | import android.content.DialogInterface.OnClickListener;
7 |
8 | public class NotificationUtils {
9 | public static void showInfoDialog(Context ctx, String msg) {
10 | AlertDialog.Builder builder = new AlertDialog.Builder(ctx);
11 | builder.setMessage(msg);
12 | builder.setPositiveButton(ctx.getString(android.R.string.ok), new OnClickListener() {
13 | public void onClick(DialogInterface dialog, int arg1) {
14 | dialog.cancel();
15 | }
16 | });
17 | AlertDialog alert = builder.create();
18 | alert.show();
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/demo/src/com/skd/androidrecordingtest/utils/StorageUtils.java:
--------------------------------------------------------------------------------
1 | package com.skd.androidrecordingtest.utils;
2 |
3 | import android.os.Environment;
4 |
5 | public class StorageUtils {
6 | private static final String AUDIO_FILE_NAME = "audiorecordtest.wav";
7 | private static final String VIDEO_FILE_NAME = "videorecordtest.3gp";
8 |
9 | public static boolean checkExternalStorageAvailable() {
10 | String state = Environment.getExternalStorageState();
11 | if (Environment.MEDIA_MOUNTED.equals(state)) {
12 | return true;
13 | }
14 | else {
15 | return false;
16 | }
17 | }
18 |
19 | public static String getFileName(boolean isAudio) {
20 | String storageDir = Environment.getExternalStorageDirectory().getAbsolutePath();
21 | return String.format("%s/%s", storageDir, (isAudio) ? AUDIO_FILE_NAME : VIDEO_FILE_NAME);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/lib/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/lib/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | AndroidRecording
4 |
5 |
6 |
7 |
8 |
9 | com.android.ide.eclipse.adt.ResourceManagerBuilder
10 |
11 |
12 |
13 |
14 | com.android.ide.eclipse.adt.PreCompilerBuilder
15 |
16 |
17 |
18 |
19 | org.eclipse.jdt.core.javabuilder
20 |
21 |
22 |
23 |
24 | com.android.ide.eclipse.adt.ApkBuilder
25 |
26 |
27 |
28 |
29 |
30 | com.android.ide.eclipse.adt.AndroidNature
31 | org.eclipse.jdt.core.javanature
32 |
33 |
34 |
--------------------------------------------------------------------------------
/lib/.settings/org.eclipse.jdt.core.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
3 | org.eclipse.jdt.core.compiler.compliance=1.6
4 | org.eclipse.jdt.core.compiler.source=1.6
5 |
--------------------------------------------------------------------------------
/lib/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
9 |
10 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/lib/gen/com/skd/androidrecording/BuildConfig.java:
--------------------------------------------------------------------------------
1 | /** Automatically generated file. DO NOT MODIFY */
2 | package com.skd.androidrecording;
3 |
4 | public final class BuildConfig {
5 | public final static boolean DEBUG = true;
6 | }
--------------------------------------------------------------------------------
/lib/libs/android-support-v4.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steelkiwi/AndroidRecording/4d7956c30dbd6b12e8477a1070773730fa31ed50/lib/libs/android-support-v4.jar
--------------------------------------------------------------------------------
/lib/libs/simplesound-0.1.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steelkiwi/AndroidRecording/4d7956c30dbd6b12e8477a1070773730fa31ed50/lib/libs/simplesound-0.1.jar
--------------------------------------------------------------------------------
/lib/proguard-project.txt:
--------------------------------------------------------------------------------
1 | # To enable ProGuard in your project, edit project.properties
2 | # to define the proguard.config property as described in that file.
3 | #
4 | # Add project specific ProGuard rules here.
5 | # By default, the flags in this file are appended to flags specified
6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt
7 | # You can edit the include path and order by changing the ProGuard
8 | # include property in project.properties.
9 | #
10 | # For more details, see
11 | # http://developer.android.com/guide/developing/tools/proguard.html
12 |
13 | # Add any project specific keep options here:
14 |
15 | # If your project uses WebView with JS, uncomment the following
16 | # and specify the fully qualified class name to the JavaScript interface
17 | # class:
18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
19 | # public *;
20 | #}
21 |
--------------------------------------------------------------------------------
/lib/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system edit
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 | #
10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
12 |
13 | # Project target.
14 | target=android-18
15 | android.library=true
16 |
--------------------------------------------------------------------------------
/lib/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steelkiwi/AndroidRecording/4d7956c30dbd6b12e8477a1070773730fa31ed50/lib/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/lib/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steelkiwi/AndroidRecording/4d7956c30dbd6b12e8477a1070773730fa31ed50/lib/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/lib/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steelkiwi/AndroidRecording/4d7956c30dbd6b12e8477a1070773730fa31ed50/lib/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/lib/res/values-v11/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/lib/res/values-v14/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/lib/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | AndroidRecording
4 |
5 |
6 |
--------------------------------------------------------------------------------
/lib/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
14 |
15 |
16 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/lib/src/com/skd/androidrecording/audio/AudioPlaybackManager.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Steelkiwi Development, Julia Zudikova
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 |
17 | package com.skd.androidrecording.audio;
18 |
19 | import android.content.Context;
20 | import android.media.MediaPlayer;
21 | import android.media.MediaPlayer.OnCompletionListener;
22 | import android.media.MediaPlayer.OnPreparedListener;
23 | import android.view.ViewTreeObserver.OnGlobalLayoutListener;
24 | import android.widget.MediaController;
25 | import android.widget.MediaController.MediaPlayerControl;
26 |
27 | import com.skd.androidrecording.video.MediaPlayerManager;
28 | import com.skd.androidrecording.video.PlaybackHandler;
29 | import com.skd.androidrecording.visualizer.VisualizerView;
30 |
31 | /*
32 | * Controls audio playback
33 | */
34 |
35 | public class AudioPlaybackManager implements OnGlobalLayoutListener, OnPreparedListener, MediaPlayerControl, OnCompletionListener {
36 | private VisualizerView visualizerView;
37 | private MediaPlayerManager playerManager;
38 | private MediaController controller;
39 | private PlaybackHandler playbackHandler;
40 | private boolean isPlayerPrepared, isSurfaceCreated;
41 |
42 | public AudioPlaybackManager(Context ctx, VisualizerView visualizerView, PlaybackHandler playbackHandler) {
43 | this.playerManager = new MediaPlayerManager();
44 | this.playerManager.getPlayer().setOnPreparedListener(this);
45 | this.playerManager.getPlayer().setOnCompletionListener(this);
46 |
47 | this.visualizerView = visualizerView;
48 | this.visualizerView.link(this.playerManager.getPlayer());
49 | this.visualizerView.getViewTreeObserver().addOnGlobalLayoutListener(this);
50 |
51 | this.controller = new MediaController(ctx);
52 | this.controller.setMediaPlayer(this);
53 | this.controller.setAnchorView(visualizerView);
54 |
55 | this.playbackHandler = playbackHandler;
56 | }
57 |
58 | public void setupPlayback(String fileName) {
59 | playerManager.setupPlayback(fileName);
60 | }
61 |
62 | public void showMediaController() {
63 | if (!controller.isEnabled()) {
64 | controller.setEnabled(true);
65 | }
66 | controller.show();
67 | }
68 |
69 | public void hideMediaController() {
70 | controller.hide();
71 | controller.setEnabled(false);
72 | }
73 |
74 | private void releaseVisualizer() {
75 | visualizerView.release();
76 | visualizerView = null;
77 | }
78 |
79 | public void dispose() {
80 | playerManager.releasePlayer();
81 | releaseVisualizer();
82 | controller = null;
83 | playbackHandler = null;
84 | }
85 |
86 | //visualizer setup callback *****************************************************************
87 |
88 | @Override
89 | public void onGlobalLayout() {
90 | isSurfaceCreated = true;
91 | if (isPlayerPrepared && isSurfaceCreated) {
92 | playbackHandler.onPreparePlayback();
93 | }
94 | }
95 |
96 | //media player and controller callbacks *****************************************************
97 |
98 | @Override
99 | public void onPrepared(MediaPlayer mp) {
100 | isPlayerPrepared = true;
101 | if (isPlayerPrepared && isSurfaceCreated) {
102 | playbackHandler.onPreparePlayback();
103 | }
104 | }
105 |
106 | @Override
107 | public void start() {
108 | playerManager.startPlaying();
109 | }
110 |
111 | @Override
112 | public void pause() {
113 | playerManager.pausePlaying();
114 | }
115 |
116 | @Override
117 | public void seekTo(int arg0) {
118 | playerManager.seekTo(arg0);
119 | }
120 |
121 | @Override
122 | public void onCompletion(MediaPlayer mp) {
123 | playerManager.seekTo(0);
124 | }
125 |
126 | @Override
127 | public boolean isPlaying() {
128 | return playerManager.isPlaying();
129 | }
130 |
131 | @Override
132 | public int getCurrentPosition() {
133 | return playerManager.getCurrentPosition();
134 | }
135 |
136 | @Override
137 | public int getDuration() {
138 | return playerManager.getDuration();
139 | }
140 |
141 | @Override
142 | public boolean canPause() {
143 | return true;
144 | }
145 |
146 | @Override
147 | public boolean canSeekBackward() {
148 | return true;
149 | }
150 |
151 | @Override
152 | public boolean canSeekForward() {
153 | return true;
154 | }
155 |
156 | @Override
157 | public int getAudioSessionId() {
158 | return 0;
159 | }
160 |
161 | @Override
162 | public int getBufferPercentage() {
163 | return 0;
164 | }
165 | }
166 |
--------------------------------------------------------------------------------
/lib/src/com/skd/androidrecording/audio/AudioRecordingHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Steelkiwi Development, Julia Zudikova
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 |
17 | package com.skd.androidrecording.audio;
18 |
19 | public interface AudioRecordingHandler {
20 | public void onFftDataCapture(byte[] bytes);
21 | public void onRecordSuccess();
22 | public void onRecordingError();
23 | public void onRecordSaveError();
24 | }
25 |
--------------------------------------------------------------------------------
/lib/src/com/skd/androidrecording/audio/AudioRecordingThread.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Steelkiwi Development, Julia Zudikova
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 |
17 | package com.skd.androidrecording.audio;
18 |
19 | import java.io.File;
20 | import java.io.FileNotFoundException;
21 | import java.io.FileOutputStream;
22 | import java.io.IOException;
23 |
24 | import simplesound.pcm.PcmAudioHelper;
25 | import simplesound.pcm.WavAudioFormat;
26 | import android.media.AudioFormat;
27 | import android.media.AudioRecord;
28 | import android.media.MediaRecorder.AudioSource;
29 |
30 | import com.skd.androidrecording.fft.Complex;
31 | import com.skd.androidrecording.fft.FFT;
32 |
33 | /*
34 | * Takes a portion of PCM encoded audio signal (from microphone while recording),
35 | * transforms it using FFT, passes it to a visualizer and saves to a file.
36 | * In the end converts stored audio from a temporary RAW file to WAV.
37 | */
38 |
39 | public class AudioRecordingThread extends Thread {
40 | private static final String FILE_NAME = "audiorecordtest.raw";
41 | private static final int SAMPLING_RATE = 44100;
42 | private static final int FFT_POINTS = 1024;
43 | private static final int MAGIC_SCALE = 10;
44 |
45 | private String fileName_wav;
46 | private String fileName_raw;
47 |
48 | private int bufferSize;
49 | private byte[] audioBuffer;
50 |
51 | private boolean isRecording = true;
52 |
53 | private AudioRecordingHandler handler = null;
54 |
55 | public AudioRecordingThread(String fileWavName, AudioRecordingHandler handler) {
56 | this.fileName_wav = fileWavName;
57 | this.fileName_raw = getRawName(fileWavName);
58 | this.handler = handler;
59 |
60 | bufferSize = AudioRecord.getMinBufferSize(SAMPLING_RATE,
61 | AudioFormat.CHANNEL_IN_MONO,
62 | AudioFormat.ENCODING_PCM_16BIT);
63 | audioBuffer = new byte[bufferSize];
64 | }
65 |
66 | @Override
67 | public void run() {
68 | FileOutputStream out = prepareWriting();
69 | if (out == null) { return; }
70 |
71 | AudioRecord record = new AudioRecord(AudioSource.VOICE_RECOGNITION, /*AudioSource.MIC*/
72 | SAMPLING_RATE,
73 | AudioFormat.CHANNEL_IN_MONO,
74 | AudioFormat.ENCODING_PCM_16BIT,
75 | bufferSize);
76 | record.startRecording();
77 |
78 | int read = 0;
79 | while (isRecording) {
80 | read = record.read(audioBuffer, 0, bufferSize);
81 |
82 | if ((read == AudioRecord.ERROR_INVALID_OPERATION) ||
83 | (read == AudioRecord.ERROR_BAD_VALUE) ||
84 | (read <= 0)) {
85 | continue;
86 | }
87 |
88 | proceed();
89 | write(out);
90 | }
91 |
92 | record.stop();
93 | record.release();
94 |
95 | finishWriting(out);
96 | convertRawToWav();
97 | }
98 |
99 | private void proceed() {
100 | double temp;
101 | Complex[] y;
102 | Complex[] complexSignal = new Complex[FFT_POINTS];
103 |
104 | for (int i=0; i= size.height ? size.width : size.height;
52 | }
53 | else {
54 | previewWidth = size.width > size.height ? size.width : size.height;
55 | previewHeight = size.width <= size.height ? size.width : size.height;
56 | }
57 | ratio = previewHeight / (float) previewWidth;
58 | requestLayout();
59 | }
60 |
61 | @Override
62 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
63 | int previewW = MeasureSpec.getSize(widthMeasureSpec);
64 | int previewWMode = MeasureSpec.getMode(widthMeasureSpec);
65 | int previewH = MeasureSpec.getSize(heightMeasureSpec);
66 | int previewHMode = MeasureSpec.getMode(heightMeasureSpec);
67 |
68 | int measuredWidth = 0;
69 | int measuredHeight = 0;
70 |
71 | if (previewWidth > 0 && previewHeight > 0) {
72 | measuredWidth = defineWidth(previewW, previewWMode);
73 |
74 | measuredHeight = (int) (measuredWidth * ratio);
75 | if (previewHMode != MeasureSpec.UNSPECIFIED && measuredHeight > previewH) {
76 | measuredWidth = (int) (previewH / ratio);
77 | measuredHeight = previewH;
78 | }
79 |
80 | setMeasuredDimension(measuredWidth, measuredHeight);
81 | }
82 | else {
83 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
84 | }
85 | }
86 |
87 | private int defineWidth(int previewW, int previewWMode) {
88 | int measuredWidth;
89 | if (previewWMode == MeasureSpec.UNSPECIFIED) {
90 | measuredWidth = previewWidth;
91 | }
92 | else if (previewWMode == MeasureSpec.EXACTLY) {
93 | measuredWidth = previewW;
94 | }
95 | else {
96 | measuredWidth = Math.min(previewW, previewWidth);
97 | }
98 | return measuredWidth;
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/lib/src/com/skd/androidrecording/video/CameraHelper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Steelkiwi Development, Julia Zudikova, Viacheslav Tyagotenkov
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 |
17 | package com.skd.androidrecording.video;
18 |
19 | import java.util.List;
20 |
21 | import android.annotation.SuppressLint;
22 | import android.hardware.Camera;
23 | import android.hardware.Camera.CameraInfo;
24 | import android.hardware.Camera.Size;
25 | import android.os.Build;
26 | import android.view.Surface;
27 |
28 | /*
29 | * Represents camera management helper class.
30 | * Holds method for setting camera display orientation.
31 | */
32 |
33 | public class CameraHelper {
34 |
35 | public static int getAvailableCamerasCount() {
36 | return Camera.getNumberOfCameras();
37 | }
38 |
39 | public static int getDefaultCameraID() {
40 | int camerasCnt = getAvailableCamerasCount();
41 | int defaultCameraID = 0;
42 | CameraInfo cameraInfo = new CameraInfo();
43 | for (int i=0; i getCameraSupportedVideoSizes(android.hardware.Camera camera) {
60 | if ((Build.VERSION.SDK_INT >= 11) && (camera != null)) {
61 | return camera.getParameters().getSupportedVideoSizes();
62 | }
63 | else {
64 | return null;
65 | }
66 | }
67 |
68 | public static int setCameraDisplayOrientation(int cameraId, android.hardware.Camera camera, int displayRotation) {
69 | Camera.CameraInfo info = new Camera.CameraInfo();
70 | Camera.getCameraInfo(cameraId, info);
71 | int degrees = 0;
72 | switch (displayRotation) {
73 | case Surface.ROTATION_0:
74 | degrees = 0;
75 | break;
76 | case Surface.ROTATION_90:
77 | degrees = 90;
78 | break;
79 | case Surface.ROTATION_180:
80 | degrees = 180;
81 | break;
82 | case Surface.ROTATION_270:
83 | degrees = 270;
84 | break;
85 | }
86 |
87 | int camRotationDegree = 0;
88 | if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
89 | camRotationDegree = (info.orientation + degrees) % 360;
90 | camRotationDegree = (360 - camRotationDegree) % 360; // compensate the mirror
91 | } else {
92 | camRotationDegree = (info.orientation - degrees + 360) % 360;
93 | }
94 |
95 | if (camera != null) {
96 | camera.setDisplayOrientation(camRotationDegree);
97 | }
98 | return camRotationDegree;
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/lib/src/com/skd/androidrecording/video/CameraManager.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Steelkiwi Development, Julia Zudikova, Viacheslav Tiagotenkov
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 |
17 | package com.skd.androidrecording.video;
18 |
19 | import java.io.IOException;
20 |
21 | import android.hardware.Camera;
22 | import android.hardware.Camera.Parameters;
23 | import android.hardware.Camera.Size;
24 | import android.view.SurfaceHolder;
25 |
26 | /*
27 | * Manages camera preview
28 | */
29 |
30 | public class CameraManager {
31 |
32 | private Camera camera;
33 | private int camerasCount;
34 | private int defaultCameraID;
35 | private int cameraRotationDegree;
36 | private boolean isPreviewStarted = false;
37 |
38 | public CameraManager() {
39 | camerasCount = CameraHelper.getAvailableCamerasCount();
40 | defaultCameraID = CameraHelper.getDefaultCameraID();
41 | }
42 |
43 | public void openCamera() {
44 | if (camera != null) {
45 | releaseCamera();
46 | }
47 | camera = Camera.open(defaultCameraID);
48 | }
49 |
50 | public void releaseCamera() {
51 | if (camera != null) {
52 | camera.release();
53 | camera = null;
54 | }
55 | }
56 |
57 | public void switchCamera() {
58 | stopCameraPreview();
59 |
60 | defaultCameraID = (defaultCameraID + 1) % camerasCount;
61 | openCamera();
62 | }
63 |
64 | public void setupCameraAndStartPreview(SurfaceHolder sf, Size sz, int displayRotation) {
65 | stopCameraPreview();
66 |
67 | cameraRotationDegree = CameraHelper.setCameraDisplayOrientation(defaultCameraID, camera, displayRotation);
68 |
69 | Parameters param = camera.getParameters();
70 | param.setPreviewSize(sz.width, sz.height);
71 | camera.setParameters(param);
72 |
73 | if (setDisplay(sf)) {
74 | startCameraPreview();
75 | }
76 | }
77 |
78 | public boolean setDisplay(SurfaceHolder sf) {
79 | try {
80 | camera.setPreviewDisplay(sf);
81 | return true;
82 | } catch (IOException e) {
83 | e.printStackTrace();
84 | }
85 | return false;
86 | }
87 |
88 | public void startCameraPreview() {
89 | camera.startPreview();
90 | isPreviewStarted = true;
91 | }
92 |
93 | public void stopCameraPreview() {
94 | if (isPreviewStarted && (camera != null)) {
95 | isPreviewStarted = false;
96 | camera.stopPreview();
97 | }
98 | }
99 |
100 | public Camera getCamera() {
101 | return camera;
102 | }
103 |
104 | public int getCameraDisplayOrientation() {
105 | return (CameraHelper.isCameraFacingBack(defaultCameraID)) ? cameraRotationDegree : cameraRotationDegree + 180;
106 | }
107 |
108 | public boolean hasMultipleCameras() {
109 | return (camerasCount > 1);
110 | }
111 |
112 | public boolean isPreviewStarted() {
113 | return isPreviewStarted;
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/lib/src/com/skd/androidrecording/video/MediaPlayerManager.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Steelkiwi Development, Julia Zudikova, Viacheslav Tiagotenkov
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 |
17 | package com.skd.androidrecording.video;
18 |
19 | import android.media.MediaPlayer;
20 | import android.view.SurfaceHolder;
21 |
22 | /*
23 | * Manages media player playback
24 | */
25 |
26 | public class MediaPlayerManager {
27 |
28 | private MediaPlayer player;
29 |
30 | public MediaPlayerManager() {
31 | player = new MediaPlayer();
32 | }
33 |
34 | public MediaPlayer getPlayer() {
35 | return player;
36 | }
37 |
38 | public void setupPlayback(String fileName) {
39 | try {
40 | player.setDataSource(fileName);
41 | player.prepare();
42 | } catch (Exception e) {
43 | e.printStackTrace();
44 | }
45 | }
46 |
47 | public void setDisplay(SurfaceHolder sf) {
48 | player.setDisplay(sf);
49 | }
50 |
51 | public void startPlaying() {
52 | player.start();
53 | }
54 |
55 | public void pausePlaying() {
56 | player.pause();
57 | }
58 |
59 | public void seekTo(int pos) {
60 | if (pos < 0) {
61 | player.seekTo(0);
62 | }
63 | else if (pos > getDuration()) {
64 | player.seekTo(getDuration());
65 | }
66 | else {
67 | player.seekTo(pos);
68 | }
69 | }
70 |
71 | public void stopPlaying() {
72 | if (player.isPlaying()) {
73 | player.stop();
74 | }
75 | }
76 |
77 | public boolean isPlaying() {
78 | return player.isPlaying();
79 | }
80 |
81 | public int getCurrentPosition() {
82 | return player.getCurrentPosition();
83 | }
84 |
85 | public int getDuration() {
86 | return player.getDuration();
87 | }
88 |
89 | public void releasePlayer() {
90 | setDisplay(null);
91 | player.release();
92 | player = null;
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/lib/src/com/skd/androidrecording/video/MediaRecorderManager.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Steelkiwi Development, Julia Zudikova, Viacheslav Tiagotenkov
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 |
17 | package com.skd.androidrecording.video;
18 |
19 | import java.io.IOException;
20 |
21 | import android.hardware.Camera;
22 | import android.hardware.Camera.Size;
23 | import android.media.MediaRecorder;
24 |
25 | /*
26 | * Manages media recorder recording
27 | */
28 |
29 | public class MediaRecorderManager {
30 | private static final int VIDEO_W_DEFAULT = 800;
31 | private static final int VIDEO_H_DEFAULT = 480;
32 |
33 | private MediaRecorder recorder;
34 | private boolean isRecording;
35 |
36 | public MediaRecorderManager() {
37 | recorder = new MediaRecorder();
38 | }
39 |
40 | public boolean startRecording(Camera camera, String fileName, Size sz, int cameraRotationDegree) {
41 | if (sz == null) {
42 | sz = camera.new Size(VIDEO_W_DEFAULT, VIDEO_H_DEFAULT);
43 | }
44 |
45 | try {
46 | camera.unlock();
47 | recorder.setCamera(camera);
48 | recorder.setOrientationHint(cameraRotationDegree);
49 | recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
50 | recorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
51 | recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
52 | recorder.setVideoSize(sz.width, sz.height);
53 | recorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
54 | recorder.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP);
55 | recorder.setOutputFile(fileName);
56 | recorder.prepare();
57 | recorder.start();
58 | isRecording = true;
59 | } catch (IllegalStateException e) {
60 | e.printStackTrace();
61 | } catch (IOException e) {
62 | e.printStackTrace();
63 | }
64 |
65 | return isRecording;
66 | }
67 |
68 | public boolean stopRecording() {
69 | if (isRecording) {
70 | isRecording = false;
71 | recorder.stop();
72 | recorder.reset();
73 | return true;
74 | }
75 | return false;
76 | }
77 |
78 | public void releaseRecorder() {
79 | recorder.release();
80 | recorder = null;
81 | }
82 |
83 | public boolean isRecording() {
84 | return isRecording;
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/lib/src/com/skd/androidrecording/video/PlaybackHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Steelkiwi Development, Julia Zudikova, Viacheslav Tiagotenkov
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 |
17 | package com.skd.androidrecording.video;
18 |
19 | public interface PlaybackHandler {
20 | public void onPreparePlayback();
21 | }
22 |
--------------------------------------------------------------------------------
/lib/src/com/skd/androidrecording/video/VideoPlaybackManager.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Steelkiwi Development, Julia Zudikova, Viacheslav Tiagotenkov
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 |
17 | package com.skd.androidrecording.video;
18 |
19 | import android.content.Context;
20 | import android.media.MediaPlayer;
21 | import android.media.MediaPlayer.OnCompletionListener;
22 | import android.media.MediaPlayer.OnPreparedListener;
23 | import android.view.SurfaceHolder;
24 | import android.widget.MediaController;
25 | import android.widget.MediaController.MediaPlayerControl;
26 |
27 | /*
28 | * Controls video playback
29 | */
30 |
31 | public class VideoPlaybackManager implements SurfaceHolder.Callback, OnPreparedListener, MediaPlayerControl, OnCompletionListener {
32 | private MediaPlayerManager playerManager;
33 | private MediaController controller;
34 | private PlaybackHandler playbackHandler;
35 | private boolean isPlayerPrepared, isSurfaceCreated;
36 |
37 | public VideoPlaybackManager(Context ctx, AdaptiveSurfaceView videoView, PlaybackHandler playbackHandler) {
38 | videoView.getHolder().addCallback(this);
39 |
40 | this.playerManager = new MediaPlayerManager();
41 | this.playerManager.getPlayer().setOnPreparedListener(this);
42 | this.playerManager.getPlayer().setOnCompletionListener(this);
43 |
44 | this.controller = new MediaController(ctx);
45 | this.controller.setMediaPlayer(this);
46 | this.controller.setAnchorView(videoView);
47 |
48 | this.playbackHandler = playbackHandler;
49 | }
50 |
51 | public void setupPlayback(String fileName) {
52 | playerManager.setupPlayback(fileName);
53 | }
54 |
55 | public void showMediaController() {
56 | if (!controller.isEnabled()) {
57 | controller.setEnabled(true);
58 | }
59 | controller.show();
60 | }
61 |
62 | public void hideMediaController() {
63 | controller.hide();
64 | controller.setEnabled(false);
65 | }
66 |
67 | public MediaPlayerManager getPlayerManager() {
68 | return playerManager;
69 | }
70 |
71 | public void dispose() {
72 | playerManager.releasePlayer();
73 | controller = null;
74 | playbackHandler = null;
75 | }
76 |
77 | //surface holder callbacks ******************************************************************
78 |
79 | @Override
80 | public void surfaceCreated(SurfaceHolder holder) {
81 | isSurfaceCreated = true;
82 | playerManager.setDisplay(holder);
83 | if (isPlayerPrepared && isSurfaceCreated) {
84 | playbackHandler.onPreparePlayback();
85 | }
86 | }
87 |
88 | @Override
89 | public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}
90 |
91 | @Override
92 | public void surfaceDestroyed(SurfaceHolder holder) {
93 | playerManager.setDisplay(null);
94 | }
95 |
96 | //media player and controller callbacks *****************************************************
97 |
98 | public void onPrepared(MediaPlayer mp) {
99 | isPlayerPrepared = true;
100 | if (isPlayerPrepared && isSurfaceCreated) {
101 | playbackHandler.onPreparePlayback();
102 | }
103 | }
104 |
105 | @Override
106 | public void start() {
107 | playerManager.startPlaying();
108 | }
109 |
110 | @Override
111 | public void pause() {
112 | playerManager.pausePlaying();
113 | }
114 |
115 | @Override
116 | public void seekTo(int arg0) {
117 | playerManager.seekTo(arg0);
118 | }
119 |
120 | @Override
121 | public void onCompletion(MediaPlayer mp) {
122 | playerManager.seekTo(0);
123 | }
124 |
125 | @Override
126 | public boolean isPlaying() {
127 | return playerManager.isPlaying();
128 | }
129 |
130 | @Override
131 | public int getCurrentPosition() {
132 | return playerManager.getCurrentPosition();
133 | }
134 |
135 | @Override
136 | public int getDuration() {
137 | return playerManager.getDuration();
138 | }
139 |
140 | @Override
141 | public boolean canPause() {
142 | return true;
143 | }
144 |
145 | @Override
146 | public boolean canSeekBackward() {
147 | return true;
148 | }
149 |
150 | @Override
151 | public boolean canSeekForward() {
152 | return true;
153 | }
154 |
155 | @Override
156 | public int getAudioSessionId() {
157 | return 0;
158 | }
159 |
160 | @Override
161 | public int getBufferPercentage() {
162 | return 0;
163 | }
164 | }
165 |
--------------------------------------------------------------------------------
/lib/src/com/skd/androidrecording/video/VideoRecordingHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Steelkiwi Development, Julia Zudikova, Viacheslav Tiagotenkov
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 |
17 | package com.skd.androidrecording.video;
18 |
19 | import android.hardware.Camera.Size;
20 |
21 | public interface VideoRecordingHandler {
22 | public boolean onPrepareRecording();
23 | public Size getVideoSize();
24 | public int getDisplayRotation();
25 | }
26 |
--------------------------------------------------------------------------------
/lib/src/com/skd/androidrecording/video/VideoRecordingManager.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Steelkiwi Development, Julia Zudikova, Viacheslav Tiagotenkov
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 |
17 | package com.skd.androidrecording.video;
18 |
19 | import android.hardware.Camera.Size;
20 | import android.view.SurfaceHolder;
21 |
22 | /*
23 | * Controls process of previewing and recording video
24 | */
25 |
26 | public class VideoRecordingManager implements SurfaceHolder.Callback {
27 |
28 | private AdaptiveSurfaceView videoView;
29 | private CameraManager cameraManager;
30 | private MediaRecorderManager recorderManager;
31 | private VideoRecordingHandler recordingHandler;
32 |
33 | public VideoRecordingManager(AdaptiveSurfaceView videoView, VideoRecordingHandler recordingHandler) {
34 | this.videoView = videoView;
35 | this.videoView.getHolder().addCallback(this);
36 | this.cameraManager = new CameraManager();
37 | this.recorderManager = new MediaRecorderManager();
38 | this.recordingHandler = recordingHandler;
39 | }
40 |
41 | public boolean startRecording(String fileName, Size videoSize) {
42 | int degree = cameraManager.getCameraDisplayOrientation();
43 | return recorderManager.startRecording(cameraManager.getCamera(), fileName, videoSize, degree);
44 | }
45 |
46 | public boolean stopRecording() {
47 | return recorderManager.stopRecording();
48 | }
49 |
50 | public void setPreviewSize(Size videoSize) {
51 | videoView.setPreviewSize(videoSize);
52 | }
53 |
54 | public SurfaceHolder getDisplay() {
55 | return videoView.getHolder();
56 | }
57 |
58 | public CameraManager getCameraManager() {
59 | return cameraManager;
60 | }
61 |
62 | public void dispose() {
63 | videoView = null;
64 | cameraManager.releaseCamera();
65 | recorderManager.releaseRecorder();
66 | recordingHandler = null;
67 | }
68 |
69 | //surface holder callbacks ******************************************************************
70 |
71 | @Override
72 | public void surfaceCreated(SurfaceHolder holder) {
73 | cameraManager.openCamera();
74 | }
75 |
76 | @Override
77 | public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
78 | if (recordingHandler == null) { return; }
79 | if (!recordingHandler.onPrepareRecording()) {
80 | cameraManager.setupCameraAndStartPreview(videoView.getHolder(),
81 | recordingHandler.getVideoSize(),
82 | recordingHandler.getDisplayRotation());
83 | }
84 | }
85 |
86 | @Override
87 | public void surfaceDestroyed(SurfaceHolder holder) {
88 | recorderManager.stopRecording();
89 | cameraManager.releaseCamera();
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/lib/src/com/skd/androidrecording/visualizer/AudioData.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modified by Steelkiwi Development, Julia Zudikova
3 | */
4 |
5 | /**
6 | * Copyright 2011, Felix Palmer
7 | *
8 | * Licensed under the MIT license:
9 | * http://creativecommons.org/licenses/MIT/
10 | */
11 | package com.skd.androidrecording.visualizer;
12 |
13 | // Data class to explicitly indicate that these bytes are raw audio data
14 | public class AudioData
15 | {
16 | public AudioData() {}
17 |
18 | private byte[] bytes;
19 |
20 | public byte[] getBytes() {
21 | return bytes;
22 | }
23 |
24 | public void setBytes(byte[] bytes) {
25 | this.bytes = bytes;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/lib/src/com/skd/androidrecording/visualizer/FFTData.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modified by Steelkiwi Development, Julia Zudikova
3 | */
4 |
5 | /**
6 | * Copyright 2011, Felix Palmer
7 | *
8 | * Licensed under the MIT license:
9 | * http://creativecommons.org/licenses/MIT/
10 | */
11 | package com.skd.androidrecording.visualizer;
12 |
13 | // Data class to explicitly indicate that these bytes are the FFT of audio data
14 | public class FFTData
15 | {
16 | public FFTData(){}
17 |
18 | private byte[] bytes;
19 |
20 | public byte[] getBytes() {
21 | return bytes;
22 | }
23 |
24 | public void setBytes(byte[] bytes) {
25 | this.bytes = bytes;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/lib/src/com/skd/androidrecording/visualizer/VisualizerView.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modified by Steelkiwi Development, Julia Zudikova
3 | */
4 |
5 | /**
6 | * Copyright 2011, Felix Palmer
7 | *
8 | * Licensed under the MIT license:
9 | * http://creativecommons.org/licenses/MIT/
10 | */
11 | package com.skd.androidrecording.visualizer;
12 |
13 | import java.util.HashSet;
14 | import java.util.Set;
15 |
16 | import android.content.Context;
17 | import android.graphics.Bitmap;
18 | import android.graphics.Bitmap.Config;
19 | import android.graphics.Canvas;
20 | import android.graphics.Color;
21 | import android.graphics.Matrix;
22 | import android.graphics.Paint;
23 | import android.graphics.PorterDuff.Mode;
24 | import android.graphics.PorterDuffXfermode;
25 | import android.graphics.Rect;
26 | import android.media.MediaPlayer;
27 | import android.media.audiofx.Visualizer;
28 | import android.util.AttributeSet;
29 | import android.view.View;
30 |
31 | import com.skd.androidrecording.visualizer.renderer.Renderer;
32 |
33 | /**
34 | * A class that draws visualizations of data received from a
35 | * {@link Visualizer.OnDataCaptureListener#onWaveFormDataCapture } and
36 | * {@link Visualizer.OnDataCaptureListener#onFftDataCapture }
37 | */
38 | public class VisualizerView extends View {
39 | public static final String TAG = "VisualizerView";
40 |
41 | private byte[] mBytes;
42 | private byte[] mFFTBytes;
43 | private AudioData mAudioData = null;
44 | private FFTData mFftData = null;
45 | private Rect mRect = new Rect();
46 | private Matrix mMatrix = new Matrix();
47 | private Visualizer mVisualizer;
48 |
49 | private Set mRenderers;
50 |
51 | private Paint mFlashPaint = new Paint();
52 | private Paint mFadePaint = new Paint();
53 |
54 | public VisualizerView(Context context, AttributeSet attrs, int defStyle)
55 | {
56 | super(context, attrs);
57 | init();
58 | }
59 |
60 | public VisualizerView(Context context, AttributeSet attrs)
61 | {
62 | this(context, attrs, 0);
63 | }
64 |
65 | public VisualizerView(Context context)
66 | {
67 | this(context, null, 0);
68 | }
69 |
70 | private void init() {
71 | mBytes = null;
72 | mFFTBytes = null;
73 |
74 | mFlashPaint.setColor(Color.argb(122, 255, 255, 255));
75 | mFadePaint.setColor(Color.argb(238, 255, 255, 255)); // Adjust alpha to change how quickly the image fades
76 | mFadePaint.setXfermode(new PorterDuffXfermode(Mode.MULTIPLY));
77 |
78 | mRenderers = new HashSet();
79 | }
80 |
81 | /**
82 | * Links the visualizer to a player
83 | * @param player - MediaPlayer instance to link to
84 | */
85 | public void link(MediaPlayer player)
86 | {
87 | if(player == null)
88 | {
89 | throw new NullPointerException("Cannot link to null MediaPlayer");
90 | }
91 |
92 | // Create the Visualizer object and attach it to our media player.
93 | mVisualizer = new Visualizer(player.getAudioSessionId());
94 | mVisualizer.setCaptureSize(Visualizer.getCaptureSizeRange()[1]);
95 |
96 | // Pass through Visualizer data to VisualizerView
97 | Visualizer.OnDataCaptureListener captureListener = new Visualizer.OnDataCaptureListener()
98 | {
99 | @Override
100 | public void onWaveFormDataCapture(Visualizer visualizer, byte[] bytes,
101 | int samplingRate)
102 | {
103 | updateVisualizer(bytes);
104 | }
105 |
106 | @Override
107 | public void onFftDataCapture(Visualizer visualizer, byte[] bytes,
108 | int samplingRate)
109 | {
110 | updateVisualizerFFT(bytes);
111 | }
112 | };
113 |
114 | mVisualizer.setDataCaptureListener(captureListener,
115 | Visualizer.getMaxCaptureRate() / 2, true, true);
116 |
117 | // Enabled Visualizer and disable when we're done with the stream
118 | mVisualizer.setEnabled(true);
119 | player.setOnCompletionListener(new MediaPlayer.OnCompletionListener()
120 | {
121 | @Override
122 | public void onCompletion(MediaPlayer mediaPlayer)
123 | {
124 | mVisualizer.setEnabled(false);
125 | }
126 | });
127 | }
128 |
129 | public void addRenderer(Renderer renderer)
130 | {
131 | if(renderer != null)
132 | {
133 | mRenderers.add(renderer);
134 | }
135 | }
136 |
137 | public void clearRenderers()
138 | {
139 | mRenderers.clear();
140 | }
141 |
142 | /**
143 | * Call to release the resources used by VisualizerView. Like with the
144 | * MediaPlayer it is good practice to call this method
145 | */
146 | public void release()
147 | {
148 | if (mVisualizer != null) {
149 | mVisualizer.release();
150 | }
151 | }
152 |
153 | /**
154 | * Pass data to the visualizer. Typically this will be obtained from the
155 | * Android Visualizer.OnDataCaptureListener call back. See
156 | * {@link Visualizer.OnDataCaptureListener#onWaveFormDataCapture }
157 | * @param bytes
158 | */
159 | public void updateVisualizer(byte[] bytes) {
160 | mBytes = bytes;
161 | invalidate();
162 | }
163 |
164 | /**
165 | * Pass FFT data to the visualizer. Typically this will be obtained from the
166 | * Android Visualizer.OnDataCaptureListener call back. See
167 | * {@link Visualizer.OnDataCaptureListener#onFftDataCapture }
168 | * @param bytes
169 | */
170 | public void updateVisualizerFFT(byte[] bytes) {
171 | mFFTBytes = bytes;
172 | invalidate();
173 | }
174 |
175 | boolean mFlash = false;
176 |
177 | /**
178 | * Call this to make the visualizer flash. Useful for flashing at the start
179 | * of a song/loop etc...
180 | */
181 | public void flash() {
182 | mFlash = true;
183 | invalidate();
184 | }
185 |
186 | Bitmap mCanvasBitmap;
187 | Canvas mCanvas;
188 |
189 |
190 | @Override
191 | protected void onDraw(Canvas canvas) {
192 | super.onDraw(canvas);
193 |
194 | // Create canvas once we're ready to draw
195 | mRect.set(0, 0, getWidth(), getHeight());
196 |
197 | if(mCanvasBitmap == null)
198 | {
199 | mCanvasBitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Config.ARGB_8888);
200 | }
201 | if(mCanvas == null)
202 | {
203 | mCanvas = new Canvas(mCanvasBitmap);
204 | }
205 |
206 | mCanvas.drawColor(Color.TRANSPARENT);
207 |
208 | if (mBytes != null) {
209 | // Render all audio renderers
210 | if (mAudioData == null) {
211 | mAudioData = new AudioData();
212 | }
213 | mAudioData.setBytes(mBytes);
214 | for(Renderer r : mRenderers)
215 | {
216 | r.render(mCanvas, mAudioData, mRect);
217 | }
218 | }
219 |
220 | if (mFFTBytes != null) {
221 | // Render all FFT renderers
222 | if (mFftData == null) {
223 | mFftData = new FFTData();
224 | }
225 | mFftData.setBytes(mFFTBytes);
226 | for(Renderer r : mRenderers)
227 | {
228 | r.render(mCanvas, mFftData, mRect);
229 | }
230 | }
231 |
232 | // Fade out old contents
233 | mCanvas.drawPaint(mFadePaint);
234 |
235 | if(mFlash)
236 | {
237 | mFlash = false;
238 | mCanvas.drawPaint(mFlashPaint);
239 | }
240 |
241 | mMatrix.reset();
242 | canvas.drawBitmap(mCanvasBitmap, mMatrix, null);
243 | }
244 | }
--------------------------------------------------------------------------------
/lib/src/com/skd/androidrecording/visualizer/renderer/BarGraphRenderer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modified by Steelkiwi Development, Julia Zudikova
3 | */
4 |
5 | /**
6 | * Copyright 2011, Felix Palmer
7 | *
8 | * Licensed under the MIT license:
9 | * http://creativecommons.org/licenses/MIT/
10 | */
11 | package com.skd.androidrecording.visualizer.renderer;
12 |
13 | import android.graphics.Canvas;
14 | import android.graphics.Paint;
15 | import android.graphics.Rect;
16 |
17 | import com.skd.androidrecording.visualizer.AudioData;
18 | import com.skd.androidrecording.visualizer.FFTData;
19 |
20 | public class BarGraphRenderer extends Renderer
21 | {
22 | private int mDivisions;
23 | private Paint mPaint;
24 | private boolean mTop;
25 |
26 | /**
27 | * Renders the FFT data as a series of lines, in histogram form
28 | * @param divisions - must be a power of 2. Controls how many lines to draw
29 | * @param paint - Paint to draw lines with
30 | * @param top - whether to draw the lines at the top of the canvas, or the bottom
31 | */
32 | public BarGraphRenderer(int divisions,
33 | Paint paint,
34 | boolean top)
35 | {
36 | super();
37 | mDivisions = divisions;
38 | mPaint = paint;
39 | mTop = top;
40 | }
41 |
42 | @Override
43 | public void onRender(Canvas canvas, AudioData data, Rect rect)
44 | {
45 | // Do nothing, we only display FFT data
46 | }
47 |
48 | @Override
49 | public void onRender(Canvas canvas, FFTData data, Rect rect)
50 | {
51 | for (int i = 0; i < data.getBytes().length / mDivisions; i++) {
52 | mFFTPoints[i * 4] = i * 4 * mDivisions;
53 | mFFTPoints[i * 4 + 2] = i * 4 * mDivisions;
54 | byte rfk = data.getBytes()[mDivisions * i];
55 | byte ifk = data.getBytes()[mDivisions * i + 1];
56 | float magnitude = (rfk * rfk + ifk * ifk);
57 | int dbValue = (int) (10 * Math.log10(magnitude));
58 |
59 | if(mTop)
60 | {
61 | mFFTPoints[i * 4 + 1] = 0;
62 | mFFTPoints[i * 4 + 3] = (dbValue * 2 - 10);
63 | }
64 | else
65 | {
66 | mFFTPoints[i * 4 + 1] = rect.height();
67 | mFFTPoints[i * 4 + 3] = rect.height() - (dbValue * 2 - 10);
68 | }
69 | }
70 |
71 | canvas.drawLines(mFFTPoints, mPaint);
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/lib/src/com/skd/androidrecording/visualizer/renderer/Renderer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Modified by Steelkiwi Development, Julia Zudikova
3 | */
4 |
5 | /**
6 | * Copyright 2011, Felix Palmer
7 | *
8 | * Licensed under the MIT license:
9 | * http://creativecommons.org/licenses/MIT/
10 | */
11 | package com.skd.androidrecording.visualizer.renderer;
12 |
13 | import android.graphics.Canvas;
14 | import android.graphics.Rect;
15 |
16 | import com.skd.androidrecording.visualizer.AudioData;
17 | import com.skd.androidrecording.visualizer.FFTData;
18 |
19 | abstract public class Renderer
20 | {
21 | // Have these as members, so we don't have to re-create them each time
22 | protected float[] mPoints;
23 | protected float[] mFFTPoints;
24 | public Renderer()
25 | {
26 | }
27 |
28 | // As the display of raw/FFT audio will usually look different, subclasses
29 | // will typically only implement one of the below methods
30 | /**
31 | * Implement this method to render the audio data onto the canvas
32 | * @param canvas - Canvas to draw on
33 | * @param data - Data to render
34 | * @param rect - Rect to render into
35 | */
36 | abstract public void onRender(Canvas canvas, AudioData data, Rect rect);
37 |
38 | /**
39 | * Implement this method to render the FFT audio data onto the canvas
40 | * @param canvas - Canvas to draw on
41 | * @param data - Data to render
42 | * @param rect - Rect to render into
43 | */
44 | abstract public void onRender(Canvas canvas, FFTData data, Rect rect);
45 |
46 |
47 | // These methods should actually be called for rendering
48 | /**
49 | * Render the audio data onto the canvas
50 | * @param canvas - Canvas to draw on
51 | * @param data - Data to render
52 | * @param rect - Rect to render into
53 | */
54 | final public void render(Canvas canvas, AudioData data, Rect rect)
55 | {
56 | if (mPoints == null || mPoints.length < data.getBytes().length * 4) {
57 | mPoints = new float[data.getBytes().length * 4];
58 | }
59 |
60 | onRender(canvas, data, rect);
61 | }
62 |
63 | /**
64 | * Render the FFT data onto the canvas
65 | * @param canvas - Canvas to draw on
66 | * @param data - Data to render
67 | * @param rect - Rect to render into
68 | */
69 | final public void render(Canvas canvas, FFTData data, Rect rect)
70 | {
71 | if (mFFTPoints == null || mFFTPoints.length < data.getBytes().length * 4) {
72 | mFFTPoints = new float[data.getBytes().length * 4];
73 | }
74 |
75 | onRender(canvas, data, rect);
76 | }
77 | }
78 |
--------------------------------------------------------------------------------