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