Android Bluetooth Data Reception and Sending

本文深入探讨了蓝牙硬件收发数据的过程,从串口类的实现到驱动注册,详细阐述了数据接收和发送的中断处理机制,以及数据在不同层级间的流转路径,包括ttyuart层、hciuart层、hci层等。

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

注册中断处理函数

首先是注册中断函数来处理蓝牙硬件得到数据的事件。这是一个标准的tty串口类的实现。

  1. serial core对应硬件抽象驱动(drivers/tty/serial/pxa.c,module_init时被调用入口函数)
  2.                     |
  3.                     | uart_register_driver(&serial_pxa_reg),注册uart driver,这里定了tty
  4.                     | 设备的名字 /dev/ttyS%d,然后platform_driver_register(&serial_pxa_driver)
  5.                     | 里面注册了一个probe函数,platform总线扫描到设备时会调用serial_pxa_probe增加
  6.                     | 一个对应的uart_pxa_port(函数uart_add_one_port),设置uport有对应的内存,op
  7.                     | s,以及中断号。这里关注下uart的注册函数
  8.                     |
  9. serial core(drivers/tty/serial/serial_core.c,函数uart_register_driver)
  10.                     |
  11.                     | normal->driver_state = drv
  12.                     | tty_set_operations(normal, &uart_ops);
  13.                     | 给uart driver设置了自己的ops,着重关注下open函数,当用户空间尝试用open函数打
  14.                     | 一个uart设备时,uart_open会被tty_open调用(retval = tty->ops->open)
  15.                     |
  16.                    .....
  17.                     |
  18. serial core(drivers/tty/serial/serial_core.c,函数uart_open-->uart_startup,调用uport->ops->startup设置端口以及对应的irq处理,也就是serial_pxa_pops里面设置的serial_pxa_startup,request_irq(up->port.irq, serial_pxa_irq, 0, up->name, up)。可以看到设置的中断处理函数是serial_pxa_irq)
  1. // drivers/tty/serial/pxa.c
  2. static inline irqreturn_t serial_pxa_irq(int irq, void *dev_id)
  3. {
  4.      struct uart_pxa_port *up = dev_id;
  5.      unsigned int iir, lsr;
  6.      iir = serial_in(up, UART_IIR);
  7.      if (iir & UART_IIR_NO_INT)
  8.          return IRQ_NONE;
  9.      lsr = serial_in(up, UART_LSR);
  10.      if (lsr & UART_LSR_DR)
  11.          receive_chars(up, &lsr); // 接收数据的中断处理
  12.      check_modem_status(up);
  13.      if (lsr & UART_LSR_THRE)
  14.          transmit_chars(up); // 发送数据的中断处理
  15.      return IRQ_HANDLED;
  16. }

数据接收和数据发送都不是阻塞的,可以看出这是一个全双工的传输。


数据接收

然后是数据接收流程(这里是被动接收数据,由中断调起):

  1. receive_chars调用uart_insert_char获得数据并且写到tty结构体的buffer中,通过tty_flip_buffer_push统一推送到hci uart层
  2.                 |
  3.                 |
  4. tty core(drivers/tty/tty_buffer.c,函数tty_flip_buffer_push,调用flush_to_ldisc交给ldisc去处理数据)
  5.                 |
  6.                 | 通过tty_ldisc_ref(tty)找到ldisc指针,并通过disc->ops->receive_buf
  7.                 | 让hci的ldisc去处理这些数据
  8.                 |
  9. hci uart(drivers/bluetooth/hci_ldisc.c,函数hci_uart_tty_receive)
  10.                 |
  11.                 | 调用hu->proto->recv交给proto处理数据
  12.                 |
  13. 对应的proto层(drivers/bluetooth/hci_h4.c或者hci_bcsp.c, recv,调用hci_recv_stream_fragment或者hci_recv_frame将数据推送给hci层,也就是bluez的kernel协议栈去处理数据包。这部分处理取决于bcsp协议或者h4协议,需要参看对应文档)
  14.                 |
  15. hci层(net/bluetooth/hci_core.c,函数hci_recv_frame通过tasklet异步调用hci_rx_task,调用hci_send_to_sock通过已经连接并且正在监听的sockt将数据拷贝发送给HAL,并且根据skb的类型作对应处理——这步才是关键,类型见代码)

  1. // net/bluetooth/hci_core.c
  2. static void hci_rx_task(unsigned long arg)
  3. {
  4.     ....
  5.     /* Process frame */
  6.     switch (bt_cb(skb)->pkt_type) {
  7.         case HCI_EVENT_PKT: // hci event,通常是保存下来,以便上层查询时告知
  8.             hci_event_packet(hdev, skb);
  9.             break;
  10.         case HCI_ACLDATA_PKT: // l2cap协议,如果上层有BTPROTO_L2CAP类型socket,
  11.                               // 能够收到这些数据包
  12.             hci_acldata_packet(hdev, skb);
  13.             break;
  14.         case HCI_SCODATA_PKT: // 如果上层有BTPROTO_SCO类型socket,能够收到这些数据包
  15.             hci_scodata_packet(hdev, skb);
  16.             break;
  17.         default: // 丢掉
  18.             kfree_skb(skb);
  19.             break;
  20.         ....
  21. }
这块有个疑问,就是hci的ldisc里面,bscp有给skb的pkt_type赋值,但是h4没有,不知道h4类型的proto怎么实现 的... hci_acldata_packet在调用net/bluetooth/l2cap_core.c里面的l2cap_recv_acldata往 BTPROTO_L2CAP类型socket写包,并且会通过回调函数的方法接着往BTPROTO_RFCOMM类型的socket写一遍。所以数据接收 流程简言之,就是:

  1. tty uart层中断(drivers/tty/serial/pxa.c)
  2.                  |
  3. tty core(drivers/tty/tty_buffer.c)
  4.                  |
  5. hci uart层(drivers/bluetooth/hci_ldisc.c,hci_bcsp.c)
  6.                  |
  7. hci层(net/bluetooth/hci_core.c)
  8.                  |
  9. hci层l2cap(net/bluetooth/l2cap_core.c)
  10.                  |
  11. hci层rfcomm(net/bluetooth/rfcomm/core.c)
  12.                  |
  13. HAL层(external/bluetooth/bluez/)

数据发送

基本上是数据接收的一个逆过程

  1. hci层(net/bluetooth/hci_sock.c),hci_sock_sendmsg或者hci_cmd_task
  2.                |
  3.                | 把msg打包成sk_buff结构体,放到hci_dev的raw_q里面
  4.                | 然后通过tasklet_schedule(&hdev->tx_task)唤醒
  5.                | 初始化的hci_tx_task,在这个函数里面调用hci_send_frame
  6.                | 发送hci_dev里面的raw_q
  7.                |
  8. hci层(net/bluetooth/hci_core.c),hci_send_frame
  9.                |
  10.                | 调用hdev->send(skb)将sk_buff发送
  11.                |
  12. hci uart层(drivers/bluetooth/hci_ldisc.c),hci_uart_send_frame
  13.                |
  14.                | hu->proto->enqueue(hu, skb)将sk_buff放proto对应的
  15.                | sk_buff_head里面然后调用hci_uart_tx_wakeup(hu)用一个wihle
  16.                | 循环发送sk_buff_head里面的所有sk_buff,并且调用hci_uart_tx_complete
  17.                | 进行发送的包的统计。发送数据是通过调用tty的方法实现
  18.                | 具体代码为tty->ops->write(tty, skb->data, skb->len)
  19.                | 这里面的ops是在pxa.c里面的初始化函数通过uart_register_driver注册的
  20.                |
  21. serial core(drivers/tty/serial/serial_core.c),uart_write
  22.                |
  23.                | uart_state *state = tty->driver_data,通过state获得缓冲区
  24.                | circ = &state->xmit,将需要放送的数据(也就是sk_buff)放到
  25.                | 缓冲区准备发送(注意这个xmit稍候会发现用到),发送的方式是写完数据到缓冲区后
  26.                | 调用uart_start(tty)唤醒对应端口,然后通过port->ops->start_tx(port)发送
  27.                |
  28. tty serial层硬件抽象驱动(drivers/tty/serial/pxa.c),serial_pxa_start_tx
  29.                |
  30.                | serial_out(up, UART_IER, up->ier),调用writel方法enable发送的port
  31.                | 的传输中断,真正的中断响应见前面注册的irq响应函数serial_pxa_irq;中断响应后,
  32.                | 会调具体的函数去真正发送数据
  33.                |
  34. tty serial层硬件抽象驱动(drivers/tty/serial/pxa.c),transmit_chars
  35.                |
  36.                | serial_out(up, UART_TX, xmit->buf[xmit->tail]),把前面提到的缓冲区的内容
  37.                | 往对应的芯片管脚一个char一个char的写,每次中断会发送fifosize/2个字节;其中
  38.                | fifosize对于pxa来说固定是64。当xmit里面的内容写完,会disable传输中断
  39.                | 具体波特率在这个过程怎么生效,还有待考察。

<think>好的,我现在需要回答用户关于VoLTE中RTP包在核心网传输和接收过程的问题。首先,我应该回顾一下VoLTE的基本架构和RTP的作用。VoLTE(Voice over LTE)使用IP多媒体子系统(IMS)来提供语音服务,而RTP(实时传输协议)负责传输音频数据。核心网中的主要网元包括P-CSCF、I-CSCF、S-CSCF以及媒体网关等。 接下来,我需要详细描述RTP包的传输路径。当用户发起通话时,SIP协议用于建立会话,协商媒体参数,比如编解码器和端口号。一旦会话建立,RTP流就开始在UE(用户设备)之间传输。核心网中的传输可能涉及多个节点,比如媒体网关是否需要转码或转换协议。这里要注意,有些情况下核心网可能只是透传RTP包,而不做处理,这取决于网络架构。 然后,接收过程需要考虑QoS机制,比如确保低延迟和高优先级传输。核心网中的策略控制功能(PCRF)可能会参与资源分配。另外,可能需要提到RTP的确认机制和丢包处理,比如使用RTCP进行监控和控制。 用户提供的引用中提到了FlowShark工具用于分析信令,这可能与监控RTP传输有关。需要确认RTP包在核心网中的处理是否涉及特定的设备或接口,比如MGW或SBC(会话边界控制器)。此外,核心网是否进行RTP头的压缩或加密也是需要考虑的方面。 最后,要确保回答符合格式要求,使用正确的中文表达,分步骤解释过程,并生成相关问题。同时,检查LaTeX格式是否正确,没有行内公式使用$符号,独立公式用$$,并且引用标记正确放置。</think>VoLTE中RTP包在核心网的传输和接收过程可分为以下几个步骤: ### 1. **会话建立与媒体协商** - 用户通过SIP(Session Inititation Protocol)信令建立呼叫,核心网中的IMS组件(如P-CSCF、S-CSCF)负责处理信令。 - 在SDP(Session Description Protocol)中协商媒体参数,包括RTP端口、编解码器(如AMR-WB)、采样率等[^1]。 - 示例SDP行: $$ a=rtpmap:104 AMR-WB/16000/1 $$ ### 2. **RTP传输路径** - RTP包从主叫UE(用户设备)发出后,经过LTE无线接入网(eNodeB),进入核心网的分组域(EPC)。 - **核心网关键节点**: - **P-GW(PDN Gateway)**:分配IP地址并管理QoS策略,确保RTP流优先级(QCI=1)。 - **媒体网关(MGW)**:若需要跨网络(如PSTN互通),可能进行媒体格式转换。 - **SBC(Session Border Controller)**:处理NAT穿透和安全隔离,维护RTP/RTCP流[^1]。 ### 3. **QoS保障机制** - 核心网通过PCRF(策略与计费规则功能)动态分配带宽,确保端到端延迟≤100ms、抖动≤50ms。 - 示例QoS参数公式: $$ \text{丢包率} = \frac{\text{丢失RTP包数}}{\text{总发送包数}} \times 100\% $$ ### 4. **接收与处理** - 被叫侧P-GW根据QCI标识将RTP包优先转发至目标UE。 - UE通过RTP缓冲区消除抖动,使用RTCP反馈包(如NACK)请求重传或调整编解码速率。 ```plaintext # 简化的RTP传输路径 主叫UE → eNodeB → S-GW → P-GW → SBC → 被叫侧P-GW → eNodeB → 被叫UE ``` ### 5. **监控与故障排查** - 工具如FlowShark可抓取RTP/RTCP流,分析MOS(Mean Opinion Score)和延迟指标。 - 核心网信令跟踪点(如Rx、Gx接口)用于定位QoS策略失效问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值