Androidにオーディオタイプとデュアルオーディオ出力を追加
androidは多くのオーディオタイプを定義し、native層の下に完全に定義されている.systemcoreincludesystemaudio.hファイル内:
Androidは異なるオーディオタイプに異なるルーティングを設定し、ルーティングに応じて異なる出力装置を選択する.これがandroidのオーディオ管理ポリシーである.
例えば、アプリケーション層からの音声タイプはSTREAM_であるMUSICは、ヘッドホンを差し込むと、このタイプの音がspeakerからヘッドホンに切り替わり、オーディオタイプがSTREAM_であればRINGは、ヘッドホンとspeakerから同時に伝わります.
AudioPolicyManager.hでは、いくつかのルーティングポリシーが定義されています.
出力デバイスは、主にAudioPolicyManagerのgetDeviceForStrategyメソッドにルーティングに従って選択されるため、カスタムオーディオタイプを増やしたり、getDeviceForStrategyのオーディオポリシーを変更したりすることで、androidのオーディオ管理ポリシーをカスタマイズすることができます.
例えば、androidスマートテレビに応用してデュアルオーディオ出力を実現する機能を実現する.すなわち、ユーザがテレビを見ている間に音楽を聴くことができ、テレビの音がスピーカから出力され、音楽の音がイヤホンから出力される.ここではusbイヤホン装置を選択した.
実現の原理はひとつのオーディオのタイプを増加して音楽の応用のために使用して、2重のオーディオの出力機能を開ける時、この応用の入ってくるオーディオのタイプは私達のためにカスタマイズして、このオーディオのタイプのためにusb audio設備を選んで、同時に、普通のtvと第三者の応用はSTREAM_を使いますMUSICタイプ、このオーディオタイプはルーティングポリシーに対応するSTRATEGY_MEDIAタイプは、デュアルオーディオ機能がオンのときにこのポリシーのためにspeakerデバイスを強制的に選択することで、デュアルオーディオ機能を実現します.
/* Audio stream types */
typedef enum {
/* These values must kept in sync with
* frameworks/base/media/java/android/media/AudioSystem.java
*/
AUDIO_STREAM_DEFAULT = -1,
AUDIO_STREAM_MIN = 0,
AUDIO_STREAM_VOICE_CALL = 0,
AUDIO_STREAM_SYSTEM = 1,
AUDIO_STREAM_RING = 2,
AUDIO_STREAM_MUSIC = 3,
AUDIO_STREAM_ALARM = 4,
AUDIO_STREAM_NOTIFICATION = 5,
AUDIO_STREAM_BLUETOOTH_SCO = 6,
AUDIO_STREAM_ENFORCED_AUDIBLE = 7, /* Sounds that cannot be muted by user
* and must be routed to speaker
*/
AUDIO_STREAM_DTMF = 8,
AUDIO_STREAM_TTS = 9, /* Transmitted Through Speaker.
* Plays over speaker only, silent on other devices.
*/
AUDIO_STREAM_USB_HEADSET = 10, /* For accessibility talk back prompts */
AUDIO_STREAM_REROUTING = 11, /* For dynamic policy output mixes */
AUDIO_STREAM_PATCH = 12, /* For internal audio flinger tracks. Fixed volume */
AUDIO_STREAM_USB_MIC = 13,
AUDIO_STREAM_ACCESSIBILITY = 14,
AUDIO_STREAM_PUBLIC_CNT = AUDIO_STREAM_USB_MIC + 1,
AUDIO_STREAM_CNT = AUDIO_STREAM_ACCESSIBILITY + 1,
} audio_stream_type_t;
Androidは異なるオーディオタイプに異なるルーティングを設定し、ルーティングに応じて異なる出力装置を選択する.これがandroidのオーディオ管理ポリシーである.
例えば、アプリケーション層からの音声タイプはSTREAM_であるMUSICは、ヘッドホンを差し込むと、このタイプの音がspeakerからヘッドホンに切り替わり、オーディオタイプがSTREAM_であればRINGは、ヘッドホンとspeakerから同時に伝わります.
AudioPolicyManager.hでは、いくつかのルーティングポリシーが定義されています.
enum routing_strategy {
STRATEGY_MEDIA,
STRATEGY_PHONE,
STRATEGY_SONIFICATION,
STRATEGY_SONIFICATION_RESPECTFUL,
STRATEGY_DTMF,
STRATEGY_ENFORCED_AUDIBLE,
STRATEGY_TRANSMITTED_THROUGH_SPEAKER,
STRATEGY_ACCESSIBILITY,
STRATEGY_REROUTING,
STRATEGY_USB_HEADST,
NUM_STRATEGIES
};
出力デバイスは、主にAudioPolicyManagerのgetDeviceForStrategyメソッドにルーティングに従って選択されるため、カスタムオーディオタイプを増やしたり、getDeviceForStrategyのオーディオポリシーを変更したりすることで、androidのオーディオ管理ポリシーをカスタマイズすることができます.
例えば、androidスマートテレビに応用してデュアルオーディオ出力を実現する機能を実現する.すなわち、ユーザがテレビを見ている間に音楽を聴くことができ、テレビの音がスピーカから出力され、音楽の音がイヤホンから出力される.ここではusbイヤホン装置を選択した.
実現の原理はひとつのオーディオのタイプを増加して音楽の応用のために使用して、2重のオーディオの出力機能を開ける時、この応用の入ってくるオーディオのタイプは私達のためにカスタマイズして、このオーディオのタイプのためにusb audio設備を選んで、同時に、普通のtvと第三者の応用はSTREAM_を使いますMUSICタイプ、このオーディオタイプはルーティングポリシーに対応するSTRATEGY_MEDIAタイプは、デュアルオーディオ機能がオンのときにこのポリシーのためにspeakerデバイスを強制的に選択することで、デュアルオーディオ機能を実現します.
case STRATEGY_USB_HEADST:
case STRATEGY_MEDIA: {
char propDoubOutput[PROPERTY_VALUE_MAX];
property_get("audio.output.double_output",propDoubOutput,"null");
if ((strcmp(propDoubOutput,"1") == 0) && strategy == STRATEGY_USB_HEADST) {
device = mAvailableOutputDevices.types() & AUDIO_DEVICE_OUT_USB_DEVICE;
if (device != AUDIO_DEVICE_NONE) {
device = AUDIO_DEVICE_OUT_USB_DEVICE;
}else{
ALOGE("getDeviceForStrategy() no device found for STRATEGY_USB_HEADST");
}
} else {
uint32_t device2 = AUDIO_DEVICE_NONE;
if (strategy != STRATEGY_SONIFICATION) {
// no sonification on remote submix (e.g. WFD)
if (mAvailableOutputDevices.getDevice(AUDIO_DEVICE_OUT_REMOTE_SUBMIX, String8("0")) != 0) {
device2 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
}
}
STRATEGY_USB_HEADST ,"audio.output.double_output" , , ,STRATEGY_USB_HEADST MEDIA , , STRATEGY_USB_HEADST usbaudio ,device = AUDIO_DEVICE_OUT_USB_DEVICE; MEDIA speaker :
property_get("audio.output.double_output",propDoubOutput,"null");
if (strcmp(propDoubOutput, "1") ==0) {
device = AUDIO_DEVICE_OUT_AUX_DIGITAL |AUDIO_DEVICE_OUT_SPEAKER;
} else {
device |= device2;
}
デバイスを する は に するが、jがava からframework までこのオーディオタイプのオンプロセスであることが である. には,この オーディオタイプの は に できる. にaudiotrackのjava からnative への び し を すればよい.java audiomangerとaudiosystemにカスタムオーディオタイプを した 、audiotrackの を ると、5.1は4.4に1つのAudioAttributesを し、これは から わったstreamTypeを1 パッケージし、 たちの をより にし、 streamを じてtype private int mUsage=USAGE_UNKNOWN;
およびprivate int mContentType=CONTENT_TYPE_UNKNOWNの2つのタイプは、native AudioTrackに きました.cppのset では:status_t AudioTrack::set(
audio_stream_type_t streamType,
uint32_t sampleRate,
audio_format_t format,
audio_channel_mask_t channelMask,
size_t frameCount,
audio_output_flags_t flags,
callback_t cbf,
void* user,
uint32_t notificationFrames,
const sp& sharedBuffer,
bool threadCanCallJava,
int sessionId,
transfer_type transferType,
const audio_offload_info_t *offloadInfo,
int uid,
pid_t pid,
const audio_attributes_t* pAttributes)
{
ALOGI("set(): %p streamType %d, sampleRate %u, format %#x, channelMask %#x, frameCount %zu, "
"flags #%x, notificationFrames %u, sessionId %d, transferType %d",
this,streamType, sampleRate, format, channelMask, frameCount, flags, notificationFrames,
sessionId, transferType);
switch (transferType) {
case TRANSFER_DEFAULT:
if (sharedBuffer != 0) {
transferType = TRANSFER_SHARED;
} else if (cbf == NULL || threadCanCallJava) {
transferType = TRANSFER_SYNC;
} else {
transferType = TRANSFER_CALLBACK;
}
break;
case TRANSFER_CALLBACK:
if (cbf == NULL || sharedBuffer != 0) {
ALOGE("Transfer type TRANSFER_CALLBACK but cbf == NULL || sharedBuffer != 0");
return BAD_VALUE;
}
break;
case TRANSFER_OBTAIN:
case TRANSFER_SYNC:
if (sharedBuffer != 0) {
ALOGE("Transfer type TRANSFER_OBTAIN but sharedBuffer != 0");
return BAD_VALUE;
}
break;
case TRANSFER_SHARED:
if (sharedBuffer == 0) {
ALOGE("Transfer type TRANSFER_SHARED but sharedBuffer == 0");
return BAD_VALUE;
}
break;
default:
ALOGE("Invalid transfer type %d", transferType);
return BAD_VALUE;
}
mSharedBuffer = sharedBuffer;
mTransfer = transferType;
ALOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(),
sharedBuffer->size());
ALOGV("set() streamType %d frameCount %zu flags %04x", streamType, frameCount, flags);
AutoMutex lock(mLock);
// invariant that mAudioTrack != 0 is true only after set() returns successfully
if (mAudioTrack != 0) {
ALOGE("Track already in use");
return INVALID_OPERATION;
}
// handle default values first.
if (streamType == AUDIO_STREAM_DEFAULT) {
streamType = AUDIO_STREAM_MUSIC;
}
if (pAttributes == NULL) {
if (uint32_t(streamType) >= AUDIO_STREAM_PUBLIC_CNT) {
ALOGE("Invalid stream type %d", streamType);
return BAD_VALUE;
}
mStreamType = streamType;
} else {
// stream type shouldn't be looked at, this track has audio attributes
memcpy(&mAttributes, pAttributes, sizeof(audio_attributes_t));
ALOGV("Building AudioTrack with attributes: usage=%d content=%d flags=0x%x tags=[%s]",
mAttributes.usage, mAttributes.content_type, mAttributes.flags, mAttributes.tags);
mStreamType = AUDIO_STREAM_DEFAULT;
}
// these below should probably come from the audioFlinger too...
if (format == AUDIO_FORMAT_DEFAULT) {
format = AUDIO_FORMAT_PCM_16_BIT;
}
......
mStreamType=AUDIO_を るSTREAM_DEFAULT; stream_typeは-1に されており、 でデバイスを する にstream_に がなくなりました.typeではなくaudio_attributes_tこの を し、この の を てみましょう.typedef struct {
audio_content_type_t content_type;
audio_usage_t usage;
audio_source_t source;
audio_flags_mask_t flags;
char tags[AUDIO_ATTRIBUTES_TAGS_MAX_SIZE]; /* UTF8 */
} audio_attributes_t;
のmUsageとmContentTypeです.
AudioPolicyManagerに って、getoutputForAttrインタフェースを て、インタフェースを して、 に したgetDeviceForStrategyを び してデバイスを します.......
ALOGV("getOutputForAttr() usage=%d, content=%d, tag=%s flags=%08x",
attributes.usage, attributes.content_type, attributes.tags, attributes.flags);
routing_strategy strategy = (routing_strategy) getStrategyForAttr(&attributes);
audio_devices_t device = getDeviceForStrategy(strategy, false /*fromCache*/);
......
だから でstream_typeとAudioAttributesの ができて、この は に じて、2つのオーディオ の は しました.