Skip to content

Commit fbae026

Browse files
authored
Fix incorrect meetingFailed event when meeting is ended (#701)
1 parent efd1df2 commit fbae026

File tree

5 files changed

+98
-8
lines changed

5 files changed

+98
-8
lines changed

Diff for: AmazonChimeSDK/AmazonChimeSDK/internal/audio/DefaultAudioClientObserver.swift

+27-5
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ class DefaultAudioClientObserver: NSObject, AudioClientDelegate {
6868
case .reconnecting:
6969
handleStateChangeToReconnecting()
7070
case .finishDisconnecting:
71-
handleStateChangeToDisconnected()
71+
handleStateChangeToDisconnected(newAudioStatus: newAudioStatus)
7272
case .fail:
7373
handleStateChangeToFail(newAudioStatus: newAudioStatus)
7474
default:
@@ -353,16 +353,21 @@ class DefaultAudioClientObserver: NSObject, AudioClientDelegate {
353353
eventAnalyticsController.publishEvent(name: .meetingStartSucceeded)
354354
}
355355

356-
private func handleStateChangeToDisconnected() {
356+
private func handleStateChangeToDisconnected(newAudioStatus: MeetingSessionStatusCode) {
357357
switch currentAudioState {
358358
case .connecting,
359359
.finishConnecting:
360-
// No-op, already handled in DefaultAudioClientController.stop()
360+
if newAudioStatus == .audioServerHungup {
361+
handleAudioSessionEndedByServer(newAudioStatus: newAudioStatus)
362+
} // Else no-op, client initiated stops already handled in DefaultAudioClientController.stop()
361363
break
362364
case .reconnecting:
363365
notifyAudioClientObserver { (observer: AudioVideoObserver) in
364366
observer.audioSessionDidCancelReconnect()
365367
}
368+
if newAudioStatus == .audioServerHungup {
369+
handleAudioSessionEndedByServer(newAudioStatus: newAudioStatus)
370+
} // Else no-op, client initiated stops already handled in DefaultAudioClientController.stop()
366371
default:
367372
break
368373
}
@@ -394,16 +399,26 @@ class DefaultAudioClientObserver: NSObject, AudioClientDelegate {
394399
if DefaultAudioClientController.state == .stopped {
395400
return
396401
}
397-
398402
notifyFailed(status: newAudioStatus)
403+
handleAudioClientStop(status: newAudioStatus)
404+
}
405+
406+
private func handleAudioSessionEndedByServer(newAudioStatus: MeetingSessionStatusCode) {
407+
if DefaultAudioClientController.state == .stopped {
408+
return
409+
}
410+
notifyMeetingEnded(status: newAudioStatus)
411+
handleAudioClientStop(status: newAudioStatus)
412+
}
399413

414+
private func handleAudioClientStop(status: MeetingSessionStatusCode) {
400415
DispatchQueue.global().async {
401416
self.audioLock.lock()
402417
_ = self.audioClient.stopSession()
403418
DefaultAudioClientController.state = .stopped
404419
self.audioLock.unlock()
405420
self.notifyAudioClientObserver { (observer: AudioVideoObserver) in
406-
observer.audioSessionDidStopWithStatus(sessionStatus: MeetingSessionStatus(statusCode: newAudioStatus))
421+
observer.audioSessionDidStopWithStatus(sessionStatus: MeetingSessionStatus(statusCode: status))
407422
}
408423
}
409424
}
@@ -414,6 +429,13 @@ class DefaultAudioClientObserver: NSObject, AudioClientDelegate {
414429
EventAttributeName.meetingErrorMessage: String(describing: status)])
415430
meetingStatsCollector.resetMeetingStats()
416431
}
432+
433+
private func notifyMeetingEnded(status: MeetingSessionStatusCode) {
434+
eventAnalyticsController.publishEvent(name: .meetingEnded,
435+
attributes: [EventAttributeName.meetingStatus: status,
436+
EventAttributeName.meetingErrorMessage: String(describing: status)])
437+
meetingStatsCollector.resetMeetingStats()
438+
}
417439

418440
private func processAnyDictToStringEnumDict<T: RawRepresentable>(anyDict: [AnyHashable: Any]) -> [String: T] {
419441
var strEnumDict = [String: T]()

Diff for: AmazonChimeSDK/AmazonChimeSDK/internal/utils/Converters.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,10 @@ import Foundation
5555
return .reconnecting
5656
case AUDIO_CLIENT_STATE_DISCONNECTING:
5757
return .disconnecting
58-
case AUDIO_CLIENT_STATE_DISCONNECTED_NORMAL:
58+
case AUDIO_CLIENT_STATE_DISCONNECTED_NORMAL,
59+
AUDIO_CLIENT_STATE_SERVER_HUNGUP:
5960
return .finishDisconnecting
6061
case AUDIO_CLIENT_STATE_DISCONNECTED_ABNORMAL,
61-
AUDIO_CLIENT_STATE_SERVER_HUNGUP,
6262
AUDIO_CLIENT_STATE_FAILED_TO_CONNECT:
6363
return .fail
6464
default:

Diff for: AmazonChimeSDK/AmazonChimeSDKTests/internal/audio/DefaultAudioClientObserverTests.swift

+63
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,69 @@ class DefaultAudioClientObserverTests: XCTestCase {
196196

197197
wait(for: [expect], timeout: defaultTimeout)
198198
}
199+
200+
func testAudioClientStateChanged_ConnectionFailedFromReconnecting() {
201+
given(audioClientMock.stopSession()).willReturn(0)
202+
DefaultAudioClientController.state = .started
203+
defaultAudioClientObserver.audioClientStateChanged(AUDIO_CLIENT_STATE_RECONNECTING,
204+
status: audio_client_status_t.init(MeetingSessionStatusCode.ok.rawValue))
205+
defaultAudioClientObserver.audioClientStateChanged(AUDIO_CLIENT_STATE_DISCONNECTED_ABNORMAL,
206+
status: audio_client_status_t.init(MeetingSessionStatusCode.audioServerHungup.rawValue))
207+
let expect = eventually {
208+
verify(mockAudioVideoObserver.audioSessionDidCancelReconnect()).wasCalled()
209+
verify(eventAnalyticsControllerMock.publishEvent(name: .meetingFailed, attributes: any())).wasCalled()
210+
verify(meetingStatsCollectorMock.resetMeetingStats()).wasCalled()
211+
}
212+
213+
wait(for: [expect], timeout: defaultTimeout)
214+
}
215+
216+
func testAudioClientStateChanged_FinishDisconnectingFromConnecting() {
217+
given(audioClientMock.stopSession()).willReturn(0)
218+
DefaultAudioClientController.state = .started
219+
defaultAudioClientObserver.audioClientStateChanged(AUDIO_CLIENT_STATE_CONNECTING,
220+
status: audio_client_status_t.init(MeetingSessionStatusCode.ok.rawValue))
221+
defaultAudioClientObserver.audioClientStateChanged(AUDIO_CLIENT_STATE_SERVER_HUNGUP,
222+
status: audio_client_status_t.init(MeetingSessionStatusCode.audioServerHungup.rawValue))
223+
let expect = eventually {
224+
verify(eventAnalyticsControllerMock.publishEvent(name: .meetingEnded, attributes: any())).wasCalled()
225+
verify(mockAudioVideoObserver.audioSessionDidStopWithStatus(sessionStatus: any())).wasCalled()
226+
}
227+
228+
wait(for: [expect], timeout: defaultTimeout)
229+
}
230+
231+
func testAudioClientStateChanged_FinishDisconnectingFromConnected() {
232+
given(audioClientMock.stopSession()).willReturn(0)
233+
DefaultAudioClientController.state = .started
234+
defaultAudioClientObserver.audioClientStateChanged(AUDIO_CLIENT_STATE_CONNECTED,
235+
status: audio_client_status_t.init(MeetingSessionStatusCode.ok.rawValue))
236+
defaultAudioClientObserver.audioClientStateChanged(AUDIO_CLIENT_STATE_SERVER_HUNGUP,
237+
status: audio_client_status_t.init(MeetingSessionStatusCode.audioServerHungup.rawValue))
238+
let expect = eventually {
239+
verify(mockAudioVideoObserver.audioSessionDidStopWithStatus(sessionStatus: any())).wasCalled()
240+
verify(eventAnalyticsControllerMock.publishEvent(name: .meetingEnded, attributes: any())).wasCalled()
241+
verify(meetingStatsCollectorMock.resetMeetingStats()).wasCalled()
242+
}
243+
244+
wait(for: [expect], timeout: defaultTimeout)
245+
}
246+
247+
func testAudioClientStateChanged_FinishDisconnectingFromReconnecting() {
248+
given(audioClientMock.stopSession()).willReturn(0)
249+
DefaultAudioClientController.state = .started
250+
defaultAudioClientObserver.audioClientStateChanged(AUDIO_CLIENT_STATE_RECONNECTING,
251+
status: audio_client_status_t.init(MeetingSessionStatusCode.ok.rawValue))
252+
defaultAudioClientObserver.audioClientStateChanged(AUDIO_CLIENT_STATE_SERVER_HUNGUP,
253+
status: audio_client_status_t.init(MeetingSessionStatusCode.audioServerHungup.rawValue))
254+
let expect = eventually {
255+
verify(mockAudioVideoObserver.audioSessionDidCancelReconnect()).wasCalled()
256+
verify(eventAnalyticsControllerMock.publishEvent(name: .meetingEnded, attributes: any())).wasCalled()
257+
verify(meetingStatsCollectorMock.resetMeetingStats()).wasCalled()
258+
}
259+
260+
wait(for: [expect], timeout: defaultTimeout)
261+
}
199262

200263
func testAudioClientStateChanged_NotifiesOfInputDeviceFailure() {
201264
given(audioClientMock.stopSession()).willReturn(0)

Diff for: AmazonChimeSDK/AmazonChimeSDKTests/internal/utils/ConvertersTests.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ class ConvertersTests: XCTestCase {
150150
)
151151
XCTAssertEqual(
152152
Converters.AudioClientState.toSessionStateControllerAction(state: AUDIO_CLIENT_STATE_SERVER_HUNGUP),
153-
SessionStateControllerAction.fail
153+
SessionStateControllerAction.finishDisconnecting
154154
)
155155
XCTAssertEqual(
156156
Converters.AudioClientState.toSessionStateControllerAction(state: AUDIO_CLIENT_STATE_FAILED_TO_CONNECT),

Diff for: CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
## Unreleased
2+
3+
### Fixed
4+
* When meeting has ended normally, but not initiated by the client, send a meetingEnded event rather than a meetingFailed event.
5+
16
## [0.26.2] - 2024-10-16
27

38
### Fixed

0 commit comments

Comments
 (0)