Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,42 @@ All notable changes to this project will be documented in this file. Dates are d

Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).

#### [1.0.29](https://github.com/rdkcentral/devicesettings/compare/1.0.28...1.0.29)

- RDKEMW-10899: Adding IARMBus dependency during Build Time [`#205`](https://github.com/rdkcentral/devicesettings/pull/205)
- Merge tag '1.0.28' into develop [`05c2d95`](https://github.com/rdkcentral/devicesettings/commit/05c2d95b7b413f3322c3a0b746fd9ccf260d3ad2)

#### [1.0.28](https://github.com/rdkcentral/devicesettings/compare/1.0.27...1.0.28)

> 13 January 2026

- RDKEMW-9781: Video format issue on MTK [`#199`](https://github.com/rdkcentral/devicesettings/pull/199)
- RDKEMW-12054: Fix Coverity identified issues [`#190`](https://github.com/rdkcentral/devicesettings/pull/190)
- 1.0.28 release change log updates [`f11f7de`](https://github.com/rdkcentral/devicesettings/commit/f11f7de47304fbf0a8669d1894c243dc86c76e02)
- Merge tag '1.0.27' into develop [`56fabff`](https://github.com/rdkcentral/devicesettings/commit/56fabffd8576c37eedb03dac31c3238fa318977d)

#### [1.0.27](https://github.com/rdkcentral/devicesettings/compare/1.0.26...1.0.27)

> 12 January 2026

- RDKEMW-11232 getAudioFormatApi issue on Xione-UK [`#188`](https://github.com/rdkcentral/devicesettings/pull/188)
- 1.0.27 release change log updates [`6594764`](https://github.com/rdkcentral/devicesettings/commit/6594764c3fde44fdb313576482cd7c2589fe1493)
- Merge tag '1.0.26' into develop [`62858d9`](https://github.com/rdkcentral/devicesettings/commit/62858d954e5871070b4e0433c9e06abaf8ff97d1)

#### [1.0.26](https://github.com/rdkcentral/devicesettings/compare/1.0.25...1.0.26)

> 8 January 2026

- RDKEMW-11168, RDKEMW-4848: pass the proper handle to dsEnableHDCP [`#182`](https://github.com/rdkcentral/devicesettings/pull/182)
- 1.0.26 release change log updates [`898b0bb`](https://github.com/rdkcentral/devicesettings/commit/898b0bbcbc5e16bd1c5f4bcf2e881b8ef037c8af)
- Merge tag '1.0.25' into develop [`ce8af83`](https://github.com/rdkcentral/devicesettings/commit/ce8af8303729b6a01fe4d8240de74fe365cdafe4)

#### [1.0.25](https://github.com/rdkcentral/devicesettings/compare/1.0.24...1.0.25)

> 20 November 2025

- Feature/rdkemw 7496 [`#134`](https://github.com/rdkcentral/devicesettings/pull/134)
- 1.0.25 release change log updates [`75b7563`](https://github.com/rdkcentral/devicesettings/commit/75b7563fc461eeaa31bd68140f29ccf0900a6655)
- Merge tag '1.0.24' into develop [`4e94421`](https://github.com/rdkcentral/devicesettings/commit/4e94421d193d4d5e7dea28ccf49198c7dc2bf1d4)

#### [1.0.24](https://github.com/rdkcentral/devicesettings/compare/1.0.23...1.0.24)
Expand Down
4 changes: 2 additions & 2 deletions ds/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ all: install

library: $(OBJS)
@echo "Building $(LIBNAMEFULL) ...."
$(CXX) $(OBJS) $(CFLAGS) $(DSHAL_LDFLAGS) -L$(INSTALL)/lib -ldshalcli -shared -o $(LIBNAMEFULL)
$(CXX) $(OBJS) $(CFLAGS) -L$(INSTALL)/lib -ldshalcli -shared -o $(LIBNAMECLI)
$(CXX) $(OBJS) $(CFLAGS) $(DSHAL_LDFLAGS) -L$(INSTALL)/lib -lIARMBus -ldshalcli -shared -o $(LIBNAMEFULL)
$(CXX) $(OBJS) $(CFLAGS) -L$(INSTALL)/lib -lIARMBus -ldshalcli -shared -o $(LIBNAMECLI)

%.o: %.cpp
@echo "Building $@ ...."
Expand Down
8 changes: 4 additions & 4 deletions ds/audioOutputPort.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ AudioOutputPort::AudioOutputPort(const int type, const int index, const int id)
out << getType().getName() << _index;
_name = out.str();
}
printf ("\nAudioOutputPort init: _type:%d _index:%d _handle:%d\n", _type, _index, _handle);
printf ("\nAudioOutputPort init: _type:%d _index:%d _handle:%ld\n", _type, _index, (long)_handle);
if (dsERR_NONE == ret) {
//dsGetAudioCompression (_handle, (dsAudioCompression_t *)&_compression);
dsGetAudioEncoding (_handle, (dsAudioEncoding_t *)&_encoding);
Expand Down Expand Up @@ -184,7 +184,7 @@ dsError_t AudioOutputPort::reInitializeAudioOutputPort()
_name = out.str();
}

printf ("\nAudioOutputPort init: _type:%d _index:%d _handle:%d\n", _type, _index, _handle);
printf ("\nAudioOutputPort init: _type:%d _index:%d _handle:%ld\n", _type, _index,(long)_handle);
if (dsERR_NONE == ret) {
//dsGetAudioCompression>(_handle, (dsAudioCompression_t *)&_compression);
dsGetAudioEncoding(_handle, (dsAudioEncoding_t *)&_encoding);
Expand Down Expand Up @@ -1422,11 +1422,11 @@ void AudioOutputPort::setAudioDelay(const uint32_t audioDelayMs)
dsError_t ret = dsERR_NONE;
uint32_t ms = audioDelayMs;

INT_INFO("AudioOutputPort [%s], setting delay to [%lu] ms\n", _name.c_str(), audioDelayMs);
INT_INFO("AudioOutputPort [%s], setting delay to [%u] ms\n", _name.c_str(), audioDelayMs);

if (ms > audioDelayMsMax)
{
INT_ERROR("AudioOutputPort [%s], delay [%lu] ms, exceeds max [%lu]. Setting Max \n",
INT_ERROR("AudioOutputPort [%s], delay [%u] ms, exceeds max [%u]. Setting Max \n",
_name.c_str(),
audioDelayMs,
audioDelayMsMax);
Expand Down
3 changes: 0 additions & 3 deletions ds/edid-parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ static void parse_std_timing(unsigned char* bytes, edid_data_t* data_ptr) {
case 1: v = (h * 3) / 4; break;
case 2: v = (h * 4) / 5; break;
case 3: v = (h * 9) / 16; break;
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The removal of the default case in this switch statement means that if an unexpected value appears in the 2-bit field (which can only be 0-3), the variable 'v' will remain at 0. While this switch covers all possible values for a 2-bit field, consider whether v=0 is the appropriate behavior if future EDID specifications extend this field or if corrupted EDID data is encountered. The original default case with early return provided explicit handling for invalid data.

Suggested change
case 3: v = (h * 9) / 16; break;
case 3: v = (h * 9) / 16; break;
default:
INT_DEBUG("Unexpected std timing aspect ratio code: 0x%02X\n",
(bytes[idx + 1] & 0xC0) >> 6);
return;

Copilot uses AI. Check for mistakes.
default: return;
}
int r = (bytes[idx + 1] & 0x3F) + 60;
INT_DEBUG("STD %dx%d@%d\n", h, v, r);
Expand Down Expand Up @@ -381,8 +380,6 @@ static void parse_ext_timing(unsigned char* bytes, edid_data_t* data_ptr) {
case 6: break;
// 'Use Extended Tag'
case 7: parse_extended_db(&bytes[idx], data_ptr); break;
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The removal of the default case for unsupported extension tags means that unknown tag values (anything other than 0-7) will now fall through without any logging or error handling. The original code logged "Unsupported extension tag" for unknown values, which was helpful for debugging EDID parsing issues. Consider whether silently ignoring unknown tags is the intended behavior, especially since new EDID extension tags might be added in future specifications.

Suggested change
case 7: parse_extended_db(&bytes[idx], data_ptr); break;
case 7: parse_extended_db(&bytes[idx], data_ptr); break;
// unsupported / unknown extension tag
default:
INT_DEBUG("parse_ext_timing: unsupported extension tag=%d len=%d\n", tag, len);
break;

Copilot uses AI. Check for mistakes.
// default - unsupported
default: INT_DEBUG("Unsupported extension tag: 0x%X\n", tag);
}
idx += len + 1;
}
Expand Down
2 changes: 1 addition & 1 deletion ds/hdmiIn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -528,7 +528,7 @@ void HdmiInput::getHDMISPDInfo (int iHdmiPort, std::vector<uint8_t> &data) {
data.clear();
if (ret == dsERR_NONE) {
if (sizeof(spdinfo) <= sizeof(struct dsSpd_infoframe_st)) {
printf("HdmiInput::getHDMISPDInfo has %d bytes\r\n", sizeof(spdinfo));
printf("HdmiInput::getHDMISPDInfo has %zu bytes\r\n", sizeof(spdinfo));
data.insert(data.begin(), spdinfo, spdinfo + sizeof(struct dsSpd_infoframe_st));
} else {
ret = dsERR_OPERATION_NOT_SUPPORTED;
Expand Down
51 changes: 49 additions & 2 deletions ds/host.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,53 @@ Host::~Host()
return std::string(socID);
}

intptr_t Host::getAudioPortHandle()
{
try
{
if (isHDMIOutPortPresent())
{
//STB profile with single audio output port
AudioOutputPort aPort = getAudioOutputPort("HDMI0");
return aPort.getOutputPortHandle();
}
else
{
//TV profile with multiple audio output ports
// First check the ports which are dynamically conected and finally fallback to SPEAKER0 which is always connected.
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment has a typo: "conected" should be "connected". This typo appears in the comment explaining the fallback logic for audio ports.

Suggested change
// First check the ports which are dynamically conected and finally fallback to SPEAKER0 which is always connected.
// First check the ports which are dynamically connected and finally fallback to SPEAKER0 which is always connected.

Copilot uses AI. Check for mistakes.
const std::string audio_ports[] = {"HDMI_ARC0", "HEADPHONE0", "SPDIF0", "SPEAKER0"};

// Try each port in priority order
for (const auto& portName : audio_ports)
{
try
{
AudioOutputPort aPort = getAudioOutputPort(portName);
cout << "Checking audio port: " << portName << " isEnabled: " << aPort.isEnabled() << " isConnected: " << aPort.isConnected() << "\n";
// Check if port is enabled and connected
if (aPort.isEnabled() && aPort.isConnected())
{
cout << "Using audio port: " << portName << "\n";
return aPort.getOutputPortHandle();
}
}
catch(const std::exception& e)
{
// Port not found or error accessing it, log and continue to next port
cout << "Exception while accessing audio port " << portName << ": " << e.what() << "\n";
continue;
}
}
}
}
catch(const std::exception& e)
{
cout << " Exception Thrown in getAudioPortHandle().. returning NULL...: " << e.what() << "\n";
}

Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If all audio ports in the priority list fail the enabled/connected check or throw exceptions, the function returns NULL without logging any information about why no valid port was found. This could make it difficult to diagnose issues where audio format queries fail. Consider adding a log statement before the final return to indicate that no valid audio port was found, especially since this is used by getCurrentAudioFormat which may fail silently if passed a NULL handle.

Suggested change
cout << "getAudioPortHandle(): No valid audio port found; returning NULL handle.\n";

Copilot uses AI. Check for mistakes.
return NULL;
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Returning NULL for an intptr_t type is potentially problematic. While NULL typically evaluates to 0, it's defined as a null pointer constant and may not be the most semantically appropriate choice for an integer type. Consider returning 0 explicitly instead of NULL to make the intent clearer that this represents an invalid/error handle value rather than a null pointer.

Suggested change
return NULL;
return 0;

Copilot uses AI. Check for mistakes.
}

/**
* Host::getCurrentAudioFormat(dsAudioFormat_t &audioFormat)
* @brief
Expand All @@ -397,8 +444,8 @@ Host::~Host()
{
dsError_t ret = dsERR_NONE;
dsAudioFormat_t aFormat;

ret = dsGetAudioFormat(NULL, &aFormat);
intptr_t audioPortHandle = getAudioPortHandle();
ret = dsGetAudioFormat(audioPortHandle, &aFormat);

if (ret == dsERR_NONE)
{
Expand Down
1 change: 1 addition & 0 deletions ds/include/audioOutputPort.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ class AudioOutputPort : public Enumerable {
const AudioOutputPortType & getType() const;
int getId() const {return _id;};
int getIndex() const {return _index; };
intptr_t getOutputPortHandle() const { return _handle;};


/**
Expand Down
2 changes: 1 addition & 1 deletion ds/include/exception.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class Exception : public std::exception {
*
* @return None
*/
Exception(const char *msg = "No Message for this exception") throw() : _msg(msg) {
Exception(const char *msg = "No Message for this exception") throw() : _err(0), _msg(msg) {
}


Expand Down
1 change: 1 addition & 0 deletions ds/include/host.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,7 @@ class Host {
void setSecondaryLanguage(const std::string sLang);
void getSecondaryLanguage(std::string& sLang);
bool isHDMIOutPortPresent();
intptr_t getAudioPortHandle();
std::string getDefaultVideoPortName();
std::string getDefaultAudioPortName();
void getCurrentAudioFormat(dsAudioFormat_t& audioFormat);
Expand Down
102 changes: 70 additions & 32 deletions ds/manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#include "exception.hpp"
#include <pthread.h>
#include <unistd.h>
#include <functional>

/**
* @file manager.cpp
Expand All @@ -62,6 +63,7 @@ namespace device {

int Manager::IsInitialized = 0; //!< Indicates the application has initialized with devicettings modules.
static std::mutex gManagerInitMutex;
static dsError_t initializeFunctionWithRetry(const char* functionName, std::function<dsError_t()> initFunc);

Manager::Manager() {
// TODO Auto-generated constructor stub
Expand All @@ -79,6 +81,41 @@ Manager::~Manager() {
}\
}

/**
* @brief Retry initialization function with configurable retry logic.
*
* This helper function attempts to initialize a device settings component by calling
* the provided initialization function. It retries the operation with a delay between
* attempts until either the operation succeeds, the maximum retry count is reached,
* or (optionally) a specific error state is encountered.
*
* @param[in] functionName Name of the initialization function being called. Used for logging
* purposes to identify which component is being initialized.
* @param[in] initFunc Lambda or function object that performs the actual initialization.
* Should return dsError_t indicating success (dsERR_NONE) or an error code.
*
* @return dsERR_NONE on successful initialization, or the last error code encountered after
* all retry attempts are exhausted. When checkInvalidState is true, also returns
* immediately with the error code if a non-dsERR_INVALID_STATE error occurs.
*/
dsError_t initializeFunctionWithRetry(const char* functionName,
std::function<dsError_t()> initFunc)
{
dsError_t err = dsERR_GENERAL;
unsigned int retryCount = 0;
unsigned int maxRetries = 25;

do {
err = initFunc();
printf("Manager::Initialize:%s result :%d retryCount :%d\n",
functionName, err, retryCount);
if (dsERR_NONE == err) break;
usleep(100000);
} while (retryCount++ < maxRetries);

return err;
}
Comment on lines +101 to +117
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The retry logic always retries up to 25 times (26 attempts total) regardless of the error returned. The previous implementation only retried on dsERR_INVALID_STATE errors and would stop immediately on other errors. Now all initialization functions retry on any error, which could mask genuine configuration problems or cause unnecessary delays. For example, if dsAudioPortInit fails due to missing hardware or invalid configuration, the system will still retry 25 times, adding ~2.5 seconds of delay. Consider adding error-specific retry logic or documenting why all errors warrant retries.

Copilot uses AI. Check for mistakes.

/**
* @addtogroup dssettingsmanagerapi
* @{
Expand All @@ -105,44 +142,45 @@ Manager::~Manager() {
*/
void Manager::Initialize()
{
{std::lock_guard<std::mutex> lock(gManagerInitMutex);
printf("Entering %s count %d with thread id %lu\n",__FUNCTION__,IsInitialized,pthread_self());
bool needInit = false;

{std::lock_guard<std::mutex> lock(gManagerInitMutex);
printf("Entering %s count %d with thread id %lu\n",__FUNCTION__,IsInitialized,pthread_self());
if (IsInitialized == 0) {
needInit = true;
}
IsInitialized++;
}
Comment on lines +145 to +153
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The IsInitialized counter is incremented before the initialization attempt, which means if initialization fails and an exception is thrown, the counter is decremented in the catch block. However, this creates a window where IsInitialized is incremented but initialization hasn't occurred yet. If another thread calls Initialize() during this window after the lock is released, it will see IsInitialized > 0 and skip initialization (needInit will be false). Consider moving the IsInitialized++ to after successful initialization completes, or keep it locked until after the try block completes successfully.

Copilot uses AI. Check for mistakes.

try {
if (0 == IsInitialized) {

dsError_t err = dsERR_GENERAL;
unsigned int retryCount = 0;
// This retry logic will wait for the device manager initialization from the client side
// until the device manager service initialization is completed. The retry mechanism checks
// only for dsERR_INVALID_STATE, which is reported if the underlying service is not ready.
// Once the service is ready, other port initializations can be called directly without any delay.
// That's why the retry logic is applied only for dsDisplayInit.
do {
err = dsDisplayInit();
printf ("Manager::Initialize: result :%d retryCount :%d\n", err, retryCount);
if (dsERR_NONE == err) break;
usleep(100000);
} while(( dsERR_INVALID_STATE == err) && (retryCount++ < 25));
try {
if (needInit) {
Comment on lines +147 to +156
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the new implementation, the needInit flag is checked outside the lock, allowing initialization to proceed without lock protection. Between releasing the lock at line 153 and entering the try block at line 155, another thread could also determine needInit=true and both would proceed to initialize concurrently, potentially causing race conditions in the underlying initialization functions (dsDisplayInit, dsAudioPortInit, etc.). The original implementation kept the lock held during the entire initialization sequence, preventing this race condition.

Copilot uses AI. Check for mistakes.
dsError_t err = dsERR_GENERAL;

err = initializeFunctionWithRetry("dsDisplayInit", dsDisplayInit);
CHECK_RET_VAL(err);
err = dsAudioPortInit();

err = initializeFunctionWithRetry("dsAudioPortInit", dsAudioPortInit);
CHECK_RET_VAL(err);
err = dsVideoPortInit();

err = initializeFunctionWithRetry("dsVideoPortInit", dsVideoPortInit);
CHECK_RET_VAL(err);
err = dsVideoDeviceInit();
CHECK_RET_VAL(err);
AudioOutputPortConfig::getInstance().load();
VideoOutputPortConfig::getInstance().load();
VideoDeviceConfig::getInstance().load();
}
IsInitialized++;

err = initializeFunctionWithRetry("dsVideoDeviceInit", dsVideoDeviceInit);
CHECK_RET_VAL(err);

AudioOutputPortConfig::getInstance().load();
VideoOutputPortConfig::getInstance().load();
VideoDeviceConfig::getInstance().load();
}
}
catch(const Exception &e) {
cout << "Caught exception during Initialization" << e.what() << endl;
throw e;
}
}
printf("Exiting %s with thread %lu\n",__FUNCTION__,pthread_self());
cout << "Caught exception during Initialization" << e.what() << endl;
std::lock_guard<std::mutex> lock(gManagerInitMutex);
IsInitialized--;
throw e;
}

printf("Exiting %s with thread %lu\n",__FUNCTION__,pthread_self());
}

void Manager::load()
Expand Down
2 changes: 1 addition & 1 deletion ds/videoDevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ VideoDevice & VideoDevice::getInstance(int id)
* @param[in] id Port id.
* @return None.
*/
VideoDevice::VideoDevice(int id)
VideoDevice::VideoDevice(int id): _dfc(0)
{
dsError_t ret = dsGetVideoDevice(id, &_handle);

Expand Down
2 changes: 1 addition & 1 deletion rpc/cli/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ all: install

library: $(OBJS)
@echo "Building $(LIBNAMEFULL) ...."
$(CXX) $(OBJS) $(CFLAGS) -shared -o $(LIBNAMEFULL)
$(CXX) $(OBJS) $(CFLAGS) -lIARMBus -shared -o $(LIBNAMEFULL)

%.o: %.cpp
@echo "Building $@ ...."
Expand Down
4 changes: 2 additions & 2 deletions rpc/cli/dsVideoPort.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ dsError_t dsGetVideoPort(dsVideoPortType_t type, int index, intptr_t *handle)
&param,
sizeof(param));

printf("%s..%d-%d\n",__func__,param.type,param.handle);
printf("%s..%d-%ld\n",__func__,param.type,(long)param.handle);

if (IARM_RESULT_SUCCESS == rpcRet)
{
Expand Down Expand Up @@ -530,7 +530,7 @@ dsError_t dsEnableHDCP(intptr_t handle, bool contentProtect, char *hdcpKey, siz
}
}

printf("IARM:CLI:dsEnableHDCP %d, %p, %d\r\n", contentProtect, hdcpKey, keySize);
printf("IARM:CLI:dsEnableHDCP %d, %p, %zu\r\n", contentProtect, hdcpKey, keySize);

IARM_Result_t rpcRet = IARM_RESULT_SUCCESS;
rpcRet = IARM_Bus_Call(IARM_BUS_DSMGR_NAME,
Expand Down
Loading
Loading