root/media/base/android/webaudio_media_codec_bridge.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. RunWebAudioMediaCodec
  2. data_size_
  3. SaveEncodedAudioToFile
  4. DecodeInMemoryAudioFile
  5. InitializeDestination
  6. OnChunkDecoded
  7. RegisterWebAudioMediaCodecBridge

// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "media/base/android/webaudio_media_codec_bridge.h"

#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <vector>

#include "base/android/jni_android.h"
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
#include "base/basictypes.h"
#include "base/logging.h"
#include "base/posix/eintr_wrapper.h"
#include "base/stl_util.h"
#include "jni/WebAudioMediaCodecBridge_jni.h"
#include "media/base/android/webaudio_media_codec_info.h"


using base::android::AttachCurrentThread;

namespace media {

void WebAudioMediaCodecBridge::RunWebAudioMediaCodec(
    base::SharedMemoryHandle encoded_audio_handle,
    base::FileDescriptor pcm_output,
    uint32_t data_size) {
  WebAudioMediaCodecBridge bridge(encoded_audio_handle, pcm_output, data_size);

  bridge.DecodeInMemoryAudioFile();
}

WebAudioMediaCodecBridge::WebAudioMediaCodecBridge(
    base::SharedMemoryHandle encoded_audio_handle,
    base::FileDescriptor pcm_output,
    uint32_t data_size)
    : encoded_audio_handle_(encoded_audio_handle),
      pcm_output_(pcm_output.fd),
      data_size_(data_size) {
  DVLOG(1) << "WebAudioMediaCodecBridge start **********************"
           << " output fd = " << pcm_output.fd;
}

WebAudioMediaCodecBridge::~WebAudioMediaCodecBridge() {
  if (close(pcm_output_)) {
    DVLOG(1) << "Couldn't close output fd " << pcm_output_
             << ": " << strerror(errno);
  }
}

int WebAudioMediaCodecBridge::SaveEncodedAudioToFile(
    JNIEnv* env,
    jobject context) {
  // Create a temporary file where we can save the encoded audio data.
  std::string temporaryFile =
      base::android::ConvertJavaStringToUTF8(
          env,
          Java_WebAudioMediaCodecBridge_CreateTempFile(env, context).obj());

  // Open the file and unlink it, so that it will be actually removed
  // when we close the file.
  int fd = open(temporaryFile.c_str(), O_RDWR);
  if (unlink(temporaryFile.c_str())) {
    VLOG(0) << "Couldn't unlink temp file " << temporaryFile
            << ": " << strerror(errno);
  }

  if (fd < 0) {
    return -1;
  }

  // Create a local mapping of the shared memory containing the
  // encoded audio data, and save the contents to the temporary file.
  base::SharedMemory encoded_data(encoded_audio_handle_, true);

  if (!encoded_data.Map(data_size_)) {
    VLOG(0) << "Unable to map shared memory!";
    return -1;
  }

  if (static_cast<uint32_t>(write(fd, encoded_data.memory(), data_size_))
      != data_size_) {
    VLOG(0) << "Failed to write all audio data to temp file!";
    return -1;
  }

  lseek(fd, 0, SEEK_SET);

  return fd;
}

bool WebAudioMediaCodecBridge::DecodeInMemoryAudioFile() {
  JNIEnv* env = AttachCurrentThread();
  CHECK(env);

  jobject context = base::android::GetApplicationContext();

  int sourceFd = SaveEncodedAudioToFile(env, context);

  if (sourceFd < 0)
    return false;

  jboolean decoded = Java_WebAudioMediaCodecBridge_decodeAudioFile(
      env,
      context,
      reinterpret_cast<intptr_t>(this),
      sourceFd,
      data_size_);

  close(sourceFd);

  DVLOG(1) << "decoded = " << (decoded ? "true" : "false");

  return decoded;
}

void WebAudioMediaCodecBridge::InitializeDestination(
    JNIEnv* env,
    jobject /*java object*/,
    jint channel_count,
    jint sample_rate,
    jlong duration_microsec) {
  // Send information about this audio file: number of channels,
  // sample rate (Hz), and the number of frames.
  struct WebAudioMediaCodecInfo info = {
    static_cast<unsigned long>(channel_count),
    static_cast<unsigned long>(sample_rate),
    // The number of frames is the duration of the file
    // (in microseconds) times the sample rate.
    static_cast<unsigned long>(
        0.5 + (duration_microsec * 0.000001 *
               sample_rate))
  };

  DVLOG(1) << "InitializeDestination:"
           << "  channel count = " << channel_count
           << "  rate = " << sample_rate
           << "  duration = " << duration_microsec << " microsec";

  HANDLE_EINTR(write(pcm_output_, &info, sizeof(info)));
}

void WebAudioMediaCodecBridge::OnChunkDecoded(
    JNIEnv* env,
    jobject /*java object*/,
    jobject buf,
    jint buf_size,
    jint input_channel_count,
    jint output_channel_count) {

  if (buf_size <= 0 || !buf)
    return;

  int8_t* buffer =
      static_cast<int8_t*>(env->GetDirectBufferAddress(buf));
  size_t count = static_cast<size_t>(buf_size);
  std::vector<int16_t> decoded_data;

  if (input_channel_count == 1 && output_channel_count == 2) {
    // See crbug.com/266006.  The file has one channel, but the
    // decoder decided to return two channels.  To be consistent with
    // the number of channels in the file, only send one channel (the
    // first).
    int16_t* data = static_cast<int16_t*>(env->GetDirectBufferAddress(buf));
    int frame_count  = buf_size / sizeof(*data) / 2;

    decoded_data.resize(frame_count);
    for (int k = 0; k < frame_count; ++k) {
      decoded_data[k] = *data;
      data += 2;
    }
    buffer = reinterpret_cast<int8_t*>(vector_as_array(&decoded_data));
    DCHECK(buffer);
    count = frame_count * sizeof(*data);
  }

  // Write out the data to the pipe in small chunks if necessary.
  while (count > 0) {
    int bytes_to_write = (count >= PIPE_BUF) ? PIPE_BUF : count;
    ssize_t bytes_written = HANDLE_EINTR(write(pcm_output_,
                                               buffer,
                                               bytes_to_write));
    if (bytes_written == -1)
      break;
    count -= bytes_written;
    buffer += bytes_written;
  }
}

bool WebAudioMediaCodecBridge::RegisterWebAudioMediaCodecBridge(JNIEnv* env) {
  return RegisterNativesImpl(env);
}

} // namespace

/* [<][>][^][v][top][bottom][index][help] */