Skip to content

Commit

Permalink
Media Framework updates: FocusManager and Volume as per stream info.
Browse files Browse the repository at this point in the history
Focus Manager update:
1. Make requestFocus a mandatory step for media playback

Add volume control
1. Stream Info is registered in MediaPlayer.
2. Last set volume level of a policy is stored in a json file in /mnt
partition.
3. A stream will be played according to its volume set in json file.
4. If volume is not stored for a stream policy then default driver level
volume is used.
  • Loading branch information
vibhor-m authored and Taejun-Kwon committed Nov 16, 2024
1 parent 8771b65 commit a9dac70
Show file tree
Hide file tree
Showing 24 changed files with 733 additions and 43 deletions.
75 changes: 75 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
{
"files.associations": {
"__bit_reference": "cpp",
"__config": "cpp",
"__debug": "cpp",
"__functional_base": "cpp",
"__locale": "cpp",
"__nullptr": "cpp",
"__split_buffer": "cpp",
"__string": "cpp",
"__tree": "cpp",
"__tuple": "cpp",
"algorithm": "cpp",
"array": "cpp",
"atomic": "cpp",
"bitset": "cpp",
"cctype": "cpp",
"chrono": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"exception": "cpp",
"optional": "cpp",
"string_view": "cpp",
"functional": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"ios": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"istream": "cpp",
"iterator": "cpp",
"limits": "cpp",
"locale": "cpp",
"map": "cpp",
"memory": "cpp",
"mutex": "cpp",
"new": "cpp",
"ostream": "cpp",
"random": "cpp",
"ratio": "cpp",
"set": "cpp",
"stdexcept": "cpp",
"streambuf": "cpp",
"string": "cpp",
"system_error": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"typeinfo": "cpp",
"utility": "cpp",
"vector": "cpp",
"cstdarg": "cpp",
"*.tcc": "cpp",
"memory_resource": "cpp",
"cinttypes": "cpp",
"bit": "cpp",
"unordered_map": "cpp",
"ble.h": "c",
"deque": "cpp",
"fstream": "cpp",
"numeric": "cpp",
"queue": "cpp",
"sstream": "cpp",
"hash_map": "cpp",
"hash_set": "cpp",
"unordered_set": "cpp"
}
}
39 changes: 36 additions & 3 deletions apps/examples/SoundPlayer/soundplayer_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -257,13 +257,14 @@ bool SoundPlayer::init(char *argv[])
printf("Current volume : %d new Volume : %d\n", cur_vol, volume);
mp.setVolume(volume);
stream_info_t *info;
stream_info_create(STREAM_TYPE_MEDIA, &info);
stream_info_create((stream_policy_t)(atoi(argv[4])), &info);
auto deleter = [](stream_info_t *ptr) { stream_info_destroy(ptr); };
auto stream_info = std::shared_ptr<stream_info_t>(info, deleter);
mFocusRequest = FocusRequest::Builder()
.setStreamInfo(stream_info)
.setFocusChangeListener(shared_from_this())
.build();
mp.setStreamInfo(stream_info);

mSampleRate = atoi(argv[3]);
mTrackFinished = false;
Expand All @@ -280,7 +281,6 @@ player_result_t SoundPlayer::startPlayback(void)
player_result_t res = PLAYER_OK;
string s = mList.at(mPlayIndex);
printf("startPlayback... playIndex : %d path : %s\n", mPlayIndex, s.c_str());
usleep(200000);
auto source = std::move(unique_ptr<FileInputDataSource>(new FileInputDataSource((const string)s)));
source->setSampleRate(mSampleRate);
source->setChannels(DEFAULT_CHANNEL_NUM);
Expand Down Expand Up @@ -343,11 +343,44 @@ bool SoundPlayer::checkTrackFinished(void)
}

extern "C" {
/*
This is guide to use MediaPlayer with focus request.
As MediaPlayer is updated and now without focus request, MediaPlayer can't use audio device!!!
Steps to follow to play an audio data are as follows:
1) Application to create a listener to receive onFocusChange callback. Application needs to implement FocusChangeListener interface.
2) Sample source code to create a FocusRequest object and requestFocus is as follows:
stream_info_t *info;
stream_info_create(STREAM_TYPE_BIXBY, &info); //refer to stream_policy_e for various stream types
auto deleter = [](stream_info_t *ptr) { stream_info_destroy(ptr); };
auto stream_info = std::shared_ptr<stream_info_t>(info, deleter);
mFocusRequest = FocusRequest::Builder()
.setStreamInfo(stream_info)
.setFocusChangeListener(mFocusObserver)
.build();
mp.setStreamInfo(stream_info);
auto &focusManager = FocusManager::getFocusManager();
focusManager.requestFocus(mFocusRequest);
3) Application should handle onFocusChange for FOCUS_LOSS during playback. Application must pause/stop playaback when FOCUS_LOSS / FOCUS_LOSS_TRANSIENT recevied
4) When playback finsihes, application must call abandonFocus to release focus.
5) Mandatory condition, requestFocus must be done and onFocusChange with FOCUS_GAIN options received before calling mediaplayer.prepare
6) Sequence of MediaPlayer API calls are as follows:
mp.create();
mp.setObserver(mMediaPlayerObserverInterface);
mp.setStreamInfo(stream_info);
mp.setDataSource(source);
mp.prepare();
mp.start();
mp.stop();/mp.pause();
mp.unprepare();
mp.destroy();
*/
int soundplayer_main(int argc, char *argv[])
{
auto player = std::shared_ptr<SoundPlayer>(new SoundPlayer());
printf("cur SoundPlayer : %x\n", &player);
if (argc != 4) {
if (argc != 5) {
printf("invalid input\n");
return -1;
}
Expand Down
21 changes: 20 additions & 1 deletion framework/include/media/FocusManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ namespace media {

static const int FOCUS_REQUEST_SUCCESS = 0;
static const int FOCUS_REQUEST_FAIL = -1;
static const int FOCUS_REQUEST_DELAY = -2;

/**
* @class
Expand Down Expand Up @@ -69,17 +70,34 @@ class FocusManager
* @brief Request Focus
* @details @b #include <media/FocusManager.h>
* param[in] focusRequest FocusRequest to request
* @return return FOCUS_REQUEST_SUCCESS on Success, else return FOCUS_REQUEST_FAIL
* @return return FOCUS_REQUEST_SUCCESS on immediate GAIN and FOCUS_REQUEST_DELAY for GAIN later, else return FOCUS_REQUEST_FAIL
* @since TizenRT v2.0
*/
int requestFocus(std::shared_ptr<FocusRequest> focusRequest);

/**
* @brief Request Transient Focus
* @details @b #include <media/FocusManager.h>
* param[in] focusRequest FocusRequest to request
* @return return FOCUS_REQUEST_SUCCESS on immediate GAIN and FOCUS_REQUEST_DELAY for GAIN later, else return FOCUS_REQUEST_FAIL
* @since TizenRT v2.0
*/
int requestFocusTransient(std::shared_ptr<FocusRequest> focusRequest);

/**
* @brief Get current focussed stream info
* @details @b #include <media/FocusManager.h>
* @return return STREAM_FOCUS_STATE_ACQUIRED if stream has focus, else return STREAM_FOCUS_STATE_RELEASED
*/
stream_info_t getCurrentStreamInfo(void);

private:
class FocusRequester
{
public:
FocusRequester(std::shared_ptr<stream_info_t> stream_info, std::shared_ptr<FocusChangeListener> listener);
bool hasSameId(std::shared_ptr<FocusRequest> focusRequest);
stream_info_t getStreamInfo(void);
void notify(int focusChange);

static bool compare(const FocusRequester a, const FocusRequester b);
Expand All @@ -92,6 +110,7 @@ class FocusManager

FocusManager() = default;
virtual ~FocusManager() = default;
int insertFocusElement(std::shared_ptr<FocusRequest> focusRequest, bool isTransientRequest);
void removeFocusElement(std::shared_ptr<FocusRequest> focusRequest);
std::list<std::shared_ptr<FocusRequester>> mFocusList;
std::mutex mFocusLock;
Expand Down
21 changes: 20 additions & 1 deletion framework/include/media/MediaPlayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ namespace media {
*/
enum player_error_e : int {
/** MediaPlayer Error case */
PLAYER_ERROR_NOT_ALIVE = -9,
PLAYER_ERROR_NOT_ALIVE = -10,
PLAYER_ERROR_FOCUS_NOT_READY,
PLAYER_ERROR_PLAYBACK_FINISHED,
PLAYER_ERROR_INVALID_STATE,
PLAYER_ERROR_INVALID_OPERATION,
Expand Down Expand Up @@ -230,6 +231,15 @@ class MediaPlayer
*/
bool isPlaying();

/**
* @brief set stream_info of MediaPlayer
* @details @b #include <media/MediaPlayer.h>
* This function is a synchronous API
* param[in] stream_info shared_ptr of stream_info_t
* @return The result of the setStreamInfo operation
*/
player_result_t setStreamInfo(std::shared_ptr<stream_info_t> stream_info);

/**
* @brief Set Playback to be looping or non-looping
* @details @b #include <media/MediaPlayer.h>
Expand All @@ -238,9 +248,18 @@ class MediaPlayer
* @since TizenRT v5.0
*/
player_result_t setLooping(bool loop);

private:
std::shared_ptr<MediaPlayerImpl> mPMpImpl;
uint64_t mId;

/**
* @brief Get the current set volume of player stream type
* @details @b #include <media/MediaPlayer.h>
* This function is a synchronous API
* @return The current set volume of player stream type
*/
player_result_t getStreamVolume(uint8_t *volume);
};
} // namespace media
#endif
Expand Down
1 change: 1 addition & 0 deletions framework/include/media/OutputDataSource.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#ifndef __MEDIA_OUTPUTDATASOURCE_H
#define __MEDIA_OUTPUTDATASOURCE_H

#include <memory>
#include <pthread.h>
#include <media/DataSource.h>
#include <media/BufferObserverInterface.h>
Expand Down
11 changes: 6 additions & 5 deletions framework/include/media/stream_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,12 @@ typedef enum stream_focus_state_e stream_focus_state_t;
* @brief Stream Policy, high value means higher priority
*/
enum stream_policy_e {
STREAM_TYPE_MEDIA = 0,
STREAM_TYPE_VOIP = 1,
STREAM_TYPE_NOTIFY = 2,
STREAM_TYPE_VOICE_RECOGNITION = 3,
STREAM_TYPE_EMERGENCY = 4
STREAM_TYPE_MEDIA = 0, /* Default value, music play */
STREAM_TYPE_NOTIFY = 1, /* For notification */
STREAM_TYPE_BIXBY = 2,
STREAM_TYPE_VOICE_RECORD = 3, /* Record */
STREAM_TYPE_VOIP = 4, /* Call */
STREAM_TYPE_EMERGENCY = 5
};

typedef enum stream_policy_e stream_policy_t;
Expand Down
68 changes: 57 additions & 11 deletions framework/src/media/FocusManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
******************************************************************/

#include <media/FocusManager.h>

#include <debug.h>
namespace media {

FocusManager::FocusRequester::FocusRequester(std::shared_ptr<stream_info_t> stream_info, std::shared_ptr<FocusChangeListener> listener)
Expand All @@ -30,9 +30,18 @@ bool FocusManager::FocusRequester::hasSameId(std::shared_ptr<FocusRequest> focus
return mId == focusRequest->getStreamInfo()->id;
}

stream_info_t FocusManager::FocusRequester::getStreamInfo(void)
{
return {mId, mPolicy};
}

bool FocusManager::FocusRequester::compare(const FocusManager::FocusRequester a, const FocusManager::FocusRequester b)
{
return a.mPolicy >= b.mPolicy;
if (a.mPolicy <= STREAM_TYPE_BIXBY && b.mPolicy <= STREAM_TYPE_BIXBY) {
return true;
} else {
return a.mPolicy >= b.mPolicy;
}
}

void FocusManager::FocusRequester::notify(int focusChange)
Expand Down Expand Up @@ -75,12 +84,31 @@ int FocusManager::requestFocus(std::shared_ptr<FocusRequest> focusRequest)
return FOCUS_REQUEST_FAIL;
}

return insertFocusElement(focusRequest, false);
}

int FocusManager::requestFocusTransient(std::shared_ptr<FocusRequest> focusRequest)
{
std::lock_guard<std::mutex> lock(mFocusLock);
if (focusRequest == nullptr) {
return FOCUS_REQUEST_FAIL;
}

return insertFocusElement(focusRequest, true);
}

int FocusManager::insertFocusElement(std::shared_ptr<FocusRequest> focusRequest, bool isTransientRequest)
{
medvdbg("insertFocusElement!!\n");
/* If list is empty, request always gain focus */
if (mFocusList.empty()) {
auto focusRequester = std::make_shared<FocusRequester>(focusRequest->getStreamInfo(), focusRequest->getListener());
mFocusList.push_front(focusRequester);
focusRequester->notify(FOCUS_GAIN);

if (isTransientRequest) {
focusRequester->notify(FOCUS_GAIN_TRANSIENT);
} else {
focusRequester->notify(FOCUS_GAIN);
}
return FOCUS_REQUEST_SUCCESS;
}

Expand All @@ -96,13 +124,18 @@ int FocusManager::requestFocus(std::shared_ptr<FocusRequest> focusRequest)

/* If the policy of request is the highest prio */
if (FocusRequester::compare(*focusRequester, *(*iter))) {

mFocusList.front()->notify(FOCUS_LOSS);
/* TODO add usleep as a temp code. gain should not be shared until prev player stop properly */
usleep(100000);
if (isTransientRequest) {
mFocusList.front()->notify(FOCUS_LOSS_TRANSIENT);
} else {
mFocusList.front()->notify(FOCUS_LOSS);
}
mFocusList.push_front(focusRequester);
focusRequester->notify(FOCUS_GAIN);
usleep(100000);

if (isTransientRequest) {
focusRequester->notify(FOCUS_GAIN_TRANSIENT);
} else {
focusRequester->notify(FOCUS_GAIN);
}
return FOCUS_REQUEST_SUCCESS;
}

Expand All @@ -118,7 +151,20 @@ int FocusManager::requestFocus(std::shared_ptr<FocusRequest> focusRequest)
mFocusList.push_back(focusRequester);
}

return FOCUS_REQUEST_SUCCESS;
return FOCUS_REQUEST_DELAY;
}

stream_info_t FocusManager::getCurrentStreamInfo(void)
{
medvdbg("getCurrentStreamInfo!!\n");
stream_info_t stream_info;
if (mFocusList.empty()) {
stream_info = {0, STREAM_TYPE_MEDIA};
return stream_info;
}
auto iterator = mFocusList.begin();
stream_info = (*iterator)->getStreamInfo();
return stream_info;
}

void FocusManager::removeFocusElement(std::shared_ptr<FocusRequest> focusRequest)
Expand Down
Loading

0 comments on commit a9dac70

Please sign in to comment.