--- asterisk-trunk-orig/main/audiohook.c 2010-08-19 14:33:28.000000000 +0200 +++ asterisk-trunk/main/audiohook.c 2010-08-19 14:34:50.000000000 +0200 @@ -44,8 +44,8 @@ }; struct ast_audiohook_list { - struct ast_audiohook_translate in_translate[2]; - struct ast_audiohook_translate out_translate[2]; + struct ast_audiohook_translate in_translate[4]; + struct ast_audiohook_translate out_translate[4]; AST_LIST_HEAD_NOLOCK(, ast_audiohook) spy_list; AST_LIST_HEAD_NOLOCK(, ast_audiohook) whisper_list; AST_LIST_HEAD_NOLOCK(, ast_audiohook) manipulate_list; @@ -588,24 +588,25 @@ * \brief Pass an AUDIO frame off to be handled by the audiohook core * * \details - * This function has 3 ast_frames and 3 parts to handle each. At the beginning of this - * function all 3 frames, start_frame, middle_frame, and end_frame point to the initial - * input frame. + * This function has 6 ast_frames and 3 parts to handle each. * - * Part_1: Translate the start_frame into SLINEAR audio if it is not already in that + * Part_1: Translate the start_frame into SLINEAR and SLINEAR16 audio if it is not already in that * format. The result of this part is middle_frame is guaranteed to be in - * SLINEAR format for Part_2. - * Part_2: Send middle_frame off to spies and manipulators. At this point middle_frame is + * SLINEAR format and middle_frame16 is guaranteed to be in + * SLINEAR16 format for Part_2. + * Part_2: Send middle_frame or middle_frame16 off to spies and manipulators. At this point middle_frame/middle_frame16 is * either a new frame as result of the translation, or points directly to the start_frame - * because no translation to SLINEAR audio was required. The result of this part - * is end_frame will be updated to point to middle_frame if any audiohook manipulation + * because no translation to SLINEAR/SLINEaR16 audio was required. The result of this part + * is end_frame/ned_frame16 will be updated to point to middle_frame/middle_frame16 if any audiohook manipulation * took place. - * Part_3: Translate end_frame's audio back into the format of start frame if necessary. - * At this point if middle_frame != end_frame, we are guaranteed that no manipulation - * took place and middle_frame can be freed as it was translated... If middle_frame was - * not translated and still pointed to start_frame, it would be equal to end_frame as well - * regardless if manipulation took place which would not result in this free. The result - * of this part is end_frame is guaranteed to be the format of start_frame for the return. + * Part_3a: 4 cases here: + * 1. both SLINEAR and SLINEAR16 audiohooks -> combine the manipulated frames and continue with combined frame + * 2. only SLINEAR audiohooks -> continue with middle_frame only + * 3. only SLINEAR16 audiohooks -> continue with middle_frame16 only + * 4. no manipulation -> return start_frame + * cases 1-3 make temp_frame point to the relevant frame for further processing + * Part_3b: Translate temp_frame's audio back into the format of start frame if necessary. + * The result of this part is temp_frame is guaranteed to be the format of start_frame for the return. * * \param chan Channel that the list is coming off of * \param audiohook_list List of audiohooks @@ -617,26 +618,48 @@ { struct ast_audiohook_translate *in_translate = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook_list->in_translate[0] : &audiohook_list->in_translate[1]); struct ast_audiohook_translate *out_translate = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook_list->out_translate[0] : &audiohook_list->out_translate[1]); - struct ast_frame *start_frame = frame, *middle_frame = frame, *end_frame = frame; + struct ast_audiohook_translate *in_translate16 = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook_list->in_translate[2] : &audiohook_list->in_translate[3]); + struct ast_audiohook_translate *out_translate16 = (direction == AST_AUDIOHOOK_DIRECTION_READ ? &audiohook_list->out_translate[2] : &audiohook_list->out_translate[3]); + struct ast_frame *start_frame = frame, *middle_frame = frame, *end_frame = NULL; + struct ast_frame *temp_frame = frame, *middle_frame16 = frame, *end_frame16 = NULL; struct ast_audiohook *audiohook = NULL; int samples = frame->samples; - /* ---Part_1. translate start_frame to SLINEAR if necessary. */ + /* ---Part_1a. translate start_frame to SLINEAR if necessary. */ /* If the frame coming in is not signed linear we have to send it through the in_translate path */ if (frame->subclass.codec != AST_FORMAT_SLINEAR) { if (in_translate->format != frame->subclass.codec) { if (in_translate->trans_pvt) ast_translator_free_path(in_translate->trans_pvt); if (!(in_translate->trans_pvt = ast_translator_build_path(AST_FORMAT_SLINEAR, frame->subclass.codec))) - return frame; + return frame; in_translate->format = frame->subclass.codec; } if (!(middle_frame = ast_translate(in_translate->trans_pvt, frame, 0))) return frame; samples = middle_frame->samples; } + + /* ---Part_1b. translate start_frame to SLINEAR16 if necessary. */ + /* If + 1. the frame coming in is not signed linear 16 + 2. 16khz codec + we have to send it through the in_translate16 path */ + if (frame->subclass.codec != AST_FORMAT_SLINEAR16 && ast_format_rate(frame->subclass.codec) == 16000 ) { + if (in_translate16->format != frame->subclass.codec) { + if (in_translate16->trans_pvt) + ast_translator_free_path(in_translate16->trans_pvt); + if (!(in_translate16->trans_pvt = ast_translator_build_path(AST_FORMAT_SLINEAR16, frame->subclass.codec))) + return frame; + + in_translate16->format = frame->subclass.codec; + } + if (!(middle_frame16 = ast_translate(in_translate16->trans_pvt, frame, 0))) + return frame; + } + - /* ---Part_2: Send middle_frame to spy and manipulator lists. middle_frame is guaranteed to be SLINEAR here.*/ + /* ---Part_2: Send middle_frame to spy and manipulator lists. middle_frame is guaranteed to be SLINEAR here. middle_frame16 is guaranteed to be SLINEAR16 here.*/ /* Queue up signed linear frame to each spy */ AST_LIST_TRAVERSE_SAFE_BEGIN(&audiohook_list->spy_list, audiohook, list) { ast_audiohook_lock(audiohook); @@ -691,45 +714,133 @@ continue; } /* Feed in frame to manipulation. */ - if (audiohook->manipulate_callback(audiohook, chan, middle_frame, direction)) { - /* XXX IGNORE FAILURE */ - - /* If the manipulation fails then the frame will be returned in its original state. - * Since there are potentially more manipulator callbacks in the list, no action should - * be taken here to exit early. */ + if(ast_format_rate(frame->subclass.codec) == 16000 && ast_test_flag(audiohook, AST_AUDIOHOOK_WANTS_SLINEAR16)) + { + if (audiohook->manipulate_callback(audiohook, chan, middle_frame16, direction)) { + /* XXX IGNORE FAILURE */ + + /* If the manipulation fails then the frame will be returned in its original state. + * Since there are potentially more manipulator callbacks in the list, no action should + * be taken here to exit early. */ + } + end_frame16 = middle_frame16; + } + else + { + if (audiohook->manipulate_callback(audiohook, chan, middle_frame, direction)) { + /* XXX IGNORE FAILURE */ + } + end_frame = middle_frame; } ast_audiohook_unlock(audiohook); } AST_LIST_TRAVERSE_SAFE_END; - end_frame = middle_frame; + } - /* ---Part_3: Decide what to do with the end_frame (whether to transcode or not) */ - if (middle_frame == end_frame) { - /* Middle frame was modified and became the end frame... let's see if we need to transcode */ - if (end_frame->subclass.codec != start_frame->subclass.codec) { + /* ---Part_3a: Decide what to do with the end_frames (whether to transcode or not) */ + + /* middle_frame and middle_frame16 were modified */ + if (middle_frame == end_frame && middle_frame16 == end_frame16) + { + int j = 0; + short *data3 = NULL, *data4 = NULL; + /* transcode middle_frame to AST_FORMAT_SLINEAR16 */ + if (out_translate16->format != AST_FORMAT_SLINEAR) { + if (out_translate16->trans_pvt) + ast_translator_free_path(out_translate16->trans_pvt); + if (!(out_translate16->trans_pvt = ast_translator_build_path(AST_FORMAT_SLINEAR, AST_FORMAT_SLINEAR16))) { + /* We can't transcode this... drop our middle frames and return the original */ + if(middle_frame!=start_frame) + ast_frfree(middle_frame); + if(middle_frame16!=start_frame) + ast_frfree(middle_frame16); + return start_frame; + } + out_translate16->format = AST_FORMAT_SLINEAR; + } + if (!(middle_frame = ast_translate(in_translate16->trans_pvt, middle_frame, 0))) + return start_frame; + /* add middle_frame(now SLINEAR16) and middle_frame16 */ + samples = middle_frame16->samples; + for (j = 0, data3 = middle_frame16->data.ptr, data4 = middle_frame->data.ptr; j < samples; j++, data3++, data4++) + ast_slinear_saturated_add(data3, data4); + /* combined data now in middle_frame16 */ + temp_frame = middle_frame16; + } + /* only middle_frame was modified */ + else if(middle_frame == end_frame) + { + temp_frame = middle_frame; + if(middle_frame16!=start_frame) + ast_frfree(middle_frame16); + } + /* only middle_frame16 was modified */ + else if(middle_frame16 == end_frame16) + { + temp_frame = middle_frame16; + if(middle_frame!=start_frame) + ast_frfree(middle_frame); + } + /* No frame was modified, we can just drop our middle frame and pass the frame we got in out */ + else + { + if(middle_frame!=start_frame) + ast_frfree(middle_frame); + if(middle_frame16!=start_frame) + ast_frfree(middle_frame16); + return start_frame; + } + /* ---Part_3b: Decide what to do with the temp_frame (whether to transcode or not) */ + if(temp_frame != start_frame) + { + /* middle frames were modified and became the temp frame... let's see if we need to transcode */ + if (temp_frame->subclass.codec != start_frame->subclass.codec) { if (out_translate->format != start_frame->subclass.codec) { if (out_translate->trans_pvt) ast_translator_free_path(out_translate->trans_pvt); - if (!(out_translate->trans_pvt = ast_translator_build_path(start_frame->subclass.codec, AST_FORMAT_SLINEAR))) { - /* We can't transcode this... drop our middle frame and return the original */ - ast_frfree(middle_frame); - return start_frame; + if(temp_frame == middle_frame16) + { + if (!(out_translate->trans_pvt = ast_translator_build_path(start_frame->subclass.codec, AST_FORMAT_SLINEAR16))) { + /* We can't transcode this... drop our middle frames and return the original */ + if(middle_frame!=start_frame) + ast_frfree(middle_frame); + if(middle_frame16!=start_frame) + ast_frfree(middle_frame16); + return start_frame; + } + } + else + { + if (!(out_translate->trans_pvt = ast_translator_build_path(start_frame->subclass.codec, AST_FORMAT_SLINEAR))) { + /* We can't transcode this... drop our middle frames and return the original */ + if(middle_frame!=start_frame) + ast_frfree(middle_frame); + if(middle_frame16!=start_frame) + ast_frfree(middle_frame16); + return start_frame; + } } out_translate->format = start_frame->subclass.codec; } /* Transcode from our middle (signed linear) frame to new format of the frame that came in */ - if (!(end_frame = ast_translate(out_translate->trans_pvt, middle_frame, 0))) { + if (!(end_frame = ast_translate(out_translate->trans_pvt, temp_frame, 0))) { /* Failed to transcode the frame... drop it and return the original */ - ast_frfree(middle_frame); - return start_frame; + if(middle_frame!=start_frame) + ast_frfree(middle_frame); + if(middle_frame16!=start_frame) + ast_frfree(middle_frame16); } - /* Here's the scoop... middle frame is no longer of use to us */ - ast_frfree(middle_frame); + /* Here's the scoop... middle frames are no longer of use to us */ + if(middle_frame!=start_frame) + ast_frfree(middle_frame); + if(middle_frame16!=start_frame) + ast_frfree(middle_frame16); + } + else + { + end_frame = temp_frame; } - } else { - /* No frame was modified, we can just drop our middle frame and pass the frame we got in out */ - ast_frfree(middle_frame); } return end_frame;