Skip to content
25 changes: 19 additions & 6 deletions src/ble/hal/blercu/bleservices/gatt/gatt_audioservice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,20 +83,22 @@ void GattAudioService::init()
// add all the states and the super state groupings
m_stateMachine.addState(IdleState, "Idle");
m_stateMachine.addState(ReadyState, "Ready");
m_stateMachine.addState(EnableNotificationsState, "EnableNotifications");

m_stateMachine.addState(StreamingSuperState, "StreamingSuperState");
m_stateMachine.addState(StreamingSuperState, EnableNotificationsState, "EnableNotifications");
m_stateMachine.addState(StreamingSuperState, StartStreamingState, "StartStreaming");
m_stateMachine.addState(StreamingSuperState, StreamingState, "Streaming");
m_stateMachine.addState(StreamingSuperState, StopStreamingState, "StopStreaming");


// add the transitions: From State -> Event -> To State
m_stateMachine.addTransition(IdleState, StartServiceRequestEvent, ReadyState);
m_stateMachine.addTransition(ReadyState, StopServiceRequestEvent, IdleState);
m_stateMachine.addTransition(ReadyState, StartStreamingRequestEvent, EnableNotificationsState);
m_stateMachine.addTransition(IdleState, StartServiceRequestEvent, EnableNotificationsState);
m_stateMachine.addTransition(EnableNotificationsState, RetryStartNotifyEvent, EnableNotificationsState);
m_stateMachine.addTransition(EnableNotificationsState, StopServiceRequestEvent, IdleState);
m_stateMachine.addTransition(EnableNotificationsState, NotificationsEnabledEvent, ReadyState);

Comment thread
egalla204 marked this conversation as resolved.
m_stateMachine.addTransition(EnableNotificationsState, NotificationsEnabledEvent, StartStreamingState);
m_stateMachine.addTransition(ReadyState, StopServiceRequestEvent, IdleState);
m_stateMachine.addTransition(ReadyState, StartStreamingRequestEvent, StartStreamingState);

m_stateMachine.addTransition(StartStreamingState, StreamingStartedEvent, StreamingState);

Expand Down Expand Up @@ -591,7 +593,8 @@ void GattAudioService::stopStreaming(uint32_t audioDuration, PendingReply<> &&re
{
// check the service is ready
if (m_stateMachine.state() != StreamingState) {
reply.setError("Service not currently streaming");
// Don't treat this as an error. The intent is to stop streaming, and if we're not streaming then the intent has been satisfied.
XLOGD_DEBUG("service not currently streaming");
reply.finish();
return;
}
Expand Down Expand Up @@ -738,6 +741,16 @@ void GattAudioService::stateMachinePostEvent(const Event::Type event)
m_stateMachine.postEvent(event);
}

void GattAudioService::stateMachinePostDelayedEvent(const Event::Type event, const int delay)
{
m_stateMachine.postDelayedEvent(event, delay);
}

void GattAudioService::stateMachineCancelDelayedEvents(const Event::Type eventType)
{
m_stateMachine.cancelDelayedEvents(eventType);
}

bool GattAudioService::stateMachineIsIdle()
{
return m_stateMachine.inState(IdleState);
Expand Down
17 changes: 11 additions & 6 deletions src/ble/hal/blercu/bleservices/gatt/gatt_audioservice.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ class GattAudioService : public BleRcuAudioService
void updateFrameCountSupport(bool frameCountSupported);

void stateMachinePostEvent(const Event::Type event);
void stateMachinePostDelayedEvent(const Event::Type event, const int delay);
void stateMachineCancelDelayedEvents(const Event::Type eventType);

bool stateMachineIsIdle();

void setLastError(BleRcuAudioService::StreamingError error);
Expand Down Expand Up @@ -159,15 +162,17 @@ class GattAudioService : public BleRcuAudioService
static const Event::Type StopStreamingRequestEvent = Event::Type(Event::User + 4);

static const Event::Type NotificationsEnabledEvent = Event::Type(Event::User + 5);
static const Event::Type RetryStartNotifyEvent = Event::Type(Event::User + 6);

static const Event::Type StreamingStartedEvent = Event::Type(Event::User + 7);
static const Event::Type StreamingStoppedEvent = Event::Type(Event::User + 8);

static const Event::Type StreamingStartedEvent = Event::Type(Event::User + 6);
static const Event::Type StreamingStoppedEvent = Event::Type(Event::User + 7);
static const Event::Type GattErrorEvent = Event::Type(Event::User + 9);
static const Event::Type OutputPipeCloseEvent = Event::Type(Event::User + 10);

static const Event::Type GattErrorEvent = Event::Type(Event::User + 8);
static const Event::Type OutputPipeCloseEvent = Event::Type(Event::User + 9);
static const Event::Type AudioInfoTimeoutEvent = Event::Type(Event::User + 11);
static const Event::Type AudioLastFrameTimeoutEvent = Event::Type(Event::User + 12);

static const Event::Type AudioInfoTimeoutEvent = Event::Type(Event::User + 10);
static const Event::Type AudioLastFrameTimeoutEvent = Event::Type(Event::User + 11);
};

#endif // !defined(GATT_AUDIOSERVICE_H)
38 changes: 20 additions & 18 deletions src/ble/hal/blercu/bleservices/gatt/gatt_audioservice_rdk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@ void GattAudioServiceRdk::stop()
}

void GattAudioServiceRdk::onEnteredIdle() {
stateMachineCancelDelayedEvents(RetryStartNotifyEvent);
stateMachineCancelDelayedEvents(GattErrorEvent);

if (m_audioDataCharacteristic) {
XLOGD_INFO("Disabling notifications for m_audioDataCharacteristic");
m_audioDataCharacteristic->disableNotifications();
Expand Down Expand Up @@ -141,14 +144,11 @@ void GattAudioServiceRdk::onEnteredEnableNotificationsState()
auto replyHandlerData = [this](PendingReply<> *reply)
{
if (reply->isError()) {
// this is bad if this happens as we won't get updates, so we install a timer to
// retry enabling notifications in a couple of seconds time
XLOGD_ERROR("failed to enable audio data notifications due to <%s>",
reply->errorMessage().c_str());

setLastError(StreamingError::InternalError);
stateMachinePostEvent(GattErrorEvent);

XLOGD_ERROR("failed to enable audio data notifications due to <%s>", reply->errorMessage().c_str());

// notifications are required for audio streaming, so if this fails we need to retry in a couple of seconds
stateMachineCancelDelayedEvents(RetryStartNotifyEvent);
stateMachinePostDelayedEvent(RetryStartNotifyEvent, 2000);
Comment thread
egalla204 marked this conversation as resolved.
} else {
// notifications enabled so post an event to the state machine
stateMachinePostEvent(NotificationsEnabledEvent);
Expand Down Expand Up @@ -199,8 +199,7 @@ void GattAudioServiceRdk::onEnteredStartStreamingState()
auto replyHandler = [this](PendingReply<> *reply)
{
if (reply->isError()) {
XLOGD_ERROR("failed to write audio control characteristic due to <%s>",
reply->errorMessage().c_str());
XLOGD_ERROR("failed to write audio control characteristic due to <%s>", reply->errorMessage().c_str());

setLastError(StreamingError::InternalError);
stateMachinePostEvent(GattErrorEvent);
Expand All @@ -211,12 +210,16 @@ void GattAudioServiceRdk::onEnteredStartStreamingState()
};


// the first byte is the codec to use, the second byte is to enable voice
const vector<uint8_t> value({ 0x01, 0x01 });

// send a write request to write the control characteristic
m_audioCtrlCharacteristic->writeValueWithoutResponse(value, PendingReply<>(getIsAlivePtr(), replyHandler));

if (!m_audioDataCharacteristic->notificationsEnabled()) {
XLOGD_ERROR("audio data notifications not enabled, cannot continue with audio stream");
setLastError(StreamingError::InternalError);
stateMachineCancelDelayedEvents(GattErrorEvent);
stateMachinePostDelayedEvent(GattErrorEvent, 10); // needs to be delayed to avoid re-entrancy issues with the state machine
} else {
// the first byte is the codec to use, the second byte is to enable voice
const vector<uint8_t> value({ 0x01, 0x01 });
m_audioCtrlCharacteristic->writeValueWithoutResponse(value, PendingReply<>(getIsAlivePtr(), replyHandler));
}
GattAudioService::onEnteredStartStreamingState();
}

Expand All @@ -237,8 +240,7 @@ void GattAudioServiceRdk::onEnteredStopStreamingState()
{
// check for errors
if (reply->isError()) {
XLOGD_ERROR("failed to write audio control characteristic due to <%s>",
reply->errorMessage().c_str());
XLOGD_ERROR("failed to write audio control characteristic due to <%s>", reply->errorMessage().c_str());

setLastError(StreamingError::InternalError);
stateMachinePostEvent(GattErrorEvent);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -244,8 +244,10 @@ void GattRemoteControlService::onEnteredState(int state)
requestAdvConfig();
requestAdvConfigCustomList();
requestUnpairReason();
requestRebootReason();
requestRawBatteryVoltage();

// requestRebootReason() posts InitialValuesRetrievedEvent in its reply handler, so queue it last after the other initial reads.
requestRebootReason();
Comment thread
egalla204 marked this conversation as resolved.

m_readySlots.invoke();

Expand Down
Loading