Home | History | Annotate | Download | only in android
      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 
     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 
     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 
     49 WebAudioMediaCodecBridge::~WebAudioMediaCodecBridge() {
     50   if (close(pcm_output_)) {
     51     DVLOG(1) << "Couldn't close output fd " << pcm_output_
     52              << ": " << strerror(errno);
     53   }
     54 }
     55 
     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 
     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 
    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 
    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 
    195 bool WebAudioMediaCodecBridge::RegisterWebAudioMediaCodecBridge(JNIEnv* env) {
    196   return RegisterNativesImpl(env);
    197 }
    198 
    199 } // namespace
    200