+/* This will allocate and free the translator path as needed so it can be re-used on subsequent calls */
+static void fill_frame_buffer(struct ast_frame *source_frame,
+ struct ast_format *target_format,
+ struct ast_format **last_source_format,
+ struct ast_trans_pvt **translator_path,
+ short *dest_buf,
+ size_t dest_buf_size,
+ const char *direction)
+{
+ struct ast_frame *converted_frame = NULL;
+
+ if (!source_frame) {
+ memset(dest_buf, 0, dest_buf_size);
+ return;
+ }
+
+ /*
+ * We only need to worry about translating if the frame format does not match
+ * the expected format of the frame we are writing.
+ */
+ if (ast_format_cmp(target_format, source_frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
+ /*
+ * If the format changed from the last frame or if this is the first frame
+ * that does not match the native format, we need to set up a new
+ * translator path.
+ */
+ if (ast_format_cmp(*last_source_format, source_frame->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL
+ || !*translator_path) {
+ ast_debug(3, "%s frame format changed from %s to %s, building translator path to %s\n",
+ direction,
+ *last_source_format ? ast_format_get_name(*last_source_format) : "none",
+ ast_format_get_name(source_frame->subclass.format),
+ ast_format_get_name(target_format));
+
+ if (*translator_path) {
+ ast_translator_free_path(*translator_path);
+ }
+
+ *translator_path = ast_translator_build_path(target_format, source_frame->subclass.format);
+ }
+
+ if (*translator_path) {
+ converted_frame = ast_translate(*translator_path, source_frame, 0);
+ }
+
+ /*
+ * If creating the translated frame or translator path failed, write silence for this frame. We will
+ * try rebuilding the translator path later if it is still needed.
+ */
+ if (converted_frame) {
+ memcpy(dest_buf, converted_frame->data.ptr, dest_buf_size);
+ ast_frame_free(converted_frame, 1);
+ } else {
+ memset(dest_buf, 0, dest_buf_size);
+ }
+ } else {
+ memcpy(dest_buf, source_frame->data.ptr, dest_buf_size);
+
+ /*
+ * If we are doing native frame copying, we can free the translator path if
+ * it exists. We will create a new one later if needed.
+ */
+ if (*translator_path) {
+ ast_translator_free_path(*translator_path);
+ *translator_path = NULL;
+ ast_debug(3, "%s frame format changed from %s to %s, translator path no longer needed\n",
+ direction,
+ *last_source_format ? ast_format_get_name(*last_source_format) : "none",
+ ast_format_get_name(source_frame->subclass.format));
+ }
+ }
+
+ *last_source_format = source_frame->subclass.format;
+}
+