/*
* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <condition_variable>
#include <mutex>
#include "audio_errors.h"
#include "format_convert_util.h"
#import "audio_renderer_impl.h"
#import "audio_manager_impl.h"
#define QUEUE_BUFFER_SIZE 2
#define MIN_STREAM_VOLUME 0.0
#define MAX_STREAM_VOLUME 1.0
#define WRITE_BUFFER_TIMEOUT_IN_MS 200
#define MIN_BUFFER_SIZE 20000
#define ALLOC_BUFFER_SIZE 200000
#pragma mark - AudioRendererImpl implementation
@implementation AudioRendererImpl
{
OHOS::AudioStandard::AudioRendererOptions rendererOptions_;
AudioStreamBasicDescription audioDescription_;
AudioQueueRef audioQueue_;
AudioQueueTimelineRef timeLine_;
AudioQueueBufferRef audioQueueBuffers_[QUEUE_BUFFER_SIZE];
BOOL audioQueueUsed_[QUEUE_BUFFER_SIZE];
dispatch_queue_t playQueue_;
uint8_t tempBuffer_[MIN_BUFFER_SIZE];
OHOS::AudioStandard::RendererState playState_;
std::mutex writeBufferLock_;
std::condition_variable writeThreadCv_;
bool isWrited_;
OHOS::AudioStandard::InterruptMode interruptMode_;
std::shared_ptr<OHOS::AudioStandard::AudioRendererCallback> stateCallback_;
std::shared_ptr<OHOS::AudioStandard::AudioRendererWriteCallback> writeCallback_;
std::shared_ptr<OHOS::AudioStandard::AudioRendererDeviceChangeCallback> deviceCallback_;
std::shared_ptr<OHOS::AudioStandard::AudioRendererOutputDeviceChangeCallback> deviceWithInfoCallback_;
OHOS::AudioStandard::AudioRenderMode renderMode_;
std::mutex writeCbMutex_;
}
- (void)initChannelLayout:(const OHOS::AudioStandard::AudioChannelLayout)channelLayout
{
AudioChannelLayout acl;
bool isValid = ConvertChannelLayoutFromOh(channelLayout, acl);
if (isValid) {
NSLog(@"AudioChannelLayout.mChannelLayoutTag = %d", acl.mChannelLayoutTag);
OSStatus status = AudioQueueSetProperty(audioQueue_, kAudioQueueProperty_ChannelLayout, &acl, sizeof(acl));
if (status != noErr) {
NSLog(@"Failed to AudioQueueSetProperty kAudioQueueProperty_ChannelLayout: status = %d", status);
}
} else {
NSLog(@"Unknown channel layout.");
}
}
- (void)initWithSampleRate:(const OHOS::AudioStandard::AudioRendererOptions &)rendererOptions
{
NSLog(@"initWithSampleRate samplingRate = %d, channels = %d, format = %d",
rendererOptions.streamInfo.samplingRate, rendererOptions.streamInfo.channels,
rendererOptions.streamInfo.format);
renderMode_ = OHOS::AudioStandard::RENDER_MODE_NORMAL;
rendererOptions_ = rendererOptions;
playQueue_ = dispatch_queue_create("audio queue play queue", DISPATCH_QUEUE_SERIAL);
playState_ = OHOS::AudioStandard::RENDERER_NEW;
ConvertStreamInfoFromOh(rendererOptions.streamInfo, audioDescription_);
NSLog(@"AudioStreamBasicDescription mSampleRate = %f, mFormatID = %u, mFormatFlags = %u, \
mChannelsPerFrame = %u, mFramesPerPacket = %u, mBitsPerChannel = %u, mBytesPerFrame = %u, \
mBytesPerPacket = %u",
audioDescription_.mSampleRate, audioDescription_.mFormatID, audioDescription_.mFormatFlags,
audioDescription_.mChannelsPerFrame, audioDescription_.mFramesPerPacket, audioDescription_.mBitsPerChannel,
audioDescription_.mBytesPerFrame, audioDescription_.mBytesPerPacket);
[self setupAudioQueue];
[self initChannelLayout:rendererOptions.streamInfo.channelLayout];
UInt32 enable = 1;
OSStatus status = AudioQueueSetProperty(audioQueue_, kAudioQueueProperty_EnableTimePitch, &enable, sizeof(enable));
if (status != noErr) {
NSLog(@"Failed to AudioQueueSetProperty kAudioQueueProperty_EnableTimePitch: status = %d", status);
}
UInt32 algorithm = kAudioQueueTimePitchAlgorithm_Spectral;
status = AudioQueueSetProperty(audioQueue_, kAudioQueueProperty_TimePitchAlgorithm, &algorithm, sizeof(algorithm));
if (status != noErr) {
NSLog(@"Failed to AudioQueueSetProperty kAudioQueueProperty_TimePitchAlgorithm: status = %d", status);
}
playState_ = OHOS::AudioStandard::RENDERER_PREPARED;
isWrited_ = false;
interruptMode_ = OHOS::AudioStandard::SHARE_MODE;
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
AudioManagerImpl *managerImpl = [AudioManagerImpl sharedInstance];
if (managerImpl) {
if ([managerImpl getAllInterruptMode] == OHOS::AudioStandard::SHARE_MODE &&
[audioSession.category isEqualToString:AVAudioSessionCategorySoloAmbient]) {
NSLog(@"old category = %@",audioSession.category);
[audioSession setCategory:AVAudioSessionCategoryAmbient error:nil];
NSLog(@"new category = %@",audioSession.category);
[audioSession setActive:YES error:nil];
[managerImpl updateCategory:audioSession.category options:audioSession.categoryOptions];
}
}
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleRouteChange:)
name:AVAudioSessionRouteChangeNotification
object:audioSession];
}
- (int32_t)getRendererInfo:(OHOS::AudioStandard::AudioRendererInfo &)rendererInfo
{
rendererInfo = rendererOptions_.rendererInfo;
return OHOS::AudioStandard::SUCCESS;
}
- (int32_t)getStreamInfo:(OHOS::AudioStandard::AudioStreamInfo &)streamInfo
{
if (playState_ != OHOS::AudioStandard::RENDERER_RELEASED) {
streamInfo = rendererOptions_.streamInfo;
return OHOS::AudioStandard::SUCCESS;
} else {
return OHOS::AudioStandard::ERR_OPERATION_FAILED;
}
}
- (int32_t)setRendererCallback:(const std::shared_ptr<OHOS::AudioStandard::AudioRendererCallback> &)callback
{
stateCallback_ = callback;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleAudioSessionInterruption:)
name:AVAudioSessionInterruptionNotification
object:nil];
return OHOS::AudioStandard::SUCCESS;
}
- (int32_t)setRenderMode:(OHOS::AudioStandard::AudioRenderMode)renderMode
{
NSLog(@"SetRenderMode to %s", renderMode == OHOS::AudioStandard::AudioRenderMode::RENDER_MODE_NORMAL ?
"RENDER_MODE_NORMAL" : "RENDER_MODE_CALLBACK");
if (renderMode_ == renderMode) {
return OHOS::AudioStandard::SUCCESS;
}
// renderMode_ is inited as RENDER_MODE_NORMAL, can only be set to RENDER_MODE_CALLBACK.
if (renderMode_ == OHOS::AudioStandard::RENDER_MODE_CALLBACK &&
renderMode == OHOS::AudioStandard::RENDER_MODE_NORMAL) {
NSLog(@"SetRenderMode from callback to normal is not supported.");
return OHOS::AudioStandard::ERR_INCORRECT_MODE;
}
// state check
if (playState_ != OHOS::AudioStandard::RENDERER_PREPARED && playState_ != OHOS::AudioStandard::RENDERER_NEW) {
NSLog(@"SetRenderMode failed. invalid state");
return OHOS::AudioStandard::ERR_ILLEGAL_STATE;
}
renderMode_ = renderMode;
dispatch_async(playQueue_, ^{
int32_t tryCount = QUEUE_BUFFER_SIZE;
while (tryCount > 0) {
isWrited_ = false;
writeCallback_->OnWriteData(MIN_BUFFER_SIZE);
std::unique_lock<std::mutex> lk(writeBufferLock_);
writeThreadCv_.wait_for(lk, std::chrono::milliseconds(WRITE_BUFFER_TIMEOUT_IN_MS),
[self]{ return isWrited_; });
NSLog(@"queue isWrited_:%d", isWrited_);
if (isWrited_) {
tryCount--;
}
}
});
return OHOS::AudioStandard::SUCCESS;
}
- (int32_t)setRendererWriteCallback:(const std::shared_ptr<OHOS::AudioStandard::AudioRendererWriteCallback> &)callback
{
if (renderMode_ != OHOS::AudioStandard::RENDER_MODE_CALLBACK) {
return OHOS::AudioStandard::ERR_INCORRECT_MODE;
NSLog(@"incorrect render mode");
}
std::lock_guard<std::mutex> lock(writeCbMutex_);
writeCallback_ = callback;
return OHOS::AudioStandard::SUCCESS;
}
- (int32_t)setRendererDeviceChangeCallback:
(const std::shared_ptr<OHOS::AudioStandard::AudioRendererDeviceChangeCallback> &)callback
{
deviceCallback_ = callback;
return OHOS::AudioStandard::SUCCESS;
}
- (int32_t)destroyRendererDeviceChangeCallback
{
deviceCallback_ = nil;
return OHOS::AudioStandard::SUCCESS;
}
- (int32_t)setRendererDeviceChangeWithInfoCallback:
(const std::shared_ptr<OHOS::AudioStandard::AudioRendererOutputDeviceChangeCallback> &)callback
{
deviceWithInfoCallback_ = callback;
return OHOS::AudioStandard::SUCCESS;
}
- (int32_t)destroyRendererDeviceChangeWithInfoCallback
{
deviceWithInfoCallback_ = nil;
return OHOS::AudioStandard::SUCCESS;
}
- (void)handleRouteChange:(NSNotification *)notification
{
NSDictionary *userInfo = notification.userInfo;
if (deviceCallback_) {
NSLog(@"OnStateChange");
OHOS::AudioStandard::AudioDeviceDescriptor deviceInfo;
[self getCurrentOutputDevices:deviceInfo];
deviceCallback_->OnStateChange(deviceInfo);
}
if (deviceWithInfoCallback_) {
NSLog(@"OnOutputDeviceChange");
NSInteger reason = [userInfo[AVAudioSessionRouteChangeReasonKey] integerValue];
NSLog(@"reason = %ld", reason);
OHOS::AudioStandard::AudioDeviceDescriptor deviceInfo;
[self getCurrentOutputDevices:deviceInfo];
OHOS::AudioStandard::AudioStreamDeviceChangeReason changeReason;
ConvertDeviceChangeReasonToOh(reason, changeReason);
deviceWithInfoCallback_->OnOutputDeviceChange(deviceInfo, changeReason);
}
AudioManagerImpl *managerImpl = [AudioManagerImpl sharedInstance];
if (managerImpl) {
[managerImpl updateRendererChangeInfos];
}
}
- (void)handleAudioSessionInterruption:(NSNotification *)notification
{
NSDictionary *userInfo = notification.userInfo;
AudioInterruption interruption;
interruption.interruptionType = [userInfo[AVAudioSessionInterruptionTypeKey] integerValue];
interruption.interruptionReason = [userInfo[AVAudioSessionInterruptionReasonKey] integerValue];
interruption.interruptionOption = [userInfo[AVAudioSessionInterruptionOptionKey] integerValue];
OHOS::AudioStandard::InterruptEvent interruptEvent;
ConvertInterruptEventToOh(interruption, interruptEvent);
if(stateCallback_) {
stateCallback_->OnInterrupt(interruptEvent);
}
}
static void AudioPlayerAQInputCallback(void* inUserData,AudioQueueRef outQ, AudioQueueBufferRef outQB)
{
AudioRendererImpl* player = (__bridge AudioRendererImpl*)inUserData;
[player playerCallback:outQB];
}
- (void)setupAudioQueue
{
OSStatus status = AudioQueueNewOutput(&audioDescription_, AudioPlayerAQInputCallback,
(__bridge void*)self, nil, nil, 0, &audioQueue_);
if (status != noErr) {
NSLog(@"Failed to AudioQueueNewOutput: status = %d", status);
return;
}
for (int i = 0; i < QUEUE_BUFFER_SIZE; i++) {
status = AudioQueueAllocateBuffer(audioQueue_, ALLOC_BUFFER_SIZE, &audioQueueBuffers_[i]);
if (status != noErr) {
NSLog(@"Failed to AudioQueueAllocateBuffer: i = %d, status = %d", i, status);
}
}
status = AudioQueueCreateTimeline(audioQueue_, &timeLine_);
if(status != noErr) {
NSLog(@"Failed to AudioQueueCreateTimeline: status = %d", status);
}
}
- (void)playerCallback:(AudioQueueBufferRef)outQB
{
for (int i = 0; i < QUEUE_BUFFER_SIZE; i++) {
if (outQB == audioQueueBuffers_[i]) {
audioQueueUsed_[i] = NO;
NSLog(@"playerCallback buffer i = %d", i);
}
}
if (writeCallback_) {
writeCallback_->OnWriteData(MIN_BUFFER_SIZE);
}
}
- (AudioQueueBufferRef)getNotUsedBuffer
{
for (int i = 0; i < QUEUE_BUFFER_SIZE; i++) {
if (NO == audioQueueUsed_[i]) {
audioQueueUsed_[i] = YES;
NSLog(@"getNotUsedBuffer i = %d", i);
return audioQueueBuffers_[i];
}
}
return nil;
}
- (const int32_t)enqueue:(const OHOS::AudioStandard::BufferDesc &)bufDesc
{
std::unique_lock<std::mutex> lk(writeBufferLock_);
isWrited_ = true;
writeThreadCv_.notify_all();
AudioQueueBufferRef audioQueueBuffer = nil;
audioQueueBuffer = [self getNotUsedBuffer];
if (audioQueueBuffer == nil) {
NSLog(@"Find't no used buffer");
return OHOS::AudioStandard::ERR_WRITE_BUFFER;
}
audioQueueBuffer->mAudioDataByteSize = bufDesc.dataLength;
Byte* audiodata = (Byte*)audioQueueBuffer->mAudioData;
memcpy(audiodata, bufDesc.buffer, bufDesc.dataLength);
OSStatus status = AudioQueueEnqueueBuffer(audioQueue_, audioQueueBuffer, 0, nil);
if (status != 0) {
NSLog(@"Failed to AudioQueueEnqueueBuffer: status = %d", status);
return ConvertErrorToOh(status);
} else {
return OHOS::AudioStandard::SUCCESS;
}
}
- (const int32_t)getBufferDesc:(OHOS::AudioStandard::BufferDesc &)bufDesc
{
bufDesc.buffer = tempBuffer_;
bufDesc.bufLength = MIN_BUFFER_SIZE;
bufDesc.dataLength = MIN_BUFFER_SIZE;
return OHOS::AudioStandard::SUCCESS;
}
- (void)transferState:(OHOS::AudioStandard::RendererState) playState
{
NSLog(@"transferState oldState = %d, newState = %d", playState_, playState);
OHOS::AudioStandard::RendererState oldState = playState_;
playState_ = playState;
if (oldState != playState_) {
if (stateCallback_) {
stateCallback_->OnStateChange(playState);
}
AudioManagerImpl *managerImpl = [AudioManagerImpl sharedInstance];
if (managerImpl) {
[managerImpl updateRendererChangeInfos];
}
}
}
- (const OHOS::AudioStandard::RendererState) getStatus
{
NSLog(@"getStatus playState_:%d", playState_);
return playState_;
}
- (bool)start
{
if (audioQueue_ != nil) {
if (!((playState_ == OHOS::AudioStandard::RENDERER_PREPARED) ||
(playState_ == OHOS::AudioStandard::RENDERER_STOPPED) ||
(playState_ == OHOS::AudioStandard::RENDERER_PAUSED))) {
NSLog(@"Start failed. Illegal state:%d", playState_);
return false;
}
OSStatus status = AudioQueueStart(audioQueue_, nil);
if (status != noErr) {
NSLog(@"Failed to AudioQueueStart: status = %d", status);
return false;
}
[self transferState:OHOS::AudioStandard::RENDERER_RUNNING];
return true;
} else {
return false;
}
}
- (bool)stop
{
if (audioQueue_ != nil) {
if (!((playState_ == OHOS::AudioStandard::RENDERER_RUNNING) ||
(playState_ == OHOS::AudioStandard::RENDERER_PAUSED))) {
NSLog(@"State of stream is not running. Illegal state:%d", playState_);
return false;
}
OSStatus status = AudioQueueStop(audioQueue_, true);
if (status != noErr) {
NSLog(@"Failed to AudioQueueStop: status = %d", status);
return false;
}
[self transferState:OHOS::AudioStandard::RENDERER_STOPPED];
return true;
} else {
return false;
}
}
- (bool)drain
{
if (playState_ != OHOS::AudioStandard::RENDERER_RUNNING) {
NSLog(@"State is not RUNNING. Illegal state:%d", playState_);
return false;
}
if (audioQueue_ != nil) {
OSStatus status = AudioQueueReset(audioQueue_);
if (status != noErr) {
NSLog(@"Failed to AudioQueueReset: status = %d", status);
return false;
}
return true;
} else {
return false;
}
}
- (bool)flush
{
if (!((playState_ == OHOS::AudioStandard::RENDERER_RUNNING) ||
(playState_ == OHOS::AudioStandard::RENDERER_PAUSED) ||
(playState_ == OHOS::AudioStandard::RENDERER_STOPPED))) {
NSLog(@"State is not RUNNING. Illegal state:%d", playState_);
return false;
}
if (audioQueue_ != nil) {
OSStatus status = AudioQueueFlush(audioQueue_);
if (status != noErr) {
NSLog(@"Failed to AudioQueueFlush: %d", status);
return false;
}
return true;
} else {
return false;
}
}
- (bool)pause
{
if (audioQueue_ != nil) {
if (playState_ != OHOS::AudioStandard::RENDERER_RUNNING) {
NSLog(@"State of stream is not running. Illegal state:%d", playState_);
return false;
}
OSStatus status = AudioQueuePause(audioQueue_);
if (status != noErr) {
NSLog(@"Failed to AudioQueuePause: %d", status);
return false;
}
[self transferState:OHOS::AudioStandard::RENDERER_PAUSED];
return true;
} else {
return false;
}
}
- (bool)releaseRenderer
{
std::unique_lock<std::mutex> lk(writeBufferLock_);
if (playState_ == OHOS::AudioStandard::RENDERER_RELEASED) {
NSLog(@"Already released, do nothing.");
return false;
}
if (audioQueue_ != nil) {
OSStatus status = AudioQueueStop(audioQueue_, true);
if (status != noErr) {
NSLog(@"Failed to AudioQueueStop: %d", status);
return false;
}
for (int i = 0; i < QUEUE_BUFFER_SIZE; i++) {
status = AudioQueueFreeBuffer(audioQueue_, audioQueueBuffers_[i]);
if (status != noErr) {
NSLog(@"Failed to AudioQueueFreeBuffer: i = %d, status = %d", i, status);
return false;
}
audioQueueBuffers_[i] = nil;
}
status = AudioQueueDispose(audioQueue_, true);
if (status != noErr) {
NSLog(@"Failed to AudioQueueDispose: status = %d", status);
return false;
}
audioQueue_ = nil;
}
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:AVAudioSessionRouteChangeNotification
object:audioSession];
deviceCallback_ = nil;
deviceWithInfoCallback_ = nil;
[self transferState:OHOS::AudioStandard::RENDERER_RELEASED];
return true;
}
- (bool)getAudioTime:(OHOS::AudioStandard::Timestamp &)time
{
AudioTimeStamp timeStamp;
OSStatus status = AudioQueueGetCurrentTime(audioQueue_, timeLine_, &timeStamp, nil);
if (status != noErr) {
NSLog(@"Failed to AudioQueueGetCurrentTime: status = %d", status);
return false;
}
time.time.tv_nsec = timeStamp.mSampleTime * SEC_TO_NANOSECOND / audioDescription_.mSampleRate;
time.time.tv_sec = 0;
NSLog(@"tv_nsec = %lu", time.time.tv_nsec);
return true;
}
- (int32_t)getAudioStreamId:(uint32_t &)sessionID
{
if(audioQueue_ != nil) {
sessionID = reinterpret_cast<uintptr_t>(audioQueue_);
return OHOS::AudioStandard::SUCCESS;
} else {
return OHOS::AudioStandard::ERR_ILLEGAL_STATE;
}
}
- (int32_t)getBufferSize:(size_t &)bufferSize
{
if(audioQueue_ != nil) {
bufferSize = MIN_BUFFER_SIZE;
return OHOS::AudioStandard::SUCCESS;
} else {
return OHOS::AudioStandard::ERR_ILLEGAL_STATE;
}
}
- (int32_t)setSpeed:(float)speed
{
OSStatus status = AudioQueueSetParameter(audioQueue_, kAudioQueueParam_PlayRate, speed);
if (status != noErr) {
NSLog(@"Failed to AudioQueueSetParameter kAudioQueueParam_PlayRate: status = %d", status);
return ConvertErrorToOh(status);
} else {
return OHOS::AudioStandard::SUCCESS;
}
}
- (float)getSpeed
{
float speed;
OSStatus status = AudioQueueGetParameter(audioQueue_, kAudioQueueParam_PlayRate, &speed);
if (status != noErr) {
NSLog(@"Failed to AudioQueueGetParameter kAudioQueueParam_PlayRate: status = %d", status);
}
return speed;
}
- (int32_t)setVolume:(float)volume
{
OSStatus status = AudioQueueSetParameter(audioQueue_, kAudioQueueParam_Volume, volume);
if (status != noErr) {
NSLog(@"Failed to AudioQueueSetParameter kAudioQueueParam_Volume: status = %d", status);
return ConvertErrorToOh(status);
} else {
return OHOS::AudioStandard::SUCCESS;
}
}
- (float)getMinStreamVolume
{
return MIN_STREAM_VOLUME;
}
- (float)getMaxStreamVolume
{
return MAX_STREAM_VOLUME;
}
- (int32_t)getCurrentOutputDevices:(OHOS::AudioStandard::AudioDeviceDescriptor &)deviceInfo
{
if (playState_ != OHOS::AudioStandard::RENDERER_RELEASED) {
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
AVAudioSessionRouteDescription *routeDescription = audioSession.currentRoute;
NSLog(@"routeDescription count = %lu",[routeDescription.outputs count]);
for (AVAudioSessionPortDescription *portDescription in routeDescription.outputs) {
deviceInfo.deviceRole_ = OHOS::AudioStandard::DeviceRole::OUTPUT_DEVICE;
ConvertDeviceTypeToOh(portDescription.portType, deviceInfo.deviceType_);
deviceInfo.deviceName_ = std::string([portDescription.portName UTF8String]);
deviceInfo.displayName_ = std::string([portDescription.UID UTF8String]);
NSLog(@"portType = %@, portName = %@, UID = %@", portDescription.portType, portDescription.portName,
portDescription.UID);
NSLog(@"channels = %lu",[portDescription.channels count]);
for (AVAudioSessionChannelDescription *channelDescription in portDescription.channels) {
deviceInfo.channelMasks_ |= channelDescription.channelLabel;
NSLog(@"channelName = %@, channelNumber = %lu, owningPortUID = %@, channelLabel = %u",
channelDescription.channelName,channelDescription.channelNumber,
channelDescription.owningPortUID, channelDescription.channelLabel);
}
deviceInfo.GetDeviceStreamInfo().samplingRate.insert(
static_cast<OHOS::AudioStandard::AudioSamplingRate>(audioSession.sampleRate));
NSLog(@"sampleRate = %f", audioSession.sampleRate);
}
}
return OHOS::AudioStandard::SUCCESS;
}
- (int32_t)setVolumeWithRamp:(float)volume rampTime:(int32_t)duration
{
NSLog(@"setVolumeWithRamp: volume = %f, duration(sec) = %d", volume, duration / SEC_TO_MILLISECOND);
OSStatus status = AudioQueueSetParameter(audioQueue_, kAudioQueueParam_VolumeRampTime, duration / SEC_TO_MILLISECOND);
if (status != noErr) {
NSLog(@"Failed to AudioQueueSetParameter kAudioQueueParam_VolumeRampTime: status = %d", status);
return ConvertErrorToOh(status);
}
status = AudioQueueSetParameter(audioQueue_, kAudioQueueParam_Volume, volume);
if (status != noErr) {
NSLog(@"Failed to AudioQueueSetParameter kAudioQueueParam_Volume: status = %d", status);
return ConvertErrorToOh(status);
} else {
return OHOS::AudioStandard::SUCCESS;
}
}
- (void)setInterruptMode:(OHOS::AudioStandard::InterruptMode)mode
{
if (mode == OHOS::AudioStandard::SHARE_MODE) {
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
if ([audioSession.category isEqualToString:AVAudioSessionCategorySoloAmbient]) {
NSLog(@"old category = %@",audioSession.category);
[audioSession setCategory:AVAudioSessionCategoryAmbient error:nil];
NSLog(@"new category = %@",audioSession.category);
[audioSession setActive:YES error:nil];
interruptMode_ = mode;
AudioManagerImpl *managerImpl = [AudioManagerImpl sharedInstance];
if (managerImpl) {
[managerImpl updateCategory:audioSession.category options:audioSession.categoryOptions];
}
}
} else if (mode == OHOS::AudioStandard::INDEPENDENT_MODE) {
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
if ([audioSession.category isEqualToString:AVAudioSessionCategoryAmbient]) {
NSLog(@"old category = %@",audioSession.category);
[audioSession setCategory:AVAudioSessionCategorySoloAmbient error:nil];
NSLog(@"new category = %@",audioSession.category);
[audioSession setActive:YES error:nil];
interruptMode_ = mode;
AudioManagerImpl *managerImpl = [AudioManagerImpl sharedInstance];
if (managerImpl) {
[managerImpl updateCategory:audioSession.category options:audioSession.categoryOptions];
}
}
}
}
- (OHOS::AudioStandard::InterruptMode)getInterruptMode
{
return interruptMode_;
}
@end