From 1e47fd78f11dab4b2f6cffa766417f111434f734 Mon Sep 17 00:00:00 2001 From: Benny Prijono Date: Fri, 14 Mar 2014 04:09:50 +0000 Subject: Closed #1748: enhancements to WAV player API git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@4793 74dad513-b988-da41-8d7b-12977e46ad98 --- pjsip/include/pjsua-lib/pjsua.h | 24 ++++++++++++- pjsip/include/pjsua2/media.hpp | 76 +++++++++++++++++++++++++++++++++++++++-- pjsip/src/pjsua-lib/pjsua_aud.c | 59 +++++++++++++++++++++++++++++--- pjsip/src/pjsua2/media.cpp | 61 +++++++++++++++++++++++++++++++++ 4 files changed, 211 insertions(+), 9 deletions(-) (limited to 'pjsip') diff --git a/pjsip/include/pjsua-lib/pjsua.h b/pjsip/include/pjsua-lib/pjsua.h index 00699962..895d9bd8 100644 --- a/pjsip/include/pjsua-lib/pjsua.h +++ b/pjsip/include/pjsua-lib/pjsua.h @@ -6070,6 +6070,29 @@ PJ_DECL(pjsua_conf_port_id) pjsua_player_get_conf_port(pjsua_player_id id); PJ_DECL(pj_status_t) pjsua_player_get_port(pjsua_player_id id, pjmedia_port **p_port); +/** + * Get additional info about the file player. This operation is not valid + * for playlist. + * + * @param port The file player ID. + * @param info The info. + * + * @return PJ_SUCCESS on success or the appropriate error code. + */ +PJ_DECL(pj_status_t) pjsua_player_get_info(pjsua_player_id id, + pjmedia_wav_player_info *info); + + +/** + * Get playback position. This operation is not valid for playlist. + * + * @param id The file player ID. + * + * @return The current playback position, in samples. On error, + * return the error code as negative value. + */ +PJ_DECL(pj_ssize_t) pjsua_player_get_pos(pjsua_player_id id); + /** * Set playback position. This operation is not valid for playlist. * @@ -6082,7 +6105,6 @@ PJ_DECL(pj_status_t) pjsua_player_get_port(pjsua_player_id id, PJ_DECL(pj_status_t) pjsua_player_set_pos(pjsua_player_id id, pj_uint32_t samples); - /** * Close the file of playlist, remove the player from the bridge, and free * resources associated with the file player or playlist. diff --git a/pjsip/include/pjsua2/media.hpp b/pjsip/include/pjsua2/media.hpp index 830f09b7..2f3a6855 100644 --- a/pjsip/include/pjsua2/media.hpp +++ b/pjsip/include/pjsua2/media.hpp @@ -313,6 +313,33 @@ private: /** Array of Audio Media */ typedef std::vector AudioMediaVector; +/** + * This structure contains additional info about AudioMediaPlayer. + */ +struct AudioMediaPlayerInfo +{ + /** + * Format ID of the payload. + */ + pjmedia_format_id formatId; + + /** + * The number of bits per sample of the file payload. For example, + * the value is 16 for PCM WAV and 8 for Alaw/Ulas WAV files. + */ + unsigned payloadBitsPerSample; + + /** + * The WAV payload size in bytes. + */ + pj_uint32_t sizeBytes; + + /** + * The WAV payload size in samples. + */ + pj_uint32_t sizeSamples; +}; + /** * Audio Media Player. */ @@ -354,7 +381,24 @@ public: unsigned options=0) throw(Error); /** - * Set playback position. This operation is not valid for playlist. + * Get additional info about the player. This operation is only valid + * for player. For playlist, Error will be thrown. + * + * @return the info. + */ + AudioMediaPlayerInfo getInfo() const throw(Error); + + /** + * Get current playback position in samples. This operation is not valid + * for playlist. + * + * @return Current playback position, in samples. + */ + pj_uint32_t getPos() const throw(Error); + + /** + * Set playback position in samples. This operation is not valid for + * playlist. * * @param samples The desired playback position, in samples. */ @@ -371,16 +415,42 @@ public: static AudioMediaPlayer* typecastFromAudioMedia(AudioMedia *media); /** - * Virtual destructor. + * Destructor. */ virtual ~AudioMediaPlayer(); +public: + /* + * Callbacks + */ + + /** + * Register a callback to be called when the file player reading has + * reached the end of file, or when the file reading has reached the + * end of file of the last file for a playlist. If the file or playlist + * is set to play repeatedly, then the callback will be called multiple + * times. + * + * @return If the callback returns false, the playback + * will stop. Note that if application destroys + * the player in the callback, it must return + * false here. + */ + virtual bool onEof() + { return true; } + + private: /** * Player Id. */ int playerId; + /** + * Low level PJMEDIA callback + */ + static pj_status_t eof_cb(pjmedia_port *port, + void *usr_data); }; /** @@ -430,7 +500,7 @@ public: static AudioMediaRecorder* typecastFromAudioMedia(AudioMedia *media); /** - * Virtual destructor. + * Destructor. */ virtual ~AudioMediaRecorder(); diff --git a/pjsip/src/pjsua-lib/pjsua_aud.c b/pjsip/src/pjsua-lib/pjsua_aud.c index 0f5172e9..f4f93a09 100644 --- a/pjsip/src/pjsua-lib/pjsua_aud.c +++ b/pjsip/src/pjsua-lib/pjsua_aud.c @@ -1192,7 +1192,7 @@ on_error: */ PJ_DEF(pjsua_conf_port_id) pjsua_player_get_conf_port(pjsua_player_id id) { - PJ_ASSERT_RETURN(id>=0&&id<(int)PJ_ARRAY_SIZE(pjsua_var.player), PJ_EINVAL); + PJ_ASSERT_RETURN(id>=0&&id<(int)PJ_ARRAY_SIZE(pjsua_var.player),PJ_EINVAL); PJ_ASSERT_RETURN(pjsua_var.player[id].port != NULL, PJ_EINVAL); return pjsua_var.player[id].slot; @@ -1204,7 +1204,7 @@ PJ_DEF(pjsua_conf_port_id) pjsua_player_get_conf_port(pjsua_player_id id) PJ_DEF(pj_status_t) pjsua_player_get_port( pjsua_player_id id, pjmedia_port **p_port) { - PJ_ASSERT_RETURN(id>=0&&id<(int)PJ_ARRAY_SIZE(pjsua_var.player), PJ_EINVAL); + PJ_ASSERT_RETURN(id>=0&&id<(int)PJ_ARRAY_SIZE(pjsua_var.player),PJ_EINVAL); PJ_ASSERT_RETURN(pjsua_var.player[id].port != NULL, PJ_EINVAL); PJ_ASSERT_RETURN(p_port != NULL, PJ_EINVAL); @@ -1213,17 +1213,66 @@ PJ_DEF(pj_status_t) pjsua_player_get_port( pjsua_player_id id, return PJ_SUCCESS; } +/* + * Get player info. + */ +PJ_DEF(pj_status_t) pjsua_player_get_info(pjsua_player_id id, + pjmedia_wav_player_info *info) +{ + PJ_ASSERT_RETURN(id>=0&&id<(int)PJ_ARRAY_SIZE(pjsua_var.player), + -PJ_EINVAL); + PJ_ASSERT_RETURN(pjsua_var.player[id].port != NULL, PJ_EINVAL); + PJ_ASSERT_RETURN(pjsua_var.player[id].type == 0, PJ_EINVAL); + + return pjmedia_wav_player_get_info(pjsua_var.player[id].port, info); +} + +/* + * Get playback position. + */ +PJ_DEF(pj_ssize_t) pjsua_player_get_pos( pjsua_player_id id ) +{ + pj_ssize_t pos_bytes; + pjmedia_wav_player_info info; + pj_status_t status; + + PJ_ASSERT_RETURN(id>=0&&id<(int)PJ_ARRAY_SIZE(pjsua_var.player), + -PJ_EINVAL); + PJ_ASSERT_RETURN(pjsua_var.player[id].port != NULL, -PJ_EINVAL); + PJ_ASSERT_RETURN(pjsua_var.player[id].type == 0, -PJ_EINVAL); + + pos_bytes = pjmedia_wav_player_port_get_pos(pjsua_var.player[id].port); + if (pos_bytes < 0) + return pos_bytes; + + status = pjmedia_wav_player_get_info(pjsua_var.player[id].port, &info); + if (status != PJ_SUCCESS) + return -status; + + return pos_bytes / (info.payload_bits_per_sample / 8); +} + /* * Set playback position. */ PJ_DEF(pj_status_t) pjsua_player_set_pos( pjsua_player_id id, pj_uint32_t samples) { - PJ_ASSERT_RETURN(id>=0&&id<(int)PJ_ARRAY_SIZE(pjsua_var.player), PJ_EINVAL); + pjmedia_wav_player_info info; + pj_uint32_t pos_bytes; + pj_status_t status; + + PJ_ASSERT_RETURN(id>=0&&id<(int)PJ_ARRAY_SIZE(pjsua_var.player),PJ_EINVAL); PJ_ASSERT_RETURN(pjsua_var.player[id].port != NULL, PJ_EINVAL); PJ_ASSERT_RETURN(pjsua_var.player[id].type == 0, PJ_EINVAL); - return pjmedia_wav_player_port_set_pos(pjsua_var.player[id].port, samples); + status = pjmedia_wav_player_get_info(pjsua_var.player[id].port, &info); + if (status != PJ_SUCCESS) + return status; + + pos_bytes = samples * (info.payload_bits_per_sample / 8); + return pjmedia_wav_player_port_set_pos(pjsua_var.player[id].port, + pos_bytes); } @@ -1233,7 +1282,7 @@ PJ_DEF(pj_status_t) pjsua_player_set_pos( pjsua_player_id id, */ PJ_DEF(pj_status_t) pjsua_player_destroy(pjsua_player_id id) { - PJ_ASSERT_RETURN(id>=0&&id<(int)PJ_ARRAY_SIZE(pjsua_var.player), PJ_EINVAL); + PJ_ASSERT_RETURN(id>=0&&id<(int)PJ_ARRAY_SIZE(pjsua_var.player),PJ_EINVAL); PJ_ASSERT_RETURN(pjsua_var.player[id].port != NULL, PJ_EINVAL); PJ_LOG(4,(THIS_FILE, "Destroying player %d..", id)); diff --git a/pjsip/src/pjsua2/media.cpp b/pjsip/src/pjsua2/media.cpp index a5676399..a6255ec2 100644 --- a/pjsip/src/pjsua2/media.cpp +++ b/pjsip/src/pjsua2/media.cpp @@ -262,6 +262,21 @@ void AudioMediaPlayer::createPlayer(const string &file_name, options, &playerId) ); + /* Register EOF callback */ + pjmedia_port *port; + pj_status_t status; + + status = pjsua_player_get_port(playerId, &port); + if (status != PJ_SUCCESS) { + pjsua_player_destroy(playerId); + PJSUA2_RAISE_ERROR2(status, "AudioMediaPlayer::createPlayer()"); + } + status = pjmedia_wav_player_set_eof_cb(port, this, &eof_cb); + if (status != PJ_SUCCESS) { + pjsua_player_destroy(playerId); + PJSUA2_RAISE_ERROR2(status, "AudioMediaPlayer::createPlayer()"); + } + /* Get media port id. */ id = pjsua_player_get_conf_port(playerId); @@ -280,6 +295,7 @@ void AudioMediaPlayer::createPlaylist(const StringVector &file_names, pj_str_t pj_files[MAX_FILE_NAMES]; unsigned i, count = 0; pj_str_t pj_lbl = str2Pj(label); + pj_status_t status; count = PJ_ARRAY_SIZE(pj_files); @@ -296,12 +312,50 @@ void AudioMediaPlayer::createPlaylist(const StringVector &file_names, options, &playerId) ); + /* Register EOF callback */ + pjmedia_port *port; + status = pjsua_player_get_port(playerId, &port); + if (status != PJ_SUCCESS) { + pjsua_player_destroy(playerId); + PJSUA2_RAISE_ERROR2(status, "AudioMediaPlayer::createPlaylist()"); + } + status = pjmedia_wav_playlist_set_eof_cb(port, this, &eof_cb); + if (status != PJ_SUCCESS) { + pjsua_player_destroy(playerId); + PJSUA2_RAISE_ERROR2(status, "AudioMediaPlayer::createPlaylist()"); + } + /* Get media port id. */ id = pjsua_player_get_conf_port(playerId); registerMediaPort(NULL); } +AudioMediaPlayerInfo AudioMediaPlayer::getInfo() const throw(Error) +{ + AudioMediaPlayerInfo info; + pjmedia_wav_player_info pj_info; + + PJSUA2_CHECK_EXPR( pjsua_player_get_info(playerId, &pj_info) ); + + pj_bzero(&info, sizeof(info)); + info.formatId = pj_info.fmt_id; + info.payloadBitsPerSample = pj_info.payload_bits_per_sample; + info.sizeBytes = pj_info.size_bytes; + info.sizeSamples = pj_info.size_samples; + + return info; +} + +pj_uint32_t AudioMediaPlayer::getPos() const throw(Error) +{ + pj_ssize_t pos = pjsua_player_get_pos(playerId); + if (pos < 0) { + PJSUA2_RAISE_ERROR2(-pos, "AudioMediaPlayer::getPos()"); + } + return (pj_uint32_t)pos; +} + void AudioMediaPlayer::setPos(pj_uint32_t samples) throw(Error) { PJSUA2_CHECK_EXPR( pjsua_player_set_pos(playerId, samples) ); @@ -313,6 +367,13 @@ AudioMediaPlayer* AudioMediaPlayer::typecastFromAudioMedia( return static_cast(media); } +pj_status_t AudioMediaPlayer::eof_cb(pjmedia_port *port, + void *usr_data) +{ + AudioMediaPlayer *player = (AudioMediaPlayer*)usr_data; + return player->onEof() ? PJ_SUCCESS : PJ_EEOF; +} + /////////////////////////////////////////////////////////////////////////////// AudioMediaRecorder::AudioMediaRecorder() : recorderId(PJSUA_INVALID_ID) -- cgit v1.2.3