@@ -90,7 +90,8 @@ class IsoStreamImpl final : public IsoStream {
90
90
CisEstablishedCallback on_established_cb,
91
91
hci::CommandChannel::WeakPtr cmd,
92
92
pw::Callback<void ()> on_closed_cb,
93
- hci::IsoDataChannel* data_channel);
93
+ hci::IsoDataChannel* data_channel,
94
+ pw::chrono::VirtualSystemClock& clock);
94
95
95
96
// IsoStream overrides
96
97
bool OnCisEstablished (const hci::EventPacket& event) override ;
@@ -173,6 +174,11 @@ class IsoStreamImpl final : public IsoStream {
173
174
174
175
WeakSelf<IsoStreamImpl> weak_self_;
175
176
177
+ pw::chrono::VirtualSystemClock& clock_;
178
+ pw::chrono::SystemClock::time_point reference_time_;
179
+ uint16_t next_sdu_sequence_number_ = 0 ;
180
+ uint32_t iso_interval_usec_ = 0 ;
181
+
176
182
BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE (IsoStreamImpl);
177
183
};
178
184
@@ -182,7 +188,8 @@ IsoStreamImpl::IsoStreamImpl(uint8_t cig_id,
182
188
CisEstablishedCallback on_established_cb,
183
189
hci::CommandChannel::WeakPtr cmd,
184
190
pw::Callback<void ()> on_closed_cb,
185
- hci::IsoDataChannel* data_channel)
191
+ hci::IsoDataChannel* data_channel,
192
+ pw::chrono::VirtualSystemClock& clock)
186
193
: IsoStream(),
187
194
state_ (IsoStreamState::kNotEstablished ),
188
195
cig_id_(cig_id),
@@ -194,7 +201,8 @@ IsoStreamImpl::IsoStreamImpl(uint8_t cig_id,
194
201
on_closed_cb_(std::move(on_closed_cb)),
195
202
cmd_(std::move(cmd)),
196
203
data_channel_(data_channel),
197
- weak_self_(this ) {
204
+ weak_self_(this ),
205
+ clock_(clock) {
198
206
PW_CHECK (cmd_.is_alive ());
199
207
PW_CHECK (data_channel_);
200
208
@@ -275,6 +283,11 @@ bool IsoStreamImpl::OnCisEstablished(const hci::EventPacket& event) {
275
283
276
284
cis_established_cb_ (status, GetWeakPtr (), cis_params_);
277
285
286
+ reference_time_ = clock_.now ();
287
+
288
+ iso_interval_usec_ = cis_params_.iso_interval *
289
+ CisEstablishedParameters::kIsoIntervalToMicroseconds ;
290
+
278
291
// Event handled
279
292
return true ;
280
293
}
@@ -528,22 +541,43 @@ std::unique_ptr<IsoDataPacket> IsoStreamImpl::ReadNextQueuedIncomingPacket() {
528
541
void IsoStreamImpl::Send (pw::ConstByteSpan data) {
529
542
PW_CHECK (data_channel_, " Send called while not registered to a data stream." );
530
543
PW_CHECK (data.size () <= std::numeric_limits<uint16_t >::max ());
531
-
532
544
const size_t max_length = data_channel_->buffer_info ().max_data_length ();
545
+
546
+ // Calculate the current interval sequence number
547
+ auto now = clock_.now ();
548
+ auto elapsed_time = now - reference_time_;
549
+ uint64_t elapsed_usec =
550
+ std::chrono::duration_cast<std::chrono::microseconds>(elapsed_time)
551
+ .count ();
552
+ uint16_t interval_sequence_num =
553
+ static_cast <uint16_t >(elapsed_usec / iso_interval_usec_);
554
+
555
+ uint16_t current_sequence_num = next_sdu_sequence_number_;
556
+
557
+ // Handle missed interval
558
+ if (current_sequence_num < interval_sequence_num) {
559
+ bt_log (INFO,
560
+ " iso" ,
561
+ " Skipped interval: advancing sequence number from %u to current "
562
+ " interval %u" ,
563
+ current_sequence_num,
564
+ interval_sequence_num);
565
+ current_sequence_num = interval_sequence_num;
566
+ }
567
+
533
568
std::optional<SduHeaderInfo> sdu_header = SduHeaderInfo{
534
- // TODO: https://pwbug.dev/393366531 - Implement sequence number.
535
- .packet_sequence_number = 0 ,
569
+ .packet_sequence_number = current_sequence_num,
536
570
.iso_sdu_length = static_cast <uint16_t >(data.size ()),
537
571
};
538
572
539
573
// Fragmentation loop.
540
574
while (!data.empty ()) {
541
- size_t length_remaining =
542
- TotalDataLength (/* has_timestamp=*/ false ,
543
- /* has_sdu_header=*/ sdu_header.has_value (),
544
- /* data_size=*/ data.size ());
545
- // This is the first fragment if we haven't sent the SDU header yet.
575
+ // Determine if this is the first fragment of the SDU
546
576
const bool is_first = sdu_header.has_value ();
577
+
578
+ size_t length_remaining = TotalDataLength (/* has_timestamp=*/ false ,
579
+ /* has_sdu_header=*/ is_first,
580
+ /* data_size=*/ data.size ());
547
581
// This is the last fragment if there is sufficient buffer space.
548
582
const bool is_last = length_remaining <= max_length;
549
583
@@ -567,6 +601,7 @@ void IsoStreamImpl::Send(pw::ConstByteSpan data) {
567
601
data_channel_->SendData (BuildPacketForSending (fragment, flag, sdu_header));
568
602
sdu_header.reset ();
569
603
}
604
+ next_sdu_sequence_number_ = current_sequence_num + 1 ;
570
605
}
571
606
572
607
void IsoStreamImpl::Close () { on_closed_cb_ (); }
@@ -578,14 +613,16 @@ std::unique_ptr<IsoStream> IsoStream::Create(
578
613
CisEstablishedCallback on_established_cb,
579
614
hci::CommandChannel::WeakPtr cmd,
580
615
pw::Callback<void ()> on_closed_cb,
581
- hci::IsoDataChannel* data_channel) {
616
+ hci::IsoDataChannel* data_channel,
617
+ pw::chrono::VirtualSystemClock& clock) {
582
618
return std::make_unique<IsoStreamImpl>(cig_id,
583
619
cis_id,
584
620
cis_handle,
585
621
std::move (on_established_cb),
586
622
std::move (cmd),
587
623
std::move (on_closed_cb),
588
- data_channel);
624
+ data_channel,
625
+ clock );
589
626
}
590
627
591
628
} // namespace bt::iso
0 commit comments