status_t SimplePlayer::onOutputFormatChanged( size_t trackIndex, CodecState *state) { sp<AMessage> format; status_t err = state->mCodec->getOutputFormat(&format); if (err != OK) { return err; } AString mime; CHECK(format->findString("mime", &mime)); if (!strncasecmp(mime.c_str(), "audio/", 6)) { int32_t channelCount; int32_t sampleRate; CHECK(format->findInt32("channel-count", &channelCount)); CHECK(format->findInt32("sample-rate", &sampleRate)); state->mAudioTrack = new AudioTrack( AUDIO_STREAM_MUSIC, sampleRate, AUDIO_FORMAT_PCM_16_BIT, audio_channel_out_mask_from_count(channelCount), 0); state->mNumFramesWritten = 0; } return OK; }
status_t LibmediaPlayback::Play(int duration_secs) { audio_channel_mask_t audio_mask = audio_channel_out_mask_from_count(num_channels_); const audio_stream_type_t kStreamType = AUDIO_STREAM_MUSIC; size_t frame_count = 0; // Use default value for frame count. audio_output_flags_t audio_output_flags = AUDIO_OUTPUT_FLAG_NONE; AudioTrack* track = new AudioTrack( kStreamType, sample_rate_, audio_format_, audio_mask, frame_count, audio_output_flags, LibmediaPlayback::AudioCallback, reinterpret_cast<void*>(this)); status_t status = track->initCheck(); if (status != OK) { LOG(ERROR) << "Audio track initialization failed."; return status; } float volume = 0.9; track->setVolume(volume); status = track->start(); if (status != OK) { LOG(ERROR) << "Audio track failed to start."; return status; } sleep(duration_secs); track->stop(); if (in_file_) sf_close(in_file_); else sine_data_buffer_->release(); return status; }
//------------------------------------------------------------------------------------------------- int JetPlayer::init() { //Mutex::Autolock lock(&mMutex); EAS_RESULT result; // retrieve the EAS library settings if (pLibConfig == NULL) pLibConfig = EAS_Config(); if (pLibConfig == NULL) { ALOGE("JetPlayer::init(): EAS library configuration could not be retrieved, aborting."); return EAS_FAILURE; } // init the EAS library result = EAS_Init(&mEasData); if (result != EAS_SUCCESS) { ALOGE("JetPlayer::init(): Error initializing Sonivox EAS library, aborting."); mState = EAS_STATE_ERROR; return result; } // init the JET library with the default app event controller range result = JET_Init(mEasData, NULL, sizeof(S_JET_CONFIG)); if (result != EAS_SUCCESS) { ALOGE("JetPlayer::init(): Error initializing JET library, aborting."); mState = EAS_STATE_ERROR; return result; } // create the output AudioTrack mAudioTrack = new AudioTrack(); mAudioTrack->set(AUDIO_STREAM_MUSIC, //TODO parameterize this pLibConfig->sampleRate, AUDIO_FORMAT_PCM_16_BIT, audio_channel_out_mask_from_count(pLibConfig->numChannels), mTrackBufferSize, AUDIO_OUTPUT_FLAG_NONE); // create render and playback thread { Mutex::Autolock l(mMutex); ALOGV("JetPlayer::init(): trying to start render thread"); mThread = new JetPlayerThread(this); mThread->run("jetRenderThread", ANDROID_PRIORITY_AUDIO); mCondition.wait(mMutex); } if (mTid > 0) { // render thread started, we're ready ALOGV("JetPlayer::init(): render thread(%d) successfully started.", mTid); mState = EAS_STATE_READY; } else { ALOGE("JetPlayer::init(): failed to start render thread."); mState = EAS_STATE_ERROR; return EAS_FAILURE; } return EAS_SUCCESS; }
bool android_sys_render::init_audio(void* ctx, int channels, int bits_per_sample, int sample_rate, int format) { if(!m_support)return false; int play_buf_size; status_t s; m_writedata->nchannels = channels; m_writedata->rate = sample_rate; m_sleep_in = 1000000.0/(2*channels*sample_rate); __android_log_print(ANDROID_LOG_INFO,"android_sys_render","%d %d",channels,sample_rate); int notify_frames=(int)(audio_buf_ms*(float)m_writedata->rate); m_writedata->mCard->enableVoipMode(); m_writedata->nFramesRequested=0; if (AudioTrack::getMinFrameCount(&play_buf_size,m_writedata->stype,m_writedata->rate)==0) { #ifdef WTITE_LOG __android_log_print(ANDROID_LOG_INFO,"android_sys_render","AudioTrack: min frame count is %i",play_buf_size); #endif } else { #ifdef WTITE_LOG __android_log_print(ANDROID_LOG_INFO,"android_sys_render","AudioTrack::getMinFrameCount() error"); #endif return false; } m_writedata->tr=new AudioTrack(m_writedata->stype, m_writedata->rate, AUDIO_FORMAT_PCM_16_BIT, audio_channel_out_mask_from_count(m_writedata->nchannels), play_buf_size, AUDIO_OUTPUT_FLAG_NONE, // AUDIO_OUTPUT_FLAG_NONE, android_snd_write_cb, m_writedata,notify_frames,0); s=m_writedata->tr->initCheck(); if (s!=0) { #ifdef WTITE_LOG __android_log_print(ANDROID_LOG_INFO,"android_sys_render","Problem setting up AudioTrack: %s",strerror(-s)); #endif delete m_writedata->tr; m_writedata->tr=NULL; return false; } m_writedata->nbufs=0; #ifdef WTITE_LOG __android_log_print(ANDROID_LOG_INFO,"android_sys_render","AudioTrack latency estimated to %i ms",m_writedata->tr->latency()); #endif m_writedata->mStarted=false; m_writedata->flowControlStart = av_gettime(); m_writedata->minBufferFilling = -1; return true; }
void AudioMixerController::initTrack(Track* track, std::vector<Track*>& tracksToRemove) { uint32_t channelMask = audio_channel_out_mask_from_count(2); int32_t name = _mixer->getTrackName(channelMask, AUDIO_FORMAT_PCM_16_BIT, AUDIO_SESSION_OUTPUT_MIX); if (name < 0) { // If we could not get the track name, it means that there're MAX_NUM_TRACKS tracks // So ignore the new track. tracksToRemove.push_back(track); } else { _mixer->setBufferProvider(name, track); _mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MAIN_BUFFER, _mixingBuffer.buf); _mixer->setParameter( name, AudioMixer::TRACK, AudioMixer::MIXER_FORMAT, (void *) (uintptr_t) AUDIO_FORMAT_PCM_16_BIT); _mixer->setParameter( name, AudioMixer::TRACK, AudioMixer::FORMAT, (void *) (uintptr_t) AUDIO_FORMAT_PCM_16_BIT); _mixer->setParameter( name, AudioMixer::TRACK, AudioMixer::MIXER_CHANNEL_MASK, (void *) (uintptr_t) channelMask); _mixer->setParameter( name, AudioMixer::TRACK, AudioMixer::CHANNEL_MASK, (void *) (uintptr_t) channelMask); track->setState(Track::State::PLAYING); track->setName(name); _mixer->enable(name); std::lock_guard<std::mutex> lk(track->_volumeDirtyMutex); gain_minifloat_packed_t volume = track->getVolumeLR(); float lVolume = float_from_gain(gain_minifloat_unpack_left(volume)); float rVolume = float_from_gain(gain_minifloat_unpack_right(volume)); _mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0, &lVolume); _mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1, &rVolume); track->setVolumeDirty(false); track->setInitialized(true); } }
int main(int argc, char* argv[]) { if (argc < 3) { Usage(); return -1; } // Process command line arguments. const int kAudioDeviceBase = 16; uint32_t desired_output_device = strtol( argv[1], nullptr /* look at full string*/, kAudioDeviceBase); const int kSampleRateBase = 10; uint32_t desired_sample_rate = strtol( argv[2], nullptr /* look at full string*/, kSampleRateBase); char* filename = nullptr; if (desired_sample_rate == 0) { filename = argv[2]; } LOG(INFO) << "Starting audio hal tests."; int rc = 0; const hw_module_t* module = nullptr; // Load audio HAL. rc = hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID, "primary", &module); if (rc) { LOG(WARNING) << "Could not get primary hw module, trying usb. (" << strerror(rc) << ")"; rc = hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID, "usb", &module); if (rc) { LOG(ERROR) << "Could not get hw module. (" << strerror(rc) << ")"; return -1; } } // Open audio device. CHECK(module != nullptr); audio_hw_device_t* audio_device = nullptr; rc = audio_hw_device_open(module, &audio_device); if (rc) { LOG(ERROR) << "Could not open hw device. (" << strerror(rc) << ")"; return -1; } // Set to a high number so it doesn't interfere with existing stream handles // from AudioFlinger. audio_io_handle_t handle = 0x999; audio_devices_t output_device = static_cast<audio_devices_t>(desired_output_device); audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE; audio_config_t config; SF_INFO file_info; SNDFILE* in_file = nullptr; if (filename) { in_file = sf_open(filename, SFM_READ, &file_info); CHECK(in_file != nullptr); config.channel_mask = audio_channel_out_mask_from_count(file_info.channels); if (!(file_info.format & SF_FORMAT_PCM_16)) { LOG(ERROR) << "File must be of format 16-bit PCM."; return -1; } config.format = kAudioPlaybackFormat; config.sample_rate = file_info.samplerate; } else { config.channel_mask = AUDIO_CHANNEL_OUT_STEREO; config.format = kAudioPlaybackFormat; config.sample_rate = desired_sample_rate; } LOG(INFO) << "Now playing to " << output_device << " at sample rate " << config.sample_rate; const char* stream_name = "output_stream"; // Open audio output stream. audio_stream_out_t* out_stream = nullptr; CHECK(audio_device != nullptr); rc = audio_device->open_output_stream(audio_device, handle, output_device, flags, &config, &out_stream, stream_name); if (rc) { LOG(ERROR) << "Could not open output stream. (" << strerror(rc) << ")"; return -1; } // Set volume. const float kLeftVolume = 0.75; const float kRightVolume = 0.75; CHECK(out_stream != nullptr); rc = out_stream->set_volume(out_stream, kLeftVolume, kRightVolume); if (rc) { LOG(ERROR) << "Could not set volume correctly. (" << strerror(rc) << ")"; } if (filename) { PlayFile(out_stream, in_file, &config); } else { PlaySineWave(out_stream, &config); } // Close output stream and device. audio_device->close_output_stream(audio_device, out_stream); audio_hw_device_close(audio_device); LOG(INFO) << "Done with hal tests"; return 0; }
status_t AudioPlayer::start(bool sourceAlreadyStarted) { CHECK(!mStarted); CHECK(mSource != NULL); status_t err; if (!sourceAlreadyStarted) { 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(!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; } if (mAudioSink.get() != NULL) { status_t err = mAudioSink->open( mSampleRate, numChannels, channelMask, AUDIO_FORMAT_PCM_16_BIT, DEFAULT_AUDIOSINK_BUFFERCOUNT, &AudioPlayer::AudioSinkCallback, this, (mAllowDeepBuffering ? AUDIO_OUTPUT_FLAG_DEEP_BUFFER : AUDIO_OUTPUT_FLAG_NONE)); if (err != OK) { if (mFirstBuffer != NULL) { mFirstBuffer->release(); mFirstBuffer = NULL; } if (!sourceAlreadyStarted) { mSource->stop(); } return err; } mLatencyUs = (int64_t)mAudioSink->latency() * 1000; mFrameSize = mAudioSink->frameSize(); mAudioSink->start(); } 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) { delete mAudioTrack; mAudioTrack = NULL; 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; mPinnedTimeUs = -1ll; return OK; }
static int adev_open_output_stream(struct audio_hw_device *dev, audio_io_handle_t handle, audio_devices_t devices, audio_output_flags_t flags, struct audio_config *config, struct audio_stream_out **stream_out, const char *address /*__unused*/) { ALOGV("adev_open_output_stream() handle:0x%X, device:0x%X, flags:0x%X, addr:%s", handle, devices, flags, address); struct audio_device *adev = (struct audio_device *)dev; struct stream_out *out; out = (struct stream_out *)calloc(1, sizeof(struct stream_out)); if (!out) return -ENOMEM; /* setup function pointers */ out->stream.common.get_sample_rate = out_get_sample_rate; out->stream.common.set_sample_rate = out_set_sample_rate; out->stream.common.get_buffer_size = out_get_buffer_size; out->stream.common.get_channels = out_get_channels; out->stream.common.get_format = out_get_format; out->stream.common.set_format = out_set_format; out->stream.common.standby = out_standby; out->stream.common.dump = out_dump; out->stream.common.set_parameters = out_set_parameters; out->stream.common.get_parameters = out_get_parameters; out->stream.common.add_audio_effect = out_add_audio_effect; out->stream.common.remove_audio_effect = out_remove_audio_effect; out->stream.get_latency = out_get_latency; out->stream.set_volume = out_set_volume; out->stream.write = out_write; out->stream.get_render_position = out_get_render_position; out->stream.get_presentation_position = out_get_presentation_position; out->stream.get_next_write_timestamp = out_get_next_write_timestamp; pthread_mutex_init(&out->lock, (const pthread_mutexattr_t *) NULL); pthread_mutex_init(&out->pre_lock, (const pthread_mutexattr_t *) NULL); out->dev = adev; pthread_mutex_lock(&adev->lock); out->profile = &adev->out_profile; // build this to hand to the alsa_device_proxy struct pcm_config proxy_config; memset(&proxy_config, 0, sizeof(proxy_config)); /* Pull out the card/device pair */ parse_card_device_params(true, &(out->profile->card), &(out->profile->device)); profile_read_device_info(out->profile); pthread_mutex_unlock(&adev->lock); int ret = 0; /* Rate */ if (config->sample_rate == 0) { proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(out->profile); } else if (profile_is_sample_rate_valid(out->profile, config->sample_rate)) { proxy_config.rate = config->sample_rate; } else { ALOGE("%s: The requested sample rate (%d) is not valid", __func__, config->sample_rate); proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(out->profile); ret = -EINVAL; } /* Format */ if (config->format == AUDIO_FORMAT_DEFAULT) { proxy_config.format = profile_get_default_format(out->profile); config->format = audio_format_from_pcm_format(proxy_config.format); } else { enum pcm_format fmt = pcm_format_from_audio_format(config->format); if (profile_is_format_valid(out->profile, fmt)) { proxy_config.format = fmt; } else { ALOGE("%s: The requested format (0x%x) is not valid", __func__, config->format); proxy_config.format = profile_get_default_format(out->profile); config->format = audio_format_from_pcm_format(proxy_config.format); ret = -EINVAL; } } /* Channels */ unsigned proposed_channel_count = 0; if (k_force_channels) { proposed_channel_count = k_force_channels; } else if (config->channel_mask == AUDIO_CHANNEL_NONE) { proposed_channel_count = profile_get_default_channel_count(out->profile); } if (proposed_channel_count != 0) { if (proposed_channel_count <= FCC_2) { // use channel position mask for mono and stereo config->channel_mask = audio_channel_out_mask_from_count(proposed_channel_count); } else { // use channel index mask for multichannel config->channel_mask = audio_channel_mask_for_index_assignment_from_count(proposed_channel_count); } out->hal_channel_count = proposed_channel_count; } else { out->hal_channel_count = audio_channel_count_from_out_mask(config->channel_mask); } /* we can expose any channel mask, and emulate internally based on channel count. */ out->hal_channel_mask = config->channel_mask; /* no validity checks are needed as proxy_prepare() forces channel_count to be valid. * and we emulate any channel count discrepancies in out_write(). */ proxy_config.channels = proposed_channel_count; #if TARGET_AUDIO_PRIMARY out->profile->default_config.period_count = 4; #endif proxy_prepare(&out->proxy, out->profile, &proxy_config); /* TODO The retry mechanism isn't implemented in AudioPolicyManager/AudioFlinger. */ ret = 0; out->conversion_buffer = NULL; out->conversion_buffer_size = 0; out->standby = true; *stream_out = &out->stream; return ret; err_open: free(out); *stream_out = NULL; return -ENOSYS; }
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; }
status_t VideoEditorAudioPlayer::start(bool sourceAlreadyStarted) { Mutex::Autolock autoLock(mLock); CHECK(!mStarted); CHECK(mSource != NULL); ALOGV("Start"); status_t err; M4OSA_ERR result = M4NO_ERROR; M4OSA_UInt32 startTime = 0; M4OSA_UInt32 seekTimeStamp = 0; M4OSA_Bool bStoryBoardTSBeyondBTEndCutTime = M4OSA_FALSE; if (!sourceAlreadyStarted) { err = mSource->start(); if (err != OK) { return err; } } // Create the BG Audio handler mAudioProcess = new VideoEditorBGAudioProcessing(); AudioMixSettings audioMixSettings; // Pass on the audio ducking parameters audioMixSettings.lvInDucking_threshold = mAudioMixSettings->uiInDucking_threshold; audioMixSettings.lvInDucking_lowVolume = ((M4OSA_Float)mAudioMixSettings->uiInDucking_lowVolume) / 100.0; audioMixSettings.lvInDucking_enable = mAudioMixSettings->bInDucking_enable; audioMixSettings.lvPTVolLevel = ((M4OSA_Float)mBGAudioStoryBoardCurrentMediaVolumeVal) / 100.0; audioMixSettings.lvBTVolLevel = ((M4OSA_Float)mAudioMixSettings->uiAddVolume) / 100.0; audioMixSettings.lvBTChannelCount = mAudioMixSettings->uiBTChannelCount; audioMixSettings.lvPTChannelCount = mAudioMixSettings->uiNbChannels; // Call to Audio mix param setting mAudioProcess->setMixParams(audioMixSettings); // Get the BG Audio PCM file details if ( mBGAudioPCMFileHandle ) { // TODO : 32bits required for OSAL, to be updated once OSAL is updated M4OSA_UInt32 tmp32 = 0; result = M4OSA_fileReadGetOption(mBGAudioPCMFileHandle, M4OSA_kFileReadGetFileSize, (M4OSA_Void**)&tmp32); mBGAudioPCMFileLength = tmp32; mBGAudioPCMFileTrimmedLength = mBGAudioPCMFileLength; ALOGV("VideoEditorAudioPlayer::start M4OSA_kFileReadGetFileSize = %lld", mBGAudioPCMFileLength); // Get the duration in time of the audio BT if ( result == M4NO_ERROR ) { ALOGV("VEAP: channels = %d freq = %d", mAudioMixSettings->uiNbChannels, mAudioMixSettings->uiSamplingFrequency); // No trim mBGAudioPCMFileDuration = (( (int64_t)(mBGAudioPCMFileLength/sizeof(M4OSA_UInt16)/ mAudioMixSettings->uiNbChannels))*1000 ) / mAudioMixSettings->uiSamplingFrequency; ALOGV("VideoEditorAudioPlayer:: beginCutMs %d , endCutMs %d", (unsigned int) mAudioMixSettings->beginCutMs, (unsigned int) mAudioMixSettings->endCutMs); // Remove the trim part if ((mAudioMixSettings->beginCutMs == 0) && (mAudioMixSettings->endCutMs != 0)) { // End time itself the file duration mBGAudioPCMFileDuration = mAudioMixSettings->endCutMs; // Limit the file length also mBGAudioPCMFileTrimmedLength = (( (int64_t)(mBGAudioPCMFileDuration * mAudioMixSettings->uiSamplingFrequency) * mAudioMixSettings->uiNbChannels) * sizeof(M4OSA_UInt16)) / 1000; } else if ((mAudioMixSettings->beginCutMs != 0) && (mAudioMixSettings->endCutMs == mBGAudioPCMFileDuration)) { // End time itself the file duration mBGAudioPCMFileDuration = mBGAudioPCMFileDuration - mAudioMixSettings->beginCutMs; // Limit the file length also mBGAudioPCMFileTrimmedLength = (( (int64_t)(mBGAudioPCMFileDuration * mAudioMixSettings->uiSamplingFrequency) * mAudioMixSettings->uiNbChannels) * sizeof(M4OSA_UInt16)) / 1000; } else if ((mAudioMixSettings->beginCutMs != 0) && (mAudioMixSettings->endCutMs != 0)) { // End time itself the file duration mBGAudioPCMFileDuration = mAudioMixSettings->endCutMs - mAudioMixSettings->beginCutMs; // Limit the file length also mBGAudioPCMFileTrimmedLength = (( (int64_t)(mBGAudioPCMFileDuration * mAudioMixSettings->uiSamplingFrequency) * mAudioMixSettings->uiNbChannels) * sizeof(M4OSA_UInt16)) / 1000; /*make to sec from ms*/ } ALOGV("VideoEditorAudioPlayer: file duration recorded : %lld", mBGAudioPCMFileDuration); } // Last played location to be seeked at for next media item if ( result == M4NO_ERROR ) { ALOGV("VideoEditorAudioPlayer::mBGAudioStoryBoardSkimTimeStamp %lld", mBGAudioStoryBoardSkimTimeStamp); ALOGV("VideoEditorAudioPlayer::uiAddCts %d", mAudioMixSettings->uiAddCts); if (mBGAudioStoryBoardSkimTimeStamp >= mAudioMixSettings->uiAddCts) { startTime = (mBGAudioStoryBoardSkimTimeStamp - mAudioMixSettings->uiAddCts); } else { // do nothing } ALOGV("VideoEditorAudioPlayer::startTime %d", startTime); seekTimeStamp = 0; if (startTime) { if (startTime >= mBGAudioPCMFileDuration) { // The BG track should be looped and started again if (mAudioMixSettings->bLoop) { // Add begin cut time to the mod value seekTimeStamp = ((startTime%mBGAudioPCMFileDuration) + mAudioMixSettings->beginCutMs); }else { // Looping disabled, donot do BT Mix , set to file end seekTimeStamp = (mBGAudioPCMFileDuration + mAudioMixSettings->beginCutMs); } }else { // BT still present , just seek to story board time seekTimeStamp = startTime + mAudioMixSettings->beginCutMs; } } else { seekTimeStamp = mAudioMixSettings->beginCutMs; } // Convert the seekTimeStamp to file location mBGAudioPCMFileOriginalSeekPoint = ( (int64_t)(mAudioMixSettings->beginCutMs) * mAudioMixSettings->uiSamplingFrequency * mAudioMixSettings->uiNbChannels * sizeof(M4OSA_UInt16))/ 1000 ; /*make to sec from ms*/ mBGAudioPCMFileSeekPoint = ((int64_t)(seekTimeStamp) * mAudioMixSettings->uiSamplingFrequency * mAudioMixSettings->uiNbChannels * sizeof(M4OSA_UInt16))/ 1000 ; } } // 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); mFirstBufferResult = mSource->read(&mFirstBuffer); 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(!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)); success = format->findInt32(kKeySampleRate, &mSampleRate); CHECK(success); int32_t numChannels; success = format->findInt32(kKeyChannelCount, &numChannels); CHECK(success); if (mAudioSink.get() != NULL) { status_t err = mAudioSink->open( mSampleRate, numChannels, CHANNEL_MASK_USE_CHANNEL_ORDER, AUDIO_FORMAT_PCM_16_BIT, DEFAULT_AUDIOSINK_BUFFERCOUNT, &VideoEditorAudioPlayer::AudioSinkCallback, this); if (err != OK) { if (mFirstBuffer != NULL) { mFirstBuffer->release(); mFirstBuffer = NULL; } if (!sourceAlreadyStarted) { mSource->stop(); } return err; } mLatencyUs = (int64_t)mAudioSink->latency() * 1000; mFrameSize = mAudioSink->frameSize(); mAudioSink->start(); } else { mAudioTrack = new AudioTrack( AUDIO_STREAM_MUSIC, mSampleRate, AUDIO_FORMAT_PCM_16_BIT, audio_channel_out_mask_from_count(numChannels), 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; return OK; }
static uint32_t out_get_channels(const struct audio_stream *stream) { const struct stream_out *out = (const struct stream_out*)stream; return audio_channel_out_mask_from_count(out->hal_channel_count); }