Fixed #2251: Deadlock between PJSUA LOCK and conference mutex
git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@6112 74dad513-b988-da41-8d7b-12977e46ad98
This commit is contained in:
parent
5048567815
commit
e472147378
|
@ -138,6 +138,7 @@ pjmedia_avi_stream_get_port(pjmedia_avi_stream *stream)
|
|||
PJ_DECL(pj_ssize_t) pjmedia_avi_stream_get_len(pjmedia_avi_stream *stream);
|
||||
|
||||
|
||||
#if !DEPRECATED_FOR_TICKET_2251
|
||||
/**
|
||||
* Register a callback to be called when the file reading has reached the
|
||||
* end of file. If the file is set to play repeatedly, then the callback
|
||||
|
@ -158,6 +159,31 @@ pjmedia_avi_stream_set_eof_cb(pjmedia_avi_stream *stream,
|
|||
void *user_data,
|
||||
pj_status_t (*cb)(pjmedia_avi_stream *stream,
|
||||
void *usr_data));
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Register a callback to be called when the file reading has reached the
|
||||
* end of file. If the file is set to play repeatedly, then the callback
|
||||
* will be called multiple times. Note that only one callback can be
|
||||
* registered for each AVI stream.
|
||||
*
|
||||
* @param stream The AVI stream.
|
||||
* @param user_data User data to be specified in the callback
|
||||
* @param cb Callback to be called. Note that if
|
||||
* application wishes to stop the playback, it
|
||||
* can disconnect the port in the callback, and
|
||||
* only after all connections have been removed
|
||||
* could the application safely destroy the port.
|
||||
*
|
||||
* @return PJ_SUCCESS on success.
|
||||
*/
|
||||
PJ_DECL(pj_status_t)
|
||||
pjmedia_avi_stream_set_eof_cb2(pjmedia_avi_stream *stream,
|
||||
void *user_data,
|
||||
void (*cb)(pjmedia_avi_stream *stream,
|
||||
void *usr_data));
|
||||
|
||||
|
||||
/**
|
||||
* @}
|
||||
|
|
|
@ -105,7 +105,12 @@ typedef enum pjmedia_event_type
|
|||
/**
|
||||
* Transport media error.
|
||||
*/
|
||||
PJMEDIA_EVENT_MEDIA_TP_ERR = PJMEDIA_FOURCC('T', 'E', 'R', 'R')
|
||||
PJMEDIA_EVENT_MEDIA_TP_ERR = PJMEDIA_FOURCC('T', 'E', 'R', 'R'),
|
||||
|
||||
/**
|
||||
* Callback event. Currently for internal use only.
|
||||
*/
|
||||
PJMEDIA_EVENT_CALLBACK = PJMEDIA_FOURCC('C', 'B', ' ', ' ')
|
||||
|
||||
} pjmedia_event_type;
|
||||
|
||||
|
|
|
@ -86,6 +86,7 @@ PJ_DECL(pj_status_t) pjmedia_mem_player_create(pj_pool_t *pool,
|
|||
pjmedia_port **p_port );
|
||||
|
||||
|
||||
#if !DEPRECATED_FOR_TICKET_2251
|
||||
/**
|
||||
* Register a callback to be called when the buffer reading has reached the
|
||||
* end of buffer. If the player is set to play repeatedly, then the callback
|
||||
|
@ -106,8 +107,31 @@ pjmedia_mem_player_set_eof_cb( pjmedia_port *port,
|
|||
void *user_data,
|
||||
pj_status_t (*cb)(pjmedia_port *port,
|
||||
void *usr_data));
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Register a callback to be called when the buffer reading has reached the
|
||||
* end of buffer. If the player is set to play repeatedly, then the callback
|
||||
* will be called multiple times. Note that only one callback can be
|
||||
* registered for each player port.
|
||||
*
|
||||
* @param port The memory player port.
|
||||
* @param user_data User data to be specified in the callback
|
||||
* @param cb Callback to be called. Note that if
|
||||
* application wishes to stop the playback, it
|
||||
* can disconnect the port in the callback, and
|
||||
* only after all connections have been removed
|
||||
* could the application safely destroy the port.
|
||||
*
|
||||
* @return PJ_SUCCESS on success.
|
||||
*/
|
||||
PJ_DECL(pj_status_t)
|
||||
pjmedia_mem_player_set_eof_cb2(pjmedia_port *port,
|
||||
void *user_data,
|
||||
void (*cb)(pjmedia_port *port,
|
||||
void *usr_data));
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
@ -151,6 +175,7 @@ PJ_DECL(pj_status_t) pjmedia_mem_capture_create(pj_pool_t *pool,
|
|||
pjmedia_port **p_port);
|
||||
|
||||
|
||||
#if !DEPRECATED_FOR_TICKET_2251
|
||||
/**
|
||||
* Register a callback to be called when no space left in the buffer.
|
||||
* Note that when a callback is registered, this callback will also be
|
||||
|
@ -174,6 +199,28 @@ pjmedia_mem_capture_set_eof_cb(pjmedia_port *port,
|
|||
void *user_data,
|
||||
pj_status_t (*cb)(pjmedia_port *port,
|
||||
void *usr_data));
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Register a callback to be called when no space left in the buffer.
|
||||
*
|
||||
* @param port The memory recorder port.
|
||||
* @param user_data User data to be specified in the callback
|
||||
* @param cb Callback to be called. Note that if
|
||||
* application wishes to stop the recording, it
|
||||
* can disconnect the port in the callback, and
|
||||
* only after all connections have been removed
|
||||
* could the application safely destroy the port.
|
||||
*
|
||||
* @return PJ_SUCCESS on success.
|
||||
*/
|
||||
PJ_DECL(pj_status_t)
|
||||
pjmedia_mem_capture_set_eof_cb2(pjmedia_port *port,
|
||||
void *user_data,
|
||||
void (*cb)(pjmedia_port *port,
|
||||
void *usr_data));
|
||||
|
||||
|
||||
/**
|
||||
* Return the current size of the recorded data in the buffer.
|
||||
|
|
|
@ -187,6 +187,19 @@
|
|||
PJ_BEGIN_DECL
|
||||
|
||||
|
||||
/* Since media port's callback is called synchronously and has a return value,
|
||||
* it can introduce a deadlock when a mutex is held before calling it.
|
||||
* To prevent this, media ports' set_eof_cb() and set_cb() functions have
|
||||
* been deprecated and replaced by set_eof_cb2() and set_cb2(), which
|
||||
* will call the callback asynchronously without expecting any return value.
|
||||
*
|
||||
* See also https://trac.pjsip.org/repos/ticket/2251.
|
||||
*/
|
||||
#ifndef DEPRECATED_FOR_TICKET_2251
|
||||
# define DEPRECATED_FOR_TICKET_2251 0
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Create 32bit port signature from ASCII characters.
|
||||
*/
|
||||
|
|
|
@ -72,6 +72,7 @@ PJ_DECL(pj_status_t) pjmedia_wav_playlist_create(pj_pool_t *pool,
|
|||
pjmedia_port **p_port);
|
||||
|
||||
|
||||
#if !DEPRECATED_FOR_TICKET_2251
|
||||
/**
|
||||
* Register a callback to be called when the file reading has reached the
|
||||
* end of file of the last file. If the file is set to play repeatedly,
|
||||
|
@ -92,6 +93,30 @@ pjmedia_wav_playlist_set_eof_cb(pjmedia_port *port,
|
|||
void *user_data,
|
||||
pj_status_t (*cb)(pjmedia_port *port,
|
||||
void *usr_data));
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Register a callback to be called when the file reading has reached the
|
||||
* end of file of the last file. If the file is set to play repeatedly,
|
||||
* then the callback will be called multiple times. Note that only one
|
||||
* callback can be registered for each file port.
|
||||
*
|
||||
* @param port The WAV play list port.
|
||||
* @param user_data User data to be specified in the callback
|
||||
* @param cb Callback to be called. Note that if
|
||||
* application wishes to stop the playback, it
|
||||
* can disconnect the port in the callback, and
|
||||
* only after all connections have been removed
|
||||
* could the application safely destroy the port.
|
||||
*
|
||||
* @return PJ_SUCCESS on success.
|
||||
*/
|
||||
PJ_DECL(pj_status_t)
|
||||
pjmedia_wav_playlist_set_eof_cb2(pjmedia_port *port,
|
||||
void *user_data,
|
||||
void (*cb)(pjmedia_port *port,
|
||||
void *usr_data));
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -151,6 +151,7 @@ PJ_DECL(pj_status_t) pjmedia_wav_player_port_set_pos( pjmedia_port *port,
|
|||
PJ_DECL(pj_ssize_t) pjmedia_wav_player_port_get_pos( pjmedia_port *port );
|
||||
|
||||
|
||||
#if !DEPRECATED_FOR_TICKET_2251
|
||||
/**
|
||||
* Register a callback to be called when the file reading has reached the
|
||||
* end of file. If the file is set to play repeatedly, then the callback
|
||||
|
@ -166,11 +167,36 @@ PJ_DECL(pj_ssize_t) pjmedia_wav_player_port_get_pos( pjmedia_port *port );
|
|||
*
|
||||
* @return PJ_SUCCESS on success.
|
||||
*/
|
||||
PJ_DECL(pj_status_t)
|
||||
PJ_DECL(pj_status_t)
|
||||
pjmedia_wav_player_set_eof_cb( pjmedia_port *port,
|
||||
void *user_data,
|
||||
pj_status_t (*cb)(pjmedia_port *port,
|
||||
void *usr_data));
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Register a callback to be called when the file reading has reached the
|
||||
* end of file. If the file is set to play repeatedly, then the callback
|
||||
* will be called multiple times. Note that only one callback can be
|
||||
* registered for each file port.
|
||||
*
|
||||
* @param port The file player port.
|
||||
* @param user_data User data to be specified in the callback
|
||||
* @param cb Callback to be called. Note that if
|
||||
* application wishes to stop the playback, it
|
||||
* can disconnect the port in the callback, and
|
||||
* only after all connections have been removed
|
||||
* could the application safely destroy the port.
|
||||
*
|
||||
* @return PJ_SUCCESS on success.
|
||||
*/
|
||||
PJ_DECL(pj_status_t)
|
||||
pjmedia_wav_player_set_eof_cb2(pjmedia_port *port,
|
||||
void *user_data,
|
||||
void (*cb)(pjmedia_port *port,
|
||||
void *usr_data));
|
||||
|
||||
|
||||
/**
|
||||
* @}
|
||||
|
@ -255,6 +281,7 @@ PJ_DECL(pj_status_t) pjmedia_wav_writer_port_create(pj_pool_t *pool,
|
|||
PJ_DECL(pj_ssize_t) pjmedia_wav_writer_port_get_pos( pjmedia_port *port );
|
||||
|
||||
|
||||
#if !DEPRECATED_FOR_TICKET_2251
|
||||
/**
|
||||
* Register the callback to be called when the file writing has reached
|
||||
* certain size. Application can use this callback, for example, to limit
|
||||
|
@ -277,6 +304,32 @@ pjmedia_wav_writer_port_set_cb( pjmedia_port *port,
|
|||
void *user_data,
|
||||
pj_status_t (*cb)(pjmedia_port *port,
|
||||
void *usr_data));
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Register the callback to be called when the file writing has reached
|
||||
* certain size. Application can use this callback, for example, to limit
|
||||
* the size of the output file.
|
||||
*
|
||||
* @param port The file writer port.
|
||||
* @param pos The file position on which the callback will be called.
|
||||
* @param user_data User data to be specified in the callback, and will be
|
||||
* given on the callback.
|
||||
* @param cb Callback to be called. Note that if
|
||||
* application wishes to stop the writing, it
|
||||
* can disconnect the port in the callback, and
|
||||
* only after all connections have been removed
|
||||
* could the application safely destroy the port.
|
||||
*
|
||||
* @return PJ_SUCCESS on success.
|
||||
*/
|
||||
PJ_DECL(pj_status_t)
|
||||
pjmedia_wav_writer_port_set_cb2(pjmedia_port *port,
|
||||
pj_size_t pos,
|
||||
void *user_data,
|
||||
void (*cb)(pjmedia_port *port,
|
||||
void *usr_data));
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -138,6 +138,8 @@ struct avi_reader_port
|
|||
pj_timestamp next_ts;
|
||||
|
||||
pj_status_t (*cb)(pjmedia_port*, void*);
|
||||
pj_bool_t subscribed;
|
||||
void (*cb2)(pjmedia_port*, void*);
|
||||
};
|
||||
|
||||
|
||||
|
@ -578,6 +580,7 @@ PJ_DEF(pj_ssize_t) pjmedia_avi_stream_get_len(pjmedia_avi_stream *stream)
|
|||
}
|
||||
|
||||
|
||||
#if !DEPRECATED_FOR_TICKET_2251
|
||||
/*
|
||||
* Register a callback to be called when the file reading has reached the
|
||||
* end of file.
|
||||
|
@ -596,6 +599,9 @@ pjmedia_avi_stream_set_eof_cb( pjmedia_avi_stream *stream,
|
|||
/* Check that this is really a player port */
|
||||
PJ_ASSERT_RETURN(stream->info.signature == SIGNATURE, -PJ_EINVALIDOP);
|
||||
|
||||
PJ_LOG(1, (THIS_FILE, "pjmedia_avi_stream_set_eof_cb() is deprecated. "
|
||||
"Use pjmedia_avi_stream_set_eof_cb2() instead."));
|
||||
|
||||
fport = (struct avi_reader_port*) stream;
|
||||
|
||||
fport->base.port_data.pdata = user_data;
|
||||
|
@ -603,6 +609,48 @@ pjmedia_avi_stream_set_eof_cb( pjmedia_avi_stream *stream,
|
|||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Register a callback to be called when the file reading has reached the
|
||||
* end of file.
|
||||
*/
|
||||
PJ_DEF(pj_status_t)
|
||||
pjmedia_avi_stream_set_eof_cb2(pjmedia_avi_stream *stream,
|
||||
void *user_data,
|
||||
void (*cb)(pjmedia_avi_stream *stream,
|
||||
void *usr_data))
|
||||
{
|
||||
struct avi_reader_port *fport;
|
||||
|
||||
/* Sanity check */
|
||||
PJ_ASSERT_RETURN(stream, -PJ_EINVAL);
|
||||
|
||||
/* Check that this is really a player port */
|
||||
PJ_ASSERT_RETURN(stream->info.signature == SIGNATURE, -PJ_EINVALIDOP);
|
||||
|
||||
fport = (struct avi_reader_port*) stream;
|
||||
|
||||
fport->base.port_data.pdata = user_data;
|
||||
fport->cb2 = cb;
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static pj_status_t file_on_event(pjmedia_event *event,
|
||||
void *user_data)
|
||||
{
|
||||
struct avi_reader_port *fport = (struct avi_reader_port*)user_data;
|
||||
|
||||
if (event->type == PJMEDIA_EVENT_CALLBACK) {
|
||||
if (fport->cb2)
|
||||
(*fport->cb2)(&fport->base, fport->base.port_data.pdata);
|
||||
}
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
@ -624,8 +672,44 @@ static pj_status_t avi_get_frame(pjmedia_port *this_port,
|
|||
fport->base.info.name.ptr));
|
||||
|
||||
/* Call callback, if any */
|
||||
if (fport->cb)
|
||||
if (fport->cb2) {
|
||||
pj_bool_t no_loop = (fport->options & PJMEDIA_AVI_FILE_NO_LOOP);
|
||||
|
||||
if (!fport->subscribed) {
|
||||
status = pjmedia_event_subscribe(NULL, &file_on_event,
|
||||
fport, fport);
|
||||
fport->subscribed = (status == PJ_SUCCESS)? PJ_TRUE:
|
||||
PJ_FALSE;
|
||||
}
|
||||
|
||||
if (fport->subscribed && fport->eof != 2) {
|
||||
pjmedia_event event;
|
||||
|
||||
if (no_loop) {
|
||||
/* To prevent the callback from being called repeatedly */
|
||||
fport->eof = 2;
|
||||
} else {
|
||||
fport->eof = PJ_FALSE;
|
||||
pj_file_setpos(fport->fd, fport->start_data, PJ_SEEK_SET);
|
||||
}
|
||||
|
||||
pjmedia_event_init(&event, PJMEDIA_EVENT_CALLBACK,
|
||||
NULL, fport);
|
||||
pjmedia_event_publish(NULL, fport, &event,
|
||||
PJMEDIA_EVENT_PUBLISH_POST_EVENT);
|
||||
}
|
||||
|
||||
/* Should not access player port after this since
|
||||
* it might have been destroyed by the callback.
|
||||
*/
|
||||
frame->type = PJMEDIA_FRAME_TYPE_NONE;
|
||||
frame->size = 0;
|
||||
|
||||
return (no_loop? PJ_EEOF: PJ_SUCCESS);
|
||||
|
||||
} else if (fport->cb) {
|
||||
status = (*fport->cb)(this_port, fport->base.port_data.pdata);
|
||||
}
|
||||
|
||||
/* If callback returns non PJ_SUCCESS or 'no loop' is specified,
|
||||
* return immediately (and don't try to access player port since
|
||||
|
@ -784,6 +868,11 @@ static pj_status_t avi_on_destroy(pjmedia_port *this_port)
|
|||
|
||||
pj_assert(this_port->info.signature == SIGNATURE);
|
||||
|
||||
if (fport->subscribed) {
|
||||
pjmedia_event_unsubscribe(NULL, &file_on_event, fport, fport);
|
||||
fport->subscribed = PJ_FALSE;
|
||||
}
|
||||
|
||||
if (fport->fd != (pj_oshandle_t) (pj_ssize_t)-1)
|
||||
pj_file_close(fport->fd);
|
||||
return PJ_SUCCESS;
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <pjmedia/mem_port.h>
|
||||
#include <pj/assert.h>
|
||||
#include <pj/errno.h>
|
||||
#include <pj/log.h>
|
||||
#include <pj/pool.h>
|
||||
|
||||
|
||||
|
@ -42,6 +43,8 @@ struct mem_rec
|
|||
void *user_data;
|
||||
pj_status_t (*cb)(pjmedia_port *port,
|
||||
void *user_data);
|
||||
pj_bool_t subscribed;
|
||||
void (*cb2)(pjmedia_port*, void*);
|
||||
};
|
||||
|
||||
|
||||
|
@ -101,6 +104,7 @@ PJ_DEF(pj_status_t) pjmedia_mem_capture_create( pj_pool_t *pool,
|
|||
}
|
||||
|
||||
|
||||
#if !DEPRECATED_FOR_TICKET_2251
|
||||
/*
|
||||
* Register a callback to be called when the file reading has reached the
|
||||
* end of buffer.
|
||||
|
@ -115,10 +119,36 @@ PJ_DEF(pj_status_t) pjmedia_mem_capture_set_eof_cb( pjmedia_port *port,
|
|||
PJ_ASSERT_RETURN(port->info.signature == SIGNATURE,
|
||||
PJ_EINVALIDOP);
|
||||
|
||||
PJ_LOG(1, (THIS_FILE, "pjmedia_mem_capture_set_eof_cb() is deprecated. "
|
||||
"Use pjmedia_mem_capture_set_eof_cb2() instead."));
|
||||
|
||||
rec = (struct mem_rec*) port;
|
||||
rec->user_data = user_data;
|
||||
rec->cb = cb;
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Register a callback to be called when the file reading has reached the
|
||||
* end of buffer.
|
||||
*/
|
||||
PJ_DEF(pj_status_t) pjmedia_mem_capture_set_eof_cb2( pjmedia_port *port,
|
||||
void *user_data,
|
||||
void (*cb)(pjmedia_port *port,
|
||||
void *usr_data))
|
||||
{
|
||||
struct mem_rec *rec;
|
||||
|
||||
PJ_ASSERT_RETURN(port->info.signature == SIGNATURE,
|
||||
PJ_EINVALIDOP);
|
||||
|
||||
rec = (struct mem_rec*) port;
|
||||
rec->user_data = user_data;
|
||||
rec->cb2 = cb;
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -139,6 +169,20 @@ PJ_DEF(pj_size_t) pjmedia_mem_capture_get_size(pjmedia_port *port)
|
|||
}
|
||||
|
||||
|
||||
static pj_status_t rec_on_event(pjmedia_event *event,
|
||||
void *user_data)
|
||||
{
|
||||
struct mem_rec *rec = (struct mem_rec *)user_data;
|
||||
|
||||
if (event->type == PJMEDIA_EVENT_CALLBACK) {
|
||||
if (rec->cb2)
|
||||
(*rec->cb2)(&rec->base, rec->base.port_data.pdata);
|
||||
}
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static pj_status_t rec_put_frame( pjmedia_port *this_port,
|
||||
pjmedia_frame *frame)
|
||||
{
|
||||
|
@ -177,7 +221,28 @@ static pj_status_t rec_put_frame( pjmedia_port *this_port,
|
|||
rec->write_pos = rec->buffer;
|
||||
|
||||
/* Call callback, if any */
|
||||
if (rec->cb) {
|
||||
if (rec->cb2) {
|
||||
if (!rec->subscribed) {
|
||||
pj_status_t status;
|
||||
|
||||
status = pjmedia_event_subscribe(NULL, rec_on_event,
|
||||
rec, rec);
|
||||
rec->subscribed = (status == PJ_SUCCESS)? PJ_TRUE:
|
||||
PJ_FALSE;
|
||||
}
|
||||
|
||||
if (rec->subscribed) {
|
||||
pjmedia_event event;
|
||||
|
||||
pjmedia_event_init(&event, PJMEDIA_EVENT_CALLBACK,
|
||||
NULL, rec);
|
||||
pjmedia_event_publish(NULL, rec, &event,
|
||||
PJMEDIA_EVENT_PUBLISH_POST_EVENT);
|
||||
}
|
||||
|
||||
return PJ_SUCCESS;
|
||||
|
||||
} else if (rec->cb) {
|
||||
pj_status_t status;
|
||||
|
||||
rec->eof = PJ_TRUE;
|
||||
|
@ -224,6 +289,11 @@ static pj_status_t rec_on_destroy(pjmedia_port *this_port)
|
|||
|
||||
rec = (struct mem_rec*) this_port;
|
||||
|
||||
if (rec->subscribed) {
|
||||
pjmedia_event_unsubscribe(NULL, &rec_on_event, rec, rec);
|
||||
rec->subscribed = PJ_FALSE;
|
||||
}
|
||||
|
||||
if(rec->cb && PJ_FALSE == rec->eof) {
|
||||
rec->eof = PJ_TRUE;
|
||||
(*rec->cb)(this_port, rec->user_data);
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <pjmedia/mem_port.h>
|
||||
#include <pj/assert.h>
|
||||
#include <pj/errno.h>
|
||||
#include <pj/log.h>
|
||||
#include <pj/pool.h>
|
||||
|
||||
|
||||
|
@ -43,7 +44,8 @@ struct mem_player
|
|||
void *user_data;
|
||||
pj_status_t (*cb)(pjmedia_port *port,
|
||||
void *user_data);
|
||||
|
||||
pj_bool_t subscribed;
|
||||
void (*cb2)(pjmedia_port*, void*);
|
||||
};
|
||||
|
||||
|
||||
|
@ -101,7 +103,7 @@ PJ_DEF(pj_status_t) pjmedia_mem_player_create( pj_pool_t *pool,
|
|||
}
|
||||
|
||||
|
||||
|
||||
#if !DEPRECATED_FOR_TICKET_2251
|
||||
/*
|
||||
* Register a callback to be called when the file reading has reached the
|
||||
* end of buffer.
|
||||
|
@ -116,12 +118,38 @@ PJ_DEF(pj_status_t) pjmedia_mem_player_set_eof_cb( pjmedia_port *port,
|
|||
PJ_ASSERT_RETURN(port->info.signature == SIGNATURE,
|
||||
PJ_EINVALIDOP);
|
||||
|
||||
PJ_LOG(1, (THIS_FILE, "pjmedia_mem_player_set_eof_cb() is deprecated. "
|
||||
"Use pjmedia_mem_player_set_eof_cb2() instead."));
|
||||
|
||||
player = (struct mem_player*) port;
|
||||
player->user_data = user_data;
|
||||
player->cb = cb;
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Register a callback to be called when the file reading has reached the
|
||||
* end of buffer.
|
||||
*/
|
||||
PJ_DEF(pj_status_t) pjmedia_mem_player_set_eof_cb2( pjmedia_port *port,
|
||||
void *user_data,
|
||||
void (*cb)(pjmedia_port *port,
|
||||
void *usr_data))
|
||||
{
|
||||
struct mem_player *player;
|
||||
|
||||
PJ_ASSERT_RETURN(port->info.signature == SIGNATURE,
|
||||
PJ_EINVALIDOP);
|
||||
|
||||
player = (struct mem_player*) port;
|
||||
player->user_data = user_data;
|
||||
player->cb2 = cb;
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static pj_status_t mem_put_frame( pjmedia_port *this_port,
|
||||
|
@ -134,6 +162,20 @@ static pj_status_t mem_put_frame( pjmedia_port *this_port,
|
|||
}
|
||||
|
||||
|
||||
static pj_status_t player_on_event(pjmedia_event *event,
|
||||
void *user_data)
|
||||
{
|
||||
struct mem_player *player = (struct mem_player *)user_data;
|
||||
|
||||
if (event->type == PJMEDIA_EVENT_CALLBACK) {
|
||||
if (player->cb2)
|
||||
(*player->cb2)(&player->base, player->base.port_data.pdata);
|
||||
}
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static pj_status_t mem_get_frame( pjmedia_port *this_port,
|
||||
pjmedia_frame *frame)
|
||||
{
|
||||
|
@ -150,15 +192,52 @@ static pj_status_t mem_get_frame( pjmedia_port *this_port,
|
|||
pj_status_t status = PJ_SUCCESS;
|
||||
|
||||
/* Call callback, if any */
|
||||
if (player->cb)
|
||||
if (player->cb2) {
|
||||
pj_bool_t no_loop = (player->options & PJMEDIA_MEM_NO_LOOP);
|
||||
|
||||
if (!player->subscribed) {
|
||||
status = pjmedia_event_subscribe(NULL, &player_on_event,
|
||||
player, player);
|
||||
player->subscribed = (status == PJ_SUCCESS)? PJ_TRUE:
|
||||
PJ_FALSE;
|
||||
}
|
||||
|
||||
if (player->subscribed && player->eof != 2) {
|
||||
pjmedia_event event;
|
||||
|
||||
if (no_loop) {
|
||||
/* To prevent the callback from being called repeatedly */
|
||||
player->eof = 2;
|
||||
} else {
|
||||
player->eof = PJ_FALSE;
|
||||
}
|
||||
|
||||
pjmedia_event_init(&event, PJMEDIA_EVENT_CALLBACK,
|
||||
NULL, player);
|
||||
pjmedia_event_publish(NULL, player, &event,
|
||||
PJMEDIA_EVENT_PUBLISH_POST_EVENT);
|
||||
}
|
||||
|
||||
/* Should not access player port after this since
|
||||
* it might have been destroyed by the callback.
|
||||
*/
|
||||
frame->type = PJMEDIA_FRAME_TYPE_NONE;
|
||||
frame->size = 0;
|
||||
|
||||
return (no_loop? PJ_EEOF: PJ_SUCCESS);
|
||||
|
||||
} else if (player->cb) {
|
||||
status = (*player->cb)(this_port, player->user_data);
|
||||
}
|
||||
|
||||
/* If callback returns non PJ_SUCCESS or 'no loop' is specified
|
||||
* return immediately (and don't try to access player port since
|
||||
* it might have been destroyed by the callback).
|
||||
*/
|
||||
if ((status != PJ_SUCCESS) || (player->options & PJMEDIA_MEM_NO_LOOP)) {
|
||||
if ((status != PJ_SUCCESS) || (player->options & PJMEDIA_MEM_NO_LOOP))
|
||||
{
|
||||
frame->type = PJMEDIA_FRAME_TYPE_NONE;
|
||||
frame->size = 0;
|
||||
return PJ_EEOF;
|
||||
}
|
||||
|
||||
|
@ -212,8 +291,17 @@ static pj_status_t mem_get_frame( pjmedia_port *this_port,
|
|||
|
||||
static pj_status_t mem_on_destroy(pjmedia_port *this_port)
|
||||
{
|
||||
struct mem_player *player;
|
||||
|
||||
PJ_ASSERT_RETURN(this_port->info.signature == SIGNATURE,
|
||||
PJ_EINVALIDOP);
|
||||
PJ_EINVALIDOP);
|
||||
|
||||
player = (struct mem_player*) this_port;
|
||||
|
||||
if (player->subscribed) {
|
||||
pjmedia_event_unsubscribe(NULL, &player_on_event, player, player);
|
||||
player->subscribed = PJ_FALSE;
|
||||
}
|
||||
|
||||
/* Destroy signature */
|
||||
this_port->info.signature = 0;
|
||||
|
|
|
@ -73,6 +73,8 @@ struct file_reader_port
|
|||
pj_oshandle_t fd;
|
||||
|
||||
pj_status_t (*cb)(pjmedia_port*, void*);
|
||||
pj_bool_t subscribed;
|
||||
void (*cb2)(pjmedia_port*, void*);
|
||||
};
|
||||
|
||||
|
||||
|
@ -547,7 +549,7 @@ PJ_DEF(pj_ssize_t) pjmedia_wav_player_port_get_pos( pjmedia_port *port )
|
|||
}
|
||||
|
||||
|
||||
|
||||
#if !DEPRECATED_FOR_TICKET_2251
|
||||
/*
|
||||
* Register a callback to be called when the file reading has reached the
|
||||
* end of file.
|
||||
|
@ -565,6 +567,9 @@ PJ_DEF(pj_status_t) pjmedia_wav_player_set_eof_cb( pjmedia_port *port,
|
|||
/* Check that this is really a player port */
|
||||
PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, -PJ_EINVALIDOP);
|
||||
|
||||
PJ_LOG(1, (THIS_FILE, "pjmedia_wav_player_set_eof_cb() is deprecated. "
|
||||
"Use pjmedia_wav_player_set_eof_cb2() instead."));
|
||||
|
||||
fport = (struct file_reader_port*) port;
|
||||
|
||||
fport->base.port_data.pdata = user_data;
|
||||
|
@ -572,6 +577,47 @@ PJ_DEF(pj_status_t) pjmedia_wav_player_set_eof_cb( pjmedia_port *port,
|
|||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Register a callback to be called when the file reading has reached the
|
||||
* end of file.
|
||||
*/
|
||||
PJ_DEF(pj_status_t) pjmedia_wav_player_set_eof_cb2(pjmedia_port *port,
|
||||
void *user_data,
|
||||
void (*cb)(pjmedia_port *port,
|
||||
void *usr_data))
|
||||
{
|
||||
struct file_reader_port *fport;
|
||||
|
||||
/* Sanity check */
|
||||
PJ_ASSERT_RETURN(port, -PJ_EINVAL);
|
||||
|
||||
/* Check that this is really a player port */
|
||||
PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, -PJ_EINVALIDOP);
|
||||
|
||||
fport = (struct file_reader_port*) port;
|
||||
|
||||
fport->base.port_data.pdata = user_data;
|
||||
fport->cb2 = cb;
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static pj_status_t file_on_event(pjmedia_event *event,
|
||||
void *user_data)
|
||||
{
|
||||
struct file_reader_port *fport = (struct file_reader_port*)user_data;
|
||||
|
||||
if (event->type == PJMEDIA_EVENT_CALLBACK) {
|
||||
if (fport->cb2)
|
||||
(*fport->cb2)(&fport->base, fport->base.port_data.pdata);
|
||||
}
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
@ -594,23 +640,59 @@ static pj_status_t file_get_frame(pjmedia_port *this_port,
|
|||
fport->base.info.name.ptr));
|
||||
|
||||
/* Call callback, if any */
|
||||
if (fport->cb)
|
||||
if (fport->cb2) {
|
||||
pj_bool_t no_loop = (fport->options & PJMEDIA_FILE_NO_LOOP);
|
||||
|
||||
if (!fport->subscribed) {
|
||||
status = pjmedia_event_subscribe(NULL, &file_on_event,
|
||||
fport, fport);
|
||||
fport->subscribed = (status == PJ_SUCCESS)? PJ_TRUE:
|
||||
PJ_FALSE;
|
||||
}
|
||||
|
||||
if (fport->subscribed && fport->eof != 2) {
|
||||
pjmedia_event event;
|
||||
|
||||
if (no_loop) {
|
||||
/* To prevent the callback from being called repeatedly */
|
||||
fport->eof = 2;
|
||||
} else {
|
||||
fport->eof = PJ_FALSE;
|
||||
}
|
||||
|
||||
pjmedia_event_init(&event, PJMEDIA_EVENT_CALLBACK,
|
||||
NULL, fport);
|
||||
pjmedia_event_publish(NULL, fport, &event,
|
||||
PJMEDIA_EVENT_PUBLISH_POST_EVENT);
|
||||
}
|
||||
|
||||
/* Should not access player port after this since
|
||||
* it might have been destroyed by the callback.
|
||||
*/
|
||||
frame->type = PJMEDIA_FRAME_TYPE_NONE;
|
||||
frame->size = 0;
|
||||
|
||||
return (no_loop? PJ_EEOF: PJ_SUCCESS);
|
||||
|
||||
} else if (fport->cb) {
|
||||
status = (*fport->cb)(this_port, fport->base.port_data.pdata);
|
||||
}
|
||||
|
||||
/* If callback returns non PJ_SUCCESS or 'no loop' is specified,
|
||||
* return immediately (and don't try to access player port since
|
||||
* it might have been destroyed by the callback).
|
||||
*/
|
||||
if ((status != PJ_SUCCESS) || (fport->options & PJMEDIA_FILE_NO_LOOP)) {
|
||||
if ((status != PJ_SUCCESS) || (fport->options & PJMEDIA_FILE_NO_LOOP))
|
||||
{
|
||||
frame->type = PJMEDIA_FRAME_TYPE_NONE;
|
||||
frame->size = 0;
|
||||
return PJ_EEOF;
|
||||
}
|
||||
|
||||
|
||||
/* Rewind file */
|
||||
PJ_LOG(5,(THIS_FILE, "File port %.*s rewinding..",
|
||||
(int)fport->base.info.name.slen,
|
||||
fport->base.info.name.ptr));
|
||||
|
||||
fport->eof = PJ_FALSE;
|
||||
}
|
||||
|
||||
|
@ -724,6 +806,12 @@ static pj_status_t file_on_destroy(pjmedia_port *this_port)
|
|||
pj_assert(this_port->info.signature == SIGNATURE);
|
||||
|
||||
pj_file_close(fport->fd);
|
||||
|
||||
if (fport->subscribed) {
|
||||
pjmedia_event_unsubscribe(NULL, &file_on_event, fport, fport);
|
||||
fport->subscribed = PJ_FALSE;
|
||||
}
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
@ -74,6 +74,8 @@ struct playlist_port
|
|||
int max_file; /* how many files. */
|
||||
|
||||
pj_status_t (*cb)(pjmedia_port*, void*);
|
||||
pj_bool_t subscribed;
|
||||
void (*cb2)(pjmedia_port*, void*);
|
||||
};
|
||||
|
||||
|
||||
|
@ -104,6 +106,20 @@ static struct playlist_port *create_file_list_port(pj_pool_t *pool,
|
|||
}
|
||||
|
||||
|
||||
static pj_status_t file_on_event(pjmedia_event *event,
|
||||
void *user_data)
|
||||
{
|
||||
struct playlist_port *fport = (struct playlist_port*)user_data;
|
||||
|
||||
if (event->type == PJMEDIA_EVENT_CALLBACK) {
|
||||
if (fport->cb2)
|
||||
(*fport->cb2)(&fport->base, fport->base.port_data.pdata);
|
||||
}
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Fill buffer for file_list operations.
|
||||
*/
|
||||
|
@ -175,8 +191,46 @@ static pj_status_t file_fill_buffer(struct playlist_port *fport)
|
|||
}
|
||||
|
||||
/* All files have been played. Call callback, if any. */
|
||||
if (fport->cb)
|
||||
{
|
||||
if (fport->cb2) {
|
||||
pj_bool_t no_loop = (fport->options & PJMEDIA_FILE_NO_LOOP);
|
||||
|
||||
if (!fport->subscribed) {
|
||||
status = pjmedia_event_subscribe(NULL, &file_on_event,
|
||||
fport, fport);
|
||||
fport->subscribed = (status == PJ_SUCCESS)? PJ_TRUE:
|
||||
PJ_FALSE;
|
||||
}
|
||||
|
||||
if (fport->subscribed && fport->eof != 2) {
|
||||
pjmedia_event event;
|
||||
|
||||
if (no_loop) {
|
||||
/* To prevent the callback from being called
|
||||
* repeatedly.
|
||||
*/
|
||||
fport->eof = 2;
|
||||
} else {
|
||||
fport->eof = PJ_FALSE;
|
||||
/* start with first file again. */
|
||||
fport->current_file = current_file = 0;
|
||||
fport->fpos_list[0] = fport->start_data_list[0];
|
||||
pj_file_setpos(fport->fd_list[0],
|
||||
fport->fpos_list[0], PJ_SEEK_SET);
|
||||
fport->data_left_list[0] = fport->data_len_list[0];
|
||||
}
|
||||
|
||||
pjmedia_event_init(&event, PJMEDIA_EVENT_CALLBACK,
|
||||
NULL, fport);
|
||||
pjmedia_event_publish(NULL, fport, &event,
|
||||
PJMEDIA_EVENT_PUBLISH_POST_EVENT);
|
||||
}
|
||||
|
||||
/* Should not access player port after this since
|
||||
* it might have been destroyed by the callback.
|
||||
*/
|
||||
return (no_loop? PJ_EEOF: PJ_SUCCESS);
|
||||
|
||||
} else if (fport->cb) {
|
||||
PJ_LOG(5,(THIS_FILE,
|
||||
"File port %.*s EOF, calling callback",
|
||||
(int)fport->base.info.name.slen,
|
||||
|
@ -577,6 +631,7 @@ on_error:
|
|||
}
|
||||
|
||||
|
||||
#if !DEPRECATED_FOR_TICKET_2251
|
||||
/*
|
||||
* Register a callback to be called when the file reading has reached the
|
||||
* end of the last file.
|
||||
|
@ -594,6 +649,9 @@ PJ_DEF(pj_status_t) pjmedia_wav_playlist_set_eof_cb(pjmedia_port *port,
|
|||
/* Check that this is really a playlist port */
|
||||
PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, PJ_EINVALIDOP);
|
||||
|
||||
PJ_LOG(1, (THIS_FILE, "pjmedia_wav_playlist_set_eof_cb() is deprecated. "
|
||||
"Use pjmedia_wav_playlist_set_eof_cb2() instead."));
|
||||
|
||||
fport = (struct playlist_port*) port;
|
||||
|
||||
fport->base.port_data.pdata = user_data;
|
||||
|
@ -601,6 +659,33 @@ PJ_DEF(pj_status_t) pjmedia_wav_playlist_set_eof_cb(pjmedia_port *port,
|
|||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Register a callback to be called when the file reading has reached the
|
||||
* end of the last file.
|
||||
*/
|
||||
PJ_DEF(pj_status_t) pjmedia_wav_playlist_set_eof_cb2(pjmedia_port *port,
|
||||
void *user_data,
|
||||
void (*cb)(pjmedia_port *port,
|
||||
void *usr_data))
|
||||
{
|
||||
struct playlist_port *fport;
|
||||
|
||||
/* Sanity check */
|
||||
PJ_ASSERT_RETURN(port, PJ_EINVAL);
|
||||
|
||||
/* Check that this is really a playlist port */
|
||||
PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, PJ_EINVALIDOP);
|
||||
|
||||
fport = (struct playlist_port*) port;
|
||||
|
||||
fport->base.port_data.pdata = user_data;
|
||||
fport->cb2 = cb;
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
@ -675,6 +760,11 @@ static pj_status_t file_list_on_destroy(pjmedia_port *this_port)
|
|||
|
||||
pj_assert(this_port->info.signature == SIGNATURE);
|
||||
|
||||
if (fport->subscribed) {
|
||||
pjmedia_event_unsubscribe(NULL, &file_on_event, fport, fport);
|
||||
fport->subscribed = PJ_FALSE;
|
||||
}
|
||||
|
||||
for (index=0; index<fport->max_file; index++)
|
||||
pj_file_close(fport->fd_list[index]);
|
||||
|
||||
|
|
|
@ -48,6 +48,9 @@ struct file_port
|
|||
|
||||
pj_size_t cb_size;
|
||||
pj_status_t (*cb)(pjmedia_port*, void*);
|
||||
pj_bool_t subscribed;
|
||||
pj_bool_t cb_called;
|
||||
void (*cb2)(pjmedia_port*, void*);
|
||||
};
|
||||
|
||||
static pj_status_t file_put_frame(pjmedia_port *this_port,
|
||||
|
@ -244,6 +247,7 @@ PJ_DEF(pj_ssize_t) pjmedia_wav_writer_port_get_pos( pjmedia_port *port )
|
|||
}
|
||||
|
||||
|
||||
#if !DEPRECATED_FOR_TICKET_2251
|
||||
/*
|
||||
* Register callback.
|
||||
*/
|
||||
|
@ -261,6 +265,9 @@ PJ_DEF(pj_status_t) pjmedia_wav_writer_port_set_cb( pjmedia_port *port,
|
|||
/* Check that this is really a writer port */
|
||||
PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, PJ_EINVALIDOP);
|
||||
|
||||
PJ_LOG(1, (THIS_FILE, "pjmedia_wav_writer_port_set_cb() is deprecated. "
|
||||
"Use pjmedia_wav_writer_port_set_cb2() instead."));
|
||||
|
||||
fport = (struct file_port*) port;
|
||||
|
||||
fport->cb_size = pos;
|
||||
|
@ -269,6 +276,35 @@ PJ_DEF(pj_status_t) pjmedia_wav_writer_port_set_cb( pjmedia_port *port,
|
|||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Register callback.
|
||||
*/
|
||||
PJ_DEF(pj_status_t) pjmedia_wav_writer_port_set_cb2(pjmedia_port *port,
|
||||
pj_size_t pos,
|
||||
void *user_data,
|
||||
void (*cb)(pjmedia_port *port,
|
||||
void *usr_data))
|
||||
{
|
||||
struct file_port *fport;
|
||||
|
||||
/* Sanity check */
|
||||
PJ_ASSERT_RETURN(port && cb, PJ_EINVAL);
|
||||
|
||||
/* Check that this is really a writer port */
|
||||
PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, PJ_EINVALIDOP);
|
||||
|
||||
fport = (struct file_port*) port;
|
||||
|
||||
fport->cb_size = pos;
|
||||
fport->base.port_data.pdata = user_data;
|
||||
fport->cb2 = cb;
|
||||
fport->cb_called = PJ_FALSE;
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
#if defined(PJ_IS_BIG_ENDIAN) && PJ_IS_BIG_ENDIAN!=0
|
||||
|
@ -303,6 +339,19 @@ static pj_status_t flush_buffer(struct file_port *fport)
|
|||
return status;
|
||||
}
|
||||
|
||||
static pj_status_t file_on_event(pjmedia_event *event,
|
||||
void *user_data)
|
||||
{
|
||||
struct file_port *fport = (struct file_port*)user_data;
|
||||
|
||||
if (event->type == PJMEDIA_EVENT_CALLBACK) {
|
||||
if (fport->cb2)
|
||||
(*fport->cb2)(&fport->base, fport->base.port_data.pdata);
|
||||
}
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Put a frame into the buffer. When the buffer is full, flush the buffer
|
||||
* to the file.
|
||||
|
@ -353,15 +402,38 @@ static pj_status_t file_put_frame(pjmedia_port *this_port,
|
|||
|
||||
/* Increment total written, and check if we need to call callback */
|
||||
fport->total += frame_size;
|
||||
if (fport->cb && fport->total >= fport->cb_size) {
|
||||
pj_status_t (*cb)(pjmedia_port*, void*);
|
||||
pj_status_t status;
|
||||
if (fport->total >= fport->cb_size) {
|
||||
if (fport->cb2) {
|
||||
if (!fport->subscribed) {
|
||||
pj_status_t status;
|
||||
|
||||
cb = fport->cb;
|
||||
fport->cb = NULL;
|
||||
status = pjmedia_event_subscribe(NULL, &file_on_event,
|
||||
fport, fport);
|
||||
fport->subscribed = (status == PJ_SUCCESS)? PJ_TRUE:
|
||||
PJ_FALSE;
|
||||
}
|
||||
|
||||
status = (*cb)(this_port, this_port->port_data.pdata);
|
||||
return status;
|
||||
if (fport->subscribed && !fport->cb_called) {
|
||||
pjmedia_event event;
|
||||
|
||||
/* To prevent the callback from being called more than once. */
|
||||
fport->cb_called = PJ_TRUE;
|
||||
|
||||
pjmedia_event_init(&event, PJMEDIA_EVENT_CALLBACK,
|
||||
NULL, fport);
|
||||
pjmedia_event_publish(NULL, fport, &event,
|
||||
PJMEDIA_EVENT_PUBLISH_POST_EVENT);
|
||||
}
|
||||
} else if (fport->cb) {
|
||||
pj_status_t (*cb)(pjmedia_port*, void*);
|
||||
pj_status_t status;
|
||||
|
||||
cb = fport->cb;
|
||||
fport->cb = NULL;
|
||||
|
||||
status = (*cb)(this_port, this_port->port_data.pdata);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
return PJ_SUCCESS;
|
||||
|
@ -392,6 +464,11 @@ static pj_status_t file_on_destroy(pjmedia_port *this_port)
|
|||
pj_status_t status;
|
||||
pj_uint32_t data_len_pos = DATA_LEN_POS;
|
||||
|
||||
if (fport->subscribed) {
|
||||
pjmedia_event_unsubscribe(NULL, &file_on_event, fport, fport);
|
||||
fport->subscribed = PJ_FALSE;
|
||||
}
|
||||
|
||||
/* Flush remaining buffers. */
|
||||
if (fport->writepos != fport->buf)
|
||||
flush_buffer(fport);
|
||||
|
|
|
@ -1001,7 +1001,7 @@ static pjmedia_transport* on_create_media_transport(pjsua_call_id call_id,
|
|||
#endif
|
||||
|
||||
/* Playfile done notification, set timer to hangup calls */
|
||||
pj_status_t on_playfile_done(pjmedia_port *port, void *usr_data)
|
||||
void on_playfile_done(pjmedia_port *port, void *usr_data)
|
||||
{
|
||||
pj_time_val delay;
|
||||
|
||||
|
@ -1011,12 +1011,11 @@ pj_status_t on_playfile_done(pjmedia_port *port, void *usr_data)
|
|||
/* Just rewind WAV when it is played outside of call */
|
||||
if (pjsua_call_get_count() == 0) {
|
||||
pjsua_player_set_pos(app_config.wav_id, 0);
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
/* Timer is already active */
|
||||
if (app_config.auto_hangup_timer.id == 1)
|
||||
return PJ_SUCCESS;
|
||||
return;
|
||||
|
||||
app_config.auto_hangup_timer.id = 1;
|
||||
delay.sec = 0;
|
||||
|
@ -1024,8 +1023,6 @@ pj_status_t on_playfile_done(pjmedia_port *port, void *usr_data)
|
|||
pjsip_endpt_schedule_timer(pjsua_get_pjsip_endpt(),
|
||||
&app_config.auto_hangup_timer,
|
||||
&delay);
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
/* Auto hangup timer callback */
|
||||
|
@ -1360,8 +1357,8 @@ static pj_status_t app_init(void)
|
|||
pjmedia_port *port;
|
||||
|
||||
pjsua_player_get_port(app_config.wav_id, &port);
|
||||
status = pjmedia_wav_player_set_eof_cb(port, NULL,
|
||||
&on_playfile_done);
|
||||
status = pjmedia_wav_player_set_eof_cb2(port, NULL,
|
||||
&on_playfile_done);
|
||||
if (status != PJ_SUCCESS)
|
||||
goto on_error;
|
||||
|
||||
|
|
|
@ -140,6 +140,7 @@ static void usage(void)
|
|||
puts (" frequencies, and ON,OFF=on/off duration in msec.");
|
||||
puts (" This can be specified multiple times.");
|
||||
puts (" --auto-play Automatically play the file (to incoming calls only)");
|
||||
puts (" --auto-play-hangup Automatically hangup the file after file play completes");
|
||||
puts (" --auto-loop Automatically loop incoming RTP to outgoing RTP");
|
||||
puts (" --auto-conf Automatically put calls in conference with others");
|
||||
puts (" --rec-file=file Open file recorder (extension can be .wav or .mp3");
|
||||
|
|
|
@ -587,13 +587,13 @@ int dummy_function()
|
|||
pjmedia_wav_player_port_create(NULL, NULL, 0, 0, 0, NULL);
|
||||
pjmedia_wav_player_port_set_pos(NULL, 0);
|
||||
pjmedia_wav_player_port_get_pos(NULL);
|
||||
pjmedia_wav_player_set_eof_cb(NULL, NULL, NULL);
|
||||
pjmedia_wav_player_set_eof_cb2(NULL, NULL, NULL);
|
||||
#endif
|
||||
|
||||
#ifdef HAS_PJMEDIA_FILE_CAPTURE
|
||||
pjmedia_wav_writer_port_create(NULL, NULL, 8000, 1, 80, 16, 0, 0, NULL);
|
||||
pjmedia_wav_writer_port_get_pos(NULL);
|
||||
pjmedia_wav_writer_port_set_cb(NULL, 0, NULL, NULL);
|
||||
pjmedia_wav_writer_port_set_cb2(NULL, 0, NULL, NULL);
|
||||
#endif
|
||||
|
||||
#ifdef HAS_PJMEDIA_MEM_PLAYER
|
||||
|
|
|
@ -548,6 +548,9 @@ public:
|
|||
* Callbacks
|
||||
*/
|
||||
|
||||
|
||||
/* Unfortunately for pjsua2, a hard deprecation is inevitable. */
|
||||
#if 0 // !DEPRECATED_FOR_TICKET_2251
|
||||
/**
|
||||
* 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
|
||||
|
@ -562,7 +565,21 @@ public:
|
|||
*/
|
||||
virtual bool onEof()
|
||||
{ return true; }
|
||||
#endif
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* If application wishes to stop the playback, it can stop the media
|
||||
* transmission in the callback, and only after all transmissions have
|
||||
* been stopped, could the application safely destroy the player.
|
||||
*/
|
||||
virtual void onEof2()
|
||||
{ }
|
||||
|
||||
private:
|
||||
/**
|
||||
|
@ -573,8 +590,8 @@ private:
|
|||
/**
|
||||
* Low level PJMEDIA callback
|
||||
*/
|
||||
static pj_status_t eof_cb(pjmedia_port *port,
|
||||
void *usr_data);
|
||||
static void eof_cb(pjmedia_port *port,
|
||||
void *usr_data);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -302,7 +302,7 @@ void AudioMediaPlayer::createPlayer(const string &file_name,
|
|||
pjsua_player_destroy(playerId);
|
||||
PJSUA2_RAISE_ERROR2(status, "AudioMediaPlayer::createPlayer()");
|
||||
}
|
||||
status = pjmedia_wav_player_set_eof_cb(port, this, &eof_cb);
|
||||
status = pjmedia_wav_player_set_eof_cb2(port, this, &eof_cb);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pjsua_player_destroy(playerId);
|
||||
PJSUA2_RAISE_ERROR2(status, "AudioMediaPlayer::createPlayer()");
|
||||
|
@ -350,7 +350,7 @@ void AudioMediaPlayer::createPlaylist(const StringVector &file_names,
|
|||
pjsua_player_destroy(playerId);
|
||||
PJSUA2_RAISE_ERROR2(status, "AudioMediaPlayer::createPlaylist()");
|
||||
}
|
||||
status = pjmedia_wav_playlist_set_eof_cb(port, this, &eof_cb);
|
||||
status = pjmedia_wav_playlist_set_eof_cb2(port, this, &eof_cb);
|
||||
if (status != PJ_SUCCESS) {
|
||||
pjsua_player_destroy(playerId);
|
||||
PJSUA2_RAISE_ERROR2(status, "AudioMediaPlayer::createPlaylist()");
|
||||
|
@ -398,12 +398,13 @@ AudioMediaPlayer* AudioMediaPlayer::typecastFromAudioMedia(
|
|||
return static_cast<AudioMediaPlayer*>(media);
|
||||
}
|
||||
|
||||
pj_status_t AudioMediaPlayer::eof_cb(pjmedia_port *port,
|
||||
void *usr_data)
|
||||
void AudioMediaPlayer::eof_cb(pjmedia_port *port,
|
||||
void *usr_data)
|
||||
{
|
||||
PJ_UNUSED_ARG(port);
|
||||
AudioMediaPlayer *player = (AudioMediaPlayer*)usr_data;
|
||||
return player->onEof() ? PJ_SUCCESS : PJ_EEOF;
|
||||
|
||||
player->onEof2();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -112,6 +112,8 @@ pjmedia_mp3_writer_port_create(pj_pool_t *pool,
|
|||
const pjmedia_mp3_encoder_option *option,
|
||||
pjmedia_port **p_port );
|
||||
|
||||
|
||||
#if !DEPRECATED_FOR_TICKET_2251
|
||||
/**
|
||||
* Register the callback to be called when the file writing has reached
|
||||
* certain size. Application can use this callback, for example, to limit
|
||||
|
@ -133,7 +135,33 @@ pjmedia_mp3_writer_port_set_cb( pjmedia_port *port,
|
|||
pj_size_t pos,
|
||||
void *user_data,
|
||||
pj_status_t (*cb)(pjmedia_port *port,
|
||||
void *usr_data));
|
||||
void *usr_data));
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Register the callback to be called when the file writing has reached
|
||||
* certain size. Application can use this callback, for example, to limit
|
||||
* the size of the output file.
|
||||
*
|
||||
* @param port The file writer port.
|
||||
* @param pos The file position on which the callback will be called.
|
||||
* @param user_data User data to be specified in the callback, and will be
|
||||
* given on the callback.
|
||||
* @param cb Callback to be called. Note that if
|
||||
* application wishes to stop the playback, it
|
||||
* can disconnect the port in the callback, and
|
||||
* only after all connections have been removed
|
||||
* could the application safely destroy the port.
|
||||
*
|
||||
* @return PJ_SUCCESS on success.
|
||||
*/
|
||||
PJ_DECL(pj_status_t)
|
||||
pjmedia_mp3_writer_port_set_cb2(pjmedia_port *port,
|
||||
pj_size_t pos,
|
||||
void *user_data,
|
||||
void (*cb)(pjmedia_port *port,
|
||||
void *usr_data));
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -61,6 +61,9 @@ struct mp3_file_port
|
|||
pj_oshandle_t fd;
|
||||
pj_size_t cb_size;
|
||||
pj_status_t (*cb)(pjmedia_port*, void*);
|
||||
pj_bool_t subscribed;
|
||||
pj_bool_t cb_called;
|
||||
void (*cb2)(pjmedia_port*, void*);
|
||||
|
||||
unsigned silence_duration;
|
||||
|
||||
|
@ -331,7 +334,7 @@ pjmedia_mp3_writer_port_create( pj_pool_t *pool,
|
|||
}
|
||||
|
||||
|
||||
|
||||
#if !DEPRECATED_FOR_TICKET_2251
|
||||
/*
|
||||
* Register callback.
|
||||
*/
|
||||
|
@ -350,6 +353,9 @@ pjmedia_mp3_writer_port_set_cb( pjmedia_port *port,
|
|||
/* Check that this is really a writer port */
|
||||
PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, PJ_EINVALIDOP);
|
||||
|
||||
PJ_LOG(1, (THIS_FILE, "pjmedia_mp3_writer_port_set_cb() is deprecated. "
|
||||
"Use pjmedia_mp3_writer_port_set_cb2() instead."));
|
||||
|
||||
fport = (struct mp3_file_port*) port;
|
||||
|
||||
fport->cb_size = pos;
|
||||
|
@ -359,6 +365,51 @@ pjmedia_mp3_writer_port_set_cb( pjmedia_port *port,
|
|||
return PJ_SUCCESS;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Register callback.
|
||||
*/
|
||||
PJ_DEF(pj_status_t)
|
||||
pjmedia_mp3_writer_port_set_cb2(pjmedia_port *port,
|
||||
pj_size_t pos,
|
||||
void *user_data,
|
||||
void (*cb)(pjmedia_port *port,
|
||||
void *usr_data))
|
||||
{
|
||||
struct mp3_file_port *fport;
|
||||
|
||||
/* Sanity check */
|
||||
PJ_ASSERT_RETURN(port && cb, PJ_EINVAL);
|
||||
|
||||
/* Check that this is really a writer port */
|
||||
PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, PJ_EINVALIDOP);
|
||||
|
||||
fport = (struct mp3_file_port*) port;
|
||||
|
||||
fport->cb_size = pos;
|
||||
fport->base.port_data.pdata = user_data;
|
||||
fport->cb2 = cb;
|
||||
fport->cb_called = PJ_FALSE;
|
||||
|
||||
return PJ_SUCCESS;
|
||||
|
||||
}
|
||||
|
||||
|
||||
static pj_status_t file_on_event(pjmedia_event *event,
|
||||
void *user_data)
|
||||
{
|
||||
struct file_port *fport = (struct file_port*)user_data;
|
||||
|
||||
if (event->type == PJMEDIA_EVENT_CALLBACK) {
|
||||
if (fport->cb2)
|
||||
(*fport->cb2)(&fport->base, fport->base.port_data.pdata);
|
||||
}
|
||||
|
||||
return PJ_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
@ -498,17 +549,39 @@ static pj_status_t file_put_frame(pjmedia_port *this_port,
|
|||
fport->total += bytes;
|
||||
}
|
||||
|
||||
/* Increment total written, and check if we need to call callback */
|
||||
|
||||
if (fport->cb && fport->total >= fport->cb_size) {
|
||||
pj_status_t (*cb)(pjmedia_port*, void*);
|
||||
pj_status_t status;
|
||||
/* Check if we need to call callback */
|
||||
if (fport->total >= fport->cb_size) {
|
||||
if (fport->cb2) {
|
||||
if (!fport->subscribed) {
|
||||
pj_status_t status;
|
||||
|
||||
cb = fport->cb;
|
||||
fport->cb = NULL;
|
||||
status = pjmedia_event_subscribe(NULL, &file_on_event,
|
||||
fport, fport);
|
||||
fport->subscribed = (status == PJ_SUCCESS)? PJ_TRUE:
|
||||
PJ_FALSE;
|
||||
}
|
||||
|
||||
status = (*cb)(this_port, this_port->port_data.pdata);
|
||||
return status;
|
||||
if (fport->subscribed && !fport->cb_called) {
|
||||
pjmedia_event event;
|
||||
|
||||
/* To prevent the callback from being called more than once. */
|
||||
fport->cb_called = PJ_TRUE;
|
||||
|
||||
pjmedia_event_init(&event, PJMEDIA_EVENT_CALLBACK,
|
||||
NULL, fport);
|
||||
pjmedia_event_publish(NULL, fport, &event,
|
||||
PJMEDIA_EVENT_PUBLISH_POST_EVENT);
|
||||
}
|
||||
} else if (fport->cb) {
|
||||
pj_status_t (*cb)(pjmedia_port*, void*);
|
||||
pj_status_t status;
|
||||
|
||||
cb = fport->cb;
|
||||
fport->cb = NULL;
|
||||
|
||||
status = (*cb)(this_port, this_port->port_data.pdata);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
return PJ_SUCCESS;
|
||||
|
@ -536,6 +609,10 @@ static pj_status_t file_on_destroy(pjmedia_port *this_port)
|
|||
unsigned long WriteSize;
|
||||
unsigned long MP3Err;
|
||||
|
||||
if (fport->subscribed) {
|
||||
pjmedia_event_unsubscribe(NULL, &file_on_event, fport, fport);
|
||||
fport->subscribed = PJ_FALSE;
|
||||
}
|
||||
|
||||
/* Close encoder */
|
||||
MP3Err = BladeDLL.beDeinitStream(fport->mp3_stream, fport->mp3_buf,
|
||||
|
|
Loading…
Reference in New Issue