OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "media/base/android/webaudio_media_codec_bridge.h" | |
6 | |
7 #include <errno.h> | |
8 #include <fcntl.h> | |
9 #include <stddef.h> | |
10 #include <string.h> | |
11 #include <sys/stat.h> | |
12 #include <sys/types.h> | |
13 #include <unistd.h> | |
14 #include <vector> | |
15 | |
16 #include "base/android/context_utils.h" | |
17 #include "base/android/jni_android.h" | |
18 #include "base/android/jni_array.h" | |
19 #include "base/android/jni_string.h" | |
20 #include "base/files/scoped_file.h" | |
21 #include "base/logging.h" | |
22 #include "base/posix/eintr_wrapper.h" | |
23 #include "jni/WebAudioMediaCodecBridge_jni.h" | |
24 #include "media/base/android/webaudio_media_codec_info.h" | |
25 | |
26 using base::android::AttachCurrentThread; | |
27 | |
28 namespace media { | |
29 | |
30 void WebAudioMediaCodecBridge::RunWebAudioMediaCodec( | |
31 base::SharedMemoryHandle encoded_audio_handle, | |
32 base::FileDescriptor pcm_output, | |
33 uint32_t data_size, | |
34 base::Closure on_decode_finished_cb) { | |
35 WebAudioMediaCodecBridge bridge( | |
36 encoded_audio_handle, pcm_output, data_size); | |
37 | |
38 bridge.DecodeInMemoryAudioFile(); | |
39 on_decode_finished_cb.Run(); | |
40 } | |
41 | |
42 WebAudioMediaCodecBridge::WebAudioMediaCodecBridge( | |
43 base::SharedMemoryHandle encoded_audio_handle, | |
44 base::FileDescriptor pcm_output, | |
45 uint32_t data_size) | |
46 : encoded_audio_handle_(encoded_audio_handle), | |
47 pcm_output_(pcm_output.fd), | |
48 data_size_(data_size) { | |
49 DVLOG(1) << "WebAudioMediaCodecBridge start **********************" | |
50 << " output fd = " << pcm_output.fd; | |
51 } | |
52 | |
53 WebAudioMediaCodecBridge::~WebAudioMediaCodecBridge() { | |
54 if (close(pcm_output_)) { | |
55 DVLOG(1) << "Couldn't close output fd " << pcm_output_ | |
56 << ": " << strerror(errno); | |
57 } | |
58 } | |
59 | |
60 int WebAudioMediaCodecBridge::SaveEncodedAudioToFile( | |
61 JNIEnv* env, | |
62 jobject context) { | |
63 // Create a temporary file where we can save the encoded audio data. | |
64 std::string temporaryFile = | |
65 base::android::ConvertJavaStringToUTF8( | |
66 env, | |
67 Java_WebAudioMediaCodecBridge_createTempFile(env, context).obj()); | |
68 | |
69 // Open the file and unlink it, so that it will be actually removed | |
70 // when we close the file. | |
71 base::ScopedFD fd(open(temporaryFile.c_str(), O_RDWR)); | |
72 if (unlink(temporaryFile.c_str())) { | |
73 VLOG(0) << "Couldn't unlink temp file " << temporaryFile | |
74 << ": " << strerror(errno); | |
75 } | |
76 | |
77 if (!fd.is_valid()) { | |
78 return -1; | |
79 } | |
80 | |
81 // Create a local mapping of the shared memory containing the | |
82 // encoded audio data, and save the contents to the temporary file. | |
83 base::SharedMemory encoded_data(encoded_audio_handle_, true); | |
84 | |
85 if (!encoded_data.Map(data_size_)) { | |
86 VLOG(0) << "Unable to map shared memory!"; | |
87 return -1; | |
88 } | |
89 | |
90 if (static_cast<uint32_t>(write(fd.get(), encoded_data.memory(), data_size_)) | |
91 != data_size_) { | |
92 VLOG(0) << "Failed to write all audio data to temp file!"; | |
93 return -1; | |
94 } | |
95 | |
96 lseek(fd.get(), 0, SEEK_SET); | |
97 | |
98 return fd.release(); | |
99 } | |
100 | |
101 bool WebAudioMediaCodecBridge::DecodeInMemoryAudioFile() { | |
102 JNIEnv* env = AttachCurrentThread(); | |
103 CHECK(env); | |
104 | |
105 jobject context = base::android::GetApplicationContext(); | |
106 | |
107 int sourceFd = SaveEncodedAudioToFile(env, context); | |
108 | |
109 if (sourceFd < 0) | |
110 return false; | |
111 | |
112 jboolean decoded = Java_WebAudioMediaCodecBridge_decodeAudioFile( | |
113 env, | |
114 context, | |
115 reinterpret_cast<intptr_t>(this), | |
116 sourceFd, | |
117 data_size_); | |
118 | |
119 close(sourceFd); | |
120 | |
121 DVLOG(1) << "decoded = " << (decoded ? "true" : "false"); | |
122 | |
123 return decoded; | |
124 } | |
125 | |
126 void WebAudioMediaCodecBridge::InitializeDestination( | |
127 JNIEnv* env, | |
128 const JavaParamRef<jobject>& /*java object*/, | |
129 jint channel_count, | |
130 jint sample_rate, | |
131 jlong duration_microsec) { | |
132 // Send information about this audio file: number of channels, | |
133 // sample rate (Hz), and the number of frames. | |
134 struct WebAudioMediaCodecInfo info = { | |
135 static_cast<unsigned long>(channel_count), | |
136 static_cast<unsigned long>(sample_rate), | |
137 // The number of frames is the duration of the file | |
138 // (in microseconds) times the sample rate. | |
139 static_cast<unsigned long>( | |
140 0.5 + (duration_microsec * 0.000001 * | |
141 sample_rate)) | |
142 }; | |
143 | |
144 DVLOG(1) << "InitializeDestination:" | |
145 << " channel count = " << channel_count | |
146 << " rate = " << sample_rate | |
147 << " duration = " << duration_microsec << " microsec"; | |
148 | |
149 HANDLE_EINTR(write(pcm_output_, &info, sizeof(info))); | |
150 } | |
151 | |
152 void WebAudioMediaCodecBridge::OnChunkDecoded( | |
153 JNIEnv* env, | |
154 const JavaParamRef<jobject>& /*java object*/, | |
155 const JavaParamRef<jobject>& buf, | |
156 jint buf_size, | |
157 jint input_channel_count, | |
158 jint output_channel_count) { | |
159 if (buf_size <= 0 || !buf) | |
160 return; | |
161 | |
162 int8_t* buffer = | |
163 static_cast<int8_t*>(env->GetDirectBufferAddress(buf)); | |
164 size_t count = static_cast<size_t>(buf_size); | |
165 std::vector<int16_t> decoded_data; | |
166 | |
167 if (input_channel_count == 1 && output_channel_count == 2) { | |
168 // See crbug.com/266006. The file has one channel, but the | |
169 // decoder decided to return two channels. To be consistent with | |
170 // the number of channels in the file, only send one channel (the | |
171 // first). | |
172 int16_t* data = static_cast<int16_t*>(env->GetDirectBufferAddress(buf)); | |
173 int frame_count = buf_size / sizeof(*data) / 2; | |
174 | |
175 decoded_data.resize(frame_count); | |
176 for (int k = 0; k < frame_count; ++k) { | |
177 decoded_data[k] = *data; | |
178 data += 2; | |
179 } | |
180 buffer = reinterpret_cast<int8_t*>(decoded_data.data()); | |
181 DCHECK(buffer); | |
182 count = frame_count * sizeof(*data); | |
183 } | |
184 | |
185 // Write out the data to the pipe in small chunks if necessary. | |
186 while (count > 0) { | |
187 int bytes_to_write = (count >= PIPE_BUF) ? PIPE_BUF : count; | |
188 ssize_t bytes_written = HANDLE_EINTR(write(pcm_output_, | |
189 buffer, | |
190 bytes_to_write)); | |
191 if (bytes_written == -1) | |
192 break; | |
193 count -= bytes_written; | |
194 buffer += bytes_written; | |
195 } | |
196 } | |
197 | |
198 bool WebAudioMediaCodecBridge::RegisterWebAudioMediaCodecBridge(JNIEnv* env) { | |
199 return RegisterNativesImpl(env); | |
200 } | |
201 | |
202 } // namespace | |
OLD | NEW |