in chime-sdk-signaling-cpp/src/audio_video/default_audio_frame_adapter.cc [36:139]
void DefaultAudioFrameAdapter::OnAudioStreamIdInfo(const signal_sdk::SdkAudioStreamIdInfoFrame &audio_stream_id_info) {
// Iterate the streams, store the associated attendee data, send out events based on changes.
// The order is guaranteed, and there's no reuse of the stream id in the same meeting.
for (const signal_sdk::SdkAudioStreamIdInfo& stream : audio_stream_id_info.streams()) {
// Skip when no stream id
if (!stream.has_audio_stream_id()) {
CHIME_LOG(LogLevel::kDebug, "No audio stream id in audio stream id info frame, will skip.");
continue;
}
bool has_attendee_id = stream.has_attendee_id();
bool has_external_user_id = stream.has_external_user_id();
bool has_muted = stream.has_muted();
bool has_dropped = stream.has_dropped();
// Handle new attendee
// Self presence, mute update is not batched, while other attendees' are batched for 1s,
// and there's no multiple streams for the same stream id in one frame.
if (has_attendee_id) {
// Default to empty string if external user id is absent
std::string external_user_id = has_external_user_id ? stream.external_user_id() : "";
const auto stream_itr = attendee_id_to_stream_id_.find(stream.attendee_id());
// Not seen before
if (stream_itr == attendee_id_to_stream_id_.end()) {
default_signaling_client_->NotifySignalingObserver([&] (SignalingClientObserver* observer) -> void {
observer->OnAttendeeJoined({ stream.attendee_id(), external_user_id });
});
}
attendee_id_to_stream_id_[stream.attendee_id()] = stream.audio_stream_id();
stream_id_to_attendee_id_[stream.audio_stream_id()] = stream.attendee_id();
// Audio metadata frame does not carry external user id, we need to store it for query later
stream_id_to_external_user_id_[stream.audio_stream_id()] = external_user_id;
}
// Handle mute state
if (has_muted) {
const auto attendee_itr = stream_id_to_attendee_id_.find(stream.audio_stream_id());
// Skip when stream not seen
if (attendee_itr == stream_id_to_attendee_id_.end()) {
CHIME_LOG(LogLevel::kDebug, "Failed to find stream id: " + std::to_string(stream.audio_stream_id()) + " for the mute event, will skip.");
continue;
}
std::string attendee_id = attendee_itr->second;
std::string external_user_id = stream_id_to_external_user_id_[stream.audio_stream_id()];
const auto muted_itr = attendee_id_to_muted_.find(attendee_id);
if (muted_itr == attendee_id_to_muted_.end()) {
// Not seen before
if (stream.muted()) {
default_signaling_client_->NotifySignalingObserver([&] (SignalingClientObserver* observer) -> void {
observer->OnAttendeeAudioMuted({ attendee_id, external_user_id });
});
}
} else {
// Seen before and state changes
if (muted_itr->second != stream.muted()) {
default_signaling_client_->NotifySignalingObserver([&] (SignalingClientObserver* observer) -> void {
if (stream.muted()) {
observer->OnAttendeeAudioMuted({ attendee_id, external_user_id });
} else {
observer->OnAttendeeAudioUnmuted({ attendee_id, external_user_id });
}
});
}
}
// Store the mute state
attendee_id_to_muted_[attendee_id] = stream.muted();
}
// Handle attendee leave
if (!has_attendee_id && !has_muted) {
auto attendee_itr = stream_id_to_attendee_id_.find(stream.audio_stream_id());
if (attendee_itr != stream_id_to_attendee_id_.end()) {
// Seen the stream before
std::string attendee_id = attendee_itr->second;
std::string external_user_id = stream_id_to_external_user_id_[stream.audio_stream_id()];
// Delete the stream related states
stream_id_to_attendee_id_.erase(attendee_itr);
stream_id_to_external_user_id_.erase(stream.audio_stream_id());
const auto stream_itr = attendee_id_to_stream_id_.find(attendee_id);
if (stream_itr != attendee_id_to_stream_id_.end()) {
// Found associated attendee, delete state
attendee_id_to_stream_id_.erase(attendee_id);
}
bool attendee_has_new_stream_id = false;
for (auto& other_stream : stream_id_to_attendee_id_) {
if (attendee_id == other_stream.second && other_stream.first > stream.audio_stream_id()) {
// A new stream id is associated with this attendee
attendee_has_new_stream_id = true;
break;
}
}
if (!attendee_has_new_stream_id) {
// This attendee is absent
default_signaling_client_->NotifySignalingObserver([&] (SignalingClientObserver* observer) -> void {
if (has_dropped && stream.dropped()) {
observer->OnAttendeeDropped({ attendee_id, external_user_id });
} else {
observer->OnAttendeeLeft({ attendee_id, external_user_id });
}
});
}
}
}
}
}