예제 #1
0
status_t AudioOffloadPlayer::Start(bool aSourceAlreadyStarted)
{
  MOZ_ASSERT(NS_IsMainThread());
  CHECK(!mStarted);
  CHECK(mSource.get());

  status_t err;
  CHECK(mAudioSink.get());

  if (!aSourceAlreadyStarted) {
    err = mSource->start();

    if (err != OK) {
      return err;
    }
  }

  sp<MetaData> format = mSource->getFormat();
  const char* mime;
  int avgBitRate = -1;
  int32_t channelMask;
  int32_t numChannels;
  int64_t durationUs = -1;
  audio_format_t audioFormat = AUDIO_FORMAT_PCM_16_BIT;
  uint32_t flags = AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
  audio_offload_info_t offloadInfo = AUDIO_INFO_INITIALIZER;

  CHECK(format->findCString(kKeyMIMEType, &mime));
  CHECK(format->findInt32(kKeySampleRate, &mSampleRate));
  CHECK(format->findInt32(kKeyChannelCount, &numChannels));
  format->findInt32(kKeyBitRate, &avgBitRate);
  format->findInt64(kKeyDuration, &durationUs);

  if(!format->findInt32(kKeyChannelMask, &channelMask)) {
    channelMask = CHANNEL_MASK_USE_CHANNEL_ORDER;
  }

  if (mapMimeToAudioFormat(audioFormat, mime) != OK) {
    AUDIO_OFFLOAD_LOG(PR_LOG_ERROR, ("Couldn't map mime type \"%s\" to a valid "
        "AudioSystem::audio_format", mime));
    audioFormat = AUDIO_FORMAT_INVALID;
  }

  offloadInfo.duration_us = durationUs;
  offloadInfo.sample_rate = mSampleRate;
  offloadInfo.channel_mask = channelMask;
  offloadInfo.format = audioFormat;
  offloadInfo.stream_type = AUDIO_STREAM_MUSIC;
  offloadInfo.bit_rate = avgBitRate;
  offloadInfo.has_video = false;
  offloadInfo.is_streaming = false;

  AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("isOffloadSupported: SR=%u, CM=0x%x, "
      "Format=0x%x, StreamType=%d, BitRate=%u, duration=%lld us, has_video=%d",
      offloadInfo.sample_rate, offloadInfo.channel_mask, offloadInfo.format,
      offloadInfo.stream_type, offloadInfo.bit_rate, offloadInfo.duration_us,
      offloadInfo.has_video));

  err = mAudioSink->Open(mSampleRate,
                         numChannels,
                         channelMask,
                         audioFormat,
                         &AudioOffloadPlayer::AudioSinkCallback,
                         this,
                         (audio_output_flags_t) flags,
                         &offloadInfo);
  if (err == OK) {
    // If the playback is offloaded to h/w we pass the
    // HAL some metadata information
    // We don't want to do this for PCM because it will be going
    // through the AudioFlinger mixer before reaching the hardware
    SendMetaDataToHal(mAudioSink, format);
  }
  mStarted = true;
  mPlaying = false;

  return err;
}
status_t AudioPlayer::start(bool sourceAlreadyStarted) {
    CHECK(!mStarted);
    CHECK(mSource != NULL);

    status_t err;
    if (!sourceAlreadyStarted) {
        mSourcePaused = false;
        err = mSource->start();

        if (err != OK) {
            return err;
        }
    }

    // We allow an optional INFO_FORMAT_CHANGED at the very beginning
    // of playback, if there is one, getFormat below will retrieve the
    // updated format, if there isn't, we'll stash away the valid buffer
    // of data to be used on the first audio callback.

    CHECK(mFirstBuffer == NULL);

    MediaSource::ReadOptions options;
    if (mSeeking) {
        options.setSeekTo(mSeekTimeUs);
        mSeeking = false;
    }

    mFirstBufferResult = mSource->read(&mFirstBuffer, &options);
    if (mFirstBufferResult == INFO_FORMAT_CHANGED) {
        ALOGV("INFO_FORMAT_CHANGED!!!");

        CHECK(mFirstBuffer == NULL);
        mFirstBufferResult = OK;
        mIsFirstBuffer = false;
    } else {
        mIsFirstBuffer = true;
    }

    sp<MetaData> format = mSource->getFormat();
    const char *mime;
    bool success = format->findCString(kKeyMIMEType, &mime);
    CHECK(success);
    CHECK(useOffload() || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW));

    success = format->findInt32(kKeySampleRate, &mSampleRate);
    CHECK(success);

    int32_t numChannels, channelMask;
    success = format->findInt32(kKeyChannelCount, &numChannels);
    CHECK(success);

    if(!format->findInt32(kKeyChannelMask, &channelMask)) {
        // log only when there's a risk of ambiguity of channel mask selection
        ALOGI_IF(numChannels > 2,
                "source format didn't specify channel mask, using (%d) channel order", numChannels);
        channelMask = CHANNEL_MASK_USE_CHANNEL_ORDER;
    }

    audio_format_t audioFormat = AUDIO_FORMAT_PCM_16_BIT;

    if (useOffload()) {
        if (mapMimeToAudioFormat(audioFormat, mime) != OK) {
            ALOGE("Couldn't map mime type \"%s\" to a valid AudioSystem::audio_format", mime);
            audioFormat = AUDIO_FORMAT_INVALID;
        } else {
#ifdef QCOM_HARDWARE
            // Override audio format for PCM offload
            if (audioFormat == AUDIO_FORMAT_PCM_16_BIT) {
                audioFormat = AUDIO_FORMAT_PCM_16_BIT_OFFLOAD;
            }
#endif
            ALOGV("Mime type \"%s\" mapped to audio_format 0x%x", mime, audioFormat);
        }
    }

    int avgBitRate = -1;
    format->findInt32(kKeyBitRate, &avgBitRate);

    if (mAudioSink.get() != NULL) {

        uint32_t flags = AUDIO_OUTPUT_FLAG_NONE;
        audio_offload_info_t offloadInfo = AUDIO_INFO_INITIALIZER;

        if (allowDeepBuffering()) {
            flags |= AUDIO_OUTPUT_FLAG_DEEP_BUFFER;
        }
        if (useOffload()) {
            flags |= AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;

            int64_t durationUs;
            if (format->findInt64(kKeyDuration, &durationUs)) {
                offloadInfo.duration_us = durationUs;
            } else {
                offloadInfo.duration_us = -1;
            }

            offloadInfo.sample_rate = mSampleRate;
            offloadInfo.channel_mask = channelMask;
            offloadInfo.format = audioFormat;
            offloadInfo.stream_type = AUDIO_STREAM_MUSIC;
            offloadInfo.bit_rate = avgBitRate;
            offloadInfo.has_video = ((mCreateFlags & HAS_VIDEO) != 0);
            offloadInfo.is_streaming = ((mCreateFlags & IS_STREAMING) != 0);
        }

        status_t err = mAudioSink->open(
                mSampleRate, numChannels, channelMask, audioFormat,
                DEFAULT_AUDIOSINK_BUFFERCOUNT,
                &AudioPlayer::AudioSinkCallback,
                this,
                (audio_output_flags_t)flags,
                useOffload() ? &offloadInfo : NULL);

        if (err == OK) {
            mLatencyUs = (int64_t)mAudioSink->latency() * 1000;
            mFrameSize = mAudioSink->frameSize();

            if (useOffload()) {
                // If the playback is offloaded to h/w we pass the
                // HAL some metadata information
                // We don't want to do this for PCM because it will be going
                // through the AudioFlinger mixer before reaching the hardware
                sendMetaDataToHal(mAudioSink, format);
            }

            err = mAudioSink->start();
            // do not alter behavior for non offloaded tracks: ignore start status.
            if (!useOffload()) {
                err = OK;
            }
        }

        if (err != OK) {
            if (mFirstBuffer != NULL) {
                mFirstBuffer->release();
                mFirstBuffer = NULL;
            }

            if (!sourceAlreadyStarted) {
                mSource->stop();
            }

            return err;
        }

    } else {
        // playing to an AudioTrack, set up mask if necessary
        audio_channel_mask_t audioMask = channelMask == CHANNEL_MASK_USE_CHANNEL_ORDER ?
                audio_channel_out_mask_from_count(numChannels) : channelMask;
        if (0 == audioMask) {
            return BAD_VALUE;
        }

        mAudioTrack = new AudioTrack(
                AUDIO_STREAM_MUSIC, mSampleRate, AUDIO_FORMAT_PCM_16_BIT, audioMask,
                0, AUDIO_OUTPUT_FLAG_NONE, &AudioCallback, this, 0);

        if ((err = mAudioTrack->initCheck()) != OK) {
            mAudioTrack.clear();

            if (mFirstBuffer != NULL) {
                mFirstBuffer->release();
                mFirstBuffer = NULL;
            }

            if (!sourceAlreadyStarted) {
                mSource->stop();
            }

            return err;
        }

        mLatencyUs = (int64_t)mAudioTrack->latency() * 1000;
        mFrameSize = mAudioTrack->frameSize();

        mAudioTrack->start();
    }

    mStarted = true;
    mPlaying = true;
    mPinnedTimeUs = -1ll;
    const char *componentName;
    if (!(format->findCString(kKeyDecoderComponent, &componentName))) {
          componentName = "none";
    }
    if (!strncmp(componentName, "OMX.qcom.", 9)) {
        mPauseRequired = true;
    } else {
        mPauseRequired = false;
    }

    return OK;
}