summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2014-03-14 04:09:50 +0000
committerBenny Prijono <bennylp@teluu.com>2014-03-14 04:09:50 +0000
commit1e47fd78f11dab4b2f6cffa766417f111434f734 (patch)
tree016d93a205659ea85c7d315412307e580911668e
parent9ff22c2ff305ee03b10d1d611eab060e5097cbe5 (diff)
Closed #1748: enhancements to WAV player API
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@4793 74dad513-b988-da41-8d7b-12977e46ad98
-rw-r--r--pjmedia/include/pjmedia/wav_port.h48
-rw-r--r--pjmedia/src/pjmedia/wav_player.c40
-rw-r--r--pjsip-apps/src/3rdparty_media_sample/alt_pjsua_aud.c15
-rw-r--r--pjsip/include/pjsua-lib/pjsua.h24
-rw-r--r--pjsip/include/pjsua2/media.hpp76
-rw-r--r--pjsip/src/pjsua-lib/pjsua_aud.c59
-rw-r--r--pjsip/src/pjsua2/media.cpp61
7 files changed, 309 insertions, 14 deletions
diff --git a/pjmedia/include/pjmedia/wav_port.h b/pjmedia/include/pjmedia/wav_port.h
index 29467836..bd6037f0 100644
--- a/pjmedia/include/pjmedia/wav_port.h
+++ b/pjmedia/include/pjmedia/wav_port.h
@@ -52,6 +52,35 @@ enum pjmedia_file_player_option
/**
+ * Additional information about the WAV player.
+ */
+typedef struct pjmedia_wav_player_info
+{
+ /**
+ * Format ID of the payload.
+ */
+ pjmedia_format_id fmt_id;
+
+ /**
+ * 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 payload_bits_per_sample;
+
+ /**
+ * The WAV payload size in bytes.
+ */
+ pj_uint32_t size_bytes;
+
+ /**
+ * The WAV payload size in samples.
+ */
+ pj_uint32_t size_samples;
+
+} pjmedia_wav_player_info;
+
+
+/**
* Create a media port to play streams from a WAV file. WAV player port
* supports for reading WAV file with uncompressed 16 bit PCM format or
* compressed G.711 A-law/U-law format.
@@ -76,14 +105,24 @@ PJ_DECL(pj_status_t) pjmedia_wav_player_port_create( pj_pool_t *pool,
pj_ssize_t buff_size,
pjmedia_port **p_port );
+/**
+ * Get additional info about the file player.
+ *
+ * @param port The file port.
+ * @param i The info.
+ *
+ * @return PJ_SUCCESS on success or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pjmedia_wav_player_get_info(pjmedia_port *port,
+ pjmedia_wav_player_info *i);
/**
* Get the data length, in bytes.
*
* @param port The file player port.
*
- * @return The length of the data, in bytes. Upon error it will
- * return negative value.
+ * @return The length of the data, in bytes. On error, the
+ * error code is given as negative value.
*/
PJ_DECL(pj_ssize_t) pjmedia_wav_player_get_len(pjmedia_port *port);
@@ -102,11 +141,12 @@ PJ_DECL(pj_status_t) pjmedia_wav_player_port_set_pos( pjmedia_port *port,
/**
- * Get the file play position of WAV player.
+ * Get the file play position of WAV player, in bytes.
*
* @param port The file player port.
*
- * @return PJ_SUCCESS on success.
+ * @return The current play position, in bytes. On error, the
+ * error code is given as negative value.
*/
PJ_DECL(pj_ssize_t) pjmedia_wav_player_port_get_pos( pjmedia_port *port );
diff --git a/pjmedia/src/pjmedia/wav_player.c b/pjmedia/src/pjmedia/wav_player.c
index 78a02e04..1e9a92ca 100644
--- a/pjmedia/src/pjmedia/wav_player.c
+++ b/pjmedia/src/pjmedia/wav_player.c
@@ -425,6 +425,44 @@ PJ_DEF(pj_status_t) pjmedia_wav_player_port_create( pj_pool_t *pool,
/*
+ * Get additional info about the file player.
+ */
+PJ_DEF(pj_status_t) pjmedia_wav_player_get_info(
+ pjmedia_port *port,
+ pjmedia_wav_player_info *info)
+{
+ struct file_reader_port *fport;
+ PJ_ASSERT_RETURN(port && info, PJ_EINVAL);
+
+ pj_bzero(info, sizeof(*info));
+
+ /* Check that this is really a player port */
+ PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, PJ_EINVALIDOP);
+
+ fport = (struct file_reader_port*) port;
+
+ if (fport->fmt_tag == PJMEDIA_WAVE_FMT_TAG_PCM) {
+ info->fmt_id = PJMEDIA_FORMAT_PCM;
+ info->payload_bits_per_sample = 16;
+ } else if (fport->fmt_tag == PJMEDIA_WAVE_FMT_TAG_ULAW) {
+ info->fmt_id = PJMEDIA_FORMAT_ULAW;
+ info->payload_bits_per_sample = 8;
+ } else if (fport->fmt_tag == PJMEDIA_WAVE_FMT_TAG_ALAW) {
+ info->fmt_id = PJMEDIA_FORMAT_ALAW;
+ info->payload_bits_per_sample = 8;
+ } else {
+ pj_assert(!"Unsupported format");
+ return PJ_ENOTSUP;
+ }
+
+ info->size_bytes = pjmedia_wav_player_get_len(port);
+ info->size_samples = info->size_bytes /
+ (info->payload_bits_per_sample / 8);
+
+ return PJ_SUCCESS;
+}
+
+/*
* Get the data length, in bytes.
*/
PJ_DEF(pj_ssize_t) pjmedia_wav_player_get_len(pjmedia_port *port)
@@ -484,7 +522,7 @@ PJ_DEF(pj_status_t) pjmedia_wav_player_port_set_pos(pjmedia_port *port,
/*
- * Get the file play position of WAV player.
+ * Get the file play position of WAV player (in bytes).
*/
PJ_DEF(pj_ssize_t) pjmedia_wav_player_port_get_pos( pjmedia_port *port )
{
diff --git a/pjsip-apps/src/3rdparty_media_sample/alt_pjsua_aud.c b/pjsip-apps/src/3rdparty_media_sample/alt_pjsua_aud.c
index 2b85421e..bc17be82 100644
--- a/pjsip-apps/src/3rdparty_media_sample/alt_pjsua_aud.c
+++ b/pjsip-apps/src/3rdparty_media_sample/alt_pjsua_aud.c
@@ -496,6 +496,21 @@ PJ_DEF(pj_status_t) pjsua_player_get_port( pjsua_player_id id,
return PJ_ENOTSUP;
}
+/* Get number of bits per sample of the WAV payload */
+PJ_DEF(pj_status_t) pjsua_player_get_info(pjsua_player_id id,
+ pjmedia_wav_player_info *info)
+{
+ UNIMPLEMENTED(pjsua_player_get_info)
+ return PJ_ENOTSUP;
+}
+
+/* Get position in samples */
+PJ_DEF(pj_ssize_t) pjsua_player_get_pos(pjsua_player_id id)
+{
+ UNIMPLEMENTED(pjsua_player_get_pos)
+ return -PJ_ENOTSUP;
+}
+
/* Set playback position. */
PJ_DEF(pj_status_t) pjsua_player_set_pos( pjsua_player_id id,
pj_uint32_t samples)
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
@@ -6071,6 +6071,29 @@ 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.
*
* @param id The file player ID.
@@ -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
@@ -314,6 +314,33 @@ private:
typedef std::vector<AudioMedia*> 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.
*/
class AudioMediaPlayer : public AudioMedia
@@ -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);
@@ -1214,16 +1214,65 @@ PJ_DEF(pj_status_t) pjsua_player_get_port( pjsua_player_id id,
}
/*
+ * 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<AudioMediaPlayer*>(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)