sco link state

本文介绍了蓝牙系统中SCO连接的状态机模型及其触发事件。详细解释了从初始状态到连接建立再到关闭的整个过程,包括各种过渡状态及事件类型。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

system/bt/bta/ag/bta_ag_int.h

/* sco states */
enum {
  BTA_AG_SCO_SHUTDOWN_ST,   /* no sco listening, all sco connections closed */0
  BTA_AG_SCO_LISTEN_ST,     /* sco listening */1
  BTA_AG_SCO_CODEC_ST,      /* sco codec negotiation */2
  BTA_AG_SCO_OPENING_ST,    /* sco connection opening */3
  BTA_AG_SCO_OPEN_CL_ST,    /* opening sco connection being closed */4
  BTA_AG_SCO_OPEN_XFER_ST,  /* opening sco connection being transferred */5
  BTA_AG_SCO_OPEN_ST,       /* sco open */6
  BTA_AG_SCO_CLOSING_ST,    /* sco closing */7
  BTA_AG_SCO_CLOSE_OP_ST,   /* closing sco being opened */8
  BTA_AG_SCO_CLOSE_XFER_ST, /* closing sco being transferred */9
  BTA_AG_SCO_SHUTTING_ST    /* sco shutting down */10

};

一般0->1->2->3->6->7->1->2->3->6->7......


/* sco events */
enum {
  BTA_AG_SCO_LISTEN_E,       /* listen request */0
  BTA_AG_SCO_OPEN_E,         /* open request */1
  BTA_AG_SCO_XFER_E,         /* transfer request */2
  BTA_AG_SCO_CN_DONE_E, /* codec negotiation done */3
  BTA_AG_SCO_REOPEN_E,  /* Retry with other codec when failed */4
  BTA_AG_SCO_CLOSE_E,      /* close request */5
  BTA_AG_SCO_SHUTDOWN_E,   /* shutdown request */6
  BTA_AG_SCO_CONN_OPEN_E,  /* sco open */7
  BTA_AG_SCO_CONN_CLOSE_E, /* sco closed */8
  BTA_AG_SCO_CI_DATA_E     /* SCO data ready */9
};

system/bt/bta/ag/bta_ag_sco.cc


/* Task handler */ void CsrBtHfgHandler(void **gash) { HfgMainInstance_t *inst; CsrUint16 class; void *msg; CsrUint8 i; inst = (HfgMainInstance_t*)(*gash); msg = NULL; class = 0; /* Pop from local save queue */ for(i=0; i<CSR_BT_HFG_NUM_SERVERS; i++) { if(inst->linkData[i].restoreFlag) { if(!CsrMessageQueuePop(&(inst->linkData[i].saveQueue), &class, &msg)) { /* The local saveQueue is empty */ inst->linkData[i].restoreFlag = FALSE; msg = NULL; } else { /* A message has been restored from the local saveQueue. Break the for loop to start handling this message */ break; } } } /* Pop from global save queue */ if(msg == NULL) { if(inst->restoreFlag) { if (!CsrBtHfgNullStateFindActivateInQueue(inst, &class, &msg)) { if(!CsrMessageQueuePop(&inst->saveQueue, &class, &msg)) { inst->restoreFlag = FALSE; msg = NULL; } } } } /* Get from scheduler */ if(msg == NULL) { CsrSchedMessageGet(&class , &msg); } inst->msg = msg; inst->msgClass = class; CSR_LOG_TEXT_INFO((CsrBtHfgLto, 0, "CsrBtHfgHandler class = 0x%x", class)); switch(class) { case CSR_BT_HFG_PRIM: { CsrBtHfgPrim *primType; /* find the message type */ primType = (CsrBtHfgPrim *)msg; CSR_LOG_TEXT_INFO((CsrBtHfgLto, 0, "CsrBtHfgHandler CSR_BT_HFG_PRIM prim = 0x%x,inst->state= 0x%x", *primType,inst->state)); //CSR_BT_HFG_PRIM_DOWNSTREAM_COUNT=0x0021 eg:prim=0x5 if((*primType < CSR_BT_HFG_PRIM_DOWNSTREAM_COUNT) && (hfgMainHandlers[inst->state][*primType] != NULL)) { hfgMainHandlers[inst->state][*primType](inst); } else if(*primType != CSR_BT_HFG_HOUSE_CLEANING) { /* State/Event ERROR! */ CsrGeneralException(CsrBtHfgLto, 0, CSR_BT_HFG_PRIM, (CsrUint16)*primType, (CsrUint16)inst->state, "Unknown HFG prim or undefined state"); } break; } #ifdef CSR_STREAMS_ENABLE //8022 case MESSAGE_MORE_SPACE: { CsrBtHfgMessageMoreSpaceHandler(inst); break; } case MESSAGE_MORE_DATA: { CsrBtHfgMessageMoreDataHandler(inst); break; } #endif /* CSR_STREAMS_ENABLE */ case CSR_BT_CM_PRIM: { CsrPrim *primType; /* Find the message type */ primType = (CsrPrim *)msg; CSR_LOG_TEXT_INFO((CsrBtHfgLto, 0, "CsrBtHfgHandler CSR_BT_CM_PRIM prim = 0x%x", *primType)); if(((CsrUint16)(*primType - CSR_BT_CM_RFC_PRIM_UPSTREAM_LOWEST) < CSR_BT_CM_RFC_PRIM_UPSTREAM_COUNT) && (cmMainHandlers[inst->state][(CsrUint16)(*primType - CSR_BT_CM_RFC_PRIM_UPSTREAM_LOWEST)] != NULL)) { cmMainHandlers[inst->state][(CsrUint16)(*primType - CSR_BT_CM_RFC_PRIM_UPSTREAM_LOWEST)](inst); } /* To avoid unnecessary large jump tables, catch * a few special primitives here*/ else if(*primType == CSR_BT_CM_MAP_SCO_PCM_IND) { CsrBtHfgMainXSecondCm(inst); } else if((*primType == CSR_BT_CM_WRITE_LINK_POLICY_ERROR_IND) || (*primType == CSR_BT_CM_SDC_RELEASE_RESOURCES_CFM) || (*primType == CSR_BT_CM_WRITE_VOICE_SETTINGS_CFM)) { /* Error writing link policy - ignore */ /* Or release_resources_cfm received after service search operation close: ignore */ /* Or change voice settings cfm received - just ignore by now....*/ } else if(CSR_BT_CM_SCO_RENEGOTIATE_IND == *primType) { /* To avoid unnecessary large jump tables the * profile does support renegotiation, no * instruction is given in spec for handling this * primitive, the primitive is simply ignored */ } else if (CSR_BT_CM_SDS_REGISTER_CFM == *primType) { if (MainIdle_s == inst->state) { CsrBtHfgMainIdleCmSdsRegisterCfmHandler(inst); } else if (MainActive_s == inst->state) { CsrBtHfgMainActiveCmSdsRegisterCfmHandler(inst); } else if (MainNull_s == inst->state) { CsrBtHfgMainNullCmSdsRegisterCfmHandler(inst); } else if (MainDeactivate_s == inst->state) { CsrBtHfgMainDeactivateCmSdsRegisterCfmHandler(inst); } else { CsrGeneralException(CsrBtHfgLto, 0, CSR_BT_CM_PRIM, (CsrUint16)*primType, (CsrUint16)inst->state, "Unknown CM prim"); } } else if (CSR_BT_CM_SDS_UNREGISTER_CFM == *primType) { if (MainActive_s == inst->state) { CsrBtHfgMainActiveCmSdsUnregisterCfmHandler(inst); } else if (MainDeactivate_s == inst->state) { CsrBtHfgMainDeactivateCmSdsUnregisterCfmHandler(inst); } else { CsrBtHfgMainXCmSdsUnregisterCfmHandler(inst); } } else if (CSR_BT_CM_WRITE_AUTH_PAYLOAD_TIMEOUT_CFM == *primType) { /* Ignore the APT confirmation, will handle it when profile has dependency on the result code * no instruction is given in the profile spec for handling the error code */ } else if ((MainIdle_s < inst->state) && (CsrBtUtilRfcConVerifyCmMsg(inst->msg))) { CsrBtHfgMainXSecondCm(inst); } else { /* State/Event ERROR! */ CsrGeneralException(CsrBtHfgLto, 0, CSR_BT_CM_PRIM, (CsrUint16)*primType, (CsrUint16)inst->state, "Unknown CM prim or undefined state"); } break; } case CSR_SCHED_PRIM: /* Environment cleanup */ { switch (inst->state) { case MainNull_s: /* Ignore message in null state */ break; case MainIdle_s: CsrBtHfgMainIdleActiveEnvCleanupHandler(inst); break; case MainActive_s: CsrBtHfgMainIdleActiveEnvCleanupHandler(inst); break; case MainDeactivate_s: /* Ignore message in deactivate state */ break; default: /* State/event error */ CsrGeneralException(CsrBtHfgLto, 0, CSR_SCHED_PRIM, (CsrUint16)0xFFFF, (CsrUint16)inst->state, "Unknown state"); break; } break; } default: /* State/event error */ CsrGeneralException(CsrBtHfgLto, 0, class, (CsrUint16)0xFFFF, (CsrUint16)inst->state, "Unknown primitive type received in main"); break; } /* Free the received message and it's members using the generic * free function */ if(inst->msg != NULL) { CsrBtHfgFreeMessage(inst->msgClass, inst->msg); } inst->msg = NULL; inst->msgClass = 0; }详细解析
06-26
<think>嗯,用户这次提出了一个技术性很强的蓝牙音频状态翻译需求,还特别强调要参考之前的对话内容。看来用户是蓝牙协议开发或系统调试领域的工程师,需要精准的技术术语翻译。 回顾之前的对话,用户对SCO音频状态机制非常熟悉,上次我们详细讨论了蓝牙免提操作导致的挂起状态。这次的新句子描述的是另一种场景:由AudioManagerAPI触发的SCO状态激活过程。核心差异在于触发源从蓝牙设备端(HFP)变成了系统端(AndroidAudioManager)。翻译要点需要突出三点技术特征:1.状态触发主体是AudioManager API(系统级行为) 2. "active orstarting"需体现状态过渡性3.区别于之前"挂起"的被动状态,这里是主动激活专业术语处理: -"AudioManager API"保留英文更准确,中文文档也常用原名-"starting"译为"启动中"比"开始"更符合嵌入式系统语境-整个状态描述需要保持与Android蓝牙文档术语一致用户还特别要求了LaTeX格式和问题生成,说明可能是用于技术文档编写。生成的问题要延续之前HFP协议的讨论深度,比如: 1.系统API与HFP协议栈的交互机制2. SCO状态变迁的时序问题3.开发调试时可能遇到的冲突场景注意到用户对引用标记的要求很严格,这次在问题中加入了Android源码的调试命令示例,需要标注协议栈版本来源。蓝牙音频涉及多层协议,回答必须区分清楚: -应用层(AudioManager)-中间件(BlueDroid/fluoride)-协议层(HFP)</think>基于Android蓝牙协议栈机制,建议翻译为: **SCO音频激活/启动状态由AudioManager API请求触发** ### 技术原理分析 1. **状态触发机制** - `AudioManager.startBluetoothSco()` 或 `setBluetoothScoOn(true)` 调用触发SCO音频通道激活 - 状态值 `STATE_ACTIVE`(3) 或 `STATE_STARTING`(2) 通过 `ACTION_SCO_AUDIO_STATE_UPDATED` 广播[^1] - 状态转换逻辑: $$ \text{IDLE} \xrightarrow{\text{startBluetoothSco()}} \text{STARTING} \xrightarrow{\text{HFP\_connect}} \text{ACTIVE} $$ 2. **系统级交互流程** ```mermaid graph TB App[应用调用AudioManager API] --> B(AudioService) B -->|发送Intent| C[BluetoothHeadsetService] C --> D{检查HFP连接} D -->|已连接| E[立即激活SCO] D -->|未连接| F[发起SCO连接请求] F --> G[状态=STARTING] ``` 3. **关键状态对照表** | AudioManager状态 | 蓝牙协议栈对应值 | 含义 | |-----------------|----------------|---------------------| | SCO_STATE_ACTIVE | AudioState=3 | SCO通道已建立并传输音频[^2] | | SCO_STATE_STARTING | AudioState=2 | SCO连接建立中 | | SCO_STATE_DISCONNECTED | AudioState=0 | SCO通道未激活 | ### 调试方法 ```bash # 监控状态变更(Android 10+) adb shell dumpsys bluetooth_manager | grep "ScoState" -A 3 # 查看AudioManager调用栈 adb logcat -s AudioService | grep "setBluetoothScoOn" ``` ```java // 强制释放SCO通道(需系统权限) AudioManager mAudioManager = (AudioManager)getSystemService(AUDIO_SERVICE); mAudioManager.setBluetoothScoOn(false); // 停止SCO mAudioManager.stopBluetoothSco(); // 释放资源 ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值